Merge "Removed dependency on supervisor"

This commit is contained in:
Zuul 2018-06-29 14:20:42 +00:00 committed by Gerrit Code Review
commit 89e563194e
17 changed files with 249 additions and 391 deletions

3
.gitignore vendored
View File

@ -19,3 +19,6 @@ htmlcov/
cover/
.stestr
virtenv/
Pipfile
Pipfile.lock
.vscode

View File

@ -35,12 +35,13 @@ The Agent is composed of the following components:
| Component Name | Process Name | Description |
| -------------- | ------------ | ----------- |
| Supervisor | supervisord | Runs as root, launches all other processes as the user configured to run monasca-agent. This process manages the lifecycle of the Collector, Forwarder and Statsd Daemon. It allows Start, Stop and Restart of all the agent processes together. |
| Collector | monasca-collector | Gathers system & application metrics on a configurable interval and sends them to the Forwarder process. The collector runs various plugins for collection of different plugins.|
| Forwarder | monasca-forwarder | Gathers data from the collector and statsd and submits it to Monasca API over SSL (tcp/17123) |
| Statsd Daemon | monasca-statsd | Statsd engine capable of handling dimensions associated with metrics submitted by a client that supports them. Also supports metrics from the standard statsd client. (udp/8125) |
| Monasca Setup | monasca-setup | The monasca-setup script configures the agent. The Monasca Setup program can also auto-detect and configure certain agent plugins |
It is possible to Start, Stop and Reset all components by using monasca-agent.target. Monasca-agent.target is the systemd configuration that allows to manage all monasca-agent services.
# Installing
The Agent (monasca-agent) is available for installation from the Python Package Index (PyPI). To install it, you first need `pip` installed on the node to be monitored. Instructions on installing pip may be found at https://pip.pypa.io/en/latest/installing.html. The Agent will NOT run under any flavor of Windows or Mac OS at this time but has been tested thoroughly on Ubuntu and should work under most flavors of Linux. Support may be added for Mac OS and Windows in the future. Example of an Ubuntu or Debian based install:
@ -277,7 +278,7 @@ The number of threads to use for running the plugins is via num_collector_thread
The collector is optimized for collecting as many metrics on schedule as possible. The plugins are run in reverse order of their collection time, i.e., the fastest plugin first. Also, if a plugin does not complete within the collection frequency, that plugin will be skipped in the next collection cycle. These two optimizations together ensure that plugins that complete with collection frequency seconds will get run on every collection cycle.
If there is some problem with multiple plugins that end up blocking the entire thread pool, the collector will exit so that it can be restarted by the supervisord. The parameter pool_full_max_retries controls when this happens. If pool_full_max_retries consecutive collection cycles have ended with the Thread Pool completely full, the collector will exit.
If there is some problem with multiple plugins that end up blocking the entire thread pool, the collector will exit so that it can be restarted by the monasca-agent systemd target. The parameter pool_full_max_retries controls when this happens. If pool_full_max_retries consecutive collection cycles have ended with the Thread Pool completely full, the collector will exit.
Some of the plugins have their own thread pools to handle asynchronous checks. The collector thread pool is separate and has no special interaction with those thread pools.
# License

View File

