Merge "Use default cirros image to reap the benefits of infra cache"
diff --git a/.zuul.yaml b/.zuul.yaml
index 5616b7b..ceb7bc2 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,14 +243,15 @@
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
nodeset: openstack-single-node-xenial
parent: neutron-tempest-plugin-api
+ description: |
+ This job run on py2 for stable/rocky gate.
override-checkout: stable/rocky
- vars:
+ vars: &api_vars_rocky
branch_override: stable/rocky
# TODO(slaweq): find a way to put this list of extensions in
# neutron repository and keep it different per branch,
@@ -317,6 +318,24 @@
USE_PYTHON3: false
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
+ # NOTE(gmann): This job run on py2 for stable/rocky gate.
+ branches:
+ - stable/rocky
+
+
+- job:
+ name: neutron-tempest-plugin-api-rocky
+ nodeset: openstack-single-node-xenial
+ parent: neutron-tempest-plugin-api
+ description: |
+ This job run on py3 for other than stable/rocky gate
+ which is nothing but neutron-tempest-pluign master gate.
+ override-checkout: stable/rocky
+ vars:
+ <<: *api_vars_rocky
+ devstack_localrc:
+ USE_PYTHON3: True
+ branches: ^(?!stable/rocky).*$
- job:
name: neutron-tempest-plugin-api-stein
@@ -532,32 +551,53 @@
- 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
parent: neutron-tempest-plugin-scenario-openvswitch
+ description: |
+ This job run on py2 for stable/rocky gate.
nodeset: openstack-single-node-xenial
override-checkout: stable/rocky
- vars:
+ vars: &scenario_vars_rocky
branch_override: stable/rocky
network_api_extensions: *api_extensions_rocky
devstack_localrc:
USE_PYTHON3: false
NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
+ branches:
+ - stable/rocky
+
+- job:
+ name: neutron-tempest-plugin-scenario-openvswitch-rocky
+ parent: neutron-tempest-plugin-scenario-openvswitch
+ nodeset: openstack-single-node-xenial
+ description: |
+ This job run on py3 for other than stable/rocky gate
+ which is nothing but neutron-tempest-pluign master gate.
+ override-checkout: stable/rocky
+ vars:
+ <<: *scenario_vars_rocky
+ devstack_localrc:
+ USE_PYTHON3: True
+ branches: ^(?!stable/rocky).*$
- job:
name: neutron-tempest-plugin-scenario-openvswitch-stein
@@ -616,14 +656,32 @@
name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-rocky
parent: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
nodeset: openstack-single-node-xenial
+ description: |
+ This job run on py2 for stable/rocky gate.
override-checkout: stable/rocky
- vars:
+ vars: &openvswitch_vars_rocky
branch_override: stable/rocky
network_api_extensions: *api_extensions_rocky
devstack_localrc:
USE_PYTHON3: false
NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}"
TEMPEST_PLUGINS: /opt/stack/neutron-tempest-plugin
+ branches:
+ - stable/rocky
+
+- job:
+ name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-rocky
+ parent: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid
+ nodeset: openstack-single-node-xenial
+ description: |
+ This job run on py3 for other than stable/rocky gate
+ which is nothing but neutron-tempest-pluign master gate.
+ override-checkout: stable/rocky
+ vars:
+ <<: *openvswitch_vars_rocky
+ devstack_localrc:
+ USE_PYTHON3: True
+ branches: ^(?!stable/rocky).*$
- job:
name: neutron-tempest-plugin-scenario-openvswitch-iptables_hybrid-stein
@@ -682,16 +740,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
@@ -704,9 +765,11 @@
- job:
name: neutron-tempest-plugin-scenario-linuxbridge-rocky
parent: neutron-tempest-plugin-scenario-linuxbridge
+ description: |
+ This job run on py2 for stable/rocky gate.
nodeset: openstack-single-node-xenial
override-checkout: stable/rocky
- vars:
+ vars: &linuxbridge_vars_rocky
branch_override: stable/rocky
network_api_extensions: *api_extensions_rocky
devstack_localrc:
@@ -721,6 +784,22 @@
$TEMPEST_CONFIG:
neutron_plugin_options:
q_agent: None
+ branches:
+ - stable/rocky
+
+- job:
+ name: neutron-tempest-plugin-scenario-linuxbridge-rocky
+ parent: neutron-tempest-plugin-scenario-linuxbridge
+ nodeset: openstack-single-node-xenial
+ description: |
+ This job run on py3 for other than stable/rocky gate
+ which is nothing but neutron-tempest-pluign master gate.
+ override-checkout: stable/rocky
+ vars:
+ <<: *linuxbridge_vars_rocky
+ devstack_localrc:
+ USE_PYTHON3: True
+ branches: ^(?!stable/rocky).*$
- job:
name: neutron-tempest-plugin-scenario-linuxbridge-stein
@@ -883,30 +962,55 @@
- 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
parent: neutron-tempest-plugin-dvr-multinode-scenario
+ description: |
+ This job run on py2 for stable/rocky gate.
nodeset: openstack-two-node-xenial
override-checkout: stable/rocky
- vars:
+ 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
+ branches:
+ - stable/rocky
+
+- job:
+ name: neutron-tempest-plugin-dvr-multinode-scenario-rocky
+ parent: neutron-tempest-plugin-dvr-multinode-scenario
+ nodeset: openstack-two-node-xenial
+ description: |
+ This job run on py3 for other than stable/rocky gate
+ which is nothing but neutron-tempest-pluign master gate.
+ override-checkout: stable/rocky
+ vars:
+ <<: *multinode_scenario_vars_rocky
+ devstack_localrc:
+ USE_PYTHON3: True
+ group-vars:
+ subnode:
+ devstack_localrc:
+ USE_PYTHON3: True
+ branches: ^(?!stable/rocky).*$
- job:
name: neutron-tempest-plugin-dvr-multinode-scenario-stein
@@ -974,27 +1078,48 @@
- 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
parent: neutron-tempest-plugin-designate-scenario
+ description: |
+ This job run on py2 for stable/rocky gate.
nodeset: openstack-single-node-xenial
override-checkout: stable/rocky
- vars:
+ vars: &designate_scenario_vars_rocky
branch_override: stable/rocky
network_api_extensions_common: *api_extensions_rocky
devstack_localrc:
USE_PYTHON3: false
TEMPEST_PLUGINS: '"/opt/stack/designate-tempest-plugin /opt/stack/neutron-tempest-plugin"'
+ branches:
+ - stable/rocky
+
+- job:
+ name: neutron-tempest-plugin-designate-scenario-rocky
+ parent: neutron-tempest-plugin-designate-scenario
+ nodeset: openstack-single-node-xenial
+ description: |
+ This job run on py3 for other than stable/rocky gate
+ which is nothing but neutron-tempest-pluign master gate.
+ override-checkout: stable/rocky
+ vars:
+ <<: *designate_scenario_vars_rocky
+ devstack_localrc:
+ USE_PYTHON3: True
+ branches: ^(?!stable/rocky).*$
- job:
name: neutron-tempest-plugin-designate-scenario-stein
@@ -1238,7 +1363,9 @@
templates:
- build-openstack-docs-pti
- neutron-tempest-plugin-jobs
- - neutron-tempest-plugin-jobs-rocky
+ # 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/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..f8cb339 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):
@@ -743,10 +733,10 @@
@classmethod
def create_qos_policy(cls, name, description=None, shared=False,
- tenant_id=None, is_default=False):
+ project_id=None, is_default=False):
"""Wrapper utility that returns a test QoS policy."""
body = cls.admin_client.create_qos_policy(
- name, description, shared, tenant_id, is_default)
+ name, description, shared, project_id, is_default)
qos_policy = body['policy']
cls.qos_policies.append(qos_policy)
return qos_policy
diff --git a/neutron_tempest_plugin/api/test_qos.py b/neutron_tempest_plugin/api/test_qos.py
index 9f9ce67..0fc7b15 100644
--- a/neutron_tempest_plugin/api/test_qos.py
+++ b/neutron_tempest_plugin/api/test_qos.py
@@ -65,11 +65,8 @@
body = self.admin_client.show_qos_policy(policy['id'])
show_policy = body['policy']
self.assertIn('project_id', show_policy)
- self.assertIn('tenant_id', show_policy)
self.assertEqual(self.admin_client.tenant_id,
show_policy['project_id'])
- self.assertEqual(self.admin_client.tenant_id,
- show_policy['tenant_id'])
@decorators.idempotent_id('f8d20e92-f06d-4805-b54f-230f77715815')
def test_list_policy_filter_by_name(self):
@@ -90,7 +87,7 @@
policy = self.create_qos_policy(name='test-policy',
description='',
shared=False,
- tenant_id=self.admin_client.tenant_id)
+ project_id=self.admin_client.tenant_id)
self.admin_client.update_qos_policy(policy['id'],
description='test policy desc2',
shared=True)
@@ -106,7 +103,7 @@
policy = self.create_qos_policy(name='test-policy',
description='',
shared=False,
- tenant_id=self.client.tenant_id)
+ project_id=self.client.tenant_id)
self.assertRaises(
exceptions.Forbidden,
self.client.update_qos_policy,
@@ -117,7 +114,7 @@
policy = self.create_qos_policy(name='test-policy',
description='',
shared=False,
- tenant_id=self.admin_client.tenant_id)
+ project_id=self.admin_client.tenant_id)
self.assertRaises(
exceptions.NotFound,
self.client.update_qos_policy,
@@ -128,7 +125,7 @@
policy = self.create_qos_policy(name='test-policy',
description='',
shared=True,
- tenant_id=self.admin_client.tenant_id)
+ project_id=self.admin_client.tenant_id)
self.admin_client.update_qos_policy(policy['id'],
description='test policy desc2')
@@ -351,7 +348,7 @@
name='test-policy-shared',
description='shared policy',
shared=True,
- tenant_id=self.admin_client.tenant_id)
+ project_id=self.admin_client.tenant_id)
obtained_policy = self.client.show_qos_policy(policy['id'])['policy']
self.assertEqual(obtained_policy, policy)
@@ -366,7 +363,7 @@
def test_default_policy_creating_network_without_policy(self):
project_id = self.create_project()['id']
policy = self.create_qos_policy(name='test-policy',
- tenant_id=project_id,
+ project_id=project_id,
is_default=True)
network = self.create_network('test network', client=self.admin_client,
project_id=project_id)
@@ -378,10 +375,10 @@
def test_default_policy_creating_network_with_policy(self):
project_id = self.create_project()['id']
self.create_qos_policy(name='test-policy',
- tenant_id=project_id,
+ project_id=project_id,
is_default=True)
policy = self.create_qos_policy(name='test-policy',
- tenant_id=project_id)
+ project_id=project_id)
network = self.create_network('test network', client=self.admin_client,
project_id=project_id,
qos_policy_id=policy['id'])
@@ -393,7 +390,7 @@
def test_user_create_port_with_admin_qos_policy(self):
qos_policy = self.create_qos_policy(
name='test-policy',
- tenant_id=self.admin_client.tenant_id,
+ project_id=self.admin_client.tenant_id,
shared=False)
network = self.create_network(
'test network', client=self.admin_client,
@@ -536,7 +533,7 @@
policy = self.create_qos_policy(name='test-policy',
description='test policy',
shared=False,
- tenant_id=self.client.tenant_id)
+ project_id=self.client.tenant_id)
rule = self.create_qos_bandwidth_limit_rule(policy_id=policy['id'],
max_kbps=1,
max_burst_kbps=1,
@@ -551,7 +548,7 @@
policy = self.create_qos_policy(name='test-policy',
description='test policy',
shared=False,
- tenant_id=self.admin_client.tenant_id)
+ project_id=self.admin_client.tenant_id)
rule = self.create_qos_bandwidth_limit_rule(policy_id=policy['id'],
max_kbps=1,
max_burst_kbps=1,
@@ -698,23 +695,23 @@
super(RbacSharedQosPoliciesTest, cls).resource_setup()
cls.client2 = cls.os_alt.network_client
- def _create_qos_policy(self, tenant_id=None):
+ def _create_qos_policy(self, project_id=None):
args = {'name': data_utils.rand_name('test-policy'),
'description': 'test policy',
'shared': False,
- 'tenant_id': tenant_id}
+ 'project_id': project_id}
qos_policy = self.admin_client.create_qos_policy(**args)['policy']
self.addCleanup(self.admin_client.delete_qos_policy, qos_policy['id'])
return qos_policy
- def _make_admin_policy_shared_to_tenant_id(self, tenant_id):
+ def _make_admin_policy_shared_to_project_id(self, project_id):
policy = self._create_qos_policy()
rbac_policy = self.admin_client.create_rbac_policy(
object_type='qos_policy',
object_id=policy['id'],
action='access_as_shared',
- target_tenant=tenant_id,
+ target_tenant=project_id,
)['rbac_policy']
return {'policy': policy, 'rbac_policy': rbac_policy}
@@ -733,7 +730,7 @@
qos_pol = self.create_qos_policy(
name=data_utils.rand_name('test-policy'),
description='test-shared-policy', shared=False,
- tenant_id=self.admin_client.tenant_id)
+ project_id=self.admin_client.tenant_id)
self.assertNotIn(qos_pol, self.client2.list_qos_policies()['policies'])
# test update shared False -> True
@@ -764,7 +761,7 @@
self.assertNotIn(qos_pol, self.client2.list_qos_policies()['policies'])
def _create_net_bound_qos_rbacs(self):
- res = self._make_admin_policy_shared_to_tenant_id(
+ res = self._make_admin_policy_shared_to_project_id(
self.client.tenant_id)
qos_policy, rbac_for_client_tenant = res['policy'], res['rbac_policy']
@@ -782,22 +779,22 @@
return rbac_for_client_tenant, rbac_wildcard
@decorators.idempotent_id('328b1f70-d424-11e5-a57f-54ee756c66df')
- def test_net_bound_shared_policy_wildcard_and_tenant_id_wild_remove(self):
+ def test_net_bound_shared_policy_wildcard_and_project_id_wild_remove(self):
client_rbac, wildcard_rbac = self._create_net_bound_qos_rbacs()
# globally unshare the qos-policy, the specific share should remain
self.admin_client.delete_rbac_policy(wildcard_rbac['id'])
self.client.list_rbac_policies(id=client_rbac['id'])
@decorators.idempotent_id('1997b00c-0c75-4e43-8ce2-999f9fa555ee')
- def test_net_bound_shared_policy_wildcard_and_tenant_id_wild_remains(self):
+ def test_net_bound_shared_policy_wildcard_and_projectid_wild_remains(self):
client_rbac, wildcard_rbac = self._create_net_bound_qos_rbacs()
# remove client_rbac policy the wildcard share should remain
self.admin_client.delete_rbac_policy(client_rbac['id'])
self.client.list_rbac_policies(id=wildcard_rbac['id'])
@decorators.idempotent_id('2ace9adc-da6e-11e5-aafe-54ee756c66df')
- def test_policy_sharing_with_wildcard_and_tenant_id(self):
- res = self._make_admin_policy_shared_to_tenant_id(
+ def test_policy_sharing_with_wildcard_and_project_id(self):
+ res = self._make_admin_policy_shared_to_project_id(
self.client.tenant_id)
qos_policy, rbac = res['policy'], res['rbac_policy']
qos_pol = self.client.show_qos_policy(qos_policy['id'])['policy']
@@ -820,7 +817,7 @@
@decorators.idempotent_id('9f85c76a-a350-11e5-8ae5-54ee756c66df')
def test_policy_target_update(self):
- res = self._make_admin_policy_shared_to_tenant_id(
+ res = self._make_admin_policy_shared_to_project_id(
self.client.tenant_id)
# change to client2
update_res = self.admin_client.update_rbac_policy(
@@ -834,7 +831,7 @@
@decorators.idempotent_id('a9b39f46-a350-11e5-97c7-54ee756c66df')
def test_network_presence_prevents_policy_rbac_policy_deletion(self):
- res = self._make_admin_policy_shared_to_tenant_id(
+ res = self._make_admin_policy_shared_to_project_id(
self.client2.tenant_id)
qos_policy_id = res['policy']['id']
self._create_network(qos_policy_id, self.client2)
@@ -886,14 +883,14 @@
object_type='qos_policy', object_id=policy['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.admin_client.list_rbac_policies(fields=fields)
self.assertEqual(set(fields), set(res['rbac_policies'][0].keys()))
@decorators.idempotent_id('c10d993a-a350-11e5-9c7a-54ee756c66df')
def test_rbac_policy_show(self):
- res = self._make_admin_policy_shared_to_tenant_id(
+ res = self._make_admin_policy_shared_to_project_id(
self.client.tenant_id)
p1 = res['rbac_policy']
p2 = self.admin_client.create_rbac_policy(
@@ -928,7 +925,7 @@
@decorators.idempotent_id('cd7d755a-a350-11e5-a344-54ee756c66df')
def test_regular_client_blocked_from_sharing_anothers_policy(self):
- qos_policy = self._make_admin_policy_shared_to_tenant_id(
+ qos_policy = self._make_admin_policy_shared_to_project_id(
self.client.tenant_id)['policy']
with testtools.ExpectedException(exceptions.BadRequest):
self.client.create_rbac_policy(
diff --git a/neutron_tempest_plugin/api/test_security_groups.py b/neutron_tempest_plugin/api/test_security_groups.py
index 26a8c05..c2e63da 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
@@ -184,19 +272,19 @@
name=data_utils.rand_name('test-sg'),
project={'id': self.admin_client.tenant_id})
- def _make_admin_sg_shared_to_tenant_id(self, tenant_id):
+ def _make_admin_sg_shared_to_project_id(self, project_id):
sg = self._create_security_group()
rbac_policy = self.admin_client.create_rbac_policy(
object_type='security_group',
object_id=sg['id'],
action='access_as_shared',
- target_tenant=tenant_id,
+ target_tenant=project_id,
)['rbac_policy']
return {'security_group': sg, 'rbac_policy': rbac_policy}
@decorators.idempotent_id('2a41eb8f-2a35-11e9-bae9-acde48001122')
def test_policy_target_update(self):
- res = self._make_admin_sg_shared_to_tenant_id(
+ res = self._make_admin_sg_shared_to_project_id(
self.client.tenant_id)
# change to client2
update_res = self.admin_client.update_rbac_policy(
@@ -210,7 +298,7 @@
@decorators.idempotent_id('2a619a8a-2a35-11e9-90d9-acde48001122')
def test_port_presence_prevents_policy_rbac_policy_deletion(self):
- res = self._make_admin_sg_shared_to_tenant_id(
+ res = self._make_admin_sg_shared_to_project_id(
self.client2.tenant_id)
sg_id = res['security_group']['id']
net = self.create_network(client=self.client2)
@@ -253,14 +341,14 @@
object_type='security_group', object_id=sg['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.admin_client.list_rbac_policies(fields=fields)
self.assertEqual(set(fields), set(res['rbac_policies'][0].keys()))
@decorators.idempotent_id('2abf8f9e-2a35-11e9-85f7-acde48001122')
def test_rbac_policy_show(self):
- res = self._make_admin_sg_shared_to_tenant_id(
+ res = self._make_admin_sg_shared_to_project_id(
self.client.tenant_id)
p1 = res['rbac_policy']
p2 = self.admin_client.create_rbac_policy(
@@ -296,7 +384,7 @@
@decorators.idempotent_id('2aff3900-2a35-11e9-96b3-acde48001122')
def test_regular_client_blocked_from_sharing_anothers_policy(self):
- sg = self._make_admin_sg_shared_to_tenant_id(
+ sg = self._make_admin_sg_shared_to_project_id(
self.client.tenant_id)['security_group']
with testtools.ExpectedException(exceptions.BadRequest):
self.client.create_rbac_policy(
diff --git a/neutron_tempest_plugin/api/test_security_groups_negative.py b/neutron_tempest_plugin/api/test_security_groups_negative.py
index 1fcbd18..24e2289 100644
--- a/neutron_tempest_plugin/api/test_security_groups_negative.py
+++ b/neutron_tempest_plugin/api/test_security_groups_negative.py
@@ -15,11 +15,13 @@
from neutron_lib import constants
from neutron_lib.db import constants as db_const
+from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from neutron_tempest_plugin.api import base
from neutron_tempest_plugin.api import base_security_groups
+from neutron_tempest_plugin.api import test_security_groups
LONG_NAME_NG = 'x' * (db_const.NAME_FIELD_SIZE + 1)
@@ -84,6 +86,41 @@
self.os_primary.network_client.delete_security_group,
security_group_id=security_group['id'])
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('867d67c3-7e26-4288-a27b-e3d0649ee54b')
+ def test_assign_sec_group_twice(self):
+ net = self.create_network()
+ port = self.create_port(net)
+ sg = self.create_security_group()
+ self.assertRaises(lib_exc.BadRequest,
+ self.update_port,
+ port,
+ **{'security_groups': [sg['id'], sg['id']]})
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('d5ecb408-eb7e-47c1-a56f-353967dbd1c2')
+ def test_assign_nonexistent_sec_group(self):
+ net = self.create_network()
+ port = self.create_port(net)
+ self.assertRaises(lib_exc.NotFound,
+ self.update_port,
+ port,
+ **{'security_groups': [data_utils.rand_uuid()]})
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('98ef378d-81a2-43f6-bb6f-735c04cdef91')
+ def test_no_sec_group_changes_after_assignment_failure(self):
+ net = self.create_network()
+ port = self.create_port(net)
+ sg_list_before_failure = port['security_groups']
+ self.assertRaises(lib_exc.NotFound,
+ self.update_port,
+ port,
+ **{'security_groups': [data_utils.rand_uuid()]})
+ port_details_new = self.client.show_port(port['id'])['port']
+ sg_list_after_failure = port_details_new['security_groups']
+ self.assertEqual(sg_list_before_failure, sg_list_after_failure)
+
class NegativeSecGroupIPv6Test(NegativeSecGroupTest):
_ip_version = constants.IP_VERSION_6
@@ -114,3 +151,22 @@
def test_create_security_group_rule_with_ipv6_protocol_integers(self):
self._test_create_security_group_rule_with_bad_protocols(
base_security_groups.V6_PROTOCOL_INTS)
+
+
+class NegativeSecGroupQuotaTest(test_security_groups.BaseSecGroupQuota):
+
+ credentials = ['primary', 'admin']
+ required_extensions = ['security-group', 'quotas']
+
+ @decorators.attr(type=['negative'])
+ @decorators.idempotent_id('63f00cba-fcf5-4000-a3ee-eca58a1795c1')
+ def test_create_excess_sg(self):
+ self._set_sg_quota(0)
+ self.assertRaises(lib_exc.Conflict, self.create_security_group)
+
+ @decorators.attr(type=['negative'])
+ @decorators.idempotent_id('90a83445-bbc2-49d8-8c85-a111c08cd7fb')
+ def test_sg_quota_incorrect_values(self):
+ values = [-2, 2147483648, "value"]
+ for value in values:
+ self.assertRaises(lib_exc.BadRequest, self._set_sg_quota, value)
diff --git a/neutron_tempest_plugin/common/ip.py b/neutron_tempest_plugin/common/ip.py
index 1702bd3..70a3dd5 100644
--- a/neutron_tempest_plugin/common/ip.py
+++ b/neutron_tempest_plugin/common/ip.py
@@ -15,6 +15,7 @@
# under the License.
import collections
+import re
import subprocess
import netaddr
@@ -299,6 +300,23 @@
netaddr.IPNetwork(subnet['cidr']).prefixlen)
+def arp_table():
+ # 192.168.0.16 0x1 0x2 dc:a6:32:06:56:51 * enp0s31f6
+ regex_str = (r"([^ ]+)\s+(0x\d+)\s+(0x\d+)\s+(\w{2}\:\w{2}\:\w{2}\:\w{2}\:"
+ r"\w{2}\:\w{2})\s+([\w+\*]+)\s+([\-\w]+)")
+ regex = re.compile(regex_str)
+ arp_table = []
+ with open('/proc/net/arp', 'r') as proc_file:
+ for line in proc_file.readlines():
+ m = regex.match(line)
+ if m:
+ arp_table.append(ARPregister(
+ ip_address=m.group(1), hw_type=m.group(2),
+ flags=m.group(3), mac_address=m.group(4),
+ mask=m.group(5), device=m.group(6)))
+ return arp_table
+
+
class Route(HasProperties,
collections.namedtuple('Route',
['dest', 'properties'])):
@@ -314,3 +332,40 @@
@property
def src_ip(self):
return netaddr.IPAddress(self.src)
+
+ def __str__(self):
+ properties_str = ' '.join('%s %s' % (k, v)
+ for k, v in self.properties.items())
+ return '%(dest)s %(properties)s' % {'dest': self.dest,
+ 'properties': properties_str}
+
+
+class ARPregister(collections.namedtuple(
+ 'ARPregister',
+ ['ip_address', 'hw_type', 'flags', 'mac_address', 'mask', 'device'])):
+
+ def __str__(self):
+ return '%s %s %s %s %s %s' % (self.ip_address, self.hw_type,
+ self.flags, self.mac_address, self.mask,
+ self.device)
+
+
+def find_valid_cidr(valid_cidr='10.0.0.0/8', used_cidr=None):
+ total_ips = netaddr.IPSet(netaddr.IPNetwork(valid_cidr))
+ if used_cidr:
+ used_network = netaddr.IPNetwork(used_cidr)
+ netmask = used_network.netmask.netmask_bits()
+ valid_ips = total_ips.difference(netaddr.IPSet(used_network))
+ else:
+ valid_ips = total_ips
+ netmask = 24
+
+ for ip in valid_ips:
+ valid_network = netaddr.IPNetwork('%s/%s' % (ip, netmask))
+ if valid_network in valid_ips:
+ return valid_network.cidr
+
+ exception_str = 'No valid CIDR found in %s' % valid_cidr
+ if used_cidr:
+ exception_str += ', used CIDR %s' % used_cidr
+ raise Exception(exception_str)
diff --git a/neutron_tempest_plugin/common/utils.py b/neutron_tempest_plugin/common/utils.py
index bd7a367..631f75b 100644
--- a/neutron_tempest_plugin/common/utils.py
+++ b/neutron_tempest_plugin/common/utils.py
@@ -18,7 +18,6 @@
"""Utilities and helper functions."""
-import functools
import threading
import time
try:
@@ -83,22 +82,6 @@
raise WaitTimeout("Timed out after %d seconds" % timeout)
-# TODO(haleyb): move to neutron-lib
-# code copied from neutron repository - neutron/tests/base.py
-def unstable_test(reason):
- def decor(f):
- @functools.wraps(f)
- def inner(self, *args, **kwargs):
- try:
- return f(self, *args, **kwargs)
- except Exception as e:
- msg = ("%s was marked as unstable because of %s, "
- "failure was: %s") % (self.id(), reason, e)
- raise self.skipTest(msg)
- return inner
- return decor
-
-
def override_class(overriden_class, overrider_class):
"""Override class definition with a MixIn class
diff --git a/neutron_tempest_plugin/config.py b/neutron_tempest_plugin/config.py
index 51fbafc..28d6b76 100644
--- a/neutron_tempest_plugin/config.py
+++ b/neutron_tempest_plugin/config.py
@@ -67,7 +67,7 @@
# Multicast tests settings
cfg.StrOpt('multicast_group_range',
- default='224.0.0.120-224.0.0.250',
+ default='225.0.0.120-225.0.0.250',
help='Unallocated multi-cast IPv4 range, which will be used to '
'test the multi-cast support.'),
@@ -123,6 +123,12 @@
default=False,
help='Allow creation of shared resources.'
'The default value is false.'),
+ cfg.BoolOpt('is_igmp_snooping_enabled',
+ default=False,
+ help='Indicates whether IGMP snooping is enabled or not. '
+ 'If True, multicast test(s) will assert that multicast '
+ 'traffic is not being flooded to all ports. Defaults '
+ 'to False.'),
]
# TODO(amuller): Redo configuration options registration as part of the planned
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index 5a29aa1..42bd33b 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -26,6 +26,7 @@
from tempest.lib import exceptions as lib_exc
from neutron_tempest_plugin.api import base as base_api
+from neutron_tempest_plugin.common import ip as ip_utils
from neutron_tempest_plugin.common import shell
from neutron_tempest_plugin.common import ssh
from neutron_tempest_plugin import config
@@ -219,6 +220,7 @@
except lib_exc.SSHTimeout as ssh_e:
LOG.debug(ssh_e)
self._log_console_output(servers)
+ self._log_local_network_status()
raise
def _log_console_output(self, servers=None):
@@ -239,10 +241,16 @@
LOG.debug("Server %s disappeared(deleted) while looking "
"for the console log", server['id'])
+ def _log_local_network_status(self):
+ local_routes = ip_utils.IPCommand().list_routes()
+ LOG.debug('Local routes:\n%s', '\n'.join(str(r) for r in local_routes))
+ arp_table = ip_utils.arp_table()
+ LOG.debug('Local ARP table:\n%s', '\n'.join(str(r) for r in arp_table))
+
def _check_remote_connectivity(self, source, dest, count,
should_succeed=True,
nic=None, mtu=None, fragmentation=True,
- timeout=None):
+ timeout=None, pattern=None):
"""check ping server via source ssh connection
:param source: RemoteClient: an ssh connection from which to ping
@@ -253,12 +261,13 @@
:param mtu: mtu size for the packet to be sent
:param fragmentation: Flag for packet fragmentation
:param timeout: Timeout for all ping packet(s) to succeed
+ :param pattern: hex digits included in ICMP messages
:returns: boolean -- should_succeed == ping
:returns: ping is false if ping failed
"""
def ping_host(source, host, count,
size=CONF.validation.ping_size, nic=None, mtu=None,
- fragmentation=True):
+ fragmentation=True, pattern=None):
IP_VERSION_4 = neutron_lib_constants.IP_VERSION_4
IP_VERSION_6 = neutron_lib_constants.IP_VERSION_6
@@ -274,13 +283,16 @@
cmd += ' -M do'
size = str(net_utils.get_ping_payload_size(
mtu=mtu, ip_version=ip_version))
+ if pattern:
+ cmd += ' -p {pattern}'.format(pattern=pattern)
cmd += ' -c{0} -w{0} -s{1} {2}'.format(count, size, host)
return source.exec_command(cmd)
def ping_remote():
try:
result = ping_host(source, dest, count, nic=nic, mtu=mtu,
- fragmentation=fragmentation)
+ fragmentation=fragmentation,
+ pattern=pattern)
except lib_exc.SSHExecCommandFailed:
LOG.warning('Failed to ping IP: %s via a ssh connection '
@@ -301,12 +313,13 @@
def check_remote_connectivity(self, source, dest, should_succeed=True,
nic=None, mtu=None, fragmentation=True,
servers=None, timeout=None,
- ping_count=CONF.validation.ping_count):
+ ping_count=CONF.validation.ping_count,
+ pattern=None):
try:
self.assertTrue(self._check_remote_connectivity(
source, dest, ping_count, should_succeed, nic, mtu,
fragmentation,
- timeout=timeout))
+ timeout=timeout, pattern=pattern))
except lib_exc.SSHTimeout as ssh_e:
LOG.debug(ssh_e)
self._log_console_output(servers)
@@ -416,7 +429,7 @@
udp = ''
if protocol.lower() == neutron_lib_constants.PROTO_NAME_UDP:
udp = '-u'
- cmd = "sudo nc %(udp)s -p %(port)s -lk -e echo %(msg)s &" % {
+ cmd = "sudo nc %(udp)s -p %(port)s -lk -c echo %(msg)s &" % {
'udp': udp, 'port': port, 'msg': echo_msg}
try:
return ssh_client.exec_command(cmd)
diff --git a/neutron_tempest_plugin/scenario/test_connectivity.py b/neutron_tempest_plugin/scenario/test_connectivity.py
index 78d8d95..5aa8f73 100644
--- a/neutron_tempest_plugin/scenario/test_connectivity.py
+++ b/neutron_tempest_plugin/scenario/test_connectivity.py
@@ -13,11 +13,15 @@
# License for the specific language governing permissions and limitations
# under the License.
+import netaddr
+
+from neutron_lib import constants
from tempest.common import compute
from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+from neutron_tempest_plugin.common import ip as ip_utils
from neutron_tempest_plugin.common import ssh
from neutron_tempest_plugin import config
from neutron_tempest_plugin.scenario import base
@@ -161,14 +165,14 @@
Subnet is connected to dvr and non-dvr routers in the same time, test
ensures that connectivity from VM to both routers is working.
- Test scenario:
+ Test scenario: (NOTE: 10.1.0.0/24 private CIDR is used as an example)
+----------------+ +------------+
| Non-dvr router | | DVR router |
| | | |
- | 10.0.0.1 | | 10.0.0.x |
+ | 10.1.0.1 | | 10.1.0.x |
+-------+--------+ +-----+------+
| |
- | 10.0.0.0/24 |
+ | 10.1.0.0/24 |
+----------------+----------------+
|
+-+-+
@@ -176,16 +180,28 @@
+---+
where:
- 10.0.0.1 - is subnet's gateway IP address,
- 10.0.0.x - is any other IP address taken from subnet's range
+ 10.1.0.1 - is subnet's gateway IP address,
+ 10.1.0.x - is any other IP address taken from subnet's range
- Test ensures that both 10.0.0.1 and 10.0.0.x IP addresses are
+ Test ensures that both 10.1.0.1 and 10.1.0.x IP addresses are
reachable from VM.
"""
+ ext_network = self.client.show_network(self.external_network_id)
+ for ext_subnetid in ext_network['network']['subnets']:
+ ext_subnet = self.os_admin.network_client.show_subnet(ext_subnetid)
+ ext_cidr = ext_subnet['subnet']['cidr']
+ if ext_subnet['subnet']['ip_version'] == constants.IP_VERSION_4:
+ break
+ else:
+ self.fail('No IPv4 subnet was found in external network %s' %
+ ext_network['network']['id'])
+
+ subnet_cidr = ip_utils.find_valid_cidr(used_cidr=ext_cidr)
+ gw_ip = netaddr.IPAddress(subnet_cidr.first + 1)
network = self.create_network()
subnet = self.create_subnet(
- network, cidr="10.0.0.0/24", gateway="10.0.0.1")
+ network, cidr=str(subnet_cidr), gateway=str(gw_ip))
non_dvr_router = self.create_router_by_client(
tenant_id=self.client.tenant_id,
@@ -221,8 +237,7 @@
fip['floating_ip_address'], CONF.validation.image_ssh_user,
pkey=self.keypair['private_key'])
- self.check_remote_connectivity(
- sshclient, '10.0.0.1', ping_count=10)
+ self.check_remote_connectivity(sshclient, str(gw_ip), ping_count=10)
self.check_remote_connectivity(
sshclient, dvr_router_port['fixed_ips'][0]['ip_address'],
ping_count=10)
diff --git a/neutron_tempest_plugin/scenario/test_floatingip.py b/neutron_tempest_plugin/scenario/test_floatingip.py
index 39aa09d..e276a02 100644
--- a/neutron_tempest_plugin/scenario/test_floatingip.py
+++ b/neutron_tempest_plugin/scenario/test_floatingip.py
@@ -17,6 +17,7 @@
from neutron_lib import constants as lib_constants
from neutron_lib.services.qos import constants as qos_consts
+from neutron_lib.utils import test
from tempest.common import utils
from tempest.common import waiters
from tempest.lib.common.utils import data_utils
@@ -151,7 +152,7 @@
same_network = True
- @common_utils.unstable_test("bug 1717302")
+ @test.unstable_test("bug 1717302")
@decorators.idempotent_id('05c4e3b3-7319-4052-90ad-e8916436c23b')
def test_east_west(self):
self._test_east_west()
@@ -169,7 +170,7 @@
same_network = False
- @common_utils.unstable_test("bug 1717302")
+ @test.unstable_test("bug 1717302")
@decorators.idempotent_id('f18f0090-3289-4783-b956-a0f8ac511e8b')
def test_east_west(self):
self._test_east_west()
@@ -212,7 +213,7 @@
def resource_setup(cls):
super(FloatingIPPortDetailsTest, cls).resource_setup()
- @common_utils.unstable_test("bug 1815585")
+ @test.unstable_test("bug 1815585")
@decorators.idempotent_id('a663aeee-dd81-492b-a207-354fd6284dbe')
def test_floatingip_port_details(self):
"""Tests the following:
diff --git a/neutron_tempest_plugin/scenario/test_migration.py b/neutron_tempest_plugin/scenario/test_migration.py
index f4b918c..410c64e 100644
--- a/neutron_tempest_plugin/scenario/test_migration.py
+++ b/neutron_tempest_plugin/scenario/test_migration.py
@@ -17,6 +17,7 @@
from neutron_lib.api.definitions import portbindings as pb
from neutron_lib import constants as const
+from neutron_lib.utils import test
from tempest.common import utils
from tempest.lib import decorators
import testtools
@@ -224,7 +225,7 @@
class NetworkMigrationFromDVRHA(NetworkMigrationTestBase):
- @common_utils.unstable_test("bug 1756301")
+ @test.unstable_test("bug 1756301")
@decorators.idempotent_id('1be9b2e2-379c-40a4-a269-6687b81df691')
@testtools.skipUnless(
CONF.neutron_plugin_options.l3_agent_mode == 'dvr_snat',
@@ -233,7 +234,7 @@
self._test_migration(before_dvr=True, before_ha=True,
after_dvr=False, after_ha=False)
- @common_utils.unstable_test("bug 1756301")
+ @test.unstable_test("bug 1756301")
@decorators.idempotent_id('55957267-4e84-4314-a2f7-7cd36a2df04b')
@testtools.skipUnless(
CONF.neutron_plugin_options.l3_agent_mode == 'dvr_snat',
@@ -242,7 +243,7 @@
self._test_migration(before_dvr=True, before_ha=True,
after_dvr=False, after_ha=True)
- @common_utils.unstable_test("bug 1756301")
+ @test.unstable_test("bug 1756301")
@decorators.idempotent_id('d6bedff1-72be-4a9a-8ea2-dc037cd838e0')
@testtools.skipUnless(
CONF.neutron_plugin_options.l3_agent_mode == 'dvr_snat',
diff --git a/neutron_tempest_plugin/scenario/test_multicast.py b/neutron_tempest_plugin/scenario/test_multicast.py
index d511b3b..566ac95 100644
--- a/neutron_tempest_plugin/scenario/test_multicast.py
+++ b/neutron_tempest_plugin/scenario/test_multicast.py
@@ -15,6 +15,7 @@
import netaddr
from neutron_lib import constants
+from neutron_lib.utils import test
from oslo_log import log
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
@@ -110,6 +111,14 @@
'result_file': result_file}
+def get_unregistered_script(group, result_file):
+ return """#!/bin/bash
+export LC_ALL=en_US.UTF-8
+tcpdump -i any -s0 -vv host %(group)s -vvneA -s0 -l &> %(result_file)s &
+ """ % {'group': group,
+ 'result_file': result_file}
+
+
class BaseMulticastTest(object):
credentials = ['primary']
@@ -124,6 +133,7 @@
multicast_message = "Big Bang"
receiver_output_file = "/tmp/receiver_mcast_out"
sender_output_file = "/tmp/sender_mcast_out"
+ unregistered_output_file = "/tmp/unregistered_mcast_out"
@classmethod
def skip_checks(cls):
@@ -197,16 +207,16 @@
server['ssh_client'] = ssh.Client(server['fip']['floating_ip_address'],
self.username,
pkey=self.keypair['private_key'])
- self._check_python_installed_on_server(server['ssh_client'],
- server['id'])
+ self._check_cmd_installed_on_server(server['ssh_client'],
+ server['id'], PYTHON3_BIN)
return server
- def _check_python_installed_on_server(self, ssh_client, server_id):
+ def _check_cmd_installed_on_server(self, ssh_client, server_id, cmd):
try:
- ssh_client.execute_script('which %s' % PYTHON3_BIN)
+ ssh_client.execute_script('which %s' % cmd)
except exceptions.SSHScriptFailed:
raise self.skipException(
- "%s is not available on server %s" % (PYTHON3_BIN, server_id))
+ "%s is not available on server %s" % (cmd, server_id))
def _prepare_sender(self, server, mcast_address):
check_script = get_sender_script(
@@ -225,11 +235,24 @@
server['fip']['floating_ip_address'],
self.username,
pkey=self.keypair['private_key'])
- self._check_python_installed_on_server(ssh_client, server['id'])
+ self._check_cmd_installed_on_server(ssh_client, server['id'],
+ PYTHON3_BIN)
server['ssh_client'].execute_script(
'echo "%s" > ~/multicast_traffic_receiver.py' % check_script)
- @utils.unstable_test("bug 1850288")
+ def _prepare_unregistered(self, server, mcast_address):
+ check_script = get_unregistered_script(
+ group=mcast_address, result_file=self.unregistered_output_file)
+ ssh_client = ssh.Client(
+ server['fip']['floating_ip_address'],
+ self.username,
+ pkey=self.keypair['private_key'])
+ self._check_cmd_installed_on_server(ssh_client, server['id'],
+ 'tcpdump')
+ server['ssh_client'].execute_script(
+ 'echo "%s" > ~/unregistered_traffic_receiver.sh' % check_script)
+
+ @test.unstable_test("bug 1850288")
@decorators.idempotent_id('113486fc-24c9-4be4-8361-03b1c9892867')
def test_multicast_between_vms_on_same_network(self):
"""Test multicast messaging between two servers on the same network
@@ -240,9 +263,26 @@
receivers = [self._create_server() for _ in range(1)]
# Sender can be also receiver of multicast traffic
receivers.append(sender)
- self._check_multicast_conectivity(sender=sender, receivers=receivers)
+ unregistered = self._create_server()
+ self._check_multicast_conectivity(sender=sender, receivers=receivers,
+ unregistered=unregistered)
- def _check_multicast_conectivity(self, sender, receivers):
+ def _is_multicast_traffic_expected(self, mcast_address):
+ """Checks if multicast traffic is expected to arrive.
+
+ Checks if multicast traffic is expected to arrive to the
+ unregistered VM.
+
+ If IGMP snooping is enabled, multicast traffic should not be
+ flooded unless the destination IP is in the range of 224.0.0.X
+ [0].
+
+ [0] https://tools.ietf.org/html/rfc4541 (See section 2.1.2)
+ """
+ return (mcast_address.startswith('224.0.0') or not
+ CONF.neutron_plugin_options.is_igmp_snooping_enabled)
+
+ def _check_multicast_conectivity(self, sender, receivers, unregistered):
"""Test multi-cast messaging between two servers
[Sender server] -> ... some network topology ... -> [Receiver server]
@@ -256,6 +296,12 @@
path=file_path))
return msg in result
+ self._prepare_unregistered(unregistered, mcast_address)
+
+ # Run the unregistered node script
+ unregistered['ssh_client'].execute_script(
+ "bash ~/unregistered_traffic_receiver.sh", become_root=True)
+
self._prepare_sender(sender, mcast_address)
receiver_ids = []
for receiver in receivers:
@@ -294,6 +340,18 @@
for receiver_id in receiver_ids:
self.assertIn(receiver_id, replies_result)
+ # Kill the tcpdump command running on the unregistered node so
+ # tcpdump flushes its output to the output file
+ unregistered['ssh_client'].execute_script(
+ "killall tcpdump && sleep 2", become_root=True)
+
+ unregistered_result = unregistered['ssh_client'].execute_script(
+ "cat {path} || echo '{path} not exists yet'".format(
+ path=self.unregistered_output_file))
+ num_of_pckt = (1 if self._is_multicast_traffic_expected(mcast_address)
+ else 0)
+ self.assertIn('%d packets captured' % num_of_pckt, unregistered_result)
+
class MulticastTestIPv4(BaseMulticastTest, base.BaseTempestTestCase):
diff --git a/neutron_tempest_plugin/scenario/test_port_forwardings.py b/neutron_tempest_plugin/scenario/test_port_forwardings.py
index 06f175b..7283887 100644
--- a/neutron_tempest_plugin/scenario/test_port_forwardings.py
+++ b/neutron_tempest_plugin/scenario/test_port_forwardings.py
@@ -14,12 +14,12 @@
# under the License.
from neutron_lib import constants
+from neutron_lib.utils import test
from oslo_log import log
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from neutron_tempest_plugin.common import ssh
-from neutron_tempest_plugin.common import utils
from neutron_tempest_plugin import config
from neutron_tempest_plugin.scenario import base
@@ -101,7 +101,7 @@
server['port_forwarding_udp']['external_port'],
constants.PROTO_NAME_UDP))
- @utils.unstable_test("bug 1850800")
+ @test.unstable_test("bug 1850800")
@decorators.idempotent_id('ab40fc48-ca8d-41a0-b2a3-f6679c847bfe')
def test_port_forwarding_to_2_servers(self):
udp_sg_rule = {'protocol': constants.PROTO_NAME_UDP,
diff --git a/neutron_tempest_plugin/services/network/json/network_client.py b/neutron_tempest_plugin/services/network/json/network_client.py
index 05095a7..521e2be 100644
--- a/neutron_tempest_plugin/services/network/json/network_client.py
+++ b/neutron_tempest_plugin/services/network/json/network_client.py
@@ -601,7 +601,7 @@
return service_client.ResponseBody(resp, body)
def create_qos_policy(self, name, description=None, shared=False,
- tenant_id=None, is_default=False):
+ project_id=None, is_default=False):
uri = '%s/qos/policies' % self.uri_prefix
post_data = {
'policy': {
@@ -612,8 +612,8 @@
}
if description is not None:
post_data['policy']['description'] = description
- if tenant_id is not None:
- post_data['policy']['tenant_id'] = tenant_id
+ if project_id is not None:
+ post_data['policy']['project_id'] = project_id
resp, body = self.post(uri, self.serialize(post_data))
body = self.deserialize_single(body)
self.expected_success(201, resp.status)
@@ -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:
diff --git a/releasenotes/notes/igmp-snooping-8d6d85608df8880a.yaml b/releasenotes/notes/igmp-snooping-8d6d85608df8880a.yaml
new file mode 100644
index 0000000..032be1f
--- /dev/null
+++ b/releasenotes/notes/igmp-snooping-8d6d85608df8880a.yaml
@@ -0,0 +1,11 @@
+---
+features:
+ - |
+ Enhanced the ``test_multicast_between_vms_on_same_network`` adding
+ IGMP test coverage to it. A new VM running tcpdump is spawned as
+ part of the test to verify whether the traffic is reaching it or not.
+upgrade:
+ - |
+ Add a new configuration option called ``is_igmp_snooping_enabled``
+ to enable/disable IGMP testing as part of the
+ ``test_multicast_between_vms_on_same_network`` test case.