1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
# Copyright 2014: Mirantis Inc.
# 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 rally.common import cfg
from rally.task import utils
CONF = cfg.CONF
cleanup_group = cfg.OptGroup(name="cleanup", title="Cleanup Options")
# NOTE(andreykurilin): There are cases when there is no way to use any kind
# of "name" for resource as an identifier of alignment resource to the
# particular task run and even to Rally itself. Previously, we used empty
# strings as a workaround for name matching specific templates, but
# theoretically such behaviour can hide other cases when resource should have
# a name property, but it is missed.
# Let's use instances of specific class to return as a name of resources
# which do not have names at all.
class NoName(object):
def __init__(self, resource_type):
self.resource_type = resource_type
def __repr__(self):
return "<NoName %s resource>" % self.resource_type
def resource(service, resource, order=0, admin_required=False,
perform_for_admin_only=False, tenant_resource=False,
max_attempts=3, timeout=CONF.openstack.resource_deletion_timeout,
interval=1, threads=CONF.openstack.cleanup_threads):
"""Decorator that overrides resource specification.
Just put it on top of your resource class and specify arguments that you
need.
:param service: It is equal to client name for corresponding service.
E.g. "nova", "cinder" or "zaqar"
:param resource: Client manager name for resource. E.g. in case of
nova.servers you should write here "servers"
:param order: Used to adjust priority of cleanup for different resource
types
:param admin_required: Admin user is required
:param perform_for_admin_only: Perform cleanup for admin user only
:param tenant_resource: Perform deletion only 1 time per tenant
:param max_attempts: Max amount of attempts to delete single resource
:param timeout: Max duration of deletion in seconds
:param interval: Resource status pooling interval
:param threads: Amount of threads (workers) that are deleting resources
simultaneously
"""
def inner(cls):
# TODO(boris-42): This can be written better I believe =)
cls._service = service
cls._resource = resource
cls._order = order
cls._admin_required = admin_required
cls._perform_for_admin_only = perform_for_admin_only
cls._max_attempts = max_attempts
cls._timeout = timeout
cls._interval = interval
cls._threads = threads
cls._tenant_resource = tenant_resource
return cls
return inner
@resource(service=None, resource=None)
class ResourceManager(object):
"""Base class for cleanup plugins for specific resources.
You should use @resource decorator to specify major configuration of
resource manager. Usually you should specify: service, resource and order.
If project python client is very specific, you can override delete(),
list() and is_deleted() methods to make them fit to your case.
"""
def __init__(self, resource=None, admin=None, user=None, tenant_uuid=None):
self.admin = admin
self.user = user
self.raw_resource = resource
self.tenant_uuid = tenant_uuid
def _manager(self):
client = self._admin_required and self.admin or self.user
return getattr(getattr(client, self._service)(), self._resource)
def id(self):
"""Returns id of resource."""
return self.raw_resource.id
def name(self):
"""Returns name of resource."""
return self.raw_resource.name
def is_deleted(self):
"""Checks if the resource is deleted.
Fetch resource by id from service and check it status.
In case of NotFound or status is DELETED or DELETE_COMPLETE returns
True, otherwise False.
"""
try:
resource = self._manager().get(self.id())
except Exception as e:
return getattr(e, "code", getattr(e, "http_status", 400)) == 404
return utils.get_status(resource) in ("DELETED", "DELETE_COMPLETE")
def delete(self):
"""Delete resource that corresponds to instance of this class."""
self._manager().delete(self.id())
def list(self):
"""List all resources specific for admin or user."""
return self._manager().list()
|