Manipulate cisco snmp user cli data

i’m looking to delete all existing snmp users from a device. the results of ‘show snmp users’ comes back in a format i can’t figure out how to work with. if this data could be converted to a list of dictionaries, 1 dict per user, i could iterate through it but i can’t figure out how to do the conversion. i’m relatively experienced in working with ansible for cisco devices but i have little to no experience in transforming data so please lay it on me nursery school level

devices with no snmp users returns an empty string “”
devices with 1 snmp user return the 6 lines relevant to that user
devices with more than 1 snmp user return an empty string separating the user data

example of 2 users

        "stdout_lines": [
            [
                "User name: EGW",
                "Engine ID: 800000090300D4ADBD347980",
                "storage-type: nonvolatile\t active",
                "Authentication Protocol: SHA",
                "Privacy Protocol: AES128",
                "Group-name: V3Group-authPriv",
                "",
                "User name: snmp-ro",
                "Engine ID: 800000090300D4ADBD347980",
                "storage-type: nonvolatile\t active",
                "Authentication Protocol: SHA",
                "Privacy Protocol: AES128",
                "Group-name: readonly"
            ]
        ],

example of no users:

        "stdout_lines": [
            [
                ""
            ]
        ],

If you have jc installed on the Ansible controller you could use the ini filter with the jc module to convert the standard out into a list of user dictionaries, eg:

- name: Set a fact for the user dictionaries
  ansible.builtin.set_fact:
    users: "{{ var_used_to_register_the_output.stdout | community.general.jc('ini') }}"
  when: var_used_to_register_the_output.stdout_lines | length > 0 

- name: Debug users
  ansible.builtin.debug:
    var: users
  when: users is defined

Or you could use the new ini filter, then once you have the data as JSON it would be easier to transform it — could you provide some examples of what you want to do?

Actually looking at this some more my examples wouldn’t work due to the duplicates, there is the JC ini dupe filter that could be used but I expect it would be better to split the data on the empty line first, I’m not sure how best to do that, I’ll have a ponder…

for an example of what i want to do…i’m looking to delete all snmp users discovered on the device. i really only need the username and group name to do this. if the data were in a list of dicts i would approach it like this…

‘’’

  • name: delete all snmp users
    ios_config:
    lines:
    - “no snmp-server user {{item[‘username’}} {{item[‘group’}} v3”
    with_items: “{{snmp_users}}”
    ‘’’

You should be able to get user data from cisco.ios.ios_facts in an easily parsed list.

I’m not familiar with the structure specifically, but you can look at it with this:

  tasks:
    - name: Get switch facts
      cisco.ios.ios_facts:

    - name: Show facts
      debug:
        var: ansible_network_resources

Based on the code, I suspect the var you’re looking for will be something along these lines: "{{ ansible_network_resources.snmp_server.users }}", which may or may not be undefined when empty.

So something like:

    - name: delete all snmp users
      cisco.ios.ios_config:
        lines:
          - “no snmp-server user {{ item.username }} {{ item.group }} v3”
      loop: "{{ ansible_network_resources.snmp_server.users }}"
      when: ansible_network_resources.snmp_server.users is defined
1 Like

Thanks Caleb. i looked in facts before and didn’t see anything snmp and i’m getting ansible_network_resources as an empty dict. from the documentation it seems i have to call on that explicitly to get the data but everything i try results in some unknown error

  - name: get facts
    ios_facts:
      gather_subset: min
      gather_network_resources: snmp_server
The full traceback is:
  File "/tmp/ansible_ios_facts_payload_85dpnzgl/ansible_ios_facts_payload.zip/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/facts/facts.py", line 134, in get_network_resources_facts
    self._connection, self.ansible_facts, data
  File "/tmp/ansible_ios_facts_payload_85dpnzgl/ansible_ios_facts_payload.zip/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/snmp_server.py", line 87, in populate_facts
    self.sort_list_dicts(objs)
  File "/tmp/ansible_ios_facts_payload_85dpnzgl/ansible_ios_facts_payload.zip/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/snmp_server.py", line 52, in sort_list_dicts
    objs[k] = sorted(objs[k], key=lambda _k: str(_k[p_key[k]]))
  File "/tmp/ansible_ios_facts_payload_85dpnzgl/ansible_ios_facts_payload.zip/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/snmp_server.py", line 52, in <lambda>
    objs[k] = sorted(objs[k], key=lambda _k: str(_k[p_key[k]]))
[WARNING]: ['connection local support for this module is deprecated and will be removed in version 2.14, use connection ansible.netcommon.network_cli']
fatal: [10.60.5.2]: FAILED! => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "invocation": {
        "module_args": {
            "available_network_resources": false,
            "gather_network_resources": [
                "snmp_server"
            ],
            "gather_subset": [
                "min"
            ],
            "provider": {
                "auth_pass": null,
                "authorize": false,
                "host": null,
                "password": null,
                "port": null,
                "ssh_keyfile": null,
                "timeout": null,
                "username": null
            }
        }
    }
}

MSG:

'username'

i’ve tried all kinds of variations of subset and network_resources and all of them fail. mostly with the MSG: ‘username’ but on at least one occasion the MSG was ‘NoneType’ object has no attribute ‘group’

Not sure how, but it seems you’re gathering facts your controller, not the switch.

it is grabbing facts from the switch, not the controller. that is just a warning that i’m using the old method of connection: local which is deprecated and will be removed in a future version. i changed it to connection: network_cli and still get the same results.

Can you share what version of ansible and cisco.ios you’re using?

ansible --version
ansible-galaxy collection list cisco.ios

ansible 2.11.12
cisco.ios 2.6.0

i was in the process of building a new ansible box on the side anyways so i finished up with community package 8.0 and now i’m able to pull the snmp-server data
ansible 2.15.11
cisco.ios 4.5.0

thanks for your help

1 Like

I think this will accomplish what you are looking for:
(includes optional ‘when’ to keep specific users if desired)

---
- name: Just the Facts
  cisco.ios.ios_facts:
    gather_network_resources:
      - snmp_server

- name: "SNMP user cleanup"
  cisco.ios.ios_config:
    lines: "no snmp-server user {{ snmp_user.username }} {{ snmp_user.group }} {{snmp_user.version }}"
  loop:
    "{{ ansible_facts.network_resources.snmp_server.users }}"
  loop_control:
    loop_var: snmp_user
#  when: snmp_user.username not in ['keep_user_1', 'keep_user_2']