Skip to content

Commit 259d5cc

Browse files
committed
fixup: Simplify config image build by building artifacts outside docker
1 parent 68bc42a commit 259d5cc

File tree

7 files changed

+84
-120
lines changed

7 files changed

+84
-120
lines changed

scripts/build_antithesis_images.sh

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ set -euo pipefail
66

77
# e.g.,
88
# TEST_SETUP=avalanchego ./scripts/build_antithesis_images.sh # Build local images for avalanchego
9+
# TEST_SETUP=avalanchego NODE_ONLY=1 ./scripts/build_antithesis_images.sh # Build only a local node image for avalanchego
910
# TEST_SETUP=xsvm ./scripts/build_antithesis_images.sh # Build local images for xsvm
1011
# TEST_SETUP=xsvm IMAGE_PREFIX=<registry>/<repo> TAG=latest ./scripts/build_antithesis_images.sh # Specify a prefix to enable image push and use a specific tag
1112

@@ -60,20 +61,45 @@ function build_images {
6061
docker_cmd="${docker_cmd} --build-arg AVALANCHEGO_NODE_IMAGE=${avalanchego_node_image_name}"
6162
fi
6263

63-
# Build node image first to allow the config and workload image builds to use it.
64+
# Build node image first to allow the workload image to use it.
6465
${docker_cmd} -t "${node_image_name}" -f "${node_dockerfile}" "${AVALANCHE_PATH}"
6566

66-
if [[ -z "${node_only}" || "${node_only}" == "0" ]]; then
67+
if [[ -n "${node_only}" ]]; then
6768
# Skip building the config and workload images. Supports building the avalanchego
6869
# node image as the base image for the xsvm node image.
69-
${docker_cmd} --build-arg IMAGE_TAG="${TAG}" -t "${config_image_name}" -f "${base_dockerfile}.config" "${AVALANCHE_PATH}"
70-
${docker_cmd} -t "${workload_image_name}" -f "${base_dockerfile}.workload" "${AVALANCHE_PATH}"
70+
return
7171
fi
72+
73+
TARGET_PATH="${AVALANCHE_PATH}/build/antithesis/${test_setup}"
74+
if [[ -d "${TARGET_PATH}" ]]; then
75+
# Ensure the target path is empty before generating the compose config
76+
rm -r "${TARGET_PATH:?}"
77+
fi
78+
79+
# Define the env vars for the compose config generation
80+
COMPOSE_ENV="TARGET_PATH=${TARGET_PATH} IMAGE_TAG=${TAG}"
81+
82+
if [[ "${test_setup}" == "xsvm" ]]; then
83+
# Ensure avalanchego and xsvm binaries are available to create an initial db state that includes subnets.
84+
"${AVALANCHE_PATH}"/scripts/build.sh
85+
"${AVALANCHE_PATH}"/scripts/build_xsvm.sh
86+
COMPOSE_ENV="${COMPOSE_ENV} AVALANCHEGO_PATH=${AVALANCHE_PATH}/build/avalanchego AVALANCHEGO_PLUGIN_DIR=${HOME}/.avalanchego/plugins"
87+
fi
88+
89+
# Generate compose config for copying into the config image
90+
# shellcheck disable=SC2086
91+
env ${COMPOSE_ENV} go run "${AVALANCHE_PATH}/tests/antithesis/${test_setup}/gencomposeconfig"
92+
93+
# Build the config image
94+
${docker_cmd} -t "${config_image_name}" -f "${base_dockerfile}.config" "${AVALANCHE_PATH}"
95+
96+
# Build the workload image
97+
${docker_cmd} -t "${workload_image_name}" -f "${base_dockerfile}.workload" "${AVALANCHE_PATH}"
7298
}
7399

