Merge "Improve logging of network state on the test host"
diff --git a/neutron_tempest_plugin/api/base.py b/neutron_tempest_plugin/api/base.py
index 7cf8dd4..d63dec8 100644
--- a/neutron_tempest_plugin/api/base.py
+++ b/neutron_tempest_plugin/api/base.py
@@ -702,6 +702,12 @@
         return pf
 
     @classmethod
+    def update_port_forwarding(cls, fip_id, pf_id, client=None, **kwargs):
+        """Wrapper utility for update_port_forwarding."""
+        client = client or cls.client
+        return client.update_port_forwarding(fip_id, pf_id, **kwargs)
+
+    @classmethod
     def delete_port_forwarding(cls, pf, client=None):
         """Delete port forwarding
 
diff --git a/neutron_tempest_plugin/api/test_port_forwarding_negative.py b/neutron_tempest_plugin/api/test_port_forwarding_negative.py
index 76dd6ee..386cbed 100644
--- a/neutron_tempest_plugin/api/test_port_forwarding_negative.py
+++ b/neutron_tempest_plugin/api/test_port_forwarding_negative.py
@@ -12,6 +12,7 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
+
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions
@@ -81,3 +82,43 @@
             internal_ip_address=port['fixed_ips'][0]['ip_address'],
             internal_port=1111, external_port=5555,
             protocol="tcp")
+
+    @decorators.attr(type='negative')
+    @decorators.idempotent_id('e9d3ffb6-e5bf-421d-acaa-ee6010dfbf14')
+    def test_out_of_range_ports(self):
+        port = self.create_port(self.network)
+        fip_for_pf = self.create_floatingip()
+
+        pf_params = {
+            'internal_port_id': port['id'],
+            'internal_ip_address': port['fixed_ips'][0]['ip_address'],
+            'internal_port': 1111,
+            'external_port': 3333,
+            'protocol': "tcp"}
+        pf = self.create_port_forwarding(fip_for_pf['id'], **pf_params)
+
+        # Check: Invalid input for external_port update
+        self.assertRaises(
+            exceptions.BadRequest,
+            self.update_port_forwarding,
+            fip_for_pf['id'], pf['id'], external_port=108343)
+
+        # Check: Invalid input for internal_port update
+        self.assertRaises(
+            exceptions.BadRequest,
+            self.update_port_forwarding,
+            fip_for_pf['id'], pf['id'], internal_port=108343)
+
+        # Check: Invalid input for external_port create
+        pf_params['internal_port'] = 4444
+        pf_params['external_port'] = 333333
+        self.assertRaises(
+            exceptions.BadRequest,
+            self.create_port_forwarding, fip_for_pf['id'], **pf_params)
+
+        # Check: Invalid input for internal_port create
+        pf_params['internal_port'] = 444444
+        pf_params['external_port'] = 3333
+        self.assertRaises(
+            exceptions.BadRequest,
+            self.create_port_forwarding, fip_for_pf['id'], **pf_params)
diff --git a/neutron_tempest_plugin/api/test_port_forwardings.py b/neutron_tempest_plugin/api/test_port_forwardings.py
index 82c3a34..79cce39 100644
--- a/neutron_tempest_plugin/api/test_port_forwardings.py
+++ b/neutron_tempest_plugin/api/test_port_forwardings.py
@@ -124,31 +124,10 @@
         fip = self.client.show_floatingip(fip['id'])['floatingip']
         self.assertEqual(0, len(fip['port_forwardings']))
 
-    @decorators.idempotent_id('8202cded-7e82-4420-9585-c091105404f6')
-    def test_associate_2_port_forwardings_to_floating_ip(self):
-        fip = self.create_floatingip()
-        forwardings_data = [(1111, 2222), (3333, 4444)]
-        created_pfs = []
-        for data in forwardings_data:
-            internal_port = data[0]
-            external_port = data[1]
-            port = self.create_port(self.network)
-            created_pf = self.create_port_forwarding(
-                fip['id'],
-                internal_port_id=port['id'],
-                internal_ip_address=port['fixed_ips'][0]['ip_address'],
-                internal_port=internal_port, external_port=external_port,
-                protocol="tcp")
-            self.assertEqual(internal_port, created_pf['internal_port'])
-            self.assertEqual(external_port, created_pf['external_port'])
-            self.assertEqual('tcp', created_pf['protocol'])
-            self.assertEqual(port['fixed_ips'][0]['ip_address'],
-                             created_pf['internal_ip_address'])
-            created_pfs.append(created_pf)
-
+    def _verify_created_pfs(self, fip_id, created_pfs):
         # Check that all PFs are visible in Floating IP details
-        fip = self.client.show_floatingip(fip['id'])['floatingip']
-        self.assertEqual(len(forwardings_data), len(fip['port_forwardings']))
+        fip = self.client.show_floatingip(fip_id)['floatingip']
+        self.assertEqual(len(created_pfs), len(fip['port_forwardings']))
         for pf in created_pfs:
             expected_pf = {
                 'external_port': pf['external_port'],
@@ -160,13 +139,73 @@
         # Test list of port forwardings
         port_forwardings = self.client.list_port_forwardings(
             fip['id'])['port_forwardings']
-        self.assertEqual(len(forwardings_data), len(port_forwardings))
+        self.assertEqual(len(created_pfs), len(port_forwardings))
         for pf in created_pfs:
             expected_pf = pf.copy()
             expected_pf.pop('client')
             expected_pf.pop('floatingip_id')
             self.assertIn(expected_pf, port_forwardings)
 
+    def _create_and_validate_pf(self, fip_id, internal_port_id,
+                                internal_ip_address, internal_port,
+                                external_port, protocol):
+        created_pf = self.create_port_forwarding(
+            fip_id,
+            internal_port_id=internal_port_id,
+            internal_ip_address=internal_ip_address,
+            internal_port=internal_port,
+            external_port=external_port,
+            protocol=protocol)
+        self.assertEqual(internal_port, created_pf['internal_port'])
+        self.assertEqual(external_port, created_pf['external_port'])
+        self.assertEqual(protocol, created_pf['protocol'])
+        self.assertEqual(internal_ip_address,
+                         created_pf['internal_ip_address'])
+        return created_pf
+
+    @decorators.idempotent_id('8202cded-7e82-4420-9585-c091105404f6')
+    def test_associate_2_port_forwardings_to_floating_ip(self):
+        fip = self.create_floatingip()
+        forwardings_data = [(1111, 2222), (3333, 4444)]
+        created_pfs = []
+        for data in forwardings_data:
+            internal_port = data[0]
+            external_port = data[1]
+            port = self.create_port(self.network)
+            created_pf = self._create_and_validate_pf(
+                fip_id=fip['id'],
+                internal_port_id=port['id'],
+                internal_ip_address=port['fixed_ips'][0]['ip_address'],
+                internal_port=internal_port, external_port=external_port,
+                protocol="tcp")
+            created_pfs.append(created_pf)
+        self._verify_created_pfs(fip['id'], created_pfs)
+
+    @decorators.idempotent_id('a7e6cc48-8a9b-49be-82fb-cef6f5c29381')
+    def test_associate_port_forwarding_to_2_fixed_ips(self):
+        fip = self.create_floatingip()
+        port = self.create_port(self.network)
+        internal_subnet_id = port['fixed_ips'][0]['subnet_id']
+        # Add a second fixed_ip address to port (same subnet)
+        port['fixed_ips'].append({'subnet_id': internal_subnet_id})
+        port = self.update_port(port, fixed_ips=port['fixed_ips'])
+        internal_ip_address1 = port['fixed_ips'][0]['ip_address']
+        internal_ip_address2 = port['fixed_ips'][1]['ip_address']
+        forwardings_data = [(4001, internal_ip_address1),
+                            (4002, internal_ip_address2)]
+        created_pfs = []
+        for data in forwardings_data:
+            external_port = data[0]
+            internal_ip_address = data[1]
+            created_pf = self._create_and_validate_pf(
+                fip_id=fip['id'],
+                internal_port_id=port['id'],
+                internal_ip_address=internal_ip_address,
+                internal_port=123, external_port=external_port,
+                protocol="tcp")
+            created_pfs.append(created_pf)
+        self._verify_created_pfs(fip['id'], created_pfs)
+
     @decorators.idempotent_id('6a34e811-66d1-4f63-aa4d-9013f15deb62')
     def test_associate_port_forwarding_to_used_floating_ip(self):
         port_for_fip = self.create_port(self.network)
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index 85d048a..7df7a9a 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -21,6 +21,7 @@
 from neutron_lib.api import validators
 from neutron_lib import constants as neutron_lib_constants
 from oslo_log import log
+from paramiko import ssh_exception as ssh_exc
 from tempest.common.utils import net_utils
 from tempest.common import waiters
 from tempest.lib.common.utils import data_utils
@@ -264,7 +265,7 @@
                                 pkey=ssh_key, timeout=ssh_timeout)
         try:
             ssh_client.test_connection_auth()
-        except lib_exc.SSHTimeout as ssh_e:
+        except (lib_exc.SSHTimeout, ssh_exc.AuthenticationException) as ssh_e:
             LOG.debug(ssh_e)
             self._log_console_output(servers)
             self._log_local_network_status()
@@ -389,7 +390,7 @@
                 fragmentation,
                 timeout=timeout, pattern=pattern,
                 forbid_packet_loss=forbid_packet_loss))
-        except lib_exc.SSHTimeout as ssh_e:
+        except (lib_exc.SSHTimeout, ssh_exc.AuthenticationException) as ssh_e:
             LOG.debug(ssh_e)
             self._log_console_output(servers)
             self._log_local_network_status()
@@ -464,7 +465,8 @@
         self.wait_for_server_status(
             server, constants.SERVER_STATUS_ACTIVE, client)
 
-    def check_servers_hostnames(self, servers, timeout=None, log_errors=True):
+    def check_servers_hostnames(self, servers, timeout=None, log_errors=True,
+                                external_port=None):
         """Compare hostnames of given servers with their names."""
         try:
             for server in servers:
@@ -472,7 +474,7 @@
                 if timeout:
                     kwargs['timeout'] = timeout
                 try:
-                    kwargs['port'] = (
+                    kwargs['port'] = external_port or (
                         server['port_forwarding_tcp']['external_port'])
                 except KeyError:
                     pass
@@ -483,7 +485,7 @@
                     **kwargs)
                 self.assertIn(server['name'],
                               ssh_client.exec_command('hostname'))
-        except lib_exc.SSHTimeout as ssh_e:
+        except (lib_exc.SSHTimeout, ssh_exc.AuthenticationException) as ssh_e:
             LOG.debug(ssh_e)
             if log_errors:
                 self._log_console_output(servers)
@@ -518,7 +520,7 @@
             return ssh_client.execute_script(
                 get_ncat_server_cmd(port, protocol, echo_msg),
                 become_root=True, combine_stderr=True)
-        except lib_exc.SSHTimeout as ssh_e:
+        except (lib_exc.SSHTimeout, ssh_exc.AuthenticationException) as ssh_e:
             LOG.debug(ssh_e)
             self._log_console_output(servers)
             self._log_local_network_status()
diff --git a/neutron_tempest_plugin/scenario/test_floatingip.py b/neutron_tempest_plugin/scenario/test_floatingip.py
index d541642..6d4d830 100644
--- a/neutron_tempest_plugin/scenario/test_floatingip.py
+++ b/neutron_tempest_plugin/scenario/test_floatingip.py
@@ -392,7 +392,6 @@
 
     same_network = None
 
-    @test.unstable_test("bug 1897326")
     @decorators.idempotent_id('1bdd849b-03dd-4b8f-994f-457cf8a36f93')
     def test_floating_ip_update(self):
         """Test updating FIP with another port.
