From f3d044291fe75c2b6ce7a4f8e9a6885d4ffd38c0 Mon Sep 17 00:00:00 2001 From: Lianhao Lu Date: Fri, 29 Mar 2013 18:40:44 +0800 Subject: [PATCH] v2 API: added resource-show. Added resource-show command for v2 API. blueprint more-cli-cmd. Change-Id: I9e0dcff63b2ac6650094d47a947a2deaaea2ba4d --- ceilometerclient/common/base.py | 5 +- ceilometerclient/common/utils.py | 29 ++++++--- ceilometerclient/v2/resources.py | 7 ++ ceilometerclient/v2/shell.py | 17 +++++ tests/v2/test_resources.py | 106 +++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 tests/v2/test_resources.py diff --git a/ceilometerclient/common/base.py b/ceilometerclient/common/base.py index 02ecdaeb..ae1ecfcf 100644 --- a/ceilometerclient/common/base.py +++ b/ceilometerclient/common/base.py @@ -49,7 +49,8 @@ class Manager(object): def __init__(self, api): self.api = api - def _list(self, url, response_key=None, obj_class=None, body=None): + def _list(self, url, response_key=None, obj_class=None, body=None, + expect_single=False): resp, body = self.api.json_request('GET', url) if obj_class is None: @@ -62,6 +63,8 @@ class Manager(object): return [] else: data = body + if expect_single: + data = [data] return [obj_class(self, res, loaded=True) for res in data if res] def _delete(self, url): diff --git a/ceilometerclient/common/utils.py b/ceilometerclient/common/utils.py index 2703b7a3..658cdf49 100644 --- a/ceilometerclient/common/utils.py +++ b/ceilometerclient/common/utils.py @@ -17,6 +17,7 @@ import errno import hashlib import os import sys +import textwrap import uuid import prettytable @@ -49,22 +50,32 @@ def print_list(objs, fields, field_labels, formatters={}, sortby=0): if field in formatters: row.append(formatters[field](o)) else: - data = getattr(o, field, None) or '' + data = getattr(o, field, '') row.append(data) pt.add_row(row) print pt.get_string(sortby=field_labels[sortby]) -def print_dict(d, formatters={}): - pt = prettytable.PrettyTable(['Property', 'Value'], caching=False) +def print_dict(d, dict_property="Property", wrap=0): + pt = prettytable.PrettyTable([dict_property, 'Value'], caching=False) pt.align = 'l' - - for field in d.keys(): - if field in formatters: - pt.add_row([field, formatters[field](d[field])]) + for k, v in d.iteritems(): + # convert dict to str to check length + if isinstance(v, dict): + v = str(v) + if wrap > 0: + v = textwrap.fill(str(v), wrap) + # if value has a newline, add in multiple rows + # e.g. fault with stacktrace + if v and isinstance(v, basestring) and r'\n' in v: + lines = v.strip().split(r'\n') + col1 = k + for line in lines: + pt.add_row([col1, line]) + col1 = '' else: - pt.add_row([field, d[field]]) - print pt.get_string(sortby='Property') + pt.add_row([k, v]) + print pt.get_string() def find_resource(manager, name_or_id): diff --git a/ceilometerclient/v2/resources.py b/ceilometerclient/v2/resources.py index 9b80671c..59adb954 100644 --- a/ceilometerclient/v2/resources.py +++ b/ceilometerclient/v2/resources.py @@ -29,3 +29,10 @@ class ResourceManager(base.Manager): def list(self, q=None): path = '/v2/resources' return self._list(options.build_url(path, q)) + + def get(self, resource_id): + path = '/v2/resources/%s' % resource_id + try: + return self._list(path, expect_single=True)[0] + except IndexError: + return None diff --git a/ceilometerclient/v2/shell.py b/ceilometerclient/v2/shell.py index 1f11dc59..f577229e 100644 --- a/ceilometerclient/v2/shell.py +++ b/ceilometerclient/v2/shell.py @@ -91,3 +91,20 @@ def do_resource_list(cc, args={}): fields = ['resource_id', 'source', 'user_id', 'project_id'] utils.print_list(resources, fields, field_labels, sortby=1) + + +@utils.arg('-r', '--resource_id', metavar='', + help='ID of the resource to show.') +def do_resource_show(cc, args={}): + '''Show the resource''' + if args.resource_id is None: + raise exc.CommandError('Resource id not provided (-r )') + try: + resource = cc.resources.get(args.resource_id) + except exc.HTTPNotFound: + raise exc.CommandError('Resource not found: %s' % args.resource_id) + else: + fields = ['resource_id', 'source', 'user_id', + 'project_id', 'metadata'] + data = dict([(f, getattr(resource, f, '')) for f in fields]) + utils.print_dict(data, wrap=72) diff --git a/tests/v2/test_resources.py b/tests/v2/test_resources.py new file mode 100644 index 00000000..e0e45299 --- /dev/null +++ b/tests/v2/test_resources.py @@ -0,0 +1,106 @@ +# 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 ceilometerclient.v2.resources +from tests import utils + + +fixtures = { + '/v2/resources': { + 'GET': ( + {}, + [ + { + 'resource_id': 'a', + 'project_id': 'project_bla', + 'user_id': 'freddy', + 'metadata': {'zxc_id': 'bla'}, + }, + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'metadata': {'zxc_id': 'foo'}, + }, + ] + ), + }, + '/v2/resources?q.op=&q.value=a&q.field=resource_id': + { + 'GET': ( + {}, + [ + { + 'resource_id': 'a', + 'project_id': 'project_bla', + 'user_id': 'freddy', + 'metadata': {'zxc_id': 'bla'}, + }, + ] + ), + }, + '/v2/resources/a': + { + 'GET': ( + {}, + { + 'resource_id': 'a', + 'project_id': 'project_bla', + 'user_id': 'freddy', + 'metadata': {'zxc_id': 'bla'}, + }, + ), + }, +} + + +class ResourceManagerTest(unittest.TestCase): + + def setUp(self): + self.api = utils.FakeAPI(fixtures) + self.mgr = ceilometerclient.v2.resources.ResourceManager(self.api) + + def test_list_all(self): + resources = list(self.mgr.list()) + expect = [ + ('GET', '/v2/resources', {}, None), + ] + self.assertEqual(self.api.calls, expect) + self.assertEqual(len(resources), 2) + self.assertEqual(resources[0].resource_id, 'a') + self.assertEqual(resources[1].resource_id, 'b') + + def test_list_one(self): + resource = self.mgr.get(resource_id='a') + expect = [ + ('GET', '/v2/resources/a', {}, None), + ] + self.assertEqual(self.api.calls, expect) + self.assertTrue(resource) + self.assertEqual(resource.resource_id, 'a') + + def test_list_by_query(self): + resources = list(self.mgr.list(q=[ + {"field": "resource_id", + "value": "a"}, + ])) + expect = [ + ('GET', '/v2/resources?q.op=&q.value=a&q.field=resource_id', {}, None), + ] + self.assertEqual(self.api.calls, expect) + self.assertEqual(len(resources), 1) + self.assertEqual(resources[0].resource_id, 'a')