Merge "Switch enforce-scope job to ovn"
diff --git a/neutron_tempest_plugin/api/admin/test_ports.py b/neutron_tempest_plugin/api/admin/test_ports.py
index e26e122..88c35c6 100644
--- a/neutron_tempest_plugin/api/admin/test_ports.py
+++ b/neutron_tempest_plugin/api/admin/test_ports.py
@@ -65,6 +65,42 @@
         self.assertNotEqual(current_mac, new_mac)
         self.assertTrue(netaddr.valid_mac(new_mac))
 
+    @decorators.idempotent_id('4d75cc60-99d0-4949-b3ce-5826b81aa0a9')
+    @utils.requires_ext(extension="port-trusted-vif",
+                        service="network")
+    def test_port_create_with_trusted_attr_set(self):
+        port = self.admin_client.create_port(
+            network_id=self.network['id'], trusted=True)['port']
+        self.ports.append(port)
+        self.assertTrue(port['trusted'])
+        self.assertTrue(port['binding:profile']['trusted'])
+
+        port = self.admin_client.create_port(
+            network_id=self.network['id'], trusted=False)['port']
+        self.ports.append(port)
+        self.assertFalse(port['trusted'])
+        self.assertFalse(port['binding:profile']['trusted'])
+
+    @decorators.idempotent_id('26c15e2a-55b2-410f-8ed3-84db9406ff3f')
+    @utils.requires_ext(extension="port-trusted-vif",
+                        service="network")
+    def test_port_set_trusted_attr(self):
+        port = self.admin_client.create_port(
+            network_id=self.network['id'])['port']
+        self.ports.append(port)
+        self.assertIsNone(port['trusted'])
+        self.assertNotIn('trusted', port['binding:profile'])
+
+        updated_port = self.admin_client.update_port(
+            port['id'], trusted=True)['port']
+        self.assertTrue(updated_port['trusted'])
+        self.assertTrue(updated_port['binding:profile']['trusted'])
+
+        updated_port = self.admin_client.update_port(
+            port['id'], trusted=False)['port']
+        self.assertFalse(updated_port['trusted'])
+        self.assertFalse(updated_port['binding:profile']['trusted'])
+
 
 class PortTestCasesResourceRequest(base.BaseAdminNetworkTest):
 
diff --git a/neutron_tempest_plugin/common/utils.py b/neutron_tempest_plugin/common/utils.py
index c62aa78..6bc290b 100644
--- a/neutron_tempest_plugin/common/utils.py
+++ b/neutron_tempest_plugin/common/utils.py
@@ -132,17 +132,6 @@
         return False
 
 
