summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authortermie <github@anarkystic.com>2011-04-21 15:06:13 +0000
committerTarmac <>2011-04-21 15:06:13 +0000
commitc796920198305e101c75bcbf4e027ba9e81975d7 (patch)
tree4638a7be2f66a394564fbe5a4726d389ca3cdd25 /nova
parentd598c9cdd08aae388b6c2e4023d6d7cf078f5193 (diff)
parentce8fd6b5e3ef0c757c76bbe9db37c696a1d2c11c (diff)
downloadnova-c796920198305e101c75bcbf4e027ba9e81975d7.tar.gz
nova-c796920198305e101c75bcbf4e027ba9e81975d7.tar.xz
nova-c796920198305e101c75bcbf4e027ba9e81975d7.zip
Docstring cleanup and formatting (nova/image dir). Minor style fixes as well.
Diffstat (limited to 'nova')
-rw-r--r--nova/image/fake.py9
-rw-r--r--nova/image/glance.py70
-rw-r--r--nova/image/local.py11
-rw-r--r--nova/image/s3.py44
-rw-r--r--nova/image/service.py69
5 files changed, 97 insertions, 106 deletions
diff --git a/nova/image/fake.py b/nova/image/fake.py
index e02b4127e..3bc2a8287 100644
--- a/nova/image/fake.py
+++ b/nova/image/fake.py
@@ -14,6 +14,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+
"""Implementation of an fake image service"""
import copy
@@ -69,14 +70,14 @@ class FakeImageService(service.BaseImageService):
image = self.images.get(image_id)
if image:
return copy.deepcopy(image)
- LOG.warn("Unable to find image id %s. Have images: %s",
+ LOG.warn('Unable to find image id %s. Have images: %s',
image_id, self.images)
raise exception.NotFound
def create(self, context, data):
"""Store the image data and return the new image id.
- :raises Duplicate if the image already exist.
+ :raises: Duplicate if the image already exist.
"""
image_id = int(data['id'])
@@ -88,7 +89,7 @@ class FakeImageService(service.BaseImageService):
def update(self, context, image_id, data):
"""Replace the contents of the given image with the new data.
- :raises NotFound if the image does not exist.
+ :raises: NotFound if the image does not exist.
"""
image_id = int(image_id)
@@ -99,7 +100,7 @@ class FakeImageService(service.BaseImageService):
def delete(self, context, image_id):
"""Delete the given image.
- :raises NotFound if the image does not exist.
+ :raises: NotFound if the image does not exist.
"""
image_id = int(image_id)
diff --git a/nova/image/glance.py b/nova/image/glance.py
index 1a80bb2af..81661b3b0 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -14,6 +14,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+
"""Implementation of an image service that uses Glance as the backend"""
from __future__ import absolute_import
@@ -31,16 +32,18 @@ from nova.image import service
LOG = logging.getLogger('nova.image.glance')
+
FLAGS = flags.FLAGS
+
GlanceClient = utils.import_class('glance.client.Client')
class GlanceImageService(service.BaseImageService):
"""Provides storage and retrieval of disk image objects within Glance."""
- GLANCE_ONLY_ATTRS = ["size", "location", "disk_format",
- "container_format"]
+ GLANCE_ONLY_ATTRS = ['size', 'location', 'disk_format',
+ 'container_format']
# NOTE(sirp): Overriding to use _translate_to_service provided by
# BaseImageService
@@ -56,9 +59,7 @@ class GlanceImageService(service.BaseImageService):
self.client = client
def index(self, context):
- """
- Calls out to Glance for a list of images available
- """
+ """Calls out to Glance for a list of images available."""
# NOTE(sirp): We need to use `get_images_detailed` and not
# `get_images` here because we need `is_public` and `properties`
# included so we can filter by user
@@ -71,9 +72,7 @@ class GlanceImageService(service.BaseImageService):
return filtered
def detail(self, context):
- """
- Calls out to Glance for a list of detailed image information
- """
+ """Calls out to Glance for a list of detailed image information."""
filtered = []
image_metas = self.client.get_images_detailed()
for image_meta in image_metas:
@@ -83,9 +82,7 @@ class GlanceImageService(service.BaseImageService):
return filtered
def show(self, context, image_id):
- """
- Returns a dict containing image data for the given opaque image id.
- """
+ """Returns a dict with image data for the given opaque image id."""
try:
image_meta = self.client.get_image_meta(image_id)
except glance_exception.NotFound:
@@ -98,9 +95,7 @@ class GlanceImageService(service.BaseImageService):
return base_image_meta
def show_by_name(self, context, name):
- """
- Returns a dict containing image data for the given name.
- """
+ """Returns a dict containing image data for the given name."""
# TODO(vish): replace this with more efficient call when glance
# supports it.
image_metas = self.detail(context)
@@ -110,9 +105,7 @@ class GlanceImageService(service.BaseImageService):
raise exception.NotFound
def get(self, context, image_id, data):
- """
- Calls out to Glance for metadata and data and writes data.
- """
+ """Calls out to Glance for metadata and data and writes data."""
try:
image_meta, image_chunks = self.client.get_image(image_id)
except glance_exception.NotFound:
@@ -125,16 +118,16 @@ class GlanceImageService(service.BaseImageService):
return base_image_meta
def create(self, context, image_meta, data=None):
- """
- Store the image data and return the new image id.
+ """Store the image data and return the new image id.
+
+ :raises: AlreadyExists if the image already exist.
- :raises AlreadyExists if the image already exist.
"""
# Translate Base -> Service
- LOG.debug(_("Creating image in Glance. Metadata passed in %s"),
+ LOG.debug(_('Creating image in Glance. Metadata passed in %s'),
image_meta)
sent_service_image_meta = self._translate_to_service(image_meta)
- LOG.debug(_("Metadata after formatting for Glance %s"),
+ LOG.debug(_('Metadata after formatting for Glance %s'),
sent_service_image_meta)
recv_service_image_meta = self.client.add_image(
@@ -142,14 +135,15 @@ class GlanceImageService(service.BaseImageService):
# Translate Service -> Base
base_image_meta = self._translate_to_base(recv_service_image_meta)
- LOG.debug(_("Metadata returned from Glance formatted for Base %s"),
+ LOG.debug(_('Metadata returned from Glance formatted for Base %s'),
base_image_meta)
return base_image_meta
def update(self, context, image_id, image_meta, data=None):
"""Replace the contents of the given image with the new data.
- :raises NotFound if the image does not exist.
+ :raises: NotFound if the image does not exist.
+
"""
# NOTE(vish): show is to check if image is available
self.show(context, image_id)
@@ -162,10 +156,10 @@ class GlanceImageService(service.BaseImageService):
return base_image_meta
def delete(self, context, image_id):
- """
- Delete the given image.
+ """Delete the given image.
+
+ :raises: NotFound if the image does not exist.
- :raises NotFound if the image does not exist.
"""
# NOTE(vish): show is to check if image is available
self.show(context, image_id)
@@ -176,16 +170,12 @@ class GlanceImageService(service.BaseImageService):
return result
def delete_all(self):
- """
- Clears out all images
- """
+ """Clears out all images."""
pass
@classmethod
def _translate_to_base(cls, image_meta):
- """Overriding the base translation to handle conversion to datetime
- objects
- """
+ """Override translation to handle conversion to datetime objects."""
image_meta = service.BaseImageService._propertify_metadata(
image_meta, cls.SERVICE_IMAGE_ATTRS)
image_meta = _convert_timestamps_to_datetimes(image_meta)
@@ -194,9 +184,7 @@ class GlanceImageService(service.BaseImageService):
# utility functions
def _convert_timestamps_to_datetimes(image_meta):
- """
- Returns image with known timestamp fields converted to datetime objects
- """
+ """Returns image with timestamp fields converted to datetime objects."""
for attr in ['created_at', 'updated_at', 'deleted_at']:
if image_meta.get(attr):
image_meta[attr] = _parse_glance_iso8601_timestamp(
@@ -205,10 +193,8 @@ def _convert_timestamps_to_datetimes(image_meta):
def _parse_glance_iso8601_timestamp(timestamp):
- """
- Parse a subset of iso8601 timestamps into datetime objects
- """
- iso_formats = ["%Y-%m-%dT%H:%M:%S.%f", "%Y-%m-%dT%H:%M:%S"]
+ """Parse a subset of iso8601 timestamps into datetime objects."""
+ iso_formats = ['%Y-%m-%dT%H:%M:%S.%f', '%Y-%m-%dT%H:%M:%S']
for iso_format in iso_formats:
try:
@@ -216,5 +202,5 @@ def _parse_glance_iso8601_timestamp(timestamp):
except ValueError:
pass
- raise ValueError(_("%(timestamp)s does not follow any of the "
- "signatures: %(ISO_FORMATS)s") % locals())
+ raise ValueError(_('%(timestamp)s does not follow any of the '
+ 'signatures: %(ISO_FORMATS)s') % locals())
diff --git a/nova/image/local.py b/nova/image/local.py
index fa5e93346..50f00bee1 100644
--- a/nova/image/local.py
+++ b/nova/image/local.py
@@ -23,14 +23,15 @@ import shutil
from nova import exception
from nova import flags
from nova import log as logging
-from nova.image import service
from nova import utils
+from nova.image import service
FLAGS = flags.FLAGS
flags.DEFINE_string('images_path', '$state_path/images',
'path to decrypted images')
+
LOG = logging.getLogger('nova.image.local')
@@ -56,9 +57,8 @@ class LocalImageService(service.BaseImageService):
try:
unhexed_image_id = int(image_dir, 16)
except ValueError:
- LOG.error(
- _("%s is not in correct directory naming format"\
- % image_dir))
+ LOG.error(_('%s is not in correct directory naming format')
+ % image_dir)
else:
images.append(unhexed_image_id)
return images
@@ -148,7 +148,8 @@ class LocalImageService(service.BaseImageService):
def delete(self, context, image_id):
"""Delete the given image.
- Raises NotFound if the image does not exist.
+
+ :raises: NotFound if the image does not exist.
"""
# NOTE(vish): show is to check if image is available
diff --git a/nova/image/s3.py b/nova/image/s3.py
index 2a02d4674..c38c58d95 100644
--- a/nova/image/s3.py
+++ b/nova/image/s3.py
@@ -16,13 +16,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""
-Proxy AMI-related calls from the cloud controller, to the running
-objectstore service.
-"""
+"""Proxy AMI-related calls from cloud controller to objectstore service."""
import binascii
-import eventlet
import os
import shutil
import tarfile
@@ -30,6 +26,7 @@ import tempfile
from xml.etree import ElementTree
import boto.s3.connection
+import eventlet
from nova import crypto
from nova import exception
@@ -46,7 +43,8 @@ flags.DEFINE_string('image_decryption_dir', '/tmp',
class S3ImageService(service.BaseImageService):
- """Wraps an existing image service to support s3 based register"""
+ """Wraps an existing image service to support s3 based register."""
+
def __init__(self, service=None, *args, **kwargs):
if service is None:
service = utils.import_object(FLAGS.image_service)
@@ -54,7 +52,11 @@ class S3ImageService(service.BaseImageService):
self.service.__init__(*args, **kwargs)
def create(self, context, metadata, data=None):
- """metadata['properties'] should contain image_location"""
+ """Create an image.
+
+ metadata['properties'] should contain image_location.
+
+ """
image = self._s3_create(context, metadata)
return image
@@ -100,12 +102,12 @@ class S3ImageService(service.BaseImageService):
return local_filename
def _s3_create(self, context, metadata):
- """Gets a manifext from s3 and makes an image"""
+ """Gets a manifext from s3 and makes an image."""
image_path = tempfile.mkdtemp(dir=FLAGS.image_decryption_dir)
image_location = metadata['properties']['image_location']
- bucket_name = image_location.split("/")[0]
+ bucket_name = image_location.split('/')[0]
manifest_path = image_location[len(bucket_name) + 1:]
bucket = self._conn(context).get_bucket(bucket_name)
key = bucket.get_key(manifest_path)
@@ -116,7 +118,7 @@ class S3ImageService(service.BaseImageService):
image_type = 'machine'
try:
- kernel_id = manifest.find("machine_configuration/kernel_id").text
+ kernel_id = manifest.find('machine_configuration/kernel_id').text
if kernel_id == 'true':
image_format = 'aki'
image_type = 'kernel'
@@ -125,7 +127,7 @@ class S3ImageService(service.BaseImageService):
kernel_id = None
try:
- ramdisk_id = manifest.find("machine_configuration/ramdisk_id").text
+ ramdisk_id = manifest.find('machine_configuration/ramdisk_id').text
if ramdisk_id == 'true':
image_format = 'ari'
image_type = 'ramdisk'
@@ -134,7 +136,7 @@ class S3ImageService(service.BaseImageService):
ramdisk_id = None
try:
- arch = manifest.find("machine_configuration/architecture").text
+ arch = manifest.find('machine_configuration/architecture').text
except Exception:
arch = 'x86_64'
@@ -160,7 +162,7 @@ class S3ImageService(service.BaseImageService):
def delayed_create():
"""This handles the fetching and decrypting of the part files."""
parts = []
- for fn_element in manifest.find("image").getiterator("filename"):
+ for fn_element in manifest.find('image').getiterator('filename'):
part = self._download_file(bucket, fn_element.text, image_path)
parts.append(part)
@@ -174,9 +176,9 @@ class S3ImageService(service.BaseImageService):
metadata['properties']['image_state'] = 'decrypting'
self.service.update(context, image_id, metadata)
- hex_key = manifest.find("image/ec2_encrypted_key").text
+ hex_key = manifest.find('image/ec2_encrypted_key').text
encrypted_key = binascii.a2b_hex(hex_key)
- hex_iv = manifest.find("image/ec2_encrypted_iv").text
+ hex_iv = manifest.find('image/ec2_encrypted_iv').text
encrypted_iv = binascii.a2b_hex(hex_iv)
# FIXME(vish): grab key from common service so this can run on
@@ -214,7 +216,7 @@ class S3ImageService(service.BaseImageService):
process_input=encrypted_key,
check_exit_code=False)
if err:
- raise exception.Error(_("Failed to decrypt private key: %s")
+ raise exception.Error(_('Failed to decrypt private key: %s')
% err)
iv, err = utils.execute('openssl',
'rsautl',
@@ -223,8 +225,8 @@ class S3ImageService(service.BaseImageService):
process_input=encrypted_iv,
check_exit_code=False)
if err:
- raise exception.Error(_("Failed to decrypt initialization "
- "vector: %s") % err)
+ raise exception.Error(_('Failed to decrypt initialization '
+ 'vector: %s') % err)
_out, err = utils.execute('openssl', 'enc',
'-d', '-aes-128-cbc',
@@ -234,14 +236,14 @@ class S3ImageService(service.BaseImageService):
'-out', '%s' % (decrypted_filename,),
check_exit_code=False)
if err:
- raise exception.Error(_("Failed to decrypt image file "
- "%(image_file)s: %(err)s") %
+ raise exception.Error(_('Failed to decrypt image file '
+ '%(image_file)s: %(err)s') %
{'image_file': encrypted_filename,
'err': err})
@staticmethod
def _untarzip_image(path, filename):
- tar_file = tarfile.open(filename, "r|gz")
+ tar_file = tarfile.open(filename, 'r|gz')
tar_file.extractall(path)
image_file = tar_file.getnames()[0]
tar_file.close()
diff --git a/nova/image/service.py b/nova/image/service.py
index fddc72409..ab6749049 100644
--- a/nova/image/service.py
+++ b/nova/image/service.py
@@ -20,7 +20,7 @@ from nova import utils
class BaseImageService(object):
- """Base class for providing image search and retrieval services
+ """Base class for providing image search and retrieval services.
ImageService exposes two concepts of metadata:
@@ -35,7 +35,9 @@ class BaseImageService(object):
This means that ImageServices will return BASE_IMAGE_ATTRS as keys in the
metadata dict, all other attributes will be returned as keys in the nested
'properties' dict.
+
"""
+
BASE_IMAGE_ATTRS = ['id', 'name', 'created_at', 'updated_at',
'deleted_at', 'deleted', 'status', 'is_public']
@@ -45,23 +47,18 @@ class BaseImageService(object):
SERVICE_IMAGE_ATTRS = []
def index(self, context):
- """
- Returns a sequence of mappings of id and name information about
- images.
+ """List images.
- :rtype: array
- :retval: a sequence of mappings with the following signature
- {'id': opaque id of image, 'name': name of image}
+ :returns: a sequence of mappings with the following signature
+ {'id': opaque id of image, 'name': name of image}
"""
raise NotImplementedError
def detail(self, context):
- """
- Returns a sequence of mappings of detailed information about images.
+ """Detailed information about an images.
- :rtype: array
- :retval: a sequence of mappings with the following signature
+ :returns: a sequence of mappings with the following signature
{'id': opaque id of image,
'name': name of image,
'created_at': creation datetime object,
@@ -77,15 +74,14 @@ class BaseImageService(object):
NotImplementedError, in which case Nova will emulate this method
with repeated calls to show() for each image received from the
index() method.
+
"""
raise NotImplementedError
def show(self, context, image_id):
- """
- Returns a dict containing image metadata for the given opaque image id.
-
- :retval a mapping with the following signature:
+ """Detailed information about an image.
+ :returns: a mapping with the following signature:
{'id': opaque id of image,
'name': name of image,
'created_at': creation datetime object,
@@ -96,54 +92,56 @@ class BaseImageService(object):
'is_public': boolean indicating if image is public
}, ...
- :raises NotFound if the image does not exist
+ :raises: NotFound if the image does not exist
+
"""
raise NotImplementedError
def get(self, context, data):
- """
- Returns a dict containing image metadata and writes image data to data.
+ """Get an image.
:param data: a file-like object to hold binary image data
+ :returns: a dict containing image metadata, writes image data to data.
+ :raises: NotFound if the image does not exist
- :raises NotFound if the image does not exist
"""
raise NotImplementedError
def create(self, context, metadata, data=None):
- """
- Store the image metadata and data and return the new image metadata.
+ """Store the image metadata and data.
- :raises AlreadyExists if the image already exist.
+ :returns: the new image metadata.
+ :raises: AlreadyExists if the image already exist.
"""
raise NotImplementedError
def update(self, context, image_id, metadata, data=None):
- """Update the given image metadata and data and return the metadata
+ """Update the given image metadata and data and return the metadata.
- :raises NotFound if the image does not exist.
+ :raises: NotFound if the image does not exist.
"""
raise NotImplementedError
def delete(self, context, image_id):
- """
- Delete the given image.
+ """Delete the given image.
- :raises NotFound if the image does not exist.
+ :raises: NotFound if the image does not exist.
"""
raise NotImplementedError
@staticmethod
def _is_image_available(context, image_meta):
- """
+ """Check image availability.
+
Images are always available if they are public or if the user is an
admin.
Otherwise, we filter by project_id (if present) and then fall-back to
images owned by user.
+
"""
# FIXME(sirp): We should be filtering by user_id on the Glance side
# for security; however, we can't do that until we get authn/authz
@@ -169,29 +167,32 @@ class BaseImageService(object):
This is used by subclasses to expose only a metadata dictionary that
is the same across ImageService implementations.
+
"""
return cls._propertify_metadata(metadata, cls.BASE_IMAGE_ATTRS)
@classmethod
def _translate_to_service(cls, metadata):
- """Return a metadata dictionary that is usable by the ImageService
- subclass.
+ """Return a metadata dict that is usable by the ImageService subclass.
As an example, Glance has additional attributes (like 'location'); the
BaseImageService considers these properties, but we need to translate
these back to first-class attrs for sending to Glance. This method
handles this by allowing you to specify the attributes an ImageService
considers first-class.
+
"""
if not cls.SERVICE_IMAGE_ATTRS:
- raise NotImplementedError(_("Cannot use this without specifying "
- "SERVICE_IMAGE_ATTRS for subclass"))
+ raise NotImplementedError(_('Cannot use this without specifying '
+ 'SERVICE_IMAGE_ATTRS for subclass'))
return cls._propertify_metadata(metadata, cls.SERVICE_IMAGE_ATTRS)
@staticmethod
def _propertify_metadata(metadata, keys):
- """Return a dict with any unrecognized keys placed in the nested
- 'properties' dict.
+ """Move unknown keys to a nested 'properties' dict.
+
+ :returns: a new dict with the keys moved.
+
"""
flattened = utils.flatten_dict(metadata)
attributes, properties = utils.partition_dict(flattened, keys)