How declare two prompt variables for hosts in ansible playbook - ansible

How declare two prompt variables for hosts in ansible playbook, I tried below Playbook but without luck.
............................................................................................................................................................
Thank you in advance.
---
- name: MD5 File Check
gather_facts: false
hosts: "{{ cluster_host_1 }}", "{{cluster_host_2 }}"
hosts: localhost
remote_user: sv_operator
vars_prompt:
- name: "file_1"
prompt: "File name"
private: no
- name: "cluster_host_1"
prompt: "Enter 1st Host name"
private: no
- name: "cluster_host_2"
prompt: "Enter 2nd Host Name"
private: no
tasks:
- stat:
path: "/tmp/{{ file_1 }}"
checksum_algorithm: sha256
register: output
delegate_to: "{{ cluster_host_1 }}"
- debug:
msg: "{{ output.stat.checksum }}"
- stat:
path: "/tmp/{{ file_2 }}"
checksum_algorithm: sha256
register: output_
delegate_to: "{{ cluster_host_2 }}"
- debug:
msg: "{{ output_.stat.checksum }}"

Given the remote hosts and /tmp/file1
shell> ssh admin#test_01 sha256 /tmp/file1
SHA256 (/tmp/file1) = e2611a1fac7fc2ab99d2e792ad84f34e66740d6a3d77b97b4da39a3758357da0
shell> ssh admin#test_02 sha256 /tmp/file1
SHA256 (/tmp/file1) = 109f60103192b5c8f4e33c26b4f9c7b94489bf8de0325497b7f5a0668dc1a402
The playbook below
shell> cat playbook.yml
- name: SHA256 File Check
hosts: localhost
gather_facts: false
vars_prompt:
- name: "file_1"
prompt: "File name"
private: no
- name: "cluster_host_1"
prompt: "Enter 1st Host name"
private: no
- name: "cluster_host_2"
prompt: "Enter 2nd Host Name"
private: no
tasks:
- stat:
path: "/tmp/{{ file_1 }}"
checksum_algorithm: sha256
register: output
delegate_to: "{{ cluster_host_1 }}"
- debug:
msg: "{{ output.stat.checksum }}"
- stat:
path: "/tmp/{{ file_1 }}"
checksum_algorithm: sha256
register: output_
delegate_to: "{{ cluster_host_2 }}"
- debug:
msg: "{{ output_.stat.checksum }}"
works as expected
shell> ansible-playbook playbook.yml
File name: file1
Enter 1st Host name: test_01
Enter 2nd Host Name: test_02
PLAY [SHA256 File Check] ****
TASK [stat] ****
ok: [localhost -> test_01]
TASK [debug] ****
ok: [localhost] =>
msg: e2611a1fac7fc2ab99d2e792ad84f34e66740d6a3d77b97b4da39a3758357da0
TASK [stat] ****
ok: [localhost -> test_02]
TASK [debug] ****
ok: [localhost] =>
msg: 109f60103192b5c8f4e33c26b4f9c7b94489bf8de0325497b7f5a0668dc1a402
PLAY RECAP ****
localhost: ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

If you want your play to run on two hosts, declared through variables. You have two options.
Option 1:
Since your target hosts are comma separated, you might as well input them that way.
- hosts: '{{ my_hosts }}'
gather_facts: false
remote_user: 'sv_operator'
vars_prompt:
- name: 'my_hosts'
prompt: 'Comma separated list of hosts'
private: no
Then when prompted:
Comma separated list of hosts: host1.local,host2.local
Option 2:
Capture each host in individual variable like host_1 and host_2, then call it as a list in a play.
- hosts:
- '{{ host_1 }}'
- '{{ host_2 }}'
gather_facts: false
remote_user: 'sv_operator'
vars_prompt:
- name: 'host_1'
prompt: 'First host'
private: no
- name: 'host_2'
prompt: 'Second host'
private: no
Then when prompted:
First host: host1.local
Second host: host2.local

Related

Ansible How to store multiple "register" in one file with one playbook

