How can I get jenkin ansible-playbook plugin to pass a list of strings in the same way I would on the command line?
ansible-playbook ... \
-e '{"package_urls": ["http...windows.exe", "http...linux.rpm", "http...babbage.steam"]}'
In jenkins the playbook seems to take a map for extraVars and my escaping attempts haven't yet worked
ansiblePlaybook (..., extraVars: [
package_urls: """["http...windows.exe", "http...linux.rpm", "http...babbage.steam"]""" )
Results in the following which lacks ' and ' and is not recognized as a list
... -e package_urls=["http...windows.exe", "http...linux.rpm", "http...babbage.steam"]
This works in that it produces the correct command line. The playbook plugin has an extras param which can be used to pass a variety of text down the the command line. I usually use this for the '-vvv' verbosity modification.
ansiblePlaybook ( ...,
extras: """-e '{"package_urls": ["http...windows.exe", "http...linux.rpm", "http...babbage.steam"]}'""")
The desired text is passed down to the command line with no modifications and the job pulls in its list.
This is probably not the optimal approach and either populating a var file or a json file which is read by the playbook feels like a cleaner approach
Related
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
Man pages for ansible and ansible-playbook define -i option as:
-i PATH, --inventory=PATH
The PATH to the inventory hosts file, which defaults to
/etc/ansible/hosts.
Yet to run on a local system the following syntax is used in examples:
ansible -i "localhost," -c local -m ping localhost
What exactly is this "localhost," with comma at the end (otherwise it is treated as filename) and how does it relate to PATH?
This is (now, at least) a documented feature. From the man page:
-i, --inventory, --inventory-file
specify inventory host path or comma separated host list. --inventory-file is deprecated
(emphasis added)
What's still not in the manual is that "comma separated host list" means that you need to add a comma even if the "list" is a single item, to distinguish between "target a single host called hostname":
$ ansible -i 'hostname,' ...
and "load inventory from a file called hostname":
$ ansible -i 'hostname,' ...
If anyone out there has time, maybe you could submit a pull request to change the help text to explain this (and to add a hyphen in "comma-separated", but maybe that's just me..)
According to Michael DeHann, who created Ansible, the comma trick you're referring to is a hack that shouldn't be relied upon. It's a hack to run Ansible without an inventory file, for cases where you're going to run against localhost. That way you don't actually have to create an inventory file that just lists localhost.
Actually, when you want to run commands against a specific host, don't add -i, instead, run it in the following way:
ansible localhost -m ping
Use -i only to specify the path for dynamic inventory or hosts.
Is there a way to check playbook syntax and variables?
I'm trying to dry-run(--check) but for some reasons it works really slow. It looks like it tries to perform an action instead of just check the syntax
I want to omit en errors like this:
..."msg": "AnsibleUndefinedVariable: ERROR! 'application_name' is undefined"}
This is expected behaviour according to the documentation:
When ansible-playbook is executed with --check it will not make any
changes on remote systems. Instead, any module instrumented to support
‘check mode’ (which contains most of the primary core modules, but it
is not required that all modules do this) will report what changes
they would have made rather than making them. Other modules that do
not support check mode will also take no action, but just will not
report what changes they might have made.
Old link (does not work anymore): http://docs.ansible.com/ansible/playbooks_checkmode.html
New link: https://docs.ansible.com/ansible/latest/user_guide/playbooks_checkmode.html#using-check-mode
If you would like to check the YAML syntax you can use syntax-check.
ansible-playbook rds_prod.yml --syntax-check
playbook: rds_prod.yml
I was looking for the same, but was not satisfied by the --syntax-check option, since it does not work its way down to the roles. A more complete check can be performed with ansible-lint which also includes style-checks. But if you turn off all style-checks, then you have a pretty complete syntax-check.
So do something like
ansible-lint -x $(echo $(ansible-lint -L | awk -F':' '{print $1}' | grep '^[^ ]') | tr ' ' ',') my_playbook.yml
Add a task to fail the playbook when variables aren't defined. This should be the first task run.
Another option is to ensure that all variables have a default value in the /defaults/ directory so that it never fails, but the variables can still be overwritten at other levels.
My preferd way is
pip install yamllint
yamllint -d "{extends: default, rules: {quoted-strings: enable}}" .
Since I really want to catch quote errors, e.g.
validate: bash -c ' ' \""
This is valid yaml, since yaml will just quote the string and turn it into:
validate: "bash -c ' ' \\\"\""
Whilst there was just clearly a quote missing at the beginning of the validate comand.
So a normal yaml checker will not detect this, yamllint wil not even detect this in it's default configuration, so turn on quoted-strings checker.
Man pages for ansible and ansible-playbook define -i option as:
-i PATH, --inventory=PATH
The PATH to the inventory hosts file, which defaults to
/etc/ansible/hosts.
Yet to run on a local system the following syntax is used in examples:
ansible -i "localhost," -c local -m ping localhost
What exactly is this "localhost," with comma at the end (otherwise it is treated as filename) and how does it relate to PATH?
This is (now, at least) a documented feature. From the man page:
-i, --inventory, --inventory-file
specify inventory host path or comma separated host list. --inventory-file is deprecated
(emphasis added)
What's still not in the manual is that "comma separated host list" means that you need to add a comma even if the "list" is a single item, to distinguish between "target a single host called hostname":
$ ansible -i 'hostname,' ...
and "load inventory from a file called hostname":
$ ansible -i 'hostname,' ...
If anyone out there has time, maybe you could submit a pull request to change the help text to explain this (and to add a hyphen in "comma-separated", but maybe that's just me..)
According to Michael DeHann, who created Ansible, the comma trick you're referring to is a hack that shouldn't be relied upon. It's a hack to run Ansible without an inventory file, for cases where you're going to run against localhost. That way you don't actually have to create an inventory file that just lists localhost.
Actually, when you want to run commands against a specific host, don't add -i, instead, run it in the following way:
ansible localhost -m ping
Use -i only to specify the path for dynamic inventory or hosts.
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('&', ' ') }}"