def _monitor_ping_endpoint(self): config = agent_config.Plugins() http_conf = self._config.get('http', None) if http_conf['enabled']: host, port = self._explode_bind_address(http_conf) listening = utils.find_addrs_listening_on_port(port) dimensions = {'service': 'influxdb', 'component': 'influxdb'} if self.args and self.args.get(self.INFLUXDB_NODE_ARG_NAME): dimensions.update({ self.INFLUXDB_NODE_ARG_NAME: self.args.get(self.INFLUXDB_NODE_ARG_NAME) }) if listening: config['http_check'] = { 'init_config': None, 'instances': [{ 'name': 'influxdb', 'url': 'http://%s:%d/ping' % (host, port), 'dimensions': dimensions }] } else: LOG.warning( '\tInfluxDB[http] is enabled but nothing ' 'could be found listening at %d port', port) else: LOG.info('\tInfluxDB[http] is not enabled, skipping') return config
def watch_process(search_strings, service=None, component=None, exact_match=True, detailed=True, process_name=None): """Takes a list of process search strings and returns a Plugins object with the config set. This was built as a helper as many plugins setup process watching """ config = agent_config.Plugins() # Fallback to default process_name strategy if process_name is not defined process_name = process_name if process_name else search_strings[0] parameters = { 'name': process_name, 'detailed': detailed, 'exact_match': exact_match, 'search_string': search_strings } dimensions = _get_dimensions(service, component) if len(dimensions) > 0: parameters['dimensions'] = dimensions config['process'] = {'init_config': None, 'instances': [parameters]} return config
def _monitor_ping_endpoint(self): config = agent_config.Plugins() http_conf = self._config.get('http', None) if http_conf['enabled']: host, port = self._explode_bind_address(http_conf) listening = utils.find_addrs_listening_on_port(port) if listening: config['http_check'] = { 'init_config': None, 'instances': [{ 'name': 'influxdb', 'url': 'http://%s:%d/ping' % (host, port) }] } else: LOG.warning( '\tInfluxDB[http] is enabled but nothing ' 'could be found listening at %d port', port) else: LOG.info('\tInfluxDB[http] is not enabled, skipping') return config
def build_config(self): """Build the config as a Plugins object and return. """ config = agent_config.Plugins() for process in self.found_processes: # Watch the service processes log.info("\tMonitoring the {0} {1} process.".format( process, self.service_name)) config.merge( watch_process([process], self.service_name, process, exact_match=False)) if self.service_api_url and self.search_pattern: # Setup an active http_status check on the API log.info("\tConfiguring an http_check for the {0} API.".format( self.service_name)) config.merge( service_api_check(self.service_name + '-api', self.service_api_url, self.search_pattern, self.service_name)) return config
def build_config(self): """Build the config as a Plugins object and return. """ config = agent_config.Plugins() config.merge(self.ahv_monitoring_config) return config
def _monitor_endpoint(self): config = agent_config.Plugins() http_conf = self._config.get('http', None) if isinstance(http_conf, list): http_conf = http_conf[0] if http_conf: host, port = self._explode_bind_address(http_conf) listening = utils.find_addrs_listening_on_port(port) if listening: LOG.info("\tMonitoring the influxdb-relay ping endpoint") instance = { 'name': 'influxdb-relay', 'url': 'http://%s:%d/ping' % (host, port) } config['http_check'] = { 'init_config': None, 'instances': [instance] } else: LOG.warning( '\tinfluxdb-relay[http] is enabled but nothing ' 'could be found listening at %d port. ' 'It might have happened that process ' 'was just killed and hence port %d ' 'was released.', port, port) return config
def build_config(self): """Build the config as a Plugins object and return back. """ config = agent_config.Plugins() init_config = self._get_init_config() self._configure_ping(init_config) # Handle monasca-setup detection arguments, which take precedence if self.args: for arg in self.args: if arg in INT_ARGS: value = self.args[arg] try: init_config[arg] = int(value) except ValueError: log.warn( "\tInvalid integer value '{0}' for parameter {1}, ignoring value" .format(value, arg)) else: init_config[arg] = self.literal_eval(self.args[arg]) config['libvirt'] = {'init_config': init_config, 'instances': []} return config
def watch_process(search_strings, service=None, component=None, process_name=None, exact_match=True, detailed=False): """ This is a modification of watch_process utils method to accept an additional process_name argument. Takes a list of process search strings and returns a Plugins object with the config set. """ config = agent_config.Plugins() # Fallback to standard process_name strategy if not defined process_name = process_name if process_name else search_strings[0] parameters = { 'name': process_name, 'detailed': detailed, 'exact_match': exact_match, 'search_string': search_strings } dimensions = {'service': service, 'component': component} if len(dimensions) > 0: parameters['dimensions'] = dimensions config['process'] = {'init_config': None, 'instances': [parameters]} return config
def build_config(self): """Build the config as a Plugins object and return.""" LOG.info("\tEnabling the influxdb-relay check") config = agent_config.Plugins() config.merge(self._monitor_process()) config.merge(self._monitor_endpoint()) return config
def build_config(self): """Build the config as a Plugins object and return. """ # A bit silly to parse the yaml only for it to be converted back but this # plugin is the exception not the rule with open(os.path.join(self.template_dir, 'conf.d/postfix.yaml.example'), 'r') as postfix_template: default_net_config = yaml.safe_load(postfix_template.read()) config = agent_config.Plugins() config['postfix'] = default_net_config return config
def build_config(self): kibana_config = self._get_config_file() try: (kibana_host, kibana_port, kibana_protocol) = self._read_config(kibana_config) except Exception as ex: LOG.error('Failed to read configuration at %s' % kibana_config) LOG.exception(ex) return if kibana_protocol == 'https': LOG.error('"https" protocol is currently not supported') return None config = agent_config.Plugins() # retrieve user name and set in config # if passed in args (note args are optional) if (self.args and 'kibana-user' in self.args and self.args['kibana-user']): process = detection.watch_process_by_username( username=self.args['kibana-user'], process_name='kibana', service='monitoring', component='kibana') else: process = detection.watch_process(['kibana'], service='monitoring', component='kibana', process_name='kibana') config.merge(process) kibana_url = '%s://%s:%d' % (kibana_protocol, kibana_host, kibana_port) if not self._has_metrics_support(kibana_url): LOG.warning('Running kibana does not support metrics, skipping...') return None else: metrics = self._get_all_metrics(kibana_url) config['kibana'] = { 'init_config': { 'url': '%s/%s' % (kibana_url, _API_STATUS), }, 'instances': [{ "name": kibana_url, 'metrics': metrics }] } LOG.info('\tWatching the kibana process.') return config
def build_config(self): """Build the config as a Plugins object and return. """ config = agent_config.Plugins() for process in self.found_processes: # Watch the service processes log.info("\tMonitoring the {0} {1} process.".format( process, self.service_name)) config.merge( watch_process([process], self.service_name, process, exact_match=False)) # Skip the http_check if disable_http_check is set if self.args is not None and self.args.get('disable_http_check', False): self.service_api_url = None self.search_pattern = None if self.service_api_url and self.search_pattern: # Check if there is something listening on the host/port parsed = urlparse.urlparse(self.service_api_url) host, port = parsed.netloc.split(':') listening = [] for connection in psutil.net_connections(): if connection.status == psutil.CONN_LISTEN and connection.laddr[ 1] == int(port): listening.append(connection.laddr[0]) if len(listening) > 0: # If not listening on localhost or ips then use another local ip if host == 'localhost' and len( set(['127.0.0.1', '0.0.0.0', '::', '::1']) & set(listening)) == 0: new_url = list(parsed) new_url[1] = listening[0] + ':' + port api_url = urlparse.urlunparse(new_url) else: api_url = self.service_api_url # Setup an active http_status check on the API log.info("\tConfiguring an http_check for the {0} API.".format( self.service_name)) config.merge( service_api_check(self.service_name + '-api', api_url, self.search_pattern, self.service_name)) else: log.info("\tNo process found listening on {0} ".format(port) + "skipping setup of http_check for the {0} API.". format(self.service_name)) return config
def build_config(self): """Build the config as a Plugins object and return.""" config = agent_config.Plugins() config['json_plugin'] = { 'init_config': None, 'instances': [{ 'name': VAR_CACHE_DIR, 'metrics_dir': VAR_CACHE_DIR }] } return config
def watch_file_size(directory_name, file_names, file_recursive): """Takes a directory, a list of files, recursive flag and returns a Plugins object with the config set. """ config = agent_config.Plugins() parameters = {'directory_name': directory_name, 'file_names': file_names, 'recursive': file_recursive} config['file_size'] = {'init_config': None, 'instances': [parameters]} return config
def watch_directory(directory_name, service=None, component=None): """Takes a directory name and returns a Plugins object with the config set. """ config = agent_config.Plugins() parameters = {'directory': directory_name} dimensions = _get_dimensions(service, component) if len(dimensions) > 0: parameters['dimensions'] = dimensions config['directory'] = {'init_config': None, 'instances': [parameters]} return config
def build_config(self): """Build the config as a Plugins object and return.""" LOG.info("\tEnabling the Monasca InfluxDB check") config = agent_config.Plugins() config.merge(self._monitor_process()) config.merge(self._monitor_ping_endpoint()) # NOTE(trebskit) features for next iteration # TODO(trebskit) monitor influx metrics (show stats, show diagnostic) # TODO(trebskit) monitor certificate expiration return config
def build_config(self): """Build the config as a Plugin object and return it. """ log.info('\tEnabling the Monasca crash dump healthcheck') config = agent_config.Plugins() config['crash'] = { 'init_config': None, 'instances': [{ 'name': 'crash_stats' }] } return config
def build_config(self): """Build the config as a Plugins object and return. """ config = agent_config.Plugins() # There may be multiple clusters, and we construct a list of dicts # containing cluster_name and config_file for each cluster clusters = list() # Get the cluster_name from <cluster_name>.conf in /etc/ceph/ directory if os.path.exists(self.ceph_config_dir): config_files = [f for f in os.listdir(self.ceph_config_dir) if f.endswith('.conf')] if not config_files: return config for config_file in config_files: cluster_dict = dict() cluster_dict['cluster_name'] = config_file[:-5] cluster_dict['config_file'] = \ os.path.join(self.ceph_config_dir, config_file) clusters.append(cluster_dict) expected_processes = list() expected_processes.extend(self._service_config(clusters, 'mon')) expected_processes.extend(self._service_config(clusters, 'osd')) expected_processes.extend(self._service_config(clusters, 'mds')) expected_processes.extend(self._service_config(clusters, 'radosgw')) for process in expected_processes: # Watch the service processes log.info("\tMonitoring the {0} {1} process.".format( process['name'], self.service_name)) config.merge(watch_process(search_strings=process['search_string'], service=self.service_name, component=process['type'], process_name=process['name'], exact_match=False)) # Configure ceph plugin instances = [] for cluster in clusters: cluster_name = cluster['cluster_name'] log.info("\tMonitoring ceph cluster: '{0}'.".format(cluster_name)) instances.append({'cluster_name': cluster_name}) config['ceph'] = {'init_config': None, 'instances': instances} return config
def build_config(self): """Build the configs for the system metrics as Plugin objects and return. """ config = agent_config.Plugins() for metric in System.system_metrics: try: with open(os.path.join(self.template_dir, 'conf.d/' + metric + '.yaml'), 'r') as metric_template: default_config = yaml.load(metric_template.read()) config[metric] = default_config log.info('\tConfigured {0}'.format(metric)) except (OSError, IOError): log.info('\tUnable to configure {0}'.format(metric)) continue return config
def build_config(self): """Build the config as a Plugins object and return.""" config = agent_config.Plugins() parameters = {'name': self.CHECK_NAME} # set service and component dimensions = _get_dimensions('block-storage', None) if len(dimensions) > 0: parameters['dimensions'] = dimensions config[self.CHECK_NAME] = { 'init_config': None, 'instances': [parameters] } log.info("\tEnabling the CinderLMDetect plugin %s" % config) return config
def watch_file_size(directory_name, file_names, file_recursive=False, service=None, component=None, dimensions=None): """Takes a directory, a list of files, recursive flag and returns a Plugins object with the config set. """ config = agent_config.Plugins() parameters = {'directory_name': directory_name, 'file_names': file_names, 'recursive': file_recursive} dimensions = _get_dimensions(service, component, dimensions) if len(dimensions) > 0: parameters['dimensions'] = dimensions config['file_size'] = {'init_config': None, 'instances': [parameters]} return config
def build_config(self): """Build the config as a Plugins object and return. """ config = agent_config.Plugins() # There may be multiple clusters, and we construct a list of dicts # containing cluster_name and config_file for each cluster clusters = list() # Get the cluster_name from <cluster_name>.conf in /etc/ceph/ directory if os.path.exists(self.ceph_config_dir): config_files = [ f for f in os.listdir(self.ceph_config_dir) if f.endswith('.conf') ] if not config_files: return config for config_file in config_files: cluster_dict = dict() cluster_dict['cluster_name'] = config_file[:-5] cluster_dict['config_file'] = \ os.path.join(self.ceph_config_dir, config_file) clusters.append(cluster_dict) expected_processes = list() expected_processes.extend(self._service_config(clusters, 'mon')) expected_processes.extend(self._service_config(clusters, 'osd')) expected_processes.extend(self._service_config(clusters, 'mds')) # RADOS Gateway is little different from other ceph-daemons hence # the process definition is handled differently expected_processes.extend(self._radosgw_config(clusters)) for process in expected_processes: # Watch the service processes log.info("\tMonitoring the {0} {1} process.".format( process['name'], self.service_name)) config.merge( watch_process(search_strings=process['search_string'], service=self.service_name, component=process['type'], process_name=process['name'], exact_match=False)) return config
def service_api_check(name, url, pattern, service=None, component=None): """Setup a service api to be watched by the http_check plugin. """ config = agent_config.Plugins() parameters = {'name': name, 'url': url, 'match_pattern': pattern, 'timeout': 10, 'use_keystone': True} dimensions = _get_dimensions(service, component) if len(dimensions) > 0: parameters['dimensions'] = dimensions config['http_check'] = {'init_config': None, 'instances': [parameters]} return config
def watch_process_by_username(username, process_name, service=None, component=None, detailed=True): """Takes a user and returns a Plugins object with the config set for a process check by user. This was built as a helper as many plugins setup process watching. """ config = agent_config.Plugins() parameters = {'name': process_name, 'detailed': detailed, 'username': username} dimensions = _get_dimensions(service, component) if len(dimensions) > 0: parameters['dimensions'] = dimensions config['process'] = {'init_config': None, 'instances': [parameters]} return config
def plugin_detection(plugins, template_dir, detection_args, detection_args_json, skip_failed=True, remove=False): """Runs the detection step for each plugin in the list and returns the complete detected agent config. :param plugins: A list of detection plugin classes :param template_dir: Location of plugin configuration templates :param detection_args: Arguments passed to each detection plugin :param detection_args_json: Alternate json format for detection arguments, use one or the other :param skip_failed: When False any detection failure causes the run to halt and return None :param remove: When True will not log a message indicating the detected name is configuring :return: An agent_config instance representing the total configuration from all detection plugins run. """ plugin_config = agent_config.Plugins() if detection_args_json: json_data = json.loads(detection_args_json) for detect_class in plugins: # todo add option to install dependencies if detection_args_json: detect = detect_class(template_dir, False, **json_data) else: detect = detect_class(template_dir, False, detection_args) if detect.available: new_config = detect.build_config_with_name() if not remove: LOG.info('Configuring {0}'.format(detect.name)) if new_config is not None: plugin_config.merge(new_config) elif not skip_failed: LOG.warning( "Failed detection of plugin %s." "\n\tPossible causes: Service not found or missing arguments. " "\n\tFor services, the service is required to be running at " "detection time. For other plugins, check the args (paths, " "urls, etc)." "\n\tDetection may also fail if monasca-agent services " "(statsd, forwarder, collector) are not running.", detect.name) return None return plugin_config
def build_config(self): """ Build the config as a Plugins object and return. """ config = agent_config.Plugins() parameters = {'name': self.CHECK_NAME} if self.args: for arg in ('metrics_files', 'subcommands', 'suppress_ok'): if arg in self.args: parameters[arg] = self.args.get(arg) # set service and component dimensions = _get_dimensions('object-storage', None) if len(dimensions) > 0: parameters['dimensions'] = dimensions config[self.CHECK_NAME] = {'init_config': None, 'instances': [parameters]} return config
def build_config(self): """Build the config as a Plugins object and return. """ config = agent_config.Plugins() # Default cluster name cluster_name = 'ceph' config_file = '/etc/ceph/ceph.conf' # Get the cluster_name from <cluster_name>.conf in /etc/ceph/ directory if os.path.exists(self.ceph_config_dir): config_files = [ f for f in os.listdir(self.ceph_config_dir) if f.endswith('.conf') ] if not config_files: return config config_file = os.path.join(self.ceph_config_dir, config_files[0]) cluster_name = config_files[0][:-5] expected_processes = list() expected_processes.extend(self._service_config(cluster_name, 'mon')) expected_processes.extend(self._service_config(cluster_name, 'osd')) expected_processes.extend(self._service_config(cluster_name, 'mds')) # RADOS Gateway is little different from other ceph-daemons hence # the process definition is handled differently expected_processes.extend( self._radosgw_config(cluster_name, config_file)) for process in expected_processes: # Watch the service processes log.info("\tMonitoring the {0} {1} process.".format( process['name'], self.service_name)) config.merge( watch_process(search_strings=process['search_string'], service=self.service_name, component=process['type'], process_name=process['name'], exact_match=False)) return config
def __init__(self, template_dir, overwrite=True, args=None, port=9092): Plugin.__init__(self, template_dir, overwrite, args) self.port = port self.zk_url = self._find_zookeeper_url() self.config = agent_config.Plugins()
def build_config(self): """Build the config as a Plugins object and return. """ config = agent_config.Plugins() if self.found_processes: log.info("\tMonitoring by process_name(s): {0} " "for service: {1}.".format(",".join(self.found_processes), self.service_name)) for process in self.found_processes: # Watch the service processes component_name = self.component_name if self.component_name else process config.merge( watch_process(search_strings=[process], service=self.service_name, component=component_name, exact_match=False)) if self.process_username: log.info("\tMonitoring by process_username: {0} for " "service: {1}.".format(self.process_username, self.service_name)) config.merge( watch_process_by_username(username=self.process_username, process_name=self.component_name, service=self.service_name, component=self.component_name)) if self.file_dirs_names: for file_dir_name in self.file_dirs_names: # Watch file size file_dir = file_dir_name[0] file_names = file_dir_name[1] if len(file_dir_name) == 3: file_recursive = file_dir_name[2] else: file_recursive = False if file_names == ['*']: log.info("\tMonitoring the size of all the files in the " "directory {0}.".format(file_dir)) else: log.info("\tMonitoring the size of files {0} in the " "directory {1}.".format( ", ".join(str(name) for name in file_names), file_dir)) config.merge( watch_file_size(directory_name=file_dir, file_names=file_names, file_recursive=file_recursive, service=self.service_name, component=self.component_name)) if self.directory_names: for dir_name in self.directory_names: log.info( "\tMonitoring the size of directory {0}.".format(dir_name)) config.merge( watch_directory(directory_name=dir_name, service=self.service_name, component=self.component_name)) # Skip the http_check if disable_http_check is set if self.args is not None and self.args.get('disable_http_check', False): self.service_api_url = None self.search_pattern = None if self.service_api_url and self.search_pattern: # Check if there is something listening on the host/port parsed = urllib.parse.urlparse(self.service_api_url) host, port = parsed.netloc.split(':') listening = find_addrs_listening_on_port(port) if len(listening) > 0: # If not listening on localhost or ips then use another local ip if host == 'localhost' and len( set(['127.0.0.1', '0.0.0.0', '::', '::1']) & set(listening)) == 0: new_url = list(parsed) new_url[1] = listening[0] + ':' + port api_url = urllib.parse.urlunparse(new_url) else: api_url = self.service_api_url # Setup an active http_status check on the API log.info("\tConfiguring an http_check for the {0} API.".format( self.service_name)) config.merge( service_api_check(name=self.service_name + '-api', url=api_url, pattern=self.search_pattern, use_keystone=True, service=self.service_name, component=self.component_name)) else: log.info("\tNo process found listening on {0} ".format(port) + "skipping setup of http_check for the {0} API.". format(self.service_name)) return config
def build_config(self): """Build the config as a Plugins object and return. """ config = agent_config.Plugins() log.info("\tUsing neutron configuration file {0} and configuration dir" " {1}".format(self.conf.default_config_files, self.conf.default_config_dirs)) cfg_section = 'keystone_authtoken' cfg_needed = { 'username': '******', '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] = self.get_option(cfg_section, cfg_needed[option]) # Create an identity URI (again, slightly different for Devstack) if self.has_option(cfg_section, 'auth_url'): init_config['auth_url'] = self.get_option(cfg_section, 'auth_url') else: init_config['auth_url'] = self.get_option(cfg_section, 'identity_uri') # Create an region_name (again, slightly different for Devstack) if self.has_option('service_auth', 'region'): init_config['region_name'] = str( self.get_option('service_auth', 'region')) else: try: init_config['region_name'] = str( self.get_option('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( self.get_option('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