[DNM] Remove VIM monitoring depending on Mistral

Change-Id: Ia11496da7942457239df59b52af817c76e736013
This commit is contained in:
Hiromu Asahina 2023-01-07 21:25:30 +09:00
parent 01af921686
commit 6b796deb8f
20 changed files with 39 additions and 426 deletions

View File

@ -212,8 +212,7 @@ class KubernetesMgmtDriver(vnflcm_abstract_driver.VnflcmMgmtAbstractDriver):
if created_vim_info:
vim_info = self.nfvo_plugin.get_vim(
context, created_vim_info.id)
if (vim_info['auth_url'] == server and
vim_info['status'] == 'REACHABLE'):
if vim_info['auth_url'] == server:
return vim_info
try:
return self.nfvo_plugin.create_vim(context, create_vim_info)

View File

@ -11,5 +11,4 @@
# under the License.
TOPIC_ACTION_KILL = 'KILL_ACTION'
TOPIC_CONDUCTOR = 'TACKER_CONDUCTOR'

View File

@ -39,7 +39,6 @@ from oslo_utils import excutils
from oslo_utils import timeutils
from oslo_utils import uuidutils
from sqlalchemy import exc as sqlexc
from sqlalchemy.orm import exc as orm_exc
from tacker import auth
from tacker.common import coordination
@ -52,11 +51,8 @@ from tacker.common import topics
from tacker.common import utils
import tacker.conf
from tacker import context as t_context
from tacker.db.common_services import common_services_db
from tacker.db.db_sqlalchemy import models
from tacker.db.nfvo import nfvo_db
from tacker.db.vnfm import vnfm_db
from tacker.extensions import nfvo
from tacker.glance_store import store as glance_store
from tacker import manager
from tacker import objects
@ -356,28 +352,6 @@ class Conductor(manager.Manager, v2_hook.ConductorV2Hook):
CONF.vnf_package.vnf_package_csar_path)
sys.exit(1)
def update_vim(self, context, vim_id, status):
t_admin_context = t_context.get_admin_context()
update_time = timeutils.utcnow()
with t_admin_context.session.begin(subtransactions=True):
try:
query = t_admin_context.session.query(nfvo_db.Vim)
query.filter(
nfvo_db.Vim.id == vim_id).update(
{'status': status,
'updated_at': update_time})
except orm_exc.NoResultFound:
raise nfvo.VimNotFoundException(vim_id=vim_id)
event_db = common_services_db.Event(
resource_id=vim_id,
resource_type=constants.RES_TYPE_VIM,
resource_state=status,
event_details="",
event_type=constants.RES_EVT_MONITOR,
timestamp=update_time)
t_admin_context.session.add(event_db)
return status
def _create_software_images(self, context, sw_image, flavour_uuid):
vnf_sw_image = objects.VnfSoftwareImage(context=context)
vnf_sw_image.flavour_uuid = flavour_uuid

View File

@ -1 +1 @@
de8d835ae776
de6bfa5bea46

View File

@ -1,5 +1,4 @@
# Copyright 2017 OpenStack Foundation
# All Rights Reserved.
# Copyright 2023 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
@ -12,19 +11,24 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import oslo_messaging
"""remove status from Vim
from tacker.common import topics
Revision ID: de6bfa5bea46
Revises: de8d835ae776
Create Date: 2023-01-09 11:08:53.597828
"""
# flake8: noqa: E402
# revision identifiers, used by Alembic.
revision = 'de6bfa5bea46'
down_revision = 'de8d835ae776'
from alembic import op
class VIMUpdateRPC(object):
target = oslo_messaging.Target(
exchange='tacker',
topic=topics.TOPIC_CONDUCTOR,
fanout=False,
version='1.0')
def update_vim(self, context, **kwargs):
pass
def upgrade(active_plugins=None, options=None):
op.drop_column('vims', 'status')

View File

