Skip to content

Commit ad59b03

Browse files
author
Dean Troyer
committed
Add object-store show commands
* Add lib.container.show_container() and lib.object.show_object() * Add container and object show commands Change-Id: I963d664c55b59739453345f0f353aa2eaf1bf70e
1 parent 74f4e31 commit ad59b03

9 files changed

Lines changed: 368 additions & 17 deletions

File tree

‎openstackclient/object/v1/container.py‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818

1919
import logging
20+
import six
2021

2122
from cliff import lister
23+
from cliff import show
2224

2325
from openstackclient.common import utils
2426
from openstackclient.object.v1.lib import container as lib_container
@@ -91,10 +93,35 @@ def take_action(self, parsed_args):
9193
self.app.client_manager.object.endpoint,
9294
**kwargs
9395
)
94-
#print "data: %s" % data
9596

9697
return (columns,
9798
(utils.get_dict_properties(
9899
s, columns,
99100
formatters={},
100101
) for s in data))
102+
103+
104+
class ShowContainer(show.ShowOne):
105+
"""Show container information"""
106+
107+
log = logging.getLogger(__name__ + '.ShowContainer')
108+
109+
def get_parser(self, prog_name):
110+
parser = super(ShowContainer, self).get_parser(prog_name)
111+
parser.add_argument(
112+
'container',
113+
metavar='<container>',
114+
help='Container name to display',
115+
)
116+
return parser
117+
118+
def take_action(self, parsed_args):
119+
self.log.debug('take_action(%s)' % parsed_args)
120+
121+
data = lib_container.show_container(
122+
self.app.restapi,
123+
self.app.client_manager.object.endpoint,
124+
parsed_args.container,
125+
)
126+
127+
return zip(*sorted(six.iteritems(data)))

‎openstackclient/object/v1/lib/container.py‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616

1717
"""Object v1 API library"""
1818

19+
try:
20+
from urllib.parse import urlparse
21+
except ImportError:
22+
from urlparse import urlparse
23+
1924

