Merge "Distinguish between luks and cryptsetup volume types"
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index a7c8fb7..15369de 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -3,6 +3,21 @@
Tempest Configuration Guide
===========================
+This guide is a starting point for configuring tempest. It aims to elaborate
+on and explain some of the mandatory and common configuration settings and how
+they are used in conjunction. The source of truth on each option is the sample
+config file which explains the purpose of each individual option.
+
+Lock Path
+---------
+
+There are some tests and operations inside of tempest that need to be
+externally locked when running in parallel to prevent them from running at
+the same time. This is a mandatory step for configuring tempest and is still
+needed even when running serially. All that is needed to do this is:
+
+ #. Set the lock_path option in the oslo_concurrency group
+
Auth/Credentials
----------------
diff --git a/requirements.txt b/requirements.txt
index f6e30ce..56796d8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,7 +12,6 @@
python-ceilometerclient>=1.0.6
python-glanceclient>=0.15.0
python-keystoneclient>=1.1.0
-python-neutronclient>=2.3.11,<3
python-cinderclient>=1.1.0
python-heatclient>=0.3.0
python-ironicclient>=0.2.1
diff --git a/tempest/api/compute/admin/test_flavors_negative.py b/tempest/api/compute/admin/test_flavors_negative.py
deleted file mode 100644
index c7eb9ae..0000000
--- a/tempest/api/compute/admin/test_flavors_negative.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import uuid
-
-from tempest_lib.common.utils import data_utils
-from tempest_lib import exceptions as lib_exc
-
-from tempest.api.compute import base
-from tempest.api_schema.request.compute.v2 import flavors
-from tempest import config
-from tempest import test
-
-
-CONF = config.CONF
-
-load_tests = test.NegativeAutoTest.load_tests
-
-
-class FlavorsAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
-
- """
- Tests Flavors API Create and Delete that require admin privileges
- """
-
- @classmethod
- def skip_checks(cls):
- super(FlavorsAdminNegativeTestJSON, cls).skip_checks()
- if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
- msg = "OS-FLV-EXT-DATA extension not enabled."
- raise cls.skipException(msg)
-
- @classmethod
- def setup_clients(cls):
- super(FlavorsAdminNegativeTestJSON, cls).setup_clients()
- cls.client = cls.os_adm.flavors_client
- cls.user_client = cls.os.flavors_client
-
- @classmethod
- def resource_setup(cls):
- super(FlavorsAdminNegativeTestJSON, cls).resource_setup()
- cls.flavor_name_prefix = 'test_flavor_'
- cls.ram = 512
- cls.vcpus = 1
- cls.disk = 10
- cls.ephemeral = 10
- cls.swap = 1024
- cls.rxtx = 2
-
- @test.attr(type=['negative', 'gate'])
- @test.idempotent_id('404451c0-c1ae-4448-8d50-d74f26f93ec8')
- def test_get_flavor_details_for_deleted_flavor(self):
- # Delete a flavor and ensure it is not listed
- # Create a test flavor
- flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-
- # no need to specify flavor_id, we can get the flavor_id from a
- # response of create_flavor() call.
- flavor = self.client.create_flavor(flavor_name,
- self.ram,
- self.vcpus, self.disk,
- None,
- ephemeral=self.ephemeral,
- swap=self.swap,
- rxtx=self.rxtx)
- # Delete the flavor
- new_flavor_id = flavor['id']
- self.client.delete_flavor(new_flavor_id)
-
- # Deleted flavors can be seen via detailed GET
- flavor = self.client.get_flavor_details(new_flavor_id)
- self.assertEqual(flavor['name'], flavor_name)
-
- # Deleted flavors should not show up in a list however
- flavors = self.client.list_flavors_with_detail()
- flag = True
- for flavor in flavors:
- if flavor['name'] == flavor_name:
- flag = False
- self.assertTrue(flag)
-
- @test.attr(type=['negative', 'gate'])
- @test.idempotent_id('6f56e7b7-7500-4d0c-9913-880ca1efed87')
- def test_create_flavor_as_user(self):
- # only admin user can create a flavor
- flavor_name = data_utils.rand_name(self.flavor_name_prefix)
- new_flavor_id = str(uuid.uuid4())
-
- self.assertRaises(lib_exc.Forbidden,
- self.user_client.create_flavor,
- flavor_name, self.ram, self.vcpus, self.disk,
- new_flavor_id, ephemeral=self.ephemeral,
- swap=self.swap, rxtx=self.rxtx)
-
- @test.attr(type=['negative', 'gate'])
- @test.idempotent_id('a9a6dc02-8c14-4e05-a1ca-3468d4214882')
- def test_delete_flavor_as_user(self):
- # only admin user can delete a flavor
- self.assertRaises(lib_exc.Forbidden,
- self.user_client.delete_flavor,
- self.flavor_ref_alt)
-
-
-@test.SimpleNegativeAutoTest
-class FlavorCreateNegativeTestJSON(base.BaseV2ComputeAdminTest,
- test.NegativeAutoTest):
- _service = CONF.compute.catalog_type
- _schema = flavors.flavor_create
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index 7a64de3..86d90f6 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -95,7 +95,8 @@
self.assertEqual(quota_usage['volumes']['in_use'] + 1,
new_quota_usage['volumes']['in_use'])
- self.assertEqual(quota_usage['gigabytes']['in_use'] + 1,
+ self.assertEqual(quota_usage['gigabytes']['in_use'] +
+ volume["size"],
new_quota_usage['gigabytes']['in_use'])
@test.attr(type='gate')
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index 98b7143..d7287f0 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -31,7 +31,9 @@
@classmethod
def resource_setup(cls):
super(BaseVolumeQuotasNegativeV2TestJSON, cls).resource_setup()
- cls.shared_quota_set = {'gigabytes': 3, 'volumes': 1, 'snapshots': 1}
+ cls.default_volume_size = cls.volumes_client.default_volume_size
+ cls.shared_quota_set = {'gigabytes': 3 * cls.default_volume_size,
+ 'volumes': 1, 'snapshots': 1}
# NOTE(gfidente): no need to restore original quota set
# after the tests as they only work with tenant isolation.
@@ -67,14 +69,16 @@
self.demo_tenant_id,
**self.shared_quota_set)
- new_quota_set = {'gigabytes': 2, 'volumes': 2, 'snapshots': 1}
+ new_quota_set = {'gigabytes': 2 * self.default_volume_size,
+ 'volumes': 2, 'snapshots': 1}
self.quotas_client.update_quota_set(
self.demo_tenant_id,
**new_quota_set)
self.assertRaises(lib_exc.OverLimit,
self.volumes_client.create_volume)
- new_quota_set = {'gigabytes': 2, 'volumes': 1, 'snapshots': 2}
+ new_quota_set = {'gigabytes': 2 * self.default_volume_size,
+ 'volumes': 1, 'snapshots': 2}
self.quotas_client.update_quota_set(
self.demo_tenant_id,
**self.shared_quota_set)
diff --git a/tempest/api_schema/response/compute/parameter_types.py b/tempest/api_schema/response/compute/parameter_types.py
index 4a1dfdd..90d4c8f 100644
--- a/tempest/api_schema/response/compute/parameter_types.py
+++ b/tempest/api_schema/response/compute/parameter_types.py
@@ -65,3 +65,17 @@
}
}
}
+
+response_header = {
+ 'connection': {'type': 'string'},
+ 'content-length': {'type': 'string'},
+ 'content-type': {'type': 'string'},
+ 'status': {'type': 'string'},
+ 'x-compute-request-id': {'type': 'string'},
+ 'vary': {'type': 'string'},
+ 'x-openstack-nova-api-version': {'type': 'string'},
+ 'date': {
+ 'type': 'string',
+ 'format': 'data-time'
+ }
+}
diff --git a/tempest/api_schema/response/compute/servers.py b/tempest/api_schema/response/compute/servers.py
index f9c957b..3950173 100644
--- a/tempest/api_schema/response/compute/servers.py
+++ b/tempest/api_schema/response/compute/servers.py
@@ -71,6 +71,18 @@
},
'required': ['id', 'links']
},
+ 'fault': {
+ 'type': 'object',
+ 'properties': {
+ 'code': {'type': 'integer'},
+ 'created': {'type': 'string'},
+ 'message': {'type': 'string'},
+ 'details': {'type': 'string'},
+ },
+ # NOTE(gmann): 'details' is not necessary to be present
+ # in the 'fault'. So it is not defined as 'required'.
+ 'required': ['code', 'created', 'message']
+ },
'user_id': {'type': 'string'},
'tenant_id': {'type': 'string'},
'created': {'type': 'string'},
@@ -83,7 +95,9 @@
# NOTE(GMann): 'progress' attribute is present in the response
# only when server's status is one of the progress statuses
# ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE")
- # So it is not defined as 'required'.
+ # 'fault' attribute is present in the response
+ # only when server's status is one of the "ERROR", "DELETED".
+ # So they are not defined as 'required'.
'required': ['id', 'name', 'status', 'image', 'flavor',
'user_id', 'tenant_id', 'created', 'updated',
'metadata', 'links', 'addresses']
@@ -144,8 +158,11 @@
},
'required': ['id', 'links', 'name']
}
- }
+ },
+ 'servers_links': parameter_types.links
},
+ # NOTE(gmann): servers_links attribute is not necessary to be
+ # present always So it is not 'required'.
'required': ['servers']
}
}
diff --git a/tempest/api_schema/response/compute/v2/images.py b/tempest/api_schema/response/compute/v2/images.py
index 43dae38..3c0b80e 100644
--- a/tempest/api_schema/response/compute/v2/images.py
+++ b/tempest/api_schema/response/compute/v2/images.py
@@ -78,8 +78,11 @@
},
'required': ['id', 'links', 'name']
}
- }
+ },
+ 'images_links': parameter_types.links
},
+ # NOTE(gmann): images_links attribute is not necessary to be
+ # present always So it is not 'required'.
'required': ['images']
}
}
@@ -88,15 +91,16 @@
'status_code': [202],
'response_header': {
'type': 'object',
- 'properties': {
- 'location': {
- 'type': 'string',
- 'format': 'uri'
- }
- },
- 'required': ['location']
+ 'properties': parameter_types.response_header
}
}
+create_image['response_header']['properties'].update(
+ {'location': {
+ 'type': 'string',
+ 'format': 'uri'}
+ }
+)
+create_image['response_header']['required'] = ['location']
delete = {
'status_code': [204]
@@ -132,8 +136,11 @@
'images': {
'type': 'array',
'items': common_image_schema
- }
+ },
+ 'images_links': parameter_types.links
},
+ # NOTE(gmann): images_links attribute is not necessary to be
+ # present always So it is not 'required'.
'required': ['images']
}
}
diff --git a/tempest/api_schema/response/compute/v2/servers.py b/tempest/api_schema/response/compute/v2/servers.py
index c116bf5..ebee697 100644
--- a/tempest/api_schema/response/compute/v2/servers.py
+++ b/tempest/api_schema/response/compute/v2/servers.py
@@ -335,7 +335,11 @@
'items']['properties'].update({
'OS-EXT-IPS:type': {'type': 'string'},
'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address})
-
+# Defining 'servers_links' attributes for V2 server schema
+list_servers_detail['response_body'][
+ 'properties'].update({'servers_links': parameter_types.links})
+# NOTE(gmann): servers_links attribute is not necessary to be
+# present always So it is not 'required'.
rebuild_server = copy.deepcopy(update_server)
rebuild_server['status_code'] = [202]
diff --git a/tempest/cli/simple_read_only/network/__init__.py b/tempest/cli/simple_read_only/network/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/cli/simple_read_only/network/__init__.py
+++ /dev/null
diff --git a/tempest/cli/simple_read_only/network/test_neutron.py b/tempest/cli/simple_read_only/network/test_neutron.py
deleted file mode 100644
index e8b3554..0000000
--- a/tempest/cli/simple_read_only/network/test_neutron.py
+++ /dev/null
@@ -1,285 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import re
-
-from oslo_log import log as logging
-from tempest_lib import exceptions
-
-from tempest import cli
-from tempest import config
-from tempest import test
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-
-
-class SimpleReadOnlyNeutronClientTest(cli.ClientTestBase):
- """Basic, read-only tests for Neutron CLI client.
-
- Checks return values and output of read-only commands.
- These tests do not presume any content, nor do they create
- their own. They only verify the structure of output if present.
- """
-
- @classmethod
- def resource_setup(cls):
- if (not CONF.service_available.neutron):
- msg = "Skipping all Neutron cli tests because it is not available"
- raise cls.skipException(msg)
- super(SimpleReadOnlyNeutronClientTest, cls).resource_setup()
-
- def neutron(self, *args, **kwargs):
- return self.clients.neutron(*args,
- endpoint_type=CONF.network.endpoint_type,
- **kwargs)
-
- @test.attr(type='smoke')
- @test.idempotent_id('84dd7190-2b98-4709-8e2c-3c1d25b9e7d2')
- def test_neutron_fake_action(self):
- self.assertRaises(exceptions.CommandFailed,
- self.neutron,
- 'this-does-not-exist')
-
- @test.attr(type='smoke')
- @test.idempotent_id('c598c337-313a-45ac-bf27-d6b4124a9e5b')
- def test_neutron_net_list(self):
- net_list = self.parser.listing(self.neutron('net-list'))
- self.assertTableStruct(net_list, ['id', 'name', 'subnets'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('3e172b04-2e3b-4fcf-922d-99d5c803779f')
- def test_neutron_ext_list(self):
- ext = self.parser.listing(self.neutron('ext-list'))
- self.assertTableStruct(ext, ['alias', 'name'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('2e0de814-52d6-4f81-be17-fe327072fc23')
- @test.requires_ext(extension='dhcp_agent_scheduler', service='network')
- def test_neutron_dhcp_agent_list_hosting_net(self):
- self.neutron('dhcp-agent-list-hosting-net',
- params=CONF.compute.fixed_network_name)
-
- @test.attr(type='smoke')
- @test.idempotent_id('8524a24a-3895-40a5-8c9d-49d4459cdda4')
- @test.requires_ext(extension='agent', service='network')
- def test_neutron_agent_list(self):
- agents = self.parser.listing(self.neutron('agent-list'))
- field_names = ['id', 'agent_type', 'host', 'alive', 'admin_state_up']
- self.assertTableStruct(agents, field_names)
-
- @test.attr(type='smoke')
- @test.idempotent_id('97c3ef92-7303-45f1-80db-b6622f176782')
- @test.requires_ext(extension='router', service='network')
- def test_neutron_floatingip_list(self):
- self.neutron('floatingip-list')
-
- @test.attr(type='smoke')
- @test.idempotent_id('823e0fee-404c-49a7-8bf3-d2f0383cc649')
- @test.requires_ext(extension='metering', service='network')
- def test_neutron_meter_label_list(self):
- self.neutron('meter-label-list')
-
- @test.attr(type='smoke')
- @test.idempotent_id('7fb76098-01f6-417f-b9c7-e630ba3f394b')
- @test.requires_ext(extension='metering', service='network')
- def test_neutron_meter_label_rule_list(self):
- self.neutron('meter-label-rule-list')
-
- @test.requires_ext(extension='lbaas_agent_scheduler', service='network')
- def _test_neutron_lbaas_command(self, command):
- try:
- self.neutron(command)
- except exceptions.CommandFailed as e:
- if '404 Not Found' not in e.stderr:
- self.fail('%s: Unexpected failure.' % command)
-
- @test.attr(type='smoke')
- @test.idempotent_id('396d1d87-fd0c-4716-9ff0-f1baa54c6c61')
- def test_neutron_lb_healthmonitor_list(self):
- self._test_neutron_lbaas_command('lb-healthmonitor-list')
-
- @test.attr(type='smoke')
- @test.idempotent_id('f41fa54d-5cd8-4f2c-bb4e-13abc72dccb6')
- def test_neutron_lb_member_list(self):
- self._test_neutron_lbaas_command('lb-member-list')
-
- @test.attr(type='smoke')
- @test.idempotent_id('3ec04885-7573-4cce-b086-5722c0b00d85')
- def test_neutron_lb_pool_list(self):
- self._test_neutron_lbaas_command('lb-pool-list')
-
- @test.attr(type='smoke')
- @test.idempotent_id('1ab530e0-ec87-498f-baf2-85f6635a2ad9')
- def test_neutron_lb_vip_list(self):
- self._test_neutron_lbaas_command('lb-vip-list')
-
- @test.attr(type='smoke')
- @test.idempotent_id('e92f7362-4009-4b37-afee-f469105b24e7')
- @test.requires_ext(extension='external-net', service='network')
- def test_neutron_net_external_list(self):
- net_ext_list = self.parser.listing(self.neutron('net-external-list'))
- self.assertTableStruct(net_ext_list, ['id', 'name', 'subnets'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('ed840980-7c84-4b6e-b280-f13c5848a0e9')
- def test_neutron_port_list(self):
- port_list = self.parser.listing(self.neutron('port-list'))
- self.assertTableStruct(port_list, ['id', 'name', 'mac_address',
- 'fixed_ips'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('dded0dfa-f2ac-4c1f-bc90-69fd06dd7132')
- @test.requires_ext(extension='quotas', service='network')
- def test_neutron_quota_list(self):
- self.neutron('quota-list')
-
- @test.attr(type='smoke')
- @test.idempotent_id('927fca1e-4397-42a2-ba47-d738299466de')
- @test.requires_ext(extension='router', service='network')
- def test_neutron_router_list(self):
- router_list = self.parser.listing(self.neutron('router-list'))
- self.assertTableStruct(router_list, ['id', 'name',
- 'external_gateway_info'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('e2e3d2d5-1aee-499d-84d9-37382dcf26ff')
- @test.requires_ext(extension='security-group', service='network')
- def test_neutron_security_group_list(self):
- security_grp = self.parser.listing(self.neutron('security-group-list'))
- self.assertTableStruct(security_grp, ['id', 'name', 'description'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('288602c2-8b59-44cd-8c5d-1ec916a114d3')
- @test.requires_ext(extension='security-group', service='network')
- def test_neutron_security_group_rule_list(self):
- security_grp = self.parser.listing(self.neutron
- ('security-group-rule-list'))
- self.assertTableStruct(security_grp, ['id', 'security_group',
- 'direction', 'protocol',
- 'remote_ip_prefix',
- 'remote_group'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('2a874a08-b9c9-4f0f-82ef-8cadb15bbd5d')
- def test_neutron_subnet_list(self):
- subnet_list = self.parser.listing(self.neutron('subnet-list'))
- self.assertTableStruct(subnet_list, ['id', 'name', 'cidr',
- 'allocation_pools'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('048e1ec3-cf6c-4066-b262-2028e03ce825')
- @test.requires_ext(extension='vpnaas', service='network')
- def test_neutron_vpn_ikepolicy_list(self):
- ikepolicy = self.parser.listing(self.neutron('vpn-ikepolicy-list'))
- self.assertTableStruct(ikepolicy, ['id', 'name',
- 'auth_algorithm',
- 'encryption_algorithm',
- 'ike_version', 'pfs'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('bb8902b7-b2e6-49fd-b9bd-a26dd99732df')
- @test.requires_ext(extension='vpnaas', service='network')
- def test_neutron_vpn_ipsecpolicy_list(self):
- ipsecpolicy = self.parser.listing(self.neutron('vpn-ipsecpolicy-list'))
- self.assertTableStruct(ipsecpolicy, ['id', 'name',
- 'auth_algorithm',
- 'encryption_algorithm',
- 'pfs'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('c0f33f9a-0ba9-4177-bcd5-dce34b81d523')
- @test.requires_ext(extension='vpnaas', service='network')
- def test_neutron_vpn_service_list(self):
- vpn_list = self.parser.listing(self.neutron('vpn-service-list'))
- self.assertTableStruct(vpn_list, ['id', 'name',
- 'router_id', 'status'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('bb142f8a-e568-405f-b1b7-4cb458de7971')
- @test.requires_ext(extension='vpnaas', service='network')
- def test_neutron_ipsec_site_connection_list(self):
- ipsec_site = self.parser.listing(self.neutron
- ('ipsec-site-connection-list'))
- self.assertTableStruct(ipsec_site, ['id', 'name',
- 'peer_address',
- 'peer_cidrs',
- 'route_mode',
- 'auth_mode', 'status'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('89baff14-8cb7-4ad8-9c24-b0278711170b')
- @test.requires_ext(extension='fwaas', service='network')
- def test_neutron_firewall_list(self):
- firewall_list = self.parser.listing(self.neutron
- ('firewall-list'))
- self.assertTableStruct(firewall_list, ['id', 'name',
- 'firewall_policy_id'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('996e418a-2a51-4018-9602-478ca8053e61')
- @test.requires_ext(extension='fwaas', service='network')
- def test_neutron_firewall_policy_list(self):
- firewall_policy = self.parser.listing(self.neutron
- ('firewall-policy-list'))
- self.assertTableStruct(firewall_policy, ['id', 'name',
- 'firewall_rules'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('d4638dd6-98d4-4400-a920-26572de1a6fc')
- @test.requires_ext(extension='fwaas', service='network')
- def test_neutron_firewall_rule_list(self):
- firewall_rule = self.parser.listing(self.neutron
- ('firewall-rule-list'))
- self.assertTableStruct(firewall_rule, ['id', 'name',
- 'firewall_policy_id',
- 'summary', 'enabled'])
-
- @test.attr(type='smoke')
- @test.idempotent_id('1c4551e1-e3f3-4af2-8a40-c3f551e4a536')
- def test_neutron_help(self):
- help_text = self.neutron('help')
- lines = help_text.split('\n')
- self.assertFirstLineStartsWith(lines, 'usage: neutron')
-
- commands = []
- cmds_start = lines.index('Commands for API v2.0:')
- command_pattern = re.compile('^ {2}([a-z0-9\-\_]+)')
- for line in lines[cmds_start:]:
- match = command_pattern.match(line)
- if match:
- commands.append(match.group(1))
- commands = set(commands)
- wanted_commands = set(('net-create', 'subnet-list', 'port-delete',
- 'router-show', 'agent-update', 'help'))
- self.assertFalse(wanted_commands - commands)
-
- # Optional arguments:
-
- @test.attr(type='smoke')
- @test.idempotent_id('381e6fe3-cddc-47c9-a773-70ddb2f79a91')
- def test_neutron_version(self):
- self.neutron('', flags='--version')
-
- @test.attr(type='smoke')
- @test.idempotent_id('bcad0e07-da8c-4c7c-8ab6-499e5d7ab8cb')
- def test_neutron_debug_net_list(self):
- self.neutron('net-list', flags='--debug')
-
- @test.attr(type='smoke')
- @test.idempotent_id('3e42d78e-65e5-4e8f-8c29-ca7be8feebb4')
- def test_neutron_quiet_net_list(self):
- self.neutron('net-list', flags='--quiet')
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 0735eeb..ab23dea 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -118,6 +118,7 @@
import tempest.auth
from tempest import config
from tempest.services.compute.json import flavors_client
+from tempest.services.compute.json import floating_ips_client
from tempest.services.compute.json import security_groups_client
from tempest.services.compute.json import servers_client
from tempest.services.identity.v2.json import identity_client
@@ -194,6 +195,8 @@
**compute_params)
self.flavors = flavors_client.FlavorsClientJSON(_auth,
**compute_params)
+ self.floating_ips = floating_ips_client.FloatingIPsClientJSON(
+ _auth, **compute_params)
self.secgroups = security_groups_client.SecurityGroupsClientJSON(
_auth, **compute_params)
self.objects = object_client.ObjectClient(_auth,
@@ -451,15 +454,31 @@
# validate neutron is enabled and ironic disabled:
if (CONF.service_available.neutron and
not CONF.baremetal.driver_enabled):
+ _floating_is_alive = False
for network_name, body in found['addresses'].items():
for addr in body:
ip = addr['addr']
- if addr.get('OS-EXT-IPS:type', 'fixed') == 'fixed':
+ # If floatingip_for_ssh is at True, it's assumed
+ # you want to use the floating IP to reach the server,
+ # fallback to fixed IP, then other type.
+ # This is useful in multi-node environment.
+ if CONF.compute.use_floatingip_for_ssh:
+ if addr.get('OS-EXT-IPS:type',
+ 'floating') == 'floating':
+ self._ping_ip(ip, 60)
+ _floating_is_alive = True
+ elif addr.get('OS-EXT-IPS:type', 'fixed') == 'fixed':
namespace = _get_router_namespace(client,
network_name)
self._ping_ip(ip, 60, namespace)
else:
self._ping_ip(ip, 60)
+ # if floatingip_for_ssh is at True, validate found a
+ # floating IP and ping worked.
+ if CONF.compute.use_floatingip_for_ssh:
+ self.assertTrue(_floating_is_alive,
+ "Server %s has no floating IP." %
+ server['name'])
else:
addr = found['addresses']['private'][0]['addr']
self._ping_ip(addr, 60)
@@ -838,6 +857,10 @@
# create to security group(s) after server spawning
for secgroup in server['secgroups']:
client.servers.add_security_group(server_id, secgroup)
+ if CONF.compute.use_floatingip_for_ssh:
+ floating_ip = client.floating_ips.create_floating_ip()
+ client.floating_ips.associate_floating_ip_to_server(
+ floating_ip['ip'], server_id)
def destroy_servers(servers):
@@ -847,13 +870,32 @@
for server in servers:
client = client_for_user(server['owner'])
- response = _get_server_by_name(client, server['name'])
- if not response:
+ res = _get_server_by_name(client, server['name'])
+ if not res:
LOG.info("Server '%s' does not exist" % server['name'])
continue
+ res = client.servers.get_server(res['id'])
- client.servers.delete_server(response['id'])
- client.servers.wait_for_server_termination(response['id'],
+ # we iterate all interfaces until we find a floating IP
+ # and stop looping after dropping it.
+ def _find_first_floating():
+ if (CONF.service_available.neutron and
+ not CONF.baremetal.driver_enabled and
+ CONF.compute.use_floatingip_for_ssh):
+ for network_name, body in res['addresses'].items():
+ for addr in body:
+ ip = addr['addr']
+ if addr.get('OS-EXT-IPS:type',
+ 'floating') == 'floating':
+ (client.floating_ips.
+ disassociate_floating_ip_from_server(
+ ip, res['id']))
+ client.floating_ips.delete_floating_ip(ip)
+ return
+
+ _find_first_floating()
+ client.servers.delete_server(res['id'])
+ client.servers.wait_for_server_termination(res['id'],
ignore_error=True)
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index 4d66ffc..bff9a0a 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -53,7 +53,7 @@
if identity_version == 'v3':
conf_attributes.append('domain_name')
# Read the parts of credentials from config
- params = DEFAULT_PARAMS
+ params = DEFAULT_PARAMS.copy()
section, prefix = CREDENTIAL_TYPES[credential_type]
for attr in conf_attributes:
_section = getattr(CONF, section)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 7a60403..af7b683 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -393,6 +393,8 @@
"floating ip")
@test.idempotent_id('1546850e-fbaa-42f5-8b5f-03d8a6a95f15')
+ @testtools.skipIf(CONF.baremetal.driver_enabled,
+ 'Baremetal relies on a shared physical network.')
@test.attr(type='smoke')
@test.services('compute', 'network')
def test_connectivity_between_vms_on_different_networks(self):