Merge "Remove race due to 1907084"
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index c7004dd..c1981f9 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -126,16 +126,16 @@
 
 .. code-block:: python
 
-    class BaseTestCase1(api_version_utils.BaseMicroversionTest):
+   class BaseTestCase1(api_version_utils.BaseMicroversionTest):
 
-        [..]
-    @classmethod
-    def skip_checks(cls):
-        super(BaseTestCase1, cls).skip_checks()
-        api_version_utils.check_skip_with_microversion(cls.min_microversion,
-                                                       cls.max_microversion,
-                                                       CONF.compute.min_microversion,
-                                                       CONF.compute.max_microversion)
+       [..]
+       @classmethod
+       def skip_checks(cls):
+           super(BaseTestCase1, cls).skip_checks()
+           api_version_utils.check_skip_with_microversion(cls.min_microversion,
+                                                          cls.max_microversion,
+                                                          CONF.compute.min_microversion,
+                                                          CONF.compute.max_microversion)
 
 Skip logic can be added in tests base class or any specific test class depends on
 tests class structure.
diff --git a/doc/source/plugins/plugin.rst b/doc/source/plugins/plugin.rst
index ab1b0b1..6726def 100644
--- a/doc/source/plugins/plugin.rst
+++ b/doc/source/plugins/plugin.rst
@@ -268,12 +268,12 @@
 
    class MyAPIClient(rest_client.RestClient):
 
-    def __init__(self, auth_provider, service, region,
-                 my_arg, my_arg2=True, **kwargs):
-        super(MyAPIClient, self).__init__(
-            auth_provider, service, region, **kwargs)
-        self.my_arg = my_arg
-        self.my_args2 = my_arg
+       def __init__(self, auth_provider, service, region,
+                    my_arg, my_arg2=True, **kwargs):
+           super(MyAPIClient, self).__init__(
+               auth_provider, service, region, **kwargs)
+           self.my_arg = my_arg
+           self.my_args2 = my_arg
 
 Finally the service client should be structured in a python module, so that all
 service client classes are importable from it. Each major API version should
diff --git a/doc/source/write_tests.rst b/doc/source/write_tests.rst
index 0a29b7b..34df089 100644
--- a/doc/source/write_tests.rst
+++ b/doc/source/write_tests.rst
@@ -76,54 +76,54 @@
 
   class TestExampleCase(test.BaseTestCase):
 
-    @classmethod
-    def skip_checks(cls):
-        """This section is used to evaluate config early and skip all test
-           methods based on these checks
-        """
-        super(TestExampleCase, cls).skip_checks()
-        if not CONF.section.foo
-            cls.skip('A helpful message')
+      @classmethod
+      def skip_checks(cls):
+          """This section is used to evaluate config early and skip all test
+             methods based on these checks
+          """
+          super(TestExampleCase, cls).skip_checks()
+          if not CONF.section.foo
+              cls.skip('A helpful message')
 
-    @classmethod
-    def setup_credentials(cls):
-        """This section is used to do any manual credential allocation and also
-           in the case of dynamic credentials to override the default network
-           resource creation/auto allocation
-        """
-        # This call is used to tell the credential allocator to not create any
-        # network resources for this test case. It also enables selective
-        # creation of other neutron resources. NOTE: it must go before the
-        # super call
-        cls.set_network_resources()
-        super(TestExampleCase, cls).setup_credentials()
+      @classmethod
+      def setup_credentials(cls):
+          """This section is used to do any manual credential allocation and also
+             in the case of dynamic credentials to override the default network
+             resource creation/auto allocation
+          """
+          # This call is used to tell the credential allocator to not create any
+          # network resources for this test case. It also enables selective
+          # creation of other neutron resources. NOTE: it must go before the
+          # super call
+          cls.set_network_resources()
+          super(TestExampleCase, cls).setup_credentials()
 
