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
This commit is contained in:
Cyril Roelandt 2022-09-20 18:05:33 +02:00
parent 9e8fcdb92e
commit 74fa436657
3 changed files with 15 additions and 19 deletions

View File

@ -123,6 +123,8 @@ def schema_args(schema_getter, omit=None):
for name, property in properties.items(): for name, property in properties.items():
if name in omit: if name in omit:
continue continue
if property.get('readOnly', False):
continue
param = '--' + name.replace('_', '-') param = '--' + name.replace('_', '-')
kwargs = {} kwargs = {}

View File

@ -191,12 +191,17 @@ class TestUtils(testtools.TestCase):
def schema_getter(_type='string', enum=False): def schema_getter(_type='string', enum=False):
prop = { prop = {
'type': ['null', _type], 'type': ['null', _type],
'readOnly': True,
'description': 'Test schema', 'description': 'Test schema',
} }
prop_readonly = {
'type': ['null', _type],
'readOnly': True,
'description': 'Test schema read-only',
}
if enum: if enum:
prop['enum'] = [None, 'opt-1', 'opt-2'] prop['enum'] = [None, 'opt-1', 'opt-2']
prop_readonly['enum'] = [None, 'opt-ro-1', 'opt-ro-2']
def actual_getter(): def actual_getter():
return { return {
@ -205,6 +210,7 @@ class TestUtils(testtools.TestCase):
'name': 'test_schema', 'name': 'test_schema',
'properties': { 'properties': {
'test': prop, 'test': prop,
'readonly-test': prop_readonly,
} }
} }
@ -214,6 +220,7 @@ class TestUtils(testtools.TestCase):
pass pass
decorated = utils.schema_args(schema_getter())(dummy_func) decorated = utils.schema_args(schema_getter())(dummy_func)
self.assertEqual(len(decorated.__dict__['arguments']), 1)
arg, opts = decorated.__dict__['arguments'][0] arg, opts = decorated.__dict__['arguments'][0]
self.assertIn('--test', arg) self.assertIn('--test', arg)
self.assertEqual(encodeutils.safe_decode, opts['type']) self.assertEqual(encodeutils.safe_decode, opts['type'])

View File

@ -49,11 +49,7 @@ def get_image_schema():
return IMAGE_SCHEMA return IMAGE_SCHEMA
@utils.schema_args(get_image_schema, omit=['created_at', 'updated_at', 'file', @utils.schema_args(get_image_schema, omit=['locations', 'os_hidden'])
'checksum', 'virtual_size', 'size',
'status', 'schema', 'direct_url',
'locations', 'self', 'os_hidden',
'os_hash_value', 'os_hash_algo'])
# NOTE(rosmaita): to make this option more intuitive for end users, we # 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 # 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 # 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.print_image(image)
@utils.schema_args(get_image_schema, omit=['created_at', 'updated_at', 'file', @utils.schema_args(get_image_schema, omit=['locations', 'os_hidden'])
'checksum', 'virtual_size', 'size',
'status', 'schema', 'direct_url',
'locations', 'self', 'os_hidden',
'os_hash_value', 'os_hash_algo'])
# NOTE: --hidden requires special handling; see note at do_image_create # NOTE: --hidden requires special handling; see note at do_image_create
@utils.arg('--hidden', type=strutils.bool_from_string, metavar='[True|False]', @utils.arg('--hidden', type=strutils.bool_from_string, metavar='[True|False]',
default=None, default=None,
@ -354,12 +346,8 @@ def _validate_backend(backend, gc):
@utils.arg('id', metavar='<IMAGE_ID>', help=_('ID of image to update.')) @utils.arg('id', metavar='<IMAGE_ID>', help=_('ID of image to update.'))
@utils.schema_args(get_image_schema, omit=['id', 'locations', 'created_at', @utils.schema_args(get_image_schema, omit=['id', 'locations', 'tags',
'updated_at', 'file', 'checksum', 'os_hidden'])
'virtual_size', 'size', 'status',
'schema', 'direct_url', 'tags',
'self', 'os_hidden',
'os_hash_value', 'os_hash_algo'])
# NOTE: --hidden requires special handling; see note at do_image_create # NOTE: --hidden requires special handling; see note at do_image_create
@utils.arg('--hidden', type=strutils.bool_from_string, metavar='[True|False]', @utils.arg('--hidden', type=strutils.bool_from_string, metavar='[True|False]',
default=None, default=None,
@ -1105,8 +1093,7 @@ def do_md_namespace_import(gc, args):
@utils.schema_args(get_namespace_schema, omit=['property_count', 'properties', @utils.schema_args(get_namespace_schema, omit=['property_count', 'properties',
'tag_count', 'tags', 'tag_count', 'tags',
'object_count', 'objects', 'object_count', 'objects',
'resource_type_associations', 'resource_type_associations'])
'schema'])
def do_md_namespace_update(gc, args): def do_md_namespace_update(gc, args):
"""Update an existing metadata definitions namespace.""" """Update an existing metadata definitions namespace."""
schema = gc.schemas.get('metadefs/namespace') schema = gc.schemas.get('metadefs/namespace')