Merge "Zabbix Plugin for Application Monitoring in Tacker VNF Manager"

This commit is contained in:
Zuul 2018-01-03 07:16:48 +00:00 committed by Gerrit Code Review
commit 80b08ee08f
15 changed files with 1230 additions and 13 deletions

View File

@ -0,0 +1,193 @@
..
Copyright 2014-2017 OpenStack Foundation
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.
========================
How to use Zabbix Plugin
========================
This document explains how Tacker VNFM's Zabbix-plugin works with Zabbix
monitoring tool to provide application monitoring for VNF.
VNF application monitoring requires three pre-installation or configuration
settings. You do not have to do a lot of work or complex settings.
1. Zabbix-agent Installation and Setting in VNF.
Zabbix-Agent must be installed in the VNF. And you need to set it up. The
necessary settings must be made in /etc/zabbix/zabbix_agentd.conf in the
VNF. Installation and The setting method is as follows.
.. code-block:: console
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install zabbix-agent
sudo echo 'zabbix ALL=NOPASSWD: ALL' >> /etc/sudoers
Then open the /etc/zabbix/zabbix_agentd.conf file and write for Server,
ServerActive Hostname, EnableRemoteCommands. However, this approach is
more difficult to manage as the number of VNFs increases.
Therefore, to solve this problem, the method presented in this document
are as follows. After creating the VNF based on the TOSCA template,
the USER_DATA parameter is executed on the assumption that the VNF
is initialized. We can install and make the necessary settings
automatically. Here is an example of a User-data script.
.. code-block:: console
user_data: |
#!/bin/bash
sudo apt-get -y update
sudo apt-get -y upgrade
sudo apt-get -y install zabbix-agent
sudo sed -i "2s/.*/`ifconfig [Interface name in VNF] | grep ""\"inet addr:\"""| cut -d: -f2 | awk ""\"{ print $1 }\"""`/g" "/etc/hosts"
sudo sed -i "s/Bcast/`cat /etc/hostname`/g" "/etc/hosts"
sudo sed -i "3s/.*/[Zabbix Host IP Address]\tmonitor/g" "/etc/hosts"
sudo /etc/init.d/networking restart
sudo echo 'zabbix ALL=NOPASSWD: ALL' >> /etc/sudoers
sudo sed -i "s/# EnableRemoteCommands=0/EnableRemoteCommands=1/" "/etc/zabbix/zabbix_agentd.conf"
sudo sed -i "s/Server=127.0.0.1/Server=[Zabbix server's IP Address]/" "/etc/zabbix/zabbix_agentd.conf"
sudo sed -i "s/ServerActive=127.0.0.1/ServerActive=[Zabbix server's IP Address:Port]/" "/etc/zabbix/zabbix_agentd.conf"
sudo sed -i "s/Hostname=Zabbix server/Hostname=`cat /etc/hostname`/" "/etc/zabbix/zabbix_agentd.conf"
sudo service zabbix-agent restart
Use the sed command to modify the information in the conf file.
The basic network interface finds the IP address for ens3, sets it,
and sets the hostname. The zabbix user also needs permissions to run
the monitoring script. EnablRemoteCommands can be set to 1 to enable
execution of action commands created by Zabbix-Server.
2. Installing Zabbix Server
Because Zabbix Server requires a lot of processes for monitoring
projects, it is recommended to build it as a separate physical
node if performance stability is required. Installation instructions
for Zabbix Server are detailed in the manual provided by Zabbix.
Examples of installation procedures are based on Ubuntu16.04
and zabbix 3.2.
.. code-block:: console
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install php7.0* libapache2-mod-php7.0
sudo wget http://repo.zabbix.com/zabbix/3.2/ubuntu/pool/main/z/zabbix-release/zabbix-release_3.2-1+xenial_all.deb
sudo dpkg -i zabbix-release_3.2-1+xenial_all.deb
sudo apt-get install zabbix-server-mysql zabbix-frontend-php
Install mysql to store Zabbix-server and monitoring data and
necessary information, and install Zabbix-frotend-php to
provide web pages. Database creation is as follows.
.. code-block:: console
shell> mysql -uroot -p[ROOT_PASSWORD]
mysql> create database zabbix character set utf8 collate utf8_bin;
mysql> grant all privileges on zabbix.* to zabbix@localhost identified by '[PASSWORD]';
FLUSH PRIVILEGES;
mysql> quit;
cd /usr/share/doc/zabbix-server-mysql
zcat create.sql.gz | mysql -u root -p zabbix
We must modify the vi /etc/zabbix/zabbix_server.conf file to
provide the Zabbix-server.
.. code-block:: console
DBHost=localhost
DBName=[DBName]
DBUser=[DBUser]
DBPassword=[PASSWORD]
At the end of the next operation, we are now ready to use the
Zabbix-server to complete the finish operation.
.. code-block:: console
service zabbix-server start
update-rc.d zabbix-server enable
vi /etc/zabbix/apache.conf
=>php_value date.timezone [location/city]
service zabbix-server restart
service apache2 restart
This installation method is based on manual, but it includes
additional explanation and installation part of dependency
file installation.
3. Template
The following templates are used for application monitoring.
If we create a VNFD by creating the template below and use it
to create a VNF, we can monitor the application without any
additional steps. If we want automatic configuration, it is
recommended to use USER_DATA parameter.
If we enter Zabbix-related information in the template, you will
get a Token according to the internal workflow of Zabbix-plugin.
It it used to configure varitous monitoring functions.
.. code-block:: console
app_monitoring_policy:
name: zabbix
zabbix_username: [Zabbix user ID]
zabbix_password: [Zabbix user Password]
zabbix_server_ip: [Zabbix server IP]
zabbix_server_port: [Zabbix server Port]
parameters:
application:
app_name: [application-name]
app_port: [application-port]
ssh_username: [ssh username in VNF OS]
ssh_password: [ssh password in VNF OS]
app_status:
condition: [comparison,value]
actionname: [action name]
cmd-action: [Command to be executed in VNF]
app_memory:
condition: [comparison,value]
actionname: [action name]
cmd-action: [Command to be executed in VNF]
OS:
os_agent_info:
condition: [comparison,value]
actionname: [action name]
cmd-action: [Command to be executed in VNF]
os_proc_value:
condition: [comparison,value]
actionname: [action name]
cmd-action: [Command to be executed in VNF]
os_cpu_load:
condition: [comparison,value]
actionname: [action name]
cmd-action: [Command to be executed in VNF]
os_cpu_usage:
condition: [comparison,value]
actionname: [action name]
cmd-action: [Command to be executed in VNF]
4. Actions
Currently, only cmd is supported as an action function.
Respawn and Scale Action will be updated with additional
proposals and corresponding functionality as more template
definitions and corresponding additional functions are required.
References
==========
.. [#first] https://www.zabbix.com/documentation/3.2/manual

View File

@ -0,0 +1,4 @@
---
features:
- Added zabbix-pugin to monitor applications within VNF.

View File

@ -0,0 +1,136 @@
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
description: Monitoring for multiple vdus
metadata:
template_name: tosca-vnfd-monitoir-multi-vdu
topology_template:
node_templates:
VDU1:
type: tosca.nodes.nfv.VDU.Tacker
capabilities:
nfv_compute:
properties:
num_cpus: 2
mem_size: 2048 MB
disk_size: 15 GB
properties:
name: VDU1
image: ubuntu16.04
availability_zone: nova
mgmt_driver: noop
config: |
param0: key1
param1: key2
user_data_format: RAW
user_data: |
#!/bin/bash
sudo apt-get -y update
sudo apt-get -y upgrade
sudo apt-get -y install zabbix-agent
sudo apt-get -y install apache2
sudo sed -i "2s/.*/`ifconfig [Interface name in VNF] | grep ""\"inet addr:\"""| cut -d: -f2 | awk ""\"{ print $1 }\"""`/g" "/etc/hosts"
sudo sed -i "s/Bcast/`cat /etc/hostname`/g" "/etc/hosts"
sudo sed -i "3s/.*/[Zabbix Host IP Address]\tmonitor/g" "/etc/hosts"
sudo /etc/init.d/networking restart
sudo echo 'zabbix ALL=NOPASSWD: ALL' >> /etc/sudoers
sudo sed -i "s/# EnableRemoteCommands=0/EnableRemoteCommands=1/" "/etc/zabbix/zabbix_agentd.conf"
sudo sed -i "s/Server=127.0.0.1/Server=[Zabbix server's IP Address]/" "/etc/zabbix/zabbix_agentd.conf"
sudo sed -i "s/ServerActive=127.0.0.1/ServerActive=[Zabbix server's IP Address:Port]/" "/etc/zabbix/zabbix_agentd.conf"
sudo sed -i "s/Hostname=Zabbix server/Hostname=`cat /etc/hostname`/" "/etc/zabbix/zabbix_agentd.conf"
sudo service apache2 restart
sudo service zabbix-agent restart
sudo echo 'ubuntu:ubuntu' | chpasswd
sudo echo 'root:root' | chpasswd
app_monitoring_policy:
name: zabbix
zabbix_username: Admin
zabbix_password: zabbix
zabbix_server_ip: 192.168.11.53
zabbix_server_port: 80
parameters:
application:
app_name: apache2
app_port: 80
ssh_username: ubuntu
ssh_password: ubuntu
app_status:
condition: [down]
actionname: cmd
cmd-action: sudo service apache2 restart
app_memory:
condition: [greater,22]
actionname: cmd
cmd-action: sudo service apache2 stop
OS:
os_agent_info:
condition: [down]
actionname: cmd
cmd-action: sudo service zabbix-agent restart
os_proc_value:
condition: [and less,22]
actionname: cmd
cmd-action: sudo reboot
os_cpu_load:
condition: [and greater,30]
actionname: cmd
cmd-action: sudo reboot
os_cpu_usage:
condition: [less,30]
actionname: cmd
cmd-action: sudo reboot
CP11:
type: tosca.nodes.nfv.CP.Tacker
properties:
management: true
order: 0
anti_spoofing_protection: false
requirements:
- virtualLink:
node: VL1
- virtualBinding:
node: VDU1
CP12:
type: tosca.nodes.nfv.CP.Tacker
properties:
order: 1
anti_spoofing_protection: false
requirements:
- virtualLink:
node: VL2
- virtualBinding:
node: VDU1
CP13:
type: tosca.nodes.nfv.CP.Tacker
properties:
order: 2
anti_spoofing_protection: false
requirements:
- virtualLink:
node: VL3
- virtualBinding:
node: VDU1
VL1:
type: tosca.nodes.nfv.VL
properties:
network_name: net_mgmt
vendor: Tacker
VL2:
type: tosca.nodes.nfv.VL
properties:
network_name: net0
vendor: Tacker
VL3:
type: tosca.nodes.nfv.VL
properties:
network_name: net1
vendor: Tacker

View File

@ -59,6 +59,8 @@ tacker.tacker.mgmt.drivers =
tacker.tacker.monitor.drivers =
ping = tacker.vnfm.monitor_drivers.ping.ping:VNFMonitorPing
http_ping = tacker.vnfm.monitor_drivers.http_ping.http_ping:VNFMonitorHTTPPing
tacker.tacker.app_monitor.drivers =
zabbix = tacker.vnfm.monitor_drivers.zabbix.zabbix:VNFMonitorZabbix
tacker.tacker.alarm_monitor.drivers =
ceilometer = tacker.vnfm.monitor_drivers.ceilometer.ceilometer:VNFMonitorCeilometer
tacker.tacker.policy.actions =
@ -81,6 +83,7 @@ oslo.config.opts =
tacker.vnfm.monitor_drivers.http_ping.http_ping = tacker.vnfm.monitor_drivers.http_ping.http_ping:config_opts
tacker.vnfm.monitor_drivers.ping.ping = tacker.vnfm.monitor_drivers.ping.ping:config_opts
tacker.vnfm.monitor_drivers.ceilometer.ceilometer = tacker.vnfm.monitor_drivers.ceilometer.ceilometer:config_opts
tacker.vnfm.monitor_drivers.zabbix.zabbix = tacker.vnfm.monitor_drivers.zabbix.zabbix:config_opts
tacker.alarm_receiver = tacker.alarm_receiver:config_opts
mistral.actions =
tacker.vim_ping_action = tacker.nfvo.workflows.vim_monitor.vim_ping_action:PingVimAction

View File

@ -0,0 +1,54 @@
#
# 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 mock
from tacker.vnfm.monitor_drivers.zabbix import zabbix
import testtools
class TestVNFMonitorZabbix(testtools.TestCase):
def setUp(self):
super(TestVNFMonitorZabbix, self).setUp()
zabbix.VNFMonitorZabbix.tacker_token = 'a1b2c3d4e5'
self.monitor_zabbix = zabbix.VNFMonitorZabbix()
@mock.patch('tacker.vnfm.monitor_drivers.zabbix.zabbix.'
'VNFMonitorZabbix.add_to_appmonitor')
def test_add_to_appmonitor(self, mock_ac):
mock_ac.return_value = None
test_vnf = {'vnfd': {'tenant_id': u'd1e6919c73074d18ab6cd49a02e08391'},
'id': 'b9af3cb5-6e43-4b2c-a056-67bda3f71e1a'}
test_kwargs = {'vdus': {'VDU1':
{'parameters':
{'application':
{'app_name': 'apache2',
'app_status': {'actionname': 'cmd',
'cmd-action': 'sudo service \
apache2 restart',
'condition': ['down']},
'ssh_username': 'ubuntu',
'app_port': 80,
'ssh_password': 'ubuntu'}},
'name': 'zabbix',
'zabbix_username': 'Admin',
'zabbix_password': 'zabbix',
'zabbix_server_ip': '192.168.11.53',
'zabbix_server_port': 80,
'mgmt_ip': '192.168.11.206'}}}
monitor_return = self.monitor_zabbix.\
add_to_appmonitor(test_kwargs, test_vnf)
self.assertEqual(None, monitor_return)

View File

@ -13,6 +13,89 @@ data_types:
type: string
required: false
tosca.datatypes.tacker.AppActionMap:
properties:
condition:
type: map
entry_schema:
type: string
required: false
actionname:
type: string
required: false
cmd-action:
type: string
required: false
tosca.datatypes.tacker.AppInfoParams:
properties:
app_name:
type: string
required: true
app_port:
type: string
required: true
ssh_username:
type: string
required: false
ssh_password:
type: string
required: false
app_status:
type: tosca.dataypes.tacker.AppActionMap
required: false
app_memory:
type: tosca.dataypes.tacker.AppActionMap
required: false
tosca.datatypes.tacker.OSInfoParams:
properties:
os_agent_info:
type: tosca.dataypes.tacker.AppActionMap
required: false
os_proc_value:
type: tosca.datatypes.tacker.AppActionMap
required: false
os_cpu_load:
type: tosca.datatypes.tacker.AppActionMap
required: false
os_cpu_usage:
type: tosca.datatypes.tacker.AppActionMap
required: false
tosca.datatypes.tacker.AppMonitoringParams:
properties:
application:
type: tosca.datatypes.tacker.AppInfoParams
required: false
OS:
type: tosca.datatypes.tacker.OSInfoParams
required: false
tosca.datatypes.tacker.AppMonitoringType:
properties:
name:
type: string
required: true
zabbix_username:
type: string
required: true
zabbix_password:
type: string
required: true
zabbix_server_ip:
type: string
required: true
zabbix_server_port:
type: int
required: true
parameters:
type: tosca.datatypes.tacker.AppMonitoringParams
required: false
tosca.datatypes.tacker.MonitoringParams:
properties:
monitoring_delay:
@ -46,6 +129,8 @@ data_types:
type: tosca.datatypes.tacker.MonitoringParams
required: false
tosca.datatypes.compute_properties:
properties:
num_cpus:
@ -83,6 +168,7 @@ data_types:
required: false
description: The mac address allowed to be paired with specific virtual IP.
policy_types:
tosca.policies.tacker.Placement:
derived_from: tosca.policies.Root
@ -121,6 +207,20 @@ policy_types:
type: string
required: true
tosca.policies.tacker.AppMonitoring:
derived_from: tosca.policies.Root
properties:
name:
type: string
required: true
parameters:
type: map
entry_schema:
type: string
required: false
tosca.policies.tacker.Monitoring.NoOp:
derived_from: tosca.policies.tacker.Monitoring
properties:
@ -136,6 +236,12 @@ policy_types:
properties:
name: http-ping
tosca.policies.tacker.Monitoring.Zabbix:
derived_from: tosca.policies.tacker.Appmonitoring
properties:
name: zabbix
tosca.policies.tacker.Alarming:
derived_from: tosca.policies.Monitoring
triggers:

View File

@ -163,7 +163,7 @@ node_types:
type: string
required: false
image:
# type: tosca.artifacts.Deployment.Image.VM
# type: tosca.artifacts.Deployment.Image.VM
type: string
required: false
flavor:
@ -186,6 +186,13 @@ node_types:
# type: tosca.policies.tacker.Placement
type: string
required: false
app_monitoring_policy:
# type: tosca.policies.tacker.AppMonitoring
# type: tosca.datatypes.tacker.AppMonitoringType
type: map
required: false
monitoring_policy:
# type: tosca.policies.tacker.Monitoring

View File

@ -17,15 +17,14 @@ import re
import sys
import yaml
from collections import OrderedDict
from oslo_log import log as logging
from toscaparser import properties
from toscaparser.utils import yamlparser
from tacker.common import log
from tacker.common import utils
from tacker.extensions import vnfm
from toscaparser import properties
from toscaparser.utils import yamlparser
from collections import OrderedDict
FAILURE = 'tosca.policies.tacker.Failure'
LOG = logging.getLogger(__name__)
@ -160,6 +159,28 @@ def get_vdu_monitoring(template):
return monitoring_dict
def get_vdu_applicationmonitoring(template):
tpl_temp = "topology_template"
n_temp = "node_templates"
poly = "app_monitoring_policy"
monitoring_dict = dict()
policy_dict = dict()
policy_dict['vdus'] = collections.OrderedDict()
node_list = template[tpl_temp][n_temp].keys()
for node in node_list:
nt = template[tpl_temp][n_temp][node]
if nt['type'] == TACKERVDU:
if poly in nt['properties'].keys():
mon_policy = nt['properties'][poly]
if mon_policy != 'noop':
policy_dict['vdus'][node] = {}
policy_dict['vdus'][node] = mon_policy
del template[tpl_temp][n_temp][node]['properties'][poly]
if policy_dict.get('vdus'):
monitoring_dict = policy_dict
return monitoring_dict
@log.log
def get_vdu_metadata(template):
metadata = dict()

View File

@ -60,6 +60,7 @@ class TOSCAToHOT(object):
self.nested_resources = dict()
self.fields = None
self.STACK_FLAVOR_EXTRA = cfg.CONF.openstack_vim.flavor_extra_specs
self.appmonitoring_dict = None
@log.log
def generate_hot(self):
@ -78,6 +79,9 @@ class TOSCAToHOT(object):
if self.monitoring_dict:
self.vnf['attributes']['monitoring_policy'] = jsonutils.dumps(
self.monitoring_dict)
if self.appmonitoring_dict:
self.vnf['attributes']['app_monitoring_policy'] = \
jsonutils.dumps(self.appmonitoring_dict)
@log.log
def _get_vnfd(self):
@ -250,11 +254,17 @@ class TOSCAToHOT(object):
LOG.debug("Params not Well Formed: %s", str(e))
raise vnfm.ParamYAMLNotWellFormed(error_msg_details=str(e))
block_storage_details = toscautils.get_block_storage_details(vnfd_dict)
appmonitoring_dict = \
toscautils.get_vdu_applicationmonitoring(vnfd_dict)
block_storage_details = toscautils.get_block_storage_details(
vnfd_dict)
toscautils.updateimports(vnfd_dict)
if 'substitution_mappings' in str(vnfd_dict):
toscautils.check_for_substitution_mappings(vnfd_dict,
parsed_params)
toscautils.check_for_substitution_mappings(
vnfd_dict,
parsed_params
)
try:
tosca = tosca_template.ToscaTemplate(parsed_params=parsed_params,
@ -314,6 +324,7 @@ class TOSCAToHOT(object):
self.heat_template_yaml = heat_template_yaml
self.monitoring_dict = monitoring_dict
self.metadata = metadata
self.appmonitoring_dict = appmonitoring_dict
@log.log
def represent_odict(self, dump, tag, mapping, flow_style=None):

View File

@ -14,7 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import ast
import inspect
import threading
import time
@ -24,7 +24,6 @@ from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import timeutils
from tacker.common import driver_manager
from tacker import context as t_context
from tacker.db.common_services import common_services_db_plugin
@ -43,7 +42,8 @@ CONF.register_opts(OPTS, group='monitor')
def config_opts():
return [('monitor', OPTS),
('tacker', VNFMonitor.OPTS),
('tacker', VNFAlarmMonitor.OPTS), ]
('tacker', VNFAlarmMonitor.OPTS),
('tacker', VNFAppMonitor.OPTS)]
def _log_monitor_events(context, vnf_dict, evt_details):
@ -195,6 +195,49 @@ class VNFMonitor(object):
vnf=vnf_dict, kwargs=kwargs)
class VNFAppMonitor(object):
"""VNF App monitor"""
OPTS = [
cfg.ListOpt(
'app_monitor_driver', default=['zabbix'],
help=_('App monitoring driver to communicate with '
'Hosting VNF/logical service '
'instance tacker plugin will use')),
]
cfg.CONF.register_opts(OPTS, 'tacker')
def __init__(self):
self._application_monitor_manager = driver_manager.DriverManager(
'tacker.tacker.app_monitor.drivers',
cfg.CONF.tacker.app_monitor_driver)
def _create_app_monitoring_dict(self, dev_attrs, mgmt_url):
app_policy = 'app_monitoring_policy'
appmonitoring_dict = ast.literal_eval(dev_attrs[app_policy])
vdulist = appmonitoring_dict['vdus'].keys()
for vduname in vdulist:
temp = ast.literal_eval(mgmt_url)
appmonitoring_dict['vdus'][vduname]['mgmt_ip'] = temp[vduname]
return appmonitoring_dict
def create_app_dict(self, context, vnf_dict):
dev_attrs = vnf_dict['attributes']
mgmt_url = vnf_dict['mgmt_url']
return self._create_app_monitoring_dict(dev_attrs, mgmt_url)
def _invoke(self, driver, **kwargs):
method = inspect.stack()[1][3]
return self._application_monitor_manager.\
invoke(driver, method, **kwargs)
def add_to_appmonitor(self, applicationvnfdict, vnf_dict):
vdunode = applicationvnfdict['vdus'].keys()
driver = applicationvnfdict['vdus'][vdunode[0]]['name']
kwargs = applicationvnfdict
return self._invoke(driver, vnf=vnf_dict, kwargs=kwargs)
class VNFAlarmMonitor(object):
"""VNF Alarm monitor"""
OPTS = [
@ -262,7 +305,7 @@ class VNFAlarmMonitor(object):
return alarm_url
def process_alarm_for_vnf(self, vnf, trigger):
'''call in plugin'''
"""call in plugin"""
params = trigger['params']
mon_prop = trigger['trigger']
alarm_dict = dict()

View File

@ -0,0 +1,416 @@
# 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 json
import requests
import time
import copy
from oslo_log import log as logging
from tacker.vnfm.monitor_drivers import abstract_driver
from tacker.vnfm.monitor_drivers.zabbix import zabbix_api as zapi
LOG = logging.getLogger(__name__)
class VNFMonitorZabbix(abstract_driver.VNFMonitorAbstractDriver):
params = ['application', 'OS']
def __init__(self):
self.kwargs = None
self.vnf = None
self.vduname = []
self.URL = None
self.hostinfo = {}
self.tenant_id = None
def get_type(self):
"""Return one of predefined type of the hosting vnf drivers."""
plugin_type = 'zabbix'
return plugin_type
def get_name(self):
"""Return a symbolic name for the VNF Monitor plugin."""
plugin_name = 'zabbix'
return plugin_name
def get_description(self):
"""Return description of VNF Monitor plugin."""
plugin_descript = 'Tacker VNFMonitor Zabbix Driver'
return plugin_descript
def monitor_get_config(self, plugin, context, vnf):
"""Return dict of monitor configuration data.
:param plugin:
:param context:
:param vnf:
:returns: dict
:returns: dict of monitor configuration data
"""
return {}
def monitor_url(self, plugin, context, vnf):
"""Return the url of vnf to monitor.
:param plugin:
:param context:
:param vnf:
:returns: string
:returns: url of vnf to monitor
"""
pass
def send_post(self, query):
response = requests.post(self.URL, headers=zapi.HEADERS,
data=json.dumps(query))
return dict(response.json())
@staticmethod
def check_error(response):
try:
if 'result' not in response:
raise ValueError
except ValueError:
LOG.error('Cannot request error : %s', response['error']['data'])
def create_graph(self, itemid, name, nodename):
temp_graph_api = copy.deepcopy(zapi.dGRAPH_CREATE_API)
gitems = [{'itemid': itemid, 'color': '00AA00'}]
temp_graph_api['auth'] = \
self.hostinfo[nodename]['zbx_info']['zabbix_token']
temp_graph_api['params']['gitems'] = gitems
temp_graph_api['params']['name'] = name
response = self.send_post(temp_graph_api)
VNFMonitorZabbix.check_error(response)
def create_action(self):
for vdu in self.vduname:
temp_action_api = copy.deepcopy(zapi.dACTION_CREATE_API)
temp_action_api['auth'] = \
self.hostinfo[vdu]['zbx_info']['zabbix_token']
tempname_api = temp_action_api['params']['operations'][0]
temp_filter = temp_action_api['params']['filter']
for info in (self.hostinfo[vdu]['actioninfo']):
tempname_api['opcommand_hst'][0]['hostid'] = \
self.hostinfo[vdu]['hostid']
now = time.localtime()
rtime = str(now.tm_hour) + str(now.tm_min) + str(now.tm_sec)
temp_name = "Trigger Action " + \
str(
vdu + rtime + " " +
info['item'] + " " + info['action']
)
temp_action_api['params']['name'] = temp_name
if (info['action'] == 'cmd') and \
(info['item'] != 'os_agent_info'):
tempname_api['opcommand']['command'] = info['cmd-action']
elif (info['item'] == 'os_agent_info') \
and (info['action'] == 'cmd'):
tempname_api['opcommand']['authtype'] = 0
tempname_api['opcommand']['username'] = \
self.hostinfo[vdu]['appinfo']['ssh_username']
tempname_api['opcommand']['password'] = \
self.hostinfo[vdu]['appinfo']['ssh_password']
tempname_api['opcommand']['type'] = 2
tempname_api['opcommand']['command'] = info['cmd-action']
tempname_api['opcommand']['port'] = 22
temp_filter['conditions'][0]['value'] = info['trigger_id']
response = self.send_post(temp_action_api)
VNFMonitorZabbix.check_error(response)
continue
temp_filter['conditions'][0]['value'] = info['trigger_id']
response = self.send_post(temp_action_api)
VNFMonitorZabbix.check_error(response)
def create_vdu_host(self):
for vdu in self.vduname:
temp_host_api = zapi.dHOST_CREATE_API
temp_group_api = zapi.dGROUP_GET_API
temp_host_api['auth'] = \
self.hostinfo[vdu]['zbx_info']['zabbix_token']
temp_group_api['auth'] = \
self.hostinfo[vdu]['zbx_info']['zabbix_token']
response = self.send_post(temp_group_api)
gid = response['result'][0]['groupid']
temp_host_api['params']['host'] = str(vdu)
if type(self.hostinfo[vdu]['mgmt_ip']) is list:
for vduip in (self.hostinfo[vdu]['mgmt_ip']):
temp_host_api['params']['interfaces'][0]['ip'] = vduip
temp_host_api['params']['templates'][0]['templateid'] = \
self.hostinfo[vdu]['template_id'][0]
temp_host_api['params']['groups'][0]['groupid'] = gid
response = self.send_post(temp_host_api)
else:
temp_host_api['params']['interfaces'][0]['ip'] = \
self.hostinfo[vdu]['mgmt_ip']
temp_host_api['params']['templates'][0]['templateid'] = \
self.hostinfo[vdu]['template_id'][0]
temp_host_api['params']['groups'][0]['groupid'] = gid
response = self.send_post(temp_host_api)
if 'error' in response:
now = time.localtime()
rtime = str(now.tm_hour) + str(now.tm_min) + str(now.tm_sec)
temp_host_api['params']['host'] = str(vdu) + rtime
response = self.send_post(temp_host_api)
self.hostinfo[vdu]['hostid'] = response['result']['hostids'][0]
def create_trigger(self, trigger_params, vduname):
temp_trigger_api = copy.deepcopy(zapi.dTRIGGER_CREATE_API)
temp_trigger_api['auth'] = \
self.hostinfo[vduname]['zbx_info']['zabbix_token']
temp_trigger_api['params'] = trigger_params
temp_trigger_api['templateid'] = \
str(
self.hostinfo[vduname]['template_id'][0])
response = self.send_post(temp_trigger_api)
VNFMonitorZabbix.check_error(response)
return response['result']
def _create_trigger(self):
trigger_params = []
trig_act_pa = []
for vdu in self.vduname:
temp_trigger_list = copy.deepcopy(zapi.dTRIGGER_LIST)
temp_vdu_name = self.hostinfo[vdu]['appinfo']['app_name']
temp_vdu_port = self.hostinfo[vdu]['appinfo']['app_port']
for para in VNFMonitorZabbix.params:
for item in self.hostinfo[vdu]['parameters'][para].keys():
action_list = copy.deepcopy(zapi.dACTION_LIST)
temp_item = self.hostinfo[vdu]['parameters'][para][item]
if ('app_name' != item)\
and ('app_port' != item) \
and ('ssh_username' != item) \
and ('ssh_password' != item):
if 'condition' \
in temp_item.keys():
temp_con = temp_item['condition']
if len(temp_con) == 2:
temp_comparrision = temp_con[0]
temp_comparrision_value = temp_con[1]
temp_trigger_list[item][0]['expression'] += \
self.hostinfo[vdu]['template_name'] + ':'\
+ str(
zapi.dITEM_KEY_COMP[item].replace(
'*', str(temp_vdu_name))) \
+ str(
zapi.COMP_VALUE[temp_comparrision]) \
+ str(
temp_comparrision_value)
else:
temp_comparrision = temp_con[0]
if 'os_agent_info' == item:
temp_trigger_list[item][0]['expression'] += \
self.hostinfo[vdu]['template_name'] + ':' \
+ str(zapi.dITEM_KEY_COMP[item])
else:
temp_trigger_list[item][0]['expression'] += \
self.hostinfo[vdu]['template_name'] + ':' \
+ str(
zapi.dITEM_KEY_COMP[item].replace(
'*', str(temp_vdu_port))) \
+ str(
zapi.COMP_VALUE[temp_comparrision])
if 'actionname' in \
temp_item.keys():
trig_act_pa.append(temp_trigger_list[item][0])
response = self.create_trigger(trig_act_pa, vdu)
del trig_act_pa[:]
action_list['action'] = \
temp_item['actionname']
action_list['trigger_id'] = \
response['triggerids'][0]
action_list['item'] = item
if 'cmd' == \
temp_item['actionname']:
action_list['cmd-action'] = \
temp_item['cmd-action']
self.hostinfo[vdu]['actioninfo'].append(
action_list)
else:
trigger_params.append(
temp_trigger_list[item][0])
if len(trigger_params) != 0:
self.create_trigger(trigger_params, vdu)
del trigger_params[:]
def create_item(self):
# Create _ITEM
for vdu in self.vduname:
temp_item_api = copy.deepcopy(zapi.dITEM_CREATE_API)
temp_item_api['auth'] = \
self.hostinfo[vdu]['zbx_info']['zabbix_token']
self.hostinfo[vdu]['appinfo'] = \
copy.deepcopy(zapi.dAPP_INFO)
temp_app = self.hostinfo[vdu]['parameters']['application']
temp_item_api['params']['hostid'] = \
self.hostinfo[vdu]['template_id'][0]
for para in VNFMonitorZabbix.params:
if 'application' == para:
for app_info in \
temp_app.keys():
self.hostinfo[vdu]['appinfo'][app_info] = \
temp_app[app_info]
for item in (self.hostinfo[vdu]['parameters'][para].keys()):
if ('app_name' != item) and ('app_port' != item) \
and ('ssh_username' != item) \
and ('ssh_password' != item):
temp_item_api['params']['name'] = \
zapi.dITEM_KEY_INFO[item]['name']
temp_item_api['params']['value_type'] = \
zapi.dITEM_KEY_INFO[item]['value_type']
if item == 'app_status':
temp = zapi.dITEM_KEY_INFO[item]['key_']
temp_item_api['params']['key_'] = temp.replace(
'*', str(
self.hostinfo[vdu]['appinfo']['app_port']))
elif item == 'app_memory':
temp = zapi.dITEM_KEY_INFO[item]['key_']
temp_item_api['params']['key_'] = temp.replace(
'*',
str(
self.hostinfo[vdu]['appinfo']['app_name']))
else:
temp_item_api['params']['key_'] = \
zapi.dITEM_KEY_INFO[item]['key_']
response = self.send_post(temp_item_api)
self.create_graph(
response['result']['itemids'][0],
temp_item_api['params']['name'], vdu)
VNFMonitorZabbix.check_error(response)
def create_template(self):
temp_template_api = copy.deepcopy(zapi.dTEMPLATE_CREATE_API)
for vdu in self.vduname:
temp_template_api['params']['host'] = "Tacker Template " + str(vdu)
temp_template_api['auth'] = \
self.hostinfo[vdu]['zbx_info']['zabbix_token']
response = self.send_post(temp_template_api)
if 'error' in response:
if "already exists." in response['error']['data']:
now = time.localtime()
rtime = str(now.tm_hour) + str(now.tm_min) + str(
now.tm_sec)
temp_template_api['params']['host'] = \
"Tacker Template " + str(vdu) + rtime
response = self.send_post(temp_template_api)
VNFMonitorZabbix.check_error(response)
self.hostinfo[vdu]['template_id'] = \
response['result']['templateids']
self.hostinfo[vdu]['template_name'] =\
temp_template_api['params']['host']
def add_host_to_zabbix(self):
self.create_template()
self.create_item()
self._create_trigger()
self.create_vdu_host()
self.create_action()
def get_token_from_zbxserver(self, node):
temp_auth_api = copy.deepcopy(zapi.dAUTH_API)
temp_auth_api['params']['user'] = \
self.hostinfo[node]['zbx_info']['zabbix_user']
temp_auth_api['params']['password'] = \
self.hostinfo[node]['zbx_info']['zabbix_pass']
zabbixip = \
self.hostinfo[node]['zbx_info']['zabbix_ip']
zabbixport = \
self.hostinfo[node]['zbx_info']['zabbix_port']
self.URL = "http://" + zabbixip + ":" + \
str(zabbixport) + zapi.URL_
response = requests.post(
self.URL,
headers=zapi.HEADERS,
data=json.dumps(temp_auth_api)
)
response_dict = dict(response.json())
VNFMonitorZabbix.check_error(response_dict)
LOG.info('Success Connect Zabbix Server')
return response_dict['result']
def set_zbx_info(self, node):
self.hostinfo[node]['zbx_info'] = \
copy.deepcopy(zapi.dZBX_INFO)
self.hostinfo[node]['zbx_info']['zabbix_user'] = \
self.kwargs['vdus'][node]['zabbix_username']
self.hostinfo[node]['zbx_info']['zabbix_pass'] = \
self.kwargs['vdus'][node]['zabbix_password']
self.hostinfo[node]['zbx_info']['zabbix_ip'] = \
self.kwargs['vdus'][node]['zabbix_server_ip']
self.hostinfo[node]['zbx_info']['zabbix_port'] = \
self.kwargs['vdus'][node]['zabbix_server_port']
self.hostinfo[node]['zbx_info']['zabbix_token'] = \
self.get_token_from_zbxserver(node)
def set_vdu_info(self):
temp_vduname = self.kwargs['vdus'].keys()
for node in temp_vduname:
if 'application' in \
self.kwargs['vdus'][node]['parameters'].keys() \
and 'OS'\
in self.kwargs['vdus'][node]['parameters'].keys():
self.vduname.append(node)
self.hostinfo[node] = copy.deepcopy(zapi.dVDU_INFO)
self.set_zbx_info(node)
self.hostinfo[node]['mgmt_ip'] = \
self.kwargs['vdus'][node]['mgmt_ip']
self.hostinfo[node]['parameters'] = \
self.kwargs['vdus'][node]['parameters']
self.hostinfo[node]['vdu_id'] = self.vnf['id']
def add_to_appmonitor(self, vnf, kwargs):
self.__init__()
self.kwargs = kwargs
self.vnf = vnf
self.set_vdu_info()
self.tenant_id = self.vnf['vnfd']['tenant_id']
self.add_host_to_zabbix()
def monitor_call(self, vnf, kwargs):
pass
def monitor_app_driver(self, plugin, context, vnf, service_instance):
return self.get_name()

View File

@ -0,0 +1,214 @@
#
# 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.
#
URL_ = "/zabbix/api_jsonrpc.php"
HEADERS = {'Content-Type': 'application/json-rpc'}
dAUTH_API = {'jsonrpc': "2.0",
'method': 'user.login',
'params': {'user': None,
'password': None},
'id': 1,
'auth': None}
COMP_VALUE = {'greater': '>',
'less': '<',
'and greater': '>=',
'and less': '<=',
'down': '=0'}
dTEMPLATE_CREATE_API = {'jsonrpc': "2.0", 'method': "template.create",
'params': {'host': "", 'groups': {'groupid': 1},
'hosts': []},
'id': 1004, 'auth': None}
dITEM_CREATE_API = {'jsonrpc': "2.0",
'method': "item.create",
'params': {'hostid': None,
'interfaceid': 'NULL',
'name': "",
'key_': "",
'type': 0,
'value_type': 3,
'delay': 1},
'id': 1,
'auth': None}
dITEM_KEY_VALUE = {'os_agent_info': 'agent.ping',
'os_cpu_usage': 'system.cpu.util[,iowait]',
'os_cpu_load': 'system.cpu.load[percpu,avg1]',
'os_proc_value': 'proc.num[,,run]',
'app_status': 'net.tcp.port[ ,*]',
'app_memory': 'proc.mem[*,root]'}
dITEM_KEY_COMP = {'os_agent_info': str(
dITEM_KEY_VALUE['os_agent_info'] + '.nodata(15s)}=1'),
'os_cpu_usage': str(
dITEM_KEY_VALUE['os_cpu_usage'] + '.avg(5s)}'),
'os_cpu_load': str(
dITEM_KEY_VALUE['os_cpu_load'] + '.avg(5s)}'),
'os_proc_value': str(
dITEM_KEY_VALUE['os_proc_value'] + '.avg(5s)}'),
'app_status': str(
dITEM_KEY_VALUE['app_status'] + '.last(,5)}'),
'app_memory': str(
dITEM_KEY_VALUE['app_memory'] + '.avg(5s)}')}
dITEM_KEY_INFO = {'os_proc_value': {'name': 'process number',
'key_': str(
dITEM_KEY_VALUE['os_proc_value']),
'value_type': 3},
'os_cpu_load': {'name': 'cpu load',
'key_': str(
dITEM_KEY_VALUE['os_cpu_load']),
'value_type': 0},
'os_cpu_usage': {'name': 'cpu util usage',
'key_': str(
dITEM_KEY_VALUE['os_cpu_usage']),
'value_type': 0},
'os_agent_info': {'name': 'Zabbix agent status check',
'key_': str(
dITEM_KEY_VALUE['os_agent_info']),
'value_type': 0},
'app_status': {'name': ' service status check',
'key_': str(
dITEM_KEY_VALUE['app_status']),
'value_type': 3},
'app_memory': {'name': ' service memory usage',
'key_': str(
dITEM_KEY_VALUE['app_memory']),
'value_type': 3}}
dTRIGGER_CREATE_API = {'jsonrpc': "2.0",
'method': "trigger.create",
'templateid': None,
'auth': None,
'id': 1004}
dTRIGGER_INFO = {'itemname': None,
'cmdname': None,
'cmd-action': None}
dTRIGGER_LIST = {'os_agent_info': [{'description': 'Zabbix agent on '
'{HOST.NAME} is '
'unreachable '
'for 15 seconds',
'expression': '{', 'priority': 3}],
'app_status': [{'description': 'Service is down '
'on {HOST.NAME}',
'expression': '{', 'priority': 3}],
'app_memory': [{'description': 'Process Memory '
'is lacking '
'on {HOST.NAME}',
'expression': '{', 'priority': 3}],
'os_cpu_usage': [{'description': 'Disk I/O is '
'overloaded '
'on {HOST.NAME}',
'expression': '{', 'priority': 3}],
'os_cpu_load': [{'description': 'Processor load '
'is too high '
'on {HOST.NAME}',
'expression': '{', 'priority': 3}],
'os_proc_value': [{'description': 'Too many '
'processes running '
'on {HOST.NAME}',
'expression': '{', 'priority': 3}]}
dACTION_CREATE_API = {'jsonrpc': "2.0",
'method': "action.create",
'params': {'name': '',
'eventsource': 0,
'status': 0,
'esc_period': 120,
'def_shortdata': "{TRIGGER.NAME}:"
"{TRIGGER.STATUS}",
'def_longdata': "{TRIGGER.NAME}: "
"{TR`IGGER.STATUS}\r\n"
"Last value: "
"{ITEM.LASTVALUE]"
"\r\n\r\n{TRIGGER.URL}",
"filter": {"evaltype": 0,
"conditions": [{'conditiontype': 2,
'operator': 0,
'value': None}]},
'operations': [{'operationtype': 1,
'esc_period': 0,
'esc_step_from': 1,
'esc_step_to': 2,
'evaltype': 0,
'opcommand': {
'command': None,
'type': 0,
'execute_on': 0},
'opcommand_hst': [
{'hostid': None}]
}]},
'auth': None, 'id': 1}
dHOST_CREATE_API = {'jsonrpc': "2.0",
'method': "host.create",
'params': {'host': 'ubuntu',
'interfaces': [
{'type': 1,
'main': 1,
'useip': 1,
'dns': "",
'ip': None,
'port': "10050"}],
'templates': [{'templateid': None}],
'groups': [{'groupid': None}]},
'id': 4, 'auth': None}
dGROUP_GET_API = {'jsonrpc': "2.0", 'method': "hostgroup.get",
'params': {'output': 'extend',
'filter': {'name': ["Zabbix servers", ]}},
'id': 1, 'auth': None}
dGRAPH_CREATE_API = {'jsonrpc': '2.0', 'method': 'graph.create',
'params': {'name': None,
'width': 900,
'height': 200,
'gitems': []},
'auth': None, 'id': 1004}
dAPP_INFO = {'app_port': None,
'app_name': None,
'ssh_username': None,
'ssh_password': None}
dZBX_INFO = {'zabbix_user': None,
'zabbix_pass': None,
'zabbix_ip': None,
'zabbix_port': None,
'zabbix_token': None
}
dACTION_LIST = {'item': None,
'action': None,
'trigger_id': None,
'cmd-action': None}
dVDU_INFO = {'template_id': None,
'template_name': None,
'hostid': None,
'group_id': None,
'mgmt_ip': None,
'vdu_id': None,
'parameters': None,
'actioninfo': [],
'appinfo': None,
'zbx_info': None
}

View File

@ -32,11 +32,11 @@ from tacker.common import utils
from tacker.db.vnfm import vnfm_db
from tacker.extensions import vnfm
from tacker.plugins.common import constants
from tacker.tosca import utils as toscautils
from tacker.vnfm.mgmt_drivers import constants as mgmt_constants
from tacker.vnfm import monitor
from tacker.vnfm import vim_client
from tacker.tosca import utils as toscautils
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
@ -143,6 +143,7 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
cfg.CONF.tacker.policy_action)
self._vnf_monitor = monitor.VNFMonitor(self.boot_wait)
self._vnf_alarm_monitor = monitor.VNFAlarmMonitor()
self._vnf_app_monitor = monitor.VNFAppMonitor()
def spawn_n(self, function, *args, **kwargs):
self._pool.spawn_n(function, *args, **kwargs)
@ -247,6 +248,10 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
vnf_dict['attributes'].update(alarm_url)
break
def add_vnf_to_appmonitor(self, context, vnf_dict):
appmonitor = self._vnf_app_monitor.create_app_dict(context, vnf_dict)
self._vnf_app_monitor.add_to_appmonitor(appmonitor, vnf_dict)
def config_vnf(self, context, vnf_dict):
config = vnf_dict['attributes'].get('config')
if not config:
@ -392,6 +397,10 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
def create_vnf_wait():
self._create_vnf_wait(context, vnf_dict, vim_auth, infra_driver)
if 'app_monitoring_policy' in vnf_dict['attributes']:
self.add_vnf_to_appmonitor(context, vnf_dict)
if vnf_dict['status'] is not constants.ERROR:
self.add_vnf_to_monitor(context, vnf_dict)
self.config_vnf(context, vnf_dict)