Skip to content

Commit a40d22f

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Fix formatting of the flavor properties"
2 parents 4cdc953 + ad3369e commit a40d22f

4 files changed

Lines changed: 90 additions & 42 deletions

File tree

openstackclient/compute/v2/flavor.py

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import logging
1919

2020
from novaclient import api_versions
21+
from osc_lib.cli import format_columns
2122
from osc_lib.cli import parseractions
2223
from osc_lib.command import command
2324
from osc_lib import exceptions
@@ -30,6 +31,31 @@
3031
LOG = logging.getLogger(__name__)
3132

3233

34+
_formatters = {
35+
'extra_specs': format_columns.DictColumn,
36+
# Unless we finish switch to use SDK resources this need to be doubled this
37+
# way
38+
'properties': format_columns.DictColumn,
39+
'Properties': format_columns.DictColumn
40+
}
41+
42+
43+
def _get_flavor_columns(item):
44+
# To maintain backwards compatibility we need to rename sdk props to
45+
# whatever OSC was using before
46+
column_map = {
47+
'extra_specs': 'properties',
48+
'ephemeral': 'OS-FLV-EXT-DATA:ephemeral',
49+
'is_disabled': 'OS-FLV-DISABLED:disabled',
50+
'is_public': 'os-flavor-access:is_public'
51+
52+
}
53+
hidden_columns = ['links', 'location']
54+
55+
return utils.get_osc_show_columns_for_sdk_resource(
56+
item, column_map, hidden_columns)
57+
58+
3359
def _find_flavor(compute_client, flavor):
3460
try:
3561
return compute_client.flavors.get(flavor)
@@ -191,10 +217,16 @@ def take_action(self, parsed_args):
191217
LOG.error(_("Failed to set flavor property: %s"), e)
192218

193219
flavor_info = flavor._info.copy()
194-
flavor_info.pop("links")
195-
flavor_info['properties'] = utils.format_dict(flavor.get_keys())
220+
flavor_info['properties'] = flavor.get_keys()
196221

197-
return zip(*sorted(flavor_info.items()))
222+
display_columns, columns = _get_flavor_columns(flavor_info)
223+
data = utils.get_dict_properties(
224+
flavor_info, columns,
225+
formatters=_formatters,
226+
mixed_case_fields=['OS-FLV-DISABLED:disabled',
227+
'OS-FLV-EXT-DATA:ephemeral'])
228+
229+
return (display_columns, data)
198230

199231

200232
class DeleteFlavor(command.Command):
@@ -309,7 +341,7 @@ def take_action(self, parsed_args):
309341

310342
return (column_headers,
311343
(utils.get_item_properties(
312-
s, columns, formatters={'Properties': utils.format_dict},
344+
s, columns, formatters=_formatters,
313345
) for s in data))
314346

315347

@@ -428,11 +460,8 @@ def take_action(self, parsed_args):
428460
try:
429461
flavor_access = compute_client.flavor_access.list(
430462
flavor=resource_flavor.id)
431-
projects = [utils.get_field(access, 'tenant_id')
432-
for access in flavor_access]
433-
# TODO(Huanxuan Ao): This format case can be removed after
434-
# patch https://review.opendev.org/#/c/330223/ merged.
435-
access_projects = utils.format_list(projects)
463+
access_projects = [utils.get_field(access, 'tenant_id')
464+
for access in flavor_access]
436465
except Exception as e:
437466
msg = _("Failed to get access projects list "
438467
"for flavor '%(flavor)s': %(e)s")
@@ -442,11 +471,17 @@ def take_action(self, parsed_args):
442471
flavor.update({
443472
'access_project_ids': access_projects
444473
})
445-
flavor.pop("links", None)
446474

447-
flavor['properties'] = utils.format_dict(resource_flavor.get_keys())
475+
flavor['properties'] = resource_flavor.get_keys()
476+
477+
display_columns, columns = _get_flavor_columns(flavor)
478+
data = utils.get_dict_properties(
479+
flavor, columns,
480+
formatters=_formatters,
481+
mixed_case_fields=['OS-FLV-DISABLED:disabled',
482+
'OS-FLV-EXT-DATA:ephemeral'])
448483

