Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export COMPAT=${COMPAT:-1}
export PATH=$CWD/dependencies/bin:"$HOME"/.local/bin:"$PATH"
export TIMEOUT=180
export PYTEST_PAR=2
export PYTHONPATH=$PWD/contrib/pylightning:$PYTHONPATH
Comment thread
darosior marked this conversation as resolved.
# If we're not in developer mode, tests spend a lot of time waiting for gossip!
# But if we're under valgrind, we can run out of memory!
if [ "$DEVELOPER" = 0 ] && [ "$VALGRIND" = 0 ]; then
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- build: now requires `python3-mako` to be installed, i.e. `sudo apt-get install python3-mako`
- plugins: a new notification type `invoice_payment` (sent when an invoice is paid) has been added
- plugins: a new 'channel_opened' notification type is added, which is emitted when a peer succesfully funds a channel to us
- rpc: a new rpc command is added, `plugin`. It allows one to manage plugins without restarting `lightningd`.
- plugins: a new boolean field is added to the `init`'s `configuration`, `startup`. It allows a plugin to know if it has been started on `lightningd` startup.
- plugins: a new boolean field can be added to a plugin manifest, `dynamic`. It allows a plugin to tell if it can be started or stopped "on-the-fly".

@rustyrussell rustyrussell Jul 28, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll probably collapse these three lines into "plugins: dynamic plugin support", which is the better summary for this level IMHO.

(I do a CHANGELOG.md cleanup sweep as part of the release process, so I won't hold up the merge for this!)


### Deprecated

Expand Down
45 changes: 45 additions & 0 deletions contrib/pylightning/lightning/lightning.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,51 @@ def ping(self, peer_id, length=128, pongbytes=128):
}
return self.call("ping", payload)

def plugin_start(self, plugin):
"""
Adds a plugin to lightningd.
"""
payload = {
"subcommand": "start",
"plugin": plugin
}
return self.call("plugin", payload)

def plugin_startdir(self, directory):
"""
Adds all plugins from a directory to lightningd.
"""
payload = {
"subcommand": "startdir",
"directory": directory
}
return self.call("plugin", payload)

def plugin_stop(self, plugin):
"""
Stops a lightningd plugin, will fail if plugin is not dynamic.
"""
payload = {
"subcommand": "stop",
"plugin": plugin
}
return self.call("plugin", payload)

def plugin_list(self):
"""
Lists all plugins lightningd knows about.
"""
payload = {
"subcommand": "list"
}
return self.call("plugin", payload)

def plugin_rescan(self):
payload = {
"subcommand": "rescan"
}
return self.call("plugin", payload)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, discarding parameters if we don't know the subcommand seems wrong? I think we need to whitelist the known parameters?

@darosior darosior Jul 22, 2019

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand, do you mean whitelist on the C side ? Like accepting parameters for reload (soon rescandir :) and list subcommands ?
https://github.com/darosior/lightning/blob/09a2dea65292e6713aadeb60e253da8d0bd4f92c/lightningd/plugin_control.c#L81-L95

	} else if (streq(subcmd, "reload")) {
		if (!param(cmd, buffer, params,
				   p_req("subcommand", param_ignore, cmd),
				   NULL))
			return command_param_failed();

		plugins_add_default_dir(cmd->ld->plugins,
				path_join(tmpctx, cmd->ld->config_dir, "plugins"));
	} else if (streq(subcmd, "list")) {
		if (!param(cmd, buffer, params,
				   p_req("subcommand", param_ignore, cmd),
				   NULL))
			return command_param_failed();
		/* Don't do anything as we return the plugin list anyway */
	}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should rewrite this into multiple calls that map to the various plugin subcommands?

  • plugin_start
  • plugin_stop
  • plugin_rescan
  • etc

That way we have something to attach the specific help messages to instead of handling opaque sets of parameters?


def sendpay(self, route, payment_hash, description=None, msatoshi=None):
"""
Send along {route} in return for preimage of {payment_hash}
Expand Down
6 changes: 5 additions & 1 deletion contrib/pylightning/lightning/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class Plugin(object):

"""

def __init__(self, stdout=None, stdin=None, autopatch=True):
def __init__(self, stdout=None, stdin=None, autopatch=True, dynamic=True):
Comment thread
darosior marked this conversation as resolved.
Comment thread
darosior marked this conversation as resolved.
self.methods = {'init': Method('init', self._init, MethodType.RPCMETHOD)}
self.options = {}

Expand All @@ -118,6 +118,8 @@ def __init__(self, stdout=None, stdin=None, autopatch=True):
self.rpc_filename = None
self.lightning_dir = None
self.rpc = None
self.startup = True
self.dynamic = dynamic
self.child_init = None

self.write_lock = RLock()
Expand Down Expand Up @@ -496,13 +498,15 @@ def _getmanifest(self, **kwargs):
'rpcmethods': methods,
'subscriptions': list(self.subscriptions.keys()),
'hooks': hooks,
'dynamic': self.dynamic
}

def _init(self, options, configuration, request):
self.rpc_filename = configuration['rpc-file']
self.lightning_dir = configuration['lightning-dir']
path = os.path.join(self.lightning_dir, self.rpc_filename)
self.rpc = LightningRpc(path)
self.startup = configuration['startup']
for name, value in options.items():
self.options[name]['value'] = value

