Merge "Add tagging of ports during bulk creation"
diff --git a/.zuul.yaml b/.zuul.yaml
index f871dc3..2e99198 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -253,6 +253,12 @@
     description: |
       This job run on py2 for stable/rocky gate.
     override-checkout: stable/rocky
+    required-projects: &required-projects-rocky
+      - openstack/devstack-gate
+      - openstack/neutron
+      - name: openstack/neutron-tempest-plugin
+        override-checkout: 0.9.0
+      - openstack/tempest
     vars: &api_vars_rocky
       branch_override: stable/rocky
       # TODO(slaweq): find a way to put this list of extensions in
@@ -333,6 +339,7 @@
       This job run on py3 for other than stable/rocky gate
       which is nothing but neutron-tempest-pluign master gate.
     override-checkout: stable/rocky
+    required-projects: *required-projects-rocky
     vars:
       <<: *api_vars_rocky
       devstack_localrc:
@@ -577,6 +584,7 @@
       This job run on py2 for stable/rocky gate.
     nodeset: openstack-single-node-xenial
     override-checkout: stable/rocky
+    required-projects: *required-projects-rocky
     vars: &scenario_vars_rocky
       branch_override: stable/rocky
       network_api_extensions: *api_extensions_rocky
@@ -584,6 +592,10 @@
         USE_PYTHON3: false
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
+      # NOTE(bcafarel): newer tests, unstable on rocky branch
+      tempest_black_regex: "\
+          (^neutron_tempest_plugin.scenario.test_port_forwardings.PortForwardingTestJSON.test_port_forwarding_to_2_servers)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_multiple_ports_portrange_remote)"
     branches:
       - stable/rocky
 
@@ -595,6 +607,7 @@
       This job run on py3 for other than stable/rocky gate
       which is nothing but neutron-tempest-pluign master gate.
     override-checkout: stable/rocky
+    required-projects: *required-projects-rocky
     vars:
       <<: *scenario_vars_rocky
       devstack_localrc:
@@ -661,6 +674,7 @@
     description: |
       This job run on py2 for stable/rocky gate.
     override-checkout: stable/rocky
+    required-projects: *required-projects-rocky
     vars: &openvswitch_vars_rocky
       branch_override: stable/rocky
       network_api_extensions: *api_extensions_rocky
@@ -668,6 +682,13 @@
         USE_PYTHON3: false
         NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
+      # TODO(bcafarel): remove trunks subport_connectivity test from blacklist
+      # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed
+      # NOTE(bcafarel): other are newer tests, unstable on rocky branch
+      tempest_black_regex: "\
+          (^neutron_tempest_plugin.scenario.test_trunk.TrunkTest.test_subport_connectivity)|\
+          (^neutron_tempest_plugin.scenario.test_port_forwardings.PortForwardingTestJSON.test_port_forwarding_to_2_servers)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_multiple_ports_portrange_remote)"
     branches:
       - stable/rocky
 
@@ -679,6 +700,7 @@
       This job run on py3 for other than stable/rocky gate
       which is nothing but neutron-tempest-pluign master gate.
     override-checkout: stable/rocky
+    required-projects: *required-projects-rocky
     vars:
       <<: *openvswitch_vars_rocky
       devstack_localrc:
@@ -771,6 +793,7 @@
       This job run on py2 for stable/rocky gate.
     nodeset: openstack-single-node-xenial
     override-checkout: stable/rocky
+    required-projects: *required-projects-rocky
     vars: &linuxbridge_vars_rocky
       branch_override: stable/rocky
       network_api_extensions: *api_extensions_rocky
@@ -786,6 +809,10 @@
           $TEMPEST_CONFIG:
             neutron_plugin_options:
               q_agent: None
+      # NOTE(bcafarel): newer tests, unstable on rocky branch
+      tempest_black_regex: "\
+          (^neutron_tempest_plugin.scenario.test_port_forwardings.PortForwardingTestJSON.test_port_forwarding_to_2_servers)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_multiple_ports_portrange_remote)"
     branches:
       - stable/rocky
 
