Filtering Deep Dive

In this tutorial, we will explore the power of nornir filtering and demonstrate why nornir is a first-class inventory management framework.

This tutorial will demonstrate some common network use-cases and how nornir filtering can be target to target hosts or groups with precision.

Tutorial Inventory

Firstly, let’s start with initialising our nornir inventory.

  1. [1]:
  1. # Import modules
  2. from nornir import InitNornir
  3. from nornir.core.filter import F
  4. # Initialise nornir
  5. nr = InitNornir(config_file="filtering_deep_dive/config.yaml")

Next, let’s look at our tutorial hosts.yaml file. Don’t be overwhelmed by the size of the inventory or the content within as we will explore this in further detail later in the tutorial:

  1. [2]:
  1. %cat filtering_deep_dive/inventory/hosts.yaml
  1. ---
  2. lab-csr-011.lab.norn.local:
  3. hostname: lab-csr-011.lab.norn.local
  4. groups:
  5. - ios
  6. - lab
  7. - mel
  8. data:
  9. mgmt_ip: 10.0.0.16
  10. vendor: cisco
  11. device_type: router
  12. os_version: 16.6.4
  13. site_code: mel
  14. dfjt-r001.lab.norn.local:
  15. hostname: dfjt-r001.lab.norn.local
  16. groups:
  17. - ios
  18. - lab
  19. - bcn
  20. data:
  21. mgmt_ip: 10.0.0.1
  22. vendor: cisco
  23. device_type: router
  24. os_version: 16.6.3
  25. site_code: bcn
  26. lab-arista-01.lab.norn.local:
  27. hostname: lab-arista-01.lab.norn.local
  28. groups:
  29. - eos
  30. - lab
  31. - mtl
  32. data:
  33. mgmt_ip: 10.0.0.11
  34. vendor: arista
  35. device_type: switch
  36. os_version: 4.22.0F
  37. site_code: mtl
  38. lab-arista-02.lab.norn.local:
  39. hostname: lab-arista-02.lab.norn.local
  40. groups:
  41. - eos
  42. - lab
  43. - mel
  44. data:
  45. mgmt_ip: 10.0.0.18
  46. vendor: arista
  47. device_type: switch
  48. os_version: 4.23.2F
  49. site_code: mel
  50. lab-junos-01.lab.norn.local:
  51. hostname: lab-junos-01.lab.norn.local
  52. groups:
  53. - junos
  54. - lab
  55. - mtl
  56. data:
  57. mgmt_ip: 10.0.0.15
  58. vendor: juniper
  59. device_type: router
  60. os_version: 18.4R2-S5
  61. site_code: mtl
  62. lab-nxos-01.lab.norn.local:
  63. hostname: lab-nxos-01.lab.norn.local
  64. groups:
  65. - nxos
  66. - lab
  67. - mtl
  68. data:
  69. mgmt_ip: 10.0.0.14
  70. vendor: cisco
  71. device_type: switch
  72. os_version: 9.3(6)
  73. site_code: mtl
  74. lab-paloalto-01.lab.djft.local:
  75. hostname: lab-paloalto-01.lab.djft.local
  76. groups:
  77. - panos
  78. - lab
  79. - mel
  80. data:
  81. mgmt_ip: 10.0.0.21
  82. vendor: palo alto
  83. device_type: firewall
  84. os_version: 10.0.3
  85. site_code: mel
  86. lab-paloalto-02.lab.norn.local:
  87. hostname: lab-paloalto-02.lab.norn.local
  88. groups:
  89. - panos
  90. - lab
  91. - bcn
  92. data:
  93. mgmt_ip: 10.0.0.22
  94. vendor: palo alto
  95. device_type: firewall
  96. os_version: 9.1.3-h1
  97. site_code: bcn
  98. lab-junos-06.lab.norn.local:
  99. hostname: lab-junos-06.lab.norn.local
  100. groups:
  101. - junos
  102. - lab
  103. - mel
  104. data:
  105. mgmt_ip: 10.0.0.23
  106. vendor: juniper
  107. device_type: switch
  108. os_version: 18.4R2-S5
  109. site_code: mel
  110. prd-csr-01.prd.norn.local:
  111. hostname: prd-csr-01.prd.norn.local
  112. groups:
  113. - ios
  114. - prod
  115. - mel
  116. data:
  117. mgmt_ip: 10.0.16.16
  118. vendor: cisco
  119. device_type: router
  120. os_version: 16.6.4
  121. site_code: mel
  122. dfjt-r001.prd.norn.local:
  123. hostname: dfjt-r001.prd.norn.local
  124. groups:
  125. - ios
  126. - prod
  127. - mel
  128. data:
  129. mgmt_ip: 10.0.16.1
  130. vendor: cisco
  131. device_type: router
  132. os_version: 16.6.3
  133. site_code: mel
  134. prd-arista-01.prd.norn.local:
  135. hostname: prd-arista-01.prd.norn.local
  136. groups:
  137. - eos
  138. - prod
  139. - mel
  140. data:
  141. mgmt_ip: 10.0.16.11
  142. vendor: arista
  143. device_type: switch
  144. os_version: 4.21.1F
  145. site_code: mel
  146. prd-arista-02.prd.nron.local:
  147. hostname: prd-arista-02.prd.norn.local
  148. groups:
  149. - eos
  150. - prod
  151. - mel
  152. data:
  153. mgmt_ip: 10.0.16.18
  154. vendor: arista
  155. device_type: switch
  156. os_version: 4.23.1F
  157. site_code: mel
  158. prd-junos-01.prd.norn.local:
  159. hostname: prd-junos-01.prd.norn.local
  160. groups:
  161. - junos
  162. - prod
  163. - mel
  164. data:
  165. mgmt_ip: 10.0.16.15
  166. vendor: juniper
  167. device_type: router
  168. os_version: 15.1R7-S6
  169. site_code: mel
  170. prd-nxos-01.prd.norn.local:
  171. hostname: prd-nxos-01.prd.norn.local
  172. groups:
  173. - nxos_ssh
  174. - prod
  175. - mel
  176. data:
  177. mgmt_ip: 10.0.16.14
  178. vendor: cisco
  179. device_type: switch
  180. os_version: 7.0(3)
  181. site_code: mel
  182. prd-paloalto-01.prd.norn.local:
  183. hostname: prd-paloalto-01.prd.norn.local
  184. groups:
  185. - panos
  186. - prod
  187. - mel
  188. data:
  189. mgmt_ip: 10.0.16.21
  190. vendor: palo alto
  191. device_type: firewall
  192. os_version: 10.0.3
  193. site_code: mel
  194. prd-paloalto-02.prd.norn.local:
  195. hostname: prd-paloalto-02.prd.norn.local
  196. groups:
  197. - panos
  198. - prod
  199. - mel
  200. data:
  201. mgmt_ip: 10.0.16.22
  202. vendor: palo alto
  203. device_type: firewall
  204. os_version: 9.1.6
  205. site_code: mel
  206. prd-junos-06.prd.norn.local:
  207. hostname: prd-junos-06.prd.norn.local
  208. groups:
  209. - junos
  210. - prod
  211. - mel
  212. data:
  213. mgmt_ip: 10.0.16.23
  214. vendor: juniper
  215. device_type: switch
  216. os_version: 12.1R3-S4
  217. site_code: mel
  218. tst-csr-01.tst.norn.local:
  219. hostname: tst-csr-01.tst.norn.local
  220. groups:
  221. - ios
  222. - test
  223. - mel
  224. data:
  225. mgmt_ip: 10.0.32.16
  226. vendor: cisco
  227. device_type: router
  228. os_version: 16.6.4
  229. site_code: mel
  230. dfjt-r001.tst.norn.local:
  231. hostname: dfjt-r001.tst.norn.local
  232. groups:
  233. - ios
  234. - test
  235. - mel
  236. data:
  237. mgmt_ip: 10.0.32.1
  238. vendor: cisco
  239. device_type: router
  240. os_version: 15.1.4
  241. site_code: mel
  242. tst-arista-01.tst.norn.local:
  243. hostname: tst-arista-01.tst.norn.local
  244. groups:
  245. - eos
  246. - test
  247. - ptl
  248. data:
  249. mgmt_ip: 10.0.32.11
  250. vendor: arista
  251. device_type: switch
  252. os_version: 4.21.1F
  253. site_code: ptl
  254. tstt-arista-02.tst.norn.local:
  255. hostname: tstt-arista-02.tst.norn.local
  256. groups:
  257. - eos
  258. - test
  259. - ptl
  260. data:
  261. mgmt_ip: 10.0.32.18
  262. vendor: arista
  263. device_type: switch
  264. os_version: 4.21.1F
  265. site_code: ptl
  266. tst-junos-01.tst.norn.local:
  267. hostname: tst-junos-01.tst.norn.local
  268. groups:
  269. - junos
  270. - test
  271. - ptl
  272. data:
  273. mgmt_ip: 10.0.32.15
  274. vendor: juniper
  275. device_type: router
  276. os_version: 15.1R7-S6
  277. site_code: ptl
  278. tst-nxos-01.tst.norn.local:
  279. hostname: tst-nxos-01.tst.norn.local
  280. groups:
  281. - nxos
  282. - test
  283. - chc
  284. data:
  285. mgmt_ip: 10.0.32.14
  286. vendor: cisco
  287. device_type: switch
  288. os_version: 7.0(4)
  289. site_code: chc
  290. tst-paloalto-01.tst.norn.local:
  291. hostname: tst-paloalto-01.tst.norn.local
  292. groups:
  293. - panos
  294. - test
  295. - chc
  296. data:
  297. mgmt_ip: 10.0.32.21
  298. vendor: palo alto
  299. device_type: firewall
  300. os_version: 10.0.3
  301. site_code: chc
  302. tst-paloalto-02.tst.norn.local:
  303. hostname: tst-paloalto-02.tst.norn.local
  304. groups:
  305. - panos
  306. - test
  307. - chc
  308. data:
  309. mgmt_ip: 10.0.32.22
  310. vendor: palo alto
  311. device_type: firewall
  312. os_version: 8.0.8
  313. site_code: chc
  314. tst-junos-06.tst.norn.local:
  315. hostname: tst-junos-06.tst.norn.local
  316. groups:
  317. - junos
  318. - test
  319. - chc
  320. data:
  321. mgmt_ip: 10.0.32.23
  322. vendor: juniper
  323. device_type: switch
  324. os_version: 12.1R3-S4
  325. site_code: chc