74100
TEST_SETUP="${TEST_SETUP:-}"
75101
if [[ "${TEST_SETUP}" == "avalanchego" ]]; then
76-
build_images avalanchego "${AVALANCHE_PATH}/Dockerfile"
102+
build_images avalanchego "${AVALANCHE_PATH}/Dockerfile" "${NODE_ONLY:-}"
77103
elif [[ "${TEST_SETUP}" == "xsvm" ]]; then
78104
# Only build the node image to use as the base for the xsvm image
79105
NODE_ONLY=1

tests/antithesis/README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ enables discovery and reproduction of anomalous behavior.
88

99
## Package details
1010

11-
| Filename | Purpose |
12-
|:---------------|:--------------------------------------------------------------------------------|
13-
| compose.go | Generates Docker Compose project files and volume paths for antithesis testing. |
14-
| config.go | Defines common flags for the workload binary. |
15-
| init_db.go | Initializes db state for subnet testing. |
16-
| node_health.go | Helper to check node health. |
17-
| avalanchego/ | Defines an antithesis test setup for avalanchego's primary chains. |
18-
| xsvm/ | Defines an antithesis test setup for the xsvm VM. |
11+
| Filename | Purpose |
12+
|:---------------|:-----------------------------------------------------------------------------------|
13+
| compose.go | Generates Docker Compose project file and initial database for antithesis testing. |
14+
| config.go | Defines common flags for the workload binary. |
15+
| init_db.go | Initializes initial db state for subnet testing. |
16+
| node_health.go | Helper to check node health. |
17+
| avalanchego/ | Defines an antithesis test setup for avalanchego's primary chains. |
18+
| xsvm/ | Defines an antithesis test setup for the xsvm VM. |
1919

2020
## Instrumentation
2121

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,5 @@
1-
# The version is supplied as a build argument rather than hard-coded
2-
# to minimize the cost of version changes.
3-
ARG GO_VERSION
4-
5-
# ============= Compilation Stage ================
6-
FROM golang:$GO_VERSION-bullseye AS builder
7-
8-
WORKDIR /build
9-
# Copy and download avalanche dependencies using go mod
10-
COPY go.mod .
11-
COPY go.sum .
12-
RUN go mod download
13-
14-
# Copy the code into the container
15-
COPY . .
16-
17-
# IMAGE_TAG should be set to the tag for the images in the generated
18-
# docker compose file.
19-
ARG IMAGE_TAG=latest
20-
21-
# Generate docker compose configuration
22-
RUN TARGET_PATH=./build IMAGE_TAG="$IMAGE_TAG" go run ./tests/antithesis/avalanchego/gencomposeconfig
23-
24-
# ============= Cleanup Stage ================
251
FROM scratch AS execution
262

27-
# Copy the docker compose file and volumes into the container
28-
COPY --from=builder /build/build/docker-compose.yml /docker-compose.yml
29-
COPY --from=builder /build/build/volumes /volumes
3+
# Copy config artifacts from the build path. For simplicity, artifacts
4+
# are built outside of the docker image.
5+
COPY ./build/antithesis/avalanchego/ /

tests/antithesis/compose.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"github.com/ava-labs/avalanchego/utils/perms"
2121
)
2222

