How to make Ansible YAML parsing accept this command? - yaml

Question:
How to make Ansible YAML parsing accept this command ?
Details below:
This YAML:
-shell: "/home/developer/eclipse/eclipse -application org.eclipse.equinox.p2.director -noSplash -repository
'http://moreunit.sourceforge.net/update-site' -installIUs
org.moreunit.feature.group"
is validated by:
http://yaml-online-parser.appspot.com/
http://www.yamllint.com/
http://codebeautify.org/yaml-validator
but ansible says:
This one looks easy to fix. It seems that there is a value started
with a quote, and the YAML parser is expecting to see the line ended
with the same kind of quote. For instance:
when: "ok" in result.stdout
Could be written as:
when: '"ok" in result.stdout'
or equivalently:
when: "'ok' in result.stdout"
As a reference this YAML works perfectly:
-shell: "wget 'http://ftp.gnu.org/gnu/wget/wget-1.5.3.tar.gzip'"

Try
- shell: >
/home/developer/eclipse/eclipse
-application org.eclipse.equinox.p2.director
-noSplash
-repository 'http://moreunit.sourceforge.net/update-site'
-installIUs org.moreunit.feature.group
Do not trust the editor or syntax highlighter. Let ansible tell you if there is a problem (Run it with -C flag to simulate a dry-run if u want). Also try replacing single with double quotes around the repo URL.

Related

Ansible 2.9 - Escape a single "\" backslash being passed into win_command from variable

