Add --image-property parameter in 'server create'

add --image-property option, just like --image-with of novaclient did.

Change-Id: Ic1a8976559255529a8785b1b301a0307812433cb
Signed-off-by: Chen Hanxiao <chenhx@certusnet.com.cn>
This commit is contained in:
Chen Hanxiao 2018-01-19 14:30:18 +08:00
parent 3f99dbac34
commit 447d5d9e34
3 changed files with 208 additions and 0 deletions

View File

@ -442,6 +442,12 @@ class CreateServer(command.ShowOne):
metavar='<image>',
help=_('Create server boot disk from this image (name or ID)'),
)
disk_group.add_argument(
'--image-property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
help=_("Image property to be matched"),
)
disk_group.add_argument(
'--volume',
metavar='<volume>',
@ -610,6 +616,45 @@ class CreateServer(command.ShowOne):
parsed_args.image,
)
if not image and parsed_args.image_property:
def emit_duplicated_warning(img, image_property):
img_uuid_list = [str(image.id) for image in img]
LOG.warning(_('Multiple matching images: %(img_uuid_list)s\n'
'Using image: %(chosen_one)s') %
{'img_uuid_list': img_uuid_list,
'chosen_one': img_uuid_list[0]})
def _match_image(image_api, wanted_properties):
image_list = image_api.image_list()
images_matched = []
for img in image_list:
img_dict = {}
# exclude any unhashable entries
for key, value in img.items():
try:
set([key, value])
except TypeError:
pass
else:
img_dict[key] = value
if all(k in img_dict and img_dict[k] == v
for k, v in wanted_properties.items()):
images_matched.append(img)
else:
return []
return images_matched
images = _match_image(image_client.api, parsed_args.image_property)
if len(images) > 1:
emit_duplicated_warning(images,
parsed_args.image_property)
if images:
image = images[0]
else:
raise exceptions.CommandError(_("No images match the "
"property expected by "
"--image-property"))
# Lookup parsed_args.volume
volume = None
if parsed_args.volume:

View File

@ -1528,6 +1528,164 @@ class TestServerCreate(TestServer):
self.cmd.take_action,
parsed_args)
def test_server_create_image_property(self):
arglist = [
'--image-property', 'hypervisor_type=qemu',
'--flavor', 'flavor1',
'--nic', 'none',
self.new_server.name,
]
verifylist = [
('image_property', {'hypervisor_type': 'qemu'}),
('flavor', 'flavor1'),
('nic', ['none']),
('config_drive', False),
('server_name', self.new_server.name),
]
_image = image_fakes.FakeImage.create_one_image()
# create a image_info as the side_effect of the fake image_list()
image_info = {
'id': _image.id,
'name': _image.name,
'owner': _image.owner,
'hypervisor_type': 'qemu',
}
self.api_mock = mock.Mock()
self.api_mock.image_list.side_effect = [
[image_info], [],
]
self.app.client_manager.image.api = self.api_mock
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = dict(
files={},
reservation_id=None,
min_count=1,
max_count=1,
security_groups=[],
userdata=None,
key_name=None,
availability_zone=None,
block_device_mapping_v2=[],
nics='none',
meta=None,
scheduler_hints={},
config_drive=None,
)
# ServerManager.create(name, image, flavor, **kwargs)
self.servers_mock.create.assert_called_with(
self.new_server.name,
image_info,
self.flavor,
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist(), data)
def test_server_create_image_property_multi(self):
arglist = [
'--image-property', 'hypervisor_type=qemu',
'--image-property', 'hw_disk_bus=ide',
'--flavor', 'flavor1',
'--nic', 'none',
self.new_server.name,
]
verifylist = [
('image_property', {'hypervisor_type': 'qemu',
'hw_disk_bus': 'ide'}),
('flavor', 'flavor1'),
('nic', ['none']),
('config_drive', False),
('server_name', self.new_server.name),
]
_image = image_fakes.FakeImage.create_one_image()
# create a image_info as the side_effect of the fake image_list()
image_info = {
'id': _image.id,
'name': _image.name,
'owner': _image.owner,
'hypervisor_type': 'qemu',
'hw_disk_bus': 'ide',
}
self.api_mock = mock.Mock()
self.api_mock.image_list.side_effect = [
[image_info], [],
]
self.app.client_manager.image.api = self.api_mock
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = dict(
files={},
reservation_id=None,
min_count=1,
max_count=1,
security_groups=[],
userdata=None,
key_name=None,
availability_zone=None,
block_device_mapping_v2=[],
nics='none',
meta=None,
scheduler_hints={},
config_drive=None,
)
# ServerManager.create(name, image, flavor, **kwargs)
self.servers_mock.create.assert_called_with(
self.new_server.name,
image_info,
self.flavor,
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist(), data)
def test_server_create_image_property_missed(self):
arglist = [
'--image-property', 'hypervisor_type=qemu',
'--image-property', 'hw_disk_bus=virtio',
'--flavor', 'flavor1',
'--nic', 'none',
self.new_server.name,
]
verifylist = [
('image_property', {'hypervisor_type': 'qemu',
'hw_disk_bus': 'virtio'}),
('flavor', 'flavor1'),
('nic', ['none']),
('config_drive', False),
('server_name', self.new_server.name),
]
_image = image_fakes.FakeImage.create_one_image()
# create a image_info as the side_effect of the fake image_list()
image_info = {
'id': _image.id,
'name': _image.name,
'owner': _image.owner,
'hypervisor_type': 'qemu',
'hw_disk_bus': 'ide',
}
self.api_mock = mock.Mock()
self.api_mock.image_list.side_effect = [
[image_info], [],
]
self.app.client_manager.image.api = self.api_mock
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(exceptions.CommandError,
self.cmd.take_action,
parsed_args)
class TestServerDelete(TestServer):

View File

@ -0,0 +1,5 @@
---
features:
- |
Add a parameter ``--image-property`` to ``server create`` command.
This parameter will filter a image which properties that are matching.