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_STATES = (ARQ_INITIAL, ARQ_BIND_STARTED, ARQ_BOUND, ARQ_UNBOUND,
ARQ_BIND_FAILED, ARQ_DELETING) = ( ARQ_BIND_FAILED, ARQ_UNBIND_FAILED, ARQ_DELETING) = (
'Initial', 'BindStarted', 'Bound', 'Unbound', 'BindFailed', 'Deleting') 'Initial', 'BindStarted', 'Bound', 'Unbound', 'BindFailed', 'UnbindFailed',
'Deleting')
ARQ_BIND_STAGE = (ARQ_PRE_BIND, ARQ_FINISH_BIND, ARQ_BIND_STAGE = (ARQ_PRE_BIND, ARQ_FINISH_BIND,
ARQ_OUFOF_BIND_FLOW) = ( 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]) [ARQ_UNBOUND, ARQ_DELETING])

View File

@ -198,7 +198,7 @@ class ExtARQ(base.CyborgObject, object_base.VersionedObjectDictCompat,
self.update_check_state( self.update_check_state(
context, constants.ARQ_BIND_FAILED) context, constants.ARQ_BIND_FAILED)
raise 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) ah.uuid, self.arq.uuid)
def bind(self, context, deployable): def bind(self, context, deployable):
@ -211,6 +211,19 @@ class ExtARQ(base.CyborgObject, object_base.VersionedObjectDictCompat,
# if (self.arq.state == constants.ARQ_DELETING # if (self.arq.state == constants.ARQ_DELETING
# or self.arq.state == ARQ_UNBOUND): # 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): def unbind(self, context):
arq = self.arq arq = self.arq
arq.hostname = None arq.hostname = None
@ -221,8 +234,7 @@ class ExtARQ(base.CyborgObject, object_base.VersionedObjectDictCompat,
# Unbind: mark attach handles as freed # Unbind: mark attach handles as freed
ah_id = self.attach_handle_id ah_id = self.attach_handle_id
if ah_id: if ah_id:
attach_handle = AttachHandle.get_by_id(context, ah_id) self._deallocate_attach_handle(context, ah_id)
attach_handle.deallocate(context)
self.attach_handle_id = None self.attach_handle_id = None
self.save(context) 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.common import exception
from cyborg import objects from cyborg import objects
from cyborg.tests.unit.db import base 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_deployable
from cyborg.tests.unit import fake_device_profile from cyborg.tests.unit import fake_device_profile
from cyborg.tests.unit import fake_extarq 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_db_extarqs = fake_extarq.get_fake_db_extarqs()
self.fake_obj_extarqs = fake_extarq.get_fake_extarq_objs() 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_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'] self.deployable_uuids = ['0acbf8d6-e02a-4394-aae3-57557d209498']
@mock.patch('cyborg.objects.ExtARQ._from_db_object') @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) obj_extarq._allocate_attach_handle, self.context, fake_dep)
mock_log.assert_called_once_with( mock_log.assert_called_once_with(
msg, obj_extarq.arq.uuid, fake_dep.uuid, str(e)) 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.get')
@mock.patch('cyborg.objects.ExtARQ._from_db_object') @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.