ceph/teuthology/orchestra/daemon.py
Zack Cerza 7d0adcee2d Move DaemonState to teuthology.orchestra
Signed-off-by: Zack Cerza <zack.cerza@inktank.com>
2014-07-23 19:59:16 -06:00

170 lines
5.4 KiB
Python

import logging
import struct
from . import run
log = logging.getLogger(__name__)
class DaemonState(object):
"""
Daemon State. A daemon exists for each instance of each role.
"""
def __init__(self, remote, role, id_, *command_args, **command_kwargs):
"""
Pass remote command information as parameters to remote site
:param remote: Remote site
:param role: Role (osd, rgw, mon, mds)
:param id_: Id within role (osd.1, osd.2, for eaxmple)
:param command_args: positional arguments (used in restart commands)
:param command_kwargs: keyword arguments (used in restart commands)
"""
self.remote = remote
self.command_args = command_args
self.command_kwargs = command_kwargs
self.role = role
self.id_ = id_
self.log = command_kwargs.get('logger', log)
self.proc = None
def stop(self, timeout=300):
"""
Stop this daemon instance.
Note: this can raise a run.CommandFailedError,
run.CommandCrashedError, or run.ConnectionLostError.
:param timeout: timeout to pass to orchestra.run.wait()
"""
if not self.running():
self.log.error('tried to stop a non-running daemon')
return
self.proc.stdin.close()
self.log.debug('waiting for process to exit')
run.wait([self.proc], timeout=timeout)
self.proc = None
self.log.info('Stopped')
def restart(self, *args, **kwargs):
"""
Restart with a new command passed in the arguments
:param args: positional arguments passed to remote.run
:param kwargs: keyword arguments passed to remote.run
"""
self.log.info('Restarting daemon')
if self.proc is not None:
self.log.info('Stopping old one...')
self.stop()
cmd_args = list(self.command_args)
cmd_args.extend(args)
cmd_kwargs = self.command_kwargs
cmd_kwargs.update(kwargs)
self.proc = self.remote.run(*cmd_args, **cmd_kwargs)
self.log.info('Started')
def restart_with_args(self, extra_args):
"""
Restart, adding new paramaters to the current command.
:param extra_args: Extra keyword arguments to be added.
"""
self.log.info('Restarting daemon')
if self.proc is not None:
self.log.info('Stopping old one...')
self.stop()
cmd_args = list(self.command_args)
# we only want to make a temporary mod of the args list
# so we shallow copy the dict, and deepcopy the args list
cmd_kwargs = self.command_kwargs.copy()
from copy import deepcopy
cmd_kwargs['args'] = deepcopy(self.command_kwargs['args'])
cmd_kwargs['args'].extend(extra_args)
self.proc = self.remote.run(*cmd_args, **cmd_kwargs)
self.log.info('Started')
def signal(self, sig):
"""
Send a signal to associated remote commnad
:param sig: signal to send
"""
self.proc.stdin.write(struct.pack('!b', sig))
self.log.info('Sent signal %d', sig)
def running(self):
"""
Are we running?
:return: True if remote run command value is set, False otherwise.
"""
return self.proc is not None
def reset(self):
"""
clear remote run command value.
"""
self.proc = None
def wait_for_exit(self):
"""
clear remote run command value after waiting for exit.
"""
if self.proc:
try:
run.wait([self.proc])
finally:
self.proc = None
class DaemonGroup(object):
"""
Collection of daemon state instances
"""
def __init__(self):
"""
self.daemons is a dictionary indexed by role. Each entry is a
dictionary of DaemonState values indexed by an id parameter.
"""
self.daemons = {}
def add_daemon(self, remote, role, id_, *args, **kwargs):
"""
Add a daemon. If there already is a daemon for this id_ and role, stop
that daemon and. Restart the damon once the new value is set.
:param remote: Remote site
:param role: Role (osd, mds, mon, rgw, for example)
:param id_: Id (index into role dictionary)
:param args: Daemonstate positional parameters
:param kwargs: Daemonstate keyword parameters
"""
if role not in self.daemons:
self.daemons[role] = {}
if id_ in self.daemons[role]:
self.daemons[role][id_].stop()
self.daemons[role][id_] = None
self.daemons[role][id_] = DaemonState(remote, role, id_, *args,
**kwargs)
self.daemons[role][id_].restart()
def get_daemon(self, role, id_):
"""
get the daemon associated with this id_ for this role.
:param role: Role (osd, mds, mon, rgw, for example)
:param id_: Id (index into role dictionary)
"""
if role not in self.daemons:
return None
return self.daemons[role].get(str(id_), None)
def iter_daemons_of_role(self, role):
"""
Iterate through all daemon instances for this role. Return dictionary
of daemon values.
:param role: Role (osd, mds, mon, rgw, for example)
"""
return self.daemons.get(role, {}).values()