jeisenbath / ansible-collection-solarwinds-orion

An Ansible collection for managing nodes in Solarwinds Orion
11 stars 3 forks source link

Itempotency issue with monitor interface and regex character #17

Closed Andyjb8 closed 6 months ago

Andyjb8 commented 8 months ago

I noticed that with the orion_node_interface module, when I have regex expression character in the interface field, idempotency no longer works. For instance I added a "^" at the beginning so that GigabitEthernet would not match TenGigabitEthernet. However with the ^ idempotency doesn't work any more. I had to do this because my playbook was adding interfaces that were not in my "monitor_interfaces" list. In my case it was adding TenGigabitEthernet interfaces that were down and I did not want to monitor. Adding the ^ fixed that issue, but it broke idempotency. It would be nice to be able to re-run this add interfaces to monitor playbook with idempotency working to see which additional interfaces are added vs ones that are already monitored.

Here is my playbook task, in this example GigabitEthernet1 was already monitored in solarwinds when this was run.

  - name: ADD INTERFACES TO SOLARWINDS TO MONITOR
      solarwinds.orion.orion_node_interface:
        <<: *solarwinds_info
        name: "{{ inventory_hostname }}"
        state: present
        interface: "^{{ item }} " 
        regex: true
      loop: "{{ monitor_interfaces }}"
      delegate_to: localhost

Yet you can see it is a status of changed (and is in yellow text)

changed: [RTR-01 -> localhost] => (item=GigabitEthernet1) => {
    "ansible_loop_var": "item",
    "changed": true,
    "invocation": {
        "module_args": {
            "hostname": "solarwinds",
            "interface": "^GigabitEthernet1 ",
            "ip_address": null,
            "name": "RTR-01",
            "node_id": null,
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "regex": true,
            "state": "present",
            "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
        }
    },
    "item": "GigabitEthernet1",
    "orion_node": {
        "caption": "RTR-01",
        "ipaddress": "x.x.0.1",
        "netobjectid": "N:1131",
        "nodeid": 1131,
        "objectsubtype": "SNMP",
        "status": 1,
        "statusdescription": "Node status is Up.",
        "unmanaged": false,
        "unmanagefrom": "1899-12-30T00:00:00+00:00",
        "unmanageuntil": "1899-12-30T00:00:00+00:00",
        "uri": "swis://solarwinds/Orion/Orion.Nodes/NodeID=1131"
    }
}

If I remove the ^ from the beginning of the interface name in my playbook task.

    - name: ADD INTERFACES TO SOLARWINDS TO MONITOR
      solarwinds.orion.orion_node_interface:
        <<: *solarwinds_info
        name: "{{ inventory_hostname }}"
        state: present
        interface: "{{ item }} "
        regex: true
      loop: "{{ monitor_interfaces }}"
      delegate_to: localhost

It shows changed: false (and is in green) as it should because it is already added to solarwinds.


ok: [RTR-01 -> localhost] => (item=GigabitEthernet1) => {
    "ansible_loop_var": "item",
    "changed": false,
    "invocation": {
        "module_args": {
            "hostname": "solarwinds",
            "interface": "GigabitEthernet1 ",
            "ip_address": null,
            "name": "RTR-01",
            "node_id": null,
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "regex": true,
            "state": "present",
            "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
        }
    },
    "item": "GigabitEthernet1",
    "orion_node": {
        "caption": "RTR-01",
        "ipaddress": "x.x.0.1",
        "netobjectid": "N:1131",
        "nodeid": 1131,
        "objectsubtype": "SNMP",
        "status": 1,
        "statusdescription": "Node status is Up.",
        "unmanaged": false,
        "unmanagefrom": "1899-12-30T00:00:00+00:00",
        "unmanageuntil": "1899-12-30T00:00:00+00:00",
        "uri": "swis://solarwinds/Orion/Orion.Nodes/NodeID=1131"
    }
}
jeisenbath commented 8 months ago

When you pass a regex into the field, you're ultimately passing potentially a list into what really is a single task. Ansible wouldn't be able to show the output of each interface found in that list the same as the output for a single task, as if it was looping over that task.

However, maybe I could return an interfaces object with the list of interfaces and whether or not it changed. You'd have to register the output of the task into a variable, and access the object from that variable to see what changed, so that makes it a bit complex and confusing for someone at a beginner level of ansible, but it maybe be better than what is currently there. This might also cost some execution time, which the interfaces module is already the slowest because solarwinds discovery takes some time.

Andyjb8 commented 8 months ago

Okay, maybe a better way to handle this might be to see if there is a way to get the list of available interfaces to monitor from the node. When you open up list resources on a node, if we could pull that list of all the available interfaces available to monitor. If that is possible, then I could match items from that list with the names solarwinds sees (hopefully it could also include the interface status) based on my interfaces to monitor criteria and then use "regex: false" for exact matching. Remember I had related issues before (Issue#4) and started using the "regex: true" because Solarwinds is seeing interface names differently than I was expecting, for instance "GigabitEthernet1 - Gi1" instead of just "GigabitEthernet1" And on Juniper Solarwinds is seeing the interfaces as "ge-0/0/0 - " instead of just "ge-0/0/0" so adding interfaces names with exact match based on the names I was expecting wasn't working.

jeisenbath commented 6 months ago

I released 1.3.1, with some idempotency improvements to orion_node_interface, along with always returning a 'discovered' object (a list of discovered interfaces), and an 'interfaces' object (interfaces actually changed). 'interfaces' will still be a bit weird with regex: true, where if a single non-monitored interface ends up matching the regex pattern, you'll get all interfaces matching that pattern back in the 'interfaces' object.

Anyways, I hope that's useful, it ended up being somewhat tricky, and not the cleanest/prettiest implementation of idempotence. You can run the module in 'check' mode to get your discovered interfaces.