This patch:
* Converts dashes to underscores when extracting image-properties from HTTP headers (we already do this for 'regular' image attributes * Update image_properties on image PUTs rather than trying to create dups Bonus: * Remove useless test_data file (no longer needed now that we can actually use Glance API via glance/client.py) * Add glance_upload.py which we can use to add raw/extra-kernel images (this might be able to go away once we have a full-blown glance-admin tool. However, for now, this is useful for testing Glance <-> Nova integration.
This commit is contained in:
commit
33f909593f
|
@ -0,0 +1,85 @@
|
|||
#!/usr/bin/env python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 OpenStack LLC.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Upload an image into Glance
|
||||
|
||||
Usage:
|
||||
|
||||
Raw:
|
||||
|
||||
glance-upload <filename> <name>
|
||||
|
||||
Kernel-outside:
|
||||
|
||||
glance-upload --type=kernel <filename> <name>
|
||||
glance-upload --type=ramdisk <filename> <name>
|
||||
glance-upload --type=machine --kernel=KERNEL_ID --ramdisk=RAMDISK_ID \
|
||||
<filename> <name>
|
||||
|
||||
"""
|
||||
import argparse
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
from glance.client import Client
|
||||
|
||||
|
||||
def die(msg):
|
||||
print >>sys.stderr, msg
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Upload an image into Glance')
|
||||
parser.add_argument('filename', help='file to upload into Glance')
|
||||
parser.add_argument('name', help='name of image')
|
||||
parser.add_argument('--host', metavar='HOST', default='127.0.0.1',
|
||||
help='Location of Glance Server (default: 127.0.0.1)')
|
||||
parser.add_argument('--type', metavar='TYPE', default='raw',
|
||||
help='Type of Image [kernel, ramdisk, machine, raw] '
|
||||
'(default: raw)')
|
||||
parser.add_argument('--kernel', metavar='KERNEL',
|
||||
help='ID of kernel associated with this machine image')
|
||||
parser.add_argument('--ramdisk', metavar='RAMDISK',
|
||||
help='ID of ramdisk associated with this machine '
|
||||
'image')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
meta = {'name': args.name, 'type': args.type, 'is_public': True}
|
||||
|
||||
if args.type == 'machine':
|
||||
if args.kernel and args.ramdisk:
|
||||
meta['properties'] = {'kernel_id': args.kernel,
|
||||
'ramdisk_id': args.ramdisk}
|
||||
else:
|
||||
die("kernel and ramdisk required for machine image")
|
||||
|
||||
client = Client(args.host, 9292)
|
||||
with open(args.filename) as f:
|
||||
new_meta = client.add_image(meta, f)
|
||||
|
||||
print 'Stored image. Got identifier: %s' % pprint.pformat(new_meta)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -103,12 +103,24 @@ def image_update(_context, image_id, values):
|
|||
###################
|
||||
|
||||
|
||||
def image_property_create(_context, values):
|
||||
_drop_protected_attrs(models.Image, values)
|
||||
image_property_ref = models.ImageProperty()
|
||||
image_property_ref.update(values)
|
||||
image_property_ref.save()
|
||||
return image_property_ref
|
||||
def image_property_create(_context, values, session=None):
|
||||
"""Create an ImageProperty object"""
|
||||
prop_ref = models.ImageProperty()
|
||||
return _image_property_update(_context, prop_ref, values, session=session)
|
||||
|
||||
|
||||
def image_property_update(_context, prop_ref, values, session=None):
|
||||
"""Update an ImageProperty object"""
|
||||
return _image_property_update(_context, prop_ref, values, session=session)
|
||||
|
||||
|
||||
def _image_property_update(_context, prop_ref, values, session=None):
|
||||
"""Used internally by image_property_create and image_property_update
|
||||
"""
|
||||
_drop_protected_attrs(models.ImageProperty, values)
|
||||
prop_ref.update(values)
|
||||
prop_ref.save(session=session)
|
||||
return prop_ref
|
||||
|
||||
|
||||
def _drop_protected_attrs(model_class, values):
|
||||
|
@ -123,6 +135,8 @@ def _drop_protected_attrs(model_class, values):
|
|||
def _image_update(_context, values, image_id):
|
||||
"""Used internally by image_create and image_update
|
||||
|
||||
:param _context: Request context
|
||||
:param values: A dict of attributes to set
|
||||
:param image_id: If None, create the image, otherwise, find and update it
|
||||
"""
|
||||
session = get_session()
|
||||
|
@ -143,10 +157,31 @@ def _image_update(_context, values, image_id):
|
|||
image_ref.update(values)
|
||||
image_ref.save(session=session)
|
||||
|
||||
for key, value in properties.iteritems():
|
||||
prop_values = {'image_id': image_ref.id,
|
||||
'key': key,
|
||||
'value': value}
|
||||
image_property_create(_context, prop_values)
|
||||
_set_properties_for_image(_context, image_ref, properties, session)
|
||||
|
||||
return image_get(_context, image_ref.id)
|
||||
|
||||
|
||||
def _set_properties_for_image(_context, image_ref, properties, session=None):
|
||||
"""
|
||||
Create or update a set of image_properties for a given image
|
||||
|
||||
:param _context: Request context
|
||||
:param image_ref: An Image object
|
||||
:param properties: A dict of properties to set
|
||||
:param session: A SQLAlchemy session to use (if present)
|
||||
"""
|
||||
orig_properties = {}
|
||||
for prop_ref in image_ref.properties:
|
||||
orig_properties[prop_ref.key] = prop_ref
|
||||
|
||||
for key, value in properties.iteritems():
|
||||
prop_values = {'image_id': image_ref.id,
|
||||
'key': key,
|
||||
'value': value}
|
||||
if key in orig_properties:
|
||||
prop_ref = orig_properties[key]
|
||||
image_property_update(_context, prop_ref, prop_values,
|
||||
session=session)
|
||||
else:
|
||||
image_property_create(_context, prop_values, session=session)
|
||||
|
|
|
@ -76,8 +76,9 @@ def get_image_meta_from_headers(response):
|
|||
for key, value in headers:
|
||||
key = str(key.lower())
|
||||
if key.startswith('x-image-meta-property-'):
|
||||
properties[key[len('x-image-meta-property-'):]] = value
|
||||
if key.startswith('x-image-meta-'):
|
||||
field_name = key[len('x-image-meta-property-'):].replace('-', '_')
|
||||
properties[field_name] = value
|
||||
elif key.startswith('x-image-meta-'):
|
||||
field_name = key[len('x-image-meta-'):].replace('-', '_')
|
||||
result[field_name] = value
|
||||
result['properties'] = properties
|
||||
|
|
3
setup.py
3
setup.py
|
@ -71,4 +71,5 @@ setup(
|
|||
],
|
||||
install_requires=[], # removed for better compat
|
||||
scripts=['bin/glance-api',
|
||||
'bin/glance-registry'])
|
||||
'bin/glance-registry',
|
||||
'bin/glance-upload'])
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 OpenStack, LLC
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from glance.registry import db
|
||||
|
||||
|
||||
def make_swift_image():
|
||||
"""Create a real image record """
|
||||
|
||||
# TODO(sirp): Create a testing account, and define gflags for
|
||||
# test_swift_username and test_swift_api_key
|
||||
USERNAME = "your user name here" # fill these out for testing
|
||||
API_KEY = "your api key here"
|
||||
#IMAGE_CHUNKS = [("filename", 123)] # filename, size in bytes
|
||||
IMAGE_CHUNKS = [("your test chunk here", 12345)]
|
||||
|
||||
image = db.image_create(
|
||||
None,
|
||||
dict(name="testsnap",
|
||||
state="available",
|
||||
public=True,
|
||||
image_type="raw"))
|
||||
|
||||
for obj, size in IMAGE_CHUNKS:
|
||||
location = (
|
||||
"swift://%s:%s@auth.api.rackspacecloud.com/v1.0/cloudservers/%s"
|
||||
) % (USERNAME, API_KEY, obj)
|
||||
|
||||
db.image_file_create(None,
|
||||
dict(image_id=image.id, location=location, size=size))
|
||||
|
||||
if __name__ == "__main__":
|
||||
make_swift_image() # NOTE: uncomment if you have a username and api_key
|
Loading…
Reference in New Issue