transport

package
v0.19.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 29, 2024 License: Apache-2.0 Imports: 19 Imported by: 172

README

transport

GoDoc

The distribution protocol is fairly simple, but correctly implementing authentication is hard.

This package implements an http.RoundTripper that transparently performs:

for registry clients.

Raison d'être

Why not just use the docker/distribution client?

Great question! Mostly, because I don't want to depend on prometheus/client_golang.

As a performance optimization, that client uses a cache to keep track of a mapping between blob digests and their descriptors. Unfortunately, the cache uses prometheus to track hits and misses, so if you want to use that client you have to pull in all of prometheus, which is pretty large.

docker/distribution

Why does it matter if you depend on prometheus? Who cares?

It's generally polite to your downstream to reduce the number of dependencies your package requires:

  • Downloading your package is faster, which helps our Australian friends and people on airplanes.
  • There is less code to compile, which speeds up builds and saves the planet from global warming.
  • You reduce the likelihood of inflicting dependency hell upon your consumers.
  • Tim Hockin prefers it based on his experience working on Kubernetes, and he's a pretty smart guy.

Okay, what about containerd/containerd?

Similar reasons! That ends up pulling in grpc, protobuf, and logrus.

containerd/containerd

Well... what about containers/image?

That just uses the the docker/distribution client... and more!

containers/image

Wow, what about this package?

Of course, this package isn't perfect either. transport depends on authn, which in turn depends on docker's config file parsing and handling package, which you don't strictly need but almost certainly want if you're going to be interacting with a registry.

google/go-containerregistry

These graphs were generated by kisielk/godepgraph.

Usage

This is heavily used by the remote package, which implements higher level image-centric functionality, but this package is useful if you want to interact directly with the registry to do something that remote doesn't support, e.g. to handle with schema 1 images.

This package also includes some error handling facilities in the form of CheckError, which will parse the response body into a structured error for unexpected http status codes.

Here's a "simple" program that writes the result of listing tags for gcr.io/google-containers/pause to stdout.

package main

import (
	"io"
	"net/http"
	"os"

	"github.com/google/go-containerregistry/pkg/authn"
	"github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1/remote/transport"
)

func main() {
	repo, err := name.NewRepository("gcr.io/google-containers/pause")
	if err != nil {
		panic(err)
	}

	// Fetch credentials based on your docker config file, which is $HOME/.docker/config.json or $DOCKER_CONFIG.
	auth, err := authn.DefaultKeychain.Resolve(repo.Registry)
	if err != nil {
		panic(err)
	}

	// Construct an http.Client that is authorized to pull from gcr.io/google-containers/pause.
	scopes := []string{repo.Scope(transport.PullScope)}
	t, err := transport.New(repo.Registry, auth, http.DefaultTransport, scopes)
	if err != nil {
		panic(err)
	}
	client := &http.Client{Transport: t}

	// Make the actual request.
	resp, err := client.Get("https://gcr.io/v2/google-containers/pause/tags/list")
	if err != nil {
		panic(err)
	}

	// Assert that we get a 200, otherwise attempt to parse body as a structured error.
	if err := transport.CheckError(resp, http.StatusOK); err != nil {
		panic(err)
	}

	// Write the response to stdout.
	if _, err := io.Copy(os.Stdout, resp.Body); err != nil {
		panic(err)
	}
}

Documentation

Overview

Package transport provides facilities for setting up an authenticated http.RoundTripper given an Authenticator and base RoundTripper. See transport.New for more information.

Index

Constants

View Source
const (
	PullScope string = "pull"
	PushScope string = "push,pull"
	// For now DELETE is PUSH, which is the read/write ACL.
	DeleteScope  string = PushScope
	CatalogScope string = "catalog"
)

Scopes suitable to qualify each Repository

Variables

View Source
var (
	// Version can be set via:
	// -ldflags="-X 'github.com/google/go-containerregistry/pkg/v1/remote/transport.Version=$TAG'"
	Version string
)

Functions

func CheckError

func CheckError(resp *http.Response, codes ...int) error

CheckError returns a structured error if the response status is not in codes.

func FromToken added in v0.16.0

func FromToken(reg name.Registry, auth authn.Authenticator, t http.RoundTripper, pr *Challenge, tok *Token) (http.RoundTripper, error)

FromToken returns a transport given a Challenge + Token.

func New deprecated

New returns a new RoundTripper based on the provided RoundTripper that has been setup to authenticate with the remote registry "reg", in the capacity laid out by the specified scopes.

Deprecated: Use NewWithContext.

func NewLogger

func NewLogger(inner http.RoundTripper) http.RoundTripper

NewLogger returns a transport that logs requests and responses to github.com/google/go-containerregistry/pkg/logs.Debug.

func NewRetry

func NewRetry(inner http.RoundTripper, opts ...Option) http.RoundTripper

NewRetry returns a transport that retries errors.

func NewUserAgent added in v0.2.0

func NewUserAgent(inner http.RoundTripper, ua string) http.RoundTripper

NewUserAgent returns an http.Roundtripper that sets the user agent to The provided string plus additional go-containerregistry information, e.g. if provided "crane/v0.1.4" and this modules was built at v0.1.4:

User-Agent: crane/v0.1.4 go-containerregistry/v0.1.4

func NewWithContext added in v0.2.0

