Skip to content
Snippets Groups Projects
Select Git revision
  • f74cb8438025de1d4a925e71847cdfafb7663b66
  • develop default protected
  • master protected
  • feature/POL1-813-error-report-sensu-check
  • 0.22
  • 0.21
  • 0.20
  • 0.19
  • 0.18
  • 0.17
  • 0.16
  • 0.15
  • 0.14
  • 0.13
  • 0.12
  • 0.11
  • 0.10
  • 0.9
  • 0.8
  • 0.7
  • 0.6
  • 0.5
  • 0.4
  • 0.3
24 results

configuration.py

Blame
  • configuration.py 9.39 KiB
    import json
    import logging
    import logging.config
    import os
    from typing import Union
    
    import jsonschema
    
    from brian_polling_manager import inventory
    
    logger = logging.getLogger(__name__)
    
    _DEFAULT_LOGGING_FILENAME = os.path.join(
        os.path.dirname(__file__),
        'logging_default_config.json')
    
    _DEFAULT_CONFIG = {
        'inventory': [
            'http://test-inventory-provider01.geant.org:8080',
            'http://test-inventory-provider02.geant.org:8080'
        ],
        'sensu': {
            'api-base': [
                'https://test-poller-sensu-agent01.geant.org:8080',
                'https://test-poller-sensu-agent02.geant.org:8080',
                'https://test-poller-sensu-agent03.geant.org:8080'
            ],
            'api-key': '696a815c-607e-4090-81de-58988c83033e',
            'interface-check': {
                'script': '/home/brian_checks/venv/get-interface-stats',
                'config': '/var/lib/sensu/conf/get-interface-stats.config.json',
                'command': '{script} --config {config} {args}',
            },
            'gws-direct-interface-check': {
                'script': '/var/lib/sensu/bin/poll-gws-direct.sh',
                'measurement': 'gwsd_counters',
                'command': '{script} --inventory http://localhost:18080'
                           ' {measurement} {nren} {isp} {hostname} {tag}'
            },
            'dscp32-service-check': {
                'script': '/var/lib/sensu/bin/poll-gws-indirect.sh',
                'measurement': 'dscp32_counters',
                'command': '{script} {measurement} {service}'
            },
            'eumetsat-multicast-check': {
              'script': '/home/brian_checks/venv/eumetsat-multicast',
              'measurement': 'multicast',
              'command': '{script} --inventory http://localhost:18080'
                         ' --measurement {measurement} --hostname {hostname}'
            }
        },
        'statedir': '/tmp/',
        'logging': _DEFAULT_LOGGING_FILENAME,
        'statsd': {
            'hostname': 'localhost',
            'port': 8125,
            'prefix': 'brian_polling'
        }
    }
    
    CONFIG_SCHEMA = {
        '$schema': 'http://json-schema.org/draft-07/schema#',
        'definitions': {
            'influx-check': {
                'type': 'object',
                'properties': {
                    'script': {'type': 'string'},
                    'measurement': {'type': 'string'},
                    'command': {'type': 'string'},
                },
                'required': ['script', 'measurement', 'command'],
                'additionalProperties': False
            },
            'router-check': {
                'type': 'object',
                'properties': {
                    'script': {'type': 'string'},
                    'config': {'type': 'string'},
                    'command': {'type': 'string'},
                },
                'required': ['script', 'config', 'command'],
                'additionalProperties': False
            },
            'sensu': {
                'type': 'object',
                'properties': {
                    'api-base': {
                        'type': 'array',
                        'items': {'type': 'string'},
                        'minItems': 1
                    },
                    'api-key': {'type': 'string'},
                    'interface-check':
                        {'$ref': '#/definitions/router-check'},
                    'gws-direct-interface-check':
                        {'$ref': '#/definitions/influx-check'},
                    'dscp32-service-check':
                        {'$ref': '#/definitions/influx-check'},
                    'eumetsat-multicast-check':
                        {'$ref': '#/definitions/influx-check'},
                },
                'required': [
                    'api-base', 'api-key',
                    'interface-check',
                    'gws-direct-interface-check',
                    'dscp32-service-check',
                    'eumetsat-multicast-check'],
                'additionalProperties': False
            },
            'statsd': {
                'type': 'object',
                'properties': {
                    'hostname': {'type': 'string'},
                    'port': {'type': 'integer'},
                    'prefix': {'type': 'string'}
                },
                'required': ['hostname', 'port', 'prefix'],
                'additionalProperties': False
            }
        },
        'type': 'object',
        'properties': {
            'inventory': {
                'type': 'array',
                'items': {'type': 'string'},
                'minItems': 1
            },
            'sensu': {'$ref': '#/definitions/sensu'},
            'statedir': {'type': 'string'},
            'logging': {'type': 'string'},
            'statsd': {'$ref': '#/definitions/statsd'}
        },
        'required': ['inventory', 'sensu', 'statedir'],
        'additionalProperties': False
    }
    
    
    class State(object):
    
        GWS_DIRECT = 'gws-direct.json'
        GWS_INDIRECT = 'gws-indirect.json'
        INTERFACES = 'interfaces.json'
        STATE = 'state.json'
        EUMET_MC = 'eumetsat-multicast.json'
    
        STATE_SCHEMA = {
            '$schema': 'http://json-schema.org/draft-07/schema#',
            'type': 'object',
            'properties': {
                'last': {'type': 'number'}
            },
            'required': ['last'],
            'additionalProperties': False
        }
    
        def __init__(self, state_dir: str):
            assert os.path.isdir(state_dir)
            self.cache_filenames = {
                'state': os.path.join(state_dir, State.STATE),
                'interfaces': os.path.join(state_dir, State.INTERFACES),
                'gws-direct': os.path.join(state_dir, State.GWS_DIRECT),
                'gws-indirect': os.path.join(state_dir, State.GWS_INDIRECT),
                'eumetsat-multicast': os.path.join(state_dir, State.EUMET_MC)
            }
    
        @staticmethod
        def _load_json(filename, schema):
            try:
                with open(filename) as f:
                    state = json.loads(f.read())
                    jsonschema.validate(state, schema)
                    return state
            except (json.JSONDecodeError, jsonschema.ValidationError, OSError):
                logger.exception(
                    f'unable to open state file {filename}')
                return None
    
        @staticmethod
        def _save_json(filename, new_data, schema):
            try:
                jsonschema.validate(new_data, schema)
            except jsonschema.ValidationError:
                logger.exception('invalid interface state data')
                return
    
            with open(filename, 'w') as f:
                f.write(json.dumps(new_data))
    
        @property
        def last(self) -> int:
            state = State._load_json(
                self.cache_filenames['state'], State.STATE_SCHEMA)
            return state['last'] if state else -1
    
        @last.setter
        def last(self, new_last: Union[float, None]):
            if not new_last or new_last < 0:
                os.unlink(self.cache_filenames['state'])
            else:
                State._save_json(
                    self.cache_filenames['state'],
                    {'last': new_last},
                    State.STATE_SCHEMA)
    
        @property
        def interfaces(self) -> list:
            return State._load_json(
                self.cache_filenames['interfaces'],
                inventory.INVENTORY_INTERFACES_SCHEMA)
    
        @interfaces.setter
        def interfaces(self, new_interfaces):
            State._save_json(
                self.cache_filenames['interfaces'],
                new_interfaces,
                inventory.INVENTORY_INTERFACES_SCHEMA)
    
        @property
        def gws_direct(self) -> list:
            return State._load_json(
                self.cache_filenames['gws-direct'],
                inventory.GWS_DIRECT_SCHEMA)
    
        @gws_direct.setter
        def gws_direct(self, new_interfaces):
            State._save_json(
                self.cache_filenames['gws-direct'],
                new_interfaces,
                inventory.GWS_DIRECT_SCHEMA)
    
        @property
        def gws_indirect(self) -> list:
            return State._load_json(
                self.cache_filenames['gws-indirect'],
                inventory.GWS_INDIRECT_SCHEMA)
    
        @gws_indirect.setter
        def gws_indirect(self, new_services):
            State._save_json(
                self.cache_filenames['gws-indirect'],
                new_services,
                inventory.GWS_INDIRECT_SCHEMA)
    
        @property
        def eumetsat_multicast(self) -> list:
            return State._load_json(
                self.cache_filenames['eumetsat-multicast'],
                inventory.MULTICAST_SUBSCRIPTION_LIST_SCHEMA)
    
        @eumetsat_multicast.setter
        def eumetsat_multicast(self, new_subscriptions):
            State._save_json(
                self.cache_filenames['eumetsat-multicast'],
                new_subscriptions,
                inventory.MULTICAST_SUBSCRIPTION_LIST_SCHEMA)
    
    
    def _setup_logging(filename=None):
        """
        set up logging using the configured filename
    
        :raises: json.JSONDecodeError, OSError, AttributeError,
            ValueError, TypeError, ImportError
        """
        if not filename:
            filename = _DEFAULT_LOGGING_FILENAME
    
        with open(filename) as f:
            # TODO: this mac workaround should be removed ...
            d = json.loads(f.read())
            import platform
            if platform.system() == 'Darwin':
                d['handlers']['syslog_handler']['address'] = '/var/run/syslog'
            logging.config.dictConfig(d)
            # logging.config.dictConfig(json.loads(f.read()))
    
    
    def load_config(file=None):
        """
        loads, validates and returns configuration parameters
    
        :param value: filename (file-like object, opened for reading)
        :return: a dict containing configuration parameters
        :raises: json.JSONDecodeError, jsonschema.ValidationError,
            OSError, AttributeError, ValueError, TypeError, ImportError
        """
        if not file:
            config = _DEFAULT_CONFIG
        else:
            config = json.loads(file.read())
            jsonschema.validate(config, CONFIG_SCHEMA)
    
        _setup_logging(config.get('logging', None))
    
        return config