Skip to content

Commit

Permalink
Merge trunk and resolve conflict in server.py
Browse files Browse the repository at this point in the history
  • Loading branch information
[email protected] committed Jan 13, 2011
2 parents 4b924c9 + 1f4a644 commit b2cd2b0
Show file tree
Hide file tree
Showing 22 changed files with 454 additions and 369 deletions.
4 changes: 4 additions & 0 deletions doc/source/client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ The method signature is as follows::
The `image_meta` argument is a mapping containing various image metadata. The
`image_data` argument is the disk image data.

If the data is not yet available, but you would like to reserve a slot in
Glance to hold the image, you can create a 'queued' by omitting the
`image_data` parameter.

The list of metadata that `image_meta` can contain are listed below.

* `name`
Expand Down
34 changes: 21 additions & 13 deletions doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@
# Glance documentation build configuration file, created by
# sphinx-quickstart on Tue May 18 13:50:15 2010.
#
# This file is execfile()d with the current directory set to its containing dir.
# This file is execfile()'d with the current directory set to it's containing
# dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os
import os
import sys

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
Expand All @@ -36,19 +38,25 @@
os.path.abspath('../bin')
])

# -- General configuration -----------------------------------------------------
# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.coverage',
'sphinx.ext.ifconfig',
'sphinx.ext.intersphinx',
'sphinx.ext.pngmath',
'sphinx.ext.todo']

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig']
todo_include_todos = True

# Add any paths that contain templates here, relative to this directory.
templates_path = []
if os.getenv('HUDSON_PUBLISH_DOCS'):
templates_path = ['_ga', '_templates']
templates_path = ['_ga', '_templates']
else:
templates_path = ['_templates']
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'
Expand Down Expand Up @@ -89,7 +97,7 @@
# for source files.
exclude_trees = []

# The reST default role (used for this markup: `text`) to use for all documents.
# The reST default role (for this markup: `text`) to use for all documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
Expand All @@ -110,7 +118,7 @@
modindex_common_prefix = ['glance.']


# -- Options for HTML output ---------------------------------------------------
# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
Expand Down Expand Up @@ -185,7 +193,7 @@
htmlhelp_basename = 'glancedoc'


# -- Options for LaTeX output --------------------------------------------------
# -- Options for LaTeX output ------------------------------------------------

# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
Expand All @@ -194,7 +202,8 @@
#latex_font_size = '10pt'

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
# (source start file, target name, title, author,
# documentclass [howto/manual]).
latex_documents = [
('index', 'Glance.tex', u'Glance Documentation',
u'Glance Team', 'manual'),
Expand All @@ -221,4 +230,3 @@
intersphinx_mapping = {'python': ('http://docs.python.org/', None),
'nova': ('http://nova.openstack.org', None),
'swift': ('http://swift.openstack.org', None)}

16 changes: 16 additions & 0 deletions doc/source/glanceapi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -292,3 +292,19 @@ The list of metadata headers that Glance accepts are listed below.
be attached to the image. However, keep in mind that the 8K limit on the
size of all HTTP headers sent in a request will effectively limit the number
of image properties.


Updating an Image
*****************

Glance will view as image metadata any HTTP header that it receives in a
`PUT` request where the header key is prefixed with the strings
`x-image-meta-` and `x-image-meta-property-`.

If an image was previously reserved, and thus is in the `queued` state, then
image data can be added by including it as the request body. If the image
already as data associated with it (e.g. not in the `queued` state), then
including a request body will result in a `409 Conflict` exception.

On success, the `PUT` request will return the image metadata encoded as `HTTP`
headers.
37 changes: 20 additions & 17 deletions glance/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ def do_request(self, method, action, body=None, headers=None):
elif status_code == httplib.NOT_FOUND:
raise exception.NotFound
elif status_code == httplib.CONFLICT:
raise exception.Duplicate
raise exception.Duplicate(res.read())
elif status_code == httplib.BAD_REQUEST:
raise exception.BadInputError
raise exception.BadInputError(res.read())
else:
raise Exception("Unknown error occurred! %d" % status_code)
raise Exception("Unknown error occurred! %s" % res.__dict__)

except (socket.error, IOError), e:
raise ClientConnectionError("Unable to connect to "
Expand Down Expand Up @@ -203,24 +203,22 @@ def get_image_meta(self, image_id):
image = util.get_image_meta_from_headers(res)
return image

def add_image(self, image_meta, image_data=None):
def add_image(self, image_meta=None, image_data=None):
"""
Tells Glance about an image's metadata as well
as optionally the image_data itself
:param image_meta: Mapping of information about the
:param image_meta: Optional Mapping of information about the
image
:param image_data: Optional string of raw image data
or file-like object that can be
used to read the image data
:retval The newly-stored image's metadata.
"""
if not image_data and 'location' not in image_meta.keys():
raise exception.Invalid("You must either specify a location "
"for the image or supply the actual "
"image data when adding an image to "
"Glance")
if image_meta is None:
image_meta = {}

if image_data:
if hasattr(image_data, 'read'):
# TODO(jaypipes): This is far from efficient. Implement
Expand All @@ -242,17 +240,22 @@ def add_image(self, image_meta, image_data=None):

res = self.do_request("POST", "/images", body, headers)
data = json.loads(res.read())
return data['image']['id']
return data['image']

def update_image(self, image_id, image_metadata):
def update_image(self, image_id, image_meta=None, image_data=None):
"""
Updates Glance's information about an image
"""
if 'image' not in image_metadata.keys():
image_metadata = dict(image=image_metadata)
body = json.dumps(image_metadata)
self.do_request("PUT", "/images/%s" % image_id, body)
return True
if image_meta:
if 'image' not in image_meta:
image_meta = dict(image=image_meta)

headers = util.image_meta_to_http_headers(image_meta or {})

body = image_data
res = self.do_request("PUT", "/images/%s" % image_id, body, headers)
data = json.loads(res.read())
return data['image']

def delete_image(self, image_id):
"""
Expand Down
3 changes: 1 addition & 2 deletions glance/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,7 @@ def generate_uid(topic, size=8):

def generate_mac():
mac = [0x02, 0x16, 0x3e, random.randint(0x00, 0x7f),
random.randint(0x00, 0xff), random.randint(0x00, 0xff)
]
random.randint(0x00, 0xff), random.randint(0x00, 0xff)]
return ':'.join(map(lambda x: "%02x" % x, mac))


Expand Down
8 changes: 6 additions & 2 deletions glance/registry/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,13 @@ def update_image(self, image_id, image_metadata):
"""
if 'image' not in image_metadata.keys():
image_metadata = dict(image=image_metadata)

body = json.dumps(image_metadata)
self.do_request("PUT", "/images/%s" % image_id, body)
return True

res = self.do_request("PUT", "/images/%s" % image_id, body)
data = json.loads(res.read())
image = data['image']
return image

def delete_image(self, image_id):
"""
Expand Down
32 changes: 17 additions & 15 deletions glance/registry/db/sqlalchemy/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,31 +65,31 @@ def image_destroy(_context, image_id):
def image_get(context, image_id):
session = get_session()
try:
return session.query(models.Image
).options(joinedload(models.Image.properties)
).filter_by(deleted=_deleted(context)
).filter_by(id=image_id
).one()
return session.query(models.Image).\
options(joinedload(models.Image.properties)).\
filter_by(deleted=_deleted(context)).\
filter_by(id=image_id).\
one()
except exc.NoResultFound:
new_exc = exception.NotFound("No model for id %s" % image_id)
raise new_exc.__class__, new_exc, sys.exc_info()[2]


def image_get_all(context):
session = get_session()
return session.query(models.Image
).options(joinedload(models.Image.properties)
).filter_by(deleted=_deleted(context)
).all()
return session.query(models.Image).\
options(joinedload(models.Image.properties)).\
filter_by(deleted=_deleted(context)).\
all()


def image_get_all_public(context, public):
session = get_session()
return session.query(models.Image
).options(joinedload(models.Image.properties)
).filter_by(deleted=_deleted(context)
).filter_by(is_public=public
).all()
return session.query(models.Image).\
options(joinedload(models.Image.properties)).\
filter_by(deleted=_deleted(context)).\
filter_by(is_public=public).\
all()


def image_get_by_str(context, str_id):
Expand Down Expand Up @@ -129,7 +129,9 @@ def _image_update(_context, values, image_id):
with session.begin():
_drop_protected_attrs(models.Image, values)

values['size'] = int(values['size'])
if 'size' in values:
values['size'] = int(values['size'])

values['is_public'] = bool(values.get('is_public', False))
properties = values.pop('properties', {})

Expand Down
22 changes: 11 additions & 11 deletions glance/registry/db/sqlalchemy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,29 +58,29 @@ def all(cls, session=None, deleted=False):
"""Get all objects of this type"""
if not session:
session = get_session()
return session.query(cls
).filter_by(deleted=deleted
).all()
return session.query(cls).\
filter_by(deleted=deleted).\
all()

@classmethod
def count(cls, session=None, deleted=False):
"""Count objects of this type"""
if not session:
session = get_session()
return session.query(cls
).filter_by(deleted=deleted
).count()
return session.query(cls).\
filter_by(deleted=deleted).\
count()

@classmethod
def find(cls, obj_id, session=None, deleted=False):
"""Find object by id"""
if not session:
session = get_session()
try:
return session.query(cls
).filter_by(id=obj_id
).filter_by(deleted=deleted
).one()
return session.query(cls).\
filter_by(id=obj_id).\
filter_by(deleted=deleted).\
one()
except exc.NoResultFound:
new_exc = exception.NotFound("No model for id %s" % obj_id)
raise new_exc.__class__, new_exc, sys.exc_info()[2]
Expand Down Expand Up @@ -160,7 +160,7 @@ def validate_type(self, key, type):

@validates('status')
def validate_status(self, key, status):
if not status in ('available', 'pending', 'disabled'):
if not status in ('active', 'queued', 'killed', 'saving'):
raise exception.Invalid("Invalid status '%s' for image." % status)
return status

Expand Down
2 changes: 1 addition & 1 deletion glance/registry/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def create(self, req):
image_data = json.loads(req.body)['image']

# Ensure the image has a status set
image_data.setdefault('status', 'available')
image_data.setdefault('status', 'active')

context = None
try:
Expand Down
Loading

0 comments on commit b2cd2b0

Please sign in to comment.