Merge "Fix how netcat is called when started as server"
diff --git a/.zuul.yaml b/.zuul.yaml
index e544bdb..92d891a 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -181,7 +181,7 @@
       - openstack/devstack-gate
       - openstack/neutron
       - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.7.0
+        override-checkout: 0.3.0
       - openstack/tempest
     vars:
       branch_override: stable/queens
@@ -243,7 +243,6 @@
         USE_PYTHON3: false
         NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-        TEMPEST_BRANCH: queens-em
 
 - job:
     name: neutron-tempest-plugin-api-rocky
@@ -534,19 +533,22 @@
       - openstack/devstack-gate
       - openstack/neutron
       - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.7.0
+        override-checkout: 0.3.0
       - openstack/tempest
     vars:
       branch_override: stable/queens
       network_api_extensions: *api_extensions_queens
       # TODO(slaweq): remove trunks subport_connectivity test from blacklist
       # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
-      tempest_black_regex: "(^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)"
+      # NOTE(bcafarel): remove DNS test as queens pinned version does not have
+      # fix for https://bugs.launchpad.net/neutron/+bug/1826419
+      tempest_black_regex: "\
+          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)|\
+          (^neutron_tempest_plugin.scenario.test_internal_dns.InternalDNSTest.test_dns_domain_and_name)"
       devstack_localrc:
         USE_PYTHON3: false
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-        TEMPEST_BRANCH: queens-em
 
 - job:
     name: neutron-tempest-plugin-scenario-openvswitch-rocky
@@ -684,16 +686,19 @@
       - openstack/devstack-gate
       - openstack/neutron
       - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.7.0
+        override-checkout: 0.3.0
       - openstack/tempest
     vars:
       branch_override: stable/queens
       network_api_extensions: *api_extensions_queens
+      # NOTE(bcafarel): remove DNS test as queens pinned version does not have
+      # fix for https://bugs.launchpad.net/neutron/+bug/1826419
+      tempest_black_regex: "\
+          (^neutron_tempest_plugin.scenario.test_internal_dns.InternalDNSTest.test_dns_domain_and_name)"
       devstack_localrc:
         USE_PYTHON3: false
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-        TEMPEST_BRANCH: queens-em
       devstack_local_conf:
         test-config:
           # NOTE: ignores linux bridge's trunk delete on bound port test
@@ -887,18 +892,21 @@
       - openstack/devstack-gate
       - openstack/neutron
       - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.7.0
+        override-checkout: 0.3.0
       - openstack/tempest
     vars:
       branch_override: stable/queens
       network_api_extensions_common: *api_extensions_queens
       # TODO(slaweq): remove trunks subport_connectivity test from blacklist
       # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
-      tempest_black_regex: "(^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)"
+      # NOTE(bcafarel): remove DNS test as queens pinned version does not have
+      # fix for https://bugs.launchpad.net/neutron/+bug/1826419
+      tempest_black_regex: "\
+          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)|\
+          (^neutron_tempest_plugin.scenario.test_internal_dns.InternalDNSTest.test_dns_domain_and_name)"
       devstack_localrc:
         USE_PYTHON3: false
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
-        TEMPEST_BRANCH: queens-em
 
 - job:
     name: neutron-tempest-plugin-dvr-multinode-scenario-rocky
@@ -980,15 +988,18 @@
       - openstack/devstack-gate
       - openstack/neutron
       - name: openstack/neutron-tempest-plugin
-        override-checkout: 0.7.0
+        override-checkout: 0.3.0
       - openstack/tempest
     vars:
       branch_override: stable/queens
       network_api_extensions_common: *api_extensions_queens
+      # NOTE(bcafarel): remove DNS test as queens pinned version does not have
+      # fix for https://bugs.launchpad.net/neutron/+bug/1826419
+      tempest_black_regex: "\
+          (^neutron_tempest_plugin.scenario.test_internal_dns.InternalDNSTest.test_dns_domain_and_name)"
       devstack_localrc:
         USE_PYTHON3: false
         TEMPEST_PLUGINS: '"/opt/stack/designate-tempest-plugin /opt/stack/neutron-tempest-plugin"'
-        TEMPEST_BRANCH: queens-em
 
 - job:
     name: neutron-tempest-plugin-designate-scenario-rocky
diff --git a/neutron_tempest_plugin/api/admin/test_shared_network_extension.py b/neutron_tempest_plugin/api/admin/test_shared_network_extension.py
index eb902b9..1444b2d 100644
--- a/neutron_tempest_plugin/api/admin/test_shared_network_extension.py
+++ b/neutron_tempest_plugin/api/admin/test_shared_network_extension.py
@@ -104,8 +104,8 @@
         port = self.create_port(self.shared_network)
         self.addCleanup(self.admin_client.delete_port, port['id'])
         # verify the tenant id of admin network and non admin port
