Skip to content

Commit 5321182

Browse files
authored
feat(network): add field expose_routes_to_vswitch (#208)
* fix(network): missing subnets vswitch_id in networks create * feat(network): add field expose_routes_to_vswitch
1 parent 7a19add commit 5321182

4 files changed

Lines changed: 156 additions & 11 deletions

File tree

hcloud/networks/client.py

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,29 @@ def __init__(self, client, data, complete=True):
3030

3131
super().__init__(client, data, complete)
3232

33-
def update(self, name=None, labels=None):
34-
# type: (Optional[str], Optional[Dict[str, str]]) -> BoundNetwork
33+
def update(
34+
self,
35+
name=None, # type: Optional[str]
36+
expose_routes_to_vswitch=None, # type: Optional[bool]
37+
labels=None, # type: Optional[Dict[str, str]]
38+
): # type: (...) -> BoundNetwork
3539
"""Updates a network. You can update a network’s name and a networks’s labels.
3640
3741
:param name: str (optional)
3842
New name to set
43+
:param expose_routes_to_vswitch: Optional[bool]
44+
Indicates if the routes from this network should be exposed to the vSwitch connection.
45+
The exposing only takes effect if a vSwitch connection is active.
3946
:param labels: Dict[str, str] (optional)
4047
User-defined labels (key-value pairs)
4148
:return: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>`
4249
"""
43-
return self._client.update(self, name, labels)
50+
return self._client.update(
51+
self,
52+
name=name,
53+
expose_routes_to_vswitch=expose_routes_to_vswitch,
54+
labels=labels,
55+
)
4456

4557
def delete(self):
4658
# type: () -> BoundAction
@@ -217,6 +229,7 @@ def create(
217229
ip_range, # type: str
218230
subnets=None, # type: Optional[List[NetworkSubnet]]
219231
routes=None, # type: Optional[List[NetworkRoute]]
232+
expose_routes_to_vswitch=None, # type: Optional[bool]
220233
labels=None, # type: Optional[Dict[str, str]]
221234
):
222235
"""Creates a network with range ip_range.
@@ -229,48 +242,68 @@ def create(
229242
Array of subnets allocated
230243
:param routes: List[:class:`NetworkRoute <hcloud.networks.domain.NetworkRoute>`]
231244
Array of routes set in this network
245+
:param expose_routes_to_vswitch: Optional[bool]
246+
Indicates if the routes from this network should be exposed to the vSwitch connection.
247+
The exposing only takes effect if a vSwitch connection is active.
232248
:param labels: Dict[str, str] (optional)
233249
User-defined labels (key-value pairs)
234250
:return: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>`
235251
"""
236252
data = {"name": name, "ip_range": ip_range}
237253
if subnets is not None:
238-
data["subnets"] = [
239-
{
254+
data_subnets = []
255+
for subnet in subnets:
256+
data_subnet = {
240257
"type": subnet.type,
241258
"ip_range": subnet.ip_range,
242259
"network_zone": subnet.network_zone,
243260
}
244-
for subnet in subnets
245-
]
261+
if subnet.vswitch_id is not None:
262+
data_subnet["vswitch_id"] = subnet.vswitch_id
263+
264+
data_subnets.append(data_subnet)
265+
data["subnets"] = data_subnets
266+
246267
if routes is not None:
247268
data["routes"] = [
248269
{"destination": route.destination, "gateway": route.gateway}
249270
for route in routes
250271
]
272+
273+
if expose_routes_to_vswitch is not None:
274+
data["expose_routes_to_vswitch"] = expose_routes_to_vswitch
275+
251276
if labels is not None:
252277
data["labels"] = labels
253278

254279
response = self._client.request(url="/networks", method="POST", json=data)
255280

256281
return BoundNetwork(self, response["network"])
257282

258-
def update(self, network, name=None, labels=None):
259-
# type:(Network, Optional[str], Optional[Dict[str, str]]) -> BoundNetwork
283+
def update(self, network, name=None, expose_routes_to_vswitch=None, labels=None):
284+
# type:(Network, Optional[str], Optional[bool], Optional[Dict[str, str]]) -> BoundNetwork
260285
"""Updates a network. You can update a network’s name and a network’s labels.
261286
262287
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
263288
:param name: str (optional)
264289
New name to set
290+
:param expose_routes_to_vswitch: Optional[bool]
291+
Indicates if the routes from this network should be exposed to the vSwitch connection.
292+
The exposing only takes effect if a vSwitch connection is active.
265293
:param labels: Dict[str, str] (optional)
266294
User-defined labels (key-value pairs)
267295
:return: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>`
268296
"""
269297
data = {}
270298
if name is not None:
271299
data.update({"name": name})
300+
301+
if expose_routes_to_vswitch is not None:
302+
data["expose_routes_to_vswitch"] = expose_routes_to_vswitch
303+
272304
if labels is not None:
273305
data.update({"labels": labels})
306+
274307
response = self._client.request(
275308
url=f"/networks/{network.id}",
276309
method="PUT",

hcloud/networks/domain.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class Network(BaseDomain):
1616
Subnets allocated in this network
1717
:param routes: List[:class:`NetworkRoute <hcloud.networks.domain.NetworkRoute>`]
1818
Routes set in this network
19+
:param expose_routes_to_vswitch: bool
20+
Indicates if the routes from this network should be exposed to the vSwitch connection.
1921
:param servers: List[:class:`BoundServer <hcloud.servers.client.BoundServer>`]
2022
Servers attached to this network
2123
:param protection: dict
@@ -30,6 +32,7 @@ class Network(BaseDomain):
3032
"ip_range",
3133
"subnets",
3234
"routes",
35+
"expose_routes_to_vswitch",
3336
"servers",
3437
"protection",
3538
"labels",
@@ -44,6 +47,7 @@ def __init__(
4447
ip_range=None,
4548
subnets=None,
4649
routes=None,
50+
expose_routes_to_vswitch=None,
4751
servers=None,
4852
protection=None,
4953
labels=None,
@@ -54,6 +58,7 @@ def __init__(
5458
self.ip_range = ip_range
5559
self.subnets = subnets
5660
self.routes = routes
61+
self.expose_routes_to_vswitch = expose_routes_to_vswitch
5762
self.servers = servers
5863
self.protection = protection
5964
self.labels = labels

tests/unit/networks/conftest.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def network_response():
2424
},
2525
],
2626
"routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}],
27+
"expose_routes_to_vswitch": False,
2728
"servers": [42],
2829
"protection": {"delete": False},
2930
"labels": {},
@@ -55,6 +56,7 @@ def two_networks_response():
5556
},
5657
],
5758
"routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}],
59+
"expose_routes_to_vswitch": False,
5860
"servers": [42],
5961
"protection": {"delete": False},
6062
"labels": {},
@@ -73,6 +75,7 @@ def two_networks_response():
7375
}
7476
],
7577
"routes": [{"destination": "12.100.1.0/24", "gateway": "12.0.1.1"}],
78+
"expose_routes_to_vswitch": False,
7679
"servers": [45],
7780
"protection": {"delete": False},
7881
"labels": {},
@@ -105,6 +108,7 @@ def one_network_response():
105108
},
106109
],
107110
"routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}],
111+
"expose_routes_to_vswitch": False,
108112
"servers": [42],
109113
"protection": {"delete": False},
110114
"labels": {},
@@ -129,6 +133,32 @@ def network_create_response():
129133
}
130134
],
131135
"routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}],
136+
"expose_routes_to_vswitch": False,
137+
"servers": [42],
138+
"protection": {"delete": False},
139+
"labels": {},
140+
"created": "2016-01-30T23:50:00+00:00",
141+
}
142+
}
143+
144+
145+
@pytest.fixture()
146+
def network_create_response_with_expose_routes_to_vswitch():
147+
return {
148+
"network": {
149+
"id": 4711,
150+
"name": "mynet",
151+
"ip_range": "10.0.0.0/16",
152+
"subnets": [
153+
{
154+
"type": "cloud",
155+
"ip_range": "10.0.1.0/24",
156+
"network_zone": "eu-central",
157+
"gateway": "10.0.0.1",
158+
}
159+
],
160+
"routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}],
161+
"expose_routes_to_vswitch": True,
132162
"servers": [42],
133163
"protection": {"delete": False},
134164
"labels": {},
@@ -153,6 +183,7 @@ def response_update_network():
153183
}
154184
],
155185
"routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}],
186+
"expose_routes_to_vswitch": True,
156187
"servers": [42],
157188
"protection": {"delete": False},
158189
"labels": {},

