Merge "Fixing test_volume_boot_pattern when use_floatingip_for_ssh=false"
diff --git a/HACKING.rst b/HACKING.rst
index c776c49..45c35df 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -314,6 +314,39 @@
* Check written content in the instance booted from snapshot
"""
+Test Identification with Idempotent ID
+--------------------------------------
+
+Every function that provides a test must have an ``idempotent_id`` decorator
+that is a unique ``uuid-4`` instance. This ID is used to complement the fully
+qualified test name and track test funcionality through refactoring. The
+format of the metadata looks like::
+
+ @test.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997')
+ def test_list_servers_with_detail(self):
+ # The created server should be in the detailed list of all servers
+ ...
+
+Tempest includes a ``check_uuid.py`` tool that will test for the existence
+and uniqueness of idempotent_id metadata for every test. By default the
+tool runs against the Tempest package by calling::
+
+ python check_uuid.py
+
+It can be invoked against any test suite by passing a package name::
+
+ python check_uuid.py --package <package_name>
+
+Tests without an ``idempotent_id`` can be automatically fixed by running
+the command with the ``--fix`` flag, which will modify the source package
+by inserting randomly generated uuids for every test that does not have
+one::
+
+ python check_uuid.py --fix
+
+The ``check_uuid.py`` tool is used as part of the tempest gate job
+to ensure that all tests have an ``idempotent_id`` decorator.
+
Branchless Tempest Considerations
---------------------------------
diff --git a/README.rst b/README.rst
index af24569..d7063ba 100644
--- a/README.rst
+++ b/README.rst
@@ -107,7 +107,7 @@
----------
Tempest also has a set of unit tests which test the Tempest code itself. These
-tests can be run by specifing the test discovery path::
+tests can be run by specifying the test discovery path::
$> OS_TEST_PATH=./tempest/tests testr run --parallel
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index 0805544..3e6013d 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -142,7 +142,7 @@
#. alt_password
#. alt_tenant_name
-And in the auth secion:
+And in the auth section:
#. allow_tenant_isolation = False
#. comment out 'test_accounts_file' or keep it as empty
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 27d65e6..07ee026 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -72,7 +72,7 @@
#logging_exception_prefix = %(asctime)s.%(msecs)03d %(process)d ERROR %(name)s %(instance)s
# List of logger=LEVEL pairs. (list value)
-#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN
+#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN
# Enables or disables publication of error events. (boolean value)
#publish_errors = false
@@ -123,10 +123,10 @@
# Roles to assign to all users created by tempest (list value)
#tempest_roles =
-# Only applicable when identity.auth_version is v3.Domain within which
-# isolated credentials are provisioned.The default "None" means that
-# the domain from theadmin user is used instead. (string value)
-#tenant_isolation_domain_name = <None>
+# Default domain used when getting v3 credentials. This is the name
+# keystone uses for v2 compatibility. (string value)
+# Deprecated group/name - [auth]/tenant_isolation_domain_name
+#default_credentials_domain_name = Default
# If allow_tenant_isolation is set to True and Neutron is enabled
# Tempest will try to create a useable network, subnet, and router
@@ -1098,6 +1098,16 @@
#too_slow_to_test = true
+[telemetry-feature-enabled]
+
+#
+# From tempest.config
+#
+
+# Runs Ceilometer event-related tests (boolean value)
+#events = false
+
+
[validation]
#
diff --git a/requirements.txt b/requirements.txt
index d0419f7..415eaa5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,7 +12,7 @@
netaddr>=0.7.12
testrepository>=0.0.18
pyOpenSSL>=0.14
-oslo.concurrency>=2.1.0 # Apache-2.0
+oslo.concurrency>=2.3.0 # Apache-2.0
oslo.config>=1.11.0 # Apache-2.0
oslo.i18n>=1.5.0 # Apache-2.0
oslo.log>=1.6.0 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
index 36b2270..f28c481 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -32,7 +32,8 @@
tempest-cleanup = tempest.cmd.cleanup:main
tempest-account-generator = tempest.cmd.account_generator:main
tempest = tempest.cmd.main:main
-
+tempest.cm =
+ init = tempest.cmd.init:TempestInit
oslo.config.opts =
tempest.config = tempest.config:list_opts
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index dc9a7ef..3e20b46 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -56,11 +56,9 @@
@test.idempotent_id('5485077b-7e46-4cec-b402-91dc3173433b')
@test.services('network')
def test_set_reserve(self):
- body = {"reserve": "None"}
- self.client.reserve_fixed_ip(self.ip, body)
+ self.client.reserve_fixed_ip(self.ip, reserve="None")
@test.idempotent_id('7476e322-b9ff-4710-bf82-49d51bac6e2e')
@test.services('network')
def test_set_unreserve(self):
- body = {"unreserve": "None"}
- self.client.reserve_fixed_ip(self.ip, body)
+ self.client.reserve_fixed_ip(self.ip, unreserve="None")
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index 6698638..e67936c 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -60,19 +60,17 @@
@test.idempotent_id('ce60042c-fa60-4836-8d43-1c8e3359dc47')
@test.services('network')
def test_set_reserve_with_non_admin_user(self):
- body = {"reserve": "None"}
self.assertRaises(lib_exc.Forbidden,
self.non_admin_client.reserve_fixed_ip,
- self.ip, body)
+ self.ip, reserve="None")
@test.attr(type=['negative'])
@test.idempotent_id('f1f7a35b-0390-48c5-9803-5f27461439db')
@test.services('network')
def test_set_unreserve_with_non_admin_user(self):
- body = {"unreserve": "None"}
self.assertRaises(lib_exc.Forbidden,
self.non_admin_client.reserve_fixed_ip,
- self.ip, body)
+ self.ip, unreserve="None")
@test.attr(type=['negative'])
@test.idempotent_id('f51cf464-7fc5-4352-bc3e-e75cfa2cb717')
@@ -80,19 +78,17 @@
def test_set_reserve_with_invalid_ip(self):
# NOTE(maurosr): since this exercises the same code snippet, we do it
# only for reserve action
- body = {"reserve": "None"}
# NOTE(eliqiao): in Juno, the exception is NotFound, but in master, we
# change the error code to BadRequest, both exceptions should be
# accepted by tempest
self.assertRaises((lib_exc.NotFound, lib_exc.BadRequest),
self.client.reserve_fixed_ip,
- "my.invalid.ip", body)
+ "my.invalid.ip", reserve="None")
@test.attr(type=['negative'])
@test.idempotent_id('fd26ef50-f135-4232-9d32-281aab3f9176')
@test.services('network')
def test_fixed_ip_with_invalid_action(self):
- body = {"invalid_action": "None"}
self.assertRaises(lib_exc.BadRequest,
self.client.reserve_fixed_ip,
- self.ip, body)
+ self.ip, invalid_action="None")
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index 798bd30..33313be 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -32,6 +32,7 @@
cls.client = cls.os.quotas_client
cls.adm_client = cls.os_adm.quotas_client
cls.sg_client = cls.security_groups_client
+ cls.sgr_client = cls.security_group_rules_client
@classmethod
def resource_setup(cls):
@@ -167,5 +168,5 @@
# A 403 Forbidden or 413 Overlimit (old behaviour) exception
# will be raised when out of quota
self.assertRaises((lib_exc.OverLimit, lib_exc.Forbidden),
- self.sg_client.create_security_group_rule,
+ self.sgr_client.create_security_group_rule,
secgroup_id, ip_protocol, 1025, 1025)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 759bb8c..33442b2 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -64,6 +64,7 @@
cls.floating_ip_pools_client = cls.os.floating_ip_pools_client
cls.floating_ips_client = cls.os.floating_ips_client
cls.keypairs_client = cls.os.keypairs_client
+ cls.security_group_rules_client = cls.os.security_group_rules_client
cls.security_groups_client = cls.os.security_groups_client
cls.quotas_client = cls.os.quotas_client
# NOTE(mriedem): os-quota-class-sets is v2 API only
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 ff3f25b..4596e1f 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -25,7 +25,7 @@
@classmethod
def setup_clients(cls):
super(SecurityGroupRulesTestJSON, cls).setup_clients()
- cls.client = cls.security_groups_client
+ cls.client = cls.security_group_rules_client
@classmethod
def resource_setup(cls):
@@ -183,7 +183,7 @@
group_id=sg2_id)
# Delete group2
- self.client.delete_security_group(sg2_id)
+ self.security_groups_client.delete_security_group(sg2_id)
# Get rules of the Group1
rules = \
self.client.list_security_group_rules(sg1_id)
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 15e79ac..e2a1034 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
@@ -36,6 +36,7 @@
def setup_clients(cls):
super(SecurityGroupRulesNegativeTestJSON, cls).setup_clients()
cls.client = cls.security_groups_client
+ cls.rules_client = cls.security_group_rules_client
@test.attr(type=['negative'])
@test.idempotent_id('1d507e98-7951-469b-82c3-23f1e6b8c254')
@@ -49,7 +50,7 @@
from_port = 22
to_port = 22
self.assertRaises(lib_exc.NotFound,
- self.client.create_security_group_rule,
+ self.rules_client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative'])
@@ -64,7 +65,7 @@
from_port = 22
to_port = 22
self.assertRaises(lib_exc.BadRequest,
- self.client.create_security_group_rule,
+ self.rules_client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative'])
@@ -81,14 +82,15 @@
to_port = 22
rule = \
- self.client.create_security_group_rule(parent_group_id,
- ip_protocol,
- from_port,
- to_port)
- self.addCleanup(self.client.delete_security_group_rule, rule['id'])
+ self.rules_client.create_security_group_rule(parent_group_id,
+ ip_protocol,
+ from_port,
+ to_port)
+ self.addCleanup(self.rules_client.delete_security_group_rule,
+ rule['id'])
# Add the same rule to the group should fail
self.assertRaises(lib_exc.BadRequest,
- self.client.create_security_group_rule,
+ self.rules_client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative'])
@@ -106,7 +108,7 @@
to_port = 22
self.assertRaises(lib_exc.BadRequest,
- self.client.create_security_group_rule,
+ self.rules_client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative'])
@@ -123,7 +125,7 @@
from_port = data_utils.rand_int_id(start=65536)
to_port = 22
self.assertRaises(lib_exc.BadRequest,
- self.client.create_security_group_rule,
+ self.rules_client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative'])
@@ -140,7 +142,7 @@
from_port = 22
to_port = data_utils.rand_int_id(start=65536)
self.assertRaises(lib_exc.BadRequest,
- self.client.create_security_group_rule,
+ self.rules_client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative'])
@@ -157,7 +159,7 @@
from_port = 22
to_port = 21
self.assertRaises(lib_exc.BadRequest,
- self.client.create_security_group_rule,
+ self.rules_client.create_security_group_rule,
secgroup_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative'])
@@ -168,5 +170,5 @@
# with non existent id
non_existent_rule_id = not_existing_id()
self.assertRaises(lib_exc.NotFound,
- self.client.delete_security_group_rule,
+ self.rules_client.delete_security_group_rule,
non_existent_rule_id)
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 396327b..9e27f33 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -98,7 +98,7 @@
def _test_create_interface_by_network_id(self, server, ifs):
network_id = ifs[0]['net_id']
iface = self.client.create_interface(server['id'],
- network_id=network_id)
+ net_id=network_id)
iface = self.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface, network_id=network_id)
@@ -179,7 +179,7 @@
self.assertTrue(interface_count > 0)
self._check_interface(ifs[0])
network_id = ifs[0]['net_id']
- self.client.add_fixed_ip(server['id'], network_id)
+ self.client.add_fixed_ip(server['id'], networkId=network_id)
# Remove the fixed IP from server.
server_detail = self.os.servers_client.show_server(
server['id'])
@@ -192,4 +192,4 @@
break
if fixed_ip is not None:
break
- self.client.remove_fixed_ip(server['id'], fixed_ip)
+ self.client.remove_fixed_ip(server['id'], address=fixed_ip)
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 58c2206..8ee8ad4 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -52,11 +52,13 @@
cls.glance_client = cls.os.image_client
cls.keypairs_client = cls.os.keypairs_client
cls.security_client = cls.os.security_groups_client
+ cls.rule_client = cls.os.security_group_rules_client
cls.alt_client = cls.alt_manager.servers_client
cls.alt_images_client = cls.alt_manager.images_client
cls.alt_keypairs_client = cls.alt_manager.keypairs_client
cls.alt_security_client = cls.alt_manager.security_groups_client
+ cls.alt_rule_client = cls.alt_manager.security_group_rules_client
@classmethod
def resource_setup(cls):
@@ -87,7 +89,7 @@
ip_protocol = 'tcp'
from_port = 22
to_port = 22
- cls.rule = cls.security_client.create_security_group_rule(
+ cls.rule = cls.rule_client.create_security_group_rule(
parent_group_id, ip_protocol, from_port, to_port)
@classmethod
@@ -292,21 +294,21 @@
to_port = -1
try:
# Change the base URL to impersonate another user
- self.alt_security_client.auth_provider.set_alt_auth_data(
+ self.alt_rule_client.auth_provider.set_alt_auth_data(
request_part='url',
- auth_data=self.security_client.auth_provider.auth_data
+ auth_data=self.rule_client.auth_provider.auth_data
)
resp = {}
resp['status'] = None
self.assertRaises(lib_exc.BadRequest,
- self.alt_security_client.
+ self.alt_rule_client.
create_security_group_rule,
parent_group_id, ip_protocol, from_port,
to_port)
finally:
# Next request the base_url is back to normal
if resp['status'] is not None:
- self.alt_security_client.delete_security_group_rule(resp['id'])
+ self.alt_rule_client.delete_security_group_rule(resp['id'])
LOG.error("Create security group rule request should not "
"happen if the tenant id does not match the"
" current user")
@@ -316,7 +318,7 @@
# A DELETE request for another user's security group rule
# should fail
self.assertRaises(lib_exc.NotFound,
- self.alt_security_client.delete_security_group_rule,
+ self.alt_rule_client.delete_security_group_rule,
self.rule['id'])
@test.idempotent_id('c5f52351-53d9-4fc9-83e5-917f7f5e3d71')
diff --git a/tempest/api/telemetry/base.py b/tempest/api/telemetry/base.py
index 3be807b..0f9b7dd 100644
--- a/tempest/api/telemetry/base.py
+++ b/tempest/api/telemetry/base.py
@@ -121,3 +121,27 @@
'Sample for metric:%s with query:%s has not been added to the '
'database within %d seconds' % (metric, query,
CONF.compute.build_timeout))
+
+
+class BaseTelemetryAdminTest(BaseTelemetryTest):
+ """Base test case class for admin Telemetry API tests."""
+
+ credentials = ['primary', 'admin']
+
+ @classmethod
+ def setup_clients(cls):
+ super(BaseTelemetryAdminTest, cls).setup_clients()
+ cls.telemetry_admin_client = cls.os_adm.telemetry_client
+
+ def await_events(self, query):
+ timeout = CONF.compute.build_timeout
+ start = timeutils.utcnow()
+ while timeutils.delta_seconds(start, timeutils.utcnow()) < timeout:
+ body = self.telemetry_admin_client.list_events(query)
+ if body:
+ return body
+ time.sleep(CONF.compute.build_interval)
+
+ raise exceptions.TimeoutException(
+ 'Event with query:%s has not been added to the '
+ 'database within %d seconds' % (query, CONF.compute.build_timeout))
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
index 52793c8..bf1e046 100644
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ b/tempest/api/telemetry/test_telemetry_notification_api.py
@@ -29,8 +29,7 @@
"is disabled")
@test.idempotent_id('d7f8c1c8-d470-4731-8604-315d3956caad')
- @testtools.skipIf(not CONF.service_available.nova,
- "Nova is not available.")
+ @test.services('compute')
def test_check_nova_notification(self):
body = self.create_server()
@@ -71,3 +70,27 @@
for metric in self.glance_v2_notifications:
self.await_samples(metric, query)
+
+
+class TelemetryNotificationAdminAPITestJSON(base.BaseTelemetryAdminTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(TelemetryNotificationAdminAPITestJSON, cls).skip_checks()
+ if CONF.telemetry.too_slow_to_test:
+ raise cls.skipException("Ceilometer feature for fast work mysql "
+ "is disabled")
+
+ @test.idempotent_id('29604198-8b45-4fc0-8af8-1cae4f94ebe9')
+ @test.services('compute')
+ def test_check_nova_notification_event_and_meter(self):
+
+ body = self.create_server()
+
+ if CONF.telemetry_feature_enabled.events:
+ query = ('instance_id', 'eq', body['id'])
+ self.await_events(query)
+
+ query = ('resource', 'eq', body['id'])
+ for metric in self.nova_notifications:
+ self.await_samples(metric, query)
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index f8ae5eb..b67a6d2 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -62,6 +62,7 @@
super(BaseVolumeTest, cls).setup_clients()
cls.servers_client = cls.os.servers_client
cls.networks_client = cls.os.networks_client
+ cls.images_client = cls.os.images_client
if cls._api_version == 1:
cls.snapshots_client = cls.os.snapshots_client
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 29c21ed..a90f9ca 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -131,7 +131,11 @@
@test.idempotent_id('54a01030-c7fc-447c-86ee-c1182beae638')
@test.services('image')
def test_volume_create_get_update_delete_from_image(self):
- self._volume_create_get_update_delete(imageRef=CONF.compute.image_ref)
+ image = self.images_client.show_image(CONF.compute.image_ref)
+ min_disk = image.get('minDisk')
+ disk_size = max(min_disk, CONF.volume.volume_size)
+ self._volume_create_get_update_delete(
+ imageRef=CONF.compute.image_ref, size=disk_size)
@test.idempotent_id('3f591b4a-7dc6-444c-bd51-77469506b3a1')
def test_volume_create_get_update_delete_as_clone(self):
diff --git a/tempest/clients.py b/tempest/clients.py
index 6a2c601..20cefbc 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -65,6 +65,8 @@
from tempest.services.compute.json.quotas_client import QuotasClient
from tempest.services.compute.json.security_group_default_rules_client import \
SecurityGroupDefaultRulesClient
+from tempest.services.compute.json.security_group_rules_client import \
+ SecurityGroupRulesClient
from tempest.services.compute.json.security_groups_client import \
SecurityGroupsClient
from tempest.services.compute.json.server_groups_client import \
@@ -286,6 +288,8 @@
self.auth_provider, **params)
self.floating_ips_client = FloatingIPsClient(self.auth_provider,
**params)
+ self.security_group_rules_client = SecurityGroupRulesClient(
+ self.auth_provider, **params)
self.security_groups_client = SecurityGroupsClient(
self.auth_provider, **params)
self.interfaces_client = InterfacesClient(self.auth_provider,
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index dcdf7c5..2e96c81 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -76,12 +76,12 @@
CONF.identity.alt_username]
if IS_NEUTRON:
- CONF_PRIV_NETWORK = _get_priv_net_id(CONF.compute.fixed_network_name,
- CONF.identity.tenant_name)
+ CONF_PRIV_NETWORK = _get_network_id(CONF.compute.fixed_network_name,
+ CONF.identity.tenant_name)
CONF_NETWORKS = [CONF_PUB_NETWORK, CONF_PRIV_NETWORK]
-def _get_priv_net_id(prv_net_name, tenant_name):
+def _get_network_id(net_name, tenant_name):
am = clients.AdminManager()
net_cl = am.network_client
id_cl = am.identity_client
@@ -91,7 +91,7 @@
t_id = tenant['id']
n_id = None
for net in networks['networks']:
- if (net['tenant_id'] == t_id and net['name'] == prv_net_name):
+ if (net['tenant_id'] == t_id and net['name'] == net_name):
n_id = net['id']
break
return n_id
@@ -103,6 +103,10 @@
for key, value in kwargs.items():
setattr(self, key, value)
+ self.tenant_filter = {}
+ if hasattr(self, 'tenant_id'):
+ self.tenant_filter['tenant_id'] = self.tenant_id
+
def _filter_by_tenant_id(self, item_list):
if (item_list is None
or len(item_list) == 0
@@ -387,8 +391,8 @@
def list(self):
client = self.client
- networks = client.list_networks()
- networks = self._filter_by_tenant_id(networks['networks'])
+ networks = client.list_networks(**self.tenant_filter)
+ networks = networks['networks']
# filter out networks declared in tempest.conf
if self.is_preserve:
networks = [network for network in networks
@@ -414,9 +418,8 @@
def list(self):
client = self.client
- flips = client.list_floatingips()
+ flips = client.list_floatingips(**self.tenant_filter)
flips = flips['floatingips']
- flips = self._filter_by_tenant_id(flips)
LOG.debug("List count, %s Network Floating IPs" % len(flips))
return flips
@@ -438,9 +441,8 @@
def list(self):
client = self.client
- routers = client.list_routers()
+ routers = client.list_routers(**self.tenant_filter)
routers = routers['routers']
- routers = self._filter_by_tenant_id(routers)
if self.is_preserve:
routers = [router for router in routers
if router['id'] != CONF_PUB_ROUTER]
@@ -454,11 +456,12 @@
for router in routers:
try:
rid = router['id']
- ports = client.list_router_interfaces(rid)
- ports = ports['ports']
+ ports = [port for port
+ in client.list_router_interfaces(rid)['ports']
+ if port["device_owner"] == "network:router_interface"]
for port in ports:
- subid = port['fixed_ips'][0]['subnet_id']
- client.remove_router_interface_with_subnet_id(rid, subid)
+ client.remove_router_interface_with_port_id(rid,
+ port['id'])
client.delete_router(rid)
except Exception:
LOG.exception("Delete Router exception.")
@@ -616,11 +619,14 @@
def list(self):
client = self.client
- ports = client.list_ports()
- ports = ports['ports']
- ports = self._filter_by_tenant_id(ports)
+ ports = [port for port in
+ client.list_ports(**self.tenant_filter)['ports']
+ if port["device_owner"] == "" or
+ port["device_owner"].startswith("compute:")]
+
if self.is_preserve:
ports = self._filter_by_conf_networks(ports)
+
LOG.debug("List count, %s Ports" % len(ports))
return ports
@@ -638,13 +644,40 @@
self.data['ports'] = ports
+class NetworkSecGroupService(NetworkService):
+ def list(self):
+ client = self.client
+ filter = self.tenant_filter
+ # cannot delete default sec group so never show it.
+ secgroups = [secgroup for secgroup in
+ client.list_security_groups(**filter)['security_groups']
+ if secgroup['name'] != 'default']
+
+ if self.is_preserve:
+ secgroups = self._filter_by_conf_networks(secgroups)
+ LOG.debug("List count, %s securtiy_groups" % len(secgroups))
+ return secgroups
+
+ def delete(self):
+ client = self.client
+ secgroups = self.list()
+ for secgroup in secgroups:
+ try:
+ client.delete_secgroup(secgroup['id'])
+ except Exception:
+ LOG.exception("Delete security_group exception.")
+
+ def dry_run(self):
+ secgroups = self.list()
+ self.data['secgroups'] = secgroups
+
+
class NetworkSubnetService(NetworkService):
def list(self):
client = self.client
- subnets = client.list_subnets()
+ subnets = client.list_subnets(**self.tenant_filter)
subnets = subnets['subnets']
- subnets = self._filter_by_tenant_id(subnets)
if self.is_preserve:
subnets = self._filter_by_conf_networks(subnets)
LOG.debug("List count, %s Subnets" % len(subnets))
@@ -761,8 +794,8 @@
self.data['images'] = images
def save_state(self):
- images = self.list()
self.data['images'] = {}
+ images = self.list()
for image in images:
self.data['images'][image['id']] = image['name']
@@ -928,7 +961,6 @@
def get_tenant_cleanup_services():
tenant_services = []
-
if IS_CEILOMETER:
tenant_services.append(TelemetryAlarmService)
if IS_NOVA:
@@ -942,14 +974,15 @@
if IS_HEAT:
tenant_services.append(StackService)
if IS_NEUTRON:
+ tenant_services.append(NetworkFloatingIpService)
if test.is_extension_enabled('metering', 'network'):
tenant_services.append(NetworkMeteringLabelRuleService)
tenant_services.append(NetworkMeteringLabelService)
tenant_services.append(NetworkRouterService)
- tenant_services.append(NetworkFloatingIpService)
tenant_services.append(NetworkPortService)
tenant_services.append(NetworkSubnetService)
tenant_services.append(NetworkService)
+ tenant_services.append(NetworkSecGroupService)
if IS_CINDER:
tenant_services.append(SnapshotService)
tenant_services.append(VolumeService)
diff --git a/tempest/cmd/init.py b/tempest/cmd/init.py
new file mode 100644
index 0000000..c13fbe5
--- /dev/null
+++ b/tempest/cmd/init.py
@@ -0,0 +1,99 @@
+# Copyright 2015 Hewlett-Packard Development Company, L.P.
+#
+# 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 os
+import shutil
+import subprocess
+
+from cliff import command
+from oslo_log import log as logging
+from six import moves
+
+LOG = logging.getLogger(__name__)
+
+TESTR_CONF = """[DEFAULT]
+test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \\
+ OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \\
+ OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-500} \\
+ ${PYTHON:-python} -m subunit.run discover -t %s %s $LISTOPT $IDOPTION
+test_id_option=--load-list $IDFILE
+test_list_option=--list
+group_regex=([^\.]*\.)*
+"""
+
+
+class TempestInit(command.Command):
+ """Setup a local working environment for running tempest"""
+
+ def get_parser(self, prog_name):
+ parser = super(TempestInit, self).get_parser(prog_name)
+ parser.add_argument('dir', nargs='?', default=os.getcwd())
+ parser.add_argument('--config-dir', '-c', default='/etc/tempest')
+ return parser
+
+ def generate_testr_conf(self, local_path):
+ testr_conf_path = os.path.join(local_path, '.testr.conf')
+ top_level_path = os.path.dirname(os.path.dirname(__file__))
+ discover_path = os.path.join(top_level_path, 'test_discover')
+ testr_conf = TESTR_CONF % (top_level_path, discover_path)
+ with open(testr_conf_path, 'w+') as testr_conf_file:
+ testr_conf_file.write(testr_conf)
+
+ def update_local_conf(self, conf_path, lock_dir, log_dir):
+ config_parse = moves.configparser.SafeConfigParser()
+ config_parse.optionxform = str
+ with open(conf_path, 'w+') as conf_file:
+ config_parse.readfp(conf_file)
+ # Set local lock_dir in tempest conf
+ if not config_parse.has_section('oslo_concurrency'):
+ config_parse.add_section('oslo_concurrency')
+ config_parse.set('oslo_concurrency', 'lock_path', lock_dir)
+ # Set local log_dir in tempest conf
+ config_parse.set('DEFAULT', 'log_dir', log_dir)
+ # Set default log filename to tempest.log
+ config_parse.set('DEFAULT', 'log_file', 'tempest.log')
+
+ def copy_config(self, etc_dir, config_dir):
+ shutil.copytree(config_dir, etc_dir)
+
+ def create_working_dir(self, local_dir, config_dir):
+ # Create local dir if missing
+ if not os.path.isdir(local_dir):
+ LOG.debug('Creating local working dir: %s' % local_dir)
+ os.mkdir(local_dir)
+ lock_dir = os.path.join(local_dir, 'tempest_lock')
+ etc_dir = os.path.join(local_dir, 'etc')
+ config_path = os.path.join(etc_dir, 'tempest.conf')
+ log_dir = os.path.join(local_dir, 'logs')
+ testr_dir = os.path.join(local_dir, '.testrepository')
+ # Create lock dir
+ if not os.path.isdir(lock_dir):
+ LOG.debug('Creating lock dir: %s' % lock_dir)
+ os.mkdir(lock_dir)
+ # Create log dir
+ if not os.path.isdir(log_dir):
+ LOG.debug('Creating log dir: %s' % log_dir)
+ os.mkdir(log_dir)
+ # Create and copy local etc dir
+ self.copy_config(etc_dir, config_dir)
+ # Update local confs to reflect local paths
+ self.update_local_conf(config_path, lock_dir, log_dir)
+ # Generate a testr conf file
+ self.generate_testr_conf(local_dir)
+ # setup local testr working dir
+ if not os.path.isdir(testr_dir):
+ subprocess.call(['testr', 'init'], cwd=local_dir)
+
+ def take_action(self, parsed_args):
+ self.create_working_dir(parsed_args.dir, parsed_args.config_dir)
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index f091cd3..f35548a 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -122,6 +122,7 @@
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_group_rules_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
@@ -202,6 +203,8 @@
_auth, **compute_params)
self.secgroups = security_groups_client.SecurityGroupsClient(
_auth, **compute_params)
+ self.secrules = security_group_rules_client.SecurityGroupRulesClient(
+ _auth, **compute_params)
self.objects = object_client.ObjectClient(_auth,
**object_storage_params)
self.containers = container_client.ContainerClient(
@@ -917,7 +920,7 @@
# for each security group, create the rules
for rule in secgroup['rules']:
ip_proto, from_port, to_port, cidr = rule.split()
- client.secgroups.create_security_group_rule(
+ client.secrules.create_security_group_rule(
secgroup_id, ip_proto, from_port, to_port, cidr=cidr)
diff --git a/tempest/common/accounts.py b/tempest/common/accounts.py
index 78e0e72..27b44f6 100644
--- a/tempest/common/accounts.py
+++ b/tempest/common/accounts.py
@@ -216,7 +216,7 @@
if ('user_domain_name' in init_attributes and 'user_domain_name'
not in hash_attributes):
# Allow for the case of domain_name populated from config
- domain_name = CONF.identity.admin_domain_name
+ domain_name = CONF.auth.default_credentials_domain_name
hash_attributes['user_domain_name'] = domain_name
if all([getattr(creds, k) == hash_attributes[k] for
k in init_attributes]):
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index 2b7e0db..783a5fc 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -84,9 +84,9 @@
domain_fields = set(x for x in auth.KeystoneV3Credentials.ATTRIBUTES
if 'domain' in x)
if not domain_fields.intersection(kwargs.keys()):
- # TODO(andreaf) It might be better here to use a dedicated config
- # option such as CONF.auth.tenant_isolation_domain_name
- params['user_domain_name'] = CONF.identity.admin_domain_name
+ domain_name = CONF.auth.default_credentials_domain_name
+ params['user_domain_name'] = domain_name
+
auth_url = CONF.identity.uri_v3
else:
auth_url = CONF.identity.uri
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index ff4eda9..7888811 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -163,8 +163,8 @@
self.creds_domain_name = None
if self.identity_version == 'v3':
self.creds_domain_name = (
- CONF.auth.tenant_isolation_domain_name or
- self.default_admin_creds.project_domain_name)
+ self.default_admin_creds.project_domain_name or
+ CONF.auth.default_credentials_domain_name)
self.creds_client = get_creds_client(
self.identity_admin_client, self.creds_domain_name)
diff --git a/tempest/config.py b/tempest/config.py
index 5ea4d10..bdfdcdc 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -67,12 +67,13 @@
cfg.ListOpt('tempest_roles',
help="Roles to assign to all users created by tempest",
default=[]),
- cfg.StrOpt('tenant_isolation_domain_name',
- default=None,
- help="Only applicable when identity.auth_version is v3."
- "Domain within which isolated credentials are provisioned."
- "The default \"None\" means that the domain from the"
- "admin user is used instead."),
+ cfg.StrOpt('default_credentials_domain_name',
+ default='Default',
+ help="Default domain used when getting v3 credentials. "
+ "This is the name keystone uses for v2 compatibility.",
+ deprecated_opts=[cfg.DeprecatedOpt(
+ 'tenant_isolation_domain_name',
+ group='auth')]),
cfg.BoolOpt('create_isolated_networks',
default=True,
help="If allow_tenant_isolation is set to True and Neutron is "
@@ -838,6 +839,16 @@
]
+telemetry_feature_group = cfg.OptGroup(name='telemetry-feature-enabled',
+ title='Enabled Ceilometer Features')
+
+TelemetryFeaturesGroup = [
+ cfg.BoolOpt('events',
+ default=False,
+ help="Runs Ceilometer event-related tests"),
+]
+
+
dashboard_group = cfg.OptGroup(name="dashboard",
title="Dashboard options")
@@ -1178,6 +1189,7 @@
(database_group, DatabaseGroup),
(orchestration_group, OrchestrationGroup),
(telemetry_group, TelemetryGroup),
+ (telemetry_feature_group, TelemetryFeaturesGroup),
(dashboard_group, DashboardGroup),
(data_processing_group, DataProcessingGroup),
(data_processing_feature_group, DataProcessingFeaturesGroup),
@@ -1245,6 +1257,7 @@
self.orchestration = _CONF.orchestration
self.messaging = _CONF.messaging
self.telemetry = _CONF.telemetry
+ self.telemetry_feature_enabled = _CONF['telemetry-feature-enabled']
self.dashboard = _CONF.dashboard
self.data_processing = _CONF.data_processing
self.data_processing_feature_enabled = _CONF[
@@ -1257,9 +1270,11 @@
self.baremetal = _CONF.baremetal
self.input_scenario = _CONF['input-scenario']
self.negative = _CONF.negative
- _CONF.set_default('domain_name', self.identity.admin_domain_name,
+ _CONF.set_default('domain_name',
+ self.auth.default_credentials_domain_name,
group='identity')
- _CONF.set_default('alt_domain_name', self.identity.admin_domain_name,
+ _CONF.set_default('alt_domain_name',
+ self.auth.default_credentials_domain_name,
group='identity')
def __init__(self, parse_conf=True, config_path=None):
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 03e572f..e77d07c 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -54,6 +54,8 @@
cls.keypairs_client = cls.manager.keypairs_client
# Nova security groups client
cls.security_groups_client = cls.manager.security_groups_client
+ cls.security_group_rules_client = (
+ cls.manager.security_group_rules_client)
cls.servers_client = cls.manager.servers_client
cls.volumes_client = cls.manager.volumes_client
cls.snapshots_client = cls.manager.snapshots_client
@@ -217,6 +219,7 @@
def _create_loginable_secgroup_rule(self, secgroup_id=None):
_client = self.security_groups_client
+ _client_rules = self.security_group_rules_client
if secgroup_id is None:
sgs = _client.list_security_groups()
for sg in sgs:
@@ -245,10 +248,10 @@
]
rules = list()
for ruleset in rulesets:
- sg_rule = _client.create_security_group_rule(secgroup_id,
- **ruleset)
+ sg_rule = _client_rules.create_security_group_rule(secgroup_id,
+ **ruleset)
self.addCleanup(self.delete_wrapper,
- _client.delete_security_group_rule,
+ _client_rules.delete_security_group_rule,
sg_rule['id'])
rules.append(sg_rule)
return rules
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index ff58eea..e676063 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -244,7 +244,7 @@
old_port = port_list[0]
interface = self.interface_client.create_interface(
server_id=server['id'],
- network_id=self.new_net.id)
+ net_id=self.new_net.id)
self.addCleanup(self.network_client.wait_for_resource_deletion,
'port',
interface['port_id'])
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index 1269991..1a1d832 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -52,4 +52,5 @@
"""Update an agent build."""
put_body = json.dumps({'para': kwargs})
resp, body = self.put('os-agents/%s' % agent_id, put_body)
- return service_client.ResponseBody(resp, self._parse_resp(body))
+ body = json.loads(body)
+ return service_client.ResponseBody(resp, body['agent'])
diff --git a/tempest/services/compute/json/fixed_ips_client.py b/tempest/services/compute/json/fixed_ips_client.py
index 69de79f..d0d9ca1 100644
--- a/tempest/services/compute/json/fixed_ips_client.py
+++ b/tempest/services/compute/json/fixed_ips_client.py
@@ -28,9 +28,9 @@
self.validate_response(schema.get_fixed_ip, resp, body)
return service_client.ResponseBody(resp, body['fixed_ip'])
- def reserve_fixed_ip(self, fixed_ip, body):
+ def reserve_fixed_ip(self, fixed_ip, **kwargs):
"""This reserves and unreserves fixed ips."""
url = "os-fixed-ips/%s/action" % fixed_ip
- resp, body = self.post(url, json.dumps(body))
+ resp, body = self.post(url, json.dumps(kwargs))
self.validate_response(schema.reserve_fixed_ip, resp, body)
return service_client.ResponseBody(resp)
diff --git a/tempest/services/compute/json/interfaces_client.py b/tempest/services/compute/json/interfaces_client.py
index e8b2b64..c437c08 100644
--- a/tempest/services/compute/json/interfaces_client.py
+++ b/tempest/services/compute/json/interfaces_client.py
@@ -29,16 +29,8 @@
return service_client.ResponseBodyList(resp,
body['interfaceAttachments'])
- def create_interface(self, server_id, port_id=None, network_id=None,
- fixed_ip=None):
- post_body = dict(interfaceAttachment=dict())
- if port_id:
- post_body['interfaceAttachment']['port_id'] = port_id
- if network_id:
- post_body['interfaceAttachment']['net_id'] = network_id
- if fixed_ip:
- fip = dict(ip_address=fixed_ip)
- post_body['interfaceAttachment']['fixed_ips'] = [fip]
+ def create_interface(self, server_id, **kwargs):
+ post_body = {'interfaceAttachment': kwargs}
post_body = json.dumps(post_body)
resp, body = self.post('servers/%s/os-interface' % server_id,
body=post_body)
@@ -59,26 +51,18 @@
self.validate_response(schema.delete_interface, resp, body)
return service_client.ResponseBody(resp, body)
- def add_fixed_ip(self, server_id, network_id):
+ def add_fixed_ip(self, server_id, **kwargs):
"""Add a fixed IP to input server instance."""
- post_body = json.dumps({
- 'addFixedIp': {
- 'networkId': network_id
- }
- })
+ post_body = json.dumps({'addFixedIp': kwargs})
resp, body = self.post('servers/%s/action' % server_id,
post_body)
self.validate_response(servers_schema.server_actions_common_schema,
resp, body)
return service_client.ResponseBody(resp, body)
- def remove_fixed_ip(self, server_id, ip_address):
+ def remove_fixed_ip(self, server_id, **kwargs):
"""Remove input fixed IP from input server instance."""
- post_body = json.dumps({
- 'removeFixedIp': {
- 'address': ip_address
- }
- })
+ post_body = json.dumps({'removeFixedIp': kwargs})
resp, body = self.post('servers/%s/action' % server_id,
post_body)
self.validate_response(servers_schema.server_actions_common_schema,
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 4ea47ed..88d0567 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -41,59 +41,11 @@
self.validate_response(schema.get_quota_set, resp, body)
return service_client.ResponseBody(resp, body['quota_set'])
- def update_quota_set(self, tenant_id, user_id=None,
- force=None, injected_file_content_bytes=None,
- metadata_items=None, ram=None, floating_ips=None,
- fixed_ips=None, key_pairs=None, instances=None,
- security_group_rules=None, injected_files=None,
- cores=None, injected_file_path_bytes=None,
- security_groups=None):
+ def update_quota_set(self, tenant_id, user_id=None, **kwargs):
"""
Updates the tenant's quota limits for one or more resources
"""
- post_body = {}
-
- if force is not None:
- post_body['force'] = force
-
- if injected_file_content_bytes is not None:
- post_body['injected_file_content_bytes'] = \
- injected_file_content_bytes
-
- if metadata_items is not None:
- post_body['metadata_items'] = metadata_items
-
- if ram is not None:
- post_body['ram'] = ram
-
- if floating_ips is not None:
- post_body['floating_ips'] = floating_ips
-
- if fixed_ips is not None:
- post_body['fixed_ips'] = fixed_ips
-
- if key_pairs is not None:
- post_body['key_pairs'] = key_pairs
-
- if instances is not None:
- post_body['instances'] = instances
-
- if security_group_rules is not None:
- post_body['security_group_rules'] = security_group_rules
-
- if injected_files is not None:
- post_body['injected_files'] = injected_files
-
- if cores is not None:
- post_body['cores'] = cores
-
- if injected_file_path_bytes is not None:
- post_body['injected_file_path_bytes'] = injected_file_path_bytes
-
- if security_groups is not None:
- post_body['security_groups'] = security_groups
-
- post_body = json.dumps({'quota_set': post_body})
+ post_body = json.dumps({'quota_set': kwargs})
if user_id:
resp, body = self.put('os-quota-sets/%s?user_id=%s' %
diff --git a/tempest/services/compute/json/security_group_rules_client.py b/tempest/services/compute/json/security_group_rules_client.py
new file mode 100644
index 0000000..f570eb7
--- /dev/null
+++ b/tempest/services/compute/json/security_group_rules_client.py
@@ -0,0 +1,68 @@
+# 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_lib import exceptions as lib_exc
+
+from tempest.api_schema.response.compute.v2_1 import security_groups as schema
+from tempest.common import service_client
+
+
+class SecurityGroupRulesClient(service_client.ServiceClient):
+
+ def create_security_group_rule(self, parent_group_id, ip_proto, from_port,
+ to_port, **kwargs):
+ """
+ Creating a new security group rules.
+ parent_group_id :ID of Security group
+ ip_protocol : ip_proto (icmp, tcp, udp).
+ from_port: Port at start of range.
+ to_port : Port at end of range.
+ Following optional keyword arguments are accepted:
+ cidr : CIDR for address range.
+ group_id : ID of the Source group
+ """
+ post_body = {
+ 'parent_group_id': parent_group_id,
+ 'ip_protocol': ip_proto,
+ 'from_port': from_port,
+ 'to_port': to_port,
+ 'cidr': kwargs.get('cidr'),
+ 'group_id': kwargs.get('group_id'),
+ }
+ post_body = json.dumps({'security_group_rule': post_body})
+ url = 'os-security-group-rules'
+ resp, body = self.post(url, post_body)
+ body = json.loads(body)
+ self.validate_response(schema.create_security_group_rule, resp, body)
+ return service_client.ResponseBody(resp, body['security_group_rule'])
+
+ def delete_security_group_rule(self, group_rule_id):
+ """Deletes the provided Security Group rule."""
+ resp, body = self.delete('os-security-group-rules/%s' %
+ group_rule_id)
+ self.validate_response(schema.delete_security_group_rule, resp, body)
+ return service_client.ResponseBody(resp, body)
+
+ def list_security_group_rules(self, security_group_id):
+ """List all rules for a security group."""
+ resp, body = self.get('os-security-groups')
+ body = json.loads(body)
+ self.validate_response(schema.list_security_groups, resp, body)
+ for sg in body['security_groups']:
+ if sg['id'] == security_group_id:
+ return service_client.ResponseBodyList(resp, sg['rules'])
+ raise lib_exc.NotFound('No such Security Group')
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index 5a3d771..eec961c 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -86,50 +86,6 @@
self.validate_response(schema.delete_security_group, resp, body)
return service_client.ResponseBody(resp, body)
- def create_security_group_rule(self, parent_group_id, ip_proto, from_port,
- to_port, **kwargs):
- """
- Creating a new security group rules.
- parent_group_id :ID of Security group
- ip_protocol : ip_proto (icmp, tcp, udp).
- from_port: Port at start of range.
- to_port : Port at end of range.
- Following optional keyword arguments are accepted:
- cidr : CIDR for address range.
- group_id : ID of the Source group
- """
- post_body = {
- 'parent_group_id': parent_group_id,
- 'ip_protocol': ip_proto,
- 'from_port': from_port,
- 'to_port': to_port,
- 'cidr': kwargs.get('cidr'),
- 'group_id': kwargs.get('group_id'),
- }
- post_body = json.dumps({'security_group_rule': post_body})
- url = 'os-security-group-rules'
- resp, body = self.post(url, post_body)
- body = json.loads(body)
- self.validate_response(schema.create_security_group_rule, resp, body)
- return service_client.ResponseBody(resp, body['security_group_rule'])
-
- def delete_security_group_rule(self, group_rule_id):
- """Deletes the provided Security Group rule."""
- resp, body = self.delete('os-security-group-rules/%s' %
- group_rule_id)
- self.validate_response(schema.delete_security_group_rule, resp, body)
- return service_client.ResponseBody(resp, body)
-
- def list_security_group_rules(self, security_group_id):
- """List all rules for a security group."""
- resp, body = self.get('os-security-groups')
- body = json.loads(body)
- self.validate_response(schema.list_security_groups, resp, body)
- for sg in body['security_groups']:
- if sg['id'] == security_group_id:
- return service_client.ResponseBodyList(resp, sg['rules'])
- raise lib_exc.NotFound('No such Security Group')
-
def is_resource_deleted(self, id):
try:
self.show_security_group(id)
diff --git a/tempest/services/telemetry/json/telemetry_client.py b/tempest/services/telemetry/json/telemetry_client.py
index 2b1cdc0..1f181e3 100644
--- a/tempest/services/telemetry/json/telemetry_client.py
+++ b/tempest/services/telemetry/json/telemetry_client.py
@@ -84,6 +84,10 @@
uri = '%s/meters/%s' % (self.uri_prefix, meter_id)
return self._helper_list(uri, query)
+ def list_events(self, query=None):
+ uri = '%s/events' % self.uri_prefix
+ return self._helper_list(uri, query)
+
def show_resource(self, resource_id):
uri = '%s/resources/%s' % (self.uri_prefix, resource_id)
resp, body = self.get(uri)
diff --git a/tempest/tests/cmd/test_tempest_init.py b/tempest/tests/cmd/test_tempest_init.py
new file mode 100644
index 0000000..6b5af7e
--- /dev/null
+++ b/tempest/tests/cmd/test_tempest_init.py
@@ -0,0 +1,66 @@
+# Copyright 2015 Hewlett-Packard Development Company, L.P.
+#
+# 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 os
+
+import fixtures
+
+from tempest.cmd import init
+from tempest.tests import base
+
+
+class TestTempestInit(base.TestCase):
+
+ def test_generate_testr_conf(self):
+ # Create fake conf dir
+ conf_dir = self.useFixture(fixtures.TempDir())
+
+ init_cmd = init.TempestInit(None, None)
+ init_cmd.generate_testr_conf(conf_dir.path)
+
+ # Generate expected file contents
+ top_level_path = os.path.dirname(os.path.dirname(init.__file__))
+ discover_path = os.path.join(top_level_path, 'test_discover')
+ testr_conf_file = init.TESTR_CONF % (top_level_path, discover_path)
+
+ conf_path = conf_dir.join('.testr.conf')
+ conf_file = open(conf_path, 'r')
+ self.addCleanup(conf_file.close)
+ self.assertEqual(conf_file.read(), testr_conf_file)
+
+ def test_create_working_dir(self):
+ fake_local_dir = self.useFixture(fixtures.TempDir())
+ fake_local_conf_dir = self.useFixture(fixtures.TempDir())
+ # Create a fake conf file
+ fake_file = fake_local_conf_dir.join('conf_file.conf')
+ open(fake_file, 'w').close()
+ init_cmd = init.TempestInit(None, None)
+ init_cmd.create_working_dir(fake_local_dir.path,
+ fake_local_conf_dir.path)
+ # Assert directories are created
+ lock_path = os.path.join(fake_local_dir.path, 'tempest_lock')
+ etc_dir = os.path.join(fake_local_dir.path, 'etc')
+ log_dir = os.path.join(fake_local_dir.path, 'logs')
+ testr_dir = os.path.join(fake_local_dir.path, '.testrepository')
+ self.assertTrue(os.path.isdir(lock_path))
+ self.assertTrue(os.path.isdir(etc_dir))
+ self.assertTrue(os.path.isdir(log_dir))
+ self.assertTrue(os.path.isdir(testr_dir))
+ # Assert file creation
+ fake_file_moved = os.path.join(etc_dir, 'conf_file.conf')
+ local_conf_file = os.path.join(etc_dir, 'tempest.conf')
+ local_testr_conf = os.path.join(fake_local_dir.path, '.testr.conf')
+ self.assertTrue(os.path.isfile(fake_file_moved))
+ self.assertTrue(os.path.isfile(local_conf_file))
+ self.assertTrue(os.path.isfile(local_testr_conf))
diff --git a/tempest/tests/common/test_service_clients.py b/tempest/tests/common/test_service_clients.py
index 695d4a4..3a0873c 100644
--- a/tempest/tests/common/test_service_clients.py
+++ b/tempest/tests/common/test_service_clients.py
@@ -40,6 +40,7 @@
from tempest.services.compute.json import quotas_client
from tempest.services.compute.json import security_group_default_rules_client \
as nova_secgrop_default_client
+from tempest.services.compute.json import security_group_rules_client
from tempest.services.compute.json import security_groups_client
from tempest.services.compute.json import server_groups_client
from tempest.services.compute.json import servers_client
@@ -130,6 +131,7 @@
quotas_client.QuotasClient,
quota_classes_client.QuotaClassesClient,
nova_secgrop_default_client.SecurityGroupDefaultRulesClient,
+ security_group_rules_client.SecurityGroupRulesClient,
security_groups_client.SecurityGroupsClient,
server_groups_client.ServerGroupsClient,
servers_client.ServersClient,
diff --git a/tempest/tests/services/compute/test_agents_client.py b/tempest/tests/services/compute/test_agents_client.py
index d268a18..8316c90 100644
--- a/tempest/tests/services/compute/test_agents_client.py
+++ b/tempest/tests/services/compute/test_agents_client.py
@@ -14,19 +14,18 @@
import httplib2
+from oslo_serialization import jsonutils as json
from oslotest import mockpatch
from tempest.services.compute.json import agents_client
from tempest.tests import base
from tempest.tests import fake_auth_provider
-from tempest.tests import fake_config
class TestAgentsClient(base.TestCase):
def setUp(self):
super(TestAgentsClient, self).setUp()
- self.useFixture(fake_config.ConfigFixture())
fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = agents_client.AgentsClient(fake_auth,
'compute', 'regionOne')
@@ -34,7 +33,7 @@
def _test_list_agents(self, bytes_body=False):
body = '{"agents": []}'
if bytes_body:
- body = bytes(body.encode('utf-8'))
+ body = body.encode('utf-8')
expected = []
response = (httplib2.Response({'status': 200}), body)
self.useFixture(mockpatch.Patch(
@@ -42,8 +41,64 @@
return_value=response))
self.assertEqual(expected, self.client.list_agents())
+ def _test_create_agent(self, bytes_body=False):
+ expected = {"url": "http://foo.com", "hypervisor": "kvm",
+ "md5hash": "md5", "version": "2", "architecture": "x86_64",
+ "os": "linux", "agent_id": 1}
+ serialized_body = json.dumps({"agent": expected})
+ if bytes_body:
+ serialized_body = serialized_body.encode('utf-8')
+
+ mocked_resp = (httplib2.Response({'status': 200}), serialized_body)
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.service_client.ServiceClient.post',
+ return_value=mocked_resp))
+ resp = self.client.create_agent(
+ url="http://foo.com", hypervisor="kvm", md5hash="md5",
+ version="2", architecture="x86_64", os="linux"
+ )
+ self.assertEqual(expected, resp)
+
+ def _test_delete_agent(self):
+ mocked_resp = (httplib2.Response({'status': 200}), None)
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.service_client.ServiceClient.delete',
+ return_value=mocked_resp))
+ self.client.delete_agent("1")
+
+ def _test_update_agent(self, bytes_body=False):
+ expected = {"url": "http://foo.com", "md5hash": "md5", "version": "2",
+ "agent_id": 1}
+ serialized_body = json.dumps({"agent": expected})
+ if bytes_body:
+ serialized_body = serialized_body.encode('utf-8')
+
+ mocked_resp = (httplib2.Response({'status': 200}), serialized_body)
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.service_client.ServiceClient.put',
+ return_value=mocked_resp))
+ resp = self.client.update_agent(
+ "1", url="http://foo.com", md5hash="md5", version="2"
+ )
+ self.assertEqual(expected, resp)
+
def test_list_agents_with_str_body(self):
self._test_list_agents()
def test_list_agents_with_bytes_body(self):
self._test_list_agents(bytes_body=True)
+
+ def test_create_agent_with_str_body(self):
+ self._test_create_agent()
+
+ def test_create_agent_with_bytes_body(self):
+ self._test_create_agent(bytes_body=True)
+
+ def test_delete_agent(self):
+ self._test_delete_agent()
+
+ def test_update_agent_with_str_body(self):
+ self._test_update_agent()
+
+ def test_update_agent_with_bytes_body(self):
+ self._test_update_agent(bytes_body=True)
diff --git a/tempest/tests/services/compute/test_aggregates_client.py b/tempest/tests/services/compute/test_aggregates_client.py
new file mode 100644
index 0000000..9fe4544
--- /dev/null
+++ b/tempest/tests/services/compute/test_aggregates_client.py
@@ -0,0 +1,47 @@
+# Copyright 2015 NEC Corporation. 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 httplib2
+
+from oslotest import mockpatch
+
+from tempest.services.compute.json import aggregates_client
+from tempest.tests import base
+from tempest.tests import fake_auth_provider
+
+
+class TestAggregatesClient(base.TestCase):
+
+ def setUp(self):
+ super(TestAggregatesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = aggregates_client.AggregatesClient(
+ fake_auth, 'compute', 'regionOne')
+
+ def _test_list_aggregates(self, bytes_body=False):
+ body = '{"aggregates": []}'
+ if bytes_body:
+ body = body.encode('utf-8')
+ expected = []
+ response = (httplib2.Response({'status': 200}), body)
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.service_client.ServiceClient.get',
+ return_value=response))
+ self.assertEqual(expected, self.client.list_aggregates())
+
+ def test_list_aggregates_with_str_body(self):
+ self._test_list_aggregates()
+
+ def test_list_aggregates_with_bytes_body(self):
+ self._test_list_aggregates(bytes_body=True)
diff --git a/tempest/tests/services/compute/test_keypairs_client.py b/tempest/tests/services/compute/test_keypairs_client.py
new file mode 100644
index 0000000..e79e411
--- /dev/null
+++ b/tempest/tests/services/compute/test_keypairs_client.py
@@ -0,0 +1,47 @@
+# Copyright 2015 NEC Corporation. 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 httplib2
+
+from oslotest import mockpatch
+
+from tempest.services.compute.json import keypairs_client
+from tempest.tests import base
+from tempest.tests import fake_auth_provider
+
+
+class TestKeyPairsClient(base.TestCase):
+
+ def setUp(self):
+ super(TestKeyPairsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = keypairs_client.KeyPairsClient(
+ fake_auth, 'compute', 'regionOne')
+
+ def _test_list_keypairs(self, bytes_body=False):
+ body = '{"keypairs": []}'
+ if bytes_body:
+ body = body.encode('utf-8')
+ expected = []
+ response = (httplib2.Response({'status': 200}), body)
+ self.useFixture(mockpatch.Patch(
+ 'tempest.common.service_client.ServiceClient.get',
+ return_value=response))
+ self.assertEqual(expected, self.client.list_keypairs())
+
+ def test_list_keypairs_with_str_body(self):
+ self._test_list_keypairs()
+
+ def test_list_keypairs_with_bytes_body(self):
+ self._test_list_keypairs(bytes_body=True)
diff --git a/test-requirements.txt b/test-requirements.txt
index 65e3531..2ea30ec 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -9,4 +9,4 @@
mox>=0.5.3
mock>=1.2
coverage>=3.6
-oslotest>=1.7.0 # Apache-2.0
+oslotest>=1.9.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index cf7013d..389fee2 100644
--- a/tox.ini
+++ b/tox.ini
@@ -40,6 +40,16 @@
find . -type f -name "*.pyc" -delete
bash tools/pretty_tox.sh '{posargs}'
+[testenv:all-plugin]
+sitepackages = True
+# 'all' includes slow tests
+setenv = {[tempestenv]setenv}
+ OS_TEST_TIMEOUT=1200
+deps = {[tempestenv]deps}
+commands =
+ find . -type f -name "*.pyc" -delete
+ bash tools/pretty_tox.sh '{posargs}'
+
[testenv:full]
sitepackages = {[tempestenv]sitepackages}
setenv = {[tempestenv]setenv}