Skip to content

Commit b2ec3cd

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "manage: Add image_property commands"
2 parents fa10c6e + 19b7cf2 commit b2ec3cd

File tree

7 files changed

+732
-1
lines changed

7 files changed

+732
-1
lines changed

doc/source/admin/hw-machine-type.rst

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ hw_machine_type - Configuring and updating QEMU instance machine types
2525

2626
Added ``nova-manage`` commands to control the machine_type of an instance.
2727

28+
.. versionchanged:: 25.0.0 (Yoga)
29+
30+
Added ``nova-manage`` commands to set the image properties of an instance.
31+
2832
.. note::
2933

3034
The following only applies to environments using libvirt compute hosts.
@@ -135,3 +139,30 @@ Once it has been verified that all instances within the environment or specific
135139
cell have had a machine type recorded then the
136140
:oslo.config:option:`libvirt.hw_machine_type` can be updated without impacting
137141
existing instances.
142+
143+
Device bus and model image properties
144+
-------------------------------------
145+
146+
.. versionadded:: 25.0.0 (Yoga)
147+
148+
Device bus and model types defined as image properties associated with an
149+
instance are always used when launching instances with the libvirt driver.
150+
Support for each device bus and model is dependent on the machine type used and
151+
version of QEMU available on the underlying compute host. As such, any changes
152+
to the machine type of an instance or version of QEMU on a host might suddenly
153+
invalidate the stored device bus or model image properties.
154+
155+
It is now possible to change the stored image properties of an instance without
156+
having to rebuild the instance.
157+
158+
To show the stored image properties of an instance:
159+
160+
.. code-block:: shell
161+
162+
$ nova-manage image_property show $instance_uuid $property
163+
164+
To update the stored image properties of an instance:
165+
166+
.. code-block:: shell
167+
168+
$ nova-manage image_property set $instance_uuid --property $property

doc/source/cli/nova-manage.rst

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,6 +1668,91 @@ within an environment.
16681668
* - 3
16691669
- Instances found without ``hw_machine_type`` set
16701670

1671+
Image Property Commands
1672+
=======================
1673+
1674+
image_property show
1675+
-------------------
1676+
1677+
.. program:: nova-manage image_property show
1678+
1679+
.. code-block:: shell
1680+
1681+
nova-manage image_property show [INSTANCE_UUID] [IMAGE_PROPERTY]
1682+
1683+
Fetch and display the recorded image property ``IMAGE_PROPERTY`` of an
1684+
instance identified by ``INSTANCE_UUID``.
1685+
1686+
.. versionadded:: 25.0.0 (Yoga)
1687+
1688+
.. rubric:: Return codes
1689+
1690+
.. list-table::
1691+
:widths: 20 80
1692+
:header-rows: 1
1693+
1694+
* - Return code
1695+
- Description
1696+
* - 0
1697+
- Successfully completed
1698+
* - 1
1699+
- An unexpected error occurred
1700+
* - 2
1701+
- Unable to find instance or instance mapping
1702+
* - 3
1703+
- No image property found for instance
1704+
1705+
image_property set
1706+
------------------
1707+
1708+
.. program:: nova-manage image_property set
1709+
1710+
.. code-block:: shell
1711+
1712+
nova-manage image_property set \
1713+
[INSTANCE_UUID] [--property] [IMAGE_PROPERTY]=[VALUE]
1714+
1715+
Set or update the recorded image property ``IMAGE_PROPERTY`` of instance
1716+
``INSTANCE_UUID`` to value ``VALUE``.
1717+
1718+
The following criteria must be met when using this command:
1719+
1720+
* The instance must have a ``vm_state`` of ``STOPPED``, ``SHELVED`` or
1721+
``SHELVED_OFFLOADED``.
1722+
1723+
This command is useful for operators who need to update stored instance image
1724+
properties that have become invalidated by a change of instance machine type,
1725+
for example.
1726+
1727+
.. versionadded:: 25.0.0 (Yoga)
1728+
1729+
.. rubric:: Options
1730+
1731+
.. option:: --property
1732+
1733+
Image property to set using the format name=value. For example:
1734+
``--property hw_disk_bus=virtio --property hw_cdrom_bus=sata``.
1735+
1736+
.. rubric:: Return codes
1737+
1738+
.. list-table::
1739+
:widths: 20 80
1740+
:header-rows: 1
1741+
1742+
* - Return code
1743+
- Description
1744+
* - 0
1745+
- Update completed successfully
1746+
* - 1
1747+
- An unexpected error occurred
1748+
* - 2
1749+
- Unable to find instance or instance mapping
1750+
* - 3
1751+
- The instance has an invalid ``vm_state``
1752+
* - 4
1753+
- The provided image property name is invalid
1754+
* - 5
1755+
- The provided image property value is invalid
16711756

