]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: acme: publish ACME_NEWCERT event via event_hdl
authorWilliam Lallemand <wlallemand@haproxy.com>
Thu, 11 Jun 2026 13:47:42 +0000 (15:47 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Thu, 11 Jun 2026 17:14:52 +0000 (19:14 +0200)
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.

doc/lua-api/index.rst
include/haproxy/acme-t.h
include/haproxy/acme.h
include/haproxy/event_hdl-t.h
src/acme.c
src/event_hdl.c
src/hlua.c

index 08568bcc3eda10fcb2dcb52480a05859448a611c..ad6dd0b14f6f7834d11063e99b9054098720154a 100644 (file)
@@ -1031,6 +1031,10 @@ Core class
       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
@@ -1048,7 +1052,8 @@ Core class
   * **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.
@@ -4760,6 +4765,20 @@ ACME class
   :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
 ======================
index fb75399e580d7aedc068ae69578013f47c20f3e9..87c2ce306d56506b9d7989c493e8b57a5674d1d3 100644 (file)
@@ -135,6 +135,15 @@ struct acme_ctx {
 #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
index 1591ee876a6c55f416017977210f2fb8bcbe75a3..e147d131bbaafbad2574dcf1b09258d316ba9466 100644 (file)
@@ -9,5 +9,10 @@ int acme_challenge_ready(const char *crt, const char *dns);
 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
index 85d13bea7205a424524934649d59448dfe137d18..d5d8dc32feecaa0fd3b1eaeb089efc1fa41da738 100644 (file)
@@ -290,6 +290,13 @@ struct event_hdl_sub {
 #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
index b9b022947cac0ee6d0f629ac5f587af541d61ff5..5aea3146b42cd81f7100d4c2f2ee836995446e0a 100644 (file)
@@ -19,6 +19,7 @@
 #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>
@@ -1456,6 +1457,14 @@ error:
        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
  *
@@ -1509,6 +1518,15 @@ int acme_update_certificate(struct task *task, struct acme_ctx *ctx, char **errm
        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;
@@ -3699,6 +3717,24 @@ static void __acme_init(void)
 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)
  *
@@ -3731,6 +3767,10 @@ __LJMP static int hlua_acme_challenge_ready(lua_State *L)
 
 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");
@@ -3738,6 +3778,23 @@ static int acme_hlua_init_state(lua_State *L, char **errmsg)
 }
 
 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 */
index 1929f00f73ace569fe3ac540827cd64929ebcdf8..6e6358e1ac3a5ebb9932b5221835ef5521392121 100644 (file)
@@ -48,6 +48,8 @@ static struct event_hdl_sub_type_map event_hdl_sub_type_map[] = {
        {"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) */
index d2734d101a2bc001c4bf977bbb2df18871fb8016..124c8c1c0e77f2a52022b8bd47eb8f92076d4218 100644 (file)
@@ -73,6 +73,9 @@
 #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 */
 
@@ -10071,6 +10074,11 @@ __LJMP static void hlua_event_hdl_cb_push_args(struct hlua_event_sub *hlua_sub,
                        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);