@@ -797,6 +824,7 @@
       This job run on py3 for other than stable/rocky gate
       which is nothing but neutron-tempest-pluign master gate.
     override-checkout: stable/rocky
+    required-projects: *required-projects-rocky
     vars:
       <<: *linuxbridge_vars_rocky
       devstack_localrc:
@@ -987,12 +1015,17 @@
       This job run on py2 for stable/rocky gate.
     nodeset: openstack-two-node-xenial
     override-checkout: stable/rocky
+    required-projects: *required-projects-rocky
     vars: &multinode_scenario_vars_rocky
       branch_override: stable/rocky
       network_api_extensions_common: *api_extensions_rocky
       devstack_localrc:
         USE_PYTHON3: false
         TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
+      # NOTE(bcafarel): newer tests, unstable on rocky branch
+      tempest_black_regex: "\
+          (^neutron_tempest_plugin.scenario.test_port_forwardings.PortForwardingTestJSON.test_port_forwarding_to_2_servers)|\
+          (^neutron_tempest_plugin.scenario.test_security_groups.NetworkSecGroupTest.test_multiple_ports_portrange_remote)"
     branches:
       - stable/rocky
 
@@ -1008,6 +1041,7 @@
       <<: *multinode_scenario_vars_rocky
       devstack_localrc:
         USE_PYTHON3: True
+    required-projects: *required-projects-rocky
     group-vars:
       subnode:
         devstack_localrc:
@@ -1105,7 +1139,8 @@
     required-projects:
       - openstack/devstack-gate
       - openstack/neutron
-      - openstack/neutron-tempest-plugin
+      - name: openstack/neutron-tempest-plugin
+        override-checkout: 0.9.0
       - name: openstack/designate-tempest-plugin
         override-checkout: 0.7.0
       - openstack/tempest
@@ -1126,6 +1161,7 @@
       This job run on py3 for other than stable/rocky gate
       which is nothing but neutron-tempest-plugin master gate.
     override-checkout: stable/rocky
+    required-projects: *required-projects-rocky
     vars:
       <<: *designate_scenario_vars_rocky
       devstack_localrc:
@@ -1381,9 +1417,6 @@
     templates:
       - build-openstack-docs-pti
       - neutron-tempest-plugin-jobs
-      # TODO(slaweq): bring rocky jobs back when dropping py27
-      # drama will be finally over
-      # - neutron-tempest-plugin-jobs-rocky
       - neutron-tempest-plugin-jobs-stein
       - neutron-tempest-plugin-jobs-train
       - check-requirements
diff --git a/neutron_tempest_plugin/api/test_security_groups.py b/neutron_tempest_plugin/api/test_security_groups.py
index 67925f7..0221e79 100644
--- a/neutron_tempest_plugin/api/test_security_groups.py
+++ b/neutron_tempest_plugin/api/test_security_groups.py
@@ -23,6 +23,9 @@
 
 from neutron_tempest_plugin.api import base
 from neutron_tempest_plugin.api import base_security_groups
+from oslo_log import log
+
+LOG = log.getLogger(__name__)
 
 
 class SecGroupTest(base.BaseAdminNetworkTest):
@@ -154,8 +157,7 @@
         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})
+                        project_id, **{'security_group': sg_quota})
 
     def _get_sg_quota(self):
         project_id = self.client.tenant_id
@@ -193,9 +195,9 @@
         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")
+                         "Security group quota was not changed correctly")
         self.assertEqual(quota_set, self._get_sg_amount(),
-                "Amount of security groups doesn't match quota")
+                         "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):
@@ -212,6 +214,56 @@
         self.assertGreater(new_sg_amount, sg_amount)
 
 
+class BaseSecGroupRulesQuota(base.BaseAdminNetworkTest):
+
+    def _create_max_allowed_sg_rules_amount(self, port_index=1):
+        sg_rules_amount = self._get_sg_rules_amount()
+        sg_rules_quota = self._get_sg_rules_quota()
+        sg_rules_to_create = sg_rules_quota - sg_rules_amount
+        port_index += sg_rules_to_create
+        self._create_security_group_rules(sg_rules_to_create,
+                                         port_index=port_index)
+
+    def _create_security_group_rules(self, amount, port_index=1):
+        for i in range(amount):
+            self.create_security_group_rules(**{
+                'project_id': self.client.tenant_id,
+                'direction': 'ingress',
+                'port_range_max': port_index + i,
+                'port_range_min': port_index + i,
+                'protocol': 'tcp'})
+
+    def _increase_sg_rules_quota(self):
+        sg_rules_quota = self._get_sg_rules_quota()
+        new_sg_rules_quota = 2 * sg_rules_quota
+        self._set_sg_rules_quota(new_sg_rules_quota)
+        return new_sg_rules_quota
+
+    def _decrease_sg_rules_quota(self):
+        sg_rules_quota = self._get_sg_rules_quota()
+        new_sg_rules_quota = sg_rules_quota // 2
+        self._set_sg_rules_quota(new_sg_rules_quota)
+        return new_sg_rules_quota
+
+    def _set_sg_rules_quota(self, val):
+        project_id = self.client.tenant_id
+        self.admin_client.update_quotas(project_id,
+                                        **{'security_group_rule': val})
+        LOG.info('Trying to update security group rule quota {} '.format(val))
+
+    def _get_sg_rules_quota(self):
+        project_id = self.client.tenant_id
+        quotas = self.admin_client.show_quotas(project_id)
+        return quotas['quota']['security_group_rule']
+
+    def _get_sg_rules_amount(self):
+        project_id = self.client.tenant_id
+        filter_query = {'project_id': project_id}
+        security_group_rules = self.client.list_security_group_rules(
+                **filter_query)
+        return len(security_group_rules['security_group_rules'])
+
+
 class SecGroupProtocolTest(base.BaseNetworkTest):
 
     protocol_names = base_security_groups.V4_PROTOCOL_NAMES
@@ -365,7 +417,7 @@
         # ensure that 'client2' can't see the rbac-policy sharing the
         # sg to it because the rbac-policy belongs to 'client'
         self.assertNotIn(rbac_policy['id'], [p['id'] for p in
-                          self.client2.list_rbac_policies()['rbac_policies']])
+                         self.client2.list_rbac_policies()['rbac_policies']])
 
     @decorators.idempotent_id('2a9fd480-2a35-11e9-9cb6-acde48001122')
     def test_filter_fields(self):
diff --git a/neutron_tempest_plugin/scenario/admin/test_floatingip.py b/neutron_tempest_plugin/scenario/admin/test_floatingip.py
index 511452c..a08acc3 100644
--- a/neutron_tempest_plugin/scenario/admin/test_floatingip.py
+++ b/neutron_tempest_plugin/scenario/admin/test_floatingip.py
@@ -85,7 +85,7 @@
             server_ssh_clients.append(ssh.Client(
                 fips[i]['floating_ip_address'], CONF.validation.image_ssh_user,
                 pkey=self.keypair['private_key']))
-        return server_ssh_clients, fips
+        return servers, server_ssh_clients, fips
 
     @decorators.idempotent_id('6bba729b-3fb6-494b-9e1e-82bbd89a1045')
     def test_two_vms_fips(self):
@@ -99,6 +99,7 @@
         hyper = self._list_hypervisors()[0]['hypervisor_hostname']
         # Get availability zone list to pass it for vm creation
         avail_zone = self._list_availability_zones()[0]['zoneName']
-        server_ssh_clients, fips = self._create_vms(hyper, avail_zone)
+        servers, server_ssh_clients, fips = self._create_vms(hyper, avail_zone)
         self.check_remote_connectivity(
-            server_ssh_clients[0], fips[1]['floating_ip_address'])
+            server_ssh_clients[0], fips[1]['floating_ip_address'],
+            servers=servers)
diff --git a/neutron_tempest_plugin/scenario/test_connectivity.py b/neutron_tempest_plugin/scenario/test_connectivity.py
index 5aa8f73..1a7468a 100644
--- a/neutron_tempest_plugin/scenario/test_connectivity.py
+++ b/neutron_tempest_plugin/scenario/test_connectivity.py
@@ -66,6 +66,8 @@
         for vm in vms:
             self.wait_for_server_active(vm['server'])
 
+        return vms
+
     @decorators.idempotent_id('8944b90d-1766-4669-bd8a-672b5d106bb7')
     def test_connectivity_through_2_routers(self):
         ap1_net = self.create_network()
@@ -109,7 +111,7 @@
             routes=[{"destination": ap1_subnet['cidr'],
                      "nexthop": ap1_wan_port['fixed_ips'][0]['ip_address']}])
 
-        self._create_servers(ap1_internal_port, ap2_internal_port)
+        servers = self._create_servers(ap1_internal_port, ap2_internal_port)
 
         ap1_fip = self.create_and_associate_floatingip(
             ap1_internal_port['id'])
@@ -118,7 +120,8 @@
             pkey=self.keypair['private_key'])
 
         self.check_remote_connectivity(
-            ap1_sshclient, ap2_internal_port['fixed_ips'][0]['ip_address'])
+            ap1_sshclient, ap2_internal_port['fixed_ips'][0]['ip_address'],
+            servers=servers)
 
     @decorators.idempotent_id('b72c3b77-3396-4144-b05d-9cd3c0099893')
     def test_connectivity_router_east_west_traffic(self):
@@ -145,7 +148,7 @@
         self.create_router_interface(router['id'], subnet_1['id'])
         self.create_router_interface(router['id'], subnet_2['id'])
 
-        self._create_servers(internal_port_1, internal_port_2)
+        servers = self._create_servers(internal_port_1, internal_port_2)
 
         fip = self.create_and_associate_floatingip(
             internal_port_1['id'])
@@ -155,7 +158,7 @@
 
         self.check_remote_connectivity(
             sshclient, internal_port_2['fixed_ips'][0]['ip_address'],
-            ping_count=10)
+            ping_count=10, servers=servers)
 
     @utils.requires_ext(extension="dvr", service="network")
     @decorators.idempotent_id('69d3650a-5c32-40bc-ae56-5c4c849ddd37')
@@ -237,7 +240,8 @@
             fip['floating_ip_address'], CONF.validation.image_ssh_user,
             pkey=self.keypair['private_key'])
 
-        self.check_remote_connectivity(sshclient, str(gw_ip), ping_count=10)
+        self.check_remote_connectivity(
+            sshclient, str(gw_ip), ping_count=10, servers=[vm])
         self.check_remote_connectivity(
             sshclient, dvr_router_port['fixed_ips'][0]['ip_address'],
-            ping_count=10)
+            ping_count=10, servers=[vm])
diff --git a/neutron_tempest_plugin/scenario/test_floatingip.py b/neutron_tempest_plugin/scenario/test_floatingip.py
index e276a02..37df5be 100644
--- a/neutron_tempest_plugin/scenario/test_floatingip.py
+++ b/neutron_tempest_plugin/scenario/test_floatingip.py
@@ -134,10 +134,12 @@
 
         # Check connectivity
         self.check_remote_connectivity(ssh_client,
-            dest_server['port']['fixed_ips'][0]['ip_address'])
+            dest_server['port']['fixed_ips'][0]['ip_address'],
+            servers=[src_server, dest_server])
         if self.dest_has_fip:
             self.check_remote_connectivity(ssh_client,
-                dest_server['fip']['floating_ip_address'])
+                dest_server['fip']['floating_ip_address'],
+                servers=[src_server, dest_server])
 
 
 class FloatingIpSameNetwork(FloatingIpTestCasesMixin,
@@ -200,7 +202,8 @@
                                 pkey=self.keypair['private_key'],
                                 proxy_client=proxy_client)
         self.check_remote_connectivity(ssh_client,
-                                       gateway_external_ip)
+                                       gateway_external_ip,
+                                       servers=[proxy, src_server])
 
 
 class FloatingIPPortDetailsTest(FloatingIpTestCasesMixin,
@@ -418,7 +421,8 @@
         self.fip = self.create_floatingip(port=ports[0])
         self.check_connectivity(self.fip['floating_ip_address'],
                                 CONF.validation.image_ssh_user,
-                                self.keypair['private_key'])
+                                self.keypair['private_key'],
+                                servers=servers)
         self.client.update_floatingip(self.fip['id'], port_id=ports[1]['id'])
 
         def _wait_for_fip_associated():
diff --git a/neutron_tempest_plugin/scenario/test_internal_dns.py b/neutron_tempest_plugin/scenario/test_internal_dns.py
index 13ca797..d19286c 100644
--- a/neutron_tempest_plugin/scenario/test_internal_dns.py
+++ b/neutron_tempest_plugin/scenario/test_internal_dns.py
@@ -69,11 +69,14 @@
         # in very long boot times.
         self.check_remote_connectivity(
             ssh_client, leia_port['fixed_ips'][0]['ip_address'],
-            timeout=CONF.validation.ping_timeout * 10)
+            timeout=CONF.validation.ping_timeout * 10,
+            servers=[self.server, leia])
 
         resolv_conf = ssh_client.exec_command('cat /etc/resolv.conf')
         self.assertIn('openstackgate.local', resolv_conf)
         self.assertNotIn('starwars', resolv_conf)
 
-        self.check_remote_connectivity(ssh_client, 'leia')
-        self.check_remote_connectivity(ssh_client, 'leia.openstackgate.local')
+        self.check_remote_connectivity(ssh_client, 'leia',
+                                       servers=[self.server, leia])
+        self.check_remote_connectivity(ssh_client, 'leia.openstackgate.local',
+                                       servers=[self.server, leia])
diff --git a/neutron_tempest_plugin/scenario/test_mtu.py b/neutron_tempest_plugin/scenario/test_mtu.py
index df730c6..31319ec 100644
--- a/neutron_tempest_plugin/scenario/test_mtu.py
+++ b/neutron_tempest_plugin/scenario/test_mtu.py
@@ -129,7 +129,8 @@
         for fip in (fip1, fip2):
             self.check_connectivity(
                 fip['floating_ip_address'],
-                self.username, self.keypair['private_key'])
+                self.username, self.keypair['private_key'],
+                servers=[server1, server2])
         return server_ssh_client1, fip1, server_ssh_client2, fip2
 
     @testtools.skipUnless(
diff --git a/neutron_tempest_plugin/scenario/test_security_groups.py b/neutron_tempest_plugin/scenario/test_security_groups.py
index 67d9306..dc14857 100644
--- a/neutron_tempest_plugin/scenario/test_security_groups.py
+++ b/neutron_tempest_plugin/scenario/test_security_groups.py
@@ -141,11 +141,12 @@
 
         # make sure ICMP connectivity works
         self.check_remote_connectivity(server_ssh_clients[0], fips[1][
-            'fixed_ip_address'], should_succeed=should_succeed)
+            'fixed_ip_address'], should_succeed=should_succeed,
+            servers=servers)
 
     @decorators.idempotent_id('3d73ec1a-2ec6-45a9-b0f8-04a283d9d764')
     def test_default_sec_grp_scenarios(self):
