Extract server IP from the group in the inventory file - ansible

I have the following inventory file:
[group_01]
g01_h01 ansible_ssh_host='10.1.0.1'
g01_h01 ansible_ssh_host='10.1.0.2'
[group_02]
g02_h01 ansible_ssh_host='10.2.0.1'
g02_h01 ansible_ssh_host='10.2.0.2'
[group_03:children]
group_01
group_02
[group_03:vars]
fst_group2={{groups['group_02'][0]}}
snd_group1={{groups['group_01'][1]}}
I would like that in my playbook variables had the following values:
fst_group2=10.2.0.1
snd_group1=10.1.0.2
Instead I get:
fst_group2=g02_h01
snd_group1=g01_h02
Any ideas, a workaround?

Very strange task indeed... Anyway,
groups variable – is a list of hosts, which are g01_h01, g01_h02, etc.
To achieve what you expect, you may use this:
[group_03:vars]
fst_group2={{hostvars[groups['group_02'][0]]['ansible_ssh_host']}}
snd_group1={{hostvars[groups['group_01'][1]]['ansible_ssh_host']}}
And keep in mind that ansible_ssh_host is deprecated in favor of ansible_host.

Related

How to use multiple statements in Ansible azure_rm conditional_groups

I have an ansible role which pulls all VM names(Adding details below):
plugin: azure_rm
auth_source: cli
include_vm_resource_groups:
plain_host_names: yes
conditional_groups:
prod_hosts: "'prod1' in name"
uat_hosts: "'uat' in name"
The above works perfectly fine. However, I have a requirement where the prod hosts can either have prod1 or prod2 in VM name. Ex: prod1-appvm, prod2-appvm. If I add "'prod1' or 'prod2' in name", will it work?
Ex:
conditional_groups:
prod_hosts: "'prod1' or 'prod2' in name"
uat_hosts: "'uat' in name"
I tried searching online, and I found this, where it says a mapping of group names to Jinja2 expressions. But I couldn't get any confirmed answer if 'or' will work.
Thanks and Regards,
Safi Junaid.
Add conditional statement using When Condition . When condition is used to control whether a task or role runs or is skipped.
It is the simplest conditional statement applies to a single task in Ansible. Create the task, then add a when statement that applies a test. You can write something as follows :
- hosts: all
tasks:
when: name in ['prod1','prod2']
Check this document for examples on grouping VMs based on VM type.
Open this Conditionals document for more information.

Is there any way to check a Yml/Yaml file is valid ansible Playbook?

It should check all cases of imports, includes and custom variables. As of now I can see that ansible-playbook playbook.yml --list-tasks fails in few cases when we have custom variables. For example a yml having tasks only should not be a valid play. yml importing those tasks should be treated as valid ansible play.
Because of the way templating etc works, the only way to know for sure beyond basic syntax checking (eg --syntax-check or --list-tasks) is to execute it. --check-mode can tell you some things if your playbook is written correctly to support it, and there are other tools around like ansible-lint that might help, but nothing short of executing the playbook will tell you 100%.

Ansible nested variables in inventory

I've been using Ansible for a while now, and in general have no trouble with variables in inventories. However, for the first time I have to override a nested variable in the inventory, and the I'd expect it to work... doesn't.
The default/main.yml of the role looks like this:
archiver_config:
archiver_folder: "/opt/archiver"
source_folder: "/var/tmp/images"
archive_folder: "/var/tmp/imagearchive"
min_diskspace: 1e6
logfile: "/var/log/archiver.log"
I need to override the default archive folder for some hosts because some of them have an external filesystem attached for this purpose, so I did this in the inventory:
[tdevices]
10.8.0.38 adeploy_name=16014c archiver_config.archive_folder=/media/ext
I have also tried putting the value in double and single quotes, like e.g.
archiver_config.archive_folder='/media/ext'
But it doesn't work. Ansible doesn't throw any errors, but the default value does not get overridden. What's the correct syntax to do this?
There are no "nested variables" in your example. There is only one variable archiver_config which is a dictionary (hash).
You cannot assign a value to a dictionary key in the inventory file.
What you can do is add a variable in the defaults/main.yml, use it as a value for the key (now, this can be called a nested variable):
archive_folder: "/var/tmp/imagearchive"
archiver_config:
archiver_folder: "/opt/archiver"
source_folder: "/var/tmp/images"
archive_folder: "{{archive_folder}}"
min_diskspace: 1e6
logfile: "/var/log/archiver.log"
and assign value to it in the inventory file:
[tdevices]
10.8.0.38 adeploy_name=16014c archive_folder=/media/ext

Specifying a particular callback to be used in playbook

I have created different playbooks for different operations in ansible.
And I have also created different Callback Scripts for different kinds of Playbooks (And packaged them with Ansible and installed).
The playbooks will be called from many different scripts/cron jobs.
Now, is it possible to specify a particular callback script to be called for a particular playbook? (Using a command line argument probably?)
What's happening right now is, all the Callback scripts are called for each playbook.
I cannot put the callback script relative to the location/folder of the playbook because it's already packaged inside the ansible package. Also, all the playbooks are in the same location too.
I am fine with modifying a bit of ansible source code to accommodate it too if needed.
After going through the code of Ansible, I was able to solve it with the below...
In each callback_plugin, you can specify self.disabled = True and the callback wont be called at all...
Also, which calling a playbook, there's an option to parsing extra arguments as key=value pairs. It will be part of the playbook object as extra_vars field.
So I did something like this in my callback_plugin.
def playbook_on_start(self):
callback_plugins = self.playbook.extra_vars.get('callback_plugin', '') // self.playbook is populated in your callback plugin by Ansible.
if callback_plugins not in ['email_reporter', 'all']:
self.disabled = True
And while calling the playbook, I can do something like,
ansible-playbook -e callback_plugin=email_reporter //Note -e is the argument prefix key for extra vars.
If with callback scripts you mean callback plugins, you could decide in those plugins if any playbook should trigger some action.
In the playbook_on_play_start method you have the name of the play, which you could use to decide if further notifications should be processed or not.
playbook_on_stats then is called at the end of the playbook.
SHOULD_TRIGGER = false
class CallbackModule(object):
def playbook_on_play_start(self, name):
if name == "My Cool Play":
SHOULD_TRIGGER = true
def playbook_on_stats(self, stats):
if SHOULD_TRIGGER == true:
do something cool
Please note, playbook_on_play_start is called for every play in your playbook, so it might be called multiple times.
If you are simply running a playbook via script you can do something like this
ANSIBLE_STDOUT_CALLBACK="json" ansible-playbook -i hosts play.yml
You are setting the callback as an environment variable prior to ansible-playbook command running.

Is it possible to execute an ansible playbook from a URL?

I'd love to be able to run ansible-playbook -i <inventory_url> <playbook_url> from my machine, but it doesn't seem to work.
Does anyone know if this is at all possible?
No. You can see the source code here, which shows the playbooks are assumed to be local:
if not os.path.exists(playbook):
raise errors.AnsibleError("the playbook: %s could not be found" % playbook)
if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)):
raise errors.AnsibleError("the playbook: %s does not appear to be a file" % playbook)
Here's the documentation on Python's os.path, showing that is meant for local files.
Ansible itself doesn't let you do this. But Ansible Tower (a commercial product of theirs) does allow you to perform all sorts of Ansible-related tasks, including running playbooks, etc. through a REST interface.

Resources