aruba/aos-switch-ansible-collection

arubaoss_ntp.py - Query to REST API for DNS settings returns only two servers, arubaoss_ntp.py function expects 4

Closed this issue · 3 comments

  • Ansible version :
ansible [core 2.12.5]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/christophe/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/christophe/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/christophe/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/christophe/.local/bin/ansible
  python version = 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0]
  jinja version = 3.0.3
  libyaml = True
  • Collection version arubanetworks.aos_switch 1.5.0
  • Switch info :
    • model : J9783A
    • Software revision : YB.16.11.0008
    • ROM Version : YB.15.10
  • Switch configuration
    • Default (factory)
    • IP and DNS config obtained by DHCP
  • Task :
- name: configure ntp server
 arubanetworks.aos_switch.arubaoss_ntp:
   provider: "{{ hpe_provider }}"
   command: "config_ntp_ipv4addr"
   ntp_ip4addr: "{{ device_ntp_server }}"
   mode: "iburst"
  • Vars (separated) :
# role vars
device_ntp_server: 0.fr.pool.ntp.org

# group vars
ansible_user: admin
ansible_password: "{{ aos_test_adm_pwd }}"
ansible_connection: local
ansible_network_os: arubanetworks.aos_switch.arubaos

hpe_provider:
  use_ssl: True

Hey !

I've found an issue with the way the arubaoss_ntp module tries to handle the case where a FQDN is provided via ntp_ip4addr instead of an IP.

As per the following line :

check_presence = get_config(module, "/dns")

it queries the REST API for DNS settings.

I've temporarily added a print to get the json output of the REST API call, which is the following : {"uri":"/dns","dns_config_mode":"DCM_DHCP","server_1":{"version":"IAV_IP_V4","octets":"192.168.0.1"},"server_2":null,"dns_domain_names":[]}

As specified above, the DNS config is obtained via DHCP and only one DNS server is configured on the switch. There is a server_1 and a server_2 (set to null) returned by the API query. However, there is no additional keys for server_3 and server_4. Yet, in this line :

value = [newdata["server_1"], newdata["server_2"], newdata["server_3"],

They are expected in the output. As a result, handling the expected OSError due to ntp_ip4addr being a FQDN instead of an IP subsequently creates a KeyError which is not handled, because it expects more keys from the API response.

Error stack :

An exception occurred during task execution. To see the full traceback, use -vvv. The error was: TypeError: Value of unknown type: <class 'KeyError'>, 'server_3'
fatal: [192.168.0.31]: FAILED! => changed=false
  module_stderr: |-
    Traceback (most recent call last):
      File "/tmp/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload_neoq1tx_/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload.zip/ansible_collections/arubanetworks/aos_switch/plugins/modules/arubaoss_ntp.py", line 516, in config_ntp_ipv4addr
    OSError: illegal IP address string passed to inet_aton

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
      File "/tmp/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload_neoq1tx_/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload.zip/ansible_collections/arubanetworks/aos_switch/plugins/modules/arubaoss_ntp.py", line 719, in run_module
      File "/tmp/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload_neoq1tx_/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload.zip/ansible_collections/arubanetworks/aos_switch/plugins/modules/arubaoss_ntp.py", line 521, in config_ntp_ipv4addr
    KeyError: 'server_3'

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
      File "/home/christophe/.ansible/tmp/ansible-tmp-1673531210.5883613-52349-239102881802807/AnsiballZ_arubaoss_ntp.py", line 107, in <module>
        _ansiballz_main()
      File "/home/christophe/.ansible/tmp/ansible-tmp-1673531210.5883613-52349-239102881802807/AnsiballZ_arubaoss_ntp.py", line 99, in _ansiballz_main
        invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
      File "/home/christophe/.ansible/tmp/ansible-tmp-1673531210.5883613-52349-239102881802807/AnsiballZ_arubaoss_ntp.py", line 47, in invoke_module
        runpy.run_module(mod_name='ansible_collections.arubanetworks.aos_switch.plugins.modules.arubaoss_ntp', init_globals=dict(_module_fqn='ansible_collections.arubanetworks.aos_switch.plugins.modules.arubaoss_ntp', _modlib_path=modlib_path),
      File "/usr/lib/python3.10/runpy.py", line 224, in run_module
        return _run_module_code(code, init_globals, run_name, mod_spec)
      File "/usr/lib/python3.10/runpy.py", line 96, in _run_module_code
        _run_code(code, mod_globals, init_globals,
      File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
        exec(code, run_globals)
      File "/tmp/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload_neoq1tx_/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload.zip/ansible_collections/arubanetworks/aos_switch/plugins/modules/arubaoss_ntp.py", line 733, in <module>
      File "/tmp/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload_neoq1tx_/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload.zip/ansible_collections/arubanetworks/aos_switch/plugins/modules/arubaoss_ntp.py", line 729, in main
      File "/tmp/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload_neoq1tx_/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload.zip/ansible_collections/arubanetworks/aos_switch/plugins/modules/arubaoss_ntp.py", line 723, in run_module
      File "/tmp/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload_neoq1tx_/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload.zip/ansible/module_utils/basic.py", line 1538, in fail_json
      File "/tmp/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload_neoq1tx_/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload.zip/ansible/module_utils/basic.py", line 1511, in _return_formatted
      File "/tmp/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload_neoq1tx_/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload.zip/ansible/module_utils/common/parameters.py", line 890, in remove_values
      File "/tmp/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload_neoq1tx_/ansible_arubanetworks.aos_switch.arubaoss_ntp_payload.zip/ansible/module_utils/common/parameters.py", line 461, in _remove_values_conditions
    TypeError: Value of unknown type: <class 'KeyError'>, 'server_3'
  module_stdout: |-
    b'{"uri":"/dns","dns_config_mode":"DCM_DHCP","server_1":{"version":"IAV_IP_V4","octets":"192.168.0.1"},"server_2":null,"dns_domain_names":[]}'
  msg: |-
    MODULE FAILURE
    See stdout/stderr for the exact error
  rc: 1

Note module_stdout returns stuff because I added a print() to get the REST API response. It wouldn't otherwise.

I hope I didn't get anything wrong and it's useful ! Thanks for the work

Hi @SalutAToi

Nice analysis ! do you plan to push a fix ?

Hi @SalutAToi

Nice analysis ! do you plan to push a fix ?

Thanks ! Can do as I'd need it, but I can't find any documentation on the format and condition of the response from the REST API, just the JSON schema reference specifying what you can do with /dns :
image
(from ArubaOS-Switch REST API and JSON Schema Reference Guide 16.04)

Do you have info on that ? I doubt the code is public ?

In any case, if I understand the code correctly, it's just trying to figure out if there is a configured DNS on the system to resolve the NTP server ? If I understand it right and I'm not missing something, if we do not have a consistent amount of server_x keys, there'd be 2 options I can work on :

  • just check for existence of server_1 and check it's not null
  • from the response, retrieve all keys and values for any keys named server_x (using re, I guess), and check that at least one of them is not null

Salut Christophe,

You can look https://asp.arubanetworks.com/downloads/software/RmlsZTo3YTRkMzZjOC1iMDY3LTExZTgtOGZjZC1iMzIxMDI0YzhlNDg%3D for get more info about format (there is json file)