Next, let’s look at our tutorial groups.yaml file. There are a mixture of group types in here.

Some appear to be based on network operating systems, some on operating environments and others based on physical location.

nornir has no pre-conceived ideas or limits on group composition or structures:

  1. [3]:
  1. %cat filtering_deep_dive/inventory/groups.yaml
  1. ---
  2. ios:
  3. platform: ios
  4. data:
  5. vendor: cisco
  6. junos:
  7. platform: junos
  8. data:
  9. vendor: juniper
  10. eos:
  11. platform: eos
  12. data:
  13. vendor: arista
  14. nxos:
  15. platform: nxos
  16. data:
  17. vendor: cisco
  18. nxos_ssh:
  19. platform: nxos_ssh
  20. data:
  21. vendor: cisco
  22. panos:
  23. platform: paloalto_panos
  24. data:
  25. vendor: palo alto
  26. lab:
  27. data:
  28. sla: 70
  29. production: false
  30. prod:
  31. data:
  32. sla: 90
  33. production: true
  34. test:
  35. data:
  36. sla: 80
  37. production: false
  38. mel:
  39. data:
  40. full_name: Melbourne
  41. country: Australia
  42. region: apac
  43. hemisphere: southern
  44. site_type: primary
  45. hbt:
  46. data:
  47. full_name: Hobart
  48. country: Australia
  49. region: apac
  50. hemisphere: southern
  51. site_type: tertiary
  52. chc:
  53. data:
  54. full_name: Christchurch
  55. country: New Zealand
  56. region: apac
  57. hemisphere: southern
  58. site_type: secondary
  59. ptl:
  60. data:
  61. full_name: Port Louis
  62. country: Mauritius
  63. region: amea
  64. hemisphere: southern
  65. site_type: primary
  66. mtl:
  67. data:
  68. full_name: Montreal
  69. country: Canada
  70. region: amer
  71. hemisphere: northern
  72. site_type: primary
  73. bcn:
  74. data:
  75. full_name: Barcelona
  76. country: Spain
  77. region: amea
  78. hemisphere: northern
  79. site_type: primary

Custom inventory data

Before we dive into filtering, it’s important to introduce some core concepts regarding custom data.

nornir allows you to populate custom data on hosts or groups objects under the data key, in whatever key/value data structure you choose. You can name these keys whatever you like to suit your business needs.

Firstly, let’s explore an extract of one host and one group in the initial inventory introduced hosts.yaml and groups.yaml file.

NOTE: These files have been cut down to only contain one entry each, and also have some comments dispersed for readability

  1. [4]:
  1. %cat filtering_deep_dive/inventory/hosts_extract.yaml
  1. ---
  2. lab-csr-011.lab.norn.local:
  3. hostname: lab-csr-011.lab.norn.local
  4. groups:
  5. - ios
  6. - lab
  7. - mel
  8. data: # Anything under this key is custom data
  9. mgmt_ip: 10.0.0.16 # This is custom data
  10. vendor: cisco # So is this
  11. device_type: router # Same as this
  12. os_version: 16.6.4 # Also this too
  13. site_code: mel # Yes, and also this
  1. [5]:
  1. %cat filtering_deep_dive/inventory/groups_extract.yaml
  1. ---
  2. mel:
  3. data: # Anything under this key is custom data
  4. full_name: Melbourne # This is custom data
  5. country: Australia # So is this
  6. region: apac # Same as this
  7. hemisphere: southern # Also this too
  8. site_type: primary # Yes, and also this

As you can see in the two examples above, you can use custom data in any manner you like to record any information you please. The examples above are a “flat” data structure under the data key, but you can nest your data structure in any key/value structure to suit your needs.

In the below example, we take the mgmt_ip value of 10.0.0.16, and reorient it under an alternate data structure to the key mgmt which could allow for future expansion:

  1. [6]:
  1. %cat filtering_deep_dive/inventory/hosts_extract_alternate.yaml
  1. ---
  2. lab-csr-011.lab.norn.local:
  3. hostname: lab-csr-011.lab.norn.local
  4. groups:
  5. - ios
  6. - lab
  7. - mel
  8. data: # Anything under this key is custom data
  9. ip_addresses:
  10. mgmt: 10.0.0.16 # Alternate way of managing mgmt_ip data
  11. vendor: cisco
  12. device_type: router
  13. os_version: 16.6.4
  14. site_code: mel

Naturally over time, you needs to store custom data might change and ideally you enrich your custom data with as much business information as possible.

In the example below, a new set of key/value pairs related to the location of the site are now stored under the location key. This means that any existing code leveraging the existing data structure doesn’t need to be refactored:

  1. [7]:
  1. %cat filtering_deep_dive/inventory/groups_extract_alternate.yaml
  1. ---
  2. mel:
  3. data: # Anything under this key is custom data
  4. full_name: Melbourne
  5. country: Australia
  6. region: apac
  7. hemisphere: southern
  8. site_type: primary
  9. location: # New location data is stored about the site
  10. address: 1 Wurundjeri Street
  11. suburb: Northcote
  12. zip_code: 3070

Viewing host/group data

Before we revert back to filtering, we will show you how to access all data which is accessible or attributed to a host or group.

First, we will initialise nornir and filter the inventory on a single host lab-csr-011.lab.norn.local:

  1. [8]:
  1. # Import modules
  2. from nornir import InitNornir
  3. from nornir.core.filter import F
  4. # Initialise nornir
  5. nr = InitNornir(config_file="filtering_deep_dive/config.yaml")
  6. # Print the number of hosts in the inventory
  7. print(f"Number of hosts in entire inventory: {len(nr.inventory.hosts)}")
  8. # Access the host lab-csr-011.lab.norn.local using standard python key methods
  9. single_host = nr.inventory.hosts['lab-csr-011.lab.norn.local']
  10. # Print out the host
  11. print(f"Single host: {single_host}")
  1. Number of hosts in entire inventory: 27
  2. Single host: lab-csr-011.lab.norn.local

We can now print out all the data associated to the host lab-csr-011.lab.norn.local by dumping the dictionary structure:

  1. [9]:
  1. # Import the JSON module
  2. import json
  3. # Dump the dictionary, assign to variable
  4. single_host_data = json.dumps(single_host.dict(), indent=2)
  5. # Print seperator
  6. print("=" * 50)
  7. # Print header and host data structure
  8. print(f"Displaying information for host: {single_host}")
  9. print(f"{single_host_data}")
  10. # Print seperator
  11. print("=" * 50)
  1. ==================================================
  2. Displaying information for host: lab-csr-011.lab.norn.local
  3. {
  4. "name": "lab-csr-011.lab.norn.local",
  5. "connection_options": {},
  6. "groups": [
  7. "ios",
  8. "lab",
  9. "mel"
  10. ],
  11. "data": {
  12. "mgmt_ip": "10.0.0.16",
  13. "vendor": "cisco",
  14. "device_type": "router",
  15. "os_version": "16.6.4",
  16. "site_code": "mel"
  17. },
  18. "hostname": "lab-csr-011.lab.norn.local",
  19. "port": null,
  20. "username": null,
  21. "password": null,
  22. "platform": null
  23. }
  24. ==================================================

As you can see above, all our data related to the host is available for viewing and usage in any subsequent code. Whether we are using JSON or YAML, the data structure remains the same.

