Ansible manipulate variable with gsub - ansible

I have an argument that is being passed in the form of foobar-a
ansible-playbook test.yml -e "argument=foobar-a"
- name: whatever
hosts: whatever
tasks:
- name: echo
shell: echo {{ argument }}
#should return foobar-b
I need to manipulate that information to be in the form of foobar-b What is the Ansible way of doing this?
In Chef I would just use ruby gsub to do this
argument.gsub!('-a', '-b')

You should use regex_replace filter, like in the playbook below.
- name: whatever
hosts: whatever
tasks:
- name: echo
shell: echo {{ argument | regex_replace('-a','-b') }}
See filters documentation

Related

Ansible vars using lookups

I have an Ansible playbook that populates some variables, here is a snippet:
#myTest playbook
---
- hosts: localhost
connection: local
become: False
vars:
- APP_NAME: "{{lookup( 'env', 'name')| mandatory }}"
I'd like to use another lookup first, and take that value if its been populated. Is this achievable in one line? I'm figuring something like Javascript's ||:
- APP_NAME: "{{lookup( 'env', 'customName') || lookup( 'env', 'name')| mandatory }}"
You can use the default filter with an option to trigger it if the value of the preceding expression is an empty string (as in the case of an undefined environment variable):
- APP_NAME: "{{ lookup('env', 'customName') | default(lookup('env', 'name'), true) | mandatory }}"

Pass parameter from .sh file to .yml file?

I am new to Ansible as well as Ubuntu system also. I want to pass the multiple variables from .sh file to .yml. I have plan to store all input variables in an array then passing the variable one by one using for loop while calling the file distributed-setup.yml.
Currently, I am trying to pass a variable.For that,I am following the below steps.
While executing the First.sh file I am passing the a variables like First.sh Input.yaml
First.sh file is like this
echo $1
ansible-playbook distributed-setup.yml --extra-vars="v:$1" -${1:-v} | tee output.txt
Distributed-setup.yml
---
- name: Executing slaves
hosts: slave
gather_facts: no
vars:
v: "{{lookup('env','v') }}"
contents: "{{ lookup('file','/home/ubuntu/Ansible-setup/Distributed-Ubuntu-Setup/Input/Input.yaml') | from_yaml }}"
log: "{{ contents['log'][0] }}"
timeout: "{{ contents['ansible-timeout'][0] }}"
In the line, contents: I need to use variable 'v' instead of Input.yaml.
How to do this?
One of the easiest ways to do this is through the environment
someVar=value ansible-playbook ...
and then, inside your Ansible code, you can refer to ansible_env.someVar. You can also export the variable and not need to define it on the same line.
To make this a bit more concrete for your use case:
input_yaml=/home/ubuntu/Ansible-setup/Distributed-Ubuntu-Setup/Input/Input.yaml
export input_yaml
ansible-playbook distributed-setup.yml
...and in your Ansible file:
contents: "{{ lookup('file', ansible_env.input_yaml) | from_yaml }}"
This is how you could use your variable v within other ones:
---
- hosts: localhost
connection: local
gather_facts: no
vars:
v: "{{ lookup('env','v') }}"
b: "{{ lookup('file','/tmp/{{ v }}') | from_yaml }}"
tasks:
- name: set contents
set_fact:
contents: "{{ lookup('file','/tmp/{{ v }}') | from_yaml }}"
- name: debug
debug:
msg: "{{ b }} == {{ contents }}"
when: b == contents
v will get the value of the existing environment var v and then use it on var b later in a task just in case is created another variable named contents with the value of b in this case using set_fact
For testing do:
$ export v=foo
$ date > /tmp/foo
$ ansible-playbook test.yml
It will set v to foo then will create a file in /tmp/foo with the current date (output of the date command)

ansible read (more than one) values from a line in file

i am trying to read variables from a file into an array of something, but not into a pre defined variable.
The goal is a playbook, that searches for lines with item.0 and NOT item.1 and deletes them, later the playbook makes sure, that a line with item.0 item.1 is present, thats why i need this splitted.
For example i have a file with lines like this:
Parameter Value
Parameter Value
Parameter Value
to use this in a loop until EOF.
example part ot the playbook:
- name: lineinfile loop
lineinfile:
path: /myfile
regexp '^{{somethinglike item.0}}.(?!{{something like item.1}})'
state absent
...
Does anybody know a solution for the lookup and the loop?
Best regards
This should help you.
Input file
cat filein
Parameter1,Value1
Parameter2,Value2
Parameter3,Value3
Playbook:
---
- hosts: test
tasks:
- name: reg
shell: cat filein
register: myitems
- name: deb
debug: var=myitems.stdout_lines
- name: echo to file
shell: "echo {{ item.split(',')[1] }} - {{ item.split(',')[0] }} >> fileout"
with_items: "{{ myitems.stdout_lines }}"
Output file:
cat fileout
Value1 - Parameter1
Value2 - Parameter2
Value3 - Parameter3
This is not state of the art but should work.
The solutuion:
There is a ansible role in ansible galaxy, it provides exactly what i need:
https://github.com/mkouhei/ansible-role-includecsv

Ansible - Advanced shell command execution format

I have 3 variables named IPOctet, ServerIPRange and epcrange.
If I perform the following operation in my terminal, it works perfectly
IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc)
How to I do something similar in a ansible inside a task, for e.g
---
- hosts: localhost
gather_facts: False
vars_prompt:
- name: epcrange
prompt: Enter the number of EPCs that you want to configure
private: False
default: "1"
- name: serverrange
prompt: Enter the number of Clients that you want to configure
private: False
default: "1"
- name: ServerIPRange
prompt: Enter the ServerIP range
private: False
default: '128'
- name: LastIPOctet
prompt: Enter The last Octet of the IP you just entered
private: False
default: '10'
pre_tasks:
- name: Set some facts
set_fact:
ServerIP1: "{{ServerIP}}"
ServerIPRange1: "{{ServerIPRange}}"
IPOctet: "{{LastIPOctet}}"
- name: local action math
local_action: shell {{IPOctet}}=$(echo "${{ServerIPRange}}/${{epcrange}}+${{IPOctet}}" | bc) # Proper Syntax?
with_sequence: start=1 end=4
register: result
ignore_errors: yes
What is the proper syntax for this command? Maybe using shell echo "......." . I just need to save the contents of this command into the IPOctet variable and IPOctet will change with each loop iteration and the results should be stored in my result register
P.S: how can I access the individual items in the array separately?
Edit: Is anything like this possible, currently it just does the calculation once and stores it 4 times in the register...
- name: bashless math
set_fact:
IPOctet: "{{ (ServerIPRange|int/epcrange|int)+IPOctet|int }}"
register: IPOctet
with_sequence: "start=1 end={{stop}} "
register: my_ip_octet
Your terminal expression reassigns the IPOctet shell variable, so it gives a different result each time it is executed. This is fine, but difficult to reproduce in Ansible:
$ IPOctet=10 ServerIPRange=128 epcrange=1
$ IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc); echo $IPOctet
138
$ IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc); echo $IPOctet
266
The syntax: "shell {{IPOctet}}=$(echo ..." does NOT assign to the Ansible variable.
The shell attempts to execute a command like "10=138", which is not found.
When register is used within a loop, the target variable is not set until the loop completes - so your expression always sees the original value for {{IPOctet}}.
A solution is to run the whole loop as a single shell command:
- name: local action math2
local_action: shell IPOctet={{IPOctet}}; for i in 1 2 3 4; do IPOctet=$(expr {{ServerIPRange}} / {{epcrange}} + $IPOctet); echo $IPOctet; done
register: result
NOTE: I've used the expr command rather than bc, but the results are the same.
You can iterate over these results using result.stdout_lines:
- name: iterate results
local_action: debug msg={{item}}
with_items: result.stdout_lines
Firstly your Jinja template is incorrect, every single variable needs to be surrounded with a pair of brackets. You can not use multiple variables within single pair of brackets. For example,
{{ ServerIPRange }}
Secondly, set_fact is used only to set a fact value. You can not run shell commands using set_fact. You should use shell module instead.
- name: local action math
local_action: shell {{ IPOctet }}=$(echo {{ ServerIPRange|int }}/{{ epcrange|int }}+{{ IPOctet|int }}" | bc)
with_sequence: start=1 end=4
register: result
ignore_errors: yes
Ansible will do the calculation 4 times and store it in a list as 4 different elements. You can check what all is stored inside this list and can even access it by looping over it.
- debug: msg={{ result }}
Hope this helps :)

How to concatenate string in YAML?

I am writing a playbook in which I need to execute mysql query and pass
output in json format. playbook code working fine just I want facing error in string concatenate part. If I am passing sample json string it is working fine.
- name: Execute php script with json parameter
command: php -f /path/to/php/test.php "{'colors':{'red','blue','yellow'}}"
register: php_output
output.stdout_lines is variable already set in my playbook which contains output in {'red','blue','yellow'} format.
- name: Execute php script with json parameter
command: php -f /path/to/php/test.php '{"stdout_lines": {{output.stdout_lines}} }'
register: php_output
So how can I concatenate output.stdout_lines variable in '{"stdout_lines": {{output.stdout_lines}} }' ? any suggestions
stdout_lines was created for convenience. Back in the day we only had stdout. Which is what you want, I think:
command: php -f /path/to/php/test.php '{"stdout_lines": {{output.stdout}} }'
and if you want to really concat yourself, say because you have your own list of strings then you can use the Jinja2 built-in filter join:
- hosts: localhost
gather_facts: False
tags: so9
vars:
- str_list: ['Hello', 'world', '!', ]
tasks:
- debug: msg="orig list={{ str_list }}"
- debug: msg="concated = {{ str_list | join(' ') }}"
- set_fact: concated_str="{{ str_list | join(' ') }}"
- debug: msg="assigned to a variable concated_str = {{ concated_str }}"
Try like this.
vars:
- img_path: "/var/lib/libvirt/images/{{ instance_name }}-disk2.img"
Where instance name is a another variable
This will do
- name: Generate JSON output based on template
template: src=colors.json.j2 dest=/tmp/colors.json
with_items: colors
It will generate a file like
{'colors':
{
'blue',
'red',
'green',
}
}
The to_json filter is what you want.
Ansible doesn't store variables as JSON strings, it stores them as Python objects. When you're debugging e.g. with -vvv, Ansible displays these Python objects as JSON strings, but that's for your convenience.
To produce the desired command:
- name: Execute php script with json parameter
vars:
# define my desired object
my_object:
colors: "{{ output.stdout_lines }}"
# my_object contains a dict with a single key
# "colors" who's value is the list contained
# in output.stdoutlines
command: "php -f /path/to/php/test.php {{ my_object | to_json | quote }}"
register: php_output
to_json takes the object stored in my_object and outputs a JSON string.
quote automatically handles any shell quoting that might be required for the JSON string. e.g. If my JSON string contains double-quotes, quote will wrap the whole JSON string in single-quotes.

Resources