diff --git a/cmd/convertor/builder/ToTest.md b/cmd/convertor/builder/ToTest.md new file mode 100644 index 00000000..6a4bc150 --- /dev/null +++ b/cmd/convertor/builder/ToTest.md @@ -0,0 +1,46 @@ +This PR is meant to add some unit testing for some of the core portions of the userspace conversion. I have added some notes below on the added tests and notes on the remaining tests. + +## builder_engine + - uploadManifestAndConfig -> Added test + - getBuilderEngineBase -> Added test + - isGzipLayer -> Added Test + +## builder_utils.go +- fetch - Covered by fetchManifest and fetchConfig +- fetchManifest -> Added test +- fetchConfig -> Added test +- fetchManifestAndConfig -> Seemed unecessary +- downloadLayer -> Added test +- writeConfig -> Added test +- getFileDesc -> Added test +- uploadBlob -> Added test +- uploadBytes -> Added test +- buildArchiveFromFiles -> Left For later +- addFileToArchive -> Left For later + +## builder.go +- build -> Added test + +## overlaybd_builder.go +- uploadBaseLayer -> Added test +- checkForConvertedLayer -> Added test +- storeConvertedLayer -> Added test +I am not currenly sure how best to add the remaining functions due to their use of the overlaybd binaries. In the near term these should be covered by unit tests but leaving as a future work item. + +## fastoci_builder.go +Similar problem to above. Leaving for later. + +## End to End tests +- The existing CI seems like the best place to add end to end tests. TBD. + +# Introduced Tools +Tests for the userspace convertor are not particularly simple to make, if only because they require a lot of setup and work on both the filesystem and remote sources. To help with this I have introduced a few tools to help with testing. + +## local Remotes +This is an abstraction to interact with a local registry. The registry itself supports fetching, resolving, and pushes. See the local_registry.go file for more info. Along with this there is a mocks/registry folder which allows us to load stored images into the local registry for testing for now I've kept the added images small and restricted to hello-world but more can be added easily. + +# Filesystem interactivity +test_utils.go introduces RunTestWithTempDir which is a helper emulating the snapshotter tests that allows us to run a test with a temporary directory. This is useful for testing the filesystem interactions of several of the functions. + +# Other +Theres also a small bugfix to builder to remove a small contention issue found while testing. \ No newline at end of file diff --git a/cmd/convertor/builder/builder.go b/cmd/convertor/builder/builder.go index 4b6637dc..991ab234 100644 --- a/cmd/convertor/builder/builder.go +++ b/cmd/convertor/builder/builder.go @@ -115,7 +115,11 @@ func (b *overlaybdBuilder) Build(ctx context.Context) error { // in the event of failure fallback to regular process return nil } - alreadyConverted[idx] <- &desc + select { + case <-rctx.Done(): + case alreadyConverted[idx] <- &desc: + } + return nil }) @@ -133,7 +137,8 @@ func (b *overlaybdBuilder) Build(ctx context.Context) error { err := b.engine.DownloadConvertedLayer(rctx, idx, *cachedLayer) if err == nil { logrus.Infof("downloaded cached layer %d", idx) - return err + sendToChannel(rctx, downloaded[idx], nil) + return nil } logrus.Infof("failed to download cached layer %d falling back to conversion : %s", idx, err) } diff --git a/cmd/convertor/builder/builder_engine_test.go b/cmd/convertor/builder/builder_engine_test.go new file mode 100644 index 00000000..c2472909 --- /dev/null +++ b/cmd/convertor/builder/builder_engine_test.go @@ -0,0 +1,158 @@ +/* + Copyright The Accelerated Container Image Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package builder + +import ( + "context" + "encoding/json" + "fmt" + "testing" + + testingresources "github.com/containerd/accelerated-container-image/cmd/convertor/testingresources" + _ "github.com/containerd/containerd/pkg/testutil" // Handle custom root flag + "github.com/containerd/containerd/remotes" + "github.com/opencontainers/go-digest" + specs "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +func Test_builderEngineBase_isGzipLayer(t *testing.T) { + ctx := context.Background() + resolver := testingresources.GetTestResolver(t, ctx) + + type fields struct { + fetcher remotes.Fetcher + manifest specs.Manifest + } + getFields := func(ctx context.Context, ref string) fields { + _, desc, err := resolver.Resolve(ctx, ref) + if err != nil { + t.Error(err) + } + + fetcher, err := resolver.Fetcher(ctx, ref) + if err != nil { + t.Error(err) + } + + manifestStream, err := fetcher.Fetch(ctx, desc) + if err != nil { + t.Error(err) + } + + if err != nil { + t.Error(err) + } + + parsedManifest := v1.Manifest{} + decoder := json.NewDecoder(manifestStream) + if err = decoder.Decode(&parsedManifest); err != nil { + t.Error(err) + } + + return fields{ + fetcher: fetcher, + manifest: parsedManifest, + } + } + + type args struct { + ctx context.Context + idx int + } + tests := []struct { + name string + fields fields + args args + want bool + wantErr bool + }{ + // TODO Add more layers types for validation + // Unknown Layer Type + // Uncompressed Layer Type + { + name: "Valid Gzip Layer", + fields: getFields(ctx, testingresources.DockerV2_Manifest_Simple_Ref), + args: args{ + ctx: ctx, + idx: 0, + }, + want: true, + wantErr: false, + }, + { + name: "Layer Not Found", + fields: func() fields { + fields := getFields(ctx, testingresources.DockerV2_Manifest_Simple_Ref) + fields.manifest.Layers[0].Digest = digest.FromString("sample") + return fields + }(), + args: args{ + ctx: ctx, + idx: 0, + }, + want: false, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := &builderEngineBase{ + fetcher: tt.fields.fetcher, + manifest: tt.fields.manifest, + } + got, err := e.isGzipLayer(tt.args.ctx, tt.args.idx) + if (err != nil) != tt.wantErr { + t.Errorf("builderEngineBase.isGzipLayer() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("builderEngineBase.isGzipLayer() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_getBuilderEngineBase(t *testing.T) { + resolver := testingresources.GetTestResolver(t, context.Background()) + engine, err := getBuilderEngineBase(context.TODO(), + resolver, + testingresources.DockerV2_Manifest_Simple_Ref, + fmt.Sprintf("%s-obd", testingresources.DockerV2_Manifest_Simple_Ref), + ) + if err != nil { + t.Error(err) + } + + testingresources.Assert(t, engine.fetcher != nil, "Fetcher is nil") + testingresources.Assert(t, engine.pusher != nil, "Pusher is nil") + testingresources.Assert(t, + engine.manifest.Config.Digest == testingresources.DockerV2_Manifest_Simple_Config_Digest, + fmt.Sprintf("Config Digest is not equal to %s", testingresources.DockerV2_Manifest_Simple_Config_Digest)) + + content, err := testingresources.ConsistentManifestMarshal(&engine.manifest) + if err != nil { + t.Errorf("Could not parse obtained manifest, got: %v", err) + } + + testingresources.Assert(t, + digest.FromBytes(content) == testingresources.DockerV2_Manifest_Simple_Digest, + fmt.Sprintf("Manifest Digest is not equal to %s", testingresources.DockerV2_Manifest_Simple_Digest)) +} + +func Test_uploadManifestAndConfig(t *testing.T) { +} diff --git a/cmd/convertor/builder/builder_test.go b/cmd/convertor/builder/builder_test.go new file mode 100644 index 00000000..3d93e8cd --- /dev/null +++ b/cmd/convertor/builder/builder_test.go @@ -0,0 +1,129 @@ +/* + Copyright The Accelerated Container Image Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package builder + +import ( + "context" + "fmt" + "math/rand" + "testing" + "time" + + _ "github.com/containerd/containerd/pkg/testutil" // Handle custom root flag + specs "github.com/opencontainers/image-spec/specs-go/v1" +) + +// Test_builder_Err_Fuzz_Build This test is for the arguably complex error handling and potential go routine +// locking that can happen for the builder component. It works by testing multiple potential error patterns +// across all stages of the process (Through consistent pseudo random generation, for reproducibility and +// ease of adjustment). The test is designed to run in parallel to maximize the chance of a contention. +func Test_builder_Build_Contention(t *testing.T) { + // If timeout of 1 second is exceeded with the mock fuz builder engine + // then there is a high likelihood of a present contention error + contentionTimeout := time.Second * 1 + patternCount := int64(500) // Try out 500 different seeds + + var i int64 + for i = 0; i < patternCount; i++ { + seed := i + t.Run(fmt.Sprintf("Test_builder_Err_Lock Contention Seed %d", i), func(t *testing.T) { + t.Parallel() + fixedRand := rand.New(rand.NewSource(seed)) + builderEngine := newMockBuilderEngine(fixedRand) + b := &overlaybdBuilder{ + engine: builderEngine, + layers: 25, + } + ctx, cancel := context.WithTimeout(context.Background(), contentionTimeout) + defer cancel() + + b.Build(ctx) + // Build will typically return an error but completes successfully for some seeds as well + if ctx.Err() != nil { + if ctx.Err() == context.DeadlineExceeded { + t.Errorf("Context deadline was exceeded, likely contention error") + } + } + }) + } +} + +const ( + failRate = 0.05 // 5% of the time, fail any given operation +) + +type mockFuzzBuilderEngine struct { + fixedRand *rand.Rand +} + +func newMockBuilderEngine(fixedRand *rand.Rand) builderEngine { + return &mockFuzzBuilderEngine{ + fixedRand: fixedRand, + } +} + +func (e *mockFuzzBuilderEngine) DownloadLayer(ctx context.Context, idx int) error { + if e.fixedRand.Float64() < failRate { + return fmt.Errorf("random error on download") + } + return nil +} + +func (e *mockFuzzBuilderEngine) BuildLayer(ctx context.Context, idx int) error { + if e.fixedRand.Float64() < failRate { + return fmt.Errorf("random error on BuildLayer") + } + return nil +} + +func (e *mockFuzzBuilderEngine) UploadLayer(ctx context.Context, idx int) error { + if e.fixedRand.Float64() < failRate { + return fmt.Errorf("random error on UploadLayer") + } + return nil +} + +func (e *mockFuzzBuilderEngine) UploadImage(ctx context.Context) error { + if e.fixedRand.Float64() < failRate { + return fmt.Errorf("random error on UploadImage") + } + return nil +} + +func (e *mockFuzzBuilderEngine) CheckForConvertedLayer(ctx context.Context, idx int) (specs.Descriptor, error) { + if e.fixedRand.Float64() < failRate { + return specs.Descriptor{}, fmt.Errorf("random error on CheckForConvertedLayer") + } + return specs.Descriptor{}, nil +} + +func (e *mockFuzzBuilderEngine) StoreConvertedLayerDetails(ctx context.Context, idx int) error { + if e.fixedRand.Float64() < failRate { + return fmt.Errorf("random error on StoreConvertedLayerDetails") + } + return nil +} + +func (e *mockFuzzBuilderEngine) DownloadConvertedLayer(ctx context.Context, idx int, desc specs.Descriptor) error { + if e.fixedRand.Float64() < failRate { + return fmt.Errorf("random error on DownloadConvertedLayer") + } + return nil +} + +func (e *mockFuzzBuilderEngine) Cleanup() { +} diff --git a/cmd/convertor/builder/builder_utils_test.go b/cmd/convertor/builder/builder_utils_test.go new file mode 100644 index 00000000..bf8ee9ac --- /dev/null +++ b/cmd/convertor/builder/builder_utils_test.go @@ -0,0 +1,469 @@ +/* + Copyright The Accelerated Container Image Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package builder + +import ( + "compress/gzip" + "context" + "encoding/json" + "fmt" + "io" + "os" + "path" + "reflect" + "testing" + + testingresources "github.com/containerd/accelerated-container-image/cmd/convertor/testingresources" + "github.com/containerd/accelerated-container-image/pkg/snapshot" + "github.com/containerd/containerd/images" + _ "github.com/containerd/containerd/pkg/testutil" // Handle custom root flag + "github.com/containerd/containerd/remotes" + "github.com/opencontainers/go-digest" + v1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +func Test_fetchManifest(t *testing.T) { + ctx := context.Background() + resolver := testingresources.GetTestResolver(t, ctx) + _, desc, _ := resolver.Resolve(ctx, testingresources.Docker_Manifest_List_Ref) + fmt.Println(desc) + type args struct { + ctx context.Context + fetcher remotes.Fetcher + desc v1.Descriptor + } + tests := []struct { + name string + args args + want *v1.Manifest + wantErr bool + wantSubDesc v1.Descriptor + }{ + { + name: "Fetch existing manifest", + args: args{ + fetcher: testingresources.GetTestFetcherFromResolver(t, ctx, resolver, testingresources.DockerV2_Manifest_Simple_Ref), + desc: v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema2Manifest, + Digest: testingresources.DockerV2_Manifest_Simple_Digest, + Size: testingresources.DockerV2_Manifest_Simple_Size, + }, + ctx: ctx, + }, + wantErr: false, + }, + { + name: "Fetch manifest List", + args: args{ + fetcher: testingresources.GetTestFetcherFromResolver(t, ctx, resolver, testingresources.Docker_Manifest_List_Ref), + desc: v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema2ManifestList, + Digest: testingresources.Docker_Manifest_List_Digest, + Size: 2069, + }, + ctx: ctx, + }, + // The manifest list is expected to select the first manifest that can be converted + // in the list, for this image that is the very first one. + wantSubDesc: v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema2Manifest, + Digest: testingresources.DockerV2_Manifest_Simple_Digest, + Size: 525, + Platform: &v1.Platform{ + Architecture: "amd64", + OS: "linux", + }, + }, + wantErr: false, + }, + { + name: "Fetch unknown manifest errors", + args: args{ + fetcher: testingresources.GetTestFetcherFromResolver(t, ctx, resolver, "sample.localstore.io/hello-world:idontexist"), + desc: v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema2Manifest, + Digest: "sha256:82c7f9c92844bbbb5d0a101b12f7c2a7949e40f8ee90c8b3bc396879d95e899a", + Size: 524, + }, + ctx: ctx, + }, + wantErr: true, + }, + { + name: "Fetch invalid digest", + args: args{ + fetcher: testingresources.GetTestFetcherFromResolver(t, ctx, resolver, testingresources.DockerV2_Manifest_Simple_Ref), + desc: v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema2Manifest, + Digest: "sha256:829d95e899a", + Size: 524, + }, + ctx: ctx, + }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + manifest, err := fetchManifest(tt.args.ctx, tt.args.fetcher, tt.args.desc) + if (err == nil) && tt.wantErr { + t.Error("fetchManifest() error was expected but no error was returned") + } + if err != nil { + if !tt.wantErr { + t.Errorf("fetchManifest() unexpectedly returned error %v", err) + } + return + } + content, err := testingresources.ConsistentManifestMarshal(manifest) + if err != nil { + t.Errorf("Could not parse obtained manifest, got: %v", err) + } + + contentDigest := digest.FromBytes(content) + + if tt.args.desc.MediaType != images.MediaTypeDockerSchema2ManifestList && + tt.args.desc.MediaType != v1.MediaTypeImageIndex { + + if tt.args.desc.Digest != contentDigest { + t.Errorf("fetchManifest() = %v, want %v", manifest, tt.want) + } + } else { + if tt.wantSubDesc.Digest != contentDigest { + t.Errorf("fetchManifest() = %v, want %v", manifest, tt.want) + } + } + }) + } +} + +func Test_fetchConfig(t *testing.T) { + ctx := context.Background() + resolver := testingresources.GetTestResolver(t, ctx) + + type args struct { + ctx context.Context + fetcher remotes.Fetcher + desc v1.Descriptor + } + tests := []struct { + name string + args args + want *v1.Image + wantErr bool + }{ + // TODO: "Fetch Config with supported mediaType (oci)", + { + name: "Fetch Config with supported mediaType (docker v2)", + args: args{ + fetcher: testingresources.GetTestFetcherFromResolver(t, ctx, resolver, testingresources.DockerV2_Manifest_Simple_Ref), + desc: v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema2Config, + Digest: testingresources.DockerV2_Manifest_Simple_Config_Digest, + Size: testingresources.DockerV2_Manifest_Simple_Config_Size, + Platform: &v1.Platform{ + Architecture: "amd64", + OS: "linux", + }, + }, + ctx: ctx, + }, + wantErr: false, + }, + { + name: "Fetch unknown config", + args: args{ + fetcher: testingresources.GetTestFetcherFromResolver(t, ctx, resolver, testingresources.DockerV2_Manifest_Simple_Ref), + desc: v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema1Manifest, + Digest: "sha256:82c7f9c92844bbab5d0a101b12f7c2a7949e40f8ee90c8b3bc396879d95e899a", + Size: 524, + }, + ctx: ctx, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := fetchConfig(tt.args.ctx, tt.args.fetcher, tt.args.desc) + if (err == nil) && tt.wantErr { + t.Error("fetchConfig() error was expected but no error was returned") + } + if err != nil { + if !tt.wantErr { + t.Errorf("fetchConfig() unexpectedly returned error %v", err) + } + return + } + if got.Architecture != tt.args.desc.Platform.Architecture || + got.OS != tt.args.desc.Platform.OS { + t.Errorf("fetchConfig() config is not as expected") + } + + if len(got.RootFS.DiffIDs) == 0 { + t.Errorf("fetchConfig() Expected some DiffIds") + } + if len(got.History) == 0 { + t.Errorf("fetchConfig() Expected layer history") + } + }) + } +} + +func Test_uploadBytes(t *testing.T) { + ctx := context.Background() + sourceManifest := testingresources.DockerV2_Manifest_Simple_Ref + targetManifest := "sample.localstore.io/hello-world:another" + resolver := testingresources.GetTestResolver(t, ctx) + + _, desc, err := resolver.Resolve(ctx, sourceManifest) + if err != nil { + t.Error(err) + } + fetcher := testingresources.GetTestFetcherFromResolver(t, ctx, resolver, sourceManifest) + pusher := testingresources.GetTestPusherFromResolver(t, ctx, resolver, targetManifest) + + // Load manifest + content, err := fetcher.Fetch(ctx, desc) + if err != nil { + t.Error(err) + } + + test_uploadBytes := func(manifest v1.Manifest, pusher remotes.Pusher) error { + manifestBytes, err := testingresources.ConsistentManifestMarshal(&manifest) + if err != nil { + return err + } + newDesc := v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema2Manifest, + Digest: digest.FromBytes(manifestBytes), + Size: int64(len(manifestBytes)), + } + err = uploadBytes(ctx, pusher, newDesc, manifestBytes) + if err != nil { + return err + } + return nil + } + + // Docker v2 manifest + manifest := v1.Manifest{} + json.NewDecoder(content).Decode(&manifest) + + // Re-Push Manifest error should be handled + testingresources.Assert(t, test_uploadBytes(manifest, testingresources.GetTestPusherFromResolver(t, ctx, resolver, sourceManifest)) == nil, "Could not upload Re upload Docker v2 Manifest with layers present") // Docker v2 manifest + + // Modify manifest to change digest + manifest.Annotations = map[string]string{ + "test": "test", + } + testingresources.Assert(t, test_uploadBytes(manifest, pusher) == nil, "Could not upload Docker v2 Manifest with layers present") // Docker v2 manifest + + // OCI manifest + manifest.MediaType = v1.MediaTypeImageManifest + for i := range manifest.Layers { + manifest.Layers[i].MediaType = v1.MediaTypeImageLayerGzip + } + testingresources.Assert(t, test_uploadBytes(manifest, pusher) == nil, "Could not upload OCI Manifest with layers present") // Docker v2 manifest + + // Missing layer + manifest.Layers[0].Digest = digest.FromString("not there") + testingresources.Assert(t, test_uploadBytes(manifest, pusher) != nil, "Expected layer not found error") // Docker v2 manifest +} + +func Test_uploadBlob(t *testing.T) { + ctx := context.Background() + // Create a new inmemory registry to push to + reg := testingresources.GetTestRegistry(t, ctx, testingresources.RegistryOptions{ + InmemoryOnly: true, + ManifestPushIgnoresLayers: false, + }) + + resolver := testingresources.GetCustomTestResolver(t, ctx, reg) + pusher := testingresources.GetTestPusherFromResolver(t, ctx, resolver, "sample.localstore.io/hello-world:latest") + blobPath := path.Join(testingresources.GetLocalRegistryPath(), "hello-world", "blobs", "sha256", digest.Digest(testingresources.DockerV2_Manifest_Simple_Layer_0_Digest).Encoded()) + + desc := v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema2LayerGzip, + Digest: testingresources.DockerV2_Manifest_Simple_Layer_0_Digest, + Size: testingresources.DockerV2_Manifest_Simple_Layer_0_Size, + } + + testingresources.Assert(t, uploadBlob(ctx, pusher, blobPath, desc) == nil, "uploadBlob() expected no error but got one") + + // Uploads already present shuld give no issues + testingresources.Assert(t, uploadBlob(ctx, pusher, blobPath, desc) == nil, "uploadBlob() retry expected no error but got one") + // Validate manifest of pushed blob + fetcher := testingresources.GetTestFetcherFromResolver(t, ctx, resolver, "sample.localstore.io/hello-world:latest") + blob, err := fetcher.Fetch(ctx, desc) + if err != nil { + t.Error(err) + } + blobDigest, err := digest.FromReader(blob) + if err != nil { + t.Error(err) + } + testingresources.Assert(t, blobDigest == desc.Digest, "uploadBlob() blob digest does not match stored value") +} + +func Test_getFileDesc(t *testing.T) { + test_getFileDesc := func(blobPath string, compressed bool, expectedDigest string, expectedSize int64) { + desc, err := getFileDesc(blobPath, compressed) + if err != nil { + t.Error(err) + } + testingresources.Assert(t, desc.Digest.String() == expectedDigest, "getFileDesc() wrong digest returned") + testingresources.Assert(t, desc.Size == expectedSize, "getFileDesc() wrong size returned") + } + blobPath := path.Join(testingresources.GetLocalRegistryPath(), "hello-world", "blobs", "sha256") + + // Compressed blob + test_getFileDesc( + path.Join(blobPath, digest.Digest(testingresources.DockerV2_Manifest_Simple_Layer_0_Digest).Encoded()), + false, + testingresources.DockerV2_Manifest_Simple_Layer_0_Digest, + testingresources.DockerV2_Manifest_Simple_Layer_0_Size) + + // Uncompressed blob + test_getFileDesc( + path.Join(blobPath, digest.Digest(testingresources.DockerV2_Manifest_Simple_Config_Digest).Encoded()), + false, + testingresources.DockerV2_Manifest_Simple_Config_Digest, + testingresources.DockerV2_Manifest_Simple_Config_Size) +} + +func Test_downloadLayer(t *testing.T) { + ctx := context.Background() + testDownloadLayer := func(t *testing.T, ctx context.Context, testName string, sourceDesc v1.Descriptor, decompress bool) { + testingresources.RunTestWithTempDir(t, ctx, testName, func(t *testing.T, ctx context.Context, workdir string) { + resolver := testingresources.GetTestResolver(t, ctx) + fetcher := testingresources.GetTestFetcherFromResolver(t, ctx, resolver, testingresources.DockerV2_Manifest_Simple_Ref) + layerPath := path.Join(workdir, "layer.tar") + + err := downloadLayer(ctx, fetcher, layerPath, sourceDesc, decompress) + if err != nil { + t.Error(err) + } + + _, err = os.Stat(layerPath) + if err != nil { + t.Errorf("Expected layer file to exist") + } + + var outputDesc v1.Descriptor + if !decompress { + outputDesc, err = getFileDesc(layerPath, !decompress) + if err != nil { + t.Error(err) + } + } else { + // Compress again to verify digest + file, err := os.Open(layerPath) + if err != nil { + t.Error(err) + } + defer file.Close() + + r, w := io.Pipe() + defer r.Close() + gzWriter := gzip.NewWriter(w) + defer w.Close() + defer gzWriter.Close() + + go func() { + _, err := io.Copy(gzWriter, file) + defer gzWriter.Close() + if err != nil { + t.Error(err) + } + }() + data := make([]byte, sourceDesc.Size) + _, err = io.ReadFull(r, data) + if err != nil { + t.Error(err) + } + + outputDesc = v1.Descriptor{ + Digest: digest.FromBytes(data), + Size: int64(len(data)), + } + } + + testingresources.Assert(t, outputDesc.Digest == sourceDesc.Digest, "downloadLayer() wrong digest returned") + testingresources.Assert(t, outputDesc.Size == sourceDesc.Size, "downloadLayer() wrong size returned") + }) + } + + testDownloadLayer(t, ctx, "downloadGzippedLayer", + v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema2LayerGzip, + Digest: testingresources.DockerV2_Manifest_Simple_Layer_0_Digest, + Size: testingresources.DockerV2_Manifest_Simple_Layer_0_Size, + }, true) + + testDownloadLayer(t, ctx, "downloadLayer", + v1.Descriptor{ + MediaType: images.MediaTypeDockerSchema2Config, + Digest: testingresources.DockerV2_Manifest_Simple_Config_Digest, + Size: testingresources.DockerV2_Manifest_Simple_Config_Size, + }, false) +} + +func Test_writeConfig(t *testing.T) { + ctx := context.Background() + testingresources.RunTestWithTempDir(t, ctx, "writeConfigMinimal", func(t *testing.T, ctx context.Context, workdir string) { + configSample := snapshot.OverlayBDBSConfig{ + ResultFile: "", + Lowers: []snapshot.OverlayBDBSConfigLower{ + { + File: overlaybdBaseLayer, + }, + { + File: path.Join(workdir, commitFile), + }, + }, + Upper: snapshot.OverlayBDBSConfigUpper{ + Data: path.Join(workdir, "writable_data"), + Index: path.Join(workdir, "writable_index"), + }, + } + + err := writeConfig(workdir, &configSample) + if err != nil { + t.Error(err) + } + + file, err := os.Open(path.Join(workdir, "config.json")) + if err != nil { + t.Errorf("Expected layer file to exist") + } + defer file.Close() + + configRes := snapshot.OverlayBDBSConfig{} + + err = json.NewDecoder(file).Decode(&configRes) + if err != nil { + t.Error(err) + } + + if !reflect.DeepEqual(configSample, configRes) { + t.Errorf("Input config and output config are not equal, wanted: %+v \n got: %+v", configSample, configRes) + } + }) +} diff --git a/cmd/convertor/builder/overlaybd_builder_test.go b/cmd/convertor/builder/overlaybd_builder_test.go new file mode 100644 index 00000000..b35c1f9e --- /dev/null +++ b/cmd/convertor/builder/overlaybd_builder_test.go @@ -0,0 +1,162 @@ +/* + Copyright The Accelerated Container Image Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package builder + +import ( + "context" + "fmt" + "io" + "testing" + + testingresources "github.com/containerd/accelerated-container-image/cmd/convertor/testingresources" + "github.com/containerd/containerd/errdefs" + _ "github.com/containerd/containerd/pkg/testutil" // Handle custom root flag + "github.com/opencontainers/go-digest" + v1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +func Test_overlaybd_builder_uploadBaseLayer(t *testing.T) { + ctx := context.Background() + + testingresources.RunTestWithTempDir(t, ctx, "overlaybd-builder", func(t *testing.T, ctx context.Context, workdir string) { + reg := testingresources.GetTestRegistry(t, ctx, testingresources.RegistryOptions{ + InmemoryOnly: true, + }) + resolver := testingresources.GetCustomTestResolver(t, ctx, reg) + pusher := testingresources.GetTestPusherFromResolver(t, ctx, resolver, testingresources.DockerV2_Manifest_Simple_Ref) + + // Create a new overlaybd builder engine + base := &builderEngineBase{ + workDir: workdir, + pusher: pusher, + } + e := &overlaybdBuilderEngine{ + builderEngineBase: base, + } + desc, err := e.uploadBaseLayer(ctx) + if err != nil { + t.Error(err) + } + testingresources.Assert(t, + desc.Digest == testingresources.ExpectedOverlaybdBaseLayerDigest, + fmt.Sprintf("Expected digest %s, got %s", testingresources.ExpectedOverlaybdBaseLayerDigest, desc.Digest)) + + // Verify that the layer is in the registry and is the smae as expected + fetcher := testingresources.GetTestFetcherFromResolver(t, ctx, resolver, testingresources.DockerV2_Manifest_Simple_Ref) + blob, err := fetcher.Fetch(ctx, desc) + if err != nil { + t.Error(err) + } + // read blob into byte + data, err := io.ReadAll(blob) + if err != nil { + t.Error(err) + } + + digest := digest.FromBytes(data) + + testingresources.Assert(t, + digest == testingresources.ExpectedOverlaybdBaseLayerDigest, + fmt.Sprintf("Expected digest %s, got %s", testingresources.ExpectedOverlaybdBaseLayerDigest, digest)) + }) +} + +func Test_overlaybd_builder_CheckForConvertedLayer(t *testing.T) { + ctx := context.Background() + db := testingresources.NewLocalDB() + resolver := testingresources.GetTestResolver(t, ctx) + fetcher := testingresources.GetTestFetcherFromResolver(t, ctx, resolver, testingresources.DockerV2_Manifest_Simple_Ref) + base := &builderEngineBase{ + fetcher: fetcher, + host: "sample.localstore.io", + repository: "hello-world", + } + + // TODO: Maybe change this for an actually converted layer in the future + targetDesc := v1.Descriptor{ + Digest: testingresources.DockerV2_Manifest_Simple_Layer_0_Digest, + Size: testingresources.DockerV2_Manifest_Simple_Layer_0_Size, + MediaType: v1.MediaTypeImageLayerGzip, + } + + fakeChainId := "fake-chain-id" // We don't validate the chainID itself so such values are fine for testing + e := &overlaybdBuilderEngine{ + builderEngineBase: base, + overlaybdLayers: []overlaybdConvertResult{ + { + chainID: fakeChainId, + }, + }, + } + + t.Run("No DB Present", func(t *testing.T) { + _, err := e.CheckForConvertedLayer(ctx, 0) + testingresources.Assert(t, errdefs.IsNotFound(err), fmt.Sprintf("CheckForConvertedLayer() returned an unexpected Error: %v", err)) + }) + + base.db = db + + t.Run("No Entry in DB", func(t *testing.T) { + _, err := e.CheckForConvertedLayer(ctx, 0) + testingresources.Assert(t, errdefs.IsNotFound(err), fmt.Sprintf("CheckForConvertedLayer() returned an unexpected Error: %v", err)) + }) + + err := base.db.CreateEntry(ctx, e.host, e.repository, targetDesc.Digest, fakeChainId, targetDesc.Size) + if err != nil { + t.Error(err) + } + + t.Run("Entry in DB and in Registry", func(t *testing.T) { + desc, err := e.CheckForConvertedLayer(ctx, 0) + + if err != nil { + t.Error(err) + } + + testingresources.Assert(t, desc.Size == targetDesc.Size, "CheckForConvertedLayer() returned improper size layer") + testingresources.Assert(t, desc.Digest == targetDesc.Digest, "CheckForConvertedLayer() returned incorrect digest") + }) + + base.db = testingresources.NewLocalDB() // Reset DB + digestNotInRegistry := digest.FromString("Not in reg") + err = base.db.CreateEntry(ctx, e.host, e.repository, digestNotInRegistry, fakeChainId, 10) + if err != nil { + t.Error(err) + } + + t.Run("Entry in DB but not in registry", func(t *testing.T) { + _, err := e.CheckForConvertedLayer(ctx, 0) + testingresources.Assert(t, errdefs.IsNotFound(err), fmt.Sprintf("CheckForConvertedLayer() returned an unexpected Error: %v", err)) + entry := base.db.GetEntryForRepo(ctx, e.host, e.repository, fakeChainId) + testingresources.Assert(t, entry == nil, "CheckForConvertedLayer() Invalid entry was not cleaned up") + }) + + // TODO: Cross Repo Mount Scenario +} + +func Test_overlaybd_builder_StoreConvertedLayerDetails(t *testing.T) { + ctx := context.Background() + base := &builderEngineBase{ + db: nil, + } + e := &overlaybdBuilderEngine{ + builderEngineBase: base, + } + // No DB Case + err := e.StoreConvertedLayerDetails(ctx, 0) + testingresources.Assert(t, err == nil, "StoreConvertedLayerDetails() returned an unexpected Error") +} diff --git a/cmd/convertor/testingresources/consts.go b/cmd/convertor/testingresources/consts.go new file mode 100644 index 00000000..4e47bc98 --- /dev/null +++ b/cmd/convertor/testingresources/consts.go @@ -0,0 +1,69 @@ +/* +Copyright The Accelerated Container Image Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package testingresources + +import ( + "context" + "strings" + + "github.com/containerd/containerd/reference" +) + +/* +This package provides a local implementation of a registry complete with +sample images of different types. Its built in such a way that we can add +more complex images as well as more complex tests are required in the +future. Note that the local registry is not particularly optimized or a +good model for how to implement a local registry but its convenient to utilize +with existing skopeo tooling. This is something that can be easily revised as more +complex scenarios arise. For now we are using abstractions from +https://pkg.go.dev/github.com/containers/image/v5 for the purpose of maintaining +compatibility with skopeo image downloads as a quick, easy and reproducible way of +adding and downloading images. +*/ + +const ( + // MINIMAL MANIFESTS (For unit testing) + // DOCKER V2 (amd64) + DockerV2_Manifest_Simple_Ref = "sample.localstore.io/hello-world:amd64" + DockerV2_Manifest_Simple_Digest = "sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3" + DockerV2_Manifest_Simple_Size = 525 + DockerV2_Manifest_Simple_Config_Digest = "sha256:9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d" + DockerV2_Manifest_Simple_Config_Size = 1470 + DockerV2_Manifest_Simple_Layer_0_Digest = "sha256:719385e32844401d57ecfd3eacab360bf551a1491c05b85806ed8f1b08d792f6" + DockerV2_Manifest_Simple_Layer_0_Size = 2457 + + // DOCKER MANIFEST LIST + Docker_Manifest_List_Ref = "sample.localstore.io/hello-world:docker-list" + Docker_Manifest_List_Digest = "sha256:726023f73a8fc5103fa6776d48090539042cb822531c6b751b1f6dd18cb5705d" +) + +const ( + // OTHER CONSTS (For unit testing) + ExpectedOverlaybdBaseLayerDigest = "sha256:a8b5fca80efae55088290f3da8110d7742de55c2a378d5ab53226a483f390e21" +) + +// ParseRef Parses a ref into its components: host, repository, tag/digest +func ParseRef(ctx context.Context, ref string) (string, string, string, error) { + refspec, err := reference.Parse(ref) + if err != nil { + return "", "", "", err + } + host := refspec.Hostname() + repository := strings.TrimPrefix(refspec.Locator, host+"/") + object := refspec.Object + return host, repository, object, nil +} diff --git a/cmd/convertor/testingresources/local_db.go b/cmd/convertor/testingresources/local_db.go new file mode 100644 index 00000000..e1cd9440 --- /dev/null +++ b/cmd/convertor/testingresources/local_db.go @@ -0,0 +1,84 @@ +/* + Copyright The Accelerated Container Image Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package testingresources + +import ( + "context" + + "github.com/containerd/accelerated-container-image/cmd/convertor/database" + "github.com/opencontainers/go-digest" + "github.com/pkg/errors" +) + +type localdb struct { + records []*database.Entry +} + +// NewLocalDB returns a new local database for testing. This is a simple unoptimized in-memory database. +func NewLocalDB() database.ConversionDatabase { + return &localdb{} +} + +func (l *localdb) GetEntryForRepo(ctx context.Context, host string, repository string, chainID string) *database.Entry { + for _, entry := range l.records { + if entry.Host == host && entry.ChainID == chainID && entry.Repository == repository { + return entry + } + } + return nil +} + +func (l *localdb) GetCrossRepoEntries(ctx context.Context, host string, chainID string) []*database.Entry { + var entries []*database.Entry + for _, entry := range l.records { + if entry.Host == host && entry.ChainID == chainID { + entries = append(entries, entry) + } + } + return entries +} + +func (l *localdb) CreateEntry(ctx context.Context, host string, repository string, convertedDigest digest.Digest, chainID string, size int64) error { + l.records = append(l.records, &database.Entry{ + Host: host, + Repository: repository, + ChainID: chainID, + ConvertedDigest: convertedDigest, + DataSize: size, + }) + return nil +} + +func (l *localdb) DeleteEntry(ctx context.Context, host string, repository string, chainID string) error { + // Identify indices of items to be deleted. + var indicesToDelete []int + for i, entry := range l.records { + if entry.Host == host && entry.ChainID == chainID && entry.Repository == repository { + indicesToDelete = append(indicesToDelete, i) + } + } + + if len(indicesToDelete) == 0 { + return errors.Errorf("failed to find entry for host %s, repository %s, chainID %s", host, repository, chainID) + } + + // Delete items at identified indices. (Reverse order to avoid index shifting.) + for i := len(indicesToDelete) - 1; i >= 0; i-- { + l.records = append(l.records[:indicesToDelete[i]], l.records[indicesToDelete[i]+1:]...) + } + return nil +} diff --git a/cmd/convertor/testingresources/local_registry.go b/cmd/convertor/testingresources/local_registry.go new file mode 100644 index 00000000..346b016f --- /dev/null +++ b/cmd/convertor/testingresources/local_registry.go @@ -0,0 +1,145 @@ +/* +Copyright The Accelerated Container Image Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testingresources + +import ( + "context" + "errors" + "io" + "os" + "path/filepath" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + v1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +// REGISTRY +// TestRegistry is a mock registry that can be used for testing purposes. +// The implementation is a combination of in memory and local storage, where +// the in memory storage is used for pushes and overrides. The local storage +// provides a prebuilt index of repositories and manifests for pulls. +// Features: Pull, Push, Resolve. +// Limitations: Cross Repository Mounts are not currently supported, Delete +// is not supported. +type TestRegistry struct { + internalRegistry internalRegistry + opts RegistryOptions +} + +type RegistryOptions struct { + InmemoryOnly bool // Specifies if the registry should not load any resources from storage + LocalRegistryPath string // Specifies the path to the local registry + ManifestPushIgnoresLayers bool // Specifies if the registry should require layers to be pushed before manifest +} + +type internalRegistry map[string]*RepoStore + +func NewTestRegistry(ctx context.Context, opts RegistryOptions) (*TestRegistry, error) { + TestRegistry := TestRegistry{ + internalRegistry: make(internalRegistry), + opts: opts, + } + if !opts.InmemoryOnly { + files, err := os.ReadDir(opts.LocalRegistryPath) + if err != nil { + return nil, err + } + for _, file := range files { + if file.IsDir() { + // Actual load from storage is done in a deferred manner as an optimization + repoStore := NewRepoStore( + ctx, + filepath.Join(opts.LocalRegistryPath, file.Name()), + &opts, + ) + TestRegistry.internalRegistry[file.Name()] = repoStore + } + } + if err != nil { + return nil, err + } + } + return &TestRegistry, nil +} + +func (r *TestRegistry) Resolve(ctx context.Context, ref string) (v1.Descriptor, error) { + _, repository, tag, err := ParseRef(ctx, ref) + if err != nil { + return v1.Descriptor{}, err + } + if repo, ok := r.internalRegistry[repository]; ok { + return repo.Resolve(ctx, tag) + } + return v1.Descriptor{}, errors.New("Repository not found") +} + +func (r *TestRegistry) Fetch(ctx context.Context, repository string, descriptor v1.Descriptor) (io.ReadCloser, error) { + // Add in memory store for overrides/pushes + if repo, ok := r.internalRegistry[repository]; ok { + return repo.Fetch(ctx, descriptor) + } + return nil, errdefs.ErrNotFound +} + +// Push Adds content to the in-memory store +func (r *TestRegistry) Push(ctx context.Context, repository string, tag string, descriptor v1.Descriptor, content []byte) error { + repo, ok := r.internalRegistry[repository] + if ok { + return repo.Push(ctx, descriptor, tag, content) + } + + // If the repository does not exist we create a new one + repo = NewRepoStore(ctx, repository, &r.opts) + r.internalRegistry[repository] = repo + repo.Push(ctx, descriptor, tag, content) + + return nil +} + +func (r *TestRegistry) Exists(ctx context.Context, repository string, tag string, desc v1.Descriptor) (bool, error) { + repo, ok := r.internalRegistry[repository] + if !ok { + return false, nil + } + + // If no tag needs to be verified we only care about the digest + if tag == "" { + return repo.Exists(ctx, desc) + } + + // If a tag is specified for a digest we need to match the tag to the digest + switch desc.MediaType { + case v1.MediaTypeImageManifest, v1.MediaTypeImageIndex, + images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList: + digest, ok := repo.inmemoryRepo.tags[tag] + if !ok { + return false, nil + } + if digest != desc.Digest { + return false, nil + } + // Tag matches provided digest. Since no delete option exists + // we don't need to check if the digest exists in the repo stores. + return true, nil + default: + if tag != "" { + return false, errors.New("Tag specified for non manifest") + } + return repo.Exists(ctx, desc) + } +} diff --git a/cmd/convertor/testingresources/local_remotes.go b/cmd/convertor/testingresources/local_remotes.go new file mode 100644 index 00000000..8a061ad2 --- /dev/null +++ b/cmd/convertor/testingresources/local_remotes.go @@ -0,0 +1,271 @@ +/* +Copyright The Accelerated Container Image Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testingresources + +import ( + "context" + "errors" + "fmt" + "io" + "time" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/remotes" + "github.com/containerd/containerd/remotes/docker" + "github.com/opencontainers/go-digest" + v1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +// RESOLVER +type MockLocalResolver struct { + testReg *TestRegistry +} + +func NewMockLocalResolver(ctx context.Context, localRegistryPath string) (*MockLocalResolver, error) { + reg, err := NewTestRegistry(ctx, RegistryOptions{ + LocalRegistryPath: localRegistryPath, + InmemoryOnly: false, + ManifestPushIgnoresLayers: false, + }) + if err != nil { + return nil, err + } + + return &MockLocalResolver{ + testReg: reg, + }, nil +} + +func NewCustomMockLocalResolver(ctx context.Context, testReg *TestRegistry) (*MockLocalResolver, error) { + return &MockLocalResolver{ + testReg: testReg, + }, nil +} + +func (r *MockLocalResolver) Resolve(ctx context.Context, ref string) (string, v1.Descriptor, error) { + desc, err := r.testReg.Resolve(ctx, ref) + if err != nil { + return "", v1.Descriptor{}, err + } + return "", desc, nil +} + +func (r *MockLocalResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) { + _, repository, _, err := ParseRef(ctx, ref) + if err != nil { + return nil, err + } + + return &MockLocalFetcher{ + testReg: r.testReg, + repository: repository, + }, nil +} + +func (r *MockLocalResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) { + _, repository, tag, err := ParseRef(ctx, ref) + if err != nil { + return nil, err + } + + return &MockLocalPusher{ + testReg: r.testReg, + repository: repository, + tag: tag, + tracker: docker.NewInMemoryTracker(), + }, nil +} + +// FETCHER +type MockLocalFetcher struct { + testReg *TestRegistry + repository string +} + +func (f *MockLocalFetcher) Fetch(ctx context.Context, desc v1.Descriptor) (io.ReadCloser, error) { + return f.testReg.Fetch(ctx, f.repository, desc) +} + +// PUSHER +type MockLocalPusher struct { + testReg *TestRegistry + repository string + tag string + tracker docker.StatusTracker +} + +// Not used by overlaybd conversion +func (p MockLocalPusher) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) { + return nil, errors.New("Not implemented") +} + +func (p MockLocalPusher) Push(ctx context.Context, desc v1.Descriptor) (content.Writer, error) { + return p.push(ctx, desc, remotes.MakeRefKey(ctx, desc), false) +} + +func (p MockLocalPusher) push(ctx context.Context, desc v1.Descriptor, ref string, unavailableOnFail bool) (content.Writer, error) { + if l, ok := p.tracker.(docker.StatusTrackLocker); ok { + l.Lock(ref) + defer l.Unlock(ref) + } + + status, err := p.tracker.GetStatus(ref) + if err == nil { + if status.Committed && status.Offset == status.Total { + return nil, fmt.Errorf("ref %v: %w", ref, errdefs.ErrAlreadyExists) + } + if unavailableOnFail && status.ErrClosed == nil { + // Another push of this ref is happening elsewhere. The rest of function + // will continue only when `errdefs.IsNotFound(err) == true` (i.e. there + // is no actively-tracked ref already). + return nil, fmt.Errorf("push is on-going: %w", errdefs.ErrUnavailable) + } + } else if !errdefs.IsNotFound(err) { + return nil, fmt.Errorf("failed to get status: %w", err) + } + + // Check Exists first + ok, err := p.testReg.Exists(ctx, p.repository, p.tag, desc) + + if err != nil { + return nil, err + } + + if ok { + return nil, errdefs.ErrAlreadyExists + } + + respC := make(chan error, 1) + + p.tracker.SetStatus(ref, docker.Status{ + Status: content.Status{ + Ref: ref, + Total: desc.Size, + Expected: desc.Digest, + StartedAt: time.Now(), + }, + }) + + pr, pw := io.Pipe() + body := io.NopCloser(pr) + + go func() { + defer close(respC) + + // Reader must be read first before other error checks + buf, err := io.ReadAll(body) + if err != nil { + respC <- err + pr.CloseWithError(err) + return + } + + err = p.testReg.Push(ctx, p.repository, p.tag, desc, buf) + + if err != nil { + respC <- err + pr.CloseWithError(err) + return + } + respC <- nil + }() + + return &pushWriter{ + ref: ref, + pipe: pw, + responseC: respC, + expected: desc.Digest, + tracker: p.tracker, + }, nil +} + +type pushWriter struct { + ref string + pipe *io.PipeWriter + responseC <-chan error + + expected digest.Digest + tracker docker.StatusTracker +} + +func (pw *pushWriter) Write(p []byte) (n int, err error) { + status, err := pw.tracker.GetStatus(pw.ref) + if err != nil { + return n, err + } + n, err = pw.pipe.Write(p) + status.Offset += int64(n) + status.UpdatedAt = time.Now() + pw.tracker.SetStatus(pw.ref, status) + return +} + +func (pw *pushWriter) Close() error { + status, err := pw.tracker.GetStatus(pw.ref) + if err == nil && !status.Committed { + // Closing an incomplete writer. Record this as an error so that following write can retry it. + status.ErrClosed = errors.New("closed incomplete writer") + pw.tracker.SetStatus(pw.ref, status) + } + return pw.pipe.Close() +} + +func (pw *pushWriter) Status() (content.Status, error) { + status, err := pw.tracker.GetStatus(pw.ref) + if err != nil { + return content.Status{}, err + } + return status.Status, nil +} + +func (pw *pushWriter) Digest() digest.Digest { + return pw.expected +} + +func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error { + // Check whether read has already thrown an error + if _, err := pw.pipe.Write([]byte{}); err != nil && err != io.ErrClosedPipe { + return fmt.Errorf("pipe error before commit: %w", err) + } + + if err := pw.pipe.Close(); err != nil { + return err + } + + err := <-pw.responseC + if err != nil { + return err + } + + status, err := pw.tracker.GetStatus(pw.ref) + if err != nil { + return fmt.Errorf("failed to get status: %w", err) + } + + if size > 0 && size != status.Offset { + return fmt.Errorf("unexpected size %d, expected %d", status.Offset, size) + } + status.Committed = true + status.UpdatedAt = time.Now() + pw.tracker.SetStatus(pw.ref, status) + return nil +} + +func (pw *pushWriter) Truncate(size int64) error { + return errors.New("cannot truncate remote upload") +} diff --git a/cmd/convertor/testingresources/local_repo.go b/cmd/convertor/testingresources/local_repo.go new file mode 100644 index 00000000..38ce3074 --- /dev/null +++ b/cmd/convertor/testingresources/local_repo.go @@ -0,0 +1,214 @@ +/* +Copyright The Accelerated Container Image Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testingresources + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "strings" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/opencontainers/go-digest" + v1 "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras-go/v2/content/oci" +) + +// REPOSITORY +type RepoStore struct { + path string + fileStore *oci.Store + inmemoryRepo *inmemoryRepo + opts *RegistryOptions +} + +type inmemoryRepo struct { + blobs map[string][]byte + tags map[string]digest.Digest +} + +// NewRepoStore creates a new repo store. Path provides the filesystem path to the OCI layout store. The +// inmemory component is initialized with an empty store. Both components work together to provide a +// unified view of the repository. +func NewRepoStore(ctx context.Context, path string, opts *RegistryOptions) *RepoStore { + inmemoryRepo := &inmemoryRepo{ + blobs: make(map[string][]byte), + tags: make(map[string]digest.Digest), + } + + return &RepoStore{ + path: path, + opts: opts, + inmemoryRepo: inmemoryRepo, + } +} + +// LoadStore loads the OCI layout store from the provided path +func (r *RepoStore) LoadStore(ctx context.Context) error { + // File Store is already initialized + if r.fileStore != nil { + return nil + } + + if r.opts.InmemoryOnly { + return errors.New("LoadStore should not be invoked if registry is memory only") + } + + if r.path == "" { + return errors.New("LoadStore was not provided a path") + } + + // Load an OCI layout store + store, err := oci.New(r.path) + if err != nil { + return err + } + + r.fileStore = store + return nil +} + +// Resolve resolves a tag to a descriptor +func (r *RepoStore) Resolve(ctx context.Context, tag string) (v1.Descriptor, error) { + if digest, ok := r.inmemoryRepo.tags[tag]; ok { + if blob, ok := r.inmemoryRepo.blobs[digest.String()]; ok { + parsedManifest := v1.Manifest{} + json.Unmarshal(blob, &parsedManifest) + return v1.Descriptor{ + Digest: digest, + Size: int64(len(blob)), + MediaType: parsedManifest.MediaType, + }, nil + } + } + + if !r.opts.InmemoryOnly { + if err := r.LoadStore(ctx); err != nil { + return v1.Descriptor{}, err + } + + return r.fileStore.Resolve(ctx, tag) + } + return v1.Descriptor{}, errdefs.ErrNotFound +} + +// Fetch fetches a blob from the repository +func (r *RepoStore) Fetch(ctx context.Context, descriptor v1.Descriptor) (io.ReadCloser, error) { + if blob, ok := r.inmemoryRepo.blobs[descriptor.Digest.String()]; ok { + return io.NopCloser(bytes.NewReader(blob)), nil + } + + if !r.opts.InmemoryOnly { + if err := r.LoadStore(ctx); err != nil { + return nil, err + } + + content, err := r.fileStore.Fetch(ctx, descriptor) + + if err != nil { + if strings.Contains(err.Error(), "not found") { + return nil, errors.Join(err, errdefs.ErrNotFound) + } + return nil, err + } + return content, nil + } + return nil, errdefs.ErrNotFound +} + +// Exists checks if a blob exists in the repository +func (r *RepoStore) Exists(ctx context.Context, descriptor v1.Descriptor) (bool, error) { + if _, ok := r.inmemoryRepo.blobs[descriptor.Digest.String()]; ok { + return true, nil + } + + if !r.opts.InmemoryOnly { + if err := r.LoadStore(ctx); err != nil { + return false, err + } + + exists, err := r.fileStore.Exists(ctx, descriptor) + + if err != nil { + return false, err + } + + if exists { + return true, nil + } + } + + return false, nil +} + +// Push pushes a blob to the in memory repository. If the blob already exists, it returns an error. +// Tag is optional and can be empty. +func (r *RepoStore) Push(ctx context.Context, desc v1.Descriptor, tag string, content []byte) error { + exists, err := r.Exists(ctx, desc) + if err != nil { + return err + } + if exists { + return nil // No error is returned on push if image is already present + } + isManifest := false + switch desc.MediaType { + case v1.MediaTypeImageManifest, images.MediaTypeDockerSchema2Manifest: + isManifest = true + if r.opts.ManifestPushIgnoresLayers { + break // No layer verification necessary + } + manifest := v1.Manifest{} + json.Unmarshal(content, &manifest) + for _, layer := range manifest.Layers { + exists, err := r.Exists(ctx, layer) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("Layer %s not found", layer.Digest.String()) + } + } + case v1.MediaTypeImageIndex, images.MediaTypeDockerSchema2ManifestList: + isManifest = true + if r.opts.ManifestPushIgnoresLayers { + break // No manifest verification necessary + } + manifestList := v1.Index{} + json.Unmarshal(content, &manifestList) + for _, subManifestDesc := range manifestList.Manifests { + exists, err := r.Exists(ctx, subManifestDesc) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("Sub manifest %s not found", subManifestDesc.Digest.String()) + } + } + } + r.inmemoryRepo.blobs[desc.Digest.String()] = content + + if isManifest && tag != "" { + r.inmemoryRepo.tags[tag] = desc.Digest + } + + return nil +} diff --git a/cmd/convertor/testingresources/mocks/generate.sh b/cmd/convertor/testingresources/mocks/generate.sh new file mode 100755 index 00000000..9ed55832 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/generate.sh @@ -0,0 +1,20 @@ + +# Usage: ./generate.sh +# Prerequisites: skopeo and skopeo login to +# Generates simple hello-world images in ./registry folder + +srcTag="linux" +srcRepo="hello-world" +srcImage="docker.io/library/$srcRepo:$srcTag" +srcRegistry="docker.io/library" +registry=$1 +destFolder="./registry" + +echo "Begin image generation based on src image: $srcImage" + +# Docker +oras cp --to-oci-layout $srcImage $destFolder/hello-world:docker-list +# Tag Some submanifests +oras cp --to-oci-layout --platform linux/arm64 $srcRegistry/hello-world:linux $destFolder/hello-world/:arm64 +oras cp --to-oci-layout --platform linux/amd64 $srcRegistry/hello-world:linux $destFolder/hello-world/:amd64 + diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/004d23c66201b22fce069b7505756f17088de7889c83891e9bc69d749fa3690e b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/004d23c66201b22fce069b7505756f17088de7889c83891e9bc69d749fa3690e new file mode 100644 index 00000000..6c74c418 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/004d23c66201b22fce069b7505756f17088de7889c83891e9bc69d749fa3690e @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1468, + "digest": "sha256:a8117b42328be6ba54c594f9f14e216db10203deb22cc28aaa2c134f9ae2e0fd" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2716, + "digest": "sha256:630da353b594c9ca52c67727920737dba3e5aaa4fbe20cdd0fc70c0591b7a639" + } + ] +} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/06bca41ba617acf0b3644df05d0d9c2d2f82ccaab629c0e39792b24682970040 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/06bca41ba617acf0b3644df05d0d9c2d2f82ccaab629c0e39792b24682970040 new file mode 100644 index 00000000..3765e46f --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/06bca41ba617acf0b3644df05d0d9c2d2f82ccaab629c0e39792b24682970040 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1473, + "digest": "sha256:e4728a982b0acd74e810aeb5e8a5c1bd87f0de7ed93a678d58b3a79e6f7da2e9" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 4065, + "digest": "sha256:4bf3d0e19af8069cca924c84fccd58558900bd382ffbde49778906172aa135fb" + } + ] +} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/084c3bdd1271adc754e2c5f6ba7046f1a2c099597dbd9643592fa8eb99981402 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/084c3bdd1271adc754e2c5f6ba7046f1a2c099597dbd9643592fa8eb99981402 new file mode 100644 index 00000000..72e864d6 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/084c3bdd1271adc754e2c5f6ba7046f1a2c099597dbd9643592fa8eb99981402 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1483, + "digest": "sha256:de23d9589845285bb62b33da594c4a19802fda5b09bb6aef4d00e5e8c747a8df" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 3658, + "digest": "sha256:337a0e31c52265fdbab8ffb4f8922b73f2ea3689cf9970150afee8a5a026db30" + } + ] +} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/337a0e31c52265fdbab8ffb4f8922b73f2ea3689cf9970150afee8a5a026db30 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/337a0e31c52265fdbab8ffb4f8922b73f2ea3689cf9970150afee8a5a026db30 new file mode 100644 index 00000000..d85451c8 Binary files /dev/null and b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/337a0e31c52265fdbab8ffb4f8922b73f2ea3689cf9970150afee8a5a026db30 differ diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/38d49488e3b0689e88335277a18bdc2d03c9b58cb45b79902bf648885e23b9f4 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/38d49488e3b0689e88335277a18bdc2d03c9b58cb45b79902bf648885e23b9f4 new file mode 100644 index 00000000..52e8faf7 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/38d49488e3b0689e88335277a18bdc2d03c9b58cb45b79902bf648885e23b9f4 @@ -0,0 +1 @@ +{"architecture":"arm","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:b428cee5a856e0a27a68a92fdc79e07ce0e679444984d60dc60d09da91d3b256","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"a1cc96094ddc296dcc3e123f4153239d280bb09ade31fdbd6e430d19e9b48d76","container_config":{"Hostname":"a1cc96094ddc","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:b428cee5a856e0a27a68a92fdc79e07ce0e679444984d60dc60d09da91d3b256","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2023-05-04T11:46:35.356328888Z","docker_version":"20.10.23","history":[{"created":"2023-05-04T11:46:35.27781596Z","created_by":"/bin/sh -c #(nop) COPY file:bf40f70af9a56eec54a66883a31493ea31545ec09ad150c432566b5e24b0528c in / "},{"created":"2023-05-04T11:46:35.356328888Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:c8d6fe9d9f8fb6ab6e0d701141d358a8bc40b1d5c46cbdc6fd445371c895b1f6"]},"variant":"v7"} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/4bf3d0e19af8069cca924c84fccd58558900bd382ffbde49778906172aa135fb b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/4bf3d0e19af8069cca924c84fccd58558900bd382ffbde49778906172aa135fb new file mode 100644 index 00000000..71a04f78 Binary files /dev/null and b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/4bf3d0e19af8069cca924c84fccd58558900bd382ffbde49778906172aa135fb differ diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/4f1af0faa5862569c7c76d72b1c8e09ba01f2adeea0a44f8f3758d185e95e918 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/4f1af0faa5862569c7c76d72b1c8e09ba01f2adeea0a44f8f3758d185e95e918 new file mode 100644 index 00000000..b5d09121 Binary files /dev/null and b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/4f1af0faa5862569c7c76d72b1c8e09ba01f2adeea0a44f8f3758d185e95e918 differ diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/5735de2b810bba182986adaf3f0d2e6567697caecbebb5d3f2934d8d37f32d2d b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/5735de2b810bba182986adaf3f0d2e6567697caecbebb5d3f2934d8d37f32d2d new file mode 100644 index 00000000..9bd92551 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/5735de2b810bba182986adaf3f0d2e6567697caecbebb5d3f2934d8d37f32d2d @@ -0,0 +1 @@ +{"architecture":"ppc64le","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:d10f62162101fe360d2292f3163e7d4d07c9bd3a4bbba4a48a4bdccfa622cd5d","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"bf5c33b539ecc0a88ba3448ed5d95fdc587a6fb295347fc31a296286a419aea6","container_config":{"Hostname":"bf5c33b539ec","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:d10f62162101fe360d2292f3163e7d4d07c9bd3a4bbba4a48a4bdccfa622cd5d","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2023-05-04T23:35:14.791724762Z","docker_version":"20.10.23","history":[{"created":"2023-05-04T23:35:14.47386416Z","created_by":"/bin/sh -c #(nop) COPY file:d983edb4c32b67abbd6c309cebc3bf9ace8e1c065505fe8ae03686b5a75a5552 in / "},{"created":"2023-05-04T23:35:14.791724762Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:ac1bc0996cc2106a1e725a10fac1236fb365304b85257f0b82ab950db3bd8880"]}} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/574efe68740d3bee2ef780036aee2e2da5cf7097ac06513f9f01f41e03365399 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/574efe68740d3bee2ef780036aee2e2da5cf7097ac06513f9f01f41e03365399 new file mode 100644 index 00000000..ae7d84dd --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/574efe68740d3bee2ef780036aee2e2da5cf7097ac06513f9f01f41e03365399 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1470, + "digest": "sha256:d549b3d1a2550a5e42a3f3250ce9fa4aa882b25f8528fd2eea1b789ce136631b" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 3265, + "digest": "sha256:d898e3d98788d70a8f874f818177c11569c5bb3c818ef45b877e7bba29a3bf7f" + } + ] +} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/630da353b594c9ca52c67727920737dba3e5aaa4fbe20cdd0fc70c0591b7a639 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/630da353b594c9ca52c67727920737dba3e5aaa4fbe20cdd0fc70c0591b7a639 new file mode 100644 index 00000000..0538fb33 Binary files /dev/null and b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/630da353b594c9ca52c67727920737dba3e5aaa4fbe20cdd0fc70c0591b7a639 differ diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/70f5ac315c5af948332962ff4678084ebcc215809506e4b8cd9e509660417205 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/70f5ac315c5af948332962ff4678084ebcc215809506e4b8cd9e509660417205 new file mode 100644 index 00000000..6ee05062 Binary files /dev/null and b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/70f5ac315c5af948332962ff4678084ebcc215809506e4b8cd9e509660417205 differ diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/719385e32844401d57ecfd3eacab360bf551a1491c05b85806ed8f1b08d792f6 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/719385e32844401d57ecfd3eacab360bf551a1491c05b85806ed8f1b08d792f6 new file mode 100644 index 00000000..e1b49b11 Binary files /dev/null and b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/719385e32844401d57ecfd3eacab360bf551a1491c05b85806ed8f1b08d792f6 differ diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/726023f73a8fc5103fa6776d48090539042cb822531c6b751b1f6dd18cb5705d b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/726023f73a8fc5103fa6776d48090539042cb822531c6b751b1f6dd18cb5705d new file mode 100644 index 00000000..684c8f2e --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/726023f73a8fc5103fa6776d48090539042cb822531c6b751b1f6dd18cb5705d @@ -0,0 +1 @@ +{"manifests":[{"digest":"sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"amd64","os":"linux"},"size":525},{"digest":"sha256:084c3bdd1271adc754e2c5f6ba7046f1a2c099597dbd9643592fa8eb99981402","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"arm","os":"linux","variant":"v5"},"size":525},{"digest":"sha256:a0a386314d69d1514d7aa63d12532b284bf37bba15ed7b4fc1a3f86605f86c63","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"arm","os":"linux","variant":"v7"},"size":525},{"digest":"sha256:efebf0f7aee69450f99deafe11121afa720abed733943e50581a9dc7540689c8","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"arm64","os":"linux","variant":"v8"},"size":525},{"digest":"sha256:004d23c66201b22fce069b7505756f17088de7889c83891e9bc69d749fa3690e","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"386","os":"linux"},"size":525},{"digest":"sha256:06bca41ba617acf0b3644df05d0d9c2d2f82ccaab629c0e39792b24682970040","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"mips64le","os":"linux"},"size":525},{"digest":"sha256:fbe0ff1e7697da39d987a975c737a7d2fa40b6e7f7f40c00b1dcc387b9ac0e85","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"ppc64le","os":"linux"},"size":525},{"digest":"sha256:72ba79e34f1baa40cd4d9ecd684b8389d0a1e18cf6e6d5c44c19716d25f65e20","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"riscv64","os":"linux"},"size":525},{"digest":"sha256:574efe68740d3bee2ef780036aee2e2da5cf7097ac06513f9f01f41e03365399","mediaType":"application\/vnd.docker.distribution.manifest.v2+json","platform":{"architecture":"s390x","os":"linux"},"size":525}],"mediaType":"application\/vnd.docker.distribution.manifest.list.v2+json","schemaVersion":2} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/72ba79e34f1baa40cd4d9ecd684b8389d0a1e18cf6e6d5c44c19716d25f65e20 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/72ba79e34f1baa40cd4d9ecd684b8389d0a1e18cf6e6d5c44c19716d25f65e20 new file mode 100644 index 00000000..0cc18849 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/72ba79e34f1baa40cd4d9ecd684b8389d0a1e18cf6e6d5c44c19716d25f65e20 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1472, + "digest": "sha256:eb6f80695a28848498afd1eb4f9e12caeeae15f3ea5f39e1427c828f8fb38e5f" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2976, + "digest": "sha256:b102dd09f2b38103852530d8d5288ceb6779bcf33b4a453c10ac4d79fb083651" + } + ] +} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3 new file mode 100644 index 00000000..3191185f --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1470, + "digest": "sha256:9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2457, + "digest": "sha256:719385e32844401d57ecfd3eacab360bf551a1491c05b85806ed8f1b08d792f6" + } + ] +} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d new file mode 100644 index 00000000..4460e125 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d @@ -0,0 +1 @@ +{"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:62a15619037f3c4fb4e6ba9bd224cba3540e393a55dc52f6bebe212ca7b5e1a7","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"347ca68872ee924c4f9394b195dcadaf591d387a45d624225251efc6cb7a348e","container_config":{"Hostname":"347ca68872ee","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:62a15619037f3c4fb4e6ba9bd224cba3540e393a55dc52f6bebe212ca7b5e1a7","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2023-05-04T17:37:03.872958712Z","docker_version":"20.10.23","history":[{"created":"2023-05-04T17:37:03.801840823Z","created_by":"/bin/sh -c #(nop) COPY file:201f8f1849e89d53be9f6aa76937f5e209d745abfd15a8552fcf2ba45ab267f9 in / "},{"created":"2023-05-04T17:37:03.872958712Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:01bb4fce3eb1b56b05adf99504dafd31907a5aadac736e36b27595c8b92f07f1"]}} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/a0a386314d69d1514d7aa63d12532b284bf37bba15ed7b4fc1a3f86605f86c63 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/a0a386314d69d1514d7aa63d12532b284bf37bba15ed7b4fc1a3f86605f86c63 new file mode 100644 index 00000000..779d69f2 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/a0a386314d69d1514d7aa63d12532b284bf37bba15ed7b4fc1a3f86605f86c63 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1482, + "digest": "sha256:38d49488e3b0689e88335277a18bdc2d03c9b58cb45b79902bf648885e23b9f4" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2979, + "digest": "sha256:c4018b8bf4381a79e05c15591e1a1adf4452a9d383c4dcb63b1b7d4617d73af8" + } + ] +} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/a8117b42328be6ba54c594f9f14e216db10203deb22cc28aaa2c134f9ae2e0fd b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/a8117b42328be6ba54c594f9f14e216db10203deb22cc28aaa2c134f9ae2e0fd new file mode 100644 index 00000000..b9c02a21 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/a8117b42328be6ba54c594f9f14e216db10203deb22cc28aaa2c134f9ae2e0fd @@ -0,0 +1 @@ +{"architecture":"386","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:f21e55e51b02da347e5fc02f6e732997f4e0d8c8b7cb5b1359b51412c0538003","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"7e7ed95b255ae6284e5c7104fb101b1bc24e8e906232984227b7c3f785337b7c","container_config":{"Hostname":"7e7ed95b255a","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:f21e55e51b02da347e5fc02f6e732997f4e0d8c8b7cb5b1359b51412c0538003","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2023-05-04T05:56:18.664081874Z","docker_version":"20.10.23","history":[{"created":"2023-05-04T05:56:18.563912865Z","created_by":"/bin/sh -c #(nop) COPY file:228838c88f804dd6c5bd18ef2380612177731c208f251810fa950e1bc8527467 in / "},{"created":"2023-05-04T05:56:18.664081874Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:71fa18497d9fad69ff5100f14054d4d6eb3660c3ee306906ca592bac083c8c0e"]}} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/b038788ddb222cb7d6025b411759e4f5abe9910486c8f98534ead97befd77dd7 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/b038788ddb222cb7d6025b411759e4f5abe9910486c8f98534ead97befd77dd7 new file mode 100644 index 00000000..1e9e394c --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/b038788ddb222cb7d6025b411759e4f5abe9910486c8f98534ead97befd77dd7 @@ -0,0 +1 @@ +{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:80d5abfa0241246d5bf678c139e16ee47a1e70eb57b29fd414dd4f0b36d34ed8","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"9388ffe1ee206146f45b0716291ad77e94686218696a0f140a90a957a38e21ef","container_config":{"Hostname":"9388ffe1ee20","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:80d5abfa0241246d5bf678c139e16ee47a1e70eb57b29fd414dd4f0b36d34ed8","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2023-05-04T08:43:21.769453191Z","docker_version":"20.10.23","history":[{"created":"2023-05-04T08:43:21.705077487Z","created_by":"/bin/sh -c #(nop) COPY file:f56689f2cf47e7530b9a14ed69e80d2ce38371866c8776256c24d80d148ff825 in / "},{"created":"2023-05-04T08:43:21.769453191Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a7866053acacfefb68912a8916b67d6847c12b51949c6b8a5580c6609c08ae45"]},"variant":"v8"} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/b102dd09f2b38103852530d8d5288ceb6779bcf33b4a453c10ac4d79fb083651 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/b102dd09f2b38103852530d8d5288ceb6779bcf33b4a453c10ac4d79fb083651 new file mode 100644 index 00000000..6da3d065 Binary files /dev/null and b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/b102dd09f2b38103852530d8d5288ceb6779bcf33b4a453c10ac4d79fb083651 differ diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/c4018b8bf4381a79e05c15591e1a1adf4452a9d383c4dcb63b1b7d4617d73af8 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/c4018b8bf4381a79e05c15591e1a1adf4452a9d383c4dcb63b1b7d4617d73af8 new file mode 100644 index 00000000..8d20e0cf Binary files /dev/null and b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/c4018b8bf4381a79e05c15591e1a1adf4452a9d383c4dcb63b1b7d4617d73af8 differ diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/d549b3d1a2550a5e42a3f3250ce9fa4aa882b25f8528fd2eea1b789ce136631b b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/d549b3d1a2550a5e42a3f3250ce9fa4aa882b25f8528fd2eea1b789ce136631b new file mode 100644 index 00000000..14c43d32 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/d549b3d1a2550a5e42a3f3250ce9fa4aa882b25f8528fd2eea1b789ce136631b @@ -0,0 +1 @@ +{"architecture":"s390x","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:0a4ed120e12f159b468ae1fbdf6d7e2c053fd5547f6ad1e12019283e425a4f0c","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"16de42fe001ec70d74120e5db0a765dc7cf960bc3ecdfdd23fe034dac2b12962","container_config":{"Hostname":"16de42fe001e","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:0a4ed120e12f159b468ae1fbdf6d7e2c053fd5547f6ad1e12019283e425a4f0c","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2023-05-05T06:04:49.524781092Z","docker_version":"20.10.23","history":[{"created":"2023-05-05T06:04:49.407407092Z","created_by":"/bin/sh -c #(nop) COPY file:2412b45fdbb28b2191d4b0d59a4c66e460863549bae786d0aaf49c123b876e0b in / "},{"created":"2023-05-05T06:04:49.524781092Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:3aced21b93452b84cf84067c6ef10ea4a4841f8ca36a18300504f9b408f0082f"]}} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/d898e3d98788d70a8f874f818177c11569c5bb3c818ef45b877e7bba29a3bf7f b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/d898e3d98788d70a8f874f818177c11569c5bb3c818ef45b877e7bba29a3bf7f new file mode 100644 index 00000000..1f7906e9 Binary files /dev/null and b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/d898e3d98788d70a8f874f818177c11569c5bb3c818ef45b877e7bba29a3bf7f differ diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/de23d9589845285bb62b33da594c4a19802fda5b09bb6aef4d00e5e8c747a8df b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/de23d9589845285bb62b33da594c4a19802fda5b09bb6aef4d00e5e8c747a8df new file mode 100644 index 00000000..1cd079a3 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/de23d9589845285bb62b33da594c4a19802fda5b09bb6aef4d00e5e8c747a8df @@ -0,0 +1 @@ +{"architecture":"arm","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:3a7d6bbfa313f2c4ebb372d8db938b3fabc10d1843e47d88ab3eeebed171ae59","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"ef67c81477122128426ed18ce8bfea148aae5c7e560b8aabe9e9608a71e43468","container_config":{"Hostname":"ef67c8147712","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:3a7d6bbfa313f2c4ebb372d8db938b3fabc10d1843e47d88ab3eeebed171ae59","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2023-05-03T22:48:45.064468815Z","docker_version":"20.10.23","history":[{"created":"2023-05-03T22:48:44.585409244Z","created_by":"/bin/sh -c #(nop) COPY file:7df2eb05fc4f800f8ec9f08c58b4b76c2309d1d066bbb12db0f513480bd0a58f in / "},{"created":"2023-05-03T22:48:45.064468815Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:e0558fdde929b43545f3d356da59c2b877dac23a836501975b8d187d2f8aeaf0"]},"variant":"v5"} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/e4728a982b0acd74e810aeb5e8a5c1bd87f0de7ed93a678d58b3a79e6f7da2e9 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/e4728a982b0acd74e810aeb5e8a5c1bd87f0de7ed93a678d58b3a79e6f7da2e9 new file mode 100644 index 00000000..b4ae4eea --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/e4728a982b0acd74e810aeb5e8a5c1bd87f0de7ed93a678d58b3a79e6f7da2e9 @@ -0,0 +1 @@ +{"architecture":"mips64le","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:055f6f260e8a9010f1749aec3bf7b31607ac2bad9a71efc0d46cc65c3f8f85e2","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"c508647c03f03d4f3316b2c7b5aa9414807547ddc28c9222c8bf5ec923fee7ba","container_config":{"Hostname":"c508647c03f0","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:055f6f260e8a9010f1749aec3bf7b31607ac2bad9a71efc0d46cc65c3f8f85e2","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2023-05-04T16:39:55.753058102Z","docker_version":"20.10.23","history":[{"created":"2023-05-04T16:39:54.174773277Z","created_by":"/bin/sh -c #(nop) COPY file:c4f860518106986675ada896e1418193ce3a20128315306f91e75f3a73a2993e in / "},{"created":"2023-05-04T16:39:55.753058102Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:ac81192890ade5849cdfceda04ba3bb672c3ff78d22a56a3d62c69304346d2dd"]}} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/eb6f80695a28848498afd1eb4f9e12caeeae15f3ea5f39e1427c828f8fb38e5f b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/eb6f80695a28848498afd1eb4f9e12caeeae15f3ea5f39e1427c828f8fb38e5f new file mode 100644 index 00000000..c0ac0207 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/eb6f80695a28848498afd1eb4f9e12caeeae15f3ea5f39e1427c828f8fb38e5f @@ -0,0 +1 @@ +{"architecture":"riscv64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:e49a60172bde032c6acee9573c6c6862161cdd81679ac04be3222df964e476cb","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"d1030c0984bdd994cca44f1832ec5f9630879484e0d20bb400583ab130587e0b","container_config":{"Hostname":"d1030c0984bd","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:e49a60172bde032c6acee9573c6c6862161cdd81679ac04be3222df964e476cb","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2023-05-03T23:08:38.909796734Z","docker_version":"20.10.17","history":[{"created":"2023-05-03T23:08:38.382314898Z","created_by":"/bin/sh -c #(nop) COPY file:85aecc4e10d311916d976ca1efd6561da1bb16c0d6ae089b7e9b78f5d0967acc in / "},{"created":"2023-05-03T23:08:38.909796734Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:4a72d706a8b7a23ce9d3137fd2a92ee180382acaf4a4fc3a099de96c059c3575"]}} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/efebf0f7aee69450f99deafe11121afa720abed733943e50581a9dc7540689c8 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/efebf0f7aee69450f99deafe11121afa720abed733943e50581a9dc7540689c8 new file mode 100644 index 00000000..5aafebf6 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/efebf0f7aee69450f99deafe11121afa720abed733943e50581a9dc7540689c8 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1485, + "digest": "sha256:b038788ddb222cb7d6025b411759e4f5abe9910486c8f98534ead97befd77dd7" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 3190, + "digest": "sha256:70f5ac315c5af948332962ff4678084ebcc215809506e4b8cd9e509660417205" + } + ] +} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/fbe0ff1e7697da39d987a975c737a7d2fa40b6e7f7f40c00b1dcc387b9ac0e85 b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/fbe0ff1e7697da39d987a975c737a7d2fa40b6e7f7f40c00b1dcc387b9ac0e85 new file mode 100644 index 00000000..8c38c734 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/blobs/sha256/fbe0ff1e7697da39d987a975c737a7d2fa40b6e7f7f40c00b1dcc387b9ac0e85 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 1471, + "digest": "sha256:5735de2b810bba182986adaf3f0d2e6567697caecbebb5d3f2934d8d37f32d2d" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 3922, + "digest": "sha256:4f1af0faa5862569c7c76d72b1c8e09ba01f2adeea0a44f8f3758d185e95e918" + } + ] +} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/index.json b/cmd/convertor/testingresources/mocks/registry/hello-world/index.json new file mode 100644 index 00000000..1be052e7 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/index.json @@ -0,0 +1,103 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", + "digest": "sha256:726023f73a8fc5103fa6776d48090539042cb822531c6b751b1f6dd18cb5705d", + "size": 2069, + "annotations": { + "org.opencontainers.image.ref.name": "docker-list" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3", + "size": 525, + "annotations": { + "org.opencontainers.image.ref.name": "amd64" + }, + "platform": { + "architecture": "amd64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:efebf0f7aee69450f99deafe11121afa720abed733943e50581a9dc7540689c8", + "size": 525, + "annotations": { + "org.opencontainers.image.ref.name": "arm64" + }, + "platform": { + "architecture": "arm64", + "os": "linux", + "variant": "v8" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:06bca41ba617acf0b3644df05d0d9c2d2f82ccaab629c0e39792b24682970040", + "size": 525, + "platform": { + "architecture": "mips64le", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:fbe0ff1e7697da39d987a975c737a7d2fa40b6e7f7f40c00b1dcc387b9ac0e85", + "size": 525, + "platform": { + "architecture": "ppc64le", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:084c3bdd1271adc754e2c5f6ba7046f1a2c099597dbd9643592fa8eb99981402", + "size": 525, + "platform": { + "architecture": "arm", + "os": "linux", + "variant": "v5" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:004d23c66201b22fce069b7505756f17088de7889c83891e9bc69d749fa3690e", + "size": 525, + "platform": { + "architecture": "386", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:72ba79e34f1baa40cd4d9ecd684b8389d0a1e18cf6e6d5c44c19716d25f65e20", + "size": 525, + "platform": { + "architecture": "riscv64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:574efe68740d3bee2ef780036aee2e2da5cf7097ac06513f9f01f41e03365399", + "size": 525, + "platform": { + "architecture": "s390x", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:a0a386314d69d1514d7aa63d12532b284bf37bba15ed7b4fc1a3f86605f86c63", + "size": 525, + "platform": { + "architecture": "arm", + "os": "linux", + "variant": "v7" + } + } + ] +} \ No newline at end of file diff --git a/cmd/convertor/testingresources/mocks/registry/hello-world/oci-layout b/cmd/convertor/testingresources/mocks/registry/hello-world/oci-layout new file mode 100644 index 00000000..1343d370 --- /dev/null +++ b/cmd/convertor/testingresources/mocks/registry/hello-world/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion":"1.0.0"} \ No newline at end of file diff --git a/cmd/convertor/testingresources/serialize.go b/cmd/convertor/testingresources/serialize.go new file mode 100644 index 00000000..92f5be20 --- /dev/null +++ b/cmd/convertor/testingresources/serialize.go @@ -0,0 +1,110 @@ +/* +Copyright The Accelerated Container Image Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testingresources + +import ( + "encoding/json" + "errors" + + "github.com/containerd/containerd/images" + "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/specs-go" + v1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +// Docker images seem to be created with descriptors whose order +// matches mediaType -> size -> digest, oci images seem to be created with descriptors +// whose order matches mediaType -> digest -> size. Json marshalling in golang will +// result in the previous version of the descriptor given the order of the fields defined +// in the struct. This is why we need to provide a custom descriptor marshalling function +// for docker images. + +type DockerDescriptor struct { + // MediaType is the media type of the object this schema refers to. + MediaType string `json:"mediaType,omitempty"` + + // Size specifies the size in bytes of the blob. + Size int64 `json:"size"` + + // Digest is the digest of the targeted content. + Digest digest.Digest `json:"digest"` + + // URLs specifies a list of URLs from which this object MAY be downloaded + URLs []string `json:"urls,omitempty"` + + // Annotations contains arbitrary metadata relating to the targeted content. + Annotations map[string]string `json:"annotations,omitempty"` + + // Data is an embedding of the targeted content. This is encoded as a base64 + // string when marshalled to JSON (automatically, by encoding/json). If + // present, Data can be used directly to avoid fetching the targeted content. + Data []byte `json:"data,omitempty"` + + // Platform describes the platform which the image in the manifest runs on. + // + // This should only be used when referring to a manifest. + Platform *v1.Platform `json:"platform,omitempty"` + + // ArtifactType is the IANA media type of this artifact. + ArtifactType string `json:"artifactType,omitempty"` +} + +type DockerManifest struct { + specs.Versioned + + // MediaType specifies the type of this document data structure e.g. `application/vnd.oci.image.manifest.v1+json` + MediaType string `json:"mediaType,omitempty"` + + // Config references a configuration object for a container, by digest. + // The referenced configuration object is a JSON blob that the runtime uses to set up the container. + Config DockerDescriptor `json:"config"` + + // Layers is an indexed list of layers referenced by the manifest. + Layers []DockerDescriptor `json:"layers"` + + // Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest. + Subject *DockerDescriptor `json:"subject,omitempty"` + + // Annotations contains arbitrary metadata for the image manifest. + Annotations map[string]string `json:"annotations,omitempty"` +} + +func ConsistentManifestMarshal(manifest *v1.Manifest) ([]byte, error) { + // If OCI Manifest + if manifest.MediaType == v1.MediaTypeImageManifest { + return json.MarshalIndent(manifest, "", " ") + } + + if manifest.MediaType != images.MediaTypeDockerSchema2Manifest { + return nil, errors.New("unsupported manifest media type") + } + + // If Docker Manifest + content, err := json.Marshal(manifest) + if err != nil { + return nil, err + } + + // Remarshal from dockerManifest Struct + var dockerManifest DockerManifest + err = json.Unmarshal(content, &dockerManifest) + if err != nil { + return nil, err + } + + return json.MarshalIndent(dockerManifest, "", " ") +} diff --git a/cmd/convertor/testingresources/test_utils.go b/cmd/convertor/testingresources/test_utils.go new file mode 100644 index 00000000..82f25bcd --- /dev/null +++ b/cmd/convertor/testingresources/test_utils.go @@ -0,0 +1,103 @@ +/* +Copyright The Accelerated Container Image Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testingresources + +import ( + "context" + "os" + "path" + "path/filepath" + "testing" + + "github.com/containerd/containerd/pkg/testutil" + "github.com/containerd/containerd/remotes" +) + +func GetLocalRegistryPath() string { + cwd, err := os.Getwd() + if err != nil { + panic(err) + } + return path.Join(cwd, "..", "testingresources", "mocks", "registry") +} + +// GetTestRegistry returns a TestRegistry with the specified options. If opts.LocalRegistryPath is not specified, +// the default local registry path will be used. +func GetTestRegistry(t *testing.T, ctx context.Context, opts RegistryOptions) *TestRegistry { + if opts.LocalRegistryPath == "" { + opts.LocalRegistryPath = GetLocalRegistryPath() + } + reg, err := NewTestRegistry(ctx, opts) + if err != nil { + t.Error(err) + } + return reg +} + +func GetTestResolver(t *testing.T, ctx context.Context) remotes.Resolver { + localRegistryPath := GetLocalRegistryPath() + resolver, err := NewMockLocalResolver(ctx, localRegistryPath) + if err != nil { + t.Error(err) + } + return resolver +} + +func GetCustomTestResolver(t *testing.T, ctx context.Context, testRegistry *TestRegistry) remotes.Resolver { + resolver, err := NewCustomMockLocalResolver(ctx, testRegistry) + if err != nil { + t.Error(err) + } + return resolver +} + +func GetTestFetcherFromResolver(t *testing.T, ctx context.Context, resolver remotes.Resolver, ref string) remotes.Fetcher { + fetcher, err := resolver.Fetcher(ctx, ref) + if err != nil { + t.Error(err) + } + return fetcher +} + +func GetTestPusherFromResolver(t *testing.T, ctx context.Context, resolver remotes.Resolver, ref string) remotes.Pusher { + pusher, err := resolver.Pusher(ctx, ref) + if err != nil { + t.Error(err) + } + return pusher +} + +func Assert(t *testing.T, condition bool, msg string) { + if !condition { + t.Error(msg) + } +} + +// RunTestWithTempDir runs the specified test function with a temporary writable directory. +func RunTestWithTempDir(t *testing.T, ctx context.Context, name string, testFn func(t *testing.T, ctx context.Context, tmpDir string)) { + tmpDir := t.TempDir() + + work := filepath.Join(tmpDir, "work") + if err := os.MkdirAll(work, 0777); err != nil { + t.Fatal(err) + } + + defer testutil.DumpDirOnFailure(t, tmpDir) + t.Run(name, func(t *testing.T) { + testFn(t, ctx, work) + }) +} diff --git a/go.mod b/go.mod index 306b0ca4..05985020 100644 --- a/go.mod +++ b/go.mod @@ -8,27 +8,28 @@ require ( github.com/containerd/go-cni v1.1.5 github.com/go-sql-driver/mysql v1.6.0 github.com/moby/locker v1.0.1 - github.com/moby/sys/mountinfo v0.5.0 + github.com/moby/sys/mountinfo v0.6.2 github.com/opencontainers/go-digest v1.0.0 - github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 - github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 + github.com/opencontainers/image-spec v1.1.0-rc2 + github.com/opencontainers/runtime-spec v1.1.0-rc.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 - github.com/sirupsen/logrus v1.8.1 + github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.1.3 - github.com/urfave/cli v1.22.2 - golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a - google.golang.org/grpc v1.43.0 + github.com/urfave/cli v1.22.12 + golang.org/x/sync v0.1.0 + golang.org/x/sys v0.7.0 + google.golang.org/grpc v1.54.0 + oras.land/oras-go/v2 v2.1.0 ) require ( - github.com/Microsoft/go-winio v0.5.1 // indirect - github.com/Microsoft/hcsshim v0.9.2 // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/Microsoft/hcsshim v0.9.8 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cilium/ebpf v0.7.0 // indirect - github.com/containerd/cgroups v1.0.3 // indirect + github.com/containerd/cgroups v1.0.4 // indirect github.com/containerd/console v1.0.3 // indirect github.com/containerd/fifo v1.0.0 // indirect github.com/containerd/go-runc v1.0.0 // indirect @@ -37,37 +38,41 @@ require ( github.com/containernetworking/cni v1.1.0 // indirect github.com/containernetworking/plugins v1.1.1 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect - github.com/docker/go-units v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/godbus/dbus/v5 v5.0.6 // indirect github.com/gogo/googleapis v1.4.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/google/go-cmp v0.5.8 // indirect - github.com/google/uuid v1.2.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/klauspost/compress v1.15.9 // indirect + github.com/klauspost/compress v1.16.3 // indirect + github.com/kr/pretty v0.3.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/moby/sys/signal v0.6.0 // indirect github.com/moby/sys/symlink v0.2.0 // indirect - github.com/opencontainers/runc v1.1.1 // indirect - github.com/opencontainers/selinux v1.10.1 // indirect + github.com/opencontainers/runc v1.1.5 // indirect + github.com/opencontainers/selinux v1.11.0 // indirect github.com/pelletier/go-toml v1.9.3 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - github.com/russross/blackfriday/v2 v2.0.1 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - go.etcd.io/bbolt v1.3.6 // indirect - go.opencensus.io v0.23.0 // indirect - golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect - golang.org/x/text v0.3.7 // indirect - google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect - google.golang.org/protobuf v1.28.1 // indirect - gotest.tools/v3 v3.0.3 // indirect + github.com/stretchr/testify v1.8.2 // indirect + go.etcd.io/bbolt v1.3.7 // indirect + go.opencensus.io v0.24.0 // indirect + golang.org/x/mod v0.9.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/tools v0.6.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gotest.tools/v3 v3.4.0 // indirect ) // v0.5.2 was retagged: 71d70d4e738679154f62e2869e94784558cb9b36 -> fd022b910830015d8665a7b497f47bba1f90dd18 diff --git a/go.sum b/go.sum index a35356df..a1eb78fb 100644 --- a/go.sum +++ b/go.sum @@ -47,6 +47,7 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935 github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= @@ -56,8 +57,9 @@ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugX github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= @@ -66,8 +68,8 @@ github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2 github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= -github.com/Microsoft/hcsshim v0.9.2 h1:wB06W5aYFfUB3IvootYAY2WnOmIdgPGfqSI6tufQNnY= -github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.8 h1:lf7xxK2+Ikbj9sVf2QZsouGjRjEp2STj1yDHgoVtU5k= +github.com/Microsoft/hcsshim v0.9.8/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= @@ -111,8 +113,9 @@ github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInq github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= @@ -129,11 +132,7 @@ github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2u github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= @@ -149,8 +148,8 @@ github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4S github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= -github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4= -github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= +github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA= +github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= @@ -255,8 +254,9 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= @@ -285,8 +285,9 @@ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -300,7 +301,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -391,8 +391,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -407,8 +408,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -426,8 +427,9 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= @@ -499,16 +501,17 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -548,8 +551,9 @@ github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/signal v0.6.0 h1:aDpY94H8VlhTGa9sNYUFCFsMZIUh5wm0B6XkIoJj/iY= github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= @@ -606,30 +610,31 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= -github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= +github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= -github.com/opencontainers/runc v1.1.1 h1:PJ9DSs2sVwE0iVr++pAHE6QkS9tzcVWozlPifdwMgrU= -github.com/opencontainers/runc v1.1.1/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= +github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.1.0-rc.1 h1:wHa9jroFfKGQqFHj0I1fMRKLl0pfj+ynAqBxo3v6u9w= +github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opencontainers/selinux v1.10.1 h1:09LIPVRP3uuZGQvgR+SgMSNBd1Eb3vlRbGqQpoHsF8w= -github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= +github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= @@ -690,16 +695,19 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= -github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= @@ -708,8 +716,9 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -736,16 +745,22 @@ github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -758,8 +773,9 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8= +github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= @@ -784,8 +800,9 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -793,13 +810,12 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -847,6 +863,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -896,8 +914,9 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -916,8 +935,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -987,6 +1006,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1000,8 +1020,10 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1010,10 +1032,10 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1074,8 +1096,10 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1138,8 +1162,8 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1160,8 +1184,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= -google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1175,8 +1199,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1208,11 +1232,13 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1250,6 +1276,8 @@ k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +oras.land/oras-go/v2 v2.1.0 h1:1nS8BIeEP6CBVQifwxrsth2bkuD+cYfjp7Hf7smUcS8= +oras.land/oras-go/v2 v2.1.0/go.mod h1:v5ZSAPIMEJYnZjZ6rTGPAyaonH+rCFmbE95IAzCTeGU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=