push to docker registry

This commit is contained in:
Quentin 2023-05-03 13:47:53 +02:00
parent 559506c170
commit 8de564e62e
Signed by: quentin
GPG Key ID: E9602264D639FF68
4 changed files with 88 additions and 16 deletions

View File

@ -7,6 +7,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"net/http"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -15,6 +16,13 @@ import (
"strings" "strings"
"time" "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/copy"
"github.com/containers/image/v5/signature" "github.com/containers/image/v5/signature"
"github.com/containers/image/v5/transports/alltransports" "github.com/containers/image/v5/transports/alltransports"
@ -27,6 +35,27 @@ var pctx *signature.PolicyContext
const distributionPrefix = "v2" 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 //--- Image converter
type OCIImageManifest struct { type OCIImageManifest struct {
@ -345,6 +374,40 @@ func (o *OCIMultiArch) MergeSystemImages() error {
return nil 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 { func (o *OCIMultiArch) UploadImageS3(buck *blob.Bucket) error {
fmt.Printf("-- push to the s3 target --\n") fmt.Printf("-- push to the s3 target --\n")
@ -466,13 +529,13 @@ func (o *OCIMultiArch) UploadImageS3(buck *blob.Bucket) error {
} }
type StaticRegistryManager struct { type StaticRegistryManager struct {
name string name string
buck *blob.Bucket buck *blob.Bucket
images []ImageDescriptor images []ImageDescriptor
} }
type ImageDescriptor struct { type ImageDescriptor struct {
Tag string Tag string
Date time.Time Date time.Time
} }
@ -515,8 +578,8 @@ func (l *StaticRegistryManager) Scan() error {
// we ignore sha256 addressed manifests // we ignore sha256 addressed manifests
continue continue
} }
id := ImageDescriptor { id := ImageDescriptor{
Tag: fname, Tag: fname,
Date: obj.ModTime, Date: obj.ModTime,
} }
l.images = append(l.images, id) l.images = append(l.images, id)
@ -531,7 +594,7 @@ func (l *StaticRegistryManager) TagList() TagList {
}) })
// Build tagList // Build tagList
tagList := TagList { tagList := TagList{
Name: l.name, Name: l.name,
} }
for _, img := range l.images { for _, img := range l.images {
@ -584,6 +647,9 @@ var containerPublishCmd = &cobra.Command{
localPath := args[0] localPath := args[0]
remotePath := args[1] remotePath := args[1]
dockerProto := "docker://"
dockerProtoCut := len(dockerProto)
oi, err := NewOCIMultiArch(containerTag) oi, err := NewOCIMultiArch(containerTag)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
@ -601,7 +667,7 @@ var containerPublishCmd = &cobra.Command{
os.Exit(1) os.Exit(1)
} }
if strings.HasPrefix(remotePath, "s3:") { if strings.HasPrefix(remotePath, "s3://") {
// open bucket // open bucket
bucket, err := blob.OpenBucket(context.Background(), remotePath) bucket, err := blob.OpenBucket(context.Background(), remotePath)
if err != nil { if err != nil {
@ -621,6 +687,11 @@ var containerPublishCmd = &cobra.Command{
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
} else if strings.HasPrefix(remotePath, dockerProto) {
if err = oi.UploadImageRegistry(remotePath[dockerProtoCut:]); err != nil {
fmt.Println(err)
os.Exit(1)
}
} else { } else {
fmt.Printf("Protocol not supported for remote path %s. Supported transports are s3:// and docker://\n", remotePath) fmt.Printf("Protocol not supported for remote path %s. Supported transports are s3:// and docker://\n", remotePath)
os.Exit(1) os.Exit(1)

View File

@ -181,12 +181,12 @@ func (a *Artifact) Upload(buck *blob.Bucket) error {
//--- Manage uploaded artifacts, list them, etc. //--- Manage uploaded artifacts, list them, etc.
type ArtifactDescriptor struct { type ArtifactDescriptor struct {
Tag string Tag string
Date time.Time Date time.Time
} }
type ArtifactManager struct { type ArtifactManager struct {
name string name string
buck *blob.Bucket buck *blob.Bucket
artifacts []ArtifactDescriptor artifacts []ArtifactDescriptor
} }
@ -197,7 +197,6 @@ func NewArtifactManager(buck *blob.Bucket, name string) *ArtifactManager {
} }
} }
func (am *ArtifactManager) Scan() error { func (am *ArtifactManager) Scan() error {
iter := am.buck.List(&blob.ListOptions{ iter := am.buck.List(&blob.ListOptions{
Prefix: fmt.Sprintf("df-dist-v1/%s/", am.name), Prefix: fmt.Sprintf("df-dist-v1/%s/", am.name),
@ -221,8 +220,8 @@ func (am *ArtifactManager) Scan() error {
} }
fname := ksplit[len(ksplit)-1] fname := ksplit[len(ksplit)-1]
ad := ArtifactDescriptor { ad := ArtifactDescriptor{
Tag: fname, Tag: fname,
Date: obj.ModTime, Date: obj.ModTime,
} }
@ -238,7 +237,7 @@ func (am *ArtifactManager) TagList() TagList {
}) })
// Build tagList // Build tagList
tagList := TagList { tagList := TagList{
Name: am.name, Name: am.name,
} }
for _, art := range am.artifacts { for _, art := range am.artifacts {
@ -247,7 +246,6 @@ func (am *ArtifactManager) TagList() TagList {
return tagList return tagList
} }
func (am *ArtifactManager) UpdateTagList() error { func (am *ArtifactManager) UpdateTagList() error {
fmt.Printf("--- update taglist ---\n") fmt.Printf("--- update taglist ---\n")

3
go.mod
View File

@ -6,6 +6,8 @@ require (
code.gitea.io/sdk/gitea v0.15.1 code.gitea.io/sdk/gitea v0.15.1
github.com/caarlos0/env/v7 v7.1.0 github.com/caarlos0/env/v7 v7.1.0
github.com/containers/image/v5 v5.25.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/consul/api v1.20.0
github.com/hashicorp/nomad/api v0.0.0-20230314144600-1a01e8719272 github.com/hashicorp/nomad/api v0.0.0-20230314144600-1a01e8719272
github.com/spf13/cobra v1.7.0 github.com/spf13/cobra v1.7.0
@ -67,7 +69,6 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // 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/go-intervals v0.0.2 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/google/wire v0.5.0 // indirect github.com/google/wire v0.5.0 // indirect

2
go.sum
View File

@ -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.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= 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 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 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-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= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=