Merge "Forbid admin_password None in rescue Nova API"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 7c604be..bb9a68e 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -427,7 +427,7 @@
# (string value)
#alt_password=<None>
-# Administrative Username to use forKeystone API requests.
+# Administrative Username to use for Keystone API requests.
# (string value)
#admin_username=admin
@@ -439,6 +439,17 @@
#admin_password=pass
+[identity-feature-enabled]
+
+#
+# Options defined in tempest.config
+#
+
+# Does the identity service have delegation and impersonation
+# enabled (boolean value)
+#trust=true
+
+
[image]
#
diff --git a/etc/whitelist.yaml b/etc/whitelist.yaml
index a8c5276..1c12b6c 100644
--- a/etc/whitelist.yaml
+++ b/etc/whitelist.yaml
@@ -39,6 +39,8 @@
message: "Instance failed network setup after 1 attempt"
- module: "nova.compute.manager"
message: "Periodic sync_power_state task had an error"
+ - module: "nova.virt.driver"
+ message: "Info cache for instance .* could not be found"
g-api:
- module: "glance.store.sheepdog"
@@ -73,6 +75,10 @@
- module: "ceilometer.compute.pollsters.disk"
message: ".*"
+ceilometer-acentral:
+ - module: "ceilometer.central.manager"
+ message: "403 Forbidden"
+
ceilometer-alarm-evaluator:
- module: "ceilometer.alarm.service"
message: "alarm evaluation cycle failed"
diff --git a/run_tests.sh b/run_tests.sh
index 285b372..3f00453 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -126,7 +126,7 @@
exit
fi
-if [$coverage -eq 1] ; then
+if [ $coverage -eq 1 ]; then
$testrargs = "--coverage $testrargs"
fi
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index dbf7967..a1afe0e 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -66,7 +66,9 @@
self.assertRaises(exceptions.Unauthorized,
self.non_admin_client.update_host,
- hostname)
+ hostname,
+ status='enable',
+ maintenance_mode='enable')
@test.skip_because(bug="1261964", interface="xml")
@test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 311e158..5f13c09 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -169,6 +169,8 @@
@classmethod
def setUpClass(cls):
+ # By default compute tests do not create network resources
+ cls.set_network_resources()
super(BaseV2ComputeTest, cls).setUpClass()
cls.servers_client = cls.os.servers_client
cls.flavors_client = cls.os.flavors_client
@@ -274,6 +276,8 @@
cls.extensions_client = cls.os.extensions_v3_client
cls.availability_zone_client = cls.os.availability_zone_v3_client
cls.interfaces_client = cls.os.interfaces_v3_client
+ cls.instance_usages_audit_log_client = \
+ cls.os.instance_usages_audit_log_v3_client
cls.hypervisor_client = cls.os.hypervisor_v3_client
cls.keypairs_client = cls.os.keypairs_v3_client
cls.tenant_usages_client = cls.os.tenant_usages_v3_client
@@ -342,6 +346,8 @@
cls.os_adm = os_adm
cls.servers_admin_client = cls.os_adm.servers_v3_client
+ cls.instance_usages_audit_log_admin_client = \
+ cls.os_adm.instance_usages_audit_log_v3_client
cls.services_admin_client = cls.os_adm.services_v3_client
cls.availability_zone_admin_client = \
cls.os_adm.availability_zone_v3_client
diff --git a/tempest/api/compute/floating_ips/base.py b/tempest/api/compute/floating_ips/base.py
new file mode 100644
index 0000000..e2c9b04
--- /dev/null
+++ b/tempest/api/compute/floating_ips/base.py
@@ -0,0 +1,28 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2014 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.
+
+from tempest.api.compute import base
+
+
+class BaseFloatingIPsTest(base.BaseV2ComputeTest):
+
+ @classmethod
+ def setUpClass(cls):
+ # Floating IP actions might need a full network configuration
+ cls.set_network_resources(network=True, subnet=True,
+ router=True, dhcp=True)
+ super(BaseFloatingIPsTest, cls).setUpClass()
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index 32e7b39..cd5f4a8 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -15,13 +15,13 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api.compute import base
+from tempest.api.compute.floating_ips import base
from tempest.common.utils.data_utils import rand_name
from tempest import exceptions
from tempest.test import attr
-class FloatingIPsTestJSON(base.BaseV2ComputeTest):
+class FloatingIPsTestJSON(base.BaseFloatingIPsTest):
_interface = 'json'
server_id = None
floating_ip = None
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
index 89315bb..674669c 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -17,13 +17,13 @@
import uuid
-from tempest.api.compute import base
+from tempest.api.compute.floating_ips import base
from tempest.common.utils import data_utils
from tempest import exceptions
from tempest.test import attr
-class FloatingIPsNegativeTestJSON(base.BaseV2ComputeTest):
+class FloatingIPsNegativeTestJSON(base.BaseFloatingIPsTest):
_interface = 'json'
server_id = None
diff --git a/tempest/api/compute/security_groups/base.py b/tempest/api/compute/security_groups/base.py
new file mode 100644
index 0000000..66f2600
--- /dev/null
+++ b/tempest/api/compute/security_groups/base.py
@@ -0,0 +1,27 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.
+
+from tempest.api.compute import base
+
+
+class BaseSecurityGroupsTest(base.BaseV2ComputeTest):
+
+ @classmethod
+ def setUpClass(cls):
+ # A network and a subnet will be created for these tests
+ cls.set_network_resources(network=True, subnet=True)
+ super(BaseSecurityGroupsTest, cls).setUpClass()
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 2ccc3a8..eddccc1 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -15,12 +15,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api.compute import base
+from tempest.api.compute.security_groups import base
from tempest.common.utils import data_utils
from tempest.test import attr
-class SecurityGroupRulesTestJSON(base.BaseV2ComputeTest):
+class SecurityGroupRulesTestJSON(base.BaseSecurityGroupsTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index c0b202d..bec95ad 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -17,7 +17,7 @@
import testtools
-from tempest.api.compute import base
+from tempest.api.compute.security_groups import base
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
@@ -27,7 +27,7 @@
CONF = config.CONF
-class SecurityGroupRulesNegativeTestJSON(base.BaseV2ComputeTest):
+class SecurityGroupRulesNegativeTestJSON(base.BaseSecurityGroupsTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 4ae65be..ffd9fd2 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -15,13 +15,13 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api.compute import base
+from tempest.api.compute.security_groups import base
from tempest.common.utils import data_utils
from tempest import exceptions
from tempest import test
-class SecurityGroupsTestJSON(base.BaseV2ComputeTest):
+class SecurityGroupsTestJSON(base.BaseSecurityGroupsTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index 6a8e604..cf78089 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -17,7 +17,7 @@
import testtools
-from tempest.api.compute import base
+from tempest.api.compute.security_groups import base
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
@@ -26,7 +26,7 @@
CONF = config.CONF
-class SecurityGroupsNegativeTestJSON(base.BaseV2ComputeTest):
+class SecurityGroupsNegativeTestJSON(base.BaseSecurityGroupsTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index dbb7d75..738e4a8 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -26,6 +26,8 @@
def setUpClass(cls):
if not cls.config.service_available.neutron:
raise cls.skipException("Neutron is required")
+ # This test class requires network and subnet
+ cls.set_network_resources(network=True, subnet=True)
super(AttachInterfacesTestJSON, cls).setUpClass()
cls.client = cls.os.interfaces_client
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 5d62e1b..e45161b 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -109,6 +109,104 @@
self.assertTrue(linux_client.hostname_equals_servername(self.name))
+class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest):
+ _interface = 'json'
+ run_ssh = CONF.compute.run_ssh
+ disk_config = 'AUTO'
+
+ @classmethod
+ def setUpClass(cls):
+ super(ServersWithSpecificFlavorTestJSON, cls).setUpClass()
+ cls.meta = {'hello': 'world'}
+ cls.accessIPv4 = '1.1.1.1'
+ cls.accessIPv6 = '0000:0000:0000:0000:0000:babe:220.12.22.2'
+ cls.name = data_utils.rand_name('server')
+ file_contents = 'This is a test file.'
+ personality = [{'path': '/test.txt',
+ 'contents': base64.b64encode(file_contents)}]
+ cls.client = cls.servers_client
+ cls.flavor_client = cls.os_adm.flavors_client
+ cli_resp = cls.create_test_server(name=cls.name,
+ meta=cls.meta,
+ accessIPv4=cls.accessIPv4,
+ accessIPv6=cls.accessIPv6,
+ personality=personality,
+ disk_config=cls.disk_config)
+ cls.resp, cls.server_initial = cli_resp
+ cls.password = cls.server_initial['adminPass']
+ cls.client.wait_for_server_status(cls.server_initial['id'], 'ACTIVE')
+ resp, cls.server = cls.client.get_server(cls.server_initial['id'])
+
+ @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+ @attr(type='gate')
+ def test_verify_created_server_ephemeral_disk(self):
+ # Verify that the ephemeral disk is created when creating server
+
+ def create_flavor_with_extra_specs(self):
+ flavor_with_eph_disk_name = data_utils.rand_name('eph_flavor')
+ flavor_with_eph_disk_id = data_utils.rand_int_id(start=1000)
+ ram = 64
+ vcpus = 1
+ disk = 0
+
+ # Create a flavor with extra specs
+ resp, flavor = (self.flavor_client.
+ create_flavor(flavor_with_eph_disk_name,
+ ram, vcpus, disk,
+ flavor_with_eph_disk_id,
+ ephemeral=1))
+ self.addCleanup(self.flavor_clean_up, flavor['id'])
+ self.assertEqual(200, resp.status)
+
+ return flavor['id']
+
+ def create_flavor_without_extra_specs(self):
+ flavor_no_eph_disk_name = data_utils.rand_name('no_eph_flavor')
+ flavor_no_eph_disk_id = data_utils.rand_int_id(start=1000)
+
+ ram = 64
+ vcpus = 1
+ disk = 0
+
+ # Create a flavor without extra specs
+ resp, flavor = (self.flavor_client.
+ create_flavor(flavor_no_eph_disk_name,
+ ram, vcpus, disk,
+ flavor_no_eph_disk_id))
+ self.addCleanup(self.flavor_clean_up, flavor['id'])
+ self.assertEqual(200, resp.status)
+
+ return flavor['id']
+
+ def flavor_clean_up(self, flavor_id):
+ resp, body = self.flavor_client.delete_flavor(flavor_id)
+ self.assertEqual(resp.status, 202)
+ self.flavor_client.wait_for_resource_deletion(flavor_id)
+
+ flavor_with_eph_disk_id = self.create_flavor_with_extra_specs()
+ flavor_no_eph_disk_id = self.create_flavor_without_extra_specs()
+
+ admin_pass = self.image_ssh_password
+
+ resp, server_no_eph_disk = (self.
+ create_test_server(
+ wait_until='ACTIVE',
+ adminPass=admin_pass,
+ flavor=flavor_no_eph_disk_id))
+ resp, server_with_eph_disk = (self.create_test_server(
+ wait_until='ACTIVE',
+ adminPass=admin_pass,
+ flavor=flavor_with_eph_disk_id))
+ # Get partition number of server without extra specs.
+ linux_client = RemoteClient(server_no_eph_disk,
+ self.ssh_user, self.password)
+ partition_num = len(linux_client.get_partitions())
+
+ linux_client = RemoteClient(server_with_eph_disk,
+ self.ssh_user, self.password)
+ self.assertEqual(partition_num + 1, linux_client.get_partitions())
+
+
class ServersTestManualDisk(ServersTestJSON):
disk_config = 'MANUAL'
@@ -122,3 +220,7 @@
class ServersTestXML(ServersTestJSON):
_interface = 'xml'
+
+
+class ServersWithSpecificFlavorTestXML(ServersWithSpecificFlavorTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index f195562..e4af2e1 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -174,7 +174,7 @@
def _detect_server_image_flavor(self, server_id):
# Detects the current server image flavor ref.
- resp, server = self.client.get_server(self.server_id)
+ resp, server = self.client.get_server(server_id)
current_flavor = server['flavor']['id']
new_flavor_ref = self.flavor_ref_alt \
if current_flavor == self.flavor_ref else self.flavor_ref
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 1e55afb..39d9580 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -24,6 +24,8 @@
@classmethod
def setUpClass(cls):
+ # This test module might use a network and a subnet
+ cls.set_network_resources(network=True, subnet=True)
super(ServerAddressesTestJSON, cls).setUpClass()
cls.client = cls.servers_client
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index 30aa7d1..0343538 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -25,6 +25,7 @@
@classmethod
def setUpClass(cls):
+ cls.set_network_resources(network=True, subnet=True)
super(ServerAddressesNegativeTestJSON, cls).setUpClass()
cls.client = cls.servers_client
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 968ae47..7bbe30b 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -29,6 +29,8 @@
@classmethod
def setUpClass(cls):
+ # This test needs a network and a subnet
+ cls.set_network_resources(network=True, subnet=True)
super(VirtualInterfacesTestJSON, cls).setUpClass()
cls.client = cls.servers_client
resp, server = cls.create_test_server(wait_until='ACTIVE')
diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
index a2a6c11..d67e13a 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -27,6 +27,8 @@
@classmethod
def setUpClass(cls):
+ # For this test no network resources are needed
+ cls.set_network_resources()
super(VirtualInterfacesNegativeTestJSON, cls).setUpClass()
cls.client = cls.servers_client
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 327c7d1..03075df 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -30,6 +30,8 @@
@classmethod
def setUpClass(cls):
+ # No network resources required for this test
+ cls.set_network_resources()
super(AuthorizationTestJSON, cls).setUpClass()
if not cls.multi_user:
msg = "Need >1 user"
diff --git a/tempest/api/compute/v3/admin/test_hosts_negative.py b/tempest/api/compute/v3/admin/test_hosts_negative.py
index 755fa2b..598a1d3 100644
--- a/tempest/api/compute/v3/admin/test_hosts_negative.py
+++ b/tempest/api/compute/v3/admin/test_hosts_negative.py
@@ -66,7 +66,9 @@
self.assertRaises(exceptions.Unauthorized,
self.non_admin_client.update_host,
- hostname)
+ hostname,
+ status='enable',
+ maintenance_mode='enable')
@test.attr(type=['negative', 'gate'])
def test_update_host_with_extra_param(self):
diff --git a/tempest/api/compute/v3/admin/test_instance_usage_audit_log.py b/tempest/api/compute/v3/admin/test_instance_usage_audit_log.py
index cea6e92..d0cfc63 100644
--- a/tempest/api/compute/v3/admin/test_instance_usage_audit_log.py
+++ b/tempest/api/compute/v3/admin/test_instance_usage_audit_log.py
@@ -16,22 +16,22 @@
# under the License.
import datetime
-
-from tempest.api.compute import base
-from tempest.test import attr
import urllib
+from tempest.api.compute import base
+from tempest import test
-class InstanceUsageAuditLogTestJSON(base.BaseV2ComputeAdminTest):
+
+class InstanceUsageAuditLogV3TestJSON(base.BaseV3ComputeAdminTest):
_interface = 'json'
@classmethod
def setUpClass(cls):
- super(InstanceUsageAuditLogTestJSON, cls).setUpClass()
- cls.adm_client = cls.os_adm.instance_usages_audit_log_client
+ super(InstanceUsageAuditLogV3TestJSON, cls).setUpClass()
+ cls.adm_client = cls.instance_usages_audit_log_admin_client
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_instance_usage_audit_logs(self):
# list instance usage audit logs
resp, body = self.adm_client.list_instance_usage_audit_logs()
@@ -44,12 +44,12 @@
for item in expected_items:
self.assertIn(item, body)
- @attr(type='gate')
- def test_get_instance_usage_audit_log(self):
+ @test.attr(type='gate')
+ def test_list_instance_usage_audit_logs_with_filter_before(self):
# Get instance usage audit log before specified time
- now = datetime.datetime.now()
- resp, body = self.adm_client.get_instance_usage_audit_log(
- urllib.quote(now.strftime("%Y-%m-%d %H:%M:%S")))
+ ending_time = datetime.datetime(2012, 12, 24)
+ resp, body = self.adm_client.list_instance_usage_audit_logs(
+ urllib.quote(ending_time.strftime("%Y-%m-%d %H:%M:%S")))
self.assertEqual(200, resp.status)
expected_items = ['total_errors', 'total_instances', 'log',
@@ -58,7 +58,8 @@
'period_beginning', 'num_hosts_not_run']
for item in expected_items:
self.assertIn(item, body)
+ self.assertEqual(body['period_ending'], "2012-12-23 23:00:00")
-class InstanceUsageAuditLogTestXML(InstanceUsageAuditLogTestJSON):
+class InstanceUsageAuditLogV3TestXML(InstanceUsageAuditLogV3TestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/v3/admin/test_instance_usage_audit_log_negative.py
index dcf41c5..6e919c9 100644
--- a/tempest/api/compute/v3/admin/test_instance_usage_audit_log_negative.py
+++ b/tempest/api/compute/v3/admin/test_instance_usage_audit_log_negative.py
@@ -15,42 +15,34 @@
# License for the specific language governing permissions and limitations
# under the License.
-import datetime
-
from tempest.api.compute import base
from tempest import exceptions
-from tempest.test import attr
-import urllib
+from tempest import test
-class InstanceUsageAuditLogNegativeTestJSON(base.BaseV2ComputeAdminTest):
+class InstanceUsageLogNegativeV3TestJSON(base.BaseV3ComputeAdminTest):
_interface = 'json'
@classmethod
def setUpClass(cls):
- super(InstanceUsageAuditLogNegativeTestJSON, cls).setUpClass()
- cls.adm_client = cls.os_adm.instance_usages_audit_log_client
+ super(InstanceUsageLogNegativeV3TestJSON, cls).setUpClass()
+ cls.adm_client = cls.instance_usages_audit_log_admin_client
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_instance_usage_audit_logs_with_nonadmin_user(self):
# the instance_usage_audit_logs API just can be accessed by admin user
self.assertRaises(exceptions.Unauthorized,
self.instance_usages_audit_log_client.
list_instance_usage_audit_logs)
- now = datetime.datetime.now()
- self.assertRaises(exceptions.Unauthorized,
- self.instance_usages_audit_log_client.
- get_instance_usage_audit_log,
- urllib.quote(now.strftime("%Y-%m-%d %H:%M:%S")))
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_get_instance_usage_audit_logs_with_invalid_time(self):
self.assertRaises(exceptions.BadRequest,
- self.adm_client.get_instance_usage_audit_log,
+ self.adm_client.list_instance_usage_audit_logs,
"invalid_time")
-class InstanceUsageAuditLogNegativeTestXML(
- InstanceUsageAuditLogNegativeTestJSON):
+class InstanceUsageLogNegativeV3TestXML(
+ InstanceUsageLogNegativeV3TestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_create_server.py b/tempest/api/compute/v3/servers/test_create_server.py
index e1bb160..1555442 100644
--- a/tempest/api/compute/v3/servers/test_create_server.py
+++ b/tempest/api/compute/v3/servers/test_create_server.py
@@ -117,6 +117,104 @@
self.assertTrue(linux_client.hostname_equals_servername(self.name))
+class ServersWithSpecificFlavorV3TestJSON(base.BaseV3ComputeAdminTest):
+ _interface = 'json'
+ run_ssh = CONF.compute.run_ssh
+ disk_config = 'AUTO'
+
+ @classmethod
+ def setUpClass(cls):
+ super(ServersWithSpecificFlavorV3TestJSON, cls).setUpClass()
+ cls.meta = {'hello': 'world'}
+ cls.accessIPv4 = '1.1.1.1'
+ cls.accessIPv6 = '0000:0000:0000:0000:0000:babe:220.12.22.2'
+ cls.name = data_utils.rand_name('server')
+ file_contents = 'This is a test file.'
+ personality = [{'path': '/test.txt',
+ 'contents': base64.b64encode(file_contents)}]
+ cls.client = cls.servers_client
+ cls.flavor_client = cls.flavors_admin_client
+ cli_resp = cls.create_test_server(name=cls.name,
+ meta=cls.meta,
+ access_ip_v4=cls.accessIPv4,
+ access_ip_v6=cls.accessIPv6,
+ personality=personality,
+ disk_config=cls.disk_config)
+ cls.resp, cls.server_initial = cli_resp
+ cls.password = cls.server_initial['admin_password']
+ cls.client.wait_for_server_status(cls.server_initial['id'], 'ACTIVE')
+ resp, cls.server = cls.client.get_server(cls.server_initial['id'])
+
+ @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+ @test.attr(type='gate')
+ def test_verify_created_server_ephemeral_disk(self):
+ # Verify that the ephemeral disk is created when creating server
+
+ def create_flavor_with_extra_specs(self):
+ flavor_with_eph_disk_name = data_utils.rand_name('eph_flavor')
+ flavor_with_eph_disk_id = data_utils.rand_int_id(start=1000)
+ ram = 512
+ vcpus = 1
+ disk = 10
+
+ # Create a flavor with extra specs
+ resp, flavor = (self.flavor_client.
+ create_flavor(flavor_with_eph_disk_name,
+ ram, vcpus, disk,
+ flavor_with_eph_disk_id,
+ ephemeral=1, swap=1024, rxtx=1))
+ self.addCleanup(self.flavor_clean_up, flavor['id'])
+ self.assertEqual(200, resp.status)
+
+ return flavor['id']
+
+ def create_flavor_without_extra_specs(self):
+ flavor_no_eph_disk_name = data_utils.rand_name('no_eph_flavor')
+ flavor_no_eph_disk_id = data_utils.rand_int_id(start=1000)
+
+ ram = 512
+ vcpus = 1
+ disk = 10
+
+ # Create a flavor without extra specs
+ resp, flavor = (self.flavor_client.
+ create_flavor(flavor_no_eph_disk_name,
+ ram, vcpus, disk,
+ flavor_no_eph_disk_id))
+ self.addCleanup(self.flavor_clean_up, flavor['id'])
+ self.assertEqual(200, resp.status)
+
+ return flavor['id']
+
+ def flavor_clean_up(self, flavor_id):
+ resp, body = self.flavor_client.delete_flavor(flavor_id)
+ self.assertEqual(resp.status, 202)
+ self.flavor_client.wait_for_resource_deletion(flavor_id)
+
+ flavor_with_eph_disk_id = self.create_flavor_with_extra_specs()
+ flavor_no_eph_disk_id = self.create_flavor_without_extra_specs()
+
+ admin_pass = self.image_ssh_password
+
+ resp, server_no_eph_disk = (self.
+ create_test_server(
+ wait_until='ACTIVE',
+ adminPass=admin_pass,
+ flavor=flavor_no_eph_disk_id))
+ resp, server_with_eph_disk = (self.create_test_server(
+ wait_until='ACTIVE',
+ adminPass=admin_pass,
+ flavor=flavor_with_eph_disk_id))
+ # Get partition number of server without extra specs.
+ linux_client = RemoteClient(server_no_eph_disk,
+ self.ssh_user, self.password)
+ partition_num = len(linux_client.get_partitions())
+
+ linux_client = RemoteClient(server_with_eph_disk,
+ self.ssh_user, self.password)
+ self.assertEqual(partition_num + 1, linux_client.get_partitions())
+
+
class ServersV3TestManualDisk(ServersV3TestJSON):
disk_config = 'MANUAL'
@@ -130,3 +228,7 @@
class ServersV3TestXML(ServersV3TestJSON):
_interface = 'xml'
+
+
+class ServersWithSpecificFlavorV3TestXML(ServersWithSpecificFlavorV3TestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index ad9dbe1..f462cc2 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -15,7 +15,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import base64
import time
import testtools
@@ -113,15 +112,11 @@
# The server should be rebuilt using the provided image and data
meta = {'rebuild': 'server'}
new_name = data_utils.rand_name('server')
- file_contents = 'Test server rebuild.'
- personality = [{'path': 'rebuild.txt',
- 'contents': base64.b64encode(file_contents)}]
password = 'rebuildPassw0rd'
resp, rebuilt_server = self.client.rebuild(self.server_id,
self.image_ref_alt,
name=new_name,
metadata=meta,
- personality=personality,
admin_password=password)
self.addCleanup(self.client.rebuild, self.server_id, self.image_ref)
@@ -174,7 +169,7 @@
def _detect_server_image_flavor(self, server_id):
# Detects the current server image flavor ref.
- resp, server = self.client.get_server(self.server_id)
+ resp, server = self.client.get_server(server_id)
current_flavor = server['flavor']['id']
new_flavor_ref = self.flavor_ref_alt \
if current_flavor == self.flavor_ref else self.flavor_ref
diff --git a/tempest/api/compute/v3/servers/test_server_metadata.py b/tempest/api/compute/v3/servers/test_server_metadata.py
index ee0f4a9..f36feb3 100644
--- a/tempest/api/compute/v3/servers/test_server_metadata.py
+++ b/tempest/api/compute/v3/servers/test_server_metadata.py
@@ -20,12 +20,12 @@
from tempest.test import attr
-class ServerMetadataTestJSON(base.BaseV2ComputeTest):
+class ServerMetadataV3TestJSON(base.BaseV3ComputeTest):
_interface = 'json'
@classmethod
def setUpClass(cls):
- super(ServerMetadataTestJSON, cls).setUpClass()
+ super(ServerMetadataV3TestJSON, cls).setUpClass()
cls.client = cls.servers_client
cls.quotas = cls.quotas_client
cls.admin_client = cls._get_identity_admin_client()
@@ -37,7 +37,7 @@
cls.server_id = server['id']
def setUp(self):
- super(ServerMetadataTestJSON, self).setUp()
+ super(ServerMetadataV3TestJSON, self).setUp()
meta = {'key1': 'value1', 'key2': 'value2'}
resp, _ = self.client.set_server_metadata(self.server_id, meta)
self.assertEqual(resp.status, 200)
@@ -88,7 +88,7 @@
meta = {'key1': 'alt1', 'key3': 'value3'}
resp, metadata = self.client.update_server_metadata(self.server_id,
meta)
- self.assertEqual(200, resp.status)
+ self.assertEqual(201, resp.status)
# Verify the values have been updated to the proper values
resp, resp_metadata = self.client.list_server_metadata(self.server_id)
@@ -213,5 +213,5 @@
self.server_id, meta=meta, no_metadata_field=True)
-class ServerMetadataTestXML(ServerMetadataTestJSON):
+class ServerMetadataV3TestXML(ServerMetadataV3TestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_server_personality.py b/tempest/api/compute/v3/servers/test_server_personality.py
deleted file mode 100644
index c6d2e44..0000000
--- a/tempest/api/compute/v3/servers/test_server_personality.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# 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 base64
-
-from tempest.api.compute import base
-from tempest import exceptions
-from tempest.test import attr
-
-
-class ServerPersonalityTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
-
- @classmethod
- def setUpClass(cls):
- super(ServerPersonalityTestJSON, cls).setUpClass()
- cls.client = cls.servers_client
- cls.user_client = cls.limits_client
-
- @attr(type='gate')
- def test_personality_files_exceed_limit(self):
- # Server creation should fail if greater than the maximum allowed
- # number of files are injected into the server.
- file_contents = 'This is a test file.'
- personality = []
- max_file_limit = \
- self.user_client.get_specific_absolute_limit("maxPersonality")
- for i in range(0, int(max_file_limit) + 1):
- path = 'etc/test' + str(i) + '.txt'
- personality.append({'path': path,
- 'contents': base64.b64encode(file_contents)})
- self.assertRaises(exceptions.OverLimit, self.create_test_server,
- personality=personality)
-
- @attr(type='gate')
- def test_can_create_server_with_max_number_personality_files(self):
- # Server should be created successfully if maximum allowed number of
- # files is injected into the server during creation.
- file_contents = 'This is a test file.'
- max_file_limit = \
- self.user_client.get_specific_absolute_limit("maxPersonality")
- person = []
- for i in range(0, int(max_file_limit)):
- path = 'etc/test' + str(i) + '.txt'
- person.append({
- 'path': path,
- 'contents': base64.b64encode(file_contents),
- })
- resp, server = self.create_test_server(personality=person)
- self.assertEqual('202', resp['status'])
-
-
-class ServerPersonalityTestXML(ServerPersonalityTestJSON):
- _interface = "xml"
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index d316ae1..98b298e 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -17,16 +17,22 @@
from tempest.api.identity import base
from tempest import clients
from tempest.common.utils.data_utils import rand_name
+from tempest import config
from tempest import exceptions
from tempest.openstack.common import timeutils
from tempest.test import attr
+CONF = config.CONF
+
class BaseTrustsV3Test(base.BaseIdentityAdminTest):
def setUp(self):
super(BaseTrustsV3Test, self).setUp()
# Use alt_username as the trustee
+ if not CONF.identity_feature_enabled.trust:
+ raise self.skipException("Trusts aren't enabled")
+
self.trustee_username = self.config.identity.alt_username
self.trust_id = None
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 28ed5b6..b521bce 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -34,7 +34,8 @@
super(BaseImageTest, cls).setUpClass()
cls.created_images = []
cls._interface = 'json'
- cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
+ cls.isolated_creds = isolated_creds.IsolatedCreds(
+ cls.__name__, network_resources=cls.network_resources)
if not cls.config.service_available.glance:
skip_msg = ("%s skipped as glance is not available" % cls.__name__)
raise cls.skipException(skip_msg)
@@ -129,7 +130,7 @@
raise cls.skipException(msg)
-class BaseV2MemeberImageTest(BaseImageTest):
+class BaseV2MemeberImageTest(BaseV2ImageTest):
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index dcad101..fd3dc9f 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -50,6 +50,8 @@
@classmethod
def setUpClass(cls):
+ # Create no network resources for these test.
+ cls.set_network_resources()
super(BaseNetworkTest, cls).setUpClass()
os = clients.Manager(interface=cls._interface)
cls.network_cfg = os.config.network
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 68ca66a..849d62e 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -127,6 +127,21 @@
self.assertIsNotNone(found, msg)
@attr(type='smoke')
+ def test_list_networks_fields(self):
+ # Verify listing some fields of the networks
+ resp, body = self.client.list_networks(fields='id')
+ self.assertEqual('200', resp['status'])
+ networks = body['networks']
+ found = None
+ for n in networks:
+ self.assertEqual(len(n), 1)
+ self.assertIn('id', n)
+ if (n['id'] == self.network['id']):
+ found = n['id']
+ self.assertIsNotNone(found,
+ "Created network id not found in the list")
+
+ @attr(type='smoke')
def test_show_subnet(self):
# Verifies the details of a subnet
resp, body = self.client.show_subnet(self.subnet['id'])
@@ -149,6 +164,21 @@
self.assertIsNotNone(found, msg)
@attr(type='smoke')
+ def test_list_subnets_fields(self):
+ # Verify listing some fields of the subnets
+ resp, body = self.client.list_subnets(fields='id')
+ self.assertEqual('200', resp['status'])
+ subnets = body['subnets']
+ found = None
+ for n in subnets:
+ self.assertEqual(len(n), 1)
+ self.assertIn('id', n)
+ if (n['id'] == self.subnet['id']):
+ found = n['id']
+ self.assertIsNotNone(found,
+ "Created subnet id not found in the list")
+
+ @attr(type='smoke')
def test_create_update_delete_port(self):
# Verify that successful port creation, update & deletion
resp, body = self.client.create_port(self.network['id'])
@@ -184,6 +214,21 @@
found = n['id']
self.assertIsNotNone(found, "Port list doesn't contain created port")
+ @attr(type='smoke')
+ def test_list_ports_fields(self):
+ # Verify listing some fields of the ports
+ resp, body = self.client.list_ports(fields='id')
+ self.assertEqual('200', resp['status'])
+ ports_list = body['ports']
+ found = None
+ for n in ports_list:
+ self.assertEqual(len(n), 1)
+ self.assertIn('id', n)
+ if (n['id'] == self.port['id']):
+ found = n['id']
+ self.assertIsNotNone(found,
+ "Created port id not found in the list")
+
class NetworksTestXML(NetworksTestJSON):
_interface = 'xml'
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 9b0a3de..37b1f2c 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -82,6 +82,36 @@
for rule in rule_list_body['security_group_rules']]
self.assertIn(rule_create_body['security_group_rule']['id'], rule_list)
+ @attr(type='smoke')
+ def test_create_security_group_rule_with_additional_args(self):
+ # Verify creating security group rule with the following
+ # arguments works: "protocol": "tcp", "port_range_max": 77,
+ # "port_range_min": 77, "direction":"ingress".
+ group_create_body, _ = self._create_security_group()
+
+ direction = 'ingress'
+ protocol = 'tcp'
+ port_range_min = 77
+ port_range_max = 77
+ resp, rule_create_body = self.client.create_security_group_rule(
+ group_create_body['security_group']['id'],
+ direction=direction,
+ protocol=protocol,
+ port_range_min=port_range_min,
+ port_range_max=port_range_max
+ )
+
+ self.assertEqual('201', resp['status'])
+ sec_group_rule = rule_create_body['security_group_rule']
+ self.addCleanup(self._delete_security_group_rule,
+ sec_group_rule['id']
+ )
+
+ self.assertEqual(sec_group_rule['direction'], direction)
+ self.assertEqual(sec_group_rule['protocol'], protocol)
+ self.assertEqual(int(sec_group_rule['port_range_min']), port_range_min)
+ self.assertEqual(int(sec_group_rule['port_range_max']), port_range_max)
+
class SecGroupTestXML(SecGroupTest):
_interface = 'xml'
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 47d8cca..b4928dd 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -32,7 +32,8 @@
if not cls.config.service_available.swift:
skip_msg = ("%s skipped as swift is not available" % cls.__name__)
raise cls.skipException(skip_msg)
- cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
+ cls.isolated_creds = isolated_creds.IsolatedCreds(
+ cls.__name__, network_resources=cls.network_resources)
if cls.config.compute.allow_tenant_isolation:
# Get isolated creds for normal user
creds = cls.isolated_creds.get_primary_creds()
diff --git a/tempest/clients.py b/tempest/clients.py
index 519d191..75f8838 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -64,6 +64,8 @@
from tempest.services.compute.v3.json.hosts_client import HostsV3ClientJSON
from tempest.services.compute.v3.json.hypervisor_client import \
HypervisorV3ClientJSON
+from tempest.services.compute.v3.json.instance_usage_audit_log_client import \
+ InstanceUsagesAuditLogV3ClientJSON
from tempest.services.compute.v3.json.interfaces_client import \
InterfacesV3ClientJSON
from tempest.services.compute.v3.json.keypairs_client import \
@@ -88,6 +90,8 @@
from tempest.services.compute.v3.xml.hosts_client import HostsV3ClientXML
from tempest.services.compute.v3.xml.hypervisor_client import \
HypervisorV3ClientXML
+from tempest.services.compute.v3.xml.instance_usage_audit_log_client import \
+ InstanceUsagesAuditLogV3ClientXML
from tempest.services.compute.v3.xml.interfaces_client import \
InterfacesV3ClientXML
from tempest.services.compute.v3.xml.keypairs_client import KeyPairsV3ClientXML
@@ -284,6 +288,8 @@
self.credentials_client = CredentialsClientXML(*client_args)
self.instance_usages_audit_log_client = \
InstanceUsagesAuditLogClientXML(*client_args)
+ self.instance_usages_audit_log_v3_client = \
+ InstanceUsagesAuditLogV3ClientXML(*client_args)
self.volume_hosts_client = VolumeHostsClientXML(*client_args)
self.volumes_extension_client = VolumeExtensionClientXML(
*client_args)
@@ -347,6 +353,8 @@
self.credentials_client = CredentialsClientJSON(*client_args)
self.instance_usages_audit_log_client = \
InstanceUsagesAuditLogClientJSON(*client_args)
+ self.instance_usages_audit_log_v3_client = \
+ InstanceUsagesAuditLogV3ClientJSON(*client_args)
self.volume_hosts_client = VolumeHostsClientJSON(*client_args)
self.volumes_extension_client = VolumeExtensionClientJSON(
*client_args)
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index da60318..9c0d7f6 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -32,7 +32,8 @@
class IsolatedCreds(object):
def __init__(self, name, tempest_client=True, interface='json',
- password='pass'):
+ password='pass', network_resources=None):
+ self.network_resources = network_resources
self.isolated_creds = {}
self.isolated_net_resources = {}
self.ports = []
@@ -198,15 +199,33 @@
network = None
subnet = None
router = None
+ # Make sure settings
+ if self.network_resources:
+ if self.network_resources['router']:
+ if (not self.network_resources['subnet'] or
+ not self.network_resources['network']):
+ raise exceptions.InvalidConfiguration(
+ 'A router requires a subnet and network')
+ elif self.network_resources['subnet']:
+ if not self.network_resources['network']:
+ raise exceptions.InvalidConfiguration(
+ 'A subnet requires a network')
+ elif self.network_resources['dhcp']:
+ raise exceptions.InvalidConfiguration('DHCP requires a subnet')
+
data_utils.rand_name_root = data_utils.rand_name(self.name)
- network_name = data_utils.rand_name_root + "-network"
- network = self._create_network(network_name, tenant_id)
+ if not self.network_resources or self.network_resources['network']:
+ network_name = data_utils.rand_name_root + "-network"
+ network = self._create_network(network_name, tenant_id)
try:
- subnet_name = data_utils.rand_name_root + "-subnet"
- subnet = self._create_subnet(subnet_name, tenant_id, network['id'])
- router_name = data_utils.rand_name_root + "-router"
- router = self._create_router(router_name, tenant_id)
- self._add_router_interface(router['id'], subnet['id'])
+ if not self.network_resources or self.network_resources['subnet']:
+ subnet_name = data_utils.rand_name_root + "-subnet"
+ subnet = self._create_subnet(subnet_name, tenant_id,
+ network['id'])
+ if not self.network_resources or self.network_resources['router']:
+ router_name = data_utils.rand_name_root + "-router"
+ router = self._create_router(router_name, tenant_id)
+ self._add_router_interface(router['id'], subnet['id'])
except Exception:
if router:
self._clear_isolated_router(router['id'], router['name'])
@@ -230,14 +249,25 @@
if not self.tempest_client:
body = {'subnet': {'name': subnet_name, 'tenant_id': tenant_id,
'network_id': network_id, 'ip_version': 4}}
+ if self.network_resources:
+ body['enable_dhcp'] = self.network_resources['dhcp']
base_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
mask_bits = CONF.network.tenant_network_mask_bits
for subnet_cidr in base_cidr.subnet(mask_bits):
try:
if self.tempest_client:
- resp, resp_body = self.network_admin_client.create_subnet(
- network_id, str(subnet_cidr), name=subnet_name,
- tenant_id=tenant_id)
+ if self.network_resources:
+ resp, resp_body = self.network_admin_client.\
+ create_subnet(
+ network_id, str(subnet_cidr),
+ name=subnet_name,
+ tenant_id=tenant_id,
+ enable_dhcp=self.network_resources['dhcp'])
+ else:
+ resp, resp_body = self.network_admin_client.\
+ create_subnet(network_id, str(subnet_cidr),
+ name=subnet_name,
+ tenant_id=tenant_id)
else:
body['subnet']['cidr'] = str(subnet_cidr)
resp_body = self.network_admin_client.create_subnet(body)
@@ -431,26 +461,27 @@
net_client = self.network_admin_client
for cred in self.isolated_net_resources:
network, subnet, router = self.isolated_net_resources.get(cred)
- try:
- if self.tempest_client:
- net_client.remove_router_interface_with_subnet_id(
- router['id'], subnet['id'])
- else:
- body = {'subnet_id': subnet['id']}
- net_client.remove_interface_router(router['id'], body)
- except exceptions.NotFound:
- LOG.warn('router with name: %s not found for delete' %
- router['name'])
- pass
- self._clear_isolated_router(router['id'], router['name'])
- # TODO(mlavalle) This method call will be removed once patch
- # https://review.openstack.org/#/c/46563/ merges in Neutron
- self._cleanup_ports(network['id'])
- self._clear_isolated_subnet(subnet['id'], subnet['name'])
- self._clear_isolated_network(network['id'], network['name'])
- LOG.info("Cleared isolated network resources: \n"
- + " network: %s, subnet: %s, router: %s"
- % (network['name'], subnet['name'], router['name']))
+ if self.network_resources.get('router'):
+ try:
+ if self.tempest_client:
+ net_client.remove_router_interface_with_subnet_id(
+ router['id'], subnet['id'])
+ else:
+ body = {'subnet_id': subnet['id']}
+ net_client.remove_interface_router(router['id'], body)
+ except exceptions.NotFound:
+ LOG.warn('router with name: %s not found for delete' %
+ router['name'])
+ pass
+ self._clear_isolated_router(router['id'], router['name'])
+ if self.network_resources.get('network'):
+ # TODO(mlavalle) This method call will be removed once patch
+ # https://review.openstack.org/#/c/46563/ merges in Neutron
+ self._cleanup_ports(network['id'])
+ if self.network_resources.get('subnet'):
+ self._clear_isolated_subnet(subnet['id'], subnet['name'])
+ if self.network_resources.get('network'):
+ self._clear_isolated_network(network['id'], network['name'])
def clear_isolated_creds(self):
if not self.isolated_creds:
diff --git a/tempest/config.py b/tempest/config.py
index 0342380..3c7241a 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -78,7 +78,7 @@
secret=True),
cfg.StrOpt('admin_username',
default='admin',
- help="Administrative Username to use for"
+ help="Administrative Username to use for "
"Keystone API requests."),
cfg.StrOpt('admin_tenant_name',
default='admin',
@@ -90,6 +90,16 @@
secret=True),
]
+identity_feature_group = cfg.OptGroup(name='identity-feature-enabled',
+ title='Enabled Identity Features')
+
+IdentityFeatureGroup = [
+ cfg.BoolOpt('trust',
+ default=True,
+ help='Does the identity service have delegation and '
+ 'impersonation enabled')
+]
+
compute_group = cfg.OptGroup(name='compute',
title='Compute Service Options')
@@ -724,6 +734,8 @@
register_opt_group(cfg.CONF, compute_features_group,
ComputeFeaturesGroup)
register_opt_group(cfg.CONF, identity_group, IdentityGroup)
+ register_opt_group(cfg.CONF, identity_feature_group,
+ IdentityFeatureGroup)
register_opt_group(cfg.CONF, image_group, ImageGroup)
register_opt_group(cfg.CONF, image_feature_group, ImageFeaturesGroup)
register_opt_group(cfg.CONF, network_group, NetworkGroup)
@@ -752,6 +764,7 @@
self.compute = cfg.CONF.compute
self.compute_feature_enabled = cfg.CONF['compute-feature-enabled']
self.identity = cfg.CONF.identity
+ self.identity_feature_enabled = cfg.CONF['identity-feature-enabled']
self.images = cfg.CONF.image
self.image_feature_enabled = cfg.CONF['image-feature-enabled']
self.network = cfg.CONF.network
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 409fcc2..ecb55f9 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -235,7 +235,8 @@
def setUpClass(cls):
super(OfficialClientTest, cls).setUpClass()
cls.isolated_creds = isolated_creds.IsolatedCreds(
- __name__, tempest_client=False)
+ __name__, tempest_client=False,
+ network_resources=cls.network_resources)
username, password, tenant_name = cls.credentials()
@@ -527,6 +528,13 @@
private_key = self.keypair.private_key
return RemoteClient(ip, username, pkey=private_key)
+ def _log_console_output(self, servers=None):
+ if not servers:
+ servers = self.compute_client.servers.list()
+ for server in servers:
+ LOG.debug('Console output for %s', server.id)
+ LOG.debug(server.get_console_output())
+
class NetworkScenarioTest(OfficialClientTest):
"""
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
new file mode 100644
index 0000000..3ae9567
--- /dev/null
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -0,0 +1,133 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp.
+# 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.
+
+from tempest.common import tempest_fixtures as fixtures
+from tempest.common.utils.data_utils import rand_name
+from tempest.openstack.common import log as logging
+from tempest.scenario import manager
+from tempest import test
+
+
+LOG = logging.getLogger(__name__)
+
+
+class TestAggregatesBasicOps(manager.OfficialClientTest):
+ """
+ Creates an aggregate within an availability zone
+ Adds a host to the aggregate
+ Checks aggregate details
+ Updates aggregate's name
+ Removes host from aggregate
+ Deletes aggregate
+ """
+ @classmethod
+ def credentials(cls):
+ return cls.admin_credentials()
+
+ def _create_aggregate(self, aggregate_name, availability_zone=None):
+ aggregate = self.compute_client.aggregates.create(aggregate_name,
+ availability_zone)
+ self.assertEqual(aggregate.name, aggregate_name)
+ self.assertEqual(aggregate.availability_zone, availability_zone)
+ self.set_resource(aggregate.id, aggregate)
+ LOG.debug("Aggregate %s created." % (aggregate.name))
+ return aggregate
+
+ def _delete_aggregate(self, aggregate):
+ self.compute_client.aggregates.delete(aggregate.id)
+ self.remove_resource(aggregate.id)
+ LOG.debug("Aggregate %s deleted. " % (aggregate.name))
+
+ def _get_host_name(self):
+ hosts = self.compute_client.hosts.list()
+ self.assertTrue(len(hosts) >= 1)
+ hostname = hosts[0].host_name
+ return hostname
+
+ def _add_host(self, aggregate_name, host):
+ aggregate = self.compute_client.aggregates.add_host(aggregate_name,
+ host)
+ self.assertIn(host, aggregate.hosts)
+ LOG.debug("Host %s added to Aggregate %s." % (host, aggregate.name))
+
+ def _remove_host(self, aggregate_name, host):
+ aggregate = self.compute_client.aggregates.remove_host(aggregate_name,
+ host)
+ self.assertNotIn(host, aggregate.hosts)
+ LOG.debug("Host %s removed to Aggregate %s." % (host, aggregate.name))
+
+ def _check_aggregate_details(self, aggregate, aggregate_name, azone,
+ hosts, metadata):
+ aggregate = self.compute_client.aggregates.get(aggregate.id)
+ self.assertEqual(aggregate_name, aggregate.name)
+ self.assertEqual(azone, aggregate.availability_zone)
+ self.assertEqual(aggregate.hosts, hosts)
+ for meta_key in metadata.keys():
+ self.assertIn(meta_key, aggregate.metadata)
+ self.assertEqual(metadata[meta_key], aggregate.metadata[meta_key])
+ LOG.debug("Aggregate %s details match." % aggregate.name)
+
+ def _set_aggregate_metadata(self, aggregate, meta):
+ aggregate = self.compute_client.aggregates.set_metadata(aggregate.id,
+ meta)
+
+ for key, value in meta.items():
+ self.assertEqual(meta[key], aggregate.metadata[key])
+ LOG.debug("Aggregate %s metadata updated successfully." %
+ aggregate.name)
+
+ def _update_aggregate(self, aggregate, aggregate_name,
+ availability_zone):
+ values = {}
+ if aggregate_name:
+ values.update({'name': aggregate_name})
+ if availability_zone:
+ values.update({'availability_zone': availability_zone})
+ if values.keys():
+ aggregate = self.compute_client.aggregates.update(aggregate.id,
+ values)
+ for key, values in values.items():
+ self.assertEqual(getattr(aggregate, key), values)
+ return aggregate
+
+ @test.services('compute')
+ def test_aggregate_basic_ops(self):
+ self.useFixture(fixtures.LockFixture('availability_zone'))
+ az = 'foo_zone'
+ aggregate_name = rand_name('aggregate-scenario')
+ aggregate = self._create_aggregate(aggregate_name, az)
+
+ metadata = {'meta_key': 'meta_value'}
+ self._set_aggregate_metadata(aggregate, metadata)
+
+ host = self._get_host_name()
+ self._add_host(aggregate, host)
+ self._check_aggregate_details(aggregate, aggregate_name, az, [host],
+ metadata)
+
+ aggregate_name = rand_name('renamed-aggregate-scenario')
+ aggregate = self._update_aggregate(aggregate, aggregate_name, None)
+
+ additional_metadata = {'foo': 'bar'}
+ self._set_aggregate_metadata(aggregate, additional_metadata)
+
+ metadata.update(additional_metadata)
+ self._check_aggregate_details(aggregate, aggregate.name, az, [host],
+ metadata)
+
+ self._remove_host(aggregate, host)
+ self._delete_aggregate(aggregate)
diff --git a/tempest/scenario/test_cross_tenant_connectivity.py b/tempest/scenario/test_cross_tenant_connectivity.py
index faba987..a269017 100644
--- a/tempest/scenario/test_cross_tenant_connectivity.py
+++ b/tempest/scenario/test_cross_tenant_connectivity.py
@@ -371,6 +371,7 @@
msg)
except Exception:
debug.log_ip_ns()
+ self._log_console_output(servers=self.servers)
raise
def _test_in_tenant_block(self, tenant):
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index 1081a3e..9e08bb6 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -34,6 +34,7 @@
@classmethod
def setUpClass(cls):
+ cls.set_network_resources()
super(TestDashboardBasicOps, cls).setUpClass()
if not cls.config.service_available.horizon:
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
index 7f8d3e4..30468fa 100644
--- a/tempest/scenario/test_large_ops.py
+++ b/tempest/scenario/test_large_ops.py
@@ -36,6 +36,11 @@
"""
+ @classmethod
+ def setUpClass(cls):
+ cls.set_network_resources()
+ super(TestLargeOpsScenario, cls).setUpClass()
+
def _wait_for_server_status(self, status):
for server in self.servers:
self.status_timeout(
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 8a51cd1..890d00f 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -131,7 +131,12 @@
self.server.add_floating_ip(self.floating_ip)
def ssh_to_server(self):
- self.linux_client = self.get_remote_client(self.floating_ip.ip)
+ try:
+ self.linux_client = self.get_remote_client(self.floating_ip.ip)
+ except Exception:
+ LOG.exception('ssh to server failed')
+ self._log_console_output()
+ raise
def check_partitions(self):
partitions = self.linux_client.get_partitions()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 52a36e6..414aae6 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -19,11 +19,9 @@
from tempest.common import debug
from tempest.common.utils import data_utils
from tempest import config
-from tempest.openstack.common import jsonutils
from tempest.openstack.common import log as logging
from tempest.scenario import manager
-import tempest.test
from tempest.test import attr
from tempest.test import services
@@ -31,45 +29,6 @@
LOG = logging.getLogger(__name__)
-class FloatingIPCheckTracker(object):
- """
- Checking VM connectivity through floating IP addresses is bound to fail
- if the floating IP has not actually been associated with the VM yet.
- This helper class facilitates checking for floating IP assignments on
- VMs. It only checks for a given IP address once.
- """
-
- def __init__(self, compute_client, floating_ip_map):
- self.compute_client = compute_client
- self.unchecked = floating_ip_map.copy()
-
- def run_checks(self):
- """Check for any remaining unverified floating IPs
-
- Gets VM details from nova and checks for floating IPs
- within the returned information. Returns true when all
- checks are complete and is suitable for use with
- tempest.test.call_until_true()
- """
- to_delete = []
- loggable_map = {}
- for check_addr, server in self.unchecked.iteritems():
- serverdata = self.compute_client.servers.get(server.id)
- ip_addr = [addr for sublist in serverdata.networks.values() for
- addr in sublist]
- if check_addr.floating_ip_address in ip_addr:
- to_delete.append(check_addr)
- else:
- loggable_map[server.id] = check_addr
-
- for to_del in to_delete:
- del self.unchecked[to_del]
-
- LOG.debug('Unchecked floating IPs: %s',
- jsonutils.dumps(loggable_map))
- return len(self.unchecked) == 0
-
-
class TestNetworkBasicOps(manager.NetworkScenarioTest):
"""
@@ -213,11 +172,6 @@
name = data_utils.rand_name('server-smoke-%d-' % i)
self._create_server(name, network)
- def _log_console_output(self):
- for server, key in self.servers.items():
- LOG.debug('Console output for %s', server.id)
- LOG.debug(server.get_console_output())
-
def _check_tenant_network_connectivity(self):
if not CONF.network.tenant_networks_reachable:
msg = 'Tenant networks not configured to be reachable.'
@@ -234,21 +188,11 @@
key.private_key)
except Exception:
LOG.exception('Tenant connectivity check failed')
- self._log_console_output()
+ self._log_console_output(
+ servers=[server for server, _key in self.servers])
debug.log_ip_ns()
raise
- def _wait_for_floating_ip_association(self):
- ip_tracker = FloatingIPCheckTracker(self.compute_client,
- self.floating_ips)
-
- self.assertTrue(
- tempest.test.call_until_true(
- ip_tracker.run_checks, CONF.compute.build_timeout,
- CONF.compute.build_interval),
- "Timed out while waiting for the floating IP assignments "
- "to propagate")
-
def _create_and_associate_floating_ips(self):
public_network_id = CONF.network.public_network_id
for server in self.servers.keys():
@@ -272,7 +216,8 @@
should_connect=should_connect)
except Exception:
LOG.exception('Public network connectivity check failed')
- self._log_console_output()
+ self._log_console_output(
+ servers=[server for server, _key in self.servers])
debug.log_ip_ns()
raise
@@ -298,11 +243,9 @@
self._check_networks()
self._create_servers()
self._create_and_associate_floating_ips()
- self._wait_for_floating_ip_association()
self._check_tenant_network_connectivity()
self._check_public_network_connectivity(should_connect=True)
self._disassociate_floating_ips()
self._check_public_network_connectivity(should_connect=False)
self._reassociate_floating_ips()
- self._wait_for_floating_ip_association()
self._check_public_network_connectivity(should_connect=True)
diff --git a/tempest/scenario/test_network_quotas.py b/tempest/scenario/test_network_quotas.py
deleted file mode 100644
index cb7aa0b..0000000
--- a/tempest/scenario/test_network_quotas.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2013 Hewlett-Packard Development Company, L.P.
-# 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.
-
-from neutronclient.common import exceptions as exc
-
-from tempest.scenario.manager import NetworkScenarioTest
-from tempest.test import services
-
-
-class TestNetworkQuotaBasic(NetworkScenarioTest):
- """
- This test suite contains tests that each loop trying to grab a
- particular resource until a quota limit is hit.
- For sanity, there is a maximum number of iterations - if this is hit
- the test fails. Covers network, subnet, port.
- """
-
- @classmethod
- def check_preconditions(cls):
- super(TestNetworkQuotaBasic, cls).check_preconditions()
-
- @classmethod
- def setUpClass(cls):
- super(TestNetworkQuotaBasic, cls).setUpClass()
- cls.check_preconditions()
- cls.networks = []
- cls.subnets = []
- cls.ports = []
-
- @services('network')
- def test_create_network_until_quota_hit(self):
- hit_limit = False
- networknum = self._get_tenant_own_network_num(self.tenant_id)
- max = self._show_quota_network(self.tenant_id) - networknum
- for n in xrange(max):
- try:
- self.networks.append(
- self._create_network(self.tenant_id,
- namestart='network-quotatest-'))
- except exc.NeutronClientException as e:
- if (e.status_code != 409):
- raise
- hit_limit = True
- break
- self.assertFalse(hit_limit, "Failed: Hit quota limit !")
-
- try:
- self.networks.append(
- self._create_network(self.tenant_id,
- namestart='network-quotatest-'))
- except exc.NeutronClientException as e:
- if (e.status_code != 409):
- raise
- hit_limit = True
- self.assertTrue(hit_limit, "Failed: Did not hit quota limit !")
-
- @services('network')
- def test_create_subnet_until_quota_hit(self):
- if not self.networks:
- self.networks.append(
- self._create_network(self.tenant_id,
- namestart='network-quotatest-'))
- hit_limit = False
- subnetnum = self._get_tenant_own_subnet_num(self.tenant_id)
- max = self._show_quota_subnet(self.tenant_id) - subnetnum
- for n in xrange(max):
- try:
- self.subnets.append(
- self._create_subnet(self.networks[0],
- namestart='subnet-quotatest-'))
- except exc.NeutronClientException as e:
- if (e.status_code != 409):
- raise
- hit_limit = True
- break
- self.assertFalse(hit_limit, "Failed: Hit quota limit !")
-
- try:
- self.subnets.append(
- self._create_subnet(self.networks[0],
- namestart='subnet-quotatest-'))
- except exc.NeutronClientException as e:
- if (e.status_code != 409):
- raise
- hit_limit = True
- self.assertTrue(hit_limit, "Failed: Did not hit quota limit !")
-
- @services('network')
- def test_create_ports_until_quota_hit(self):
- if not self.networks:
- self.networks.append(
- self._create_network(self.tenant_id,
- namestart='network-quotatest-'))
- hit_limit = False
- portnum = self._get_tenant_own_port_num(self.tenant_id)
- max = self._show_quota_port(self.tenant_id) - portnum
- for n in xrange(max):
- try:
- self.ports.append(
- self._create_port(self.networks[0],
- namestart='port-quotatest-'))
- except exc.NeutronClientException as e:
- if (e.status_code != 409):
- raise
- hit_limit = True
- break
- self.assertFalse(hit_limit, "Failed: Hit quota limit !")
-
- try:
- self.ports.append(
- self._create_port(self.networks[0],
- namestart='port-quotatest-'))
- except exc.NeutronClientException as e:
- if (e.status_code != 409):
- raise
- hit_limit = True
- self.assertTrue(hit_limit, "Failed: Did not hit quota limit !")
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index 112c8a2..2c9446f 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -33,6 +33,7 @@
@classmethod
def setUpClass(cls):
+ cls.set_network_resources()
super(TestServerAdvancedOps, cls).setUpClass()
if not cls.config.compute_feature_enabled.resize:
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index ca3035d..279b80e 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -151,10 +151,15 @@
instance = self.get_resource('instance')
instance.add_floating_ip(floating_ip)
# Check ssh
- self.get_remote_client(
- server_or_ip=floating_ip.ip,
- username=self.image_utils.ssh_user(self.image_ref),
- private_key=self.keypair.private)
+ try:
+ self.get_remote_client(
+ server_or_ip=floating_ip.ip,
+ username=self.image_utils.ssh_user(self.image_ref),
+ private_key=self.keypair.private)
+ except Exception:
+ LOG.exception('ssh to server failed')
+ self._log_console_output()
+ raise
@services('compute', 'network')
def test_server_basicops(self):
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index 00139f0..874bc60 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -15,10 +15,14 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.openstack.common import log
from tempest.scenario import manager
from tempest.test import services
+LOG = log.getLogger(__name__)
+
+
class TestSnapshotPattern(manager.OfficialClientTest):
"""
This test is for snapshotting an instance and booting with it.
@@ -40,7 +44,11 @@
self.keypair = self.create_keypair()
def _ssh_to_server(self, server_or_ip):
- linux_client = self.get_remote_client(server_or_ip)
+ try:
+ linux_client = self.get_remote_client(server_or_ip)
+ except Exception:
+ LOG.exception()
+ self._log_console_output()
return linux_client.ssh_client
def _write_timestamp(self, server_or_ip):
diff --git a/tempest/scenario/test_swift_basic_ops.py b/tempest/scenario/test_swift_basic_ops.py
index 6763503..4ef2aca 100644
--- a/tempest/scenario/test_swift_basic_ops.py
+++ b/tempest/scenario/test_swift_basic_ops.py
@@ -39,6 +39,7 @@
@classmethod
def setUpClass(cls):
+ cls.set_network_resources()
super(TestSwiftBasicOps, cls).setUpClass()
if not cls.config.service_available.swift:
skip_msg = ("%s skipped as swift is not available" %
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index fa9a228..2a2b527 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -13,10 +13,14 @@
# under the License.
from tempest.common.utils import data_utils
+from tempest.openstack.common import log
from tempest.scenario import manager
from tempest.test import services
+LOG = log.getLogger(__name__)
+
+
class TestVolumeBootPattern(manager.OfficialClientTest):
"""
@@ -96,8 +100,14 @@
network_name_for_ssh = self.config.compute.network_for_ssh
ip = server.networks[network_name_for_ssh][0]
- client = self.get_remote_client(ip,
- private_key=keypair.private_key)
+ try:
+ client = self.get_remote_client(
+ ip,
+ private_key=keypair.private_key)
+ except Exception:
+ LOG.exception('ssh to server failed')
+ self._log_console_output()
+ raise
return client.ssh_client
def _get_content(self, ssh_client):
diff --git a/tempest/services/compute/v3/json/flavors_client.py b/tempest/services/compute/v3/json/flavors_client.py
index e99ac91..a790c40 100644
--- a/tempest/services/compute/v3/json/flavors_client.py
+++ b/tempest/services/compute/v3/json/flavors_client.py
@@ -61,7 +61,7 @@
'id': flavor_id,
}
if kwargs.get('ephemeral'):
- post_body['OS-FLV-EXT-DATA:ephemeral'] = kwargs.get('ephemeral')
+ post_body['ephemeral'] = kwargs.get('ephemeral')
if kwargs.get('swap'):
post_body['swap'] = kwargs.get('swap')
if kwargs.get('rxtx'):
diff --git a/tempest/services/compute/v3/json/instance_usage_audit_log_client.py b/tempest/services/compute/v3/json/instance_usage_audit_log_client.py
index 07ce1bb..bd73c13 100644
--- a/tempest/services/compute/v3/json/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/v3/json/instance_usage_audit_log_client.py
@@ -20,21 +20,18 @@
from tempest.common.rest_client import RestClient
-class InstanceUsagesAuditLogClientJSON(RestClient):
+class InstanceUsagesAuditLogV3ClientJSON(RestClient):
def __init__(self, config, username, password, auth_url, tenant_name=None):
- super(InstanceUsagesAuditLogClientJSON, self).__init__(
+ super(InstanceUsagesAuditLogV3ClientJSON, self).__init__(
config, username, password, auth_url, tenant_name)
- self.service = self.config.compute.catalog_type
+ self.service = self.config.compute.catalog_v3_type
- def list_instance_usage_audit_logs(self):
- url = 'os-instance_usage_audit_log'
- resp, body = self.get(url)
- body = json.loads(body)
- return resp, body["instance_usage_audit_logs"]
-
- def get_instance_usage_audit_log(self, time_before):
- url = 'os-instance_usage_audit_log/%s' % time_before
+ def list_instance_usage_audit_logs(self, time_before=None):
+ if time_before:
+ url = 'os-instance-usage-audit-log?before=%s' % time_before
+ else:
+ url = 'os-instance-usage-audit-log'
resp, body = self.get(url)
body = json.loads(body)
return resp, body["instance_usage_audit_log"]
diff --git a/tempest/services/compute/v3/json/limits_client.py b/tempest/services/compute/v3/json/limits_client.py
deleted file mode 100644
index 3e53e3e..0000000
--- a/tempest/services/compute/v3/json/limits_client.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# 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 json
-from tempest.common.rest_client import RestClient
-
-
-class LimitsClientJSON(RestClient):
-
- def __init__(self, config, username, password, auth_url, tenant_name=None):
- super(LimitsClientJSON, self).__init__(config, username, password,
- auth_url, tenant_name)
- self.service = self.config.compute.catalog_type
-
- def get_absolute_limits(self):
- resp, body = self.get("limits")
- body = json.loads(body)
- return resp, body['limits']['absolute']
-
- def get_specific_absolute_limit(self, absolute_limit):
- resp, body = self.get("limits")
- body = json.loads(body)
- if absolute_limit not in body['limits']['absolute']:
- return None
- else:
- return body['limits']['absolute'][absolute_limit]
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index 3e361a1..eba3be5 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -45,8 +45,6 @@
admin_password: Sets the initial root password.
key_name: Key name of keypair that was created earlier.
meta: A dictionary of values to be used as metadata.
- personality: A list of dictionaries for files to be injected into
- the server.
security_groups: A list of security group dicts.
networks: A list of network dicts with UUID and fixed_ip.
user_data: User data for instance.
@@ -64,7 +62,7 @@
'flavor_ref': flavor_ref
}
- for option in ['personality', 'admin_password', 'key_name', 'networks',
+ for option in ['admin_password', 'key_name', 'networks',
('os-security-groups:security_groups',
'security_groups'),
('os-user-data:user_data', 'user_data'),
@@ -103,7 +101,6 @@
Updates the properties of an existing server.
server_id: The id of an existing server.
name: The name of the server.
- personality: A list of files to be injected into the server.
access_ip_v4: The IPv4 access address for the server.
access_ip_v6: The IPv6 access address for the server.
"""
diff --git a/tempest/services/compute/v3/xml/instance_usage_audit_log_client.py b/tempest/services/compute/v3/xml/instance_usage_audit_log_client.py
index 175997b..b8429b2 100644
--- a/tempest/services/compute/v3/xml/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/v3/xml/instance_usage_audit_log_client.py
@@ -21,21 +21,18 @@
from tempest.services.compute.xml.common import xml_to_json
-class InstanceUsagesAuditLogClientXML(RestClientXML):
+class InstanceUsagesAuditLogV3ClientXML(RestClientXML):
def __init__(self, config, username, password, auth_url, tenant_name=None):
- super(InstanceUsagesAuditLogClientXML, self).__init__(
+ super(InstanceUsagesAuditLogV3ClientXML, self).__init__(
config, username, password, auth_url, tenant_name)
- self.service = self.config.compute.catalog_type
+ self.service = self.config.compute.catalog_v3_type
- def list_instance_usage_audit_logs(self):
- url = 'os-instance_usage_audit_log'
+ def list_instance_usage_audit_logs(self, time_before=None):
+ if time_before:
+ url = 'os-instance-usage-audit-log?before=%s' % time_before
+ else:
+ url = 'os-instance-usage-audit-log'
resp, body = self.get(url, self.headers)
instance_usage_audit_logs = xml_to_json(etree.fromstring(body))
return resp, instance_usage_audit_logs
-
- def get_instance_usage_audit_log(self, time_before):
- url = 'os-instance_usage_audit_log/%s' % time_before
- resp, body = self.get(url, self.headers)
- instance_usage_audit_log = xml_to_json(etree.fromstring(body))
- return resp, instance_usage_audit_log
diff --git a/tempest/services/compute/v3/xml/limits_client.py b/tempest/services/compute/v3/xml/limits_client.py
deleted file mode 100644
index 704de52..0000000
--- a/tempest/services/compute/v3/xml/limits_client.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright 2012 IBM Corp.
-# 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.
-
-from lxml import objectify
-
-from tempest.common.rest_client import RestClientXML
-
-NS = "{http://docs.openstack.org/common/api/v1.0}"
-
-
-class LimitsClientXML(RestClientXML):
-
- def __init__(self, config, username, password, auth_url, tenant_name=None):
- super(LimitsClientXML, self).__init__(config, username, password,
- auth_url, tenant_name)
- self.service = self.config.compute.catalog_type
-
- def get_absolute_limits(self):
- resp, body = self.get("limits", self.headers)
- body = objectify.fromstring(body)
- lim = NS + 'absolute'
- ret = {}
-
- for el in body[lim].iterchildren():
- attributes = el.attrib
- ret[attributes['name']] = attributes['value']
- return resp, ret
-
- def get_specific_absolute_limit(self, absolute_limit):
- resp, body = self.get("limits", self.headers)
- body = objectify.fromstring(body)
- lim = NS + 'absolute'
- ret = {}
-
- for el in body[lim].iterchildren():
- attributes = el.attrib
- ret[attributes['name']] = attributes['value']
- if absolute_limit not in ret:
- return None
- else:
- return ret[absolute_limit]
diff --git a/tempest/services/compute/v3/xml/servers_client.py b/tempest/services/compute/v3/xml/servers_client.py
index 7405fc9..68831cd 100644
--- a/tempest/services/compute/v3/xml/servers_client.py
+++ b/tempest/services/compute/v3/xml/servers_client.py
@@ -304,8 +304,6 @@
admin_password: Sets the initial root password.
key_name: Key name of keypair that was created earlier.
meta: A dictionary of values to be used as metadata.
- personality: A list of dictionaries for files to be injected into
- the server.
security_groups: A list of security group dicts.
networks: A list of network dicts with UUID and fixed_ip.
user_data: User data for instance.
@@ -404,14 +402,6 @@
meta.append(Text(v))
metadata.append(meta)
- if 'personality' in kwargs:
- personality = Element('personality')
- server.append(personality)
- for k in kwargs['personality']:
- temp = Element('file', path=k['path'])
- temp.append(Text(k['contents']))
- personality.append(temp)
-
resp, body = self.post('servers', str(Document(server)), self.headers)
server = self._parse_server(etree.fromstring(body))
return resp, server
@@ -614,7 +604,7 @@
def set_server_metadata_item(self, server_id, key, meta):
doc = Document()
for k, v in meta.items():
- meta_element = Element("meta", key=k)
+ meta_element = Element("metadata", key=k)
meta_element.append(Text(v))
doc.append(meta_element)
resp, body = self.put('servers/%s/metadata/%s' % (str(server_id), key),
diff --git a/tempest/test.py b/tempest/test.py
index d57ed83..931aa5d 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -230,6 +230,8 @@
setUpClassCalled = False
+ network_resources = {}
+
@classmethod
def setUpClass(cls):
if hasattr(super(BaseTestCase, cls), 'setUpClass'):
@@ -277,7 +279,8 @@
"""
Returns an Openstack client manager
"""
- cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
+ cls.isolated_creds = isolated_creds.IsolatedCreds(
+ cls.__name__, network_resources=cls.network_resources)
force_tenant_isolation = getattr(cls, 'force_tenant_isolation', None)
if (cls.config.compute.allow_tenant_isolation or
@@ -319,6 +322,27 @@
cls.config.identity.uri
)
+ @classmethod
+ def set_network_resources(self, network=False, router=False, subnet=False,
+ dhcp=False):
+ """Specify which network resources should be created
+
+ @param network
+ @param router
+ @param subnet
+ @param dhcp
+ """
+ # network resources should be set only once from callers
+ # in order to ensure that even if it's called multiple times in
+ # a chain of overloaded methods, the attribute is set only
+ # in the leaf class
+ if not self.network_resources:
+ self.network_resources = {
+ 'network': network,
+ 'router': router,
+ 'subnet': subnet,
+ 'dhcp': dhcp}
+
def call_until_true(func, duration, sleep_for):
"""
diff --git a/test-requirements.txt b/test-requirements.txt
index 9486244..d7340f3 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -6,3 +6,4 @@
oslo.sphinx
mox>=0.5.3
mock>=1.0
+coverage>=3.6
diff --git a/tox.ini b/tox.ini
index 6d596e3..88f2537 100644
--- a/tox.ini
+++ b/tox.ini
@@ -25,6 +25,10 @@
setenv = OS_TEST_PATH=./tempest/tests
commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
+[testenv:cover]
+setenv = OS_TEST_PATH=./tempest/tests
+commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
+
[testenv:all]
setenv = VIRTUAL_ENV={envdir}
commands =