Chi Lo 446168b7bd Display Ranger error response messasge in tempest exception
When resource creation failed, the region's error message is
retrieved and included as part of the tempest exception
message.

Change-Id: I6309b29ad516651b9a89ffe54763d11fb56949a4
2020-11-10 07:14:33 -08:00

365 lines
14 KiB
Python
Executable File

# Copyright 2016 AT&T 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.
import random
import time
import uuid
from oslo_log import log as logging
from ranger_tempest_plugin.tests.api import base
from tempest import config
from tempest.lib import exceptions
from tempest.lib.common.utils import data_utils
CONF = config.CONF
LOG = logging.getLogger(__name__)
class FmsBaseOrmTest(base.BaseOrmTest):
credentials = ['admin', 'primary', 'alt']
@classmethod
def setup_clients(cls):
super(FmsBaseOrmTest, cls).setup_clients()
cls.client = cls.os_primary.fms_client
cls.flavors_client = cls.os_admin.flavors_client
cls.rms_client = cls.os_primary.rms_client
cls.cms_client = cls.os_primary.cms_client
@classmethod
def resource_setup(cls):
super(FmsBaseOrmTest, cls).resource_setup()
cls.tenant_id = None
cls.alt_tenant_id = None
@classmethod
def resource_cleanup(cls):
super(FmsBaseOrmTest, cls).resource_cleanup()
@classmethod
def _create_customer(cls):
cust = {}
cust['description'] = ''
cust['enabled'] = True
cust['name'] = data_utils.rand_name('ormTempestFms')
cust['regions'] = [{'name': CONF.identity.region, 'type': 'single'}]
cust['defaultQuotas'] = []
cust['users'] = []
cust['uuid'] = uuid.uuid4().hex
_, body = cls.cms_client.create_customer(**cust)
customer_id = body["customer"]["id"]
_, customer = cls.cms_client.get_customer(customer_id)
if customer["name"] != cust["name"]:
message = "Customer %s creation FAILED" % cust["name"]
exceptions.TempestException(message)
customer_status = customer["status"]
expected_status = 'Success'
start = int(time.time())
while customer_status != expected_status:
time.sleep(cls.build_interval)
_, customer = cls.cms_client.get_customer(customer_id)
customer_status = customer["status"]
if customer_status == 'Error':
message = ""
for region in customer["regions"]:
if "error_message" in region:
message += "Region %s Error: %s. " % (
region["name"], region["error_message"])
if not message:
message = ('Customer %s failed to reach %s status and is'
' in ERROR status' % (customer_id,
expected_status))
raise exceptions.ServerFault(message)
if int(time.time()) - start >= cls.build_timeout:
message = ('Customer %s failed to reach %s'
'status within the required time (%s s) '
'and is in %s status.'
% (customer_id, expected_status,
cls.build_timeout,
customer_status))
raise exceptions.TimeoutException(message)
return customer_id
@classmethod
def _del_cust_validate_deletion_on_dcp_and_lcp(cls, customer_id):
_, customer = cls.cms_client.get_customer(customer_id)
regions_on_customer = \
[region['name'] for region in customer["regions"]]
for region in regions_on_customer:
cls.cms_client.delete_region_from_customer(customer_id, region)
time.sleep(cls.build_timeout)
_, body = cls.cms_client.get_customer(customer_id)
if len(body['regions']) != 0:
message = \
'Failed to delete regions for customer %s' % customer_id
raise exceptions.TimeoutException(message)
cls.cms_client.delete_customer(customer_id)
cls._validate_customer_deletion_on_lcp(customer_id)
@classmethod
def _validate_customer_deletion_on_lcp(cls, customer_id):
body = cls.project_client.list_projects()["projects"]
customer_ids = [customer["id"]
for customer in body
if customer["id"] == customer_id]
if customer_ids:
message = "customer %s failed to get deleted on lcp" \
% customer_id
raise exceptions.TempestException(message)
@classmethod
def _get_flavor_params(cls, set_region=True, single_tenant=True,
public=False):
post_body, region = {}, {}
region["name"] = CONF.identity.region
ram = random.randint(1, 4) * 1024
swap = random.randint(1, 40) * 1024
vcpus = random.randint(2, 36)
disk = random.randint(2, 102)
post_body['id'] = uuid.uuid4().hex
post_body["description"] = \
"orm-plugin-BaseORMTest-flavor"
post_body["series"] = random.choice(CONF.ranger.flavor_series)
post_body["alias"] = "flavor_alias"
post_body["ram"] = str(ram)
post_body["vcpus"] = str(vcpus)
post_body["disk"] = str(disk)
post_body["swap"] = str(swap)
post_body["ephemeral"] = "1024"
post_body["regions"] = [region] if set_region else []
post_body["visibility"] = "private" if not public else "public"
post_body['tag'] = {'a': 'b', 'c': 'd'}
if public:
post_body["tenants"] = []
else:
if single_tenant:
post_body["tenants"] = [cls.tenant_id]
else:
post_body["tenants"] = [cls.tenant_id, cls.alt_tenant_id]
return post_body
@classmethod
def _create_flv_and_validate_creation_on_dcp_and_lcp(cls, **kwargs):
"""kwargs contain all field data needed in a flavor POST body:
- name
- description
- alias
- ram
- vcpus
- disk
- swap
- ephemeral
- regions
- visibility
- tenants
"""
_, body = cls.client.create_flavor(**kwargs)
flavor = body["flavor"]
flavor_id = flavor["id"]
_, body = cls.client.get_flavor(flavor_id)
flavor_detail = body["flavor"]
if flavor_detail["vcpus"] != kwargs["vcpus"]:
message = "Flavor %s not created successfully" % flavor_id
raise exceptions.TempestException(message)
if flavor_detail["regions"] != []:
flavor_id = flavor_detail["id"]
cls._wait_for_flavor_status_on_dcp(flavor_id, 'Success')
cls._validate_flavor_creation_on_lcp(flavor_id)
return flavor
@classmethod
def _wait_for_flavor_status_on_dcp(cls, flavor_id, status):
_, body = cls.client.get_flavor(flavor_id)
flavor = body["flavor"]
flavor_status = flavor["status"]
start = int(time.time())
while flavor_status != status:
time.sleep(cls.build_interval)
_, body = cls.client.get_flavor(flavor_id)
flavor = body["flavor"]
flavor_status = flavor["status"]
if flavor_status == 'Error':
# Some test cases have multiple regions
message = ""
for region in flavor["regions"]:
if "error_message" in region:
message += "Region %s Error: %s. " % (
region["name"], region["error_message"])
if not message:
message = ('Flavor %s failed to reach %s status'
' and is in ERROR status' % (flavor_id, status))
raise exceptions.ServerFault(message)
if int(time.time()) - start >= cls.build_timeout:
message = ('Flavor %s failed to reach %s status within'
' the required time (%s s) and is in'
' %s status.') % (flavor_id, status,
cls.build_timeout,
flavor_status)
raise exceptions.TimeoutException(message)
@classmethod
def _validate_flavor_creation_on_lcp(cls, flavor_id):
_, body = cls.client.list_flavors()
flavor = [flavor["id"] for flavor in body["flavors"]
if flavor["id"] == flavor_id]
if not flavor:
message = "flavor %s not in nova flavor list" % flavor_id
raise exceptions.TempestException(message)
@classmethod
def _validate_flv_extraspecs_on_dcp_and_lcp(cls, flavor_id,
expected_specs):
expected_specs_count = len(expected_specs)
_, body = cls.client.get_flavor(flavor_id)
flavor_orm = body["flavor"]
flavor_lcp = cls.flavors_client.show_flavor(flavor_id)["flavor"]
def _validate_extra_specs(flv):
actual_specs_count = 0
actual_specs = {}
for spec in flv["extra-specs"]:
actual_specs[spec] = flv["extra-specs"][spec]
for spec in expected_specs:
if spec in actual_specs:
if expected_specs[spec] == actual_specs[spec]:
actual_specs_count += 1
return bool(expected_specs_count == actual_specs_count)
return bool(_validate_extra_specs(flavor_orm)
and _validate_extra_specs(flavor_lcp))
@classmethod
def _del_flv_and_validate_deletion_on_dcp_and_lcp(cls, flavor_id):
_, body = cls.client.get_flavor(flavor_id)
regions_on_flavor = \
[region['name'] for region in body["flavor"]["regions"]]
for regs in regions_on_flavor:
cls._delete_region_from_flavor_and_validate_deletion(
flavor_id, regs)
cls.client.delete_flavor(flavor_id)
cls._wait_for_flavor_deletion_on_dcp(flavor_id)
cls._validate_flavor_deletion_on_lcp(flavor_id)
@classmethod
def _delete_region_from_flavor_and_validate_deletion(
cls, flavor_id, rname):
cls.client.delete_region_from_flavor(flavor_id, rname)
_, body = cls.client.get_flavor(flavor_id)
loopcount = 0
while loopcount < 10:
if len(body['flavor']['regions']) == 0:
break
for regions_on_flavor in body['flavor']['regions']:
if regions_on_flavor['name'] == rname:
time.sleep(cls.build_interval)
_, body = cls.client.get_flavor(flavor_id)
break
loopcount += 1
for regions_on_flavor in body['flavor']['regions']:
if regions_on_flavor['name'] == rname:
message = \
'Region {} failed to get deleted from flavor {}' \
.format(rname, flavor_id)
raise exceptions.TimeoutException(message)
@classmethod
def _wait_for_flavor_deletion_on_dcp(cls, flavor_id):
_, body = cls.client.list_flavors()
flavor_ids = [flavor["id"] for flavor in body["flavors"]
if flavor["id"] == flavor_id]
start = int(time.time())
while flavor_ids:
time.sleep(cls.build_interval)
_, body = cls.client.list_flavors()
flavor_ids = [flavor["id"] for flavor in body["flavors"]
if flavor["id"] == flavor_id]
if flavor_ids:
flavor_status = flavor_ids[0]["status"]
if flavor_status == 'Error':
message = \
('Flavor %s failed to get deleted'
'and is in error status') % flavor_id
raise exceptions.TempestException(message)
if int(time.time()) - start >= cls.build_timeout:
message = (
'flavor %s failed to get deleted within '
'the required time (%s s) and is in %s status.'
% (flavor_id, cls.build_timeout, flavor_status))
raise exceptions.TimeoutException(message)
@classmethod
def _validate_flavor_deletion_on_lcp(cls, flavor_id):
body = cls.flavors_client.list_flavors()["flavors"]
flavor_ids = [flavor["id"] for flavor in body]
if flavor_id in flavor_ids:
flavor_status = cls.flavors_client.show_flavor(
flavor_id)["flavor"]["status"]
message = "flavor %s failed to get deleted and is in %s status" \
% (flavor_id, flavor_status)
raise exceptions.TempestException(message)
@classmethod
def _get_project_id(cls, project_name):
body = cls.project_client.list_projects()
for project in body["projects"]:
if(project["name"] == project_name):
return project["id"]
message = ('project %s not found on projects list' % project_name)
raise exceptions.TempestException(message)
@classmethod
def _get_expected_flavor_name(cls, post_body):
name = post_body["series"] + "." + "c" + \
post_body["vcpus"] + "r" + \
str(int(post_body["ram"]) // 1024) \
+ "d" + post_body["disk"] + "s" + \
str(int(post_body["swap"]) // 1024) \
+ "e" + str(int(post_body["ephemeral"]) // 1024)
return name
@classmethod
def _validate_flv_geometry_on_lcp(cls, flavor_id, post_body):
flv = cls.flavors_client.show_flavor(flavor_id)["flavor"]
return bool(flv["vcpus"] == int(post_body["vcpus"])
and flv["ram"] == post_body["ram"]
and flv["swap"] == int(post_body["swap"])
and flv["disk"] == int(post_body["disk"])
and flv["ephemeral"] == post_body["ephemeral"])