Ansible Host Variable Issues - ansible

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

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: How do I run an entire playbook based on a condition?

Context: provisioning fresh new servers.
I would like to provision them just once especially the update part.
After launching the first playbook bootstrap.yml I made it leave a file in a folder for me to know that the playbook ran well.
So then in the same playbook I would have to add a condition above every task (which I did) to check for the existance of this file.
If file exists skip running the playbook against all those machines who have that file.
Problem: How do I add the condition to run the playbook only if the file isn't found? I don't want to add a "when:" statement for each of my own tasks I find it silly.
Question: Does anyone have a better solution that maybe solves this with a single line or a parameter in the inventory file that I haven't thought of?
edit:
This is how i check for the file
- name: Bootstrap check
find:
path: /home/bot/bootstrapped-ok
register: bootstrap
and then when condition would be:
when: bootstrap.matched == 0
so if file is not found run the entire playbook.
I think you may be over-complicating this slightly. Would it be accurate to say "I want to bail early on a playbook without error under a certain condition?"
If so, you want "end_host"
How do I exit Ansible play without error on a condition
Just begin with a check for the file, and end_host if it's found.
- name: Bootstrap check
stat:
path: /home/bot/bootstrapped-ok
register: bootstrap
- name: End the play if previous provisioning was successful
meta: end_host
when: bootstrap.stat.exists == True
- name: Confinue if bootstrap missing
debug:
msg: "Hello"

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

How to check if inventory group exists in 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([])"

Ansible: Conditional check to either output name of child group or individual host based on specified limit

Hi to all friendly automagicians,
I'm using ansible in order to administrate tasks on a heap of embedded linux nodes that are rapidly expanding. Since our project is using hipchat, I figured it's necessary to start notifying to a room so I don't keep annoying researchers by rebooting or something when working on a node.
I have divided the hosts inventory up into child groups based on their switch ports and vlans.
So when I want to do something to all production, I don't use use the limit option..
When I want to do something to a specific chain of nodes, I limit to a child group.. and when I want to do something individually I limit to the hostname.
So I am using a notify at the end of a task to post to hipchat like so:
- name: "Notify hipchat"
hipchat_v2:
msg='{{ inventory_hostname }} was updated from {{ version.stdout }} to {{ newversion.stdout }}'
The problem is when I go to do an action like system wide updates in batches of child groups it's going result in a message for each node to the room which will mean hundreds over a couple of hours, so in this case I'd rather output the name of the child group.
However I still want to maintain the ability to notify room of the same action performed on an individual host.
That's where my question comes in:
Is there a way I can configure the playbook to use a conditional test in order to output an individual host name if the action is limited to a single host name like I'm doing with {{ inventory hostname }}, yet only output the name of the child group if the action is limited to a child group instead?
So in a logical flow (yes I know this isn't real code - just code logic), something like:
If --limit option = group
then print group
elif --limit option = group:research-nodes
then print research-nodes
elif --limit option = individual host
then print hostname
fi
Here's one way you could do it - I do something similar with some playbooks I have. The trick is to have well defined group names, and to pass a host, group, etc. into your script as a variable. So your playbook might look a little like this:
- hosts: "{{ host }}"
- tasks:
- name: reboot node
command: shutdown -r now
- name: Group notify
local_action: hipchat_v2 msg="Group {{ host }} was rebooted"
run_once: true
when: host.find("group_") != -1
- name: Individual notify
local_action: hipchat_v2 msg="Host {{ inventory_hostname }} was rebooted"
when: host.find("group_") == -1
This example would assume that any group names start with the prefix "group_" The first task would invoke the hipchat task once on the host Ansible is running from if the host variable contains "group_". The second task would invoke that hipchat task if "group_" isn't found in the host variable. So you would invoke ansible with something like this:
$ ansible-playbook reboot.yml --extra-vars="host=group_production"

Resources