Added new OpenStack services

This commit is contained in:
gary-hessler 2014-06-30 17:24:27 -06:00
parent 52ed313d0c
commit e86e1dc43a
30 changed files with 268 additions and 274 deletions

View File

@ -11,6 +11,7 @@ import time
import traceback
from monagent.common import check_status
from monagent.common.keystone import Keystone
from monagent.common.config import get_confd_path
from monagent.common.exceptions import CheckException, NaN, Infinity, UnknownValue
from monagent.common.util import LaconicFilter, get_hostname, get_os
@ -256,6 +257,8 @@ class Check(object):
class AgentCheck(object):
keystone = None
def __init__(self, name, init_config, agent_config, instances=None):
"""
@ -282,6 +285,12 @@ class AgentCheck(object):
self.warnings = []
self.library_versions = None
api_config = self.agent_config['Api']
AgentCheck.keystone = Keystone(api_config['keystone_url'],
api_config['username'],
api_config['password'],
api_config['project_name'])
def instance_count(self):
""" Return the number of instances that are configured for this check. """
return len(self.instances)
@ -453,6 +462,7 @@ class AgentCheck(object):
instance_statuses = []
for i, instance in enumerate(self.instances):
try:
instance['keystone'] = AgentCheck.keystone
self.check(instance)
if self.has_warnings():
instance_status = check_status.InstanceStatus(i,

View File

@ -8,15 +8,13 @@ import re
from httplib2 import Http, HttpLib2Error, httplib
from monagent.collector.checks.services_checks import ServicesCheck, Status
from monagent.common.keystone import Keystone
from monagent.collector.checks.check import AgentCheck
from monagent.common.config import get_config
token = None
class HTTPCheck(ServicesCheck):
def __init__(self, name, init_config, agent_config, instances=None):
ServicesCheck.__init__(self, name, init_config, agent_config, instances)
super(HTTPCheck, self).__init__(name, init_config, agent_config, instances)
@staticmethod
def _load_conf(instance):
@ -34,28 +32,17 @@ class HTTPCheck(ServicesCheck):
raise Exception("Bad configuration. You must specify a url")
include_content = instance.get('include_content', False)
ssl = instance.get('disable_ssl_validation', True)
config = get_config()
api_config = config['Api']
if use_keystone:
keystone = Keystone(api_config['keystone_url'],
api_config['username'],
api_config['password'],
api_config['project_name'])
else:
keystone = None
token = AgentCheck.keystone.get_token()
return url, username, password, timeout, include_content, headers, response_time, dimensions, ssl, pattern, use_keystone, keystone
return url, username, password, timeout, include_content, headers, response_time, dimensions, ssl, pattern, use_keystone, token
def _create_status_event(self, status, msg, instance):
"""Does nothing: status events are not yet supported by Mon API"""
return
def _check(self, instance):
addr, username, password, timeout, include_content, headers, response_time, dimensions, disable_ssl_validation, pattern, use_keystone, keystone = self._load_conf(instance)
addr, username, password, timeout, include_content, headers, response_time, dimensions, disable_ssl_validation, pattern, use_keystone, token = self._load_conf(instance)
global token
self.keystone = keystone
content = ''
new_dimensions = dimensions.copy()
@ -65,10 +52,9 @@ class HTTPCheck(ServicesCheck):
start = time.time()
done = False
while not done:
retry = False
while not done or retry:
if use_keystone:
if not token:
token = self.keystone.get_token()
if token:
headers["X-Auth-Token"] = token
headers["Content-type"] = "application/json"
@ -125,13 +111,18 @@ class HTTPCheck(ServicesCheck):
if int(resp.status) >= 400:
if use_keystone and int(resp.status) == 401:
# Get a new token and retry
token = self.keystone.refresh_token()
continue
if retry:
return Status.DOWN, "%s is DOWN, unable to get a valid token to connect with" % (addr)
else:
# Get a new token and retry
self.log.warning("Token expired, getting new token and retrying...")
HTTPCheck.token = self.keystone.refresh_token()
retry = True
continue
else:
self.log.info("%s is DOWN, error code: %s" % (addr, str(resp.status)))
self.gauge('http_status', 1, dimensions=new_dimensions)
return
return Status.DOWN, "%s is DOWN, error code: %s" % (addr, str(resp.status))
if pattern is not None:
if re.search(pattern, content, re.DOTALL):

View File

@ -1 +1 @@
__version__ = '1.0.6'
__version__ = '1.0.7'

View File

@ -102,4 +102,4 @@ class MonAPI(object):
kwargs = {
'token': token
}
return client.Client(self.api_version, self.url, **kwargs)
return client.Client(self.api_version, self.url, **kwargs)

View File

@ -1,3 +1,3 @@
from plugin import Plugin
from utils import find_process_cmdline, find_process_name, watch_process, service_api_check
from service_plugin import ServicePlugin

View File

@ -1,36 +0,0 @@
import logging
from . import Plugin, find_process_cmdline, watch_process
from monsetup import agent_config
log = logging.getLogger(__name__)
class Cinder(Plugin):
"""Detect cinder daemons and setup configuration to monitor them."""
def _detect(self):
"""Run detection"""
self.cinder_processes = ['cinder-volume', 'cinder-scheduler']
self.found_processes = []
for process in self.cinder_processes:
if find_process_cmdline(process) is not None:
log.info('Found {0} cinder process'.format(process))
self.found_processes.append(process)
if len(self.found_processes) > 0:
self.available = True
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 Cinder processes
log.info("\tMonitoring the {0} cinder process.".format(process))
config.merge(watch_process([process], 'cinder'))
return config
def dependencies_installed(self):
return True

View File

@ -1,36 +0,0 @@
import logging
from . import Plugin, find_process_cmdline, watch_process, service_api_check
from monsetup import agent_config
log = logging.getLogger(__name__)
class CinderAPI(Plugin):
"""Detect the Cinder-API daemon and setup configuration to monitor it."""
def _detect(self):
"""Run detection"""
self.service_name = 'cinder'
self.process_name = 'cinder-api'
if find_process_cmdline(self.process_name) is not None:
log.info('Found {0}'.format(self.process_name))
self.available = True
def build_config(self):
"""Build the config as a Plugins object and return.
"""
config = agent_config.Plugins()
# First watch the Nova-API process
log.info("\tMonitoring the cinder API process.")
config.merge(watch_process([self.process_name], self.service_name))
# Next setup an active http_status check on the API
log.info("\tConfiguring an http_check for the cinder API.")
config.merge(
service_api_check(self.process_name, 'http://localhost:8776/v2.0', '.*version=1.*', self.service_name))
return config
def dependencies_installed(self):
return True

View File

@ -1,40 +0,0 @@
import logging
from . import Plugin, find_process_cmdline, watch_process
from monsetup import agent_config
log = logging.getLogger(__name__)
class Nova(Plugin):
"""Detect Nova daemons and setup configuration to monitor them."""
def _detect(self):
"""Run detection"""
self.nova_processes = ['nova-compute', 'nova-conductor',
'nova-cert', 'nova-network',
'nova-scheduler', 'nova-novncproxy',
'nova-xvpncproxy', 'nova-consoleauth',
'nova-objectstore']
self.found_processes = []
for process in self.nova_processes:
if find_process_cmdline(process) is not None:
log.info('Found {0} nova process'.format(process))
self.found_processes.append(process)
if len(self.found_processes) > 0:
self.available = True
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 Nova processes
log.info("\tMonitoring the {0} nova process.".format(process))
config.merge(watch_process([process], 'nova'))
return config
def dependencies_installed(self):
return True

View File

@ -1,36 +0,0 @@
import logging
from . import Plugin, find_process_cmdline, watch_process, service_api_check
from monsetup import agent_config
log = logging.getLogger(__name__)
class NovaAPI(Plugin):
"""Detect the Nova-API daemon and setup configuration to monitor it."""
def _detect(self):
"""Run detection"""
self.service_name = 'nova'
self.process_name = 'nova-api'
if find_process_cmdline(self.process_name) is not None:
log.info('Found {0}'.format(self.process_name))
self.available = True
def build_config(self):
"""Build the config as a Plugins object and return.
"""
config = agent_config.Plugins()
# First watch the Nova-API process
log.info("\tMonitoring the nova API process.")
config.merge(watch_process([self.process_name], self.service_name))
# Next setup an active http_status check on the API
log.info("\tConfiguring an http_check for the nova API.")
config.merge(
service_api_check(self.process_name, 'http://localhost:8774/v2.0', '.*version=2.*', self.service_name))
return config
def dependencies_installed(self):
return True

View File

@ -1,18 +1,19 @@
"""Classes for detection of running resources to be monitored.
Detection classes should be platform independent
"""
from monclient import exc as exc, client
class Plugin(object):
"""Abstract class implemented by the mon-agent plugin detection classes
"""
# todo these should include dependency detection
def __init__(self, template_dir, overwrite=True):
def __init__(self, template_dir, overwrite=True, alarms=None):
self.available = False
self.template_dir = template_dir
self.dependencies = ()
self.overwrite = overwrite
self.alarms = alarms
self._detect()
def _detect(self):
@ -29,6 +30,19 @@ class Plugin(object):
"""
raise NotImplementedError
def configure_alarms(self, mon_url, token):
"""Create default alarms.
"""
if(self.alarms):
kwargs = {
'token': token
}
my_client = client.Client('2_0', mon_url, **kwargs)
for alarm in self.alarms:
# Create the alarm here
pass
return True
@property
def name(self):
"""Return _name if set otherwise the class name"""
@ -36,5 +50,3 @@ class Plugin(object):
return self._name
else:
return self.__class__.__name__

View File

View File

@ -0,0 +1,23 @@
from monsetup.detection import ServicePlugin
class Ceilometer(ServicePlugin):
"""Detect Ceilometer daemons and setup configuration to monitor them."""
def __init__(self, template_dir, overwrite=True):
service_params = {
'template_dir' : template_dir,
'overwrite' : overwrite,
'service_name' : 'ceilometer',
'process_names' : ['ceilometer-agent-compute', 'ceilometer-agent-central',
'ceilometer-agent-notification', 'ceilometer-collector',
'ceilometer-alarm-notifier', 'ceilometer-alarm-evaluator',
'ceilometer-api'],
# TO DO: Update once the health check is implemented in Ceilometer
# 'service_api_url': 'http://localhost:8777/v2/health',
# 'search_pattern' : '.*200 OK.*',
'service_api_url': '',
'search_pattern' : '',
'alarms' : []
}
super(Ceilometer, self).__init__(service_params)

View File

@ -0,0 +1,18 @@
from monsetup.detection import ServicePlugin
class Cinder(ServicePlugin):
"""Detect Cinder daemons and setup configuration to monitor them."""
def __init__(self, template_dir, overwrite=True):
service_params = {
'template_dir' : template_dir,
'overwrite' : overwrite,
'service_name' : 'cinder',
'process_names' : ['cinder-volume', 'cinder-scheduler',
'cinder-api'],
'service_api_url': 'http://localhost:8776/v2.0',
'search_pattern' : '.*version=1.*',
'alarms' : []
}
super(Cinder, self).__init__(service_params)

View File

@ -0,0 +1,18 @@
from monsetup.detection import ServicePlugin
class Glance(ServicePlugin):
"""Detect Glance daemons and setup configuration to monitor them."""
def __init__(self, template_dir, overwrite=True):
service_params = {
'template_dir' : template_dir,
'overwrite' : overwrite,
'service_name' : 'glance',
'process_names' : ['glance-registry',
'glance-api'],
'service_api_url': 'http://localhost:9292',
'search_pattern' : '.*v2.0.*',
'alarms' : []
}
super(Glance, self).__init__(service_params)

View File

@ -1,7 +1,7 @@
import collections
import logging
from . import Plugin, find_process_cmdline, watch_process
from monsetup.detection import Plugin, find_process_cmdline, watch_process
from monsetup import agent_config
log = logging.getLogger(__name__)

View File

@ -0,0 +1,17 @@
from monsetup.detection import ServicePlugin
class Keystone(ServicePlugin):
"""Detect Keystone daemons and setup configuration to monitor them."""
def __init__(self, template_dir, overwrite=True):
service_params = {
'template_dir' : template_dir,
'overwrite' : overwrite,
'service_name' : 'keystone',
'process_names' : ['keystone-all'],
'service_api_url': 'http://localhost:35357/v3',
'search_pattern' : '.*v3.0.*',
'alarms' : []
}
super(Keystone, self).__init__(service_params)

