In my playbook I have this:
- name: compile
hosts: localhost
gather_facts: false
tasks:
- name: compile binary
local_action: command make build FOO=foo1
I want to execute make build FOO=bar1 on localhost once if host is either bar-1 or bar-2 (they're both in group bars, so distinguishing by group is fine too). I tried using when:
- name: compile binary
local_action: command make build FOO=foo1
when: (inventory_hostname != "bar-1") and (inventory_hostname != "bar-2")
- name: compile binary
local_action: command make build FOO=bar1
when: (inventory_hostname == "bar-1") or (inventory_hostname == "bar-2")
But inventory_hostname is always localhost.
In my hosts I have
[foos]
foo-1 ...
foo-2 ...
[bars]
bar-1 ...
bar-2 ...
And I run it as
ansible-playbook -i provision/hosts -l localhost,bars provision/deploy.yml
This works fine for me:
---
- hosts: localhost,test-server
gather_facts: no
tasks:
- shell: echo {{ inventory_hostname }}
delegate_to: localhost
Commands are executed on localhost, but printing localhost and test-server.
This task will run a command on localhost once if the current host being operated on is part of the bars group.
shell: echo {{ inventory_hostname }}
run_once: true
delegate_to: localhost
when: "'bars' in group_names"
Note: If you plan on using serial mode it affects run_once behaviour.
http://docs.ansible.com/ansible/playbooks_delegation.html#run-once
Way to run actions on localhost basis of hostnames in inventory
Command:
ansible-playbook -i ~/inventory_file provision/deploy.yml -e 'host_group=bars'
Add hosts in inventory file
~/inventory_file
[foos]
foo-1 ...
foo-2 ...
[bars]
bar-1 ...
bar-2 ...
deploy.yml
- name: compile
hosts: localhost
gather_facts: false
tasks:
- name: compile binary
local_action: command make build FOO=foo1
when: {{item}} not in "'bar-1','bar-2'"
with_items:
- groups['host_group']
- name: compile binary
local_action: command make build FOO=bar1
when: {{item}} in "'bar-1','bar-2'"
with_items:
- groups[host_group]
Related
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 am writing a playbook where I am automating my deployment. In the command line I am passing some parameters which needs to be validated mandatory. I am using roles/tags to run my playbook. Below is my command -
ansible-playbook -i my-inventory my-main.yml --tags=copy,deploy -e my_release_version=1.0.0 -e target_env=prod
In my-main.yml I am first validating the parameters and then executing the roles. Now if i pass tags in the command it is not doing any validation and directly executing the tags which is the way ansible works i guess.
Is there a way to pre execute the steps as mentioned in my-main.yml before executing the tags?
and my-main.yml looks like below -
- hosts: localhost
connection: local
gather_facts: no
vars:
_allowed_envs:
- dev
- preprod
- prod
pre_tasks:
- name: Checking if the Target Environment is ok
fail:
msg: >-
Environment "{{ target_env }}" is not allowed.
Please choose a target environment from "{{ _allowed_envs | join(', ') }}"
when: not target_env in _allowed_envs
run_once: true
roles:
- role: copy
tags:
- copy
- role: deploy
tags:
- deploy
NOTE : My playbook will have roles/tags like copy,deploy and also stoptomcat, starttomcat. So when user only mention tags like stoptomcat and starttomcat I just want one input parameter to be validated target_env because in that case I would not want my_release_version.
Any help is appreciated.
There is nothing wrong with the pre_tasks or with your play; the pre_tasks are skipped because you are passing --tags in the command line while calling the playbook; hence tags take the highest precedence while invoking the play that is the reason your validation fails each time; If you want to run the pre_tasks, then you dont have to mention ----tags option in cli- and handle the roles-validation with pre-tasks by passing only -e options: something like this
---
- name: test_play
hosts: localhost
connection: local
gather_facts: false
vars:
_allowed_envs:
- dev
- preprod
- prod
pre_tasks:
- name: Checking if the Target Environment is ok
fail:
msg: >-
Environment "{{ target_env }}" is not allowed.
Please choose a target environment from "{{ _allowed_envs | join(', ') }}"
when: not target_env in _allowed_envs
run_once: true
tasks:
- name: include the dynamic role
include_role:
name: "{{ ROLE }}"
tags: "{{ tag_name }}"
and then run it ansible-playbook -i my-inventory my-main.yml -e my_release_version=1.0.0 -e target_env=dev -e ROLE=copy -e tag_name=copy
Hope this helps!
Cheers
I have a playbook that is supposed to create a config file for all specified hosts, on my monitoring_sever.
- hosts: all
gather_facts: True
hosts: monitoring_server
tasks:
- command: touch {{ hostvars[item]['ansible_fqdn'] }}
with_items: "{{ groups['all'] }}"
I execute the playbook with ansible-playbook main.yml -l "new_client, new_client2, monitoring_server"
The Resulting files on the monitoring server should look like the following:
client1.conf client2.conf
But I get an error about missing quotes, I've tried all sorts of syntax changes but I can't seem to find the problem.
Updated:
- hosts: all
gather_facts: True
tasks:
- file:
path: "{{ hostvars[item]['ansible_fqdn'] }}"
state: touch
delegate_to: host_name # Delegate task to specific host
with_items: "{{ groups['all'] }}"
You have typos in your original playbook.
with:items should be with_items
items should be item
Usage of delegate_to: http://docs.ansible.com/ansible/playbooks_delegation.html#delegation
As long as you are targeting all hosts, you don't have to make a loop as Ansible executes tasks on all targeted hosts unless excluded by condition.
On the other hand, I would suggest using file module instead of command to touch the file.
- hosts: all
tasks:
- name: Touch a file
file:
path: "{{ ansible_fqdn }}"
state: touch
PS. I assumed ansible_fqdn is a host var you defined for each host.
You need to fix:
with_items: instead of with:items:
item instead of items
a single hosts: declaration in each item on the list of plays
This should work for your case:
---
- hosts: all
gather_facts: true
- hosts: monitoring_server
tasks:
- command: touch {{ hostvars[item]['ansible_fqdn'] }}
with_items: "{{ groups['all'] }}"
Alternatively you can use delegate_to: localhost and completely drop the loop as well as the reference to hostvars:
---
- hosts: all
gather_facts: true
tasks:
- command: touch {{ ansible_fqdn }}
delegate_to: localhost
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
Playbook below. I'm trying to replace test#ip: with a way to pull from my inventory file the IP from a group I've created.
- hosts: firewall
gather_facts: no
tasks:
- name: run shell script
raw: 'sh /home/test/firewall.sh'
- hosts: localhost
gather_facts: no
tasks:
- name: Copy File to Local Machine
shell: 'scp test#ip:/home/test/test.test /Users/dest/Desktop'
You need to change your task like this:
- hosts: localhost
gather_facts: no
tasks:
- name: Copy File to Local Machine
shell: 'scp test#{{ item }}:/home/test/test.test /Users/dest/Desktop'
with_items: groups['your_group_name']
If you want to run on all the hosts in the inventory then you can use like this:
with_items: groups['all']
Hope that will help you.