Add unique constraint on vnfd_id column

In Vnf LCM, when user will call create vnf instance API, vnfdId
will be passed in the CreateVnfRequest as per SOL002,
section 5.5.2.3 [1]. Based on this vnfdId, it will look for the
vnf package to load the csar package at the time of instantiating vnf
instance. So it's important that vnfdId is unique in the
``vnf_package_vnfd`` dbb table.

Added ``vnfd_id`` and ``deleted`` columns as unique key in
``vnf_package_vnfd`` db table.

[1] : https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/002/02.06.01_60/gs_nfv-sol002v020601p.pdf

Change-Id: I2da2acf256bec307b606c5a152c0d47af24ad525
Blueprint: support-etsi-nfv-specs
This commit is contained in:
tpatil 2020-01-30 01:37:52 +00:00
parent dcbeac526b
commit 55b96c51e3
6 changed files with 94 additions and 4 deletions

View File

@ -207,6 +207,10 @@ class VnfPackageNotFound(NotFound):
message = _("No vnf package with id %(id)s.")
class VnfPackageVnfdIdDuplicate(TackerException):
message = _("Vnf package with vnfd id %(vnfd_id)s already exists.")
class VnfDeploymentFlavourNotFound(NotFound):
message = _("No vnf deployment flavour with id %(id)s.")

View File

@ -14,7 +14,9 @@
# under the License.
from oslo_db.sqlalchemy import models
from oslo_utils import timeutils
import sqlalchemy as sa
from sqlalchemy import DateTime
from sqlalchemy import orm
from tacker.db import model_base
@ -96,11 +98,27 @@ class VnfDeploymentFlavour(model_base.BASE, models.SoftDeleteMixin,
'VnfSoftwareImage.deleted == 0)')
class VnfPackageVnfd(model_base.BASE, models.SoftDeleteMixin,
class VnfPackageVnfdSoftDeleteMixin(object):
deleted_at = sa.Column(DateTime)
deleted = sa.Column(sa.String(36), default='0')
def soft_delete(self, session):
"""Mark this object as deleted."""
self.deleted = self.id
self.deleted_at = timeutils.utcnow()
self.save(session=session)
class VnfPackageVnfd(model_base.BASE, VnfPackageVnfdSoftDeleteMixin,
models.TimestampMixin, models_v1.HasId):
"""Contains all info about vnf packages VNFD."""
__tablename__ = 'vnf_package_vnfd'
__table_args__ = (
sa.schema.UniqueConstraint("vnfd_id", "deleted",
name="uniq_vnf_package_vnfd0vnfd_id0deleted"),
)
package_uuid = sa.Column(sa.String(36),
sa.ForeignKey('vnf_packages.id'),
nullable=False)

View File

@ -0,0 +1,62 @@
# Copyright (C) 2020 NTT DATA
# All Rights Reserved.
#
# 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 unique constraints on vnfd_id,deleted in vnf_package_vnfd
Revision ID: 975e28392888
Revises: abbef484b34c
Create Date: 2019-12-10 02:40:12.966027
"""
# revision identifiers, used by Alembic.
revision = '975e28392888'
down_revision = 'abbef484b34c'
from alembic import op
import sqlalchemy as sa
def _migrate_duplicate_vnf_package_vnfd_id(table):
meta = sa.MetaData(bind=op.get_bind())
t = sa.Table(table, meta, autoload=True)
session = sa.orm.Session(bind=op.get_bind())
with session.begin(subtransactions=True):
dup_vnfd_ids = session.query(t.c.vnfd_id).group_by(
t.c.vnfd_id).having(sa.func.count() > 1).all()
if dup_vnfd_ids:
for vnfd_id in dup_vnfd_ids:
duplicate_obj_query = session.query(t).filter(
t.c.vnfd_id == vnfd_id[0]).all()
for dup_obj in duplicate_obj_query:
if dup_obj.deleted == '1':
session.execute(t.update().where(
t.c.id == dup_obj.id).values(deleted=dup_obj.id))
session.commit()
op.create_unique_constraint(
constraint_name='uniq_%s0vnfd_id0deleted' % table,
table_name=table,
columns=['vnfd_id', 'deleted'])
def upgrade(active_plugins=None, options=None):
op.alter_column('vnf_package_vnfd',
'deleted',
type_=sa.String(36), default="0")
_migrate_duplicate_vnf_package_vnfd_id('vnf_package_vnfd')

View File

@ -1 +1 @@
abbef484b34c
975e28392888

View File

@ -216,7 +216,7 @@ def _destroy_vnf_package(context, package_uuid):
update(updated_values, synchronize_session=False)
api.model_query(context, models.VnfPackageVnfd). \
filter_by(package_uuid=package_uuid). \
update(updated_values, synchronize_session=False)
soft_delete(synchronize_session=False)
api.model_query(context, models.VnfPackage).\
filter_by(id=package_uuid). \
update(updated_values, synchronize_session=False)

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_db import exception as db_exc
from oslo_utils import uuidutils
from tacker.common import exceptions
@ -26,7 +27,12 @@ def _vnf_package_vnfd_create(context, values):
vnf_package_vnfd = models.VnfPackageVnfd()
vnf_package_vnfd.update(values)
vnf_package_vnfd.save(context.session)
try:
vnf_package_vnfd.save(context.session)
except db_exc.DBDuplicateEntry as e:
if 'vnfd_id' in e.columns:
raise exceptions.VnfPackageVnfdIdDuplicate(
vnfd_id=values.get('vnfd_id'))
return vnf_package_vnfd