diff --git a/doc/configuration.txt b/doc/configuration.txt index a5e6603c0..790c6076f 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -5934,7 +5934,7 @@ it could block the event loop, blocking the traffic on the same thread. Meaning that the certificates and keys generated from HAProxy will need to be dumped from outside HAProxy using "dump ssl cert" on the stats socket. The generation is not scheduled and must be triggered using the CLI command -"acme renew". +"acme renew". See also "acme ps" in the management guide. The following keywords are usable in the ACME section: diff --git a/doc/management.txt b/doc/management.txt index 66fecc635..785037069 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -1641,10 +1641,19 @@ abort ssl crl-file See also "set ssl crl-file" and "commit ssl crl-file". +acme ps + Show the running ACME tasks. See also "acme renew". + + Example: + $ echo "@1 acme ps" | socat /run/haproxy-master.sock - | column -t -s $'\t' + # certificate section state + foobar.pem.rsa LE1 Running + foobar.pem.ecdsa LE2 Running + acme renew Starts an ACME certificate generation task with the given certificate name. The certificate must be linked to an acme section, see section 3.13. of the - configuration manual. + configuration manual. See also "acme ps". add acl [@] Add an entry into the acl . is the # or the returned by diff --git a/include/haproxy/acme-t.h b/include/haproxy/acme-t.h index 8a3527df4..c614468c3 100644 --- a/include/haproxy/acme-t.h +++ b/include/haproxy/acme-t.h @@ -79,5 +79,6 @@ struct acme_ctx { X509_REQ *req; struct ist finalize; struct ist certificate; + struct mt_list el; }; #endif diff --git a/src/acme.c b/src/acme.c index a1be20fa2..6897952b2 100644 --- a/src/acme.c +++ b/src/acme.c @@ -11,6 +11,7 @@ #include #include +#include #include @@ -35,6 +36,9 @@ #if defined(HAVE_ACME) + +struct mt_list acme_tasks = MT_LIST_HEAD_INIT(acme_tasks); + static struct acme_cfg *acme_cfgs = NULL; static struct acme_cfg *cur_acme = NULL; @@ -613,6 +617,8 @@ static void acme_ctx_destroy(struct acme_ctx *ctx) X509_REQ_free(ctx->req); + MT_LIST_DELETE(&ctx->el); + free(ctx); } @@ -1737,6 +1743,7 @@ struct task *acme_process(struct task *task, void *context, unsigned int state) enum acme_st st = ctx->state; enum http_st http_st = ctx->http_state; char *errmsg = NULL; + struct mt_list tmp = MT_LIST_LOCK_FULL(&ctx->el); switch (st) { case ACME_RESSOURCES: @@ -1935,6 +1942,7 @@ struct task *acme_process(struct task *task, void *context, unsigned int state) } + MT_LIST_UNLOCK_FULL(&ctx->el, tmp); ctx->retries = ACME_RETRY; ctx->http_state = http_st; ctx->state = st; @@ -1969,6 +1977,7 @@ retry: ha_free(&errmsg); + MT_LIST_UNLOCK_FULL(&ctx->el, tmp); return task; abort: @@ -1976,6 +1985,7 @@ abort: ha_free(&errmsg); end: + MT_LIST_UNLOCK_FULL(&ctx->el, tmp); acme_del_acme_ctx_map(ctx); acme_ctx_destroy(ctx); task_destroy(task); @@ -2172,6 +2182,9 @@ static int cli_acme_renew_parse(char **args, char *payload, struct appctx *appct ctx->cfg = cfg; task->context = ctx; + MT_LIST_INIT(&ctx->el); + MT_LIST_APPEND(&acme_tasks, &ctx->el); + task_wakeup(task, TASK_WOKEN_INIT); return 0; @@ -2186,9 +2199,38 @@ err: } +static int cli_acme_ps_io_handler(struct appctx *appctx) +{ + struct mt_list back; + struct acme_ctx *ctx; + + chunk_reset(&trash); + + chunk_appendf(&trash, "# certificate\tsection\tstate\n"); + if (applet_putchk(appctx, &trash) == -1) + return 1; + + MT_LIST_FOR_EACH_ENTRY_LOCKED(ctx, &acme_tasks, el, back) { + chunk_appendf(&trash, "%s\t%s\tRunning\n", ctx->store->path, ctx->cfg->name); + + /* TODO: handle backref list when list of task > buffer size */ + if (applet_putchk(appctx, &trash) == -1) + return 1; + } + + return 1; +} + +static int cli_acme_ps(char **args, char *payload, struct appctx *appctx, void *private) +{ + return 0; +} + + static struct cli_kw_list cli_kws = {{ },{ { { "acme", "renew", NULL }, "acme renew : renew a certificate using the ACME protocol", cli_acme_renew_parse, NULL, NULL, NULL, 0 }, + { { "acme", "ps", NULL }, "acme ps : show running ACME tasks", cli_acme_ps, cli_acme_ps_io_handler, NULL, NULL, 0 }, { { NULL }, NULL, NULL, NULL } }};