1 | # py312 |
2 | # requirements: |
3 | # pynetbox==7.9.0 |
4 |
|
5 |
|
6 | from typing import List, Literal, Optional, TypedDict |
7 |
|
8 | import pynetbox |
9 |
|
10 |
|
11 | class netbox(TypedDict): |
12 | url: str |
13 | token: str |
14 |
|
15 |
|
16 | DynSelect_site_id = str |
17 | DynSelect_role_id = str |
18 | DynSelect_device_type_id = str |
19 |
|
20 |
|
21 | def api(auth: netbox): |
22 | # pynetbox adds /api itself; the resource URL may already end with it. |
23 | return pynetbox.api( |
24 | auth["url"].rstrip("/").removesuffix("/api"), token=auth["token"] |
25 | ) |
26 |
|
27 |
|
28 | def keep(**fields): |
29 | # The run form sends "" / [] / {} for untouched fields: drop them. |
30 | return {k: v for k, v in fields.items() if v not in (None, "", [], {})} |
31 |
|
32 |
|
33 | def options(endpoint, key="id", **filters): |
34 | return [ |
35 | {"value": str(getattr(r, key)), "label": r.display} |
36 | for r in endpoint.filter(brief=1, limit=1000, offset=0, **filters) |
37 | ] |
38 |
|
39 |
|
40 | # Dropdown of the instance's sites: the first 1000 (NetBox MAX_PAGE_SIZE); set the value by expression beyond that. |
41 | def site_id(auth: netbox): |
42 | return options(api(auth).dcim.sites) |
43 |
|
44 |
|
45 | # Dropdown of the instance's device roles. |
46 | def role_id(auth: netbox): |
47 | return options(api(auth).dcim.device_roles) |
48 |
|
49 |
|
50 | # Dropdown of the instance's device types. |
51 | def device_type_id(auth: netbox): |
52 | return options(api(auth).dcim.device_types) |
53 |
|
54 |
|
55 | def main( |
56 | auth: netbox, |
57 | name: str, |
58 | site_id: DynSelect_site_id, |
59 | role_id: DynSelect_role_id, |
60 | device_type_id: DynSelect_device_type_id, |
61 | status: Optional[ |
62 | Literal[ |
63 | "offline", |
64 | "active", |
65 | "planned", |
66 | "staged", |
67 | "failed", |
68 | "inventory", |
69 | "decommissioning", |
70 | ] |
71 | ] = None, |
72 | platform_id: Optional[int] = None, |
73 | rack_id: Optional[int] = None, |
74 | serial: Optional[str] = None, |
75 | description: Optional[str] = None, |
76 | tags: Optional[List[str]] = None, |
77 | custom_fields: Optional[dict] = None, |
78 | ): |
79 | """ |
80 | Create Device |
81 | Create a device in a site with a role and device type. Tags are slugs; custom_fields is a {name: value} object. |
82 | """ |
83 | body = keep( |
84 | name=name, |
85 | site=int(site_id), |
86 | role=int(role_id), |
87 | device_type=int(device_type_id), |
88 | status=status, |
89 | platform=platform_id, |
90 | rack=rack_id, |
91 | serial=serial, |
92 | description=description, |
93 | tags=[{"slug": s} for s in tags or []], |
94 | custom_fields=custom_fields, |
95 | ) |
96 | return dict(api(auth).dcim.devices.create(body)) |
97 | |