func NewWithContext(ctx context.Context, reg name.Registry, auth authn.Authenticator, t http.RoundTripper, scopes []string) (http.RoundTripper, error)

NewWithContext returns a new RoundTripper based on the provided RoundTripper that has been set up to authenticate with the remote registry "reg", in the capacity laid out by the specified scopes. In case the RoundTripper is already of the type Wrapper it assumes authentication was already done prior to this call, so it just returns the provided RoundTripper without further action

Types

type Backoff added in v0.7.0

type Backoff = retry.Backoff

Backoff is an alias of retry.Backoff to expose this configuration option to consumers of this lib

type Challenge added in v0.16.0

type Challenge struct {
	Scheme string

	// Following the challenge there are often key/value pairs
	// e.g. Bearer service="gcr.io",realm="https://auth.gcr.io/v36/tokenz"
	Parameters map[string]string

	// Whether we had to use http to complete the Ping.
	Insecure bool
}

func Ping added in v0.16.0

Ping does a GET /v2/ against the registry and returns the response.

type Diagnostic

type Diagnostic struct {
	Code    ErrorCode `json:"code"`
	Message string    `json:"message,omitempty"`
	Detail  any       `json:"detail,omitempty"`
}

Diagnostic represents a single error returned by a Docker registry interaction.

func (Diagnostic) String

func (d Diagnostic) String() string

String stringifies the Diagnostic in the form: $Code: $Message[; $Detail]

type Error

type Error struct {
	Errors []Diagnostic `json:"errors,omitempty"`
	// The http status code returned.
	StatusCode int
	// The request that failed.
	Request *http.Request
	// contains filtered or unexported fields
}

Error implements error to support the following error specification: https://github.com/docker/distribution/blob/master/docs/spec/api.md#errors

func (*Error) Error

func (e *Error) Error() string

Error implements error

func (*Error) Temporary

func (e *Error) Temporary() bool

Temporary returns whether the request that preceded the error is temporary.

type ErrorCode

type ErrorCode string

ErrorCode is an enumeration of supported error codes.

const (
	BlobUnknownErrorCode         ErrorCode = "BLOB_UNKNOWN"
	BlobUploadInvalidErrorCode   ErrorCode = "BLOB_UPLOAD_INVALID"
	BlobUploadUnknownErrorCode   ErrorCode = "BLOB_UPLOAD_UNKNOWN"
	DigestInvalidErrorCode       ErrorCode = "DIGEST_INVALID"
	ManifestBlobUnknownErrorCode ErrorCode = "MANIFEST_BLOB_UNKNOWN"
	ManifestInvalidErrorCode     ErrorCode = "MANIFEST_INVALID"
	ManifestUnknownErrorCode     ErrorCode = "MANIFEST_UNKNOWN"
	ManifestUnverifiedErrorCode  ErrorCode = "MANIFEST_UNVERIFIED"
	NameInvalidErrorCode         ErrorCode = "NAME_INVALID"
	NameUnknownErrorCode         ErrorCode = "NAME_UNKNOWN"
	SizeInvalidErrorCode         ErrorCode = "SIZE_INVALID"
	TagInvalidErrorCode          ErrorCode = "TAG_INVALID"
	UnauthorizedErrorCode        ErrorCode = "UNAUTHORIZED"
	DeniedErrorCode              ErrorCode = "DENIED"
	UnsupportedErrorCode         ErrorCode = "UNSUPPORTED"
	TooManyRequestsErrorCode     ErrorCode = "TOOMANYREQUESTS"
	UnknownErrorCode             ErrorCode = "UNKNOWN"

	// This isn't defined by either docker or OCI spec, but is defined by docker/distribution:
	// https://github.com/distribution/distribution/blob/6a977a5a754baa213041443f841705888107362a/registry/api/errcode/register.go#L60
	UnavailableErrorCode ErrorCode = "UNAVAILABLE"
)

The set of error conditions a registry may return: https://github.com/docker/distribution/blob/master/docs/spec/api.md#errors-2

type Option

type Option func(*options)

Option is a functional option for retryTransport.

func WithRetryBackoff

func WithRetryBackoff(backoff Backoff) Option

WithRetryBackoff sets the backoff for retry operations.

func WithRetryPredicate

func WithRetryPredicate(predicate func(error) bool) Option

WithRetryPredicate sets the predicate for retry operations.

func WithRetryStatusCodes added in v0.13.0

func WithRetryStatusCodes(codes ...int) Option

WithRetryStatusCodes sets which http response codes will be retried.

type Token added in v0.16.0

type Token struct {
	Token        string `json:"token"`
	AccessToken  string `json:"access_token,omitempty"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int    `json:"expires_in"`
}

func Exchange added in v0.16.0

func Exchange(ctx context.Context, reg name.Registry, auth authn.Authenticator, t http.RoundTripper, scopes []string, pr *Challenge) (*Token, error)

Exchange requests a registry Token with the given scopes.

type Wrapper added in v0.7.0

type Wrapper struct {
	// contains filtered or unexported fields
}

Wrapper results in *not* wrapping supplied transport with additional logic such as retries, useragent and debug logging Consumers are opt-ing into providing their own transport without any additional wrapping.

func (*Wrapper) RoundTrip added in v0.7.0

func (w *Wrapper) RoundTrip(in *http.Request) (*http.Response, error)

RoundTrip delegates to the inner RoundTripper

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL