Improve plugin flexibility

The monitoring plugin such as prometheus plugin or
fault notification have been modified
to be replaceable according to the configuration.

Therefore, operators can use their original monitoring
functions without changing tacker source code.

Implements: blueprint support-auto-lcm
Implements: blueprint support-autoheal-queue
Change-Id: Ifcdf12c4be2d307c78b38703fe6db4e5aac236ea
changes/08/861808/6
Koji Shimizu 4 months ago
parent a97899864c
commit c297b4300d

@ -118,17 +118,17 @@ The ``additionalParams`` must be set when using FaultNotification.
- Cardinality
- Description
* - additionalParams
- 0..1
- KeyValuePairs (inlined)
- 0..1
- Additional input parameters for the instantiation process,
specific to the VNF being instantiated.
* - >ServerNotifierUri
- 1
- String
- 1
- Base Uri for ServerNotifier.
* - >ServerNotifierFaultID
- 1..N
- String
- 1..N
- List of string that indicates which type of alarms to detect.
The value of ``ServerNotifierUri`` and ``ServerNotifierFaultID`` are stored
@ -162,6 +162,28 @@ whether AutoHealing should be performed. In case of performing
AutoHealing, VMs are deleted and created via Heat. The client is
no need to handle healing.
Using Vendor Specific Plugin
----------------------------
ServerNotification plugin can be replaced with a vendor specific function.
To replace a plugin, change the configurations below.
The replaced class must be a subclass of
tacker.sol_refactored.common.monitoring_plugin_base.MonitoringPlugin.
.. list-table::
:header-rows: 1
:widths: 40 40 40
* - Configuration
- Default
- Description
* - ``CONF.server_notification.server_notification_package``
- tacker.sol_refactored.common.server_notification
- Package name for server notification.
* - ``CONF.server_notification.server_notification_class``
- ServerNotification
- Class name for server notification.
References
==========

@ -334,3 +334,37 @@ rule file directly. Below is example of alert rule.
auto_scale_type: SCALE_OUT,
aspect_id: VDU1_aspect
annotations:
Using Vendor Specific Plugin
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prometheus Plugin can be replaced with a vendor specific function.
To replace a plugin, change the configurations below.
The replaced class must be a subclass of
tacker.sol_refactored.common.monitoring_plugin_base.MonitoringPlugin.
.. list-table::
:header-rows: 1
:widths: 40 40 40
* - Configuration
- Default
- Description
* - ``CONF.prometheus_plugin.performance_management_package``
- tacker.sol_refactored.common.prometheus_plugin
- Package name for performance management.
* - ``CONF.prometheus_plugin.performance_management_class``
- PrometheusPluginPm
- Class name for performance management.
* - ``CONF.prometheus_plugin.fault_management_package``
- tacker.sol_refactored.common.prometheus_plugin
- Package name for fault management.
* - ``CONF.prometheus_plugin.fault_management_class``
- PrometheusPluginFm
- Class name for fault management.
* - ``CONF.prometheus_plugin.auto_scaling_package``
- tacker.sol_refactored.common.prometheus_plugin
- Package name for auto scaling.
* - ``CONF.prometheus_plugin.auto_scaling_class``
- PrometheusPluginAutoScaling
- Class name for auto scaling.

@ -116,18 +116,51 @@ PROMETHEUS_PLUGIN_OPTS = [
cfg.BoolOpt('performance_management',
default=False,
help=_('Enable prometheus plugin performance management')),
cfg.IntOpt('reporting_period_margin',
default=1,
help=_('Some margin time for PM jos\'s reportingPeriod')),
cfg.BoolOpt('fault_management',
default=False,
help=_('Enable prometheus plugin fault management')),
cfg.BoolOpt('auto_scaling',
default=False,
help=_('Enable prometheus plugin autoscaling')),
cfg.StrOpt('performance_management_package',
default='tacker.sol_refactored.common.prometheus_plugin',
help=_('Package name for performance management. '
'This configuration is changed in case of replacing '
'the original function with a vendor specific '
'function.')),
cfg.StrOpt('performance_management_class',
default='PrometheusPluginPm',
help=_('Class name for performance management. '
'This configuration is changed in case of replacing '
'the original function with a vendor specific '
'function.')),
cfg.StrOpt('fault_management_package',
default='tacker.sol_refactored.common.prometheus_plugin',
help=_('Package name for fault management. '
'This configuration is changed in case of replacing '
'the original function with a vendor specific '
'function.')),
cfg.StrOpt('fault_management_class',
default='PrometheusPluginFm',
help=_('Class name for fault management. '
'This configuration is changed in case of replacing '
'the original function with a vendor specific '
'function.')),
cfg.StrOpt('auto_scaling_package',
default='tacker.sol_refactored.common.prometheus_plugin',
help=_('Package name for auto scaling. '
'This configuration is changed in case of replacing '
'the original function with a vendor specific '
'function.')),
cfg.StrOpt('auto_scaling_class',
default='PrometheusPluginAutoScaling',
help=_('Class name for auto scaling. '
'This configuration is changed in case of replacing '
'the original function with a vendor specific '
'function.')),
]
CONF.register_opts(PROMETHEUS_PLUGIN_OPTS, 'prometheus_plugin')
@ -136,7 +169,6 @@ SERVER_NOTIFICATION_OPTS = [
cfg.BoolOpt('server_notification',
default=False,
help=_('Enable server notification autohealing')),
cfg.StrOpt('uri_path_prefix',
default='/server_notification',
help=_('Uri path prefix string for server notification. '
@ -147,6 +179,18 @@ SERVER_NOTIFICATION_OPTS = [
default=20,
help=_('Timeout (second) of packing for multiple '
'server notification.')),
cfg.StrOpt('server_notification_package',
default='tacker.sol_refactored.common.server_notification',
help=_('Package name for server notification. '
'This configuration is changed in case of replacing '
'the original function with a vendor specific '
'function.')),
cfg.StrOpt('server_notification_class',
default='ServerNotification',
help=_('Class name for server notification. '
'This configuration is changed in case of replacing '
'the original function with a vendor specific '
'function.')),
]
CONF.register_opts(SERVER_NOTIFICATION_OPTS, 'server_notification')

@ -416,6 +416,11 @@ class ResourcesOtherOperationInProgress(SolHttpError409):
"is in progress.")
# plugin base
class MonitoringPluginClassError(SolHttpError503):
message = _("%(class_name)s is not a subclass of MonitoringPlugin.")
# prometheus plugin
class PrometheusPluginNotEnabled(SolHttpError404):
message = _("%(name)s API is not enabled.")

@ -14,29 +14,20 @@
# under the License.
from importlib import import_module
from oslo_log import log as logging
module_and_class = {
'stub':
('tacker.sol_refactored.common.monitoring_plugin_base',
'MonitoringPluginStub'),
'pm_event':
('tacker.sol_refactored.common.prometheus_plugin',
'PrometheusPluginPm'),
'alert':
('tacker.sol_refactored.common.prometheus_plugin',
'PrometheusPluginFm'),
'auto_healing':
('tacker.sol_refactored.common.prometheus_plugin',
'PrometheusPluginAutoScaling'),
'server_notification':
('tacker.sol_refactored.common.server_notification',
'ServerNotification'),
}
from tacker.sol_refactored.common import exceptions as sol_ex
LOG = logging.getLogger(__name__)
def get_class(short_name):
module = import_module(module_and_class[short_name][0])
return getattr(module, module_and_class[short_name][1])
def get_class(package_name, class_name):
module = import_module(package_name)
_class = getattr(module, class_name)
if not issubclass(_class, MonitoringPlugin):
LOG.error(f"Loading plugin failed: {package_name}.{class_name}.")
raise sol_ex.MonitoringPluginClassError(class_name=class_name)
return _class
class MonitoringPlugin():

@ -398,7 +398,7 @@ class PrometheusPluginPm(PrometheusPlugin, mon_base.MonitoringPlugin):
collection_period))
return rules
def get_compute_resouce_by_sub_obj(self, vnf_instance, sub_obj):
def get_compute_resource_by_sub_obj(self, vnf_instance, sub_obj):
inst = vnf_instance
if (not inst.obj_attr_is_set('instantiatedVnfInfo') or
not inst.instantiatedVnfInfo.obj_attr_is_set(
@ -440,7 +440,7 @@ class PrometheusPluginPm(PrometheusPlugin, mon_base.MonitoringPlugin):
# resource id is like 'test-test1-756757f8f-xcwmt'
# obtain 'test-test1' as deployment
# obtain 'test' as container
compute_resource = self.get_compute_resouce_by_sub_obj(
compute_resource = self.get_compute_resource_by_sub_obj(
inst, sub_obj)
if not compute_resource:
continue

@ -26,7 +26,9 @@ class PmEventController(prom_wsgi.PrometheusPluginAPIController):
if not CONF.prometheus_plugin.performance_management:
raise sol_ex.PrometheusPluginNotEnabled(
name='Performance management')
cls = mon_base.get_class('pm_event')
cls = mon_base.get_class(
CONF.prometheus_plugin.performance_management_package,
CONF.prometheus_plugin.performance_management_class)
mon_base.MonitoringPlugin.get_instance(cls).alert(
request=request, body=body)
return prom_wsgi.PrometheusPluginResponse(204, None)
@ -37,7 +39,9 @@ class FmAlertController(prom_wsgi.PrometheusPluginAPIController):
if not CONF.prometheus_plugin.fault_management:
raise sol_ex.PrometheusPluginNotEnabled(
name='Fault management')
cls = mon_base.get_class('alert')
cls = mon_base.get_class(
CONF.prometheus_plugin.fault_management_package,
CONF.prometheus_plugin.fault_management_class)
mon_base.MonitoringPlugin.get_instance(cls).alert(
request=request, body=body)
return prom_wsgi.PrometheusPluginResponse(204, None)
@ -48,7 +52,9 @@ class AutoScalingController(prom_wsgi.PrometheusPluginAPIController):
if not CONF.prometheus_plugin.auto_scaling:
raise sol_ex.PrometheusPluginNotEnabled(
name='Auto scaling')
cls = mon_base.get_class('auto_healing')
cls = mon_base.get_class(
CONF.prometheus_plugin.auto_scaling_package,
CONF.prometheus_plugin.auto_scaling_class)
mon_base.MonitoringPlugin.get_instance(cls).alert(
request=request, body=body)
return prom_wsgi.PrometheusPluginResponse(204, None)

@ -25,7 +25,9 @@ class ServerNotificationController(sn_wsgi.ServerNotificationAPIController):
def notify(self, request, vnf_instance_id, server_id, body):
if not CONF.server_notification.server_notification:
raise sol_ex.ServerNotificationNotEnabled()
cls = mon_base.get_class('server_notification')
cls = mon_base.get_class(
CONF.server_notification.server_notification_package,
CONF.server_notification.server_notification_class)
mon_base.MonitoringPlugin.get_instance(cls).alert(
request=request, vnf_instance_id=vnf_instance_id,
server_id=server_id, body=body)

@ -116,7 +116,9 @@ class VnfPmControllerV2(sol_wsgi.SolAPIController):
self.nfvo_client = nfvo_client.NfvoClient()
self.endpoint = CONF.v2_vnfm.endpoint
self._pm_job_view = vnfpm_view.PmJobViewBuilder(self.endpoint)
cls = plugin.get_class('pm_event')
cls = plugin.get_class(
CONF.prometheus_plugin.performance_management_package,
CONF.prometheus_plugin.performance_management_class)
self.plugin = plugin.MonitoringPlugin.get_instance(cls)
@validator.schema(schema.CreatePmJobRequest_V210, '2.1.0')

@ -147,8 +147,6 @@ class ServerNotificationTest(test_vnflcm_basic_common.CommonVnfLcmTest):
# Test notification
self.assert_notification_get(callback_url)
# check usageState of VNF Package
self._check_package_usage(is_nfvo, self.svn_pkg)
# 1. LCM-Create
# ETSI NFV SOL003 v3.3.1 5.5.2.2 VnfInstance

@ -463,7 +463,7 @@ class TestPrometheusPluginPm(base.TestCase):
group='prometheus_plugin', performance_management=True)
pp = mon_base.MonitoringPlugin.get_instance(
prometheus_plugin.PrometheusPluginPm)
# noromal
# normal
job = objects.PmJobV2.from_dict(_pm_job)
pp.delete_job(context=self.context, pm_job=job)
# error

@ -124,7 +124,7 @@ class TestPrometheusPlugin(db_base.SqlTestCase):
self.conductor = conductor_v2.ConductorV2()
@mock.patch.object(http_client.HttpClient, 'do_request')
def test_requst_scale(self, mock_do_request):
def test_request_scale(self, mock_do_request):
resp = webob.Response()
resp.status_code = 202
mock_do_request.return_value = resp, {}

@ -145,7 +145,7 @@ _body_scale_alert1 = {
'fingerprint': '5ef77f1f8a3ecb8d'
}
# fuction_type mismatch
# function_type mismatch
_body_scale_alert2 = copy.deepcopy(_body_scale_alert1)
_body_scale_alert2['labels']['function_type'] = 'vnffm'

@ -18,6 +18,7 @@ from unittest import mock
from tacker import context
from tacker.sol_refactored.common import exceptions as sol_ex
from tacker.sol_refactored.common import monitoring_plugin_base as mon_base
from tacker.sol_refactored.common import server_notification as sn_common
from tacker.sol_refactored.common import vnf_instance_utils as inst_utils
from tacker.sol_refactored.controller import server_notification
@ -77,6 +78,31 @@ _body2 = {
'error_schema': {}
}
pkg = 'tacker.tests.unit.sol_refactored.controller.test_server_notification'
class VendorSpecificMonitoringPlugin(mon_base.MonitoringPlugin):
_instance = None
@staticmethod
def instance():
if not VendorSpecificMonitoringPlugin._instance:
VendorSpecificMonitoringPlugin()
return VendorSpecificMonitoringPlugin._instance
def __init__(self):
if VendorSpecificMonitoringPlugin._instance:
raise SystemError(
"Not constructor but instance() should be used.")
VendorSpecificMonitoringPlugin._instance = self
def alert(self, **kwargs):
pass
class NotASubClassOfMonitoringPlugin():
pass
class TestServerNotification(base.TestCase):
def setUp(self):
@ -105,8 +131,7 @@ class TestServerNotification(base.TestCase):
server_id='test_server_id', body=_body)
@mock.patch.object(inst_utils, 'get_inst')
def test_notify(self,
mock_inst):
def test_notify(self, mock_inst):
self.config_fixture.config(
group='server_notification', server_notification=True)
mock_inst.return_value = objects.VnfInstanceV2.from_dict(_inst1)
@ -168,3 +193,30 @@ class TestServerNotification(base.TestCase):
self.controller.notify, request=self.request,
vnf_instance_id='test_id',
server_id='test_server_id', body=_body)
def test_vendor_specific_plugin(self):
self.config_fixture.config(
group='server_notification', server_notification=True)
self.config_fixture.config(
group='server_notification', server_notification_package=pkg)
self.config_fixture.config(
group='server_notification',
server_notification_class='VendorSpecificMonitoringPlugin')
response = self.controller.notify(
request=self.request,
vnf_instance_id='test_id',
server_id='test_server_id', body=_body)
self.assertEqual(204, response.status)
def test_vendor_specific_plugin_subclass(self):
self.config_fixture.config(
group='server_notification', server_notification=True)
self.config_fixture.config(
group='server_notification', server_notification_package=pkg)
self.config_fixture.config(
group='server_notification',
server_notification_class='NotASubClassOfMonitoringPlugin')
self.assertRaises(
sol_ex.MonitoringPluginClassError, self.controller.notify,
request=self.request, vnf_instance_id='test_id',
server_id='test_server_id', body=_body)

Loading…
Cancel
Save