mirror of
https://github.com/ceph/ceph
synced 2025-01-11 21:50:26 +00:00
7d0adcee2d
Signed-off-by: Zack Cerza <zack.cerza@inktank.com>
170 lines
5.4 KiB
Python
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()
|