-    @classmethod
-    def setup_clients(cls):
-        """This section is used to setup client aliases from the manager object
-           or to initialize any additional clients. Except in a few very
-           specific situations you should not need to use this.
-        """
-        super(TestExampleCase, cls).setup_clients()
-        cls.servers_client = cls.os_primary.servers_client
+      @classmethod
+      def setup_clients(cls):
+          """This section is used to setup client aliases from the manager object
+             or to initialize any additional clients. Except in a few very
+             specific situations you should not need to use this.
+          """
+          super(TestExampleCase, cls).setup_clients()
+          cls.servers_client = cls.os_primary.servers_client
 
-    @classmethod
-    def resource_setup(cls):
-        """This section is used to create any resources or objects which are
-           going to be used and shared by **all** test methods in the
-           TestCase. Note then anything created in this section must also be
-           destroyed in the corresponding resource_cleanup() method (which will
-           be run during tearDownClass())
-        """
-        super(TestExampleCase, cls).resource_setup()
-        cls.shared_server = cls.servers_client.create_server(...)
-        cls.addClassResourceCleanup(waiters.wait_for_server_termination,
-                                    cls.servers_client,
-                                    cls.shared_server['id'])
-        cls.addClassResourceCleanup(
-            test_utils.call_and_ignore_notfound_exc(
-                cls.servers_client.delete_server,
-                cls.shared_server['id']))
+      @classmethod
+      def resource_setup(cls):
+          """This section is used to create any resources or objects which are
+             going to be used and shared by **all** test methods in the
+             TestCase. Note then anything created in this section must also be
+             destroyed in the corresponding resource_cleanup() method (which will
+             be run during tearDownClass())
+          """
+          super(TestExampleCase, cls).resource_setup()
+          cls.shared_server = cls.servers_client.create_server(...)
+          cls.addClassResourceCleanup(waiters.wait_for_server_termination,
+                                      cls.servers_client,
+                                      cls.shared_server['id'])
+          cls.addClassResourceCleanup(
+              test_utils.call_and_ignore_notfound_exc(
+                  cls.servers_client.delete_server,
+                  cls.shared_server['id']))
 
 .. _credentials:
 
@@ -150,9 +150,9 @@
 
         credentials = ['primary', 'admin']
 
-    @classmethod
-    def skip_checks(cls):
-    ...
+        @classmethod
+        def skip_checks(cls):
+            ...
 
 In this example the ``TestExampleAdmin`` TestCase will allocate 2 sets of
 credentials, one regular user and one admin user. The corresponding manager
@@ -225,10 +225,10 @@
 
   class TestExampleCase(test.BaseTestCase):
 
-  @classmethod
-  def setup_credentials(cls):
-      cls.set_network_resources(network=True, subnet=True, router=False)
-      super(TestExampleCase, cls).setup_credentials()
+      @classmethod
+      def setup_credentials(cls):
+          cls.set_network_resources(network=True, subnet=True, router=False)
+          super(TestExampleCase, cls).setup_credentials()
 
 There are 2 quirks with the usage here. First for the set_network_resources
 function to work properly it **must be called before super()**. This is so
@@ -242,10 +242,10 @@
 
   class TestExampleCase(test.BaseTestCase):
 
-  @classmethod
-  def setup_credentials(cls):
-      cls.set_network_resources()
-      super(TestExampleCase, cls).setup_credentials()
+      @classmethod
+      def setup_credentials(cls):
+          cls.set_network_resources()
+          super(TestExampleCase, cls).setup_credentials()
 
 This will not allocate any networking resources. This is because by default all
 the arguments default to False.
@@ -282,8 +282,8 @@
 
 
   class TestExampleCase(test.BaseTestCase):
-    def test_example_create_server(self):
-      self.os_primary.servers_client.create_server(...)
+      def test_example_create_server(self):
+          self.os_primary.servers_client.create_server(...)
 
 is all you need to do. As described previously, in the above example the
 ``self.os_primary`` is created automatically because the base test class sets the
@@ -305,8 +305,8 @@
 
 
   class TestExampleCase(test.BaseTestCase):
-    def test_example_create_server(self):
-      credentials = self.os_primary.credentials
+      def test_example_create_server(self):
+          credentials = self.os_primary.credentials
 
 The credentials object provides access to all of the credential information you
 would need to make API requests. For example, building off the previous
