A module to get Ansible facts from SNMP devices - Feedback requested

537 views
Skip to first unread message

Patrick Ogenstad

unread,
Oct 22, 2014, 3:40:28 PM10/22/14
to ansible...@googlegroups.com
Hi,

I'd like to get some feedback on an Ansible module I've written. It can target SNMP devices and collect information which it stores as Ansible facts.

There is some more information about the module here:

Specifically I would like to get suggestions about the structure of the data which is to be stored.

Best regards
Patrick

Michael DeHaan

unread,
Oct 23, 2014, 9:02:10 PM10/23/14
to ansible...@googlegroups.com
Hi Patrick,

SNMP can definitely be a beast.

I'd be interested if seeing if you could share an example of some of the output from the snmp module.

My other piece of advice would probably be to define constants for each of the MIB values, and see if there is an snmp library defines any of these (it might not).

I'd also move the import to the top of the file, and enclose it in a try/except ImportError block, so it can produce a nice error when something is not defined.

calls like "print json.dumps" can be replaced with the "fail_json" and "exit_json" calls you can see throughout AnsibleModule code.

You can also use the "required_together" feature of argument_spec (grep through the code) to simplify some of the argument checking.

Variables that are not constants, like SNMP_AUTH should be downcased ("snmp_auth")

Additionally, some duplication like:

snmp_result['ansible_facts']

throughout the system

Could be done just by having the final module return like so:

exit_json(ansible_facts=results)

As you can find done by 'setup', the most basic ansible facts module.


Hope that helps for starters

My other thought is different types of devices might not surface the same types of things, so it may be possible your module is written for certain network hardware -- which might make the module not generally applicable? (i.e. is it always true that an SNMP thing has an IP address?)

Possibly something to think about.

--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/49d164d2-4069-4947-87ca-3f042f2ee676%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Patrick Ogenstad

unread,
Oct 24, 2014, 3:17:53 AM10/24/14
to ansible...@googlegroups.com
Hi Michael,

Thank you for your comments! I'll do some changes to the code. Great about the require_together feature! I'll change the OID numbers to constants instead, for some of these basic values there are (or should be) some preloaded MIBs with pysnmp. However this could add another dependency and will be an issue if additional OIDs are to be polled. 

I'm not quite sure what you mean about the snmp_result['ansible_facts'] comment, aren't you doing the same thing in the setup module with "setup_result['ansible_facts'][k] = v"?

Concerning your thought about different devices you are correct SNMP support differs a lot. I'm not sure it's that big of an issue, but I will move the facts assignments so that the code doesn't try to assign something which isn't there. What we will we however if you look at the output below is that some SNMP tables doesn't exist on all devices. For example the ifXTable, which contain ifAlias (typically the description you set on a port in a switch or router), doesn't exist on the printer I tested against. So under the interfaces for the printer the "description" key is missing. Would you see this as a problem?

For device specific information I'm thinking about adding arguments as in:
snmp_facts: host={{ inventory_hostname }} version=v2 community=public cdp=true (cdp=false would be default)
snmp_facts: host={{ inventory_hostname }} version=v2 community=public lldp=true (lldp=false would be default)
snmp_facts: host={{ inventory_hostname }} version=v2 community=public route_table=IP-FORWARD-MIB (options would be IP-FORWARD-MIB or RFC1213-MIB)
This could be split up into device specific modules too.

This is the playbook I'm currently using:

---
- hosts: switches
  connection: local
  gather_facts: false
  tasks:
    - name: Get SNMP information from switches
      snmp_facts: host={{ inventory_hostname }} version=v3 level=authPriv username=snmpv3 integrity=sha privacy=aes authkey=s9k3acdfeasDwk privkey=daddkws3azscx9jeSDM

- hosts: printers
  connection: local
  gather_facts: false
  tasks:
    - name: Get SNMP information from printers
      snmp_facts: host={{ inventory_hostname }} version=v2 community=public

The output looks like this:

patrick@srv-master-1:~/play-ansible$ ansible-playbook -i inventory snmp_facts-playbook.yml -v

PLAY [switches] ***************************************************************

TASK: [Get SNMP information from switches] ************************************
ok: [172.29.50.3] => {"ansible_facts": {"ansible_all_ipv4_addresses": ["172.29.50.3", "172.29.52.34"], "ansible_interfaces": {"1": {"adminstatus": "down", "description": "", "ifindex": "1", "mac": "0024f7dd7740", "mtu": "1500", "name": "Vlan1", "operstatus": "down", "speed": "1000000000"}, "10101": {"adminstatus": "up", "description": "", "ifindex": "10101", "mac": "0024f7dd7701", "mtu": "1500", "name": "GigabitEthernet0/1", "operstatus": "down", "speed": "1000000000"}, "10102": {"adminstatus": "up", "description": "TELIA ADSL", "ifindex": "10102", "mac": "0024f7dd7702", "mtu": "1500", "name": "GigabitEthernet0/2", "operstatus": "down", "speed": "10000000"}, "10103": {"adminstatus": "up", "description": "", "ifindex": "10103", "mac": "0024f7dd7703", "mtu": "1500", "name": "GigabitEthernet0/3", "operstatus": "up", "speed": "1000000000"}, "10104": {"adminstatus": "up", "description": "", "ifindex": "10104", "mac": "0024f7dd7704", "mtu": "1500", "name": "GigabitEthernet0/4", "operstatus": "down", "speed": "10000000"}, "10105": {"adminstatus": "up", "description": "", "ifindex": "10105", "mac": "0024f7dd7705", "mtu": "1500", "name": "GigabitEthernet0/5", "operstatus": "up", "speed": "100000000"}, "10106": {"adminstatus": "up", "description": "*** srv-esxi-1 ***", "ifindex": "10106", "mac": "0024f7dd7706", "mtu": "1500", "name": "GigabitEthernet0/6", "operstatus": "up", "speed": "1000000000"}, "10107": {"adminstatus": "up", "description": "", "ifindex": "10107", "mac": "0024f7dd7707", "mtu": "1500", "name": "GigabitEthernet0/7", "operstatus": "down", "speed": "10000000"}, "10108": {"adminstatus": "up", "description": "*** NS2903-ASA-01 ***", "ifindex": "10108", "mac": "0024f7dd7708", "mtu": "1500", "name": "GigabitEthernet0/8", "operstatus": "up", "speed": "100000000"}, "10501": {"adminstatus": "up", "description": "", "ifindex": "10501", "mac": "", "mtu": "1500", "name": "Null0", "operstatus": "up", "speed": "4294967295"}, "20": {"adminstatus": "up", "description": "", "ifindex": "20", "mac": "0024f7dd7741", "mtu": "1500", "name": "Vlan20", "operstatus": "up", "speed": "1000000000"}, "40": {"adminstatus": "up", "description": "", "ifindex": "40", "mac": "0024f7dd7742", "mtu": "1500", "name": "Vlan40", "operstatus": "up", "speed": "1000000000"}, "41": {"adminstatus": "up", "description": "", "ifindex": "41", "mac": "0024f7dd7743", "mtu": "1500", "name": "Vlan41", "operstatus": "up", "speed": "1000000000"}, "5001": {"adminstatus": "up", "description": "", "ifindex": "5001", "mac": "000000000000", "mtu": "1500", "name": "Port-channel1", "operstatus": "down", "speed": "10000000"}}, "ansible_syscontact": "support", "ansible_sysdescr": "Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 15.0(2)SE4, RELEASE SOFTWARE (fc1)\r\nTechnical Support: http://www.cisco.com/techsupport\r\nCopyright (c) 1986-2013 by Cisco Systems, Inc.\r\nCompiled Wed 26-Jun-13 02:49 by prod_rel_team", "ansible_syslocation": "NS2903", "ansible_sysname": "NS2903-ASW-01.int.ogenstad.com", "ansible_sysobjectid": "1.3.6.1.4.1.9.1.799", "ansible_sysuptime": "24143432"}, "changed": false}

PLAY [printers] ***************************************************************

TASK: [Get SNMP information from printers] ************************************
ok: [172.29.51.2] => {"ansible_facts": {"ansible_all_ipv4_addresses": ["127.0.0.1", "172.29.51.2"], "ansible_interfaces": {"1": {"adminstatus": "up", "ifindex": "1", "mac": "", "mtu": "1500", "name": "LOOPBACK", "operstatus": "up", "speed": "0"}, "2": {"adminstatus": "up", "ifindex": "2", "mac": "001a4b1a1e7c", "mtu": "1500", "name": "NetDrvr", "operstatus": "up", "speed": "10000000"}}, "ansible_syscontact": "", "ansible_sysdescr": "HP ETHERNET MULTI-ENVIRONMENT", "ansible_syslocation": "", "ansible_sysname": "NPI1A1E7C", "ansible_sysobjectid": "1.3.6.1.4.1.11.1", "ansible_sysuptime": "310355"}, "changed": false}

PLAY RECAP ********************************************************************
172.29.50.3                : ok=1    changed=0    unreachable=0    failed=0
172.29.51.2                : ok=1    changed=0    unreachable=0    failed=0

patrick@srv-master-1:~/play-ansible$

An example template would look like this:
{% for host in groups['snmp'] %}
---
host: {{ hostvars[host].inventory_hostname }}
sysdescr: {{ hostvars[host].ansible_sysdescr }}
sysobjectid: {{ hostvars[host].ansible_sysobjectid }}
syscontact: {{ hostvars[host].ansible_syscontact }}
sysname: {{ hostvars[host].ansible_sysname }}
syslocation: {{ hostvars[host].ansible_syslocation }}
ipaddresses: {% for ip in hostvars[host].ansible_all_ipv4_addresses %}
             {{ ip }}
{% endfor %}
interfaces:
{% for interface in hostvars[host].ansible_interfaces %}
 name: {{ hostvars[host].ansible_interfaces[interface].name }}
 mac: {{ hostvars[host].ansible_interfaces[interface].mac }}
{% endfor %}
all addresses: {{ hostvars[host].ansible_all_ipv4_addresses }}

{% endfor %}

Again, thanks for your comments!

Best regards
Patrick

Ps. As per our Twitter discussion I sent a post to the dev-list about the pull request. But I guess it's stuck in moderation.
Reply all
Reply to author
Forward
0 new messages