3 Revize 972f796b4d ... eaa2e4a378

Autor SHA1 Zpráva Datum
  JDierkse eaa2e4a378 Enable Removal of veths před 6 dny
  JDierkse 990027ac86 Update Requirements před 6 dny
  JDierkse 14f994902e Add Gateway Priority Option před 6 dny
2 změnil soubory, kde provedl 56 přidání a 16 odebrání
  1. 55 16
      net-dhcp/network.py
  2. 1 0
      requirements.txt

+ 55 - 16
net-dhcp/network.py

@@ -61,8 +61,9 @@ def iface_nets(iface):
 def get_bridges():
     get_docker_client()
     reserved_nets = set(map(ipaddress.ip_network, map(lambda c: c['Subnet'], \
-        itertools.chain.from_iterable(map(lambda i: i['Config'], filter(lambda i: i['Driver'] != 'net-dhcp', \
-            map(lambda n: n.attrs['IPAM'], dockerClient.networks.list())))))))
+        itertools.chain.from_iterable(map(lambda x: [] if x is None else x, \
+            map(lambda i: i['Config'], filter(lambda i: i['Driver'] != 'net-dhcp', \
+                map(lambda n: n.attrs['IPAM'], dockerClient.networks.list()))))))))
 
     return dict(map(lambda i: (i['ifname'], i), filter(lambda i: i['kind'] == 'bridge' and not \
         set(iface_nets(i)).intersection(reserved_nets), map(lambda i: interface.GetInterface(LIBRARY, i['ifname']), \
@@ -95,6 +96,7 @@ def endpoint_container_iface(n, e):
                         }
             break
     return None
+
 def await_endpoint_container_iface(n, e, timeout=5):
     start = time.time()
     iface = None
@@ -103,6 +105,8 @@ def await_endpoint_container_iface(n, e, timeout=5):
             iface = endpoint_container_iface(n, e)
         except docker.errors.NotFound:
             time.sleep(0.5)
+        except KeyError:
+            time.sleep(0.5)
     if not iface:
         raise NetDhcpError('Timed out waiting for container to become availabile')
     return iface
@@ -114,6 +118,46 @@ def endpoint_container_hostname(n, e):
             return dockerClient.containers.get(cid).attrs['Config']['Hostname']
     return None
 
+def endpoint_container_network_gwpriority(n, e):
+    get_docker_client()
+    for cid, info in dockerClient.networks.get(n).attrs['Containers'].items():
+        if info['EndpointID'] == e:
+            networkName = dockerClient.networks.get(n).attrs['Name']
+            if 'GwPriority' in dockerClient.containers.get(cid).attrs['NetworkSettings']['Networks'][networkName]:
+                return dockerClient.containers.get(cid).attrs['NetworkSettings']['Networks'][networkName]['GwPriority']
+            else:
+                return 0
+    return None
+
+def remove_veth(host_ifname):
+    logger.info('Removing veth %s', host_ifname)
+    if LIBRARY == 'NDB':
+        if_host = interface.GetInterface(LIBRARY, if_host)
+        bridge = net_bridge(req['NetworkID'])
+        interface.DelPort(LIBRARY, bridge.ifname, if_host.ifname)
+        interface.RemoveInterface(LIBRARY, if_host.ifname)
+        logger.info('Removed veth for endpoint %s on ()', endpoint)
+    else:
+        logger.info('Deleting veth via shell: %s', host_ifname)
+        try:
+            subprocess.run(
+                ['ip', 'link', 'del', host_ifname],
+                stdout=subprocess.DEVNULL,
+                stderr=subprocess.PIPE,
+                check=True
+            )
+            logger.info('Deleted veth %s', host_ifname)
+
+        except subprocess.CalledProcessError as e:
+            if b'Cannot find device' in e.stderr:
+                logger.info('Veth %s already gone', host_ifname)
+            else:
+                logger.warning(
+                    'Failed to delete veth %s: %s',
+                    host_ifname,
+                    e.stderr.decode().strip()
+                )
+
 @app.route('/NetworkDriver.GetCapabilities', methods=['POST'])
 def net_get_capabilities():
     return jsonify({
@@ -250,18 +294,8 @@ def endpoint_info():
 def delete_endpoint():
     req = request.get_json(force=True)
 
-    if_host, _if_container = veth_pair(req['EndpointID'])
-    if_host = interface.GetInterface(LIBRARY, if_host)
-
-    try:
-        if LIBRARY == 'NDB':
-            bridge = net_bridge(req['NetworkID'])
-            interface.DelPort(LIBRARY, bridge.ifname, if_host.ifname)
-        else:
-            interface.DelPort(LIBRARY, 'dummy0', if_host.ifname)
-        interface.RemoveInterface(LIBRARY, if_host.ifname)
-    except Exception as e:
-        logger.exception(e)
+    if_host, _ = veth_pair(req['EndpointID'])
+    remove_veth(if_host)
 
     return jsonify({})
 
@@ -335,6 +369,7 @@ class ContainerDHCPManager:
 
         self.dhcp = None
         self.dhcp6 = None
+        self.gwPriority = None
         self._thread = threading.Thread(target=self.run)
         self._thread.start()
 
@@ -373,7 +408,7 @@ class ContainerDHCPManager:
                 str(dhcp.iface['ifname'])],
                 timeout=1, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 
-            if dhcp.gateway:
+            if dhcp.gateway and self.gwPriority >= 0:
                 logger.info('[dhcp container] Replacing gateway with %s', dhcp.gateway)
                 subprocess.check_call(['nsenter', f'-n{dhcp.netns}', '--', '/sbin/ip', 'route', 'replace', 'default', 'via',
                     str(dhcp.gateway)],
@@ -393,8 +428,12 @@ class ContainerDHCPManager:
         try:
             iface = await_endpoint_container_iface(self.network, self.endpoint)
             hostname = endpoint_container_hostname(self.network, self.endpoint)
+            self.gwPriority = endpoint_container_network_gwpriority(self.network, self.endpoint)
 
-            self.dhcp = udhcpc.DHCPClient(iface, event_listener=self._on_event, hostname=hostname)
+            if self.gwPriority >= 0:
+                self.dhcp = udhcpc.DHCPClient(iface, event_listener=self._on_event, hostname=hostname)
+            else:
+                self.dhcp = udhcpc.DHCPClient(iface, event_listener=self._on_event)
             logger.info('Starting DHCPv4 client on %s in container namespace %s', iface['ifname'], \
                 self.dhcp.netns)
 

+ 1 - 0
requirements.txt

@@ -3,3 +3,4 @@ pyroute2==0.5.6
 docker==4.0.2
 eventfd==0.2
 posix_ipc==1.0.4
+urllib3==1.26.20