Skip to content

Commit 59b2f14

Browse files
szachovyCopilot
andcommitted
Add pull-or-build fallback to source code, always build in tests
Add pull_or_build_image static method to ContainerConnection that tries to pull images from GHCR first and falls back to local build. Apply it to MySQLServer, MySQLMgmt, and Superset container runs. Revert test workflow to always build images locally since tests validate the latest code, not published images. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2e7f3e6 commit 59b2f14

3 files changed

Lines changed: 30 additions & 12 deletions

File tree

.github/workflows/tests.yml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,28 +47,25 @@ jobs:
4747
run: "terraform apply --auto-approve"
4848
working-directory: "${{ env.TERRAFORM_WORKING_DIRECTORY }}"
4949

50-
- name: "Pull or build service images and pre-load into test containers"
50+
- name: "Build and pre-load service images into test containers"
5151
run: |
52-
pull_or_build_and_load() {
52+
build_and_load() {
5353
local image_name="$1"
5454
local build_context="$2"
5555
shift 2
5656
local nodes=("$@")
57-
if ! docker pull "${image_name}:latest" 2>/dev/null; then
58-
echo "Pull failed for ${image_name}:latest, building locally"
59-
docker build --quiet -t "${image_name}:latest" "$build_context"
60-
fi
57+
docker build --quiet -t "${image_name}:latest" "$build_context"
6158
for node in "${nodes[@]}"; do
6259
docker save "${image_name}:latest" | docker exec -i "$node" docker load
6360
done
6461
docker rmi "${image_name}:latest" || true
6562
docker image prune --force
6663
}
67-
pull_or_build_and_load "ghcr.io/szachovy/superset-cluster-mysql-server" \
64+
build_and_load "ghcr.io/szachovy/superset-cluster-mysql-server" \
6865
"services/mysql-server" node-2 node-3 node-4
69-
pull_or_build_and_load "ghcr.io/szachovy/superset-cluster-mysql-mgmt" \
66+
build_and_load "ghcr.io/szachovy/superset-cluster-mysql-mgmt" \
7067
"services/mysql-mgmt" node-0 node-1
71-
pull_or_build_and_load "ghcr.io/szachovy/superset-cluster-superset-service" \
68+
build_and_load "ghcr.io/szachovy/superset-cluster-superset-service" \
7269
"services/superset" node-0 node-1
7370
docker image prune --all --force
7471

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
* CodeQL code scanning workflow for Python static analysis. (#29)
1515
* Dependabot updates for `github-actions` and `terraform` ecosystems. (#29)
1616
* CI workflow to build and push service images to GitHub Container Registry on master merge. (#97)
17+
* Pull-first with local build fallback for container images during deployment. (#97)
1718

1819
### Changed
1920

2021
* Completed [ARCHITECTURE.md](./docs/ARCHITECTURE.md) (#93)
2122
* Migrated CI from self-hosted to GitHub-hosted runners with Docker-in-Docker test infrastructure. (#94)
22-
* Test workflow pulls pre-built images from GHCR with local build fallback. (#97)
23+
* Test workflow always builds service images locally for reproducibility. (#97)
2324

2425
### Fixed
2526

src/container.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ def __init__(self, container: str | None) -> None:
100100
self.client = docker.from_env()
101101
self.container = container
102102

103+
@staticmethod
104+
def pull_or_build_image(client: docker.client.DockerClient, image: str, build_context: str) -> None:
105+
try:
106+
client.images.pull(image)
107+
except docker.errors.APIError:
108+
client.images.build(path=build_context, tag=image)
109+
103110
def run_command_on_the_container(
104111
self,
105112
command: str,
@@ -210,14 +217,18 @@ def __init__(self, client: docker.client.DockerClient, container: str) -> None:
210217
self.healthcheck_retries = 3
211218

212219
def run(self) -> None:
220+
image = "ghcr.io/szachovy/superset-cluster-mysql-server:latest"
221+
ContainerConnection.pull_or_build_image(
222+
self.client, image, "/opt/superset-cluster/mysql-server"
223+
)
213224
with open(
214225
file="/opt/superset-cluster/mysql-server/seccomp.json",
215226
mode="r",
216227
encoding="utf-8"
217228
) as seccomp:
218229
seccomp_parsed = json.dumps(json.load(seccomp), separators=(',', ':'))
219230
self.client.containers.run(
220-
"ghcr.io/szachovy/superset-cluster-mysql-server:latest",
231+
image,
221232
detach=True,
222233
name=self.container,
223234
hostname=socket.gethostname(),
@@ -317,6 +328,11 @@ def setup_env(self) -> None:
317328

318329
def run(self) -> None:
319330
self.setup_env()
331+
ContainerConnection.pull_or_build_image(
332+
docker.from_env(),
333+
"ghcr.io/szachovy/superset-cluster-mysql-mgmt:latest",
334+
"/opt/superset-cluster/mysql-mgmt"
335+
)
320336
subprocess.run(" \
321337
docker \
322338
compose \
@@ -417,9 +433,13 @@ def create_mysql_superset_password_secret(self) -> str:
417433
).id
418434

419435
def run(self) -> None:
436+
image = "ghcr.io/szachovy/superset-cluster-superset-service:latest"
437+
ContainerConnection.pull_or_build_image(
438+
self.client, image, "/opt/superset-cluster/superset"
439+
)
420440
self.client.services.create(
421441
name="superset",
422-
image="ghcr.io/szachovy/superset-cluster-superset-service:latest",
442+
image=image,
423443
networks=["superset-network"],
424444
secrets=[
425445
docker.types.SecretReference(

0 commit comments

Comments
 (0)