I'm trying to pass multiple lines as a value to my Ansible file But it's only just passing the first line.
cat slot_number.txt
slot4
slot2
slot1
slot3
My ansible file as below
update_bios.yml
tasks:
- name: Powering off slot number
command: "/usr/local/bin/power-util {{slot_number}} off"
- name: Starting to update BIOS
command: "/usr/bin/fw-util {{slot_number}} --update --bios"
ansible-playbook -l myhosts update_bios.yml -e "slot_number=$(cat slot_number.txt)"
I want to run my command like below:
/usr/local/bin/power-util slot1 off
/usr/local/bin/power-util slot2 off
/usr/local/bin/power-util slot3 off
Edit after understanding the question details:
Map the slot numbers to a host:
cat slot_numbers.yml
slot_numbers:
server1:
-slot4
-slot2
server2:
-slot1
-slot3
After that distinguish between hosts in the playbook as follows,
tasks:
- name: Powering off slot number
command: "/usr/local/bin/power-util {{ item }} off"
loop: "{{ slot_numbers[inventory_hostname] }}"
- name: Starting to update BIOS
command: "/usr/bin/fw-util {{ item }} --update --bios"
loop: "{{ slot_numbers[inventory_hostname] }}"
In this approach we are doing the mapping between hosts and slots in the slot_numbers variable file. Alternatively, you can define the variables as host variables also.
Previous answer:
Ansible understands yaml and json.
Also, playbook needs to handle what happens with the data available to it via variables. So, if you want to loop through a list of slot numbers you have to tell your playbook to do exactly that.
Define your slot number file as follows:
In this file, you are creating a list of slot numbers and assigning it to the key 'slot_numbers'
cat slot_numbers.yml
slot_numbers:
-slot4
-slot2
-slot1
-slot3
Modify your update_bios.yml to loop through the slot numbers you are passing,
tasks:
- name: Powering off slot number
command: "/usr/local/bin/power-util {{ item }} off"
loop: "{{ slot_numbers }}"
- name: Starting to update BIOS
command: "/usr/bin/fw-util {{ item }} --update --bios"
loop: "{{ slot_numbers }}"
then use:
ansible-playbook -l myhosts update_bios.yml -e "#slot_numbers.yml"
Detailed documentation of how to use variables and playbooks can be found here
Something like this should work.
vars:
slot_numbers: "{{ lookup('file', './slot_number.txt').splitlines() }}"
tasks:
- name: Powering off slot number
command: "/usr/local/bin/power-util {{ item }} off"
loop: "{{ slot_numbers }}"
- name: Starting to update BIOS
command: "/usr/bin/fw-util {{ item }} --update --bios"
loop: "{{ slot_numbers }}"
Related
I have the following Ansible playbook: remove.yaml that have two variable and it loops through a set of items.
- name: calling helm commands tasks
include_tasks: helm_commands.yaml
vars:
name_spce: "sdn"
extra_parameter: "--no-hooks"
loop: ['dre','hju','cny','wer','guy']
The included tasks file helm_commands.yaml is:
---
- name: check if {{item}} exist
shell:
cmd: /usr/local/bin/helm3 get manifest {{item}} --namespace {{name_spce}}
register: get_release
failed_when: get_release.rc ==2
- name: helm delete {{item}}
shell:
cmd: /usr/local/bin/helm3 delete {{item}} {{extra_parameter}} --namespace {{name_spce}}
when: get_release.rc ==0
The problem is I want the variable extra_parameter take the value --no-hooks only when it loop through the first item 'dre' otherwise take empty value ''
extra_parameter: "--no-hooks" when loop with 'dre'
"" when loop with other items
You could use the extended loop functionalities for that:
- name: calling helm commands tasks
include_tasks: helm_commands.yaml
vars:
name_spce: "sdn"
extra_parameter: "{{ '--no-hooks' if ansible_loop.first }}"
loop: ['dre','hju','cny','wer','guy']
loop_control:
extended: yes
If you want to add the flag --no-hooks regardless of the position of dre in the list, then it is as simple as:
- name: calling helm commands tasks
include_tasks: helm_commands.yaml
vars:
name_spce: "sdn"
extra_parameter: "{{ '--no-hooks' if item == 'dre' }}"
loop: ['dre','hju','cny','wer','guy']
For me the below code is working -
with_items: "{{ groups['mlpoc'] }}" but instead of hardcoded mlpoc I want to pass it in a variable as a parameter.
Say the command parameter is mlhosts=mlpoc and I want to use the variable instead of hardcoded value, something like -
with_items: "{{ groups['{{ mlhosts }}'] }}" but it throws error. Is it even possible to pass a dynamic value to groups ?
Here is my code -
- hosts: dbsrd3510
user: '{{ mluser }}'
gather_facts: no
no_log: false
tasks:
- name: Fetch source list from clients
with_items: "{{ groups['mlpoc'] }}"
shell: rsync -av /MLbackup/{{ pkg }} {{ mluser }}#{{ item }}:/tmp/
Try something like this,
---
- hosts: all
gather_facts: no
tasks:
- name: Add a line to a file if the file does not exist, without passing regexp
debug:
msg: "{{ item }}"
with_items: " {{ groups[group_name] }} "
And you can test the above changes using,
ansible-playbook -i hosts main.yml -e group_name="all"
I am trying to use a register in Ansible playbook to store my output. Below is the code which i am using.
I have tried below code
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: {{ item }}_service_status
with_items:
- XXX
- YYY
- ZZZ
I need different outputs to be stored in different register variables based on the items as mentioned in the code. It is failing and not able to proceed. Any help would be appreciated.
Updated answer
I think you need to put quotes around it:
register: "{{ item }}_service_status"
Or you can use set_fact (1, 2, 3, 4)
register all the output to a single static variable output and then use a loop to iteratively build a new variable service_status (a list) by looping over each item in the static variable output
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: output
with_items:
- XXX
- YYY
- ZZZ
- name: Setting fact using output of loop
set_fact:
service_status:
- rc: "{{ item.rc }}"
stdout: "{{ item.stdout }}"
id: "{{ item.id }}"
with_items:
- "{{ output }}"
- debug:
msg: "ID and stdout: {{ item.id }} - {{ item.stdout }}"
with_items:
- "{{ service_status }}"
Initial Answer
IIUC, this link from the Ansible docs shows how to use register inside a loop (see another example in this SO post).
A couple of points
it may be more convenient to assign the list (XXX, YYY, ZZZ) to a separate variable (eg. 1, 2)
I don't know if this is part of the problem, but with_items is no longer the recommended approach to loop over a variable: instead use loop - see here for an example
vars:
items:
- XXX
- YYY
- ZZZ
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: service_status
loop: "{{ items|flatten(levels=1) }}"
- name: Show the return code and stdout
debug:
msg: "Cmd {{ item.cmd }}, return code {{ item.rc }}, stdout {{ item.stdout }}"
when: item.rc != 0
with_items: "{{ service_status.results }}"
We need to go through this structure
Zone spec
https://gist.github.com/git001/9230f041aaa34d22ec82eb17d444550c
I was able to run the following snipplet but now I'm stucked at the error checking.
playbook
--
- hosts: all
gather_facts: no
vars_files:
- "../doc/application-zone-spec.yml"
roles:
- { role: ingress_add, customers: "{{ application_zone_spec }}" }
role
- name: check if router exists
shell: "oc get dc -n default {{ customers.zone_name }}-{{ item.type }}"
with_items: "{{ customers.ingress }}"
ignore_errors: True
register: check_router
- name: Print ingress hostnames
debug: var=check_router
- name: create new router
shell: "echo 'I will create a router'"
with_items: "{{ customers.ingress }}"
when: check_router.rc == 1
Output of a ansible run
https://gist.github.com/git001/dab97d7d12a53edfcf2a69647ad543b7
The problem is that I need to go through the ingress items and I need to map the error of the differnt types from the "check_router" register.
It would be nice to make something like.
Pseudo code.
Iterate through the "customers.ingress"
check in "check_router" if the rc is ! 0
execute command.
We use.
ansible-playbook --version
ansible-playbook 2.1.0.0
config file = /etc/ansible/ansible.cfg
configured module search path = Default w/o overrides
You can replace the second loop with:
- name: create new router
shell: "echo 'I will create a router with type {{ item.item }}'"
with_items: "{{ check_router.results }}"
when: item.rc == 1
This will iterate over every step of check_route loop and you can access original items via item.item.
I am trying to write a script (adduser.yml) to create users in a linux machine which imports users list from userlist.csv file. When I executed adduser.yml, the loop failed creating only 1st user. Can someone help me understand what mistake I am doing and how to correct it?
userlist.csv:
id,username,password,sudo
1,ansible1,ansible#123,yes
2,ansible2,ansible#123,no
3,ansible3,ansible#123,yes
4,ansible4,ansible#123,yes
adduser.yml:
---
## executed but until loop failed; check
- hosts: 192.168.0.3
vars:
count: "{{COUNT}}"
x: "1"
uname: "{{ lookup('csvfile', '{{x}} file=userlist.csv delimiter=, col=1') }}"
password: "{{ lookup('csvfile', '{{x}} file=userlist.csv delimiter=, col=2') }}"
sudo: "{{ lookup('csvfile', '{{x}} file=userlist.csv delimiter=, col=3') }}"
tasks:
name: "user add"
action:
- user:
x: "x+=1"
name: "{{ uname }}"
password: "{{ password }}"
state: present
register: x
until: "{{x > count}}"
name: "add to sudoers"
when: sudo == "yes"
lineinfile:
dest: /etc/sudoers
There are quite some things that will not work as you expected them. First thing, your loop is defined for your first task. That means only the user task will be repeated. Neither the sudo task nor the vars definition at the top will be looped. But don't try to re-define your loop, this is not going to work with vars.
Ansible has no build-in way to read vars from a csv file other than the csv lookup which will read exactly one line. But as said, you can not combine that with a loop.
I see two options you have:
Do not use csv. Ansible is mostly bound to yaml. If you'd had a yaml definition of your users, you simply could use the include_vars module to load these vars.
If you are bound to csv, you could try to use this includecsv module. (I have no experience with it and can not tell if it actually works)
Now, let's assume you have loaded your users into a list either from yaml or from csv with mentioned module. Then you'd simply loop with with_items:
tasks:
- name: "user add"
user:
name: "{{ item['uname'] }}"
password: "{{ item['password'] }}"
state: present
with_items: users_you_loaded
- name: "add to sudoers"
when: "{{ item['sudo'] }} == 'yes'"
...
with_items: users_you_loaded