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_prefix_id = str |
17 |
|
18 |
|
19 | def api(auth: netbox): |
20 | # pynetbox adds /api itself; the resource URL may already end with it. |
21 | return pynetbox.api( |
22 | auth["url"].rstrip("/").removesuffix("/api"), token=auth["token"] |
23 | ) |
24 |
|
25 |
|
26 | def keep(**fields): |
27 | # The run form sends "" / [] / {} for untouched fields: drop them. |
28 | return {k: v for k, v in fields.items() if v not in (None, "", [], {})} |
29 |
|
30 |
|
31 | def options(endpoint, key="id", **filters): |
32 | return [ |
33 | {"value": str(getattr(r, key)), "label": r.display} |
34 | for r in endpoint.filter(brief=1, limit=1000, offset=0, **filters) |
35 | ] |
36 |
|
37 |
|
38 | # Dropdown of the instance's prefixes. |
39 | def prefix_id(auth: netbox): |
40 | return options(api(auth).ipam.prefixes) |
41 |
|
42 |
|
43 | def main( |
44 | auth: netbox, |
45 | prefix_id: DynSelect_prefix_id, |
46 | count: Optional[int] = None, |
47 | status: Optional[ |
48 | Literal["active", "reserved", "deprecated", "dhcp", "slaac"] |
49 | ] = None, |
50 | dns_name: Optional[str] = None, |
51 | description: Optional[str] = None, |
52 | interface_id: Optional[int] = None, |
53 | tags: Optional[List[str]] = None, |
54 | custom_fields: Optional[dict] = None, |
55 | ): |
56 | """ |
57 | Allocate Next Available IP |
58 | Reserve the next free IP address(es) in a prefix and create them, optionally assigned to a device interface. Returns the created IP address(es). |
59 | """ |
60 | prefix = api(auth).ipam.prefixes.get(int(prefix_id)) |
61 | if prefix is None: |
62 | raise ValueError(f"No prefix with id {prefix_id}") |
63 | ip = keep( |
64 | status=status, |
65 | dns_name=dns_name, |
66 | description=description, |
67 | assigned_object_type="dcim.interface" if interface_id else None, |
68 | assigned_object_id=interface_id, |
69 | tags=[{"slug": s} for s in tags or []], |
70 | custom_fields=custom_fields, |
71 | ) |
72 | # NetBox allocates one IP for an object body, one per item for a list. |
73 | n = count or 1 |
74 | if n == 1: |
75 | return dict(prefix.available_ips.create(ip)) |
76 | return [dict(r) for r in prefix.available_ips.create([ip] * n)] |
77 | |