-def spawn_http_server(ssh_client, port, message):
-    cmd = ("(echo -e 'HTTP/1.1 200 OK\r\n'; echo '%(msg)s') "
-           "| sudo nc -lp %(port)d &" % {'msg': message, 'port': port})
-    ssh_client.exec_command(cmd)
-
-
-def call_url_remote(ssh_client, url):
-    cmd = "curl %s --retry 3 --connect-timeout 2" % url
-    return ssh_client.exec_command(cmd)
-
-
 class StatefulConnection:
     """Class to test connection that should remain opened
 
diff --git a/neutron_tempest_plugin/config.py b/neutron_tempest_plugin/config.py
index d259201..55d9d9e 100644
--- a/neutron_tempest_plugin/config.py
+++ b/neutron_tempest_plugin/config.py
@@ -81,7 +81,8 @@
                 default=False,
                 help='Whether SNAT rules apply recursively to all connected '
                 'networks. This is the default behavior for ovs and '
-                'linuxbridge drivers.'),
+                'linuxbridge drivers. OVN requires '
+                'ovn_router_indirect_snat=True setting to implement it.'),
 
     # Multicast tests settings
     cfg.StrOpt('multicast_group_range',
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index 6149b06..70cb2dc 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -337,7 +337,7 @@
         if create_fip:
             self.fip = self.create_floatingip(port=self.port)
 
-    def check_connectivity(self, host, ssh_user=None, ssh_key=None,
+    def check_connectivity(self, host=None, ssh_user=None, ssh_key=None,
                            servers=None, ssh_timeout=None, ssh_client=None):
         # Either ssh_client or ssh_user+ssh_key is mandatory.
         if ssh_client is None:
diff --git a/neutron_tempest_plugin/scenario/test_dns_integration.py b/neutron_tempest_plugin/scenario/test_dns_integration.py
index d520aa2..8163b51 100644
--- a/neutron_tempest_plugin/scenario/test_dns_integration.py
+++ b/neutron_tempest_plugin/scenario/test_dns_integration.py
@@ -39,6 +39,8 @@
 # when designate_tempest_plugin is not available
 dns_base = testtools.try_import('designate_tempest_plugin.tests.base')
 dns_waiters = testtools.try_import('designate_tempest_plugin.common.waiters')
+dns_data_utils = testtools.try_import('designate_tempest_plugin.data_utils')
+
 if dns_base:
     DNSMixin = dns_base.BaseDnsV2Test
 else:
@@ -52,8 +54,9 @@
     def setup_clients(cls):
         super(BaseDNSIntegrationTests, cls).setup_clients()
         cls.zone_client = cls.os_tempest.dns_v2.ZonesClient()
+        cls.admin_zone_client = cls.os_admin.dns_v2.ZonesClient()
         cls.recordset_client = cls.os_tempest.dns_v2.RecordsetClient()
-        cls.query_client.build_timeout = 30
+        cls.query_client.build_timeout = 60
 
     @classmethod
     def skip_checks(cls):
@@ -68,12 +71,13 @@
     @utils.requires_ext(extension="dns-integration", service="network")
     def resource_setup(cls):
         super(BaseDNSIntegrationTests, cls).resource_setup()
-        cls.zone = cls.zone_client.create_zone()[1]
-        cls.addClassResourceCleanup(cls.zone_client.delete_zone,
-            cls.zone['id'], ignore_errors=lib_exc.NotFound)
-        dns_waiters.wait_for_zone_status(
-            cls.zone_client, cls.zone['id'], 'ACTIVE')
-
+        cls.zone_name = dns_data_utils.rand_zone_name(
+            name="basednsintegrationtests")
+        cls.zone = cls.zone_client.create_zone(
+            name=cls.zone_name, wait_until='ACTIVE')[1]
+        cls.addClassResourceCleanup(
+            cls.zone_client.delete_zone, cls.zone['id'],
+            ignore_errors=lib_exc.NotFound)
         cls.network = cls.create_network(dns_domain=cls.zone['name'])
         cls.subnet = cls.create_subnet(cls.network)
         cls.subnet_v6 = cls.create_subnet(cls.network, ip_version=6)
@@ -81,6 +85,20 @@
         cls.create_router_interface(cls.router['id'], cls.subnet['id'])
         cls.keypair = cls.create_keypair()
 
+    @classmethod
+    def resource_cleanup(cls):
+        super(BaseDNSIntegrationTests, cls).resource_cleanup()
+        admin_listed_zones = cls.admin_zone_client.list_zones(
+            headers=dns_base.BaseDnsV2Test.all_projects_header)[1]['zones']
+        neutron_zone_ids = [
+            zn['id'] for zn in admin_listed_zones if
+            'zone for reverse lookups set up by Neutron.' in
+            str(zn['description']) and cls.zone_name.strip('.') in zn['email']]
+        for id in neutron_zone_ids:
+            cls.admin_zone_client.delete_zone(
+                id, headers=dns_base.BaseDnsV2Test.all_projects_header,
+                ignore_errors=lib_exc.NotFound)
+
     def _create_floatingip_with_dns(self, dns_name):
         return self.create_floatingip(client=self.os_primary.network_client,
                                       dns_name=dns_name,
@@ -250,7 +268,8 @@
     @classmethod
     def resource_setup(cls):
         super(DNSIntegrationExtraTests, cls).resource_setup()
-        cls.network2 = cls.create_network()
+        cls.network2 = cls.create_network(
+            name=data_utils.rand_name('dns_integration_net'))
         cls.subnet2 = cls.create_subnet(cls.network2)
         cls.subnet2_v6 = cls.create_subnet(cls.network2,
                                            ip_version=6,
@@ -274,6 +293,16 @@
         self.client.delete_port(port['id'])
         self._verify_dns_records(addr_v6, name, record_type='AAAA',
                                  found=False)
+        self.client.update_subnet(
+            self.subnet2['id'], dns_publish_fixed_ip=True)
+        port = self.create_port(self.network2,
+                                dns_domain=self.zone['name'],
+                                dns_name=name)
+        addr_v4 = port['fixed_ips'][1 - v6_index]['ip_address']
+        self._verify_dns_records(addr_v4, name, record_type='A')
+        self.client.delete_port(port['id'])
+        self._verify_dns_records(addr_v4, name, record_type='A',
+                                 found=False)
 
 
 class DNSIntegrationDomainPerProjectTests(BaseDNSIntegrationTests):
@@ -286,19 +315,15 @@
     @classmethod
     def resource_setup(cls):
         super(BaseDNSIntegrationTests, cls).resource_setup()
-
-        name = data_utils.rand_name('test-domain')
-        zone_name = "%s.%s.%s.zone." % (cls.client.user_id,
+        cls.name = data_utils.rand_name('test-domain')
+        cls.zone_name = "%s.%s.%s.zone." % (cls.client.user_id,
                                         cls.client.project_id,
-                                        name)
-        dns_domain_template = "<user_id>.<project_id>.%s.zone." % name
-
-        cls.zone = cls.zone_client.create_zone(name=zone_name)[1]
+                                        cls.name)
+        dns_domain_template = "<user_id>.<project_id>.%s.zone." % cls.name
+        cls.zone = cls.zone_client.create_zone(
+            name=cls.zone_name, wait_until='ACTIVE')[1]
         cls.addClassResourceCleanup(cls.zone_client.delete_zone,
             cls.zone['id'], ignore_errors=lib_exc.NotFound)
-        dns_waiters.wait_for_zone_status(
-            cls.zone_client, cls.zone['id'], 'ACTIVE')
-
         cls.network = cls.create_network(dns_domain=dns_domain_template)
         cls.subnet = cls.create_subnet(cls.network,
                                        dns_publish_fixed_ip=True)
@@ -309,6 +334,20 @@
         cls.create_router_interface(cls.router['id'], cls.subnet['id'])
         cls.keypair = cls.create_keypair()
 
+    @classmethod
+    def resource_cleanup(cls):
+        super(BaseDNSIntegrationTests, cls).resource_cleanup()
+        admin_listed_zones = cls.admin_zone_client.list_zones(
+            headers=dns_base.BaseDnsV2Test.all_projects_header)[1]['zones']
+        neutron_zone_ids = [
+            zn['id'] for zn in admin_listed_zones if
+            'zone for reverse lookups set up by Neutron.' in
+            str(zn['description']) and cls.zone_name.strip('.') in zn['email']]
+        for id in neutron_zone_ids:
+            cls.admin_zone_client.delete_zone(
+                id, headers=dns_base.BaseDnsV2Test.all_projects_header,
+                ignore_errors=lib_exc.NotFound)
+
     @decorators.idempotent_id('43a67509-3161-4125-8f2c-0d4a67599721')
     def test_port_with_dns_name(self):
         name = data_utils.rand_name('port-test')
diff --git a/neutron_tempest_plugin/scenario/test_metadata.py b/neutron_tempest_plugin/scenario/test_metadata.py
index 239f6bc..26fbab6 100644
--- a/neutron_tempest_plugin/scenario/test_metadata.py
+++ b/neutron_tempest_plugin/scenario/test_metadata.py
@@ -169,8 +169,7 @@
             self.network, use_advanced_image=use_advanced_image)
         self.wait_for_server_active(server=vm.server)
         self.wait_for_guest_os_ready(vm.server)
-        self.check_connectivity(host=vm.floating_ip['floating_ip_address'],
-                                ssh_client=vm.ssh_client)
+        self.check_connectivity(ssh_client=vm.ssh_client)
         interface = self._get_primary_interface(vm.ssh_client)
 
         try:
@@ -193,15 +192,14 @@
         CONF.neutron_plugin_options.advanced_image_ref or
         CONF.neutron_plugin_options.default_image_is_advanced,
         'Advanced image is required to run this test.')
-    @testtools.skipUnless(
-        CONF.neutron_plugin_options.firewall_driver == 'ovn',
-        "OVN driver is required to run this test - "
-        " while LP#2076916 is fixed")
     @decorators.idempotent_id('7542892a-d132-471c-addb-172dcf888ff6')
     def test_metadata_ipv6_only_network(self):
         ipv6_network = self.create_network()
-        self.create_subnet(network=ipv6_network, ip_version=6,
-                           ipv6_ra_mode="slaac", ipv6_address_mode="slaac")
+        ipv6_subnet = self.create_subnet(network=ipv6_network, ip_version=6,
+                                         ipv6_ra_mode="slaac",
+                                         ipv6_address_mode="slaac")
+        if not CONF.neutron_plugin_options.firewall_driver == 'ovn':
+            self.create_router_interface(self.router['id'], ipv6_subnet['id'])
         use_advanced_image = (
             not CONF.neutron_plugin_options.default_image_is_advanced)
         params = self._get_metadata_query_script()
diff --git a/neutron_tempest_plugin/scenario/test_security_groups.py b/neutron_tempest_plugin/scenario/test_security_groups.py
index 03156c7..dc0f5ef 100644
--- a/neutron_tempest_plugin/scenario/test_security_groups.py
+++ b/neutron_tempest_plugin/scenario/test_security_groups.py
@@ -51,37 +51,13 @@
     credentials = ['primary', 'admin']
     required_extensions = ['router', 'security-group']
 
-    def _verify_http_connection(self, ssh_client, ssh_server,
-                                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
-        :rtype: bool
-        """
-        utils.kill_nc_process(ssh_server)
-        url = 'http://%s:%d' % (test_ip, test_port)
-        utils.spawn_http_server(ssh_server, port=test_port, message='foo_ok')
-        utils.process_is_running(ssh_server, 'nc')
+    def _test_connection_and_log(self, con, *args, **kwargs):
         try:
