Add ARQ_UNBIND_FAILED status for ARQ

When we unbind ARQ faild, we should set ARQ status to ARQ_UNBIND_FAILED.
Add try except for unbind ARQ operation.

Depends-On: https://review.opendev.org/c/openstack/cyborg/+/833529
Change-Id: I9a04b63a8ac7f20a0265f604eabc4107a40010b2
This commit is contained in:
songwenping 2021-02-24 17:12:36 +08:00 committed by Brin Zhang
parent 82d1ed968b
commit 82255a0e09
5 changed files with 137 additions and 6 deletions

View File

@ -24,13 +24,15 @@ DEVICE_NIC = 'NIC'
ARQ_STATES = (ARQ_INITIAL, ARQ_BIND_STARTED, ARQ_BOUND, ARQ_UNBOUND,
ARQ_BIND_FAILED, ARQ_DELETING) = (
'Initial', 'BindStarted', 'Bound', 'Unbound', 'BindFailed', 'Deleting')
ARQ_BIND_FAILED, ARQ_UNBIND_FAILED, ARQ_DELETING) = (
'Initial', 'BindStarted', 'Bound', 'Unbound', 'BindFailed', 'UnbindFailed',
'Deleting')
ARQ_BIND_STAGE = (ARQ_PRE_BIND, ARQ_FINISH_BIND,
ARQ_OUFOF_BIND_FLOW) = (
[ARQ_INITIAL, ARQ_BIND_STARTED], [ARQ_BOUND, ARQ_BIND_FAILED],
[ARQ_INITIAL, ARQ_BIND_STARTED],
[ARQ_BOUND, ARQ_BIND_FAILED],
[ARQ_UNBOUND, ARQ_DELETING])

View File

