diff options
author | gord chung <gord@live.ca> | 2017-10-05 16:28:55 +0000 |
---|---|---|
committer | gord chung <gord@live.ca> | 2017-11-16 14:43:46 -0500 |
commit | 50415c0d08a3199d2280f3638dd121779585f0fe (patch) | |
tree | 9e0440b015d697b19a846effee09ba62b4d1ac26 /ceilometer/agent.py | |
parent | 124297b28332c5f047aa71ae362c2071d293d582 (diff) | |
download | ceilometer-50415c0d08a3199d2280f3638dd121779585f0fe.tar.gz |
separate base manager from pipeline
common agent for all
Change-Id: I19a83d3d0e5c91ab5cb6e792ab7389e36f8ede55
Diffstat (limited to 'ceilometer/agent.py')
-rw-r--r-- | ceilometer/agent.py | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/ceilometer/agent.py b/ceilometer/agent.py new file mode 100644 index 00000000..c5a15fdf --- /dev/null +++ b/ceilometer/agent.py @@ -0,0 +1,151 @@ +# +# Copyright 2013 Intel Corp. +# Copyright 2014 Red Hat, Inc +# +# 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 hashlib +import os +import pkg_resources + +from oslo_log import log +from oslo_utils import fnmatch +import six +import yaml + +LOG = log.getLogger(__name__) + + +class ConfigException(Exception): + def __init__(self, cfg_type, message, cfg): + self.cfg_type = cfg_type + self.msg = message + self.cfg = cfg + + def __str__(self): + return '%s %s: %s' % (self.cfg_type, self.cfg, self.msg) + + +class SourceException(Exception): + def __init__(self, message, cfg): + self.msg = message + self.cfg = cfg + + def __str__(self): + return 'Source definition invalid: %s (%s)' % (self.msg, self.cfg) + + +class ConfigManagerBase(object): + """Base class for managing configuration file refresh""" + + def __init__(self, conf): + self.conf = conf + self.cfg_loc = None + + def load_config(self, cfg_file, fallback_cfg_prefix='pipeline/data/'): + """Load a configuration file and set its refresh values.""" + if os.path.exists(cfg_file): + self.cfg_loc = cfg_file + else: + self.cfg_loc = self.conf.find_file(cfg_file) + if not self.cfg_loc and fallback_cfg_prefix is not None: + LOG.debug("No pipeline definitions configuration file found! " + "Using default config.") + self.cfg_loc = pkg_resources.resource_filename( + __name__, fallback_cfg_prefix + cfg_file) + with open(self.cfg_loc) as fap: + data = fap.read() + conf = yaml.safe_load(data) + self.cfg_mtime = self.get_cfg_mtime() + self.cfg_hash = self.get_cfg_hash() + LOG.info("Config file: %s", conf) + return conf + + def get_cfg_mtime(self): + """Return modification time of cfg file""" + return os.path.getmtime(self.cfg_loc) if self.cfg_loc else None + + def get_cfg_hash(self): + """Return hash of configuration file""" + if not self.cfg_loc: + return None + + with open(self.cfg_loc) as fap: + data = fap.read() + if six.PY3: + data = data.encode('utf-8') + + file_hash = hashlib.md5(data).hexdigest() + return file_hash + + def cfg_changed(self): + """Returns hash of changed cfg else False.""" + mtime = self.get_cfg_mtime() + if mtime > self.cfg_mtime: + LOG.info('Configuration file has been updated.') + self.cfg_mtime = mtime + _hash = self.get_cfg_hash() + if _hash != self.cfg_hash: + LOG.info("Detected change in configuration.") + return _hash + return False + + +class Source(object): + """Represents a generic source""" + + def __init__(self, cfg): + self.cfg = cfg + try: + self.name = cfg['name'] + except KeyError as err: + raise SourceException( + "Required field %s not specified" % err.args[0], cfg) + + def __str__(self): + return self.name + + def check_source_filtering(self, data, d_type): + """Source data rules checking + + - At least one meaningful datapoint exist + - Included type and excluded type can't co-exist on the same pipeline + - Included type meter and wildcard can't co-exist at same pipeline + """ + if not data: + raise SourceException('No %s specified' % d_type, self.cfg) + + if ([x for x in data if x[0] not in '!*'] and + [x for x in data if x[0] == '!']): + raise SourceException( + 'Both included and excluded %s specified' % d_type, + self.cfg) + + if '*' in data and [x for x in data if x[0] not in '!*']: + raise SourceException( + 'Included %s specified with wildcard' % d_type, + self.cfg) + + @staticmethod + def is_supported(dataset, data_name): + # Support wildcard like storage.* and !disk.* + # Start with negation, we consider that the order is deny, allow + if any(fnmatch.fnmatch(data_name, datapoint[1:]) + for datapoint in dataset if datapoint[0] == '!'): + return False + + if any(fnmatch.fnmatch(data_name, datapoint) + for datapoint in dataset if datapoint[0] != '!'): + return True + + # if we only have negation, we suppose the default is allow + return all(datapoint.startswith('!') for datapoint in dataset) |