How to pass variable value from command parameter and use it in with_items:? - ansible

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"

Related

Ansible trim string

I'm trying write role to install MySql 8, and get problem with this:
- name: Extract root password from logs into {{ mysql_root_old_password }} variable
ansible.builtin.slurp:
src: "{{ mysql_logfile_path }}"
register: mysql_root_old_password
#when: "'mysql' in ansible_facts.packages"
- name: Extract root password from logs into {{ mysql_root_old_password }} variable
set_fact:
mysql_root_old_password: "{{ mysql_root_old_password.content | b64decode | regex_findall('generated for root#localhost: (.*)$', 'multiline=true') }}"
#when: "'mysqld' in ansible_facts.packages"
- name: Get Server template
ansible.builtin.template:
src: "{{ item.name }}.j2"
dest: "{{ item.path }}"
loop:
- { name: "my.cnf", path: "/root/.my.cnf" }
notify:
- Restart mysqld
on the .my.cnf I get password with quotes and brackets:
[client]
user=root
password=['th6k(gZeJSt4']
How to trim that?
What I try:
- name: trim password
set_fact:
mysql_root_old_password2: "{{ mysql_root_old_password | regex_findall('[a-zA-Z0-9,()!##$%^&*]{12}')}}"
Thanks.
The result of regex_findall is a list because there might be more matches. Take the last item
- set_fact:
mysql_root_old_password: "{{ mysql_root_old_password.content|
b64decode|
regex_findall('generated for root#localhost: (.*)$', 'multiline=true')|
last }}"
From your description
on the .my.cnf I get password with quotes and brackets ... How to trim that
I understand that you like to read a INI file like my.cnf.ini
[client]
user=root
password=['A1234567890B']
where the value of the key password looks like a list with one element in YAML and the structure doesn't change, but you are interested in the value without leading and trailing square brackets and single quotes only.
To do so there are several possibilities.
Via Ansible Lookup plugins
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Extract root password from INI file
debug:
msg: "{{ lookup('ini', 'password section=client file=my.cnf.ini') }}"
register: result
- name: Show result with type
debug:
msg:
- "{{ result.msg }}"
- "result.msg is of type {{ result.msg | type_debug }}"
- "Show password only {{ result.msg[0] }}" # the first list element
Such approach will work on the Control Node.
Like all templating, lookups execute and are evaluated on the Ansible control machine.
Further Q&A
How to read a line from a file into an Ansible variable
What is the difference between .ini and .conf?
Further Documentation
ini lookup – read data from an INI file
Via Ansible shell module, sed and cut.
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Extract root password from INI file
shell:
cmd: echo $(sed -n 's/^password=//p' my.cnf.ini | cut -d "'" -f 2)
register: result
- name: Show result
debug:
msg: "{{ result.stdout }}"
Please take note regarding "I get password with quotes and brackets ... ['<pass>'] ... How to trim that?" that from perspective of the SQL service, .cnf file, [' and '] are actually part of the password!
- name: Server template
template:
src: "my.cnf.ini"
dest: "/root/.my.cnf"
If that is correct they will be necessary for proper function of the service.

set path when file exists in Ansible yml code

I'm trying to set a var only when a file exists, here is one of my attempts
---
- hosts: all
tasks:
- stat:
path: '{{ srch_path_new }}/bin/run'
register: result
- vars: srch_path="{{ srch_path_new }}"
when: result.stat.exists
This also didn't work
- vars: srch_path:"{{ srch_path_new }}"
The task you are looking for is called set_fact: and is the mechanism ansible uses to declare arbitrary "host variables", sometimes called "hostvars", or (also confusingly) "facts"
The syntax would be:
- set_fact:
srch_path: "{{ srch_path_new }}"
when: result.stat.exists
Also, while vars: is a legal keyword on a Task, its syntax is the same as set_fact: (or the vars: on the playbook): a yaml dictionary, not a key:value pair as you had. For example:
- debug:
msg: hello, {{ friend }}
vars:
friend: Jane Doe
and be aware that vars: on a task exist only for that task

Return Variable from Included Ansible Playbook

I have seen how to register variables within tasks in an ansible playbook and then use those variables elsewhere in the same playbook, but can you register a variable in an included playbook and then access those variables back in the original playbook?
Here is what I am trying to accomplish:
This is my main playbook:
- include: sub-playbook.yml job_url="http://some-jenkins-job"
- hosts: localhost
roles:
- some_role
sub-playbook.yml:
---
- hosts: localhost
tasks:
- name: Collect info from Jenkins Job
script: whatever.py --url "{{ job_url }}"
register: jenkins_artifacts
I'd like to be able to access the jenkins_artifacts results back in main_playbook if possible. I know you can access it from other hosts in the same playbook like this: "{{ hostvars['localhost']['jenkins_artifacts'].stdout_lines }}"
Is it the same idea for sharing across playbooks?
I'm confused what this question is about. Just use the variable name jenkins_artifacts:
- include: sub-playbook.yml job_url="http://some-jenkins-job"
- hosts: localhost
debug:
var: jenkins_artifacts
This might seem complicated but I love doing this in my Playbooks:
rc defines the name of the variable which contains the return value
ar gives the arguments to the include tasks
master.yml:
- name: verify_os
include_tasks: "verify_os/main.yml"
vars:
verify_os:
rc: "isos_present"
ar:
image: "{{ os.ar.to_os }}"
verify_os/main.yml:
---
- name: check image on device
ios_command:
commands:
- "sh bootflash: | inc {{ verify_os.ar.image }}"
register: image_check
- name: check if available
shell: "printf '{{ image_check.stdout_lines[0][0] }}\n' | grep {{ verify_os.ar.image }} | wc -l"
register: image_available
delegate_to: localhost
- set_fact: { "{{ verify_os.rc }}": "{{ true if image_available.stdout == '1' else false }}" }
...
I can now use the isos_present variable anywhere in the master.yml to access the returned value.

Iterate over a array in with_items loop

Based on this question
Ansible recursive checks in playbooks
I have another one.
We need to go through this structure
Zone spec https://gist.github.com/git001/9230f041aaa34d22ec82eb17d444550c
Now I can adress the hostnames via the array index but can I also iterate over the array "hosts"?
playbook
--
- hosts: all
gather_facts: no
vars_files:
- "../doc/application-zone-spec.yml"
roles:
- { role: ingress_add, customers: "{{ application_zone_spec }}" }
role
- name: Print ingress hostnames
debug: msg="{{ item.hosts.0.hostname }} {{ item.hosts.1.hostname }}"
with_items: "{{ customers.ingress }}"
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
Use with_subelements:
- name: Print ingress hostnames
debug: msg="{{ item.0.type }} {{ item.1.hostname }}"
with_subelements:
- "{{ customers.ingress }}"
- "hosts"
There is quite a bit of examples for different loops in the Loops section of the documentation.

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