Add parameters field for protectable instances API

Scenario #1
User need a parameter for the region name to query resource
instances from different region endpoint.

Scenario #2
User uses the Protectable Instances API to query database
instances from the verdor's backup software. User must provide
some parameters about authentication to the restfull API of the
verdor's backup software.

A dict type parameter is needed for Protectable Instances API.
And it is optional.

blueprint instances-parameters

Change-Id: I6677e86467c516433a1ba15eac42f339b953d3d9
This commit is contained in:
chenying 2016-09-27 15:35:56 +08:00
parent 1a8adb3014
commit 8af4ffc5f7
11 changed files with 65 additions and 32 deletions

View File

@ -765,6 +765,7 @@ paths:
- $ref: '#/parameters/sortParam' - $ref: '#/parameters/sortParam'
- $ref: '#/parameters/limitParam' - $ref: '#/parameters/limitParam'
- $ref: '#/parameters/markerParam' - $ref: '#/parameters/markerParam'
- $ref: '#/parameters/parametersParam'
tags: tags:
- Protectable - Protectable
- Resource - Resource
@ -811,6 +812,7 @@ paths:
- $ref: '#/parameters/projectParam' - $ref: '#/parameters/projectParam'
- $ref: '#/parameters/protectable_typeParam' - $ref: '#/parameters/protectable_typeParam'
- $ref: '#/parameters/resource_idParam' - $ref: '#/parameters/resource_idParam'
- $ref: '#/parameters/parametersParam'
tags: tags:
- Protectable - Protectable
- Resource - Resource
@ -1893,6 +1895,12 @@ parameters:
response as the marker parameter value in a subsequent limited request. response as the marker parameter value in a subsequent limited request.
type: string type: string
parametersParam:
name: parameters
in: query
description: |
The parameters field for protectable instances query.
type: string
provider_idParam: provider_idParam:
name: provider_id name: provider_id
in: path in: path

View File

@ -11,7 +11,6 @@
# under the License. # under the License.
"""The protectables api.""" """The protectables api."""
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
@ -126,6 +125,7 @@ class ProtectablesController(wsgi.Controller):
"""Return data about the given protectable_type.""" """Return data about the given protectable_type."""
context = req.environ['karbor.context'] context = req.environ['karbor.context']
protectable_type = id protectable_type = id
LOG.info(_LI("Show the information of a given" LOG.info(_LI("Show the information of a given"
" protectable type: %s"), protectable_type) " protectable type: %s"), protectable_type)
@ -181,6 +181,13 @@ class ProtectablesController(wsgi.Controller):
marker, limit, offset = common.get_pagination_params(params) marker, limit, offset = common.get_pagination_params(params)
sort_keys, sort_dirs = common.get_sort_params(params) sort_keys, sort_dirs = common.get_sort_params(params)
filters = params filters = params
utils.check_filters(filters)
parameters = filters.get("parameters", None)
if parameters is not None:
if not isinstance(parameters, dict):
msg = _("The parameters must be a dict.")
raise exception.InvalidInput(reason=msg)
utils.remove_invalid_filter_options( utils.remove_invalid_filter_options(
context, context,
@ -193,11 +200,10 @@ class ProtectablesController(wsgi.Controller):
msg = _("Invalid protectable type provided.") msg = _("Invalid protectable type provided.")
raise exception.InvalidInput(reason=msg) raise exception.InvalidInput(reason=msg)
utils.check_filters(filters)
instances = self._instances_get_all( instances = self._instances_get_all(
context, protectable_type, marker, limit, context, protectable_type, marker, limit,
sort_keys=sort_keys, sort_dirs=sort_dirs, sort_keys=sort_keys, sort_dirs=sort_dirs,
filters=filters, offset=offset) filters=filters, offset=offset, parameters=parameters)
for instance in instances: for instance in instances:
protectable_id = instance.get("id") protectable_id = instance.get("id")
@ -216,7 +222,7 @@ class ProtectablesController(wsgi.Controller):
def _instances_get_all(self, context, protectable_type, marker=None, def _instances_get_all(self, context, protectable_type, marker=None,
limit=None, sort_keys=None, sort_dirs=None, limit=None, sort_keys=None, sort_dirs=None,
filters=None, offset=None): filters=None, offset=None, parameters=None):
check_policy(context, 'get_all') check_policy(context, 'get_all')
if filters is None: if filters is None:
@ -240,7 +246,8 @@ class ProtectablesController(wsgi.Controller):
sort_keys=sort_keys, sort_keys=sort_keys,
sort_dirs=sort_dirs, sort_dirs=sort_dirs,
filters=filters, filters=filters,
offset=offset) offset=offset,
parameters=parameters)
LOG.info(_LI("Get all instances completed successfully.")) LOG.info(_LI("Get all instances completed successfully."))
return instances return instances
@ -253,9 +260,18 @@ class ProtectablesController(wsgi.Controller):
"""Return a instance about the given protectable_type and id.""" """Return a instance about the given protectable_type and id."""
context = req.environ['karbor.context'] context = req.environ['karbor.context']
params = req.params.copy()
utils.check_filters(params)
parameters = params.get("parameters", None)
LOG.info(_LI("Show the instance of a given protectable" LOG.info(_LI("Show the instance of a given protectable"
" type: %s"), protectable_type) " type: %s"), protectable_type)
if parameters is not None:
if not isinstance(parameters, dict):
msg = _("The parameters must be a dict.")
raise exception.InvalidInput(reason=msg)
protectable_types = self._get_all(context) protectable_types = self._get_all(context)
if protectable_type not in protectable_types: if protectable_type not in protectable_types:
@ -264,7 +280,7 @@ class ProtectablesController(wsgi.Controller):
instance = self.protection_api.\ instance = self.protection_api.\
show_protectable_instance(context, protectable_type, show_protectable_instance(context, protectable_type,
protectable_id) protectable_id, parameters=parameters)
if instance is None: if instance is None:
raise exception.InvalidProtectableInstance( raise exception.InvalidProtectableInstance(
protectable_id=instance.get('id')) protectable_id=instance.get('id'))

