Example #1
0
    def load(self) -> Inventory:
        yml = ruamel.yaml.YAML(typ="safe")

        if self.defaults_file.exists():
            with open(self.defaults_file, "r") as f:
                defaults_dict = yml.load(f) or {}
            defaults = _get_defaults(defaults_dict)
        else:
            defaults = Defaults()

        hosts = Hosts()
        with open(self.host_file, "r") as f:
            hosts_dict = yml.load(f)

        for n, h in hosts_dict.items():
            hosts[n] = _get_inventory_element(Host, h, n, defaults)

        groups = Groups()
        if self.group_file.exists():
            with open(self.group_file, "r") as f:
                groups_dict = yml.load(f) or {}

            for n, g in groups_dict.items():
                groups[n] = _get_inventory_element(Group, g, n, defaults)

            for g in groups.values():
                g.groups = ParentGroups([groups[g] for g in g.groups])

        for h in hosts.values():
            h.groups = ParentGroups([groups[g] for g in h.groups])

        return Inventory(hosts=hosts, groups=groups, defaults=defaults)
    def load(self) -> Inventory:
        """Standard Nornir 3 load method boilerplate."""
        if not self.credentials_params:
            self.credentials_params = {}

        # Initialize QuerySet
        if not self.queryset:
            self.queryset = Device.objects.all()

        if self.filters:
            self.queryset = self.queryset.filter(**self.filters)

        if not self.params:
            self.params = {}

        self.queryset = self.queryset.select_related(
            "device_role",
            "device_type",
            "device_type__manufacturer",
            "site",
            "platform",
            "tenant",
        )

        # Initialize Hosts and Groups vars
        hosts = Hosts()
        defaults = Defaults(data=self.defaults)
        groups = Groups()

        if self.credentials_params:
            cred = self.cred_class(params=self.credentials_params)
        else:
            cred = self.cred_class()

        # Create all hosts
        for device in self.queryset:
            host = self.create_host(device=device,
                                    cred=cred,
                                    params=self.params)
            hosts[device.name] = _set_host(data=host["data"],
                                           name=host["name"],
                                           groups=host["groups"],
                                           host=host,
                                           defaults=defaults)

            # Initialize all groups if they don't already exist
            for group in hosts[device.name].groups:
                if group not in groups.keys():
                    groups[group] = Group(name=group, defaults=defaults)

        for _host in hosts.values():
            _host.groups = ParentGroups(
                [groups[_group] for _group in _host.groups])
        for _group in groups.values():
            _group.groups = ParentGroups(
                [groups[_group] for _group in _group.groups])

        return Inventory(hosts=hosts, groups=groups, defaults=defaults)
Example #3
0
def nornir_ping_job(args):
    task, node, results = args
    nornir_inventory = {node.name: {'nornir_ip': node.ip_address}}
    external = Nornir(inventory=Inventory(nornir_inventory), dry_run=True)
    ping_result = external.run(networking.tcp_ping, ports=[23, 443])
    return {
        'success': all(res for res in ping_result[node.name].result.keys()),
        'logs': str(ping_result[node.name].result)
    }
Example #4
0
    def load(self) -> Inventory:

        nb_devices: List[Dict[str, Any]] = []

        nb_devices = self._get_resources(
            url=f"{self.nb_url}/api/dcim/devices/?limit=0",
            params=self.filter_parameters,
        )

        if self.include_vms:
            nb_devices.extend(
                self._get_resources(
                    url=f"{self.nb_url}/api/virtualization/virtual-machines/?limit=0",
                    params=self.filter_parameters,
                )
            )

        hosts = Hosts()
        groups = Groups()
        defaults = Defaults()

        for device in nb_devices:
            serialized_device: Dict[Any, Any] = {}
            serialized_device["data"] = device

            if self.flatten_custom_fields:
                for cf, value in device["custom_fields"].items():
                    serialized_device["data"][cf] = value
                serialized_device["data"].pop("custom_fields")

            hostname = None
            if device.get("primary_ip"):
                hostname = device.get("primary_ip", {}).get("address", "").split("/")[0]
            else:
                if device.get("name") is not None:
                    hostname = device["name"]
            serialized_device["hostname"] = hostname

            if isinstance(device["platform"], dict) and self.use_platform_slug:
                platform = device["platform"].get("slug")
            elif isinstance(device["platform"], dict):
                platform = device["platform"].get("name")
            else:
                platform = device["platform"]

            serialized_device["platform"] = platform

            name = serialized_device["data"].get("name") or str(
                serialized_device["data"].get("id")
            )

            hosts[name] = _get_inventory_element(
                Host, serialized_device, name, defaults
            )

        return Inventory(hosts=hosts, groups=groups, defaults=defaults)
