Merge "Move floating IP operation from nova-network to neutron"
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 5188191..fc0a730 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -47,7 +47,7 @@
 class ScenarioTest(tempest.test.BaseTestCase):
     """Base class for scenario tests. Uses tempest own clients. """
 
-    credentials = ['primary']
+    credentials = ['primary', 'admin']
 
     compute_min_microversion = None
     compute_max_microversion = LATEST_MICROVERSION
@@ -115,8 +115,6 @@
         """This setup the service clients for the tests"""
         super(ScenarioTest, cls).setup_clients()
         cls.flavors_client = cls.os_primary.flavors_client
-        cls.compute_floating_ips_client = (
-            cls.os_primary.compute_floating_ips_client)
         if CONF.service_available.glance:
             # Check if glance v1 is available to determine which client to use.
             if CONF.image_feature_enabled.api_v1:
@@ -962,20 +960,98 @@
                 LOG.exception(extra_msg)
                 raise
 
-    def create_floating_ip(self, server, pool_name=None, **kwargs):
-        """Create a floating IP and associates to a server on Nova"""
+    def get_server_port_id_and_ip4(self, server, ip_addr=None, **kwargs):
 
-        if not pool_name:
-            pool_name = CONF.network.floating_network_name
+        if ip_addr and not kwargs.get('fixed_ips'):
+            kwargs['fixed_ips'] = 'ip_address=%s' % ip_addr
+        ports = self.os_admin.ports_client.list_ports(
+            device_id=server['id'], **kwargs)['ports']
 
-        floating_ip = (self.compute_floating_ips_client.
-                       create_floating_ip(pool=pool_name,
-                                          **kwargs)['floating_ip'])
+        # A port can have more than one IP address in some cases.
+        # If the network is dual-stack (IPv4 + IPv6), this port is associated
+        # with 2 subnets
+
+        def _is_active(port):
+            # NOTE(vsaienko) With Ironic, instances live on separate hardware
+            # servers. Neutron does not bind ports for Ironic instances, as a
+            # result the port remains in the DOWN state. This has been fixed
+            # with the introduction of the networking-baremetal plugin but
+            # it's not mandatory (and is not used on all stable branches).
+            return (port['status'] == 'ACTIVE' or
+                    port.get('binding:vnic_type') == 'baremetal')
+
+        port_map = [(p["id"], fxip["ip_address"])
+                    for p in ports
+                    for fxip in p["fixed_ips"]
+                    if (netutils.is_valid_ipv4(fxip["ip_address"]) and
+                        _is_active(p))]
+        inactive = [p for p in ports if p['status'] != 'ACTIVE']
+        if inactive:
+            LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
+
+        self.assertNotEmpty(port_map,
+                            "No IPv4 addresses found in: %s" % ports)
+        self.assertEqual(len(port_map), 1,
+                         "Found multiple IPv4 addresses: %s. "
+                         "Unable to determine which port to target."
+                         % port_map)
+        return port_map[0]
+
+    def create_floating_ip(self, server, external_network_id=None,
+                           port_id=None, client=None, **kwargs):
+        """Create a floating IP and associates to a resource/port on Neutron"""
+
+        if not external_network_id:
+            external_network_id = CONF.network.public_network_id
+        if not client:
+            client = self.floating_ips_client
+        if not port_id:
+            port_id, ip4 = self.get_server_port_id_and_ip4(server)
+        else:
+            ip4 = None
+
+        floatingip_kwargs = {
+            'floating_network_id': external_network_id,
+            'port_id': port_id,
+            'tenant_id': server.get('project_id') or server['tenant_id'],
+            'fixed_ip_address': ip4,
+        }
+        if CONF.network.subnet_id:
+            floatingip_kwargs['subnet_id'] = CONF.network.subnet_id
+
+        floatingip_kwargs.update(kwargs)
+        result = client.create_floatingip(**floatingip_kwargs)
+        floating_ip = result['floatingip']
+
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.compute_floating_ips_client.delete_floating_ip,
+                        client.delete_floatingip,
                         floating_ip['id'])
-        self.compute_floating_ips_client.associate_floating_ip_to_server(
-            floating_ip['ip'], server['id'])
+        return floating_ip
+
+    def associate_floating_ip(self, floating_ip, server):
+        """Associate floating ip to server
+
+        This wrapper utility attaches the floating_ip for
+        the respective port_id of server
+        """
+        port_id, _ = self.get_server_port_id_and_ip4(server)
+        kwargs = dict(port_id=port_id)
+        floating_ip = self.floating_ips_client.update_floatingip(
+            floating_ip['id'], **kwargs)['floatingip']
+        self.assertEqual(port_id, floating_ip['port_id'])
+        return floating_ip
+
+    def disassociate_floating_ip(self, floating_ip):
+        """Disassociates floating ip
+
+        This wrapper utility disassociates given floating ip.
+        :param floating_ip: a dict which is a return value of
+        floating_ips_client.create_floatingip method
+        """
+        kwargs = dict(port_id=None)
+        floating_ip = self.floating_ips_client.update_floatingip(
+            floating_ip['id'], **kwargs)['floatingip']
+        self.assertIsNone(floating_ip['port_id'])
         return floating_ip
 
     def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
