Allow package_get by name

If package lookup by id fails, filter by fully_qualified_name
and choose the first (and what will be only) result. Also allows
delete and update to use FQN as well as ID.

This may need revisiting to allow non-unique FQNs.

Change-Id: I84fb8e155b5aa4bc036f8b598101b6b969962325
Implements: blueprint id-fqn-equivalence
This commit is contained in:
Steve McLellan 2014-05-23 15:46:52 -05:00
parent 84bff3be68
commit da7fda4832
2 changed files with 44 additions and 23 deletions

View File

@ -25,7 +25,7 @@ Methods for application package management
**Package Properties**
- ``id``: guid corresponds to database record
- ``id``: guid of a package (``fully_qualified_name`` can also be used for some API functions)
- ``fully_qualified_name``: fully qualified domain name - domain name that specifies exact application location
- ``name``: user-friendly name
- ``type``: package type, "library" or "application"
@ -181,9 +181,11 @@ Get package details
"""""""""""""""""""
`/v1/catalog/packages/{id} [GET]`
Display details for a package.
**Parameters**
``id`` (required) Numeric `id` of the package to perform action with
``id`` (required) Hexadecimal `id` (or fully qualified name) of the package
**Response 200 (application/json)**
@ -226,6 +228,10 @@ Update a Package
Allows to edit mutable fields (categories, tags, name, description, is_public, enabled).
See the full specification `here <http://tools.ietf.org/html/rfc6902>`_.
**Parameters**
``id`` (required) Hexadecimal `id` (or fully qualified name) of the package
Allowed operations:
::
@ -288,19 +294,23 @@ Note, that replacing categories with empty list is not allowed as well as the re
**Response 400**
* In attempt to replace categories with empty list or remove last category
* An attempt to replace categories with empty list or remove last category
**Response 404**
* In attempt to update package that doesn't exist
* An attempt to update package that doesn't exist
Delete application definition from the catalog
""""""""""""""""""""""""""""""""""""""""""""""
`/v1/catalog/packages/{id} [DELETE]`
**Parameters**
``id`` (required) Hexadecimal `id` (or fully qualified name) of the package to delete
**Response 404**
* In attempt to delete package that doesn't exist
* An attempt to delete package that doesn't exist
Download application data
-------------------------
@ -313,7 +323,7 @@ Get application definition package
**Parameters**
* id (required) Numeric `id` of the package to perform action with
* id (required) Hexadecimal `id` (or fully qualified name) of the package
**Response 200 (application/octetstream)**
@ -331,7 +341,7 @@ Retrieve UI definition for a application which described in a package with provi
**Parameters**
* id (required) Numeric `id` of the package to perform action with
* id (required) Hexadecimal `id` (or fully qualified name) of the package
**Response 200 (application/octet-stream)**
@ -357,8 +367,7 @@ Retrieve application logo which described in a package with provided id
**Parameters**
id (required) Numeric `id` of the package to perform action with
id (required) Hexadecimal `id` (or fully qualified name) of the package
**Response 200 (application/octet-stream)**

View File

@ -33,10 +33,25 @@ SEARCH_MAPPING = {'fqn': 'fully_qualified_name',
LOG = logging.getLogger(__name__)
def _package_get(package_id, session):
package = session.query(models.Package).get(package_id)
def _package_get(package_id_or_name, session):
# TODO (sjmc7): update openstack/common and pull in
# uuidutils, check that package_id_or_name resembles a
# UUID before trying to treat it as one
package = session.query(models.Package).get(package_id_or_name)
if not package:
msg = _("Package id '{0}' is not found").format(package_id)
# Try using the FQN name instead. Since FQNs right now are unique,
# don't need to do any logic to figure out if we have the right one.
# # TODO (sjmc7): Revisit for precedence rules.
# Heat does this in nicer way, giving each stack an unambiguous ID of
# stack_name/id and redirecting to it in the API. We need to do some
# reworking for precedence rules later, so maybe take a look at this
package = session.query(models.Package).filter_by(
fully_qualified_name=package_id_or_name
).first()
if not package:
msg = _("Package id or name '{0}' not found").\
format(package_id_or_name)
LOG.error(msg)
raise exc.HTTPNotFound(msg)
@ -60,14 +75,14 @@ def _authorize_package(package, context, allow_public=False):
raise exc.HTTPForbidden(msg)
def package_get(package_id, context):
def package_get(package_id_or_name, context):
"""
Return package details
:param package_id: ID of a package, string
:param package_id: ID or name of a package, string
:returns: detailed information about package, dict
"""
session = db_session.get_session()
package = _package_get(package_id, session)
package = _package_get(package_id_or_name, session)
_authorize_package(package, context, allow_public=True)
return package
@ -191,7 +206,7 @@ def _do_remove(package, change):
return package
def package_update(pkg_id, changes, context):
def package_update(pkg_id_or_name, changes, context):
"""
Update package information
:param changes: parameters to update
@ -203,7 +218,7 @@ def package_update(pkg_id, changes, context):
'remove': _do_remove}
session = db_session.get_session()
with session.begin():
pkg = _package_get(pkg_id, session)
pkg = _package_get(pkg_id_or_name, session)
_authorize_package(pkg, context)
for change in changes:
@ -338,15 +353,12 @@ def package_upload(values, tenant_id):
return package
def package_delete(package_id, context):
"""
Delete package information from the system ID of a package, string
parameters to update
"""
def package_delete(package_id_or_name, context):
"""Delete a package by name or by ID"""
session = db_session.get_session()
with session.begin():
package = _package_get(package_id, session)
package = _package_get(package_id_or_name, session)
_authorize_package(package, context)
session.delete(package)