Spaces:
Configuration error
Configuration error
package oci | |
import ( | |
"context" | |
"errors" | |
"fmt" | |
"io" | |
"net/http" | |
"runtime" | |
"strings" | |
"syscall" | |
"time" | |
"github.com/containerd/containerd/archive" | |
registrytypes "github.com/docker/docker/api/types/registry" | |
"github.com/google/go-containerregistry/pkg/authn" | |
"github.com/google/go-containerregistry/pkg/logs" | |
"github.com/google/go-containerregistry/pkg/name" | |
v1 "github.com/google/go-containerregistry/pkg/v1" | |
"github.com/google/go-containerregistry/pkg/v1/mutate" | |
"github.com/google/go-containerregistry/pkg/v1/remote" | |
"github.com/google/go-containerregistry/pkg/v1/remote/transport" | |
) | |
// ref: https://github.com/mudler/luet/blob/master/pkg/helpers/docker/docker.go#L117 | |
type staticAuth struct { | |
auth *registrytypes.AuthConfig | |
} | |
func (s staticAuth) Authorization() (*authn.AuthConfig, error) { | |
if s.auth == nil { | |
return nil, nil | |
} | |
return &authn.AuthConfig{ | |
Username: s.auth.Username, | |
Password: s.auth.Password, | |
Auth: s.auth.Auth, | |
IdentityToken: s.auth.IdentityToken, | |
RegistryToken: s.auth.RegistryToken, | |
}, nil | |
} | |
var defaultRetryBackoff = remote.Backoff{ | |
Duration: 1.0 * time.Second, | |
Factor: 3.0, | |
Jitter: 0.1, | |
Steps: 3, | |
} | |
var defaultRetryPredicate = func(err error) bool { | |
if err == nil { | |
return false | |
} | |
if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) || errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET) || strings.Contains(err.Error(), "connection refused") { | |
logs.Warn.Printf("retrying %v", err) | |
return true | |
} | |
return false | |
} | |
// ExtractOCIImage will extract a given targetImage into a given targetDestination | |
func ExtractOCIImage(img v1.Image, targetDestination string) error { | |
reader := mutate.Extract(img) | |
_, err := archive.Apply(context.Background(), targetDestination, reader, archive.WithNoSameOwner()) | |
return err | |
} | |
func ParseImageParts(image string) (tag, repository, dstimage string) { | |
tag = "latest" | |
repository = "library" | |
if strings.Contains(image, ":") { | |
parts := strings.Split(image, ":") | |
image = parts[0] | |
tag = parts[1] | |
} | |
if strings.Contains("/", image) { | |
parts := strings.Split(image, "/") | |
repository = parts[0] | |
image = parts[1] | |
} | |
dstimage = image | |
return tag, repository, image | |
} | |
// GetImage if returns the proper image to pull with transport and auth | |
// tries local daemon first and then fallbacks into remote | |
// if auth is nil, it will try to use the default keychain https://github.com/google/go-containerregistry/tree/main/pkg/authn#tldr-for-consumers-of-this-package | |
func GetImage(targetImage, targetPlatform string, auth *registrytypes.AuthConfig, t http.RoundTripper) (v1.Image, error) { | |
var platform *v1.Platform | |
var image v1.Image | |
var err error | |
if targetPlatform != "" { | |
platform, err = v1.ParsePlatform(targetPlatform) | |
if err != nil { | |
return image, err | |
} | |
} else { | |
platform, err = v1.ParsePlatform(fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)) | |
if err != nil { | |
return image, err | |
} | |
} | |
ref, err := name.ParseReference(targetImage) | |
if err != nil { | |
return image, err | |
} | |
if t == nil { | |
t = http.DefaultTransport | |
} | |
tr := transport.NewRetry(t, | |
transport.WithRetryBackoff(defaultRetryBackoff), | |
transport.WithRetryPredicate(defaultRetryPredicate), | |
) | |
opts := []remote.Option{ | |
remote.WithTransport(tr), | |
remote.WithPlatform(*platform), | |
} | |
if auth != nil { | |
opts = append(opts, remote.WithAuth(staticAuth{auth})) | |
} else { | |
opts = append(opts, remote.WithAuthFromKeychain(authn.DefaultKeychain)) | |
} | |
image, err = remote.Image(ref, opts...) | |
return image, err | |
} | |
func GetOCIImageSize(targetImage, targetPlatform string, auth *registrytypes.AuthConfig, t http.RoundTripper) (int64, error) { | |
var size int64 | |
var img v1.Image | |
var err error | |
img, err = GetImage(targetImage, targetPlatform, auth, t) | |
if err != nil { | |
return size, err | |
} | |
layers, _ := img.Layers() | |
for _, layer := range layers { | |
s, _ := layer.Size() | |
size += s | |
} | |
return size, nil | |
} | |