Skip to content

Commit

Permalink
Merge pull request #2390 from dtrudg/issue2384
Browse files Browse the repository at this point in the history
refactor: use ggcr for e2e OCI image copy
  • Loading branch information
dtrudg authored Nov 28, 2023
2 parents bef3ce4 + 58f2ad9 commit b64f91f
Show file tree
Hide file tree
Showing 10 changed files with 3,493 additions and 8,181 deletions.
11,268 changes: 3,378 additions & 7,890 deletions LICENSE_DEPENDENCIES.md

Large diffs are not rendered by default.

16 changes: 4 additions & 12 deletions e2e/actions/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"encoding/json"
"fmt"
"os"
"os/exec"
"os/user"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -44,19 +43,12 @@ var (
func (c actionTests) actionOciRun(t *testing.T) {
e2e.EnsureImage(t, c.env)
e2e.EnsureORASImage(t, c.env)
e2e.EnsureOCILayout(t, c.env)
e2e.EnsureOCIArchive(t, c.env)
e2e.EnsureOCISIF(t, c.env)
e2e.EnsureDockerArchive(t, c.env)
e2e.EnsureORASOCISIF(t, c.env)

// Prepare oci source (oci directory layout)
ociLayout := t.TempDir()
cmd := exec.Command("tar", "-C", ociLayout, "-xf", c.env.OCIArchivePath)
err := cmd.Run()
if err != nil {
t.Fatalf("Error extracting oci archive to layout: %v", err)
}

tests := []struct {
name string
imageRef string
Expand Down Expand Up @@ -99,18 +91,18 @@ func (c actionTests) actionOciRun(t *testing.T) {
},
{
name: "oci",
imageRef: "oci:" + ociLayout,
imageRef: "oci:" + c.env.OCILayoutPath,
exit: 0,
},
{
name: "true",
imageRef: "oci:" + ociLayout,
imageRef: "oci:" + c.env.OCILayoutPath,
argv: []string{"true"},
exit: 0,
},
{
name: "false",
imageRef: "oci:" + ociLayout,
imageRef: "oci:" + c.env.OCILayoutPath,
argv: []string{"false"},
exit: 1,
},
Expand Down
1 change: 1 addition & 0 deletions e2e/internal/e2e/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type TestEnv struct {
OrasTestOCISIF string // URI to OCI-SIF image pushed into local registry with ORAS
OrasTestPrivImage string // URI to SIF image pushed into local registry with ORAS
OCIArchivePath string // Path to test OCI archive tar file
OCILayoutPath string // Path to test OCI layout directory
OCISIFPath string // Path to test OCI-SIF file
DockerArchivePath string // Path to test Docker archive tar file
TestDir string // Path to the directory from which a Singularity command needs to be executed
Expand Down
143 changes: 77 additions & 66 deletions e2e/internal/e2e/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,25 @@ package e2e

import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"testing"

"github.com/containers/image/v5/copy"
"github.com/containers/image/v5/docker"
dockerarchive "github.com/containers/image/v5/docker/archive"
ociarchive "github.com/containers/image/v5/oci/archive"
ocilayout "github.com/containers/image/v5/oci/layout"
"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/types"
"github.com/sylabs/singularity/v4/internal/pkg/ociimage"
"github.com/sylabs/singularity/v4/internal/pkg/ociplatform"
"github.com/sylabs/singularity/v4/internal/pkg/test/tool/exec"
"github.com/sylabs/singularity/v4/pkg/syfs"
useragent "github.com/sylabs/singularity/v4/pkg/util/user-agent"
)

var (
ensureMutex sync.Mutex
pullMutex sync.Mutex
ensureMutex sync.Mutex
pullMutex sync.Mutex
ociCopyMutex sync.Mutex
)

// EnsureImage checks if e2e test image is already built or built
Expand Down Expand Up @@ -112,50 +106,61 @@ func BusyboxSIF(t *testing.T) string {

// CopyImage will copy an OCI image from source to destination
func CopyOCIImage(t *testing.T, source, dest string, insecureSource, insecureDest bool) {
policy := &signature.Policy{Default: []signature.PolicyRequirement{signature.NewPRInsecureAcceptAnything()}}
policyCtx, err := signature.NewPolicyContext(policy)
// Mutex required due to https://github.com/google/go-containerregistry/issues/1849
ociCopyMutex.Lock()
defer ociCopyMutex.Unlock()
// Use the auth config written out in dockerhub_auth.go - only if
// source/dest are not insecure, or are the localhost. We don't want to
// inadvertently send out credentials over http (!)
u := CurrentUser(t)
configPath := filepath.Join(u.Dir, ".singularity", syfs.DockerConfFile)

srcType, srcRef, err := ociimage.URItoSourceSinkRef(source)
if err != nil {
t.Fatalf("failed to copy %s to %s: %s", source, dest, err)
t.Fatalf("failed to parse %s reference: %s", source, err)
}

srcCtx := &types.SystemContext{
OCIInsecureSkipTLSVerify: insecureSource,
DockerInsecureSkipTLSVerify: types.NewOptionalBool(insecureSource),
DockerRegistryUserAgent: useragent.Value(),
platform, err := ociplatform.DefaultPlatform()
if err != nil {
t.Fatalf("failed to obtain platform: %s", err)
}
dstCtx := &types.SystemContext{
OCIInsecureSkipTLSVerify: insecureDest,
DockerInsecureSkipTLSVerify: types.NewOptionalBool(insecureDest),
DockerRegistryUserAgent: useragent.Value(),

srcOpts := ociimage.TransportOptions{
Insecure: insecureSource,
Platform: *platform,
}
if !insecureSource || isLocalHost(source) {
srcOpts.AuthFilePath = configPath
}

srcRef, err := parseRef(source)
srcImage, err := srcType.Image(context.Background(), srcRef, &srcOpts)
if err != nil {
t.Fatalf("failed to parse %s reference: %s", source, err)
t.Fatalf("failed to initialize source: %v", err)
}
dstRef, err := parseRef(dest)

// Must copy through a temp layout due to https://github.com/google/go-containerregistry/issues/1849
tmpDir, cleanup := MakeTempDir(t, "", "copy-oci-image-", "")
defer cleanup(t)
if err := ociimage.OCISourceSink.WriteImage(srcImage, tmpDir, nil); err != nil {
t.Fatalf("failed to write temporary layout: %s", err)
}
tmpImg, err := ociimage.OCISourceSink.Image(context.Background(), tmpDir, nil)
if err != nil {
t.Fatalf("failed to parse %s reference: %s", dest, err)
t.Fatalf("failed to initialize temporary layout source: %v", err)
}

// Use the auth config written out in dockerhub_auth.go - only if
// source/dest are not insecure, or are the localhost. We don't want to
// inadvertently send out credentials over http (!)
u := CurrentUser(t)
configPath := filepath.Join(u.Dir, ".singularity", syfs.DockerConfFile)
if !insecureSource || isLocalHost(source) {
srcCtx.AuthFilePath = configPath
dstType, dstRef, err := ociimage.URItoSourceSinkRef(dest)
if err != nil {
t.Fatalf("failed to parse %s reference: %s", dest, err)
}
dstOpts := ociimage.TransportOptions{
Insecure: insecureSource,
}
if !insecureDest || isLocalHost(dest) {
dstCtx.AuthFilePath = configPath
dstOpts.AuthFilePath = configPath
}

_, err = copy.Image(context.Background(), policyCtx, dstRef, srcRef, &copy.Options{
ReportWriter: io.Discard,
SourceCtx: srcCtx,
DestinationCtx: dstCtx,
})
if err != nil {
if err := dstType.WriteImage(tmpImg, dstRef, &dstOpts); err != nil {
t.Fatalf("failed to copy %s to %s: %s", source, dest, err)
}
}
Expand Down Expand Up @@ -266,9 +271,34 @@ func DownloadFile(url string, path string) error {
return nil
}

func EnsureOCILayout(t *testing.T, env TestEnv) {
ensureMutex.Lock()
defer ensureMutex.Unlock()

switch _, err := os.Stat(env.OCILayoutPath); {
case err == nil:
// OK: dir exists, return
return

case os.IsNotExist(err):
// OK: dir does not exist, continue

default:
// FATAL: something else is wrong
t.Fatalf("Failed when checking image %q: %+v\n",
env.OCILayoutPath,
err)
}

// Prepare oci-archive source
t.Logf("Copying %s to %s", env.TestRegistryImage, "oci:"+env.OCILayoutPath)
CopyOCIImage(t, env.TestRegistryImage, "oci:"+env.OCILayoutPath, true, false)
}

// EnsureImage checks if e2e OCI test archive is available, and fetches
// it otherwise.
func EnsureOCIArchive(t *testing.T, env TestEnv) {
EnsureOCILayout(t, env)
ensureMutex.Lock()
defer ensureMutex.Unlock()

Expand All @@ -287,9 +317,12 @@ func EnsureOCIArchive(t *testing.T, env TestEnv) {
err)
}

// Prepare oci-archive source
t.Logf("Copying %s to %s", env.TestRegistryImage, "oci-archive:"+env.OCIArchivePath)
CopyOCIImage(t, env.TestRegistryImage, "oci-archive:"+env.OCIArchivePath, true, false)
t.Logf("Tarring %s to %s", env.OCILayoutPath, "oci-archive:"+env.OCIArchivePath)
cmd := exec.Command("tar", "-cf", env.OCIArchivePath, "-C", env.OCILayoutPath, "index.json", "oci-layout", "blobs")
err := cmd.Run(t)
if err.ExitCode != 0 {
t.Fatalf("Error tarring oci layout to archive: %v", err)
}
}

// EnsureImage checks if e2e OCI-SIF file is available, and fetches it
Expand Down Expand Up @@ -347,25 +380,3 @@ func EnsureDockerArchive(t *testing.T, env TestEnv) {
t.Logf("Copying %s to %s", env.TestRegistryImage, "docker-archive:"+env.DockerArchivePath)
CopyOCIImage(t, env.TestRegistryImage, "docker-archive:"+env.DockerArchivePath, true, false)
}

func parseRef(refString string) (ref types.ImageReference, err error) {
parts := strings.SplitN(refString, ":", 2)
if len(parts) < 2 {
return nil, fmt.Errorf("could not parse image ref: %s", refString)
}

switch parts[0] {
case "docker":
ref, err = docker.ParseReference(parts[1])
case "docker-archive":
ref, err = dockerarchive.ParseReference(parts[1])
case "oci":
ref, err = ocilayout.ParseReference(parts[1])
case "oci-archive":
ref, err = ociarchive.ParseReference(parts[1])
default:
return nil, fmt.Errorf("cannot create an OCI container from %s source", parts[0])
}

return ref, err
}
9 changes: 7 additions & 2 deletions e2e/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,19 @@ func Run(t *testing.T) {
t.Log("Path to test image:", imagePath)
testenv.ImagePath = imagePath

// OCI Layout test directory path, built on demand by e2e.EnsureOCILayout
ociLayoutPath := path.Join(name, "oci-layout")
t.Log("Path to test OCI layout:", ociLayoutPath)
testenv.OCILayoutPath = ociLayoutPath

// OCI Archive test image path, built on demand by e2e.EnsureOCIArchive
ociArchivePath := path.Join(name, "oci.tar")
ociArchivePath := path.Join(name, "oci-archive.tar")
t.Log("Path to test OCI archive:", ociArchivePath)
testenv.OCIArchivePath = ociArchivePath

// OCI-SIF Image, retrieved on demand by e2e.EnsureOCISIF
ociSifPath := path.Join(name, "oci-sif.sif")
t.Log("Path to test OCI-SIF image:", ociArchivePath)
t.Log("Path to test OCI-SIF image:", ociSifPath)
testenv.OCISIFPath = ociSifPath

// Docker Archive test image path, built on demand by e2e.EnsureDockerArchive
Expand Down
31 changes: 0 additions & 31 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ require (
github.com/alexflint/go-filemutex v1.2.0 // indirect
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
Expand All @@ -97,13 +96,10 @@ require (
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
github.com/containerd/ttrpc v1.2.2 // indirect
github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
github.com/containers/ocicrypt v1.1.9 // indirect
github.com/containers/storage v1.51.0 // indirect
github.com/coreos/go-iptables v0.6.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/creack/pty v1.1.18 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c // indirect
github.com/d2g/dhcp4client v1.0.0 // indirect
github.com/distribution/reference v0.5.0 // indirect
Expand All @@ -114,19 +110,8 @@ require (
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 // indirect
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect
github.com/go-openapi/errors v0.20.4 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/loads v0.21.2 // indirect
github.com/go-openapi/runtime v0.26.0 // indirect
github.com/go-openapi/spec v0.20.9 // indirect
github.com/go-openapi/strfmt v0.21.7 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-openapi/validate v0.22.1 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
Expand All @@ -147,38 +132,28 @@ require (
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/in-toto/in-toto-golang v0.9.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.3 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/letsencrypt/boulder v0.0.0-20230213213521-fdfea0d469b6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/mattn/go-sqlite3 v1.14.18 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/mount v0.3.3 // indirect
github.com/moby/sys/mountinfo v0.7.1 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/signal v0.7.0 // indirect
github.com/moby/sys/user v0.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/networkplumbing/go-nft v0.3.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/proglottis/gpgme v0.1.3 // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
Expand All @@ -189,26 +164,20 @@ require (
github.com/safchain/ethtool v0.3.0 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/sigstore/fulcio v1.4.3 // indirect
github.com/sigstore/rekor v1.2.2 // indirect
github.com/spdx/tools-golang v0.5.1 // indirect
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 // indirect
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb // indirect
github.com/tonistiigi/go-archvariant v1.0.0 // indirect
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/vbatts/go-mtree v0.5.0 // indirect
github.com/vbatts/tar-split v0.11.5 // indirect
github.com/vishvananda/netlink v1.2.1-beta.2 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
go.mongodb.org/mongo-driver v1.11.3 // indirect
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 // indirect
Expand Down
Loading

0 comments on commit b64f91f

Please sign in to comment.