diff options
| author | Stephen Finucane <sfinucan@redhat.com> | 2019-09-27 12:19:29 +0100 |
|---|---|---|
| committer | Stephen Finucane <sfinucan@redhat.com> | 2020-02-19 13:28:49 +0000 |
| commit | 38e1274f478219bee8899b6c9eaa09dbfd03bbcd (patch) | |
| tree | 757e1e1b1ad926c0379c902dd873659c921375d7 /openstackclient | |
| parent | 29ec8c8134072b9b3eb6ff89320506bef9ec358a (diff) | |
| download | python-openstackclient-38e1274f478219bee8899b6c9eaa09dbfd03bbcd.tar.gz | |
Stop silently ignoring invalid 'server create --hint' options
The '--hint' option for 'server create' expects a key-value pair like so:
openstack server create --hint group=245e1dfe-2d0e-4139-80a9-fce124948896 ...
However, the command doesn't complain if this isn't the case, meaning
typos like the below aren't indicated to the user:
openstack server create --hint 245e1dfe-2d0e-4139-80a9-fce124948896
Due to how we'd implemented this here, this ultimately results in us
POSTing the following as part of the body to 'os-servers':
{
...
"OS-SCH-HNT:scheduler_hints": {
"245e1dfe-2d0e-4139-80a9-fce124948896": null
}
...
}
Which is unfortunately allowed and ignored by nova due to the use of
'additionalProperties' in the schema [1]
Do what we do for loads of other options and explicitly fail on invalid
values. This involves adding a new argparse action since none of those
defined in osc-lib work for us. This is included here to ease
backporting of the fix but will be moved to osc-lib in a future patch.
Conflicts:
openstackclient/tests/unit/compute/v2/test_server.py
NOTE(stephenfin): Conflicts are due to the absence of tests for changes
Ic06d97b29e51828b29d7ac5172645c288e4ada9e ("Compute: Add description
support for server") and If188c3d96fa506dbe62ef256418f2f9bca1520c2 ("Add
host and hypervisor_hostname to create servers"), neither of which we
want to backport.
[1] https://github.com/openstack/nova/blob/19.0.0/nova/api/openstack/compute/schemas/servers.py#L142-L146
Change-Id: I9e96d2978912c8dfeadae4a782c481a17cd7e348
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
Story: #2006628
Task: #36840
Related-Bug: #1845322
(cherry picked from commit ea27ebb0f918db9eab2f5751a1b065818faa0e6d)
(cherry picked from commit 576d9ecfd0ac27611ec89af6d34e7378b7a39fb3)
Diffstat (limited to 'openstackclient')
| -rw-r--r-- | openstackclient/compute/v2/server.py | 48 | ||||
| -rw-r--r-- | openstackclient/tests/unit/compute/v2/test_server.py | 25 |
2 files changed, 61 insertions, 12 deletions
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 86c5e7bc..da607bda 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -201,6 +201,36 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True): return info +# TODO(stephenfin): Migrate this to osc-lib +class KeyValueAppendAction(argparse.Action): + """A custom action to parse arguments as key=value pairs + + Ensures that ``dest`` is a dict and values are lists of strings. + """ + + def __call__(self, parser, namespace, values, option_string=None): + # Make sure we have an empty dict rather than None + if getattr(namespace, self.dest, None) is None: + setattr(namespace, self.dest, {}) + + # Add value if an assignment else remove it + if '=' in values: + key, value = values.split('=', 1) + # NOTE(qtang): Prevent null key setting in property + if '' == key: + msg = _("Property key must be specified: %s") + raise argparse.ArgumentTypeError(msg % str(values)) + + dest = getattr(namespace, self.dest) + if key in dest: + dest[key].append(value) + else: + dest[key] = [value] + else: + msg = _("Expected 'key=value' type, but got: %s") + raise argparse.ArgumentTypeError(msg % str(values)) + + class AddFixedIP(command.Command): _description = _("Add fixed IP address to server") @@ -612,8 +642,8 @@ class CreateServer(command.ShowOne): parser.add_argument( '--hint', metavar='<key=value>', - action='append', - default=[], + action=KeyValueAppendAction, + default={}, help=_('Hints for the scheduler (optional extension)'), ) parser.add_argument( @@ -872,16 +902,12 @@ class CreateServer(command.ShowOne): security_group_names.append(sg['name']) hints = {} - for hint in parsed_args.hint: - key, _sep, value = hint.partition('=') - # NOTE(vish): multiple copies of the same hint will - # result in a list of values - if key in hints: - if isinstance(hints[key], six.string_types): - hints[key] = [hints[key]] - hints[key] += [value] + for key, values in parsed_args.hint.items(): + # only items with multiple values will result in a list + if len(values) == 1: + hints[key] = values[0] else: - hints[key] = value + hints[key] = values # What does a non-boolean value for config-drive do? # --config-drive argument is either a volume id or diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py index dbea6fb4..39e8a836 100644 --- a/openstackclient/tests/unit/compute/v2/test_server.py +++ b/openstackclient/tests/unit/compute/v2/test_server.py @@ -675,7 +675,7 @@ class TestServerCreate(TestServer): ('key_name', 'keyname'), ('property', {'Beta': 'b'}), ('security_group', ['securitygroup']), - ('hint', ['a=b', 'a=c']), + ('hint', {'a': ['b', 'c']}), ('config_drive', False), ('server_name', self.new_server.name), ] @@ -1848,6 +1848,29 @@ class TestServerCreate(TestServer): self.cmd.take_action, parsed_args) + def test_server_create_invalid_hint(self): + # Not a key-value pair + arglist = [ + '--image', 'image1', + '--flavor', 'flavor1', + '--hint', 'a0cf03a5-d921-4877-bb5c-86d26cf818e1', + self.new_server.name, + ] + self.assertRaises(argparse.ArgumentTypeError, + self.check_parser, + self.cmd, arglist, []) + + # Empty key + arglist = [ + '--image', 'image1', + '--flavor', 'flavor1', + '--hint', '=a0cf03a5-d921-4877-bb5c-86d26cf818e1', + self.new_server.name, + ] + self.assertRaises(argparse.ArgumentTypeError, + self.check_parser, + self.cmd, arglist, []) + class TestServerDelete(TestServer): |
