def load(self) -> Inventory:
        if self.defaults_dict:
            defaults = _get_defaults(self.defaults_dict)
        else:
            defaults = Defaults()

        hosts = Hosts()
        hosts_dict = self.host_dict

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

        groups = Groups()
        if self.group_dict:
            groups_dict = self.group_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)
예제 #2
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 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) -> 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)
예제 #4
0
    def load(self) -> Inventory:

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

        hosts_redis = check_redis("nornir_hosts")
        groups_redis = check_redis("nornir_groups")

        if len(hosts_redis) > 0 and len(groups_redis) > 0:
            print(f"Found cached info in Redis and will used that")
            serialized_groups = groups_redis
            serialized_hosts = hosts_redis

        else:
            serialized_groups, lnetd_groups = _lnetd_get_groups(self.lnetd_db)
            serialized_hosts = _lnetd_get_hosts(self.lnetd_db, lnetd_groups)
            for h in serialized_hosts.values():
                h.groups = ParentGroups(
                    [serialized_groups[g] for g in h.groups])

            update_redis("nornir_hosts", serialized_hosts)
            update_redis("nornir_groups", serialized_groups)

        return Inventory(hosts=serialized_hosts,
                         groups=serialized_groups,
                         defaults=defaults)
예제 #5
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)
예제 #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(),
     )
예제 #7
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)
예제 #8
0
    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)
예제 #9
0
    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)
예제 #10
0
def _lnetd_get_groups(lnetd_db):
    conn = sqlite3.connect(lnetd_db)
    sql_groups = "select * from tag join tags on tag.id = tags.tag_id"
    df_groups = pd.read_sql(sql_groups, conn)
    df_groups.replace("", float("NaN"),
                      inplace=True)  # replace empty tags with NaN
    df_groups.dropna(inplace=True)  # drop NaN values
    lnetd_groups = df_groups.to_dict(orient="records")
    groups_initial = {}
    groups = Groups()
    defaults = Defaults()
    for gr in lnetd_groups:
        group: GroupDict = {"data": {}}
        group["data"]["role"] = gr["name"]
        groups_initial[gr["name"]] = group

    for group_name, group_data in groups_initial.items():

        groups[group_name] = _get_inventory_element(Group, group_data,
                                                    group_name, defaults)
    return groups, lnetd_groups
예제 #11
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())
예제 #12
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)
예제 #13
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)
예제 #14
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)
예제 #15
0
    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)
예제 #16
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)
예제 #17
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)