Efficient way of reading data from inventory - ansible

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

Related

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"

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

how to run commands on different servers with different users

I have to check the status of my databases which runs on many servers with different user ids for example: on server1 it runs with user1 on server2 it runs with user2 etc. In my playbook, I have the code to check the database status but don't know how to run this on different hosts and different user ids.
I have written playbook which can check the database status but doesn't know how to make this run with different user ids on different servers.
Playbook:
---
- hosts: all
become: true
become_user: db2inst1
tasks:
- name: Start DB2
command: /home/db2inst1/sqllib/adm/db2_ps
Inventory:
[db-servers]
192.168.4.30
You should take a look at the "Connecting to hosts: behavioral inventory parameters" section of Ansible Docs. It explains all the variables you can set to modify Ansible's behavior on each host.
In your case, you are going to have to define the ansible_user variable to use on each host, and the corresponding authentication details (passwords, ssh keys, etc.)
You can configure these variables on your inventory files. For example, suppose that you need to use the user root for some server, and ubuntu for another. You can configure your playbook like this.
[db-servers]
192.168.4.30 ansible_user=root
192.178.4.31 ansible_user=ubuntu
I hope it helps.

Ansible - Change target to IP in task

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).

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