CiscoDevNet / ansible-aci

Cisco ACI Ansible Collection
https://galaxy.ansible.com/cisco/aci
GNU General Public License v3.0
143 stars 97 forks source link

aci_snmp_user Auth Types Posting Incorrectly #573

Closed aj-cruz closed 10 months ago

aj-cruz commented 11 months ago

Community Note

Description

Affected Module Name(s):

APIC version and APIC Platform

Collection versions

Output/ Error message

failed: [APIC1 -> localhost] (item=User 'snmpuser' for SNMP Policy 'MySNMP_Pol') => {"ansible_loop_var": "item", "changed": false, "error": {"code": "120", "text": "unknown property value hmac-hmac-sha2-512, name authType, class snmpUserP [(Dn0)] Dn0=uni/fabric/snmppol-MySNMP_Pol/user-snmpuser, "}, "item": [{"administratively_enabled": true, "client_group_profiles": [{"client_entries": [{"address": "10.9.9.1", "name": "SolarWinds1"}, {"address": "10.9.9.2", "name": "SolarWinds2"}], "description": "A Client Group Description", "management_epg": "default", "name": "MyClientGroup"}], "community_policies": [{"community": "mysnmpcommunity", "description": "Some Description"}, {"community": "mysnmpcommunitytoo", "description": "Some Other Description"}], "description": "POD1 SNMP Policy", "name": "MySNMP_Pol", "snmp_contact": "AJ Cruz (aj.cruz@adomain.com)", "snmp_location": "Kerrville, TX", "trap_forward_servers": [{"address": "10.9.9.1", "port": 162}, {"address": "10.9.9.2", "port": 162}]}, {"authorization_key": "keykeykey", "authorization_type": "hmac-sha2-512", "enable_aes_128_privacy": true, "privacy_key": "keykeykey", "user": "snmpuser"}], "msg": "APIC Error 120: unknown property value hmac-hmac-sha2-512, name authType, class snmpUserP [(Dn0)] Dn0=uni/fabric/snmppol-MySNMP_Pol/user-snmpuser, ", "status": -1}

Expected Behavior

*Payload posts with Auth Type property value: hmac-sha2-512

Actual Behavior

*Payload posts with Auth Type property value: hmac-hmac-sha2-512

Playbook tasks to Reproduce

- name: Add SNMPv3 Users to SNMP Policies
  cisco.aci.aci_snmp_user:
    <<: *apic_login
    state: present
    policy: MySNMP_Pol
    name: Tenant1
    auth_type: hmac-sha2-512
    auth_key: keykeykey
    privacy_type: aes-128
    privacy_key: keykeykey
  delegate_to: localhost

Important Factoids

References

akinross commented 10 months ago

Hi @aj-cruz,

I just tried to recreate your issue on 5.2(7f) APIC and do not have this double prepend of hmac- error. Also in our tests that all pass we run the code on 4.2(7s), Version 5.2(7g), and Version 6.0(2h). Could you provide some more verbose logging?

aj-cruz commented 10 months ago

@akinross Sorry I'm not sure what happened, but it's working now. I've since re-factored my playbook to use listify instead of nested loops and in doing that pulled and re-built the collection from source. Sorry to waste your time on that, thanks for checking.

aj-cruz commented 10 months ago

Actually, I might still have a problem with it though might be a different problem. Now the task is posting but has an idempotency problem. Lemme do some digging and get back...

aj-cruz commented 10 months ago

Confirmed the task shows a change every time I run the playbook. Here's my task:

- name: Add SNMPv3 Users to SNMP Policies
  cisco.aci.aci_snmp_user:
    <<: *apic_login
    state: present
    policy: MySNMP_Pol
    name: snmpuser1
    auth_type: hmac-sha2-512
    auth_key: keykeykey
    privacy_type: aes-128
    privacy_key: keykeykey
  delegate_to: localhost

If I do it via aci_rest it doesn't show a change after the first run:

- name: Add SNMPv3 Users to SNMP Policies
  cisco.aci.aci_rest:
    <<: *apic_login
    path: /api/node/mo/uni/fabric/snmppol-MySNMP_Pol/user-snmpuser1.json
    method: post
    content:
      snmpUserP:
        attributes:
          dn: "uni/fabric/snmppol-MySNMP_Pol/user-snmpuser1"
          name: snmpuser1
          privType: aes-128
          privKey: keykeykey
          authType: hmac-sha2-512
          authKey: keykeykey
          rn: user-snmpuser1
          status: created,modified
  delegate_to: localhost

Here's the verbose output of the task:

TASK [apic_fabric_policies : Add SNMPv3 Users to SNMP Policies] *******************************************************************************************
task path: /home/aj/projects/ansible-labs/basic-apic/roles/apic_fabric_policies/tasks/policies_pod.yml:191
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: aj
<localhost> EXEC /bin/sh -c 'echo ~aj && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/aj/.ansible/tmp `"&& mkdir "` echo /home/aj/.ansible/tmp/ansible-tmp-1704728257.8934727-13878-119087577592905 `" && echo ansible-tmp-1704728257.8934727-13878-119087577592905="` echo /home/aj/.ansible/tmp/ansible-tmp-1704728257.8934727-13878-119087577592905 `" ) && sleep 0'
Using module file /home/aj/.ansible/collections/ansible_collections/cisco/aci/plugins/modules/aci_snmp_user.py
<localhost> PUT /home/aj/.ansible/tmp/ansible-local-13845i6_wmd7y/tmp0yis534b TO /home/aj/.ansible/tmp/ansible-tmp-1704728257.8934727-13878-119087577592905/AnsiballZ_aci_snmp_user.py
<localhost> EXEC /bin/sh -c 'chmod u+x /home/aj/.ansible/tmp/ansible-tmp-1704728257.8934727-13878-119087577592905/ /home/aj/.ansible/tmp/ansible-tmp-1704728257.8934727-13878-119087577592905/AnsiballZ_aci_snmp_user.py && sleep 0'
<localhost> EXEC /bin/sh -c '/home/aj/.pyenv/versions/3.11.4/envs/ansible-aci/bin/python3.11 /home/aj/.ansible/tmp/ansible-tmp-1704728257.8934727-13878-119087577592905/AnsiballZ_aci_snmp_user.py && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /home/aj/.ansible/tmp/ansible-tmp-1704728257.8934727-13878-119087577592905/ > /dev/null 2>&1 && sleep 0'
changed: [APIC1 -> localhost] => {
    "changed": true,
    "current": [
        {
            "snmpUserP": {
                "attributes": {
                    "annotation": "orchestrator:ansible",
                    "authType": "hmac-sha2-512",
                    "descr": "",
                    "dn": "uni/fabric/snmppol-MySNMP_Pol/user-snmpuser1",
                    "name": "snmpuser1",
                    "nameAlias": "",
                    "privType": "aes-128",
                    "userdom": ":all:"
                }
            }
        }
    ],
    "invocation": {
        "module_args": {
            "annotation": "orchestrator:ansible",
            "auth_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "auth_type": "hmac-sha2-512",
            "certificate_name": null,
            "description": null,
            "host": "192.168.253.2",
            "name": "snmpuser1",
            "output_level": "normal",
            "output_path": null,
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "policy": "MySNMP_Pol",
            "port": null,
            "privacy_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "privacy_type": "aes-128",
            "private_key": null,
            "protocol": "https",
            "state": "present",
            "timeout": null,
            "use_proxy": false,
            "use_ssl": null,
            "username": "admin",
            "validate_certs": false
        }
    },
    "mo": {
        "snmpUserP": {
            "attributes": {
                "annotation": "orchestrator:ansible",
                "authKey": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "authType": "hmac-sha2-512",
                "dn": "uni/fabric/snmppol-MySNMP_Pol/user-snmpuser1",
                "name": "snmpuser1",
                "privKey": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "privType": "aes-128"
            }
        }
    }
}

PLAY RECAP ************************************************************************************************************************************************
APIC1                      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
akinross commented 10 months ago

Hi @aj-cruz,

Currently this is expected behaviour due to this class having protected properties (auth_key and privacy_key) that are not being returned in the GET request. Let me explain a bit more the difference in implementation for regular modules versus the aci_rest module.

All regular modules should work with the following steps for configuration applies (state=present):

  1. Create URL
  2. GET existing configuration
  3. Construct payload
  4. Construct configuration difference between retrieved configuration in step 2 and the constructed payload in step 3
  5. POST this difference, config is only posted when there is remaining config after the difference construction in step 4
  6. GET existing configuration (changed by POST) to display the full current configuration

For the aci_rest module these steps for configuration applies (method=post) are:

  1. Construct payload (input defines the exact payload)
  2. Create URL a. Determine if modified properties should be returned (rsp_subtree_preserve argument defines this behaviour). Where default behaviour is to append ?rsp-subtree=modified to the path when method is not a GET operation.
  3. POST payload
  4. Determine if changed from returned imdata (changed can only be set to true when ?rsp-subtree=modified is appended to url, because imdata in response can then be non-empty list)

As you can see there are a few differences:

  1. The payload construction, user input in aci_rest module versus calculated difference in regular modules
  2. The url construction, appending of ?rsp-subtree=modified in the aci_rest module
  3. When applying configuration the aci_rest module always does a single POST operation, while regular resources do a GET, POST (only if there is a config difference), and another GET operation

Getting back to the issue as to why the aci_snmp_user is not idempotent. This is because of the payload construction in step 4. When the configuration difference is constructed with the GET response and the user provided arguments in the module, there will always be a difference because of the protected properties (auth_key and privacy_key) which are not returned in the GET response. So with every execution of the task with state=present the module will execute a POST operation and thus the changed output is always set to true.

The aci_rest module on the other hand, will execute the POST request but depending on the rsp_subtree_preserve=false and can have a response with imdata list containing the modified attributes. Depending on this response changed value will reflected in the output.

I can have a discussion in our team to see if this is something that we could adjust.

aj-cruz commented 10 months ago

@akinross Thanks for the explanation, I appreciate it.