def load(self): return Inventory( hosts=Hosts({ "h1": Host("h1"), "h2": Host("h2"), "h3": Host("h3") }), groups=Groups({"g1": Group("g1")}), defaults=Defaults(), )
def process_dc_data(group: Group, group_data: Dict[str, Dict[str, str]]) -> Hosts: """ Arguments: group: Current group we are processing group_data: the data for the entire group as returned by the backend """ # we create a placeholder for the hosts hosts = Hosts() # inside each datacenter we had a dictionary where the key was the hostname # and the data inside had some data about it, we iterate over the hosts for hostname, host_data in group_data.items(): # for each host we create a Host object mapping it's required parameters # with the data we got hosts[hostname] = Host( name=hostname, hostname=hostname, platform=host_data.pop("platform"), groups=ParentGroups([group ]), # we add the DC group as a parent group data={ "site": group.name, **host_data }, # extra data ) return hosts
def _process_special_reset_device(self, device: Host) -> None: device.data["special_reset"] = True pod_mgmt_interface = self.deployment.device_to_pod_mgmt_port[ device.name] device_name = pod_mgmt_interface.device_name pod_mgmt_interfaces = self.get_device( device_name=device_name).get("interfaces") pod_mgmt_interfaces[pod_mgmt_interface.num]["shutdown"] = True
def load_credentials(host: Host, username: Optional[str] = None, password: Optional[str] = None) -> None: """ load_credentials is an transform_functions to add credentials to every host. Environment variables `NORNIR_USERNAME` and `NORNIR_PASSWORD` or arguments can be used. Args: username: Device username password: Device password """ username = username if username is not None else os.getenv( "NORNIR_USERNAME") if username is not None: host.username = username password = password if password is not None else os.getenv( "NORNIR_PASSWORD") if password is not None: host.password = password
def create_result( result_content: Any, host: str = "", destination: Optional[str] = None, failed: bool = False, exception: Optional[BaseException] = None, **kwargs: Any ) -> Result: result = Result(host=Host(name=host), destination=destination, **kwargs) result.result = result_content result.failed = failed result.exception = exception return result
def subtask_instance_completed(self, task: Task, host: Host, result: MultiResult) -> None: """For each host, check if the results returned by the task is valid and cleanup results as needed. Args: task (Task): Nornir Task host (Host): Nornir Host result (MultiResult): Nornir Results """ if task.name != self.task_name: return if result[0].failed: LOGGER.warning( "%s | Something went wrong while trying to pull the neighbor information", host.name) host.status = "fail-other" return if not isinstance(result[0].result, dict) or "neighbors" not in result[0].result: LOGGER.warning("%s | No neighbor information returned", host.name) result[0].failed = True return interfaces = list(result[0].result["neighbors"].keys()) for interface in interfaces: neighbors = result[0].result["neighbors"][interface] if len(neighbors) > 1: LOGGER.warning( "%s | More than 1 neighbor found on interface %s, SKIPPING", host.name, interface) del result[0].result["neighbors"][interface] continue if is_mac_address(neighbors[0]["hostname"]): del result[0].result["neighbors"][interface] continue # Clean up hostname to remove full FQDN result[0].result["neighbors"][interface][0][ "hostname"] = self.clean_neighbor_name( neighbors[0]["hostname"]) # Clean up the portname if genie incorrectly capitalized it result[0].result["neighbors"][interface][0][ "port"] = self.clean_neighbor_port_name(neighbors[0]["port"])
def patch_inventory_delegate(inv: Inventory) -> Inventory: """ Patch nornir inventory configurations per cli arguments. Arguments: inv: nornir.core.inventory.Inventory object; Initialized Nornir Inventory object Returns: inv: nornir.core.inventory.Inventory object; Updated Nornir Inventory object Raises: N/A # noqa """ inv.hosts["delegate"] = Host(name="delegate") return inv
def _set_host(data: Dict[str, Any], name: str, groups, host, defaults) -> Host: connection_option = {} for key, value in data.get("connection_options", {}).items(): connection_option[key] = ConnectionOptions( hostname=value.get("hostname"), port=value.get("port"), username=value.get("username"), password=value.get("password"), platform=value.get("platform"), extras=value.get("extras"), ) return Host( name=name, hostname=host["hostname"], username=host["username"], password=host["password"], platform=host["platform"], data=data, groups=groups, defaults=defaults, connection_options=connection_option, )
from nornir import InitNornir from nornir.core.inventory import Host import json my_nornir = InitNornir(config_file="config.yaml") # this displays the default schema for the inventory # hosts and groups file. Defaults is same without repetition # for individual devices. print(json.dumps(Host.schema(), indent=4)) # my_nornir # now has an inventory with dict-like attributes hosts and groups print(my_nornir.inventory.hosts) print(my_nornir.inventory.groups) # you can access the like regular dictionaries print(my_nornir.inventory.hosts.keys()) print(my_nornir.inventory.hosts['R1']) # Showing inheritance hosts --> groups --> defaults router1 = my_nornir.inventory.hosts['R1'] rtr_priority = router1['priority'] print("Router1 priority is: " + str(rtr_priority)) router2 = my_nornir.inventory.hosts['R2'] print("Router2 priority is: {}".format(router2['priority'])) router4 = my_nornir.inventory.hosts['R4'] print("Router4 priority is: {}".format(router4['priority'])) # filters can be based on key: value pairs from the inventory yaml files
def subtask_instance_completed(self, task: Task, host: Host, result: MultiResult) -> None: """Verify the configuration returned and store it to disk. After collecting the configuration for each host. - Inspect the result and ensure the configuration is valid - If the configuration is valid, check the md5 - if the MD5 is different, write the new configuration to disk Args: task (Task): Nornir Task host (Host): Nornir Host result (MultiResult): Nornir MultiResult """ if task.name != self.task_name: return if result[0].failed: if result[0].exception: LOGGER.warning("%s | %s", task.host.name, result[0].exception) else: LOGGER.warning( "%s | Something went wrong while trying to update the configuration ", task.host.name) host.status = "fail-other" return conf = result[0].result.get("config", None) if not conf: LOGGER.warning("%s | No configuration return ", task.host.name) host.status = "fail-other" return # Count the number of lines in the config file, if less than 10 report an error # mostlikely something went wrong while pulling the config if conf.count("\n") < 10: LOGGER.warning("%s | Less than 10 configuration lines returned", task.host.name) host.status = "fail-other" return if host.name in self.existing_config_hostnames: self.existing_config_hostnames.remove(host.name) # Save configuration to file and verify the new MD5 with open(self.config_filename[host.name], "w") as config_: config_.write(conf) host.has_config = True self.current_md5[host.name] = hashlib.md5( conf.encode("utf-8")).hexdigest() # changed = False if host.name in self.previous_md5 and self.previous_md5[ host.name] == self.current_md5[host.name]: LOGGER.info("%s | Latest config file already present ...", task.host.name) else: LOGGER.info("%s | Configuration file updated", task.host.name)
def test_hosts(self): defaults = {"var4": "ALL"} g1 = Group(name="g1", var1="1", var2="2", var3="3") g2 = Group(name="g2", var1="a", var2="b") g3 = Group(name="g3", var1="A", var4="Z") g4 = Group(name="g4", groups=[g2, g1], var3="q") h1 = Host(name="host1", groups=[g1, g2], defaults=defaults) assert h1["var1"] == "1" assert h1["var2"] == "2" assert h1["var3"] == "3" assert h1["var4"] == "ALL" assert compare_lists( list(h1.keys()), ["name", "groups", "var1", "var2", "var3", "var4"] ) assert compare_lists( list(h1.values()), ["host1", ["g1", "g2"], "1", "2", "3", "ALL"] ) assert compare_lists( list(h1.items()), [ ("name", "host1"), ("groups", ["g1", "g2"]), ("var1", "1"), ("var2", "2"), ("var3", "3"), ("var4", "ALL"), ], ) h2 = Host(name="host2", groups=[g2, g1], defaults=defaults) assert h2["var1"] == "a" assert h2["var2"] == "b" assert h2["var3"] == "3" assert h2["var4"] == "ALL" assert compare_lists( list(h2.keys()), ["name", "groups", "var1", "var2", "var3", "var4"] ) assert compare_lists( list(h2.values()), ["host2", ["g2", "g1"], "a", "b", "3", "ALL"] ) assert compare_lists( list(h2.items()), [ ("name", "host2"), ("groups", ["g2", "g1"]), ("var1", "a"), ("var2", "b"), ("var3", "3"), ("var4", "ALL"), ], ) h3 = Host(name="host3", groups=[g4, g3], defaults=defaults) assert h3["var1"] == "a" assert h3["var2"] == "b" assert h3["var3"] == "q" assert h3["var4"] == "Z" assert compare_lists( list(h3.keys()), ["name", "groups", "var3", "var1", "var2", "var4"] ) assert compare_lists( list(h3.values()), ["host3", ["g4", "g3"], "q", "a", "b", "Z"] ) assert compare_lists( list(h3.items()), [ ("name", "host3"), ("groups", ["g4", "g3"]), ("var3", "q"), ("var1", "a"), ("var2", "b"), ("var4", "Z"), ], ) h4 = Host(name="host4", groups=[g3, g4], defaults=defaults) assert h4["var1"] == "A" assert h4["var2"] == "b" assert h4["var3"] == "q" assert h4["var4"] == "Z" assert compare_lists( list(h4.keys()), ["name", "groups", "var1", "var4", "var3", "var2"] ) assert compare_lists( list(h4.values()), ["host4", ["g3", "g4"], "A", "Z", "q", "b"] ) assert compare_lists( list(h4.items()), [ ("name", "host4"), ("groups", ["g3", "g4"]), ("var1", "A"), ("var4", "Z"), ("var3", "q"), ("var2", "b"), ], ) with pytest.raises(KeyError): assert h2["asdasd"]
C 10.0.0.0/24 is directly connected, GigabitEthernet1 L 10.0.0.15/32 is directly connected, GigabitEthernet1""" RAW_RESULT = "\n".join([IOSXE_SHOW_VERSION, IOSXE_SHOW_IP_ROUTE]) TEST_SCRAPLI_RESPONSE_ONE = Response(host="sea-ios-1", channel_input="show version", textfsm_platform="cisco_iosxe") TEST_SCRAPLI_RESPONSE_ONE._record_response(result=IOSXE_SHOW_VERSION) TEST_SCRAPLI_RESPONSE_TWO = Response(host="sea-ios-1", channel_input="show ip route", textfsm_platform="cisco_iosxe") TEST_SCRAPLI_RESPONSE_TWO._record_response(result=IOSXE_SHOW_IP_ROUTE) TEST_SCRAPLI_RESPONSE = [TEST_SCRAPLI_RESPONSE_ONE, TEST_SCRAPLI_RESPONSE_TWO] TEST_HOST = Host(name="sea-ios-1") TEST_AGG_RESULT = AggregatedResult("send_commands") TEST_MULTI_RESULT = MultiResult("send_commands") TEST_RESULT = Result(host=TEST_HOST, result=RAW_RESULT, name="send_commands") setattr(TEST_RESULT, "scrapli_response", TEST_SCRAPLI_RESPONSE) TEST_MULTI_RESULT.append(TEST_RESULT) TEST_AGG_RESULT[TEST_HOST.name] = TEST_MULTI_RESULT @pytest.mark.parametrize( "to_dict", [ ( True,
def load(self) -> Inventory: defaults = Defaults( connection_options={ "napalm": ConnectionOptions(extras={ "optional_args": { # args to eAPI HttpsEapiConnection for EOS "enforce_verification": True, "context": ssl_context } }) } ) insecure_device_states = [ DeviceState.INIT, DeviceState.DHCP_BOOT, DeviceState.PRE_CONFIGURED, DeviceState.DISCOVERED ] insecure_connection_options = { "napalm": ConnectionOptions(extras={ "optional_args": {"enforce_verification": False} }) } groups = Groups() for device_type in list(DeviceType.__members__): group_name = 'T_'+device_type groups[group_name] = Group(name=group_name, defaults=defaults) for device_state in list(DeviceState.__members__): username, password = self._get_credentials(device_state) group_name = 'S_'+device_state groups[group_name] = Group( name=group_name, username=username, password=password, defaults=defaults) for group_name in get_groups(): groups[group_name] = Group(name=group_name, defaults=defaults) hosts = Hosts() with cnaas_nms.db.session.sqla_session() as session: instance: Device for instance in session.query(Device): hostname = self._get_management_ip(instance.management_ip, instance.dhcp_ip) port = None if instance.port and isinstance(instance.port, int): port = instance.port host_groups = [ 'T_' + instance.device_type.name, 'S_' + instance.state.name ] for member_group in get_groups(instance.hostname): host_groups.append(member_group) if instance.state in insecure_device_states: host_connection_options = insecure_connection_options else: host_connection_options = None hosts[instance.hostname] = Host( name=instance.hostname, hostname=hostname, platform=instance.platform, groups=ParentGroups(groups[g] for g in host_groups), port=port, data={ 'synchronized': instance.synchronized, 'managed': (True if instance.state == DeviceState.MANAGED else False) }, connection_options=host_connection_options, defaults=defaults ) return Inventory(hosts=hosts, groups=groups, defaults=defaults)