Enables soft deletion for VIM, VNFD and VNF
implements blueprint: audit-support Change-Id: Ia73389d76f7112fa7849a4904b3b2f32089406f0 Co-Authored-By: Vishwanath Jayaraman <vishwanathj@hotmail.com>
This commit is contained in:
parent
8ca9c9cfea
commit
30a1d2464b
@ -101,6 +101,11 @@ class CommonDbMixin(object):
|
||||
# condition, raising an exception
|
||||
if query_filter is not None:
|
||||
query = query.filter(query_filter)
|
||||
|
||||
# Don't list the deleted entries
|
||||
if hasattr(model, 'deleted_at'):
|
||||
query = query.filter_by(deleted_at=None)
|
||||
|
||||
return query
|
||||
|
||||
def _fields(self, resource, fields):
|
||||
@ -138,6 +143,7 @@ class CommonDbMixin(object):
|
||||
|
||||
if result_filter:
|
||||
query = result_filter(query, filters)
|
||||
|
||||
return query
|
||||
|
||||
def _apply_dict_extend_functions(self, resource_type,
|
||||
|
@ -0,0 +1,39 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""enable soft delete
|
||||
|
||||
Revision ID: 941b5a6fff9e
|
||||
Revises: 2ff0a0e360f1
|
||||
Create Date: 2016-06-06 10:12:49.787430
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '941b5a6fff9e'
|
||||
down_revision = '2ff0a0e360f1'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade(active_plugins=None, options=None):
|
||||
for table in ['vims', 'vnf', 'vnfd']:
|
||||
op.add_column(table,
|
||||
sa.Column('deleted_at', sa.DateTime(), nullable=True))
|
||||
|
||||
# unique constraint is taken care by the nfvo_db plugin to support
|
||||
# soft deletion of vim
|
||||
op.drop_index('auth_url', table_name='vimauths')
|
@ -1,2 +1,2 @@
|
||||
2ff0a0e360f1
|
||||
941b5a6fff9e
|
||||
|
||||
|
@ -40,3 +40,4 @@ class Audit(object):
|
||||
created_at = sa.Column(sa.DateTime,
|
||||
default=lambda: timeutils.utcnow())
|
||||
updated_at = sa.Column(sa.DateTime)
|
||||
deleted_at = sa.Column(sa.DateTime)
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
import uuid
|
||||
|
||||
from oslo_db import exception
|
||||
from oslo_utils import strutils
|
||||
from oslo_utils import timeutils
|
||||
import sqlalchemy as sa
|
||||
@ -63,7 +62,6 @@ class VimAuth(model_base.BASE, models_v1.HasId):
|
||||
auth_url = sa.Column(sa.String(255), nullable=False)
|
||||
vim_project = sa.Column(types.Json, nullable=False)
|
||||
auth_cred = sa.Column(types.Json, nullable=False)
|
||||
__table_args__ = (sa.UniqueConstraint('auth_url'), {})
|
||||
|
||||
|
||||
class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
|
||||
@ -101,10 +99,23 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
|
||||
else:
|
||||
raise
|
||||
|
||||
def _does_already_exist(self, context, vim):
|
||||
try:
|
||||
query = self._model_query(context, VimAuth)
|
||||
for v_auth in query.filter(VimAuth.auth_url == vim.get('auth_url')
|
||||
).all():
|
||||
vim = self._get_by_id(context, Vim, v_auth.get('vim_id'))
|
||||
if vim.get('deleted_at') is None:
|
||||
return True
|
||||
except orm_exc.NoResultFound:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def create_vim(self, context, vim):
|
||||
self._validate_default_vim(context, vim)
|
||||
vim_cred = vim['auth_cred']
|
||||
try:
|
||||
if not self._does_already_exist(context, vim):
|
||||
with context.session.begin(subtransactions=True):
|
||||
vim_db = Vim(
|
||||
id=vim.get('id'),
|
||||
@ -124,20 +135,23 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
|
||||
auth_url=vim.get('auth_url'),
|
||||
auth_cred=vim_cred)
|
||||
context.session.add(vim_auth_db)
|
||||
except exception.DBDuplicateEntry:
|
||||
else:
|
||||
raise nfvo.VimDuplicateUrlException()
|
||||
return self._make_vim_dict(vim_db)
|
||||
|
||||
def delete_vim(self, context, vim_id):
|
||||
def delete_vim(self, context, vim_id, soft_delete=True):
|
||||
with context.session.begin(subtransactions=True):
|
||||
vim_db = self._get_resource(context, Vim, vim_id)
|
||||
context.session.query(VimAuth).filter_by(
|
||||
vim_id=vim_id).delete()
|
||||
context.session.delete(vim_db)
|
||||
if soft_delete:
|
||||
vim_db.update({'deleted_at': timeutils.utcnow()})
|
||||
else:
|
||||
context.session.query(VimAuth).filter_by(
|
||||
vim_id=vim_id).delete()
|
||||
context.session.delete(vim_db)
|
||||
|
||||
def is_vim_still_in_use(self, context, vim_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
devices_db = context.session.query(vm_db.VNF).filter_by(
|
||||
devices_db = self._model_query(context, vm_db.VNF).filter_by(
|
||||
vim_id=vim_id).first()
|
||||
if devices_db is not None:
|
||||
raise nfvo.VimInUseException(vim_id=vim_id)
|
||||
|
@ -277,23 +277,29 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
template_db.update({'updated_at': timeutils.utcnow()})
|
||||
return self._make_template_dict(template_db)
|
||||
|
||||
def delete_device_template(self, context, device_template_id):
|
||||
def delete_device_template(self,
|
||||
context,
|
||||
device_template_id,
|
||||
soft_delete=True):
|
||||
with context.session.begin(subtransactions=True):
|
||||
# TODO(yamahata): race. prevent from newly inserting hosting device
|
||||
# that refers to this template
|
||||
devices_db = context.session.query(VNF).filter_by(
|
||||
vnfd_id=device_template_id).first()
|
||||
if devices_db is not None:
|
||||
if devices_db is not None and devices_db.deleted_at is None:
|
||||
raise vnfm.DeviceTemplateInUse(
|
||||
device_template_id=device_template_id)
|
||||
|
||||
context.session.query(ServiceType).filter_by(
|
||||
vnfd_id=device_template_id).delete()
|
||||
context.session.query(VNFDAttribute).filter_by(
|
||||
vnfd_id=device_template_id).delete()
|
||||
template_db = self._get_resource(context, VNFD,
|
||||
device_template_id)
|
||||
context.session.delete(template_db)
|
||||
if soft_delete:
|
||||
template_db.update({'deleted_at': timeutils.utcnow()})
|
||||
else:
|
||||
context.session.query(ServiceType).filter_by(
|
||||
vnfd_id=device_template_id).delete()
|
||||
context.session.query(VNFDAttribute).filter_by(
|
||||
vnfd_id=device_template_id).delete()
|
||||
context.session.delete(template_db)
|
||||
|
||||
def get_device_template(self, context, device_template_id, fields=None):
|
||||
template_db = self._get_resource(context, VNFD,
|
||||
@ -437,10 +443,6 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
def _update_device_post(self, context, device_id, new_status,
|
||||
new_device_dict=None):
|
||||
with context.session.begin(subtransactions=True):
|
||||
(self._model_query(context, VNF).
|
||||
filter(VNF.id == device_id).
|
||||
filter(VNF.status == constants.PENDING_UPDATE).
|
||||
update({'status': new_status}))
|
||||
(self._model_query(context, VNF).
|
||||
filter(VNF.id == device_id).
|
||||
filter(VNF.status == constants.PENDING_UPDATE).
|
||||
@ -466,7 +468,7 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
|
||||
return self._make_device_dict(device_db)
|
||||
|
||||
def _delete_device_post(self, context, device_id, error):
|
||||
def _delete_device_post(self, context, device_id, error, soft_delete=True):
|
||||
with context.session.begin(subtransactions=True):
|
||||
query = (
|
||||
self._model_query(context, VNF).
|
||||
@ -475,9 +477,12 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
if error:
|
||||
query.update({'status': constants.ERROR})
|
||||
else:
|
||||
(self._model_query(context, VNFAttribute).
|
||||
filter(VNFAttribute.vnf_id == device_id).delete())
|
||||
query.delete()
|
||||
if soft_delete:
|
||||
query.update({'deleted_at': timeutils.utcnow()})
|
||||
else:
|
||||
(self._model_query(context, VNFAttribute).
|
||||
filter(VNFAttribute.vnf_id == device_id).delete())
|
||||
query.delete()
|
||||
|
||||
# reference implementation. needs to be overrided by subclass
|
||||
def create_device(self, context, device):
|
||||
@ -503,12 +508,15 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
return device_dict
|
||||
|
||||
# reference implementation. needs to be overrided by subclass
|
||||
def delete_device(self, context, device_id):
|
||||
def delete_device(self, context, device_id, soft_delete=True):
|
||||
self._delete_device_pre(context, device_id)
|
||||
# start actual deletion of hosting device.
|
||||
# Waiting for completion of deletion should be done backgroundly
|
||||
# by another thread if it takes a while.
|
||||
self._delete_device_post(context, device_id, False)
|
||||
self._delete_device_post(context,
|
||||
device_id,
|
||||
False,
|
||||
soft_delete=soft_delete)
|
||||
|
||||
def get_device(self, context, device_id, fields=None):
|
||||
device_db = self._get_resource(context, VNF, device_id)
|
||||
|
Loading…
Reference in New Issue
Block a user