trio2o/tricircle/common/resource_handle.py
XiongQiu 7b6a6af766 Implement volume actions
The purpose of this patch set is to provide the end users with
the following functionalities:
1. Extend the size of the specified volume.
2. Set attachment metadata of the specified volume.
3. Update state of the specified volume.
4. Set image metadata of the specified volume.
5. Unset image metadata of the specified volume.
6. Show image metadata of the specified volume.

Change-Id: Ie9e4ca15a412c89a3c44f1b8526e6597eddf762c
2016-06-25 18:46:24 +08:00

355 lines
14 KiB
Python

# Copyright 2015 Huawei Technologies Co., Ltd.
# 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 cinderclient import client as c_client
from cinderclient import exceptions as c_exceptions
import glanceclient as g_client
import glanceclient.exc as g_exceptions
from neutronclient.common import exceptions as q_exceptions
from neutronclient.neutron import client as q_client
from novaclient import client as n_client
from novaclient import exceptions as n_exceptions
from oslo_config import cfg
from oslo_log import log as logging
from requests import exceptions as r_exceptions
from tricircle.common import constants as cons
from tricircle.common import exceptions
client_opts = [
cfg.IntOpt('cinder_timeout',
default=60,
help='timeout for cinder client in seconds'),
cfg.IntOpt('glance_timeout',
default=60,
help='timeout for glance client in seconds'),
cfg.IntOpt('neutron_timeout',
default=60,
help='timeout for neutron client in seconds'),
cfg.IntOpt('nova_timeout',
default=60,
help='timeout for nova client in seconds'),
]
cfg.CONF.register_opts(client_opts, group='client')
LIST, CREATE, DELETE, GET, ACTION, UPDATE = 1, 2, 4, 8, 16, 32
operation_index_map = {'list': LIST, 'create': CREATE, 'delete': DELETE,
'get': GET, 'action': ACTION, 'update': UPDATE}
LOG = logging.getLogger(__name__)
def _transform_filters(filters):
filter_dict = {}
for query_filter in filters:
# only eq filter supported at first
if query_filter['comparator'] != 'eq':
continue
key = query_filter['key']
value = query_filter['value']
filter_dict[key] = value
return filter_dict
class ResourceHandle(object):
def __init__(self, auth_url):
self.auth_url = auth_url
self.endpoint_url = None
def is_endpoint_url_set(self):
return self.endpoint_url is not None
def update_endpoint_url(self, url):
self.endpoint_url = url
class GlanceResourceHandle(ResourceHandle):
service_type = cons.ST_GLANCE
support_resource = {'image': LIST | GET}
def _get_client(self, cxt):
return g_client.Client('1',
token=cxt.auth_token,
auth_url=self.auth_url,
endpoint=self.endpoint_url,
timeout=cfg.CONF.client.glance_timeout)
def handle_list(self, cxt, resource, filters):
try:
client = self._get_client(cxt)
collection = '%ss' % resource
return [res.to_dict() for res in getattr(
client, collection).list(filters=_transform_filters(filters))]
except g_exceptions.InvalidEndpoint:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable('glance',
client.http_client.endpoint)
def handle_get(self, cxt, resource, resource_id):
try:
client = self._get_client(cxt)
collection = '%ss' % resource
return getattr(client, collection).get(resource_id).to_dict()
except g_exceptions.InvalidEndpoint:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable('glance',
client.http_client.endpoint)
except g_exceptions.HTTPNotFound:
LOG.debug("%(resource)s %(resource_id)s not found",
{'resource': resource, 'resource_id': resource_id})
class NeutronResourceHandle(ResourceHandle):
service_type = cons.ST_NEUTRON
support_resource = {'network': LIST | CREATE | DELETE | GET,
'subnet': LIST | CREATE | DELETE | GET,
'port': LIST | CREATE | DELETE | GET,
'router': LIST | CREATE | ACTION | UPDATE,
'security_group': LIST | CREATE | GET,
'security_group_rule': LIST | CREATE | DELETE,
'floatingip': LIST | CREATE | UPDATE | DELETE}
def _get_client(self, cxt):
return q_client.Client('2.0',
token=cxt.auth_token,
auth_url=self.auth_url,
endpoint_url=self.endpoint_url,
timeout=cfg.CONF.client.neutron_timeout)
def handle_list(self, cxt, resource, filters):
try:
client = self._get_client(cxt)
collection = '%ss' % resource
search_opts = _transform_filters(filters)
return [res for res in getattr(
client, 'list_%s' % collection)(**search_opts)[collection]]
except q_exceptions.ConnectionFailed:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable(
'neutron', client.httpclient.endpoint_url)
def handle_create(self, cxt, resource, *args, **kwargs):
try:
client = self._get_client(cxt)
ret = getattr(client, 'create_%s' % resource)(
*args, **kwargs)
if resource in ret:
return ret[resource]
else:
return ret['%ss' % resource]
except q_exceptions.ConnectionFailed:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable(
'neutron', client.httpclient.endpoint_url)
def handle_update(self, cxt, resource, *args, **kwargs):
try:
client = self._get_client(cxt)
return getattr(client, 'update_%s' % resource)(
*args, **kwargs)[resource]
except q_exceptions.ConnectionFailed:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable(
'neutron', client.httpclient.endpoint_url)
def handle_get(self, cxt, resource, resource_id):
try:
client = self._get_client(cxt)
return getattr(client, 'show_%s' % resource)(resource_id)[resource]
except q_exceptions.ConnectionFailed:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable(
'neutron', client.httpclient.endpoint_url)
except q_exceptions.NotFound:
LOG.debug("%(resource)s %(resource_id)s not found",
{'resource': resource, 'resource_id': resource_id})
def handle_delete(self, cxt, resource, resource_id):
try:
client = self._get_client(cxt)
return getattr(client, 'delete_%s' % resource)(resource_id)
except q_exceptions.ConnectionFailed:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable(
'neutron', client.httpclient.endpoint_url)
except q_exceptions.NotFound:
LOG.debug("Delete %(resource)s %(resource_id)s which not found",
{'resource': resource, 'resource_id': resource_id})
def handle_action(self, cxt, resource, action, *args, **kwargs):
try:
client = self._get_client(cxt)
return getattr(client, '%s_%s' % (action, resource))(*args,
**kwargs)
except q_exceptions.ConnectionFailed:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable(
'neutron', client.httpclient.endpoint_url)
def _convert_into_with_meta(item, resp):
return resp, item
class NovaResourceHandle(ResourceHandle):
service_type = cons.ST_NOVA
support_resource = {'flavor': LIST,
'server': LIST | CREATE | DELETE | GET | ACTION,
'aggregate': LIST | CREATE | DELETE | ACTION,
'server_volume': ACTION}
def _get_client(self, cxt):
cli = n_client.Client('2',
auth_token=cxt.auth_token,
auth_url=self.auth_url,
timeout=cfg.CONF.client.nova_timeout)
cli.set_management_url(
self.endpoint_url.replace('$(tenant_id)s', cxt.tenant))
return cli
def _adapt_resource(self, resource):
if resource == 'server_volume':
return 'volume'
else:
return resource
def handle_list(self, cxt, resource, filters):
try:
resource = self._adapt_resource(resource)
client = self._get_client(cxt)
collection = '%ss' % resource
# only server list supports filter
if resource == 'server':
search_opts = _transform_filters(filters)
return [res.to_dict() for res in getattr(
client, collection).list(search_opts=search_opts)]
else:
return [res.to_dict() for res in getattr(client,
collection).list()]
except r_exceptions.ConnectTimeout:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable('nova',
client.client.management_url)
def handle_create(self, cxt, resource, *args, **kwargs):
try:
resource = self._adapt_resource(resource)
client = self._get_client(cxt)
collection = '%ss' % resource
return getattr(client, collection).create(
*args, **kwargs).to_dict()
except r_exceptions.ConnectTimeout:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable('nova',
client.client.management_url)
def handle_get(self, cxt, resource, resource_id):
try:
resource = self._adapt_resource(resource)
client = self._get_client(cxt)
collection = '%ss' % resource
return getattr(client, collection).get(resource_id).to_dict()
except r_exceptions.ConnectTimeout:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable('nova',
client.client.management_url)
except n_exceptions.NotFound:
LOG.debug("%(resource)s %(resource_id)s not found",
{'resource': resource, 'resource_id': resource_id})
def handle_delete(self, cxt, resource, resource_id):
try:
resource = self._adapt_resource(resource)
client = self._get_client(cxt)
collection = '%ss' % resource
return getattr(client, collection).delete(resource_id)
except r_exceptions.ConnectTimeout:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable('nova',
client.client.management_url)
except n_exceptions.NotFound:
LOG.debug("Delete %(resource)s %(resource_id)s which not found",
{'resource': resource, 'resource_id': resource_id})
def handle_action(self, cxt, resource, action, *args, **kwargs):
try:
resource = self._adapt_resource(resource)
client = self._get_client(cxt)
collection = '%ss' % resource
resource_manager = getattr(client, collection)
resource_manager.convert_into_with_meta = _convert_into_with_meta
# NOTE(zhiyuan) yes, this is a dirty hack. but the original
# implementation hides response object which is needed
return getattr(resource_manager, action)(*args, **kwargs)
except r_exceptions.ConnectTimeout:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable('nova',
client.client.management_url)
class CinderResourceHandle(ResourceHandle):
service_type = cons.ST_CINDER
support_resource = {'volume': LIST | CREATE | DELETE | GET | ACTION,
'transfer': CREATE | ACTION}
def _get_client(self, cxt):
cli = c_client.Client('2',
auth_url=self.auth_url,
timeout=cfg.CONF.client.cinder_timeout)
cli.client.set_management_url(
self.endpoint_url.replace('$(tenant_id)s', cxt.tenant))
cli.client.auth_token = cxt.auth_token
return cli
def handle_get(self, cxt, resource, resource_id):
try:
client = self._get_client(cxt)
collection = '%ss' % resource
res = getattr(client, collection).get(resource_id)
info = {}
info.update(res._info)
return info
except r_exceptions.ConnectTimeout:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable('cinder',
client.client.management_url)
def handle_delete(self, cxt, resource, resource_id):
try:
client = self._get_client(cxt)
collection = '%ss' % resource
return getattr(client, collection).delete(resource_id)
except r_exceptions.ConnectTimeout:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable('cinder',
client.client.management_url)
except c_exceptions.NotFound:
LOG.debug("Delete %(resource)s %(resource_id)s which not found",
{'resource': resource, 'resource_id': resource_id})
def handle_action(self, cxt, resource, action, *args, **kwargs):
try:
client = self._get_client(cxt)
collection = '%ss' % resource
resource_manager = getattr(client, collection)
getattr(resource_manager, action)(*args, **kwargs)
except r_exceptions.ConnectTimeout:
self.endpoint_url = None
raise exceptions.EndpointNotAvailable('cinder',
client.client.management_url)