Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hostname Attribute error when NetBoxInventory2 plugin in use #779

Open
ignatievia opened this issue Feb 17, 2022 · 11 comments
Open

hostname Attribute error when NetBoxInventory2 plugin in use #779

ignatievia opened this issue Feb 17, 2022 · 11 comments

Comments

@ignatievia
Copy link

Similar issue was described here - #279
In my case primary_ip is defined in Netbox and populates 'hostname' attribute

print (nr.inventory.hosts["eve_cisco_ios"].hostname)
10.0.10.71
nr = InitNornir(
        inventory={
            "plugin": "NetBoxInventory2",
            "options": {
                "nb_url": NB_URL,
                "nb_token": NB_TOKEN,
                "filter_parameters": filter_params
            }
        }

nr.run(netmiko_send_config, config_commands=commands) gets back error

Traceback (most recent call last):
File "/Users/ivan/project_name/venv/lib/python3.9/site-packages/nornir/core/task.py", line 99, in start
r = self.task(self, **self.params)
File "/Users/ivan/project_name/venv/lib/python3.9/site-packages/nornir_netmiko/tasks/netmiko_send_config.py", line 28, in netmiko_send_config
net_connect = task.host.get_connection(CONNECTION_NAME, task.nornir.config)
File "/Users/ivan/project_name/venv/lib/python3.9/site-packages/nornir/core/inventory.py", line 493, in get_connection
conn = self.get_connection_parameters(connection)
File "/Users/ivan/project_name/venv/lib/python3.9/site-packages/nornir/core/inventory.py", line 427, in get_connection_parameters
r = self._get_connection_options_recursively(connection)
File "/Users/ivan/project_name/venv/lib/python3.9/site-packages/nornir/core/inventory.py", line 456, in _get_connection_options_recursively
sp = g._get_connection_options_recursively(connection)
File "/Users/ivan/project_name/venv/lib/python3.9/site-packages/nornir/core/inventory.py", line 467, in _get_connection_options_recursively
p.hostname = p.hostname if p.hostname is not None else sp.hostname
AttributeError: 'dict' object has no attribute 'hostname'

@ignatievia ignatievia changed the title hostname Attribute error when NetBoxInventory2 plugin is using hostname Attribute error when NetBoxInventory2 plugin in use Feb 17, 2022
@ktbyers
Copy link
Collaborator

ktbyers commented Feb 17, 2022

What does the following show?

for host_obj in nr.inventory.hosts:
    print(host_obj.hostname)

Are there any devices that do not have a hostname?

@ignatievia
Copy link
Author

ignatievia commented Feb 17, 2022

for host_obj in nr.inventory.hosts:
...     print(host_obj.hostname)
...     
Traceback (most recent call last):
  File "<input>", line 2, in <module>
AttributeError: 'str' object has no attribute 'hostname'

while

print (nr.inventory.hosts)
{'eve_cisco_ios': Host: eve_cisco_ios}
print (nr.inventory.hosts["eve_cisco_ios"].hostname)
10.0.10.71

In this particular case there's only 1 device in inventory

@ignatievia
Copy link
Author

May the root of the problem be in object type?

for host_obj in nr.inventory.hosts:
...     print(type(host_obj))    
... 
<class 'str'>
type (nr.inventory.hosts["eve_cisco_ios"])
<class 'nornir.core.inventory.Host'>

@ktbyers
Copy link
Collaborator

ktbyers commented Feb 17, 2022

My error above...so what do you get with this:

for name, host_obj in nr.inventory.hosts.items():
        print(f"{name} -> {host_obj.hostname}")

@ktbyers
Copy link
Collaborator

ktbyers commented Feb 17, 2022

You might need to look at the Python debugger and see what things are at this line 467:

File "/Users/ivan/project_name/venv/lib/python3.9/site-packages/nornir/core/inventory.py", line 467, in _get_connection_options_recursively
p.hostname = p.hostname if p.hostname is not None else sp.hostname

i.e. print out both p and `sp.

@ignatievia
Copy link
Author

for name, host_obj in nr.inventory.hosts.items():
...         print(f"{name} -> {host_obj.hostname}")
...         
eve_cisco_ios -> 10.0.10.71

Below is pycharm screenshot with p and sp variables at the line 467 (sorry, have not found more convenient way to show it)
https://drive.google.com/file/d/1dZV-sxS9xh0pP_4whwfR4uD9htmwmQLl/view?usp=sharing

@dbarrosop
Copy link
Contributor

dbarrosop commented Feb 20, 2022

sp shouldn't be a dict. sp should be a ConnectionOptions object. Whoever is populating defaults.connection_options is doing it wrong.

Fore reference, here is the type definition:

https://github.com/nornir-automation/nornir/blob/develop/nornir/core/inventory.py#L216

and where sp is coming from:

https://github.com/nornir-automation/nornir/blob/develop/nornir/core/inventory.py#L465

However, according to your traceback and debug information sp is a dict.

This is most likely a plugin issue so I'd suggest checking with them.

@davama
Copy link

davama commented Mar 10, 2022

Fyi,

Faced same issue.
Created ticket wvandeun/nornir_netbox#40

thanks

@wvandeun
Copy link
Contributor

wvandeun commented Mar 11, 2022

@dbarrosop
I may have identified the issue, but need more details to properly identify how this is triggered and to be able to confirm it.

The problem is here https://github.com/wvandeun/nornir_netbox/blob/860d2f80e3fd2b2989c33044c560decdd2685cf1/nornir_netbox/plugins/inventory/netbox.py#L47

We try to retrieve the connection_options from the dictionary data, but that key does not exist. The connection options are instead defined in data["data"] instead. The same issue exists on line 66.

These functions were directly copied from Nornir's Simple inventory plugin, so the same issue should also exist in that plugin:

connection_options=_get_connection_options(data.get("connection_options", {})),

The nornir_ansible inventory plugin seems to have the exact same approach as well btw:
https://github.com/carlmontanari/nornir_ansible/blob/d00fa4788bbca5b24a18b9c15ccc6361bd890bd0/nornir_ansible/plugins/inventory/ansible.py#L471 (probably also copied from simple inventory)

If I modify the line to:

        connection_options=_get_connection_options(data.get("data", {}).get("connection_options", {})),

then it seems to work properly

>>> nr.inventory.defaults.connection_options
{'netmiko': <nornir.core.inventory.ConnectionOptions object at 0x107e4aa90>}
>>> nr.inventory.defaults.connection_options.get("netmiko").hostname
"10.10.10.10"

@dbarrosop
Copy link
Contributor

dbarrosop commented Mar 11, 2022

connection_options=_get_connection_options(data.get("data", {}).get("connection_options", {})),

This doesn't look correct though. This would mean that your defaults_dict looks like:

data:
   connection_options:
          ...

And it shouldn't as connection_options is an attribute of Defaults, it doesn't belong inside data . Look at the test file for reference. So I suspect that the issue is simply that the defaults.yaml you are using is wrong.

If I am wrong, I'd suggest you create a branch with a unit test that triggers the issue and I will try to help out but I am confident this is not a nornir issue as we are actively testing this scenario.

@ignatievia
Copy link
Author

Appreciate your help @ktbyers @dbarrosop
The problem was in connection_options population and was fixed this way
nr.inventory.defaults.connection_options["netmiko"] = ConnectionOptions(extras={'device_type': device_type})
Looks like it's a documentation problem cause I've found similar issue by @dmfigol #369

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants