Closed dejantep closed 4 years ago
Going to assume you are talking about the NetBoxInventory2 and that you mean Nornir inventory filters. Since those details are missing from your report.
NetBoxInventory2 stores the complete JSON reponse from the NetBox devices API endpoint into the data attribute of a Nornir host. "role" doesn't exist in the data model of NetBox, NetBox's data model refers to this as a "device_role". You can find an example here https://github.com/wvandeun/nornir_netbox/blob/070c09282f341ae43907e068544668699310998e/tests/NetBoxInventory2/2.8.9/expected.json#L20
To filter for that particular device_role you would need to use an F object filter, since we want to filter on data that is nested in the device_role https://nornir.readthedocs.io/en/latest/tutorial/inventory.html#Advanced-filtering
You can filter the inventory for the device_role with name "Router" like this:
nr.inventory.filter(F(device_role__name="Router"))
or slug rt:
nr.inventory.filter(F(device_role__slug="rt"))
thank you so much for this clarification. i'm new to all this and I tried some different approaches with F object filter but always got an empty dict. Now it works great. From what i understand about "Role" is that you can call it from config,yml under "filter_parameters" of your plugin. This is what i used to do prior to this.
"filter_parameters": {
"role": "distribution",
},
Yes, you can still do that through the Nornir configuration file or when you instantiate a Nornir object with InitNornir()
Somewhat related to this issue, in Netbox >2.9 the tags on devices are now stored as an array of dictionaries, instead of a simple array of strings, do you have any examples how to use F object to filter on tags such as:
nrRun = nr.filter(F(device_type__manufacturer__name="Cisco") & F(tags__slug__contains="switch-stack"))
The line above does not work with 2.9 version of NB, since tags is an array of dictionaries
example data:
nrRun.inventory.hosts['zzzzzzzz'].data.get('tags')
[{'color': '9e9e9e', 'id': 5, 'name': 'switch-stack', 'slug': 'switch-stack', 'url': 'https://xxxxxx/tags/5/'}]
Probably missing something simple, any help would be greatly appreciated.
I have an ugly workaround that uses existing transform function to flatten the tags back to a simple list so that my filter object can continue to work, but I was hoping to figure out a cleaner way in the future:
Nornir 3.0 changed the transform as well to make it much simpler (I think) https://github.com/twin-bridges/nornir_course/blob/master/nornir3_changes.md#transform-function-is-now-an-entry-point
for host in nr.inventory.hosts.values():
adapt_host_data(host)
def adapt_host_data(host):
tag_list = host.data.get('tags')
tags=[]
for tag in tag_list:
tags.append(tag.get('slug'))
host.data['tags']=tags
Not sure if F filters are still an option in that case. It should be possible if you know the exact contents of the tag dictionary you are looking for, which doesn't seem to be to practical.
nr.filter(F(tags__contains={'color': '9e9e9e', 'id': 5, 'name': 'switch-stack', 'slug': 'switch-stack', 'url': 'https://xxxxxx/tags/5/'}))
But I could be missing some functionality that I'm not aware off.
Alternative approaches:
def my_filter(host: Host):
value_to_search_for = "something"
return value_to_search_for in[ tag.name for tag in host.get("tags")]
nr.filter(filter_func=my_filter)
- use filter_parameters
Not sure if F filters are still an option in that case. It should be possible if you know the exact contents of the tag dictionary you are looking for, which doesn't seem to be to practical.
nr.filter(F(tags__contains={'color': '9e9e9e', 'id': 5, 'name': 'switch-stack', 'slug': 'switch-stack', 'url': 'https://xxxxxx/tags/5/'}))
But I could be missing some functionality that I'm not aware off.
This method would work, but way too fragile as tag colors can change, for example, and it would break the code.
Alternative approaches:
* use a filter function
def my_filter(host: Host): value_to_search_for = "something" return value_to_search_for in[ tag.name for tag in host.get("tags")] nr.filter(filter_func=my_filter)
This is probably a much cleaner way to handle this, I will probably adopt this, however for compatibility reason in my scripts, I may stick to the transform function library to flatten the tags attribute for now. Just wondering if we should look at potentially adding an option to flatten it as part of the inventory plugin. If you are open I can look into creating a PR.
* use filter_parameters
We already use some of that, but that is also a great suggestion.
Just wondering if we should look at potentially adding an option to flatten it as part of the inventory plugin. If you are open I can look into creating a PR.
Not convinced that we need to offer an option to flatten this. The whole point of NetBoxInventory2 is to have more relevant data available in the data attribute of a Nornir host. There is a lot of benefit in keeping the data structure as close to the original data structure returned by the NetBox API.
Just wondering if we should look at potentially adding an option to flatten it as part of the inventory plugin. If you are open I can look into creating a PR.
Not convinced that we need to offer an option to flatten this. The whole point of NetBoxInventory2 is to have more relevant data available in the data attribute of a Nornir host. There is a lot of benefit in keeping the data structure as close to the original data structure returned by the NetBox API.
After thinking about it more, I tend to agree with your statement and using filter_parameters should be a much cleaner way to filter out the results.
How would i go about to filter inventory on data that Netbox presents?
I can see "name", "platform", "primary_ip" in your code but i was looking for "role" as in first version