View File

@ -5,7 +5,7 @@
import logging
from . import Plugin, find_process_cmdline, watch_process
from monsetup.detection import Plugin, find_process_cmdline, watch_process
from monsetup import agent_config
log = logging.getLogger(__name__)

View File

@ -1,6 +1,6 @@
import logging
from . import Plugin, find_process_name, watch_process
from monsetup.detection import Plugin, find_process_name, watch_process
from monsetup import agent_config
log = logging.getLogger(__name__)

View File

@ -1,7 +1,7 @@
import os
import yaml
from . import Plugin
from monsetup.detection import Plugin
from monsetup import agent_config

View File

@ -0,0 +1,20 @@
from monsetup.detection import ServicePlugin
class Neutron(ServicePlugin):
"""Detect Neutron daemons and setup configuration to monitor them."""
def __init__(self, template_dir, overwrite=True):
service_params = {
'template_dir' : template_dir,
'overwrite' : overwrite,
'service_name' : 'neutron',
'process_names' : ['neutron-server', 'neutron-openvswitch-agent',
'neutron-rootwrap', 'neutron-dhcp-agent',
'neutron-vpn-agent', 'neutron-metadata-agent',
'neutron-metering-agent', 'neutron-ns-metadata-proxy'],
'service_api_url': 'http://localhost:9696',
'search_pattern' : '.*v2.0.*',
'alarms' : []
}
super(Neutron, self).__init__(service_params)

View File

@ -0,0 +1,21 @@
from monsetup.detection import ServicePlugin
class Nova(ServicePlugin):
"""Detect Nova daemons and setup configuration to monitor them."""
def __init__(self, template_dir, overwrite=True):
service_params = {
'template_dir' : template_dir,
'overwrite' : overwrite,
'service_name' : 'nova',
'process_names' : ['nova-compute', 'nova-conductor',
'nova-cert', 'nova-network',
'nova-scheduler', 'nova-novncproxy',
'nova-xvpncproxy', 'nova-consoleauth',
'nova-objectstore', 'nova-api'],
'service_api_url': 'http://localhost:8774/v2.0',
'search_pattern' : '.*version=2.*',
'alarms' : []
}
super(Nova, self).__init__(service_params)

View File

@ -1,7 +1,7 @@
import os
import yaml
from . import Plugin, find_process_name
from monsetup.detection import Plugin, find_process_name
from monsetup import agent_config

View File

@ -0,0 +1,23 @@
from monsetup.detection import ServicePlugin
class Swift(ServicePlugin):
"""Detect Swift daemons and setup configuration to monitor them."""
def __init__(self, template_dir, overwrite=True):
service_params = {
'template_dir' : template_dir,
'overwrite' : overwrite,
'service_name' : 'swift',
'process_names' : ['swift-container-updater', 'swift-account-auditor',
'swift-object-replicator', 'swift-container-replicator',
'swift-object-auditor', 'swift-container-auditor',
'swift-account-reaper', 'swift-container-sync',
'swift-account-replicator', 'swift-object-updater',
'swift-object-server', 'swift-account-server',
'swift-container-server', 'swift-proxy-server'],
'service_api_url': 'http://localhost:8080/healthcheck',
'search_pattern' : '.*OK.*',
'alarms' : []
}
super(Swift, self).__init__(service_params)

