A simple base class for services.
"""
- def __init__(me, friendly, *args, **kw):
+ def __init__(me, friendly, name = None, *args, **kw):
super(BasicService, me).__init__(*args)
+ me.name = name
me.friendly = friendly
me.meta = kw
configuration.
"""
- def _run(me, cmd, input = None):
+ def _run(me, cmd, input = None, state = None):
"""
This is the core of the remote service machinery. It issues a command
and parses the response. It will generate strings of informational
output from the command; error responses cause appropriate exceptions to
be raised.
- The command is determined by passing the CMD argument to the `_mkcmd'
- method, which a subclass must implement; it should return a list of
- command-line arguments suitable for `subprocess.Popen'. The INPUT is a
- string to make available on the command's stdin; if None, then no input
+ The command is determined by passing the CMD and STATE arguments to the
+ `_mkcmd' method, which a subclass must implement; it should return a list
+ of command-line arguments suitable for `subprocess.Popen'. The INPUT is
+ a string to make available on the command's stdin; if None, then no input
is provided to the command. The `_describe' method must provide a
description of the remote service for use in timeout messages.
## Run the command and collect its output and status.
with U.timeout(30, "waiting for remote service %s" % me._describe()):
- proc = SUB.Popen(me._mkcmd(cmd),
+ proc = SUB.Popen(me._mkcmd(cmd, state),
stdin = input is not None and SUB.PIPE or None,
stdout = SUB.PIPE, stderr = SUB.PIPE)
out, err = proc.communicate(input)
if not win:
raise U.ExpectedError, (500, 'No reply from remote service')
- def _run_noout(me, cmd, input = None):
+ def _run_noout(me, cmd, input = None, state = None):
"""Like `_run', but expect no output."""
- for _ in me._run(cmd, input):
+ for _ in me._run(cmd, input, state):
raise U.ExpectedError, (500, 'Unexpected output from remote service')
class SSHRemoteService (BasicRemoteService):
(probably of the form `LOGIN@HOSTNAME') and referring to the service
NAME.
"""
- super(SSHRemoteService, me).__init__(*args, **kw)
+ super(SSHRemoteService, me).__init__(name = name, *args, **kw)
me._remote = remote
- me._name = name
def _describe(me):
"""Description of the remote service."""
- return "`%s' via SSH to `%s'" % (me._name, me._remote),
+ return "`%s' via SSH to `%s'" % (me.name, me._remote),
- def _mkcmd(me, cmd):
+ def _mkcmd(me, cmd, state):
"""Format a command for SSH. Mainly escaping arguments."""
return ['ssh', me._remote, ' '.join(map(CGI.urlencode, cmd))]
def setpasswd(me, user, passwd):
"""Service protocol: set the USER's password to PASSWD."""
- me._run_noout(['set', me._name, user], passwd + '\n')
+ me._run_noout(['set', me.name, user], passwd + '\n')
def clearpasswd(me, user):
"""Service protocol: clear the USER's password."""
- me._run_noout(['clear', me._name, user])
+ me._run_noout(['clear', me.name, user])
CONF.export('SSHRemoteService')
R_PAT = RX.compile('%(.)')
def __init__(me, set, clear, *args, **kw):
- """
- Initialize the command remote service.
- """
+ """Initialize the command remote service."""
super(CommandRemoteService, me).__init__(*args, **kw)
me._set = set
me._clear = clear
- me._map = dict(u = user)
- def _subst(me, c):
+ def _describe(me):
+ """Description of the remote service."""
+ return "`%s' command service (%s)" % (me.name, ' '.join(me._default))
+
+ def _subst(me, c, map):
"""Return the substitution for the placeholder `%C'."""
- return me._map.get(c, c)
+ return map.get(c, c)
- def _mkcmd(me, cmd):
+ def _mkcmd(me, cmd, map):
"""Construct the command to be executed, by substituting placeholders."""
- return [me.R_PAT.sub(lambda m: me._subst(m.group(1))) for arg in cmd]
+ return [me.R_PAT.sub(lambda m: me._subst(m.group(1), map), arg)
+ for arg in cmd]
def setpasswd(me, user, passwd):
"""Service protocol: set the USER's password to PASSWD."""
- me._run_noout(me._set, passwd + '\n')
+ me._run_noout(me._set, passwd + '\n', state = dict(u = user))
def clearpasswd(me, user):
"""Service protocol: clear the USER's password."""
- me._run_noout(me._clear)
+ me._run_noout(me._clear, state = dict(u = user))
CONF.export('CommandRemoteService')
'users', 'user', 'passwd'),
CFG.HASH,
friendly = 'Password changing service')
+ for name, svc in SERVICES.iteritems():
+ if svc.name is None: svc.name = name
###----- That's all, folks --------------------------------------------------