Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .dev/README.md
Original file line number Diff line number Diff line change
@@ -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=<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).
33 changes: 33 additions & 0 deletions .dev/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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"
47 changes: 47 additions & 0 deletions .dev/seed.sh
Original file line number Diff line number Diff line change
@@ -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"
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -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