From efefb5371f307286565ef82d2715895264946bde Mon Sep 17 00:00:00 2001 From: Kenneth Bingham Date: Fri, 2 Aug 2024 16:42:47 -0400 Subject: [PATCH] add docker deployment test workflow --- .github/workflows/test-docker-deployments.yml | 36 ++++++++ .../linux/openziti-controller/bootstrap.bash | 12 ++- .../linux/openziti-router/bootstrap.bash | 22 +++-- dist/docker-images/ziti-cli/Dockerfile | 16 ++-- dist/docker-images/ziti-controller/Dockerfile | 1 + .../ziti-controller/compose.test.bash | 80 ++++++++++++++++ .../ziti-controller/compose.test.yml | 91 +++++++++++++++++++ .../docker-images/ziti-controller/compose.yml | 9 ++ dist/docker-images/ziti-router/Dockerfile | 3 +- .../ziti-router/compose.test.yml | 7 ++ dist/docker-images/ziti-router/compose.yml | 3 +- quickstart/test/README.md | 13 ++- 12 files changed, 272 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/test-docker-deployments.yml create mode 100755 dist/docker-images/ziti-controller/compose.test.bash create mode 100644 dist/docker-images/ziti-controller/compose.test.yml create mode 100644 dist/docker-images/ziti-router/compose.test.yml diff --git a/.github/workflows/test-docker-deployments.yml b/.github/workflows/test-docker-deployments.yml new file mode 100644 index 000000000..811a0042b --- /dev/null +++ b/.github/workflows/test-docker-deployments.yml @@ -0,0 +1,36 @@ +name: Test Deployments +on: + workflow_dispatch: + push: + branches: + - main + pull_request: + branches: + - main + +# cancel older, redundant runs of same workflow on same branch +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }} + cancel-in-progress: true + +jobs: + docker-deployments: + name: Test the Docker Deployments + runs-on: ubuntu-latest + env: + ZIGGY_UID: 1001 # let container EUID run-as GHA "runner" user to share cache, etc. + steps: + - name: Shallow checkout + uses: actions/checkout@v4 + + - name: Install Go + id: setup-go + uses: actions/setup-go@v5 + with: + go-version-file: ./go.mod + + - name: Run the Compose Test Script + shell: bash + run: dist/docker-images/ziti-controller/compose.test.bash + env: + ZITI_GO_VERSION: ${{ steps.setup-go.outputs.go-version }} diff --git a/dist/dist-packages/linux/openziti-controller/bootstrap.bash b/dist/dist-packages/linux/openziti-controller/bootstrap.bash index 20c56ae52..ec1df01c9 100755 --- a/dist/dist-packages/linux/openziti-controller/bootstrap.bash +++ b/dist/dist-packages/linux/openziti-controller/bootstrap.bash @@ -544,8 +544,16 @@ trap exitHandler EXIT SIGINT SIGTERM : "${ZITI_BOOTSTRAP_LOG_FILE:=$(mktemp)}" # where the exit handler should concatenate verbose and debug messages ZITI_BOOTSTRAP_NOW="$(date --utc --iso-8601=seconds)" -# run the bootstrap function if this script is executed directly -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then +# if sourced then only define vars and functions and change working directory; else if exec'd then run bootstrap() +if ! [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + + # ensure ZITI_HOME is working dir to allow paths to be relative or absolute + cd "${ZITI_HOME:=${PWD}}" || { + echo "ERROR: failed to cd to '${ZITI_HOME}'" >&2 + exit 1 + } + +else set -o errexit set -o nounset diff --git a/dist/dist-packages/linux/openziti-router/bootstrap.bash b/dist/dist-packages/linux/openziti-router/bootstrap.bash index c57e82344..ae9430267 100755 --- a/dist/dist-packages/linux/openziti-router/bootstrap.bash +++ b/dist/dist-packages/linux/openziti-router/bootstrap.bash @@ -69,13 +69,15 @@ enroll() { if [[ -n "${1:-}" && ! "${1}" =~ ^-- ]]; then local _config_file="${1}" + local _ziti_home + _ziti_home="$(dirname "${_config_file}")" shift else - echo "ERROR: no config file path provided" >&2 + echo "ERROR: no config file path provided in first param" >&2 return 1 fi - if [[ ! -s "${ZITI_HOME}/${ZITI_ROUTER_IDENTITY_CERT}" || "${1:-}" == --force ]]; then + if [[ ! -s "${ZITI_ROUTER_IDENTITY_CERT}" || "${1:-}" == --force ]]; then if [[ -n "${ZITI_ENROLL_TOKEN:-}" && ! -f "${ZITI_ENROLL_TOKEN}" ]]; then # shellcheck disable=SC2188 ziti router enroll "${_config_file}" \ @@ -198,7 +200,7 @@ promptRouterAddress() { promptEnrollToken() { # do nothing if identity file has stuff in it - if [[ -s "${ZITI_HOME}/${ZITI_ROUTER_IDENTITY_CERT}" ]]; then + if [[ -s "${ZITI_ROUTER_IDENTITY_CERT}" ]]; then echo "DEBUG: not prompting for token because identity exists in ${ZITI_HOME}/${ZITI_ROUTER_IDENTITY_CERT}" >&3 # prompt for enrollment token if interactive, unless already answered else @@ -409,8 +411,6 @@ fi trap exitHandler EXIT SIGINT SIGTERM # set defaults -# : "${ZITI_SERVER_FILE:=server}" # relative to intermediate CA "keys" and "certs" dirs -# : "${ZITI_CLIENT_FILE:=client}" # relative to intermediate CA "keys" and "certs" dirs : "${ZITI_CTRL_ADVERTISED_PORT:=1280}" : "${ZITI_ROUTER_ADVERTISED_ADDRESS:=localhost}" : "${ZITI_ROUTER_PORT:=3022}" @@ -423,8 +423,16 @@ trap exitHandler EXIT SIGINT SIGTERM : "${ZITI_ROUTER_DNS_IP_RANGE:=100.64.0.1/10}" # CIDR range of IP addresses to assign to DNS clients in tproxy mode ZITI_BOOTSTRAP_NOW="$(date --utc --iso-8601=seconds)" -# run the bootstrap function if this script is executed directly -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then +# if sourced then only define vars and functions and change working directory; else if exec'd then run bootstrap() +if ! [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + + # ensure ZITI_HOME is working dir to allow paths to be relative or absolute + cd "${ZITI_HOME:=${PWD}}" || { + echo "ERROR: failed to cd to '${ZITI_HOME}'" >&2 + exit 1 + } + +else set -o errexit set -o nounset diff --git a/dist/docker-images/ziti-cli/Dockerfile b/dist/docker-images/ziti-cli/Dockerfile index cf43f6410..a70cb92a7 100644 --- a/dist/docker-images/ziti-cli/Dockerfile +++ b/dist/docker-images/ziti-cli/Dockerfile @@ -2,7 +2,7 @@ # get kubectl CLI from a source with Docker Content Trust (DCT) # FIXME: require DCT at build time -FROM bitnami/kubectl as bitnami-kubectl +FROM bitnami/kubectl AS bitnami-kubectl # FIXME: This repo requires terms acceptance and is only available on registry.redhat.io. # FROM registry.access.redhat.com/openshift4/ose-cli as openshift-cli @@ -21,6 +21,8 @@ ARG TARGETARCH ARG ZUID=2171 ARG ZGID=2171 +ARG HOME=/home/ziggy + ### Required OpenShift Labels LABEL name="openziti/ziti-cli" \ maintainer="developers@openziti.org" \ @@ -48,10 +50,10 @@ RUN mkdir -p -m0755 /licenses COPY ./LICENSE /licenses/apache.txt RUN groupadd --gid ${ZGID} ziggy \ - && adduser --uid ${ZUID} --gid ${ZGID} --system --home /home/ziggy --shell /bin/bash ziggy \ - && mkdir -p /home/ziggy \ - && chown -R ${ZUID}:${ZGID} /home/ziggy \ - && chmod -R g+rwX /home/ziggy + && adduser --uid ${ZUID} --gid ${ZGID} --system --home ${HOME} --shell /bin/bash ziggy \ + && mkdir -p ${HOME} \ + && chown -R ${ZUID}:${ZGID} ${HOME} \ + && chmod -R g+rwX ${HOME} RUN mkdir -p /usr/local/bin COPY ${ARTIFACTS_DIR}/${TARGETARCH}/${TARGETOS}/ziti /usr/local/bin/ RUN chmod 0755 /usr/local/bin/ziti @@ -59,5 +61,7 @@ RUN chmod 0755 /usr/local/bin/ziti RUN /usr/local/bin/ziti completion bash > /etc/bash_completion.d/ziti_cli USER ziggy -COPY ${DOCKER_BUILD_DIR}/bashrc /home/ziggy/.bashrc +ENV HOME=${HOME} +COPY ${DOCKER_BUILD_DIR}/bashrc ${HOME}/.bashrc + ENTRYPOINT [ "ziti" ] diff --git a/dist/docker-images/ziti-controller/Dockerfile b/dist/docker-images/ziti-controller/Dockerfile index ec7abcf3d..5241f241f 100644 --- a/dist/docker-images/ziti-controller/Dockerfile +++ b/dist/docker-images/ziti-controller/Dockerfile @@ -40,6 +40,7 @@ COPY --from=ziti-console /usr/src/app/dist/app-ziti-console /ziti-console RUN mkdir -p /ziti-controller RUN chown -R ziggy:ziggy /ziti-controller /ziti-console WORKDIR /ziti-controller +ENV ZITI_HOME=/ziti-controller # configure logging ENV ZITI_TIME_FORMAT=utc diff --git a/dist/docker-images/ziti-controller/compose.test.bash b/dist/docker-images/ziti-controller/compose.test.bash new file mode 100755 index 000000000..3b813646b --- /dev/null +++ b/dist/docker-images/ziti-controller/compose.test.bash @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +# exec this script from the root directory of the repository to test the Docker deployment + +set -o errexit +set -o nounset +set -o pipefail +set -o xtrace + +cleanup(){ + docker compose --profile test down --volumes --remove-orphans +} + +[[ -s ./go.work ]] && { + echo "ERROR: remove go.work before testing deployment" >&2 + exit 1 +} + +: "${ZIGGY_UID:=$(id -u)}" +: "${ZITI_GO_VERSION:=$(grep -Po '^go\s+\K\d+\.\d+(\.\d+)?$' ./go.mod)}" + +export COMPOSE_FILE=\ +./dist/docker-images/ziti-controller/compose.yml\ +:./dist/docker-images/ziti-controller/compose.test.yml\ +:./dist/docker-images/ziti-router/compose.yml\ +:./dist/docker-images/ziti-router/compose.test.yml \ +ZIGGY_UID \ +ZITI_GO_VERSION \ +ZITI_PWD="ziggypw" \ +ZITI_CTRL_ADVERTISED_ADDRESS="ctrl1.127.21.71.0.sslip.io" \ +ZITI_CONTROLLER_IMAGE="ziti-controller:local" \ +ZITI_ROUTER_IMAGE="ziti-router:local" \ +ZITI_ROUTER_NAME="router1" + +export ZITI_ROUTER_ADVERTISED_ADDRESS="${ZITI_ROUTER_NAME}.127.21.71.0.sslip.io" \ +ZITI_ENROLL_TOKEN="/home/ziggy/.config/ziti/${ZITI_ROUTER_NAME}.jwt" + +mkdir -p ./release/amd64/linux +go build -o ./release/amd64/linux ./... + +ZITI_CLI_IMAGE="ziti-cli" +ZITI_CLI_TAG="local" + +docker buildx build \ +--build-arg "DOCKER_BUILD_DIR=./dist/docker-images/ziti-cli" \ +--platform "linux/amd64" \ +--tag "${ZITI_CLI_IMAGE}:${ZITI_CLI_TAG}" \ +--file "./dist/docker-images/ziti-cli/Dockerfile" \ +--load "$PWD" + +docker buildx build \ +--build-arg "DOCKER_BUILD_DIR=./dist/docker-images/ziti-controller" \ +--build-arg "ZITI_CLI_IMAGE=${ZITI_CLI_IMAGE}" \ +--build-arg "ZITI_CLI_TAG=${ZITI_CLI_TAG}" \ +--platform "linux/amd64" \ +--tag "${ZITI_CONTROLLER_IMAGE}" \ +--file "./dist/docker-images/ziti-controller/Dockerfile" \ +--load "$PWD" + +docker buildx build \ +--build-arg "DOCKER_BUILD_DIR=./dist/docker-images/ziti-router" \ +--build-arg "ZITI_CLI_IMAGE=${ZITI_CLI_IMAGE}" \ +--build-arg "ZITI_CLI_TAG=${ZITI_CLI_TAG}" \ +--platform "linux/amd64" \ +--tag "${ZITI_ROUTER_IMAGE}" \ +--file "./dist/docker-images/ziti-router/Dockerfile" \ +--load "$PWD" + +cleanup + +docker compose up ziti-login + +docker compose run --rm --entrypoint=/bin/bash --env ZITI_ROUTER_NAME="${ZITI_ROUTER_NAME}" ziti-login \ +-euxc 'ziti edge create edge-router "${ZITI_ROUTER_NAME}" -to ~ziggy/.config/ziti/"${ZITI_ROUTER_NAME}.jwt"' + +docker compose up ziti-router --detach + +docker compose run --rm quickstart-test + +cleanup diff --git a/dist/docker-images/ziti-controller/compose.test.yml b/dist/docker-images/ziti-controller/compose.test.yml new file mode 100644 index 000000000..77c1d3cf1 --- /dev/null +++ b/dist/docker-images/ziti-controller/compose.test.yml @@ -0,0 +1,91 @@ +volumes: + ziti-login: + +services: + ziti-controller: + network_mode: host + networks: !override [] + ports: !override [] + + quickstart-test: + profiles: + - test + depends_on: + ziti-login: + condition: service_completed_successfully + ziti-router: + condition: service_healthy + image: golang:${ZITI_GO_VERSION:-noop}-alpine + # networks: + # - quickstart + # run as the same user as the host, so we can use the host's GOCACHE + user: ${ZIGGY_UID:-2171} + network_mode: host + volumes: + # mount the parent dir of the quickstart, which is the top-level of the ziti repo working copy, as /mnt, so we can + # run the tests in the "edge" Go package + - ../../../:/mnt + # re-run tests if significant changes from last result in GOCACHE + - ${GOCACHE:-${HOME}/.cache/go-build}:/.cache/go-build + # re-download dep packages if significant changes from last download in GOPATH + - ${GOPATH:-${HOME}/go}:/go + working_dir: /mnt + environment: + # verbose, tests tagged 'quickstart && manual', manual means test an existing network, don't run a network inside + # the test process + GOFLAGS: "-tags=quickstart,manual" + GOCACHE: /.cache/go-build + GOPATH: /go + ZITI_PWD: # default "admin" + ZITI_CTRL_ADVERTISED_ADDRESS: ${ZITI_CTRL_ADVERTISED_ADDRESS:-quickstart} + ZITI_CTRL_EDGE_ADVERTISED_ADDRESS: ${ZITI_CTRL_ADVERTISED_ADDRESS:-quickstart} # deprecated by ZITI_CTRL_ADVERTISED_ADDRESS + ZITI_CTRL_EDGE_ADVERTISED_PORT: ${ZITI_CTRL_ADVERTISED_PORT:-1280} # deprecated by ZITI_CTRL_ADVERTISED_PORT + ZITI_CTRL_ADVERTISED_PORT: ${ZITI_CTRL_ADVERTISED_PORT:-1280} + ZITI_ROUTER_ADVERTISED_ADDRESS: ${ZITI_CTRL_ADVERTISED_ADDRESS:-quickstart} + ZITI_ROUTER_PORT: ${ZITI_ROUTER_PORT:-3022} + ZITI_ROUTER_NAME: ${ZITI_ROUTER_NAME:-quickstart-router} + command: go test -v ./ziti/cmd/edge/... + + chown-login: + profiles: + - test + image: busybox + command: chown -R ${ZIGGY_UID:-2171} /ziti-login + volumes: + - ziti-login:/ziti-login + + ziti-login: + profiles: + - test + depends_on: + ziti-controller: + condition: service_healthy + chown-login: + condition: service_completed_successfully + image: ${ZITI_CONTROLLER_IMAGE:-docker.io/openziti/ziti-controller} + # run as the same user as the host, so we can write in ~/.config/ziti + user: ${ZIGGY_UID:-2171} + network_mode: host + volumes: + - ziti-controller:/ziti-controller + - ziti-login:/home/ziggy/.config/ziti + entrypoint: + - bash + - -euxc + - | + set -o pipefail + ATTEMPTS=10 + DELAY=3 + until !((ATTEMPTS)) || ziti $${@}; do + (( ATTEMPTS-- )) + echo "Waiting for controller to start" + sleep $${DELAY} + done + command: > + -- edge login + ${ZITI_CTRL_ADVERTISED_ADDRESS:-ziti-controller}:${ZITI_CTRL_ADVERTISED_PORT:-1280} + --ca=/ziti-controller/pki/root/certs/root.cert + --username=${ZITI_USER:-admin} + --password=${ZITI_PWD:-admin} + --timeout=1 + --verbose diff --git a/dist/docker-images/ziti-controller/compose.yml b/dist/docker-images/ziti-controller/compose.yml index 4e8059da7..646aa5eac 100644 --- a/dist/docker-images/ziti-controller/compose.yml +++ b/dist/docker-images/ziti-controller/compose.yml @@ -3,6 +3,10 @@ volumes: ziti-controller: driver: local +networks: + ziti: + driver: bridge + services: chown-controller: image: busybox @@ -15,8 +19,13 @@ services: depends_on: chown-controller: condition: service_completed_successfully + user: ${ZIGGY_UID:-2171} volumes: - ziti-controller:/ziti-controller + networks: + ziti: + aliases: + - ${ZITI_CTRL_ADVERTISED_ADDRESS:-ziti-controller} # assign override vars in an .env file or export from parent env to ensure consistency throughout the compose # project environment: diff --git a/dist/docker-images/ziti-router/Dockerfile b/dist/docker-images/ziti-router/Dockerfile index 3a694136e..9c0f2a5a9 100644 --- a/dist/docker-images/ziti-router/Dockerfile +++ b/dist/docker-images/ziti-router/Dockerfile @@ -28,6 +28,7 @@ COPY ${ROUTER_PACKAGE}/entrypoint.bash / WORKDIR /ziti-router RUN chown -R ziggy:ziggy /ziti-router +ENV ZITI_HOME=/ziti-router # run as ziggy (2171:2171) by default, override run-as user with root when DOCKER_ROUTER_MODE=tproxy USER ziggy @@ -46,7 +47,7 @@ ENV ZITI_BOOTSTRAP_ENROLLMENT=true ENV ZITI_ROUTER_NAME=router ENV ZITI_ROUTER_TYPE=edge ENV ZITI_ROUTER_PORT=3022 -ENV ZITI_ROUTER_MODE=none +ENV ZITI_ROUTER_MODE=host # renew router certs at startup with run --extend ENV ZITI_AUTO_RENEW_CERTS=true diff --git a/dist/docker-images/ziti-router/compose.test.yml b/dist/docker-images/ziti-router/compose.test.yml new file mode 100644 index 000000000..0eb5befad --- /dev/null +++ b/dist/docker-images/ziti-router/compose.test.yml @@ -0,0 +1,7 @@ +services: + ziti-router: + network_mode: host + networks: !override [] + ports: !override [] + volumes: + - ziti-login:/home/ziggy/.config/ziti diff --git a/dist/docker-images/ziti-router/compose.yml b/dist/docker-images/ziti-router/compose.yml index b5294b53d..adefd3e6f 100644 --- a/dist/docker-images/ziti-router/compose.yml +++ b/dist/docker-images/ziti-router/compose.yml @@ -15,6 +15,7 @@ services: depends_on: chown-router: condition: service_completed_successfully + user: ${ZIGGY_UID:-2171} volumes: - ziti-router:/ziti-router # these declared vars pass through to container and should be assigned in an .env file or exported from parent env @@ -26,7 +27,7 @@ services: ZITI_ENROLL_TOKEN: ${ZITI_ENROLL_TOKEN:-} # enrollment token for this router (required) ZITI_ROUTER_ADVERTISED_ADDRESS: ${ZITI_ROUTER_ADVERTISED_ADDRESS:-ziti-router} # domain name for this router (default: the container ID [hostname -f]) ZITI_ROUTER_PORT: ${ZITI_ROUTER_PORT:-3022} # exposed port for this router - ZITI_ROUTER_MODE: ${ZITI_ROUTER_MODE:-none} # none, host, tproxy, tproxy (default: none, tproxy requires additional config below) + ZITI_ROUTER_MODE: ${ZITI_ROUTER_MODE:-host} # none, host, tproxy, tproxy (default: host, tproxy requires additional config below) # *** less relevant vars below *** ZITI_BOOTSTRAP: true # bootstrap the router if "true" diff --git a/quickstart/test/README.md b/quickstart/test/README.md index 8d45da2d4..f470903cb 100644 --- a/quickstart/test/README.md +++ b/quickstart/test/README.md @@ -1,12 +1,15 @@ # Running Quickstart Tests + The quickstart test ensures a network is minimally functional by creating a service that intercepts the controller's edge HTTP/API plane, then obtains a valid http response by dialing that service. ## Automated + The automated test starts up an ephemeral OpenZiti network and runs `performQuickstartTest`. To run the automated edge test, execute the following from the project root (environment variables are auto populated) -``` + +```bash # From project root go test -v -tags "quickstart automated" ./ziti/cmd/edge/... -run TestEdgeQuickstartAutomated @@ -15,7 +18,8 @@ go test -v -tags "quickstart automated" ../../ziti/cmd/edge/... -run TestEdgeQui ``` ## Manual -The manual test utilizes an existing network and runs `performQuickstartTest`. Use the manual method to test + +The manual test utilizes an existing network and runs `performQuickstartTest`. Use the manual method to test any network, anywhere, by adjusting the environment variables as necessary. The following environment variables are referenced for network information. @@ -27,7 +31,8 @@ The following environment variables are referenced for network information. * `ZITI_ROUTER_NAME` - defaults to `ziti-edge-router` To run the manual test, edit the environment variables as necessary and execute the following from the project root -``` + +```bash # Optionally adjust environment variable values as needed ZITI_USER="admin" ZITI_PWD="admin" @@ -40,4 +45,4 @@ go test -v -tags "quickstart manual" ./ziti/cmd/edge/... -run TestEdgeQuickstart # From relative README path go test -v -tags "quickstart manual" ../../ziti/cmd/edge/... -run TestEdgeQuickstartManual -``` \ No newline at end of file +```