Merge "fix docstring warnings and errors"

This commit is contained in:
Jenkins 2016-03-21 16:52:59 +00:00 committed by Gerrit Code Review
commit e0ba0c4fd0
20 changed files with 199 additions and 124 deletions

View File

@ -49,14 +49,14 @@ Following components are present in the Glance architecture:
* **REST API** - Glance functionalities are exposed via REST.
* **Database Abstraction Layer (DAL)** - an application programming interface
(API) that unifies the communication between Glance and databases.
(API) that unifies the communication between Glance and databases.
* **Glance Domain Controller** - middleware that implements the main
Glance functionalities such as authorization, notifications, policies,
database connections.
Glance functionalities such as authorization, notifications, policies,
database connections.
* **Glance Store** - used to organize interactions between Glance and various
data stores.
data stores.
* **Registry Layer** - optional layer that is used to organise secure
communication between the domain and the DAL by using a separate service.
communication between the domain and the DAL by using a separate service.

View File

@ -40,6 +40,7 @@ information. In order to configure Glance to use Keystone, the
the authentication token validation and retrieves actual user authentication
information. It can be found in the Keystone distribution.
Configuring Glance API to use Keystone
--------------------------------------
@ -59,8 +60,11 @@ an example for ``authtoken``::
The actual values for these variables will need to be set depending on
your situation. For more information, please refer to the Keystone
`documentation`_ on the ``auth_token`` middleware, but in short:
.. _documentation http://docs.openstack.org/developer/keystonemiddleware/middlewarearchitecture.html#configuration
`documentation`_ on the ``auth_token`` middleware.
.. _`documentation`: http://docs.openstack.org/developer/keystonemiddleware/middlewarearchitecture.html#configuration
In short:
* The ``auth_url`` variable points to the Keystone service.
This information is used by the middleware to actually query Keystone about
@ -83,6 +87,7 @@ with ``authtoken`` and ``context``::
[pipeline:glance-api]
pipeline = versionnegotiation authtoken context apiv1app
Configuring Glance Registry to use Keystone
-------------------------------------------

View File

@ -1722,10 +1722,10 @@ deployment. Without HMAC key the profiling will not be triggered even profiling
feature is enabled.
**IMPORTANT NOTE**: previously HMAC keys (as well as enabled parameter) were
placed at /etc/glance/api-paste.ini and /etc/glance/registry-paste.ini files
placed at `/etc/glance/api-paste.ini` and `/etc/glance/registry-paste.ini` files
for Glance API and Glance Registry services respectively. Starting with
opsrofiler 0.3.1 release there is no need to set these arguments in the
*-paste.ini files. This functionality is still supported, although the
`*-paste.ini` files. This functionality is still supported, although the
config values are having larger priority.
The config value ``trace_sqlalchemy`` is used to determine whether fully enable

View File

@ -55,14 +55,16 @@ The workflow for the life of a spec-lite in Launchpad is as follows:
* File a bug with a small summary of what the request change is
following the format below:
.. NOTE: add format
* The bug is triaged and tagged with the `spec-lite` tag.
* The bug is evaluated and marked as `Triaged` to announce approval or
to `Won't fix` to announce rejection or `Invalid` to request a full
spec.
* The bug is moved to `In Progress` once the code is up and ready to
review.
* The bug is moved to `Fix Committed` once the patch lands.
.. NOTE: add format
* The bug is triaged and tagged with the `spec-lite` tag.
* The bug is evaluated and marked as `Triaged` to announce approval or
to `Won't fix` to announce rejection or `Invalid` to request a full
spec.
* The bug is moved to `In Progress` once the code is up and ready to
review.
* The bug is moved to `Fix Committed` once the patch lands.
In summary:
@ -80,9 +82,9 @@ In summary:
The drivers team will be discussing the following bug reports during their IRC meeting:
* `New RFE's <https://bugs.launchpad.net/glance/+bugs?field.status%3Alist=NEW&field.tag=spec-lite&field.importance%3Alist=WISHLIST>`_
* `New RFE's <https://bugs.launchpad.net/glance-store/+bugs?field.status%3Alist=NEW&field.tag=spec-lite&field.importance%3Alist=WISHLIST>`_
* `New RFE's <https://bugs.launchpad.net/python-glanceclient/+bugs?field.status%3Alist=NEW&field.tag=spec-lite&field.importance%3Alist=WISHLIST>`_
* `New Glance RFE's <https://bugs.launchpad.net/glance/+bugs?field.status%3Alist=NEW&field.tag=spec-lite&field.importance%3Alist=WISHLIST>`_
* `New Glance-Store RFE's <https://bugs.launchpad.net/glance-store/+bugs?field.status%3Alist=NEW&field.tag=spec-lite&field.importance%3Alist=WISHLIST>`_
* `New Glanceclient RFE's <https://bugs.launchpad.net/python-glanceclient/+bugs?field.status%3Alist=NEW&field.tag=spec-lite&field.importance%3Alist=WISHLIST>`_
Lite spec Submission Guidelines

