Refactor: separating backend actions out from monitor
Currently, backend actions are tightly coupled with monitor module. This is like a barrier when we have a various actions in the future. Also, it will be good for separating monitoring-related features out from tacker-server. This patch also proposes a policy action framework so that VNF operators can easily add their own actions. Change-Id: I6ad163f7435c3b778810f96c506c77298be0c53d Closes-bug: #1582446
This commit is contained in:
parent
aa36918f77
commit
829f50e915
|
@ -0,0 +1,91 @@
|
|||
Tacker Policy Framework
|
||||
=======================
|
||||
|
||||
This section will introduce framework for tacker policy actions.
|
||||
|
||||
* Introduction
|
||||
* How to write a new policy action
|
||||
* Event and Auditing support
|
||||
* How to combine policy actions with existing monitoring frameworks in Tacker
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Tacker policy actions framework provides the NFV operators and VNF vendors to
|
||||
write a pluggable action that manages their own VNFs. Currently Tacker
|
||||
already provided some common actions like autoscaling, respawning, and
|
||||
logging. With this framework the custom actions can be easily
|
||||
applied for the management purpose.
|
||||
|
||||
How to write a new policy action
|
||||
--------------------------------
|
||||
|
||||
A policy action for tacker is a python module which contains a class that
|
||||
inherits from
|
||||
"tacker.vnfm.policy_actions.abstract_action.AbstractPolicyAction". If the
|
||||
driver depends/imports more than one module, then create a new python package
|
||||
under tacker/vnfm/policy_actions folder. After this we have to mention our
|
||||
driver path in setup.cfg file in root directory.
|
||||
|
||||
For example:
|
||||
::
|
||||
|
||||
tacker.tacker.policy.actions =
|
||||
respawn = tacker.vnfm.policy_actions.respawn.respawn:VNFActionRespawn
|
||||
|
||||
Following methods need to be overridden in the new action:
|
||||
|
||||
``def get_type(self)``
|
||||
This method must return the type of action. ex: respawn
|
||||
|
||||
``def get_name(self)``
|
||||
This method must return the symbolic name of the vnf policy action.
|
||||
|
||||
``def get_description(self)``
|
||||
This method must return the description for the policy action.
|
||||
|
||||
``def execute_action(self, plugin, context, vnf, arguments)``
|
||||
This method must expose what will be executed with the policy action.
|
||||
'arguments' is used to add more options for policy actions. For example,
|
||||
if action is scaling, 'arguments' should let you know
|
||||
'scaling-out' or 'scaling-in' will be applied.
|
||||
|
||||
Event and Auditing support
|
||||
--------------------------
|
||||
|
||||
This function can be used to describe the execution process of policy.
|
||||
For example:
|
||||
::
|
||||
|
||||
_log_monitor_events(context, vnf_dict, "ActionRespawnHeat invoked")
|
||||
|
||||
|
||||
How to combine policy with existing monitoring framework in Tacker
|
||||
------------------------------------------------------------------
|
||||
|
||||
In the monitoring policy section, you can specify the monitors details with
|
||||
corresponding action.
|
||||
|
||||
The below example shows how policy is used for alarm monitor.
|
||||
Example Template
|
||||
----------------
|
||||
|
||||
::
|
||||
|
||||
policies:
|
||||
- vdu1_cpu_usage_monitoring_policy:
|
||||
type: tosca.policies.tacker.Alarming
|
||||
triggers:
|
||||
resize_compute:
|
||||
event_type:
|
||||
type: tosca.events.resource.utilization
|
||||
implementation: ceilometer
|
||||
metrics: cpu_util
|
||||
condition:
|
||||
threshold: 50
|
||||
constraint: utilization greater_than 50%
|
||||
period: 65
|
||||
evaluations: 1
|
||||
method: avg
|
||||
comparison_operator: gt
|
||||
actions: [respawn]
|
|
@ -13,6 +13,9 @@ namespace = tacker.vnfm.mgmt_drivers.openwrt.openwrt
|
|||
namespace = tacker.vnfm.monitor_drivers.http_ping.http_ping
|
||||
namespace = tacker.vnfm.monitor_drivers.ping.ping
|
||||
namespace = tacker.vnfm.monitor_drivers.ceilometer.ceilometer
|
||||
namespace = tacker.tacker.policy_actions.autoscaling.autoscaling
|
||||
namespace = tacker.tacker.policy_actions.respawn.respawn
|
||||
namespace = tacker.tacker.policy_actions.log.log
|
||||
namespace = tacker.alarm_receiver
|
||||
namespace = keystonemiddleware.auth_token
|
||||
namespace = oslo.middleware
|
||||
|
|
|
@ -59,6 +59,11 @@ tacker.tacker.monitor.drivers =
|
|||
http_ping = tacker.vnfm.monitor_drivers.http_ping.http_ping:VNFMonitorHTTPPing
|
||||
tacker.tacker.alarm_monitor.drivers =
|
||||
ceilometer = tacker.vnfm.monitor_drivers.ceilometer.ceilometer:VNFMonitorCeilometer
|
||||
tacker.tacker.policy.actions =
|
||||
autoscaling = tacker.vnfm.policy_actions.autoscaling.autoscaling:VNFActionAutoscaling
|
||||
respawn = tacker.vnfm.policy_actions.respawn.respawn:VNFActionRespawn
|
||||
log_only = tacker.vnfm.policy_actions.log.log:VNFActionLogOnly
|
||||
log_and_kill = tacker.vnfm.policy_actions.log.log:VNFActionLogAndKill
|
||||
oslo.config.opts =
|
||||
tacker.common.config = tacker.common.config:config_opts
|
||||
tacker.wsgi = tacker.wsgi:config_opts
|
||||
|
|
|
@ -15,7 +15,7 @@ DEFAULT_ALARM_ACTIONS = ['respawn', 'log', 'log_and_kill', 'notify']
|
|||
VNF_CIRROS_CREATE_TIMEOUT = 300
|
||||
VNFC_CREATE_TIMEOUT = 600
|
||||
VNF_CIRROS_DELETE_TIMEOUT = 300
|
||||
VNF_CIRROS_DEAD_TIMEOUT = 250
|
||||
VNF_CIRROS_DEAD_TIMEOUT = 500
|
||||
ACTIVE_SLEEP_TIME = 3
|
||||
DEAD_SLEEP_TIME = 1
|
||||
SCALE_WINDOW_SLEEP_TIME = 120
|
||||
|
|
|
@ -63,7 +63,7 @@ topology_template:
|
|||
type: tosca.nodes.nfv.VDU.Tacker
|
||||
properties:
|
||||
image: cirros-0.3.5-x86_64-disk
|
||||
flavor: m1.medium
|
||||
flavor: m1.tiny
|
||||
availability_zone: nova
|
||||
mgmt_driver: noop
|
||||
config: |
|
||||
|
|
|
@ -434,33 +434,20 @@ class TestVNFMPlugin(db_base.SqlTestCase):
|
|||
self.assertEqual(expected_result, trigger_result)
|
||||
|
||||
@patch('tacker.db.vnfm.vnfm_db.VNFMPluginDb.get_vnf')
|
||||
@patch('tacker.vnfm.monitor.ActionPolicy.get_policy')
|
||||
def test_create_vnf_trigger_respawn(self, mock_get_policy, mock_get_vnf):
|
||||
def test_create_vnf_trigger_respawn(self, mock_get_vnf):
|
||||
dummy_vnf = self._get_dummy_active_vnf(
|
||||
utils.vnfd_alarm_respawn_tosca_template)
|
||||
mock_get_vnf.return_value = dummy_vnf
|
||||
mock_action_class = mock.Mock()
|
||||
mock_get_policy.return_value = mock_action_class
|
||||
self._test_create_vnf_trigger(policy_name="vdu_hcpu_usage_respawning",
|
||||
action_value="respawn")
|
||||
mock_get_policy.assert_called_once_with('respawn', 'test_vim')
|
||||
mock_action_class.execute_action.assert_called_once_with(
|
||||
self.vnfm_plugin, dummy_vnf)
|
||||
|
||||
@patch('tacker.db.vnfm.vnfm_db.VNFMPluginDb.get_vnf')
|
||||
@patch('tacker.vnfm.monitor.ActionPolicy.get_policy')
|
||||
def test_create_vnf_trigger_scale(self, mock_get_policy, mock_get_vnf):
|
||||
def test_create_vnf_trigger_scale(self, mock_get_vnf):
|
||||
dummy_vnf = self._get_dummy_active_vnf(
|
||||
utils.vnfd_alarm_scale_tosca_template)
|
||||
mock_get_vnf.return_value = dummy_vnf
|
||||
mock_action_class = mock.Mock()
|
||||
mock_get_policy.return_value = mock_action_class
|
||||
scale_body = {'scale': {'policy': 'SP1', 'type': 'out'}}
|
||||
self._test_create_vnf_trigger(policy_name="vdu_hcpu_usage_scaling_out",
|
||||
action_value="SP1-out")
|
||||
mock_get_policy.assert_called_once_with('scaling', 'test_vim')
|
||||
mock_action_class.execute_action.assert_called_once_with(
|
||||
self.vnfm_plugin, dummy_vnf, scale_body)
|
||||
|
||||
@patch('tacker.db.vnfm.vnfm_db.VNFMPluginDb.get_vnf')
|
||||
def test_get_vnf_policies(self, mock_get_vnf):
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import abc
|
||||
|
||||
import inspect
|
||||
import threading
|
||||
import time
|
||||
|
@ -23,14 +23,12 @@ from oslo_config import cfg
|
|||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
|
||||
|
||||
from tacker.common import driver_manager
|
||||
from tacker import context as t_context
|
||||
from tacker.db.common_services import common_services_db
|
||||
from tacker.plugins.common import constants
|
||||
from tacker.vnfm.infra_drivers.openstack import heat_client as hc
|
||||
from tacker.vnfm import vim_client
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
|
@ -281,126 +279,3 @@ class VNFAlarmMonitor(object):
|
|||
def process_alarm(self, driver, vnf_dict, kwargs):
|
||||
return self._invoke(driver,
|
||||
vnf=vnf_dict, kwargs=kwargs)
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class ActionPolicy(object):
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def execute_action(cls, plugin, vnf_dict):
|
||||
pass
|
||||
|
||||
_POLICIES = {}
|
||||
|
||||
@staticmethod
|
||||
def register(policy, infra_driver=None):
|
||||
def _register(cls):
|
||||
cls._POLICIES.setdefault(policy, {})[infra_driver] = cls
|
||||
return cls
|
||||
return _register
|
||||
|
||||
@classmethod
|
||||
def get_policy(cls, policy, infra_driver=None):
|
||||
action_clses = cls._POLICIES.get(policy)
|
||||
if not action_clses:
|
||||
return None
|
||||
cls = action_clses.get(infra_driver)
|
||||
if cls:
|
||||
return cls
|
||||
return action_clses.get(None)
|
||||
|
||||
@classmethod
|
||||
def get_supported_actions(cls):
|
||||
return cls._POLICIES.keys()
|
||||
|
||||
|
||||
@ActionPolicy.register('respawn', 'openstack')
|
||||
class ActionRespawnHeat(ActionPolicy):
|
||||
@classmethod
|
||||
def execute_action(cls, plugin, vnf_dict):
|
||||
vnf_id = vnf_dict['id']
|
||||
LOG.info(_('vnf %s is dead and needs to be respawned'), vnf_id)
|
||||
attributes = vnf_dict['attributes']
|
||||
vim_id = vnf_dict['vim_id']
|
||||
# TODO(anyone) set the current request ctxt
|
||||
context = t_context.get_admin_context()
|
||||
|
||||
def _update_failure_count():
|
||||
failure_count = int(attributes.get('failure_count', '0')) + 1
|
||||
failure_count_str = str(failure_count)
|
||||
LOG.debug(_("vnf %(vnf_id)s failure count %(failure_count)s"),
|
||||
{'vnf_id': vnf_id, 'failure_count': failure_count_str})
|
||||
attributes['failure_count'] = failure_count_str
|
||||
attributes['dead_instance_id_' + failure_count_str] = vnf_dict[
|
||||
'instance_id']
|
||||
|
||||
def _fetch_vim(vim_uuid):
|
||||
return vim_client.VimClient().get_vim(context, vim_uuid)
|
||||
|
||||
def _delete_heat_stack(vim_auth):
|
||||
placement_attr = vnf_dict.get('placement_attr', {})
|
||||
region_name = placement_attr.get('region_name')
|
||||
heatclient = hc.HeatClient(auth_attr=vim_auth,
|
||||
region_name=region_name)
|
||||
heatclient.delete(vnf_dict['instance_id'])
|
||||
LOG.debug(_("Heat stack %s delete initiated"), vnf_dict[
|
||||
'instance_id'])
|
||||
_log_monitor_events(context, vnf_dict, "ActionRespawnHeat invoked")
|
||||
|
||||
def _respin_vnf():
|
||||
update_vnf_dict = plugin.create_vnf_sync(context, vnf_dict)
|
||||
LOG.info(_('respawned new vnf %s'), update_vnf_dict['id'])
|
||||
plugin.config_vnf(context, update_vnf_dict)
|
||||
return update_vnf_dict
|
||||
|
||||
if plugin._mark_vnf_dead(vnf_dict['id']):
|
||||
_update_failure_count()
|
||||
vim_res = _fetch_vim(vim_id)
|
||||
if vnf_dict['attributes'].get('monitoring_policy'):
|
||||
plugin._vnf_monitor.mark_dead(vnf_dict['id'])
|
||||
_delete_heat_stack(vim_res['vim_auth'])
|
||||
updated_vnf = _respin_vnf()
|
||||
plugin.add_vnf_to_monitor(updated_vnf, vim_res['vim_type'])
|
||||
LOG.debug(_("VNF %s added to monitor thread"), updated_vnf[
|
||||
'id'])
|
||||
if vnf_dict['attributes'].get('alarming_policy'):
|
||||
_delete_heat_stack(vim_res['vim_auth'])
|
||||
vnf_dict['attributes'].pop('alarming_policy')
|
||||
_respin_vnf()
|
||||
|
||||
|
||||
@ActionPolicy.register('scaling')
|
||||
class ActionAutoscalingHeat(ActionPolicy):
|
||||
@classmethod
|
||||
def execute_action(cls, plugin, vnf_dict, scale):
|
||||
vnf_id = vnf_dict['id']
|
||||
_log_monitor_events(t_context.get_admin_context(),
|
||||
vnf_dict,
|
||||
"ActionAutoscalingHeat invoked")
|
||||
plugin.create_vnf_scale(t_context.get_admin_context(), vnf_id, scale)
|
||||
|
||||
|
||||
@ActionPolicy.register('log')
|
||||
class ActionLogOnly(ActionPolicy):
|
||||
@classmethod
|
||||
def execute_action(cls, plugin, vnf_dict):
|
||||
vnf_id = vnf_dict['id']
|
||||
LOG.error(_('vnf %s dead'), vnf_id)
|
||||
_log_monitor_events(t_context.get_admin_context(),
|
||||
vnf_dict,
|
||||
"ActionLogOnly invoked")
|
||||
|
||||
|
||||
@ActionPolicy.register('log_and_kill')
|
||||
class ActionLogAndKill(ActionPolicy):
|
||||
@classmethod
|
||||
def execute_action(cls, plugin, vnf_dict):
|
||||
_log_monitor_events(t_context.get_admin_context(),
|
||||
vnf_dict,
|
||||
"ActionLogAndKill invoked")
|
||||
vnf_id = vnf_dict['id']
|
||||
if plugin._mark_vnf_dead(vnf_dict['id']):
|
||||
if vnf_dict['attributes'].get('monitoring_policy'):
|
||||
plugin._vnf_monitor.mark_dead(vnf_dict['id'])
|
||||
plugin.delete_vnf(t_context.get_admin_context(), vnf_id)
|
||||
LOG.error(_('vnf %s dead'), vnf_id)
|
||||
|
|
|
@ -43,7 +43,8 @@ CONF = cfg.CONF
|
|||
|
||||
def config_opts():
|
||||
return [('tacker', VNFMMgmtMixin.OPTS),
|
||||
('tacker', VNFMPlugin.OPTS)]
|
||||
('tacker', VNFMPlugin.OPTS_INFRA_DRIVER),
|
||||
('tacker', VNFMPlugin.OPTS_POLICY_ACTION)]
|
||||
|
||||
|
||||
class VNFMMgmtMixin(object):
|
||||
|
@ -111,12 +112,21 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
|
|||
|
||||
Plugin which supports Tacker framework
|
||||
"""
|
||||
OPTS = [
|
||||
OPTS_INFRA_DRIVER = [
|
||||
cfg.ListOpt(
|
||||
'infra_driver', default=['noop', 'openstack'],
|
||||
help=_('Hosting vnf drivers tacker plugin will use')),
|
||||
]
|
||||
cfg.CONF.register_opts(OPTS, 'tacker')
|
||||
cfg.CONF.register_opts(OPTS_INFRA_DRIVER, 'tacker')
|
||||
|
||||
OPTS_POLICY_ACTION = [
|
||||
cfg.ListOpt(
|
||||
'policy_action', default=['autoscaling', 'respawn',
|
||||
'log_only', 'log_and_kill'],
|
||||
help=_('Hosting vnf drivers tacker plugin will use')),
|
||||
]
|
||||
cfg.CONF.register_opts(OPTS_POLICY_ACTION, 'tacker')
|
||||
|
||||
supported_extension_aliases = ['vnfm']
|
||||
|
||||
def __init__(self):
|
||||
|
@ -127,6 +137,9 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
|
|||
self._vnf_manager = driver_manager.DriverManager(
|
||||
'tacker.tacker.vnfm.drivers',
|
||||
cfg.CONF.tacker.infra_driver)
|
||||
self._vnf_action = driver_manager.DriverManager(
|
||||
'tacker.tacker.policy.actions',
|
||||
cfg.CONF.tacker.policy_action)
|
||||
self._vnf_monitor = monitor.VNFMonitor(self.boot_wait)
|
||||
self._vnf_alarm_monitor = monitor.VNFAlarmMonitor()
|
||||
|
||||
|
@ -203,15 +216,15 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
|
|||
tosca)
|
||||
LOG.debug(_('vnfd %s'), vnfd)
|
||||
|
||||
def add_vnf_to_monitor(self, vnf_dict, infra_driver):
|
||||
def add_vnf_to_monitor(self, context, vnf_dict):
|
||||
dev_attrs = vnf_dict['attributes']
|
||||
mgmt_url = vnf_dict['mgmt_url']
|
||||
if 'monitoring_policy' in dev_attrs and mgmt_url:
|
||||
def action_cb(action):
|
||||
action_cls = monitor.ActionPolicy.get_policy(action,
|
||||
infra_driver)
|
||||
if action_cls:
|
||||
action_cls.execute_action(self, hosting_vnf['vnf'])
|
||||
LOG.debug('policy action: %s', action)
|
||||
self._vnf_action.invoke(
|
||||
action, 'execute_action', plugin=self, context=context,
|
||||
vnf_dict=hosting_vnf['vnf'], args={})
|
||||
|
||||
hosting_vnf = self._vnf_monitor.to_hosting_vnf(
|
||||
vnf_dict, action_cb)
|
||||
|
@ -376,7 +389,7 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
|
|||
def create_vnf_wait():
|
||||
self._create_vnf_wait(context, vnf_dict, vim_auth, infra_driver)
|
||||
if vnf_dict['status'] is not constants.ERROR:
|
||||
self.add_vnf_to_monitor(vnf_dict, infra_driver)
|
||||
self.add_vnf_to_monitor(context, vnf_dict)
|
||||
self.config_vnf(context, vnf_dict)
|
||||
self.spawn_n(create_vnf_wait)
|
||||
return vnf_dict
|
||||
|
@ -760,11 +773,9 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
|
|||
if trigger['action_name'] in constants.DEFAULT_ALARM_ACTIONS:
|
||||
action = trigger['action_name']
|
||||
LOG.debug(_('vnf for monitoring: %s'), vnf_dict)
|
||||
infra_driver, vim_auth = self._get_infra_driver(context, vnf_dict)
|
||||
action_cls = monitor.ActionPolicy.get_policy(action,
|
||||
infra_driver)
|
||||
if action_cls:
|
||||
action_cls.execute_action(self, vnf_dict)
|
||||
self._vnf_action.invoke(
|
||||
action, 'execute_action', plugin=self, context=context,
|
||||
vnf_dict=vnf_dict, args={})
|
||||
|
||||
if trigger.get('bckend_policy'):
|
||||
bckend_policy = trigger['bckend_policy']
|
||||
|
@ -776,17 +787,14 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
|
|||
{"status": vnf_dict['status'],
|
||||
"vnfid": vnf_dict['id']})
|
||||
return
|
||||
action = 'scaling'
|
||||
action = 'autoscaling'
|
||||
scale = {}
|
||||
scale.setdefault('scale', {})
|
||||
scale['scale']['type'] = trigger['bckend_action']
|
||||
scale['scale']['policy'] = bckend_policy['name']
|
||||
infra_driver, vim_auth = self._get_infra_driver(context,
|
||||
vnf_dict)
|
||||
action_cls = monitor.ActionPolicy.get_policy(action,
|
||||
infra_driver)
|
||||
if action_cls:
|
||||
action_cls.execute_action(self, vnf_dict, scale)
|
||||
self._vnf_action.invoke(
|
||||
action, 'execute_action', plugin=self, context=context,
|
||||
vnf_dict=vnf_dict, args=scale)
|
||||
|
||||
def create_vnf_trigger(
|
||||
self, context, vnf_id, trigger):
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# 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.
|
||||
|
||||
import abc
|
||||
import six
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class AbstractPolicyAction(object):
|
||||
@abc.abstractmethod
|
||||
def get_type(self):
|
||||
"""Return one of predefined type of the hosting vnf drivers."""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_name(self):
|
||||
"""Return a symbolic name for the service VM plugin."""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_description(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def execute_action(self, plugin, context, vnf_dict, args):
|
||||
"""args: policy is enabled to execute with additional arguments."""
|
||||
pass
|
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
# 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 oslo_utils import timeutils
|
||||
|
||||
from tacker.db.common_services import common_services_db
|
||||
from tacker.plugins.common import constants
|
||||
from tacker.vnfm.policy_actions import abstract_action
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _log_monitor_events(context, vnf_dict, evt_details):
|
||||
_cos_db_plg = common_services_db.CommonServicesPluginDb()
|
||||
_cos_db_plg.create_event(context, res_id=vnf_dict['id'],
|
||||
res_type=constants.RES_TYPE_VNF,
|
||||
res_state=vnf_dict['status'],
|
||||
evt_type=constants.RES_EVT_MONITOR,
|
||||
tstamp=timeutils.utcnow(),
|
||||
details=evt_details)
|
||||
|
||||
|
||||
class VNFActionAutoscaling(abstract_action.AbstractPolicyAction):
|
||||
def get_type(self):
|
||||
return 'autoscaling'
|
||||
|
||||
def get_name(self):
|
||||
return 'autoscaling'
|
||||
|
||||
def get_description(self):
|
||||
return 'Tacker VNF auto-scaling policy'
|
||||
|
||||
def execute_action(self, plugin, context, vnf_dict, args):
|
||||
vnf_id = vnf_dict['id']
|
||||
_log_monitor_events(context,
|
||||
vnf_dict,
|
||||
"ActionAutoscalingHeat invoked")
|
||||
plugin.create_vnf_scale(context, vnf_id, args)
|
|
@ -0,0 +1,72 @@
|
|||
#
|
||||
# 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 oslo_utils import timeutils
|
||||
|
||||
from tacker.db.common_services import common_services_db
|
||||
from tacker.plugins.common import constants
|
||||
from tacker.vnfm.policy_actions import abstract_action
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _log_monitor_events(context, vnf_dict, evt_details):
|
||||
_cos_db_plg = common_services_db.CommonServicesPluginDb()
|
||||
_cos_db_plg.create_event(context, res_id=vnf_dict['id'],
|
||||
res_type=constants.RES_TYPE_VNF,
|
||||
res_state=vnf_dict['status'],
|
||||
evt_type=constants.RES_EVT_MONITOR,
|
||||
tstamp=timeutils.utcnow(),
|
||||
details=evt_details)
|
||||
|
||||
|
||||
class VNFActionLogOnly(abstract_action.AbstractPolicyAction):
|
||||
def get_type(self):
|
||||
return 'log_only'
|
||||
|
||||
def get_name(self):
|
||||
return 'log_only'
|
||||
|
||||
def get_description(self):
|
||||
return 'Tacker VNF logging policy'
|
||||
|
||||
def execute_action(self, plugin, context, vnf_dict, args):
|
||||
vnf_id = vnf_dict['id']
|
||||
LOG.error(_('vnf %s dead'), vnf_id)
|
||||
_log_monitor_events(context,
|
||||
vnf_dict,
|
||||
"ActionLogOnly invoked")
|
||||
|
||||
|
||||
class VNFActionLogAndKill(abstract_action.AbstractPolicyAction):
|
||||
def get_type(self):
|
||||
return 'log_and_kill'
|
||||
|
||||
def get_name(self):
|
||||
return 'log_and_kill'
|
||||
|
||||
def get_description(self):
|
||||
return 'Tacker VNF log_and_kill policy'
|
||||
|
||||
def execute_action(self, plugin, context, vnf_dict, args):
|
||||
_log_monitor_events(context,
|
||||
vnf_dict,
|
||||
"ActionLogAndKill invoked")
|
||||
vnf_id = vnf_dict['id']
|
||||
if plugin._mark_vnf_dead(vnf_dict['id']):
|
||||
if vnf_dict['attributes'].get('monitoring_policy'):
|
||||
plugin._vnf_monitor.mark_dead(vnf_dict['id'])
|
||||
plugin.delete_vnf(context, vnf_id)
|
||||
LOG.error(_('vnf %s dead'), vnf_id)
|
|
@ -0,0 +1,94 @@
|
|||
#
|
||||
# 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 oslo_utils import timeutils
|
||||
|
||||
from tacker.db.common_services import common_services_db
|
||||
from tacker.plugins.common import constants
|
||||
from tacker.vnfm.infra_drivers.openstack import heat_client as hc
|
||||
from tacker.vnfm.policy_actions import abstract_action
|
||||
from tacker.vnfm import vim_client
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _log_monitor_events(context, vnf_dict, evt_details):
|
||||
_cos_db_plg = common_services_db.CommonServicesPluginDb()
|
||||
_cos_db_plg.create_event(context, res_id=vnf_dict['id'],
|
||||
res_type=constants.RES_TYPE_VNF,
|
||||
res_state=vnf_dict['status'],
|
||||
evt_type=constants.RES_EVT_MONITOR,
|
||||
tstamp=timeutils.utcnow(),
|
||||
details=evt_details)
|
||||
|
||||
|
||||
class VNFActionRespawn(abstract_action.AbstractPolicyAction):
|
||||
def get_type(self):
|
||||
return 'respawn'
|
||||
|
||||
def get_name(self):
|
||||
return 'respawn'
|
||||
|
||||
def get_description(self):
|
||||
return 'Tacker VNF respawning policy'
|
||||
|
||||
def execute_action(self, plugin, context, vnf_dict, args):
|
||||
vnf_id = vnf_dict['id']
|
||||
LOG.info(_('vnf %s is dead and needs to be respawned'), vnf_id)
|
||||
attributes = vnf_dict['attributes']
|
||||
vim_id = vnf_dict['vim_id']
|
||||
|
||||
def _update_failure_count():
|
||||
failure_count = int(attributes.get('failure_count', '0')) + 1
|
||||
failure_count_str = str(failure_count)
|
||||
LOG.debug(_("vnf %(vnf_id)s failure count %(failure_count)s"),
|
||||
{'vnf_id': vnf_id, 'failure_count': failure_count_str})
|
||||
attributes['failure_count'] = failure_count_str
|
||||
attributes['dead_instance_id_' + failure_count_str] = vnf_dict[
|
||||
'instance_id']
|
||||
|
||||
def _fetch_vim(vim_uuid):
|
||||
return vim_client.VimClient().get_vim(context, vim_uuid)
|
||||
|
||||
def _delete_heat_stack(vim_auth):
|
||||
placement_attr = vnf_dict.get('placement_attr', {})
|
||||
region_name = placement_attr.get('region_name')
|
||||
heatclient = hc.HeatClient(auth_attr=vim_auth,
|
||||
region_name=region_name)
|
||||
heatclient.delete(vnf_dict['instance_id'])
|
||||
LOG.debug(_("Heat stack %s delete initiated"), vnf_dict[
|
||||
'instance_id'])
|
||||
_log_monitor_events(context, vnf_dict, "ActionRespawnHeat invoked")
|
||||
|
||||
def _respin_vnf():
|
||||
update_vnf_dict = plugin.create_vnf_sync(context, vnf_dict)
|
||||
LOG.info(_('respawned new vnf %s'), update_vnf_dict['id'])
|
||||
plugin.config_vnf(context, update_vnf_dict)
|
||||
return update_vnf_dict
|
||||
|
||||
if plugin._mark_vnf_dead(vnf_dict['id']):
|
||||
_update_failure_count()
|
||||
vim_res = _fetch_vim(vim_id)
|
||||
if vnf_dict['attributes'].get('monitoring_policy'):
|
||||
plugin._vnf_monitor.mark_dead(vnf_dict['id'])
|
||||
_delete_heat_stack(vim_res['vim_auth'])
|
||||
updated_vnf = _respin_vnf()
|
||||
plugin.add_vnf_to_monitor(context, updated_vnf)
|
||||
LOG.debug(_("VNF %s added to monitor thread"), updated_vnf[
|
||||
'id'])
|
||||
if vnf_dict['attributes'].get('alarming_policy'):
|
||||
_delete_heat_stack(vim_res['vim_auth'])
|
||||
vnf_dict['attributes'].pop('alarming_policy')
|
||||
_respin_vnf()
|
Loading…
Reference in New Issue