Adds audit support for VIM, VNFD and VNF

implements blueprint: audit-support

Co-Authored-By: Vishwanath Jayaraman <vishwanathj@hotmail.com>

Change-Id: I8e6c4d6d47130c447c9a77e654d2dfad5d23ae7e
This commit is contained in:
Kanagaraj Manickam 2016-06-06 10:07:52 +05:30 committed by vish
parent 492796465f
commit 8ca9c9cfea
9 changed files with 112 additions and 8 deletions

View File

@ -0,0 +1,37 @@
# 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.
#
"""audit support
Revision ID: 2ff0a0e360f1
Revises: 22f5385a3d50
Create Date: 2016-06-02 15:14:31.888078
"""
# revision identifiers, used by Alembic.
revision = '2ff0a0e360f1'
down_revision = '22f5385a3d50'
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('created_at', sa.DateTime(), nullable=True))
op.add_column(table,
sa.Column('updated_at', sa.DateTime(), nullable=True))

View File

@ -1 +1,2 @@
22f5385a3d50 2ff0a0e360f1

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_utils import timeutils
from oslo_utils import uuidutils from oslo_utils import uuidutils
import sqlalchemy as sa import sqlalchemy as sa
@ -31,3 +32,11 @@ class HasId(object):
id = sa.Column(types.Uuid, id = sa.Column(types.Uuid,
primary_key=True, primary_key=True,
default=uuidutils.generate_uuid) default=uuidutils.generate_uuid)
class Audit(object):
"""Helps to add time stamp for create, update and delete actions. """
created_at = sa.Column(sa.DateTime,
default=lambda: timeutils.utcnow())
updated_at = sa.Column(sa.DateTime)

View File

@ -18,6 +18,7 @@ import uuid
from oslo_db import exception from oslo_db import exception
from oslo_utils import strutils from oslo_utils import strutils
from oslo_utils import timeutils
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import orm from sqlalchemy import orm
from sqlalchemy.orm import exc as orm_exc from sqlalchemy.orm import exc as orm_exc
@ -33,11 +34,16 @@ from tacker import manager
VIM_ATTRIBUTES = ('id', 'type', 'tenant_id', 'name', 'description', VIM_ATTRIBUTES = ('id', 'type', 'tenant_id', 'name', 'description',
'placement_attr', 'shared', 'is_default', 'status') 'placement_attr', 'shared', 'is_default',
'created_at', 'updated_at', 'status')
VIM_AUTH_ATTRIBUTES = ('auth_url', 'vim_project', 'password', 'auth_cred') VIM_AUTH_ATTRIBUTES = ('auth_url', 'vim_project', 'password', 'auth_cred')
class Vim(model_base.BASE, models_v1.HasId, models_v1.HasTenant): class Vim(model_base.BASE,
models_v1.HasId,
models_v1.HasTenant,
models_v1.Audit):
type = sa.Column(sa.String(64), nullable=False) type = sa.Column(sa.String(64), nullable=False)
name = sa.Column(sa.String(255), nullable=False) name = sa.Column(sa.String(255), nullable=False)
description = sa.Column(sa.Text, nullable=True) description = sa.Column(sa.Text, nullable=True)
@ -151,9 +157,9 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
vim_cred = vim['auth_cred'] vim_cred = vim['auth_cred']
vim_project = vim['vim_project'] vim_project = vim['vim_project']
is_default = vim.get('is_default') is_default = vim.get('is_default')
vim_db = self._get_resource(context, Vim, vim_id)
try: try:
if is_default: if is_default:
vim_db = self._get_resource(context, Vim, vim_id)
vim_db.update({'is_default': is_default}) vim_db.update({'is_default': is_default})
vim_auth_db = (self._model_query(context, VimAuth).filter( vim_auth_db = (self._model_query(context, VimAuth).filter(
VimAuth.vim_id == vim_id).with_lockmode('update').one()) VimAuth.vim_id == vim_id).with_lockmode('update').one())
@ -162,6 +168,8 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
vim_auth_db.update({'auth_cred': vim_cred, 'password': vim_auth_db.update({'auth_cred': vim_cred, 'password':
vim_cred.pop('password'), 'vim_project': vim_cred.pop('password'), 'vim_project':
vim_project}) vim_project})
vim_db.update({'updated_at': timeutils.utcnow()})
return self.get_vim(context, vim_id) return self.get_vim(context, vim_id)
def update_vim_status(self, context, vim_id, status): def update_vim_status(self, context, vim_id, status):

View File

