I am trying to preserve a command output from one dynamic host group to another one but get a variable is undefined error in my ansible playbook.
My playbook is dynamically getting the primary and secondary hosts by running a command. I want to use the output that I get from the secondary host on the primary with a when statement. Here's what I have.
- hosts: all
serial: 1
tasks:
- name: run curl command to determine primary/secondary
command: /tmp/status.sh
register: apis_op
- name: run curl command to determine primary/secondary
debug: var=apis_op.stdout_lines
- name: If node is primary add to primary
add_host:
name: "{{ ansible_hostname }}"
groups: temp_primary
when: apis_op.stdout == "primary"
- name: run curl command to determine primary/secondary
debug: var=groups
- name: If node is secondary add to secondary
add_host:
name: "{{ ansible_hostname }}"
groups: temp_secondary
when: apis_op.stdout == "secondary"
- name: run curl command to determine primary/secondary
debug: var=groups
- hosts: temp_secondary
tasks:
- name: Run schell script
command: /tmp/runthis.sh
become: yes
become_user: root
register: op
- hosts: temp_primary
tasks:
- name: Run schell script
command: /tmp/testthis.sh
become: yes
become_user: root
when: hostvars['temp_secondary']['op'] == "{false}"
When I run this I get a hostvars['temp_secondary'] is undefined error. Can I not use hostvars with temporary/dynamic host groups?
Related
I have a task based on a shell command that needs to run on a local computer. As part of the command, I need to add the IP address on part of the groups I have in my inventory file
Inventory file :
[server1]
130.1.1.1
130.1.1.2
[server2]
130.1.1.3
130.1.1.4
[server3]
130.1.1.5
130.1.1.6
I need to run the following command from the local computer on the Ips that are part of the Server 2 + 3 groups
ssh-copy-id user#<IP>
# <IP> should be 130.1.1.3 , 130.1.1.4 , 130.1.1.5 , 130.1.1.6
Playbook - were I'm missing the part of the ip
- hosts: localhost
gather_facts: no
become: yes
tasks:
- name: Generate ssh key for root user
shell: "ssh-copy-id user#{{ item }}"
run_once: True
with_items:
- server2 group
- server3 group
In a nutshell:
- hosts: server1:server2
gather_facts: no
become: true
tasks:
- name: Push local root pub key for remote user
shell: "ssh-copy-id user#{{ inventory_hostname }}"
delegate_to: localhost
Note that I kept your exact shell command which is actually a bad practice since there is a dedicated ansible module to manage that. So this could be translated to something like.
- hosts: server1:server2
gather_facts: no
become: true
tasks:
- name: Push local root pub key for remote user
authorized_key:
user: user
state: present
key: "{{ lookup('file', '/root/.ssh/id_rsa.pub') }}"
I am trying to write a playbook that completes some of its tasks on the machine that the playbook is running on. I know i can use local_action for this but I am just testing if the playbook works for now. Eventually I will need to use the delegate_to. I have defined the variable and I am using delegate_to: 'variable name' but I am getting this error. : " fatal [target node]: FAILED! => { msg": "'variablename' is undefined. Below is my playbook:
name: Create certs
gather_facts: true
vars:
master: "{{ nameofhost }}"
tasks:
- name: Run command
shell: Command to run
delegate_to: "{{ master }}"
You need to target your play to a target hosts of an inventory
name: Create certs
gather_facts: true
hosts: target_hosts
vars:
master: "{{ nameofhost }}"
tasks:
- name: Run command
shell: Command to run
delegate_to: "{{ master }}"
```
Your inventory files may look like that:
[target_hosts]
master ansible_host=your_master_dns_or_ip
And then ansible can target that inventory group and then reduce the task scope to master host. Or you can just use the localhost as target.
I've main yml (select.yml) which reuse machine-id.yml.
Both has prompt to ask for host ip, so I can run machine-id.yml directly and it will ask for IP.
select.yml as main script has also prompt for asking IP. But because it reuse machine-id.yml, I don't want to ask twice for IP, because in future I will add another subscript with another prompt maybe.
Problem I faced is that machine-id.yml takes dynamic_hosts value from select.yml. And it works - I can run select.yml and it will ask me for IP twice. When I put IP1 as prompt value and IP2 as second one, I see tasks are run on both hosts.
but I cannot use when: to prevent prompt in machine-id.yml. It says variable is not defined in debug. Also did not react on condition dynamic_hosts is not defined
select.yml
- hosts: localhost
gather_facts: no
vars_prompt:
- name: target_host
prompt: "[M] please enter the target host IP"
private: no
tasks:
- add_host:
name: "{{ target_host }}"
groups: dynamic_hosts
- import_playbook: machine_id.yml
machine-id.yml:
- hosts: localhost
gather_facts: no
tasks:
- debug:
var: dynamic_hosts
- name: PROMPT
block:
- name: ask host
pause:
prompt: "Please enter target IP"
register: target_host
- name: add to dynamic_hosts
add_host:
name: "{{ target_host.user_input }}"
groups: dynamic_hosts2
when: dynamic_hosts is not defined
- hosts: dynamic_hosts
vars:
ansible_python_interpreter: /usr/bin/python3
become: yes
tasks:
- name: Reset machine-id
shell: rm /etc/machine-id && rm /var/lib/dbus/machine-id && dbus-uuidgen --ensure=/etc/machine-id && dbus-uuidgen --ensure
args:
warn: no
dynamic_hosts is not a variable, it's an element in the list of groups. You can debug that if you do a debug var=groups
You have to access it via groups.dynamic_hosts.
- hosts: localhost
gather_facts: no
tasks:
- debug:
var: groups.dynamic_hosts
- name: PROMPT
block:
- name: ask host
pause:
prompt: "Please enter target IP"
register: target_host
- name: add to dynamic_hosts
add_host:
name: "{{ target_host.user_input }}"
groups: dynamic_hosts2
when: groups.dynamic_hosts is not defined
I have a simple playbook:
- name: "Ensure /etc/host contains '127.0.0.1'"
lineinfile:
name: /etc/host
line: "127.0.0.1"
state: present
check_mode: yes
register: conf
- name: "Use java role playbook"
roles:
- role: java
if_exist: conf
My question: Will this conf variable be visible and assigned to if_exist?
First you can use shell module to read the file and register the output, then use "when" to search for a specific content in the registered output of the file and base of the result run the task.
- name: cat
shell: "cat /etc/host "
register: conf
- include_role:
name:
when: conf.stdout.find('127.0.0.1') != 1
It's possible even without cat/grep/awk, just use Ansible's lookup and search.
vars:
out: "{{ lookup('file', '/etc/host') }}"
tasks:
- name: "Use java role playbook"
include_role:
name: Java
when: out is search("127.0.0.1")
I have a need to know the index of host names in the inventory. I am using the below code to create a variable file that I can use in a subsequent play book
- name: Debug me
hosts: hosts
tasks:
- debug: msg="{{ inventory_hostname }}"
- debug: msg="{{ play_hosts.index(inventory_hostname) }}"
- local_action: 'lineinfile create=yes dest=/tmp/test.conf
line="host{{ play_hosts.index(inventory_hostname) }}=
{{ inventory_hostname }}"'
I have the following inventory file
[hosts]
my.host1.com
my.host2.com
Now when I run this, the test.conf that gets generated under /tmp sometimes has both hostnames like this
host1= my.host2.com
host0= my.host1.com
when I run the same playbook a few times each time emptying the test.conf before running. quite a few times the file only has one entry
host1= my.host2.com
or
host0= my.host1.com
how come the same ansible playbook behaving differently?
I believe the issue is your running two threads against different hosts, and using local_action is not thread safe.
Try using the serial keyword:
- name: Debug me
hosts: hosts
serial: 1
tasks:
- debug: msg="{{ inventory_hostname }}"
- debug: msg="{{ play_hosts.index(inventory_hostname) }}"
- local_action: 'lineinfile create=yes dest=/tmp/test.conf
line="host{{ play_hosts.index(inventory_hostname) }}=
{{ inventory_hostname }}"'
Edit: A better way to do this if just trying to operate on the list of host in inventory on the localhost, would be to avoid doing the action on the host and using local_action in the first place.
- name: Debug me
hosts: localhost
tasks:
- lineinfile:
create: yes
dest: /tmp/test.conf
line: "host{{ groups['hosts'].index(item)}}={{ item }}"
with_items: " {{ groups['hosts'] }}"
This will get you the results you desire. Then you can add another play to do operations against the hosts themselves.
The solution I am trying to avoid problems with race conditions with non-thread safe Local_action: lineinfile to write gathered data to local file. Split it across 2 different plays in the same file.
eg:
- name: gather_date
hosts: all
any_errors_fatal: false
gather_facts: no
tasks:
- name: get_Aptus_device_count_list
shell: gather_data.sh
become: true
register: Aptus_device_count_list
changed_when: false
- name: Log_gathered_date
hosts: all
any_errors_fatal: false
gather_facts: no
tasks:
- name: log_gathered_info
local_action:
module: lineinfile
dest: /home/rms-mit/MyAnsible/record_Device_count_collection.out
line: "\n--- {{ inventory_hostname }} --- \n
{{ Aptus_device_count_list.stdout }} \n.\n---\n"
changed_when: false