Example #5
0
def job(script, task, device, results, incoming_payload):
    '''Script that uses Nornir to ping a device.'''
    nornir_inventory = {device.name: {'nornir_ip': device.ip_address}}
    external = Nornir(inventory=Inventory(nornir_inventory), dry_run=True)
    ping_result = external.run(networking.tcp_ping, ports=[23, 443])
    return (
        all(res for res in ping_result[device.name].result.keys()),
        str(ping_result[device.name].result),
        incoming_payload,
    )
Example #6
0
 def load(self):
     return Inventory(
         hosts=Hosts({
             "h1": Host("h1"),
             "h2": Host("h2"),
             "h3": Host("h3")
         }),
         groups=Groups({"g1": Group("g1")}),
         defaults=Defaults(),
     )
Example #7
0
def job(args):
    # Script that uses Nornir to ping a device
    task, device, results, payloads = args
    nornir_inventory = {device.name: {'nornir_ip': device.ip_address}}
    external = Nornir(inventory=Inventory(nornir_inventory), dry_run=True)
    ping_result = external.run(networking.tcp_ping, ports=[23, 443])
    results[device.name] = {
        'success': all(res for res in ping_result[device.name].result.keys()),
        'payload': payloads,
        'logs': str(ping_result[device.name].result)
    }
    def load(self) -> Inventory:

        url = f"{self.nb_url}/api/dcim/devices/?limit=0"
        nb_devices: List[Dict[str, Any]] = []

        while url:
            r = self.session.get(url, params=self.filter_parameters)

            if not r.status_code == 200:
                raise ValueError(
                    f"Failed to get devices from NetBox instance {self.nb_url}"
                )

            resp = r.json()
            nb_devices.extend(resp.get("results"))

            url = resp.get("next")

        hosts = Hosts()
        groups = Groups()
        defaults = Defaults()

        for device in nb_devices:
            serialized_device: Dict[Any, Any] = {}
            serialized_device["data"] = device

            if self.flatten_custom_fields:
                for cf, value in device["custom_fields"].items():
                    serialized_device["data"][cf] = value
                serialized_device["data"].pop("custom_fields")

            hostname = None
            if device.get("primary_ip"):
                hostname = device.get("primary_ip", {}).get("address",
                                                            "").split("/")[0]
            else:
                if device.get("name") is not None:
                    hostname = device["name"]
            serialized_device["hostname"] = hostname

            platform = (device["platform"]["name"] if isinstance(
                device["platform"], dict) else device["platform"])
            serialized_device["platform"] = platform

            name = serialized_device["data"].get("name") or str(
                serialized_device["data"].get("id"))

            hosts[name] = _get_inventory_element(Host, serialized_device, name,
                                                 defaults)

        return Inventory(hosts=hosts, groups=groups, defaults=defaults)
def update_description(inventory: Inventory) -> None:
    infra_devices = inventory.filter(
        F(has_parent_group='infra')).hosts.values()
    for device in infra_devices:
        for interface in device.get('interfaces', []):
            if 'connected_device' in interface:
                connected_device_info = interface["connected_device"]
                connected_device_name = connected_device_info["name"]
                port = connected_device_info["port"]
                connected_device = inventory.hosts[connected_device_name]
                rack = connected_device['rack']
                rack_unit = connected_device['rack_unit']
                description = (
                    f"To Rack {rack} RU {rack_unit} -> {connected_device_name} {port}"
                )
                interface["description"] = description