@ -17,6 +17,8 @@
import uuid import uuid
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import timeutils
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import orm from sqlalchemy import orm
from sqlalchemy.orm import exc as orm_exc from sqlalchemy.orm import exc as orm_exc
@ -42,7 +44,8 @@ CREATE_STATES = (constants.PENDING_CREATE, constants.DEAD)
########################################################################### ###########################################################################
# db tables # db tables
class VNFD(model_base.BASE, models_v1.HasId, models_v1.HasTenant): class VNFD(model_base.BASE, models_v1.HasId, models_v1.HasTenant,
models_v1.Audit):
"""Represents VNFD to create VNF.""" """Represents VNFD to create VNF."""
__tablename__ = 'vnfd' __tablename__ = 'vnfd'
@ -92,7 +95,8 @@ class VNFDAttribute(model_base.BASE, models_v1.HasId):
value = sa.Column(sa.TEXT(65535), nullable=True) value = sa.Column(sa.TEXT(65535), nullable=True)
class VNF(model_base.BASE, models_v1.HasId, models_v1.HasTenant): class VNF(model_base.BASE, models_v1.HasId, models_v1.HasTenant,
models_v1.Audit):
"""Represents devices that hosts services. """Represents devices that hosts services.
Here the term, 'VM', is intentionally avoided because it can be Here the term, 'VM', is intentionally avoided because it can be
@ -181,7 +185,8 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
template.service_types) template.service_types)
} }
key_list = ('id', 'tenant_id', 'name', 'description', key_list = ('id', 'tenant_id', 'name', 'description',
'infra_driver', 'mgmt_driver') 'infra_driver', 'mgmt_driver',
'created_at', 'updated_at')
res.update((key, template[key]) for key in key_list) res.update((key, template[key]) for key in key_list)
return self._fields(res, fields) return self._fields(res, fields)
@ -198,7 +203,7 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
} }
key_list = ('id', 'tenant_id', 'name', 'description', 'instance_id', key_list = ('id', 'tenant_id', 'name', 'description', 'instance_id',
'vim_id', 'placement_attr', 'vnfd_id', 'status', 'vim_id', 'placement_attr', 'vnfd_id', 'status',
'mgmt_url', 'error_reason') 'mgmt_url', 'error_reason', 'created_at', 'updated_at')
res.update((key, device_db[key]) for key in key_list) res.update((key, device_db[key]) for key in key_list)
return self._fields(res, fields) return self._fields(res, fields)
@ -269,6 +274,7 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
template_db = self._get_resource(context, VNFD, template_db = self._get_resource(context, VNFD,
device_template_id) device_template_id)
template_db.update(device_template['device_template']) template_db.update(device_template['device_template'])
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):
@ -435,6 +441,11 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
filter(VNF.id == device_id). filter(VNF.id == device_id).
filter(VNF.status == constants.PENDING_UPDATE). filter(VNF.status == constants.PENDING_UPDATE).
update({'status': new_status})) update({'status': new_status}))
(self._model_query(context, VNF).
filter(VNF.id == device_id).
filter(VNF.status == constants.PENDING_UPDATE).
update({'status': new_status,
'updated_at': timeutils.utcnow()}))
dev_attrs = new_device_dict.get('attributes', {}) dev_attrs = new_device_dict.get('attributes', {})
(context.session.query(VNFAttribute). (context.session.query(VNFAttribute).

View File

@ -160,6 +160,16 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_visible': True, 'is_visible': True,
'default': False 'default': False
}, },
'created_at': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
'updated_at': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
} }
} }

View File

@ -224,6 +224,16 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_visible': True, 'is_visible': True,
'default': None, 'default': None,
}, },
'created_at': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
'updated_at': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
}, },
'vnfs': { 'vnfs': {
@ -303,6 +313,16 @@ RESOURCE_ATTRIBUTE_MAP = {
'allow_put': False, 'allow_put': False,
'is_visible': True, 'is_visible': True,
}, },
'created_at': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
'updated_at': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
}, },
} }

View File

@ -88,6 +88,8 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertEqual(SECRET_PASSWORD, res['auth_cred']['password']) self.assertEqual(SECRET_PASSWORD, res['auth_cred']['password'])
self.assertIn('id', res) self.assertIn('id', res)
self.assertIn('placement_attr', res) self.assertIn('placement_attr', res)
self.assertIn('created_at', res)
self.assertIn('updated_at', res)
def test_delete_vim(self): def test_delete_vim(self):
self._insert_dummy_vim() self._insert_dummy_vim()
@ -118,3 +120,4 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertEqual(vim_project, res['vim_project']) self.assertEqual(vim_project, res['vim_project'])
self.assertEqual(vim_auth_username, res['auth_cred']['username']) self.assertEqual(vim_auth_username, res['auth_cred']['username'])
self.assertEqual(SECRET_PASSWORD, res['auth_cred']['password']) self.assertEqual(SECRET_PASSWORD, res['auth_cred']['password'])
self.assertIn('updated_at', res)

View File

@ -152,6 +152,8 @@ class TestVNFMPlugin(db_base.SqlTestCase):
self.assertIn('id', result) self.assertIn('id', result)
self.assertIn('service_types', result) self.assertIn('service_types', result)
self.assertIn('attributes', result) self.assertIn('attributes', result)
self.assertIn('created_at', result)
self.assertIn('updated_at', result)
self._device_manager.invoke.assert_called_once_with( self._device_manager.invoke.assert_called_once_with(
mock.ANY, mock.ANY,
mock.ANY, mock.ANY,
@ -183,6 +185,8 @@ class TestVNFMPlugin(db_base.SqlTestCase):
self.assertIn('status', result) self.assertIn('status', result)
self.assertIn('attributes', result) self.assertIn('attributes', result)
self.assertIn('mgmt_url', result) self.assertIn('mgmt_url', result)
self.assertIn('created_at', result)
self.assertIn('updated_at', result)
self._device_manager.invoke.assert_called_with(mock.ANY, mock.ANY, self._device_manager.invoke.assert_called_with(mock.ANY, mock.ANY,
plugin=mock.ANY, plugin=mock.ANY,
context=mock.ANY, context=mock.ANY,
@ -217,5 +221,6 @@ class TestVNFMPlugin(db_base.SqlTestCase):
self.assertIn('status', result) self.assertIn('status', result)
self.assertIn('attributes', result) self.assertIn('attributes', result)
self.assertIn('mgmt_url', result) self.assertIn('mgmt_url', result)
self.assertIn('updated_at', result)
self._pool.spawn_n.assert_called_once_with(mock.ANY, mock.ANY, self._pool.spawn_n.assert_called_once_with(mock.ANY, mock.ANY,
mock.ANY, mock.ANY) mock.ANY, mock.ANY)