-        self.assertNotEqual(self.shared_network['tenant_id'],
-                            port['tenant_id'])
+        self.assertNotEqual(self.shared_network['project_id'],
+                            port['project_id'])
 
     @decorators.idempotent_id('3e39c4a6-9caf-4710-88f1-d20073c6dd76')
     def test_create_bulk_shared_network(self):
@@ -183,7 +183,7 @@
         super(RBACSharedNetworksTest, cls).resource_setup()
         cls.client2 = cls.os_alt.network_client
 
-    def _make_admin_net_and_subnet_shared_to_tenant_id(self, tenant_id):
+    def _make_admin_net_and_subnet_shared_to_project_id(self, project_id):
         net = self.admin_client.create_network(
             name=data_utils.rand_name('test-network'))['network']
         self.addCleanup(self.admin_client.delete_network, net['id'])
@@ -191,7 +191,7 @@
         # network is shared to first unprivileged client by default
         pol = self.admin_client.create_rbac_policy(
             object_type='network', object_id=net['id'],
-            action='access_as_shared', target_tenant=tenant_id
+            action='access_as_shared', target_tenant=project_id
         )['rbac_policy']
         return {'network': net, 'subnet': subnet, 'policy': pol}
 
@@ -199,21 +199,21 @@
     @decorators.idempotent_id('86c3529b-1231-40de-803c-bfffffff1eee')
     def test_create_rbac_policy_with_target_tenant_none(self):
         with testtools.ExpectedException(lib_exc.BadRequest):
-            self._make_admin_net_and_subnet_shared_to_tenant_id(
-                tenant_id=None)
+            self._make_admin_net_and_subnet_shared_to_project_id(
+                project_id=None)
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('86c3529b-1231-40de-803c-bfffffff1fff')
     def test_create_rbac_policy_with_target_tenant_too_long_id(self):
         with testtools.ExpectedException(lib_exc.BadRequest):
-            target_tenant = '1234' * 100
-            self._make_admin_net_and_subnet_shared_to_tenant_id(
-                tenant_id=target_tenant)
+            target_project = '1234' * 100
+            self._make_admin_net_and_subnet_shared_to_project_id(
+                project_id=target_project)
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('86c3529b-1231-40de-803c-afffffff1fff')
     def test_network_only_visible_to_policy_target(self):
