ansibl inventory : create temporary inventory with multiple groups with add_host or group_by - ansible

I have an assignment to provision {{ create new hosts }} according to a given
invonteroy file,
example
[SET1]
1.1.1.1 new_ip=1.1.1.1
[SET2]
1.1.1.2 new_ip=1.1.1.2
[SET3]
1.1.1.3 new_ip=1.1.1.3
Here is the problem. The inventory file contains set of ip addresses that do not exists yet.
What I want to do
- connect to vsphere host(5.5)
- create new machines based on amount of hosts in the inventory
- change the machines ip address to match the one in the given inventory
modules like
vmware_shell
vmware_guest
requires administrative permissions which I don't have.
The only way to hack around this issue is to try and create an in memory or temporary inventory during provisioning task.
Here is my role:
- vsphere_guest:
vcenter_hostname: {{ vcenter }}
validate_certs: no
username: "{{ vsphere.username }}"
password: "{{ vsphere.password }}"
guest: "{{ item }}"
from_template: yes
template_src: Centos_base
resource_pool: "/Resources"
esxi:
datacenter: Remote
hostname: {{ esx_host }}
with_items:
- "{{ play_hosts }}"
- name: wait for power on to finish
pause: seconds=5
- name: get facts from vm
vsphere_guest:
validate_certs: False
vcenter_hostname: {{ vcenter }}
username: "{{ vsphere.username }}"
password: "{{ vsphere.password }}"
guest: "{{ item }}"
vmware_guest_facts: yes
with_items:
- "{{ play_hosts }}"
register: vm_facts
until: vm_facts.ansible_facts.hw_eth0.ipaddresses[0] is defined
retries: 10
delay: 10
- name: grab new ipaddresses
set_fact: myIp="{{ inventory_hostname }}"
- name: Add production VMs to inventory
add_host: hostname={{item.ansible_facts.hw_eth0.ipaddresses[0] }} groups=temp
new_ip={{ myIp }}
with_items: "{{ vm_facts.results }}"
ignore_errors: yes
my question:
is there any way to create a temp inventory with multiple groups and mutilple variables that matches the given inventory!?

update
I hacked a way around it:
- name: Add production VMs to inventory
add_host: hostname={{item.ansible_facts.hw_eth0.ipaddresses[0] }} groups=temp
new_ip="{{ item.ansible_facts.hw_name }}"
with_items: "{{ vm_facts.results }}"
ignore_errors: yes
this works since the machine name is equal to {{ play_host }}

Related

Ansible: Delete interfaces that are not in my host_vars

I've an ansible playbook that creates l3_subinterfaces on a Palo Alto firewall, the creating is based on the host_vars of the firewall.
- l3_subinterfaces:
- tag: "9"
vr_name: "vr_production"
ip: "10.0.9.2/24"
comment: "VLAN9 Subinterface"
parent_if: "ethernet1/1"
zone: "Infrastructuur"
- tag: "13"
vr_name: "vr_production"
ip: "10.0.13.2/24"
comment: "VLAN13 Subinterface"
parent_if: "ethernet1/2"
zone: "Infrastructuur"
And the playbook task which create the interfaces:
- name: Configure l3_subinterfaces
panos_l3_subinterface:
provider: "{{ panos_provider }}"
name: "{{ item.parent_if }}.{{ item.tag }}"
tag: "{{ item.tag }}"
ip: ["{{ item.ip }}"]
vr_name: "{{ item.vr_name }}"
zone_name: "{{ item.zone }}"
comment: "{{ item.comment }}"
enable_dhcp: false
with_items:
- "{{ l3_subinterfaces }}"
when: l3_subinterfaces is defined
So at this point everything is working fine. However the thing I'm trying to achieve is holding the state of the firewall in the Ansible inventory.
So for example I'm now delete the l3_subinterface with tag 13 and run the task again, it still have the l3_subinterface with tag 13 configured on the Palo Alto firewall.
I'm trying to figure out how I can delete the l3_subinterfaces which exists on the firewall, but doesn't exists in my host_vars. I think I need to compare something like te facts with the host_vars, but really have no clue how to do it.
Actually I've already found my own answer. The solution is to compare the list l3_subinterfaces against the palo alto interfaces:
- name: Get interfaces facts
panos_facts:
provider: '{{ panos_provider }}'
gather_subset: ['interfaces']
- name: Delete unused l3_subinterfaces
panos_l3_subinterface:
provider: "{{ panos_provider }}"
name: "{{ item }}"
tag: "{{ item|regex_search('\\d+$') }}"
state: "absent"
with_items:
- "{{ ansible_net_interfaces|selectattr('tag', 'defined')|map(attribute='name')|list | difference(l3_subinterfaces|map(attribute='name')|list) }}"

add_host - divide by os

I want to create playbook that going on the entire inventory file and divide the servers to 2 groups: Windows and Linux (add-host going only on the first server on the inv)
I tried this code:
- name: Linux Group
add_host:
name: "{{ item }}"
group: LinuxGroup
when: hostvars[" {{ item }} "]['ansible_system'] == 'Linux'
with_items: "{{ ansible_play_hosts_all }} "
This code suppose to create the linux group
and I tried with other conditions of when but non was a succsess. I would like to get your help please.
PS:
I changed the code to this:
tasks:
- name: Create linux group
add_host:
name: "{{ item }}"
group: LinuxGroup
when: hostvars[item].ansible_system == 'Linux'
with_items: "{{ ansible_play_hosts_all }} "
ignore_errors: yes
- name: ping to Linux
ping:
with_items: LinuxGroup
and when I run the code the windows servers are skipped in the "Create linux group" task, but I used the module debug to print to group's items and there are the windows servers.
The fact ansible_system is a key under the host, not a list of keys. Also, conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}, use hostvars[item] instead of hostvars[ "{{ item }}" ].
Make sure gather_facts is set to true.
Note that the add_host module does not update the inventory file but updates the in-memory inventory. I have included a debug task to print the groups from the in-memory inventory of ansible.
gather_facts: true
tasks:
- name: Linux Group
add_host:
name: "{{ item }}"
group: LinuxGroup
when: hostvars[item].ansible_system == 'Linux'
with_items: "{{ ansible_play_hosts_all }}"
- debug: msg="{{ groups }}"

printing the host name from group in inventory

I have below inventory file:
[web]
10.0.1.0
[db]
10.0.3.0
[frontend]
10.0.5.0
[X_all:children]
web
db
frontend
Now in my playbook: I'm trying to print the hostname under X_all group in the name line.
- name: "Copying the output of Registry run to local machine from {{ hostvars[item]['inventory_hostname'] }}"
become: true
become_user: "{{ login }}"
fetch:
src: /tmp/DeploymentRegistry.txt
dest: /tmp/DeploymentRegistry-{{ inventory_hostname }}.txt
flat: yes
with_items:
- "{{ groups['X_all'] }}"
Is it even possible to add the hostname in the name line?
I tried replacing {{ hostvars[item]['inventory_hostname'] }} with inventory_hostname but it's also not working.
Regarding your requirement
I'm trying to print the hostname under test group in the name line.
take note that the group has more than one member and therefore more than one hostname, but a list of hostnames.
- name: Show hosts {{ groups['test'] }}
delegate_to: localhost
debug:
msg: "{{ item }}" # will show the group member hostname(s)
with_items:
- "{{ groups['test'] }}"
Is it even possible to add the hostname in the name line? I tried ... with inventory_hostname but it's also not working.
Yes, it is.
- name: Show host {{ inventory_hostname }}
debug:
msg: "{{ item }}"
with_items:
- "{{ groups['test'] }}"
But it will print the first hostname from list only.

Ansible Pass multiple vaules with single defined Variable

I need to add a server to service group every time I create a new server using the following task.
Task
- name: Create a service group
a10_service_group_v3:
validate_certs: no
host: "{{ item.0.a10_host }}"
state: "{{ item.1.service_state }}"
username: "{{ item.0.user }}"
password: "{{ item.0.pass }}"
service_group: "{{ item.1.group_name }}"
reset_on_server_selection_fail: yes
servers:
- name: "{{ item.1.server_name1 }}"
port: "{{ item.1.server_port1 }}"
overwrite: yes
write_config: yes
ignore_errors: yes
with_nested:
- "{{ a10 }}"
- "{{ service_group }}"
Variables:
service_group:
- group_name: bif_sg
service_state: present
server_name1: bif01
server_port1: 80
I need help with passing variables for server_name and server_port, let's say If I have 3 servers to add to service group in the task I need to add 3 times server_name1, server_port1
server_name2, server_port2 ......
Everytime I add server I need to update in the task as well :(
Is there a way to pass multiple times sever_name and serer_port with single defined value in the task.
I you expect server_group to have a list of servers, refactor your variable to have a list of servers and not a bunch of separate subkeys:
service_group:
- group_name: bif_sg
service_state: present
servers:
- name: bif01
port: 80
- name: bif02
port: 8080
And in your task:
...
servers: "{{ item.1.servers }}"
...

ansible: create temporary inventory with multiple groups with add_host or group_by

Is there any way to create an in memory inventory during provisioning tasks with add_host or group_by modules such:
[SET]
1.1.1.1
[SET:vars]
ip_address={{ inventory_hostname }}
[SET1]
1.1.1.2
[SET:vars]
ip_address={{ inventory_hostname }}
Yes. You can do something like this (if you provide more information in your question, we can provide more specificity ourselves):
- add_host:
hostname: 1.1.1.1
groups: SET
- add_host:
hostname: 1.1.1.2
groups: SET1
This will dynamically add 1.1.1.1 to the inventory as part of the SET group and 1.1.1.2 to the inventory as part of the SET1 group. there are a couple of good example of doing this during provision steps for rackspace
tasks:
- name: Provision a set of instances
local_action:
module: rax
name: "{{ rax_name }}"
flavor: "{{ rax_flavor }}"
image: "{{ rax_image }}"
count: "{{ rax_count }}"
group: "{{ group }}"
wait: yes
register: rax
- name: Add the instances we created (by public IP) to the group 'raxhosts'
local_action:
module: add_host
hostname: "{{ item.name }}"
ansible_host: "{{ item.rax_accessipv4 }}"
ansible_ssh_pass: "{{ item.rax_adminpass }}"
groups: raxhosts
with_items: "{{ rax.success }}"
when: rax.action == 'create'

Resources