@ -37,7 +37,6 @@ class Vim(model_base.BASE,
is_default = sa.Column(sa.Boolean, default=False, server_default=sql.false(
), nullable=False)
vim_auth = orm.relationship('VimAuth')
status = sa.Column(sa.String(255), nullable=False)
extra = sa.Column(types.Json, nullable=True)
__table_args__ = (

View File

@ -31,7 +31,7 @@ from tacker.plugins.common import constants
VIM_ATTRIBUTES = ('id', 'type', 'tenant_id', 'name', 'description',
'placement_attr', 'shared', 'is_default',
'created_at', 'updated_at', 'status', 'extra')
'created_at', 'updated_at', 'extra')
VIM_AUTH_ATTRIBUTES = ('auth_url', 'vim_project', 'password', 'auth_cred')
@ -97,7 +97,6 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
description=vim.get('description'),
placement_attr=vim.get('placement_attr'),
is_default=vim.get('is_default'),
status=vim.get('status'),
extra=vim.get('extra'),
deleted_at=datetime.min)
context.session.add(vim_db)
@ -114,10 +113,14 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
_type="vim",
entry=e.columns)
vim_dict = self._make_vim_dict(vim_db)
# TODO(hiromu): Remove Event table
# NOTE(hiromu): "REGISTERED" in res_state is a workaround to delete
# the status field from the Vim table.
self._cos_db_plg.create_event(
context, res_id=vim_dict['id'],
res_type=constants.RES_TYPE_VIM,
res_state=vim_dict['status'],
res_state='REGISTERED',
evt_type=constants.RES_EVT_CREATE,
tstamp=vim_dict['created_at'])
return vim_dict
@ -127,10 +130,15 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
vim_db = self._get_resource(context, nfvo_db.Vim, vim_id)
if soft_delete:
vim_db.update({'deleted_at': timeutils.utcnow()})
# TODO(hiromu): Remove Event table
# NOTE(hiromu): "REGISTERED" in res_state is a workaround to
# delete
# the status field from the Vim table.
self._cos_db_plg.create_event(
context, res_id=vim_db['id'],
res_type=constants.RES_TYPE_VIM,
res_state=vim_db['status'],
res_state='REGISTERED',
evt_type=constants.RES_EVT_DELETE,
tstamp=vim_db[constants.RES_EVT_DELETED_FLD])
else:
@ -181,26 +189,19 @@ class NfvoPluginDb(nfvo.NFVOPluginBase, db_base.CommonDbMixin):
vim_cred.pop('password', None), 'vim_project':
vim_project})
vim_db.update({'updated_at': timeutils.utcnow()})
# TODO(hiromu): Remove Event table
# NOTE(hiromu): "REGISTERED" in res_state is a workaround to delete
# the status field from the Vim table.
self._cos_db_plg.create_event(
context, res_id=vim_db['id'],
res_type=constants.RES_TYPE_VIM,
res_state=vim_db['status'],
res_state='REGISTERED',
evt_type=constants.RES_EVT_UPDATE,
tstamp=vim_db[constants.RES_EVT_UPDATED_FLD])
return self.get_vim(context, vim_id)
def update_vim_status(self, context, vim_id, status):
with context.session.begin(subtransactions=True):
try:
vim_db = (self._model_query(context, nfvo_db.Vim).filter(
nfvo_db.Vim.id == vim_id).with_for_update().one())
except orm_exc.NoResultFound:
raise nfvo.VimNotFoundException(vim_id=vim_id)
vim_db.update({'status': status,
'updated_at': timeutils.utcnow()})
return self._make_vim_dict(vim_db)
def _validate_default_vim(self, context, vim, vim_id=None):
if not vim.get('is_default'):
return True

View File

@ -1,27 +0,0 @@
# 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.
import oslo_messaging
from tacker.common import topics
class MistralActionKillRPC(object):
target = oslo_messaging.Target(
exchange='tacker',
topic=topics.TOPIC_ACTION_KILL,
fanout=False,
version='1.0')
def killAction(self, context, **kwargs):
pass

View File