View File

@ -362,9 +362,9 @@ The first call should be a ``POST`` to ``http://glance.example.com/v1/images``,
which will result in a new image id being registered with a status of
``queued``::
{"image":
{"status": "queued",
"id": "71c675ab-d94f-49cd-a114-e12490b328d9",
{'image':
{'status': 'queued',
'id': '71c675ab-d94f-49cd-a114-e12490b328d9',
...}
...}

View File

@ -332,16 +332,19 @@ class Controller(controller.BaseController):
* size -- Size of image data in bytes
:param req: The WSGI/Webob Request object
:retval The response body is a mapping of the following form::
:returns: The response body is a mapping of the following form
.. code-block:: json
{'images': [
{'id': <ID>,
'name': <NAME>,
'disk_format': <DISK_FORMAT>,
'container_format': <DISK_FORMAT>,
'checksum': <CHECKSUM>
'size': <SIZE>}, ...
]}
'checksum': <CHECKSUM>,
'size': <SIZE>}, {...}]
}
"""
self._enforce(req, 'get_images')
params = self._get_query_params(req)
@ -357,24 +360,29 @@ class Controller(controller.BaseController):
Returns detailed information for all available images
:param req: The WSGI/Webob Request object
:retval The response body is a mapping of the following form::
:returns: The response body is a mapping of the following form
.. code-block:: json
{'images':
[{
'id': <ID>,
'name': <NAME>,
'size': <SIZE>,
'disk_format': <DISK_FORMAT>,
'container_format': <CONTAINER_FORMAT>,
'checksum': <CHECKSUM>,
'min_disk': <MIN_DISK>,
'min_ram': <MIN_RAM>,
'store': <STORE>,
'status': <STATUS>,
'created_at': <TIMESTAMP>,
'updated_at': <TIMESTAMP>,
'deleted_at': <TIMESTAMP>|<NONE>,
'properties': {'distro': 'Ubuntu 10.04 LTS', {...}}
}, {...}]
}
{'images': [
{'id': <ID>,
'name': <NAME>,
'size': <SIZE>,
'disk_format': <DISK_FORMAT>,
'container_format': <CONTAINER_FORMAT>,
'checksum': <CHECKSUM>,
'min_disk': <MIN_DISK>,
'min_ram': <MIN_RAM>,
'store': <STORE>,
'status': <STATUS>,
'created_at': <TIMESTAMP>,
'updated_at': <TIMESTAMP>,
'deleted_at': <TIMESTAMP>|<NONE>,
'properties': {'distro': 'Ubuntu 10.04 LTS', ...}}, ...
]}
"""
if req.method == 'HEAD':
msg = (_("This operation is currently not permitted on "
@ -405,7 +413,7 @@ class Controller(controller.BaseController):
Extracts necessary query params from request.
:param req: the WSGI Request object
:retval dict of parameters that can be used by registry client
:returns: dict of parameters that can be used by registry client
"""
params = {'filters': self._get_filters(req)}
@ -423,7 +431,7 @@ class Controller(controller.BaseController):
Return a dictionary of query param filters from the request
:param req: the Request object coming from the wsgi layer
:retval a dict of key/value filters
:returns: a dict of key/value filters
"""
query_filters = {}
for param in req.params:
@ -443,7 +451,7 @@ class Controller(controller.BaseController):
:param req: The WSGI/Webob Request object
:param id: The opaque image identifier
:retval similar to 'show' method but without image_data
:returns: similar to 'show' method but without image_data
:raises: HTTPNotFound if image metadata is not available to user
"""
@ -634,7 +642,7 @@ class Controller(controller.BaseController):
:param image_meta: Mapping of metadata about image
:raises: HTTPConflict if image already exists
:retval The location where the image was stored
:returns: The location where the image was stored
"""
scheme = req.headers.get('x-image-meta-store',
@ -734,7 +742,7 @@ class Controller(controller.BaseController):
:param req: The WSGI/Webob Request object
:param image_meta: Mapping of metadata about image
:retval Mapping of updated image data
:returns: Mapping of updated image data
"""
location_data = self._upload(req, image_meta)
image_id = image_meta['id']
@ -938,7 +946,7 @@ class Controller(controller.BaseController):
:param request: The WSGI/Webob Request object
:param id: The opaque image identifier
:retval Returns the updated image information as a mapping
:returns: Returns the updated image information as a mapping
"""
self._enforce(req, 'modify_image')
is_public = image_meta.get('is_public')

View File

@ -62,12 +62,15 @@ class Controller(controller.BaseController):
:param req: the Request object coming from the wsgi layer
:param image_id: The opaque image identifier
:retval The response body is a mapping of the following form::
:returns: The response body is a mapping of the following form
.. code-block:: json
{'members': [
{'member_id': <MEMBER>,
'can_share': <SHARE_PERMISSION>, ...}, ...
]}
"""
self._enforce(req, 'get_members')
self._raise_404_if_image_deleted(req, image_id)
@ -128,13 +131,15 @@ class Controller(controller.BaseController):
def update(self, req, image_id, id, body=None):
"""
Adds a membership to the image, or updates an existing one.
If a body is present, it is a dict with the following format::
If a body is present, it is a dict with the following format
{"member": {
"can_share": [True|False]
.. code-block:: json
{'member': {
'can_share': [True|False]
}}
If "can_share" is provided, the member's ability to share is
If `can_share` is provided, the member's ability to share is
set accordingly. If it is not provided, existing memberships
remain unchanged and new memberships default to False.
"""
@ -169,12 +174,15 @@ class Controller(controller.BaseController):
def update_all(self, req, image_id, body):
"""
Replaces the members of the image with those specified in the
body. The body is a dict with the following format::
body. The body is a dict with the following format
{"memberships": [
{"member_id": <MEMBER_ID>,
["can_share": [True|False]]}, ...
.. code-block:: json
{'memberships': [
{'member_id': <MEMBER_ID>,
['can_share': [True|False]]}, ...
]}
"""
self._check_can_access_image_members(req.context)
self._enforce(req, 'modify_member')
@ -206,12 +214,15 @@ class Controller(controller.BaseController):
:param req: the Request object coming from the wsgi layer
:param id: the opaque member identifier
:retval The response body is a mapping of the following form::
:returns: The response body is a mapping of the following form
.. code-block:: json
{'shared_images': [
{'image_id': <IMAGE>,
'can_share': <SHARE_PERMISSION>, ...}, ...
]}
"""
try:
members = registry.get_member_images(req.context, id)

View File

@ -95,7 +95,9 @@ class ImageMembersController(object):
:param req: the Request object coming from the wsgi layer
:param image_id: the image identifier
:param member_id: the member identifier
:retval The response body is a mapping of the following form::
:returns: The response body is a mapping of the following form
.. code-block:: json
{'member_id': <MEMBER>,
'image_id': <IMAGE>,
@ -137,11 +139,13 @@ class ImageMembersController(object):
:param req: the Request object coming from the wsgi layer
:param image_id: the image identifier
:param member_id: the member identifier
:retval The response body is a mapping of the following form::
:returns: The response body is a mapping of the following form
.. code-block:: json
{'member_id': <MEMBER>,
'image_id': <IMAGE>,
'status': <MEMBER_STATUS>
'status': <MEMBER_STATUS>,
'created_at': ..,
'updated_at': ..}
@ -170,15 +174,18 @@ class ImageMembersController(object):
:param req: the Request object coming from the wsgi layer
:param image_id: The image identifier
:retval The response body is a mapping of the following form::
:returns: The response body is a mapping of the following form
.. code-block:: json
{'members': [
{'member_id': <MEMBER>,
'image_id': <IMAGE>,
'status': <MEMBER_STATUS>
'status': <MEMBER_STATUS>,
'created_at': ..,
'updated_at': ..}, ..
]}
"""
image = self._lookup_image(req, image_id)
member_repo = self._get_member_repo(req, image)
@ -198,13 +205,16 @@ class ImageMembersController(object):
:param req: the Request object coming from the wsgi layer
:param image_id: The image identifier
:retval The response body is a mapping of the following form::
:returns: The response body is a mapping of the following form
.. code-block:: json
{'member_id': <MEMBER>,
'image_id': <IMAGE>,
'status': <MEMBER_STATUS>
'created_at': ..,
'updated_at': ..}
"""
try:
image = self._lookup_image(req, image_id)

View File

@ -68,6 +68,7 @@ class _OVF_Process(task.Task):
def _get_ova_iter_objects(self, uri):
"""Returns iterable object either for local file or uri
:param uri: uri (remote or local) to the ova package we want to iterate
"""
@ -134,9 +135,10 @@ class OVAImageExtractor(object):
Extracts a single disk image and OVF from OVA tar archive and calls
OVF parser method.
:param ova: a file object containing the OVA file
:returns: a tuple of extracted disk file object and dictionary of
properties parsed from the OVF file
properties parsed from the OVF file
:raises: RuntimeError for malformed OVA and OVF files
"""
with tarfile.open(fileobj=ova) as tar_file:
@ -163,6 +165,7 @@ class OVAImageExtractor(object):
The OVF file's qualified namespaces are removed from the included
properties.
:param ovf: a file object containing the OVF file
:returns: a tuple of disk filename and a properties dictionary
:raises: RuntimeError for malformed OVF file

View File

@ -584,7 +584,7 @@ class BaseClient(object):
:param actual_params: dict of keys to filter
:param allowed_params: list of keys that 'actual_params' will be
reduced to
:retval subset of 'params' dict
:returns: subset of 'params' dict
"""
try:
# expect 'filters' param to be a dict here

View File

@ -86,6 +86,8 @@ class Controller(object):
This is the base controller for RPC based APIs. Commands
handled by this controller respect the following form:
.. code-block:: json
[{
'command': 'method_name',
'kwargs': {...}
@ -94,8 +96,9 @@ class Controller(object):
The controller is capable of processing more than one command
per request and will always return a list of results.
:params raise_exc: Boolean that specifies whether to raise
exceptions instead of "serializing" them.
:param bool raise_exc: Specifies whether to raise
exceptions instead of "serializing" them.
"""
def __init__(self, raise_exc=False):
@ -106,13 +109,14 @@ class Controller(object):
"""
Exports methods through the RPC Api.
:params resource: Resource's instance to register.
:params filtered: List of methods that *can* be registered. Read
as "Method must be in this list".
:params excluded: List of methods to exclude.
:params refiner: Callable to use as filter for methods.
:param resource: Resource's instance to register.
:param filtered: List of methods that *can* be registered. Read
as "Method must be in this list".
:param excluded: List of methods to exclude.
:param refiner: Callable to use as filter for methods.
:raises TypeError: If refiner is not callable.
"""
funcs = filter(lambda x: not x.startswith("_"), dir(resource))
@ -216,13 +220,16 @@ class RPCClient(client.BaseClient):
"""
Execute multiple commands in a single request.
:params commands: List of commands to send. Commands
must respect the following form:
:param commands: List of commands to send. Commands
must respect the following form
.. code-block:: json
{
'command': 'method_name',
'kwargs': method_kwargs
}
"""
body = self._serializer.to_json(commands)
response = super(RPCClient, self).do_request('POST',
@ -236,8 +243,8 @@ class RPCClient(client.BaseClient):
the outgoing body and builds the command that will
be sent.
:params method: The remote python method to call
:params kwargs: Dynamic parameters that will be
:param method: The remote python method to call
:param kwargs: Dynamic parameters that will be
passed to the remote method.
"""
content = self.bulk_request([{'command': method,

View File

@ -61,7 +61,7 @@ def from_migration_import(module_name, fromlist):
:param module_name: name of migration module to import from
(ex: 001_add_images_table)
:param fromlist: list of items to import (ex: define_images_table)
:retval: module object
:returns: module object
This bit of ugliness warrants an explanation:

View File

@ -284,7 +284,7 @@ class ImageCache(object):
:param image_file: Iterator retrieving image chunks
:param image_checksum: Checksum of image
:retval True if image file was cached, False otherwise
:returns: True if image file was cached, False otherwise
"""
if not self.driver.is_cacheable(image_id):
return False
@ -301,7 +301,7 @@ class ImageCache(object):
:param image_id: Image ID
:param image_file: Image file to cache
:retval True if image file was cached, False otherwise
:returns: True if image file was cached, False otherwise
"""
CHUNKSIZE = 64 * units.Mi

View File

@ -161,10 +161,12 @@ class ImageFactoryProxy(glance.domain.proxy.ImageFactory):
class StoreLocations(collections.MutableSequence):
"""
The proxy for store location property. It takes responsibility for:
The proxy for store location property. It takes responsibility for::
1. Location uri correctness checking when adding a new location.
2. Remove the image data from the store when a location is removed
from an image.
"""
def __init__(self, image_proxy, value):
self.image_proxy = image_proxy

View File

@ -138,20 +138,25 @@ class Controller(object):
"""Return a basic filtered list of public, non-deleted images
:param req: the Request object coming from the wsgi layer
:retval a mapping of the following form::
:returns: a mapping of the following form
.. code-block:: python
dict(images=[image_list])
Where image_list is a sequence of mappings::
Where image_list is a sequence of mappings
.. code-block:: json
{
'id': <ID>,
'name': <NAME>,
'size': <SIZE>,
'disk_format': <DISK_FORMAT>,
'container_format': <CONTAINER_FORMAT>,
'checksum': <CHECKSUM>
'id': <ID>,
'name': <NAME>,
'size': <SIZE>,
'disk_format': <DISK_FORMAT>,
'container_format': <CONTAINER_FORMAT>,
'checksum': <CHECKSUM>
}
"""
params = self._get_query_params(req)
images = self._get_images(req.context, **params)
@ -170,12 +175,29 @@ class Controller(object):
"""Return a filtered list of public, non-deleted images in detail
:param req: the Request object coming from the wsgi layer
:retval a mapping of the following form::
:returns: a mapping of the following form
dict(images=[image_list])
.. code-block:: json
{'images':
[{
'id': <ID>,
'name': <NAME>,
'size': <SIZE>,
'disk_format': <DISK_FORMAT>,
'container_format': <CONTAINER_FORMAT>,
'checksum': <CHECKSUM>,
'min_disk': <MIN_DISK>,
'min_ram': <MIN_RAM>,
'store': <STORE>,
'status': <STATUS>,
'created_at': <TIMESTAMP>,
'updated_at': <TIMESTAMP>,
'deleted_at': <TIMESTAMP>|<NONE>,
'properties': {'distro': 'Ubuntu 10.04 LTS', {...}}
}, {...}]
}
Where image_list is a sequence of mappings containing
all image model fields.
"""
params = self._get_query_params(req)
@ -188,7 +210,7 @@ class Controller(object):
"""Extract necessary query parameters from http request.
:param req: the Request object coming from the wsgi layer
:retval dictionary of filters to apply to list of images
:returns: dictionary of filters to apply to list of images
"""
params = {
'filters': self._get_filters(req),
@ -217,7 +239,7 @@ class Controller(object):
"""Return a dictionary of query param filters from the request
:param req: the Request object coming from the wsgi layer
:retval a dict of key/value filters
:returns: a dict of key/value filters
"""
filters = {}
properties = {}
@ -360,8 +382,9 @@ class Controller(object):
:param req: wsgi Request object
:param id: The opaque internal identifier for the image
:retval Returns 200 if delete was successful, a fault if not. On
success, the body contains the deleted image information as a mapping.
:returns: 200 if delete was successful, a fault if not. On
success, the body contains the deleted image
information as a mapping.
"""
try:
deleted_image = self.db_api.image_destroy(req.context, id)
@ -390,9 +413,9 @@ class Controller(object):
:param req: wsgi Request object
:param body: Dictionary of information about the image
:retval Returns the newly-created image information as a mapping,
which will include the newly-created image's internal id
in the 'id' field
:returns: The newly-created image information as a mapping,
which will include the newly-created image's internal id
in the 'id' field
"""
image_data = body['image']
@ -441,7 +464,7 @@ class Controller(object):
:param body: Dictionary of information about the image
:param id: The opaque internal identifier for the image
:retval Returns the updated image information as a mapping,
:returns: Returns the updated image information as a mapping,
"""
image_data = body['image']
from_state = body.get('from_state', None)

View File

@ -88,9 +88,9 @@ class Controller(object):
Replaces the members of the image with those specified in the
body. The body is a dict with the following format::
{"memberships": [
{"member_id": <MEMBER_ID>,
["can_share": [True|False]]}, ...
{'memberships': [
{'member_id': <MEMBER_ID>,
['can_share': [True|False]]}, ...
]}
"""
self._check_can_access_image_members(req.context)
@ -205,11 +205,11 @@ class Controller(object):
Adds a membership to the image, or updates an existing one.
If a body is present, it is a dict with the following format::
{"member": {
"can_share": [True|False]
{'member': {
'can_share': [True|False]
}}
If "can_share" is provided, the member's ability to share is
If `can_share` is provided, the member's ability to share is
set accordingly. If it is not provided, existing memberships
remain unchanged and new memberships default to False.
"""

View File

@ -113,7 +113,7 @@ class ScrubDBQueue(object):
:param image_id: The opaque image identifier
:param location: The opaque image location
:retval A boolean value to indicate success or not
:returns: A boolean value to indicate success or not
"""
loc_id = location.get('id')
if loc_id:
@ -151,7 +151,9 @@ class ScrubDBQueue(object):
def get_all_locations(self):
"""Returns a list of image id and location tuple from scrub queue.
:retval a list of image id, location id and uri tuple from scrub queue
:returns: a list of image id, location id and uri tuple from
scrub queue
"""
ret = []
@ -187,7 +189,7 @@ class ScrubDBQueue(object):
:param image_id: The opaque image identifier
:retval a boolean value to inform including or not
:returns: a boolean value to inform including or not
"""
try:
image = self.registry.get_image(image_id)

View File

@ -608,20 +608,21 @@ class TestApi(functional.FunctionalTest):
def test_download_non_exists_image_raises_http_forbidden(self):
"""
We test the following sequential series of actions:
We test the following sequential series of actions::
0. POST /images with public image named Image1
and no custom properties
- Verify 201 returned
and no custom properties
- Verify 201 returned
1. HEAD image
- Verify HTTP headers have correct information we just added
- Verify HTTP headers have correct information we just added
2. GET image
- Verify all information on image we just added is correct
- Verify all information on image we just added is correct
3. DELETE image1
- Delete the newly added image
- Delete the newly added image
4. GET image
- Verify that 403 HTTPForbidden exception is raised prior to
404 HTTPNotFound
- Verify that 403 HTTPForbidden exception is raised prior to
404 HTTPNotFound
"""
self.cleanup()
self.start_servers(**self.__dict__.copy())

View File

@ -228,7 +228,7 @@ class TestApi(base.ApiTest):
0. GET /images
- Verify no public images
1. POST /images with public image named Image1 with no location
attribute and no image data.
attribute and no image data.
- Verify 201 returned
2. GET /images
- Verify one public image

View File

@ -138,9 +138,10 @@ class TestArtifactsLoader(utils.BaseTestCase):
"""
A test to show that plugin-load specific options in artifacts.conf
are correctly processed:
* no plugins can be loaded if load_enabled = False
* if available_plugins list is given only plugins specified can be
be loaded
* no plugins can be loaded if load_enabled = False
* if available_plugins list is given only plugins specified can be
be loaded
"""
self.config(load_enabled=False)
self.assertRaises(exception.ArtifactLoadError,