Ansible loop list in dictionary and retain the key - ansible

I'm trying to create a series of firewalld rules using a variable imported from a yaml file. The yaml file creates a dictionary of service names and the associated ports are a list within each item. A segment of the yaml looks like this:
---
myservice:
description: My service desc
ports:
- 1234/tcp
- 1235/tcp
another:
description: Another service
ports:
- 2222/tcp
- 3333/tcp
The Ansible role I have so far is:
- name: Read services from file
include_vars:
file: "services.yml"
name: services
- name: Create firewalld services
command: >
firewall-cmd --permanent
--new-service={{ item.key }}
--set-description="{{ item.value.description }}"
register: addserv
failed_when: addserv.rc != 26 and addserv.rc != 0
changed_when: not "NAME_CONFLICT" in addserv.stderr
with_dict: "{{ services }}"
- name: Add ports to firewalld service
command: >
firewall-cmd --permanent
--service={{ item.key }} --add-port={{ item.value.ports }}
register: addport
changed_when: not "ALREADY_ENABLED" in addport.stderr
The first segment to create the firewalld service works fine but I'm stumped on the second part with how to loop over the list of ports while retaining the dictionary key. I've tried using subelements to extract the ports list and that works but I can't figure out how to retain the service name from the key.

Use subelements. For example
- debug:
msg: "{{ item.0.key }} - {{ item.0.value.description }} - {{ item.1 }}"
with_subelements:
- "{{ services|dict2items }}"
- value.ports
gives
"msg": "myservice - My service desc - 1234/tcp"
"msg": "myservice - My service desc - 1235/tcp"
"msg": "another - Another service - 2222/tcp"
"msg": "another - Another service - 3333/tcp"

Related

ansible start multiple service and truncate name service

I want to start multiple service on playbook, but I want to remove end of service string like :
a.service => a
b.service => b
because I cannot use service a.service start, but I have to use service a start
because variable item is stored in default/main.yml role playbook like that :
name_services:
- a.service
- b.service
on main.yml
- name: start multiple service
service:
name: "{{ item }}"
state: started
with_items: "{{ name_services }}"
Use the filter splitext
- name: start multiple service
service:
name: "{{ item | splitext | first }}"
state: started
with_items: "{{ name_services }}"
here is a way to achieve it, given that the services have only one dot (.) in their string value. you split based on the dot and take the first chunk (string before the dot).
- debug:
var: item.split('.')[0]
loop: "{{ name_services }}"
another way would be to remove the .service part from the string:
- debug:
var: item.replace('.service','')
loop: "{{ name_services }}"
cheers

saving variables from playbook run to ansible host local file

