ansible start multiple service and truncate name service - ansible

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

Related

Multiple variables in a survey in Ansible Tower

I am developing a playbook which adds host_group to groups in IdM.
I'm having trouble if an operator needs to add more than one user to the list I've created in Ansible Tower.
My development is as follows:
---
- name: Add hostgroup to group
ipahostgroup:
ipaadmin_password: 'password'
name: "{{ host_group }}"
hostgroup:
- "{{ item }}"
with_items: "{{ hostgroup_name.split(', ') }}"
action: member
In the Ansible Tower survey, the operator must specify the host_groups by commas.
Any suggestion??
Thank you.
The solution:
---
- name: Add hostgroup to group
ipahostgroup:
ipaadmin_password: 'password'
name: "{{ host_group }}"
hostgroup:
- "{{ item }}"
action: member
with_items: "{{ hostgroup_name.split(', ') }}"
Just wrong order... :-)
Thank you!

A method for listing Ansible modules used by playbooks

I'm creating a requirements.yml in an Ansible project, and I want to identify all of the modules that need to be installed from ansible-galaxy that are used by project playbooks. ansible-doc --list --playbook-dir foo seems like the right tool for the job, but it lists all locally available modules, not just the ones which are actually used in the foo directory. ansible-galaxy list doesn't account for any which are needed but not installed.
Is there a way to do this where I don't end up writing a shell script to sed|awk|grep the info I want?
The best approach I've been able to come up with so far is to ansible-playbook --syntax-check each of the playbooks. This will throw errors such as
ERROR! the role 'foo' was not found ...
ERROR! couldn't resolve module/action 'bar'. This often indicates a misspelling, missing collection, or incorrect module path.
but this is not ideal because it exits as soon as any error occurs. I have to fix each one and run the syntax check again.
FWIW, as a concept, the playbook below lists the modules used in a role
- hosts: localhost
vars:
keywords:
- always
- become
- block
- loop
- loop_control
- name
- notify
- register
- tags
- vars
- when
tasks:
- name: The variable my_role_path is mandatory
assert:
that: my_role_path|d('')|length > 0
- name: Find tasks files
find:
path: "{{ my_role_path }}/tasks"
patterns: '*.yml,*.yaml'
recurse: true
register: result
- name: Create list of tasks
set_fact:
lft: "{{ lft|d([]) + lookup('file', item)|from_yaml }}"
loop: "{{ result.files|map(attribute='path')|list }}"
- name: Get list of keys
set_fact:
lfk: "{{ lfk|d([]) + item.keys()|list }}"
loop: "{{ lft }}"
- name: Get list of keys from block/rescue/always
set_fact:
lfk: "{{ lfk|d([]) + item.keys()|list }}"
loop: "{{ lft|json_query('[].[block, rescue, always]')|flatten }}"
- name: Display list of modules
debug:
var: lfk|unique|sort|difference(keywords)
For example, analyze the role systemd
shell> ansible-playbook pb.yml -e my_role_path=roles/ansible-role-systemd
...
lfk|unique|sort|difference(keywords):
- command
- file
- include_tasks
- meta
- systemd
- template
Complete the list of the keywords.
Use the tasks below to analyze a playbook
tasks:
- name: The variable my_playbook_path is mandatory
assert:
that: my_playbook_path|d('')|length > 0
- name: Create list of tasks
set_fact:
lft: "{{ _playbook|map(attribute='tasks')|flatten }}"
vars:
_playbook: "{{ lookup('file', my_playbook_path)|from_yaml }}"
- name: Get list of keys
set_fact:
lfk: "{{ lfk|d([]) + item.keys()|list }}"
loop: "{{ lft }}"
- name: Get list of keys from block/rescue/always
set_fact:
lfk: "{{ lfk|d([]) + item.keys()|list }}"
loop: "{{ lft|json_query('[].[block, rescue, always]')|flatten }}"
- name: Display list of modules
debug:
var: lfk|unique|sort|difference(keywords)
For example, analyzing the first playbook gives
lfk|unique|sort|difference(keywords):
- assert
- debug
- find
- set_fact

how can i loop over a variable that might have single value?

I'm writing a playbook and want to loop a role over a variable that gets its value from the user. however that value might not always be a list of items, it might be a single value and whenever that happens it throws an error.
My Task:
- name: task name
include role:
name: role name
vars:
cluster_name: '{{ item }}'
loop: "{{ list_or_not }}"
loop_control:
loop_var: item
error:
...Invalid data passed to 'loop', it requires a list...
Have you tried the: "| list" filter?
Sorry cannot test at the moment.
You could test if the variable is a string, and if so, transform it into a single-item list. Something like this:
---
- hosts: localhost
gather_facts: false
tasks:
- set_fact:
list_or_not: ["{{ list_or_not }}"]
when: list_or_not is string
- debug:
msg: "{{ item }}"
loop: "{{ list_or_not }}"

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 }}"

loop control with digital_ocean ansible module

Thanks to other stackoverflow users, I have managed to pull some data out of a variable registered by the digital_ocean ansible module. I attempted to use loop_control to print only part of the huge variable that is registered. Here is an extract from the role:
- name: Add droplet
digital_ocean: >
{ some parameters }
with_dict: "{{ droplets_up }}"
register: my_droplet
- debug: msg="Droplet IP is {{ item.droplet.ip_address }}"
with_items: "{{ my_droplet.results }}"
loop_control:
label: "{{ item }}"
I'm obviously doing it wrong here, as it prints the whole variable as well as the debug message. I don't quite understand loop_control at this point, but does anyone know if it's possible to use it in this manner with this module?
debug action has result['_ansible_verbose_always'] = True, so it will always print full item, no matter what your label is (although label: "{{item}}" doesn't change anything, try label: "{{ item.droplet.ip_address }}").
If you just need to list all your IP addresses, use map filter and single debug statement:
- name: Print droplets IP
debug:
msg: "{{ my_droplet.results | map(attribute='droplet.ip_address') | list }}"

Resources