Skip to content

Commit d065ad4

Browse files
authored
Merge pull request #803 from gefyrahq/#802
fix(#802): subnet negotiation
2 parents e5e940c + b329fa2 commit d065ad4

File tree

3 files changed

+69
-9
lines changed

3 files changed

+69
-9
lines changed

client/gefyra/api/connect.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@
3838
logger = logging.getLogger(__name__)
3939

4040

41+
def _get_client_networks(config: ClientConfiguration) -> List[str]:
42+
clients = config.K8S_CUSTOM_OBJECT_API.list_namespaced_custom_object(
43+
namespace=config.NAMESPACE,
44+
plural="gefyraclients",
45+
group="gefyra.dev",
46+
version="v1",
47+
)
48+
return [
49+
client["providerParameter"]["subnet"]
50+
for client in filter(lambda x: x["state"] == "ACTIVE" in x, clients["items"])
51+
]
52+
53+
4154
@stopwatch
4255
def connect( # noqa: C901
4356
connection_name: str,
@@ -106,8 +119,10 @@ def connect( # noqa: C901
106119
config.CARGO_PROBE_TIMEOUT = probe_timeout
107120

108121
_retry = 0
122+
occupied_networks = _get_client_networks(config)
123+
109124
while _retry < 10:
110-
gefyra_network = get_or_create_gefyra_network(config)
125+
gefyra_network = get_or_create_gefyra_network(config, occupied_networks)
111126
try:
112127
client.activate_connection(
113128
gefyra_network.attrs["IPAM"]["Config"][0]["Subnet"]

client/gefyra/local/networking.py

+36-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import logging
2-
from typing import TYPE_CHECKING
2+
from typing import TYPE_CHECKING, List, Optional
33

44

55
from gefyra.configuration import ClientConfiguration
@@ -12,13 +12,41 @@
1212
logger = logging.getLogger(__name__)
1313

1414

15-
def get_or_create_gefyra_network(config: ClientConfiguration) -> "Network":
16-
gefyra_network = handle_create_network(config)
15+
def get_or_create_gefyra_network(
16+
config: ClientConfiguration, occupied_networks: Optional[List[str]] = None
17+
) -> "Network":
18+
if not occupied_networks:
19+
occupied_networks = []
20+
gefyra_network = handle_create_network(config, occupied_networks)
1721
logger.debug(f"Network {gefyra_network.attrs}")
1822
return gefyra_network
1923

2024

21-
def handle_create_network(config: ClientConfiguration) -> "Network":
25+
def _get_subnet(
26+
config: ClientConfiguration, network_name: str, occupied_networks: List[str]
27+
) -> str:
28+
tries = 255
29+
networks: List[Network] = []
30+
subnet = ""
31+
# this is a workaround to select a free subnet (instead of finding it with python code)
32+
for i in range(tries):
33+
temp_network = config.DOCKER.networks.create(
34+
f"{network_name}-{i}", driver="bridge"
35+
)
36+
networks.append(temp_network)
37+
subnet = temp_network.attrs["IPAM"]["Config"][0]["Subnet"]
38+
if subnet not in occupied_networks:
39+
break
40+
for network in networks:
41+
network.remove()
42+
if not subnet:
43+
raise RuntimeError("Could not find a free subnet")
44+
return subnet
45+
46+
47+
def handle_create_network(
48+
config: ClientConfiguration, occupied_networks: List[str]
49+
) -> "Network":
2250
from docker.errors import NotFound
2351
from docker.types import IPAMConfig, IPAMPool
2452

@@ -56,10 +84,10 @@ def handle_create_network(config: ClientConfiguration) -> "Network":
5684
except NotFound:
5785
pass
5886

59-
# this is a workaround to select a free subnet (instead of finding it with python code)
60-
temp_network = config.DOCKER.networks.create(network_name, driver="bridge")
61-
subnet = temp_network.attrs["IPAM"]["Config"][0]["Subnet"]
62-
temp_network.remove() # remove the temp network again
87+
subnet = _get_subnet(
88+
config=config, network_name=network_name, occupied_networks=occupied_networks
89+
)
90+
logger.debug(f"Using subnet: {subnet}")
6391

6492
ipam_pool = IPAMPool(subnet=f"{subnet}", aux_addresses={})
6593
ipam_config = IPAMConfig(pool_configs=[ipam_pool])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from gefyra.configuration import ClientConfiguration
2+
from gefyra.local.networking import _get_subnet
3+
4+
5+
def test_subnet_negotiation():
6+
"""This test assumes, that docker will reuse the same subnet, if it is free."""
7+
config = ClientConfiguration()
8+
temp_network = config.DOCKER.networks.create("gefyra-test-network")
9+
temp_subnet = temp_network.attrs["IPAM"]["Config"][0]["Subnet"]
10+
temp_network.remove()
11+
occupied_networks = [temp_subnet]
12+
subnet = _get_subnet(
13+
config=config,
14+
network_name="gefyra-test-network",
15+
occupied_networks=occupied_networks,
16+
)
17+
assert subnet != temp_subnet

0 commit comments

Comments
 (0)