Example #10
0
    def load(self) -> Inventory:
        nr_defaults = _get_defaults(self.defaults)

        nr_hosts = {
            n: _get_inventory_element(Host, h, n, nr_defaults)
            for n, h in self.hosts.items()
        }

        nr_groups = {
            n: _get_inventory_element(Group, g, n, nr_defaults)
            for n, g in self.groups.items()
        }

        for h in nr_hosts.values():
            h.groups = ParentGroups([nr_groups[g] for g in h.groups])
        for g in nr_groups.values():
            g.groups = ParentGroups([groups[g] for g in g.groups])
        return Inventory(hosts=nr_hosts, groups=nr_groups, defaults=nr_defaults)
Example #11
0
    def load(self) -> Inventory:
        defaults = _get_defaults(self.defaults_dict)

        hosts = Hosts()
        hosts_dict = _get_devices_excel(self._excel_file)
        for n, h in hosts_dict.items():
            hosts[n] = _get_inventory_element(Host, h, n, defaults)

        groups = Groups()
        for n, g in self.groups_dict.items():
            groups[n] = _get_inventory_element(Group, g, n, defaults)

        for h in hosts.values():
            h.groups = ParentGroups([groups[g] for g in h.groups])

        for g in groups.values():
            g.groups = ParentGroups([groups[g] for g in g.groups])

        return Inventory(hosts=hosts, groups=groups, defaults=defaults)
Example #12
0
    def load(self) -> Inventory:
        """Return nornir Inventory object."""
        serialized_defaults = _get_defaults(self.defaults)

        serialized_hosts = {}
        for host_name, host_data in self.hosts.items():
            serialized_hosts[host_name] = _get_inventory_element(
                Host, host_data, host_name, serialized_defaults)

        serialized_groups = {}
        for group_name, group_data in self.groups.items():
            serialized_groups[group_name] = _get_inventory_element(
                Group, group_data, group_name, serialized_defaults)

        for h in serialized_hosts.values():
            h.groups = ParentGroups([serialized_groups[g] for g in h.groups])

        for g in serialized_groups.values():
            g.groups = ParentGroups([serialized_groups[g] for g in g.groups])

        return Inventory(hosts=serialized_hosts,
                         groups=serialized_groups,
                         defaults=serialized_defaults)
    def load(self) -> Inventory:

        if self.defaults_file.exists():
            with open(self.defaults_file, "r") as f:
                try:
                    defaults_dict = json.load(f)
                except JSONDecodeError:
                    defaults_dict = {}
            defaults = _get_defaults(defaults_dict)
        else:
            defaults = Defaults()

        hosts = Hosts()

        with open(self.host_file, "r") as f:
            hosts_dict = json.load(f)

        for n, h in hosts_dict.items():
            hosts[n] = _get_inventory_element(Host, h, n, defaults)

        groups = Groups()
        if self.group_file.exists():
            with open(self.group_file, "r") as f:
                try:
                    groups_dict = json.load(f)
                except JSONDecodeError:
                    groups_dict = {}
            for n, g in groups_dict.items():
                groups[n] = _get_inventory_element(Group, g, n, defaults)

            for h in hosts.values():
                h.groups = ParentGroups([groups[g] for g in h.groups])

            for g in groups.values():
                g.groups = ParentGroups([groups[g] for g in g.groups])

        return Inventory(hosts=hosts, groups=groups, defaults=defaults)
