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

Move FloatingIP under InternetGateway, as per #104

Enis Afgan 8 лет назад
Родитель
Сommit
212671fecd

+ 32 - 0
cloudbridge/cloud/base/resources.py

@@ -19,6 +19,7 @@ from cloudbridge.cloud.interfaces.resources import BucketContainer
 from cloudbridge.cloud.interfaces.resources import BucketObject
 from cloudbridge.cloud.interfaces.resources import CloudResource
 from cloudbridge.cloud.interfaces.resources import FloatingIP
+from cloudbridge.cloud.interfaces.resources import FloatingIPContainer
 from cloudbridge.cloud.interfaces.resources import FloatingIpState
 from cloudbridge.cloud.interfaces.resources import GatewayState
 from cloudbridge.cloud.interfaces.resources import Instance
@@ -987,6 +988,37 @@ class BaseSubnet(BaseCloudResource, BaseObjectLifeCycleMixin, Subnet):
             interval=interval)
 
 
+class BaseFloatingIPContainer(BaseCloudResource, FloatingIPContainer,
+                              BasePageableObjectMixin):
+
+    def __init__(self, provider, gateway):
+        # super(BaseFloatingIPContainer, self).__init__(provider)
+        self.__provider = provider
+        self.gateway = gateway
+
+    @property
+    def _provider(self):
+        return self.__provider
+
+    def find(self, **kwargs):
+        if 'name' in kwargs:
+            name = kwargs.get('name')
+            log.info("Searching for FloatingIPContainer with the "
+                     "name: %s...", name)
+            if name:
+                return [fip for fip in self if fip.name == name]
+        else:
+            log.exception("TypeError exception raised. Invalid parameters "
+                          "used for search.")
+            raise TypeError(
+                "Invalid parameters for search. Supported attributes: {name}")
+
+    def delete(self, fip_id):
+        floating_ip = self.get(fip_id)
+        if floating_ip:
+            floating_ip.delete()
+
+
 class BaseFloatingIP(BaseCloudResource, BaseObjectLifeCycleMixin, FloatingIP):
 
     def __init__(self, provider):

+ 0 - 26
cloudbridge/cloud/base/services.py

@@ -7,7 +7,6 @@ from cloudbridge.cloud.interfaces.resources import Router
 from cloudbridge.cloud.interfaces.services import BucketService
 from cloudbridge.cloud.interfaces.services import CloudService
 from cloudbridge.cloud.interfaces.services import ComputeService
-from cloudbridge.cloud.interfaces.services import FloatingIPService
 from cloudbridge.cloud.interfaces.services import GatewayService
 from cloudbridge.cloud.interfaces.services import ImageService
 from cloudbridge.cloud.interfaces.services import InstanceService
@@ -198,31 +197,6 @@ class BaseSubnetService(
                 "Invalid parameters for search. Supported attributes: {name}")
 
 
-class BaseFloatingIPService(
-        BasePageableObjectMixin, FloatingIPService, BaseCloudService):
-
-    def __init__(self, provider):
-        super(BaseFloatingIPService, self).__init__(provider)
-
-    def find(self, **kwargs):
-        if 'name' in kwargs:
-            name = kwargs.get('name')
-            log.info("Searching for FloatingIPService with the "
-                     "name: %s...", name)
-            if name:
-                return [fip for fip in self if fip.name == name]
-        else:
-            log.exception("TypeError exception raised. Invalid parameters "
-                          "used for search.")
-            raise TypeError(
-                "Invalid parameters for search. Supported attributes: {name}")
-
-    def delete(self, fip_id):
-        floating_ip = self.get(fip_id)
-        if floating_ip:
-            floating_ip.delete()
-
-
 class BaseRouterService(
         BasePageableObjectMixin, RouterService, BaseCloudService):
 

+ 70 - 0
cloudbridge/cloud/interfaces/resources.py

@@ -949,6 +949,66 @@ class Subnet(ObjectLifeCycleMixin, CloudResource):
         pass
 
 
