Skip to content

Commit

Permalink
fixup: Add a docker image for the bootstrap tester
Browse files Browse the repository at this point in the history
  • Loading branch information
marun committed Jul 24, 2024
1 parent 4f6b08b commit 585a15c
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 8 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/check-bootstrap-testnet-full-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ on:
# TODO(marun) Add a schedule
workflow_dispatch:

# TODO(marun) For testing only - remove before merge
pull_request:

jobs:
check_bootstrap_testnet_full_sync:
name: Check Bootstrap (testnet,full-sync)
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/publish_docker_image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@ jobs:
DOCKER_PASS: ${{ secrets.docker_pass }}
DOCKER_IMAGE: ${{ secrets.docker_repo }}
run: scripts/build_image.sh
- name: Build and publish boostrap tester image to DockerHub
env:
DOCKER_USERNAME: ${{ secrets.docker_username }}
DOCKER_PASS: ${{ secrets.docker_pass }}
IMAGE_PREFIX: avaplatform
run: bash -x scripts/build_bootstrap_tester_image.sh
13 changes: 13 additions & 0 deletions scripts/build_bootstrap_tester.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash

set -euo pipefail

if ! [[ "$0" =~ scripts/build_bootstrap_tester.sh ]]; then
echo "must be run from repository root"
exit 255
fi

source ./scripts/constants.sh

echo "Building bootstrap tester..."
go build -o ./build/bootstrap-tester ./tests/bootstrap/
52 changes: 52 additions & 0 deletions scripts/build_bootstrap_tester_image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env bash

set -euo pipefail

# Directory above this script
AVALANCHE_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd )

source ./scripts/constants.sh

IMAGE_NAME="bootstrap-tester"

IMAGE_TAG="${IMAGE_TAG:-}"
if [[ -z "${IMAGE_TAG}" ]]; then
# Default to tagging with the commit hash
IMAGE_TAG="${commit_hash}"
fi

# Build the avalanchego image
DOCKER_CMD="docker buildx build"

# Specifying an image prefix will ensure the image is pushed after build
IMAGE_PREFIX="${IMAGE_PREFIX:-}"
if [[ -n "${IMAGE_PREFIX}" ]]; then
IMAGE_NAME="${IMAGE_PREFIX}/${IMAGE_NAME}"
DOCKER_CMD="${DOCKER_CMD} --push"

# Tag the image as latest for the master branch
if [[ "${image_tag}" == "master" ]]; then
DOCKER_CMD="${DOCKER_CMD} -t ${IMAGE_NAME}:latest"
fi

# A populated DOCKER_USERNAME env var triggers login
if [[ -n "${DOCKER_USERNAME:-}" ]]; then
echo "$DOCKER_PASS" | docker login --username "$DOCKER_USERNAME" --password-stdin
fi

# The avalanchego image will have already have been built
AVALANCHEGO_NODE_IMAGE="${IMAGE_PREFIX}/avalanchego:${IMAGE_TAG}"
else
# Build the avalanchego image locally
./scripts/build_image.sh
AVALANCHEGO_NODE_IMAGE="avalanchego:${IMAGE_TAG}"
fi

# The dockerfiles don't specify the golang version to minimize the changes required to bump
# the version. Instead, the golang version is provided as an argument.
GO_VERSION="$(go list -m -f '{{.GoVersion}}')"

# Build the image for the bootstrap tester
${DOCKER_CMD} -t "${IMAGE_NAME}:${IMAGE_TAG}" \
--build-arg GO_VERSION="${GO_VERSION}" --build-arg AVALANCHEGO_NODE_IMAGE="${AVALANCHEGO_NODE_IMAGE}" \
-f "${AVALANCHE_PATH}/tests/bootstrap/Dockerfile" "${AVALANCHE_PATH}"
34 changes: 34 additions & 0 deletions tests/bootstrap/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# The version is supplied as a build argument rather than hard-coded
# to minimize the cost of version changes.
ARG GO_VERSION

