diff --git a/doc/source/zabbix_vitrage.rst b/doc/source/zabbix_vitrage.rst index b66e30f53..ccd0ff33e 100644 --- a/doc/source/zabbix_vitrage.rst +++ b/doc/source/zabbix_vitrage.rst @@ -7,11 +7,11 @@ Consolidate Zabbix alerts from across multiple sites into a single "at-a-glance" Installation ------------ -Copy the `zabbix_vitrage.py` script into the Zabbix servers' `AlertScriptsPath` directory which is by default `/etc/zabbix/alertscripts` and make it executable: +Copy the `zabbix_vitrage.py` script into the Zabbix servers' `AlertScriptsPath` directory which is by default `/usr/lib/zabbix/alertscripts` and make it executable: | $ wget https://github.com/openstack/vitrage/tree/master/vitrage/datasources/zabbix/auxiliary/zabbix_vitrage.py -| $ cp zabbix_vitrage.py /etc/zabbix/alertscripts/ -| $ chmod 755 /etc/zabbix/alertscripts/zabbix_vitrage.py +| $ cp zabbix_vitrage.py /usr/lib/zabbix/alertscripts/ +| $ chmod 755 /usr/lib/zabbix/alertscripts/zabbix_vitrage.py Configuration ------------- diff --git a/vitrage/common/constants.py b/vitrage/common/constants.py index 74c02f172..0086aa986 100644 --- a/vitrage/common/constants.py +++ b/vitrage/common/constants.py @@ -71,6 +71,12 @@ class SyncMode(object): UPDATE = 'update' +class UpdateMethod(object): + NONE = 'none' + PULL = 'pull' + PUSH = 'push' + + class EntityCategory(object): RESOURCE = 'RESOURCE' ALARM = 'ALARM' diff --git a/vitrage/datasources/__init__.py b/vitrage/datasources/__init__.py index 3078ef9ee..653796c8f 100644 --- a/vitrage/datasources/__init__.py +++ b/vitrage/datasources/__init__.py @@ -27,7 +27,6 @@ OPENSTACK_CLUSTER = 'openstack.cluster' # Register options for the service OPTS = [ - cfg.ListOpt('types', default=[NOVA_HOST_DATASOURCE, NOVA_INSTANCE_DATASOURCE, @@ -44,5 +43,8 @@ OPTS = [ cfg.IntOpt('snapshots_interval', default=600, min=10, - help='interval between full snapshots') + help='interval between full snapshots'), + cfg.StrOpt('notification_topic', + default='vitrage_notifications', + help='Vitrage configured notifications topic') ] diff --git a/vitrage/datasources/aodh/__init__.py b/vitrage/datasources/aodh/__init__.py index 812e970c8..2e3b4a651 100644 --- a/vitrage/datasources/aodh/__init__.py +++ b/vitrage/datasources/aodh/__init__.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +from vitrage.common.constants import UpdateMethod AODH_DATASOURCE = 'aodh' @@ -26,9 +27,15 @@ OPTS = [ default='vitrage.datasources.aodh.driver.AodhDriver', help='Aodh driver class path', required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.PULL, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), cfg.IntOpt('changes_interval', default=20, min=20, - help='interval between checking changes in aodh data source', - required=True), + help='interval between checking changes in aodh data source'), ] diff --git a/vitrage/datasources/aodh/driver.py b/vitrage/datasources/aodh/driver.py index d27cb94bf..d3691d344 100644 --- a/vitrage/datasources/aodh/driver.py +++ b/vitrage/datasources/aodh/driver.py @@ -113,6 +113,10 @@ class AodhDriver(AlarmDriverBase): else: LOG.warning('Unsupported Aodh alarm of type %s' % alarm_type) + @staticmethod + def get_update_method(conf): + return conf[AODH_DATASOURCE].update_method + def _parse_query(data, key): query_fields = data.get(AodhProps.QUERY, {}) diff --git a/vitrage/datasources/cinder/volume/__init__.py b/vitrage/datasources/cinder/volume/__init__.py index c0a14fde7..aafbc43e6 100644 --- a/vitrage/datasources/cinder/volume/__init__.py +++ b/vitrage/datasources/cinder/volume/__init__.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +from vitrage.common.constants import UpdateMethod CINDER_VOLUME_DATASOURCE = 'cinder.volume' @@ -27,7 +28,11 @@ OPTS = [ 'CinderVolumeDriver', help='Nova host driver class path', required=True), - cfg.StrOpt('notification_topic', - default='vitrage_notifications', - help='Cinder configured notifications topic for Vitrage'), + cfg.StrOpt('update_method', + default=UpdateMethod.PUSH, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), ] diff --git a/vitrage/datasources/cinder/volume/driver.py b/vitrage/datasources/cinder/volume/driver.py index 70c3d9875..0325c71e9 100644 --- a/vitrage/datasources/cinder/volume/driver.py +++ b/vitrage/datasources/cinder/volume/driver.py @@ -68,5 +68,5 @@ class CinderVolumeDriver(DriverBase): 'volume.delete.end'] @staticmethod - def get_topic(conf): - return conf[CINDER_VOLUME_DATASOURCE].notification_topic + def get_update_method(conf): + return conf[CINDER_VOLUME_DATASOURCE].update_method diff --git a/vitrage/datasources/driver_base.py b/vitrage/datasources/driver_base.py index 894d430e6..9a71d40db 100644 --- a/vitrage/datasources/driver_base.py +++ b/vitrage/datasources/driver_base.py @@ -116,21 +116,16 @@ class DriverBase(object): @staticmethod @abc.abstractmethod - def get_topic(conf): - """Return the topic of events processed by this driver + def get_update_method(conf): + """Return the update method for this driver - Example: - to listen to nova topic, add another topic to nova.conf so nova will - notify the notifications to another queue. - - example of nova.conf: - notification_topics = notifications,new_topic - - example of get_topic(): - return 'new_topic' + update methods available are: + None: updates only via overall snapshots + Pull: updates every [changes_interval] seconds + Push: updates by getting notifications from the datasource itself :param conf: the datasource's configuration - :return: the topic of the datasource + :return: the update method of the datasource :rtype: str """ diff --git a/vitrage/datasources/launcher.py b/vitrage/datasources/launcher.py index be5ef1eb4..4bc9da7c8 100644 --- a/vitrage/datasources/launcher.py +++ b/vitrage/datasources/launcher.py @@ -17,11 +17,12 @@ import itertools from oslo_service import service as os_service from oslo_utils import importutils as utils +from vitrage.common.constants import UpdateMethod +from vitrage.common.utils import opt_exists from vitrage.datasources.listener_service import ListenerService -from services import ChangesService -from services import SnapshotsService -from vitrage.common.utils import opt_exists +from vitrage.datasources.services import ChangesService +from vitrage.datasources.services import SnapshotsService CHANGES_INTERVAL = 'changes_interval' @@ -37,7 +38,7 @@ class Launcher(object): def __init__(self, conf, callback): self.conf = conf self.callback = callback - self.snapshot_datasources = self._register_snapshot_datasources() + self.snapshot_datasources = self._register_snapshot_datasources(conf) self.services = self._register_services() def launch(self): @@ -45,25 +46,34 @@ class Launcher(object): for service in self.services: launcher.launch_service(service, 1) - def _register_snapshot_datasources(self): - return {plugin: utils.import_object(self.conf[plugin].driver, - self.conf) - for plugin in self.conf.datasources.types} + @staticmethod + def _register_snapshot_datasources(conf): + return {datasource: utils.import_object(conf[datasource].driver, conf) + for datasource in conf.datasources.types} def _register_services(self): - return itertools.chain( + pull_datasources = self._get_pull_datasources(self.conf) + changes_services = \ (ChangesService(self.conf, - [self.snapshot_datasources[plugin]], - self.conf[plugin].changes_interval, + [self.snapshot_datasources[datasource]], + self.conf[datasource].changes_interval, self.callback) + for datasource in pull_datasources) - for plugin in self.conf.datasources.types - if opt_exists(self.conf[plugin], CHANGES_INTERVAL)), + snapshot_service = (SnapshotsService(self.conf, + self.snapshot_datasources, + self.callback),) - (SnapshotsService(self.conf, - self.snapshot_datasources, - self.callback),), + listener_service = (ListenerService(self.conf, + self.snapshot_datasources, + self.callback),) - (ListenerService(self.conf, - self.snapshot_datasources, - self.callback),),) + return itertools.chain(changes_services, + snapshot_service, + listener_service) + + @staticmethod + def _get_pull_datasources(conf): + return (datasource for datasource in conf.datasources.types + if conf[datasource].update_method.lower() == UpdateMethod.PULL + and opt_exists(conf[datasource], CHANGES_INTERVAL)) diff --git a/vitrage/datasources/listener_service.py b/vitrage/datasources/listener_service.py index b94a5cb5f..04dbdaeb0 100644 --- a/vitrage/datasources/listener_service.py +++ b/vitrage/datasources/listener_service.py @@ -18,6 +18,7 @@ from oslo_log import log import oslo_messaging from oslo_service import service as os_service +from vitrage.common.constants import UpdateMethod from vitrage import messaging @@ -29,12 +30,11 @@ class ListenerService(os_service.Service): def __init__(self, conf, drivers, callback): super(ListenerService, self).__init__() - # Get the topics of the drivers and callbacks - topics = self._get_topics_set(drivers, conf) self.enrich_callbacks_by_events = \ self._create_callbacks_by_events_dict(drivers, conf) - self.listener = self._get_topics_listener(conf, topics, callback) + topic = conf.datasources.notification_topic + self.listener = self._get_topic_listener(conf, topic, callback) def start(self): LOG.info("Vitrage data source Listener Service - Starting...") @@ -51,36 +51,31 @@ class ListenerService(os_service.Service): LOG.info("Vitrage data source Listener Service - Stopped!") - @staticmethod - def _get_topics_set(drivers, conf): - topics = {driver.get_topic(conf) for driver in drivers.values()} - - if None in topics: - topics.remove(None) - - return topics - - @staticmethod - def _create_callbacks_by_events_dict(drivers, conf): + @classmethod + def _create_callbacks_by_events_dict(cls, drivers, conf): ret = defaultdict(list) + push_drivers = cls._get_push_drivers(drivers, conf) - for driver in drivers.values(): + for driver in push_drivers: for event in driver.get_event_types(conf): ret[event].append(driver.enrich_event) return ret - def _get_topics_listener(self, conf, topics, callback): + @staticmethod + def _get_push_drivers(drivers, conf): + return (driver for driver in drivers.values() + if driver.get_update_method(conf).lower() == UpdateMethod.PUSH) + + def _get_topic_listener(self, conf, topic, callback): # Create a listener for each topic transport = messaging.get_transport(conf) - targets = [oslo_messaging.Target(topic=topic, exchange='nova') - for topic in topics] + targets = [oslo_messaging.Target(topic=topic, exchange='nova')] return messaging.get_notification_listener( transport, targets, - [NotificationsEndpoint(self.enrich_callbacks_by_events, - callback)]) + [NotificationsEndpoint(self.enrich_callbacks_by_events, callback)]) class NotificationsEndpoint(object): diff --git a/vitrage/datasources/nagios/__init__.py b/vitrage/datasources/nagios/__init__.py index 7bdb44b64..d208abf53 100644 --- a/vitrage/datasources/nagios/__init__.py +++ b/vitrage/datasources/nagios/__init__.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +from vitrage.common.constants import UpdateMethod NAGIOS_DATASOURCE = 'nagios' @@ -26,11 +27,17 @@ OPTS = [ default='vitrage.datasources.nagios.driver.NagiosDriver', help='Nagios driver class path', required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.PULL, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), cfg.IntOpt('changes_interval', default=30, min=30, - help='interval between checking changes in nagios data source', - required=True), + help='interval between checking changes in nagios data source'), cfg.StrOpt('user', default='nagiosadmin', help='Nagios user name'), cfg.StrOpt('password', default='nagiosadmin', diff --git a/vitrage/datasources/nagios/driver.py b/vitrage/datasources/nagios/driver.py index fc317c84e..f263fefe3 100644 --- a/vitrage/datasources/nagios/driver.py +++ b/vitrage/datasources/nagios/driver.py @@ -103,3 +103,7 @@ class NagiosDriver(AlarmDriverBase): def _is_valid(self, alarm): return alarm[NagiosProps.RESOURCE_TYPE] is not None and \ alarm[NagiosProps.RESOURCE_NAME] is not None + + @staticmethod + def get_update_method(conf): + return conf[NAGIOS_DATASOURCE].update_method diff --git a/vitrage/datasources/neutron/network/__init__.py b/vitrage/datasources/neutron/network/__init__.py index d2da28f11..ddd44269f 100644 --- a/vitrage/datasources/neutron/network/__init__.py +++ b/vitrage/datasources/neutron/network/__init__.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +from vitrage.common.constants import UpdateMethod NEUTRON_NETWORK_DATASOURCE = 'neutron.network' @@ -27,8 +28,11 @@ OPTS = [ 'NetworkDriver', help='Neutron network driver class path', required=True), - cfg.StrOpt('notification_topic', - default='vitrage_notifications', - help='Neutron network configured notifications topic for ' - 'Vitrage'), + cfg.StrOpt('update_method', + default=UpdateMethod.PUSH, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), ] diff --git a/vitrage/datasources/neutron/network/driver.py b/vitrage/datasources/neutron/network/driver.py index 96d03b498..598154ca1 100644 --- a/vitrage/datasources/neutron/network/driver.py +++ b/vitrage/datasources/neutron/network/driver.py @@ -22,8 +22,8 @@ from vitrage.datasources.neutron.network import NEUTRON_NETWORK_DATASOURCE class NetworkDriver(NeutronBase): @staticmethod - def get_topic(conf): - return conf[NEUTRON_NETWORK_DATASOURCE].notification_topic + def get_update_method(conf): + return conf[NEUTRON_NETWORK_DATASOURCE].update_method @staticmethod def get_event_types(conf): diff --git a/vitrage/datasources/neutron/port/__init__.py b/vitrage/datasources/neutron/port/__init__.py index defdf22f2..ba3d53285 100644 --- a/vitrage/datasources/neutron/port/__init__.py +++ b/vitrage/datasources/neutron/port/__init__.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +from vitrage.common.constants import UpdateMethod NEUTRON_PORT_DATASOURCE = 'neutron.port' @@ -26,7 +27,11 @@ OPTS = [ default='vitrage.datasources.neutron.port.driver.PortDriver', help='Neutron port driver class path', required=True), - cfg.StrOpt('notification_topic', - default='vitrage_notifications', - help='Neutron port configured notifications topic for Vitrage'), + cfg.StrOpt('update_method', + default=UpdateMethod.PUSH, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), ] diff --git a/vitrage/datasources/neutron/port/driver.py b/vitrage/datasources/neutron/port/driver.py index b4c998b6a..c0b9a403c 100644 --- a/vitrage/datasources/neutron/port/driver.py +++ b/vitrage/datasources/neutron/port/driver.py @@ -22,8 +22,8 @@ from vitrage.datasources.neutron.port import NEUTRON_PORT_DATASOURCE class PortDriver(NeutronBase): @staticmethod - def get_topic(conf): - return conf[NEUTRON_PORT_DATASOURCE].notification_topic + def get_update_method(conf): + return conf[NEUTRON_PORT_DATASOURCE].update_method @staticmethod def get_event_types(conf): diff --git a/vitrage/datasources/nova/host/__init__.py b/vitrage/datasources/nova/host/__init__.py index fb498ab00..96fd8c72f 100644 --- a/vitrage/datasources/nova/host/__init__.py +++ b/vitrage/datasources/nova/host/__init__.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +from vitrage.common.constants import UpdateMethod NOVA_HOST_DATASOURCE = 'nova.host' @@ -26,4 +27,11 @@ OPTS = [ default='vitrage.datasources.nova.host.driver.HostDriver', help='Nova host driver class path', required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.NONE, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), ] diff --git a/vitrage/datasources/nova/host/driver.py b/vitrage/datasources/nova/host/driver.py index b74f92dfe..1c6001415 100644 --- a/vitrage/datasources/nova/host/driver.py +++ b/vitrage/datasources/nova/host/driver.py @@ -27,6 +27,10 @@ class HostDriver(NovaDriverBase): compute_hosts.append(host_dict) return compute_hosts + @staticmethod + def get_update_method(conf): + return conf[NOVA_HOST_DATASOURCE].update_method + def get_all(self, sync_mode): return self.make_pickleable( self.filter_none_compute_hosts(self.client.hosts.list()), diff --git a/vitrage/datasources/nova/instance/__init__.py b/vitrage/datasources/nova/instance/__init__.py index dfaa517c5..db83ccdd9 100644 --- a/vitrage/datasources/nova/instance/__init__.py +++ b/vitrage/datasources/nova/instance/__init__.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +from vitrage.common.constants import UpdateMethod NOVA_INSTANCE_DATASOURCE = 'nova.instance' @@ -27,7 +28,11 @@ OPTS = [ 'InstanceDriver', help='Nova instance driver class path', required=True), - cfg.StrOpt('notification_topic', - default='vitrage_notifications', - help='Nova configured notifications topic for Vitrage'), + cfg.StrOpt('update_method', + default=UpdateMethod.PUSH, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), ] diff --git a/vitrage/datasources/nova/instance/driver.py b/vitrage/datasources/nova/instance/driver.py index d3ba918d2..d96a8fbec 100644 --- a/vitrage/datasources/nova/instance/driver.py +++ b/vitrage/datasources/nova/instance/driver.py @@ -69,5 +69,5 @@ class InstanceDriver(NovaDriverBase): 'compute.instance.unpause.end'] @staticmethod - def get_topic(conf): - return conf[NOVA_INSTANCE_DATASOURCE].notification_topic + def get_update_method(conf): + return conf[NOVA_INSTANCE_DATASOURCE].update_method diff --git a/vitrage/datasources/nova/zone/__init__.py b/vitrage/datasources/nova/zone/__init__.py index 5a9d7e89e..a1f1a0b7e 100644 --- a/vitrage/datasources/nova/zone/__init__.py +++ b/vitrage/datasources/nova/zone/__init__.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +from vitrage.common.constants import UpdateMethod NOVA_ZONE_DATASOURCE = 'nova.zone' @@ -27,4 +28,11 @@ OPTS = [ '.ZoneDriver', help='Nova zone datasource class path', required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.NONE, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), ] diff --git a/vitrage/datasources/nova/zone/driver.py b/vitrage/datasources/nova/zone/driver.py index 30eea9475..cb3120324 100644 --- a/vitrage/datasources/nova/zone/driver.py +++ b/vitrage/datasources/nova/zone/driver.py @@ -27,6 +27,10 @@ class ZoneDriver(NovaDriverBase): zones_res.append(zone_dict) return zones_res + @staticmethod + def get_update_method(conf): + return conf[NOVA_ZONE_DATASOURCE].update_method + def get_all(self, sync_mode): return self.make_pickleable(self.filter_internal_zone( self.client.availability_zones.list()), diff --git a/vitrage/datasources/static_physical/__init__.py b/vitrage/datasources/static_physical/__init__.py index 268424186..dd979b869 100644 --- a/vitrage/datasources/static_physical/__init__.py +++ b/vitrage/datasources/static_physical/__init__.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +from vitrage.common.constants import UpdateMethod STATIC_PHYSICAL_DATASOURCE = 'static_physical' SWITCH = 'switch' @@ -28,12 +29,18 @@ OPTS = [ 'StaticPhysicalDriver', help='Static physical driver class path', required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.PULL, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), cfg.IntOpt('changes_interval', default=20, min=5, help='interval between checking changes in the configuration ' - 'files of the physical topology data sources', - required=True), + 'files of the physical topology data sources'), cfg.StrOpt('directory', default='/etc/vitrage/static_datasources', help='Static physical data sources directory'), cfg.ListOpt('entities', diff --git a/vitrage/datasources/static_physical/driver.py b/vitrage/datasources/static_physical/driver.py index 443668360..f27f96f3e 100644 --- a/vitrage/datasources/static_physical/driver.py +++ b/vitrage/datasources/static_physical/driver.py @@ -33,8 +33,8 @@ class StaticPhysicalDriver(DriverBase): pass @staticmethod - def get_topic(conf): - return None + def get_update_method(conf): + return conf[STATIC_PHYSICAL_DATASOURCE].update_method ENTITIES_SECTION = 'entities' diff --git a/vitrage/datasources/zabbix/__init__.py b/vitrage/datasources/zabbix/__init__.py index fba50697c..46100085b 100644 --- a/vitrage/datasources/zabbix/__init__.py +++ b/vitrage/datasources/zabbix/__init__.py @@ -13,6 +13,7 @@ # under the License. from oslo_config import cfg +from vitrage.common.constants import UpdateMethod ZABBIX_DATASOURCE = 'zabbix' @@ -26,11 +27,17 @@ OPTS = [ default='vitrage.datasources.zabbix.driver.ZabbixDriver', help='Zabbix driver class path', required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.PUSH, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), cfg.IntOpt('changes_interval', default=30, - min=30, - help='interval between checking changes in zabbix data source', - required=True), + min=10, + help='interval between checking changes in zabbix data source'), cfg.StrOpt('user', default='admin', help='Zabbix user name'), cfg.StrOpt('password', default='zabbix', @@ -39,7 +46,4 @@ OPTS = [ help='Zabbix url'), cfg.StrOpt('config_file', default='/etc/vitrage/zabbix_conf.yaml', help='Zabbix configuration file'), - cfg.StrOpt('notification_topic', - default='vitrage_notifications', - help='Zabbix configured notifications topic for Vitrage'), ] diff --git a/vitrage/datasources/zabbix/auxiliary/readme b/vitrage/datasources/zabbix/auxiliary/readme index 0a1e20675..db559db5d 100644 --- a/vitrage/datasources/zabbix/auxiliary/readme +++ b/vitrage/datasources/zabbix/auxiliary/readme @@ -10,11 +10,11 @@ Installation ------------ Copy the 'zabbix_vitrage.py' script into the Zabbix servers' 'AlertScriptsPath' -directory which is by default '/etc/zabbix/alertscripts' and make it executable: +directory which is by default '/usr/lib/zabbix/alertscripts' and make it executable: $ wget https://github.com/openstack/vitrage/tree/master/vitrage/datasources/zabbix/auxiliary/zabbix_vitrage.py - $ cp zabbix_vitrage.py /etc/zabbix/alertscripts/ - $ chmod 755 /etc/zabbix/alertscripts/zabbix_vitrage.py + $ cp zabbix_vitrage.py /usr/lib/zabbix/alertscripts/ + $ chmod 755 /usr/lib/zabbix/alertscripts/zabbix_vitrage.py Configuration ------------- diff --git a/vitrage/datasources/zabbix/auxiliary/zabbix_vitrage.py b/vitrage/datasources/zabbix/auxiliary/zabbix_vitrage.py index b8ccc2e7c..aa5e33203 100644 --- a/vitrage/datasources/zabbix/auxiliary/zabbix_vitrage.py +++ b/vitrage/datasources/zabbix/auxiliary/zabbix_vitrage.py @@ -19,6 +19,7 @@ import argparse from datetime import datetime import logging +from logging.handlers import RotatingFileHandler from oslo_config import cfg import oslo_messaging as messaging import six @@ -47,6 +48,7 @@ Message: LOG_FILE = '/var/log/zabbix/zabbix_vitrage.log' +LOG_MAX_SIZE = 10240 LOG_FORMAT = '%(asctime)s.%(msecs).03d %(name)s[%(process)d] %(threadName)s %' \ '(levelname)s - %(message)s' LOG_DATE_FMT = '%Y.%m.%d %H:%M:%S' @@ -68,17 +70,16 @@ def main(): transport_url = args.sendto transport = messaging.get_transport(cfg.CONF, transport_url) - driver = 'messaging' + driver = 'messagingv2' + publisher = 'zabbix_%s' % socket.gethostname() notifier = messaging.Notifier(transport, driver=driver, - publisher_id='zabbix', + publisher_id=publisher, topic='vitrage_notifications') alarm_status = args.topic.lower() event_type = '%s.%s' % (ZABBIX_EVENT_TYPE, alarm_status) - publisher = 'zabbix_%s' % socket.gethostname() - payload = {key.lower().strip(): prop.strip() for key, prop in (line.split('=') for line in args.body.splitlines())} @@ -99,5 +100,9 @@ if __name__ == '__main__': else: logging.basicConfig(filename=LOG_FILE, format=LOG_FORMAT, datefmt=LOG_DATE_FMT, level=logging.DEBUG) - + log = logging.getLogger() + handler = RotatingFileHandler(filename=LOG_FILE, + maxBytes=LOG_MAX_SIZE, + backupCount=1) + log.addHandler(handler) main() diff --git a/vitrage/datasources/zabbix/driver.py b/vitrage/datasources/zabbix/driver.py index 750df94b2..5dacd2422 100644 --- a/vitrage/datasources/zabbix/driver.py +++ b/vitrage/datasources/zabbix/driver.py @@ -187,5 +187,5 @@ class ZabbixDriver(AlarmDriverBase): return ['zabbix.alarm.ok', 'zabbix.alarm.problem'] @staticmethod - def get_topic(conf): - return conf[ZABBIX_DATASOURCE].notification_topic + def get_update_method(conf): + return conf[ZABBIX_DATASOURCE].update_method diff --git a/vitrage/tests/unit/datasources/nagios/mock_driver.py b/vitrage/tests/unit/datasources/nagios/mock_driver.py index 8083c387f..6cfbc9f66 100644 --- a/vitrage/tests/unit/datasources/nagios/mock_driver.py +++ b/vitrage/tests/unit/datasources/nagios/mock_driver.py @@ -13,6 +13,7 @@ # under the License. from vitrage.datasources.nagios.driver import NagiosDriver +from vitrage.datasources.nagios import NAGIOS_DATASOURCE from vitrage.tests.mocks import mock_driver @@ -32,8 +33,8 @@ class MockNagiosDriver(NagiosDriver): pass @staticmethod - def get_topic(conf): - return None + def get_update_method(conf): + return conf[NAGIOS_DATASOURCE].update_method def __init__(self, conf): super(MockNagiosDriver, self).__init__(conf) diff --git a/vitrage/tests/unit/datasources/test_datasource_update_method.py b/vitrage/tests/unit/datasources/test_datasource_update_method.py new file mode 100644 index 000000000..f3ef6823a --- /dev/null +++ b/vitrage/tests/unit/datasources/test_datasource_update_method.py @@ -0,0 +1,197 @@ +# 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 oslo_utils import importutils as utils + +from vitrage.common.constants import UpdateMethod +from vitrage.datasources.launcher import Launcher +from vitrage.datasources.listener_service import ListenerService +from vitrage.datasources.nagios import NAGIOS_DATASOURCE +from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE +from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE +from vitrage.datasources.zabbix import ZABBIX_DATASOURCE +from vitrage.tests import base + + +CHANGES_INTERVAL = 'changes_interval' +LOG = logging.getLogger(__name__) +ZABBIX_DATASOURCE_NONE = '_'.join((ZABBIX_DATASOURCE, UpdateMethod.NONE)) +ZABBIX_DATASOURCE_PULL = '_'.join((ZABBIX_DATASOURCE, UpdateMethod.PULL)) +ZABBIX_DATASOURCE_PUSH = ZABBIX_DATASOURCE +ZABBIX_DATASOURCE_PULL_NO_INTERVAL = \ + '_'.join((ZABBIX_DATASOURCE, UpdateMethod.PULL, 'no_interval')) + + +class DatasourceUpdateMethod(base.BaseTest): + + DATASOURCES_OPTS = [ + cfg.ListOpt('types', + default=[NOVA_HOST_DATASOURCE, + NOVA_INSTANCE_DATASOURCE, + NAGIOS_DATASOURCE, + ZABBIX_DATASOURCE_NONE, + ZABBIX_DATASOURCE_PULL, + ZABBIX_DATASOURCE_PUSH, + ZABBIX_DATASOURCE_PULL_NO_INTERVAL], + help='Names of supported data sources'), + cfg.StrOpt('notification_topic', + default='vitrage_notifications', + help='Vitrage configured notifications topic') + ] + + NOVA_HOST_OPTS = [ + cfg.StrOpt('driver', + default='vitrage.datasources.nova.host.driver.HostDriver', + help='Nova host driver class path', + required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.NONE, + help='None: updates only via Vitrage periodic snapshots.' + 'Pull: updates every [changes_interval] seconds.' + 'Push: updates by getting notifications from the' + ' datasource itself.', + required=True), + ] + + NOVA_INSTANCE_OPTS = [ + cfg.StrOpt('driver', + default='vitrage.datasources.nova.instance.driver.' + 'InstanceDriver', + help='Nova instance driver class path', + required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.PUSH, + required=True), + ] + + NAGIOS_OPTS = [ + cfg.StrOpt('driver', + default='vitrage.datasources.nagios.driver.NagiosDriver', + help='Nagios driver class path', + required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.PULL, + required=True), + cfg.IntOpt('changes_interval', + default=30, + min=30, + help='interval between checking changes in nagios' + ' data source'), + ] + + ZABBIX_OPTS_PUSH = [ + cfg.StrOpt('driver', + default='vitrage.datasources.zabbix.driver.ZabbixDriver', + help='Zabbix driver class path', + required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.PUSH, + required=True), + cfg.IntOpt('changes_interval', + default=30, + min=30, + help='interval between checking changes in zabbix' + ' data source'), + ] + + ZABBIX_OPTS_PULL = [ + cfg.StrOpt('driver', + default='vitrage.datasources.zabbix.driver.ZabbixDriver', + help='Zabbix driver class path', + required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.PULL, + required=True), + cfg.IntOpt('changes_interval', + default=30, + min=30, + help='interval between checking changes in zabbix' + ' data source'), + ] + + ZABBIX_OPTS_PULL_NO_INTERVAL = [ + cfg.StrOpt('driver', + default='vitrage.datasources.zabbix.driver.ZabbixDriver', + help='Zabbix driver class path', + required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.PULL, + required=True), + ] + + ZABBIX_OPTS_NONE = [ + cfg.StrOpt('driver', + default='vitrage.datasources.zabbix.driver.ZabbixDriver', + help='Zabbix driver class path', + required=True), + cfg.StrOpt('update_method', + default=UpdateMethod.NONE, + required=True), + cfg.IntOpt('changes_interval', + default=30, + min=30, + help='interval between checking changes in zabbix' + ' data source'), + ] + + # noinspection PyPep8Naming + @classmethod + def setUpClass(cls): + cls.conf = cfg.ConfigOpts() + cls.conf.register_opts(cls.DATASOURCES_OPTS, group='datasources') + cls.conf.register_opts(cls.NOVA_HOST_OPTS, group=NOVA_HOST_DATASOURCE) + cls.conf.register_opts(cls.NOVA_INSTANCE_OPTS, + group=NOVA_INSTANCE_DATASOURCE) + cls.conf.register_opts(cls.NAGIOS_OPTS, group=NAGIOS_DATASOURCE) + cls.conf.register_opts(cls.ZABBIX_OPTS_NONE, + group=ZABBIX_DATASOURCE_NONE) + cls.conf.register_opts(cls.ZABBIX_OPTS_PULL, + group=ZABBIX_DATASOURCE_PULL) + cls.conf.register_opts(cls.ZABBIX_OPTS_PUSH, + group=ZABBIX_DATASOURCE_PUSH) + cls.conf.register_opts(cls.ZABBIX_OPTS_PULL_NO_INTERVAL, + group=ZABBIX_DATASOURCE_PULL_NO_INTERVAL) + + def test_datasource_update_method_none(self): + none_drivers = tuple(driver for driver in self.conf.datasources.types + if self.conf[driver].update_method + == UpdateMethod.NONE) + self.assertSequenceEqual(none_drivers, + (NOVA_HOST_DATASOURCE, + ZABBIX_DATASOURCE_NONE)) + + def test_datasource_update_method_push(self): + drivers = {driver: utils.import_class(self.conf[driver].driver) + for driver in self.conf.datasources.types} + push_drivers = ListenerService._get_push_drivers( + drivers=drivers, conf=self.conf) + self.assertSequenceEqual(set(push_drivers), {utils.import_class( + self.conf[NOVA_INSTANCE_DATASOURCE].driver), utils.import_class( + self.conf[ZABBIX_DATASOURCE_PUSH].driver)}) + + def test_datasource_update_method_pull(self): + pull_drivers = tuple(Launcher._get_pull_datasources(self.conf)) + self.assertSequenceEqual(pull_drivers, + (NAGIOS_DATASOURCE, + ZABBIX_DATASOURCE_PULL)) + + def test_datasource_update_method_pull_with_no_changes_interval(self): + pull_drivers = tuple(Launcher._get_pull_datasources(self.conf)) + self.assertNotIn(ZABBIX_DATASOURCE_PULL_NO_INTERVAL, pull_drivers) + + def test_datasources_notification_topic(self): + self.assertEqual(self.conf.datasources.notification_topic, + 'vitrage_notifications') diff --git a/vitrage/tests/unit/datasources/zabbix/mock_driver.py b/vitrage/tests/unit/datasources/zabbix/mock_driver.py index 8825465e7..ca1aea4f8 100644 --- a/vitrage/tests/unit/datasources/zabbix/mock_driver.py +++ b/vitrage/tests/unit/datasources/zabbix/mock_driver.py @@ -13,6 +13,7 @@ # under the License. from vitrage.datasources.zabbix.driver import ZabbixDriver +from vitrage.datasources.zabbix import ZABBIX_DATASOURCE from vitrage.tests.mocks import mock_driver @@ -32,8 +33,8 @@ class MockZabbixDriver(ZabbixDriver): pass @staticmethod - def get_topic(conf): - return None + def get_update_method(conf): + return conf[ZABBIX_DATASOURCE].update_method def __init__(self, conf): super(MockZabbixDriver, self).__init__(conf)