ea8d4a7594
Change the auth related options corresponding to keystone v3:
admin_password -> password
admin_tenant_name -> project_name
admin_user -> username
identity_uri -> auth_url
Change-Id: Id1dd6424cfa2f040864f4336a1b996e02f470b3a
(cherry picked from commit 37df865559
)
207 lines
9.0 KiB
Python
207 lines
9.0 KiB
Python
# (C) Copyright 2016 Hewlett Packard Enterprise Development Company LP
|
|
|
|
import ConfigParser
|
|
import logging
|
|
import os
|
|
import re
|
|
|
|
from monasca_setup import agent_config
|
|
from monasca_setup import detection
|
|
from monasca_setup.detection import utils
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
# Maximum time to wait before updating neutron router cache(in seconds)
|
|
neutron_refresh = 60 * 60 * 4 # Four hours
|
|
# Directory to use for metric caches
|
|
cache_dir = "/dev/shm"
|
|
# ovs-vsctl command needs sudo privileges to connect to
|
|
# /var/run/openvswitch/db.sock which is created by ovsdb-server.
|
|
ovs_cmd = "sudo /usr/bin/ovs-vsctl"
|
|
# If set, will submit network metrics in bits
|
|
network_use_bits = False
|
|
# Regular expression for interface types
|
|
included_interface_re = 'qg.*|vhu.*|sg.*'
|
|
# If set, will submit raw counters from ovs-vsctl command output for the given
|
|
# network interface
|
|
use_absolute_metrics = True
|
|
# If set, will submit the rate metrics
|
|
use_rate_metrics = True
|
|
# If set, will submit the health metrics
|
|
use_health_metrics = True
|
|
# If set, router max capacity metrics will be published
|
|
publish_router_capacity = False
|
|
# Acceptable arguments
|
|
acceptable_args = ['username', 'password', 'project_name',
|
|
'auth_url', 'cache_dir', 'neutron_refresh', 'ovs_cmd',
|
|
'network_use_bits', 'check_router_ha', 'region_name',
|
|
'included_interface_re', 'conf_file_path', 'use_absolute_metrics',
|
|
'use_rate_metrics', 'use_health_metrics', 'publish_router_capacity']
|
|
# Arguments which must be ignored if provided
|
|
ignorable_args = ['username', 'password', 'project_name',
|
|
'auth_url', 'region_name', 'conf_file_path']
|
|
|
|
|
|
class Ovs(detection.Plugin):
|
|
"""Detect OVS daemons and setup configuration to monitor
|
|
|
|
"""
|
|
|
|
PROC_NAME = 'neutron-openvsw'
|
|
"""Name of the ovs process to look for"""
|
|
REQUIRED_CONF_SECTIONS = 'keystone_authtoken',
|
|
"""Tuple of sections that must be part of neutron configuration file"""
|
|
|
|
def _detect(self):
|
|
process_exist = utils.find_process_cmdline(Ovs.PROC_NAME)
|
|
has_dependencies = self.dependencies_installed()
|
|
neutron_conf = self._get_ovs_config_file() if process_exist else ''
|
|
neutron_conf_exists = os.path.isfile(neutron_conf)
|
|
neutron_conf_valid = (neutron_conf_exists
|
|
and self._is_neutron_conf_valid(neutron_conf))
|
|
|
|
self.available = (process_exist is not None and
|
|
neutron_conf_valid and has_dependencies)
|
|
if not self.available:
|
|
if not process_exist:
|
|
log.error('OVS daemon process [%s] does not exist.',
|
|
Ovs.PROC_NAME)
|
|
elif not neutron_conf_exists:
|
|
log.error(('OVS daemon process exists but configuration '
|
|
'file was not found. Path to file does not exist '
|
|
'as a process parameter or was not '
|
|
'passed via args.'))
|
|
elif not neutron_conf_valid:
|
|
log.error(('OVS daemon process exists, configuration file was '
|
|
'found but it looks like it does not contain '
|
|
'one of following sections=%s. '
|
|
'Check if neutron was not configured to load '
|
|
'configuration from /etc/neutron/neutron.conf.d/.'),
|
|
Ovs.REQUIRED_CONF_SECTIONS)
|
|
# NOTE(trebskit) the problem with that approach is that
|
|
# each setting that Ovs plugin require might be scattered
|
|
# through multiple files located inside
|
|
# /etc/neutron/neutron.conf.d/
|
|
# not to mention that it is still possible to have
|
|
# yet another configuration file passed as neutron CLI
|
|
# argument
|
|
elif not has_dependencies:
|
|
log.error(('OVS daemon process exists but required '
|
|
'dependence python-neutronclient is '
|
|
'not installed.'))
|
|
else:
|
|
log.info("\tUsing neutron configuration file {0}".format(neutron_conf))
|
|
self.neutron_conf = neutron_conf
|
|
|
|
def _is_neutron_conf_valid(self, conf_file):
|
|
neutron_cfg = ConfigParser.SafeConfigParser()
|
|
neutron_cfg.read(conf_file)
|
|
|
|
for section in self.REQUIRED_CONF_SECTIONS:
|
|
if not neutron_cfg.has_section(section=section):
|
|
return False
|
|
|
|
return True
|
|
|
|
def _get_ovs_config_file(self):
|
|
neutron_conf = None
|
|
if self.args:
|
|
for arg in self.args:
|
|
if arg == 'conf_file_path':
|
|
neutron_conf = self.args[arg]
|
|
# Try to detect the location of the Neutron configuration file.
|
|
# Walk through the list of processes, searching for 'neutron'
|
|
# process with 'neutron.conf' inside one of the parameters.
|
|
if not neutron_conf:
|
|
proc = utils.find_process_name(Ovs.PROC_NAME)
|
|
proc_dict = proc.as_dict(attrs=['cmdline'])
|
|
cmd = proc_dict['cmdline']
|
|
neutron_config_params = [param for param in cmd if
|
|
'neutron.conf' in param]
|
|
if neutron_config_params:
|
|
if '=' in neutron_config_params[0]:
|
|
neutron_conf = neutron_config_params[0].split('=')[1]
|
|
else:
|
|
neutron_conf = neutron_config_params[0]
|
|
return neutron_conf
|
|
|
|
def build_config(self):
|
|
"""Build the config as a Plugins object and return.
|
|
|
|
"""
|
|
config = agent_config.Plugins()
|
|
neutron_cfg = ConfigParser.SafeConfigParser()
|
|
log.info("\tUsing neutron configuration file %s", self.neutron_conf)
|
|
neutron_cfg.read(self.neutron_conf)
|
|
cfg_section = 'keystone_authtoken'
|
|
cfg_needed = {'username': 'username',
|
|
'password': 'password',
|
|
'project_name': 'project_name'}
|
|
|
|
# Start with plugin-specific configuration parameters
|
|
init_config = {'cache_dir': cache_dir,
|
|
'neutron_refresh': neutron_refresh,
|
|
'ovs_cmd': ovs_cmd,
|
|
'network_use_bits': network_use_bits,
|
|
'included_interface_re': included_interface_re,
|
|
'use_absolute_metrics': use_absolute_metrics,
|
|
'use_rate_metrics': use_rate_metrics,
|
|
'use_health_metrics': use_health_metrics,
|
|
'publish_router_capacity': publish_router_capacity}
|
|
|
|
for option in cfg_needed:
|
|
init_config[option] = neutron_cfg.get(cfg_section, cfg_needed[option])
|
|
|
|
# Create an identity URI (again, slightly different for Devstack)
|
|
if neutron_cfg.has_option(cfg_section, 'auth_url'):
|
|
init_config['auth_url'] = neutron_cfg.get(cfg_section, 'auth_url')
|
|
else:
|
|
init_config['auth_url'] = neutron_cfg.get(cfg_section, 'identity_uri')
|
|
|
|
# Create an region_name (again, slightly different for Devstack)
|
|
if neutron_cfg.has_option('service_auth', 'region'):
|
|
init_config['region_name'] = str(neutron_cfg.get('service_auth', 'region'))
|
|
else:
|
|
try:
|
|
init_config['region_name'] = str(neutron_cfg.get('nova', 'region_name'))
|
|
except ConfigParser.NoOptionError:
|
|
log.debug(('Option region_name was not found in nova '
|
|
'section, nova_region_name option from '
|
|
'DEFAULT section will be used.'))
|
|
init_config['region_name'] = str(neutron_cfg.get('DEFAULT',
|
|
'nova_region_name'))
|
|
|
|
# Handle monasca-setup detection arguments, which take precedence
|
|
if self.args:
|
|
for arg in self.args:
|
|
if arg in acceptable_args and arg not in ignorable_args:
|
|
if arg == 'included_interface_re':
|
|
try:
|
|
re.compile(self.args[arg])
|
|
except re.error as e:
|
|
exception_msg = (
|
|
"Invalid regular expression given for "
|
|
"'included_interface_re'. {0}.".format(e))
|
|
log.exception(exception_msg)
|
|
raise Exception(exception_msg)
|
|
|
|
init_config[arg] = self.literal_eval(self.args[arg])
|
|
elif arg in ignorable_args:
|
|
log.warn("Argument '{0}' is ignored; Fetching {0} from "
|
|
"neutron configuration file.".format(arg))
|
|
else:
|
|
log.warn("Invalid argument '{0}' "
|
|
"has been provided!!!".format(arg))
|
|
|
|
config['ovs'] = {'init_config': init_config,
|
|
'instances': []}
|
|
|
|
return config
|
|
|
|
def dependencies_installed(self):
|
|
try:
|
|
import neutronclient.v2_0.client
|
|
except ImportError:
|
|
return False
|
|
return True
|