Просмотр исходного кода

Fixed internet gateway handling in OpenStack to take routability into account

Nuwan Goonasekera 8 лет назад
Родитель
Сommit
879117a2a1

+ 41 - 0
cloudbridge/cloud/base/helpers.py

@@ -1,7 +1,13 @@
+import sys
+import traceback
+from contextlib import contextmanager
+
 from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.primitives import serialization as crypt_serialization
 from cryptography.hazmat.primitives.asymmetric import rsa
 
+from six import reraise
+
 
 def generate_key_pair():
     """
@@ -52,3 +58,38 @@ def generic_find(filter_names, kwargs, objs):
             % (kwargs, filter_names))
 
     return matches
+
+
+@contextmanager
+def cleanup_action(cleanup_func):
+    """
+    Context manager to carry out a given
+    cleanup action after carrying out a set
+    of tasks, or when an exception occurs.
+    If any errors occur during the cleanup
+    action, those are ignored, and the original
+    traceback is preserved.
+
+    :params func: This function is called if
+    an exception occurs or at the end of the
+    context block. If any exceptions raised
+        by func are ignored.
+    Usage:
+        with cleanup_action(lambda e: print("Oops!")):
+            do_something()
+    """
+    try:
+        yield
+    except Exception:
+        ex_class, ex_val, ex_traceback = sys.exc_info()
+        try:
+            cleanup_func()
+        except Exception as e:
+            print("Error during exception cleanup: {0}".format(e))
+            traceback.print_exc()
+        reraise(ex_class, ex_val, ex_traceback)
+    try:
+        cleanup_func()
+    except Exception as e:
+        print("Error during cleanup: {0}".format(e))
+        traceback.print_exc()

+ 22 - 9
cloudbridge/cloud/providers/openstack/resources.py

@@ -728,19 +728,32 @@ class OpenStackGatewayContainer(BaseGatewayContainer):
     def __init__(self, provider, network):
         super(OpenStackGatewayContainer, self).__init__(provider, network)
 
+    def _check_fip_connectivity(self, external_net):
+        # Due to current limitations in OpenStack:
+        # https://bugs.launchpad.net/neutron/+bug/1743480, it's not
+        # possible to differentiate between floating ip networks and provider
+        # external networks. Therefore, we systematically step through
+        # all available networks and perform an assignment test to infer valid
+        # floating ip nets.
+        dummy_router = self._provider.networking.routers.create(
+            network=self._network, name='cb_conn_test_router')
+        with cb_helpers.cleanup_action(lambda: dummy_router.delete()):
+            try:
+                dummy_router.attach_gateway(external_net)
+                return True
+            except Exception:
+                return False
+
     def get_or_create_inet_gateway(self, name=None):
         """For OS, inet gtw is any net that has `external` property set."""
         if name:
             OpenStackInternetGateway.assert_valid_resource_name(name)
 
-        for n in self._provider.networking.networks:
-            # Check whether network has subnets for legacy NeCTAR networking
-            # compatibility. Otherwise, it may attempt to connect to classic
-            # network (network id 0000) and result in: Bad floatingip request:
-            # Network 00000000-0000-0000-0000-000000000000 does not contain any
-            # subnet.
-            if n.external and n.subnets:
-                return OpenStackInternetGateway(self._provider, n)
+        external_nets = (n for n in self._provider.networking.networks
+                         if n.external)
+        for net in external_nets:
+            if self._check_fip_connectivity(net):
+                return OpenStackInternetGateway(self._provider, net)
         return None
 
     def delete(self, gateway):
@@ -751,7 +764,7 @@ class OpenStackGatewayContainer(BaseGatewayContainer):
         log.debug("OpenStack listing of all current internet gateways")
         igl = [OpenStackInternetGateway(self._provider, n)
                for n in self._provider.networking.networks
-               if n.external and n.subnets]
+               if n.external and self._check_fip_connectivity(n)]
         return ClientPagedResultList(self._provider, igl, limit=limit,
                                      marker=marker)