How to check if inventory group exists in Ansible? - ansible

Is there a way to check if an inventory group exists (and if it doesn't, the task should be skipped)?
I know you can check if a host exists in a group by way of "'Cool-Server' in groups['WebServers']" but I am having a hard time figuring out how to make ansible ignore a task if the group itself is not defined.
I basically have a task like such:
- name: Some Task
command: ls -ltr
when:
- "'Cool-Server' in groups['WebServers]"
and I'd like for ansible to be able to only run this task if the group WebServers itself is defined in the inventory, otherwise it should skip the task. Right now, if the group WebServers does not exist in the inventory, ansible/jinja freaks out and errors because its trying to look for something that does not exist.
Any ideas?

The following should work for you:
when:
- "'Cool-Server' in groups['WebServers] | default([])"

Related

Ansible playbook syntax for executing a task when Ansible controller file exists

When using Ansible, the controller is the machine you execute playbooks from.
I want to only run an Ansible task in a playbook when the controller has a file.
Is there a way to write something like this and exists(x.tgz), below?
- name: "copy up and unarchive the x for x if we have it on our controller"
unarchive:
src: x.tgz
dest: /usr/local/lib/x
when: "{{ { enable_me | bool } and exists(x.tgz) }}"
I want to only run an Ansible task in a playbook when the controller has a file.
By default, lookup plugins execute and are evaluated on the Ansible control machine only.
Is there a way to write something like this and exists(x.tgz), below?
Therefore and instead of using multiple tasks to check for the file existence, addressing delegation and running once, registering the result, running tasks conditionally on the registered result, you could probably write something like this
when: ( enable_x | bool ) and lookup('file', './x.tgz', errors='warn')
since it will
Check if the file exists on the Ansible Control Node
Returns the path to file found
Filter returns true if there is a path
Further Documentation
Lookup plugins
Like all templating, lookups execute and are evaluated on the Ansible control machine.
first_found lookup – return first file found from list
Further Q&A
How to search for ... a file using Ansible when condition

ansible-playbook:: how to play on other host than configured

I am trying to play a yml on other host than configured, using -l option.. but skipping: no hosts matched .
The scenario is where a host associated playbook is needed to be exceptionally used for some other host. (and for safety reasons, the playbook cannot have hosts:all and be left to the admin to limit the target(s))
What is the correct way to do this (if there is any)?
L.E. So, in the end, the answer of #mdaniel gave me the idea o a bash wrapper that creates a temp yml where the host: field is replaced with the argument.. it's not pretty but it works. (same works for a dynamical generation of a playbook from a series of tasks)
and the proper ansible way to do it i just found it here:
https://stackoverflow.com/a/18195217/624734
What is the correct way to do this?
Use all as the target of the playbook, and then constrain the hosts it applies to via the inventory, or the --limit that you mentioned
- hosts: all
# and now the rest of your playbook
You can try the below approach if you want to restrict hosts:all in your ansible script.
- hosts: "{{ host_group }}"
# Rest of your playbook
And you can have a specific group in your hosts file which you can use for testing.
For example,
[test]
192.168.1.1 # Test host
# Rest of your inventory file
And trigger the ansible playbook in the following order,
ansible-playbook -i hosts main.yml -e host_group="test"

how to get the current executing host group_name not group_names in ansible?

I have read How do you get group name of the executing role in ansible
I also read https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html
but I can't understand it.
If the same host IP in different host_groups, I think: "ansible is separated execute when executing the host, it should belong to only one group_name, not group_names".
How can I get current executing host gorup_name, not group_names?
It sounds like you want want the group equivalent to inventory_hostname. Unfortunately, it doesn't exist. You might consider setting an extra variable during execution as a workaround. Example: --extra-vars targetgroup=group1
This would work well if you typically only target one group. If targeting multiple groups, consider creating a new parent group for each combination and then targeting that.
First,
you can write one host in several groups.
Second,
In my opinion, Getting the 'group_name' of executing host make no sense
Whatever you using ad-hoc(playbook), you must declare which group of hosts you want to execute command(role), all group must be written in your ansible command(role) even if you want to execute on all hosts.
So when the command(role) are running, you have already know which group is running now.
Third,
Even if you run command(role) on two groups which have the same hosts, why do you want to know the host is from which group.
UPDATE:
1.Like my origin reply, you can define many groups include the same host.
For instance, this is the inventory file
[production]
machine01
machine02
[staging]
mchines01
And Using this judging condition in tasks.
when:
- inventory_hostname in groups['production']
2.And you also can add tags for the specific tasks.
For instance
- name: set hostname
hostname:
name: machine03
tags:
- production
- staging
- name: reboot
reboot:
reboot_timeout: 1200
tags:
- staging
Running ansible-playbook commond with -t option
-t TAGS, --tags=TAGS only run plays and tasks tagged with these values

Ansible Host Variable Issues

I have a issue when i am trying to have a conditional statement based on the variable set in my inventory file. Below is the details. My inventory file looks like this.
[webserver]
server1
server2
[appserver]
server1
[webserver:vars]
TYPE=w
[appserver:vars]
TYPE=a
Now when i am trying to add a condition in my task like
name: abc
shell: run this task
when: TYPE == "w"
name: cde
shell: run this task
when: TYPE == "a"
Now when i run the Play 1 it picks up the first variable and stores it but when it tries to run the task second time (Play2) its still have the same variable and fails. I have two plays 1 for web and other for app. Please let me know what may be the issue.
You can't define the same variable twice in an inventory file, even if it belongs to another group.
After the parsing of your inventory file the only "TYPE" known to Ansible will be the last one defined in your inventory file. In your case that would be one within appserver.
If you switch the order of your variables you will face the exact opposite behavior I guess.
In my opinion you should change the way to determine which tasks to run.
Little example:
- name: some task for webservers
shell: run this webserver task
when: run_webserver_task
- name: some task for appservers
shell: run this appserver task
when: run_appserver_task
Please see this link as evidence for my bold statement:
https://github.com/ansible/ansible/issues/6538
OR
You could try to design your inventory file the yamlish way instead of using an ini file. Please see:
http://docs.ansible.com/ansible/latest/intro_inventory.html

Ansible: Include playbook according to inventory variable

I am trying to set up Ansible to be able to run a playbook according to what inventory group the host is in. For example, in the inventory, we have:
[group1]
host1.sub.domain.tld ansible_host=10.0.0.2
...
[group1:vars]
whatsmyplaybook=build-server.yml
Then we want to make a simple playbook that will more or less redirect to the playbook that is in the inventory:
---
- name: Load Playbook from inventory
include: "{{hostvars[server].whatsmyplaybook}}"
Where the "server" variable would be the host's FQDN, passed in from the command line:
ansible-playbook whatsmyplaybook.yml -e "server=host1.sub.domain.tld"
Our reasoning for this would be to have a server bootstrap itself from a fresh installation (PXE boot), where it will only really know its FQDN, then have a firstboot script SSH to our Ansible host and kick off the above command. However, when we do this, we get the below error:
ERROR! 'hostvars' is undefined
This suggests that the inventory is not parsed until a host list is provided, which sucks a lot. Is there another way to accomplish this?
A bit strange workflow, honestly.
Your setup doesn't work, because most of variables are not defined during playbook parse time.
You may be more lucky with defining single playbook with different plays for different groups (no need to set group var, just use correct host pattern (group name in my example)) and execute it limiting to specific host:
site.yml:
---
- hosts: group1
tasks:
- include: build-web-server-tasks.yml
- hosts: group2
tasks:
- include: build-db-server-tasks2.yml
command to provision specific server:
ansible-playbook -l host1.sub.domain.tld site.yml
You can develop your own dynamic inventory file so that all machines which needs to be bootstrapped will automatically added into your inventory and group respectively with out an manual entry in to the inventory file.
For developing dynamic inventory you can follow the below link:
http://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html
You can include multiple playbooks targeted to different groups as follows.
---
- hosts: all
tasks:
- include: build-web-server-tasks.yml
where: inventory_hostname in groups['group1']
- include: build-db-server-tasks2.yml
where: inventory_hostname in groups['group2']
inventory_hostname is the name of the hostname as configured in Ansible’s inventory host file. This can be useful for when you don’t want to rely on the discovered hostname ansible_hostname or for other mysterious reasons. If you have a long FQDN, inventory_hostname_short also contains the part up to the first period, without the rest of the domain.

Resources