I use ansible for create and run lxc containers in proxmox.
Run container task:
- name: "DHCP IP"
proxmox:
...
hostname: "{{ item }}"
...
pubkey: "{{ pubkey }}"
with_items:
- "{{ (servers_name_suggested | union(servers_name_list)) | unique }}"
register: output_dhcp
when: not static_ip
- set_fact:
vmid: "{{ output_dhcp.results[0].msg | regex_search('[0-9][0-9][0-9]') }}"
- name: "Start container {{ vmid }}"
proxmox:
vmid: "{{ vmid }}"
api_user: root#pam
api_password: "{{ api_password }}"
api_host: "{{ api_host }}"
state: started
when: start_lxc
It's work if launched one container, one item in task "DHCP IP". If I set
two or more item, my task started only first container. Because I am setting
output_dhcp.results[0].msg
How I can take information about all containers, as example, if I will create tree containers:
output_dhcp.results[1].msg
output_dhcp.results[2].msg
and received to
- name: "Start container {{ vmid }}"
proxmox:
vmid: "{{ vmid }}"
for run all my new cotainers.
The output_dhcp.results is a list, if you extract only the first item with a [0] you will only have the first item.
You need to transform the list into another list you can iterate over in the "Start container" task:
- set_fact:
vmids: "{{ output_dhcp.results | map(attribute='msg') | map('regex_search', '[0-9][0-9][0-9]') | list }}"
- name: "Start container {{ item }}"
proxmox:
vmid: "{{ item }}"
api_user: root#pam
api_password: "{{ api_password }}"
api_host: "{{ api_host }}"
state: started
with_items: "{{ vmids }}"
when: start_lxc
To explain the transformation part:
output_dhcp.results | map(attribute='msg') => get the msg attribute of each item of the output_dhcp.results list (http://jinja.pocoo.org/docs/dev/templates/#map)
| map('regex_search', '[0-9][0-9][0-9]') => apply the regex_search on each item of the list
| list => transform the generator into a list
Related
I am performing a grep with multiple items.
---
- hosts: my_host
gather_facts: false
vars:
my_list:
- whatever
- something
tasks:
- name: grep for item in search path
shell: "grep -rIL {{ item }} /tmp"
register: the_grep
loop: "{{ my_list }}"
- debug:
msg: "{{ item.stdout_lines }}"
loop: "{{ the_grep.results }}"
Depending on the result, multiple files could match.
msg:
- /tmp/something.conf
- /tmp/folder/file.txt
Q: How would I configure Ansible to loop over the items in stdout_lines?
The use case I'm solving is to delete .ini sections based on the item, but in this case, Ansible doesn't loop over the stdout_lines.
- name: remove stanza from ini file
ini_file:
path: "{{ item.stdout_lines }}"
section: "{{ item.item }}"
mode: '0600'
state: absent
loop: "{{ the_grep.results }}"
when: item.stdout_lines | length > 0
It seems that this doesn't work, but configuring item.stdout_lines[0] gives the partially expected result, since Ansible will use only the first item in that list. But ofc, not the 2nd and so on.
Perhaps there's a prettier answer, but solved it by using with_nested and creating a json_query:
- name: remove stanza from ini file
ini_file:
path: "{{ item.0 }}"
section: "{{ item.1.item }}"
mode: '0600'
state: absent
with_nested:
- "{{ the_grep | json_query('results[].stdout_lines[]') }}"
- "{{ the_grep.results }}"
Below is the condition
- name: Find the image
slurp:
src: "{{ IMAGE }}"
register: slurp_results
- name: Upload image
shell: |
skopeo copy -docker-archive:{{ item }}.tar docker://{{ URL }}/TESTIMAGE
with_items: "{{ (slurp_results.content|b64decode).splitlines() }}"
The above code works.
But I would need "TESTIMAGE" also to be replaced as {{ item }} like below.
skopeo copy -docker-archive:{{ item }}.tar docker://{{ URL }}/{{ item }}
How to define 2 with_items in a single shell task with 2 different slurp results
I believe you can by using the subelements module. Here is a link. Try going by this example:
- name: Setup MySQL users, given the mysql hosts and privs subkey lists
mysql_user:
name: "{{ item.0.name }}"
password: "{{ item.0.mysql.password }}"
host: "{{ item.1 }}"
priv: "{{ item.0.mysql.privs | join('/') }}"
with_subelements:
- "{{ users }}"
- mysql.hosts
Users is referred to as item.0 and hosts as item.1 and so on.
I am looking to loop through a list of variables. I have it looping through the of variables using with_items, however the catch is there is a list within that variables list that needs to have a different subset / number of variables that i need to iterate through as well.
I have tried different filters to include with_nested, with_subelements, and with_items. I know that they are moving towards loops as the primary driver moving forward so any solution ideally would leverage the ansible path moving forward. I am looking at having an "inner" loop or an external task that will iterate through the vlans_list and input that data as its to that point.
group Variables
vnic_templates:
- name: vNIC-A
fabric: A
mac_pool: testmac1
mtu: 1500
org_dn: org-root
redundancy_type: none
state: present
template_type: initial-template
vlans_list: ### THE PROBLEM CHILD
- name: vlan2
native: 'no'
state: present
- name: vlan3
native: 'no'
state: present
The actual task - i have issues when i have to input multiple vlans. The vnic template will have a 1 to one relationship however the vlans_list could be 1 vnic_template to many vlans.
ucs_vnic_template:
hostname: "{{ ucs_manager_hostname }}"
username: "{{ ucs_manager_username }}"
password: "{{ ucs_manager_password }}"
name: "{{ item.name }}"
fabric: "{{ item.fabric }}"
mac_pool: "{{ item.mac_pool }}"
mtu: "{{ item.mtu }}"
org_dn: "{{ item.org_dn }}"
redundancy_type: "{{ item.redundancy_type }}"
state: "{{ item.state }}"
template_type: "{{ item.template_type }}"
vlans_list:
- name: "{{ item.1.name }}"
native: "{{ item.1.native }}"
state: "{{ item.1.present }}"
# loop: "{{ vnic_templates | subelements('vlans_list') }}"
with_items:
- "{{ vnic_templates }}"
I am starting down the road of adding an include vlan_list.yml outside of this task but no familiar with out to do that.
Actual results are
The task includes an option with an undefined variable. The error was: 'item' is undefined\n\n
I need the create a single vnic template with multiple vlans defined in that list.
Another engineer i work with was able to solve the question. By the way the variables are laid out we were able to easily just change the code
Change this:
vlans_list:
- name: "{{ item.1.name }}"
native: "{{ item.1.native }}"
state: "{{ item.1.present }}"
To this:
vlans_list: "{{ item.vlans_list }}"
Full Code listed below.
- name: Add vNIC Templates
ucs_vnic_template:
hostname: "{{ ucs_manager_hostname }}"
username: "{{ ucs_manager_username }}"
password: "{{ ucs_manager_password }}"
name: "{{ item.name }}"
fabric: "{{ item.fabric }}"
mac_pool: "{{ item.mac_pool }}"
mtu: "{{ item.mtu }}"
org_dn: "{{ item.org_dn }}"
redundancy_type: "{{ item.redundancy_type }}"
state: "{{ item.state }}"
template_type: "{{ item.template_type }}"
vlans_list: "{{ item.vlans_list }}"
with_items:
- "{{ vnic_templates }}"
I'm wondering if it is possible to perform a loop in the hostvars folder when using Ansible?
Here is what I've tried but haven't had success in making it work - or is it just not possible to do?
---
list_pool: 'list ltm pool {{ items }}'
with_items:
- 'abc123'
- 'def456'
I would use the "list_pool" variable in a playbook afterward:
- name: List pool
bigip_command:
server: "{{ some_server }}"
user: "{{ some_user }}"
password: "{{ some_password }}"
commands:
- "{{ list_pool }}"
validate_certs: no
delegate_to: localhost
Not sure what you mean when you say you want to loop over hostvars folder.
From what I can interpret from your tasks is: "You need to execute big-ip command list ltm <pool-name> for multiple pools in the list list_pool"
If that's what you're after, this should work:
- name: Set list_pool fact
set_fact:
list_pool: "{{ list_pool | default([]) + [item] }}"
with_items:
- 'abc123'
- 'def456'
- name: List pool
bigip_command:
server: "{{ some_server }}"
user: "{{ some_user }}"
password: "{{ some_password }}"
commands:
- "list ltm {{ item }}"
validate_certs: no
delegate_to: localhost
with_items: "{{ list_pool }}"
I got this working with the following solution:
hostvars file would look like this:
---
pre_checks:
checks:
pool:
- name: "pool_123"
- name: "pool_456"
...
And the play would look like this:
--output truncated---
- name: Fetch device host_vars
set_fact:
device_config: "{{ ((lookup('file','{{playbook_dir}}/host_vars/{{inventory_hostname}}.yml')) | from_yaml) }}"
- name: Check pool
bigip_command:
server: "{{ inventory_hostname }}"
user: "{{ remote_username }}"
password: "{{ remote_passwd }}"
commands:
- "list ltm pool {{ item }}"
validate_certs: no
with_items:
- "{{ device_config.pre_checks | json_query('checks.pool[*].name') }}"
delegate_to: localhost
when: "'active' in Active_LTM['stdout'][0]"
register: Pre_Checks
- name: Verify pool
debug: var=item
with_items: "{{ Pre_Checks.results | map(attribute='stdout_lines') | list }}"
I have 3 task in my ansible yml file as below.
---
- name: Instance provisioning
local_action:
module: ec2
region: "{{ vpc_region }}"
key_name: "{{ ec2_keypair }}"
instance_type: "{{ instance_type }}"
image: "{{ ec2_image}}"
zone: "{{ public_az }}"
volumes:
- device_name: "{{ device }}"
volume_type: "{{ instance_volumetype }}"
volume_size: "{{ volume }}"
delete_on_termination: "{{ state }}"
instance_tags:
Name: "{{ instance_name }}_{{ release_name }}_APACHE"
environment: "{{ env_type }}"
vpc_subnet_id: "{{ public_id }}"
assign_public_ip: "{{ public_ip_assign }}"
group_id: "{{ sg_apache }},{{ sg_internal }}"
wait: "{{ wait_type }}"
register: ec2
- name: adding group to inventory file
lineinfile:
dest: "/etc/ansible/hosts"
regexp: "^\\[{{ release_name }}\\]"
line: "[{{ release_name }}]"
state: present
- name: adding apache ip to hosts
lineinfile:
dest: "/etc/ansible/hosts"
line: "{{ item.private_ip }} name=apache dns={{ item.public_dns_name }}
with_items: ec2.instances
Now i want to check the exit status of each task whether it is success or failure.
If any one of the task fails my other task should not execute.
Please advice how to write an ansible playbook
In your first task, you have register the output to ec2.
now use fail module to stop the play if the task fails.
Ex.
register: ec2
fail:
when: "ec2.rc == 1"
here rc is the return code of the command .. we are assuming 1 for fail and 0 for success.
use fail module after every task.
Let me know if it works for you ..
Register a variable in each task and then check it in the next task. See http://docs.ansible.com/ansible/playbooks_tests.html#task-results
This is already the default behavior in Ansible. If a task fails, the Playbook aborts and reports the failure. You don't need to build in any extra functionality around this.
Maybe playbook blocks and it's error handling is to help you?
Kumar
if You want to check each task output if it is success or failure do this,
---
- name: Instance provisioning
local_action:
module: ec2
region: "{{ vpc_region }}"
key_name: "{{ ec2_keypair }}"
instance_type: "{{ instance_type }}"
image: "{{ ec2_image}}"
zone: "{{ public_az }}"
volumes:
- device_name: "{{ device }}"
volume_type: "{{ instance_volumetype }}"
volume_size: "{{ volume }}"
delete_on_termination: "{{ state }}"
instance_tags:
Name: "{{ instance_name }}_{{ release_name }}_APACHE"
environment: "{{ env_type }}"
vpc_subnet_id: "{{ public_id }}"
assign_public_ip: "{{ public_ip_assign }}"
group_id: "{{ sg_apache }},{{ sg_internal }}"
wait: "{{ wait_type }}"
register: ec2
- name: adding group to inventory file
lineinfile:
dest: "/etc/ansible/hosts"
regexp: "^\\[{{ release_name }}\\]"
line: "[{{ release_name }}]"
state: present
when: ec2 | changed
register: fileoutput
- name: adding apache ip to hosts
lineinfile:
dest: "/etc/ansible/hosts"
line: "{{ item.private_ip }} name=apache dns={{ item.public_dns_name }}
with_items: ec2.instances
when: fileoutput | changed
In your code register a variable in each and every Task if The Task has Changed to True, The Followed Task will execute otherwise it will skip that Task.