View File

@ -61,11 +61,11 @@ class API(base.Base):
def list_protectable_instances(self, context, protectable_type, def list_protectable_instances(self, context, protectable_type,
marker, limit, sort_keys, marker, limit, sort_keys,
sort_dirs, filters, offset): sort_dirs, filters, offset, parameters):
return self.protection_rpcapi.\ return self.protection_rpcapi.\
list_protectable_instances(context, protectable_type, list_protectable_instances(context, protectable_type,
marker, limit, sort_keys, marker, limit, sort_keys,
sort_dirs, filters) sort_dirs, filters, parameters)
def list_protectable_dependents(self, context, def list_protectable_dependents(self, context,
protectable_id, protectable_id,
@ -77,11 +77,13 @@ class API(base.Base):
def show_protectable_instance(self, context, def show_protectable_instance(self, context,
protectable_type, protectable_type,
protectable_id): protectable_id,
parameters=None):
return self.protection_rpcapi.\ return self.protection_rpcapi.\
show_protectable_instance(context, show_protectable_instance(context,
protectable_type, protectable_type,
protectable_id) protectable_id,
parameters=parameters)
def show_provider(self, context, provider_id): def show_provider(self, context, provider_id):
return self.protection_rpcapi.\ return self.protection_rpcapi.\

View File

@ -284,14 +284,15 @@ class ProtectionManager(manager.Manager):
limit=None, limit=None,
sort_keys=None, sort_keys=None,
sort_dirs=None, sort_dirs=None,
filters=None): filters=None,
parameters=None):
LOG.info(_LI("Start to list protectable instances of type: %s"), LOG.info(_LI("Start to list protectable instances of type: %s"),
protectable_type) protectable_type)
try: try:
resource_instances = self.protectable_registry.list_resources( resource_instances = self.protectable_registry.list_resources(
context, protectable_type) context, protectable_type, parameters)
except exception.ListProtectableResourceFailed as err: except exception.ListProtectableResourceFailed as err:
LOG.error(_LE("List resources of type %(type)s failed: %(err)s"), LOG.error(_LE("List resources of type %(type)s failed: %(err)s"),
{'type': protectable_type, {'type': protectable_type,
@ -306,7 +307,7 @@ class ProtectionManager(manager.Manager):
@messaging.expected_exceptions(exception.ListProtectableResourceFailed) @messaging.expected_exceptions(exception.ListProtectableResourceFailed)
def show_protectable_instance(self, context, protectable_type, def show_protectable_instance(self, context, protectable_type,
protectable_id): protectable_id, parameters=None):
LOG.info(_LI("Start to show protectable instance of type: %s"), LOG.info(_LI("Start to show protectable instance of type: %s"),
protectable_type) protectable_type)
@ -314,7 +315,8 @@ class ProtectionManager(manager.Manager):
resource_instance = \ resource_instance = \
self.protectable_registry.show_resource(context, self.protectable_registry.show_resource(context,
protectable_type, protectable_type,
protectable_id) protectable_id,
parameters=parameters)
except exception.ListProtectableResourceFailed as err: except exception.ListProtectableResourceFailed as err:
LOG.error(_LE("Show resources of type %(type)s id %(id)s " LOG.error(_LE("Show resources of type %(type)s id %(id)s "
"failed: %(err)s"), "failed: %(err)s"),

View File

@ -43,7 +43,7 @@ class ProtectablePlugin(object):
pass pass
@abc.abstractmethod @abc.abstractmethod
def list_resources(self, context): def list_resources(self, context, parameters=None):
"""List resource instances of type this plugin supported. """List resource instances of type this plugin supported.
:return: The list of resource instance. :return: The list of resource instance.
@ -51,7 +51,7 @@ class ProtectablePlugin(object):
pass pass
@abc.abstractmethod @abc.abstractmethod
def show_resource(self, context, resource_id): def show_resource(self, context, resource_id, parameters=None):
"""Show resource detail information. """Show resource detail information.
""" """

View File

@ -43,7 +43,7 @@ class ImageProtectablePlugin(protectable_plugin.ProtectablePlugin):
return (constants.SERVER_RESOURCE_TYPE, return (constants.SERVER_RESOURCE_TYPE,
constants.PROJECT_RESOURCE_TYPE,) constants.PROJECT_RESOURCE_TYPE,)
def list_resources(self, context): def list_resources(self, context, parameters=None):
try: try:
images = self._glance_client(context).images.list() images = self._glance_client(context).images.list()
except Exception as e: except Exception as e:
@ -98,7 +98,7 @@ class ImageProtectablePlugin(protectable_plugin.ProtectablePlugin):
for image in images for image in images
if image.owner == parent_resource.id] if image.owner == parent_resource.id]
def show_resource(self, context, resource_id): def show_resource(self, context, resource_id, parameters=None):
try: try:
image = self._glance_client(context).images.get(resource_id) image = self._glance_client(context).images.get(resource_id)
except Exception as e: except Exception as e:

View File

@ -28,7 +28,7 @@ class ProjectProtectablePlugin(protectable_plugin.ProtectablePlugin):
def get_parent_resource_types(self): def get_parent_resource_types(self):
return () return ()
def list_resources(self, context): def list_resources(self, context, parameters=None):
# TODO(yuvalbr) handle admin context for multiple projects? # TODO(yuvalbr) handle admin context for multiple projects?
return [resource.Resource(type=self._SUPPORT_RESOURCE_TYPE, return [resource.Resource(type=self._SUPPORT_RESOURCE_TYPE,
id=context.project_id, id=context.project_id,
@ -37,7 +37,7 @@ class ProjectProtectablePlugin(protectable_plugin.ProtectablePlugin):
def get_dependent_resources(self, context, parent_resource): def get_dependent_resources(self, context, parent_resource):
pass pass
def show_resource(self, context, resource_id): def show_resource(self, context, resource_id, parameters=None):
# TODO(yinwei) get project name through keystone client # TODO(yinwei) get project name through keystone client
return resource.Resource(type=self._SUPPORT_RESOURCE_TYPE, return resource.Resource(type=self._SUPPORT_RESOURCE_TYPE,
id=resource_id, id=resource_id,

View File

@ -43,7 +43,7 @@ class ServerProtectablePlugin(protectable_plugin.ProtectablePlugin):
def get_parent_resource_types(self): def get_parent_resource_types(self):
return (constants.PROJECT_RESOURCE_TYPE, ) return (constants.PROJECT_RESOURCE_TYPE, )
def list_resources(self, context): def list_resources(self, context, parameters=None):
try: try:
servers = self._client(context).servers.list(detailed=False) servers = self._client(context).servers.list(detailed=False)
except Exception as e: except Exception as e:
@ -57,7 +57,7 @@ class ServerProtectablePlugin(protectable_plugin.ProtectablePlugin):
name=server.name) name=server.name)
for server in servers] for server in servers]
def show_resource(self, context, resource_id): def show_resource(self, context, resource_id, parameters=None):
try: try:
server = self._client(context).servers.get(resource_id) server = self._client(context).servers.get(resource_id)
except Exception as e: except Exception as e:

View File

@ -44,7 +44,7 @@ class VolumeProtectablePlugin(protectable_plugin.ProtectablePlugin):
return (constants.SERVER_RESOURCE_TYPE, return (constants.SERVER_RESOURCE_TYPE,
constants.PROJECT_RESOURCE_TYPE) constants.PROJECT_RESOURCE_TYPE)
def list_resources(self, context): def list_resources(self, context, parameters=None):
try: try:
volumes = self._client(context).volumes.list(detailed=False) volumes = self._client(context).volumes.list(detailed=False)
except Exception as e: except Exception as e:
@ -58,7 +58,7 @@ class VolumeProtectablePlugin(protectable_plugin.ProtectablePlugin):
id=vol.id, name=vol.name) id=vol.id, name=vol.name)
for vol in volumes] for vol in volumes]
def show_resource(self, context, resource_id): def show_resource(self, context, resource_id, parameters=None):
try: try:
volume = self._client(context).volumes.get(resource_id) volume = self._client(context).volumes.get(resource_id)
except Exception as e: except Exception as e:

View File

@ -70,16 +70,17 @@ class ProtectableRegistry(object):
"""Get the protectable plugin with the specified type.""" """Get the protectable plugin with the specified type."""
return self._plugin_map.get(resource_type) return self._plugin_map.get(resource_type)
def list_resources(self, context, resource_type): def list_resources(self, context, resource_type, parameters=None):
"""List resource instances of given type. """List resource instances of given type.
:param resource_type: The resource type to list instance. :param resource_type: The resource type to list instance.
:return: The list of resource instance. :return: The list of resource instance.
""" """
protectable = self._get_protectable(context, resource_type) protectable = self._get_protectable(context, resource_type)
return protectable.list_resources(context) return protectable.list_resources(context, parameters=parameters)
def show_resource(self, context, resource_type, resource_id): def show_resource(self, context, resource_type, resource_id,
parameters=None):
"""List resource instances of given type. """List resource instances of given type.
:param resource_type: The resource type of instance. :param resource_type: The resource type of instance.
@ -87,7 +88,8 @@ class ProtectableRegistry(object):
:return: The show of resource instance. :return: The show of resource instance.
""" """
protectable = self._get_protectable(context, resource_type) protectable = self._get_protectable(context, resource_type)
return protectable.show_resource(context, resource_id) return protectable.show_resource(context, resource_id,
parameters=parameters)
def fetch_dependent_resources(self, context, resource): def fetch_dependent_resources(self, context, resource):
"""List dependent resources under given parent resource. """List dependent resources under given parent resource.

View File

@ -105,7 +105,7 @@ class ProtectionAPI(object):
def list_protectable_instances( def list_protectable_instances(
self, ctxt, protectable_type=None, self, ctxt, protectable_type=None,
marker=None, limit=None, sort_keys=None, marker=None, limit=None, sort_keys=None,
sort_dirs=None, filters=None): sort_dirs=None, filters=None, parameters=None):
cctxt = self.client.prepare(version='1.0') cctxt = self.client.prepare(version='1.0')
return cctxt.call( return cctxt.call(
ctxt, ctxt,
@ -115,7 +115,8 @@ class ProtectionAPI(object):
limit=limit, limit=limit,
sort_keys=sort_keys, sort_keys=sort_keys,
sort_dirs=sort_dirs, sort_dirs=sort_dirs,
filters=filters) filters=filters,
parameters=parameters)
def list_protectable_dependents(self, def list_protectable_dependents(self,
ctxt, protectable_id=None, ctxt, protectable_id=None,
@ -129,13 +130,15 @@ class ProtectionAPI(object):
def show_protectable_instance(self, def show_protectable_instance(self,
ctxt, protectable_type=None, ctxt, protectable_type=None,
protectable_id=None): protectable_id=None,
parameters=None):
cctxt = self.client.prepare(version='1.0') cctxt = self.client.prepare(version='1.0')
return cctxt.call( return cctxt.call(
ctxt, ctxt,
'show_protectable_instance', 'show_protectable_instance',
protectable_type=protectable_type, protectable_type=protectable_type,
protectable_id=protectable_id) protectable_id=protectable_id,
parameters=parameters)
def show_provider(self, def show_provider(self,
ctxt, provider_id=None): ctxt, provider_id=None):