Add support to capture error_reason for the VNF

Partial-Bug: #1524214
Change-Id: I4897e7e4ebdb8c887fb9882e693e5b3d3f4664e5
This commit is contained in:
Bharath Thiruveedula 2015-12-09 18:20:39 +05:30
parent 10c05eb874
commit edd3b04e5b
6 changed files with 107 additions and 26 deletions

View File

@ -1 +1 @@
5246a6bd410f
acf941e54075

View File

@ -0,0 +1,38 @@
# Copyright 2016 OpenStack Foundation
#
# 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.
#
"""Add error_reason to device
Revision ID: acf941e54075
Revises: 5246a6bd410f
Create Date: 2016-04-07 23:53:56.623647
"""
# revision identifiers, used by Alembic.
revision = 'acf941e54075'
down_revision = '5246a6bd410f'
from alembic import op
import sqlalchemy as sa
def upgrade(active_plugins=None, options=None):
op.add_column('devices', sa.Column('error_reason',
sa.Text(), nullable=True))
def downgrade(active_plugins=None, options=None):
op.drop_column('devices', 'error_reason')

View File

@ -119,6 +119,7 @@ class Device(model_base.BASE, models_v1.HasTenant):
vim_id = sa.Column(sa.String(36), sa.ForeignKey('vims.id'), nullable=False)
placement_attr = sa.Column(sa.PickleType, nullable=True)
vim = orm.relationship('Vim')
error_reason = sa.Column(sa.Text, nullable=True)
class DeviceAttribute(model_base.BASE, models_v1.HasId):
@ -195,7 +196,7 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
}
key_list = ('id', 'tenant_id', 'name', 'description', 'instance_id',
'vim_id', 'placement_attr', 'template_id', 'status',
'mgmt_url')
'mgmt_url', 'error_reason')
res.update((key, device_db[key]) for key in key_list)
return self._fields(res, fields)
@ -354,7 +355,8 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
template_id=template_id,
vim_id=vim_id,
placement_attr=placement_attr,
status=constants.PENDING_CREATE)
status=constants.PENDING_CREATE,
error_reason=None)
context.session.add(device_db)
for key, value in attributes.items():
arg = DeviceAttribute(
@ -493,6 +495,12 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
return [device for device in devices
if uuidutils.is_uuid_like(device['id'])]
def set_device_error_status_reason(self, context, device_id, new_reason):
with context.session.begin(subtransactions=True):
(self._model_query(context, Device).
filter(Device.id == device_id).
update({'error_reason': new_reason}))
def _mark_device_status(self, device_id, exclude_status, new_status):
context = t_context.get_admin_context()
with context.session.begin(subtransactions=True):
@ -540,7 +548,8 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
mgmt_url=device_db.mgmt_url,
status=device_db.status,
vim_id=device_db.vim_id,
placement_attr=device_db.placement_attr)
placement_attr=device_db.placement_attr,
error_reason=device_db.error_reason)
context.session.add(new_device_db)
(self._model_query(context, DeviceAttribute).

View File

@ -66,7 +66,7 @@ class DeviceCreateFailed(exceptions.TackerException):
class DeviceCreateWaitFailed(exceptions.TackerException):
message = _('waiting for creation of VNF %(device_id)s failed')
message = _('%(reason)s')
class DeviceDeleteFailed(exceptions.TackerException):
@ -298,6 +298,11 @@ RESOURCE_ATTRIBUTE_MAP = {
'allow_put': False,
'is_visible': True,
},
'error_reason': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
},
}

View File

