nautobot / nautobot-ansible

Ansible Collection for managing Nautobot Data
https://nautobot-ansible.readthedocs.io/en/latest/
GNU General Public License v3.0
40 stars 31 forks source link

GraphQL inventory plugin error: 'NoneType' object has no attribute 'get' #347

Closed mamullen13316 closed 2 months ago

mamullen13316 commented 2 months ago
ISSUE TYPE
SOFTWARE VERSIONS
pynautobot

pynautobot==2.1.1

Ansible:

ansible==9.5.1 ansible-core==2.16.6

Nautobot:

2.2.2

Collection:

networktocode.nautobot 5.2.0

SUMMARY

After upgrading from version 5.1.1 to 5.2.0, the below error 'NoneType' object has no attribute 'get' is displayed when using the gql_inventory plugin. It appears to be trying to invoke a get after retrieving the platform on the device object here:

File "/Users/root/.ansible/collections/ansible_collections/networktocode/nautobot/plugins/inventory/gql_inventory.py", line 265, in add_ansible_platform
    if device.get("platform", {}).get("napalm_driver")

We don't have anything populated in the platform field of our devices, so that initial query for device.get("platform") does return None. We'll need to add that soon anyway to start using the Golden Config Plugin.

STEPS TO REPRODUCE

INVENTORY: inv.yml

plugin: networktocode.nautobot.gql_inventory
api_endpoint: https://{{ nautobot_url}}
validate_certs: False

query:
  devices:
    filters:
      manufacturer: "Cisco"

PLAYBOOK: testinv.yml

- name: test
  hosts: all
  gather_facts: false

  tasks:
    - debug:
        var: inventory_hostname
      delegate_to: localhost

ansible-playbook -i inv.yml testinv.yml -vvvv

EXPECTED RESULTS

Using 5.1.1...