-        net = self._make_admin_net_and_subnet_shared_to_tenant_id(
+        net = self._make_admin_net_and_subnet_shared_to_project_id(
             self.client.tenant_id)['network']
         self.client.show_network(net['id'])
         with testtools.ExpectedException(lib_exc.NotFound):
@@ -222,7 +222,7 @@
 
     @decorators.idempotent_id('86c3529b-1231-40de-803c-afffffff2fff')
     def test_subnet_on_network_only_visible_to_policy_target(self):
-        sub = self._make_admin_net_and_subnet_shared_to_tenant_id(
+        sub = self._make_admin_net_and_subnet_shared_to_project_id(
             self.client.tenant_id)['subnet']
         self.client.show_subnet(sub['id'])
         with testtools.ExpectedException(lib_exc.NotFound):
@@ -231,7 +231,7 @@
 
     @decorators.idempotent_id('86c3529b-1231-40de-803c-afffffff2eee')
     def test_policy_target_update(self):
-        res = self._make_admin_net_and_subnet_shared_to_tenant_id(
+        res = self._make_admin_net_and_subnet_shared_to_project_id(
             self.client.tenant_id)
         # change to client2
         update_res = self.admin_client.update_rbac_policy(
@@ -245,7 +245,7 @@
 
     @decorators.idempotent_id('86c3529b-1231-40de-803c-affefefef321')
     def test_duplicate_policy_error(self):
-        res = self._make_admin_net_and_subnet_shared_to_tenant_id(
+        res = self._make_admin_net_and_subnet_shared_to_project_id(
             self.client.tenant_id)
         with testtools.ExpectedException(lib_exc.Conflict):
             self.admin_client.create_rbac_policy(
@@ -254,7 +254,7 @@
 
     @decorators.idempotent_id('86c3529b-1231-40de-803c-afffffff3fff')
     def test_port_presence_prevents_network_rbac_policy_deletion(self):
-        res = self._make_admin_net_and_subnet_shared_to_tenant_id(
+        res = self._make_admin_net_and_subnet_shared_to_project_id(
             self.client.tenant_id)
         port = self.create_port(res['network'])
         # a port on the network should prevent the deletion of a policy
@@ -272,7 +272,7 @@
         self_share = self.client.create_rbac_policy(
                          object_type='network', object_id=net['id'],
                          action='access_as_shared',
-                         target_tenant=net['tenant_id'])['rbac_policy']
+                         target_tenant=net['project_id'])['rbac_policy']
         port = self.create_port(net)
         self.client.delete_rbac_policy(self_share['id'])
         self.client.delete_port(port['id'])
@@ -318,14 +318,14 @@
             object_type='network', object_id=net['id'],
             action='access_as_shared', target_tenant=self.client2.tenant_id)
         field_args = (('id',), ('id', 'action'), ('object_type', 'object_id'),
-                      ('tenant_id', 'target_tenant'))
+                      ('project_id', 'target_tenant'))
         for fields in field_args:
             res = self.client.list_rbac_policies(fields=fields)
             self.assertEqual(set(fields), set(res['rbac_policies'][0].keys()))
 
     @decorators.idempotent_id('86c3529b-1231-40de-803c-afffffff5fff')
     def test_policy_show(self):
-        res = self._make_admin_net_and_subnet_shared_to_tenant_id(
+        res = self._make_admin_net_and_subnet_shared_to_project_id(
             self.client.tenant_id)
         p1 = res['policy']
         p2 = self.admin_client.create_rbac_policy(
@@ -358,7 +358,7 @@
 
     @decorators.idempotent_id('86c3529b-1231-40de-803c-afffffff6fff')
     def test_regular_client_blocked_from_sharing_anothers_network(self):
-        net = self._make_admin_net_and_subnet_shared_to_tenant_id(
+        net = self._make_admin_net_and_subnet_shared_to_project_id(
             self.client.tenant_id)['network']
         with testtools.ExpectedException(lib_exc.BadRequest):
             self.client.create_rbac_policy(
@@ -402,7 +402,7 @@
         self_share = self.client.create_rbac_policy(
                          object_type='network', object_id=net['id'],
                          action='access_as_shared',
-                         target_tenant=net['tenant_id'])['rbac_policy']
+                         target_tenant=net['project_id'])['rbac_policy']
         port = self.create_port(net)
         self.client.update_rbac_policy(self_share['id'],
                                        target_tenant=self.client2.tenant_id)
@@ -411,7 +411,7 @@
     @utils.requires_ext(extension="standard-attr-revisions", service="network")
     @decorators.idempotent_id('86c3529b-1231-40de-1234-89664291a4cb')
     def test_rbac_bumps_network_revision(self):
-        resp = self._make_admin_net_and_subnet_shared_to_tenant_id(
+        resp = self._make_admin_net_and_subnet_shared_to_project_id(
             self.client.tenant_id)
         net_id = resp['network']['id']
         rev = self.client.show_network(net_id)['network']['revision_number']
@@ -425,7 +425,7 @@
 
     @decorators.idempotent_id('86c3529b-1231-40de-803c-aeeeeeee7fff')
     def test_filtering_works_with_rbac_records_present(self):
-        resp = self._make_admin_net_and_subnet_shared_to_tenant_id(
+        resp = self._make_admin_net_and_subnet_shared_to_project_id(
             self.client.tenant_id)
         net = resp['network']['id']
         sub = resp['subnet']['id']
diff --git a/neutron_tempest_plugin/api/base.py b/neutron_tempest_plugin/api/base.py
index 4441dd1..0891bb6 100644
--- a/neutron_tempest_plugin/api/base.py
+++ b/neutron_tempest_plugin/api/base.py
@@ -378,16 +378,6 @@
         return cls.create_network(name=network_name, shared=True, **kwargs)
 
     @classmethod
-    def create_network_keystone_v3(cls, network_name=None, project_id=None,
-                                   tenant_id=None, client=None):
-        params = {}
-        if project_id:
-            params['project_id'] = project_id
-        if tenant_id:
-            params['tenant_id'] = tenant_id
-        return cls.create_network(name=network_name, client=client, **params)
-
-    @classmethod
     def create_subnet(cls, network, gateway='', cidr=None, mask_bits=None,
                       ip_version=None, client=None, reserve_cidr=True,
                       **kwargs):
diff --git a/neutron_tempest_plugin/api/test_security_groups.py b/neutron_tempest_plugin/api/test_security_groups.py
index 26a8c05..cdd7017 100644
--- a/neutron_tempest_plugin/api/test_security_groups.py
+++ b/neutron_tempest_plugin/api/test_security_groups.py
@@ -91,6 +91,94 @@
             self.assertIsNotNone(secgrp['id'])
 
 
+class BaseSecGroupQuota(base.BaseAdminNetworkTest):
+
+    def _create_max_allowed_sg_amount(self):
+        sg_amount = self._get_sg_amount()
+        sg_quota = self._get_sg_quota()
+        sg_to_create = sg_quota - sg_amount
+        self._create_security_groups(sg_to_create)
+
+    def _create_security_groups(self, amount):
+        for _ in range(amount):
+            sg = self.create_security_group()
+            self.addCleanup(self.delete_security_group, sg)
+
+    def _increase_sg_quota(self):
+        sg_quota = self._get_sg_quota()
+        new_sg_quota = 2 * sg_quota
+        self._set_sg_quota(new_sg_quota)
+        return new_sg_quota
+
+    def _decrease_sg_quota(self):
+        sg_quota = self._get_sg_quota()
+        new_sg_quota = sg_quota // 2
+        self._set_sg_quota(new_sg_quota)
+        return new_sg_quota
+
+    def _set_sg_quota(self, val):
+        sg_quota = self._get_sg_quota()
+        project_id = self.client.tenant_id
+        self.admin_client.update_quotas(project_id, **{'security_group': val})
+        self.addCleanup(self.admin_client.update_quotas,
+                project_id,
+                **{'security_group': sg_quota})
+
+    def _get_sg_quota(self):
+        project_id = self.client.tenant_id
+        quotas = self.admin_client.show_quotas(project_id)
+        return quotas['quota']['security_group']
+
+    def _get_sg_amount(self):
+        project_id = self.client.tenant_id
+        filter_query = {'project_id': project_id}
+        security_groups = self.client.list_security_groups(**filter_query)
+        return len(security_groups['security_groups'])
+
+
+class SecGroupQuotaTest(BaseSecGroupQuota):
+
+    credentials = ['primary', 'admin']
+    required_extensions = ['security-group', 'quotas']
+
+    @decorators.idempotent_id('1826aa02-090d-4717-b43a-50ee449b02e7')
+    def test_sg_quota_values(self):
+        values = [-1, 0, 10, 2147483647]
+        for value in values:
+            self._set_sg_quota(value)
+            self.assertEqual(value, self._get_sg_quota())
+
+    @decorators.idempotent_id('df7981fb-b83a-4779-b13e-65494ef44a72')
+    def test_max_allowed_sg_amount(self):
+        self._create_max_allowed_sg_amount()
+        self.assertEqual(self._get_sg_quota(), self._get_sg_amount())
+
+    @decorators.idempotent_id('623d909c-6ef8-43d6-93ee-97086e2651e8')
+    def test_sg_quota_increased(self):
+        self._create_max_allowed_sg_amount()
+        new_quota = self._increase_sg_quota()
+        self._create_max_allowed_sg_amount()
+        quota_set = self._get_sg_quota()
+        self.assertEqual(quota_set, new_quota,
+                "Security group quota was not changed correctly")
+        self.assertEqual(quota_set, self._get_sg_amount(),
+                "Amount of security groups doesn't match quota")
+
+    @decorators.idempotent_id('ba95676c-8d9a-4482-b4ec-74d51a4602a6')
+    def test_sg_quota_decrease_less_than_created(self):
+        self._create_max_allowed_sg_amount()
+        new_quota = self._decrease_sg_quota()
+        self.assertEqual(self._get_sg_quota(), new_quota)
+
+    @decorators.idempotent_id('d43cf1a7-aa7e-4c41-9340-627a1a6ab961')
+    def test_create_sg_when_quota_disabled(self):
+        sg_amount = self._get_sg_amount()
+        self._set_sg_quota(-1)
+        self._create_security_groups(10)
+        new_sg_amount = self._get_sg_amount()
+        self.assertGreater(new_sg_amount, sg_amount)
+
+
 class SecGroupProtocolTest(base.BaseNetworkTest):
 
     protocol_names = base_security_groups.V4_PROTOCOL_NAMES
diff --git a/neutron_tempest_plugin/services/network/json/network_client.py b/neutron_tempest_plugin/services/network/json/network_client.py
index 05095a7..8f79b5d 100644
--- a/neutron_tempest_plugin/services/network/json/network_client.py
+++ b/neutron_tempest_plugin/services/network/json/network_client.py
@@ -1063,21 +1063,6 @@
         self.expected_success(204, resp.status)
         service_client.ResponseBody(resp, body)
 
-    def create_network_keystone_v3(self, name, project_id, tenant_id=None):
-        uri = '%s/networks' % self.uri_prefix
-        post_data = {
-            'network': {
-                'name': name,
-                'project_id': project_id
-            }
-        }
-        if tenant_id is not None:
-            post_data['network']['tenant_id'] = tenant_id
-        resp, body = self.post(uri, self.serialize(post_data))
-        body = self.deserialize_single(body)
-        self.expected_success(201, resp.status)
-        return service_client.ResponseBody(resp, body)
-
     def list_extensions(self, **filters):
         uri = self.get_uri("extensions")
         if filters: