summaryrefslogtreecommitdiff
path: root/vendor/github.com/containers/image/docker/archive/transport.go
blob: 169a2b2e2fb01e267cc3f188e51a5ea75bf89948 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package archive

import (
	"context"
	"fmt"
	"strings"

	"github.com/containers/image/docker/reference"
	ctrImage "github.com/containers/image/image"
	"github.com/containers/image/transports"
	"github.com/containers/image/types"
	"github.com/pkg/errors"
)

func init() {
	transports.Register(Transport)
}

// Transport is an ImageTransport for local Docker archives.
var Transport = archiveTransport{}

type archiveTransport struct{}

func (t archiveTransport) Name() string {
	return "docker-archive"
}

// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an ImageReference.
func (t archiveTransport) 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 archiveTransport) ValidatePolicyConfigurationScope(scope string) error {
	// See the explanation in archiveReference.PolicyConfigurationIdentity.
	return errors.New(`docker-archive: does not support any scopes except the default "" one`)
}

// archiveReference is an ImageReference for Docker images.
type archiveReference struct {
	destinationRef reference.NamedTagged // only used for destinations
	path           string
}

// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an Docker ImageReference.
func ParseReference(refString string) (types.ImageReference, error) {
	if refString == "" {
		return nil, errors.Errorf("docker-archive reference %s isn't of the form <path>[:<reference>]", refString)
	}

	parts := strings.SplitN(refString, ":", 2)
	path := parts[0]
	var destinationRef reference.NamedTagged

	// A :tag was specified, which is only necessary for destinations.
	if len(parts) == 2 {
		ref, err := reference.ParseNormalizedNamed(parts[1])
		if err != nil {
			return nil, errors.Wrapf(err, "docker-archive parsing reference")
		}
		ref = reference.TagNameOnly(ref)

		if _, isDigest := ref.(reference.Canonical); isDigest {
			return nil, errors.Errorf("docker-archive doesn't support digest references: %s", refString)
		}

		refTagged, isTagged := ref.(reference.NamedTagged)
		if !isTagged {
			// Really shouldn't be hit...
			return nil, errors.Errorf("internal error: reference is not tagged even after reference.TagNameOnly: %s", refString)
		}
		destinationRef = refTagged
	}

	return archiveReference{
		destinationRef: destinationRef,
		path:           path,
	}, nil
}

func (ref archiveReference) 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.
func (ref archiveReference) StringWithinTransport() string {
	if ref.destinationRef == nil {
		return ref.path
	}
	return fmt.Sprintf("%s:%s", ref.path, ref.destinationRef.String())
}

// 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 archiveReference) DockerReference() reference.Named {
	return ref.destinationRef
}

// 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 archiveReference) PolicyConfigurationIdentity() string {
	// Punt, the justification is similar to dockerReference.PolicyConfigurationIdentity.
	return ""
}

// 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 archiveReference) PolicyConfigurationNamespaces() []string {
	// TODO
	return []string{}
}

// 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 archiveReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
	src, err := newImageSource(ctx, ref)
	if err != nil {
		return nil, err
	}
	return ctrImage.FromSource(ctx, sys, src)
}

// NewImageSource returns a types.ImageSource for this reference.
// The caller must call .Close() on the returned ImageSource.
func (ref archiveReference) NewImageSource(ctx context.Context, sys *types.SystemContext) (types.ImageSource, error) {
	return newImageSource(ctx, ref)
}

// NewImageDestination returns a types.ImageDestination for this reference.
// The caller must call .Close() on the returned ImageDestination.
func (ref archiveReference) NewImageDestination(ctx context.Context, sys *types.SystemContext) (types.ImageDestination, error) {
	return newImageDestination(ref)
}

// DeleteImage deletes the named image from the registry, if supported.
func (ref archiveReference) DeleteImage(ctx context.Context, sys *types.SystemContext) error {
	// Not really supported, for safety reasons.
	return errors.New("Deleting images not implemented for docker-archive: images")
}