push to docker registry
This commit is contained in:
parent
559506c170
commit
8de564e62e
4 changed files with 88 additions and 16 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
3
go.mod
|
@ -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
2
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.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=
|
||||||
|
|
Loading…
Reference in a new issue