mirror of https://github.com/docker/cli.git
vendor: github.com/docker/docker 7abd7fa73965 (v25.0.0-dev)
full diff: a65c948e7e...7abd7fa739
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
f74f88445f
commit
04af128211
|
@ -133,7 +133,7 @@ func runStats(dockerCli command.Cli, opts *statsOptions) error {
|
||||||
// would "miss" a creation.
|
// would "miss" a creation.
|
||||||
started := make(chan struct{})
|
started := make(chan struct{})
|
||||||
eh := command.InitEventHandler()
|
eh := command.InitEventHandler()
|
||||||
eh.Handle("create", func(e events.Message) {
|
eh.Handle(events.ActionCreate, func(e events.Message) {
|
||||||
if opts.all {
|
if opts.all {
|
||||||
s := NewStats(e.ID[:12])
|
s := NewStats(e.ID[:12])
|
||||||
if cStats.add(s) {
|
if cStats.add(s) {
|
||||||
|
@ -143,7 +143,7 @@ func runStats(dockerCli command.Cli, opts *statsOptions) error {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
eh.Handle("start", func(e events.Message) {
|
eh.Handle(events.ActionStart, func(e events.Message) {
|
||||||
s := NewStats(e.ID[:12])
|
s := NewStats(e.ID[:12])
|
||||||
if cStats.add(s) {
|
if cStats.add(s) {
|
||||||
waitFirst.Add(1)
|
waitFirst.Add(1)
|
||||||
|
@ -151,7 +151,7 @@ func runStats(dockerCli command.Cli, opts *statsOptions) error {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
eh.Handle("die", func(e events.Message) {
|
eh.Handle(events.ActionDie, func(e events.Message) {
|
||||||
if !opts.all {
|
if !opts.all {
|
||||||
cStats.remove(e.ID[:12])
|
cStats.remove(e.ID[:12])
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,21 +10,21 @@ import (
|
||||||
// EventHandler is abstract interface for user to customize
|
// EventHandler is abstract interface for user to customize
|
||||||
// own handle functions of each type of events
|
// own handle functions of each type of events
|
||||||
type EventHandler interface {
|
type EventHandler interface {
|
||||||
Handle(action string, h func(events.Message))
|
Handle(action events.Action, h func(events.Message))
|
||||||
Watch(c <-chan events.Message)
|
Watch(c <-chan events.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitEventHandler initializes and returns an EventHandler
|
// InitEventHandler initializes and returns an EventHandler
|
||||||
func InitEventHandler() EventHandler {
|
func InitEventHandler() EventHandler {
|
||||||
return &eventHandler{handlers: make(map[string]func(events.Message))}
|
return &eventHandler{handlers: make(map[events.Action]func(events.Message))}
|
||||||
}
|
}
|
||||||
|
|
||||||
type eventHandler struct {
|
type eventHandler struct {
|
||||||
handlers map[string]func(events.Message)
|
handlers map[events.Action]func(events.Message)
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *eventHandler) Handle(action string, h func(events.Message)) {
|
func (w *eventHandler) Handle(action events.Action, h func(events.Message)) {
|
||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
w.handlers[action] = h
|
w.handlers[action] = h
|
||||||
w.mu.Unlock()
|
w.mu.Unlock()
|
||||||
|
|
|
@ -17,9 +17,9 @@ import (
|
||||||
|
|
||||||
func TestEventsFormat(t *testing.T) {
|
func TestEventsFormat(t *testing.T) {
|
||||||
var evts []events.Message
|
var evts []events.Message
|
||||||
for i, action := range []string{"create", "start", "attach", "die"} {
|
for i, action := range []events.Action{events.ActionCreate, events.ActionStart, events.ActionAttach, events.ActionDie} {
|
||||||
evts = append(evts, events.Message{
|
evts = append(evts, events.Message{
|
||||||
Status: action,
|
Status: string(action),
|
||||||
ID: "abc123",
|
ID: "abc123",
|
||||||
From: "ubuntu:latest",
|
From: "ubuntu:latest",
|
||||||
Type: events.ContainerEventType,
|
Type: events.ContainerEventType,
|
||||||
|
|
|
@ -12,7 +12,7 @@ require (
|
||||||
github.com/containerd/containerd v1.6.22
|
github.com/containerd/containerd v1.6.22
|
||||||
github.com/creack/pty v1.1.18
|
github.com/creack/pty v1.1.18
|
||||||
github.com/docker/distribution v2.8.2+incompatible
|
github.com/docker/distribution v2.8.2+incompatible
|
||||||
github.com/docker/docker v24.0.0-rc.2.0.20230828170219-a65c948e7edf+incompatible // master (v25.0.0-dev)
|
github.com/docker/docker v24.0.0-rc.2.0.20230905102234-7abd7fa73965+incompatible // master (v25.0.0-dev)
|
||||||
github.com/docker/docker-credential-helpers v0.8.0
|
github.com/docker/docker-credential-helpers v0.8.0
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.0
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
|
|
|
@ -50,8 +50,8 @@ github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xb
|
||||||
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=
|
||||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v24.0.0-rc.2.0.20230828170219-a65c948e7edf+incompatible h1:kW2gtg0d8U36kbMoM7eqXIA7PuXGw3l/A3cxwdnbZPU=
|
github.com/docker/docker v24.0.0-rc.2.0.20230905102234-7abd7fa73965+incompatible h1:i2QiMyOrwAI5M1Gg9U5jJJxx45b6YeqbDny9xwsUmv8=
|
||||||
github.com/docker/docker v24.0.0-rc.2.0.20230828170219-a65c948e7edf+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v24.0.0-rc.2.0.20230905102234-7abd7fa73965+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
|
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
|
||||||
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
|
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
|
||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||||
|
|
|
@ -8268,7 +8268,7 @@ paths:
|
||||||
/images/create:
|
/images/create:
|
||||||
post:
|
post:
|
||||||
summary: "Create an image"
|
summary: "Create an image"
|
||||||
description: "Create an image by either pulling it from a registry or importing it."
|
description: "Pull or import an image."
|
||||||
operationId: "ImageCreate"
|
operationId: "ImageCreate"
|
||||||
consumes:
|
consumes:
|
||||||
- "text/plain"
|
- "text/plain"
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/strslice"
|
"github.com/docker/docker/api/types/strslice"
|
||||||
|
dockerspec "github.com/docker/docker/image/spec/specs-go/v1"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -33,26 +34,7 @@ type StopOptions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
|
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
|
||||||
type HealthConfig struct {
|
type HealthConfig = dockerspec.HealthcheckConfig
|
||||||
// Test is the test to perform to check that the container is healthy.
|
|
||||||
// An empty slice means to inherit the default.
|
|
||||||
// The options are:
|
|
||||||
// {} : inherit healthcheck
|
|
||||||
// {"NONE"} : disable healthcheck
|
|
||||||
// {"CMD", args...} : exec arguments directly
|
|
||||||
// {"CMD-SHELL", command} : run command with system's default shell
|
|
||||||
Test []string `json:",omitempty"`
|
|
||||||
|
|
||||||
// Zero means to inherit. Durations are expressed as integer nanoseconds.
|
|
||||||
Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks.
|
|
||||||
Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung.
|
|
||||||
StartPeriod time.Duration `json:",omitempty"` // The start period for the container to initialize before the retries starts to count down.
|
|
||||||
StartInterval time.Duration `json:",omitempty"` // The interval to attempt healthchecks at during the start period
|
|
||||||
|
|
||||||
// Retries is the number of consecutive failures needed to consider a container as unhealthy.
|
|
||||||
// Zero means inherit.
|
|
||||||
Retries int `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecStartOptions holds the options to start container's exec.
|
// ExecStartOptions holds the options to start container's exec.
|
||||||
type ExecStartOptions struct {
|
type ExecStartOptions struct {
|
||||||
|
|
|
@ -18,6 +18,86 @@ const (
|
||||||
VolumeEventType Type = "volume" // VolumeEventType is the event type that volumes generate.
|
VolumeEventType Type = "volume" // VolumeEventType is the event type that volumes generate.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Action is used for event-actions.
|
||||||
|
type Action string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ActionCreate Action = "create"
|
||||||
|
ActionStart Action = "start"
|
||||||
|
ActionRestart Action = "restart"
|
||||||
|
ActionStop Action = "stop"
|
||||||
|
ActionCheckpoint Action = "checkpoint"
|
||||||
|
ActionPause Action = "pause"
|
||||||
|
ActionUnPause Action = "unpause"
|
||||||
|
ActionAttach Action = "attach"
|
||||||
|
ActionDetach Action = "detach"
|
||||||
|
ActionResize Action = "resize"
|
||||||
|
ActionUpdate Action = "update"
|
||||||
|
ActionRename Action = "rename"
|
||||||
|
ActionKill Action = "kill"
|
||||||
|
ActionDie Action = "die"
|
||||||
|
ActionOOM Action = "oom"
|
||||||
|
ActionDestroy Action = "destroy"
|
||||||
|
ActionRemove Action = "remove"
|
||||||
|
ActionCommit Action = "commit"
|
||||||
|
ActionTop Action = "top"
|
||||||
|
ActionCopy Action = "copy"
|
||||||
|
ActionArchivePath Action = "archive-path"
|
||||||
|
ActionExtractToDir Action = "extract-to-dir"
|
||||||
|
ActionExport Action = "export"
|
||||||
|
ActionImport Action = "import"
|
||||||
|
ActionSave Action = "save"
|
||||||
|
ActionLoad Action = "load"
|
||||||
|
ActionTag Action = "tag"
|
||||||
|
ActionUnTag Action = "untag"
|
||||||
|
ActionPush Action = "push"
|
||||||
|
ActionPull Action = "pull"
|
||||||
|
ActionPrune Action = "prune"
|
||||||
|
ActionDelete Action = "delete"
|
||||||
|
ActionEnable Action = "enable"
|
||||||
|
ActionDisable Action = "disable"
|
||||||
|
ActionConnect Action = "connect"
|
||||||
|
ActionDisconnect Action = "disconnect"
|
||||||
|
ActionReload Action = "reload"
|
||||||
|
ActionMount Action = "mount"
|
||||||
|
ActionUnmount Action = "unmount"
|
||||||
|
|
||||||
|
// ActionExecCreate is the prefix used for exec_create events. These
|
||||||
|
// event-actions are commonly followed by a colon and space (": "),
|
||||||
|
// and the command that's defined for the exec, for example:
|
||||||
|
//
|
||||||
|
// exec_create: /bin/sh -c 'echo hello'
|
||||||
|
//
|
||||||
|
// This is far from ideal; it's a compromise to allow filtering and
|
||||||
|
// to preserve backward-compatibility.
|
||||||
|
ActionExecCreate Action = "exec_create"
|
||||||
|
// ActionExecStart is the prefix used for exec_create events. These
|
||||||
|
// event-actions are commonly followed by a colon and space (": "),
|
||||||
|
// and the command that's defined for the exec, for example:
|
||||||
|
//
|
||||||
|
// exec_start: /bin/sh -c 'echo hello'
|
||||||
|
//
|
||||||
|
// This is far from ideal; it's a compromise to allow filtering and
|
||||||
|
// to preserve backward-compatibility.
|
||||||
|
ActionExecStart Action = "exec_start"
|
||||||
|
ActionExecDie Action = "exec_die"
|
||||||
|
ActionExecDetach Action = "exec_detach"
|
||||||
|
|
||||||
|
// ActionHealthStatus is the prefix to use for health_status events.
|
||||||
|
//
|
||||||
|
// Health-status events can either have a pre-defined status, in which
|
||||||
|
// case the "health_status" action is followed by a colon, or can be
|
||||||
|
// "free-form", in which case they're followed by the output of the
|
||||||
|
// health-check output.
|
||||||
|
//
|
||||||
|
// This is far form ideal, and a compromise to allow filtering, and
|
||||||
|
// to preserve backward-compatibility.
|
||||||
|
ActionHealthStatus Action = "health_status"
|
||||||
|
ActionHealthStatusRunning Action = "health_status: running"
|
||||||
|
ActionHealthStatusHealthy Action = "health_status: healthy"
|
||||||
|
ActionHealthStatusUnhealthy Action = "health_status: unhealthy"
|
||||||
|
)
|
||||||
|
|
||||||
// Actor describes something that generates events,
|
// Actor describes something that generates events,
|
||||||
// like a container, or a network, or a volume.
|
// like a container, or a network, or a volume.
|
||||||
// It has a defined name and a set of attributes.
|
// It has a defined name and a set of attributes.
|
||||||
|
@ -37,7 +117,7 @@ type Message struct {
|
||||||
From string `json:"from,omitempty"` // Deprecated: use Actor.Attributes["image"] instead.
|
From string `json:"from,omitempty"` // Deprecated: use Actor.Attributes["image"] instead.
|
||||||
|
|
||||||
Type Type
|
Type Type
|
||||||
Action string
|
Action Action
|
||||||
Actor Actor
|
Actor Actor
|
||||||
// Engine events are local scope. Cluster events are swarm scope.
|
// Engine events are local scope. Cluster events are swarm scope.
|
||||||
Scope string `json:"scope,omitempty"`
|
Scope string `json:"scope,omitempty"`
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package errdefs // import "github.com/docker/docker/errdefs"
|
package errdefs
|
||||||
|
|
||||||
// ErrNotFound signals that the requested object doesn't exist
|
// ErrNotFound signals that the requested object doesn't exist
|
||||||
type ErrNotFound interface {
|
type ErrNotFound interface {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package errdefs // import "github.com/docker/docker/errdefs"
|
package errdefs
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package errdefs // import "github.com/docker/docker/errdefs"
|
package errdefs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package errdefs // import "github.com/docker/docker/errdefs"
|
package errdefs
|
||||||
|
|
||||||
type causer interface {
|
type causer interface {
|
||||||
Cause() error
|
Cause() error
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DockerOCIImageMediaType = "application/vnd.docker.container.image.v1+json"
|
||||||
|
|
||||||
|
// DockerOCIImage is a ocispec.Image extended with Docker specific Config.
|
||||||
|
type DockerOCIImage struct {
|
||||||
|
ocispec.Image
|
||||||
|
|
||||||
|
// Shadow ocispec.Image.Config
|
||||||
|
Config DockerOCIImageConfig `json:"config,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DockerOCIImageConfig is a ocispec.ImageConfig extended with Docker specific fields.
|
||||||
|
type DockerOCIImageConfig struct {
|
||||||
|
ocispec.ImageConfig
|
||||||
|
|
||||||
|
DockerOCIImageConfigExt
|
||||||
|
}
|
||||||
|
|
||||||
|
// DockerOCIImageConfigExt contains Docker-specific fields in DockerImageConfig.
|
||||||
|
type DockerOCIImageConfigExt struct {
|
||||||
|
Healthcheck *HealthcheckConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
|
||||||
|
|
||||||
|
OnBuild []string `json:",omitempty"` // ONBUILD metadata that were defined on the image Dockerfile
|
||||||
|
Shell []string `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
|
||||||
|
}
|
||||||
|
|
||||||
|
// HealthcheckConfig holds configuration settings for the HEALTHCHECK feature.
|
||||||
|
type HealthcheckConfig struct {
|
||||||
|
// Test is the test to perform to check that the container is healthy.
|
||||||
|
// An empty slice means to inherit the default.
|
||||||
|
// The options are:
|
||||||
|
// {} : inherit healthcheck
|
||||||
|
// {"NONE"} : disable healthcheck
|
||||||
|
// {"CMD", args...} : exec arguments directly
|
||||||
|
// {"CMD-SHELL", command} : run command with system's default shell
|
||||||
|
Test []string `json:",omitempty"`
|
||||||
|
|
||||||
|
// Zero means to inherit. Durations are expressed as integer nanoseconds.
|
||||||
|
Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks.
|
||||||
|
Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung.
|
||||||
|
StartPeriod time.Duration `json:",omitempty"` // The start period for the container to initialize before the retries starts to count down.
|
||||||
|
StartInterval time.Duration `json:",omitempty"` // The interval to attempt healthchecks at during the start period
|
||||||
|
|
||||||
|
// Retries is the number of consecutive failures needed to consider a container as unhealthy.
|
||||||
|
// Zero means inherit.
|
||||||
|
Retries int `json:",omitempty"`
|
||||||
|
}
|
|
@ -125,8 +125,10 @@ func v2AuthHTTPClient(endpoint *url.URL, authTransport http.RoundTripper, modifi
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertToHostname converts a registry url which has http|https prepended
|
// ConvertToHostname normalizes a registry URL which has http|https prepended
|
||||||
// to just an hostname.
|
// to just its hostname. It is used to match credentials, which may be either
|
||||||
|
// stored as hostname or as hostname including scheme (in legacy configuration
|
||||||
|
// files).
|
||||||
func ConvertToHostname(url string) string {
|
func ConvertToHostname(url string) string {
|
||||||
stripped := url
|
stripped := url
|
||||||
if strings.HasPrefix(url, "http://") {
|
if strings.HasPrefix(url, "http://") {
|
||||||
|
@ -147,8 +149,8 @@ func ResolveAuthConfig(authConfigs map[string]registry.AuthConfig, index *regist
|
||||||
|
|
||||||
// Maybe they have a legacy config file, we will iterate the keys converting
|
// Maybe they have a legacy config file, we will iterate the keys converting
|
||||||
// them to the new format and testing
|
// them to the new format and testing
|
||||||
for registry, ac := range authConfigs {
|
for registryURL, ac := range authConfigs {
|
||||||
if configKey == ConvertToHostname(registry) {
|
if configKey == ConvertToHostname(registryURL) {
|
||||||
return ac
|
return ac
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,7 +320,8 @@ func isCIDRMatch(cidrs []*registry.NetIPNet, URLHost string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateMirror validates an HTTP(S) registry mirror
|
// ValidateMirror validates an HTTP(S) registry mirror. It is used by the daemon
|
||||||
|
// to validate the daemon configuration.
|
||||||
func ValidateMirror(val string) (string, error) {
|
func ValidateMirror(val string) (string, error) {
|
||||||
uri, err := url.Parse(val)
|
uri, err := url.Parse(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -340,7 +341,8 @@ func ValidateMirror(val string) (string, error) {
|
||||||
return strings.TrimSuffix(val, "/") + "/", nil
|
return strings.TrimSuffix(val, "/") + "/", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateIndexName validates an index name.
|
// ValidateIndexName validates an index name. It is used by the daemon to
|
||||||
|
// validate the daemon configuration.
|
||||||
func ValidateIndexName(val string) (string, error) {
|
func ValidateIndexName(val string) (string, error) {
|
||||||
// TODO: upstream this to check to reference package
|
// TODO: upstream this to check to reference package
|
||||||
if val == "index.docker.io" {
|
if val == "index.docker.io" {
|
||||||
|
@ -426,19 +428,10 @@ func newRepositoryInfo(config *serviceConfig, name reference.Named) (*Repository
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseRepositoryInfo performs the breakdown of a repository name into a RepositoryInfo, but
|
// ParseRepositoryInfo performs the breakdown of a repository name into a
|
||||||
// lacks registry configuration.
|
// [RepositoryInfo], but lacks registry configuration.
|
||||||
|
//
|
||||||
|
// It is used by the Docker cli to interact with registry-related endpoints.
|
||||||
func ParseRepositoryInfo(reposName reference.Named) (*RepositoryInfo, error) {
|
func ParseRepositoryInfo(reposName reference.Named) (*RepositoryInfo, error) {
|
||||||
return newRepositoryInfo(emptyServiceConfig, reposName)
|
return newRepositoryInfo(emptyServiceConfig, reposName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseSearchIndexInfo will use repository name to get back an indexInfo.
|
|
||||||
//
|
|
||||||
// TODO(thaJeztah) this function is only used by the CLI, and used to get
|
|
||||||
// information of the registry (to provide credentials if needed). We should
|
|
||||||
// move this function (or equivalent) to the CLI, as it's doing too much just
|
|
||||||
// for that.
|
|
||||||
func ParseSearchIndexInfo(reposName string) (*registry.IndexInfo, error) {
|
|
||||||
indexName, _ := splitReposSearchTerm(reposName)
|
|
||||||
return newIndexInfo(emptyServiceConfig, indexName)
|
|
||||||
}
|
|
||||||
|
|
|
@ -113,51 +113,6 @@ func Headers(userAgent string, metaHeaders http.Header) []transport.RequestModif
|
||||||
return modifiers
|
return modifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
// httpClient returns an HTTP client structure which uses the given transport
|
|
||||||
// and contains the necessary headers for redirected requests
|
|
||||||
func httpClient(transport http.RoundTripper) *http.Client {
|
|
||||||
return &http.Client{
|
|
||||||
Transport: transport,
|
|
||||||
CheckRedirect: addRequiredHeadersToRedirectedRequests,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func trustedLocation(req *http.Request) bool {
|
|
||||||
var (
|
|
||||||
trusteds = []string{"docker.com", "docker.io"}
|
|
||||||
hostname = strings.SplitN(req.Host, ":", 2)[0]
|
|
||||||
)
|
|
||||||
if req.URL.Scheme != "https" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, trusted := range trusteds {
|
|
||||||
if hostname == trusted || strings.HasSuffix(hostname, "."+trusted) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// addRequiredHeadersToRedirectedRequests adds the necessary redirection headers
|
|
||||||
// for redirected requests
|
|
||||||
func addRequiredHeadersToRedirectedRequests(req *http.Request, via []*http.Request) error {
|
|
||||||
if len(via) != 0 && via[0] != nil {
|
|
||||||
if trustedLocation(req) && trustedLocation(via[0]) {
|
|
||||||
req.Header = via[0].Header
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for k, v := range via[0].Header {
|
|
||||||
if k != "Authorization" {
|
|
||||||
for _, vv := range v {
|
|
||||||
req.Header.Add(k, vv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newTransport returns a new HTTP transport. If tlsConfig is nil, it uses the
|
// newTransport returns a new HTTP transport. If tlsConfig is nil, it uses the
|
||||||
// default TLS configuration.
|
// default TLS configuration.
|
||||||
func newTransport(tlsConfig *tls.Config) *http.Transport {
|
func newTransport(tlsConfig *tls.Config) *http.Transport {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package registry // import "github.com/docker/docker/registry"
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -6,12 +6,11 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/log"
|
||||||
|
"github.com/docker/distribution/registry/client/auth"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
|
|
||||||
"github.com/containerd/containerd/log"
|
|
||||||
"github.com/docker/distribution/registry/client/auth"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -139,3 +138,26 @@ func (s *Service) searchUnfiltered(ctx context.Context, term string, limit int,
|
||||||
|
|
||||||
return newSession(client, endpoint).searchRepositories(remoteName, limit)
|
return newSession(client, endpoint).searchRepositories(remoteName, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// splitReposSearchTerm breaks a search term into an index name and remote name
|
||||||
|
func splitReposSearchTerm(reposName string) (string, string) {
|
||||||
|
nameParts := strings.SplitN(reposName, "/", 2)
|
||||||
|
if len(nameParts) == 1 || (!strings.Contains(nameParts[0], ".") &&
|
||||||
|
!strings.Contains(nameParts[0], ":") && nameParts[0] != "localhost") {
|
||||||
|
// This is a Docker Hub repository (ex: samalba/hipache or ubuntu),
|
||||||
|
// use the default Docker Hub registry (docker.io)
|
||||||
|
return IndexName, reposName
|
||||||
|
}
|
||||||
|
return nameParts[0], nameParts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseSearchIndexInfo will use repository name to get back an indexInfo.
|
||||||
|
//
|
||||||
|
// TODO(thaJeztah) this function is only used by the CLI, and used to get
|
||||||
|
// information of the registry (to provide credentials if needed). We should
|
||||||
|
// move this function (or equivalent) to the CLI, as it's doing too much just
|
||||||
|
// for that.
|
||||||
|
func ParseSearchIndexInfo(reposName string) (*registry.IndexInfo, error) {
|
||||||
|
indexName, _ := splitReposSearchTerm(reposName)
|
||||||
|
return newIndexInfo(emptyServiceConfig, indexName)
|
||||||
|
}
|
||||||
|
|
|
@ -82,23 +82,14 @@ func validateEndpoint(endpoint *v1Endpoint) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// trimV1Address trims the version off the address and returns the
|
// trimV1Address trims the "v1" version suffix off the address and returns
|
||||||
// trimmed address or an error if there is a non-V1 version.
|
// the trimmed address. It returns an error on "v2" endpoints.
|
||||||
func trimV1Address(address string) (string, error) {
|
func trimV1Address(address string) (string, error) {
|
||||||
address = strings.TrimSuffix(address, "/")
|
trimmed := strings.TrimSuffix(address, "/")
|
||||||
chunks := strings.Split(address, "/")
|
if strings.HasSuffix(trimmed, "/v2") {
|
||||||
apiVersionStr := chunks[len(chunks)-1]
|
return "", invalidParamf("search is not supported on v2 endpoints: %s", address)
|
||||||
if apiVersionStr == "v1" {
|
|
||||||
return strings.Join(chunks[:len(chunks)-1], "/"), nil
|
|
||||||
}
|
}
|
||||||
|
return strings.TrimSuffix(trimmed, "/v1"), nil
|
||||||
for k, v := range apiVersions {
|
|
||||||
if k != APIVersion1 && apiVersionStr == v {
|
|
||||||
return "", invalidParamf("unsupported V1 version path %s", apiVersionStr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return address, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newV1EndpointFromStr(address string, tlsConfig *tls.Config, headers http.Header) (*v1Endpoint, error) {
|
func newV1EndpointFromStr(address string, tlsConfig *tls.Config, headers http.Header) (*v1Endpoint, error) {
|
||||||
|
@ -184,3 +175,48 @@ func (e *v1Endpoint) ping() (v1PingResult, error) {
|
||||||
log.G(context.TODO()).Debugf("v1PingResult.Standalone: %t", info.Standalone)
|
log.G(context.TODO()).Debugf("v1PingResult.Standalone: %t", info.Standalone)
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// httpClient returns an HTTP client structure which uses the given transport
|
||||||
|
// and contains the necessary headers for redirected requests
|
||||||
|
func httpClient(transport http.RoundTripper) *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: transport,
|
||||||
|
CheckRedirect: addRequiredHeadersToRedirectedRequests,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func trustedLocation(req *http.Request) bool {
|
||||||
|
var (
|
||||||
|
trusteds = []string{"docker.com", "docker.io"}
|
||||||
|
hostname = strings.SplitN(req.Host, ":", 2)[0]
|
||||||
|
)
|
||||||
|
if req.URL.Scheme != "https" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, trusted := range trusteds {
|
||||||
|
if hostname == trusted || strings.HasSuffix(hostname, "."+trusted) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// addRequiredHeadersToRedirectedRequests adds the necessary redirection headers
|
||||||
|
// for redirected requests
|
||||||
|
func addRequiredHeadersToRedirectedRequests(req *http.Request, via []*http.Request) error {
|
||||||
|
if len(via) != 0 && via[0] != nil {
|
||||||
|
if trustedLocation(req) && trustedLocation(via[0]) {
|
||||||
|
req.Header = via[0].Header
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for k, v := range via[0].Header {
|
||||||
|
if k != "Authorization" {
|
||||||
|
for _, vv := range v {
|
||||||
|
req.Header.Add(k, vv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -20,8 +20,8 @@ type Service struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewService returns a new instance of defaultService ready to be
|
// NewService returns a new instance of [Service] ready to be installed into
|
||||||
// installed into an engine.
|
// an engine.
|
||||||
func NewService(options ServiceOptions) (*Service, error) {
|
func NewService(options ServiceOptions) (*Service, error) {
|
||||||
config, err := newServiceConfig(options)
|
config, err := newServiceConfig(options)
|
||||||
|
|
||||||
|
@ -91,18 +91,6 @@ func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, use
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitReposSearchTerm breaks a search term into an index name and remote name
|
|
||||||
func splitReposSearchTerm(reposName string) (string, string) {
|
|
||||||
nameParts := strings.SplitN(reposName, "/", 2)
|
|
||||||
if len(nameParts) == 1 || (!strings.Contains(nameParts[0], ".") &&
|
|
||||||
!strings.Contains(nameParts[0], ":") && nameParts[0] != "localhost") {
|
|
||||||
// This is a Docker Hub repository (ex: samalba/hipache or ubuntu),
|
|
||||||
// use the default Docker Hub registry (docker.io)
|
|
||||||
return IndexName, reposName
|
|
||||||
}
|
|
||||||
return nameParts[0], nameParts[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResolveRepository splits a repository name into its components
|
// ResolveRepository splits a repository name into its components
|
||||||
// and configuration of the associated registry.
|
// and configuration of the associated registry.
|
||||||
func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
|
func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
|
||||||
|
@ -115,7 +103,7 @@ func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, erro
|
||||||
type APIEndpoint struct {
|
type APIEndpoint struct {
|
||||||
Mirror bool
|
Mirror bool
|
||||||
URL *url.URL
|
URL *url.URL
|
||||||
Version APIVersion
|
Version APIVersion // Deprecated: v1 registries are deprecated, and endpoints are always v2.
|
||||||
AllowNondistributableArtifacts bool
|
AllowNondistributableArtifacts bool
|
||||||
Official bool
|
Official bool
|
||||||
TrimHostname bool
|
TrimHostname bool
|
||||||
|
|
|
@ -25,7 +25,7 @@ func (s *Service) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, e
|
||||||
}
|
}
|
||||||
endpoints = append(endpoints, APIEndpoint{
|
endpoints = append(endpoints, APIEndpoint{
|
||||||
URL: mirrorURL,
|
URL: mirrorURL,
|
||||||
Version: APIVersion2,
|
Version: APIVersion2, //nolint:staticcheck // ignore SA1019 (Version is deprecated) to allow potential consumers to transition.
|
||||||
Mirror: true,
|
Mirror: true,
|
||||||
TrimHostname: true,
|
TrimHostname: true,
|
||||||
TLSConfig: mirrorTLSConfig,
|
TLSConfig: mirrorTLSConfig,
|
||||||
|
@ -33,7 +33,7 @@ func (s *Service) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, e
|
||||||
}
|
}
|
||||||
endpoints = append(endpoints, APIEndpoint{
|
endpoints = append(endpoints, APIEndpoint{
|
||||||
URL: DefaultV2Registry,
|
URL: DefaultV2Registry,
|
||||||
Version: APIVersion2,
|
Version: APIVersion2, //nolint:staticcheck // ignore SA1019 (Version is deprecated) to allow potential consumers to transition.
|
||||||
Official: true,
|
Official: true,
|
||||||
TrimHostname: true,
|
TrimHostname: true,
|
||||||
TLSConfig: tlsconfig.ServerDefault(),
|
TLSConfig: tlsconfig.ServerDefault(),
|
||||||
|
@ -55,7 +55,7 @@ func (s *Service) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, e
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Host: hostname,
|
Host: hostname,
|
||||||
},
|
},
|
||||||
Version: APIVersion2,
|
Version: APIVersion2, //nolint:staticcheck // ignore SA1019 (Version is deprecated) to allow potential consumers to transition.
|
||||||
AllowNondistributableArtifacts: ana,
|
AllowNondistributableArtifacts: ana,
|
||||||
TrimHostname: true,
|
TrimHostname: true,
|
||||||
TLSConfig: tlsConfig,
|
TLSConfig: tlsConfig,
|
||||||
|
@ -68,7 +68,7 @@ func (s *Service) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, e
|
||||||
Scheme: "http",
|
Scheme: "http",
|
||||||
Host: hostname,
|
Host: hostname,
|
||||||
},
|
},
|
||||||
Version: APIVersion2,
|
Version: APIVersion2, //nolint:staticcheck // ignore SA1019 (Version is deprecated) to allow potential consumers to transition.
|
||||||
AllowNondistributableArtifacts: ana,
|
AllowNondistributableArtifacts: ana,
|
||||||
TrimHostname: true,
|
TrimHostname: true,
|
||||||
// used to check if supposed to be secure via InsecureSkipVerify
|
// used to check if supposed to be secure via InsecureSkipVerify
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
|
|
||||||
// APIVersion is an integral representation of an API version (presently
|
// APIVersion is an integral representation of an API version (presently
|
||||||
// either 1 or 2)
|
// either 1 or 2)
|
||||||
|
//
|
||||||
|
// Deprecated: v1 registries are deprecated, and endpoints are always v2.
|
||||||
type APIVersion int
|
type APIVersion int
|
||||||
|
|
||||||
func (av APIVersion) String() string {
|
func (av APIVersion) String() string {
|
||||||
|
@ -15,8 +17,8 @@ func (av APIVersion) String() string {
|
||||||
|
|
||||||
// API Version identifiers.
|
// API Version identifiers.
|
||||||
const (
|
const (
|
||||||
APIVersion1 APIVersion = 1
|
APIVersion1 APIVersion = 1 // Deprecated: v1 registries are deprecated, and endpoints are always v2.
|
||||||
APIVersion2 APIVersion = 2
|
APIVersion2 APIVersion = 2 // Deprecated: v1 registries are deprecated, and endpoints are always v2.
|
||||||
)
|
)
|
||||||
|
|
||||||
var apiVersions = map[APIVersion]string{
|
var apiVersions = map[APIVersion]string{
|
||||||
|
|
|
@ -49,7 +49,7 @@ github.com/docker/distribution/registry/client/transport
|
||||||
github.com/docker/distribution/registry/storage/cache
|
github.com/docker/distribution/registry/storage/cache
|
||||||
github.com/docker/distribution/registry/storage/cache/memory
|
github.com/docker/distribution/registry/storage/cache/memory
|
||||||
github.com/docker/distribution/uuid
|
github.com/docker/distribution/uuid
|
||||||
# github.com/docker/docker v24.0.0-rc.2.0.20230828170219-a65c948e7edf+incompatible
|
# github.com/docker/docker v24.0.0-rc.2.0.20230905102234-7abd7fa73965+incompatible
|
||||||
## explicit
|
## explicit
|
||||||
github.com/docker/docker/api
|
github.com/docker/docker/api
|
||||||
github.com/docker/docker/api/types
|
github.com/docker/docker/api/types
|
||||||
|
@ -73,6 +73,7 @@ github.com/docker/docker/builder/remotecontext/git
|
||||||
github.com/docker/docker/builder/remotecontext/urlutil
|
github.com/docker/docker/builder/remotecontext/urlutil
|
||||||
github.com/docker/docker/client
|
github.com/docker/docker/client
|
||||||
github.com/docker/docker/errdefs
|
github.com/docker/docker/errdefs
|
||||||
|
github.com/docker/docker/image/spec/specs-go/v1
|
||||||
github.com/docker/docker/internal/multierror
|
github.com/docker/docker/internal/multierror
|
||||||
github.com/docker/docker/pkg/archive
|
github.com/docker/docker/pkg/archive
|
||||||
github.com/docker/docker/pkg/homedir
|
github.com/docker/docker/pkg/homedir
|
||||||
|
|
Loading…
Reference in New Issue