Merge "implements: blueprint synchronizer-nagios-get-all"
This commit is contained in:
commit
db68a02b03
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
{
|
||||
"status": "OK",
|
||||
"event_type": "DELETE"
|
||||
"status": "OK"
|
||||
}
|
37
vitrage/tests/unit/synchronizer/nagios/nagios_base_test.py
Normal file
37
vitrage/tests/unit/synchronizer/nagios/nagios_base_test.py
Normal 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)
|
@ -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
|
@ -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)
|
||||
|
@ -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))
|
Loading…
x
Reference in New Issue
Block a user