Advanced filtering
In this tutorial we are going to see how to use the F
object to do advanced filtering of hosts. Let’s start by initiating nornir and looking at the inventory:
[1]:
from nornir import InitNornir
from nornir.core.filter import F
nr = InitNornir(config_file="advanced_filtering/config.yaml")
[2]:
%cat advanced_filtering/inventory/hosts.yaml
---
cat:
groups:
- terrestrial
- mammal
data:
domestic: true
diet: omnivore
additional_data:
lifespan: 17
famous_members:
- garfield
- felix
- grumpy
bat:
groups:
- terrestrial
- mammal
data:
domestic: false
fly: true
diet: carnivore
additional_data:
lifespan: 15
famous_members:
- batman
- count chocula
- nosferatu
eagle:
groups:
- terrestrial
- bird
data:
domestic: false
diet: carnivore
additional_data:
lifespan: 50
famous_members:
- thorondor
- sam
canary:
groups:
- terrestrial
- bird
data:
domestic: true
diet: herbivore
additional_data:
lifespan: 15
famous_members:
- tweetie
caterpillaer:
groups:
- terrestrial
- invertebrate
data:
domestic: false
diet: herbivore
additional_data:
lifespan: 1
famous_members:
- Hookah-Smoking
octopus:
groups:
- marine
- invertebrate
data:
domestic: false
diet: carnivore
additional_data:
lifespan: 1
famous_members:
- sharktopus
[3]:
%cat advanced_filtering/inventory/groups.yaml
---
mammal:
data:
reproduction: birth
fly: false
bird:
data:
reproduction: eggs
fly: true
invertebrate:
data:
reproduction: mitosis
fly: false
terrestrial: {}
marine: {}
As you can see we have built ourselves a collection of animals with different properties. The F
object let’s you access the magic methods of each types by just prepeding two underscores and the the name of the magic method. For instance, if you want to check if a list contains a particular element you can just prepend __contains
. Let’s use this feature to retrieve all the animals that belong to the group bird
:
[4]:
birds = nr.filter(F(groups__contains="bird"))
print(birds.inventory.hosts.keys())
dict_keys(['eagle', 'canary'])
We can also invert the F
object by prepending ~
:
[5]:
not_birds = nr.filter(~F(groups__contains="bird"))
print(not_birds.inventory.hosts.keys())
dict_keys(['cat', 'bat', 'caterpillaer', 'octopus'])
We can also combine F
objects and perform AND and OR operations with the symbols &
and |
(pipe) respectively:
[6]:
domestic_or_bird = nr.filter(F(groups__contains="bird") | F(domestic=True))
print(domestic_or_bird.inventory.hosts.keys())
dict_keys(['cat', 'eagle', 'canary'])
[7]:
domestic_mammals = nr.filter(F(groups__contains="mammal") & F(domestic=True))
print(domestic_mammals.inventory.hosts.keys())
dict_keys(['cat'])
As expected, you can combine all of the symbols:
[8]:
flying_not_carnivore = nr.filter(F(fly=True) & ~F(diet="carnivore"))
print(flying_not_carnivore.inventory.hosts.keys())
dict_keys(['canary'])
You can also access nested data the same way you access magic methods, by appending two underscores and the data you want to access. You can keep building on this as much as needed and even access the magic methods of the nested data. For instance, let’s get the animals that have a lifespan greater or equal than 15:
[9]:
long_lived = nr.filter(F(additional_data__lifespan__ge=15))
print(long_lived.inventory.hosts.keys())
dict_keys(['cat', 'bat', 'eagle', 'canary'])
There are two extra facilities to help you working with lists; any
and all
. Those facilities let’s you send a list of elements and get the objects that has either any of the members or all of them. For instance:
[10]:
marine_and_invertebrates = nr.filter(F(groups__all=["marine", "invertebrate"]))
print(marine_and_invertebrates.inventory.hosts.keys())
dict_keys(['octopus'])
[11]:
bird_or_invertebrates = nr.filter(F(groups__any=["bird", "invertebrate"]))
print(bird_or_invertebrates.inventory.hosts.keys())
dict_keys(['eagle', 'canary', 'caterpillaer', 'octopus'])