Expand complex ansible variable - ansible

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).

Related

Need to convert back slashes to forward slashes in github action work flow

In my actions yml file, I set an environment variable pointing to the root directory for my ctest input image files (I run ctest to test an image codec decompressor, and these are the input images).
env:
DATA_ROOT: ${{github.workspace}}/data
On windows, this is gives me something like c:\Foo\Bar/data, and I would like to convert it to
c:/Foo/Bar/data
I can do the conversion in PowerShell:
$temp = ${DATA_ROOT}
$pattern = '[\\]'
$temp = $temp -replace $pattern, '/'
but how do I then reset ${DATA_ROOT} to equal $temp ?
I want subsequent steps to use the new ${DATA_ROOT} .
Note this is hurting me right now with ${{github.workspace}} using \ path separators on windows, breaking any "run" actions using the bash shell. So this doesn't work;
defaults:
run:
shell: bash
jobs:
build:
steps:
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build
A workaround is to put single quotes around '${{github.workspace}}/build' which prevents bash from treating the \ path separators as escapes.
I'm not sure why this is tagged CMake, but you can set environment variables in GitHub Actions by writing a line containing NAME=VALUE to $GITHUB_ENV.
From the GitHub Actions documentation:
echo "{name}={value}" >> $GITHUB_ENV
Creates or updates an environment variable for any actions running next in a job. The action that creates or updates the environment variable does not have access to the new value, but all subsequent actions in a job will have access. Environment variables are case-sensitive and you can include punctuation.
Example
steps:
- name: Set the value
id: step_one
run: |
echo "action_state=yellow" >> $GITHUB_ENV
- name: Use the value
id: step_two
run: |
echo "${{ env.action_state }}" # This will output 'yellow'
Multiline strings
For multiline strings, you may use a delimiter with the following syntax.
{name}<<{delimiter}
{value}
{delimiter}
For a CMake solution, if you have a path with potentially mixed slashes, you can use file(TO_CMAKE_PATH)
file(TO_CMAKE_PATH "c:\\Foo\\Bar/data" path)
message(STATUS "path = ${path}") # prints: path = c:/Foo/Bar/data
Note that this function assumes the incoming path is a native path for the platform on which CMake is running. So on Linux, an input with a drive letter would be invalid (the : would be interpreted as a PATH separator and converted to a ;)

shell variable in vars/main.yml?

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.

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

How to use wildcard with variable [duplicate]

This question already has answers here:
Ansible Command module says that '|' is illegal character
(2 answers)
Closed 5 years ago.
I want to list the files as per the host name.But problem is i not able to use the wildcard with variable properly.Can someone suggest me on this.
---
- hosts: local
become_user: yes
vars:
filename: /root/stuff
tasks:
- name: list files
action: command ls -lrt {{ filename }}/'*{{ansible_hostname}}'
register: listfiles
- debug: var=listfiles
If your question is why * doesn't expand?, then:
command module:
The command module takes the command name followed by a list of space-delimited arguments. The given command will be executed on all selected nodes. It will not be processed through the shell, so variables like $HOME and operations like "<", ">", "|", and "&" will not work
shell module:
The shell module takes the command name followed by a list of space-delimited arguments. It is almost exactly like the command module but runs the command through a shell (/bin/sh) on the remote node.
So if you need any shell tricks, like wildcard expansion or access to environment variables, use shell module.

Resources