Below are some examples for displaying the values of some of the keys:

  1. [10]:
  1. print(f"Displaying data for host: {single_host}")
  2. # Access the site_code value, nested under the data key
  3. single_host_site_code = single_host.dict()["data"]["site_code"]
  4. print(f"Site code is: {single_host_site_code}")
  5. # Access the platform value
  6. single_host_platform = single_host.dict()["platform"]
  7. print(f"Platform is: {single_host_platform}")
  8. # Access the os_version value, nested under the data key
  9. single_host_os_version = single_host.dict()["data"]["os_version"]
  10. print(f"OS Version is: {single_host_os_version}")
  1. Displaying data for host: lab-csr-011.lab.norn.local
  2. Site code is: mel
  3. Platform is: None
  4. OS Version is: 16.6.4

The same concept shown above with a host, also applies to a group.

As we have described how this works, we will show the same concepts as they apply to groups below, with comments:

  1. [11]:
  1. # Import modules
  2. from nornir import InitNornir
  3. from nornir.core.filter import F
  4. import json
  5. # Initialise nornir
  6. nr = InitNornir(config_file="filtering_deep_dive/config.yaml")
  7. # Print the number of groups in the inventory
  8. print(f"Number of groups in entire inventory: {len(nr.inventory.groups)}")
  9. # Filter the entire group inventory on one group
  10. single_group = nr.inventory.groups['ptl']
  11. # Print out the group
  12. print(f"Single group: {single_group}")
  13. # Dump the dictionary, assign to variable
  14. single_group_data = json.dumps(single_group.dict(), indent=2)
  15. # Print seperator
  16. print("=" * 50)
  17. # Print header and host data structure
  18. print(f"Displaying information for group: {single_group}")
  19. print(f"{single_group_data}")
  20. # Print seperator
  21. print("=" * 50)
  22. print(f"Displaying data for group: {single_group}")
  23. # Access the full_name value, nested under the data key
  24. single_group_site_code = single_group.dict()["data"]["full_name"]
  25. print(f"Full Name is: {single_group_site_code}")
  26. # Access the platform value
  27. single_group_platform = single_group.dict()["platform"]
  28. print(f"Platform is: {single_group_platform}")
  29. # Access the os_version value, nested under the data key
  30. single_group_region = single_group.dict()["data"]["region"]
  31. print(f"Region is: {single_group_region}")
  1. Number of groups in entire inventory: 15
  2. Single group: ptl
  3. ==================================================
  4. Displaying information for group: ptl
  5. {
  6. "name": "ptl",
  7. "connection_options": {},
  8. "groups": [],
  9. "data": {
  10. "full_name": "Port Louis",
  11. "country": "Mauritius",
  12. "region": "amea",
  13. "hemisphere": "southern",
  14. "site_type": "primary"
  15. },
  16. "hostname": null,
  17. "port": null,
  18. "username": null,
  19. "password": null,
  20. "platform": null
  21. }
  22. ==================================================
  23. Displaying data for group: ptl
  24. Full Name is: Port Louis
  25. Platform is: None
  26. Region is: amea

By now, you should have an understanding of the following regarding inventory custom data:

- What is nornir custom data?

- How can it be stored?

- How can I access it?

- How can I view and troubleshoot it?

In the next section, we will now revert back to nornir filtering, which will build off your understanding of these concepts.

Filtering Types

nornir offers three types of filtering capabilities:

  • basic/intermediate filtering using the filter method

  • advanced filtering using the F object

  • advanced filtering using filter functions

It should be noted that the F object filtering method can address all filtering requirements of the filter method, but the filter method cannot address all the filtering requirements of the F object. This tutorial will explore both filtering methods, so you can understand their potential use-cases, limitations and trade-offs.

Basic Filtering

Let’s explore the filter method, which can used for straight forward filtering requirements. We will reinitialise the same nornir inventory introduced in the top of this tutorial:

  1. [12]:
  1. # Import modules
  2. from nornir import InitNornir
  3. from nornir.core.filter import F
  4. # Initialise nornir
  5. nr = InitNornir(config_file="filtering_deep_dive/config.yaml")
  6. # Informational printouts
  7. print(f"There are {len(nr.inventory.hosts)} hosts in this tutorial inventory.")
  8. print(f"There are {len(nr.inventory.groups)} groups in this tutorial inventory.")
  1. There are 27 hosts in this tutorial inventory.
  2. There are 15 groups in this tutorial inventory.

The basic filter method allows to filter on any key attributable to a host or a group. In the example below, we will filter the inventory on a single host:

  1. [13]:
  1. # Assign filter value to a variable for usage
  2. filter_query = "lab-arista-02.lab.norn.local"
  3. # Filter inventory for all hostnames which equal the filter value
  4. target_hosts = nr.filter(hostname=filter_query)
  5. print(f"Filtering entire inventory on {filter_query} ...")
  6. print(f"Total results found: {len(target_hosts.inventory.hosts)}")
  7. # Iterate over filtered results and printout information
  8. for host, data in target_hosts.inventory.hosts.items():
  9. print(
  10. f"Host: {host} "
  11. + f"- Hostname: {data.hostname}"
  12. )
  1. Filtering entire inventory on lab-arista-02.lab.norn.local ...
  2. Total results found: 1
  3. Host: lab-arista-02.lab.norn.local - Hostname: lab-arista-02.lab.norn.local

Host-based basic filters

Let’s look at some more useful examples below whereby we filter on properties directly attributed to a host, such as:

  • filter hosts by vendor

  • filter hosts by device_type

  • filter hosts by mgmt_ip

  1. [14]:
  1. # Import modules
  2. from nornir import InitNornir
  3. # Initialise nornir
  4. nr = InitNornir(config_file="filtering_deep_dive/config.yaml")
  5. # Use Case 1 - filter hosts by vendor
  6. # Assign vendor to variable for later usage
  7. vendor="palo alto"
  8. # Execute filter based on vendor
  9. target_hosts = nr.filter(vendor=vendor)
  10. # Print seperator and header
  11. print("=" * 50)
  12. print(f"The hosts which have vendor {vendor} are:")
  13. # Iterate over filtered results and printout information
  14. for host, data in target_hosts.inventory.hosts.items():
  15. print(
  16. f"Host: {host} "
  17. + f"- Vendor: {data['vendor']}"
  18. )
  19. # Print total and seperator
  20. print(f"Total: {len(target_hosts.inventory.hosts.items())}")
  21. print("=" * 50)
  22. # Use Case 2 - filter hosts by device_type
  23. # Assign device_type to variable for later usage
  24. device_type="switch"
  25. # Execute filter based on device_type
  26. target_hosts = nr.filter(device_type=device_type)
  27. # Print seperator and header
  28. print("=" * 50)
  29. print(f"The hosts which have device type {device_type} are:")
  30. # Iterate over filtered results and printout information
  31. for host, data in target_hosts.inventory.hosts.items():
  32. print(
  33. f"Host: {host} "
  34. + f"- Device Type: {data['device_type']}"
  35. )
  36. # Print total and seperator
  37. print(f"Total: {len(target_hosts.inventory.hosts.items())}")
  38. print("=" * 50)
  39. # Use Case 3 - filter hosts by mgmt_ip
  40. # Assign mgmt_ip to variable for later usage
  41. mgmt_ip="10.0.0.16"
  42. # Execute filter based on mgmt_ip
  43. target_hosts = nr.filter(mgmt_ip=mgmt_ip)
  44. # Print seperator and header
  45. print("=" * 50)
  46. print(f"The hosts which have management IP address {mgmt_ip} are:")
  47. # Iterate over filtered results and printout information
  48. for host, data in target_hosts.inventory.hosts.items():
  49. print(
  50. f"Host: {host} "
  51. + f"- Management IP Address: {data['mgmt_ip']}"
  52. )
  53. # Print total and seperator
  54. print(f"Total: {len(target_hosts.inventory.hosts.items())}")
  55. print("=" * 50)
  1. ==================================================
  2. The hosts which have vendor palo alto are:
  3. Host: lab-paloalto-01.lab.djft.local - Vendor: palo alto
  4. Host: lab-paloalto-02.lab.norn.local - Vendor: palo alto
  5. Host: prd-paloalto-01.prd.norn.local - Vendor: palo alto
  6. Host: prd-paloalto-02.prd.norn.local - Vendor: palo alto
  7. Host: tst-paloalto-01.tst.norn.local - Vendor: palo alto
  8. Host: tst-paloalto-02.tst.norn.local - Vendor: palo alto
  9. Total: 6
  10. ==================================================
  11. ==================================================
  12. The hosts which have device type switch are:
  13. Host: lab-arista-01.lab.norn.local - Device Type: switch
  14. Host: lab-arista-02.lab.norn.local - Device Type: switch
  15. Host: lab-nxos-01.lab.norn.local - Device Type: switch
  16. Host: lab-junos-06.lab.norn.local - Device Type: switch
  17. Host: prd-arista-01.prd.norn.local - Device Type: switch
  18. Host: prd-arista-02.prd.nron.local - Device Type: switch
  19. Host: prd-nxos-01.prd.norn.local - Device Type: switch
  20. Host: prd-junos-06.prd.norn.local - Device Type: switch
  21. Host: tst-arista-01.tst.norn.local - Device Type: switch
  22. Host: tstt-arista-02.tst.norn.local - Device Type: switch
  23. Host: tst-nxos-01.tst.norn.local - Device Type: switch
  24. Host: tst-junos-06.tst.norn.local - Device Type: switch
  25. Total: 12
  26. ==================================================
  27. ==================================================
  28. The hosts which have management IP address 10.0.0.16 are:
  29. Host: lab-csr-011.lab.norn.local - Management IP Address: 10.0.0.16
  30. Total: 1
  31. ==================================================

