From 4679c3ce33f7eef98ed6ace0e7cfc41c15d23621 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 2 Aug 2022 09:45:50 -0400 Subject: [PATCH] move sigularity to a container for portability Signed-off-by: Alex Goodman --- .github/workflows/validations.yaml | 20 ++++++++-- .gitignore | 1 + Makefile | 20 +++++++++- pkg/imagetest/image_fixtures.go | 38 +++++++++---------- test/integration/fixture_image_simple_test.go | 13 ++----- test/integration/tools/.gitignore | 1 + test/integration/tools/Makefile | 17 +++++++++ .../tools/singularity/.dockerignore | 1 + test/integration/tools/singularity/Dockerfile | 4 ++ test/integration/tools/singularity/Makefile | 28 ++++++++++++++ 10 files changed, 108 insertions(+), 35 deletions(-) create mode 100644 test/integration/tools/.gitignore create mode 100644 test/integration/tools/Makefile create mode 100644 test/integration/tools/singularity/.dockerignore create mode 100644 test/integration/tools/singularity/Dockerfile create mode 100644 test/integration/tools/singularity/Makefile diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 51d97c5a..a15b99d9 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -151,15 +151,29 @@ jobs: - name: Bootstrap CI environment dependencies run: make ci-bootstrap - - name: Build key for tar cache + - name: Build key for test-fixture cache run: make integration-fingerprint - - name: Restore integration test cache + - name: Restore integration test-fixture cache uses: actions/cache@v2.1.3 with: path: ${{ github.workspace }}/test/integration/test-fixtures/cache key: ${{ runner.os }}-integration-test-cache-${{ hashFiles('test/integration/test-fixtures/cache.fingerprint') }} - + + - name: Build key for tool cache + run: make integration-tools-fingerprint + + - name: Restore integration tool cache + id: integration-tool-cache + uses: actions/cache@v2.1.3 + with: + path: ${{ github.workspace }}/test/integration/tools/cache + key: ${{ runner.os }}-integration-tools-cache-${{ hashFiles('test/integration/tools/cache.fingerprint') }} + + - name: (cache-hit) Load integration tool cache + if: steps.integration-tool-cache.outputs.cache-hit == 'true' + run: make integration-tools-load + - name: Run integration tests run: make integration diff --git a/.gitignore b/.gitignore index 7e0426e6..930ca30b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.DS_Store coverage.txt **/test-fixtures/cache/ +**/*.fingerprint # Binaries for programs and plugins *.exe diff --git a/Makefile b/Makefile index cf9e18c7..f8be25ac 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ help: .PHONY: ci-bootstrap ci-bootstrap: bootstrap sudo apt install -y bc - curl -sLO https://github.com/sylabs/singularity/releases/download/v3.10.0/singularity-ce_3.10.0-focal_amd64.deb && sudo dpkg -i singularity-ce_3.10.0-focal_amd64.deb + curl -sLO https://github.com/sylabs/singularity/releases/download/v3.10.0/singularity-ce_3.10.0-focal_amd64.deb && sudo apt-get install -y -f singularity-ce_3.10.0-focal_amd64.deb $(RESULTSDIR): mkdir -p $(RESULTSDIR) @@ -111,8 +111,24 @@ show-benchstat: integration-fingerprint: find test/integration/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/integration/test-fixtures/cache.fingerprint +.PHONY: integration-tools-fingerprint +integration-tools-fingerprint: + @cd test/integration/tools && make fingerprint + +.PHONY: integration-tools +integration-tools: + @cd test/integration/tools && make + +.PHONY: integration-tools +integration-tools-load: + @cd test/integration/tools && make load-cache + +.PHONY: integration-tools +integration-tools-save: + @cd test/integration/tools && make save-cache + .PHONY: integration -integration: ## Run integration tests +integration: integration-tools ## Run integration tests $(call title,Running integration tests) go test -v ./test/integration diff --git a/pkg/imagetest/image_fixtures.go b/pkg/imagetest/image_fixtures.go index 56527b1a..7429f542 100644 --- a/pkg/imagetest/image_fixtures.go +++ b/pkg/imagetest/image_fixtures.go @@ -289,27 +289,25 @@ func getFixtureImageSIFPath(t testing.TB, fixtureName, sifStoreDir, sifFileName } func buildSIFFromDocker(t testing.TB, image, path string) error { - singularity, err := exec.LookPath("singularity") - if err != nil { - t.Skipf("singularity not found: %v", err) - } - - outfile, err := os.Create(path) - if err != nil { - t.Fatal("unable to create file for SIF image:", err) - } - defer func() { - err := outfile.Close() - if err != nil { - t.Fatalf("unable to close file path=%q : %+v", path, err) - } - }() - - cmdArgs := []string{"build", "--disable-cache", "--force", path, "docker-daemon:" + image} - cmd := exec.Command(singularity, cmdArgs...) - cmd.Env = os.Environ() + absHostDir, err := filepath.Abs(filepath.Dir(path)) + require.NoError(t, err) - cmd.Stdout = outfile + singularityArgs := []string{"build", "--disable-cache", "--force", "image/" + filepath.Base(path), "docker-daemon:" + image} + + allArgs := append([]string{ + "run", + "-t", + "--rm", + "-v", + "/var/run/docker.sock:/var/run/docker.sock", + "-v", + absHostDir + ":/image", + "localhost/singularity:dev", // from integration tools (make integration-tools) + "singularity", + }, singularityArgs...) + + cmd := exec.Command("docker", allArgs...) + cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin return cmd.Run() diff --git a/test/integration/fixture_image_simple_test.go b/test/integration/fixture_image_simple_test.go index a0f61308..8cacf75d 100644 --- a/test/integration/fixture_image_simple_test.go +++ b/test/integration/fixture_image_simple_test.go @@ -49,7 +49,6 @@ var simpleImageSingularityLayer = []image.LayerMetadata{ var simpleImageTestCases = []testCase{ { - name: "FromTarball", source: "docker-archive", imageMediaType: v1Types.DockerManifestSchema2, layerMediaType: v1Types.DockerLayer, @@ -58,7 +57,6 @@ var simpleImageTestCases = []testCase{ size: 65, }, { - name: "FromDocker", source: "docker", imageMediaType: v1Types.DockerManifestSchema2, layerMediaType: v1Types.DockerLayer, @@ -69,7 +67,6 @@ var simpleImageTestCases = []testCase{ size: 65, }, { - name: "FromPodman", source: "podman", imageMediaType: v1Types.DockerManifestSchema2, layerMediaType: v1Types.DockerLayer, @@ -78,7 +75,6 @@ var simpleImageTestCases = []testCase{ size: 65, }, { - name: "FromOciTarball", source: "oci-archive", imageMediaType: v1Types.OCIManifestSchema1, layerMediaType: v1Types.OCILayer, @@ -87,7 +83,6 @@ var simpleImageTestCases = []testCase{ size: 65, }, { - name: "FromOciDirectory", source: "oci-dir", imageMediaType: v1Types.OCIManifestSchema1, layerMediaType: v1Types.OCILayer, @@ -96,7 +91,6 @@ var simpleImageTestCases = []testCase{ size: 65, }, { - name: "FromSingularity", source: "singularity", imageMediaType: sif.SingularityMediaType, layerMediaType: image.SingularitySquashFSLayer, @@ -108,7 +102,6 @@ var simpleImageTestCases = []testCase{ } type testCase struct { - name string source string imageMediaType v1Types.MediaType layerMediaType v1Types.MediaType @@ -125,7 +118,7 @@ func TestSimpleImage(t *testing.T) { expectedSet.Remove(int(image.OciRegistrySource)) for _, c := range simpleImageTestCases { - t.Run(c.name, func(t *testing.T) { + t.Run(c.source, func(t *testing.T) { i := imagetest.GetFixtureImage(t, c.source, "image-simple") assertImageSimpleMetadata(t, i, c) @@ -153,7 +146,7 @@ func BenchmarkSimpleImage_GetImage(b *testing.B) { } request := imagetest.PrepareFixtureImage(b, c.source, "image-simple") - b.Run(c.name, func(b *testing.B) { + b.Run(c.source, func(b *testing.B) { var bi *image.Image for i := 0; i < b.N; i++ { @@ -182,7 +175,7 @@ func BenchmarkSimpleImage_FetchSquashedContents(b *testing.B) { if len(paths) == 0 { b.Fatalf("expected paths but found none") } - b.Run(c.name, func(b *testing.B) { + b.Run(c.source, func(b *testing.B) { for i := 0; i < b.N; i++ { for _, ref := range paths { f, err := img.FileCatalog.Get(ref) diff --git a/test/integration/tools/.gitignore b/test/integration/tools/.gitignore new file mode 100644 index 00000000..5e465967 --- /dev/null +++ b/test/integration/tools/.gitignore @@ -0,0 +1 @@ +cache \ No newline at end of file diff --git a/test/integration/tools/Makefile b/test/integration/tools/Makefile new file mode 100644 index 00000000..383d41a3 --- /dev/null +++ b/test/integration/tools/Makefile @@ -0,0 +1,17 @@ +.PHONY: all +all: + cd singularity && make + +.PHONY: save-cache +save-cache: + cd singularity && make save-cache + +.PHONY: load-cache +load-cache: + cd singularity && make load-cache + +.PHONY: fingerprint +fingerprint: + @# for all tools, generate + @rm -f cache.fingerprint + @cat */cache.fingerprint | sort | md5sum | tee cache.fingerprint diff --git a/test/integration/tools/singularity/.dockerignore b/test/integration/tools/singularity/.dockerignore new file mode 100644 index 00000000..33ceb8f0 --- /dev/null +++ b/test/integration/tools/singularity/.dockerignore @@ -0,0 +1 @@ +Makefile \ No newline at end of file diff --git a/test/integration/tools/singularity/Dockerfile b/test/integration/tools/singularity/Dockerfile new file mode 100644 index 00000000..052479c8 --- /dev/null +++ b/test/integration/tools/singularity/Dockerfile @@ -0,0 +1,4 @@ +FROM ubuntu:20.04 +RUN apt-get update && apt-get install curl -y && \ + curl -sLO https://github.com/sylabs/singularity/releases/download/v3.10.0/singularity-ce_3.10.0-focal_amd64.deb && \ + apt-get install -f ./singularity-ce_3.10.0-focal_amd64.deb -y diff --git a/test/integration/tools/singularity/Makefile b/test/integration/tools/singularity/Makefile new file mode 100644 index 00000000..14c5458a --- /dev/null +++ b/test/integration/tools/singularity/Makefile @@ -0,0 +1,28 @@ +CACHE_DIR = ../cache +CACHE_FILE_NAME = singularity-image.tar +CACHE_FILE = $(CACHE_DIR)/$(CACHE_FILE_NAME) +TAG = localhost/singularity:dev + +.PHONY: all +all: + @docker inspect $(TAG) > /dev/null && echo "$(TAG) already exists" || (make build && make save-cache) + +.PHONY: build +build: + docker build -t $(TAG) . + +.PHONY: save-cache +save-cache: $(CACHE_DIR) + docker image save $(TAG) -o $(CACHE_FILE) + +.PHONY: load-cache +load-cache: + docker image load -i $(CACHE_FILE) + +$(CACHE_DIR): + mkdir -p $(CACHE_DIR) + +# note: this is used by CI to determine if the tool image should be rebuilt/refreshed +.PHONY: fingerprint +fingerprint: + find Dockerfile -type f -exec md5sum {} + | sort | md5sum | tee cache.fingerprint