From 002d8fe1962df04ef15721553fe648a7330e8824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phan=20Sainl=C3=A9ger?= Date: Fri, 25 Sep 2026 19:06:38 +0200 Subject: [PATCH] fix: [carbone-ee] enable Studio and template management The charm had no ``hooks/init``, so Carbone started in its default stateless mode: no Studio, no template management, and ``CARBONE_BIND`` defaulting to ``127.0.0.1`` (unreachable behind the web-proxy). Add ``hooks/init`` to: - bind on ``0.0.0.0`` so the ``web-proxy`` can reach the service ; - serve the Studio and ``/carbone-studio.js`` (``CARBONE_STUDIO``) ; - enable stateful template management (``CARBONE_TEMPLATE_MANAGEMENT``): stable 64-bit template IDs, versioning and the ``/template`` endpoints ; - align the datastore/configstore ownership on the unprivileged ``carbone`` image user, otherwise the container crash-loops with ``EACCES`` on ``/app/config/config.json``. Persist ``/app/config`` as a ``config-resources`` and set a ``docker-compose.stop_grace_period`` of 200s: Carbone flushes its template metadata on graceful shutdown, and Docker's 10s default would SIGKILL it and lose templates on redeploy. Flush metadata every 5 minutes to shrink the hard-crash window. Bump the image to ``full-5.15.1`` and add a local ``basic-deploy`` test. Verified locally: ``/status`` 200, ``/carbone-studio.js`` 200, ``GET /templates`` 200, template upload with versioning plus render from the stable template ID, and metadata survival across a container recreation. --- carbone/README.org | 57 +++++++++++++++++-- carbone/hooks/init | 47 +++++++++++++++ carbone/metadata.yml | 17 +++++- .../tests/compose/basic-deploy/compose.yml | 2 + 4 files changed, 117 insertions(+), 6 deletions(-) create mode 100755 carbone/hooks/init create mode 100644 carbone/tests/compose/basic-deploy/compose.yml diff --git a/carbone/README.org b/carbone/README.org index 2225b26..ad3df93 100644 --- a/carbone/README.org +++ b/carbone/README.org @@ -1,17 +1,66 @@ # -*- ispell-local-dictionary: "english" -*- -* Info +* Info From: Carbone https://hub.docker.com/r/carbone/carbone-ee#running-carbone-community-edition-forever-free -## Usage : +Upstream documentation: +- On-premise configuration: https://carbone.io/documentation/developer/on-premise-installation/configuration.html +- Template management: https://carbone.io/documentation/developer/on-premise-installation/template-management.html +- Studio Web Component: https://carbone.io/documentation/developer/embedding/studio-web-component.html + +* What this charm enables + +By default Carbone starts in the *stateless* mode: it only renders the +template sent with each request, exposes no Studio and keeps no template +metadata. The =init= hook turns it into the *stateful* service, which is +what the charm is meant to provide: + +- =CARBONE_STUDIO=true= serves the Studio web interface and the + =/carbone-studio.js= Web Component. +- =CARBONE_TEMPLATE_MANAGEMENT=true= enables stable 64-bit template IDs, + versioning, the =GET/POST/PATCH /template= endpoints and the + =embedded-versioning= Studio mode. +- =CARBONE_BIND=0.0.0.0= makes Carbone listen on all interfaces so the + =web-proxy= can reach it (the upstream default is =127.0.0.1=). + +* Usage ex : -``` +#+begin_src yaml carbone: relations: web-proxy: frontend: domain: carbone.dev1.elabore.coop -``` +#+end_src + +* Persistence + +| Path | Resource type | Content | +|-----------------+------------------+------------------------------------------------------| +| =/app/template= | =data-resources= | Templates and the metadata store (metadata.db) | +| =/app/config= | =config-resources= | Optional license, authentication public key (key.pub) | + +Templates and their versioning metadata both live under =/app/template=, +so they survive redeploys and are covered by the =backup= relation. + +* Enterprise license + +Carbone runs fine without a license (Community Edition, forever free). +Advanced features (dynamic images/colors, barcodes, charts, HTML +aggregation, PDF operations, ...) require an Enterprise license. + +To enable it, drop your =*.carbone-license= file into the config store +(=/app/config= on the host side, i.e. +=$SERVICE_CONFIGSTORE/app/config=) and redeploy the service. + +* API authentication + +Authentication is *disabled by default*: the API is reachable as soon as +the service is up, which is the expected setup behind the =web-proxy=. +If you ever need an API key (JWT), enable =CARBONE_AUTHENTICATION=true=, +generate an EC keypair with =generate-keys=, expose the public key as +=/app/config/key.pub= and generate a token with =generate-token=. See +the upstream "Deploy with Docker" documentation for the exact commands. \ No newline at end of file diff --git a/carbone/hooks/init b/carbone/hooks/init new file mode 100755 index 0000000..ce1ee9c --- /dev/null +++ b/carbone/hooks/init @@ -0,0 +1,47 @@ +#!/bin/bash + +## Init is run on host +## For now it is run every time the script is launched, but +## it should be launched only once after build. + +## Accessible variables are: +## - SERVICE_NAME Name of current service +## - DOCKER_BASE_IMAGE Base image from which this service might be built if any +## - SERVICE_DATASTORE Location on host of the DATASTORE of this service +## - SERVICE_CONFIGSTORE Location on host of the CONFIGSTORE of this service + +set -e + +## The image runs as the unprivileged "carbone" user, while the datastore +## and configstore bind mounts are created by root. Both /app/template +## (templates + metadata.db) and /app/config (config.json, keys, license) +## must be writable by that user, otherwise the container crash-loops with +## "EACCES: permission denied, open '/app/config/config.json'". +uid_gid=($(docker_get_uid_gid "$SERVICE_NAME" "carbone" "carbone")) || exit 1 +uid="${uid_gid[0]}" +gid="${uid_gid[1]}" + +mkdir -p "$SERVICE_DATASTORE/app/template" "$SERVICE_CONFIGSTORE/app/config" +chown "$uid:$gid" "$SERVICE_DATASTORE/app/template" "$SERVICE_CONFIGSTORE/app/config" + +## Carbone starts in stateless mode (document generation only) and binds +## to 127.0.0.1 by default (see `carbone webserver --help`, v5.15.1). +## Inside Docker it must: +## - listen on all interfaces so the web-proxy can reach it (CARBONE_BIND) ; +## - serve the Studio web interface and /carbone-studio.js (CARBONE_STUDIO) ; +## - enable stateful template management: stable 64-bit template IDs, +## versioning and the GET/POST/PATCH /template endpoints +## (CARBONE_TEMPLATE_MANAGEMENT). +## +## CARBONE_TEMPLATE_METADATA_FLUSH_CRON defaults to once a day; flushing +## every 5 minutes shrinks the window where a hard crash (SIGKILL, OOM) +## would lose template metadata. The graceful-shutdown flush remains the +## safety net for redeploys (see docker-compose.stop_grace_period). +init-config-add " +$SERVICE_NAME: + environment: + CARBONE_BIND: \"0.0.0.0\" + CARBONE_STUDIO: \"true\" + CARBONE_TEMPLATE_MANAGEMENT: \"true\" + CARBONE_TEMPLATE_METADATA_FLUSH_CRON: \"*/5 * * * *\" +" \ No newline at end of file diff --git a/carbone/metadata.yml b/carbone/metadata.yml index 0b4df01..caf1d6d 100644 --- a/carbone/metadata.yml +++ b/carbone/metadata.yml @@ -1,7 +1,20 @@ -## From carbone/carbone-ee:full-5.4.2 -docker-image: docker.0k.io/carbone-ee:5.4.2 +## From carbone/carbone-ee:full-5.15.1 +docker-image: docker.0k.io/carbone-ee:5.15.1 +docker-compose: + ## Carbone flushes its template metadata to disk on graceful shutdown. + ## Docker's default 10s stop timeout is shorter than Carbone's shutdown + ## sequence (exitQuietPeriod + flush), so a plain redeploy would SIGKILL + ## it and lose the templates/versioning. Keep this above Carbone's + ## exitDeadline (default 3 min). + stop_grace_period: 200s data-resources: + ## Templates and the template-management metadata store (metadata.db) + ## both live here, so they survive redeploys and are covered by backup. - /app/template +config-resources: + ## Holds the optional Enterprise license (*.carbone-license) and the + ## authentication public key (key.pub). See README.org. + - /app/config uses: web-proxy: diff --git a/carbone/tests/compose/basic-deploy/compose.yml b/carbone/tests/compose/basic-deploy/compose.yml new file mode 100644 index 0000000..be37891 --- /dev/null +++ b/carbone/tests/compose/basic-deploy/compose.yml @@ -0,0 +1,2 @@ +carbone-test: + charm: carbone \ No newline at end of file