@ -61,7 +61,6 @@ OPENSTACK_OPTS = [
help=_('Number of seconds to wait between packets'))
]
cfg.CONF.register_opts(OPTS, 'vim_keys')
cfg.CONF.register_opts(OPENSTACK_OPTS, 'vim_monitor')
_VALID_RESOURCE_TYPES = {'network': {'client': neutron_client.Client,
'cmd': 'list_networks',
@ -87,8 +86,7 @@ SFC_ENCAP = 'sfc_encap'
def config_opts():
return [('vim_keys', OPTS),
('vim_monitor', OPENSTACK_OPTS)]
return [('vim_keys', OPTS)]
class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver,

View File

@ -42,7 +42,6 @@ from tacker.extensions import common_services as cs
from tacker.extensions import nfvo
from tacker.keymgr import API as KEYMGR_API
from tacker import manager
from tacker.nfvo.workflows.vim_monitor import vim_monitor_utils
from tacker.plugins.common import constants
from tacker.vnfm import keystone
from tacker.vnfm import vim_client
@ -124,7 +123,6 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
if vim_type == 'openstack':
vim_obj['auth_url'] = utils.get_auth_url_v3(vim_obj['auth_url'])
vim_obj['id'] = uuidutils.generate_uuid()
vim_obj['status'] = 'PENDING'
try:
self._vim_drivers.invoke(vim_type,
'register_vim',
@ -136,11 +134,6 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
'delete_vim_auth',
vim_id=vim_obj['id'],
auth=vim_obj['auth_cred'])
try:
self.monitor_vim(context, vim_obj)
except Exception:
LOG.warning("Failed to set up vim monitoring")
return res
def _get_vim(self, context, vim_id):
@ -250,18 +243,8 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
self._vim_drivers.invoke(vim_obj['type'],
'deregister_vim',
vim_obj=vim_obj)
try:
auth_dict = self.get_auth_dict(context)
vim_monitor_utils.delete_vim_monitor(context, auth_dict, vim_obj)
except Exception:
LOG.exception("Failed to remove vim monitor")
super(NfvoPlugin, self).delete_vim(context, vim_id)
@log.log
def monitor_vim(self, context, vim_obj):
auth_dict = self.get_auth_dict(context)
vim_monitor_utils.monitor_vim(auth_dict, vim_obj)
@log.log
def validate_tosca(self, template):
if "tosca_definitions_version" not in template:

View File

@ -1,15 +0,0 @@
# 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.
RESOURCE_NAME = 'ping_vim'
PING_VIM_TASK_NAME = 'PingVIMTASK'

View File

@ -1,94 +0,0 @@
# 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.
import yaml
from oslo_config import cfg
from oslo_log import log as logging
from tacker.common import rpc
from tacker.mistral.actionrpc import kill_action as killaction
from tacker.mistral import mistral_client
from tacker.nfvo.workflows.vim_monitor import workflow_generator
from tacker.vnfm import keystone
LOG = logging.getLogger(__name__)
def get_mistral_client(auth_dict):
return mistral_client.MistralClient(
keystone.Keystone().initialize_client(**auth_dict),
auth_dict['token']).get_client()
def prepare_and_create_workflow(mistral_client, vim_id, action,
kwargs):
wg = workflow_generator.WorkflowGenerator(vim_id, action)
wg.task(**kwargs)
yaml.SafeDumper.ignore_aliases = lambda self, data: True
definition_yaml = yaml.safe_dump(wg.definition, default_flow_style=False)
LOG.debug('vim monitor workflow: %s', definition_yaml)
workflow = mistral_client.workflows.create(definition_yaml)
return {'id': workflow[0].id, 'input': wg.get_input_dict()}
def execute_workflow(mistral_client, workflow):
return mistral_client.executions.create(
wf_identifier=workflow['id'],
workflow_input=workflow['input'],
wf_params={})
def delete_executions(mistral_client, vim_id):
executions = mistral_client.executions.list(
workflow_name='vim_id_' + vim_id)
for execution in executions:
mistral_client.executions.delete(execution.id, force=True)
def delete_workflow(mistral_client, vim_id):
return mistral_client.workflows.delete('vim_id_' + vim_id)
def monitor_vim(auth_dict, vim_obj):
mc = get_mistral_client(auth_dict)
auth_url = vim_obj["auth_url"]
vim_type = vim_obj['type']
if vim_type == 'openstack':
vim_ip = auth_url.split("//")[-1].split(":")[0].split("/")[0]
elif vim_type == 'kubernetes':
vim_ip = auth_url.split("//")[-1].split(":")[0]
workflow_input_dict = {
'vim_id': vim_obj['id'],
'count': cfg.CONF.vim_monitor.count,
'timeout': cfg.CONF.vim_monitor.timeout,
'interval': cfg.CONF.vim_monitor.interval,
'targetip': vim_ip}
workflow = prepare_and_create_workflow(
mc, vim_obj['id'], 'monitor',
workflow_input_dict)
execute_workflow(mc, workflow)
def kill_action(context, vim_obj):
target = killaction.MistralActionKillRPC.target
rpc_client = rpc.get_client(target)
cctxt = rpc_client.prepare(server=vim_obj['id'])
cctxt.cast(context, 'killAction')
def delete_vim_monitor(context, auth_dict, vim_obj):
mc = get_mistral_client(auth_dict)
delete_executions(mc, vim_obj['id'])
delete_workflow(mc, vim_obj['id'])
kill_action(context, vim_obj)

View File

@ -1,114 +0,0 @@
# 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.
import netaddr
from mistral_lib import actions
from oslo_config import cfg
from oslo_log import log as logging
from tacker.agent.linux import utils as linux_utils
from tacker.common import rpc
from tacker.common import topics
from tacker.conductor.conductorrpc import vim_monitor_rpc
from tacker import context as t_context
LOG = logging.getLogger(__name__)
class PingVimAction(actions.Action):
def __init__(self, count, targetip, vim_id,
interval, timeout):
self.killed = False
self.count = count
self.timeout = timeout
self.interval = interval
self.targetip = targetip
self.vim_id = vim_id
self.current_status = "PENDING"
def start_rpc_listeners(self):
"""Start the RPC loop to let the server communicate with actions."""
self.endpoints = [self]
self.conn = rpc.create_connection()
self.conn.create_consumer(topics.TOPIC_ACTION_KILL,
self.endpoints, fanout=False,
host=self.vim_id)
return self.conn.consume_in_threads()
def killAction(self, context, **kwargs):
self.killed = True
def _ping(self):
cmd_ping = 'ping'
if netaddr.valid_ipv6(self.targetip):
cmd_ping = 'ping6'
ping_cmd = [cmd_ping, '-c', self.count,
'-W', self.timeout,
'-i', self.interval,
self.targetip]
try:
# NOTE(gongysh) since it is called in a loop, the debug log
# should be disabled to avoid eating up mistral executor.
linux_utils.execute(ping_cmd, check_exit_code=True,
debuglog=False)
return 'REACHABLE'
except RuntimeError:
LOG.warning(("Cannot ping ip address: %s"), self.targetip)
return 'UNREACHABLE'
def _update(self, status):
LOG.info("VIM %s changed to status %s", self.vim_id, status)
target = vim_monitor_rpc.VIMUpdateRPC.target
rpc_client = rpc.get_client(target)
cctxt = rpc_client.prepare()
return cctxt.call(t_context.get_admin_context_without_session(),
'update_vim',
vim_id=self.vim_id,
status=status)
def run(self, action_ctx):
servers = []
try:
rpc.init_action_rpc(cfg.CONF)
servers = self.start_rpc_listeners()
except Exception:
LOG.exception('failed to start rpc in vim action')
return 'FAILED'
try:
while True:
if self.killed:
break
status = self._ping()
if self.current_status != status:
self.current_status = self._update(status)
# TODO(gongysh) If we need to sleep a little time here?
except Exception:
LOG.exception('failed to run mistral action for vim %s',
self.vim_id)
return 'FAILED'
# to stop rpc connection
for server in servers:
try:
server.stop()
except Exception:
LOG.exception(
'failed to stop rpc connection for vim %s',
self.vim_id)
return 'KILLED'
def test(self):
return 'REACHABLE'

View File

@ -1,59 +0,0 @@
# 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.
from oslo_log import log as logging
from tacker.mistral import workflow_generator
from tacker.nfvo.workflows import vim_monitor
LOG = logging.getLogger(__name__)
class WorkflowGenerator(workflow_generator.WorkflowGeneratorBase):
def __init__(self, vim_id, action):
super(WorkflowGenerator, self).__init__(
vim_monitor.RESOURCE_NAME, action)
self.wf_identifier = 'vim_id_' + vim_id
self._build_basic_workflow()
def _add_ping_vim_tasks(self):
task_dict = dict()
task = self.wf_name + vim_monitor.PING_VIM_TASK_NAME
task_dict[task] = {
'action': 'tacker.vim_ping_action',
'input': {'count': self.input_dict_data['count'],
'targetip': self.input_dict_data['targetip'],
'vim_id': self.input_dict_data['vim_id'],
'interval': self.input_dict_data['interval'],
'timeout': self.input_dict_data['timeout']},
}
return task_dict
def get_input_dict(self):
return self.input_dict
def _build_input(self, vim_id, count, timeout,
interval, targetip):
self.input_dict_data = {'vim_id': vim_id,
'count': count,
'timeout': timeout,
'interval': interval,
'targetip': targetip}
self.input_dict[self.resource] = self.input_dict_data
def monitor_ping_vim(self, vim_id=None, count=1, timeout=1,
interval=1, targetip="127.0.0.1"):
self._build_input(vim_id, count, timeout,
interval, targetip)
self.definition[self.wf_identifier]['tasks'] = dict()
self.definition[self.wf_identifier]['tasks'].update(
self._add_ping_vim_tasks())

View File

@ -85,7 +85,6 @@ class VIMCreateTestCase(base.TestCase):
]
},
'shared': False,
'status': 'PENDING',
'tenant_id': 'test-project',
'type': 'openstack',
'updated_at': None,