@@ -435,8 +434,7 @@
 
         # The FIP is now associated with the port of the second server.
         try:
-            common_utils.wait_until_true(_wait_for_fip_associated,
-                                         timeout=15, sleep=3)
+            common_utils.wait_until_true(_wait_for_fip_associated, sleep=3)
         except common_utils.WaitTimeout:
             self._log_console_output(servers[-1:])
             self.fail(
diff --git a/neutron_tempest_plugin/scenario/test_ipv6.py b/neutron_tempest_plugin/scenario/test_ipv6.py
index 02e2846..15f05d0 100644
--- a/neutron_tempest_plugin/scenario/test_ipv6.py
+++ b/neutron_tempest_plugin/scenario/test_ipv6.py
@@ -15,6 +15,7 @@
 
 from neutron_lib import constants as lib_constants
 from oslo_log import log
+from paramiko import ssh_exception as ssh_exc
 from tempest.common import utils as tempest_utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
@@ -108,16 +109,22 @@
                     return True
             return False
 
-        # Set NIC with IPv6 to be UP and wait until IPv6 address will be
-        # configured on this NIC
-        turn_nic6_on(ssh_client, ipv6_port)
-        # And check if IPv6 address will be properly configured on this NIC
-        utils.wait_until_true(
-            lambda: guest_has_address(ipv6_address),
-            timeout=120,
-            exception=RuntimeError(
-                "Timed out waiting for IP address {!r} to be configured in "
-                "the VM {!r}.".format(ipv6_address, vm['id'])))
+        try:
+            # Set NIC with IPv6 to be UP and wait until IPv6 address will be
+            # configured on this NIC
+            turn_nic6_on(ssh_client, ipv6_port)
+            # And check if IPv6 address will be properly configured on this NIC
+            utils.wait_until_true(
+                lambda: guest_has_address(ipv6_address),
+                timeout=120,
+                exception=RuntimeError(
+                    "Timed out waiting for IP address {!r} to be configured "
+                    "in the VM {!r}.".format(ipv6_address, vm['id'])))
+        except (lib_exc.SSHTimeout, ssh_exc.AuthenticationException) as ssh_e:
+            LOG.debug(ssh_e)
+            self._log_console_output([vm])
+            self._log_local_network_status()
+            raise
 
     def _test_ipv6_hotplug(self, ra_mode, address_mode):
         ipv6_networks = [self.create_network() for _ in range(2)]
diff --git a/neutron_tempest_plugin/scenario/test_port_forwardings.py b/neutron_tempest_plugin/scenario/test_port_forwardings.py
index 3158ea0..4080bca 100644
--- a/neutron_tempest_plugin/scenario/test_port_forwardings.py
+++ b/neutron_tempest_plugin/scenario/test_port_forwardings.py
@@ -45,9 +45,14 @@
         cls.secgroup = cls.create_security_group(
             name=data_utils.rand_name("test_port_secgroup"))
         cls.create_loginable_secgroup_rule(secgroup_id=cls.secgroup['id'])
+        udp_sg_rule = {'protocol': constants.PROTO_NAME_UDP,
+                       'direction': constants.INGRESS_DIRECTION,
+                       'remote_ip_prefix': '0.0.0.0/0'}
+        cls.create_secgroup_rules(
+            [udp_sg_rule], secgroup_id=cls.secgroup['id'])
         cls.keypair = cls.create_keypair()
 
-    def _prepare_resources(self, num_servers, internal_tcp_port, protocol,
+    def _prepare_resources(self, num_servers, internal_tcp_port=22,
                            external_port_base=1025):
         servers = []
         for i in range(1, num_servers + 1):
@@ -82,7 +87,7 @@
             servers.append(server)
         return servers
 
-    def _test_udp_port_forwarding(self, servers):
+    def _test_udp_port_forwarding(self, servers, timeout=None):
 
         def _message_received(server, ssh_client, expected_msg):
             self.nc_listen(ssh_client,
@@ -103,23 +108,22 @@
                 CONF.validation.image_ssh_user,
                 pkey=self.keypair['private_key'],
                 port=server['port_forwarding_tcp']['external_port'])
+            wait_params = {
+                'exception': RuntimeError(
+                    "Timed out waiting for message from server {!r} ".format(
+                        server['id']))
+            }
+            if timeout:
+                wait_params['timeout'] = timeout
             utils.wait_until_true(
                 lambda: _message_received(server, ssh_client, expected_msg),
-                exception=RuntimeError(
-                    "Timed out waiting for message from server {!r} ".format(
-                        server['id'])))
+                **wait_params)
 
     @test.unstable_test("bug 1896735")
     @decorators.idempotent_id('ab40fc48-ca8d-41a0-b2a3-f6679c847bfe')
     def test_port_forwarding_to_2_servers(self):
-        udp_sg_rule = {'protocol': constants.PROTO_NAME_UDP,
-                       'direction': constants.INGRESS_DIRECTION,
-                       'remote_ip_prefix': '0.0.0.0/0'}
-        self.create_secgroup_rules(
-            [udp_sg_rule], secgroup_id=self.secgroup['id'])
-        servers = self._prepare_resources(
-            num_servers=2, internal_tcp_port=22,
-            protocol=constants.PROTO_NAME_TCP)
+        servers = self._prepare_resources(num_servers=2,
+                                          external_port_base=1035)
         # Test TCP port forwarding by SSH to each server
         self.check_servers_hostnames(servers)
         # And now test UDP port forwarding using nc
@@ -128,25 +132,16 @@
     @test.unstable_test("bug 1896735")
     @decorators.idempotent_id('aa19d46c-a4a6-11ea-bb37-0242ac130002')
     def test_port_forwarding_editing_and_deleting_tcp_rule(self):
-        server = self._prepare_resources(
-            num_servers=1, internal_tcp_port=22,
-            protocol=constants.PROTO_NAME_TCP,
-            external_port_base=1035)
+        test_ext_port = 3333
+        server = self._prepare_resources(num_servers=1,
+                                         external_port_base=1045)
         fip_id = server[0]['port_forwarding_tcp']['floatingip_id']
         pf_id = server[0]['port_forwarding_tcp']['id']
 
         # Check connectivity with the original parameters
         self.check_servers_hostnames(server)
 
-        # Use a reasonable timeout to verify that connections will not
-        # happen. Default would be 196 seconds, which is an overkill.
-        test_ssh_connect_timeout = 6
-
-        # Update external port and check connectivity with original parameters
-        # Port under server[0]['port_forwarding_tcp']['external_port'] should
-        # not answer at this point.
-
-        def fip_pf_connectivity():
+        def fip_pf_connectivity(test_ssh_connect_timeout=60):
             try:
                 self.check_servers_hostnames(
                     server, timeout=test_ssh_connect_timeout)
@@ -155,9 +150,13 @@
                 return False
 
         def no_fip_pf_connectivity():
-            return not fip_pf_connectivity()
+            return not fip_pf_connectivity(6)
 
-        self.client.update_port_forwarding(fip_id, pf_id, external_port=3333)
+        # Update external port and check connectivity with original parameters
+        # Port under server[0]['port_forwarding_tcp']['external_port'] should
+        # not answer at this point.
+        self.client.update_port_forwarding(fip_id, pf_id,
+                                           external_port=test_ext_port)
         utils.wait_until_true(
             no_fip_pf_connectivity,
             exception=RuntimeError(
@@ -167,7 +166,7 @@
                     server[0]['port_forwarding_tcp']['external_port'])))
 
         # Check connectivity with the new parameters