tests/unit/networks/test_client.py

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,25 @@ def test_create(self, networks_client, network_create_response):
268268
json={"name": "mynet", "ip_range": "10.0.0.0/8"},
269269
)
270270

271+
def test_create_with_expose_routes_to_vswitch(
272+
self, networks_client, network_create_response_with_expose_routes_to_vswitch
273+
):
274+
networks_client._client.request.return_value = (
275+
network_create_response_with_expose_routes_to_vswitch
276+
)
277+
networks_client.create(
278+
name="mynet", ip_range="10.0.0.0/8", expose_routes_to_vswitch=True
279+
)
280+
networks_client._client.request.assert_called_with(
281+
url="/networks",
282+
method="POST",
283+
json={
284+
"name": "mynet",
285+
"ip_range": "10.0.0.0/8",
286+
"expose_routes_to_vswitch": True,
287+
},
288+
)
289+
271290
def test_create_with_subnet(
272291
self, networks_client, network_subnet, network_create_response
273292
):
@@ -291,6 +310,32 @@ def test_create_with_subnet(
291310
},
292311
)
293312

313+
def test_create_with_subnet_vswitch(
314+
self, networks_client, network_subnet, network_create_response
315+
):
316+
networks_client._client.request.return_value = network_create_response
317+
network_subnet.type = NetworkSubnet.TYPE_VSWITCH
318+
network_subnet.vswitch_id = 1000
319+
networks_client.create(
320+
name="mynet", ip_range="10.0.0.0/8", subnets=[network_subnet]
321+
)
322+
networks_client._client.request.assert_called_with(
323+
url="/networks",
324+
method="POST",
325+
json={
326+
"name": "mynet",
327+
"ip_range": "10.0.0.0/8",
328+
"subnets": [
329+
{
330+
"type": NetworkSubnet.TYPE_VSWITCH,
331+
"ip_range": "10.0.1.0/24",
332+
"network_zone": "eu-central",
333+
"vswitch_id": 1000,
334+
}
335+
],
336+
},
337+
)
338+
294339
def test_create_with_route(
295340
self, networks_client, network_route, network_create_response
296341
):
@@ -308,6 +353,32 @@ def test_create_with_route(
308353
},
309354
)
310355