View File

@ -2,7 +2,7 @@ import logging
import os
import yaml
from . import Plugin, find_process_cmdline, watch_process
from monsetup.detection import Plugin, find_process_cmdline, watch_process
from monsetup import agent_config
log = logging.getLogger(__name__)

View File

@ -0,0 +1,52 @@
import psutil
import logging
from plugin import Plugin
from monsetup import agent_config
from monsetup.detection import find_process_cmdline, watch_process, service_api_check
log = logging.getLogger(__name__)
class ServicePlugin(Plugin):
"""Base class implemented by the mon-agent plugin detection classes
for OpenStack Services
"""
def __init__(self, kwargs):
self.service_name = kwargs['service_name']
self.process_names = kwargs['process_names']
self.service_api_url = kwargs['service_api_url']
self.search_pattern = kwargs['search_pattern']
super(ServicePlugin, self).__init__(kwargs['template_dir'], kwargs['overwrite'], kwargs['alarms'])
def _detect(self):
"""Run detection"""
self.found_processes = []
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
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))
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 dependencies_installed(self):
"""return True if dependencies are installed
"""
return True

View File

@ -1,42 +0,0 @@
import logging
from . import Plugin, find_process_cmdline, watch_process
from monsetup import agent_config
log = logging.getLogger(__name__)
class Swift(Plugin):
"""Detect Swift daemons and setup configuration to monitor them."""
def _detect(self):
"""Run detection"""
self.swift_processes = ['swift-container-updater', 'swift-account-auditor',
'swift-object-replicator', 'swift-container-replicator',
'swift-object-auditor', 'swift-container-auditor',
'swift-account-reaper', 'swift-container-sync',
'swift-account-replicator', 'swift-object-updater',
'swift-object-server', 'swift-account-server',
'swift-container-server']
self.found_processes = []
for process in self.swift_processes:
if find_process_cmdline(process) is not None:
log.info('Found {0} swift process'.format(process))
self.found_processes.append(process)
if len(self.found_processes) > 0:
self.available = True
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 Swift processes
log.info("\tMonitoring the {0} swift process.".format(process))
config.merge(watch_process([process], 'swift'))
return config
def dependencies_installed(self):
return True

View File

@ -1,36 +0,0 @@
import logging
from . import Plugin, find_process_cmdline, watch_process, service_api_check
from monsetup import agent_config
log = logging.getLogger(__name__)
class SwiftAPI(Plugin):
"""Detect the Swift-API daemon and setup configuration to monitor it."""
def _detect(self):
"""Run detection"""
self.service_name = 'swift'
self.process_name = 'swift-proxy-server'
if find_process_cmdline(self.process_name) is not None:
log.info('Found {0}'.format(self.process_name))
self.available = True
def build_config(self):
"""Build the config as a Plugins object and return.
"""
config = agent_config.Plugins()
# First watch the Swift-API process
log.info("\tMonitoring the swift API process.")
config.merge(watch_process([self.process_name], self.service_name))
# Next setup an active http_status check on the API
log.info("\tConfiguring an http_check for the swift API.")
config.merge(
service_api_check(self.process_name, 'http://localhost:8080/healthcheck', '.*OK.*', self.service_name))
return config
def dependencies_installed(self):
return True

View File

