Edits history of script submission #23935 for ' Select Devices (netbox)'

  • python3
    One script reply has been approved by the moderators
    Ap­pro­ved
    # py312
    # requirements:
    # pynetbox==7.9.0
    
    
    from typing import List, Literal, Optional, TypedDict
    
    import pynetbox
    
    
    class netbox(TypedDict):
        url: str
        token: str
    
    
    DynSelect_site = str
    DynSelect_role = str
    
    
    def api(auth: netbox):
        # pynetbox adds /api itself; the resource URL may already end with it.
        return pynetbox.api(
            auth["url"].rstrip("/").removesuffix("/api"), token=auth["token"]
        )
    
    
    def keep(**fields):
        # The run form sends "" / [] / {} for untouched fields: drop them.
        return {k: v for k, v in fields.items() if v not in (None, "", [], {})}
    
    
    def options(endpoint, key="id", **filters):
        return [
            {"value": str(getattr(r, key)), "label": r.display}
            for r in endpoint.filter(brief=1, limit=1000, offset=0, **filters)
        ]
    
    
    # Dropdown of the instance's sites, by slug: the first 1000 (NetBox MAX_PAGE_SIZE); set the value by expression beyond that.
    def site(auth: netbox):
        return options(api(auth).dcim.sites, "slug")
    
    
    # Dropdown of the instance's device roles, by slug.
    def role(auth: netbox):
        return options(api(auth).dcim.device_roles, "slug")
    
    
    DynMultiselect_device_ids = List[str]
    
    
    # Candidate devices for the chosen site, role and status: the first 1000; use all_matching beyond that.
    def device_ids(
        auth: netbox,
        site: DynSelect_site,
        role: DynSelect_role,
        status: Optional[List[str]] = None,
    ):
        if not site or not role:
            return []
        return options(api(auth).dcim.devices, **keep(site=site, role=role, status=status))
    
    
    def main(
        auth: netbox,
        site: DynSelect_site,
        role: DynSelect_role,
        status: Optional[
            List[
                Literal[
                    "offline",
                    "active",
                    "planned",
                    "staged",
                    "failed",
                    "inventory",
                    "decommissioning",
                ]
            ]
        ] = None,
        device_ids: Optional[DynMultiselect_device_ids] = None,
        all_matching: bool = False,
    ):
        """
        Select Devices
        Pick devices of a site and role (optionally by status) from a live list, or take all of them, and return their raw NetBox JSON, including platform.name and custom_fields.
        """
        if not all_matching and not device_ids:
            return []
        # pynetbox sends a None filter as "null", so drop the empty ones.
        filters = keep(
            site=site, role=role, status=status, id=None if all_matching else device_ids
        )
    
        # Page by offset: pynetbox's full iteration requests NetBox's next links
        # as is, and behind a proxy their host or scheme can be internal.
        endpoint, devices = api(auth).dcim.devices, []
        while True:
            records = endpoint.filter(**filters, limit=1000, offset=len(devices))
            batch = [dict(r) for r in records]
            devices += batch
            if not batch or len(devices) >= len(records):
                return devices
    

    Submitted by hugo989 3 hours ago