Added a systemd service provider
Change-Id: I2e98f120bd937131b739778f5737f068976a0a14
This commit is contained in:
parent
48b1c4bc5f
commit
5f5c77847d
@ -5,7 +5,6 @@
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import pwd
|
||||
import socket
|
||||
import subprocess
|
||||
@ -14,13 +13,8 @@ import yaml
|
||||
|
||||
import agent_config
|
||||
from detection.plugins import DETECTION_PLUGINS
|
||||
import service.sysv as sysv
|
||||
from service.detection import detect_init
|
||||
|
||||
from detection.utils import check_output
|
||||
|
||||
# List of all detection plugins to run
|
||||
# Map OS to service type
|
||||
OS_SERVICE_MAP = {'Linux': sysv.SysV}
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -101,41 +95,8 @@ def main(argv=None):
|
||||
else:
|
||||
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
|
||||
|
||||
# Detect os
|
||||
detected_os = platform.system()
|
||||
if detected_os == 'Linux':
|
||||
supported_linux_flavors = ['Ubuntu', 'debian']
|
||||
this_linux_flavor = platform.linux_distribution()[0]
|
||||
if this_linux_flavor in supported_linux_flavors:
|
||||
for package in ['coreutils']:
|
||||
# Check for required dependencies for system checks
|
||||
try:
|
||||
output = check_output('dpkg -s {0}'.format(package),
|
||||
stderr=subprocess.STDOUT,
|
||||
shell=True)
|
||||
except subprocess.CalledProcessError:
|
||||
log.warn("*** {0} package is not installed! ***".format(package) +
|
||||
"\nNOTE: If you do not install the {0} ".format(package) +
|
||||
"package, you will not receive all of the standard " +
|
||||
"operating system type metrics!")
|
||||
else:
|
||||
pass
|
||||
elif detected_os == 'Darwin':
|
||||
print("Mac OS is not currently supported by the Monasca Agent")
|
||||
sys.exit()
|
||||
elif detected_os == 'Windows':
|
||||
print("Windows is not currently supported by the Monasca Agent")
|
||||
sys.exit()
|
||||
else:
|
||||
print("{0} is not currently supported by the Monasca Agent".format(detected_os))
|
||||
|
||||
# Service enable, includes setup of users/config directories so must be
|
||||
# done before configuration
|
||||
agent_service = OS_SERVICE_MAP[detected_os](PREFIX_DIR,
|
||||
args.config_dir,
|
||||
args.log_dir,
|
||||
args.template_dir,
|
||||
username=args.user)
|
||||
# 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)
|
||||
if not args.skip_enable:
|
||||
agent_service.enable()
|
||||
|
||||
@ -152,7 +113,7 @@ def main(argv=None):
|
||||
args.dimensions = dict((name, value) for (name, value) in dimensions.iteritems())
|
||||
write_template(os.path.join(args.template_dir, 'agent.yaml.template'),
|
||||
os.path.join(args.config_dir, 'agent.yaml'),
|
||||
{'args': args, 'hostname': socket.getfqdn() },
|
||||
{'args': args, 'hostname': socket.getfqdn()},
|
||||
gid,
|
||||
is_yaml=True)
|
||||
|
||||
|
40
monasca_setup/service/detection.py
Normal file
40
monasca_setup/service/detection.py
Normal file
@ -0,0 +1,40 @@
|
||||
import logging
|
||||
import platform
|
||||
import sys
|
||||
|
||||
import linux
|
||||
|
||||
|
||||
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 apropriate Service object for this system
|
||||
"""
|
||||
detected_os = platform.system()
|
||||
if detected_os == 'Linux':
|
||||
supported_linux_flavors = ['Ubuntu', 'debian']
|
||||
flavor = platform.linux_distribution()[0]
|
||||
if flavor not in supported_linux_flavors:
|
||||
log.warn('{0} is not a support 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
|
||||
|
||||
|
||||
def detect_linux_init(*args, **kwargs):
|
||||
""" Detect which of the linux inits is running
|
||||
:return: Return a valid Linux service manager object
|
||||
"""
|
||||
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)
|
@ -1,5 +1,4 @@
|
||||
"""System V style service.
|
||||
|
||||
""" Systemd based service
|
||||
"""
|
||||
import glob
|
||||
import logging
|
||||
@ -9,24 +8,15 @@ import subprocess
|
||||
|
||||
import service
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SysV(service.Service):
|
||||
|
||||
def __init__(self, prefix_dir, config_dir, log_dir, template_dir, name='monasca-agent', username='monasca-agent'):
|
||||
"""Setup this service with the given init template.
|
||||
|
||||
"""
|
||||
super(SysV, self).__init__(prefix_dir, config_dir, log_dir, name)
|
||||
self.init_script = '/etc/init.d/%s' % self.name
|
||||
self.init_template = os.path.join(template_dir, 'monasca-agent.init.template')
|
||||
self.username = username
|
||||
|
||||
class LinuxInit(service.Service):
|
||||
""" Parent class for all Linux based init systems.
|
||||
"""
|
||||
def enable(self):
|
||||
"""Sets monasca-agent to start on boot.
|
||||
|
||||
Generally this requires running as super user
|
||||
""" Does user/group directory creation.
|
||||
"""
|
||||
# Create monasca-agent user/group if needed
|
||||
try:
|
||||
@ -44,6 +34,94 @@ class SysV(service.Service):
|
||||
# the 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
|
||||
|
||||
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, 0644)
|
||||
|
||||
# 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))
|
||||
|
||||
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 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)])
|
||||
|
||||
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.
|
||||
"""
|
||||
try:
|
||||
subprocess.check_output(['systemctl', 'is-enabled', '{0}.service'.format(self.name)])
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class SysV(LinuxInit):
|
||||
|
||||
def __init__(self, prefix_dir, config_dir, log_dir, template_dir, name='monasca-agent', username='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:
|
||||
@ -63,9 +141,7 @@ class SysV(service.Service):
|
||||
|
||||
If the agent is running and restart is True, restart
|
||||
"""
|
||||
if not self.is_enabled():
|
||||
log.error('The service is not enabled')
|
||||
return False
|
||||
LinuxInit.start(self)
|
||||
|
||||
log.info('Starting {0} service via SysV init script'.format(self.name))
|
||||
if restart:
|
||||
@ -78,9 +154,7 @@ class SysV(service.Service):
|
||||
"""Stops monasca-agent.
|
||||
|
||||
"""
|
||||
if not self.is_enabled():
|
||||
log.error('The service is not enabled')
|
||||
return False
|
||||
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
|
||||
@ -96,4 +170,4 @@ class SysV(service.Service):
|
||||
if len(glob.glob('/etc/rc?.d/S??monasca-agent')) > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return False
|
@ -1,20 +1,21 @@
|
||||
"""Classes implementing different methods for running monasca-agent on startup as well as starting the process immediately.
|
||||
"""Code to handle various service managers used on different OS
|
||||
|
||||
"""
|
||||
import psutil
|
||||
|
||||
|
||||
class Service(object):
|
||||
|
||||
"""Abstract base class implementing the interface for various service types.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, prefix_dir, config_dir, log_dir, name='monasca-agent'):
|
||||
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.
|
||||
@ -42,14 +43,13 @@ class Service(object):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def is_running():
|
||||
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 '/etc/monasca/agent/supervisor.conf' in process.cmdline():
|
||||
if '{0}/supervisor.conf'.format(self.config_dir) in process.cmdline():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
12
packaging/monasca-agent.service.template
Normal file
12
packaging/monasca-agent.service.template
Normal file
@ -0,0 +1,12 @@
|
||||
[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
|
Loading…
x
Reference in New Issue
Block a user