vars:
- windowsLogonAccount: NT AUTHORITY\SYSTEM
tasks:
- name: Install Agent via CMD
win_command: "config.cmd --windowsLogonAccount '{{ windowsLogonAccount }}'"
args:
chdir: "c:/agent"
I'm attempting to get just a single backslash to pass via Ansible to Windows. I've tried double backslashes "\\" and I've tried {{ var | safe }}, but without luck. I'm hoping somebody in the community can point me in the right direction. I can't believe it is as complicated as some of the other examples I've seen using replace and regex...
Everything I try I keep getting a double backslash:
2021-10-19T04:45:52.8643709Z TASK [Get Variable Output to Screen] *******************************************
2021-10-19T04:45:52.9042957Z "msg": "My Variable Test Area 'NT AUTHORITY\\SYSTEM'"
I came here having not the exact same problem, but a similar one (passing an escaped backslash (\\) to the command), and my solution might also help here. When inserting variables into the command for command or win_command, it is always good to pipe the variable to the quote filter to preserve the content of the variable as is. In your case:
win_command: "config.cmd --windowsLogonAccount {{ windowsLogonAccount | quote }}"
----Resolved----
So this is a unique thing with Ansible Outputs to Terminal. They write output in valid JSON and thus "auto" escape special characters like backslashes in the output. But the actual value passed during run-time does not contain both back slashes. I'm posting this in case any other Ansible noobs run into this surprise.
Example output to screen:
2021-10-19T04:46:11.6003956Z: [COMPUTERNAME]: CHANGED! => {"changed": true, "cmd": "config.cmd --unattended --windowsLogonAccount 'NT AUTHORITY\SYSTEM'
Actual output to host:
config.cmd --unattended --windowsLogonAccount 'NT AUTHORITY\SYSTEM'

What is the purpose of ">" in "shell: >" within an Ansible task?

What function does the ">" character serve, in a simple Ansible task that executes a shell command? For the life of me I can't find documentation or mention of this! Here is the template for the task:
- name: <task_name>
shell: >
<command>
Thank you.
The > is a mark for yaml. It means that the following lines will be compressed into a single string with leading indentation compressed to a single space. There are some technical details regarding leading indentation that will modify how the final string is generated, but to the yaml parser the following are equivalent:
- name: task_name
shell: >
this is some
arbitrary string which may
be a shell command
- name: task2_name
shell: this is some arbitrary string which may be a shell command

How to supply both named and free_form arguments to ansible ad-hoc?

I ran across one of Ansible's modules that take free_form arguments along with named arguments - win_command. A specific example is given, where a powershell script is provided on stdin:
- name: Run an executable and send data to the stdin for the executable
win_command: powershell.exe -
args:
stdin: Write-Host test
I want to use this as a one-off task, so I want to use ad-hoc execution in the style of
ansible <host> -m <module> -a <args...>
Unfortunately, I see no info in the documentation on how to deal with a module that requires specifying both free_form and named arguments. Does anyone know?
Putting the named arguments after the free_form argument puts everything in the free_form argument, resulting in powershell complaining about extraneous arguments
... -m win_command -a 'powershell - stdin=C:\some\script.ps1 -arg1 value_1 -arg2 value_2'
PS: I'm aware I could probably stuff both the script path and arguments in the free_form argument, but I am more interested in learning whether this is possible with ad-hoc, as the docs don't say either way.
I can't test the win_command module directly, but with the command module, which is syntactically very similar, you can reproduce this:
- command: some_command
args:
chdir: /tmp
creates: flagfile
Like this:
ansible -m command -a 'chdir=/tmp creates=flagfile some_command'
Update
Upon investigation...the problem you've encountered with stdin isn't a quoting issue;
it's that when using the k1=v1 k2=v2 somecommand format of passing parameters to e.g. the command module, Ansible only handles specific keys. In lib/ansible/parsing/splitter.py we see:
if check_raw and k not in ('creates', 'removes', 'chdir', 'executable', 'warn'):
raw_params.append(orig_x)
else:
options[k.strip()] = unquote(v.strip())
That is, it only recognizes creates, removes, chdir, executable, and warn as module arguments. I would argue that this is a bug in Ansible. Adding support for the stdin argument is trivial, of course:
if check_raw and k not in ('stdin', 'creates', 'removes', 'chdir', 'executable', 'warn'):
With this change, we can include stdin with spaces as expected:
$ ansible localhost -m command -a 'chdir=/tmp stdin="Hello world" sed s/Hello/Goodbye/'
[WARNING]: Unable to parse /home/lars/.ansible_hosts as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
localhost | CHANGED | rc=0 >>
Goodbye world

Trying to duplicate a Bash script into ansible -- Not sure how to best handle alternatives with Slaves

I see there was a feature request for this, but they do not note how they actually worked around it. In a nutshell, we download a groovy archive, unzip it, and create slaves for every file in the archive that is not the groovy executable, and doesnt end with .bat. We then do a update-alternatives for groovy.
GROOVY_ALT_SLAVES=""
for f in $(ls /opt/groovy-${GROOVY_VERSION}/bin | fgrep -v .bat | grep -v '^groovy$'); do
GROOVY_ALT_SLAVES=" ${GROOVY_ALT_SLAVES} --slave /usr/bin/${f} ${f} /opt/groovy-${GROOVY_VERSION}/bin/${f}"
done
update-alternatives --install /usr/bin/groovy groovy /opt/groovy-${GROOVY_VERSION}/bin/groovy 2000 ${GROOVY_ALT_SLAVES}
update-alternatives --set groovy /opt/groovy-${GROOVY_VERSION}/bin/groovy
I cant really wrap my head around the best way to dupe this, that isnt just running the shell module. Once I resigned myself to using the shell module, I then read that doing something like
- shell: GROOVY_ALT_SLAVES=" ${GROOVY_ALT_SLAVES} --slave /usr/bin/{{ item }} {{ item }} /opt/groovy-{{ groovy_version }}/bin/{{ item }}"
with_items: ['file1', 'file2']
Wouldn't work, since each shell run is a separate connection, so Im not really building up a long string to then append to the update-alternatives command. There is also the fact I have to manually specify a list of items, since I cant use glob because i need to match files that do not match a certain set of expressions.
Im sure Im missing something obvious, but I haven't made any progress on this one and any help would be great.
Make your string inside a playbook and execute shell only once.
Something like this:
- shell: update-alternatives --install /usr/bin/groovy groovy /opt/groovy-{{ groovy_version }}/bin/groovy 2000 {{ alt_slaves }}
vars:
alt_slaves: "{{ myfiles | map('regex_replace','(.*)','--slave /usr/bin/\1 \1 /opt/groovy-'+groovy_version+'/bin/\1') | list | join(' ') }}
I didn't test this, you may have to play with escaping \1 to make it work.

Ansible variable length command line options

I'm trying to create a directive using shell or command to execute something that could have any number of command line arguments.
So something like
- Name: Runs MediaWiki command line setup.
command: "php /opt/wiki/maintanance/install.php {{ arguments }}"
I'm looking for something like a [item for "%s=%s % (key, value) in arguments"]
Looking at ansible variables, everything I see there wants to loop each command on any of the datastruture.
Does anyone know what is the best way to join an arbitrary list of arguments for a command and the best way to structure that in a variables file?
If arguments is a list you can use the join filter.
- Name: Runs MediaWiki command line setup.
command: "php /opt/wiki/maintanance/install.php {{ arguments | join }}"
If arguments is a dict you might be able to do something like this:
- Name: Runs MediaWiki command line setup.
command: "php /opt/wiki/maintanance/install.php {{ arguments | urlencode | replace('&', ' ') }}"

Resources