
Replace the following items with Python 3 style code. - six.PY2 - six.add_metaclass - six.string_types - six.text_type - six.moves - six.StringIO - six.wraps - six.integer_types Story: 2008305 Task: 41191 Change-Id: I68710421b69d4049c9e990451da491dc14251fb5
223 lines
11 KiB
Python
223 lines
11 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.
|
|
|
|
import logging
|
|
import urllib
|
|
|
|
from monasca_setup import agent_config
|
|
from monasca_setup.detection.plugin import Plugin
|
|
from monasca_setup.detection.utils import find_addrs_listening_on_port
|
|
from monasca_setup.detection.utils import find_process_cmdline
|
|
from monasca_setup.detection.utils import service_api_check
|
|
from monasca_setup.detection.utils import watch_directory
|
|
from monasca_setup.detection.utils import watch_file_size
|
|
from monasca_setup.detection.utils import watch_process
|
|
from monasca_setup.detection.utils import watch_process_by_username
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class ServicePlugin(Plugin):
|
|
"""Base class implemented by the monasca-agent plugin detection classes for OpenStack Services.
|
|
Detection plugins inheriting from this class can easily setup up processes to be watched and
|
|
a http endpoint to be checked.
|
|
|
|
This class covers Process, HTTP endpoints, Directory, and File monitoring. It is primarily
|
|
used for monitoring OpenStack components.
|
|
Note: There are existing default detection plugins for http_check.py, directory.py, and
|
|
file_size.py that only require configuration.
|
|
|
|
A process can be monitored by process_names or by process_username. Pass in the process_names
|
|
list argument when watching process by name. Pass in the process_username argument and
|
|
component_name arguments when watching process by username. Watching by username is useful for
|
|
groups of processes that are owned by a specific user.
|
|
For process monitoring by process_username the component_name is required since it is used to
|
|
initialize the instance name in process.yaml. component_name is optional for monitoring by
|
|
process_name and all other checks.
|
|
|
|
An http endpoint connection can be checked by passing in the service_api_url and optional
|
|
search_pattern parameters.
|
|
The http check can be skipped by specifying the argument 'disable_http_check'
|
|
|
|
Directory size can be checked by passing in a directory_names list.
|
|
|
|
File size can be checked by passing in a file_dirs_names list where each directory name item
|
|
includes a list of files.
|
|
example: 'file_dirs_names': [('/var/log/monasca/api', ['monasca-api'])]
|
|
|
|
Note: service_name and component_name are optional (except component_name is required with
|
|
process_username) arguments used for metric dimensions by all checks.
|
|
"""
|
|
|
|
def __init__(self, kwargs):
|
|
self.service_name = kwargs['service_name']
|
|
self.process_names = kwargs.get('process_names')
|
|
self.process_username = kwargs.get('process_username', None)
|
|
self.component_name = kwargs.get('component_name', None)
|
|
self.file_dirs_names = kwargs.get('file_dirs_names')
|
|
self.directory_names = kwargs.get('directory_names')
|
|
self.service_api_url = kwargs.get('service_api_url')
|
|
self.search_pattern = kwargs.get('search_pattern')
|
|
# overwrite is currently not used with this class, make optional until we remove it.
|
|
overwrite = kwargs.get('overwrite', False)
|
|
template_dir = kwargs['template_dir'],
|
|
if 'args' in kwargs:
|
|
args = kwargs['args']
|
|
if isinstance(args, str):
|
|
try:
|
|
# Turn 'service_api_url=url' into
|
|
# dict {'service_api_url':'url'}
|
|
args_dict = dict(
|
|
[item.split('=') for item in args.split()])
|
|
# Allow args to override all of these parameters
|
|
if 'process_names' in args_dict:
|
|
self.process_names = args_dict['process_names'].split(',')
|
|
if 'process_username' in args_dict:
|
|
self.process_username = args_dict['process_username']
|
|
if 'component_name' in args_dict:
|
|
self.component_name = args_dict['component_name']
|
|
if 'file_dirs_names' in args_dict:
|
|
self.file_dirs_names = args_dict['file_dirs_names']
|
|
if 'directory_names' in args_dict:
|
|
self.directory_names = args_dict['directory_names'].split(',')
|
|
if 'service_api_url' in args_dict:
|
|
self.service_api_url = args_dict['service_api_url']
|
|
if 'search_pattern' in args_dict:
|
|
self.search_pattern = args_dict['search_pattern']
|
|
if 'overwrite' in args_dict:
|
|
overwrite = args_dict['overwrite']
|
|
if 'template_dir' in args_dict:
|
|
template_dir = args_dict['template_dir']
|
|
except Exception:
|
|
log.exception('Error parsing detection arguments')
|
|
|
|
super(ServicePlugin, self).__init__(template_dir, overwrite, kwargs.get('args'))
|
|
|
|
def _detect(self):
|
|
"""Run detection.
|
|
|
|
"""
|
|
self.found_processes = []
|
|
if self.process_names:
|
|
for process in self.process_names:
|
|
if find_process_cmdline(process) is not None:
|
|
self.found_processes.append(process)
|
|
if len(self.found_processes) > 0:
|
|
self.available = True
|
|
if self.process_username and self.component_name:
|
|
self.available = True
|
|
if self.file_dirs_names:
|
|
self.available = True
|
|
if self.directory_names:
|
|
self.available = True
|
|
|
|
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 dependencies_installed(self):
|
|
"""Return True if dependencies are installed.
|
|
|
|
"""
|
|
return True
|