Example #14
0
    def load(self) -> Inventory:
        # we retrieve the data from the inventory passing the options we saved
        # in he constructor
        data = self.conn.get(self.filter_sites, self.filter_dev_types)

        # we create placeholder for the hosts and for the groups
        hosts = Hosts()
        groups = Groups()

        # the inventory returned the hosts by datacenter so we iterate over them
        for dc_name, dc_data in data.items():
            # we are going to start bt creating a group per DC
            groups[dc_name] = Group(dc_name)

            # now we process the dc data we got
            hosts_in_dc = process_dc_data(groups[dc_name], dc_data)

            # we add the hosts in the dc to the main hosts object
            hosts.update(hosts_in_dc)

        # we populate the inventory and return it
        # note our inventory doesn't support defaults so we just return
        # and empty object
        return Inventory(hosts=hosts, groups=groups, defaults=Defaults())
Example #15
0
    def load(self) -> Inventory:

        if len(self.defaults_dict) > 0:
            defaults = _get_defaults(self.defaults_dict)
        else:
            defaults = Defaults()

        hosts = Hosts()

        for n, h in self.hosts_dict.items():
            hosts[n] = _get_inventory_element(Host, h, n, defaults)

        groups = Groups()
        if len(self.groups_dict) > 0:
            for n, g in self.groups_dict.items():
                groups[n] = _get_inventory_element(Group, g, n, defaults)

            for h in hosts.values():
                h.groups = ParentGroups([groups[g] for g in h.groups])

            for g in groups.values():
                g.groups = ParentGroups([groups[g] for g in g.groups])

        return Inventory(hosts=hosts, groups=groups, defaults=defaults)
    def load(self):
        """Load inventory by fetching devices from netbox."""
        if self.filter_parameters:
            devices: List[pynetbox.modules.dcim.
                          Devices] = self.session.dcim.devices.filter(
                              **self.filter_parameters)
        else:
            devices: List[pynetbox.modules.dcim.
                          Devices] = self.session.dcim.devices.all()

        # fetch all platforms from Netbox and build mapping:   platform:  napalm_driver
        platforms = self.session.dcim.platforms.all()
        platforms_mapping = {
            platform.slug: platform.napalm_driver
            for platform in platforms if platform.napalm_driver
        }

        hosts = Hosts()
        groups = Groups()
        defaults = Defaults()

        for dev in devices:
            # Netbox allows devices to be unnamed, but the Nornir model does not allow this
            # If a device is unnamed we will set the name to the id of the device in netbox
            dev_name = dev.name or dev.id
            host = NetworkImporterHost(name=dev_name,
                                       connection_options=ConnectionOptions())

            # Only add virtual chassis master as inventory element
            if dev.virtual_chassis and dev.virtual_chassis.master:
                if dev.id != dev.virtual_chassis.master.id:
                    continue
                host.data["virtual_chassis"] = True

            else:
                host.data["virtual_chassis"] = False

            # If supported_platforms is provided
            # skip all devices that do not match the list of supported platforms
            # TODO need to see if we can filter when doing the query directly
            if self.supported_platforms:
                if not dev.platform:
                    continue

                if dev.platform.slug not in self.supported_platforms:
                    continue

            # Add value for IP address
            if self.settings.use_primary_ip and dev.primary_ip:
                host.hostname = dev.primary_ip.address.split("/")[0]
            elif self.settings.use_primary_ip and not dev.primary_ip:
                host.is_reachable = False
                host.not_reachable_reason = "primary ip not defined in Netbox"
            elif not self.settings.use_primary_ip and self.settings.fqdn:
                host.hostname = f"{dev.name}.{self.settings.fqdn}"
            elif not self.settings.use_primary_ip:
                host.hostname = dev.name
            else:
                host.hostname = dev_name

            host.site_name = dev.site.slug

            host.data["serial"] = dev.serial
            host.data["vendor"] = dev.device_type.manufacturer.slug
            host.data["asset_tag"] = dev.asset_tag
            host.data["custom_fields"] = dev.custom_fields
            host.data["site_id"] = dev.site.id
            host.data["device_id"] = dev.id
            host.data["role"] = dev.device_role.slug
            host.data["model"] = dev.device_type.slug

            # Attempt to add 'platform' based of value in 'slug'
            if dev.platform and dev.platform.slug in platforms_mapping:
                host.connection_options = {
                    "napalm":
                    ConnectionOptions(
                        platform=platforms_mapping[dev.platform.slug])
                }

            if dev.platform:
                host.platform = dev.platform.slug
            else:
                host.platform = None

            host.groups = ParentGroups([self.global_group])

            if dev.site.slug not in groups.keys():
                groups[dev.site.slug] = {}

            if dev.device_role.slug not in groups.keys():
                groups[dev.device_role.slug] = {}

            if host.hostname and host.platform:
                host.is_reachable = True

            # Assign temporary dict to outer dict

            hosts[dev_name] = host

        return Inventory(hosts=hosts, groups=groups, defaults=defaults)