Ansible store only the first output in a file
Example
I have 3 hosts inside the inventory
My playbook ask for memory info.
with
- name: Check memory
hosts: all
tasks:
- name: Check Memory
shell: free
register: memory_output
- name: save
lineinfile:
path: "mypc/test.log"
line: "--{{ memory_output.stdout }}% "
create: yes
delegate_to: localhost
output write in file sometimes all the hosts memory,sometimes only the first,sometimes only the last
How i append every result from every hosts in one file.
Sometimes it export all the results but not every time
For example, given the inventory
shell> cat hosts
test_11
test_12
test_13
declare the below variable and put it into the vars
vmstat: "{{ out.stdout|community.general.jc('vmstat') }}"
Get the free memory
- command: vmstat
register: out
- set_fact:
free_mem: "{{ vmstat.1.free_mem }}"
- debug:
var: free_mem
gives (abridged)
ok: [test_11] =>
free_mem: '3434124'
ok: [test_12] =>
free_mem: '3496908'
ok: [test_13] =>
free_mem: '3434992'
Q: "How to store multiple 'register' in one file with one playbook."
A: Write it to the log
- lineinfile:
create: true
path: /tmp/test.log
line: >-
{{ '%Y-%m-%d %H:%M:%S'|strftime() }}
{{ item }}
{{ hostvars[item].free_mem }}
loop: "{{ ansible_play_hosts }}"
delegate_to: localhost
run_once: true
gives
shell> cat /tmp/test.log
2022-09-12 13:39:48 test_11 3434124
2022-09-12 13:39:49 test_12 3496908
2022-09-12 13:39:49 test_13 3434992
Example of a complete playbook for testing
- hosts: test_11,test_12,test_13
vars:
vmstat: "{{ out.stdout|community.general.jc('vmstat') }}"
tasks:
- command: vmstat
register: out
- set_fact:
free_mem: "{{ vmstat.1.free_mem }}"
- debug:
var: free_mem
- lineinfile:
create: true
path: /tmp/test.log
line: >-
{{ '%Y-%m-%d %H:%M:%S'|strftime() }}
{{ item }}
{{ hostvars[item].free_mem }}
loop: "{{ ansible_play_hosts }}"
delegate_to: localhost
run_once: true
Here's the simplest example. Assuming that you are running ansible in controller machine and you have to append the output of executing tasks in remote machines. The host list will obviously be different for you and will have all the remote machines.
- hosts: localhost
tasks:
## Playbook to copy the file from controller machine to remote machine
- name: Copy the file from controller machine to remote machine
copy:
src: /tmp/tmpdir/output.txt
dest: /tmp/tmpdir/output.txt
## Playbook to store the shell output to a variable
- name: Store the output of the shell command to a variable
shell: "echo '\nHello World'"
register: output
- name: Print the output of the shell command
debug:
msg: "{{ output.stdout }}"
## Playbook to append output to a file
- name: Append output to a file
lineinfile:
path: /tmp/tmpdir/output.txt
line: "{{ output.stdout }}"
create: yes
## Playbook to copy the file from remote machine to controller machine
- name: Copy the file from remote machine to controller machine
fetch:
src: /tmp/tmpdir/output.txt
dest: /tmp/tmpdir/output.txt
flat: yes
After running it the third time
╰─ ansible-playbook test.yaml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [localhost] *******************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************
ok: [localhost]
TASK [Copy the file from controller machine to remote machine] *********************************************************************************************
ok: [localhost]
TASK [Store the output of the shell command to a variable] *************************************************************************************************
changed: [localhost]
TASK [Print the output of the shell command] ***************************************************************************************************************
ok: [localhost] => {
"msg": "\nHello World"
}
TASK [Append output to a file] *****************************************************************************************************************************
changed: [localhost]
TASK [Copy the file from remote machine to controller machine] *********************************************************************************************
ok: [localhost]
PLAY RECAP *************************************************************************************************************************************************
localhost : ok=6 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
╰─ cat output.txt
Hello World
Hello World
Hello World
So on every machine you run the controller machine will get the latest file output. We will copy the file to remote, add contents to the file and then copy it back to controller. Continue the same until all the hosts have been completed.
If you want to take the result from selective servers then the last task can be replaced by following. Replace the hostnames with required values
## Playbook to copy the file from remote machine to controller machine if the hostname maches localhost1 or localhost2
- name: Copy the file from remote machine to controller machine if the hostname maches localhost1 or localhost2
fetch:
src: /tmp/tmpdir/output.txt
dest: /tmp/tmpdir/output.txt
flat: yes
fail_on_missing: yes
when: inventory_hostname == 'localhost1' or inventory_hostname == 'localhost2'

ansible regex_replace IP change