Host-based basic filters (from group inheritance)

As nornir uses an inheritance model, we filter on group-based attributes which are inherited down to the host.

In the examples below, we will filter the inventory based on some group-based attributes which inherited from their group values:

  • filter hosts by platform

  • filter hosts by production equals false

  • filter hosts by site_type of secondary

  1. [15]:
  1. # Import modules
  2. from nornir import InitNornir
  3. # Initialise nornir
  4. nr = InitNornir(config_file="filtering_deep_dive/config.yaml")
  5. # Use Case 1 - filter hosts by platform
  6. # Assign platform to variable for later usage
  7. platform="junos"
  8. # Execute filter based on platform
  9. target_hosts = nr.filter(platform=platform)
  10. # Print seperator and header
  11. print("=" * 50)
  12. print(f"The hosts which have platform {platform} are:")
  13. # Iterate over filtered results and printout information
  14. for host, data in target_hosts.inventory.hosts.items():
  15. print(
  16. f"Host: {host} "
  17. + f"- Platform: {data.platform}"
  18. )
  19. # Print total and seperator
  20. print(f"Total: {len(target_hosts.inventory.hosts.items())}")
  21. print("=" * 50)
  22. # Use Case 2 - filter hosts by production equals false
  23. # Assign production equals false to variable for later usage
  24. production = False
  25. # Execute filter based on production
  26. target_hosts = nr.filter(production=production)
  27. # Print seperator and header
  28. print("=" * 50)
  29. print(f"The hosts which have production boolean value of {production} are:")
  30. # Iterate over filtered results and printout information
  31. for host, data in target_hosts.inventory.hosts.items():
  32. print(
  33. f"Host: {host} "
  34. + f"- Production: {data['production']}"
  35. )
  36. # Print total and seperator
  37. print(f"Total: {len(target_hosts.inventory.hosts.items())}")
  38. print("=" * 50)
  39. # Use Case 3 - filter hosts by site_type of tertiary
  40. # Assign site_type of secondary to variable for later usage
  41. site_type="secondary"
  42. # Execute filter based on site_type
  43. target_hosts = nr.filter(site_type=site_type)
  44. # Print seperator and header
  45. print("=" * 50)
  46. print(f"The hosts which have site_type of {site_type} are:")
  47. # Iterate over filtered results and printout information
  48. for host, data in target_hosts.inventory.hosts.items():
  49. print(
  50. f"Host: {host} "
  51. + f"- Site Type: {data['site_type']}"
  52. )
  53. # Print total and seperator
  54. print(f"Total: {len(target_hosts.inventory.hosts.items())}")
  55. print("=" * 50)
  1. ==================================================
  2. The hosts which have platform junos are:
  3. Host: lab-junos-01.lab.norn.local - Platform: junos
  4. Host: lab-junos-06.lab.norn.local - Platform: junos
  5. Host: prd-junos-01.prd.norn.local - Platform: junos
  6. Host: prd-junos-06.prd.norn.local - Platform: junos
  7. Host: tst-junos-01.tst.norn.local - Platform: junos
  8. Host: tst-junos-06.tst.norn.local - Platform: junos
  9. Total: 6
  10. ==================================================
  11. ==================================================
  12. The hosts which have production boolean value of False are:
  13. Host: lab-csr-011.lab.norn.local - Production: False
  14. Host: dfjt-r001.lab.norn.local - Production: False
  15. Host: lab-arista-01.lab.norn.local - Production: False
  16. Host: lab-arista-02.lab.norn.local - Production: False
  17. Host: lab-junos-01.lab.norn.local - Production: False
  18. Host: lab-nxos-01.lab.norn.local - Production: False
  19. Host: lab-paloalto-01.lab.djft.local - Production: False
  20. Host: lab-paloalto-02.lab.norn.local - Production: False
  21. Host: lab-junos-06.lab.norn.local - Production: False
  22. Host: tst-csr-01.tst.norn.local - Production: False
  23. Host: dfjt-r001.tst.norn.local - Production: False
  24. Host: tst-arista-01.tst.norn.local - Production: False
  25. Host: tstt-arista-02.tst.norn.local - Production: False
  26. Host: tst-junos-01.tst.norn.local - Production: False
  27. Host: tst-nxos-01.tst.norn.local - Production: False
  28. Host: tst-paloalto-01.tst.norn.local - Production: False
  29. Host: tst-paloalto-02.tst.norn.local - Production: False
  30. Host: tst-junos-06.tst.norn.local - Production: False
  31. Total: 18
  32. ==================================================
  33. ==================================================
  34. The hosts which have site_type of secondary are:
  35. Host: tst-nxos-01.tst.norn.local - Site Type: secondary
  36. Host: tst-paloalto-01.tst.norn.local - Site Type: secondary
  37. Host: tst-paloalto-02.tst.norn.local - Site Type: secondary
  38. Host: tst-junos-06.tst.norn.local - Site Type: secondary
  39. Total: 4
  40. ==================================================

Intermediate filtering

We can chain or join filters together using the filter method to be narrow down results and end up with specific devices.

In the examples below, we will use output of a filter result and feed that into the next filter and filter incrementally to end up with a specific result of the Christchurch Cisco Switch.

  1. [16]:
  1. # Import modules
  2. from nornir import InitNornir
  3. # Initialise nornir
  4. nr = InitNornir(config_file="filtering_deep_dive/config.yaml")
  5. # Filter all devices for Cisco devices
  6. cisco_devices = nr.filter(vendor="cisco")
  7. # Print seperator and header
  8. print("=" * 50)
  9. print("All cisco devices")
  10. # Iterate over filtered results and printout information
  11. for host, data in cisco_devices.inventory.hosts.items():
  12. print(
  13. f"Host: {host} "
  14. + f"- Vendor: {data['vendor']}"
  15. )
  16. # Print total and seperator
  17. print(f"Total: {len(cisco_devices.inventory.hosts.items())}")
  18. print("=" * 50)
  19. # Filter all Cisco devices for Cisco switches
  20. cisco_switches = cisco_devices.filter(device_type="switch")
  21. # Print seperator and header
  22. print("=" * 50)
  23. print("All cisco switches")
  24. # Iterate over filtered results and printout information
  25. for host, data in cisco_switches.inventory.hosts.items():
  26. print(
  27. f"Host: {host} "
  28. + f"- Device Type: {data['device_type']}"
  29. )
  30. # Print total and seperator
  31. print(f"Total: {len(cisco_switches.inventory.hosts.items())}")
  32. print("=" * 50)
  33. # Filter all Cisco switches for Christchurch switches
  34. chc_cisco_switches = cisco_switches.filter(full_name="Christchurch")
  35. # Print seperator and header
  36. print("=" * 50)
  37. print("All Christchuch cisco switches")
  38. # Iterate over filtered results and printout information
  39. for host, data in chc_cisco_switches.inventory.hosts.items():
  40. print(
  41. f"Host: {host} \n"
  42. + " " * 8 + f"- Vendor: {data['vendor']}\n"
  43. + " " * 8 + f"- Device Type: {data['device_type']}\n"
  44. + " " * 8 + f"- Site Name: {data['full_name']}"
  45. )
  46. # Print total and seperator
  47. print(f"Total: {len(chc_cisco_switches.inventory.hosts.items())}")
  48. print("=" * 50)
  1. ==================================================
  2. All cisco devices
  3. Host: lab-csr-011.lab.norn.local - Vendor: cisco
  4. Host: dfjt-r001.lab.norn.local - Vendor: cisco
  5. Host: lab-nxos-01.lab.norn.local - Vendor: cisco
  6. Host: prd-csr-01.prd.norn.local - Vendor: cisco
  7. Host: dfjt-r001.prd.norn.local - Vendor: cisco
  8. Host: prd-nxos-01.prd.norn.local - Vendor: cisco
  9. Host: tst-csr-01.tst.norn.local - Vendor: cisco
  10. Host: dfjt-r001.tst.norn.local - Vendor: cisco
  11. Host: tst-nxos-01.tst.norn.local - Vendor: cisco
  12. Total: 9
  13. ==================================================
  14. ==================================================
  15. All cisco switches
  16. Host: lab-nxos-01.lab.norn.local - Device Type: switch
  17. Host: prd-nxos-01.prd.norn.local - Device Type: switch
  18. Host: tst-nxos-01.tst.norn.local - Device Type: switch
  19. Total: 3
  20. ==================================================
  21. ==================================================
  22. All Christchuch cisco switches
  23. Host: tst-nxos-01.tst.norn.local
  24. - Vendor: cisco
  25. - Device Type: switch
  26. - Site Name: Christchurch
  27. Total: 1
  28. ==================================================