356+
def test_create_with_route_and_expose_routes_to_vswitch(
357+
self,
358+
networks_client,
359+
network_route,
360+
network_create_response_with_expose_routes_to_vswitch,
361+
):
362+
networks_client._client.request.return_value = (
363+
network_create_response_with_expose_routes_to_vswitch
364+
)
365+
networks_client.create(
366+
name="mynet",
367+
ip_range="10.0.0.0/8",
368+
routes=[network_route],
369+
expose_routes_to_vswitch=True,
370+
)
371+
networks_client._client.request.assert_called_with(
372+
url="/networks",
373+
method="POST",
374+
json={
375+
"name": "mynet",
376+
"ip_range": "10.0.0.0/8",
377+
"routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}],
378+
"expose_routes_to_vswitch": True,
379+
},
380+
)
381+
311382
def test_create_with_route_and_subnet(
312383
self, networks_client, network_subnet, network_route, network_create_response
313384
):
@@ -358,13 +429,18 @@ def test_get_actions_list(self, networks_client, network, response_get_actions):
358429
)
359430
def test_update(self, networks_client, network, response_update_network):
360431
networks_client._client.request.return_value = response_update_network
361-
network = networks_client.update(network, name="new-name")
432+
network = networks_client.update(
433+
network, name="new-name", expose_routes_to_vswitch=True
434+
)
362435
networks_client._client.request.assert_called_with(
363-
url="/networks/1", method="PUT", json={"name": "new-name"}
436+
url="/networks/1",
437+
method="PUT",
438+
json={"name": "new-name", "expose_routes_to_vswitch": True},
364439
)
365440

366441
assert network.id == 4711
367442
assert network.name == "new-name"
443+
assert network.expose_routes_to_vswitch is True
368444

369445
@pytest.mark.parametrize(
370446
"network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]

0 commit comments

Comments
 (0)