Example #17
0
    def load(self) -> Inventory:
        yml = ruamel.yaml.YAML(typ="safe")

        platforms: List[Dict[str, Any]] = []

        if self.use_platform_napalm_driver:
            platforms = self._get_resources(
                url=f"{self.nb_url}/api/dcim/platforms/?limit=0", params={})

        nb_devices: List[Dict[str, Any]] = []

        nb_devices = self._get_resources(
            url=f"{self.nb_url}/api/dcim/devices/?limit=0",
            params=self.filter_parameters,
        )

        if self.include_vms:
            nb_devices.extend(
                self._get_resources(
                    url=
                    f"{self.nb_url}/api/virtualization/virtual-machines/?limit=0",
                    params=self.filter_parameters,
                ))

        hosts = Hosts()
        groups = Groups()
        defaults = Defaults()

        if self.defaults_file.exists():
            with self.defaults_file.open("r") as f:
                defaults_dict = yml.load(f) or {}
            defaults = _get_defaults(defaults_dict)
        else:
            defaults = Defaults()

        if self.group_file.exists():
            with self.group_file.open("r") as f:
                groups_dict = yml.load(f) or {}

            for n, g in groups_dict.items():
                groups[n] = _get_inventory_element(Group, g, n, defaults)

            for g in groups.values():
                g.groups = ParentGroups([groups[g] for g in g.groups])

        for device in nb_devices:
            serialized_device: Dict[Any, Any] = {}
            serialized_device["data"] = device

            if self.flatten_custom_fields:
                for cf, value in device["custom_fields"].items():
                    serialized_device["data"][cf] = value
                serialized_device["data"].pop("custom_fields")

            hostname = None
            if device.get("primary_ip"):
                hostname = device.get("primary_ip", {}).get("address",
                                                            "").split("/")[0]
            else:
                if device.get("name") is not None:
                    hostname = device["name"]
            serialized_device["hostname"] = hostname

            if isinstance(device["platform"], dict) and self.use_platform_slug:
                platform = device["platform"].get("slug")
            elif (isinstance(device["platform"], dict)
                  and self.use_platform_napalm_driver):
                platform = [
                    platform for platform in platforms
                    if device["platform"]["slug"] == platform["slug"]
                ][0]["napalm_driver"]
            elif isinstance(device["platform"], dict):
                platform = device["platform"].get("name")
            else:
                platform = device["platform"]

            serialized_device["platform"] = platform

            name = serialized_device["data"].get("name") or str(
                serialized_device["data"].get("id"))

            hosts[name] = _get_inventory_element(Host, serialized_device, name,
                                                 defaults)

            groups_extracted = self._extract_device_groups(device)

            for group in groups_extracted:
                if group not in groups.keys():
                    groups[group] = _get_inventory_element(
                        Group, {}, group, defaults)

            hosts[name].groups = ParentGroups(
                [groups[g] for g in groups_extracted])

        return Inventory(hosts=hosts, groups=groups, defaults=defaults)
Example #18
0
    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)