Expand Down
13 changes: 11 additions & 2 deletions doc/PLUGINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ this example:
"hooks": [
"openchannel",
"htlc_accepted"
]
],
"dynamic": true
}
```

Expand All @@ -102,6 +103,10 @@ are mandatory, while the `long_description` can be omitted (it'll be
set to `description` if it was not provided). `usage` should surround optional
parameter names in `[]`.

The `dynamic` indicates if the plugin can be managed after `lightningd`
has been started. Critical plugins that should not be stop should set it
to false.

Plugins are free to register any `name` for their `rpcmethod` as long
as the name was not previously registered. This includes both built-in
methods, such as `help` and `getinfo`, as well as methods registered
Expand All @@ -122,7 +127,8 @@ simple JSON object containing the options:
},
"configuration": {
"lightning-dir": "/home/user/.lightning",
"rpc-file": "lightning-rpc"
"rpc-file": "lightning-rpc",
"startup": true
}
}
```
Expand All @@ -132,6 +138,9 @@ arbitrary and will currently be discarded by `lightningd`. JSON-RPC
commands were chosen over notifications in order not to force plugins
to implement notifications which are not that well supported.

The `startup` field allows a plugin to detect if it was started at
`lightningd` startup (true), or at runtime (false).

## JSON-RPC passthrough

Plugins may register their own JSON-RPC methods that are exposed
Expand Down
56 changes: 56 additions & 0 deletions doc/lightning-plugin.7
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'\" t
.\" Title: lightning-plugin
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 07/23/2019
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "LIGHTNING\-PLUGIN" "7" "07/23/2019" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
lightning-plugin \- Manage plugins with RPC
.SH "SYNOPSIS"
.sp
\fBplugin\fR command [parameter] [second_parameter]
.SH "DESCRIPTION"
.sp
The \fBplugin\fR RPC command allows to manage plugins without having to restart lightningd\&. It takes 1 to 3 parameters: a command (start/stop/startdir/rescan/list) which describes the action to take and optionally one or two parameters which describes the plugin on which the action has to be taken\&.
.sp
The \fIstart\fR command takes a path as parameter and will load the plugin available from this path\&.
.sp
The \fIstop\fR command takes a plugin name as parameter and will kill and unload the specified plugin\&.
.sp
The \fIstartdir\fR command takes a directory path as parameter and will load all plugins this directory contains\&.
.sp
The \fIrescan\fR command starts all not\-already\-loaded plugins from the default plugins directory (by default \fI~/\&.lightning/plugins\fR)\&.
.sp
The \fIlist\fR command will return all the active plugins\&.
.SH "RETURN VALUE"
.sp
On success, this returns an array \fIplugins\fR of objects, one by plugin\&. Each object contains the name of the plugin (\fIname\fR field) and its status (\fIactive\fR boolean field)\&. Since plugins are configured asynchronously, a freshly started plugin may not appear immediately\&.
.SH "AUTHOR"
.sp
Antoine Poinsot <darosior@protonmail\&.com> is mainly responsible\&.
.SH "RESOURCES"
.sp
Main web site: https://github\&.com/ElementsProject/lightning
48 changes: 48 additions & 0 deletions doc/lightning-plugin.7.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
LIGHTNING-PLUGIN(7)
===================
:doctype: manpage

NAME
----
lightning-plugin - Manage plugins with RPC

SYNOPSIS
--------
*plugin* command [parameter] [second_parameter]

DESCRIPTION
-----------

The *plugin* RPC command allows to manage plugins without having to restart lightningd.
It takes 1 to 3 parameters: a command (start/stop/startdir/rescan/list) which describes the
action to take and optionally one or two parameters which describes the plugin on which
the action has to be taken.

The 'start' command takes a path as parameter and will load the plugin available from this
Comment thread
darosior marked this conversation as resolved.
path.

The 'stop' command takes a plugin name as parameter and will kill and unload the specified
plugin.

The 'startdir' command takes a directory path as parameter and will load all plugins this
directory contains.

The 'rescan' command starts all not-already-loaded plugins from the default plugins directory
(by default '~/.lightning/plugins').

The 'list' command will return all the active plugins.

RETURN VALUE
------------

On success, this returns an array 'plugins' of objects, one by plugin. Each object contains
the name of the plugin ('name' field) and its status ('active' boolean field).
Since plugins are configured asynchronously, a freshly started plugin may not appear immediately.

AUTHOR
------
Antoine Poinsot <darosior@protonmail.com> is mainly responsible.

RESOURCES
---------
Main web site: https://github.com/ElementsProject/lightning
1 change: 1 addition & 0 deletions lightningd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ LIGHTNINGD_SRC := \
lightningd/peer_htlcs.c \
lightningd/ping.c \
lightningd/plugin.c \
lightningd/plugin_control.c \
lightningd/plugin_hook.c \
lightningd/subd.c \
lightningd/watch.c
Expand Down
1 change: 1 addition & 0 deletions lightningd/lightningd.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
*the plugins.
*/
ld->plugins = plugins_new(ld, ld->log_book, ld);
ld->plugins->startup = true;

/*~ This is set when a JSON RPC command comes in to shut us down. */
ld->stop_conn = NULL;
Expand Down
Loading