@ -10,15 +10,16 @@ import socket
import subprocess
import sys
import yaml
from monagent.common.keystone import Keystone
import agent_config
from detection import kafka, mon, mysql, network, nova, nova_api, cinder, cinder_api, swift, swift_api, zookeeper
from detection.plugins import kafka, mon, mysql, network, zookeeper, nova, glance, cinder, neutron, swift, ceilometer, keystone
from service import sysv
# List of all detection plugins to run
DETECTION_PLUGINS = [kafka.Kafka, mon.MonAPI, mon.MonPersister, mon.MonThresh, mysql.MySQL,
network.Network, nova.Nova, nova_api.NovaAPI, cinder.Cinder,
cinder_api.CinderAPI, swift.Swift, swift_api.SwiftAPI, zookeeper.Zookeeper]
network.Network, nova.Nova, cinder.Cinder, swift.Swift, glance.Glance,
ceilometer.Ceilometer, neutron.Neutron, keystone.Keystone, zookeeper.Zookeeper]
# Map OS to service type
OS_SERVICE_MAP = {'linux': sysv.SysV}
@ -78,6 +79,17 @@ def main(argv=None):
os.remove(supervisor_path)
os.symlink(os.path.join(args.template_dir, 'supervisor.conf'), supervisor_path)
# Create the keystone object to use for alarm creation
token = None
try:
keystone = Keystone(args.keystone_url,
args.username,
args.password,
args.project_name)
token = keystone.get_token()
except:
log.exception('Unable to get Keystone Token, skipping alarm configuration...')
# Run through detection and config building for the plugins
plugin_config = agent_config.Plugins()
for detect_class in DETECTION_PLUGINS:
@ -86,6 +98,9 @@ def main(argv=None):
log.info('Configuring {0}'.format(detect.name))
new_config = detect.build_config()
plugin_config.merge(new_config)
if token and args.mon_url:
if not detect.configure_alarms(args.mon_url, token):
log.warn('Unable to configure alarms for {0}'.format(detect.name))
#todo add option to install dependencies
@ -113,4 +128,4 @@ def main(argv=None):
if __name__ == "__main__":
sys.exit(main())
sys.exit(main())

View File

@ -53,9 +53,9 @@ install_full: source
# Install the source to usr/share
cp -r $(ROOT)/* $(BUILD)/usr/share/mon/agent/
# Install the common executables.
ln -sf ../share/mon/agent/monagent/monstatsd/__init__.py $(BUILD)/usr/bin/monstatsd
ln -sf ../share/mon/agent/monagent/forwarder/__init__.py $(BUILD)/usr/bin/mon-forwarder
ln -sf ../share/mon/agent/monagent/collector/daemon.py $(BUILD)/usr/bin/mon-collector
ln -sf ../share/mon/agent/monagent/monstatsd/daemon.py $(BUILD)/usr/bin/monstatsd
ln -sf ../share/mon/agent/monagent/forwarder/daemon.py $(BUILD)/usr/bin/mon-forwarder
ln -sf ../share/mon/agent/monagent/collector/daemon.py $(BUILD)/usr/bin/mon-collector
chmod 755 $(BUILD)/usr/bin/monstatsd
chmod 755 $(BUILD)/usr/bin/mon-forwarder
chmod 755 $(BUILD)/usr/bin/mon-collector

View File

@ -14,11 +14,11 @@
PATH=$PATH:/sbin # add the location of start-stop-daemon on Debian
export PYTHONPATH=$PYTHONPATH:/usr/share/mon/agent/
AGENTPATH="/usr/bin/mon-collector"
AGENTPATH="/usr/local/bin/mon-collector"
AGENTCONF="/etc/mon-agent/agent.conf"
MONSTATSDPATH="/usr/bin/monstatsd"
MONSTATSDPATH="/usr/local/bin/monstatsd"
AGENTUSER="mon-agent"
FORWARDERPATH="/usr/bin/mon-forwarder"
FORWARDERPATH="/usr/local/bin/mon-forwarder"
NAME="mon-agent"
DESC="Monitoring Agent"
AGENT_PID_PATH="/var/run/mon-agent.pid"