# AVALANCHEGO_NODE_IMAGE needs to identify an existing node image and should include the tag
ARG AVALANCHEGO_NODE_IMAGE

FROM golang:$GO_VERSION-bullseye AS builder

WORKDIR /builder_workdir

# Copy and download avalanche dependencies using go mod
COPY go.mod .
COPY go.sum .
RUN go mod download

# Copy the code into the container
COPY . .

# Ensure pre-existing builds are not available for inclusion in the final image
RUN [ -d ./build ] && rm -rf ./build/* || true

# Build tester binary
RUN ./scripts/build_bootstrap_tester.sh

# ============= Cleanup Stage ================
FROM $AVALANCHEGO_NODE_IMAGE AS execution

COPY --from=builder /builder_workdir/build/bootstrap-tester /avalanchego/build/bootstrap-tester

# Clear the CMD set by the base image
CMD [ "" ]

ENTRYPOINT [ "/avalanchego/build/bootstrap-tester" ]
31 changes: 26 additions & 5 deletions tests/bootstrap/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/ava-labs/avalanchego/config"
"github.com/ava-labs/avalanchego/tests/fixture/tmpnet"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/logging"
)

Expand All @@ -25,6 +26,8 @@ func main() {
networkID := flag.Int64("network-id", 0, "The ID of the network to bootstrap from")
stateSyncEnabled := flag.Bool("state-sync-enabled", false, "Whether state syncing should be enabled")
maxDuration := flag.Duration("max-duration", time.Hour*72, "The maximum duration the network should run for")
dataDir := flag.String("data-dir", "", "The directory to store the node's data")
useDynamicPorts := flag.Bool("use-dynamic-ports", false, "Whether the bootstrapping node should bind to dynamic ports")

flag.Parse()

Expand All @@ -38,25 +41,43 @@ func main() {
log.Fatal("max-duration is required")
}

if err := checkBootstrap(*avalanchegoPath, uint32(*networkID), *stateSyncEnabled, *maxDuration); err != nil {
if err := checkBootstrap(*dataDir, *avalanchegoPath, uint32(*networkID), *useDynamicPorts, *stateSyncEnabled, *maxDuration); err != nil {
log.Fatalf("Failed to check bootstrap: %v\n", err)
}
}

func checkBootstrap(avalanchegoPath string, networkID uint32, stateSyncEnabled bool, maxDuration time.Duration) error {
func checkBootstrap(
dataDir string,
avalanchegoPath string,
networkID uint32,
useDynamicPorts bool,
stateSyncEnabled bool,
maxDuration time.Duration,
) error {
flags := tmpnet.DefaultLocalhostFlags()
flags.SetDefaults(tmpnet.FlagsMap{
config.HealthCheckFreqKey: "30s",
// Minimize logging overhead
config.LogDisplayLevelKey: logging.Off.String(),
config.LogLevelKey: logging.Info.String(),
})
if !useDynamicPorts {
flags.SetDefaults(tmpnet.FlagsMap{
config.HTTPPortKey: config.DefaultHTTPPort,
config.StakingPortKey: config.DefaultStakingPort,
})
}

networkName := constants.NetworkName(networkID)
syncString := "full-sync"
if stateSyncEnabled {
syncString = "state-sync"
}

// Create a new single-node network that will bootstrap from the specified network
network := &tmpnet.Network{
UUID: uuid.NewString(),
NetworkID: networkID,
Owner: "bootstrap-test",
Owner: fmt.Sprintf("bootstrap-test-%s-%s", networkName, syncString),
Nodes: tmpnet.NewNodesOrPanic(1),
DefaultFlags: flags,
DefaultRuntimeConfig: tmpnet.NodeRuntimeConfig{
Expand All @@ -70,7 +91,7 @@ func checkBootstrap(avalanchegoPath string, networkID uint32, stateSyncEnabled b
},
}

if err := network.Create(""); err != nil {
if err := network.Create(dataDir); err != nil {
return fmt.Errorf("failed to create network: %w", err)
}
node := network.Nodes[0]
Expand Down

0 comments on commit 585a15c

Please sign in to comment.