# py312
# requirements:
# pynetbox==7.9.0
from typing import List, Literal, Optional, TypedDict
import pynetbox
class netbox(TypedDict):
url: str
token: str
DynMultiselect_site = List[str]
DynMultiselect_role = List[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 page(records):
# One page (limit/offset), as NetBox's count plus the raw records.
results = [dict(r) for r in records]
return {"count": len(records), "results": results}
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")
def main(
auth: netbox,
site: Optional[DynMultiselect_site] = None,
role: Optional[DynMultiselect_role] = None,
status: Optional[
List[
Literal[
"offline",
"active",
"planned",
"staged",
"failed",
"inventory",
"decommissioning",
]
]
] = None,
tag: Optional[List[str]] = None,
name: Optional[str] = None,
custom_field_filters: Optional[dict] = None,
q: Optional[str] = None,
limit: Optional[int] = None,
offset: Optional[int] = None,
):
"""
List Devices
List devices filtered by sites, roles, status, tags (slugs), exact name or custom fields ({tier: "edge"} becomes cf_tier=edge). Returns NetBox's count and one page of raw devices, including platform and custom_fields.
"""
cf = {
k if k.startswith("cf_") else f"cf_{k}": v
for k, v in (custom_field_filters or {}).items()
}
records = api(auth).dcim.devices.filter(
**keep(site=site, role=role, status=status, tag=tag, name=name, q=q, **cf),
# limit=0 means NetBox's MAX_PAGE_SIZE, which also caps an explicit 1000.
limit=50 if limit is None else limit or 1000,
offset=offset or 0,
)
return page(records)
Submitted by hugo989 3 hours ago