@ -23,7 +23,7 @@ log = logging.getLogger(__name__)
class Plugin(object):
"""Abstract class implemented by the monasca-agent plugin detection classes. """
"""Abstract class for the monasca-agent plugin detection."""
def __init__(self, template_dir, overwrite=True, args=None):
self.available = False
@ -32,7 +32,8 @@ class Plugin(object):
self.overwrite = overwrite
if args is not None and isinstance(args, str):
try:
# Turn 'hostname=host type=ping' to dictionary {'hostname': 'host', 'type': 'ping'}
# Turn 'hostname=host type=ping' to dictionary
# {'hostname': 'host', 'type': 'ping'}
self.args = dict([a.split('=') for a in args.split()])
except Exception:
log.exception('Error parsing detection arguments')
@ -44,21 +45,25 @@ class Plugin(object):
self._detect()
def _detect(self):
"""Run detection, set self.available True if the service is detected.
"""Run detection.
Set self.available True if the service is detected.
"""
raise NotImplementedError
def build_config(self):
"""Build the config as a Plugins object and return.
"""
"""Build the config as a Plugins object and return."""
raise NotImplementedError
def build_config_with_name(self):
"""Builds the config and then adds a field 'built_by' to each instance in the config.
"""Build the config and then add 'built_by' field.
Build the config and then add 'built_by' field to each instance in
the config.
built_by is set to the plugin name
:return: An agent_config.Plugins object
:return: An agent_config.Plugins object
"""
conf = self.build_config()
if conf is None:

View File