@@ -1046,7 +1122,8 @@
             # The tests calling this method don't have a floating IP
             # and can't make use of the validation resources. So the
             # method is creating the floating IP there.
-            return self.create_floating_ip(server, **kwargs)['ip']
+            return self.create_floating_ip(
+                server, **kwargs)['floating_ip_address']
         elif CONF.validation.connect_method == 'fixed':
             # Determine the network name to look for based on config or creds
             # provider network resources.
@@ -1138,8 +1215,6 @@
 
     """
 
-    credentials = ['primary', 'admin']
-
     @classmethod
     def skip_checks(cls):
         super(NetworkScenarioTest, cls).skip_checks()
@@ -1274,43 +1349,6 @@
 
         return subnet
 
-    def get_server_port_id_and_ip4(self, server, ip_addr=None, **kwargs):
-
-        if ip_addr and not kwargs.get('fixed_ips'):
-            kwargs['fixed_ips'] = 'ip_address=%s' % ip_addr
-        ports = self.os_admin.ports_client.list_ports(
-            device_id=server['id'], **kwargs)['ports']
-
-        # A port can have more than one IP address in some cases.
-        # If the network is dual-stack (IPv4 + IPv6), this port is associated
-        # with 2 subnets
-
-        def _is_active(port):
-            # NOTE(vsaienko) With Ironic, instances live on separate hardware
-            # servers. Neutron does not bind ports for Ironic instances, as a
-            # result the port remains in the DOWN state. This has been fixed
-            # with the introduction of the networking-baremetal plugin but
-            # it's not mandatory (and is not used on all stable branches).
-            return (port['status'] == 'ACTIVE' or
-                    port.get('binding:vnic_type') == 'baremetal')
-
-        port_map = [(p["id"], fxip["ip_address"])
-                    for p in ports
-                    for fxip in p["fixed_ips"]
-                    if (netutils.is_valid_ipv4(fxip["ip_address"]) and
-                        _is_active(p))]
-        inactive = [p for p in ports if p['status'] != 'ACTIVE']
-        if inactive:
-            LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
-
-        self.assertNotEmpty(port_map,
-                            "No IPv4 addresses found in: %s" % ports)
-        self.assertEqual(len(port_map), 1,
-                         "Found multiple IPv4 addresses: %s. "
-                         "Unable to determine which port to target."
-                         % port_map)
-        return port_map[0]
-
     def get_network_by_name(self, network_name):
         net = self.os_admin.networks_client.list_networks(
             name=network_name)['networks']
@@ -1318,63 +1356,6 @@
                             "Unable to get network by name: %s" % network_name)
         return net[0]
 
-    def create_floating_ip(self, server, external_network_id=None,
-                           port_id=None, client=None, **kwargs):
-        """Create a floating IP and associates to a resource/port on Neutron"""
-
-        if not external_network_id:
-            external_network_id = CONF.network.public_network_id
-        if not client:
-            client = self.floating_ips_client
-        if not port_id:
-            port_id, ip4 = self.get_server_port_id_and_ip4(server)
-        else:
-            ip4 = None
-
-        floatingip_kwargs = {
-            'floating_network_id': external_network_id,
-            'port_id': port_id,
-            'tenant_id': server.get('project_id') or server['tenant_id'],
-            'fixed_ip_address': ip4,
-        }
-        if CONF.network.subnet_id:
-            floatingip_kwargs['subnet_id'] = CONF.network.subnet_id
-
-        floatingip_kwargs.update(kwargs)
-        result = client.create_floatingip(**floatingip_kwargs)
-        floating_ip = result['floatingip']
-
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        client.delete_floatingip,
-                        floating_ip['id'])
-        return floating_ip
-
-    def associate_floating_ip(self, floating_ip, server):
-        """Associate floating ip
-
-        This wrapper utility attaches the floating_ip for
-        the respective port_id of server
-        """
-        port_id, _ = self.get_server_port_id_and_ip4(server)
-        kwargs = dict(port_id=port_id)
-        floating_ip = self.floating_ips_client.update_floatingip(
-            floating_ip['id'], **kwargs)['floatingip']
-        self.assertEqual(port_id, floating_ip['port_id'])
-        return floating_ip
-
-    def disassociate_floating_ip(self, floating_ip):
-        """Disassociates floating ip
-
-        This wrapper utility disassociates given floating ip.
-        :param floating_ip: a dict which is a return value of
-        floating_ips_client.create_floatingip method
-        """
-        kwargs = dict(port_id=None)
-        floating_ip = self.floating_ips_client.update_floatingip(
-            floating_ip['id'], **kwargs)['floatingip']
-        self.assertIsNone(floating_ip['port_id'])
-        return floating_ip
-
     def check_floating_ip_status(self, floating_ip, status):
         """Verifies floatingip reaches the given status
 
