Merge "implements: blueprint synchronizer-nagios-get-all"

This commit is contained in:
Jenkins 2016-02-22 11:38:26 +00:00 committed by Gerrit Code Review
commit db68a02b03
8 changed files with 264 additions and 66 deletions

View File

@ -27,29 +27,28 @@ class NagiosParser(object):
NAME_XPATH = 'table/tr/td[position()=1]/table/tr/td/a'
def __init__(self):
self.last_host_name = ''
return
self.last_host_name = None
def parse(self, html):
services = []
parser = etree.HTMLParser()
try:
tree = etree.parse(StringIO(html), parser)
tree = etree.parse(StringIO(html), etree.HTMLParser())
status_tables = tree.xpath(self.STATUS_TABLE_XPATH)
for status_table in status_tables:
service_rows = status_table.xpath(self.SERVICE_ROWS_XPATH)
for service_row in service_rows:
service = self._parse_service_row(service_row)
if service:
services.append(service)
return self._parse_services(status_tables)
except Exception as e:
LOG.exception('Failed to get nagios services %s', e)
return services
return None
def _parse_services(self, status_tables):
services = []
for status_table in status_tables:
service_rows = status_table.xpath(self.SERVICE_ROWS_XPATH)
for service_row in service_rows:
service = self._parse_service_row(service_row)
if service:
services.append(service)
return services
def _parse_service_row(self, service_row):
@ -59,41 +58,34 @@ class NagiosParser(object):
# there are also two blank lines between different hosts,
# so len(columns)==1 is also valid
# TODO(ifat_afek): get column names by the header line
if (len(columns) == NagiosProperties.NUM_COLUMNS):
if len(columns) == NagiosProperties.NUM_COLUMNS:
return self._parse_service_columns(columns)
elif (len(columns) > NagiosProperties.NUM_COLUMNS):
elif len(columns) > NagiosProperties.NUM_COLUMNS:
LOG.warn('Too many columns in nagios service row. '
'Found %d', len(columns))
elif (len(columns) > 1):
elif len(columns) > 1:
LOG.warn('Missing columns in nagios service row. '
'Found only %d', len(columns))
return None
def _parse_service_columns(self, columns):
host_name = self._parse_host_name(columns[0], self.NAME_XPATH)
service_name = self._get_column_data(columns[1], self.NAME_XPATH)
status = columns[2].text
last_check = columns[3].text
duration = columns[4].text
attempt = columns[5].text
status_information = columns[6].text
service = {
NagiosProperties.RESOURCE_NAME: host_name,
NagiosProperties.SERVICE: service_name,
NagiosProperties.STATUS: status,
NagiosProperties.LAST_CHECK: last_check,
NagiosProperties.DURATION: duration,
NagiosProperties.ATTEMPT: attempt,
NagiosProperties.STATUS_INFO: status_information
return {
NagiosProperties.RESOURCE_NAME:
self._parse_host_name(columns[0], self.NAME_XPATH),
NagiosProperties.SERVICE:
self._get_column_data(columns[1], self.NAME_XPATH),
NagiosProperties.STATUS: columns[2].text,
NagiosProperties.LAST_CHECK: columns[3].text,
NagiosProperties.DURATION: columns[4].text,
NagiosProperties.ATTEMPT: columns[5].text,
NagiosProperties.STATUS_INFO: columns[6].text
}
return service
def _get_column_data(self, column, xpath):
@staticmethod
def _get_column_data(column, xpath):
contents = column.xpath(xpath)
if len(contents) == 1:
@ -105,7 +97,7 @@ class NagiosParser(object):
else:
# len(contents) might be 0 for a host, since each host name appears
# only once in the table
return ''
return None
def _parse_host_name(self, column, xpath):
"""Parse the host name and return it

View File

@ -47,6 +47,11 @@ class NagiosSynchronizer(SynchronizerBase):
return []
def _get_services(self):
nagios_services = self._get_services_from_nagios()
self._enrich_services(nagios_services)
return self._cache_and_filter_services(nagios_services)
def _get_services_from_nagios(self):
nagios_user = self.conf.synchronizer_plugins.nagios_user
nagios_password = self.conf.synchronizer_plugins.nagios_password
nagios_url = self.conf.synchronizer_plugins.nagios_url
@ -71,8 +76,7 @@ class NagiosSynchronizer(SynchronizerBase):
if response.status_code == requests.codes.ok:
nagios_services = NagiosParser().parse(response.text)
self._enrich_services(nagios_services)
return self._cache_and_filter_services(nagios_services)
return nagios_services
else:
LOG.error(_LE('Failed to get nagios data. Response code: %s') %
response.status_code)

View File

@ -8,6 +8,5 @@
"duration": "61d 21h 52m 38s",
"attempt": "1/1",
"status_info": "OK - user: 0\\.6%, system: 0\\.3%, wait: 0\\.4%",
"event_type": "CREATE|UPDATE",
"sync_mode": "snapshot|init_snapshot|update"
}

View File

@ -1,4 +1,3 @@
{
"status": "OK",
"event_type": "DELETE"
"status": "OK"
}

View File

@ -0,0 +1,37 @@
# Copyright 2016 - Nokia
#
# 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 vitrage.synchronizer.plugins.nagios.properties import NagiosProperties \
as NagiosProps
from vitrage.tests import base
class NagiosBaseTest(base.BaseTest):
def _assert_contains(self, expected_service, services):
for service in services:
if service[NagiosProps.RESOURCE_NAME] == \
expected_service[NagiosProps.RESOURCE_NAME] and \
service[NagiosProps.SERVICE] == \
expected_service[NagiosProps.SERVICE]:
self._assert_expected_service(expected_service, service)
return
self.fail("service not found: %(resource_name)s %(service_name)s" %
{'resource_name':
expected_service[NagiosProps.RESOURCE_NAME],
'service_name':
expected_service[NagiosProps.SERVICE]})
def _assert_expected_service(self, expected_service, service):
for key, value in expected_service.items():
self.assertEqual(value, service[key], 'wrong value for ' + key)

View File

@ -0,0 +1,43 @@
# Copyright 2016 - Nokia
#
# 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 vitrage.synchronizer.plugins.nagios.synchronizer import NagiosSynchronizer
from vitrage.tests.mocks import mock_syncronizer as mock_sync
class NagiosSynchronizerWithMockData(NagiosSynchronizer):
"""A nagios synchronizer for tests.
Instead of calling Nagios URL to get the data, it returns the data it
is asked to
"""
def __init__(self, conf):
super(NagiosSynchronizerWithMockData, self).__init__(conf)
self.service_datas = None
def set_service_datas(self, service_datas):
self.service_datas = service_datas
def _get_services_from_nagios(self):
alarms = []
for service_data in self.service_datas:
generators = mock_sync.simple_nagios_alarm_generators(
host_num=1,
events_num=1,
snap_vals=service_data)
alarms.append(
mock_sync.generate_sequential_events_list(generators)[0])
return alarms

View File

@ -15,13 +15,14 @@ from oslo_log import log as logging
from vitrage.synchronizer.plugins.nagios.parser import NagiosParser
from vitrage.synchronizer.plugins.nagios.properties import NagiosProperties
from vitrage.tests import base
from vitrage.tests.mocks import utils
from vitrage.tests.unit.synchronizer.nagios.nagios_base_test \
import NagiosBaseTest
LOG = logging.getLogger(__name__)
class NagiosParserTest(base.BaseTest):
class NagiosParserTest(NagiosBaseTest):
expected_service1 = {NagiosProperties.RESOURCE_NAME: 'compute-0-0.local',
NagiosProperties.SERVICE: 'CPU load',
@ -64,25 +65,6 @@ class NagiosParserTest(base.BaseTest):
# Test assertions
self.assertTrue(nagios_services)
self._assert_contains(nagios_services, self.expected_service1)
self._assert_contains(nagios_services, self.expected_service2)
self._assert_contains(nagios_services, self.expected_service3)
def _assert_contains(self, services, expected_service):
for service in services:
if service[NagiosProperties.RESOURCE_NAME] == \
expected_service[NagiosProperties.RESOURCE_NAME] and \
service[NagiosProperties.SERVICE] == \
expected_service[NagiosProperties.SERVICE]:
self._assert_expected_service(expected_service, service)
return
self.fail("service not found: %(resource_name)s %(service_name)s" %
{'resource_name':
expected_service[NagiosProperties.RESOURCE_NAME],
'service_name':
expected_service[NagiosProperties.SERVICE]})
def _assert_expected_service(self, expected_service, service):
for key, value in expected_service.items():
self.assertEqual(value, service[key], 'wrong value for ' + key)
self._assert_contains(self.expected_service1, nagios_services)
self._assert_contains(self.expected_service2, nagios_services)
self._assert_contains(self.expected_service3, nagios_services)

View File

@ -0,0 +1,142 @@
# Copyright 2016 - Nokia
#
# 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_config import cfg
from oslo_log import log as logging
from vitrage.synchronizer.plugins.nagios.properties import NagiosProperties \
as NagiosProps
from vitrage.tests.unit.synchronizer.nagios.nagios_base_test \
import NagiosBaseTest
from vitrage.tests.unit.synchronizer.nagios.synchronizer_with_mock_data \
import NagiosSynchronizerWithMockData
LOG = logging.getLogger(__name__)
class NagiosSynchronizerTest(NagiosBaseTest):
def setUp(self):
super(NagiosSynchronizerTest, self).setUp()
self.conf = cfg.ConfigOpts()
def test_get_all(self):
"""Check get_all functionality.
Check the logic of which tests are returned: tests that are not OK,
or tests that were changed from not-OK to OK
"""
# Setup
nagios_synchronizer = NagiosSynchronizerWithMockData(self.conf)
# Action
service_data1 = {NagiosProps.RESOURCE_NAME: 'compute-0',
NagiosProps.SERVICE: 'CPU utilization',
NagiosProps.STATUS: 'OK'}
service_data2 = {NagiosProps.RESOURCE_NAME: 'compute-1',
NagiosProps.SERVICE: 'CPU utilization',
NagiosProps.STATUS: 'OK'}
service_data3 = {NagiosProps.RESOURCE_NAME: 'compute-1',
NagiosProps.SERVICE: 'Uptime',
NagiosProps.STATUS: 'OK'}
nagios_synchronizer.set_service_datas([service_data1,
service_data2,
service_data3])
services = nagios_synchronizer._get_services()
# Test assertions
# Services with status OK should not be returned
self.assertIsNotNone(services, 'No services returned')
self.assertEqual(0, len(services))
# Action
service_data1 = {NagiosProps.RESOURCE_NAME: 'compute-0',
NagiosProps.SERVICE: 'CPU utilization',
NagiosProps.STATUS: 'WARNING'}
service_data2 = {NagiosProps.RESOURCE_NAME: 'compute-1',
NagiosProps.SERVICE: 'CPU utilization',
NagiosProps.STATUS: 'OK'}
service_data3 = {NagiosProps.RESOURCE_NAME: 'compute-1',
NagiosProps.SERVICE: 'Uptime',
NagiosProps.STATUS: 'OK'}
nagios_synchronizer.set_service_datas([service_data1,
service_data2,
service_data3])
services = nagios_synchronizer._get_services()
# Test assertions
self.assertIsNotNone(services, 'No services returned')
self.assertEqual(1, len(services))
self._assert_contains(service_data1, services)
# Action
service_data1 = {NagiosProps.RESOURCE_NAME: 'compute-0',
NagiosProps.SERVICE: 'CPU utilization',
NagiosProps.STATUS: 'CRITICAL'}
service_data2 = {NagiosProps.RESOURCE_NAME: 'compute-1',
NagiosProps.SERVICE: 'CPU utilization',
NagiosProps.STATUS: 'WARNING'}
service_data3 = {NagiosProps.RESOURCE_NAME: 'compute-1',
NagiosProps.SERVICE: 'Uptime',
NagiosProps.STATUS: 'OK'}
nagios_synchronizer.set_service_datas([service_data1,
service_data2,
service_data3])
services = nagios_synchronizer._get_services()
# Test assertions
self.assertIsNotNone(services, 'No services returned')
self.assertEqual(2, len(services))
self._assert_contains(service_data1, services)
self._assert_contains(service_data2, services)
# Action
service_data1 = {NagiosProps.RESOURCE_NAME: 'compute-0',
NagiosProps.SERVICE: 'CPU utilization',
NagiosProps.STATUS: 'OK'}
service_data2 = {NagiosProps.RESOURCE_NAME: 'compute-1',
NagiosProps.SERVICE: 'CPU utilization',
NagiosProps.STATUS: 'OK'}
service_data3 = {NagiosProps.RESOURCE_NAME: 'compute-1',
NagiosProps.SERVICE: 'Uptime',
NagiosProps.STATUS: 'OK'}
nagios_synchronizer.set_service_datas([service_data1,
service_data2,
service_data3])
services = nagios_synchronizer._get_services()
# Test assertions
# The services of service_data1/2 should be returned although their
# status is OK, because they were not OK earlier
self.assertIsNotNone(services, 'No services returned')
self.assertEqual(2, len(services))
self._assert_contains(service_data1, services)
self._assert_contains(service_data2, services)
# Action
services = nagios_synchronizer._get_services()
# Test assertions
# Calling get_services again should not return anything, since all
# services are still OK
self.assertIsNotNone(services, 'services is None')
self.assertEqual(0, len(services))