@@ -316,9 +316,9 @@
 
 
   class TestExampleCase(test.BaseTestCase):
-    def test_example_create_server(self):
-      credentials = self.os_primary.credentials
-      username = credentials.username
-      user_id = credentials.user_id
-      password = credentials.password
-      tenant_id = credentials.tenant_id
+      def test_example_create_server(self):
+          credentials = self.os_primary.credentials
+          username = credentials.username
+          user_id = credentials.user_id
+          password = credentials.password
+          tenant_id = credentials.tenant_id
diff --git a/releasenotes/notes/associate-disassociate-floating_ip-0b6cfebeef1304b0.yaml b/releasenotes/notes/associate-disassociate-floating_ip-0b6cfebeef1304b0.yaml
new file mode 100644
index 0000000..8e42e85
--- /dev/null
+++ b/releasenotes/notes/associate-disassociate-floating_ip-0b6cfebeef1304b0.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Added associate_floating_ip() and dissociate_floating_ip() methods
+    to the scenario manager.
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 28299a4..9e25901 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -402,7 +402,8 @@
         # Validate that the list was fetched sorted accordingly
         msg = 'No images were found that met the filter criteria.'
         self.assertNotEmpty(images_list, msg)
-        sorted_list = [image['size'] for image in images_list]
+        sorted_list = [image['size'] for image in images_list
+                       if image['size'] is not None]
         msg = 'The list of images was not sorted correctly.'
         self.assertEqual(sorted(sorted_list, reverse=desc), sorted_list, msg)
 
diff --git a/tempest/config.py b/tempest/config.py
index 0d49b51..382b80f 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -761,11 +761,13 @@
                 deprecated_reason="This config option is no longer "
                                   "used anywhere, so it can be removed."),
     cfg.StrOpt('port_vnic_type',
-               choices=[None, 'normal', 'direct', 'macvtap'],
+               choices=[None, 'normal', 'direct', 'macvtap', 'direct-physical',
+                        'baremetal', 'virtio-forwarder'],
                help="vnic_type to use when launching instances"
                     " with pre-configured ports."
                     " Supported ports are:"
-                    " ['normal','direct','macvtap']"),
+                    " ['normal', 'direct', 'macvtap', 'direct-physical', "
+                    "'baremetal', 'virtio-forwarder']"),
     cfg.Opt('port_profile',
             type=ProfileType,
             default={},
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 5ae72b2..2a41d13 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -201,6 +201,14 @@
                 direct: an SR-IOV port that is directly attached to a VM
                 macvtap: an SR-IOV port that is attached to a VM via a macvtap
                          device.
+                direct-physical: an SR-IOV port that is directly attached to a
+                                 VM using physical instead of virtual
+                                 functions.
+                baremetal: a baremetal port directly attached to a baremetal
+                           node.
+                virtio-forwarder:  an SR-IOV port that is indirectly attached
+                                   to a VM using a low-latency vhost-user
+                                   forwarding process.
               Defaults to ``CONF.network.port_vnic_type``.
             * *port_profile* (``dict``) --
               This attribute is a dictionary that can be used (with admin
@@ -861,15 +869,25 @@
         return timestamp
 
     def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
-                      private_key=None, server=None):
+                      private_key=None, server=None, username=None):
         """Returns timestamp
 
         This wrapper utility does ssh and returns the timestamp.
+
+        :param ip_address: The floating IP or fixed IP of the remote server
+        :param dev_name: Name of the device that stores the timestamp
+        :param mount_path: Path which should be used as mount point for
+                           dev_name
+        :param private_key: The SSH private key to use for authentication
+        :param server: Server dict, used for debugging purposes
+        :param username: Name of the Linux account on the remote server
         """
 
         ssh_client = self.get_remote_client(ip_address,
                                             private_key=private_key,
-                                            server=server)
+                                            server=server,
+                                            username=username)
+
         if dev_name is not None:
             ssh_client.mount(dev_name, mount_path)
         timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
@@ -1165,6 +1183,32 @@
                         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