16721757
See Also
16731758
========

nova/cmd/manage.py

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3192,13 +3192,176 @@ def refresh(self, instance_uuid=None, volume_id=None, connector_path=None):
31923192
return 1
31933193

31943194

3195+
class ImagePropertyCommands():
3196+
3197+
@action_description(_("Show the value of an instance image property."))
3198+
@args(
3199+
'instance_uuid', metavar='<instance_uuid>',
3200+
help='UUID of the instance')
3201+
@args(
3202+
'property', metavar='<image_property>',
3203+
help='Image property to show')
3204+
def show(self, instance_uuid=None, image_property=None):
3205+
"""Show value of a given instance image property.
3206+
3207+
Return codes:
3208+
* 0: Command completed successfully.
3209+
* 1: An unexpected error happened.
3210+
* 2: Instance not found.
3211+
* 3: Image property not found.
3212+
"""
3213+
try:
3214+
ctxt = context.get_admin_context()
3215+
im = objects.InstanceMapping.get_by_instance_uuid(
3216+
ctxt, instance_uuid)
3217+
with context.target_cell(ctxt, im.cell_mapping) as cctxt:
3218+
instance = objects.Instance.get_by_uuid(
3219+
cctxt, instance_uuid, expected_attrs=['system_metadata'])
3220+
image_property = instance.system_metadata.get(
3221+
f'image_{image_property}')
3222+
if image_property:
3223+
print(image_property)
3224+
return 0
3225+
else:
3226+
print(f'Image property {image_property} not found '
3227+
f'for instance {instance_uuid}.')
3228+
return 3
3229+
except (
3230+
exception.InstanceNotFound,
3231+
exception.InstanceMappingNotFound,
3232+
) as e:
3233+
print(str(e))
3234+
return 2
3235+
except Exception as e:
3236+
print(f'Unexpected error, see nova-manage.log for the full '
3237+
f'trace: {str(e)}')
3238+
LOG.exception('Unexpected error')
3239+
return 1
3240+
3241+
def _validate_image_properties(self, image_properties):
3242+
"""Validate the provided image property names and values
3243+
3244+
:param image_properties: List of image property names and values
3245+
"""
3246+
# Sanity check the format of the provided properties, this should be
3247+
# in the format of name=value.
3248+
if any(x for x in image_properties if '=' not in x):
3249+
raise exception.InvalidInput(
3250+
"--property should use the format key=value")
3251+
3252+
# Transform the list of delimited properties to a dict
3253+
image_properties = dict(prop.split('=') for prop in image_properties)
3254+
3255+
# Validate the names of each property by checking against the o.vo
3256+
# fields currently listed by ImageProps. We can't use from_dict to
3257+
# do this as it silently ignores invalid property keys.
3258+
for image_property_name in image_properties.keys():
3259+
if image_property_name not in objects.ImageMetaProps.fields:
3260+
raise exception.InvalidImagePropertyName(
3261+
image_property_name=image_property_name)
3262+
3263+
# Validate the values by creating an object from the provided dict.
3264+
objects.ImageMetaProps.from_dict(image_properties)
3265+
3266+
# Return the dict so we can update the instance system_metadata
3267+
return image_properties
3268+
3269+
def _update_image_properties(self, instance, image_properties):
3270+
"""Update instance image properties
3271+
3272+
:param instance: The instance to update
3273+
:param image_properties: List of image properties and values to update
3274+
"""
3275+
# Check the state of the instance
3276+
allowed_states = [
3277+
obj_fields.InstanceState.STOPPED,
3278+
obj_fields.InstanceState.SHELVED,
3279+
obj_fields.InstanceState.SHELVED_OFFLOADED,
3280+
]
3281+
if instance.vm_state not in allowed_states:
3282+
raise exception.InstanceInvalidState(
3283+
instance_uuid=instance.uuid, attr='vm_state',
3284+
state=instance.vm_state,
3285+
method='image_property set (must be STOPPED, SHELVED, OR '
3286+
'SHELVED_OFFLOADED).')
3287+
3288+
# Validate the property names and values
3289+
image_properties = self._validate_image_properties(image_properties)
3290+
3291+
# Update the image properties and save the instance record
3292+
for image_property, value in image_properties.items():
3293+
instance.system_metadata[f'image_{image_property}'] = value
3294+
3295+
# Save and return 0
3296+
instance.save()
3297+
return 0
3298+
3299+
@action_description(_(
3300+
"Set the values of instance image properties stored in the database. "
3301+
"This is only allowed for " "instances with a STOPPED, SHELVED or "
3302+
"SHELVED_OFFLOADED vm_state."))
3303+
@args(
3304+
'instance_uuid', metavar='<instance_uuid>',
3305+
help='UUID of the instance')
3306+
@args(
3307+
'--property', metavar='<image_property>', action='append',
3308+
dest='image_properties',
3309+
help='Image property to set using the format name=value. For example: '
3310+
'--property hw_disk_bus=virtio --property hw_cdrom_bus=sata')
3311+
def set(self, instance_uuid=None, image_properties=None):
3312+
"""Set instance image property values
3313+
3314+
Return codes:
3315+
* 0: Command completed successfully.
3316+
* 1: An unexpected error happened.
3317+
* 2: Unable to find instance.
3318+
* 3: Instance is in an invalid state.
3319+
* 4: Invalid input format.
3320+
* 5: Invalid image property name.
3321+
* 6: Invalid image property value.
3322+
"""
3323+
try:
3324+
ctxt = context.get_admin_context()
3325+
im = objects.InstanceMapping.get_by_instance_uuid(
3326+
ctxt, instance_uuid)
3327+
with context.target_cell(ctxt, im.cell_mapping) as cctxt:
3328+
instance = objects.Instance.get_by_uuid(
3329+
cctxt, instance_uuid, expected_attrs=['system_metadata'])
3330+
return self._update_image_properties(
3331+
instance, image_properties)
3332+
except ValueError as e:
3333+
print(str(e))
3334+
return 6
3335+
except exception.InvalidImagePropertyName as e:
3336+
print(str(e))
3337+
return 5
3338+
except exception.InvalidInput as e:
3339+
print(str(e))
3340+
return 4
3341+
except exception.InstanceInvalidState as e:
3342+
print(str(e))
3343+
return 3
3344+
except (
3345+
exception.InstanceNotFound,
3346+
exception.InstanceMappingNotFound,
3347+
) as e:
3348+
print(str(e))
3349+
return 2
3350+
except Exception as e:
3351+
print('Unexpected error, see nova-manage.log for the full '
3352+
'trace: %s ' % str(e))
3353+
LOG.exception('Unexpected error')
3354+
return 1
3355+
3356+
31953357
CATEGORIES = {
31963358
'api_db': ApiDbCommands,
31973359
'cell_v2': CellV2Commands,
31983360
'db': DbCommands,
31993361
'placement': PlacementCommands,
32003362
'libvirt': LibvirtCommands,
32013363
'volume_attachment': VolumeAttachmentCommands,
3364+
'image_property': ImagePropertyCommands,
32023365
}
32033366

32043367

nova/exception.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,10 @@ class InvalidImageRef(Invalid):
736736
msg_fmt = _("Invalid image href %(image_href)s.")
737737

738738

739+
class InvalidImagePropertyName(Invalid):
740+
msg_fmt = _("Invalid image property name %(image_property_name)s.")
741+
742+
739743
class AutoDiskConfigDisabledByImage(Invalid):
740744
msg_fmt = _("Requested image %(image)s "
741745
"has automatic disk resize disabled.")

0 commit comments

Comments
 (0)