Skip to content

Commit 799147f

Browse files
DoDiODevCopilot
andauthored
fix(grafana): run entrypoint with POSIX sh (#9312)
grafana/grafana:13.3.0 no longer ships bash, so the image failed to start with "exec /entrypoint.sh: no such file or directory". Switch the shebang to /bin/sh and replace the only bashism ($'\n'). Add grafana/scripts/smoke-test.sh plus a pull_request workflow that builds the image and checks that it starts and creates a healthy datasource against MySQL and PostgreSQL, so base image bumps that break startup are caught before merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 6cfd55b commit 799147f

3 files changed

Lines changed: 148 additions & 2 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
name: grafana-image-smoke-test
18+
19+
on:
20+
pull_request:
21+
branches:
22+
- main
23+
- release-*
24+
paths:
25+
- 'grafana/**'
26+
- '.github/workflows/grafana-image-smoke-test.yml'
27+
28+
jobs:
29+
grafana-image-smoke-test:
30+
name: grafana image smoke test (${{ matrix.db }})
31+
runs-on: ubuntu-24.04
32+
strategy:
33+
fail-fast: false
34+
matrix:
35+
db: [mysql, postgresql]
36+
steps:
37+
- uses: actions/checkout@v7
38+
- name: Build grafana image
39+
run: docker build -t devlake-dashboard:smoke grafana
40+
- name: Start image and check datasource
41+
run: grafana/scripts/smoke-test.sh devlake-dashboard:smoke ${{ matrix.db }}

‎grafana/scripts/entrypoint.sh‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/bin/bash
1+
#!/bin/sh
22
# Licensed to the Apache Software Foundation (ASF) under one or more
33
# contributor license agreements. See the NOTICE file distributed with
44
# this work for additional information regarding copyright ownership.
@@ -271,14 +271,18 @@ fi
271271

272272
echo "Creating datasource via API..."
273273
DATASOURCE_OK=false
274+
# The grafana/grafana image (Alpine/busybox) ships no bash, so stay POSIX sh.
275+
NL='
276+
'
274277
for i in $(seq 1 10); do
275278
# "|| true": a failing curl must not end this script (set -e) and with it the
276279
# container; the status check below reports the problem instead.
277280
RESPONSE=$(grafana_api -w '\nHTTP_STATUS=%{http_code}' -X POST "${GRAFANA_API}/datasources" \
278281
-H "Content-Type: application/json" \
279282
-d @"$PAYLOAD_FILE" 2>&1) || true
280283
STATUS="${RESPONSE##*HTTP_STATUS=}"
281-
RESPONSE="${RESPONSE%$'\n'HTTP_STATUS=*}"
284+
RESPONSE="${RESPONSE%HTTP_STATUS=*}"
285+
RESPONSE="${RESPONSE%"$NL"}"
282286

283287
if [ "$STATUS" = "401" ] || [ "$STATUS" = "403" ]; then
284288
# Retrying cannot help: the credentials do not match the Grafana admin.

‎grafana/scripts/smoke-test.sh‎

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#!/usr/bin/env bash
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# Smoke test for the devlake-dashboard (Grafana) image: starts it next to a
18+
# throwaway database and checks that the entrypoint runs, Grafana becomes
19+
# healthy and the DevLake datasource is created and can reach the database.
20+
#
21+
# Usage: grafana/scripts/smoke-test.sh <image> [mysql|postgresql]
22+
# Uses uniquely named containers/network only; nothing else is touched.
23+
24+
set -euo pipefail
25+
26+
IMAGE="${1:?usage: $0 <image> [mysql|postgresql]}"
27+
DB_TYPE="${2:-mysql}"
28+
TIMEOUT="${SMOKE_TIMEOUT:-180}"
29+
MYSQL_IMAGE="${MYSQL_IMAGE:-mysql:8.4}"
30+
POSTGRES_IMAGE="${POSTGRES_IMAGE:-postgres:18}"
31+
32+
PREFIX="grafana-smoke-$$"
33+
NET="$PREFIX-net"
34+
DB="$PREFIX-db"
35+
GRAFANA="$PREFIX-grafana"
36+
37+
cleanup() {
38+
docker rm -fv "$GRAFANA" "$DB" >/dev/null 2>&1 || true
39+
docker network rm "$NET" >/dev/null 2>&1 || true
40+
}
41+
trap cleanup EXIT
42+
43+
fail() {
44+
echo "FAIL: $*"
45+
echo "----- grafana container logs -----"
46+
docker logs "$GRAFANA" 2>&1 | grep -v 'logger=' | tail -50 || true
47+
exit 1
48+
}
49+
50+
docker network create "$NET" >/dev/null
51+
52+
case "$DB_TYPE" in
53+
mysql)
54+
docker run -d -q --name "$DB" --network "$NET" \
55+
-e MYSQL_ROOT_PASSWORD=admin -e MYSQL_DATABASE=lake \
56+
-e MYSQL_USER=merico -e MYSQL_PASSWORD=merico \
57+
"$MYSQL_IMAGE" >/dev/null
58+
DS_UID="devlake-mysql-api"
59+
;;
60+
postgresql)
61+
docker run -d -q --name "$DB" --network "$NET" \
62+
-e POSTGRES_DB=lake -e POSTGRES_USER=merico -e POSTGRES_PASSWORD=merico \
63+
"$POSTGRES_IMAGE" >/dev/null
64+
DS_UID="devlake-postgres-api"
65+
;;
66+
*)
67+
echo "unknown database type '$DB_TYPE' (expected mysql or postgresql)"
68+
exit 2
69+
;;
70+
esac
71+
72+
docker run -d --name "$GRAFANA" --network "$NET" \
73+
-e DATABASE_TYPE="$DB_TYPE" -e DATABASE_HOST="$DB" \
74+
"$IMAGE" >/dev/null
75+
76+
echo "Waiting for $IMAGE ($DB_TYPE) to create its datasource..."
77+
deadline=$((SECONDS + TIMEOUT))
78+
until docker logs "$GRAFANA" 2>&1 | grep -q "Datasource created successfully"; do
79+
if [ "$(docker inspect -f '{{.State.Running}}' "$GRAFANA")" != "true" ]; then
80+
fail "grafana container exited (exit code $(docker inspect -f '{{.State.ExitCode}}' "$GRAFANA"))"
81+
fi
82+
if docker logs "$GRAFANA" 2>&1 | grep -q "ERROR: datasource"; then
83+
fail "entrypoint could not create the datasource"
84+
fi
85+
[ "$SECONDS" -lt "$deadline" ] || fail "datasource not created within ${TIMEOUT}s"
86+
sleep 3
87+
done
88+
89+
api() {
90+
docker exec "$GRAFANA" curl -fsS --user admin:admin "http://localhost:3000/api/$1"
91+
}
92+
93+
api health >/dev/null || fail "/api/health not OK"
94+
95+
# The database may still be initialising; retry the datasource health check.
96+
until api "datasources/uid/$DS_UID/health" >/dev/null 2>&1; do
97+
[ "$SECONDS" -lt "$deadline" ] || fail "datasource $DS_UID cannot reach the $DB_TYPE database"
98+
sleep 3
99+
done
100+
101+
echo "OK: $IMAGE starts and datasource $DS_UID is healthy ($DB_TYPE)"

0 commit comments

Comments
 (0)