11#! /usr/bin/env bash
2- # sd-bridge.sh
3- # Discover Docker containers by label, pull each container's discovery JSON, merge, de-duplicate,
4- # and write a single Prometheus file_sd JSON. Optionally serve the same JSON over HTTP .
2+ # sd-bridge.sh (simplified)
3+ # Discover Docker containers by label, pull each container's discovery JSON,
4+ # add labels, merge + de-duplicate, and write a single file_sd JSON.
55
66set -Eeuo pipefail
77
8- # ---------- Configuration via env vars ------- ---
9- LABEL_MATCH=" ${LABEL_MATCH:- prom_sd=true} " # filter for worker containers
8+ # --- Config ( env) ---
9+ LABEL_MATCH=" ${LABEL_MATCH:- framework=ctf} "
1010DEFAULT_PATH=" ${DISCOVERY_PATH:-/ discovery} "
1111DEFAULT_PORT=" ${DISCOVERY_PORT:- 6688} "
1212DEFAULT_SCHEME=" ${DISCOVERY_SCHEME:- http} "
13- PREFER_NETWORK=" ${NETWORK_NAME:- } " # optional Docker network to prefer for IP
14- OUT=" ${OUT:-/ out/ merged.json} " # file_sd output
15- SLEEP=" ${SLEEP:- 15} " # seconds between scans
16- REQUEST_TIMEOUT=" ${REQUEST_TIMEOUT:- 5} " # curl timeout seconds
13+ PREFER_NETWORK=" ${NETWORK_NAME:- } "
14+ OUT=" ${OUT:-/ out/ merged.json} "
15+ SLEEP=" ${SLEEP:- 15} "
16+ REQUEST_TIMEOUT=" ${REQUEST_TIMEOUT:- 5} "
17+ REWRITE_TO_IP=" ${REWRITE_TO_IP:- 0} " # set to 1 to replace host with container IP
1718
18- # Optional lightweight HTTP serving of OUT for http_sd
19- SERVE_ADDR=" ${SERVE_ADDR:- } " # example: ":8080" to serve /targets
20- SERVE_PATH=" ${SERVE_PATH:-/ targets} " # URL path
21-
22- # ---------- Helpers ----------
19+ # --- Helpers ---
2320log (){ printf ' [sd-bridge] %s\n' " $* " >&2 ; }
2421get_ip (){
25- local cid=" $1 " ; local net=" $2 "
22+ local cid=" $1 " net=" $2 "
2623 if [[ -n " $net " ]]; then
2724 docker inspect " $cid " | jq -r --arg n " $net " ' .[0].NetworkSettings.Networks[$n].IPAddress // empty'
2825 else
2926 docker inspect " $cid " | jq -r ' .[0].NetworkSettings.Networks | to_entries[0].value.IPAddress // empty'
3027 fi
3128}
32- get_label (){
33- local cid=" $1 " key=" $2 "
34- docker inspect " $cid " | jq -r --arg k " $key " ' .[0].Config.Labels[$k] // empty'
35- }
29+ get_label (){ docker inspect " $1 " | jq -r --arg k " $2 " ' .[0].Config.Labels[$k] // empty' ; }
30+ get_name (){ docker inspect " $1 " | jq -r ' .[0].Name | ltrimstr("/")' ; }
3631merge_and_dedupe (){
37- # stdin: many JSON arrays of target groups
38- # out: one array, grouped by identical labels with unique sorted targets
3932 jq -s '
4033 add // []
4134 | map({targets: (.targets // []), labels: (.labels // {})})
42- | sort_by(.labels)
4335 | group_by(.labels)
4436 | map({labels: (.[0].labels), targets: ([.[].targets[]] | unique | sort)})
4537 '
4638}
47- atomic_write (){
48- local path=" $1 " ; local tmp=" $1 .tmp"
49- cat > " $tmp " && mv " $tmp " " $path "
50- }
39+ atomic_write (){ local p=" $1 " t=" $1 .tmp" ; cat > " $t " && mv " $t " " $p " ; }
5140
52- # ---------- Optional HTTP server ----------
53- serve_http (){
54- # Serves OUT at SERVE_PATH. Requires busybox httpd or python3 in the container.
55- if command -v busybox > /dev/null 2>&1 ; then
56- log " serving http_sd at ${SERVE_ADDR}${SERVE_PATH} using busybox httpd"
57- # Busybox serves a directory. Symlink requested path to OUT.
58- local root; root=" $( dirname " $OUT " ) " ; mkdir -p " $root "
59- # Keep a symlink named targets.json and rewrite on change
60- ln -sf " $( basename " $OUT " ) " " $root /targets.json"
61- exec busybox httpd -f -p " ${SERVE_ADDR#: } " -h " $root "
62- elif command -v python3 > /dev/null 2>&1 ; then
63- log " serving http_sd at ${SERVE_ADDR}${SERVE_PATH} using python http.server"
64- cd " $( dirname " $OUT " ) " && exec python3 -m http.server " ${SERVE_ADDR#: } "
65- else
66- log " no http server available in image; install busybox or python3"
67- sleep infinity
68- fi
69- }
70-
71- # Ensure output dir and initial file
41+ # --- Init ---
7242mkdir -p " $( dirname " $OUT " ) "
7343echo ' []' | atomic_write " $OUT "
7444
75- # If SERVE_ADDR is set, background a tiny polling loop that keeps a shadow file named targets.json
76- if [[ -n " $SERVE_ADDR " ]]; then
77- # Run server in background subshell so main loop continues to update OUT
78- serve_http &
79- fi
80-
81- # ---------- Main loop ----------
45+ # --- Main loop ---
8246while true ; do
8347 mapfile -t cids < <( docker ps -q --filter " label=$LABEL_MATCH " || true)
8448 if (( ${# cids[@]} == 0 )) ; then
@@ -90,16 +54,38 @@ while true; do
9054 files=()
9155 for cid in " ${cids[@]} " ; do
9256 ip=" $( get_ip " $cid " " $PREFER_NETWORK " ) "
93- if [[ -z " $ip " ]]; then log " skip ${cid: 0: 12} : no IP" ; continue ; fi
57+ [[ -z " $ip " ]] && { log " skip ${cid: 0: 12} : no IP" ; continue ; }
58+ name=" $( get_name " $cid " ) "
9459
95- # Per container overrides via labels
96- path=" $( get_label " $cid " prom_sd_path) " ; path=" ${path:- $DEFAULT_PATH } "
97- port=" $( get_label " $cid " prom_sd_port) " ; port=" ${port:- $DEFAULT_PORT } "
60+ # Per- container overrides (optional)
61+ path=" $( get_label " $cid " prom_sd_path) " ; path=" ${path:- $DEFAULT_PATH } "
62+ port=" $( get_label " $cid " prom_sd_port) " ; port=" ${port:- $DEFAULT_PORT } "
9863 scheme=" $( get_label " $cid " prom_sd_scheme) " ; scheme=" ${scheme:- $DEFAULT_SCHEME } "
9964
10065 url=" ${scheme} ://${ip} :${port}${path} "
10166 f=" $( mktemp) " ; files+=(" $f " )
10267 if curl -fsSL --max-time " $REQUEST_TIMEOUT " " $url " | jq ' .' > " $f " 2> /dev/null; then
68+ # Add labels (and optionally rewrite host -> container IP)
69+ if [[ " $REWRITE_TO_IP " == " 1" ]]; then
70+ jq --arg ip " $ip " --arg name " $name " '
71+ map(
72+ .targets |= map($ip + ":" + (split(":")[1])) |
73+ .labels = ((.labels // {}) + {
74+ container_name: $name,
75+ scrape_path: (.labels.__metrics_path__ // "")
76+ })
77+ )
78+ ' " $f " > " $f .tmp" && mv " $f .tmp" " $f "
79+ else
80+ jq --arg name " $name " '
81+ map(
82+ .labels = ((.labels // {}) + {
83+ container_name: $name,
84+ scrape_path: (.labels.__metrics_path__ // "")
85+ })
86+ )
87+ ' " $f " > " $f .tmp" && mv " $f .tmp" " $f "
88+ fi
10389 log " ok ${url} "
10490 else
10591 log " fail ${url} ; using []"
@@ -116,5 +102,4 @@ while true; do
116102 fi
117103
118104 sleep " $SLEEP "
119-
120105done
0 commit comments