Fixes for device image alarm

This commit clears the in-progress alarm if there is no more
pending, failed or in-progress device images to be updated
after a device image is removed.

It also raises the alarm only when there are pending image updates.
If the system does not have any FPGA devices then the alarm is not
raised as there is no image update to be processed.

This commit also improved some comments about the applied field.

Story: 2007875
Task: 40392
Closes-Bug: 1883293

Change-Id: Ie8a8e6071ba9d5296992d46e410a7cbf19f8e1d1
Signed-off-by: Teresa Ho <teresa.ho@windriver.com>
This commit is contained in:
Teresa Ho 2020-07-30 15:31:33 -04:00
parent 179a4cb2b8
commit 5c24844b84
4 changed files with 51 additions and 23 deletions

View File

@ -162,11 +162,16 @@ def _get_applied_labels(device_image):
applied_labels.append({label.label_key: label.label_value})
device_image.applied_labels = applied_labels
# if applied without labels, insert a null dict to applied-labels
# In the database, 'applied' field is True if the image is applied without
# labels and False if the image is not applied.
# In the api response, 'applied' field is True if the image is applied with
# or without labels.
if device_image.applied:
# image is applied without labels, insert a null dict to applied-labels
applied_labels.append({})
device_image.applied_labels = applied_labels
elif device_image.applied_labels is not None:
# image is applied with labels, set the applied attribute to True
device_image.applied = True
return device_image
@ -327,13 +332,12 @@ class DeviceImageController(rest.RestController):
update_device_image_state(device_label.host_id,
device_label.pcidevice_id,
device_image.id, dconstants.DEVICE_IMAGE_UPDATE_PENDING)
update_host_device_image_update(device_label.host_uuid)
# Create an entry of image to label mapping
pecan.request.dbapi.device_image_label_create({
'image_id': device_image.id,
'label_id': device_label.id,
})
pecan.request.rpcapi.apply_device_image(
pecan.request.context, device_label.host_uuid)
elif action == dconstants.REMOVE_ACTION:
try:
img_lbl = pecan.request.dbapi.device_image_label_get_by_image_label(
@ -365,17 +369,30 @@ class DeviceImageController(rest.RestController):
update_device_image_state(host.id,
dev.pci_id, device_image.id,
dconstants.DEVICE_IMAGE_UPDATE_PENDING)
pecan.request.rpcapi.apply_device_image(
pecan.request.context, host.uuid)
update_host_device_image_update(host.uuid)
elif action == dconstants.REMOVE_ACTION:
delete_device_image_state(dev.pci_id, device_image)
# set applied flag to indicate if the image is applied without label or not
if action == dconstants.APPLY_ACTION:
# set applied flag to True to indicate the image is applied
# without label
pecan.request.dbapi.deviceimage_update(device_image.uuid,
{'applied': True})
else:
elif action == dconstants.REMOVE_ACTION:
# set applied flag to False to indicate the image is not applied
pecan.request.dbapi.deviceimage_update(device_image.uuid,
{'applied': False})
if action == dconstants.APPLY_ACTION:
# If any of the devices needs updating, call rpc to raise alarm
if pecan.request.dbapi.device_image_state_get_all(
image_id=device_image.id,
status=[dconstants.DEVICE_IMAGE_UPDATE_PENDING,
dconstants.DEVICE_IMAGE_UPDATE_FAILED,
dconstants.DEVICE_IMAGE_UPDATE_IN_PROGRESS]):
pecan.request.rpcapi.apply_device_image(pecan.request.context)
elif action == dconstants.REMOVE_ACTION:
pecan.request.rpcapi.remove_device_image(pecan.request.context)
device_image = objects.device_image.get_by_uuid(pecan.request.context, uuid)
return DeviceImage.convert_with_links(device_image)
@ -447,6 +464,13 @@ def _validate_syntax(device_image):
return msg
def update_host_device_image_update(host_uuid):
host = objects.host.get_by_uuid(pecan.request.context, host_uuid)
if host.device_image_update != dconstants.DEVICE_IMAGE_UPDATE_IN_PROGRESS:
host.device_image_update = dconstants.DEVICE_IMAGE_UPDATE_PENDING
host.save()
def update_device_image_state(host_id, pcidevice_id, image_id, status):
try:
dev_img_state = pecan.request.dbapi.device_image_state_get_by_image_device(

View File

@ -11816,14 +11816,8 @@ class ConductorManager(service.PeriodicService):
self.fm_api.clear_fault(fm_constants.FM_ALARM_ID_DEVICE_IMAGE_UPDATE_IN_PROGRESS,
entity_instance_id)
def apply_device_image(self, context, host_uuid):
def apply_device_image(self, context):
"""Apply device image"""
if host_uuid is not None:
host = objects.host.get_by_uuid(context, host_uuid)
if host.device_image_update != dconstants.DEVICE_IMAGE_UPDATE_IN_PROGRESS:
host.device_image_update = dconstants.DEVICE_IMAGE_UPDATE_PENDING
host.save()
# Raise device image update alarm if not already exists
alarm_id = fm_constants.FM_ALARM_ID_DEVICE_IMAGE_UPDATE_IN_PROGRESS
system_uuid = self.dbapi.isystem_get_one().uuid
@ -11843,6 +11837,9 @@ class ConductorManager(service.PeriodicService):
service_affecting=False)
self.fm_api.set_fault(fault)
def remove_device_image(self, context):
self._clear_device_image_alarm(context)
def host_device_image_update_next(self, context, host_uuid):
# Find the first device on this host that needs updating,
# and trigger an update of it.
@ -11957,11 +11954,13 @@ class ConductorManager(service.PeriodicService):
img.image_uuid))
def _clear_device_image_alarm(self, context):
# If there are no more pending device image update in the DB
# for any host, and if no host has the "reboot needed" DB entry set,
# then the "Device image update in progress" alarm is cleared.
# If there are no more pending, failed or in-progress device image
# update in the DB for any host, and if no host has the "reboot needed"
# DB entry set, then the "Device image update in progress" alarm is cleared.
dev_img_list = self.dbapi.device_image_state_get_all(
status=dconstants.DEVICE_IMAGE_UPDATE_PENDING)
status=[dconstants.DEVICE_IMAGE_UPDATE_PENDING,
dconstants.DEVICE_IMAGE_UPDATE_FAILED,
dconstants.DEVICE_IMAGE_UPDATE_IN_PROGRESS])
if not dev_img_list:
if self.dbapi.count_hosts_matching_criteria(reboot_needed=True) > 0:
return

View File

@ -1963,15 +1963,19 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
return self.cast(context, self.make_msg('delete_bitstream_file',
filename=filename))
def apply_device_image(self, context, host_uuid):
def apply_device_image(self, context):
"""Asynchronously, have the conductor apply the device image
on this host.
:param context: request context
:param host_uuid: uuid or id of the host
"""
return self.cast(context, self.make_msg('apply_device_image',
host_uuid=host_uuid))
return self.cast(context, self.make_msg('apply_device_image'))
def remove_device_image(self, context):
"""Asynchronously, have the conductor remove the device image
:param context: request context
"""
return self.cast(context, self.make_msg('remove_device_image'))
def host_device_image_update(self, context, host_uuid):
"""Asynchronously, have the conductor update the device image

View File

@ -28,6 +28,7 @@ class FakeConductorAPI(object):
self.store_bitstream_file = mock.MagicMock()
self.delete_bitstream_file = mock.MagicMock()
self.apply_device_image = mock.MagicMock()
self.remove_device_image = mock.MagicMock()
class TestDeviceImage(base.FunctionalTest, dbbase.BaseHostTestCase):