23+
const bootstrapIndex = 0
24+
2325
// Initialize the given path with the docker-compose configuration (compose file and
2426
// volumes) needed for an Antithesis test setup.
2527
func GenerateComposeConfig(
@@ -132,12 +134,14 @@ func newComposeProject(network *tmpnet.Network, nodeImageName string, workloadIm
132134
}
133135
if len(trackSubnets) > 0 {
134136
env[config.TrackSubnetsKey] = trackSubnets
135-
// DB volume will need to initialized with the subnet
136-
volumes = append(volumes, types.ServiceVolumeConfig{
137-
Type: types.VolumeTypeBind,
138-
Source: fmt.Sprintf("./volumes/%s/db", serviceName),
139-
Target: "/root/.avalanchego/db",
140-
})
137+
if i == bootstrapIndex {
138+
// DB volume for bootstrap node will need to initialized with the subnet
139+
volumes = append(volumes, types.ServiceVolumeConfig{
140+
Type: types.VolumeTypeBind,
141+
Source: fmt.Sprintf("./volumes/%s/db", serviceName),
142+
Target: "/root/.avalanchego/db",
143+
})
144+
}
141145
}
142146

143147
if i == 0 {

tests/antithesis/init_db.go

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,19 @@ import (
1515
"github.com/ava-labs/avalanchego/utils/perms"
1616
)
1717

18-
// Initialize the db volumes for a docker-compose configuration. The returned network will be updated with
19-
// subnet and chain IDs and the target path will be configured with volumes for each node containing the
20-
// initialized db state.
21-
func InitDBVolumes(network *tmpnet.Network, avalancheGoPath string, pluginDir string, targetPath string) error {
18+
// Given a path, compose the expected path of the bootstrap node's docker compose db volume.
19+
func GetBootstrapVolumePath(targetPath string) (string, error) {
20+
absPath, err := filepath.Abs(targetPath)
21+
if err != nil {
22+
return "", fmt.Errorf("failed to convert target path to absolute path: %w", err)
23+
}
24+
return filepath.Join(absPath, "volumes", getServiceName(bootstrapIndex)), nil
25+
}
26+
27+
// Bootstraps a local process-based network, creates its subnets and chains, and copies
28+
// the resulting db state from one of the nodes to the provided path. The path will be
29+
// created if it does not already exist.
30+
func InitBootstrapDB(network *tmpnet.Network, avalancheGoPath string, pluginDir string, destPath string) error {
2231
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*2)
2332
defer cancel()
2433
if err := tmpnet.StartNewNetwork(
@@ -37,23 +46,15 @@ func InitDBVolumes(network *tmpnet.Network, avalancheGoPath string, pluginDir st
3746
return fmt.Errorf("failed to stop network: %w", err)
3847
}
3948

40-
absPath, err := filepath.Abs(targetPath)
41-
if err != nil {
42-
return fmt.Errorf("failed to convert target path to absolute path: %w", err)
49+
// Copy the db state from the bootstrap node to the compose volume path.
50+
sourcePath := filepath.Join(network.Nodes[0].GetDataDir(), "db")
51+
if err := os.MkdirAll(destPath, perms.ReadWriteExecute); err != nil {
52+
return fmt.Errorf("failed to create db path %q: %w", destPath, err)
4353
}
44-
45-
// Create volumes in the target path and copy the db state from the nodes
46-
for i, node := range network.Nodes {
47-
sourcePath := filepath.Join(node.GetDataDir(), "db")
48-
destPath := filepath.Join(absPath, "volumes", getServiceName(i))
49-
if err := os.MkdirAll(destPath, perms.ReadWriteExecute); err != nil {
50-
return fmt.Errorf("failed to create volume path %q: %w", destPath, err)
51-
}
52-
// TODO(marun) Replace with os.CopyFS once we upgrade to Go 1.23
53-
cmd := exec.Command("cp", "-r", sourcePath, destPath)
54-
if err := cmd.Run(); err != nil {
55-
return fmt.Errorf("failed to copy db state from %q to %q: %w", sourcePath, destPath, err)
56-
}
54+
// TODO(marun) Replace with os.CopyFS once we upgrade to Go 1.23
55+
cmd := exec.Command("cp", "-r", sourcePath, destPath)
56+
if err := cmd.Run(); err != nil {
57+
return fmt.Errorf("failed to copy bootstrap db from %q to %q: %w", sourcePath, destPath, err)
5758
}
5859

5960
return nil
Lines changed: 3 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,5 @@
1-
# The version is supplied as a build argument rather than hard-coded
2-
# to minimize the cost of version changes.
3-
ARG GO_VERSION
4-
5-
# NODE_IMAGE needs to identify an existing xsvm node image and should include the tag
6-
ARG NODE_IMAGE
7-
8-
# ============= Node Image State ================
9-
FROM $NODE_IMAGE AS xsvm_node
10-
11-
# If this is not an instrumented node image, fake the antithesis dependencies expected by the builder.
12-
RUN [ ! -d /symbols ] && mkdir /symbols || true
13-
RUN [ ! -f /usr/lib/libvoidstar.so ] && touch /usr/lib/libvoidstar.so || true
14-
15-
# ============= Compilation Stage ================
16-
FROM golang:$GO_VERSION-bullseye AS builder
17-
18-
WORKDIR /build
19-
# Copy and download avalanche dependencies using go mod
20-
COPY go.mod .
21-
COPY go.sum .
22-
RUN go mod download
23-
24-
# Copy the code into the container
25-
COPY . .
26-
27-
# IMAGE_TAG should be set to the tag for the images in the generated docker compose file.
28-
ARG IMAGE_TAG=latest
29-
30-
# Copy the avalanchego binary and plugin from the node image
31-
RUN mkdir -p ./build/plugins
32-
COPY --from=xsvm_node /avalanchego/build/avalanchego ./build
33-
COPY --from=xsvm_node /root/.avalanchego/plugins/* ./build/plugins/
34-
35-
# Copy antithesis dependencies required by instrumented binaries
36-
COPY --from=xsvm_node /symbols /symbols
37-
COPY --from=xsvm_node /usr/lib/libvoidstar.so /usr/lib/libvoidstar.so
38-
39-
# Generate docker compose configuration. If the command fails, it will likely be due to a
40-
# node configuration problem. Attempt to start a node with the same configuration so that
41-
# its logging output will be available to aid in troubleshooting.
42-
RUN export AVALANCHEGO_PATH=./build/avalanchego\
43-
export AVALANCHEGO_PLUGIN_DIR=./build/plugins;\
44-
TARGET_PATH=./build IMAGE_TAG="$IMAGE_TAG" go run ./tests/antithesis/xsvm/gencomposeconfig\
45-
|| ${AVALANCHEGO_PATH} --log-display-level=debug\
46-
--config-file=$(find /root/.tmpnet/networks -name "flags.json" | head -n 1)
47-
48-
# ============= Cleanup Stage ================
491
FROM scratch AS execution
502

51-
# Copy the docker compose file and volumes into the container
52-
COPY --from=builder /build/build/docker-compose.yml /docker-compose.yml
53-
COPY --from=builder /build/build/volumes /volumes
3+
# Copy config artifacts from the build path. For simplicity, artifacts
4+
# are built outside of the docker image.
5+
COPY ./build/antithesis/xsvm/ /

tests/antithesis/xsvm/gencomposeconfig/main.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,16 @@ func main() {
4747
subnet.NewXSVMOrPanic("xsvm", genesis.VMRQKey, network.Nodes...),
4848
}
4949

50-
if err := antithesis.InitDBVolumes(network, avalancheGoPath, pluginDir, targetPath); err != nil {
51-
log.Fatalf("failed to initialize db volumes: %s", err)
50+
bootstrapVolumePath, err := antithesis.GetBootstrapVolumePath(targetPath)
51+
if err != nil {
52+
log.Fatalf("failed to get bootstrap volume path: %v", err)
53+
}
54+
55+
if err := antithesis.InitBootstrapDB(network, avalancheGoPath, pluginDir, bootstrapVolumePath); err != nil {
56+
log.Fatalf("failed to initialize db volumes: %v", err)
5257
}
5358

5459
if err := antithesis.GenerateComposeConfig(network, nodeImageName, workloadImageName, targetPath); err != nil {
55-
log.Fatalf("failed to generate config for docker-compose: %s", err)
60+
log.Fatalf("failed to generate config for docker-compose: %v", err)
5661
}
5762
}

0 commit comments

Comments
 (0)