I'm sort of trying to build an inventory file from an ansible playbook run.
I'm trying to list out all the kvm hosts and the guests running on them, by running both service libvirtd status and if successful, virsh list --all, and to store the values in a file on the ansible host.
Ive tried a few different playbook structures but none have been successful in writing the file (using local_action wrote the ansible_hostname from just one host).
Please can someone guide me on what I'm doing wrong?
This is what I'm running:
- name: Determine KVM hosts
hosts: all
become: yes
#gather_facts: false
tasks:
- name: Check if libvirtd service exists
shell: "service libvirtd status"
register: libvirtd_status
failed_when: not(libvirtd_status.rc == 0)
ignore_errors: true
- name: List KVM guests
shell: "virsh list --all"
register: list_vms
when: libvirtd_status.rc == 0
ignore_errors: true
- name: Write hostname to file
lineinfile:
path: /tmp/libvirtd_hosts
line: "{{ ansible_hostname }} kvm guests: "
create: true
#local_action: copy content="{{ item.value }}" dest="/tmp/libvirtd_hosts"
with_items:
- variable: ansible_hostname
value: "{{ ansible_hostname }}"
- variable: list_vms
value: "{{ list_vms }}"
when: libvirtd_status.rc == 0 or list_vms.rc == 0
Was able to cobble something that's mostly working:
- name: Check if libvirtd service exists
shell: "service libvirtd status"
register: libvirtd_status
failed_when: libvirtd_status.rc not in [0, 1]
- name: List KVM guests
#shell: "virsh list --all"
virt:
command: list_vms
register: all_vms
when: libvirtd_status.rc == 0
---
- name: List all KVM hosts
hosts: production, admin_hosts, kvm_hosts
become: yes
tasks:
- name: create file
file:
dest: /tmp/libvirtd_hosts
state: touch
delegate_to: localhost
- name: Copy VMs list
include_tasks: run_libvirtd_commands.yaml
- name: saving cumulative result
lineinfile:
line: '{{ ansible_hostname }} has {{ all_vms }}'
dest: /tmp/libvirtd_hosts
insertafter: EOF
delegate_to: localhost
when: groups["list_vms"] is defined and (groups["list_vms"] | length > 0)
Now if only I could clean up the output to filter out false positives (machines that don't have libvirtd status, and have an empty/no list of VMs, because the above doesn't really work.
But at least there is output from all the KVM hosts!

loop using with_sequence over with_subelement in ansible

I am trying to loop over a subelement variables using the a loop like with_sequence,
For the moment I have :
---
- hosts: corosync
gather_facts: no
vars:
host_list:
- node_one
- node_two
list_services:
- group: ALPHA
services:
- name: DHCP
directory: /etc/dhcp
- name: DNS
directory : /etc/dns
- group: BETA
services:
- name: SSH
directory: /etc/ssh
- name: FTP
directory: /ztc/ftp
tasks:
- name: create group-services
debug:
msg: "the service name is {{ item.0.group}}-{{ item.1.name}} , directory is {{ item.1.directory }}"
with_subelements:
- "{{ list_services }}"
- services
Since I have 2 nodes in my cluster
node_one
node_two
I want to deplucate each service like below :
{{ item.0.group}}-{{host_id}}-{{ item.1.name}}
with {{ host_id }} a list that equal ['0','1'] since I have 2 nodes
and the with_subelement function loop over the {{ host_id }} twice since we have two nodes, what gives :
ALPHA-0-DHCP
ALPHA-0-DNS
ALPHA-1-DHCP
ALPHA-1-DNS
BETA-0-SSH
BETA-0-FTP
BETA-1-SSH
BETA-1-FTP
I want to use something like with_sequence function beside with_subelement like
with_sequence: start=0, end={{ groups['host_list']|length}}
Any suggestions please
The loop declaration introduced in Ansible 2.5 makes it pretty straightforward ー you just need to combine the two patterns replacing legacy with_sequence and legacy with_subelements:
- name: create group-services
debug:
msg: "{{item.1.0.group}}-{{item.0}}-{{item.1.1.name}}"
loop: "{{ range(0, host_list|length) | product(list_services|subelements('services')) | list }}"

How set ansible function to when modeule?

I want install one of Filebit prospectors only if service redis is running on the host. For that i create default list of prospectors ( redis, aerospike, postgress ) with {{ item.id }}. But right now i want put some expression to "when:" which will install prospector for redis only if it running - how can i do it ?
- name: Configure Filebeat prospectors
template: src=filebeat_conf.yml.j2 dest=/etc/filebeat/conf.d/{{ item.id }}.yml
notify: restart filebeat
with_items: prospectors
when: { " service: " }
Split your task in two: collect facts, act depending on facts.
In your case, you can list installed services first, then configure only existing ones.
For example:
- hosts: test-host
vars:
services:
- name: apache2
id: 1
- name: nginx
id: 2
- name: openvpn
id: 3
tasks:
- name: get list of services
shell: "service --status-all 2>&1 | awk {'print $4'}"
args:
warn: false
register: services_list
- name: process only existing services
debug: msg="service {{ item.name }} with id={{ item.id }} exists"
with_items: "{{ services }}"
when: item.name in services_list.stdout_lines

Ansible recursive checks in playbooks

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.

Resources