Skip to content

Commit 0d67823

Browse files
Finish implementation; needs fixtures & tests
1 parent a7a33da commit 0d67823

File tree

4 files changed

+379
-1
lines changed

4 files changed

+379
-1
lines changed

linode_api4/objects/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from .region import Region
77
from .image import Image
88
from .linode import *
9+
from .linode_interfaces import *
910
from .volume import *
1011
from .domain import *
1112
from .account import *

linode_api4/objects/linode.py

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import string
22
import sys
3-
from dataclasses import dataclass
3+
from dataclasses import dataclass, field
44
from datetime import datetime
55
from enum import Enum
66
from os import urandom
@@ -19,6 +19,14 @@
1919
from linode_api4.objects.dbase import DerivedBase
2020
from linode_api4.objects.filtering import FilterableAttribute
2121
from linode_api4.objects.image import Image
22+
from linode_api4.objects.linode_interfaces import (
23+
LinodeInterface,
24+
LinodeInterfaceDefaultRouteOptions,
25+
LinodeInterfacePublicOptions,
26+
LinodeInterfacesSettings,
27+
LinodeInterfaceVLANOptions,
28+
LinodeInterfaceVPCOptions,
29+
)
2230
from linode_api4.objects.networking import (
2331
Firewall,
2432
IPAddress,
@@ -653,6 +661,13 @@ class MigrationType:
653661
WARM = "warm"
654662

655663

664+
@dataclass
665+
class UpgradeInterfacesResult(JSONObject):
666+
dry_run: bool = False
667+
config_id: int = 0
668+
interfaces: List[ConfigInterface] = field(default_factory=list)
669+
670+
656671
class Instance(Base):
657672
"""
658673
A Linode Instance.
@@ -686,6 +701,7 @@ class Instance(Base):
686701
"disk_encryption": Property(),
687702
"lke_cluster_id": Property(),
688703
"capabilities": Property(unordered=True),
704+
"interfaces_settings": Property(relationship=LinodeInterfacesSettings),
689705
}
690706

691707
@property
@@ -1846,6 +1862,77 @@ def stats_for(self, dt):
18461862
model=self,
18471863
)
18481864

1865+
def interface_create(
1866+
self,
1867+
firewall: Union[Firewall, int] = None,
1868+
default_route: Optional[LinodeInterfaceDefaultRouteOptions] = None,
1869+
public: Optional[LinodeInterfacePublicOptions] = None,
1870+
vlan: Optional[LinodeInterfaceVLANOptions] = None,
1871+
vpc: Optional[LinodeInterfaceVPCOptions] = None,
1872+
**kwargs,
1873+
):
1874+
params = {
1875+
"firewall_id": firewall,
1876+
"default_route": default_route,
1877+
"public": public,
1878+
"vlan": vlan,
1879+
"vpc": vpc,
1880+
}
1881+
1882+
params.update(kwargs)
1883+
1884+
result = self._client.post(
1885+
"{}/interfaces".format(Instance.api_endpoint),
1886+
model=self,
1887+
data=drop_null_keys(_flatten_request_body_recursive(params)),
1888+
)
1889+
1890+
if not "id" in result:
1891+
raise UnexpectedResponseError(
1892+
"Unexpected response creating config!", json=result
1893+
)
1894+
1895+
return LinodeInterface(self._client, result["id"], self.id, json=result)
1896+
1897+
def upgrade_interfaces(
1898+
self,
1899+
config: Union[Config, int],
1900+
dry_run: bool = False,
1901+
) -> UpgradeInterfacesResult:
1902+
"""
1903+
Automatically upgrades all legacy config interfaces of a
1904+
single configuration profile to Linode interfaces.
1905+
1906+
NOTE: If dry_run is True, interfaces in the result will be
1907+
of type MappedObject rather than LinodeInterface.
1908+
1909+
API Documentation: Not yet available.
1910+
1911+
:returns: Information about the newly upgraded interfaces.
1912+
:rtype: UpgradeInterfacesResult
1913+
"""
1914+
params = {"config_id": config, dry_run: dry_run}
1915+
1916+
result = self._client.post(
1917+
"{}/upgrade-interfaces".format(Instance.api_endpoint),
1918+
model=self,
1919+
data=_flatten_request_body_recursive(drop_null_keys(params)),
1920+
)
1921+
1922+
# We don't convert interface dicts to LinodeInterface objects on dry runs
1923+
# actual API entities aren't created
1924+
if dry_run:
1925+
result["interfaces"] = [
1926+
MappedObject(**iface) for iface in result["interfaces"]
1927+
]
1928+
else:
1929+
result["interfaces"] = [
1930+
LinodeInterface(self._client, self.id, iface["id"], iface)
1931+
for iface in result["interfaces"]
1932+
]
1933+
1934+
return UpgradeInterfacesResult.from_json(result)
1935+
18491936

18501937
class UserDefinedFieldType(Enum):
18511938
text = 1
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
from dataclasses import dataclass, field
2+
from typing import List, Optional
3+
4+
from linode_api4.objects.base import Base, Property
5+
from linode_api4.objects.dbase import DerivedBase
6+
from linode_api4.objects.networking import Firewall
7+
from linode_api4.objects.serializable import JSONObject
8+
9+
10+
@dataclass
11+
class LinodeInterfacesSettingsDefaultRouteOptions(JSONObject):
12+
ipv4_interface_id: Optional[int] = None
13+
ipv6_interface_id: Optional[int] = None
14+
15+
16+
@dataclass
17+
class LinodeInterfacesSettingsDefaultRoute(JSONObject):
18+
put_body = LinodeInterfacesSettingsDefaultRouteOptions
19+
20+
ipv4_interface_id: Optional[int] = None
21+
ipv4_eligible_interface_ids: List[int] = field(default_factory=list)
22+
ipv6_interface_id: Optional[int] = None
23+
ipv6_eligible_interface_ids: List[int] = field(default_factory=list)
24+
25+
26+
class LinodeInterfacesSettings(Base):
27+
api_endpoint = "/linode/instances/{linode_id}/interfaces/settings"
28+
29+
properties = {
30+
"linode_id": Property(identifier=True),
31+
"network_helper": Property(mutable=True),
32+
"default_route": Property(
33+
mutable=True, json_object=LinodeInterfacesSettingsDefaultRoute
34+
),
35+
}
36+
37+
38+
@dataclass
39+
class LinodeInterfaceDefaultRouteOptions(JSONObject):
40+
ipv4: bool = False
41+
ipv6: bool = False
42+
43+
44+
@dataclass
45+
class LinodeInterfaceVPCIPv4AddressOptions(JSONObject):
46+
address: str = ""
47+
primary: Optional[bool] = None
48+
nat_1_1_address: Optional[str] = None
49+
50+
51+
@dataclass
52+
class LinodeInterfaceVPCIPv4RangeOptions(JSONObject):
53+
range: str = ""
54+
55+
56+
@dataclass
57+
class LinodeInterfaceVPCIPv4Options(JSONObject):
58+
addresses: Optional[List[LinodeInterfaceVPCIPv4AddressOptions]] = None
59+
ranges: Optional[List[LinodeInterfaceVPCIPv4RangeOptions]] = None
60+
61+
62+
@dataclass
63+
class LinodeInterfaceVPCOptions(JSONObject):
64+
subnet_id: int = 0
65+
ipv4: Optional[LinodeInterfaceVPCIPv4Options] = None
66+
67+
68+
@dataclass
69+
class LinodeInterfacePublicIPv4AddressOptions(JSONObject):
70+
address: str = ""
71+
primary: Optional[bool] = None
72+
73+
74+
@dataclass
75+
class LinodeInterfacePublicIPv4Options(JSONObject):
76+
addresses: Optional[List[LinodeInterfacePublicIPv4AddressOptions]] = None
77+
78+
79+
@dataclass
80+
class LinodeInterfacePublicIPv6RangeOptions(JSONObject):
81+
range: str = ""
82+
83+
84+
@dataclass
85+
class LinodeInterfacePublicIPv6Options(JSONObject):
86+
ranges: Optional[List[LinodeInterfacePublicIPv6RangeOptions]] = None
87+
88+
89+
@dataclass
90+
class LinodeInterfacePublicOptions(JSONObject):
91+
ipv4: Optional[LinodeInterfacePublicIPv4Options] = None
92+
ipv6: Optional[LinodeInterfacePublicIPv6Options] = None
93+
94+
95+
@dataclass
96+
class LinodeInterfaceVLANOptions(JSONObject):
97+
vlan_label: str = ""
98+
ipam_address: Optional[str] = None
99+
100+
101+
@dataclass
102+
class LinodeInterfaceDefaultRoute(JSONObject):
103+
ipv4: bool = False
104+
ipv6: bool = False
105+
106+
107+
@dataclass
108+
class LinodeInterfaceVPCIPv4Address(JSONObject):
109+
address: str = ""
110+
primary: bool = False
111+
nat_1_1_address: Optional[str] = None
112+
113+
114+
@dataclass
115+
class LinodeInterfaceVPCIPv4Range(JSONObject):
116+
range: str = ""
117+
118+
119+
@dataclass
120+
class LinodeInterfaceVPCIPv4(JSONObject):
121+
addresses: List[LinodeInterfaceVPCIPv4Address] = field(default_factory=list)
122+
ranges: List[LinodeInterfaceVPCIPv4Range] = field(default_factory=list)
123+
124+
125+
@dataclass
126+
class LinodeInterfaceVPC(JSONObject):
127+
vpc_id: int = 0
128+
vpc_subnet: int = 0
129+
130+
ipv4: Optional[LinodeInterfaceVPCIPv4] = None
131+
132+
133+
@dataclass
134+
class LinodeInterfacePublicIPv4Address(JSONObject):
135+
address: str = ""
136+
primary: bool = False
137+
138+
139+
@dataclass
140+
class LinodeInterfacePublicIPv4Shared(JSONObject):
141+
address: str = ""
142+
linode_id: int = 0
143+
144+
145+
@dataclass
146+
class LinodeInterfacePublicIPv4(JSONObject):
147+
addresses: List[LinodeInterfacePublicIPv4Address] = field(
148+
default_factory=list
149+
)
150+
shared: List[LinodeInterfacePublicIPv4Shared] = field(default_factory=list)
151+
152+
153+
@dataclass
154+
class LinodeInterfacePublicIPv6SLAAC(JSONObject):
155+
address: str = ""
156+
prefix: int = 0
157+
158+
159+
@dataclass
160+
class LinodeInterfacePublicIPv6Shared(JSONObject):
161+
range: str = ""
162+
route_target: Optional[str] = None
163+
164+
165+
@dataclass
166+
class LinodeInterfacePublicIPv6Range(JSONObject):
167+
range: str = ""
168+
route_target: Optional[str] = None
169+
170+
171+
@dataclass
172+
class LinodeInterfacePublicIPv6(JSONObject):
173+
slaac: List[LinodeInterfacePublicIPv6SLAAC] = field(default_factory=list)
174+
shared: List[LinodeInterfacePublicIPv6Shared] = field(default_factory=list)
175+
ranges: List[LinodeInterfacePublicIPv6Range] = field(default_factory=list)
176+
177+
178+
@dataclass
179+
class LinodeInterfacePublic(JSONObject):
180+
ipv4: Optional[LinodeInterfacePublicIPv4] = None
181+
ipv6: Optional[LinodeInterfacePublicIPv6] = None
182+
183+
184+
@dataclass
185+
class LinodeInterfaceVLAN(JSONObject):
186+
vlan_label: str = ""
187+
ipam_address: Optional[str] = None
188+
189+
190+
class LinodeInterface(DerivedBase):
191+
"""
192+
A Linode's network interface.
193+
194+
API Documentation: Not yet available.
195+
"""
196+
197+
api_endpoint = "/linode/instances/{linode_id}/interfaces/{id}"
198+
derived_url_path = "interfaces"
199+
parent_id_name = "linode_id"
200+
201+
properties = {
202+
"linode_id": Property(identifier=True),
203+
"id": Property(identifier=True),
204+
"mac_address": Property(),
205+
"created": Property(is_datetime=True),
206+
"updated": Property(is_datetime=True),
207+
"version": Property(),
208+
"default_route": Property(
209+
mutable=True, json_object=LinodeInterfaceDefaultRoute
210+
),
211+
"public": Property(mutable=True, json_object=LinodeInterfacePublic),
212+
"vlan": Property(mutable=True, json_object=LinodeInterfaceVLAN),
213+
"vpc": Property(mutable=True, json_object=LinodeInterfaceVPC),
214+
}
215+
216+
def firewalls(self, *filters) -> List[Firewall]:
217+
"""
218+
Retrieves a list of Firewalls for this Linode Interface.
219+
220+
:param filters: Any number of filters to apply to this query.
221+
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
222+
for more details on filtering.
223+
224+
:returns: A List of Firewalls for this Linode Interface.
225+
:rtype: List[Firewall]
226+
227+
NOTE: Caching is disabled on this method and each call will make
228+
an additional Linode API request.
229+
"""
230+
231+
return self._client._get_and_filter(
232+
Firewall,
233+
*filters,
234+
endpoint="{}/firewalls".format(LinodeInterface.api_endpoint).format(
235+
**vars(self)
236+
),
237+
)

0 commit comments

Comments
 (0)