+class FloatingIPContainer(PageableObjectMixin):
+    """
+    Base interface for a FloatingIP Service.
+    """
+    __metaclass__ = ABCMeta
+
+    @abstractmethod
+    def get(self, fip_id):
+        """
+        Returns a FloatingIP given its ID or ``None`` if not found.
+
+        :type fip_id: ``str``
+        :param fip_id: The ID of the FloatingIP to retrieve.
+
+        :rtype: ``object`` of :class:`.FloatingIP`
+        :return: a FloatingIP object
+        """
+        pass
+
+    @abstractmethod
+    def list(self, limit=None, marker=None):
+        """
+        List floating (i.e., static) IP addresses.
+
+        :rtype: ``list`` of :class:`.FloatingIP`
+        :return: list of FloatingIP objects
+        """
+        pass
+
+    @abstractmethod
+    def find(self, name):
+        """
+        Searches for a FloatingIP by a given list of attributes.
+
+        :rtype: List of ``object`` of :class:`.FloatingIP`
+        :return: A list of FloatingIP objects matching the supplied attributes.
+        """
+        pass
+
+    @abstractmethod
+    def create(self):
+        """
+        Allocate a new floating (i.e., static) IP address.
+
+        :rtype: ``object`` of :class:`.FloatingIP`
+        :return:  A FloatingIP object
+        """
+        pass
+
+    @abstractmethod
+    def delete(self, fip_id):
+        """
+        Delete an existing FloatingIP.
+
+        :type fip_id: ``str``
+        :param fip_id: The ID of the FloatingIP to be deleted.
+        """
+        pass
+
+
 class FloatingIpState(object):
 
     """
@@ -1153,6 +1213,16 @@ class Gateway(CloudResource):
         """
         pass
 
+    @abstractproperty
+    def floating_ips(self):
+        """
+        Provides access to floating IPs connected to this internet gateway.
+
+        :rtype: :class:`.FloatingIPContainer`
+        :return: A FloatingIPContainer object
+        """
+        pass
+
 
 class InternetGateway(ObjectLifeCycleMixin, Gateway):
     """

+ 0 - 71
cloudbridge/cloud/interfaces/services.py

@@ -585,16 +585,6 @@ class NetworkingService(CloudService):
         """
         pass
 
-    @abstractproperty
-    def floating_ips(self):
-        """
-        Provides access to all Floating IP services.
-
-        :rtype: :class:`.FloatingIPService`
-        :return: a FloatingIPService object
-        """
-        pass
-
     @abstractproperty
     def gateways(self):
         """
@@ -806,67 +796,6 @@ class SubnetService(PageableObjectMixin, CloudService):
         pass
 
 
-class FloatingIPService(PageableObjectMixin, CloudService):
-
-    """
-    Base interface for a FloatingIP Service.
-    """
-    __metaclass__ = ABCMeta
-
-    @abstractmethod
-    def get(self, fip_id):
-        """
-        Returns a FloatingIP given its ID or ``None`` if not found.
-
-        :type fip_id: ``str``
-        :param fip_id: The ID of the FloatingIP to retrieve.
-
-        :rtype: ``object`` of :class:`.FloatingIP`
-        :return: a FloatingIP object
-        """
-        pass
-
-    @abstractmethod
-    def list(self, limit=None, marker=None):
-        """
-        List floating (i.e., static) IP addresses.
-
-        :rtype: ``list`` of :class:`.FloatingIP`
-        :return: list of FloatingIP objects
-        """
-        pass
-
-    @abstractmethod
-    def find(self, name):
-        """
-        Searches for a FloatingIP by a given list of attributes.
-
-        :rtype: List of ``object`` of :class:`.FloatingIP`
-        :return: A list of FloatingIP objects matching the supplied attributes.
-        """
-        pass
-
-    @abstractmethod
-    def create(self):
-        """
-        Allocate a new floating (i.e., static) IP address.
-
-        :rtype: ``object`` of :class:`.FloatingIP`
-        :return:  A FloatingIP object
-        """
-        pass
-
-    @abstractmethod
-    def delete(self, fip_id):
-        """
-        Delete an existing FloatingIP.
-
-        :type fip_id: ``str``
-        :param fip_id: The ID of the FloatingIP to be deleted.
-        """
-        pass
-
-
 class RouterService(PageableObjectMixin, CloudService):
     """
     Manage networking router actions and resources.