@ -198,7 +198,7 @@ class ExtARQ(base.CyborgObject, object_base.VersionedObjectDictCompat,
self.update_check_state(
context, constants.ARQ_BIND_FAILED)
raise
LOG.info('Attach handle(%s) for ARQ(%s) successfully.',
LOG.info('Attach handle(%s) allocate for ARQ(%s) successfully.',
ah.uuid, self.arq.uuid)
def bind(self, context, deployable):
@ -211,6 +211,19 @@ class ExtARQ(base.CyborgObject, object_base.VersionedObjectDictCompat,
# if (self.arq.state == constants.ARQ_DELETING
# or self.arq.state == ARQ_UNBOUND):
def _deallocate_attach_handle(self, context, ah_id):
try:
attach_handle = AttachHandle.get_by_id(context, ah_id)
attach_handle.deallocate(context)
except Exception as e:
LOG.error("Failed to deallocate attach handle %s for ARQ %s."
"Reason: %s", ah_id, self.arq.uuid, str(e))
self.update_check_state(
context, constants.ARQ_UNBIND_FAILED)
raise
LOG.info('Attach handle(%s) deallocate for ARQ(%s) successfully.',
ah_id, self.arq.uuid)
def unbind(self, context):
arq = self.arq
arq.hostname = None
@ -221,8 +234,7 @@ class ExtARQ(base.CyborgObject, object_base.VersionedObjectDictCompat,
# Unbind: mark attach handles as freed
ah_id = self.attach_handle_id
if ah_id:
attach_handle = AttachHandle.get_by_id(context, ah_id)
attach_handle.deallocate(context)
self._deallocate_attach_handle(context, ah_id)
self.attach_handle_id = None
self.save(context)

View File

@ -0,0 +1,77 @@
# Copyright 2021 Inspur.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_utils import uuidutils
from cyborg import objects
from cyborg.objects import attach_handle
from cyborg.objects import fields
def get_fake_attach_handle_as_dict():
attach_handle1 = {
'id': 1,
'uuid': uuidutils.generate_uuid(),
'in_use': 0,
'cp_id': 1,
'deployable_id': 1,
'attach_type': "PCI",
'attach_info': '{"domain": "0000", "bus": "0c",'
'"device": "0", "function": "1"}',
}
attach_handle2 = {
'id': 2,
'uuid': uuidutils.generate_uuid(),
'in_use': 1,
'cp_id': 2,
'deployable_id': 2,
'attach_type': "PCI",
'attach_info': '{"domain": "0000", "bus": "0c",'
'"device": "0", "function": "1"}',
}
return [attach_handle1, attach_handle2]
def _convert_from_dict_to_obj(ah_dict):
obj_ah = attach_handle.AttachHandle()
for field in ah_dict.keys():
obj_ah[field] = ah_dict[field]
return obj_ah
def _convert_to_db_ah(ah_dict):
for name, field in objects.AttachHandle.fields.items():
if name in ah_dict:
continue
if field.nullable:
ah_dict[name] = None
elif field.default != fields.UnspecifiedDefault:
ah_dict[name] = field.default
else:
raise Exception('fake_db_attach_handle needs help with %s' % name)
return ah_dict
def get_db_attach_handles():
ahs_list = get_fake_attach_handle_as_dict()
db_ahs = list(map(_convert_to_db_ah, ahs_list))
return db_ahs
def get_fake_attach_handle_objs():
ahs_list = get_fake_attach_handle_as_dict()
obj_ahs = list(map(_convert_from_dict_to_obj, ahs_list))
return obj_ahs

View File

@ -21,6 +21,7 @@ from cyborg.common import constants
from cyborg.common import exception
from cyborg import objects
from cyborg.tests.unit.db import base
from cyborg.tests.unit import fake_attach_handle
from cyborg.tests.unit import fake_deployable
from cyborg.tests.unit import fake_device_profile
from cyborg.tests.unit import fake_extarq
@ -33,6 +34,7 @@ class TestExtARQObject(base.DbTestCase):
self.fake_db_extarqs = fake_extarq.get_fake_db_extarqs()
self.fake_obj_extarqs = fake_extarq.get_fake_extarq_objs()
self.fake_obj_fpga_extarqs = fake_extarq.get_fake_fpga_extarq_objs()
self.fake_obj_ahs = fake_attach_handle.get_fake_attach_handle_objs()
self.deployable_uuids = ['0acbf8d6-e02a-4394-aae3-57557d209498']
@mock.patch('cyborg.objects.ExtARQ._from_db_object')
@ -334,6 +336,39 @@ class TestExtARQObject(base.DbTestCase):
obj_extarq._allocate_attach_handle, self.context, fake_dep)
mock_log.assert_called_once_with(
msg, obj_extarq.arq.uuid, fake_dep.uuid, str(e))
mock_check_state.assert_called_once_with(
self.context, constants.ARQ_BIND_FAILED)
@mock.patch('cyborg.objects.ExtARQ.update_check_state')
@mock.patch('cyborg.objects.attach_handle.AttachHandle.get_by_id')
@mock.patch('cyborg.objects.attach_handle.AttachHandle.deallocate')
def test_deallocate_attach_handle(
self, mock_deallocate, mock_ah, mock_check_state):
obj_extarq = self.fake_obj_extarqs[0]
mock_ah.return_value = self.fake_obj_ahs[0]
obj_extarq._deallocate_attach_handle(self.context, mock_ah.id)
mock_check_state.assert_not_called()
@mock.patch('logging.LoggerAdapter.error')
@mock.patch('cyborg.objects.ExtARQ.update_check_state')
@mock.patch('cyborg.objects.attach_handle.AttachHandle.get_by_id')
@mock.patch('cyborg.objects.attach_handle.AttachHandle.deallocate')
def test_deallocate_attach_handle_with_error_log(
self, mock_ah, mock_deallocate, mock_check_state, mock_log):
obj_extarq = self.fake_obj_extarqs[0]
mock_ah.return_value = self.fake_obj_ahs[0]
e = exception.ResourceNotFound(
resource='AttachHandle', msg="Just for Test")
msg = ("Failed to deallocate attach handle %s for ARQ %s."
"Reason: %s")
mock_deallocate.side_effect = e
self.assertRaises(
exception.ResourceNotFound,
obj_extarq._deallocate_attach_handle, self.context, mock_ah.id)
mock_log.assert_called_once_with(
msg, mock_ah.id, obj_extarq.arq.uuid, str(e))
mock_check_state.assert_called_once_with(
self.context, constants.ARQ_UNBIND_FAILED)
@mock.patch('cyborg.objects.ExtARQ.get')
@mock.patch('cyborg.objects.ExtARQ._from_db_object')

View File

@ -0,0 +1,5 @@
---
features:
- |
Add ``ARQ_UNBIND_FAILED`` status for Accelerator Requests (arq) unbind process. Nowdays the status is
needed to accurate record the arq status.