92ac626c9b
Change-Id: Ieb4039e5af8d876218ce9b20d6f293c3dff989a9
145 lines
5.2 KiB
Python
145 lines
5.2 KiB
Python
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
|
|
# 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.
|
|
|
|
"""Classes to aid in configuration of the agent."""
|
|
|
|
import collections
|
|
import logging
|
|
import os
|
|
import pwd
|
|
import yaml
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class Plugins(collections.defaultdict):
|
|
|
|
"""A container for the plugin configurations used by the monasca-agent.
|
|
|
|
This is essentially a defaultdict(dict) but put into a class primarily to make the
|
|
interface clear, also to add a couple of helper methods.
|
|
Each plugin config is stored with the key being its config name (excluding .yaml).
|
|
The value a dict which will convert to yaml.
|
|
"""
|
|
|
|
def __init__(self):
|
|
super(Plugins, self).__init__(dict)
|
|
|
|
# todo Possibly enforce the key being a string without .yaml in it.
|
|
|
|
def diff(self, other_plugins):
|
|
raise NotImplementedError
|
|
|
|
def merge(self, other):
|
|
"""Do a deep merge with precedence going to other (as is the case with update).
|
|
|
|
"""
|
|
# Implemented as a function so it can be used for arbitrary dictionaries not just self,
|
|
# this is needed for the recursive nature of the merge.
|
|
deep_merge(self, other)
|
|
|
|
|
|
def deep_merge(adict, other):
|
|
"""A recursive merge of two dictionaries including combining of any lists within the data
|
|
structure.
|
|
|
|
"""
|
|
for key, value in other.items():
|
|
if key in adict:
|
|
if isinstance(adict[key], dict) and isinstance(value, dict):
|
|
deep_merge(adict[key], value)
|
|
elif isinstance(adict[key], list) and isinstance(value, list):
|
|
adict[key] += value
|
|
else:
|
|
adict[key] = value
|
|
|
|
|
|
def merge_by_name(first, second):
|
|
"""Merge a list of dictionaries replacing any dictionaries with the same 'name' value rather
|
|
than merging.
|
|
|
|
The precedence goes to first.
|
|
"""
|
|
first_names = [i['name'] for i in first if 'name' in i]
|
|
for item in second:
|
|
if 'name' not in item or item['name'] not in first_names:
|
|
first.append(item)
|
|
|
|
|
|
def read_plugin_config_from_disk(config_dir, plugin_name):
|
|
"""Reads from the Agent on disk configuration the config for a specific plugin
|
|
:param config_dir: Monasca Agent configuration directory
|
|
:param plugin_name: The name of the check plugin
|
|
:return: Dictionary of parsed yaml content
|
|
"""
|
|
config_path = os.path.join(config_dir, 'conf.d', plugin_name + '.yaml')
|
|
config = None
|
|
if os.path.exists(config_path):
|
|
with open(config_path, 'r') as config_file:
|
|
config = yaml.safe_load(config_file.read())
|
|
return config
|
|
|
|
|
|
def save_plugin_config(config_dir, plugin_name, user, conf):
|
|
"""Writes configuration for plugin_name to disk in the config_dir
|
|
:param config_dir: Monasca Agent configuration directory
|
|
:param plugin_name: The name of the check plugin
|
|
:param user: The username Monasca-agent will run as
|
|
:param conf: The value of the configuration to write to disk
|
|
:return: None
|
|
"""
|
|
config_path = os.path.join(config_dir, 'conf.d', plugin_name + '.yaml')
|
|
|
|
with open(config_path, 'w') as config_file:
|
|
# The gid is created on service activation which we assume has happened
|
|
config_file.write((yaml.safe_dump(conf,
|
|
encoding='utf-8',
|
|
allow_unicode=True,
|
|
default_flow_style=False)).decode('utf-8'))
|
|
stat = pwd.getpwnam(user)
|
|
|
|
gid = stat.pw_gid
|
|
uid = stat.pw_uid
|
|
|
|
os.chmod(config_path, 0o640)
|
|
os.chown(config_path, uid, gid)
|
|
|
|
|
|
def check_endpoint_changes(value, config):
|
|
"""Change urls in config with same path but different protocols into new
|
|
endpoints.
|
|
"""
|
|
new_url = value['instances'][0]['url']
|
|
old_urls = [i['url'] for i in config['instances'] if 'url' in i]
|
|
new_path = new_url.split("://")[1]
|
|
old_paths = [url.split("://")[1] for url in old_urls]
|
|
for i, old_path in enumerate(old_paths):
|
|
if old_path == new_path:
|
|
if config['instances'][i]['url'] == config['instances'][i]['name']:
|
|
config['instances'][i]['name'] = new_url
|
|
config['instances'][i]['url'] = new_url
|
|
return config
|
|
|
|
|
|
def delete_from_config(args, config, file_path, plugin_name):
|
|
if args.dry_run:
|
|
info_msg = ("Changes would be made to the config file {0}".format(file_path))
|
|
else:
|
|
if len(config['instances']) == 0:
|
|
info_msg = ("Removing configuration file {0} it is no longer needed.".format(file_path))
|
|
os.remove(file_path)
|
|
else:
|
|
info_msg = ("Saving changes to configuration file {0}.".format(file_path))
|
|
save_plugin_config(args.config_dir, plugin_name, args.user, config)
|
|
log.info(info_msg)
|