From 74fa43665719ddc830999fa15bb052a87d69dd14 Mon Sep 17 00:00:00 2001 From: Cyril Roelandt Date: Tue, 20 Sep 2022 18:05:33 +0200 Subject: [PATCH] schema_args: Do not generate option for read-only properties The schema_args decorator generates command line options based on the properties defined in a schema. This commit makes sure read-only properties are skipped during this process, since trying to modify their value would result in a Glance error. Closes-Bug: #1561828 Change-Id: I7ccc628a23c9ebdaeedcb9e6d43559f497ce9555 --- glanceclient/common/utils.py | 2 ++ glanceclient/tests/unit/test_utils.py | 9 ++++++++- glanceclient/v2/shell.py | 23 +++++------------------ 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/glanceclient/common/utils.py b/glanceclient/common/utils.py index c3f08de8..e131bd97 100644 --- a/glanceclient/common/utils.py +++ b/glanceclient/common/utils.py @@ -123,6 +123,8 @@ def schema_args(schema_getter, omit=None): for name, property in properties.items(): if name in omit: continue + if property.get('readOnly', False): + continue param = '--' + name.replace('_', '-') kwargs = {} diff --git a/glanceclient/tests/unit/test_utils.py b/glanceclient/tests/unit/test_utils.py index 46cefbf6..db08a1c8 100644 --- a/glanceclient/tests/unit/test_utils.py +++ b/glanceclient/tests/unit/test_utils.py @@ -191,12 +191,17 @@ class TestUtils(testtools.TestCase): def schema_getter(_type='string', enum=False): prop = { 'type': ['null', _type], - 'readOnly': True, 'description': 'Test schema', } + prop_readonly = { + 'type': ['null', _type], + 'readOnly': True, + 'description': 'Test schema read-only', + } if enum: prop['enum'] = [None, 'opt-1', 'opt-2'] + prop_readonly['enum'] = [None, 'opt-ro-1', 'opt-ro-2'] def actual_getter(): return { @@ -205,6 +210,7 @@ class TestUtils(testtools.TestCase): 'name': 'test_schema', 'properties': { 'test': prop, + 'readonly-test': prop_readonly, } } @@ -214,6 +220,7 @@ class TestUtils(testtools.TestCase): pass decorated = utils.schema_args(schema_getter())(dummy_func) + self.assertEqual(len(decorated.__dict__['arguments']), 1) arg, opts = decorated.__dict__['arguments'][0] self.assertIn('--test', arg) self.assertEqual(encodeutils.safe_decode, opts['type']) diff --git a/glanceclient/v2/shell.py b/glanceclient/v2/shell.py index 773c1986..93a93776 100644 --- a/glanceclient/v2/shell.py +++ b/glanceclient/v2/shell.py @@ -49,11 +49,7 @@ def get_image_schema(): return IMAGE_SCHEMA -@utils.schema_args(get_image_schema, omit=['created_at', 'updated_at', 'file', - 'checksum', 'virtual_size', 'size', - 'status', 'schema', 'direct_url', - 'locations', 'self', 'os_hidden', - 'os_hash_value', 'os_hash_algo']) +@utils.schema_args(get_image_schema, omit=['locations', 'os_hidden']) # NOTE(rosmaita): to make this option more intuitive for end users, we # do not use the Glance image property name 'os_hidden' here. This means # we must include 'os_hidden' in the 'omit' list above and handle the @@ -118,11 +114,7 @@ def do_image_create(gc, args): utils.print_image(image) -@utils.schema_args(get_image_schema, omit=['created_at', 'updated_at', 'file', - 'checksum', 'virtual_size', 'size', - 'status', 'schema', 'direct_url', - 'locations', 'self', 'os_hidden', - 'os_hash_value', 'os_hash_algo']) +@utils.schema_args(get_image_schema, omit=['locations', 'os_hidden']) # NOTE: --hidden requires special handling; see note at do_image_create @utils.arg('--hidden', type=strutils.bool_from_string, metavar='[True|False]', default=None, @@ -354,12 +346,8 @@ def _validate_backend(backend, gc): @utils.arg('id', metavar='', help=_('ID of image to update.')) -@utils.schema_args(get_image_schema, omit=['id', 'locations', 'created_at', - 'updated_at', 'file', 'checksum', - 'virtual_size', 'size', 'status', - 'schema', 'direct_url', 'tags', - 'self', 'os_hidden', - 'os_hash_value', 'os_hash_algo']) +@utils.schema_args(get_image_schema, omit=['id', 'locations', 'tags', + 'os_hidden']) # NOTE: --hidden requires special handling; see note at do_image_create @utils.arg('--hidden', type=strutils.bool_from_string, metavar='[True|False]', default=None, @@ -1105,8 +1093,7 @@ def do_md_namespace_import(gc, args): @utils.schema_args(get_namespace_schema, omit=['property_count', 'properties', 'tag_count', 'tags', 'object_count', 'objects', - 'resource_type_associations', - 'schema']) + 'resource_type_associations']) def do_md_namespace_update(gc, args): """Update an existing metadata definitions namespace.""" schema = gc.schemas.get('metadefs/namespace')