Merge "Add --image-property parameter in 'server create'"
This commit is contained in:
commit
5ed81c5a77
@ -435,6 +435,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>',
|
||||
@ -609,6 +615,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:
|
||||
|
@ -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):
|
||||
|
||||
|
@ -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.
|
Loading…
x
Reference in New Issue
Block a user