Example #19
0
    def load(self) -> Inventory:

        url = f"{self.base_url}/api/dcim/devices/?limit=0"

        nb_devices: List[Dict[str, Any]] = []

        while url:
            r = self.session.get(url, params=self.filter_parameters)

            if not r.status_code == 200:
                raise ValueError(
                    f"Failed to get devices from NetBox instance {self.base_url}"
                )

            resp = r.json()
            nb_devices.extend(resp.get("results"))

            url = resp.get("next")

        hosts = Hosts()
        groups = Groups()
        defaults = Defaults()

        for device in nb_devices:

            serialized_device: Dict[Any, Any] = {}
            serialized_device["data"] = {}
            serialized_device["data"]["serial"] = device.get("serial")
            serialized_device["data"]["vendor"] = (device.get(
                "device_type", {}).get("manufacturer", {}).get("name"))
            serialized_device["data"]["asset_tag"] = device.get("asset_tag")

            if self.flatten_custom_fields:
                for key, value in device.get("custom_fields", {}).items():
                    serialized_device["data"][key] = value
            else:
                serialized_device["data"]["custom_fields"] = device.get(
                    "custom_fields", {})

            if self.use_slugs:
                serialized_device["data"]["site"] = device.get("site",
                                                               {}).get("slug")
                serialized_device["data"]["role"] = device.get(
                    "device_role", {}).get("slug")
                serialized_device["data"]["model"] = device.get(
                    "device_type", {}).get("slug")
                serialized_device["platform"] = (
                    device["platform"]["slug"] if isinstance(
                        device["platform"], dict) else device["platform"])
            else:
                serialized_device["data"]["site"] = device.get("site",
                                                               {}).get("name")
                serialized_device["data"]["role"] = device.get("device_role")
                serialized_device["data"]["model"] = device.get("device_type")
                serialized_device["platform"] = (
                    device["platform"]["name"] if isinstance(
                        device["platform"], dict) else device["platform"])

            serialized_device["hostname"] = None
            if device.get("primary_ip"):
                serialized_device["hostname"] = (device.get(
                    "primary_ip", {}).get("address", "").split("/")[0])
            else:
                if device.get("name") is not None:
                    serialized_device["hostname"] = device["name"]

            name = device.get("name") or str(device.get("id"))

            hosts[name] = _get_inventory_element(Host, serialized_device, name,
                                                 defaults)

        return Inventory(hosts=hosts, groups=groups, defaults=defaults)
Example #20
0
    def load(self) -> Inventory:
        """
        Load inventory
        """

        url = f"{self.ipf_url}/api/v1/tables/inventory/devices"

        if self.ipf_token:
            headers = {
                "Content-type": "application/json",
                "X-API-Token": self.ipf_token,
            }
        else:
            credentials = b64encode(
                f"{self.ipf_user}:{self.ipf_password}".encode("utf-8")).decode(
                    "utf-8")
            headers = {
                "Content-type": "application/json",
                "Authorization": f"Basic {credentials}",
            }
        data = {
            "columns": [
                "loginIp",
                "family",
                "hostname",
                "platform",
                "loginType",
                "sn",
                "siteName",
                "vendor",
                "version",
            ],
            "filters": {},
            "snapshot":
            self.ipf_snapshot,
        }
        try:  # get device inventory from IP Fabric
            deviceInventory = requests.post(
                url,
                data=json.dumps(data),
                headers=headers,
                verify=self.ssl_verify,
            )
        except:
            raise ValueError(
                f"Failed to get devices from IP Fabric {self.ipf_url}")

        if not deviceInventory.status_code == 200:
            raise ValueError(
                f"Failed to get devices from IP Fabric {self.ipf_url}")

        ipf_devices = json.loads(deviceInventory.content).get("data")

        groups = Groups()

        username = self.default.get("username", None)
        password = self.default.get("password", None)
        defaults = Defaults(username=username, password=password)

        serialized_hosts = {}
        for device in ipf_devices:
            serialized_hosts[device.get("loginIp")] = _get_inventory_element(
                Host, device, defaults)

        return Inventory(hosts=serialized_hosts,
                         groups=groups,
                         defaults=defaults)
