-
Notifications
You must be signed in to change notification settings - Fork 629
feat(docker): add attachable Hubble Compose add-on for the 3-node cluster #3149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
b056d0d
620f7ff
0694ff7
1b4f008
950f645
8a0c6b0
931c258
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,18 +95,20 @@ jobs: | |
| rendered="$(mktemp)" | ||
|
|
||
| if env -u HUGEGRAPH_ADMIN_PASSWORD \ | ||
| docker compose -f "$file" config -q >/dev/null 2>&1; then | ||
| docker compose --env-file /dev/null -f "$file" config -q >/dev/null 2>&1; then | ||
| echo "$file accepted an unset admin password" >&2 | ||
| return 1 | ||
| fi | ||
| if HUGEGRAPH_ADMIN_PASSWORD= \ | ||
| docker compose -f "$file" config -q >/dev/null 2>&1; then | ||
| docker compose --env-file /dev/null -f "$file" config -q >/dev/null 2>&1; then | ||
| echo "$file accepted an empty admin password" >&2 | ||
| return 1 | ||
| fi | ||
|
|
||
| HUGEGRAPH_ADMIN_PASSWORD=ci-test-password \ | ||
| docker compose -f "$file" config --format json > "$rendered" | ||
| env -u HUBBLE_IMAGE -u HUBBLE_PULL_POLICY -u HUBBLE_PUBLISH_HOST \ | ||
| -u HUGEGRAPH_SERVER_IMAGE -u HUGEGRAPH_SERVER_PULL_POLICY \ | ||
| docker compose --env-file /dev/null -f "$file" config --format json > "$rendered" | ||
| jq -e \ | ||
| --arg server_policy "$server_policy" \ | ||
| --arg hubble_policy "$hubble_policy" ' | ||
|
|
@@ -138,6 +140,159 @@ jobs: | |
| check_compose docker/docker-compose.yml always always | ||
| check_compose docker/docker-compose.dev.yml build missing | ||
|
|
||
| check_cluster_compose() { | ||
| local cluster="docker/docker-compose-3pd-3store-3server.yml" | ||
| local addon="docker/docker-compose-hubble.yml" | ||
| local rendered | ||
| rendered="$(mktemp)" | ||
|
|
||
| # RETURN only: an EXIT trap would fire after this function's | ||
| # `local rendered` has gone out of scope, which `set -u` turns | ||
| # into an "unbound variable" error. A hard errexit abort can | ||
| # therefore still leak one temp file, which is acceptable on an | ||
| # ephemeral runner. | ||
| trap 'rm -f "$rendered"' RETURN | ||
|
|
||
| # --env-file /dev/null on every invocation: Compose otherwise reads | ||
| # docker/.env automatically. Without it the add-on render below — | ||
| # which deliberately unsets overrides to assert their defaults — | ||
| # would read whatever HUGEGRAPH_NETWORK/HUGEGRAPH_VERSION that | ||
| # .env holds. Pinning an empty env file makes both renders depend | ||
| # only on what each invocation sets explicitly. | ||
|
|
||
| # The add-on alone must define Hubble and nothing else, join the | ||
| # shared external network with its default name, and need no | ||
| # credentials or overrides. | ||
| env -u HUGEGRAPH_ADMIN_PASSWORD -u HUGEGRAPH_AUTH_TOKEN_SECRET \ | ||
| -u HUGEGRAPH_NETWORK -u HUGEGRAPH_VERSION \ | ||
| -u HUBBLE_IMAGE -u HUBBLE_PULL_POLICY -u HUBBLE_PUBLISH_HOST \ | ||
| -u HUBBLE_DB_VOLUME -u HUBBLE_UPLOAD_VOLUME \ | ||
| docker compose --env-file /dev/null -f "$addon" config --format json > "$rendered" | ||
| jq -e ' | ||
| (.services | keys) == ["hubble"] and | ||
| .networks."hg-net".external == true and | ||
| .networks."hg-net".name == "hugegraph-net" and | ||
| (.services.hubble.networks | has("hg-net")) and | ||
| (.services.hubble | has("depends_on") | not) and | ||
| .volumes."hg-hubble-db".name == "hugegraph-hubble-db" and | ||
| .volumes."hg-hubble-upload-files".name == | ||
| "hugegraph-hubble-upload-files" and | ||
| .services.hubble.environment.SPRING_DATASOURCE_URL == | ||
| "jdbc:h2:file:./db/hubble;DB_CLOSE_ON_EXIT=FALSE" and | ||
| any(.services.hubble.volumes[]; | ||
| .target == "/hubble/conf/hugegraph-hubble.properties" and | ||
| (.source | endswith("hugegraph-hubble-3x3.properties"))) | ||
| and any(.services.hubble.volumes[]; | ||
| .source == "hg-hubble-db" and | ||
| .target == "/hubble/db") | ||
| and any(.services.hubble.volumes[]; | ||
| .source == "hg-hubble-upload-files" and | ||
| .target == "/hubble/upload-files") | ||
| ' "$rendered" >/dev/null | ||
|
|
||
| # The cluster's own default network name must match the add-on's, | ||
| # or the attach flow and the cluster land on different networks. | ||
| # The combined render below pins an override, so it cannot catch a | ||
| # drifting default. | ||
| env -u HUGEGRAPH_NETWORK -u HUBBLE_IMAGE -u HUBBLE_PULL_POLICY \ | ||
| -u HUBBLE_PUBLISH_HOST -u HUGEGRAPH_ADMIN_PASSWORD \ | ||
| -u HUGEGRAPH_AUTH_TOKEN_SECRET \ | ||
| docker compose --env-file /dev/null -f "$cluster" \ | ||
| config --format json > "$rendered" | ||
| jq -e '.networks."hg-net".name == "hugegraph-net"' \ | ||
| "$rendered" >/dev/null | ||
|
|
||
| # The combined render carries PD-registration on every server | ||
| # replica, keeps Server anonymous (no PASSWORD), and keeps Hubble | ||
| # on loopback. Rendered with non-default HUGEGRAPH_NETWORK / | ||
| # HUGEGRAPH_VERSION so CI fails if any file stops honoring the | ||
| # overrides (the add-on render above covers the defaults). | ||
| HUGEGRAPH_NETWORK=ci-test-net \ | ||
| HUGEGRAPH_VERSION=ci-test-tag \ | ||
| env -u HUBBLE_IMAGE -u HUBBLE_PULL_POLICY -u HUBBLE_PUBLISH_HOST \ | ||
| -u HUBBLE_DB_VOLUME -u HUBBLE_UPLOAD_VOLUME \ | ||
| -u HUGEGRAPH_ADMIN_PASSWORD -u HUGEGRAPH_AUTH_TOKEN_SECRET \ | ||
| docker compose --env-file /dev/null -f "$cluster" -f "$addon" \ | ||
| config --format json > "$rendered" | ||
| jq -e ' | ||
| . as $root | | ||
| .name == "hugegraph-3x3" and | ||
| (.services | keys | length) == 10 and | ||
| .networks."hg-net".external == true and | ||
| .networks."hg-net".name == "ci-test-net" and | ||
| all(.services[]; .networks | has("hg-net")) and | ||
| .services.pd0.image == "hugegraph/pd:ci-test-tag" and | ||
| .services.store0.image == "hugegraph/store:ci-test-tag" and | ||
| .services.server0.image == "hugegraph/server:ci-test-tag" and | ||
| .services.hubble.image == "hugegraph/hubble:ci-test-tag" and | ||
| all(["server0", "server1", "server2"][]; | ||
| $root.services[.].environment.HG_SERVER_USE_PD == "true" and | ||
| $root.services[.].environment.HG_SERVER_CLUSTER == "hg" and | ||
| $root.services[.].environment.HG_SERVER_INIT_STORE_ENABLED == | ||
| "false" and | ||
| ($root.services[.].environment.PASSWORD == null) and | ||
| ($root.services[.].environment.HG_SERVER_AUTH_TOKEN_SECRET == | ||
| null)) and | ||
| .services.server0.environment.HG_SERVER_REST_URL == | ||
| "http://server0:8080" and | ||
| .services.server1.environment.HG_SERVER_REST_URL == | ||
| "http://server1:8080" and | ||
| .services.server2.environment.HG_SERVER_REST_URL == | ||
| "http://server2:8080" and | ||
| (.services.hubble | has("depends_on") | not) and | ||
| .services.hubble.pull_policy == "missing" and | ||
| .volumes."hg-hubble-db".name == "hugegraph-hubble-db" and | ||
| .volumes."hg-hubble-upload-files".name == | ||
| "hugegraph-hubble-upload-files" and | ||
| .services.hubble.environment.SPRING_DATASOURCE_URL == | ||
| "jdbc:h2:file:./db/hubble;DB_CLOSE_ON_EXIT=FALSE" and | ||
| (.services.hubble.healthcheck.test[1] | | ||
| contains("http://127.0.0.1:8088/about") and | ||
| contains("\"status\":200") and | ||
| contains("\"name\":\"hugegraph-hubble\"")) and | ||
| any(.services.hubble.ports[]; | ||
| .target == 8088 and .published == "8088" and | ||
| .host_ip == "127.0.0.1") | ||
| ' "$rendered" >/dev/null | ||
|
|
||
| # Hubble's properties file is mounted, not rendered, so Compose | ||
| # validation alone cannot catch it drifting from the services it | ||
| # describes. Tie the two together: renaming a service, changing a | ||
| # container hostname, or moving a REST port must be reflected in | ||
| # both places or CI fails here. Values are derived from the | ||
| # rendered model (hostnames and ports included) so the assertions | ||
| # cannot silently agree with a stale file. | ||
| local props="docker/hugegraph-hubble-3x3.properties" | ||
| local pd_peers store_targets cluster_name pd_rest | ||
| assert_props() { # assert_props <exact-line> <what-it-must-match> | ||
| grep -Fqx "$1" "$props" || | ||
| { echo "$props: expected line '$1' ($2)" >&2; return 1; } | ||
| } | ||
| cluster_name="$(jq -r '.services.server0.environment.HG_SERVER_CLUSTER' \ | ||
| "$rendered")" | ||
| pd_peers="$(jq -r '.services.server0.environment.HG_SERVER_PD_PEERS' \ | ||
| "$rendered")" | ||
| store_targets="[$(jq -r '[.services | to_entries[] | ||
| | select(.key | startswith("store")) | ||
| | "http://" + .value.hostname + ":" | ||
| + (.value.environment.HG_STORE_REST_PORT)] | ||
| | sort | join(",")' "$rendered")]" | ||
| pd_rest="$(jq -r --arg h "$(printf '%s' "${pd_peers}" | cut -d, -f1 | cut -d: -f1)" \ | ||
| '.services | to_entries[] | ||
| | select(.value.hostname == $h) | ||
| | .value.hostname + ":" + .value.environment.HG_PD_REST_PORT' \ | ||
| "$rendered")" | ||
| assert_props "cluster=${cluster_name}" "matches HG_SERVER_CLUSTER" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’ll add an explicit |
||
| assert_props "pd.enabled=true" "keeps Hubble in PD mode" | ||
| assert_props "auth.enabled=false" "matches the anonymous cluster" | ||
| assert_props "pd.peers=${pd_peers}" "matches HG_SERVER_PD_PEERS" | ||
| assert_props "pd.server=${pd_rest}" "names a real PD REST endpoint" | ||
| assert_props "operations.store.allowed_targets=${store_targets}" \ | ||
| "lists every Store REST endpoint" | ||
| } | ||
|
|
||
| check_cluster_compose | ||
|
|
||
| - name: Run check_port unit tests | ||
| if: ${{ env.BACKEND == 'rocksdb' }} | ||
| run: | | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
docker compose configplus jq/grep and never creates the external network, starts the services, probes Hubble/about, verifies PD registration, or checks authenticated graph access. Add a Docker-capable smoke job for the combined and attach flows so entrypoint, DNS, registration, and auth failures cannot remain green.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Render‑only cannot catch runtime auth/DNS failures. For this PR I’ll keep and strengthen the compose contract assertions (including the in‑scope ones above). A full combined or attached Docker smoke job is useful but adds heavier CI overhead; I’d prefer a follow‑up rather than blocking the add‑on here.