ansible-playbook [core 2.16.6]
  config file = /Users/root/ansible.cfg
  configured module search path = ['/Users/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/root/.pyenv/versions/3.11.1/envs/ansible/lib/python3.11/site-packages/ansible
  ansible collection location = /Users/root/.ansible/collections:/usr/share/ansible/collections
  executable location = /Users/root/.pyenv/versions/ansible/bin/ansible-playbook
  python version = 3.11.1 (main, Jan 18 2023, 22:40:43) [Clang 14.0.0 (clang-1400.0.29.202)] (/Users/root/.pyenv/versions/3.11.1/envs/ansible/bin/python3.11)
  jinja version = 3.1.3
  libyaml = True
Using /Users/root/ansible.cfg as config file
setting up inventory plugins
Loading collection ansible.builtin from
host_list declined parsing /Users/root/inv2.yml as it did not pass its verify_file() method
script declined parsing /Users/root/inv2.yml as it did not pass its verify_file() method
Loading collection networktocode.nautobot from /Users/root/.ansible/collections/ansible_collections/networktocode/nautobot
Using inventory plugin 'ansible_collections.networktocode.nautobot.plugins.inventory.gql_inventory' to process inventory source '/Users/root/inv2.yml'
GraphQL query:
query {
  devices (manufacturer: "Cisco") {
    name
    primary_ip4 {
      host
    }
    platform {
      napalm_driver
    }
  }
  virtual_machines {
    name
    primary_ip4 {
      host
    }
    platform {
      name
    }
  }
}
JSON response: ...snip
ACTUAL RESULTS

Using 5.2.0...

ansible-playbook testinv.yml -i inv.yml -vvvv
ansible-playbook [core 2.16.6]
  config file = /Users/root/ansible.cfg
  configured module search path = ['/Users/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/root/.pyenv/versions/3.11.1/envs/ansible/lib/python3.11/site-packages/ansible
  ansible collection location = /Users/root/.ansible/collections:/usr/share/ansible/collections
  executable location = /Users/root/.pyenv/versions/ansible/bin/ansible-playbook
  python version = 3.11.1 (main, Jan 18 2023, 22:40:43) [Clang 14.0.0 (clang-1400.0.29.202)] (/Users/root/.pyenv/versions/3.11.1/envs/ansible/bin/python3.11)
  jinja version = 3.1.3
  libyaml = True
Using /Users/root/ansible.cfg as config file
setting up inventory plugins
Loading collection ansible.builtin from
host_list declined parsing /Users/root/inv2.yml as it did not pass its verify_file() method
script declined parsing /Users/root/inv2.yml as it did not pass its verify_file() method
Loading collection networktocode.nautobot from /Users/root/.ansible/collections/ansible_collections/networktocode/nautobot
Using inventory plugin 'ansible_collections.networktocode.nautobot.plugins.inventory.gql_inventory' to process inventory source '/Users/root/inv.yml'
GraphQL query:
query {
  devices (manufacturer: "Cisco") {
    name
    primary_ip4 {
      host
    }
    platform {
      napalm_driver
    }
  }
  virtual_machines {
    name
    primary_ip4 {
      host
    }
    platform {
      name
    }
  }
}
JSON response: ...output omitted

[WARNING]:  * Failed to parse /Users/root/inv2.yml with auto plugin: 'NoneType' object has no attribute 'get'
  File "/Users/root/.pyenv/versions/3.11.1/envs/ansible/lib/python3.11/site-packages/ansible/inventory/manager.py", line 293, in parse_source
    plugin.parse(self._inventory, self._loader, source, cache=cache)
  File "/Users/root/.pyenv/versions/3.11.1/envs/ansible/lib/python3.11/site-packages/ansible/plugins/inventory/auto.py", line 59, in parse
    plugin.parse(inventory, loader, path, cache=cache)
  File "/Users/root/.ansible/collections/ansible_collections/networktocode/nautobot/plugins/inventory/gql_inventory.py", line 429, in parse
    self.main()
  File "/Users/root/.ansible/collections/ansible_collections/networktocode/nautobot/plugins/inventory/gql_inventory.py", line 392, in main
    self.add_ansible_platform(device)
  File "/Users/root/.ansible/collections/ansible_collections/networktocode/nautobot/plugins/inventory/gql_inventory.py", line 265, in add_ansible_platform
    if device.get("platform", {}).get("napalm_driver"):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PadillaNavyMil commented 2 months ago

I have been encountering the exact same issue.

To add a little to this post, I get this added line to the end of the JSON response: toml declined parsing InventoryFile.yml as it did not pass its verify_file() method

Only started to get this issue recently when v5.2.0 went live.

joewesch commented 2 months ago

Hello @mamullen13316, thanks for the report. I have been unable to reproduce this using the demo site, can you confirm it is also broken with the following inventory file?

plugin: networktocode.nautobot.gql_inventory
api_endpoint: https://demo.nautobot.com
token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
query:
  devices:
    filters:
      manufacturer: "Cisco"

~As for your initial assessment regarding .get() returning None, if "platform" is not a key in the device dict then device.get("platform", {}) should return what is after the comma (e.g. an empty dictionary) instead of None. So, it sounds like device in this case is instead None.~

Edit: I apologize, a correction to my previous statement as I understand the problem now. The key "platform" is indeed in the device dictionary but the value of platform is None. :iblameken:

mamullen13316 commented 2 months ago

Hi @joewesch, The demo environment works fine for me as well on 5.2.0. The demo environment also appears to have the platform field populated. Here's a device from the demo environment:

 {'name': 'wee-n9k-02.nautobot.com', 'primary_ip4': {'host': '68.170.147.169'}, 'platform': {'napalm_driver': 'nxos'}}

Here's one from our environment:

{'name': 'use1-vpn-1a', 'primary_ip4': None, 'platform': None}

Haha, just noticed your :iblameken: :) Looks like we are on the same page now, let me know if you need any more info or testing.