Advanced filtering

The final and most powerful method of filtering is using the F object. As mentioned in sections above, the F object can perform all forms of filtering.

In this section we will cover:

- F object filter operators

- F object filter operations

- filter functions using filter_func

F object filter operators

There are three F filter operators which are described below:

Character Pattern

Description

~

NOT

&

AND

|

OR

In the proceeding code, we will show examples of these in use:

  1. [17]:
  1. # Import modules
  2. from nornir import InitNornir
  3. from nornir.core.filter import F
  4. # Initialise nornir
  5. nr = InitNornir(config_file="filtering_deep_dive/config.yaml")
  6. # Use Case 1 - NOT operator
  7. # Filter for NOT equals platform of "junos"
  8. not_junos = nr.filter(~F(platform__eq="junos"))
  9. # Print seperator and header
  10. print("=" * 50)
  11. print("All non-junos devices - using NOT operator")
  12. # Iterate over filtered results and printout information
  13. for host, data in not_junos.inventory.hosts.items():
  14. print(
  15. f"Host: {host} "
  16. + f"- Platform: {data.platform}"
  17. )
  18. # Print total and seperator
  19. print(f"Total: {len(not_junos.inventory.hosts.items())}")
  20. print("=" * 50)
  21. # Use Case 2 - AND operator
  22. # Filter for platform equals "nxos" AND device_type equals "switch"
  23. nxos_switches = nr.filter(F(platform__eq="nxos") & F(device_type__eq="switch"))
  24. # Print seperator and header
  25. print("=" * 50)
  26. print("All nxos switches - using AND operator")
  27. # Iterate over filtered results and printout information
  28. for host, data in nxos_switches.inventory.hosts.items():
  29. print(
  30. f"Host: {host} "
  31. + f"- Platform: {data.platform} "
  32. + f"- Device Type: {data['device_type']}"
  33. )
  34. # Print total and seperator
  35. print(f"Total: {len(nxos_switches.inventory.hosts.items())}")
  36. print("=" * 50)
  37. # Use Case 3 - OR operator
  38. # Filter for site code equals "ptl" OR site code equals "chc"
  39. ptl_or_chc_devices = nr.filter(
  40. F(site_code__eq="ptl") | F(site_code__eq="chc")
  41. )
  42. print("=" * 50)
  43. print("All ptl or chc site code devices - using OR operator")
  44. # Iterate over filtered results and printout information
  45. for host, data in ptl_or_chc_devices.inventory.hosts.items():
  46. print(
  47. f"Host: {host} "
  48. + f"- Site Code: {data['site_code']}"
  49. )
  50. # Print total and seperator
  51. print(f"Total: {len(ptl_or_chc_devices.inventory.hosts.items())}")
  52. print("=" * 50)
  1. ==================================================
  2. All non-junos devices - using NOT operator
  3. Host: lab-csr-011.lab.norn.local - Platform: ios
  4. Host: dfjt-r001.lab.norn.local - Platform: ios
  5. Host: lab-arista-01.lab.norn.local - Platform: eos
  6. Host: lab-arista-02.lab.norn.local - Platform: eos
  7. Host: lab-nxos-01.lab.norn.local - Platform: nxos
  8. Host: lab-paloalto-01.lab.djft.local - Platform: paloalto_panos
  9. Host: lab-paloalto-02.lab.norn.local - Platform: paloalto_panos
  10. Host: prd-csr-01.prd.norn.local - Platform: ios
  11. Host: dfjt-r001.prd.norn.local - Platform: ios
  12. Host: prd-arista-01.prd.norn.local - Platform: eos
  13. Host: prd-arista-02.prd.nron.local - Platform: eos
  14. Host: prd-nxos-01.prd.norn.local - Platform: nxos_ssh
  15. Host: prd-paloalto-01.prd.norn.local - Platform: paloalto_panos
  16. Host: prd-paloalto-02.prd.norn.local - Platform: paloalto_panos
  17. Host: tst-csr-01.tst.norn.local - Platform: ios
  18. Host: dfjt-r001.tst.norn.local - Platform: ios
  19. Host: tst-arista-01.tst.norn.local - Platform: eos
  20. Host: tstt-arista-02.tst.norn.local - Platform: eos
  21. Host: tst-nxos-01.tst.norn.local - Platform: nxos
  22. Host: tst-paloalto-01.tst.norn.local - Platform: paloalto_panos
  23. Host: tst-paloalto-02.tst.norn.local - Platform: paloalto_panos
  24. Total: 21
  25. ==================================================
  26. ==================================================
  27. All nxos switches - using AND operator
  28. Host: lab-nxos-01.lab.norn.local - Platform: nxos - Device Type: switch
  29. Host: tst-nxos-01.tst.norn.local - Platform: nxos - Device Type: switch
  30. Total: 2
  31. ==================================================
  32. ==================================================
  33. All ptl or chc site code devices - using OR operator
  34. Host: tst-arista-01.tst.norn.local - Site Code: ptl
  35. Host: tstt-arista-02.tst.norn.local - Site Code: ptl
  36. Host: tst-junos-01.tst.norn.local - Site Code: ptl
  37. Host: tst-nxos-01.tst.norn.local - Site Code: chc
  38. Host: tst-paloalto-01.tst.norn.local - Site Code: chc
  39. Host: tst-paloalto-02.tst.norn.local - Site Code: chc
  40. Host: tst-junos-06.tst.norn.local - Site Code: chc
  41. Total: 7
  42. ==================================================

F object operations

There are eleven F filter operations which are described below:

Character Pattern

Description

Type Usage

eq

Equals

string, integer

ge

Greater than or equal to

integer

gt

Greater than

integer

le

Less than or equal to

integer

lt

Less than

integer

contains

Contains

string

startswith

Starts with

string

endswith

ends with

string

any

Any of the following

string

has_parent_group

Host has a parent group

string

in

In

string

all

All of

list

In the proceeding code, we will show examples of these in use.

