Netbox Ansible VLAN Assignments - ansible

I am currently using the netbox ansible module to pull interface information from Cisco devices into Netbox. So far I have managed to pull in the interfaces and basic information like their MAC addresses.
Is there a way that you can get the untagged and tagged VLANS on each port and push them into netbox too?
This is my current ansible playbook:
---
- name: "PLAY 1: ADD INTERFACES TO NETBOX AND CLEANUP TEMP"
connection: network_cli
hosts: platforms_ios
tags: [ ios ]
tasks:
- name: "TASK 1: IOS >> GET IOS FACTS"
ios_facts:
gather_subset: "!config"
when: "ansible_network_os == 'ios'"
- name: "TASK 2: NETBOX >> ADD INTERFACES TO NETBOX"
netbox.netbox.netbox_device_interface:
netbox_url: "<netbox url>"
netbox_token: "<netbox_token>"
data:
device: "{{ inventory_hostname }}"
name: "{{ item.key }}"
form_factor: "{{ item.key | get_interface_type }}"
mac_address: "{{ item.value.macaddress | convert_mac_address }}"
state: present
with_dict:
- "{{ ansible_facts['net_interfaces'] }}"
loop_control:
label: "{{ item.key }}"
netbox.netbox.netbox_device_interface has options for untagged_vlan: and tagged_vlans: in their documentation. I am unsure if this information can be provided from ansible however.

Related

Ansible Tower how to pass inventory to my playbook variables

I am setting up a vmware job in Ansible Tower to snapshot a list of VM's, ideally, this list should be generated by AWX/Tower from the vSphere dynamic inventory. Inventory is named "lab_vm" in AWX and use either the hostname or the UUID of the VM.
How do I pass this through in my playbook variables file?
---
vars:
vmware:
host: '{{ lookup("env", "VMWARE_HOST") }}'
username: '{{ lookup("env", "VMWARE_USER") }}'
password: '{{ lookup("env", "VMWARE_PASSWORD") }}'
vcenter_datacenter: "dc1"
vcenter_validate_certs: false
vm_name: "EVE-NG"
vm_template: "Win2019-Template"
vm_folder: "Network Labs"
my playbook
---
- name: vm snapshot
hosts: localhost
become: false
gather_facts: false
collections:
- community.vmware
pre_tasks:
- include_vars: vars.yml
tasks:
- name: create snapshot
vmware_guest_snapshot:
# hostname: "{{ host }}"
# username: "{{ user }}"
# password: "{{ password }}"
datacenter: "{{ vcenter_datacenter }}"
validate_certs: False
name: "{{ vm_name }}"
state: present
snapshot_name: "Ansible Managed Snapshot"
folder: "{{ vm_folder }}"
description: "This snapshot is created by Ansible Playbook"
You're going about it backward. Ansible loops through the inventory for you. Use that feature, and delegate the task to localhost:
---
- name: vm snapshot
hosts: all
become: false
gather_facts: false
collections:
- community.vmware
pre_tasks:
- include_vars: vars.yml
tasks:
- name: create snapshot
vmware_guest_snapshot:
datacenter: "{{ vcenter_datacenter }}"
validate_certs: False
name: "{{ inventory_hostname }}"
state: present
snapshot_name: "Ansible Managed Snapshot"
folder: "{{ vm_folder }}"
description: "This snapshot is created by Ansible Playbook"
delegate_to: localhost
I've not used this particular module before, but don't your want snapshot_name to be unique for each guest?

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) }}"

Registering and using multiple variables in Ansible

I'm trying to pop VM instances, put them into different host groups (say webservers and devops/admin machines) and install what is needed on them in one single playbook.
I don't know what IP addresses, for instance, GCP will give these instances, and so i am trying to capture them in a variable for use later on in the playbook. I can capture them fine by using "register" but using them is proving tricky. For instance if I do.
- name: création des adresses statiques
gcp_compute_address:
name: "{{ item }}"
state: present
region: "{{ region }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/compute
loop:
- adresse-1
- adresse-2
- adresse-3
- adresse-4
- adresse-5
register: address
The best way i have figured out to use these variables later on is:
network_interfaces:
- network: "{{ network.name }}"
access_configs:
- name: 'External NAT'
type: 'ONE_TO_ONE_NAT'
nat_ip:
- "{{ address.results[0].address }}"
- "{{ address.results[1].address }}"
- "{{ address.results[2].address }}"
Which fails miserably.
Please help ? How can I use the range of addresses I have created ?
I am going nuts over this
It is possible to add_host to the group webservers and proceed with the next play
- add_host:
name: "{{ item }}"
groups: webservers
loop: "{{ address.results|json_query('[*].address') }}"
- debug:
msg: "{{ groups['webservers'] }}"
- hosts: webservers
tasks:
- name: Configure cluster
...
The tasks below split the hosts into two groups
- set_fact:
my_hosts: "{{ address.results|json_query('[*].address') }}"
- add_host:
name: "{{ item }}"
groups: webservers1
loop: "{{ my_hosts[0:(my_hosts|length / 2)|int] }}"
- add_host:
name: "{{ item }}"
groups: webservers2
loop: "{{ my_hosts[(my_hosts|length / 2)|int:my_hosts|length] }}"
- debug:
msg: "{{ groups['webservers1'] }}"
- debug:
msg: "{{ groups['webservers2'] }}"
There is also GCE Dynamic Inventory and other 100+ gcp modules. You might want to start with Google Cloud Platform Guide.
FWIW, Ansible 2 Cloud Automation Cookbook covers leading providers incl. GCP.

