shell variable in vars/main.yml? - ansible

I need to create a variable from a shell command. I can do it in a role file like so:
- name: random value
shell: head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16
register: rnd_value
But this doesn't work when placed in vars/main.yml:
ERROR! The vars/main.yml file for role 'test' must contain a
dictionary of variables
What is the recommended way to place the instruction to create a variable from a shell command?

Following comments, variables set in vars/main.yml only take static values.
It's the same for defaults/main.yml.
They are declarative only, and best used for setting static values, possibly to be overwritten later if needed.
Tasks are better for the given example.

Related

Replace an element in a string of csv bash

Working on a bash script. I'm reading a line from a properties file using grep and cut and have fetched some value in a variable role_portions something like this role_portions=role_1:10,role_2:25,role_3:75,role_4:50,role_5:75,role_6:25,role_7:50
Now, I get a few roles as csv input parameter in my bash script and I would want to change those roles values to 0.
For example, when I run modify_script.sh role_2,role_4,role_7, after reading the above value from the file, the script should provide as output role_1:10,role_2:0,role_3:75,role_4:0,role_5:75,role_6:25,role_7:0. Can someone help with this?
When the role names are without special characters (like & and /) you can use sed.
for role in role_2 role_4 role_7; do
role_portions=$(sed -r "s/(^|,)(${role}):[^,]*/\1\2:0/" <<< "${role_portions}")
done
When you are already using grep and cut you might be able to combine commands (maybe use awk).

Expand complex ansible variable

I have distinct ansible variables which are combined in a single command. More precisely, the system defines a variable with default value:
# This exists in an ansible variable definition file
instrumentor = ''
At some the python script that "creates" the ansible commands specifies the extra arguments to override the default values. I'm jumping through some hoops (using \" and \') because the desired value contain spaces:
# This is a line from python script
instrumentation_specs =
'-e \'instrumentor=\"/software/cuda-memcheck --tool racecheck --log-file /tmp/memlog\"\''
On the ansible side then the command is structured as
;; This exists in a jinja template (.j2 extension)
;; command is what the start.yml script will be running
command="{{ instrumentor }}" my_program
Unfortunately I cannot get this to work. The command is reported to expand to something that contains extra ' and ":
start.yml (...) -e 'instrumentor="/software/cuda-memcheck --tool racecheck --log-file /tmp/memlog"' (...)
The weird thing is that
if I create another variable before command that only contains instrumentor, it is reported to have the exact value that I need
instr_tmp = "{{ instrumentor }}"
command = "{{ instr_tmp }}" my_program
i.e. the extra ' and " don't appear in instr_tmp but do appear in command
If I ommit the \" and \' on the python side (when creating the string that is used to provide the extra arguments) everything that's after a space gets omitted.
Anyone knows how to specify such a variable override, i.e. how the string should look like when I specify a variable that contains multiple space separated strings (instrumentor), but that variable is supposed to be plugged into another ansible variable (command).

How to return a value from ansible playbook to an shell script?

I call a playbook from a shell script , example
#!/bin/bash
UPGRADE=`ansible-playbook -i /etc/ansible/hosts checkUpgrade.yml`
echo " UPGRADE VALUE $UPGRADE "
I want to return/set some variable from checkUpgrade.yml, so that my caller script can use it for further use.
Note: Don't want to write the value to file
Registering Variables for later use in playbooks
Using registered variables in conditionals
Reading Registered variable Return Values
If you register a variable on a command or shell, the return code is always(?) saved.
More specific to your apparent use, have the end of the playbook output some key sentinel string that you can scan for in $UPGRADE.
if grep -q SPECIAL_CONDITION_1 <<< "$UPGRADE"
then doStuff1
elif grep -q SPECIAL_CONDITION_2 <<< "$UPGRADE"
then doStuff2
...
ways to make more efficient, but this should make the point.

looping a shell command in ansible

I'm trying to get going with some more advanced Ansible playbooks and have hit a wall. I'm trying to get Ansible to do what this /bin/bash 'for' loop does;
for i in $(</filename.txt);do '/some/command options=1 user=usera server=$i';done
filesnames.txt contains 50-100 hostnames.
I can't use jinja templates as the command has to be run, not just the config file updated.
Any help would be greatly appreciated.
Thanks in advance,
Jeremy
you can use jinja templates, but differently
your specific code is not doing something that is most advisable
for multi-line code you should use shell module.
example of multi-code piece of call:
- name: run multiline stuff
shell: |
for x in "${envvar}"; do
echo "${x}"
done
args:
executable: /bin/bash
note I'm explicitly setting executable, which will ensure bash-isms would work.
I just used envvar as an example, of arbitrary environment variable available.
if you need to pass specific env variables, you should use environment clause of the call to shell module, refer to: http://docs.ansible.com/ansible/playbooks_environment.html
For simple variables you can just use their value in shell: echo "myvar: {{myvar}}"
If you wish to use an ansible list/tuple variable inside bash code, you can make it bash variable first. e.g. if you have a list of stuff in mylist, you can expand it and assign into a bash array, and then iterate over it. the shell code of the call to shell would be:
mylist_for_bash=({{mylist|join(" ")}})
for myitem in "${mylist_for_bash[#]}"; do
echo "my current item: ${myitem}"
done
Another approach would be to pass it as string env variable, and convert it into an array later in the code.
NOTE:
of course all this works correctly only with SPACELESS values
I've never had to pass array with space containing items

Ansible. Fast way to check syntax?

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.

Resources