View File

@ -1,24 +0,0 @@
# Copyright (C) 2021 FUJITSU
# 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.
from tacker.conductor.conductorrpc import vim_monitor_rpc
from tacker.tests.unit import base as unit_base
class TestVIMUpdateRPC(unit_base.TestCase):
def setUp(self):
super(TestVIMUpdateRPC, self).setUp()
self.vimupdaterpc_object = vim_monitor_rpc.VIMUpdateRPC()

View File

@ -3497,12 +3497,6 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
self.vnfd_pkg_data,
vnfd_id)
def test_update_vim(self):
vim_id = uuidsentinel.vim_id
status = "REACHABLE"
result = self.conductor.update_vim(self.context, vim_id, status)
self.assertEqual(result, "REACHABLE")
@mock.patch.object(csar_utils, 'load_csar_data')
@mock.patch.object(glance_store, 'load_csar')
@mock.patch.object(glance_store, 'delete_csar')

View File

@ -480,9 +480,6 @@ class TestNfvoPlugin(db_base.SqlTestCase):
).start()
mock.patch('tacker.nfvo.nfvo_plugin.NfvoPlugin.get_auth_dict'
).start()
mock.patch('tacker.nfvo.workflows.vim_monitor.vim_monitor_utils.'
'delete_vim_monitor'
).start()
self._cos_db_plugin =\
common_services_db_plugin.CommonServicesPluginDb()
self.nfvo_plugin.delete_vim(self.context, vim_id)

View File

@ -137,7 +137,6 @@ vim_data = {
'description': "test_description",
'placement_attr': "test_placement_attr",
'shared': 0,
'status': "REACHABLE",
'is_default': 0
}

View File

@ -158,7 +158,7 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
vnfs = self.get_vnfs(context)
for vnf in vnfs:
# Add tenant_id in context object as it is required
# to get VIM in monitoring.
# to get VNF in monitoring.
context.tenant_id = vnf['tenant_id']
self.add_vnf_to_monitor(context, vnf)