449-
return zip(*sorted(flavor.items()))
484+
return (display_columns, data)
450485

451486

452487
class UnsetFlavor(command.Command):

openstackclient/tests/functional/compute/v2/test_flavor.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ def test_flavor_list(self):
115115
self.assertFalse(
116116
cmd_output["os-flavor-access:is_public"],
117117
)
118-
self.assertEqual(
119-
"a='b2', b='d2'",
118+
self.assertDictEqual(
119+
{"a": "b2", "b": "d2"},
120120
cmd_output["properties"],
121121
)
122122

@@ -133,12 +133,18 @@ def test_flavor_list(self):
133133
"flavor list -f json " +
134134
"--long"
135135
))
136-
col_name = [x["Name"] for x in cmd_output]
137-
col_properties = [x['Properties'] for x in cmd_output]
138-
self.assertIn(name1, col_name)
139-
self.assertIn("a='b', c='d'", col_properties)
140-
self.assertNotIn(name2, col_name)
141-
self.assertNotIn("b2', b='d2'", col_properties)
136+
# We have list of complex json objects
137+
# Iterate through the list setting flags
138+
found_expected = False
139+
for rec in cmd_output:
140+
if rec['Name'] == name1:
141+
found_expected = True
142+
self.assertEqual('b', rec['Properties']['a'])
143+
self.assertEqual('d', rec['Properties']['c'])
144+
elif rec['Name'] == name2:
145+
# We should have not seen private flavor
146+
self.assertFalse(True)
147+
self.assertTrue(found_expected)
142148

143149
# Test list --public
144150
cmd_output = json.loads(self.openstack(
@@ -201,8 +207,8 @@ def test_flavor_properties(self):
201207
self.assertFalse(
202208
cmd_output["os-flavor-access:is_public"],
203209
)
204-
self.assertEqual(
205-
"a='first', b='second'",
210+
self.assertDictEqual(
211+
{"a": "first", "b": "second"},
206212
cmd_output["properties"],
207213
)
208214

@@ -223,9 +229,14 @@ def test_flavor_properties(self):
223229
cmd_output["id"],
224230
)
225231
self.assertEqual(
226-
"a='third and 10', b='second', g='fourth'",
227-
cmd_output['properties'],
228-
)
232+
'third and 10',
233+
cmd_output['properties']['a'])
234+
self.assertEqual(
235+
'second',
236+
cmd_output['properties']['b'])
237+
self.assertEqual(
238+
'fourth',
239+
cmd_output['properties']['g'])
229240

230241
raw_output = self.openstack(
231242
"flavor unset " +
@@ -238,7 +249,5 @@ def test_flavor_properties(self):
238249
"flavor show -f json " +
239250
name1
240251
))
241-
self.assertEqual(
242-
"a='third and 10', g='fourth'",
243-
cmd_output["properties"],
244-
)
252+
253+
self.assertNotIn('b', cmd_output['properties'])

openstackclient/tests/unit/compute/v2/test_flavor.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
from unittest.mock import call
1818

1919
import novaclient
20+
from osc_lib.cli import format_columns
2021
from osc_lib import exceptions
21-
from osc_lib import utils
2222

2323
from openstackclient.compute.v2 import flavor
2424
from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
@@ -70,7 +70,7 @@ class TestFlavorCreate(TestFlavor):
7070
flavor.id,
7171
flavor.name,
7272
flavor.is_public,
73-
utils.format_dict(flavor.properties),
73+
format_columns.DictColumn(flavor.properties),
7474
flavor.ram,
7575
flavor.rxtx_factor,
7676
flavor.swap,
@@ -111,7 +111,7 @@ def test_flavor_create_default_options(self):
111111
self.flavors_mock.create.assert_called_once_with(*default_args)
112112

113113
self.assertEqual(self.columns, columns)
114-
self.assertEqual(self.data, data)
114+
self.assertItemEqual(self.data, data)
115115