Ansible: ec2_eni cannot attach interface

Using ansible I am trying to create ec2 instances and attach an extra network interface to each instance so that they will have two private IP addresses. However, for some reason, it seems that the ec2_eni module can create network interfaces, but will not attach them to the instances specified. What am I doing wrong? Below is my playbook:
---
- hosts: localhost
connection: local
gather_facts: false
tasks:
- name: Create new servers
ec2:
region: "{{ region }}"
vpc_subnet_id: "{{ subnet }}"
group_id: "{{ sec_group }}"
assign_public_ip: yes
wait: true
key_name: '{{ key }}'
instance_type: t2.micro
image: '{{ ami }}'
exact_count: '{{ count }}'
count_tag:
Name: "{{ server_name }}"
instance_tags:
Name: "{{ server_name }}"
register: ec2
- name: Show ec2 instance json data
debug:
msg: "{{ ec2['tagged_instances'] }}"
- name: allocate new elastic IPs and associate it with instances
ec2_eip:
region: "{{ region }}"
device_id: "{{ item['id'] }}"
with_items: "{{ ec2['tagged_instances'] }}"
register: eips
- name: Show eip instance json data
debug:
msg: "{{ eips['results'] }}"
- ec2_eni:
subnet_id: "{{ subnet }}"
state: present
secondary_private_ip_address_count: 1
security_groups: "{{ sec_group }}"
region: "{{ region }}"
device_index: 1
description: "test-eni"
instance_id: "{{ item['id'] }}"
with_items: "{{ ec2['tagged_instances'] }}"
The strange thing is that the ec2_eni task succeeds, saying that it has attached the network interface to each instance when in reality it just creates the network interface and then does nothing with it.
As best I can tell, since attached defaults to None, but the module docs say:
Specifies if network interface should be attached or detached from instance. If ommited, attachment status won't change
then the code does what they claim and skips the attachment step.
This appears to be a bug in the documentation, which claims the default is 'yes' but is not accurate.

Adding field to dict items

Consider the following play. What I am trying to do is add a field, tmp_path which is basically the key and revision appended together to each element in the scripts dict.
---
- hosts: localhost
connection: local
gather_facts: no
vars:
scripts:
a.pl:
revision: 123
b.pl:
revision: 456
tasks:
- with_dict: "{{ scripts }}"
debug:
msg: "{{ item.key }}_{{ item.value.revision }}"
# - with_items: "{{ scripts }}"
# set_fact: {{item.value.tmp_path}}="{{item.key}}_{{item.value.revision}}"
# - with_items: "{{ scripts }}"
# debug:
# msg: "{{ item.value.tmp_path }}"
...
Obviously the commented code doesn't work, any idea how I can get this working? Is it possible to alter the scripts dict directly, or should I somehow be creating a new dict to reference instead?
By the way welcome to correct the terminology for what I am trying to do.
OK, I think I got a solution (below), at least to let me move forwards with this. Disadvantages are it has removed the structure of my dict and also seems a bit redundant having to redefine all the fields and use a new variable, If anyone can provide a better solution I will accept that instead.
---
- hosts: localhost
connection: local
gather_facts: no
vars:
scripts:
a.pl:
revision: 123
b.pl:
revision: 456
tasks:
- with_dict: "{{ scripts }}"
debug:
msg: "{{ item.key }}_{{ item.value.revision }}"
- with_dict: "{{ scripts }}"
set_fact:
new_scripts: "{{ (new_scripts | default([])) + [ {'name': item.key, 'revision': item.value.revision, 'tmp_path': item.key ~ '_' ~ item.value.revision}] }}"
# - debug:
# var: x
# - with_dict: "{{ scripts }}"
- with_items: "{{ new_scripts }}"
debug:
msg: "{{ item.tmp_path }}"
...
BTW credit to the following question which pointed me in the right direction:
Using Ansible set_fact to create a dictionary from register results

Resources