NOTE: These are spread out over multiple snippets of code to cut down the amount of interpreting you need to perform at once

  1. [18]:
  1. # Import modules
  2. from nornir import InitNornir
  3. from nornir.core.filter import F
  4. # Initialise nornir
  5. nr = InitNornir(config_file="filtering_deep_dive/config.yaml")
  6. # Use Case 1 - eq operation
  7. # Filter for equals platform of "junos"
  8. junos_devices = nr.filter(F(platform__eq="junos"))
  9. # Print seperator and header
  10. print("=" * 50)
  11. print("All junos devices - using eq operation")
  12. # Iterate over filtered results and printout information
  13. for host, data in junos_devices.inventory.hosts.items():
  14. print(
  15. f"Host: {host} "
  16. + f"- Platform: {data.platform}"
  17. )
  18. # Print total and seperator
  19. print(f"Total: {len(junos_devices.inventory.hosts.items())}")
  20. print("=" * 50)
  21. # Use Case 2 - ge operation
  22. # Filter for sla greater than or equal to 80
  23. sla_eighty_or_greater = nr.filter(F(sla__ge=80))
  24. # Print seperator and header
  25. print("=" * 50)
  26. print("All devices with SLA greater than or equal to 80 - using gt operation")
  27. # Iterate over filtered results and printout information
  28. for host, data in sla_eighty_or_greater.inventory.hosts.items():
  29. print(
  30. f"Host: {host} "
  31. + f"- SLA: {data['sla']}"
  32. )
  33. # Print total and seperator
  34. print(f"Total: {len(sla_eighty_or_greater.inventory.hosts.items())}")
  35. print("=" * 50)
  36. # Use Case 3 - gt operation
  37. # Filter for sla greater than 79
  38. sla_more_than_seventy_nine = nr.filter(F(sla__gt=79))
  39. # Print seperator and header
  40. print("=" * 50)
  41. print("All devices with SLA greater than 79 - using gt operation")
  42. # Iterate over filtered results and printout information
  43. for host, data in sla_more_than_seventy_nine.inventory.hosts.items():
  44. print(
  45. f"Host: {host} "
  46. + f"- SLA: {data['sla']}"
  47. )
  48. # Print total and seperator
  49. print(f"Total: {len(sla_more_than_seventy_nine.inventory.hosts.items())}")
  50. print("=" * 50)
  51. # Use Case 4 - le operation
  52. # Filter for sla lesser than or equal to 80
  53. sla_eighty_or_lesser = nr.filter(F(sla__le=80))
  54. # Print seperator and header
  55. print("=" * 50)
  56. print("All devices with SLA less than or equal to 80 - using le operation")
  57. # Iterate over filtered results and printout information
  58. for host, data in sla_eighty_or_lesser.inventory.hosts.items():
  59. print(
  60. f"Host: {host} "
  61. + f"- SLA: {data['sla']}"
  62. )
  63. # Print total and seperator
  64. print(f"Total: {len(sla_eighty_or_lesser.inventory.hosts.items())}")
  65. print("=" * 50)
  66. # Use Case 4 - lt operation
  67. # Filter for sla lesser than 80
  68. sla_less_than_eighty = nr.filter(F(sla__lt=80))
  69. # Print seperator and header
  70. print("=" * 50)
  71. print("All devices with SLA less than 80 - using lt operation")
  72. # Iterate over filtered results and printout information
  73. for host, data in sla_less_than_eighty.inventory.hosts.items():
  74. print(
  75. f"Host: {host} "
  76. + f"- SLA: {data['sla']}"
  77. )
  78. # Print total and seperator
  79. print(f"Total: {len(sla_less_than_eighty.inventory.hosts.items())}")
  80. print("=" * 50)
  1. ==================================================
  2. All junos devices - using eq operation
  3. Host: lab-junos-01.lab.norn.local - Platform: junos
  4. Host: lab-junos-06.lab.norn.local - Platform: junos
  5. Host: prd-junos-01.prd.norn.local - Platform: junos
  6. Host: prd-junos-06.prd.norn.local - Platform: junos
  7. Host: tst-junos-01.tst.norn.local - Platform: junos
  8. Host: tst-junos-06.tst.norn.local - Platform: junos
  9. Total: 6
  10. ==================================================
  11. ==================================================
  12. All devices with SLA greater than or equal to 80 - using gt operation
  13. Host: prd-csr-01.prd.norn.local - SLA: 90
  14. Host: dfjt-r001.prd.norn.local - SLA: 90
  15. Host: prd-arista-01.prd.norn.local - SLA: 90
  16. Host: prd-arista-02.prd.nron.local - SLA: 90
  17. Host: prd-junos-01.prd.norn.local - SLA: 90
  18. Host: prd-nxos-01.prd.norn.local - SLA: 90
  19. Host: prd-paloalto-01.prd.norn.local - SLA: 90
  20. Host: prd-paloalto-02.prd.norn.local - SLA: 90
  21. Host: prd-junos-06.prd.norn.local - SLA: 90
  22. Host: tst-csr-01.tst.norn.local - SLA: 80
  23. Host: dfjt-r001.tst.norn.local - SLA: 80
  24. Host: tst-arista-01.tst.norn.local - SLA: 80
  25. Host: tstt-arista-02.tst.norn.local - SLA: 80
  26. Host: tst-junos-01.tst.norn.local - SLA: 80
  27. Host: tst-nxos-01.tst.norn.local - SLA: 80
  28. Host: tst-paloalto-01.tst.norn.local - SLA: 80
  29. Host: tst-paloalto-02.tst.norn.local - SLA: 80
  30. Host: tst-junos-06.tst.norn.local - SLA: 80
  31. Total: 18
  32. ==================================================
  33. ==================================================
  34. All devices with SLA greater than 79 - using gt operation
  35. Host: prd-csr-01.prd.norn.local - SLA: 90
  36. Host: dfjt-r001.prd.norn.local - SLA: 90
  37. Host: prd-arista-01.prd.norn.local - SLA: 90
  38. Host: prd-arista-02.prd.nron.local - SLA: 90
  39. Host: prd-junos-01.prd.norn.local - SLA: 90
  40. Host: prd-nxos-01.prd.norn.local - SLA: 90
  41. Host: prd-paloalto-01.prd.norn.local - SLA: 90
  42. Host: prd-paloalto-02.prd.norn.local - SLA: 90
  43. Host: prd-junos-06.prd.norn.local - SLA: 90
  44. Host: tst-csr-01.tst.norn.local - SLA: 80
  45. Host: dfjt-r001.tst.norn.local - SLA: 80
  46. Host: tst-arista-01.tst.norn.local - SLA: 80
  47. Host: tstt-arista-02.tst.norn.local - SLA: 80
  48. Host: tst-junos-01.tst.norn.local - SLA: 80
  49. Host: tst-nxos-01.tst.norn.local - SLA: 80
  50. Host: tst-paloalto-01.tst.norn.local - SLA: 80
  51. Host: tst-paloalto-02.tst.norn.local - SLA: 80
  52. Host: tst-junos-06.tst.norn.local - SLA: 80
  53. Total: 18
  54. ==================================================
  55. ==================================================
  56. All devices with SLA less than or equal to 80 - using le operation
  57. Host: lab-csr-011.lab.norn.local - SLA: 70
  58. Host: dfjt-r001.lab.norn.local - SLA: 70
  59. Host: lab-arista-01.lab.norn.local - SLA: 70
  60. Host: lab-arista-02.lab.norn.local - SLA: 70
  61. Host: lab-junos-01.lab.norn.local - SLA: 70
  62. Host: lab-nxos-01.lab.norn.local - SLA: 70
  63. Host: lab-paloalto-01.lab.djft.local - SLA: 70
  64. Host: lab-paloalto-02.lab.norn.local - SLA: 70
  65. Host: lab-junos-06.lab.norn.local - SLA: 70
  66. Host: tst-csr-01.tst.norn.local - SLA: 80
  67. Host: dfjt-r001.tst.norn.local - SLA: 80
  68. Host: tst-arista-01.tst.norn.local - SLA: 80
  69. Host: tstt-arista-02.tst.norn.local - SLA: 80
  70. Host: tst-junos-01.tst.norn.local - SLA: 80
  71. Host: tst-nxos-01.tst.norn.local - SLA: 80
  72. Host: tst-paloalto-01.tst.norn.local - SLA: 80
  73. Host: tst-paloalto-02.tst.norn.local - SLA: 80
  74. Host: tst-junos-06.tst.norn.local - SLA: 80
  75. Total: 18
  76. ==================================================
  77. ==================================================
  78. All devices with SLA less than 80 - using lt operation
  79. Host: lab-csr-011.lab.norn.local - SLA: 70
  80. Host: dfjt-r001.lab.norn.local - SLA: 70
  81. Host: lab-arista-01.lab.norn.local - SLA: 70
  82. Host: lab-arista-02.lab.norn.local - SLA: 70
  83. Host: lab-junos-01.lab.norn.local - SLA: 70
  84. Host: lab-nxos-01.lab.norn.local - SLA: 70
  85. Host: lab-paloalto-01.lab.djft.local - SLA: 70
  86. Host: lab-paloalto-02.lab.norn.local - SLA: 70
  87. Host: lab-junos-06.lab.norn.local - SLA: 70
  88. Total: 9
  89. ==================================================
  1. [19]:
  1. # Use Case 5 - contains operation
  2. # Filter for a platform that contains "nos" in it.
  3. # i.e match "paloalto_panos" or "junos" but not "nxos"
  4. network_nos = nr.filter(F(platform__contains="nos"))
  5. # Print seperator and header
  6. print("=" * 50)
  7. print("All devices contain 'nos' in platform - using contain operation")
  8. # Iterate over filtered results and printout information
  9. for host, data in network_nos.inventory.hosts.items():
  10. print(
  11. f"Host: {host} "
  12. + f"- Platform: {data.platform}"
  13. )
  14. # Print total and seperator
  15. print(f"Total: {len(network_nos.inventory.hosts.items())}")
  16. print("=" * 50)
  17. # Use Case 6 - startswith operation
  18. # Filter for a platform that starts with "am".
  19. # i.e match "amer", "amea" but not "apac"
  20. am_devs = nr.filter(F(region__startswith="am"))
  21. # Print seperator and header
  22. print("=" * 50)
  23. print("All devices starts with 'am' in region - using startswith operation")
  24. # Iterate over filtered results and printout information
  25. for host, data in am_devs.inventory.hosts.items():
  26. print(
  27. f"Host: {host} "
  28. + f"- Platform: {data['region']}"
  29. )
  30. # Print total and seperator
  31. print(f"Total: {len(am_devs.inventory.hosts.items())}")
  32. print("=" * 50)
  33. # Use Case 7 - startswith operation
  34. # Filter for a platform that ends with "l".
  35. # i.e match "mtl", "mel" or "ptl", but not "chc", "hbt" or "bcn"
  36. l_site_code_devs = nr.filter(F(site_code__endswith="l"))
  37. # Print seperator and header
  38. print("=" * 50)
  39. print("All devices ends with 'l' in site code - using endswith operation")
  40. # Iterate over filtered results and printout information
  41. for host, data in l_site_code_devs.inventory.hosts.items():
  42. print(
  43. f"Host: {host} "
  44. + f"- Platform: {data['site_code']}"
  45. )
  46. # Print total and seperator
  47. print(f"Total: {len(l_site_code_devs.inventory.hosts.items())}")
  48. print("=" * 50)
  49. # Use Case 8 - startswith operation
  50. # Filter for a platform that is any of elements in our cisco_platforms
  51. # list
  52. cisco_platforms = ["catos", "ios", "iosxe", "iosxr", "nxos"]
  53. cisco_devs = nr.filter(F(platform__any=cisco_platforms))
  54. # Print seperator and header
  55. print("=" * 50)
  56. print(f"All devices which contains {cisco_platforms} - using contains operation")
  57. # Iterate over filtered results and printout information
  58. for host, data in cisco_devs.inventory.hosts.items():
  59. print(
  60. f"Host: {host} "
  61. + f"- Platform: {data.platform}"
  62. )
  63. # Print total and seperator
  64. print(f"Total: {len(cisco_devs.inventory.hosts.items())}")
  65. print("=" * 50)
  66. # Use Case 9 - has_parent_group operation
  67. # Filter for any hosts which have the parent group of test
  68. test_devs = nr.filter(F(has_parent_group="test"))
  69. # Print seperator and header
  70. print("=" * 50)
  71. print(f"All devices which has parent group of test - using has_parent_group operation")
  72. # Iterate over filtered results and printout information
  73. for host, data in test_devs.inventory.hosts.items():
  74. print(
  75. f"Host: {host} "
  76. + f"- Production: {data['production']}"
  77. )
  78. # Print total and seperator
  79. print(f"Total: {len(test_devs.inventory.hosts.items())}")
  80. print("=" * 50)
  81. # Use Case 10 - in operation
  82. # Filter for a platform that is in one of elements in our non_cisco_platforms
  83. # list
  84. # NOTE: Not sure how different this is to the "any" operation in case you
  85. # were wondering too.
  86. non_cisco_platforms = ["eos", "paloalto_panos", "junos"]
  87. non_cisco_devs = nr.filter(F(platform__in=non_cisco_platforms))
  88. # Print seperator and header
  89. print("=" * 50)
  90. print(f"All devices which are in the list {non_cisco_platforms} - using in operation")
  91. # Iterate over filtered results and printout information
  92. for host, data in non_cisco_devs.inventory.hosts.items():
  93. print(
  94. f"Host: {host} "
  95. + f"- Platform: {data.platform}"
  96. )
  97. # Print total and seperator
  98. print(f"Total: {len(non_cisco_devs.inventory.hosts.items())}")
  99. print("=" * 50)
  100. # Use Case 11 - all operation
  101. # Filter for a device which has all groups
  102. all_groups = ["eos","prod", "mel"]
  103. eos_prod_mel = nr.filter(F(groups__all=all_groups))
  104. # Print seperator and header
  105. print("=" * 50)
  106. print(f"All devices which all the groups {all_groups} - using all operation")
  107. # Iterate over filtered results and printout information
  108. for host, data in eos_prod_mel.inventory.hosts.items():
  109. print(
  110. f"Host: {host} "
  111. + f"- Groups: {data.groups}"
  112. )
  113. # Print total and seperator
  114. print(f"Total: {len(eos_prod_mel.inventory.hosts.items())}")
  115. print("=" * 50)
  1. ==================================================
  2. All devices contain 'nos' in platform - using contain operation
  3. Host: lab-junos-01.lab.norn.local - Platform: junos
  4. Host: lab-paloalto-01.lab.djft.local - Platform: paloalto_panos
  5. Host: lab-paloalto-02.lab.norn.local - Platform: paloalto_panos
  6. Host: lab-junos-06.lab.norn.local - Platform: junos
  7. Host: prd-junos-01.prd.norn.local - Platform: junos
  8. Host: prd-paloalto-01.prd.norn.local - Platform: paloalto_panos
  9. Host: prd-paloalto-02.prd.norn.local - Platform: paloalto_panos
  10. Host: prd-junos-06.prd.norn.local - Platform: junos
  11. Host: tst-junos-01.tst.norn.local - Platform: junos
  12. Host: tst-paloalto-01.tst.norn.local - Platform: paloalto_panos
  13. Host: tst-paloalto-02.tst.norn.local - Platform: paloalto_panos
  14. Host: tst-junos-06.tst.norn.local - Platform: junos
  15. Total: 12
  16. ==================================================
  17. ==================================================
  18. All devices starts with 'am' in region - using startswith operation
  19. Host: dfjt-r001.lab.norn.local - Platform: amea
  20. Host: lab-arista-01.lab.norn.local - Platform: amer
  21. Host: lab-junos-01.lab.norn.local - Platform: amer
  22. Host: lab-nxos-01.lab.norn.local - Platform: amer
  23. Host: lab-paloalto-02.lab.norn.local - Platform: amea
  24. Host: tst-arista-01.tst.norn.local - Platform: amea
  25. Host: tstt-arista-02.tst.norn.local - Platform: amea
  26. Host: tst-junos-01.tst.norn.local - Platform: amea
  27. Total: 8
  28. ==================================================
  29. ==================================================
  30. All devices ends with 'l' in site code - using endswith operation
  31. Host: lab-csr-011.lab.norn.local - Platform: mel
  32. Host: lab-arista-01.lab.norn.local - Platform: mtl
  33. Host: lab-arista-02.lab.norn.local - Platform: mel
  34. Host: lab-junos-01.lab.norn.local - Platform: mtl
  35. Host: lab-nxos-01.lab.norn.local - Platform: mtl
  36. Host: lab-paloalto-01.lab.djft.local - Platform: mel
  37. Host: lab-junos-06.lab.norn.local - Platform: mel
  38. Host: prd-csr-01.prd.norn.local - Platform: mel
  39. Host: dfjt-r001.prd.norn.local - Platform: mel
  40. Host: prd-arista-01.prd.norn.local - Platform: mel
  41. Host: prd-arista-02.prd.nron.local - Platform: mel
  42. Host: prd-junos-01.prd.norn.local - Platform: mel
  43. Host: prd-nxos-01.prd.norn.local - Platform: mel
  44. Host: prd-paloalto-01.prd.norn.local - Platform: mel
  45. Host: prd-paloalto-02.prd.norn.local - Platform: mel
  46. Host: prd-junos-06.prd.norn.local - Platform: mel
  47. Host: tst-csr-01.tst.norn.local - Platform: mel
  48. Host: dfjt-r001.tst.norn.local - Platform: mel
  49. Host: tst-arista-01.tst.norn.local - Platform: ptl
  50. Host: tstt-arista-02.tst.norn.local - Platform: ptl
  51. Host: tst-junos-01.tst.norn.local - Platform: ptl
  52. Total: 21
  53. ==================================================
  54. ==================================================
  55. All devices which contains ['catos', 'ios', 'iosxe', 'iosxr', 'nxos'] - using contains operation
  56. Host: lab-csr-011.lab.norn.local - Platform: ios
  57. Host: dfjt-r001.lab.norn.local - Platform: ios
  58. Host: lab-nxos-01.lab.norn.local - Platform: nxos
  59. Host: prd-csr-01.prd.norn.local - Platform: ios
  60. Host: dfjt-r001.prd.norn.local - Platform: ios
  61. Host: tst-csr-01.tst.norn.local - Platform: ios
  62. Host: dfjt-r001.tst.norn.local - Platform: ios
  63. Host: tst-nxos-01.tst.norn.local - Platform: nxos
  64. Total: 8
  65. ==================================================
  66. ==================================================
  67. All devices which has parent group of test - using has_parent_group operation
  68. Host: tst-csr-01.tst.norn.local - Production: False
  69. Host: dfjt-r001.tst.norn.local - Production: False
  70. Host: tst-arista-01.tst.norn.local - Production: False
  71. Host: tstt-arista-02.tst.norn.local - Production: False
  72. Host: tst-junos-01.tst.norn.local - Production: False
  73. Host: tst-nxos-01.tst.norn.local - Production: False
  74. Host: tst-paloalto-01.tst.norn.local - Production: False
  75. Host: tst-paloalto-02.tst.norn.local - Production: False
  76. Host: tst-junos-06.tst.norn.local - Production: False
  77. Total: 9
  78. ==================================================
  79. ==================================================
  80. All devices which are in the list ['eos', 'paloalto_panos', 'junos'] - using in operation
  81. Host: lab-arista-01.lab.norn.local - Platform: eos
  82. Host: lab-arista-02.lab.norn.local - Platform: eos
  83. Host: lab-junos-01.lab.norn.local - Platform: junos
  84. Host: lab-paloalto-01.lab.djft.local - Platform: paloalto_panos
  85. Host: lab-paloalto-02.lab.norn.local - Platform: paloalto_panos
  86. Host: lab-junos-06.lab.norn.local - Platform: junos
  87. Host: prd-arista-01.prd.norn.local - Platform: eos
  88. Host: prd-arista-02.prd.nron.local - Platform: eos
  89. Host: prd-junos-01.prd.norn.local - Platform: junos
  90. Host: prd-paloalto-01.prd.norn.local - Platform: paloalto_panos
  91. Host: prd-paloalto-02.prd.norn.local - Platform: paloalto_panos
  92. Host: prd-junos-06.prd.norn.local - Platform: junos
  93. Host: tst-arista-01.tst.norn.local - Platform: eos
  94. Host: tstt-arista-02.tst.norn.local - Platform: eos
  95. Host: tst-junos-01.tst.norn.local - Platform: junos
  96. Host: tst-paloalto-01.tst.norn.local - Platform: paloalto_panos
  97. Host: tst-paloalto-02.tst.norn.local - Platform: paloalto_panos
  98. Host: tst-junos-06.tst.norn.local - Platform: junos
  99. Total: 18
  100. ==================================================
  101. ==================================================
  102. All devices which all the groups ['eos', 'prod', 'mel'] - using all operation
  103. Host: prd-arista-01.prd.norn.local - Groups: [Group: eos, Group: prod, Group: mel]
  104. Host: prd-arista-02.prd.nron.local - Groups: [Group: eos, Group: prod, Group: mel]
  105. Total: 2
  106. ==================================================

