From 904e3776ff88bed6a4b34c9bbe8b0298f85e0cfe Mon Sep 17 00:00:00 2001 From: Rom1-B <8530352+Rom1-B@users.noreply.github.com> Date: Wed, 16 Sep 2026 14:17:01 +0200 Subject: [PATCH] Feat: add local Docker dev environment for the plugin --- .dev/README.md | 40 +++++++++++++++++++++++++++++++++++ .dev/docker-compose.yml | 33 +++++++++++++++++++++++++++++ .dev/seed.sh | 47 +++++++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 6 ++++++ Makefile | 25 ++++++++++++++++++++++ 5 files changed, 151 insertions(+) create mode 100644 .dev/README.md create mode 100644 .dev/docker-compose.yml create mode 100644 .dev/seed.sh create mode 100644 Makefile diff --git a/.dev/README.md b/.dev/README.md new file mode 100644 index 0000000..ffb89ab --- /dev/null +++ b/.dev/README.md @@ -0,0 +1,40 @@ +# metabase plugin — local test environment + +Adds a [Metabase](https://www.metabase.com/) instance for this plugin's dashboard-embedding +feature. + +## What's here + +| File | Purpose | +|------|---------| +| `docker-compose.yml` | Purely additive: declares only `metabase` and `metabase-seed` (never touches `app`) | +| `seed.sh` | Runs Metabase's first-time setup, sets a fixed embedding secret key, enables static embedding | + +## Usage + +```bash +make up +make config +``` + +Then, in GLPI: *Setup → Metabase*, fill in the fields printed by `make config` +(`host`/`port` for the server-to-server API calls, `username`/`password` for the Metabase admin +account, `metabase_url` for the browser-facing iframe source, `embedded_token` as the embedding +signing key). Save, then use the plugin's own actions on that page: + +- *Create GLPI database in local Metabase*: has the plugin connect Metabase directly to GLPI's own + database, using this compose stack's `db` service (reachable at `db:3306`). +- *Push reports and dashboards in Metabase*: has the plugin build its bundled dashboards/cards + against that database connection. + +Neither of those two steps is pre-seeded here: they are exactly what the plugin's config page is +for, and exercising them for real is how this environment is validated. + +The published port defaults to `3010`; override with `METABASE_PORT=` if already taken. + +## Field names + +The plugin's config page (`inc/config.class.php`) uses `host`/`port`/`username`/`password` for the +Metabase API connection, `metabase_url` for the iframe source, and `embedded_token` for the +embedding secret key (despite the name, it is used directly as JWT signing key material in +`PluginMetabaseDashboard::showForCentral()`, not as a bearer token). diff --git a/.dev/docker-compose.yml b/.dev/docker-compose.yml new file mode 100644 index 0000000..365b71e --- /dev/null +++ b/.dev/docker-compose.yml @@ -0,0 +1,33 @@ +# ------------------------------------------------------------------------- +# Metabase plugin GLPI - local test environment +# ------------------------------------------------------------------------- +# Adds a Metabase instance, plus a one-shot sidecar that runs first-time +# setup (dev admin account) and enables static embedding, via the Metabase +# REST API. The plugin itself pushes the "GLPI database" connection and the +# demo dashboards/cards from GLPI's own config page (Setup > Metabase), not +# from this compose file. +# +# File is *purely additive*: declares only `metabase` and `metabase-seed` +# services, never redefines `app` or `db`. +# ------------------------------------------------------------------------- +services: + metabase: + image: "metabase/metabase:latest" + ports: + - "${METABASE_PORT:-3010}:3000" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"] + interval: "5s" + timeout: "3s" + retries: 40 + start_period: "30s" + + metabase-seed: + image: "alpine:3.21" + depends_on: + metabase: + condition: "service_healthy" + volumes: + - "${METABASE_DEV_DIR:-.}/seed.sh:/seed.sh:ro" + entrypoint: ["/bin/sh", "/seed.sh"] + restart: "no" diff --git a/.dev/seed.sh b/.dev/seed.sh new file mode 100644 index 0000000..953cbfb --- /dev/null +++ b/.dev/seed.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# Runs Metabase's first-time setup (or confirms an existing admin account +# still works on a re-run), then sets a fixed embedding secret key and +# enables static embedding, via the Metabase REST API. +# Idempotent: reuses the existing admin account and re-applies the settings +# on every run. +set -eu + +apk add --no-cache curl jq >/dev/null + +BASE_URL="http://metabase:3000" +ADMIN_EMAIL="admin@glpi.local" +ADMIN_PASSWORD="stk-dev-admin1" +SECRET_KEY="2628b70987266db59aa1e05bb06afa2a620a75548569263774d26ca7a3357797" + +api() { + method="$1"; path="$2"; body="${3:-}" + if [ -n "$body" ]; then + if [ -n "${SESSION:-}" ]; then + curl -sf -X "$method" "$BASE_URL$path" -H "Content-Type: application/json" -H "X-Metabase-Session: $SESSION" -d "$body" + else + curl -sf -X "$method" "$BASE_URL$path" -H "Content-Type: application/json" -d "$body" + fi + else + if [ -n "${SESSION:-}" ]; then + curl -sf -X "$method" "$BASE_URL$path" -H "X-Metabase-Session: $SESSION" + else + curl -sf -X "$method" "$BASE_URL$path" + fi + fi +} + +props=$(api GET /api/session/properties) +has_user_setup=$(printf '%s' "$props" | jq -r '.["has-user-setup"]') + +if [ "$has_user_setup" = "true" ]; then + SESSION=$(api POST /api/session "$(jq -n --arg u "$ADMIN_EMAIL" --arg p "$ADMIN_PASSWORD" '{username:$u,password:$p}')" | jq -r '.id') +else + setup_token=$(printf '%s' "$props" | jq -r '.["setup-token"]') + SESSION=$(api POST /api/setup "$(jq -n --arg t "$setup_token" --arg e "$ADMIN_EMAIL" --arg p "$ADMIN_PASSWORD" \ + '{token:$t, user:{first_name:"Stk", last_name:"Dev", email:$e, password:$p}, prefs:{site_name:"GLPI Dev", allow_tracking:false}}')" | jq -r '.id') +fi + +api PUT /api/setting/embedding-secret-key "$(jq -n --arg v "$SECRET_KEY" '{value:$v}')" >/dev/null +api PUT /api/setting/enable-embedding-static '{"value":true}' >/dev/null + +echo "metabase: dev admin account and static embedding ready" diff --git a/CHANGELOG.md b/CHANGELOG.md index 921fffc..bacf969 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] + +### Added + +- Local dev environment (Metabase instance + admin/embedding seeding) for plugin development + ## [1.4.2] - 2026-08-04 ### Fixed diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3fda998 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +include ../../PluginsMakefile.mk + +# Absolute path to this plugin's own .dev directory, referenced as ${METABASE_DEV_DIR} +# in .dev/docker-compose.yml: Compose resolves relative volume paths against the +# directory of the first -f file, not per-file, so a bare relative path breaks once +# merged with the core compose file. +export METABASE_DEV_DIR = $(CURDIR)/.dev + +up: ## Start the local dev services (see .dev/docker-compose.yml) + @$(COMPOSE) -f ../../docker-compose.yaml -f .dev/docker-compose.yml --project-directory ../.. up -d metabase +.PHONY: up + +down: ## Stop the local dev services + @$(COMPOSE) -f ../../docker-compose.yaml -f .dev/docker-compose.yml --project-directory ../.. down +.PHONY: down + +config: ## Print the values to enter in GLPI's Setup > Metabase config page + @echo "host: metabase" + @echo "port: 3000" + @echo "username: admin@glpi.local" + @echo "password: stk-dev-admin1" + @echo "metabase_url: http://localhost:$${METABASE_PORT:-3010}/" + @echo "embedded_token: 2628b70987266db59aa1e05bb06afa2a620a75548569263774d26ca7a3357797" + +.PHONY: config