Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

ansible - sec_fact gives me the last match

I'm pulling the facts from Juniper devices and pushing that information to NetBox.

Below is my playbook, basically set_fact gives me the last result and then the netbox play sends the same result to all my interfaces, and that's not what I want.

- name: SETTING INT TYPE VIRTUAL
  set_fact:
    interfacetype: "Virtual"
  loop: "{{ansible_network_resources.interfaces}}"
  when: item.name == "irb" or 
        item.name == "lo0" 
      
- name: SETTING INT TYPE 1GE
  set_fact:
    interfacetype: "1000BASE-T (1GE)"
  loop: "{{ansible_network_resources.interfaces}}"
  when: item.name | regex_search('(ge-)')
  register: inter1

- name: SETTING INT TYPE 40GE
  set_fact:
    interfacetype: "QSFP+ (40GE)"
  loop: "{{ansible_network_resources.interfaces}}"
  when: item.name | regex_search('(et-)') and
        ansible_net_model | regex_search('^ex[2-4][2346]00|qfx5100$')

- name: CREATE DEVICE INTERFACES
  netbox_device_interface:
    netbox_url: https://netbox.something.org
    netbox_token: 99999999999999999999999999999999999
    data:
      device: "{{ ansible_net_hostname }}"
      name: "{{ item.name }}"
      description: "{{ item.description|default('') }}"
      enabled: "{{ item.enabled }}"
      mtu: "{{ item.mtu|default('') }}"
      type: "{{ interfacetype }}"
    state: present
  loop: "{{ansible_network_resources.interfaces}}"
  delegate_to: localhost

I think the below makes more sense based on the above. I think I need to combine inside the list, on each part that has a dictionary pointing to ge- a new item that will be like intertype:"1000BASE-T (1GE)"

That way I can use that list of dictionaries on the last play.

This is what I get:

ok: [device1.something.org] => {
"ansible_network_resources.interfaces": [
    {
        "enabled": true,
        "mtu": 9216,
        "name": "ge-0/0/0"
    },
    {
        "enabled": false,
        "mtu": 9216,
        "name": "ge-0/0/1"
    },
    {
        "enabled": false,
        "mtu": 9216,
        "name": "ge-0/0/2"
    },
    {
        "enabled": false,
        "mtu": 9216,
        "name": "ge-0/0/3"
    },
    {
        "enabled": false,
        "mtu": 9216,
        "name": "ge-0/0/4"
    },
    {
        "description": "agaga2",
        "enabled": true,
        "mtu": 9216,
        "name": "et-0/1/0"
    },
    {
        "enabled": false,
        "mtu": 9216,
        "name": "et-0/1/1"
    },
    {
        "enabled": true,
        "mtu": 9216,
        "name": "xe-0/2/0"
    },
    {
        "enabled": false,
        "mtu": 9216,
        "name": "xe-0/2/1"
    },
    {
        "enabled": false,
        "mtu": 9216,
        "name": "xe-0/2/2"
    },
    {
        "description": "blabla1",
        "enabled": true,
        "mtu": 9216,
        "name": "xe-0/2/3"
    },
    {
        "enabled": true,
        "name": "irb"
    },
    {
        "enabled": true,
        "name": "lo0"
    }
]

}

Can I add inside there a new dictionary so that the result is the following:

    {
    "intertype":"Virtual"  
    "enabled": true,
        "name": "lo0"
    }
    {
    "intertype":"QSFP+ (40GE)"  
    "enabled": false,
    "mtu": 9216,
     "name": "et-0/2/2"
    },
    {
    "intertype":"1000BASE-T (1GE)"     
    "enabled": false,
        "mtu": 9216,
        "name": "ge-0/0/1"
    },
question from:https://stackoverflow.com/questions/65930814/sec-fact-gives-me-the-last-match

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

In your code, the variable interfacetype is set in each iteration

- name: SETTING INT TYPE VIRTUAL
  set_fact:
    interfacetype: "Virtual"
  loop: "{{ansible_network_resources.interfaces}}"
  when: item.name == "irb" or 
        item.name == "lo0" 

I read the logic of this task as "If any of [irb, lo0] is in the interfaces set interfacetype to Virtual". It's more efficient to select the interfaces and intersect the lists. For example, given the data

    ansible_network_resources:
      interfaces:
        - {enabled: true, name: em1, mtu: '1476'}
        - {enabled: true, name: irb, mtu: '1514'}
        - {enabled: true, name: lo0, mtu: "Unlimited"}
    sel_intfs: [irb, lo0]

select the interfaces

    - set_fact:
        my_intfs: "{{ ansible_network_resources.interfaces|
                      map(attribute='name')|list }}"

gives

  my_intfs:
  - em1
  - irb
  - lo0

and intersect

    - set_fact:
        no_intfs: "{{ sel_intfs|intersect(my_intfs)|length }}"

gives the number of common interfaces

  no_intfs: '2'

When you put this together

    - set_fact:
        interfacetype: Virtual
      when: no_intfs|int > 0
      vars:
        my_intfs: "{{ ansible_network_resources.interfaces|
                              map(attribute='name')|list }}"
        no_intfs: "{{ sel_intfs|intersect(my_intfs)|length }}"
    - debug:
        var: interfacetype

give

  interfacetype: Virtual

In the case the intersect is an empty list, i.e. there are no common interfaces, for example, sel_intfs: [irc, lo1] the same tasks give

  interfacetype: VARIABLE IS NOT DEFINED!

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...