Filter functions

Filter functions are a powerful method of filtering your nornir inventory through another python function.

Using this method, you can write complex filtering logic and manage that in another function, then simply call them as needed.

In this example, we will introduce a few examples using regex to perform some analysis based on the hostnames, then call those from another function. This is just one idea of many that this can be used for so hopefully it helps spark your imagination.

  1. [20]:
  1. # Import modules
  2. from nornir import InitNornir
  3. from nornir.core.filter import F
  4. import re
  5. # Initialise nornir
  6. nr = InitNornir(config_file="filtering_deep_dive/config.yaml")
  7. """
  8. Below are some example filter functions, which we will call in later functions
  9. """
  10. def even_device_naming_convention(host):
  11. """
  12. Helper filter function to filter hosts based targeting
  13. host names which have even number names.
  14. Examples:
  15. - lab-junos-08.prd.norn.local
  16. - lab-arista-22.tst.norn.local
  17. - lab-nxos-64.lab.norn.local
  18. :param host: The host you want to filter on
  19. :return bool: True if it matches, False if it doesn't match
  20. """
  21. # Perform regex match on host name and return boolean
  22. if re.match(".+\-[0-9][2,4,6,8,0].+", host.name):
  23. return True
  24. else:
  25. return False
  26. def device_name_convention(host):
  27. """
  28. Helper filter function to filter hosts based targeting
  29. host names which a specified naming convention
  30. Examples:
  31. - lab-junos-08.tst.norn.local
  32. - lab-arista-22.prd.norn.local
  33. - lab-nxos-01.lab.norn.local
  34. :param host: The host you want to filter on
  35. :return bool: True if it matches, False if it doesn't match
  36. """
  37. # Perform regex match on host name and return boolean
  38. if re.match("\w{3}\-\w+\-\d{2}.\w{3}.norn.local", host.name):
  39. return True
  40. else:
  41. return False
  42. def non_device_name_convention(host):
  43. """
  44. Helper filter function to filter hosts based targeting
  45. host names which do NOT match a specified naming convention
  46. Examples:
  47. - lab-junos-08.tstt.norn.local
  48. - dfjt-arista-22.prd.norn.local
  49. - lab-nxos-001.lab.nron.local
  50. :param host: The host you want to filter on
  51. :return bool: True if does not match, False if it matches the convention
  52. """
  53. # Perform regex match on host name and return boolean
  54. if re.match("\w{3}\-\w+\-\d{2}.\w{3}.norn.local", host.name):
  55. return False
  56. else:
  57. return True
  58. def filter_functions(nr):
  59. """
  60. An example of wrapping filter functions to retrieve some more complex
  61. filtering queries.
  62. Three use cases are shown:
  63. - Use Case 1 - Filter inventory for "even" numbered devices.
  64. - Use Case 2 - Filter inventory for device which meet
  65. the naming convention.
  66. - Use Case 3 - Filter inventory for device which DO NOT meet
  67. the naming convention.
  68. :param nr: An initialised Nornir inventory, used for processing.
  69. """
  70. # We use the 'filter_func' option to run our entire inventory through the python
  71. # function called 'even_device_naming_convention'
  72. even_device_name_hosts = nr.filter(filter_func=even_device_naming_convention)
  73. # Print seperator and header
  74. print("=" * 50)
  75. print("The hosts which match the even device naming convention are:")
  76. # Iterate over filtered results and printout information
  77. for host, data in even_device_name_hosts.inventory.hosts.items():
  78. print(f"Host: {host} ")
  79. # Print total and seperator
  80. print(f"Total: {len(even_device_name_hosts.inventory.hosts.items())}")
  81. print("=" * 50)
  82. # Use Case 2 - Devices which match the naming convention
  83. # We use the 'filter_func' option to run our entire inventory through the python
  84. # function called 'device_name_convention'
  85. compliant_naming_convention_hosts = nr.filter(filter_func=device_name_convention)
  86. # Print seperator and header
  87. print("=" * 50)
  88. print("The hosts which match the device naming convention are:")
  89. # Iterate over filtered results and printout information
  90. for host, data in compliant_naming_convention_hosts.inventory.hosts.items():
  91. print(f"Host: {host} ")
  92. # Print total and seperator
  93. print(f"Total: {len(compliant_naming_convention_hosts.inventory.hosts.items())}")
  94. print("=" * 50)
  95. # Use Case 2 - Devices which DO NOT match the naming convention
  96. # We use the 'filter_func' option to run our entire inventory through the python
  97. # function called 'non_device_name_convention'
  98. non_compliant_naming_convention_hosts = nr.filter(filter_func=non_device_name_convention)
  99. # Print seperator and header
  100. print("=" * 50)
  101. print("The hosts which DO NOT match the device naming convention are:")
  102. # Iterate over filtered results and printout information
  103. for host, data in non_compliant_naming_convention_hosts.inventory.hosts.items():
  104. print(f"Host: {host} ")
  105. # Print total and seperator
  106. print(f"Total: {len(non_compliant_naming_convention_hosts.inventory.hosts.items())}")
  107. print("=" * 50)
  108. # Call wrapper function
  109. filter_functions(nr)
  1. ==================================================
  2. The hosts which match the even device naming convention are:
  3. Host: lab-arista-02.lab.norn.local
  4. Host: lab-paloalto-02.lab.norn.local
  5. Host: lab-junos-06.lab.norn.local
  6. Host: prd-arista-02.prd.nron.local
  7. Host: prd-paloalto-02.prd.norn.local
  8. Host: prd-junos-06.prd.norn.local
  9. Host: tstt-arista-02.tst.norn.local
  10. Host: tst-paloalto-02.tst.norn.local
  11. Host: tst-junos-06.tst.norn.local
  12. Total: 9
  13. ==================================================
  14. ==================================================
  15. The hosts which match the device naming convention are:
  16. Host: lab-arista-01.lab.norn.local
  17. Host: lab-arista-02.lab.norn.local
  18. Host: lab-junos-01.lab.norn.local
  19. Host: lab-nxos-01.lab.norn.local
  20. Host: lab-paloalto-02.lab.norn.local
  21. Host: lab-junos-06.lab.norn.local
  22. Host: prd-csr-01.prd.norn.local
  23. Host: prd-arista-01.prd.norn.local
  24. Host: prd-junos-01.prd.norn.local
  25. Host: prd-nxos-01.prd.norn.local
  26. Host: prd-paloalto-01.prd.norn.local
  27. Host: prd-paloalto-02.prd.norn.local
  28. Host: prd-junos-06.prd.norn.local
  29. Host: tst-csr-01.tst.norn.local
  30. Host: tst-arista-01.tst.norn.local
  31. Host: tst-junos-01.tst.norn.local
  32. Host: tst-nxos-01.tst.norn.local
  33. Host: tst-paloalto-01.tst.norn.local
  34. Host: tst-paloalto-02.tst.norn.local
  35. Host: tst-junos-06.tst.norn.local
  36. Total: 20
  37. ==================================================
  38. ==================================================
  39. The hosts which DO NOT match the device naming convention are:
  40. Host: lab-csr-011.lab.norn.local
  41. Host: dfjt-r001.lab.norn.local
  42. Host: lab-paloalto-01.lab.djft.local
  43. Host: dfjt-r001.prd.norn.local
  44. Host: prd-arista-02.prd.nron.local
  45. Host: dfjt-r001.tst.norn.local
  46. Host: tstt-arista-02.tst.norn.local
  47. Total: 7
  48. ==================================================

Conclusion

Thanks for following along with this tutorial. If you have got to this point, I’m sure you would agree that nornir filtering is powerful and limitless in it’s possibilities.

We have covered basic, intermediate and advanced filtering using network-automation specific use-cases. Hopefully this will give you some ideas and insipiration on how to leverage this feature.

There is also a helpful filtering cheatsheet which has been created for your reference.