@@ -1575,8 +1556,6 @@
 class EncryptionScenarioTest(ScenarioTest):
     """Base class for encryption scenario tests"""
 
-    credentials = ['primary', 'admin']
-
     @classmethod
     def setup_clients(cls):
         super(EncryptionScenarioTest, cls).setup_clients()
@@ -1618,6 +1597,8 @@
     class.
     """
 
+    credentials = ['primary']
+
     @classmethod
     def skip_checks(cls):
         super(ObjectStorageScenarioTest, cls).skip_checks()
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 5201315..2c981c8 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -100,7 +100,7 @@
         for addresses in server['addresses'].values():
             for address in addresses:
                 if (address['OS-EXT-IPS:type'] == 'floating' and
-                        address['addr'] == floating_ip['ip']):
+                        address['addr'] == floating_ip['floating_ip_address']):
                     return address
 
     @decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
@@ -129,7 +129,9 @@
         server = self.servers_client.show_server(server['id'])['server']
         if (CONF.network_feature_enabled.floating_ips and
             CONF.network.floating_network_name):
-            floating_ip = self.create_floating_ip(server)
+            fip = self.create_floating_ip(server)
+            floating_ip = self.associate_floating_ip(
+                fip, server)
             # fetch the server again to make sure the addresses were refreshed
             # after associating the floating IP
             server = self.servers_client.show_server(server['id'])['server']
@@ -138,8 +140,8 @@
             self.assertIsNotNone(
                 address,
                 "Failed to find floating IP '%s' in server addresses: %s" %
-                (floating_ip['ip'], server['addresses']))
-            ssh_ip = floating_ip['ip']
+                (floating_ip['floating_ip_address'], server['addresses']))
+            ssh_ip = floating_ip['floating_ip_address']
         else:
             ssh_ip = self.get_server_ip(server)
 
@@ -162,8 +164,7 @@
 
         if floating_ip:
             # delete the floating IP, this should refresh the server addresses
-            self.compute_floating_ips_client.delete_floating_ip(
-                floating_ip['id'])
+            self.disassociate_floating_ip(floating_ip)
 
             def is_floating_ip_detached_from_server():
                 server_info = self.servers_client.show_server(
@@ -177,5 +178,6 @@
                 CONF.compute.build_timeout,
                 CONF.compute.build_interval):
                 msg = ("Floating IP '%s' should not be in server addresses: %s"
-                       % (floating_ip['ip'], server['addresses']))
+                       % (floating_ip['floating_ip_address'],
+                          server['addresses']))
                 raise exceptions.TimeoutException(msg)
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 4c82d84..2a15470 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -52,7 +52,9 @@
             # Obtain a floating IP if floating_ips is enabled
             if (CONF.network_feature_enabled.floating_ips and
                 CONF.network.floating_network_name):
-                self.ip = self.create_floating_ip(self.instance)['ip']
+                fip = self.create_floating_ip(self.instance)
+                self.ip = self.associate_floating_ip(
+                    fip, self.instance)['floating_ip_address']
             else:
                 server = self.servers_client.show_server(
                     self.instance['id'])['server']
diff --git a/tempest/scenario/test_volume_backup_restore.py b/tempest/scenario/test_volume_backup_restore.py
index 71e6b53..d0885cf 100644
--- a/tempest/scenario/test_volume_backup_restore.py
+++ b/tempest/scenario/test_volume_backup_restore.py
@@ -84,11 +84,11 @@
                                     security_groups=[
                                         {'name': security_group['name']}])
 
-        # Create a floating ip
-        floating_ip = self.create_floating_ip(server)
-
+        # Create a floating ip and associate it to server.
+        fip = self.create_floating_ip(server)
+        floating_ip = self.associate_floating_ip(fip, server)
         # Check server connectivity
-        self.check_vm_connectivity(floating_ip['ip'],
+        self.check_vm_connectivity(floating_ip['floating_ip_address'],
                                    username=CONF.validation.image_ssh_user,
                                    private_key=keypair['private_key'],
                                    should_connect=True)