-        server[0]['port_forwarding_tcp']['external_port'] = 3333
+        server[0]['port_forwarding_tcp']['external_port'] = test_ext_port
         utils.wait_until_true(
             fip_pf_connectivity,
             exception=RuntimeError(
@@ -187,3 +186,105 @@
                 "port {!r} is still possible.".format(
                     server[0]['id'],
                     server[0]['port_forwarding_tcp']['external_port'])))
+
+    @test.unstable_test("bug 1896735")
+    @decorators.idempotent_id('6d05b1b2-6109-4c30-b402-1503f4634acb')
+    def test_port_forwarding_editing_and_deleting_udp_rule(self):
+        test_ext_port = 3344
+        server = self._prepare_resources(num_servers=1,
+                                         external_port_base=1055)
+        fip_id = server[0]['port_forwarding_udp']['floatingip_id']
+        pf_id = server[0]['port_forwarding_udp']['id']
+
+        # Check connectivity with the original parameters
+        self.check_servers_hostnames(server)
+
+        def fip_pf_udp_connectivity(test_udp_timeout=60):
+            try:
+                self._test_udp_port_forwarding(server, test_udp_timeout)
+                return True
+            except (AssertionError, RuntimeError):
+                return False
+
+        def no_fip_pf_udp_connectivity():
+            return not fip_pf_udp_connectivity(6)
+
+        # Update external port and check connectivity with original parameters
+        # Port under server[0]['port_forwarding_udp']['external_port'] should
+        # not answer at this point.
+        self.client.update_port_forwarding(fip_id, pf_id,
+                                           external_port=test_ext_port)
+        utils.wait_until_true(
+            no_fip_pf_udp_connectivity,
+            exception=RuntimeError(
+                "Connection to the server {!r} through "
+                "port {!r} is still possible.".format(
+                    server[0]['id'],
+                    server[0]['port_forwarding_udp']['external_port'])))
+
+        # Check connectivity with the new parameters
+        server[0]['port_forwarding_udp']['external_port'] = test_ext_port
+        utils.wait_until_true(
+            fip_pf_udp_connectivity,
+            exception=RuntimeError(
+                "Connection to the server {!r} through "
+                "port {!r} is not possible.".format(
+                    server[0]['id'],
+                    server[0]['port_forwarding_udp']['external_port'])))
+
+        # Remove port forwarding and ensure connection stops working.
+        self.client.delete_port_forwarding(fip_id, pf_id)
+        self.assertRaises(lib_exc.NotFound, self.client.get_port_forwarding,
+                          fip_id, pf_id)
+        utils.wait_until_true(
+            no_fip_pf_udp_connectivity,
+            exception=RuntimeError(
+                "Connection to the server {!r} through "
+                "port {!r} is still possible.".format(
+                    server[0]['id'],
+                    server[0]['port_forwarding_udp']['external_port'])))
+
+    @test.unstable_test("bug 1896735")
+    @decorators.idempotent_id('5971881d-06a0-459e-b636-ce5d1929e2d4')
+    def test_port_forwarding_to_2_fixed_ips(self):
+        port = self.create_port(self.network,
+            security_groups=[self.secgroup['id']])
+        name = data_utils.rand_name("server-0")
+        server = self.create_server(flavor_ref=CONF.compute.flavor_ref,
+            image_ref=CONF.compute.image_ref, key_name=self.keypair['name'],
+            name=name, networks=[{'port': port['id']}])['server']
+        server['name'] = name
+        self.wait_for_server_active(server)
+
+        # Add a second fixed_ip address to port (same subnet)
+        internal_subnet_id = port['fixed_ips'][0]['subnet_id']
+        port['fixed_ips'].append({'subnet_id': internal_subnet_id})
+        port = self.update_port(port, fixed_ips=port['fixed_ips'])
+        internal_ip_address1 = port['fixed_ips'][0]['ip_address']
+        internal_ip_address2 = port['fixed_ips'][1]['ip_address']
+        pfs = []
+        for ip_address, external_port in [(internal_ip_address1, 1066),
+                                          (internal_ip_address2, 1067)]:
+            pf = self.create_port_forwarding(
+                self.fip['id'], internal_port_id=port['id'],
+                internal_ip_address=ip_address,
+                internal_port=22, external_port=external_port,
+                protocol=constants.PROTO_NAME_TCP)
+            pfs.append(pf)
+
+        test_ssh_connect_timeout = 32
+        number_of_connects = 0
+        for pf in pfs:
+            try:
+                self.check_servers_hostnames(
+                    [server], timeout=test_ssh_connect_timeout,
+                    external_port=pf['external_port'])
+                number_of_connects += 1
+            except (AssertionError, lib_exc.SSHTimeout):
+                pass
+
+        # TODO(flaviof): Quite possibly, the server is using only one of the
+        # fixed ips associated with the neutron port. Being so, we should not
+        # fail the test, as long as at least one connection was successful.
+        self.assertGreaterEqual(
+            number_of_connects, 1, "Did not connect via FIP port forwarding")
diff --git a/neutron_tempest_plugin/scenario/test_security_groups.py b/neutron_tempest_plugin/scenario/test_security_groups.py
index 23a5224..9059a2f 100644
--- a/neutron_tempest_plugin/scenario/test_security_groups.py
+++ b/neutron_tempest_plugin/scenario/test_security_groups.py
@@ -33,13 +33,15 @@
     required_extensions = ['router', 'security-group']
 
     def _verify_http_connection(self, ssh_client, ssh_server,
-                                test_ip, test_port, should_pass=True):
+                                test_ip, test_port, servers, should_pass=True):
         """Verify if HTTP connection works using remote hosts.
 
         :param ssh.Client ssh_client: The client host active SSH client.
         :param ssh.Client ssh_server: The HTTP server host active SSH client.
         :param string test_ip: IP address of HTTP server
         :param string test_port: Port of HTTP server
+        :param list servers: List of servers for which console output will be
+                             logged in case when test case
         :param bool should_pass: Wheter test should pass or not.
 
         :return: if passed or not
@@ -57,6 +59,8 @@
         except Exception as e:
             if not should_pass:
                 return
+            self._log_console_output(servers)
+            self._log_local_network_status()
             raise e
 
     @classmethod
@@ -378,6 +382,7 @@
                 ssh_clients[0],
                 ssh_clients[2],
                 test_ip, port,
+                servers,
                 should_pass=False)
 
         # add two remote-group rules with port-ranges
@@ -399,7 +404,8 @@
             self._verify_http_connection(
                 ssh_clients[0],
                 ssh_clients[2],
-                test_ip, port)
+                test_ip, port,
+                servers)
 
     @decorators.idempotent_id('f07d0159-8f9e-4faa-87f5-a869ab0ad490')
     def test_intra_sg_isolation(self):
diff --git a/neutron_tempest_plugin/services/network/json/network_client.py b/neutron_tempest_plugin/services/network/json/network_client.py
index f056c7f..0b2544b 100644
--- a/neutron_tempest_plugin/services/network/json/network_client.py
+++ b/neutron_tempest_plugin/services/network/json/network_client.py
@@ -952,8 +952,6 @@
         return service_client.ResponseBody(resp, body)
 
     def list_floatingips(self, **kwargs):
-        post_body = {'floatingips': kwargs}
-        body = jsonutils.dumps(post_body)
         uri = '%s/floatingips' % self.uri_prefix
         if kwargs:
             uri += '?' + urlparse.urlencode(kwargs, doseq=1)
diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml
index ddf7dc6..77947fa 100644
--- a/zuul.d/base.yaml
+++ b/zuul.d/base.yaml
@@ -17,6 +17,8 @@
       devstack_localrc:
         USE_PYTHON3: true
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
+        CIRROS_VERSION: 0.5.1
+        BUILD_TIMEOUT: 784
       devstack_plugins:
         neutron: https://opendev.org/openstack/neutron.git
         neutron-tempest-plugin: https://opendev.org/openstack/neutron-tempest-plugin.git
@@ -100,6 +102,7 @@
       tempest_test_regex: ^neutron_tempest_plugin\.scenario
       devstack_localrc:
         PHYSICAL_NETWORK: default
+        CIRROS_VERSION: 0.5.1
         IMAGE_URLS: https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-amd64.img
         ADVANCED_IMAGE_NAME: ubuntu-18.04-server-cloudimg-amd64
         ADVANCED_INSTANCE_TYPE: ds512M
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index 5607274..71dfcb2 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -271,8 +271,9 @@
         USE_PYTHON3: true
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_dvr) | join(',') }}"
         PHYSICAL_NETWORK: default
-        IMAGE_URLS: https://cloud-images.ubuntu.com/releases/xenial/release/ubuntu-16.04-server-cloudimg-amd64-disk1.img
-        ADVANCED_IMAGE_NAME: ubuntu-16.04-server-cloudimg-amd64-disk1
+        CIRROS_VERSION: 0.5.1
+        IMAGE_URLS: https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-amd64.img
+        ADVANCED_IMAGE_NAME: ubuntu-18.04-server-cloudimg-amd64
         ADVANCED_INSTANCE_TYPE: ds512M
         ADVANCED_INSTANCE_USER: ubuntu
         BUILD_TIMEOUT: 784
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index afab1d3..0355f69 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -136,6 +136,30 @@
         - neutron-tempest-plugin-dvr-multinode-scenario-ussuri
 
 
+- project-template:
+    name: neutron-tempest-plugin-jobs-victoria
+    check:
+      jobs:
+        - neutron-tempest-plugin-api-victoria
+        - neutron-tempest-plugin-designate-scenario-victoria:
+            # TODO(slaweq): switch it to be voting when bug
+            # https://bugs.launchpad.net/neutron/+bug/1891309
+            # will be fixed
+            voting: false
+        - neutron-tempest-plugin-scenario-linuxbridge-victoria
+        - neutron-tempest-plugin-scenario-openvswitch-victoria
+        - neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-victoria
+        - neutron-tempest-plugin-scenario-ovn-victoria
+    gate:
+      jobs:
+        - neutron-tempest-plugin-api-victoria
+    #TODO(slaweq): Move neutron-tempest-plugin-dvr-multinode-scenario out of
+    #              the experimental queue when it will be more stable
+    experimental:
+      jobs:
+        - neutron-tempest-plugin-dvr-multinode-scenario-victoria
+
+
 - project:
     templates:
       - build-openstack-docs-pti
@@ -143,6 +167,7 @@
       - neutron-tempest-plugin-jobs-stein
       - neutron-tempest-plugin-jobs-train
       - neutron-tempest-plugin-jobs-ussuri
+      - neutron-tempest-plugin-jobs-victoria
       - check-requirements
       - tempest-plugin-jobs
       - release-notes-jobs-python3
@@ -151,6 +176,7 @@
         - neutron-tempest-plugin-sfc
         - neutron-tempest-plugin-sfc-train
         - neutron-tempest-plugin-sfc-ussuri
+        - neutron-tempest-plugin-sfc-victoria
         - neutron-tempest-plugin-bgpvpn-bagpipe:
             # TODO(slaweq): switch it to be voting when bug
             # https://bugs.launchpad.net/networking-bagpipe/+bug/1897408
@@ -162,6 +188,11 @@
             # https://bugs.launchpad.net/networking-bagpipe/+bug/1897408
             # will be fixed
             voting: false
+        - neutron-tempest-plugin-bgpvpn-bagpipe-victoria:
+            # TODO(slaweq): switch it to be voting when bug
+            # https://bugs.launchpad.net/networking-bagpipe/+bug/1897408
+            # will be fixed
+            voting: false
         - neutron-tempest-plugin-fwaas-train:
             # TODO(slaweq): switch it to be voting when bug
             # https://bugs.launchpad.net/neutron/+bug/1858645 will be fixed
@@ -172,8 +203,10 @@
             voting: false
         - neutron-tempest-plugin-dynamic-routing
         - neutron-tempest-plugin-dynamic-routing-ussuri
+        - neutron-tempest-plugin-dynamic-routing-victoria
         - neutron-tempest-plugin-vpnaas
         - neutron-tempest-plugin-vpnaas-ussuri
+        - neutron-tempest-plugin-vpnaas-victoria
 
     gate:
       jobs:
diff --git a/zuul.d/victoria_jobs.yaml b/zuul.d/victoria_jobs.yaml
new file mode 100644
index 0000000..0bc1e13
--- /dev/null
+++ b/zuul.d/victoria_jobs.yaml
@@ -0,0 +1,188 @@
+- job:
+    name: neutron-tempest-plugin-api-victoria
+    parent: neutron-tempest-plugin-api
+    override-checkout: stable/victoria
+    vars:
+      branch_override: stable/victoria
+      # TODO(slaweq): find a way to put this list of extensions in
+      # neutron repository and keep it different per branch,
+      # then it could be removed from here
+      network_api_extensions_common: &api_extensions
+        - address-scope
+        - agent
+        - allowed-address-pairs
+        - auto-allocated-topology
+        - availability_zone
+        - binding
+        - default-subnetpools
+        - dhcp_agent_scheduler
+        - dns-domain-ports
+        - dns-integration
+        - empty-string-filtering
+        - expose-port-forwarding-in-fip
+        - expose-l3-conntrack-helper
+        - ext-gw-mode
+        - external-net
+        - extra_dhcp_opt
+        - extraroute
+        - extraroute-atomic
+        - filter-validation
+        - fip-port-details
+        - flavors
+        - floating-ip-port-forwarding
+        - floatingip-pools
+        - ip-substring-filtering
+        - l3-conntrack-helper
+        - l3-flavors
+        - l3-ha
+        - l3_agent_scheduler
+        - logging
+        - metering
+        - multi-provider
+        - net-mtu
+        - net-mtu-writable
+        - network-ip-availability
+        - network_availability_zone
+        - network-segment-range
+        - pagination
+        - port-resource-request
+        - port-mac-address-regenerate
+        - port-security
+        - port-security-groups-filtering
+        - project-id
+        - provider
+        - qos
+        - qos-bw-minimum-ingress
+        - qos-fip
+        - quotas
+        - quota_details
+        - rbac-address-scope
+        - rbac-policies
+        - rbac-security-groups
+        - rbac-subnetpool
+        - router
+        - router-admin-state-down-before-update
+        - router_availability_zone
+        - security-group
+        - segment
+        - service-type
+        - sorting
+        - standard-attr-description
+        - standard-attr-revisions
+        - standard-attr-segment
+        - standard-attr-tag
+        - standard-attr-timestamp
+        - subnet_allocation
+        - subnet-dns-publish-fixed-ip
+        - subnetpool-prefix-ops
+        - tag-ports-during-bulk-creation
+        - trunk
+        - trunk-details
+        - uplink-status-propagation
+      network_api_extensions_tempest:
+        - dvr
+      devstack_localrc:
+        NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
+
+- job:
+    name: neutron-tempest-plugin-scenario-openvswitch-victoria
+    parent: neutron-tempest-plugin-scenario-openvswitch
+    override-checkout: stable/victoria
+    vars:
+      branch_override: stable/victoria
+      network_api_extensions: *api_extensions
+      devstack_localrc:
+        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
+      devstack_local_conf:
+        test-config:
+          $TEMPEST_CONFIG:
+            neutron_plugin_options:
+              ipv6_metadata: False
+
+- job:
+    name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-victoria
+    parent: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
+    override-checkout: stable-victoria
+    vars:
+      branch_override: stable-victoria
+      network_api_extensions: *api_extensions
+      devstack_localrc:
+        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
+      devstack_local_conf:
+        test-config:
+          $TEMPEST_CONFIG:
+            neutron_plugin_options:
+              ipv6_metadata: False
+
+- job:
+    name: neutron-tempest-plugin-scenario-linuxbridge-victoria
+    parent: neutron-tempest-plugin-scenario-linuxbridge
+    override-checkout: stable/victoria
+    vars:
+      branch_override: stable/victoria
+      network_api_extensions: *api_extensions
+      devstack_localrc:
+        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
+      devstack_local_conf:
+        test-config:
+          $TEMPEST_CONFIG:
+            neutron_plugin_options:
+              ipv6_metadata: False
+
+- job:
+    name: neutron-tempest-plugin-scenario-ovn-victoria
+    parent: neutron-tempest-plugin-scenario-ovn
+    override-checkout: stable/victoria
+    vars:
+      branch_override: stable/victoria
+      network_api_extensions: *api_extensions
+      devstack_localrc:
+        NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
+
+- job:
+    name: neutron-tempest-plugin-dvr-multinode-scenario-victoria
+    parent: neutron-tempest-plugin-dvr-multinode-scenario
+    override-checkout: stable/victoria
+    vars:
+      network_api_extensions_common: *api_extensions
+      branch_override: stable/victoria
+
+- job:
+    name: neutron-tempest-plugin-designate-scenario-victoria
+    parent: neutron-tempest-plugin-designate-scenario
+    override-checkout: stable/victoria
+    vars:
+      branch_override: stable/victoria
+      network_api_extensions_common: *api_extensions
+
+- job:
+    name: neutron-tempest-plugin-sfc-victoria
+    parent: neutron-tempest-plugin-sfc
+    override-checkout: stable/victoria
+    vars:
+      branch_override: stable/victoria
+      network_api_extensions_common: *api_extensions
+
+- job:
+    name: neutron-tempest-plugin-bgpvpn-bagpipe-victoria
+    parent: neutron-tempest-plugin-bgpvpn-bagpipe
+    override-checkout: stable/victoria
+    vars:
+      branch_override: stable/victoria
+      network_api_extensions: *api_extensions
+
+- job:
+    name: neutron-tempest-plugin-dynamic-routing-victoria
+    parent: neutron-tempest-plugin-dynamic-routing
+    override-checkout: stable/victoria
+    vars:
+      branch_override: stable/victoria
+      network_api_extensions_common: *api_extensions
+
+- job:
+    name: neutron-tempest-plugin-vpnaas-victoria
+    parent: neutron-tempest-plugin-vpnaas
+    override-checkout: stable/victoria
+    vars:
+      branch_override: stable/victoria
+      network_api_extensions_common: *api_extensions