Merge "Fix 'nova-manage image_property set' command"

This commit is contained in:
Zuul
2025-09-03 17:29:24 +00:00
committed by Gerrit Code Review
2 changed files with 56 additions and 0 deletions

View File

@@ -3336,6 +3336,8 @@ class ImagePropertyCommands:
# fields currently listed by ImageProps. We can't use from_dict to
# do this as it silently ignores invalid property keys.
for image_property_name in image_properties.keys():
if image_property_name.startswith("trait:"):
continue
if image_property_name not in objects.ImageMetaProps.fields:
raise exception.InvalidImagePropertyName(
image_property_name=image_property_name)

View File

@@ -4340,6 +4340,60 @@ class ImagePropertyCommandsTestCase(test.NoDBTestCase):
image_properties=['hw_cdrom_bus'])
self.assertEqual(4, ret, 'return code')
@mock.patch('nova.objects.RequestSpec.save')
@mock.patch('nova.objects.RequestSpec.get_by_instance_uuid')
@mock.patch('nova.objects.Instance.get_by_uuid')
@mock.patch('nova.context.target_cell')
@mock.patch('nova.objects.Instance.save')
@mock.patch('nova.objects.InstanceMapping.get_by_instance_uuid',
new=mock.Mock(cell_mapping=mock.sentinel.cm))
@mock.patch('nova.context.get_admin_context',
new=mock.Mock(return_value=mock.sentinel.ctxt))
def test_set_image_properties_with_trait_in_property_name(
self, mock_instance_save, mock_target_cell, mock_get_instance,
mock_get_request_spec, mock_request_spec_save
):
mock_target_cell.return_value.__enter__.return_value = \
mock.sentinel.cctxt
mock_get_instance.return_value = objects.Instance(
uuid=uuidsentinel.instance,
vm_state=obj_fields.InstanceState.STOPPED,
system_metadata={
'image_hw_disk_bus': 'virtio',
},
image_ref=''
)
mock_get_request_spec.return_value = objects.RequestSpec()
ret = self.commands.set(
instance_uuid=uuidsentinel.instance,
image_properties=["trait:CUSTOM_WINDOWS_HOST=required"])
self.assertEqual(0, ret, 'return code')
img_props = mock_get_instance.return_value.image_meta.properties
self.assertIn('CUSTOM_WINDOWS_HOST', img_props.traits_required)
@mock.patch('nova.objects.Instance.get_by_uuid')
@mock.patch('nova.context.target_cell')
@mock.patch('nova.objects.InstanceMapping.get_by_instance_uuid',
new=mock.Mock(cell_mapping=mock.sentinel.cm))
@mock.patch('nova.context.get_admin_context',
new=mock.Mock(return_value=mock.sentinel.ctxt))
def test_set_image_properties_without_trait_in_property_name(
self, mock_target_cell, mock_get_instance
):
mock_target_cell.return_value.__enter__.return_value = \
mock.sentinel.cctxt
mock_get_instance.return_value = objects.Instance(
uuid=uuidsentinel.instance,
vm_state=obj_fields.InstanceState.SHELVED_OFFLOADED,
system_metadata={
'image_hw_disk_bus': 'virtio',
}
)
ret = self.commands.set(
instance_uuid=uuidsentinel.instance,
image_properties=['CUSTOM_WINDOWS_HOST=required'])
self.assertEqual(5, ret, 'return code')
@mock.patch('nova.objects.Instance.get_by_uuid')
@mock.patch('nova.context.target_cell')
@mock.patch('nova.objects.InstanceMapping.get_by_instance_uuid',