def update_matrix(
    inventory: Inventory,
    topologies: Dict[str, TopologyDict],
    deployment: DeploymentDict,
) -> None:

    # (lab_hostname, pod_number) -> device hostname in inventory
    # (edge-1, 1000) -> 9348-1

    hostname_and_pod_num_to_device: Dict[Tuple[str, int], str] = {}

    for device, device_info in deployment["devices"].items():
        pod_number = device_info["pod_number"]
        lab_hostname = device_info["lab_hostname"]
        hostname_and_pod_num_to_device[(lab_hostname, pod_number)] = device

    # (R1, Ethernet1/1) -> ('matrix-1', 1)
    device_port_to_matrix_port = {}

    matrix_switches = inventory.filter(F(has_parent_group="matrix-switches")).hosts.values()

    for matrix_switch in matrix_switches:
        for port_number, matrix_interface in enumerate(
            matrix_switch.get("interfaces", [])
        ):
            if matrix_interface.get("mode") == "dot1q-tunnel":
                if "connected_device" not in matrix_interface:
                    raise ValueError(
                        f"Interface {matrix_interface['name']} on the switch "
                        f"{matrix_switch.name} is "
                        f"dot1q-tunnel but does not have connected_device variable"
                    )

                connected_device = matrix_interface["connected_device"]["name"]
                connected_device_port = matrix_interface["connected_device"]["port"]
                # print(connected_device_port, connected_device_name)
                device_port_to_matrix_port[
                    (connected_device, connected_device_port)
                ] = (matrix_switch.name, port_number)

    current_dot1q_tunnel_vlan = matrix_switch.get("dot1q_tunnel_vlan_start")

    for pod in deployment["pods"]:
        pod_number = pod["pod_number"]
        topology = pod["topology"]
        for connection in topologies[topology]["connections"]:
            for connection_end in connection:
                lab_hostname = connection_end["lab_hostname"]
                port = connection_end["port"]
                device = hostname_and_pod_num_to_device[(lab_hostname, pod_number)]
                pod_device = inventory.hosts[device]
                if (
                    pod_device.get("lab_hostname", lab_hostname) != lab_hostname
                    and pod_device.get("pod_number", pod_number) != pod_number
                ):
                    raise ValueError(
                        f"Trying to assign lab hostname '{lab_hostname}' "
                        f"and pod number '{pod_number}', "
                        f"but this device already has"
                        f"lab hostname '{pod_device.name}'"
                        f'and pod number "{pod_device.get("pod_number")}" assigned'
                    )

                else:
                    pod_device["lab_hostname"] = lab_hostname
                    pod_device["pod_number"] = pod_number
                    pod_device["lab_template"] = topology
                    pod_device["updated_vars"] = [
                        "lab_hostname",
                        "pod_number",
                        "lab_template",
                    ]

                (
                    matrix_switch_name,
                    matrix_switch_port_number,
                ) = device_port_to_matrix_port[(device, port)]

                matrix_switch = inventory.hosts[matrix_switch_name]
                matrix_interface = matrix_switch["interfaces"][
                    matrix_switch_port_number
                ]
                if "access_vlan" in matrix_interface:
                    raise ValueError(
                        f"{matrix_switch.name} already has vlan "
                        f"assigned to the interface {mastrix_interface['name']}"
                    )

                elif matrix_interface.get("mode") != "dot1q-tunnel":
                    raise ValueError(
                        f"{matrix_switch.name} interface {matrix_interface['name']} "
                        f"has mode {matrix_interface['mode']} "
                        f"instead of 'dot1q-tunnel'"
                    )

                else:
                    matrix_interface["access_vlan"] = current_dot1q_tunnel_vlan
                    matrix_interface["shutdown"] = False
                    matrix_interface["dynamic"] = True
                    matrix_interface["description"] = (
                        f"connected to {port} {device} "
                        f"| lab hostname: {lab_hostname} "
                        f"| pod: {pod_number}"
                    )
                    # matrix_switch_vars["updated_vars"] = ["interfaces"]

            current_dot1q_tunnel_vlan += 1

        # for the next pod start with the vlan divisible by 10
        remainder = current_dot1q_tunnel_vlan % 10
        if remainder:
            current_dot1q_tunnel_vlan += 10 - remainder

    for matrix_switch in matrix_switches:
        for matrix_interface in matrix_switch["interfaces"]:
            if (
                matrix_interface.get("access_vlan") is None
                and matrix_interface.get("mode") == "dot1q-tunnel"
            ):
                matrix_interface["shutdown"] = True
