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
|
# condition, raising an exception
|
||||||
if query_filter is not None:
|
if query_filter is not None:
|
||||||
query = query.filter(query_filter)
|
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
|
return query
|
||||||
|
|
||||||
def _fields(self, resource, fields):
|
def _fields(self, resource, fields):
|
||||||
@ -138,6 +143,7 @@ class CommonDbMixin(object):
|
|||||||
|
|
||||||
if result_filter:
|
if result_filter:
|
||||||
query = result_filter(query, filters)
|
query = result_filter(query, filters)
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
def _apply_dict_extend_functions(self, resource_type,
|
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,
|
created_at = sa.Column(sa.DateTime,
|
||||||
default=lambda: timeutils.utcnow())
|
default=lambda: timeutils.utcnow())
|
||||||
updated_at = sa.Column(sa.DateTime)
|
updated_at = sa.Column(sa.DateTime)
|
||||||
|
deleted_at = sa.Column(sa.DateTime)
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from oslo_db import exception
|
|
||||||
from oslo_utils import strutils
|
from oslo_utils import strutils
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import sqlalchemy as sa
|
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)
|
auth_url = sa.Column(sa.String(255), nullable=False)
|
||||||
vim_project = sa.Column(types.Json, nullable=False)
|
vim_project = sa.Column(types.Json, nullable=False)
|
||||||
auth_cred = 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):
|
class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
|
||||||
@ -101,10 +99,23 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
|
|||||||
else:
|
else:
|
||||||
raise
|
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):
|
def create_vim(self, context, vim):
|
||||||
self._validate_default_vim(context, vim)
|
self._validate_default_vim(context, vim)
|
||||||
vim_cred = vim['auth_cred']
|
vim_cred = vim['auth_cred']
|
||||||
try:
|
if not self._does_already_exist(context, vim):
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
vim_db = Vim(
|
vim_db = Vim(
|
||||||
id=vim.get('id'),
|
id=vim.get('id'),
|
||||||
@ -124,20 +135,23 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
|
|||||||
auth_url=vim.get('auth_url'),
|
auth_url=vim.get('auth_url'),
|
||||||
auth_cred=vim_cred)
|
auth_cred=vim_cred)
|
||||||
context.session.add(vim_auth_db)
|
context.session.add(vim_auth_db)
|
||||||
except exception.DBDuplicateEntry:
|
else:
|
||||||
raise nfvo.VimDuplicateUrlException()
|
raise nfvo.VimDuplicateUrlException()
|
||||||
return self._make_vim_dict(vim_db)
|
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):
|
with context.session.begin(subtransactions=True):
|
||||||
vim_db = self._get_resource(context, Vim, vim_id)
|
vim_db = self._get_resource(context, Vim, vim_id)
|
||||||
context.session.query(VimAuth).filter_by(
|
if soft_delete:
|
||||||
vim_id=vim_id).delete()
|
vim_db.update({'deleted_at': timeutils.utcnow()})
|
||||||
context.session.delete(vim_db)
|
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):
|
def is_vim_still_in_use(self, context, vim_id):
|
||||||
with context.session.begin(subtransactions=True):
|
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()
|
vim_id=vim_id).first()
|
||||||
if devices_db is not None:
|
if devices_db is not None:
|
||||||
raise nfvo.VimInUseException(vim_id=vim_id)
|
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()})
|
template_db.update({'updated_at': timeutils.utcnow()})
|
||||||
return self._make_template_dict(template_db)
|
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):
|
with context.session.begin(subtransactions=True):
|
||||||
# TODO(yamahata): race. prevent from newly inserting hosting device
|
# TODO(yamahata): race. prevent from newly inserting hosting device
|
||||||
# that refers to this template
|
# that refers to this template
|
||||||
devices_db = context.session.query(VNF).filter_by(
|
devices_db = context.session.query(VNF).filter_by(
|
||||||
vnfd_id=device_template_id).first()
|
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(
|
raise vnfm.DeviceTemplateInUse(
|
||||||
device_template_id=device_template_id)
|
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,
|
template_db = self._get_resource(context, VNFD,
|
||||||
device_template_id)
|
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):
|
def get_device_template(self, context, device_template_id, fields=None):
|
||||||
template_db = self._get_resource(context, VNFD,
|
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,
|
def _update_device_post(self, context, device_id, new_status,
|
||||||
new_device_dict=None):
|
new_device_dict=None):
|
||||||
with context.session.begin(subtransactions=True):
|
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).
|
(self._model_query(context, VNF).
|
||||||
filter(VNF.id == device_id).
|
filter(VNF.id == device_id).
|
||||||
filter(VNF.status == constants.PENDING_UPDATE).
|
filter(VNF.status == constants.PENDING_UPDATE).
|
||||||
@ -466,7 +468,7 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
|||||||
|
|
||||||
return self._make_device_dict(device_db)
|
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):
|
with context.session.begin(subtransactions=True):
|
||||||
query = (
|
query = (
|
||||||
self._model_query(context, VNF).
|
self._model_query(context, VNF).
|
||||||
@ -475,9 +477,12 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
|||||||
if error:
|
if error:
|
||||||
query.update({'status': constants.ERROR})
|
query.update({'status': constants.ERROR})
|
||||||
else:
|
else:
|
||||||
(self._model_query(context, VNFAttribute).
|
if soft_delete:
|
||||||
filter(VNFAttribute.vnf_id == device_id).delete())
|
query.update({'deleted_at': timeutils.utcnow()})
|
||||||
query.delete()
|
else:
|
||||||
|
(self._model_query(context, VNFAttribute).
|
||||||
|
filter(VNFAttribute.vnf_id == device_id).delete())
|
||||||
|
query.delete()
|
||||||
|
|
||||||
# reference implementation. needs to be overrided by subclass
|
# reference implementation. needs to be overrided by subclass
|
||||||
def create_device(self, context, device):
|
def create_device(self, context, device):
|
||||||
@ -503,12 +508,15 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
|||||||
return device_dict
|
return device_dict
|
||||||
|
|
||||||
# reference implementation. needs to be overrided by subclass
|
# 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)
|
self._delete_device_pre(context, device_id)
|
||||||
# start actual deletion of hosting device.
|
# start actual deletion of hosting device.
|
||||||
# Waiting for completion of deletion should be done backgroundly
|
# Waiting for completion of deletion should be done backgroundly
|
||||||
# by another thread if it takes a while.
|
# 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):
|
def get_device(self, context, device_id, fields=None):
|
||||||
device_db = self._get_resource(context, VNF, device_id)
|
device_db = self._get_resource(context, VNF, device_id)
|
||||||
|
Loading…
Reference in New Issue
Block a user