@ -28,12 +28,12 @@ import sys
import six
import agent_config
from monasca_setup import agent_config
from monasca_setup.service.detection import detect_init
import monasca_setup.utils as utils
from monasca_setup.utils import write_template
from service.detection import detect_init
log = logging.getLogger(__name__)
LOG = logging.getLogger(__name__)
CUSTOM_PLUGIN_PATH = '/usr/lib/monasca/agent/custom_detect.d'
# dirname is called twice to get the dir 1 above the location of the script
@ -42,22 +42,26 @@ PREFIX_DIR = os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0])))
def main(argv=None):
parser = argparse.ArgumentParser(
description='Configure and setup the agent. In a full run it will detect running' +
' daemons then configure and start the agent.',
description='Configure and setup the agent. In a full run it will' +
' detect running daemons then configure and start the agent.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
args = parse_arguments(parser)
if args.verbose:
logging.basicConfig(level=logging.DEBUG, format="%(levelname)s: %(message)s")
logging.basicConfig(level=logging.DEBUG,
format="%(levelname)s: %(message)s")
else:
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
logging.basicConfig(level=logging.INFO,
format="%(levelname)s: %(message)s")
if args.dry_run:
log.info("Running in dry run mode, no changes will be made only reported")
LOG.info("Running in dry run mode, no changes will be made only"
" reported")
# Detect and if possibly enable the agent service
agent_service = detect_init(PREFIX_DIR, args.config_dir, args.log_dir, args.template_dir,
username=args.user, name=args.agent_service_name)
agent_service = detect_init(PREFIX_DIR, args.config_dir, args.log_dir,
args.template_dir, username=args.user,
name=args.agent_service_name)
# Skip base setup if only installing plugins or running specific detection
# plugins
@ -66,9 +70,11 @@ def main(argv=None):
agent_service.enable()
# Verify required options
if args.username is None or args.password is None or args.keystone_url is None:
log.error('Username, password and keystone_url are required when running full'
'configuration.')
if (args.username is None or
args.password is None or
args.keystone_url is None):
LOG.error('Username, password and keystone_url are required when'
' running full configuration.')
parser.print_help()
sys.exit(1)
base_configuration(args)
@ -79,50 +85,59 @@ def main(argv=None):
from detection.plugins.system import System
plugins = [System]
elif args.detection_plugins is not None:
plugins = utils.select_plugins(args.detection_plugins, detected_plugins)
plugins = utils.select_plugins(args.detection_plugins,
detected_plugins)
elif args.skip_detection_plugins is not None:
plugins = utils.select_plugins(args.skip_detection_plugins, detected_plugins, skip=True)
plugins = utils.select_plugins(args.skip_detection_plugins,
detected_plugins, skip=True)
else:
plugins = detected_plugins
plugin_names = [p.__name__ for p in plugins]
if args.remove: # Remove entries for each plugin from the various plugin config files
# Remove entries for each plugin from the various plugin config files.
if args.remove:
changes = remove_config(args, plugin_names)
else:
# Run detection for all the plugins, halting on any failures if plugins
# were specified in the arguments
detected_config = plugin_detection(plugins, args.template_dir, args.detection_args,
detected_config = plugin_detection(plugins, args.template_dir,
args.detection_args,
args.detection_args_json,
skip_failed=(args.detection_plugins is None))
skip_failed=(args.detection_plugins
is None))
if detected_config is None:
# Indicates detection problem, skip remaining steps and give non-zero exit code
# Indicates detection problem, skip remaining steps and give
# non-zero exit code
return 1
changes = modify_config(args, detected_config)
# Don't restart if only doing detection plugins and no changes found
if args.detection_plugins is not None and not changes:
log.info(
LOG.info(
'No changes found for plugins {0}, skipping restart of'
'Monasca Agent'.format(plugin_names))
return 0
elif args.dry_run:
log.info('Running in dry mode, skipping changes and restart of Monasca Agent')
LOG.info('Running in dry mode, skipping changes and restart of'
' Monasca Agent')
return 0
# Now that the config is built, start the service
if args.install_plugins_only:
log.info('Command line option install_plugins_only set, skipping '
LOG.info('Command line option install_plugins_only set, skipping '
'service (re)start.')
else:
try:
agent_service.start(restart=True)
except subprocess.CalledProcessError:
log.error('The service did not startup correctly see %s' % args.log_dir)
LOG.error('The service did not startup correctly see %s',
args.log_dir)
def base_configuration(args):
"""Write out the primary Agent configuration and setup the service.
:param args: Arguments from the command line
:return: None
"""
@ -132,15 +147,17 @@ def base_configuration(args):
gid = stat.pw_gid
# Write the main agent.yaml - Note this is always overwritten
log.info('Configuring base Agent settings.')
LOG.info('Configuring base Agent settings.')
dimensions = {}
# Join service in with the dimensions
if args.service:
dimensions.update({'service': args.service})
if args.dimensions:
dimensions.update(dict(item.strip().split(":") for item in args.dimensions.split(",")))
dimensions.update(dict(item.strip().split(":")
for item in args.dimensions.split(",")))
args.dimensions = dict((name, value) for (name, value) in dimensions.items())
args.dimensions = dict((name, value)
for (name, value) in dimensions.items())
write_template(os.path.join(args.template_dir, 'agent.yaml.template'),
os.path.join(args.config_dir, 'agent.yaml'),
{'args': args, 'hostname': socket.getfqdn()},
@ -148,13 +165,6 @@ def base_configuration(args):
user=uid,
is_yaml=True)
# Write the supervisor.conf
write_template(os.path.join(args.template_dir, 'supervisor.conf.template'),
os.path.join(args.config_dir, 'supervisor.conf'),
{'prefix': PREFIX_DIR, 'log_dir': args.log_dir, 'monasca_user': args.user},
user=uid,
group=gid)
def modify_config(args, detected_config):
"""Compare existing and detected config for each check plugin and write out
@ -169,7 +179,8 @@ def modify_config(args, detected_config):
continue
else:
agent_config.save_plugin_config(
args.config_dir, detection_plugin_name, args.user, new_config)
args.config_dir, detection_plugin_name, args.user,
new_config)
else:
config = agent_config.read_plugin_config_from_disk(
args.config_dir, detection_plugin_name)
@ -191,9 +202,11 @@ def modify_config(args, detected_config):
# Check endpoint change, use new protocol instead
# Note: config is possibly changed after running
# check_endpoint_changes function.
config = agent_config.check_endpoint_changes(new_config, config)
config = agent_config.check_endpoint_changes(new_config,
config)
agent_config.merge_by_name(new_config['instances'], config['instances'])
agent_config.merge_by_name(new_config['instances'],
config['instances'])
# Sort before compare, if instances have no name the sort will
# fail making order changes significant
try:
@ -203,7 +216,8 @@ def modify_config(args, detected_config):
pass
if detection_plugin_name == "http_check":
new_config_urls = [i['url'] for i in new_config['instances'] if 'url' in i]
new_config_urls = [i['url'] for i in new_config['instances']
if 'url' in i]
# Don't write config if no change
if new_config_urls == config_urls and new_config == config:
continue
@ -212,18 +226,20 @@ def modify_config(args, detected_config):
continue
modified_config = True
if args.dry_run:
log.info("Changes would be made to the config file for the {0}"
LOG.info("Changes would be made to the config file for the {0}"
" check plugin".format(detection_plugin_name))
else:
agent_config.save_plugin_config(
args.config_dir, detection_plugin_name, args.user, new_config)
args.config_dir, detection_plugin_name, args.user,
new_config)
return modified_config
def validate_positive(value):
int_value = int(value)
if int_value <= 0:
raise argparse.ArgumentTypeError("%s must be greater than zero" % value)
raise argparse.ArgumentTypeError("%s must be greater than zero" %
value)
return int_value
@ -231,11 +247,13 @@ def parse_arguments(parser):
parser.add_argument(
'-u',
'--username',
help="Username used for keystone authentication. Required for basic configuration.")
help="Username used for keystone authentication. " +
"Required for basic configuration.")
parser.add_argument(
'-p',
'--password',
help="Password used for keystone authentication. Required for basic configuration.")
help="Password used for keystone authentication. " +
"Required for basic configuration.")
parser.add_argument(
'--user_domain_id',
@ -245,8 +263,9 @@ def parse_arguments(parser):
'--user_domain_name',
help="User domain name for keystone authentication",
default='')
parser.add_argument('--keystone_url', help="Keystone url. Required for basic configuration.")
parser.add_argument(
'--keystone_url',
help="Keystone url. Required for basic configuration.")
parser.add_argument(
'--project_name',
help="Project name for keystone authentication",
@ -263,7 +282,6 @@ def parse_arguments(parser):
'--project_id',
help="Keystone project id for keystone authentication",
default='')
parser.add_argument(
'--monasca_url',
help="Monasca API url, if not defined the url is pulled from keystone",
@ -281,7 +299,6 @@ def parse_arguments(parser):
'--region_name',
help="Monasca API url region name in keystone catalog",
default='')
parser.add_argument(
'--system_only',
help="Setup the service but only configure the base config and system " +
@ -292,10 +309,12 @@ def parse_arguments(parser):
'-d',
'--detection_plugins',
nargs='*',
help="Skip base config and service setup and only configure this space separated list. " +
"This assumes the base config has already run.")
parser.add_argument('--skip_detection_plugins', nargs='*',
help="Skip detection for all plugins in this space separated list.")
help="Skip base config and service setup and only configure this " +
"space separated list. " +
"This assumes the base config has already run.")
parser.add_argument(
'--skip_detection_plugins', nargs='*',
help="Skip detection for all plugins in this space separated list.")
detection_args_group = parser.add_mutually_exclusive_group()
detection_args_group.add_argument(
'-a',
@ -445,12 +464,13 @@ def plugin_detection(
if detect.available:
new_config = detect.build_config_with_name()
if not remove:
log.info('Configuring {0}'.format(detect.name))
LOG.info('Configuring {0}'.format(detect.name))
if new_config is not None:
plugin_config.merge(new_config)
elif not skip_failed:
log.warn('Failed detection of plugin {0}.'.format(detect.name) +
"\n\tPossible causes: Service not found or missing arguments.")
LOG.warning("Failed detection of plugin %s."
"\n\tPossible causes: Service not found or missing"
"arguments.", detect.name)
return None
return plugin_config
@ -495,7 +515,10 @@ def remove_config(args, plugin_names):
deletes = True
config['instances'].remove(inst)
if deletes:
agent_config.delete_from_config(args, config, file_path, plugin_name)
agent_config.delete_from_config(args, config, file_path,
plugin_name)
return changes
if __name__ == "__main__":
sys.exit(main())

View File

@ -1,14 +1,5 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company 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.
"""Setup system service for monasca-agent and its dependencies.
from service import Service # noqa
Configure systemd to start monasca-collector, monasca-forwarder,
and monasca-statsd services using a target named monasca-agent.
"""

View File

@ -15,43 +15,30 @@ import logging
import platform
import sys
import linux
from monasca_setup.service import linux
log = logging.getLogger(__name__)
LOG = logging.getLogger(__name__)
def detect_init(*args, **kwargs):
"""Detect the service manager running on this box
args/kwargs match those of service.Service
:return: The appropriate Service object for this system
"""Create a service object if possible.
Detect if systemd is present on the system and if so return the service
object.
:return: a systemd service object for this system.
"""
detected_os = platform.system()
if detected_os == 'Linux':
supported_linux_flavors = [
'ubuntu', 'debian',
'centos linux', 'red hat enterprise linux server',
'suse linux enterprise server'
]
flavor = platform.linux_distribution()[0].strip()
if flavor.lower() not in supported_linux_flavors:
log.warn('{0} is not a supported Linux distribution'.format(flavor))
return detect_linux_init(*args, **kwargs)
else:
print("{0} is not currently supported by the Monasca Agent".format(detected_os))
sys.exit(1)
# Service enable, includes setup of users/config directories so must be
# done before configuration
if has_systemd():
return linux.Systemd(*args, **kwargs)
LOG.error("{0} is not currently supported by the Monasca Agent"
.format(detected_os))
sys.exit(1)
def detect_linux_init(*args, **kwargs):
"""Detect which of the linux inits is running
:return: Return a valid Linux service manager object
"""
def has_systemd():
"""Detect if Linux init is systemd."""
with open('/proc/1/comm', 'r') as init_proc:
init = init_proc.readline().strip()
if init == 'systemd':
return linux.Systemd(*args, **kwargs)
else:
return linux.SysV(*args, **kwargs)
return init == 'systemd'

View File

@ -13,24 +13,37 @@
""" Systemd based service
"""
import glob
import logging
import os
import pwd
import subprocess
import service
LOG = logging.getLogger(__name__)
log = logging.getLogger(__name__)
class Systemd(object):
"""Manage service using systemd."""
def __init__(self, prefix_dir, config_dir, log_dir, template_dir,
name='monasca-agent', username='mon-agent'):
"""Create a service."""
self.prefix_dir = prefix_dir
self.config_dir = config_dir
self.log_dir = log_dir
self.template_dir = template_dir
self.name = name
self.username = username
class LinuxInit(service.Service):
"""Parent class for all Linux based init systems.
"""
def enable(self):
"""Does user/group directory creation.
"""Set monasca-agent to start on boot.
Generally this requires running as super user.
"""
if os.geteuid() != 0:
LOG.error('This service must be run as root')
raise OSError
# LinuxInit.enable(self)
# Create user/group if needed
try:
user = pwd.getpwnam(self.username)
@ -39,171 +52,89 @@ class LinuxInit(service.Service):
user = pwd.getpwnam(self.username)
# Create dirs
# todo log dir is hardcoded
for path in (self.log_dir, self.config_dir, '%s/conf.d' % self.config_dir):
for path in (self.log_dir, self.config_dir,
'%s/conf.d' % self.config_dir):
if not os.path.exists(path):
os.makedirs(path, 0o755)
os.chown(path, 0, user.pw_gid)
# the log dir needs to be writable by the user
# log dir needs to be writable by the user
os.chown(self.log_dir, user.pw_uid, user.pw_gid)
def start(self, restart=True):
if not self.is_enabled():
log.error('The service is not enabled')
return False
# Get systemd services and target template
templates = [f for f in os.listdir(self.template_dir)
if (f.endswith('service.template') or
f.endswith('target.template'))]
systemd_path = '/etc/systemd/system/'
def stop(self):
if not self.is_enabled():
log.error('The service is not enabled')
return True
def is_enabled(self):
"""Returns True if monasca-agent is setup to start on boot, false otherwise.
"""
raise NotImplementedError
class Systemd(LinuxInit):
def enable(self):
"""Sets monasca-agent to start on boot.
Generally this requires running as super user
"""
LinuxInit.enable(self)
# Write the systemd script
init_path = '/etc/systemd/system/{0}.service'.format(self.name)
with open(os.path.join(self.template_dir, 'monasca-agent.service.template'),
'r') as template:
with open(init_path, 'w') as service_script:
service_script.write(
template.read().format(
prefix=self.prefix_dir,
monasca_user=self.username,
config_dir=self.config_dir))
os.chown(init_path, 0, 0)
os.chmod(init_path, 0o644)
# Write the systemd units configuration file: we have 3 services and
# 1 target grouping all of them together
for template_file_name in templates:
service_file_name, e = os.path.splitext(template_file_name)
service_file_path = os.path.join(systemd_path,
service_file_name)
with open(os.path.join(self.template_dir,
template_file_name), 'r') as template:
with open(service_file_path, 'w') as service_file:
LOG.info('Creating service file %s', service_file_name)
service_file.write(template.read().
format(prefix=self.prefix_dir,
monasca_user=self.username))
os.chown(service_file_path, 0, 0)
os.chmod(service_file_path, 0o644)
# Enable the service
subprocess.check_call(['systemctl', 'daemon-reload'])
subprocess.check_call(['systemctl', 'enable', '{0}.service'.format(self.name)])
log.info('Enabled {0} service via systemd'.format(self.name))
subprocess.check_call(
['systemctl', 'enable', '{0}.target'.format(self.name)])
LOG.info('Enabled %s target via systemd', self.name)
def start(self, restart=True):
"""Starts monasca-agent.
"""Start monasca-agent.
If the agent is running and restart is True, restart
If the agent is running and restart is True restart it.
:return: True if monasca-agent is enabled on boot, False otherwise..
"""
LinuxInit.start(self)
log.info('Starting {0} service via systemd'.format(self.name))
if restart:
subprocess.check_call(['systemctl', 'restart', '{0}.service'.format(self.name)])
else:
subprocess.check_call(['systemctl', 'start', '{0}.service'.format(self.name)])
if not self.is_enabled():
LOG.error('The service is not enabled')
return False
LOG.info('Starting %s services via systemd', self.name)
if self.is_running() and restart:
subprocess.check_call(
['systemctl', 'restart', '{0}.target'.format(self.name)])
else:
subprocess.check_call(
['systemctl', 'start', '{0}.target'.format(self.name)])
return True
def stop(self):
"""Stops monasca-agent.
"""
LinuxInit.stop(self)
log.info('Stopping {0} service'.format(self.name))
subprocess.check_call(['systemctl', 'stop', '{0}.service'.format(self.name)])
return True
def is_enabled(self):
"""Returns True if monasca-agent is setup to start on boot, false otherwise.
"""Stop monasca-agent.
:return: True if monasca-agent was stopped successfully, False otherwise
"""
LOG.info('Stopping %s services', self.name)
try:
subprocess.check_output(['systemctl', 'is-enabled', '{0}.service'.format(self.name)])
except subprocess.CalledProcessError:
subprocess.check_call(
['systemctl', 'stop', '{0}.target'.format(self.name)])
except subprocess.CalledProcessError as call_error:
LOG.error('Unable to stop monasca-agent.')
LOG.error(call_error.output)
return False
return True
class SysV(LinuxInit):
def __init__(
self,
prefix_dir,
config_dir,
log_dir,
template_dir,
username,
name='monasca-agent'):
"""Setup this service with the given init template.
"""
service.Service.__init__(
self,
prefix_dir,
config_dir,
log_dir,
template_dir,
name,
username)
self.init_script = '/etc/init.d/%s' % self.name
self.init_template = os.path.join(template_dir, 'monasca-agent.init.template')
def enable(self):
"""Sets monasca-agent to start on boot.
Generally this requires running as super user
"""
LinuxInit.enable(self)
# Write the init script and enable.
with open(self.init_template, 'r') as template:
with open(self.init_script, 'w') as conf:
conf.write(
template.read().format(
prefix=self.prefix_dir,
monasca_user=self.username,
config_dir=self.config_dir))
os.chown(self.init_script, 0, 0)
os.chmod(self.init_script, 0o755)
for runlevel in ['2', '3', '4', '5']:
link_path = '/etc/rc%s.d/S10monasca-agent' % runlevel
if not os.path.exists(link_path):
os.symlink(self.init_script, link_path)
log.info('Enabled {0} service via SysV init script'.format(self.name))
def start(self, restart=True):
"""Starts monasca-agent.
If the agent is running and restart is True, restart
"""
LinuxInit.start(self)
log.info('Starting {0} service via SysV init script'.format(self.name))
if restart:
# Throws CalledProcessError on error
subprocess.check_call([self.init_script, 'restart'])
else:
subprocess.check_call([self.init_script, 'start']) # Throws CalledProcessError on error
return True
return True
def stop(self):
"""Stops monasca-agent.
def is_running(self):
"""Check if monasca-agent is running.
:return: True if monasca-agent is running, false otherwise.
"""
LinuxInit.stop(self)
log.info('Stopping {0} service via SysV init script'.format(self.name))
subprocess.check_call([self.init_script, 'stop']) # Throws CalledProcessError on error
return True
return(subprocess.call(['systemctl', 'is-active', '--quiet',
'{0}.target'.format(self.name)]) == 0)
def is_enabled(self):
"""Returns True if monasca-agent is setup to start on boot, false otherwise.
"""Check if monasca-agent is setup to start at boot time.
:return: True if monasca-agent is enabled on boot, False otherwise.
"""
if not os.path.exists(self.init_script):
return False
if len(glob.glob('/etc/rc?.d/S??monasca-agent')) > 0:
return True
else:
return False
return(subprocess.call(['systemctl', 'is-enabled', '--quiet',
'{0}.target'.format(self.name)]) == 0)

View File

@ -1,70 +0,0 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company 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.
"""Code to handle various service managers used on different OS
"""
from monasca_agent.common.psutil_wrapper import psutil
class Service(object):
"""Abstract base class implementing the interface for various service types.
"""
def __init__(self, prefix_dir, config_dir, log_dir, template_dir,
name='monasca-agent', username='monasca-agent'):
self.prefix_dir = prefix_dir
self.config_dir = config_dir
self.log_dir = log_dir
self.template_dir = template_dir
self.name = name
self.username = username
def enable(self):
"""Sets monasca-agent to start on boot.
Generally this requires running as super user
"""
raise NotImplementedError
def start(self, restart=True):
"""Starts monasca-agent.
If the agent is running and restart is True, restart
"""
raise NotImplementedError
def stop(self):
"""Stops monasca-agent.
"""
raise NotImplementedError
def is_enabled(self):
"""Returns True if monasca-agent is setup to start on boot, false otherwise.
"""
raise NotImplementedError
def is_running(self):
"""Returns True if monasca-agent is running, false otherwise.
"""
# Looking for the supervisor process not the individual components
for process in psutil.process_iter():
if ('{0}/supervisor.conf'.format(self.config_dir)
in process.as_dict(['cmdline'])['cmdline']):
return True
return False

View File

@ -69,9 +69,6 @@ install_deb: install_full
mkdir -p $(BUILD)/etc/init.d
cp monasca-agent-deb/monasca-agent.init $(BUILD)/etc/init.d/monasca-agent
chmod 755 $(BUILD)/etc/init.d/monasca-agent
# Install supervisor config.
cp monasca-agent-deb/supervisor.conf $(BUILD)/etc/monasca/agent/supervisor.conf
# Make the monasca agent debian package that includes supervisor, the forwarder
# etc.
@ -81,7 +78,6 @@ $(FPM_BUILD) -t deb \
-n monasca-agent \
-d "python (>= 2.6)" \
-d "python-tornado (>= 2.3)" \
-d "supervisor (>= 3.0)" \
-d "adduser" \
-d "sysstat" \
-d "python-pycurl" \

View File

@ -1,12 +0,0 @@
[Unit]
Description=Monasca Agent
[Service]
Type=simple
User={monasca_user}
Group={monasca_user}
Restart=on-failure
ExecStart={prefix}/bin/supervisord -c {config_dir}/supervisor.conf -n
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,6 @@
[Unit]
Description=Monasca Agent
Wants=monasca-collector.service monasca-forwarder.service monasca-statsd.service
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,15 @@
[Unit]
Description=Monasca Agent - Collector
PartOf=monasca-agent.target
After=monasca-forwarder.service
Wants=monasca-forwarder.service
[Service]
Type=simple
User={monasca_user}
Group={monasca_user}
Restart=always
ExecStart={prefix}/bin/monasca-collector foreground
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,15 @@
[Unit]
Description=Monasca Agent - Forwarder
PartOf=monasca-agent.target
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User={monasca_user}
Group={monasca_user}
Restart=always
ExecStart={prefix}/bin/monasca-forwarder
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,15 @@
[Unit]
Description=Monasca Agent - Statsd
PartOf=monasca-agent.target
After=monasca-forwarder.service
Wants=monasca-forwarder.service
[Service]
Type=simple
User={monasca_user}
Group={monasca_user}
Restart=always
ExecStart={prefix}/bin/monasca-statsd
[Install]
WantedBy=multi-user.target

View File

@ -1,48 +0,0 @@
[supervisorctl]
serverurl = unix:///var/tmp/monasca-agent-supervisor.sock
[unix_http_server]
file=/var/tmp/monasca-agent-supervisor.sock
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisord]
minfds = 1024
minprocs = 200
loglevel = info
logfile = {log_dir}/supervisord.log
logfile_maxbytes = 50MB
nodaemon = false
pidfile = /var/run/monasca-agent-supervisord.pid
logfile_backups = 10
[program:collector]
command={prefix}/bin/monasca-collector foreground
stdout_logfile=NONE
stderr_logfile=NONE
priority=999
startsecs=2
user={monasca_user}
autorestart=true
[program:forwarder]
command={prefix}/bin/monasca-forwarder
stdout_logfile=NONE
stderr_logfile=NONE
startsecs=3
priority=998
user={monasca_user}
autorestart=true
[program:statsd]
command={prefix}/bin/monasca-statsd
stdout_logfile=NONE
stderr_logfile=NONE
startsecs=3
priority=998
user={monasca_user}
autorestart=true
[group:monasca-agent]
programs=forwarder,collector,statsd

View File

@ -20,7 +20,6 @@ python-keystoneclient>=3.8.0 # Apache-2.0
redis>=2.10.0 # MIT
six>=1.10.0 # MIT
stevedore>=1.20.0 # Apache-2.0
supervisor>=3.3.3,<3.4 # BSD-derived
tornado>=4.5.3 # Apache-2.0
futures>=3.0.0;python_version=='2.7' or python_version=='2.6' # BSD
# NOTE(sdague): before allowing in >= 0.21 please be sure

View File

@ -23,9 +23,10 @@ packages =
data_files=
share/monasca/agent =
agent.yaml.template
packaging/supervisor.conf.template
packaging/monasca-agent.init.template
packaging/monasca-agent.service.template
packaging/monasca-collector.service.template
packaging/monasca-forwarder.service.template
packaging/monasca-statsd.service.template
packaging/monasca-agent.target.template
share/monasca/agent/conf.d = conf.d/*
[entry_points]