Example #22
0
def inventory_from_yaml():
    dir_path = os.path.dirname(os.path.realpath(__file__))
    yml = ruamel.yaml.YAML(typ="safe")

    def get_connection_options(data):
        cp = {}
        for cn, c in data.items():
            cp[cn] = ConnectionOptions(
                hostname=c.get("hostname"),
                port=c.get("port"),
                username=c.get("username"),
                password=c.get("password"),
                platform=c.get("platform"),
                extras=c.get("extras"),
            )
        return cp

    def get_defaults():
        defaults_file = f"{dir_path}/inventory_data/defaults.yaml"
        with open(defaults_file, "r") as f:
            defaults_dict = yml.load(f)

            defaults = Defaults(
                hostname=defaults_dict.get("hostname"),
                port=defaults_dict.get("port"),
                username=defaults_dict.get("username"),
                password=defaults_dict.get("password"),
                platform=defaults_dict.get("platform"),
                data=defaults_dict.get("data"),
                connection_options=get_connection_options(
                    defaults_dict.get("connection_options", {})),
            )

        return defaults

    def get_inventory_element(typ, data, name, defaults):
        return typ(
            name=name,
            hostname=data.get("hostname"),
            port=data.get("port"),
            username=data.get("username"),
            password=data.get("password"),
            platform=data.get("platform"),
            data=data.get("data"),
            groups=data.get(
                "groups"
            ),  # this is a hack, we will convert it later to the correct type
            defaults=defaults,
            connection_options=get_connection_options(
                data.get("connection_options", {})),
        )

    host_file = f"{dir_path}/inventory_data/hosts.yaml"
    group_file = f"{dir_path}/inventory_data/groups.yaml"

    defaults = get_defaults()

    hosts = Hosts()
    with open(host_file, "r") as f:
        hosts_dict = yml.load(f)

    for n, h in hosts_dict.items():
        hosts[n] = get_inventory_element(Host, h, n, defaults)

    groups = Groups()
    with open(group_file, "r") as f:
        groups_dict = yml.load(f)

    for n, g in groups_dict.items():
        groups[n] = get_inventory_element(Group, g, n, defaults)

    for h in hosts.values():
        h.groups = ParentGroups([groups[g] for g in h.groups])

    for g in groups.values():
        g.groups = ParentGroups([groups[g] for g in g.groups])

    return Inventory(hosts=hosts, groups=groups, defaults=defaults)
def getHosts():
    #whatever you need to do to return the hosts dict
    yml = ruamel.yaml.YAML(typ="safe")
    hosts_file = "inventory/hosts2.yaml"
    with open(hosts_file, "r") as f:
        hosts_dict = yml.load(f)
    return hosts_dict


def buildHosts(hosts_dict):
    #remember no groups or defaults
    hosts = Hosts()
    for n, h in hosts_dict.items():
        h.pop('groups', None)
        hosts[n] = _get_inventory_element(Host, h, n, {})
    return hosts


#you will still need a default dictionary to load, but overwrite after
nr = InitNornir(config_file='config.yaml', )
print(len(nr.inventory.hosts))

setattr(nr, 'inventory',
        Inventory(hosts=buildHosts(getHosts()), groups={}, defaults={}))
print(len(nr.inventory.hosts))

agg_result = nr.run(task=show_version)
for hostname, multi_result in agg_result.items():
    print(hostname, multi_result[1].result)