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 | def api(auth: netbox): |
17 | # pynetbox adds /api itself; the resource URL may already end with it. |
18 | return pynetbox.api( |
19 | auth["url"].rstrip("/").removesuffix("/api"), token=auth["token"] |
20 | ) |
21 |
|
22 |
|
23 | def keep(**fields): |
24 | # The run form sends "" / [] / {} for untouched fields: drop them so a PATCH never blanks a value. |
25 | return {k: v for k, v in fields.items() if v not in (None, "", [], {})} |
26 |
|
27 |
|
28 | def main( |
29 | auth: netbox, |
30 | ip_address_id: int, |
31 | address: Optional[str] = None, |
32 | status: Optional[ |
33 | Literal["active", "reserved", "deprecated", "dhcp", "slaac"] |
34 | ] = None, |
35 | vrf_id: Optional[int] = None, |
36 | dns_name: Optional[str] = None, |
37 | description: Optional[str] = None, |
38 | interface_id: Optional[int] = None, |
39 | tags: Optional[List[str]] = None, |
40 | custom_fields: Optional[dict] = None, |
41 | ): |
42 | """ |
43 | Update IP Address |
44 | Patch an IP address: status, VRF, DNS name, description, interface assignment, tags or custom fields. Only the fields you set change. |
45 | """ |
46 | body = keep( |
47 | address=address, |
48 | status=status, |
49 | vrf=vrf_id, |
50 | dns_name=dns_name, |
51 | description=description, |
52 | assigned_object_type="dcim.interface" if interface_id else None, |
53 | assigned_object_id=interface_id, |
54 | tags=[{"slug": s} for s in tags or []], |
55 | custom_fields=custom_fields, |
56 | ) |
57 | # A list body on the collection endpoint is NetBox's PATCH of only these fields. |
58 | return dict(api(auth).ipam.ip_addresses.update([{"id": ip_address_id, **body}])[0]) |
59 | |