@ -417,6 +417,7 @@ class DeviceHeat(abstract_driver.DeviceAbstractDriver):
stack = heatclient_.get(device_id)
status = stack.stack_status
stack_retries = STACK_RETRIES
error_reason = None
while status == 'CREATE_IN_PROGRESS' and stack_retries > 0:
time.sleep(STACK_RETRY_WAIT)
try:
@ -433,14 +434,22 @@ class DeviceHeat(abstract_driver.DeviceAbstractDriver):
LOG.debug(_('stack status: %(stack)s %(status)s'),
{'stack': str(stack), 'status': status})
if stack_retries == 0:
LOG.warning(_("Resource creation is"
" not completed within %(wait)s seconds as "
"creation of Stack %(stack)s is not completed"),
{'wait': (STACK_RETRIES * STACK_RETRY_WAIT),
'stack': device_id})
if status != 'CREATE_COMPLETE':
raise vnfm.DeviceCreateWaitFailed(device_id=device_id)
if stack_retries == 0 and status != 'CREATE_COMPLETE':
error_reason = _("Resource creation is not completed within"
" {wait} seconds as creation of stack {stack}"
" is not completed").format(
wait=(STACK_RETRIES * STACK_RETRY_WAIT),
stack=device_id)
LOG.warning(_("VNF Creation failed: %(reason)s"),
{'reason': error_reason})
raise vnfm.DeviceCreateWaitFailed(device_id=device_id,
reason=error_reason)
elif stack_retries != 0 and status != 'CREATE_COMPLETE':
error_reason = stack.stack_status_reason
raise vnfm.DeviceCreateWaitFailed(device_id=device_id,
reason=error_reason)
outputs = stack.outputs
LOG.debug(_('outputs %s'), outputs)
PREFIX = 'mgmt_ip-'
@ -510,6 +519,7 @@ class DeviceHeat(abstract_driver.DeviceAbstractDriver):
stack = heatclient_.get(device_id)
status = stack.stack_status
error_reason = None
stack_retries = STACK_RETRIES
while (status == 'DELETE_IN_PROGRESS' and stack_retries > 0):
time.sleep(STACK_RETRY_WAIT)
@ -526,16 +536,23 @@ class DeviceHeat(abstract_driver.DeviceAbstractDriver):
status = stack.stack_status
stack_retries = stack_retries - 1
if stack_retries == 0:
LOG.warning(_("Resource cleanup for device is"
" not completed within %(wait)s seconds as "
"deletion of Stack %(stack)s is not completed"),
{'wait': (STACK_RETRIES * STACK_RETRY_WAIT),
'stack': device_id})
if status != 'DELETE_COMPLETE':
LOG.warning(_("device (%(device_id)d) deletion is not completed. "
"%(stack_status)s"),
{'device_id': device_id, 'stack_status': status})
if stack_retries == 0 and status != 'DELETE_COMPLETE':
error_reason = _("Resource cleanup for device is"
" not completed within {wait} seconds as "
"deletion of Stack {stack} is "
"not completed").format(stack=device_id,
wait=(STACK_RETRIES * STACK_RETRY_WAIT))
LOG.warning(error_reason)
raise vnfm.DeviceCreateWaitFailed(device_id=device_id,
reason=error_reason)
if stack_retries != 0 and status != 'DELETE_COMPLETE':
error_reason = _("device {device_id} deletion is not completed. "
"{stack_status}").format(device_id=device_id,
stack_status=status)
LOG.warning(error_reason)
raise vnfm.DeviceCreateWaitFailed(device_id=device_id,
reason=error_reason)
class HeatClient(object):

View File

@ -16,6 +16,7 @@
import copy
import inspect
import six
import eventlet
from oslo_config import cfg
@ -200,10 +201,12 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
driver_name, 'create_wait', plugin=self, context=context,
device_dict=device_dict, device_id=instance_id,
auth_attr=auth_attr)
except vnfm.DeviceCreateWaitFailed:
except vnfm.DeviceCreateWaitFailed as e:
LOG.error(_LE("VNF Create failed for vnf_id %s"), device_id)
create_failed = True
device_dict['status'] = constants.ERROR
self.set_device_error_status_reason(context, device_id,
six.text_type(e))
if instance_id is None or create_failed:
mgmt_url = None
@ -231,6 +234,8 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
except Exception:
LOG.exception(_('create_device_wait'))
new_status = constants.ERROR
self.set_device_error_status_reason(context, device_id,
'Unable to configure VDU')
device_dict['status'] = new_status
self._create_device_status(context, device_id, new_status)
@ -302,9 +307,11 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
context=context, device_id=instance_id, auth_attr=vim_auth,
region_name=region_name)
self.mgmt_call(context, device_dict, kwargs)
except Exception:
except Exception as e:
LOG.exception(_('_update_device_wait'))
new_status = constants.ERROR
self.set_device_error_status_reason(context, device_dict['id'],
six.text_type(e))
device_dict['status'] = new_status
self.mgmt_update_post(context, device_dict)
@ -323,9 +330,12 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
driver_name, 'update', plugin=self, context=context,
device_id=instance_id, device_dict=device_dict,
device=device, auth_attr=vim_auth)
except Exception:
except Exception as e:
with excutils.save_and_reraise_exception():
device_dict['status'] = constants.ERROR
self.set_device_error_status_reason(context,
device_dict['id'],
six.text_type(e))
self.mgmt_update_post(context, device_dict)
self._update_device_post(context, device_id, constants.ERROR)
@ -346,6 +356,7 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
except Exception as e_:
e = e_
device_dict['status'] = constants.ERROR
device_dict['error_reason'] = six.text_type(e)
LOG.exception(_('_delete_device_wait'))
self.mgmt_delete_post(context, device_dict)
device_id = device_dict['id']
@ -377,6 +388,7 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
# Other case mark error
with excutils.save_and_reraise_exception():
device_dict['status'] = constants.ERROR
device_dict['error_reason'] = six.text_type(e)
self.mgmt_delete_post(context, device_dict)
self._delete_device_post(context, device_id, e)