lightningd/plugin.c: Add important plugins, which if they terminate, lightningd also terminates.

Changelog-Added: New option `--important-plugin` loads a plugin is so important that if it dies, `lightningd` will exit rather than continue.  You can still `--disable-plugin` it, however, which trumps `--important-plugin` and it will not be started at all.
This commit is contained in:
ZmnSCPxj jxPCSnmZ
2020-07-29 19:24:07 +08:00
committed by neil saitug
parent 50600dce95
commit a847487bbe
7 changed files with 123 additions and 24 deletions

View File

@@ -53,6 +53,7 @@ struct plugins *plugins_new(const tal_t *ctx, struct log_book *log_book,
p->startup = true;
p->json_cmds = tal_arr(p, struct command *, 0);
p->blacklist = tal_arr(p, const char *, 0);
p->shutdown = false;
uintmap_init(&p->pending_requests);
memleak_add_helper(p, memleak_help_pending_requests);
@@ -62,6 +63,9 @@ struct plugins *plugins_new(const tal_t *ctx, struct log_book *log_book,
void plugins_free(struct plugins *plugins)
{
struct plugin *p;
plugins->shutdown = true;
/* Plugins are usually the unit of allocation, and they are internally
* consistent, so let's free each plugin first. */
while (!list_empty(&plugins->plugins)) {
@@ -105,6 +109,7 @@ struct command_result *plugin_register_all_complete(struct lightningd *ld,
static void destroy_plugin(struct plugin *p)
{
struct plugin_rpccall *call;
plugin_hook_unregister_all(p);
list_del(&p->list);
@@ -118,10 +123,23 @@ static void destroy_plugin(struct plugin *p)
/* Don't call this if we're still parsing options! */
if (p->plugin_state != UNCONFIGURED)
check_plugins_resolved(p->plugins);
/* If we are shutting down, do not continue to checking if
* the dying plugin is important. */
if (p->plugins->shutdown)
return;
/* Now check if the dying plugin is important. */
if (p->important) {
log_broken(p->log,
"Plugin marked as important, "
"shutting down lightningd!");
lightningd_exit(p->plugins->ld, 1);
}
}
struct plugin *plugin_register(struct plugins *plugins, const char* path TAKES,
struct command *start_cmd)
struct command *start_cmd, bool important)
{
struct plugin *p, *p_temp;
@@ -130,6 +148,9 @@ struct plugin *plugin_register(struct plugins *plugins, const char* path TAKES,
if (streq(path, p_temp->cmd)) {
if (taken(path))
tal_free(path);
/* If added as "important", upgrade to "important". */
if (important)
p_temp->important = true;
return NULL;
}
}
@@ -153,6 +174,8 @@ struct plugin *plugin_register(struct plugins *plugins, const char* path TAKES,
list_add_tail(&plugins->plugins, &p->list);
tal_add_destructor(p, destroy_plugin);
list_head_init(&p->pending_rpccalls);
p->important = important;
return p;
}
@@ -186,6 +209,8 @@ void plugin_blacklist(struct plugins *plugins, const char *name)
log_info(plugins->log, "%s: disabled via disable-plugin",
p->cmd);
list_del_from(&plugins->plugins, &p->list);
/* disable-plugin overrides important-plugin. */
p->important = false;
tal_free(p);
}
}
@@ -1188,7 +1213,7 @@ char *add_plugin_dir(struct plugins *plugins, const char *dir, bool error_ok)
log_info(plugins->log, "%s: disabled via disable-plugin",
fullpath);
} else {
p = plugin_register(plugins, fullpath, NULL);
p = plugin_register(plugins, fullpath, NULL, false);
if (!p && !error_ok)
return tal_fmt(NULL, "Failed to register %s: %s",
fullpath, strerror(errno));
@@ -1396,24 +1421,35 @@ void plugins_config(struct plugins *plugins)
plugins->startup = false;
}
void json_add_opt_plugins(struct json_stream *response,
const struct plugins *plugins)
/** json_add_opt_plugins_array
*
* @brief add a named array of plugins to the given response,
* depending on whether it is important or not important.
*
* @param response - the `json_stream` to write into.
* @param name - the field name of the array.
* @param plugins - the plugins object to query.
* @param important - match the `important` setting of the
* plugins to be added.
*/
static
void json_add_opt_plugins_array(struct json_stream *response,
const char *name,
const struct plugins *plugins,
bool important)
{
struct plugin *p;
struct plugin_opt *opt;
const char *plugin_name;
struct plugin_opt *opt;
const char *opt_name;
/* DEPRECATED: duplicated JSON "plugin" entries */
if (deprecated_apis) {
list_for_each(&plugins->plugins, p, list) {
json_add_string(response, "plugin", p->cmd);
}
}
/* we output 'plugins' and their options as an array of substructures */
json_array_start(response, "plugins");
json_array_start(response, name);
list_for_each(&plugins->plugins, p, list) {
/* Skip if not matching. */
if (p->important != important)
continue;
json_object_start(response, NULL);
json_add_string(response, "path", p->cmd);
@@ -1444,6 +1480,23 @@ void json_add_opt_plugins(struct json_stream *response,
json_array_end(response);
}
void json_add_opt_plugins(struct json_stream *response,
const struct plugins *plugins)
{
struct plugin *p;
json_add_opt_plugins_array(response, "plugins", plugins, false);
json_add_opt_plugins_array(response, "important-plugins", plugins, true);
/* DEPRECATED: duplicated JSON "plugin" entries */
if (deprecated_apis) {
list_for_each(&plugins->plugins, p, list) {
json_add_string(response, p->important ? "important-plugin" : "plugin", p->cmd);
}
}
}
void json_add_opt_disable_plugins(struct json_stream *response,
const struct plugins *plugins)
{
@@ -1546,7 +1599,6 @@ static void mark_plugin_destroyed(const struct plugin *unused,
pd->plugin = NULL;
}
struct plugin_destroyed *plugin_detect_destruction(const struct plugin *plugin)
{
struct plugin_destroyed *pd = tal(NULL, struct plugin_destroyed);