116116
def test_flavor_create_all_options(self):
117117

@@ -165,7 +165,7 @@ def test_flavor_create_all_options(self):
165165
self.flavor.get_keys.assert_called_once_with()
166166

167167
self.assertEqual(self.columns, columns)
168-
self.assertEqual(self.data, data)
168+
self.assertItemEqual(self.data, data)
169169

170170
def test_flavor_create_other_options(self):
171171

@@ -226,7 +226,7 @@ def test_flavor_create_other_options(self):
226226
{'key1': 'value1', 'key2': 'value2'})
227227
self.flavor.get_keys.assert_called_with()
228228
self.assertEqual(self.columns, columns)
229-
self.assertEqual(self.data, data)
229+
self.assertItemEqual(self.data, data)
230230

231231
def test_public_flavor_create_with_project(self):
232232
arglist = [
@@ -300,7 +300,7 @@ def test_flavor_create_with_description_api_newer(self):
300300
self.flavors_mock.create.assert_called_once_with(*args)
301301

302302
self.assertEqual(self.columns, columns)
303-
self.assertEqual(self.data, data)
303+
self.assertItemEqual(self.data, data)
304304

305305
def test_flavor_create_with_description_api_older(self):
306306
arglist = [
@@ -429,7 +429,7 @@ class TestFlavorList(TestFlavor):
429429
data_long = (data[0] + (
430430
flavors[0].swap,
431431
flavors[0].rxtx_factor,
432-
u'property=\'value\''
432+
format_columns.DictColumn(flavors[0].properties)
433433
), )
434434

435435
def setUp(self):
@@ -583,7 +583,7 @@ def test_flavor_list_long(self):
583583
)
584584

585585
self.assertEqual(self.columns_long, columns)
586-
self.assertEqual(tuple(self.data_long), tuple(data))
586+
self.assertListItemEqual(self.data_long, tuple(data))
587587

588588

589589
class TestFlavorSet(TestFlavor):
@@ -817,7 +817,7 @@ class TestFlavorShow(TestFlavor):
817817
flavor.id,
818818
flavor.name,
819819
flavor.is_public,
820-
utils.format_dict(flavor.get_keys()),
820+
format_columns.DictColumn(flavor.get_keys()),
821821
flavor.ram,
822822
flavor.rxtx_factor,
823823
flavor.swap,
@@ -854,7 +854,7 @@ def test_public_flavor_show(self):
854854
columns, data = self.cmd.take_action(parsed_args)
855855

856856
self.assertEqual(self.columns, columns)
857-
self.assertEqual(self.data, data)
857+
self.assertItemEqual(self.data, data)
858858

859859
def test_private_flavor_show(self):
860860
private_flavor = compute_fakes.FakeFlavor.create_one_flavor(
@@ -874,13 +874,13 @@ def test_private_flavor_show(self):
874874
data_with_project = (
875875
private_flavor.disabled,
876876
private_flavor.ephemeral,
877-
self.flavor_access.tenant_id,
877+
[self.flavor_access.tenant_id],
878878
private_flavor.description,
879879
private_flavor.disk,
880880
private_flavor.id,
881881
private_flavor.name,
882882
private_flavor.is_public,
883-
utils.format_dict(private_flavor.get_keys()),
883+
format_columns.DictColumn(private_flavor.get_keys()),
884884
private_flavor.ram,
885885
private_flavor.rxtx_factor,
886886
private_flavor.swap,
@@ -894,7 +894,7 @@ def test_private_flavor_show(self):
894894
self.flavor_access_mock.list.assert_called_with(
895895
flavor=private_flavor.id)
896896
self.assertEqual(self.columns, columns)
897-
self.assertEqual(data_with_project, data)
897+
self.assertItemEqual(data_with_project, data)
898898

899899

900900
class TestFlavorUnset(TestFlavor):
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
fixes:
3+
Fix '-f json' output of the flavor properties to return valid json object
4+
instead of stringying it.

0 commit comments

Comments
 (0)