mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 14:42:40 +01:00
lightningd/plugin_control: add a 'plugin' command
This adds a new pair of files : lightningd/plugin_control, along with a new RPC command : 'plugin'. This command can be used to manage plugins without restarting lightningd: lightning-cli plugin start helloworld.py lightning-cli plugin stop helloworld.py
This commit is contained in:
parent
d299420fbe
commit
2864b4de01
4 changed files with 147 additions and 1 deletions
|
@ -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
|
||||
|
|
|
@ -121,7 +121,7 @@ void PRINTF_FMT(2,3) plugin_kill(struct plugin *plugin, char *fmt, ...)
|
|||
msg = tal_vfmt(plugin, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
log_broken(plugin->log, "Killing plugin: %s", msg);
|
||||
log_info(plugin->log, "Killing plugin: %s", msg);
|
||||
plugin->stop = true;
|
||||
io_wake(plugin);
|
||||
kill(plugin->pid, SIGKILL);
|
||||
|
@ -813,6 +813,12 @@ static void plugin_manifest_cb(const char *buffer,
|
|||
plugin_kill(
|
||||
plugin,
|
||||
"Failed to register options, methods, hooks, or subscriptions.");
|
||||
|
||||
/* If all plugins have replied to getmanifest and this is not
|
||||
* the startup init, configure them */
|
||||
if (!plugin->plugins->startup && plugin->plugins->pending_manifests == 0)
|
||||
plugins_config(plugin->plugins);
|
||||
|
||||
/* Reset timer, it'd kill us otherwise. */
|
||||
tal_free(plugin->timeout_timer);
|
||||
}
|
||||
|
|
132
lightningd/plugin_control.c
Normal file
132
lightningd/plugin_control.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
#include <ccan/tal/path/path.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/jsonrpc_errors.h>
|
||||
#include <common/param.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <lightningd/plugin_control.h>
|
||||
#include <lightningd/plugin_hook.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* A plugin command which permits to control plugins without restarting
|
||||
* lightningd. It takes a subcommand, and an optional subcommand parameter.
|
||||
*/
|
||||
static struct command_result *json_plugin_control(struct command *cmd,
|
||||
const char *buffer,
|
||||
const jsmntok_t *obj UNNEEDED,
|
||||
const jsmntok_t *params)
|
||||
{
|
||||
const char *subcmd;
|
||||
subcmd = param_subcommand(cmd, buffer, params,
|
||||
"start", "stop", "startdir", "rescan", "list", NULL);
|
||||
if (!subcmd)
|
||||
return command_param_failed();
|
||||
|
||||
struct plugin *p;
|
||||
struct json_stream *response;
|
||||
|
||||
if (streq(subcmd, "stop")) {
|
||||
const char *plugin_name;
|
||||
bool plugin_found;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("subcommand", param_ignore, cmd),
|
||||
p_req("plugin", param_string, &plugin_name),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
plugin_found = false;
|
||||
list_for_each(&cmd->ld->plugins->plugins, p, list) {
|
||||
if (plugin_paths_match(p->cmd, plugin_name)) {
|
||||
plugin_found = true;
|
||||
plugin_hook_unregister_all(p);
|
||||
plugin_kill(p, "%s stopped by lightningd via RPC",
|
||||
plugin_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!plugin_found)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Could not find plugin %s", plugin_name);
|
||||
} else if (streq(subcmd, "start")) {
|
||||
const char *plugin_path;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("subcommand", param_ignore, cmd),
|
||||
p_req("plugin", param_string, &plugin_path),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
if (access(plugin_path, X_OK) == 0)
|
||||
plugin_register(cmd->ld->plugins, plugin_path);
|
||||
else
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"%s is not executable: %s",
|
||||
plugin_path, strerror(errno));
|
||||
} else if (streq(subcmd, "startdir")) {
|
||||
const char *dir_path;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("subcommand", param_ignore, cmd),
|
||||
p_req("directory", param_string, &dir_path),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
if (access(dir_path, F_OK) == 0)
|
||||
add_plugin_dir(cmd->ld->plugins, dir_path, true);
|
||||
else
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Could not open %s", dir_path);
|
||||
} else if (streq(subcmd, "rescan")) {
|
||||
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 */
|
||||
}
|
||||
|
||||
/* The config function is called once we got the manifest,
|
||||
* in 'plugin_manifest_cb'.*/
|
||||
plugins_start(cmd->ld->plugins, cmd->ld->dev_debug_subprocess);
|
||||
|
||||
response = json_stream_success(cmd);
|
||||
json_array_start(response, "plugins");
|
||||
list_for_each(&cmd->ld->plugins->plugins, p, list) {
|
||||
json_object_start(response, NULL);
|
||||
json_add_string(response, "name", p->cmd);
|
||||
json_add_bool(response, "active", p->configured);
|
||||
json_object_end(response);
|
||||
}
|
||||
json_array_end(response);
|
||||
|
||||
return command_success(cmd, response);
|
||||
}
|
||||
|
||||
static const struct json_command plugin_control_command = {
|
||||
"plugin",
|
||||
"plugin",
|
||||
json_plugin_control,
|
||||
"Control plugins (start, stop, startdir, rescan, list)",
|
||||
.verbose = "Usage :\n"
|
||||
"plugin start /path/to/a/plugin\n"
|
||||
" adds a new plugin to c-lightning\n"
|
||||
"plugin stop plugin_name\n"
|
||||
" stops an already registered plugin\n"
|
||||
"plugin startdir /path/to/a/plugin_dir/\n"
|
||||
" adds a new plugin directory\n"
|
||||
"plugin rescan\n"
|
||||
" loads not-already-loaded plugins from the default plugins dir\n"
|
||||
"plugin list\n"
|
||||
" lists all active plugins\n"
|
||||
"\n"
|
||||
};
|
||||
AUTODATA(json_command, &plugin_control_command);
|
7
lightningd/plugin_control.h
Normal file
7
lightningd/plugin_control.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef LIGHTNING_LIGHTNINGD_PLUGIN_CONTROL_H
|
||||
#define LIGHTNING_LIGHTNINGD_PLUGIN_CONTROL_H
|
||||
#include "config.h"
|
||||
#include <lightningd/lightningd.h>
|
||||
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_PLUGIN_CONTROL_H */
|
Loading…
Add table
Reference in a new issue