-        server_ssh_clients, fips, _ = self.create_vm_testing_sec_grp()
+        server_ssh_clients, fips, servers = self.create_vm_testing_sec_grp()
         # Check ssh connectivity when you add sec group rule, enabling ssh
         self.create_loginable_secgroup_rule(
             self.os_primary.network_client.list_security_groups()[
@@ -162,7 +163,8 @@
         # Check ICMP connectivity between VMs without specific rule for that
         # It should work though the rule is not configured
         self.check_remote_connectivity(
-            server_ssh_clients[0], fips[1]['fixed_ip_address'])
+            server_ssh_clients[0], fips[1]['fixed_ip_address'],
+            servers=servers)
 
         # Check ICMP connectivity from VM to external network
         subnets = self.os_admin.network_client.list_subnets(
@@ -173,7 +175,8 @@
                 ext_net_ip = subnet['gateway_ip']
                 break
         self.assertTrue(ext_net_ip)
-        self.check_remote_connectivity(server_ssh_clients[0], ext_net_ip)
+        self.check_remote_connectivity(server_ssh_clients[0], ext_net_ip,
+                                       servers=servers)
 
     @decorators.idempotent_id('3d73ec1a-2ec6-45a9-b0f8-04a283d9d864')
     def test_protocol_number_rule(self):
@@ -297,7 +300,8 @@
             rule_list, secgroup_id=ssh_secgrp['security_group']['id'])
         # verify ICMP connectivity between instances works
         self.check_remote_connectivity(
-            server_ssh_clients[0], fips[1]['fixed_ip_address'])
+            server_ssh_clients[0], fips[1]['fixed_ip_address'],
+            servers=servers)
         # make sure ICMP connectivity doesn't work from framework
         self.ping_ip_address(fips[0]['floating_ip_address'],
                              should_succeed=False)
diff --git a/neutron_tempest_plugin/scenario/test_trunk.py b/neutron_tempest_plugin/scenario/test_trunk.py
index 6d855f1..7fd6c52 100644
--- a/neutron_tempest_plugin/scenario/test_trunk.py
+++ b/neutron_tempest_plugin/scenario/test_trunk.py
@@ -282,7 +282,8 @@
         self.create_pingable_secgroup_rule(self.security_group['id'])
         self.check_remote_connectivity(
             vm1.ssh_client,
-            vm2.subport['fixed_ips'][0]['ip_address'])
+            vm2.subport['fixed_ips'][0]['ip_address'],
+            servers=[vm1, vm2])
 
     @testtools.skipUnless(
         (CONF.neutron_plugin_options.advanced_image_ref or
@@ -308,11 +309,12 @@
             use_advanced_image=use_advanced_image)
         normal_network_server = self._create_server_with_network(self.network)
         vlan_network_server = self._create_server_with_network(vlan_network)
+        vms = [normal_network_server, vlan_network_server]
 
         self._configure_vlan_subport(vm=trunk_network_server,
                                      vlan_tag=vlan_tag,
                                      vlan_subnet=vlan_subnet)
-        for vm in [normal_network_server, vlan_network_server]:
+        for vm in vms:
             self.wait_for_server_active(vm.server)
 
         # allow ICMP traffic
@@ -323,14 +325,16 @@
         self.check_remote_connectivity(
             trunk_network_server.ssh_client,
             normal_network_server.port['fixed_ips'][0]['ip_address'],
-            should_succeed=True)
+            should_succeed=True,
+            servers=vms)
 
         # Ping from trunk_network_server to vlan_network_server via VLAN
         # interface should success
         self.check_remote_connectivity(
             trunk_network_server.ssh_client,
             vlan_network_server.port['fixed_ips'][0]['ip_address'],
-            should_succeed=True)
+            should_succeed=True,
+            servers=vms)
 
         # Delete the trunk
         self.delete_trunk(
@@ -344,7 +348,8 @@
         self.check_remote_connectivity(
             trunk_network_server.ssh_client,
             normal_network_server.port['fixed_ips'][0]['ip_address'],
-            should_succeed=True)
+            should_succeed=True,
+            servers=vms)
 
         # Ping from trunk_network_server to vlan_network_server via VLAN
         # interface should fail after trunk deleted