Ansible - Advanced shell command execution format
Solution 1
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 thanbc
, 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
Solution 2
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 :)
Khan
Updated on July 09, 2022Comments
-
Khan almost 2 years
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