2025
def list_containers(
2126
api,
@@ -75,3 +80,34 @@ def list_containers(
7580
url = "%s?%s" % (object_url, query)
7681
response = api.request('GET', url)
7782
return response.json()
83+
84+
85+
def show_container(
86+
api,
87+
url,
88+
container,
89+
):
90+
"""Get container details
91+
92+
:param api: a restapi object
93+
:param url: endpoint
94+
:param container: name of container to show
95+
:returns: dict of returned headers
96+
"""
97+
98+
object_url = "%s/%s" % (url, container)
99+
url_parts = urlparse(url)
100+
response = api.request('HEAD', object_url)
101+
data = {
102+
'account': url_parts.path.split('/')[-1],
103+
'container': container,
104+
}
105+
data['object_count'] = response.headers.get(
106+
'x-container-object-count', None)
107+
data['bytes_used'] = response.headers.get('x-container-bytes-used', None)
108+
data['read_acl'] = response.headers.get('x-container-read', None)
109+
data['write_acl'] = response.headers.get('x-container-write', None)
110+
data['sync_to'] = response.headers.get('x-container-sync-to', None)
111+
data['sync_key'] = response.headers.get('x-container-sync-key', None)
112+
113+
return data

‎openstackclient/object/v1/lib/object.py‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616

1717
"""Object v1 API library"""
1818

19+
import six
20+
21+
try:
22+
from urllib.parse import urlparse
23+
except ImportError:
24+
from urlparse import urlparse
25+
1926

2027
def list_objects(
2128
api,
@@ -95,3 +102,47 @@ def list_objects(
95102
url = "%s/%s?%s" % (object_url, container, query)
96103
response = api.request('GET', url)
97104
return response.json()
105+
106+
107+
def show_object(
108+
api,
109+
url,
110+
container,
111+
obj,
112+
):
113+
"""Get object details
114+
115+
:param api: a restapi object
116+
:param url: endpoint
117+
:param container: container name to get a listing for
118+
:returns: dict of object properties
119+
"""
120+
121+
object_url = "%s/%s/%s" % (url, container, obj)
122+
url_parts = urlparse(url)
123+
response = api.request('HEAD', object_url)
124+
data = {
125+
'account': url_parts.path.split('/')[-1],
126+
'container': container,
127+
'object': obj,
128+
}
129+
#print "data: %s" % data
130+
data['content-type'] = response.headers.get('content-type', None)
131+
if 'content-length' in response.headers:
132+
data['content-length'] = response.headers.get('content-length', None)
133+
if 'last-modified' in response.headers:
134+
data['last-modified'] = response.headers.get('last-modified', None)
135+
if 'etag' in response.headers:
136+
data['etag'] = response.headers.get('etag', None)
137+
if 'x-object-manifest' in response.headers:
138+
data['x-object-manifest'] = response.headers.get(
139+
'x-object-manifest', None)
140+
for key, value in six.iteritems(response.headers):
141+
if key.startswith('x-object-meta-'):
142+
data[key[len('x-object-meta-'):].title()] = value
143+
elif key not in (
144+
'content-type', 'content-length', 'last-modified',
145+
'etag', 'date', 'x-object-manifest'):
146+
data[key.title()] = value
147+
148+
return data

‎openstackclient/object/v1/object.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818

1919
import logging
20+
import six
2021

2122
from cliff import lister
23+
from cliff import show
2224

2325
from openstackclient.common import utils
2426
from openstackclient.object.v1.lib import object as lib_object
@@ -116,3 +118,35 @@ def take_action(self, parsed_args):
116118
s, columns,
117119
formatters={},
118120
) for s in data))
121+
122+
123+
class ShowObject(show.ShowOne):
124+
"""Show object information"""
125+
126+
log = logging.getLogger(__name__ + '.ShowObject')
127+
128+
def get_parser(self, prog_name):
129+
parser = super(ShowObject, self).get_parser(prog_name)
130+
parser.add_argument(
131+
'container',
132+
metavar='<container>',
133+
help='Container name for object to display',
134+
)
135+
parser.add_argument(
136+
'object',
137+
metavar='<object>',
138+
help='Object name to display',
139+
)
140+
return parser
141+
142+
def take_action(self, parsed_args):
143+
self.log.debug('take_action(%s)' % parsed_args)
144+
145+
data = lib_object.show_object(
146+
self.app.restapi,
147+
self.app.client_manager.object.endpoint,
148+
parsed_args.container,
149+
parsed_args.object,
150+
)
151+
152+
return zip(*sorted(six.iteritems(data)))

‎openstackclient/tests/object/test_container.py‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,3 +313,49 @@ def test_object_list_containers_all(self, c_mock):
313313
(object_fakes.container_name_3, ),
314314
)
315315
self.assertEqual(tuple(data), datalist)
316+
317+
318+
@mock.patch(
319+
'openstackclient.object.v1.container.lib_container.show_container'
320+
)
321+
class TestContainerShow(TestObject):
322+
323+
def setUp(self):
324+
super(TestContainerShow, self).setUp()
325+
326+
# Get the command object to test
327+
self.cmd = container.ShowContainer(self.app, None)
328+
329+
def test_container_show(self, c_mock):
330+
c_mock.return_value = copy.deepcopy(object_fakes.CONTAINER)
331+
332+
arglist = [
333+
object_fakes.container_name,
334+
]
335+
verifylist = [
336+
('container', object_fakes.container_name),
337+
]
338+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
339+
340+
# DisplayCommandBase.take_action() returns two tuples
341+
columns, data = self.cmd.take_action(parsed_args)
342+
343+
# Set expected values
344+
kwargs = {
345+
}
346+
# lib.container.show_container(api, url, container)
347+
c_mock.assert_called_with(
348+
self.app.restapi,
349+
AUTH_URL,
350+
object_fakes.container_name,
351+
**kwargs
352+
)
353+
354+
collist = ('bytes', 'count', 'name')
355+
self.assertEqual(columns, collist)
356+
datalist = (
357+
object_fakes.container_bytes,
358+
object_fakes.container_count,
359+
object_fakes.container_name,
360+
)
361+
self.assertEqual(data, datalist)

‎openstackclient/tests/object/test_object.py‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,3 +360,54 @@ def test_object_list_objects_all(self, o_mock):
360360
(object_fakes.object_name_2, ),
361361
)
362362
self.assertEqual(tuple(data), datalist)
363+
364+
365+
@mock.patch(
366+
'openstackclient.object.v1.object.lib_object.show_object'
367+
)
368+
class TestObjectShow(TestObject):
369+
370+
def setUp(self):
371+
super(TestObjectShow, self).setUp()
372+
373+
# Get the command object to test
374+
self.cmd = obj.ShowObject(self.app, None)
375+
376+
def test_object_show(self, c_mock):
377+
c_mock.return_value = copy.deepcopy(object_fakes.OBJECT)
378+
379+
arglist = [
380+
object_fakes.container_name,
381+
object_fakes.object_name_1,
382+
]
383+
verifylist = [
384+
('container', object_fakes.container_name),
385+
('object', object_fakes.object_name_1),
386+
]
387+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
388+
389+
# DisplayCommandBase.take_action() returns two tuples
390+
columns, data = self.cmd.take_action(parsed_args)
391+
392+
# Set expected values
393+
kwargs = {
394+
}
395+
# lib.container.show_container(api, url, container)
396+
c_mock.assert_called_with(
397+
self.app.restapi,
398+
AUTH_URL,
399+
object_fakes.container_name,
400+
object_fakes.object_name_1,
401+
**kwargs
402+
)
403+
404+
collist = ('bytes', 'content_type', 'hash', 'last_modified', 'name')
405+
self.assertEqual(columns, collist)
406+
datalist = (
407+
object_fakes.object_bytes_1,
408+
object_fakes.object_content_type_1,
409+
object_fakes.object_hash_1,
410+
object_fakes.object_modified_1,
411+
object_fakes.object_name_1,
412+
)
413+
self.assertEqual(data, datalist)

0 commit comments

Comments
 (0)