I would like to modify vars for drupal configuration file settings.php with ansible and regex_replace module. My initial var is an IP xxx.xxx.xxx.xxx and I want this as my new var xxx\.xxx\.xxx\.xxx
My playbook:
---
- hosts: localhost
remote_user: cal
become: yes
become_user: cal
tasks:
- set_fact:
ip_front: "10.11.12.13"
ip_front_back: "{{ ip_front | regex_replace('\\.', '\\.') }}"
- name: "show all var"
debug:
msg:
- "{{ ip_front }}"
- "{{ ip_front_ok }}"
Output:
ok: [localhost] => {
"msg": [
"10.11.12.13",
"10\\.11\\.12\\.13"
]
}
How can I use pattern to resolve it?

Iterate sub-items Ansible with sublements

Have task which copies each user's key
- name: SSH Keys
authorized_key:
user: "{{ item.0.name }}"
key: "{{ item.0.ssh_key.0.key }}"
state: "{{ item.0.ssh_key.0.state }}"
when:
- item.1 == 'all' or item.1 in group_names or item.1 == inventory_hostname
with_subelements:
- "{{ users }}"
- servers
Var list:
users:
- name: user1
ssh_key:
- key:
- "key1.user1"
- "key2.user1"
- "key3.user1"
state: present
servers:
- server1
- name: user2
ssh_key:
- key:
- "key1.user2"
- "key2.user2"
state: present
servers:
- all
QUESTION: How can we allow users to copy multiple keys? Without deleting servers from with_subelements.
When starting the task, either the last key or an array with keys is copied, depending on how we write it in var list.
In this format copied last key.
- key: "key1.user1"
- key: "key2.user1"
- key: "key3.user1"
In this array.
- key:
- "key1"
- "key2"
Let's fit the structure of the data to this purpose. For example,
users:
- name: user1
ssh_key:
- "key1.user1"
- "key2.user1"
- "key3.user1"
state: present
servers:
- server1
...
It's possible to loop include_tasks. For example, create the task (test it with debug first)
shell> cat conf_authorized_key.yml
- name: SSH Keys
# authorized_key:
debug:
msg:
- "user: {{ item.0.name }}"
- "state: {{ item.0.state }}"
- "key: {{ iitem }}"
loop: "{{ item.0.ssh_key }}"
loop_control:
loop_var: iitem
Then include it in the playbook
shell> cat playbook.yml
- hosts: localhost
vars:
users:
- name: user1
ssh_key:
- "key1.user1"
- "key2.user1"
- "key3.user1"
state: present
servers:
- server1
- name: user2
ssh_key:
- "key1.user2"
- "key2.user2"
state: present
servers:
- all
tasks:
- name: Loop include_task
include_tasks: conf_authorized_key.yml
loop: "{{ users|subelements('servers') }}"
loop_control:
label: "{{ item.1 }}"
when: (item.1 == 'all') or
(item.1 in group_names) or
(item.1 == inventory_hostname)
gives
shell> ansible-playbook playbook.yml
PLAY [localhost] ****
TASK [Loop include_task] ****
skipping: [localhost] => (item=server1)
included: /export/scratch/tmp/conf_authorized_key.yml for localhost
TASK [SSH Keys] ****
ok: [localhost] => (item=key1.user2) => {
"msg": [
"user: user2",
"state: present",
"key: key1.user2"
]
}
ok: [localhost] => (item=key2.user2) => {
"msg": [
"user: user2",
"state: present",
"key: key2.user2"
]
}
PLAY RECAP ****
localhost: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

import_ansible plabook and use variables from a master playbook

