Add a new EVENT_HDL_SUB_ACME_NEWCERT event type in the ACME family.
It is published after a new certificate has been successfully fetched
and installed. The event carries the certificate store name, allowing
subscribers to act on newly available certificates.
Lua subscribers using core.event_sub() receive the event data as an
AcmeEvent object with a crtname field containing the certificate store
name.
Be careful when subscribing to this type since many events might be
generated.
+ **ACME** Family:
+
+ * **ACME_NEWCERT**: when a new certificate is successfully installed
+
.. Note::
Use **SERVER** in **event_types** to subscribe to all server events types
at once. Note that this should only be used for testing purposes since a
* **event** (*string*): the event type (one of the **event_types** specified
when subscribing)
* **event_data**: specific to each event family (For **SERVER** family,
- a :ref:`server_event_class` object)
+ a :ref:`server_event_class` object; for **ACME** family,
+ a :ref:`acme_event_class` object)
* **sub**: class to manage the subscription from within the event
(a :ref:`event_sub_class` object)
* **when**: timestamp corresponding to the date when the event was generated.
:returns: The number of remaining challenges (integer), or 0 when all
challenges are done and validation has been triggered.
+.. _acme_event_class:
+
+AcmeEvent class
+===============
+
+.. js:class:: AcmeEvent
+
+This class is provided with **ACME_NEWCERT** events.
+
+See :js:func:`core.event_sub()` for more info.
+
+.. js:attribute:: AcmeEvent.crtname
+
+ Contains the certificate store name of the newly installed certificate.
External Lua libraries
======================
#define ACME_VERB_ADVANCED 4
#define ACME_VERB_COMPLETE 5
+/* event data for EVENT_HDL_SUB_ACME_NEWCERT:
+ * published when a new certificate was successfully installed.
+ */
+struct event_hdl_cb_data_acme_newcert {
+ struct {
+ char *crtname; /* certificate store name (heap-allocated) */
+ } safe;
+};
+
#endif /* ! HAVE_ACME */
#endif
EVP_PKEY *acme_gen_tmp_pkey();
X509 *acme_gen_tmp_x509();
+#if defined(USE_LUA)
+#include <haproxy/hlua-t.h>
+#include <haproxy/event_hdl-t.h>
+void acme_hlua_event_push_args(struct hlua *hlua, struct event_hdl_sub_type event, void *data);
+#endif /* USE_LUA */
#endif
#define EVENT_HDL_SUB_PAT_REF_COMMIT EVENT_HDL_SUB_TYPE(2,4)
#define EVENT_HDL_SUB_PAT_REF_CLEAR EVENT_HDL_SUB_TYPE(2,5)
+/* ACME family, published in global subscription list.
+ * Provides event_hdl_cb_data_acme_newcert struct (defined in haproxy/acme-t.h).
+ */
+#define EVENT_HDL_SUB_ACME EVENT_HDL_SUB_FAMILY(3)
+/* a new certificate was successfully installed */
+#define EVENT_HDL_SUB_ACME_NEWCERT EVENT_HDL_SUB_TYPE(3,1)
+
/* --------------------------------------- */
/* Please reflect changes above in event_hdl_sub_type_map defined
#include <haproxy/acme-t.h>
#include <haproxy/acme_resolvers.h>
+#include <haproxy/event_hdl.h>
#include <haproxy/base64.h>
#include <haproxy/intops.h>
#include <haproxy/cfgparse.h>
return ret;
}
+/* mfree callback for EVENT_HDL_SUB_ACME_NEWCERT: frees the heap-allocated path */
+static void acme_newcert_event_mfree(const void *data)
+{
+ const struct event_hdl_cb_data_acme_newcert *e = data;
+
+ free(e->safe.crtname);
+}
+
/*
* Update every certificate instances for the new store
*
if (dpapi)
sink_write(dpapi, LOG_HEADER_NONE, 0, line, 3);
+ {
+ struct event_hdl_cb_data_acme_newcert cb_data = { };
+
+ cb_data.safe.crtname = strdup(ctx->store->path);
+ if (cb_data.safe.crtname)
+ event_hdl_publish(NULL, EVENT_HDL_SUB_ACME_NEWCERT,
+ EVENT_HDL_CB_DATA_DM(&cb_data, acme_newcert_event_mfree));
+ }
+
ctx->store = NULL;
ret = 0;
INITCALL0(STG_REGISTER, __acme_init);
#ifdef USE_LUA
+
+#define CLASS_ACME_EVENT "AcmeEvent"
+static int class_acme_event_ref;
+
+/* Push a new AcmeEvent object for an ACME_NEWCERT event onto the Lua stack.
+ * The object exposes a <crtname> field with the certificate store name.
+ */
+static void hlua_fcn_new_acme_event_newcert(lua_State *L, const char *crtname)
+{
+ lua_newtable(L);
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, class_acme_event_ref);
+ lua_setmetatable(L, -2);
+
+ lua_pushstring(L, crtname);
+ lua_setfield(L, -2, "crtname");
+}
+
/*
* ACME.challenge_ready(crt, dns)
*
static int acme_hlua_init_state(lua_State *L, char **errmsg)
{
+ /* Register AcmeEvent class */
+ lua_newtable(L);
+ class_acme_event_ref = hlua_register_metatable(L, CLASS_ACME_EVENT);
+
lua_newtable(L);
hlua_class_function(L, "challenge_ready", hlua_acme_challenge_ready);
lua_setglobal(L, "ACME");
}
REGISTER_HLUA_STATE_INIT(acme_hlua_init_state);
+
+/* Push ACME event data as a Lua table for core.event_sub() handlers.
+ * Called from hlua_event_hdl_cb_push_args() when the event family is ACME.
+ */
+void acme_hlua_event_push_args(struct hlua *hlua, struct event_hdl_sub_type event, void *data)
+{
+ if (!lua_checkstack(hlua->T, 3))
+ WILL_LJMP(luaL_error(hlua->T, "Lua out of memory error."));
+
+ if (event_hdl_sub_type_equal(EVENT_HDL_SUB_ACME_NEWCERT, event)) {
+ struct event_hdl_cb_data_acme_newcert *e_acme = data;
+
+ hlua->nargs += 1;
+ MAY_LJMP(hlua_fcn_new_acme_event_newcert(hlua->T, e_acme->safe.crtname));
+ }
+}
+
#endif /* USE_LUA */
#endif /* ! HAVE_ACME */
{"PAT_REF_SET", EVENT_HDL_SUB_PAT_REF_SET},
{"PAT_REF_COMMIT", EVENT_HDL_SUB_PAT_REF_COMMIT},
{"PAT_REF_CLEAR", EVENT_HDL_SUB_PAT_REF_CLEAR},
+ {"ACME", EVENT_HDL_SUB_ACME},
+ {"ACME_NEWCERT", EVENT_HDL_SUB_ACME_NEWCERT},
};
/* internal types (only used in this file) */
#include <haproxy/event_hdl.h>
#include <haproxy/check.h>
#include <haproxy/mailers.h>
+#if defined(HAVE_ACME)
+#include <haproxy/acme.h>
+#endif /* HAVE_ACME */
/* Global LUA flags */
lua_settable(hlua->T, -3);
}
}
+#if defined(HAVE_ACME)
+ else if (event_hdl_sub_family_equal(EVENT_HDL_SUB_ACME, event)) {
+ MAY_LJMP(acme_hlua_event_push_args(hlua, event, data));
+ }
+#endif /* HAVE_ACME */
/* sub mgmt */
hlua->nargs += 1;
hlua_fcn_new_event_sub(hlua->T, hlua_sub->sub);