From 8de564e62e665e7601416a61c07452197fff964a Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Wed, 3 May 2023 13:47:53 +0200 Subject: [PATCH] push to docker registry --- cmd/container.go | 85 ++++++++++++++++++++++++++++++++++++++++++++---- cmd/static.go | 14 ++++---- go.mod | 3 +- go.sum | 2 ++ 4 files changed, 88 insertions(+), 16 deletions(-) diff --git a/cmd/container.go b/cmd/container.go index 5810a1a..856bbc2 100644 --- a/cmd/container.go +++ b/cmd/container.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "net/http" "os" "path" "path/filepath" @@ -15,6 +16,13 @@ import ( "strings" "time" + "github.com/docker/cli/cli/config" + + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/layout" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/containers/image/v5/copy" "github.com/containers/image/v5/signature" "github.com/containers/image/v5/transports/alltransports" @@ -27,6 +35,27 @@ var pctx *signature.PolicyContext const distributionPrefix = "v2" +//--- +//--- vendored from crane +// headerTransport sets headers on outgoing requests. +type headerTransport struct { + httpHeaders map[string]string + inner http.RoundTripper +} + +// RoundTrip implements http.RoundTripper. +func (ht *headerTransport) RoundTrip(in *http.Request) (*http.Response, error) { + for k, v := range ht.httpHeaders { + if http.CanonicalHeaderKey(k) == "User-Agent" { + // Docker sets this, which is annoying, since we're not docker. + // We might want to revisit completely ignoring this. + continue + } + in.Header.Set(k, v) + } + return ht.inner.RoundTrip(in) +} + //--- //--- Image converter type OCIImageManifest struct { @@ -345,6 +374,40 @@ func (o *OCIMultiArch) MergeSystemImages() error { return nil } +func (o *OCIMultiArch) UploadImageRegistry(tag string) error { + fmt.Println("--- push to registry ---") + multiArchRoot := filepath.Join(o.path, "multi") + + img, err := layout.ImageIndexFromPath(multiArchRoot) + if err != nil { + return fmt.Errorf("loading %s as OCI layout: %w", multiArchRoot, err) + } + + ref, err := name.ParseReference(tag) + if err != nil { + return err + } + + // Build transport + transport := remote.DefaultTransport.(*http.Transport).Clone() + var rt http.RoundTripper = transport + cf, err := config.Load(os.Getenv("DOCKER_CONFIG")) + if err != nil { + fmt.Printf("failed to read config file: %v", err) + } else if len(cf.HTTPHeaders) != 0 { + rt = &headerTransport{ + inner: rt, + httpHeaders: cf.HTTPHeaders, + } + } + + if err := remote.WriteIndex(ref, img, remote.WithTransport(rt), remote.WithAuthFromKeychain(authn.DefaultKeychain)); err != nil { + return err + } + + return nil +} + func (o *OCIMultiArch) UploadImageS3(buck *blob.Bucket) error { fmt.Printf("-- push to the s3 target --\n") @@ -466,13 +529,13 @@ func (o *OCIMultiArch) UploadImageS3(buck *blob.Bucket) error { } type StaticRegistryManager struct { - name string - buck *blob.Bucket + name string + buck *blob.Bucket images []ImageDescriptor } type ImageDescriptor struct { - Tag string + Tag string Date time.Time } @@ -515,8 +578,8 @@ func (l *StaticRegistryManager) Scan() error { // we ignore sha256 addressed manifests continue } - id := ImageDescriptor { - Tag: fname, + id := ImageDescriptor{ + Tag: fname, Date: obj.ModTime, } l.images = append(l.images, id) @@ -531,7 +594,7 @@ func (l *StaticRegistryManager) TagList() TagList { }) // Build tagList - tagList := TagList { + tagList := TagList{ Name: l.name, } for _, img := range l.images { @@ -584,6 +647,9 @@ var containerPublishCmd = &cobra.Command{ localPath := args[0] remotePath := args[1] + dockerProto := "docker://" + dockerProtoCut := len(dockerProto) + oi, err := NewOCIMultiArch(containerTag) if err != nil { fmt.Println(err) @@ -601,7 +667,7 @@ var containerPublishCmd = &cobra.Command{ os.Exit(1) } - if strings.HasPrefix(remotePath, "s3:") { + if strings.HasPrefix(remotePath, "s3://") { // open bucket bucket, err := blob.OpenBucket(context.Background(), remotePath) if err != nil { @@ -621,6 +687,11 @@ var containerPublishCmd = &cobra.Command{ fmt.Println(err) os.Exit(1) } + } else if strings.HasPrefix(remotePath, dockerProto) { + if err = oi.UploadImageRegistry(remotePath[dockerProtoCut:]); err != nil { + fmt.Println(err) + os.Exit(1) + } } else { fmt.Printf("Protocol not supported for remote path %s. Supported transports are s3:// and docker://\n", remotePath) os.Exit(1) diff --git a/cmd/static.go b/cmd/static.go index ea217f5..2d4bdea 100644 --- a/cmd/static.go +++ b/cmd/static.go @@ -181,12 +181,12 @@ func (a *Artifact) Upload(buck *blob.Bucket) error { //--- Manage uploaded artifacts, list them, etc. type ArtifactDescriptor struct { - Tag string + Tag string Date time.Time } type ArtifactManager struct { - name string - buck *blob.Bucket + name string + buck *blob.Bucket artifacts []ArtifactDescriptor } @@ -197,7 +197,6 @@ func NewArtifactManager(buck *blob.Bucket, name string) *ArtifactManager { } } - func (am *ArtifactManager) Scan() error { iter := am.buck.List(&blob.ListOptions{ Prefix: fmt.Sprintf("df-dist-v1/%s/", am.name), @@ -221,8 +220,8 @@ func (am *ArtifactManager) Scan() error { } fname := ksplit[len(ksplit)-1] - ad := ArtifactDescriptor { - Tag: fname, + ad := ArtifactDescriptor{ + Tag: fname, Date: obj.ModTime, } @@ -238,7 +237,7 @@ func (am *ArtifactManager) TagList() TagList { }) // Build tagList - tagList := TagList { + tagList := TagList{ Name: am.name, } for _, art := range am.artifacts { @@ -247,7 +246,6 @@ func (am *ArtifactManager) TagList() TagList { return tagList } - func (am *ArtifactManager) UpdateTagList() error { fmt.Printf("--- update taglist ---\n") diff --git a/go.mod b/go.mod index a5d7410..0027ecd 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,8 @@ require ( code.gitea.io/sdk/gitea v0.15.1 github.com/caarlos0/env/v7 v7.1.0 github.com/containers/image/v5 v5.25.0 + github.com/docker/cli v20.10.20+incompatible + github.com/google/go-containerregistry v0.13.0 github.com/hashicorp/consul/api v1.20.0 github.com/hashicorp/nomad/api v0.0.0-20230314144600-1a01e8719272 github.com/spf13/cobra v1.7.0 @@ -67,7 +69,6 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/go-containerregistry v0.13.0 // indirect github.com/google/go-intervals v0.0.2 // indirect github.com/google/uuid v1.3.0 // indirect github.com/google/wire v0.5.0 // indirect diff --git a/go.sum b/go.sum index 09926e9..aa9341c 100644 --- a/go.sum +++ b/go.sum @@ -847,6 +847,8 @@ github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyG github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.20+incompatible h1:lWQbHSHUFs7KraSN2jOJK7zbMS2jNCHI4mt4xUFUVQ4= +github.com/docker/cli v20.10.20+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=