mirror of
https://github.com/containers/image.git
synced 2025-04-18 19:44:05 +03:00
This is just the minimal update: the gofmt-created updates have been reviewed and edited to preserve original semantic intent, but I didn't review all existing comments to benefit from the new syntax. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
220 lines
11 KiB
Go
220 lines
11 KiB
Go
package daemon
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"fmt"
|
||
|
||
"github.com/containers/image/v5/docker/policyconfiguration"
|
||
"github.com/containers/image/v5/docker/reference"
|
||
"github.com/containers/image/v5/internal/image"
|
||
"github.com/containers/image/v5/transports"
|
||
"github.com/containers/image/v5/types"
|
||
"github.com/opencontainers/go-digest"
|
||
)
|
||
|
||
func init() {
|
||
transports.Register(Transport)
|
||
}
|
||
|
||
// Transport is an ImageTransport for images managed by a local Docker daemon.
|
||
var Transport = daemonTransport{}
|
||
|
||
type daemonTransport struct{}
|
||
|
||
// Name returns the name of the transport, which must be unique among other transports.
|
||
func (t daemonTransport) Name() string {
|
||
return "docker-daemon"
|
||
}
|
||
|
||
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an ImageReference.
|
||
func (t daemonTransport) ParseReference(reference string) (types.ImageReference, error) {
|
||
return ParseReference(reference)
|
||
}
|
||
|
||
// ValidatePolicyConfigurationScope checks that scope is a valid name for a signature.PolicyTransportScopes keys
|
||
// (i.e. a valid PolicyConfigurationIdentity() or PolicyConfigurationNamespaces() return value).
|
||
// It is acceptable to allow an invalid value which will never be matched, it can "only" cause user confusion.
|
||
// scope passed to this function will not be "", that value is always allowed.
|
||
func (t daemonTransport) ValidatePolicyConfigurationScope(scope string) error {
|
||
// ID values cannot be effectively namespaced, and are clearly invalid host:port values.
|
||
if _, err := digest.Parse(scope); err == nil {
|
||
return fmt.Errorf(`docker-daemon: can not use algo:digest value %s as a namespace`, scope)
|
||
}
|
||
|
||
// FIXME? We could be verifying the various character set and length restrictions
|
||
// from docker/distribution/reference.regexp.go, but other than that there
|
||
// are few semantically invalid strings.
|
||
return nil
|
||
}
|
||
|
||
// daemonReference is an ImageReference for images managed by a local Docker daemon
|
||
// Exactly one of id and ref can be set.
|
||
// For daemonImageSource, both id and ref are acceptable, ref must not be a NameOnly (interpreted as all tags in that repository by the daemon)
|
||
// For daemonImageDestination, it must be a ref, which is NamedTagged.
|
||
// (We could, in principle, also allow storing images without tagging them, and the user would have to refer to them using the docker image ID = config digest.
|
||
// Using the config digest requires the caller to parse the manifest themselves, which is very cumbersome; so, for now, we don’t bother.)
|
||
type daemonReference struct {
|
||
id digest.Digest
|
||
ref reference.Named // !reference.IsNameOnly
|
||
}
|
||
|
||
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an ImageReference.
|
||
func ParseReference(refString string) (types.ImageReference, error) {
|
||
// This is intended to be compatible with reference.ParseAnyReference, but more strict about refusing some of the ambiguous cases.
|
||
// In particular, this rejects unprefixed digest values (64 hex chars), and sha256 digest prefixes (sha256:fewer-than-64-hex-chars).
|
||
|
||
// digest:hexstring is structurally the same as a reponame:tag (meaning docker.io/library/reponame:tag).
|
||
// reference.ParseAnyReference interprets such strings as digests.
|
||
if dgst, err := digest.Parse(refString); err == nil {
|
||
// The daemon explicitly refuses to tag images with a reponame equal to digest.Canonical - but _only_ this digest name.
|
||
// Other digest references are ambiguous, so refuse them.
|
||
if dgst.Algorithm() != digest.Canonical {
|
||
return nil, fmt.Errorf("Invalid docker-daemon: reference %s: only digest algorithm %s accepted", refString, digest.Canonical)
|
||
}
|
||
return NewReference(dgst, nil)
|
||
}
|
||
|
||
ref, err := reference.ParseNormalizedNamed(refString) // This also rejects unprefixed digest values
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if reference.FamiliarName(ref) == digest.Canonical.String() {
|
||
return nil, fmt.Errorf("Invalid docker-daemon: reference %s: The %s repository name is reserved for (non-shortened) digest references", refString, digest.Canonical)
|
||
}
|
||
return NewReference("", ref)
|
||
}
|
||
|
||
// NewReference returns a docker-daemon reference for either the supplied image ID (config digest) or the supplied reference (which must satisfy !reference.IsNameOnly)
|
||
func NewReference(id digest.Digest, ref reference.Named) (types.ImageReference, error) {
|
||
if id != "" && ref != nil {
|
||
return nil, errors.New("docker-daemon: reference must not have an image ID and a reference string specified at the same time")
|
||
}
|
||
if ref != nil {
|
||
if reference.IsNameOnly(ref) {
|
||
return nil, fmt.Errorf("docker-daemon: reference %s has neither a tag nor a digest", reference.FamiliarString(ref))
|
||
}
|
||
// A github.com/distribution/reference value can have a tag and a digest at the same time!
|
||
// Most versions of docker/reference do not handle that (ignoring the tag), so reject such input.
|
||
// This MAY be accepted in the future.
|
||
// (Even if it were supported, the semantics of policy namespaces are unclear - should we drop
|
||
// the tag or the digest first?)
|
||
_, isTagged := ref.(reference.NamedTagged)
|
||
_, isDigested := ref.(reference.Canonical)
|
||
if isTagged && isDigested {
|
||
return nil, fmt.Errorf("docker-daemon: references with both a tag and digest are currently not supported")
|
||
}
|
||
}
|
||
return daemonReference{
|
||
id: id,
|
||
ref: ref,
|
||
}, nil
|
||
}
|
||
|
||
func (ref daemonReference) Transport() types.ImageTransport {
|
||
return Transport
|
||
}
|
||
|
||
// StringWithinTransport returns a string representation of the reference, which MUST be such that
|
||
// reference.Transport().ParseReference(reference.StringWithinTransport()) returns an equivalent reference.
|
||
// NOTE: The returned string is not promised to be equal to the original input to ParseReference;
|
||
// e.g. default attribute values omitted by the user may be filled in in the return value, or vice versa.
|
||
// WARNING: Do not use the return value in the UI to describe an image, it does not contain the Transport().Name() prefix;
|
||
// instead, see transports.ImageName().
|
||
func (ref daemonReference) StringWithinTransport() string {
|
||
switch {
|
||
case ref.id != "":
|
||
return ref.id.String()
|
||
case ref.ref != nil:
|
||
return reference.FamiliarString(ref.ref)
|
||
default: // Coverage: Should never happen, NewReference above should refuse such values.
|
||
panic("Internal inconsistency: daemonReference has empty id and nil ref")
|
||
}
|
||
}
|
||
|
||
// DockerReference returns a Docker reference associated with this reference
|
||
// (fully explicit, i.e. !reference.IsNameOnly, but reflecting user intent,
|
||
// not e.g. after redirect or alias processing), or nil if unknown/not applicable.
|
||
func (ref daemonReference) DockerReference() reference.Named {
|
||
return ref.ref // May be nil
|
||
}
|
||
|
||
// PolicyConfigurationIdentity returns a string representation of the reference, suitable for policy lookup.
|
||
// This MUST reflect user intent, not e.g. after processing of third-party redirects or aliases;
|
||
// The value SHOULD be fully explicit about its semantics, with no hidden defaults, AND canonical
|
||
// (i.e. various references with exactly the same semantics should return the same configuration identity)
|
||
// It is fine for the return value to be equal to StringWithinTransport(), and it is desirable but
|
||
// not required/guaranteed that it will be a valid input to Transport().ParseReference().
|
||
// Returns "" if configuration identities for these references are not supported.
|
||
func (ref daemonReference) PolicyConfigurationIdentity() string {
|
||
// We must allow referring to images in the daemon by image ID, otherwise untagged images would not be accessible.
|
||
// But the existence of image IDs means that we can’t truly well namespace the input:
|
||
// a single image can be namespaced either using the name or the ID depending on how it is named.
|
||
//
|
||
// That’s fairly unexpected, but we have to cope somehow.
|
||
//
|
||
// So, use the ordinary docker/policyconfiguration namespacing for named images.
|
||
// image IDs all fall into the root namespace.
|
||
// Users can set up the root namespace to be either untrusted or rejected,
|
||
// and to set up specific trust for named namespaces. This allows verifying image
|
||
// identity when a name is known, and unnamed images would be untrusted or rejected.
|
||
switch {
|
||
case ref.id != "":
|
||
return "" // This still allows using the default "" scope to define a global policy for ID-identified images.
|
||
case ref.ref != nil:
|
||
res, err := policyconfiguration.DockerReferenceIdentity(ref.ref)
|
||
if res == "" || err != nil { // Coverage: Should never happen, NewReference above should refuse values which could cause a failure.
|
||
panic(fmt.Sprintf("Internal inconsistency: policyconfiguration.DockerReferenceIdentity returned %#v, %v", res, err))
|
||
}
|
||
return res
|
||
default: // Coverage: Should never happen, NewReference above should refuse such values.
|
||
panic("Internal inconsistency: daemonReference has empty id and nil ref")
|
||
}
|
||
}
|
||
|
||
// PolicyConfigurationNamespaces returns a list of other policy configuration namespaces to search
|
||
// for if explicit configuration for PolicyConfigurationIdentity() is not set. The list will be processed
|
||
// in order, terminating on first match, and an implicit "" is always checked at the end.
|
||
// It is STRONGLY recommended for the first element, if any, to be a prefix of PolicyConfigurationIdentity(),
|
||
// and each following element to be a prefix of the element preceding it.
|
||
func (ref daemonReference) PolicyConfigurationNamespaces() []string {
|
||
// See the explanation in daemonReference.PolicyConfigurationIdentity.
|
||
switch {
|
||
case ref.id != "":
|
||
return []string{}
|
||
case ref.ref != nil:
|
||
return policyconfiguration.DockerReferenceNamespaces(ref.ref)
|
||
default: // Coverage: Should never happen, NewReference above should refuse such values.
|
||
panic("Internal inconsistency: daemonReference has empty id and nil ref")
|
||
}
|
||
}
|
||
|
||
// NewImage returns a types.ImageCloser for this reference, possibly specialized for this ImageTransport.
|
||
// The caller must call .Close() on the returned ImageCloser.
|
||
// NOTE: If any kind of signature verification should happen, build an UnparsedImage from the value returned by NewImageSource,
|
||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
||
// WARNING: This may not do the right thing for a manifest list, see image.FromSource for details.
|
||
func (ref daemonReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
|
||
return image.FromReference(ctx, sys, ref)
|
||
}
|
||
|
||
// NewImageSource returns a types.ImageSource for this reference.
|
||
// The caller must call .Close() on the returned ImageSource.
|
||
func (ref daemonReference) NewImageSource(ctx context.Context, sys *types.SystemContext) (types.ImageSource, error) {
|
||
return newImageSource(ctx, sys, ref)
|
||
}
|
||
|
||
// NewImageDestination returns a types.ImageDestination for this reference.
|
||
// The caller must call .Close() on the returned ImageDestination.
|
||
func (ref daemonReference) NewImageDestination(ctx context.Context, sys *types.SystemContext) (types.ImageDestination, error) {
|
||
return newImageDestination(ctx, sys, ref)
|
||
}
|
||
|
||
// DeleteImage deletes the named image from the registry, if supported.
|
||
func (ref daemonReference) DeleteImage(ctx context.Context, sys *types.SystemContext) error {
|
||
// Should this just untag the image? Should this stop running containers?
|
||
// The semantics is not quite as clear as for remote repositories.
|
||
// The user can run (docker rmi) directly anyway, so, for now(?), punt instead of trying to guess what the user meant.
|
||
return errors.New("Deleting images not implemented for docker-daemon: images")
|
||
}
|