mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-26 20:30:59 +01:00
reckless: add function for lightning-cli calls
This also simplifies dynamic enable/disable by catching the exception raised when the cli is unable to connect to RPC (lightningd offline or misconfigured relative to reckless).
This commit is contained in:
parent
4a95a4c7da
commit
53ad1ee576
1 changed files with 70 additions and 57 deletions
127
tools/reckless
127
tools/reckless
|
@ -447,14 +447,48 @@ def search(plugin_name: str) -> InstInfo:
|
||||||
print(f'Unable to locate source for plugin {plugin_name}')
|
print(f'Unable to locate source for plugin {plugin_name}')
|
||||||
|
|
||||||
|
|
||||||
def lightning_cli_available() -> bool:
|
class RPCError(Exception):
|
||||||
"""returns True if lightning-cli rpc available with current config"""
|
"""lightning-cli fails to connect to lightningd RPC"""
|
||||||
clncli = Popen(LIGHTNING_CLI_CALL, stdout=PIPE, stderr=PIPE)
|
def __init__(self, err):
|
||||||
clncli.wait(timeout=1)
|
self.err = err
|
||||||
if clncli.returncode == 0:
|
|
||||||
return True
|
def __str__(self):
|
||||||
|
return 'RPCError({self.err})'
|
||||||
|
|
||||||
|
|
||||||
|
class CLIError(Exception):
|
||||||
|
"""lightningd error response"""
|
||||||
|
def __init__(self, code, message):
|
||||||
|
self.code = code
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'CLIError({self.code} {self.message})'
|
||||||
|
|
||||||
|
|
||||||
|
def lightning_cli(*args, timeout=15) -> dict:
|
||||||
|
# CLI commands will be added to any necessary options
|
||||||
|
cmd = LIGHTNING_CLI_CALL.copy()
|
||||||
|
cmd.extend(args)
|
||||||
|
clncli = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
||||||
|
clncli.wait(timeout=timeout)
|
||||||
|
out = clncli.stdout.read().decode()
|
||||||
|
if len(out) > 0 and out[0] == '{':
|
||||||
|
# If all goes well, a json object is typically returned
|
||||||
|
out = json.loads(out.replace('\n', ''))
|
||||||
else:
|
else:
|
||||||
return False
|
# help, -V, etc. may not return json, so stash it here.
|
||||||
|
out = {'content': out}
|
||||||
|
if clncli.returncode == 0:
|
||||||
|
return out
|
||||||
|
if clncli.returncode == 1:
|
||||||
|
# RPC doesn't like our input
|
||||||
|
# output contains 'code' and 'message'
|
||||||
|
raise CLIError(out['code'], out['message'])
|
||||||
|
if clncli.returncode == 2:
|
||||||
|
# RPC not available - lightningd not running or using alternate config
|
||||||
|
err = clncli.stderr.read().decode()
|
||||||
|
raise RPCError(err)
|
||||||
|
|
||||||
|
|
||||||
def enable(plugin_name: str):
|
def enable(plugin_name: str):
|
||||||
|
@ -463,33 +497,21 @@ def enable(plugin_name: str):
|
||||||
inst = InferInstall(plugin_name)
|
inst = InferInstall(plugin_name)
|
||||||
path = inst.entry
|
path = inst.entry
|
||||||
if not Path(path).exists():
|
if not Path(path).exists():
|
||||||
print('cannot find installed plugin at expected path {}'
|
print(f'cannot find installed plugin at expected path {path}')
|
||||||
.format(path))
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
verbose('activating {}'.format(plugin_name))
|
verbose(f'activating {plugin_name}')
|
||||||
|
try:
|
||||||
if not lightning_cli_available():
|
lightning_cli('plugin', 'start', path)
|
||||||
# Config update should not be dependent upon lightningd running
|
except CLIError as err:
|
||||||
RECKLESS_CONFIG.enable_plugin(path)
|
if 'already registered' in err.message:
|
||||||
return
|
verbose(f'{inst.name} is already running')
|
||||||
|
|
||||||
cmd = LIGHTNING_CLI_CALL.copy()
|
|
||||||
cmd.extend(['plugin', 'start', path])
|
|
||||||
clncli = Popen(cmd, stdout=PIPE)
|
|
||||||
clncli.wait(timeout=3)
|
|
||||||
if clncli.returncode == 0:
|
|
||||||
RECKLESS_CONFIG.enable_plugin(path)
|
|
||||||
print('{} enabled'.format(plugin_name))
|
|
||||||
else:
|
|
||||||
err = eval(clncli.stdout.read().decode().replace('\n', ''))['message']
|
|
||||||
if ': already registered' in err:
|
|
||||||
RECKLESS_CONFIG.enable_plugin(path)
|
|
||||||
verbose(f'{inst.name} already registered with lightningd')
|
|
||||||
print('{} enabled'.format(plugin_name))
|
|
||||||
else:
|
else:
|
||||||
print(f'reckless: {inst.name} failed to start!')
|
print(f'reckless: {inst.name} failed to start!')
|
||||||
print(err)
|
raise err
|
||||||
sys.exit(clncli.returncode)
|
except RPCError:
|
||||||
|
verbose('lightningd rpc unavailable. Skipping dynamic activation.')
|
||||||
|
RECKLESS_CONFIG.enable_plugin(path)
|
||||||
|
print(f'{plugin_name} enabled')
|
||||||
|
|
||||||
|
|
||||||
def disable(plugin_name: str):
|
def disable(plugin_name: str):
|
||||||
|
@ -501,22 +523,17 @@ def disable(plugin_name: str):
|
||||||
if not Path(path).exists():
|
if not Path(path).exists():
|
||||||
sys.stderr.write(f'Could not find plugin at {path}\n')
|
sys.stderr.write(f'Could not find plugin at {path}\n')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if not lightning_cli_available():
|
verbose(f'deactivating {plugin_name}')
|
||||||
RECKLESS_CONFIG.disable_plugin(path)
|
try:
|
||||||
print(f'{plugin_name} disabled')
|
lightning_cli('plugin', 'stop', path)
|
||||||
return
|
except CLIError as err:
|
||||||
cmd = LIGHTNING_CLI_CALL.copy()
|
if err.code == -32602:
|
||||||
cmd.extend(['plugin', 'stop', path])
|
verbose('plugin not currently running')
|
||||||
clncli = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
else:
|
||||||
clncli.wait(timeout=3)
|
print('lightning-cli plugin stop failed')
|
||||||
output = json.loads(clncli.stdout.read().decode()
|
raise err
|
||||||
.replace('\n', '').replace(' ', ''))
|
except RPCError:
|
||||||
if ('code' in output.keys() and output['code'] == -32602):
|
verbose('lightningd rpc unavailable. Skipping dynamic deactivation.')
|
||||||
print('plugin not currently running')
|
|
||||||
elif clncli.returncode != 0:
|
|
||||||
print('lightning-cli plugin stop failed')
|
|
||||||
sys.stderr.write(clncli.stderr.read().decode())
|
|
||||||
sys.exit(clncli.returncode)
|
|
||||||
RECKLESS_CONFIG.disable_plugin(path)
|
RECKLESS_CONFIG.disable_plugin(path)
|
||||||
print(f'{plugin_name} disabled')
|
print(f'{plugin_name} disabled')
|
||||||
|
|
||||||
|
@ -526,16 +543,12 @@ def load_config(reckless_dir: Union[str, None] = None,
|
||||||
"""Initial directory discovery and config file creation."""
|
"""Initial directory discovery and config file creation."""
|
||||||
# Does the lightning-cli already reference an explicit config?
|
# Does the lightning-cli already reference an explicit config?
|
||||||
net_conf = None
|
net_conf = None
|
||||||
if lightning_cli_available():
|
try:
|
||||||
cmd = LIGHTNING_CLI_CALL
|
active_config = lightning_cli('listconfigs', timeout=3)
|
||||||
cmd.extend(['listconfigs'])
|
if 'conf' in active_config:
|
||||||
clncli = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
net_conf = LightningBitcoinConfig(path=active_config['conf'])
|
||||||
clncli.wait(timeout=3)
|
except RPCError:
|
||||||
if clncli.returncode == 0:
|
pass
|
||||||
output = json.loads(clncli.stdout.read().decode()
|
|
||||||
.replace('\n', '').replace(' ', ''))
|
|
||||||
if 'conf' in output:
|
|
||||||
net_conf = LightningBitcoinConfig(path=output['conf'])
|
|
||||||
if reckless_dir is None:
|
if reckless_dir is None:
|
||||||
reckless_dir = Path(LIGHTNING_DIR).joinpath('reckless')
|
reckless_dir = Path(LIGHTNING_DIR).joinpath('reckless')
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Add table
Reference in a new issue