|
| 1 | +package archive |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "strings" |
| 6 | + |
| 7 | + "github.com/containers/image/docker/reference" |
| 8 | + ctrImage "github.com/containers/image/image" |
| 9 | + "github.com/containers/image/transports" |
| 10 | + "github.com/containers/image/types" |
| 11 | + "github.com/pkg/errors" |
| 12 | +) |
| 13 | + |
| 14 | +func init() { |
| 15 | + transports.Register(Transport) |
| 16 | +} |
| 17 | + |
| 18 | +// Transport is an ImageTransport for local Docker archives. |
| 19 | +var Transport = archiveTransport{} |
| 20 | + |
| 21 | +type archiveTransport struct{} |
| 22 | + |
| 23 | +func (t archiveTransport) Name() string { |
| 24 | + return "docker-archive" |
| 25 | +} |
| 26 | + |
| 27 | +// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an ImageReference. |
| 28 | +func (t archiveTransport) ParseReference(reference string) (types.ImageReference, error) { |
| 29 | + return ParseReference(reference) |
| 30 | +} |
| 31 | + |
| 32 | +// ValidatePolicyConfigurationScope checks that scope is a valid name for a signature.PolicyTransportScopes keys |
| 33 | +// (i.e. a valid PolicyConfigurationIdentity() or PolicyConfigurationNamespaces() return value). |
| 34 | +// It is acceptable to allow an invalid value which will never be matched, it can "only" cause user confusion. |
| 35 | +// scope passed to this function will not be "", that value is always allowed. |
| 36 | +func (t archiveTransport) ValidatePolicyConfigurationScope(scope string) error { |
| 37 | + // See the explanation in archiveReference.PolicyConfigurationIdentity. |
| 38 | + return errors.New(`docker-archive: does not support any scopes except the default "" one`) |
| 39 | +} |
| 40 | + |
| 41 | +// archiveReference is an ImageReference for Docker images. |
| 42 | +type archiveReference struct { |
| 43 | + destinationRef reference.NamedTagged // only used for destinations |
| 44 | + path string |
| 45 | +} |
| 46 | + |
| 47 | +// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an Docker ImageReference. |
| 48 | +func ParseReference(refString string) (types.ImageReference, error) { |
| 49 | + if refString == "" { |
| 50 | + return nil, errors.Errorf("docker-archive reference %s isn't of the form <path>[:<reference>]", refString) |
| 51 | + } |
| 52 | + |
| 53 | + parts := strings.SplitN(refString, ":", 2) |
| 54 | + path := parts[0] |
| 55 | + var destinationRef reference.NamedTagged |
| 56 | + |
| 57 | + // A :tag was specified, which is only necessary for destinations. |
| 58 | + if len(parts) == 2 { |
| 59 | + ref, err := reference.ParseNormalizedNamed(parts[1]) |
| 60 | + if err != nil { |
| 61 | + return nil, errors.Wrapf(err, "docker-archive parsing reference") |
| 62 | + } |
| 63 | + ref = reference.TagNameOnly(ref) |
| 64 | + |
| 65 | + if _, isDigest := ref.(reference.Canonical); isDigest { |
| 66 | + return nil, errors.Errorf("docker-archive doesn't support digest references: %s", refString) |
| 67 | + } |
| 68 | + |
| 69 | + refTagged, isTagged := ref.(reference.NamedTagged) |
| 70 | + if !isTagged { |
| 71 | + // Really shouldn't be hit... |
| 72 | + return nil, errors.Errorf("internal error: reference is not tagged even after reference.TagNameOnly: %s", refString) |
| 73 | + } |
| 74 | + destinationRef = refTagged |
| 75 | + } |
| 76 | + |
| 77 | + return archiveReference{ |
| 78 | + destinationRef: destinationRef, |
| 79 | + path: path, |
| 80 | + }, nil |
| 81 | +} |
| 82 | + |
| 83 | +func (ref archiveReference) Transport() types.ImageTransport { |
| 84 | + return Transport |
| 85 | +} |
| 86 | + |
| 87 | +// StringWithinTransport returns a string representation of the reference, which MUST be such that |
| 88 | +// reference.Transport().ParseReference(reference.StringWithinTransport()) returns an equivalent reference. |
| 89 | +// NOTE: The returned string is not promised to be equal to the original input to ParseReference; |
| 90 | +// e.g. default attribute values omitted by the user may be filled in in the return value, or vice versa. |
| 91 | +// WARNING: Do not use the return value in the UI to describe an image, it does not contain the Transport().Name() prefix. |
| 92 | +func (ref archiveReference) StringWithinTransport() string { |
| 93 | + if ref.destinationRef == nil { |
| 94 | + return ref.path |
| 95 | + } |
| 96 | + return fmt.Sprintf("%s:%s", ref.path, ref.destinationRef.String()) |
| 97 | +} |
| 98 | + |
| 99 | +// DockerReference returns a Docker reference associated with this reference |
| 100 | +// (fully explicit, i.e. !reference.IsNameOnly, but reflecting user intent, |
| 101 | +// not e.g. after redirect or alias processing), or nil if unknown/not applicable. |
| 102 | +func (ref archiveReference) DockerReference() reference.Named { |
| 103 | + return ref.destinationRef |
| 104 | +} |
| 105 | + |
| 106 | +// PolicyConfigurationIdentity returns a string representation of the reference, suitable for policy lookup. |
| 107 | +// This MUST reflect user intent, not e.g. after processing of third-party redirects or aliases; |
| 108 | +// The value SHOULD be fully explicit about its semantics, with no hidden defaults, AND canonical |
| 109 | +// (i.e. various references with exactly the same semantics should return the same configuration identity) |
| 110 | +// It is fine for the return value to be equal to StringWithinTransport(), and it is desirable but |
| 111 | +// not required/guaranteed that it will be a valid input to Transport().ParseReference(). |
| 112 | +// Returns "" if configuration identities for these references are not supported. |
| 113 | +func (ref archiveReference) PolicyConfigurationIdentity() string { |
| 114 | + // Punt, the justification is similar to dockerReference.PolicyConfigurationIdentity. |
| 115 | + return "" |
| 116 | +} |
| 117 | + |
| 118 | +// PolicyConfigurationNamespaces returns a list of other policy configuration namespaces to search |
| 119 | +// for if explicit configuration for PolicyConfigurationIdentity() is not set. The list will be processed |
| 120 | +// in order, terminating on first match, and an implicit "" is always checked at the end. |
| 121 | +// It is STRONGLY recommended for the first element, if any, to be a prefix of PolicyConfigurationIdentity(), |
| 122 | +// and each following element to be a prefix of the element preceding it. |
| 123 | +func (ref archiveReference) PolicyConfigurationNamespaces() []string { |
| 124 | + // TODO |
| 125 | + return []string{} |
| 126 | +} |
| 127 | + |
| 128 | +// NewImage returns a types.Image for this reference, possibly specialized for this ImageTransport. |
| 129 | +// The caller must call .Close() on the returned Image. |
| 130 | +// NOTE: If any kind of signature verification should happen, build an UnparsedImage from the value returned by NewImageSource, |
| 131 | +// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage. |
| 132 | +func (ref archiveReference) NewImage(ctx *types.SystemContext) (types.Image, error) { |
| 133 | + src := newImageSource(ctx, ref) |
| 134 | + return ctrImage.FromSource(src) |
| 135 | +} |
| 136 | + |
| 137 | +// NewImageSource returns a types.ImageSource for this reference, |
| 138 | +// asking the backend to use a manifest from requestedManifestMIMETypes if possible. |
| 139 | +// nil requestedManifestMIMETypes means manifest.DefaultRequestedManifestMIMETypes. |
| 140 | +// The caller must call .Close() on the returned ImageSource. |
| 141 | +func (ref archiveReference) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) { |
| 142 | + return newImageSource(ctx, ref), nil |
| 143 | +} |
| 144 | + |
| 145 | +// NewImageDestination returns a types.ImageDestination for this reference. |
| 146 | +// The caller must call .Close() on the returned ImageDestination. |
| 147 | +func (ref archiveReference) NewImageDestination(ctx *types.SystemContext) (types.ImageDestination, error) { |
| 148 | + return newImageDestination(ctx, ref) |
| 149 | +} |
| 150 | + |
| 151 | +// DeleteImage deletes the named image from the registry, if supported. |
| 152 | +func (ref archiveReference) DeleteImage(ctx *types.SystemContext) error { |
| 153 | + // Not really supported, for safety reasons. |
| 154 | + return errors.New("Deleting images not implemented for docker-archive: images") |
| 155 | +} |
0 commit comments