-            ret = utils.call_url_remote(ssh_client, url)
-            if should_pass:
-                self.assertIn('foo_ok', ret)
-                return
-            self.assertNotIn('foo_ok', ret)
-        except Exception as e:
-            if not should_pass:
-                return
-            self._log_console_output(servers)
+            con.test_connection(*args, **kwargs)
+        except utils.WaitTimeout:
+            self._log_console_output()
             self._log_local_network_status()
-            raise e
+            raise
 
     @classmethod
     def setup_credentials(cls):
@@ -601,7 +577,7 @@
         for port in range(80, 84):
             with utils.StatefulConnection(
                     ssh_clients[0], ssh_clients[2], test_ip, port) as con:
-                con.test_connection(should_pass=False)
+                self._test_connection_and_log(con, should_pass=False)
 
         # add two remote-group rules with port-ranges
         rule_list = [{'protocol': constants.PROTO_NUM_TCP,
@@ -636,7 +612,7 @@
         for port in range(80, 84):
             with utils.StatefulConnection(
                     ssh_clients[0], ssh_clients[2], test_ip, port) as con:
-                con.test_connection()
+                self._test_connection_and_log(con)
 
         # list the tcp rule id by SG id and port-range
         sg_rule_id = self.os_primary.network_client.list_security_group_rules(
@@ -650,7 +626,7 @@
         for port in range(80, 82):
             with utils.StatefulConnection(
                     ssh_clients[0], ssh_clients[2], test_ip, port) as con:
-                con.test_connection(should_pass=False)
+                self._test_connection_and_log(con, should_pass=False)
 
     def _test_overlapping_sec_grp_rules(self):
         """Test security group rules with overlapping port ranges"""
@@ -714,11 +690,11 @@
         for _ in range(2):
             with utils.StatefulConnection(
                     client_ssh[0], srv_ssh, srv_ip, tcp_port) as con:
-                con.test_connection()
+                self._test_connection_and_log(con)
             for port in range(tcp_port, tcp_port + 3):
                 with utils.StatefulConnection(
                         client_ssh[1], srv_ssh, srv_ip, port) as con:
-                    con.test_connection()
+                    self._test_connection_and_log(con)
 
     def _test_remove_sec_grp_from_active_vm(self):
         """Tests the following:
@@ -906,23 +882,23 @@
                 vm_ssh[0], vm_ssh[1], srv_ip, 6666) as con:
             self.client.update_port(srv_port['id'],
                     security_groups=[ssh_sg['id'], sg['id']])
-            con.test_connection()
+            self._test_connection_and_log(con)
         with utils.StatefulConnection(
                 vm_ssh[0], vm_ssh[1], srv_ip, 6666) as con:
             self.client.update_port(
                     srv_port['id'], security_groups=[ssh_sg['id']])
-            con.test_connection(should_pass=False)
+            self._test_connection_and_log(con, should_pass=False)
         with utils.StatefulConnection(
                 vm_ssh[0], vm_ssh[1], srv_ip, 6666) as con:
             self.client.update_port(srv_port['id'],
                     security_groups=[ssh_sg['id'], sg['id']])
-            con.test_connection()
+            self._test_connection_and_log(con)
             self.client.update_port(srv_port['id'],
                     security_groups=[ssh_sg['id']])
-            con.test_connection(should_pass=False)
+            self._test_connection_and_log(con, should_pass=False)
             self.client.update_port(srv_port['id'],
                     security_groups=[ssh_sg['id'], sg['id']])
-            con.test_connection()
+            self._test_connection_and_log(con)
 
     @decorators.idempotent_id('4a724164-bbc0-4029-a844-644ece66c026')
     def test_connectivity_between_vms_using_different_sec_groups(self):
diff --git a/neutron_tempest_plugin/scenario/test_trunk.py b/neutron_tempest_plugin/scenario/test_trunk.py
index 2ba8f13..47b8415 100644
--- a/neutron_tempest_plugin/scenario/test_trunk.py
+++ b/neutron_tempest_plugin/scenario/test_trunk.py
@@ -193,7 +193,6 @@
         self._wait_for_port(port=vm.port)
         self._wait_for_port(port=vm.subport)
         self.check_connectivity(
-            host=vm.floating_ip['floating_ip_address'],
             ssh_client=vm.ssh_client,
             servers=[vm.server])
 
diff --git a/neutron_tempest_plugin/scenario/test_vlan_transparency.py b/neutron_tempest_plugin/scenario/test_vlan_transparency.py
index d9a529c..11f12e9 100644
--- a/neutron_tempest_plugin/scenario/test_vlan_transparency.py
+++ b/neutron_tempest_plugin/scenario/test_vlan_transparency.py
@@ -138,9 +138,7 @@
             ssh_clients.append(
                 self._create_ssh_client(floating_ip=floating_ips[i]))
 
-            self.check_connectivity(
-                host=floating_ips[i]['floating_ip_address'],
-                ssh_client=ssh_clients[i])
+            self.check_connectivity(ssh_client=ssh_clients[i])
             self._configure_vlan_transparent(port=self.vm_ports[-1],
                                              ssh_client=ssh_clients[i],
                                              vlan_tag=vlan_tag,
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index 23e4102..59933e6 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -98,6 +98,7 @@
         - port-resource-request
         - port-resource-request-groups
         - port-mac-address-regenerate
+        - port-trusted-vif
         - port-security
         - port-security-groups-filtering
         - project-id
@@ -148,6 +149,7 @@
         neutron-tag-ports-during-bulk-creation: true
         neutron-ndp-proxy: true
         neutron-subnet-external-network: true
+        neutron-port-trusted-vif: true
         br-ex-tcpdump: true
         br-int-flows: true
         # Cinder services
@@ -463,15 +465,6 @@
       devstack_localrc:
         NEUTRON_ENFORCE_SCOPE: false
 
-
-# TODO(slaweq): remove that job's definition as soon as new job
-# "neutron-tempest-plugin-openvswitch-iptables_hybrid" will be used in the
-# neutron repo as a parent for a
-# "neutron-ovs-tempest-plugin-scenario-iptables_hybrid-nftables" job
-- job:
-    name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
-    parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
-
 - job:
     name: neutron-tempest-plugin-openvswitch-distributed-dhcp
     parent: neutron-tempest-plugin-openvswitch
@@ -632,13 +625,6 @@
       - ^zuul.d/yoga_jobs.yaml
       - ^zuul.d/zed_jobs.yaml
 
-# TODO(slaweq): remove that job's definition as soon as new job
-# "neutron-tempest-plugin-linuxbridge" will be used in the neutron repo as
-# a parent for a "neutron-linuxbridge-tempest-plugin-scenario-nftables" job
-- job:
-    name: neutron-tempest-plugin-scenario-linuxbridge
-    parent: neutron-tempest-plugin-linuxbridge
-
 - job:
     name: neutron-tempest-plugin-ovn
     parent: neutron-tempest-plugin-base-nested-switch
@@ -1180,9 +1166,7 @@
         Q_ML2_TENANT_NETWORK_TYPE: vxlan
         Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_sfc) | join(',') }}"
-        # TODO(slaweq): Switch it back to be deployed with mod_wsgi as soon as
-        # bug with RPC worker will be resolved
-        NEUTRON_DEPLOY_MOD_WSGI: false
+        NEUTRON_DEPLOY_MOD_WSGI: true
       # TODO(bcafarel): tests still fail from time to time in parallel
       # https://bugs.launchpad.net/neutron/+bug/1851500
       # https://bugs.launchpad.net/networking-sfc/+bug/1660366