Merge changes Ib98e912a,Ib98e912a,Ib98e912a,Ib98e912a,Ib98e912a
* changes: Align print_dict to the left Convert v2 images list method to generator Replace static v2 Image model with warlock model Add support for viewing a single image through v2 Rewrite link parsing for finding v2 schemas
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
import prettytable
|
||||
@@ -47,7 +48,7 @@ def print_list(objs, fields, formatters={}):
|
||||
row.append(formatters[field](o))
|
||||
else:
|
||||
field_name = field.lower().replace(' ', '_')
|
||||
data = getattr(o, field_name, '')
|
||||
data = getattr(o, field_name, None) or ''
|
||||
row.append(data)
|
||||
pt.add_row(row)
|
||||
|
||||
@@ -56,7 +57,7 @@ def print_list(objs, fields, formatters={}):
|
||||
|
||||
def print_dict(d):
|
||||
pt = prettytable.PrettyTable(['Property', 'Value'], caching=False)
|
||||
pt.aligns = ['l', 'l']
|
||||
pt.align = 'l'
|
||||
[pt.add_row(list(r)) for r in d.iteritems()]
|
||||
print pt.get_string(sortby='Property')
|
||||
|
||||
@@ -123,3 +124,9 @@ def import_versioned_module(version, submodule=None):
|
||||
if submodule:
|
||||
module = '.'.join((module, submodule))
|
||||
return importutils.import_module(module)
|
||||
|
||||
|
||||
def exit(msg=''):
|
||||
if msg:
|
||||
print >> sys.stderr, msg
|
||||
sys.exit(1)
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
import logging
|
||||
|
||||
import warlock
|
||||
|
||||
from glanceclient.common import http
|
||||
from glanceclient.v2 import images
|
||||
from glanceclient.v2 import schemas
|
||||
@@ -36,5 +38,10 @@ class Client(object):
|
||||
def __init__(self, endpoint, token=None, timeout=600, **kwargs):
|
||||
self.http_client = http.HTTPClient(
|
||||
endpoint, token=token, timeout=timeout)
|
||||
self.images = images.Controller(self.http_client)
|
||||
self.schemas = schemas.Controller(self.http_client)
|
||||
self.images = images.Controller(self.http_client,
|
||||
self._get_image_model())
|
||||
|
||||
def _get_image_model(self):
|
||||
schema = self.schemas.get('image')
|
||||
return warlock.model_factory(schema.raw())
|
||||
|
||||
@@ -14,16 +14,27 @@
|
||||
# under the License.
|
||||
|
||||
|
||||
class Image(object):
|
||||
def __init__(self, id, name):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
||||
|
||||
class Controller(object):
|
||||
def __init__(self, http_client):
|
||||
def __init__(self, http_client, model):
|
||||
self.http_client = http_client
|
||||
self.model = model
|
||||
|
||||
def list(self):
|
||||
"""Retrieve a listing of Image objects
|
||||
|
||||
:returns generator over list of Images
|
||||
"""
|
||||
resp, body = self.http_client.json_request('GET', '/v2/images')
|
||||
return [Image(i['id'], i['name']) for i in body['images']]
|
||||
for image in body['images']:
|
||||
#NOTE(bcwaldon): remove 'self' for now until we have an elegant
|
||||
# way to pass it into the model constructor without conflict
|
||||
image.pop('self', None)
|
||||
yield self.model(**image)
|
||||
|
||||
def get(self, image_id):
|
||||
url = '/v2/images/%s' % image_id
|
||||
resp, body = self.http_client.json_request('GET', url)
|
||||
#NOTE(bcwaldon): remove 'self' for now until we have an elegant
|
||||
# way to pass it into the model constructor without conflict
|
||||
body['image'].pop('self', None)
|
||||
return self.model(**body['image'])
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
from glanceclient import exc
|
||||
|
||||
|
||||
@@ -40,6 +42,9 @@ class Schema(object):
|
||||
raw_properties = raw_schema['properties']
|
||||
self.properties = translate_schema_properties(raw_properties)
|
||||
|
||||
def raw(self):
|
||||
return copy.deepcopy(self._raw_schema)
|
||||
|
||||
|
||||
class Controller(object):
|
||||
def __init__(self, http_client):
|
||||
@@ -52,7 +57,7 @@ class Controller(object):
|
||||
|
||||
def _find_schema_uri(self, schema_name):
|
||||
_, schema_index = self.http_client.json_request('GET', '/v2/schemas')
|
||||
for link in schema_index['links']:
|
||||
if link['rel'] == schema_name:
|
||||
return link['href']
|
||||
raise exc.SchemaNotFound(schema_name)
|
||||
try:
|
||||
return schema_index[schema_name]
|
||||
except KeyError:
|
||||
raise exc.SchemaNotFound(schema_name)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
from glanceclient.common import utils
|
||||
from glanceclient import exc
|
||||
|
||||
|
||||
def do_image_list(gc, args):
|
||||
@@ -23,9 +24,21 @@ def do_image_list(gc, args):
|
||||
utils.print_list(images, columns)
|
||||
|
||||
|
||||
@utils.arg('name', metavar='<NAME>', help='Name of model to describe.')
|
||||
@utils.arg('id', metavar='<IMAGE_ID>', help='ID of image to describe.')
|
||||
def do_image_show(gc, args):
|
||||
"""Describe a specific image."""
|
||||
image = gc.images.get(args.id)
|
||||
utils.print_dict(image)
|
||||
|
||||
|
||||
@utils.arg('model', metavar='<MODEL>', help='Name of model to describe.')
|
||||
def do_explain(gc, args):
|
||||
"""Describe a specific model."""
|
||||
schema = gc.schemas.get(args.name)
|
||||
columns = ['Name', 'Description']
|
||||
utils.print_list(schema.properties, columns)
|
||||
try:
|
||||
schema = gc.schemas.get(args.model)
|
||||
except exc.SchemaNotFound:
|
||||
utils.exit('Unable to find requested model \'%s\'' % args.model)
|
||||
else:
|
||||
formatters = {'Attribute': lambda m: m.name}
|
||||
columns = ['Attribute', 'Description']
|
||||
utils.print_list(schema.properties, columns, formatters)
|
||||
|
||||
75
tests/v2/test_images.py
Normal file
75
tests/v2/test_images.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# Copyright 2012 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.
|
||||
|
||||
import unittest
|
||||
|
||||
import warlock
|
||||
|
||||
from glanceclient.v2 import images
|
||||
from tests import utils
|
||||
|
||||
|
||||
fixtures = {
|
||||
'/v2/images': {
|
||||
'GET': (
|
||||
{},
|
||||
{'images': [
|
||||
{
|
||||
'id': '3a4560a1-e585-443e-9b39-553b46ec92d1',
|
||||
'name': 'image-1',
|
||||
},
|
||||
{
|
||||
'id': '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810',
|
||||
'name': 'image-2',
|
||||
},
|
||||
]},
|
||||
),
|
||||
},
|
||||
'/v2/images/3a4560a1-e585-443e-9b39-553b46ec92d1': {
|
||||
'GET': (
|
||||
{},
|
||||
{
|
||||
'image': {
|
||||
'id': '3a4560a1-e585-443e-9b39-553b46ec92d1',
|
||||
'name': 'image-1',
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
fake_schema = {'name': 'image', 'properties': {'id': {}, 'name': {}}}
|
||||
FakeModel = warlock.model_factory(fake_schema)
|
||||
|
||||
|
||||
class TestController(unittest.TestCase):
|
||||
def setUp(self):
|
||||
super(TestController, self).setUp()
|
||||
self.api = utils.FakeAPI(fixtures)
|
||||
self.controller = images.Controller(self.api, FakeModel)
|
||||
|
||||
def test_list_images(self):
|
||||
#NOTE(bcwaldon): cast to list since the controller returns a generator
|
||||
images = list(self.controller.list())
|
||||
self.assertEqual(images[0].id, '3a4560a1-e585-443e-9b39-553b46ec92d1')
|
||||
self.assertEqual(images[0].name, 'image-1')
|
||||
self.assertEqual(images[1].id, '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810')
|
||||
self.assertEqual(images[1].name, 'image-2')
|
||||
|
||||
def test_get_image(self):
|
||||
image = self.controller.get('3a4560a1-e585-443e-9b39-553b46ec92d1')
|
||||
self.assertEqual(image.id, '3a4560a1-e585-443e-9b39-553b46ec92d1')
|
||||
self.assertEqual(image.name, 'image-1')
|
||||
@@ -23,10 +23,10 @@ fixtures = {
|
||||
'/v2/schemas': {
|
||||
'GET': (
|
||||
{},
|
||||
{'links': [
|
||||
{'rel': 'image', 'href': '/v2/schemas/image'},
|
||||
{'rel': 'access', 'href': '/v2/schemas/image/access'},
|
||||
]},
|
||||
{
|
||||
'image': '/v2/schemas/image',
|
||||
'access': '/v2/schemas/image/access',
|
||||
},
|
||||
),
|
||||
},
|
||||
'/v2/schemas/image': {
|
||||
@@ -67,6 +67,11 @@ class TestSchema(unittest.TestCase):
|
||||
self.assertEqual(schema.name, 'Country')
|
||||
self.assertEqual([p.name for p in schema.properties], ['size'])
|
||||
|
||||
def test_raw(self):
|
||||
raw_schema = {'name': 'Country', 'properties': {}}
|
||||
schema = schemas.Schema(raw_schema)
|
||||
self.assertEqual(schema.raw(), raw_schema)
|
||||
|
||||
|
||||
class TestController(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
||||
@@ -2,3 +2,4 @@ argparse
|
||||
httplib2
|
||||
prettytable==0.6
|
||||
python-keystoneclient>=0.1,<0.2
|
||||
warlock==0.1.0
|
||||
|
||||
Reference in New Issue
Block a user