+ 37 - 0
cloudbridge/cloud/providers/aws/resources.py

@@ -3,6 +3,7 @@ DataTypes used by this provider
 """
 import hashlib
 import inspect
+import logging
 
 from botocore.exceptions import ClientError
 
@@ -11,6 +12,7 @@ from cloudbridge.cloud.base.resources import BaseBucket
 from cloudbridge.cloud.base.resources import BaseBucketContainer
 from cloudbridge.cloud.base.resources import BaseBucketObject
 from cloudbridge.cloud.base.resources import BaseFloatingIP
+from cloudbridge.cloud.base.resources import BaseFloatingIPContainer
 from cloudbridge.cloud.base.resources import BaseInstance
 from cloudbridge.cloud.base.resources import BaseInternetGateway
 from cloudbridge.cloud.base.resources import BaseKeyPair
@@ -39,9 +41,12 @@ from cloudbridge.cloud.interfaces.resources import SubnetState
 from cloudbridge.cloud.interfaces.resources import TrafficDirection
 from cloudbridge.cloud.interfaces.resources import VolumeState
 
+from .helpers import BotoEC2Service
 from .helpers import find_tag_value
 from .helpers import trim_empty_params
 
+log = logging.getLogger(__name__)
+
 
 class AWSMachineImage(BaseMachineImage):
 
@@ -995,6 +1000,31 @@ class AWSSubnet(BaseSubnet):
             self._subnet.state = SubnetState.UNKNOWN
 
 
+class AWSFloatingIPContainer(BaseFloatingIPContainer):
+
+    def __init__(self, provider, gateway):
+        super(AWSFloatingIPContainer, self).__init__(provider, gateway)
+        self.svc = BotoEC2Service(provider=self._provider,
+                                  cb_resource=AWSFloatingIP,
+                                  boto_collection_name='vpc_addresses')
+
+    def get(self, fip_id):
+        log.debug("Getting AWS Floating IP Service with the id: %s", fip_id)
+        return self.svc.get(fip_id)
+
+    def list(self, limit=None, marker=None):
+        log.debug("Listing all floating IPs under gateway %s", self.gateway)
+        return self.svc.list(limit=limit, marker=marker)
+
+    def create(self):
+        log.debug("Creating a floating IP under gateway %s", self.gateway)
+        ip = self._provider.ec2_conn.meta.client.allocate_address(
+            Domain='vpc')
+        return AWSFloatingIP(
+            self._provider,
+            self._provider.ec2_conn.VpcAddress(ip.get('AllocationId')))
+
+
 class AWSFloatingIP(BaseFloatingIP):
 
     def __init__(self, provider, floating_ip):
@@ -1099,6 +1129,7 @@ class AWSInternetGateway(BaseInternetGateway):
         super(AWSInternetGateway, self).__init__(provider)
         self._gateway = gateway
         self._gateway.state = ''
+        self._fips_container = AWSFloatingIPContainer(provider, self)
 
     @property
     def id(self):
@@ -1134,8 +1165,14 @@ class AWSInternetGateway(BaseInternetGateway):
         return None
 
     def delete(self):
+        if self.network_id:
+            self._gateway.detach_from_vpc(VpcId=self.network_id)
         self._gateway.delete()
 
+    @property
+    def floating_ips(self):
+        return self._fips_container
+
 
 class AWSLaunchConfig(BaseLaunchConfig):
 

+ 0 - 29
cloudbridge/cloud/providers/aws/services.py

@@ -8,7 +8,6 @@ import cloudbridge.cloud.base.helpers as cb_helpers
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.services import BaseBucketService
 from cloudbridge.cloud.base.services import BaseComputeService
-from cloudbridge.cloud.base.services import BaseFloatingIPService
 from cloudbridge.cloud.base.services import BaseGatewayService
 from cloudbridge.cloud.base.services import BaseImageService
 from cloudbridge.cloud.base.services import BaseInstanceService
@@ -589,7 +588,6 @@ class AWSNetworkingService(BaseNetworkingService):
         super(AWSNetworkingService, self).__init__(provider)
         self._network_service = AWSNetworkService(self.provider)
         self._subnet_service = AWSSubnetService(self.provider)
-        self._fip_service = AWSFloatingIPService(self.provider)
         self._router_service = AWSRouterService(self.provider)
         self._gateway_service = AWSGatewayService(self.provider)
 
@@ -601,10 +599,6 @@ class AWSNetworkingService(BaseNetworkingService):
     def subnets(self):
         return self._subnet_service
 
-    @property
-    def floating_ips(self):
-        return self._fip_service
-
     @property
     def routers(self):
         return self._router_service
@@ -730,29 +724,6 @@ class AWSSubnetService(BaseSubnetService):
         self.svc.delete(subnet_id)
 
 
-class AWSFloatingIPService(BaseFloatingIPService):
-
-    def __init__(self, provider):
-        super(AWSFloatingIPService, self).__init__(provider)
-        self.svc = BotoEC2Service(provider=self.provider,
-                                  cb_resource=AWSFloatingIP,
-                                  boto_collection_name='vpc_addresses')
-
-    def get(self, fip_id):
-        log.debug("Getting AWS Floating IP Service with the id: %s", fip_id)
-        return self.svc.get(fip_id)
-
-    def list(self, limit=None, marker=None):
-        return self.svc.list(limit=limit, marker=marker)
-
-    def create(self):
-        ip = self.provider.ec2_conn.meta.client.allocate_address(
-            Domain='vpc')
-        return AWSFloatingIP(
-            self.provider,
-            self.provider.ec2_conn.VpcAddress(ip.get('AllocationId')))
-
-
 class AWSRouterService(BaseRouterService):
     """For AWS, a CloudBridge router corresponds to an AWS Route Table."""
 

+ 38 - 1
cloudbridge/cloud/providers/azure/resources.py

@@ -4,13 +4,15 @@ DataTypes used by this provider
 import collections
 import logging
 import time
+import uuid
 
 from azure.common import AzureException
 from azure.mgmt.network.models import NetworkSecurityGroup
 
 from cloudbridge.cloud.base.resources import BaseAttachmentInfo, \
     BaseBucket, BaseBucketContainer, BaseBucketObject, BaseFloatingIP, \
-    BaseInstance, BaseInternetGateway, BaseKeyPair, BaseLaunchConfig, \
+    BaseFloatingIPContainer, BaseInstance, BaseInternetGateway, BaseKeyPair, \
+    BaseLaunchConfig, \
     BaseMachineImage, BaseNetwork, BasePlacementZone, BaseRegion, BaseRouter, \
     BaseSnapshot, BaseSubnet, BaseVMFirewall, BaseVMFirewallRule, \
     BaseVMFirewallRuleContainer, BaseVMType, BaseVolume, ClientPagedResultList
@@ -964,6 +966,36 @@ class AzureNetwork(BaseNetwork):
             create(network=self.id, cidr_block=cidr_block, name=name)
 
 
+class AzureFloatingIPContainer(BaseFloatingIPContainer):
+
+    def __init__(self, provider, gateway):
+        super(AzureFloatingIPContainer, self).__init__(provider, gateway)
+
+    def get(self, fip_id):
+        log.debug("Getting Azure Floating IP container with the id: %s",
+                  fip_id)
+        fip = [fip for fip in self.list() if fip.id == fip_id]
+        return fip[0] if fip else None
+
+    def list(self, limit=None, marker=None):
+        floating_ips = [AzureFloatingIP(self._provider, floating_ip)
+                        for floating_ip in self._provider.azure_client.
+                        list_floating_ips()]
+        return ClientPagedResultList(self._provider, floating_ips,
+                                     limit=limit, marker=marker)
+
+    def create(self):
+        public_ip_address_name = "{0}-{1}".format(
+            'public_ip', uuid.uuid4().hex[:6])
+        public_ip_parameters = {
+            'location': self._provider.azure_client.region_name,
+            'public_ip_allocation_method': 'Static'
+        }
+        floating_ip = self._provider.azure_client.\
+            create_floating_ip(public_ip_address_name, public_ip_parameters)
+        return AzureFloatingIP(self._provider, floating_ip)
+
+
 class AzureFloatingIP(BaseFloatingIP):
 
     def __init__(self, provider, floating_ip):
@@ -1702,6 +1734,7 @@ class AzureInternetGateway(BaseInternetGateway):
         self._name = None
         self._network_id = None
         self._state = ''
+        self._fips_container = AzureFloatingIPContainer(provider, self)
 
     @property
     def id(self):
@@ -1738,3 +1771,7 @@ class AzureInternetGateway(BaseInternetGateway):
 
     def delete(self):
         pass
+
+    @property
+    def floating_ips(self):
+        return self._fips_container

+ 1 - 37
cloudbridge/cloud/providers/azure/services.py

@@ -8,7 +8,7 @@ import cloudbridge.cloud.base.helpers as cb_helpers
 from cloudbridge.cloud.base.resources import ClientPagedResultList, \
     ServerPagedResultList
 from cloudbridge.cloud.base.services import BaseBucketService, \
-    BaseComputeService, BaseFloatingIPService, BaseGatewayService, \
+    BaseComputeService, BaseGatewayService, \
     BaseImageService, BaseInstanceService, BaseKeyPairService, \
     BaseNetworkService, BaseNetworkingService, BaseRegionService, \
     BaseRouterService, BaseSecurityService, BaseSnapshotService, \
@@ -770,7 +770,6 @@ class AzureNetworkingService(BaseNetworkingService):
         super(AzureNetworkingService, self).__init__(provider)
         self._network_service = AzureNetworkService(self.provider)
         self._subnet_service = AzureSubnetService(self.provider)
-        self._fip_service = AzureFloatingIPService(self.provider)
         self._router_service = AzureRouterService(self.provider)
         self._gateway_service = AzureGatewayService(self.provider)
 
@@ -782,10 +781,6 @@ class AzureNetworkingService(BaseNetworkingService):
     def subnets(self):
         return self._subnet_service
 
-    @property
-    def floating_ips(self):
-        return self._fip_service
-
     @property
     def routers(self):
         return self._router_service
@@ -860,37 +855,6 @@ class AzureNetworkService(BaseNetworkService):
             return False
 
 
-class AzureFloatingIPService(BaseFloatingIPService):
-
-    def __init__(self, provider):
-        super(AzureFloatingIPService, self).__init__(provider)
-
-    def get(self, floating_ip):
-        log.debug("Getting AWS Floating IP Service with the id: %s",
-                  floating_ip)
-        fip = [fip for fip in self.list() if fip.id == floating_ip]
-        return fip[0] if fip else None
-
-    def list(self, limit=None, marker=None):
-        floating_ips = [AzureFloatingIP(self.provider, floating_ip)
-                        for floating_ip in self.provider.azure_client.
-                        list_floating_ips()]
-        return ClientPagedResultList(self.provider, floating_ips,
-                                     limit=limit, marker=marker)
-
-    def create(self):
-        public_ip_address_name = "{0}-{1}".format(
-            'public_ip', uuid.uuid4().hex[:6])
-        public_ip_parameters = {
-            'location': self.provider.azure_client.region_name,
-            'public_ip_allocation_method': 'Static'
-        }
-
-        floating_ip = self.provider.azure_client.\
-            create_floating_ip(public_ip_address_name, public_ip_parameters)
-        return AzureFloatingIP(self.provider, floating_ip)
-
-
 class AzureRegionService(BaseRegionService):
     def __init__(self, provider):
         super(AzureRegionService, self).__init__(provider)

+ 37 - 2
cloudbridge/cloud/providers/openstack/resources.py

@@ -11,6 +11,7 @@ from cloudbridge.cloud.base.resources import BaseBucket
 from cloudbridge.cloud.base.resources import BaseBucketContainer
 from cloudbridge.cloud.base.resources import BaseBucketObject
 from cloudbridge.cloud.base.resources import BaseFloatingIP
+from cloudbridge.cloud.base.resources import BaseFloatingIPContainer
 from cloudbridge.cloud.base.resources import BaseInstance
 from cloudbridge.cloud.base.resources import BaseInternetGateway
 from cloudbridge.cloud.base.resources import BaseKeyPair
@@ -28,6 +29,7 @@ from cloudbridge.cloud.base.resources import BaseVMType
 from cloudbridge.cloud.base.resources import BaseVolume
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.interfaces.exceptions import InvalidValueException
+from cloudbridge.cloud.interfaces.exceptions import ProviderInternalException
 from cloudbridge.cloud.interfaces.resources import GatewayState
 from cloudbridge.cloud.interfaces.resources import InstanceState
 from cloudbridge.cloud.interfaces.resources import MachineImageState
@@ -46,6 +48,7 @@ from neutronclient.common.exceptions import PortNotFoundClient
 import novaclient.exceptions as novaex
 
 from openstack.exceptions import HttpException
+from openstack.exceptions import ResourceNotFound
 
 import swiftclient
 from swiftclient.service import SwiftService, SwiftUploadObject
@@ -762,7 +765,8 @@ class OpenStackNetwork(BaseNetwork):
         return ''
 
     def delete(self):
-        if self.id in str(self._provider.neutron.list_networks()):
+        if not self.external and self.id in str(
+                self._provider.neutron.list_networks()):
             # If there are ports associated with the network, it won't delete
             ports = self._provider.neutron.list_ports(
                 network_id=self.id).get('ports', [])
@@ -854,6 +858,32 @@ class OpenStackSubnet(BaseSubnet):
             self._state = SubnetState.UNKNOWN
 
 
+class OpenStackFloatingIPContainer(BaseFloatingIPContainer):
+
+    def __init__(self, provider, gateway):
+        super(OpenStackFloatingIPContainer, self).__init__(provider, gateway)
+
+    def get(self, fip_id):
+        try:
+            return OpenStackFloatingIP(
+                self._provider, self._provider.os_conn.network.get_ip(fip_id))
+        except ResourceNotFound:
+            return None
+
+    def list(self, limit=None, marker=None):
+        fips = [OpenStackFloatingIP(self._provider, fip)
+                for fip in self._provider.os_conn.network.ips(
+                    floating_network_id=self.gateway.id
+                )]
+        return ClientPagedResultList(self._provider, fips,
+                                     limit=limit, marker=marker)
+
+    def create(self):
+        return OpenStackFloatingIP(
+            self._provider, self._provider.os_conn.network.create_ip(
+                floating_network_id=self.gateway.id))
+
+
 class OpenStackFloatingIP(BaseFloatingIP):
 
     def __init__(self, provider, floating_ip):
@@ -969,6 +999,7 @@ class OpenStackInternetGateway(BaseInternetGateway):
             # pylint:disable=protected-access
             gateway_net = gateway_net._network
         self._gateway_net = gateway_net
+        self._fips_container = OpenStackFloatingIPContainer(provider, self)
 
     @property
     def id(self):
@@ -988,7 +1019,7 @@ class OpenStackInternetGateway(BaseInternetGateway):
 
     @property
     def network_id(self):
-        return self._gateway_net.id
+        return self._gateway_net.get('id')
 
     def refresh(self):
         """Refresh the state of this network by re-querying the provider."""
@@ -1009,6 +1040,10 @@ class OpenStackInternetGateway(BaseInternetGateway):
         """Do nothing on openstack"""
         pass
 
+    @property
+    def floating_ips(self):
+        return self._fips_container
+
 
 class OpenStackKeyPair(BaseKeyPair):
 

+ 0 - 38
cloudbridge/cloud/providers/openstack/services.py

@@ -12,7 +12,6 @@ from cloudbridge.cloud.base.resources import BaseLaunchConfig
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.services import BaseBucketService
 from cloudbridge.cloud.base.services import BaseComputeService
-from cloudbridge.cloud.base.services import BaseFloatingIPService
 from cloudbridge.cloud.base.services import BaseGatewayService
 from cloudbridge.cloud.base.services import BaseImageService
 from cloudbridge.cloud.base.services import BaseInstanceService
@@ -28,7 +27,6 @@ from cloudbridge.cloud.base.services import BaseSubnetService
 from cloudbridge.cloud.base.services import BaseVMFirewallService
 from cloudbridge.cloud.base.services import BaseVMTypeService
 from cloudbridge.cloud.base.services import BaseVolumeService
-from cloudbridge.cloud.interfaces.exceptions import ProviderInternalException
 from cloudbridge.cloud.interfaces.resources import KeyPair
 from cloudbridge.cloud.interfaces.resources import MachineImage
 from cloudbridge.cloud.interfaces.resources import PlacementZone
@@ -46,7 +44,6 @@ from novaclient.exceptions import NotFound as NovaNotFound
 from openstack.exceptions import ResourceNotFound
 
 from .resources import OpenStackBucket
-from .resources import OpenStackFloatingIP
 from .resources import OpenStackInstance
 from .resources import OpenStackInternetGateway
 from .resources import OpenStackKeyPair
@@ -756,7 +753,6 @@ class OpenStackNetworkingService(BaseNetworkingService):
         super(OpenStackNetworkingService, self).__init__(provider)
         self._network_service = OpenStackNetworkService(self.provider)
         self._subnet_service = OpenStackSubnetService(self.provider)
-        self._fip_service = OpenStackFloatingIPService(self.provider)
         self._router_service = OpenStackRouterService(self.provider)
         self._gateway_service = OpenStackGatewayService(self.provider)
 
@@ -768,10 +764,6 @@ class OpenStackNetworkingService(BaseNetworkingService):
     def subnets(self):
         return self._subnet_service
 
-    @property
-    def floating_ips(self):
-        return self._fip_service
-
     @property
     def routers(self):
         return self._router_service
@@ -892,36 +884,6 @@ class OpenStackSubnetService(BaseSubnetService):
         return False
 
 
-class OpenStackFloatingIPService(BaseFloatingIPService):
-
-    def __init__(self, provider):
-        super(OpenStackFloatingIPService, self).__init__(provider)
-
-    def get(self, fip_id):
-        try:
-            return OpenStackFloatingIP(
-                self.provider, self.provider.os_conn.network.get_ip(fip_id))
-        except ResourceNotFound:
-            return None
-
-    def list(self, limit=None, marker=None):
-        fips = [OpenStackFloatingIP(self.provider, fip)
-                for fip in self.provider.os_conn.network.ips()]
-        return ClientPagedResultList(self.provider, fips,
-                                     limit=limit, marker=marker)
-
-    def create(self):
-        # OpenStack requires a floating IP to be associated with an external,
-        # network, so choose the first external network found
-        for n in self.provider.networking.networks:
-            if n.external:
-                return OpenStackFloatingIP(
-                    self.provider, self.provider.os_conn.network.create_ip(
-                        floating_network_id=n.id))
-        raise ProviderInternalException(
-            "This OpenStack cloud has no designated external network")
-
-
 class OpenStackRouterService(BaseRouterService):
 
     def __init__(self, provider):

+ 21 - 0
test/helpers/__init__.py

@@ -132,6 +132,27 @@ def delete_test_network(network):
                 pass
 
 
+def get_test_gateway(provider, name):
+    """
+    Get an internet gateway for testing.
+
+    This includes creating a network for the gateway, which is also returned.
+    """
+    net_name = 'cb_testgwnet-{0}'.format(get_uuid())
+    net = provider.networking.networks.create(
+        name=net_name, cidr_block='10.0.0.0/16')
+    return net, provider.networking.gateways.get_or_create_inet_gateway(
+        net, name)
+
+
+def delete_test_gateway(network, gateway):
+    """
+    Delete the supplied network and gateway.
+    """
+    gateway.delete()
+    network.delete()
+
+
 def create_test_instance(
         provider, instance_name, subnet, launch_config=None,
         key_pair=None, vm_firewalls=None, user_data=None):

+ 31 - 23
test/test_network_service.py

@@ -91,38 +91,46 @@ class CloudNetworkServiceTestCase(ProviderTestBase):
             sit.check_crud(self, self.provider.networking.subnets, Subnet,
                            "cb_crudsubnet", create_subnet, cleanup_subnet)
 
-    @helpers.skipIfNoService(['networking.floating_ips'])
     def test_crud_floating_ip(self):
 
         def create_fip(name):
-            return self.provider.networking.floating_ips.create()
+            fip = gw.floating_ips.create()
+            return fip
 
         def cleanup_fip(fip):
-            self.provider.networking.floating_ips.delete(fip.id)
+            gw.floating_ips.delete(fip.id)
 
-        sit.check_crud(self, self.provider.networking.floating_ips, FloatingIP,
-                       "cb_crudfip", create_fip, cleanup_fip,
-                       skip_name_check=True)
+        net, gw = helpers.get_test_gateway(
+            self.provider, 'cb_crudfipgw-{0}'.format(helpers.get_uuid()))
+        with helpers.cleanup_action(
+                lambda: helpers.delete_test_gateway(net, gw)):
+            sit.check_crud(self, gw.floating_ips, FloatingIP,
+                           "cb_crudfip", create_fip, cleanup_fip,
+                           skip_name_check=True)
 
     def test_floating_ip_properties(self):
         # Check floating IP address
-        fip = self.provider.networking.floating_ips.create()
-        with helpers.cleanup_action(lambda: fip.delete()):
-            fipl = list(self.provider.networking.floating_ips)
-            self.assertIn(fip, fipl)
-            # 2016-08: address filtering not implemented in moto
-            # empty_ipl = self.provider.network.floating_ips('dummy-net')
-            # self.assertFalse(
-            #     empty_ipl,
-            #     "Bogus network should not have any floating IPs: {0}"
-            #     .format(empty_ipl))
-            self.assertFalse(
-                fip.private_ip,
-                "Floating IP should not have a private IP value ({0})."
-                .format(fip.private_ip))
-            self.assertFalse(
-                fip.in_use,
-                "Newly created floating IP address should not be in use.")
+        net, gw = helpers.get_test_gateway(
+            self.provider, 'cb_crudfipgw-{0}'.format(helpers.get_uuid()))
+        fip = gw.floating_ips.create()
+        with helpers.cleanup_action(
+                lambda: helpers.delete_test_gateway(net, gw)):
+            with helpers.cleanup_action(lambda: fip.delete()):
+                fipl = list(gw.floating_ips)
+                self.assertIn(fip, fipl)
+                # 2016-08: address filtering not implemented in moto
+                # empty_ipl = self.provider.network.floating_ips('dummy-net')
+                # self.assertFalse(
+                #     empty_ipl,
+                #     "Bogus network should not have any floating IPs: {0}"
+                #     .format(empty_ipl))
+                self.assertFalse(
+                    fip.private_ip,
+                    "Floating IP should not have a private IP value ({0})."
+                    .format(fip.private_ip))
+                self.assertFalse(
+                    fip.in_use,
+                    "Newly created floating IP address should not be in use.")
 
     @helpers.skipIfNoService(['networking.routers'])
     def test_crud_router(self):