I want to use in my imported playbook the varaibles which I have defined in the master playbook. Unfortunately I get the following error message:
fatal: [localhost]: FAILED! =>
{
"msg": "The task includes an option with an
undefined variable. The error was: 'vcenter_username' is undefined\n\nThe
error appears to have been in '/home/ansible/ansible/vcenter/vm-
provisioning/vcenter_vm_creation.yml': line 4, column 7, but may\nbe
elsewhere in the file depending on the exact syntax
problem.\n\nThe
offending line appears to be:\n\n tasks:\n
}
My Playbook looks like this:
---
- hosts: localhost
vars_prompt:
- name: prompt_vcenter_domain
prompt: "Enter the Vcenter Domain Name for example vcenter"
private: no
- name: prompt_vcenter_username
prompt: "Enter your Vcenter User Name"
private: no
- name: prompt_vcenter_password
prompt: "Enter your Vcenter user Password"
- name: prompt_environment_to_deploy
prompt: "Enter the right Environment, Type Produktiv or Test VM"
private: no
- name: prompt_template_to_deploy
prompt: "Enter the right Template, Template Ubuntu 18.04 LTS x64 or Template Ubuntu 18.04 LTS x64 SMALL"
private: no
- name: prompt_vm_hostname
prompt: "Enter the VM Hostname"
- import_playbook: vcenter_vm_creation.yml
vars:
vcenter_domain: "{{ prompt_vcenter_domain }}"
vcenter_username: "{{ prompt_vcenter_username }}"
vcenter_password: "{{ prompt_vcenter_password }}"
vm_hostname: "{{ prompt_vm_hostname }}"
template_to_deploy: "{{ prompt_template_to_deploy }}"
environment_to_deploy: "{{ prompt_environment_to_deploy }}"
and the child playbook looks like this:
---
- hosts: localhost
tasks:
- name: Clone the template
vmware_guest:
hostname: '{{ vcenter_domain }}.muc.lv1871.de'
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: False
name: "{{ vm_hostname }}"
template: "{{ template_to_deploy }}"
folder: /{{ environment_to_deploy }}/Linux
state: poweredon
wait_for_ip_address: no
Can anyone help how to get the variables in the child playbook?
You can use set_vact for this purpose. Variable that defined in set_fact will be available to subsequent plays during ansible-playbook execution.
Can be confirmed with following playbook:
- hosts: localhost
gather_facts: false
vars_prompt:
- name: prompt_vcenter_username
prompt: "Enter your Vcenter User Name"
tasks:
- name: Set vcenter_username variable with set_fact
set_fact:
vcenter_username: "{{ prompt_vcenter_username }}"
- hosts: localhost
gather_facts: false
tasks:
- name: Display vcenter_username
debug:
msg: "{{ vcenter_username }}"
Results:
Enter your Vcenter User Name:
PLAY [localhost] *******************************************************************************
TASK [Set vcenter_username variable with set_fact] *********************************************
ok: [localhost]
PLAY [localhost] *******************************************************************************
TASK [Display vcenter_username] ****************************************************************
ok: [localhost] => {
"msg": "test_user"
}
PLAY RECAP *************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
I am not sure you can pass vars into the import_playbook directive like that, hence you are seeing them as undefined. Moreover, unless you have a specific reason to, using import_playbook at all, is not really a common pattern.
You can simply place the 'Clone the template' task in the same play as the one containing the vars_prompt, or if you want to split it out into a separate file, use the include statement, making the included file part of the same play:
playbook.yml
---
- hosts: localhost
vars_prompt:
- name: vcenter_domain
prompt: "Enter the Vcenter Domain Name for example vcenter"
private: no
- name: vcenter_username
prompt: "Enter your Vcenter User Name"
private: no
- name: vcenter_password
prompt: "Enter your Vcenter user Password"
- name: environment_to_deploy
prompt: "Enter the right Environment, Type Produktiv or Test VM"
private: no
- name: template_to_deploy
prompt: "Enter the right Template, Template Ubuntu 18.04 LTS x64 or Template Ubuntu 18.04 LTS x64 SMALL"
private: no
- name: vm_hostname
prompt: "Enter the VM Hostname"
tasks:
- include: template_clone.yml
template_clone.yml
---
- name: Clone the template
vmware_guest:
hostname: '{{ vcenter_domain }}.muc.lv1871.de'
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: False
name: "{{ vm_hostname }}"
template: "{{ template_to_deploy }}"
folder: /{{ environment_to_deploy }}/Linux
state: poweredon
wait_for_ip_address: no

ansible vars_files and extra_vars to read input

looking to pass the dict to read a set of key value pairs based on the location. When values are hardcoded to the playbook, it works fine but calling through extra_vars giving an error message. Not sure even if it supports. appreciate, your thoughts and inputs.
ansible-playbook play3.yml -e '{"var1":"loc2"}' -vv
play3.yml
---
- name: testing
hosts: localhost
connection: local
gather_facts: no
vars_files:
- var_file.yml
tasks:
- debug:
msg: "{{ var1['first'] }}"
var_file.yml
---
loc1:
first: name1
last: name2
loc2:
first: python
last: perl
...
"Anything's possible in an animated cartoon." -Bugs Bunny
This playook:
---
- name: testing
hosts: localhost
connection: local
gather_facts: no
vars_files:
- var_file.yml
tasks:
- debug:
var: "{{ item }}.first"
with_items: "{{ var1 }}"
Gave me this output:
TASK [debug] **********************************************************************************************************************************
task path: /home/jack/Ansible/CANES/PLAYBOOKS/play3.yml:9
ok: [localhost] => (item=None) => {
"loc2.first": "python"
}

Resources