Ansible - Change target to IP in task - ansible

I'm writing a role thats creates virtual machines & configures them. I need to perform a few tasks on the VM's before their DNS entries are created.
How can I get the task to connect to a known IP address instead of the usual ansible_host variable (FQDN)? I can't set it in the inventory file since the IP is not known when it is created.
TIA

The inventory file can use IP addresses. See the jumper example in https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html.

The way you typically handle this is to use Ansible's add_host module, which lets you create inventory entries dynamically during your playbook run. A task looks something like:
- name: add host to inventory
add_host:
name: my_new_host
ansible_host: "{{ new_host_ipaddr }}"
groups: [webservers]
You can see an example of this in action here (just search for add_host).

Related

How to pass an additional inventory file (dynamic inventory script) in molecule?

In my playbook I use var group[inventory_group]. And I need to use my dynamic inventory script. In the documentation I found:
Like above, it is possible to pass an additional inventory file (or
even dynamic inventory script), using the hosts key. Ansible will
automatically merge this inventory with the one generated by molecule.
This can be useful if you want to define extra hosts that are not
managed by Molecule.
But I didn't find any examples.
So, how do I "pass an additional inventory file (or even dynamic inventory script), using the hosts key" ?
Perhaps you could execute the dynamic inventory script in create or prepare steps in the molecule scenario, and then use the add_host module to add the hosts to the in memory inventory?
So something like:
- command:
cmd: /path/to/your_dynamic_inventory_scri.pt
delegate_to: localhost
register: dynamic_inventory
- add_host:
name: "{{ item }}"
loop: "{{ dynamic_inventory.stdout_lines }}"

Using wildcard in Ansible inventory group doesn't work as expected

Running Ansible 2.9.3
Working in a large environment with hosts coming and going on a daily basis, I need to use wildcard hostnames in a host group: ie:
[excluded_hosts]
host01
host02
host03
[everyone]
host*
in my playbook I have
name: "Test working with host groups"
hosts: everyone,!excluded_hosts
connection: local
tasks:
The problem is, the task is running on hosts in the excluded group.
If I specifically list one of the excluded hosts in the everyone group, that host then gets properly excluded.
So Ansible isn't working as one might assume it would.
What's the best way to get this to work?
I tried:
hosts: "{{ ansible_hostname }}",!excluded_hosts
but it errored as invalid yaml syntax.
requirements: I can not specifically list each host, they come and go too frequently.
The playbooks are going to be automatically copied down to each host and the execution started afterwards, therefore I need to use the same ansible command line on all hosts.
I was able to come up with a solution to my problem:
---
- name: "Add host name to thishost group"
hosts: localhost
connection: local
tasks:
- name: "add host"
ini_file:
path: /opt/ansible/etc/hosts
section: thishost
option: "{{ ansible_hostname }}"
allow_no_value: yes
- meta: refresh_inventory
- name: "Do tasks on all except excluded_hosts"
hosts: thishost,!excluded_hosts
connection: local
tasks:
What this does is it adds the host's name to a group called "thishost" when the playbook runs. Then it refreshs the inventory file and runs the next play.
This avoids a having to constantly update the inventory with thousands of hosts, and avoids the use of wildcards and ranges.
Blaster,
Have you tried assigning hosts by IP address yet?
You can use wildcard patterns ... IP addresses, as long as the hosts are named in your inventory by ... IP address:
192.0.\*
\*.example.com
\*.com**
https://docs.ansible.com/ansible/latest/user_guide/intro_patterns.html

Ansible get hostname as defined in inventory

In my inventory I define hosts like this:
[server1]
141.151.176.223
I am looking for a variable which keeps the server1 name, as I am using it to define server hostname.
inventory_hostname is set to 141.151.176.223
ansible_hostname as well as inventory_hostname_short is set to 148.
To workaround this problem I am setting my own variable like this:
[server1]
141.151.176.223 hostname=server1
but I am not satisfied with this approach.
Any ideas?
Explanation
If the inventory file was defined this way:
[server1_group]
server1 ansible_host=141.151.176.223
Then you can access:
server1 with the inventory_hostname fact;
141.151.176.223 with the ansible_host fact;
server1_group with group_names|first (group_names fact contains a list of all groups server belongs to, first selects the first element from that list).
Regardless of the above, ansible_hostname fact contains the host name as defined on the host itself (the value is set during facts gathering).
Solution
You should use a standard ansible_host declaration to point to the target's IP address and set the inventory hostname to however you want to refer to the server in Ansible playbooks.
In particular you can skip groups definition altogether and define just:
server1 ansible_host=141.151.176.223
The [server1] declaration is the name of a group, not a host (even if you only assign a single host to that group).
As ansible allows a host to be placed in multiple groups, you can only get the names as an array: http://docs.ansible.com/ansible/latest/playbooks_variables.html#magic-variables-and-how-to-access-information-about-other-hosts
So I think the workaround that you found is the way to go, unless you can use real host names instead of IP addresses (using DNS or just static hosts file).

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.

Efficient way of reading data from inventory

What's the best way to read host variables from inventory file provided the script will not access the host? I want to create some virtual machines first before installing our test application in those machines. So, I want to keep the parameters required to create virtual machine in same inventory file so that I can use the same file to create virtual machines and to install our test product on those machines. The inventory will look like the following:
[testmachines1]
host1 vm=vmname1 description=vm1description
host2 vm=vmname2 description=vm2description
[testmachines2]
host3 vm=vmname3 description=vm3description
host4 vm=vmname4 description=vm4description
Script that will create the virtual machines will not access the hosts rather will read the parameters and create virtual machines accordingly.
One of the ways to do this:
---
- hosts: localhost
tasks:
- debug: msg="VM={{ hostvars[item].vm }}, Desc={{ hostvars[item]. description }}"
when: hostvars[item].vm is defined
with_inventory_hostnames: all

Resources