2015-08-21 06:50:15 +02:00
|
|
|
package distribution
|
|
|
|
|
|
|
|
import (
|
2017-08-12 00:31:16 +02:00
|
|
|
"context"
|
2015-08-21 06:50:15 +02:00
|
|
|
"fmt"
|
2016-01-20 18:59:19 +01:00
|
|
|
"mime"
|
2015-08-21 06:50:15 +02:00
|
|
|
|
2016-12-17 01:28:34 +01:00
|
|
|
"github.com/opencontainers/go-digest"
|
2024-09-06 11:59:19 +02:00
|
|
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
2015-08-21 06:50:15 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// Manifest represents a registry object specifying a set of
|
|
|
|
// references and an optional target
|
|
|
|
type Manifest interface {
|
|
|
|
// References returns a list of objects which make up this manifest.
|
2016-10-13 02:20:27 +02:00
|
|
|
// A reference is anything which can be represented by a
|
2024-09-06 11:59:19 +02:00
|
|
|
// Descriptor. These can consist of layers, resources or other
|
2016-10-13 02:20:27 +02:00
|
|
|
// manifests.
|
|
|
|
//
|
|
|
|
// While no particular order is required, implementations should return
|
|
|
|
// them from highest to lowest priority. For example, one might want to
|
|
|
|
// return the base layer before the top layer.
|
2024-09-06 11:59:19 +02:00
|
|
|
References() []v1.Descriptor
|
2015-08-21 06:50:15 +02:00
|
|
|
|
|
|
|
// Payload provides the serialized format of the manifest, in addition to
|
2017-01-18 07:15:40 +01:00
|
|
|
// the media type.
|
|
|
|
Payload() (mediaType string, payload []byte, err error)
|
2015-08-21 06:50:15 +02:00
|
|
|
}
|
|
|
|
|
2023-08-15 15:37:43 +02:00
|
|
|
// ManifestService describes operations on manifests.
|
2015-08-21 06:50:15 +02:00
|
|
|
type ManifestService interface {
|
|
|
|
// Exists returns true if the manifest exists.
|
|
|
|
Exists(ctx context.Context, dgst digest.Digest) (bool, error)
|
|
|
|
|
|
|
|
// Get retrieves the manifest specified by the given digest
|
|
|
|
Get(ctx context.Context, dgst digest.Digest, options ...ManifestServiceOption) (Manifest, error)
|
|
|
|
|
|
|
|
// Put creates or updates the given manifest returning the manifest digest
|
|
|
|
Put(ctx context.Context, manifest Manifest, options ...ManifestServiceOption) (digest.Digest, error)
|
|
|
|
|
|
|
|
// Delete removes the manifest specified by the given digest. Deleting
|
|
|
|
// a manifest that doesn't exist will return ErrManifestNotFound
|
|
|
|
Delete(ctx context.Context, dgst digest.Digest) error
|
2016-01-19 23:26:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ManifestEnumerator enables iterating over manifests
|
|
|
|
type ManifestEnumerator interface {
|
|
|
|
// Enumerate calls ingester for each manifest.
|
|
|
|
Enumerate(ctx context.Context, ingester func(digest.Digest) error) error
|
|
|
|
}
|
2015-08-21 06:50:15 +02:00
|
|
|
|
Descriptor: do not implement Describable interface
Commit cb6f0023500c3d2afb8c9f3ee4a0097526192156 implemented a generic
Manifest interface to represent manifests in the registry and remove
references to schema specific manifests.
As part of this refactor, the Describable interface was introduced,
which allowed for a single ManifestBuilder interface to handle both
schema1 and schema2 manifests. Implementations of Describable are
generally objects which can be described, not simply descriptors, but
for convenience, this interface was also implemented on Descriptor in
2ff77c00bad887928be04367f0dd58f6aed5b756.
This interface served its purpose, but no longer needed for most cases;
schema2 (and OCI) descriptors do not need this method, making it only
needed for `schema1.Reference`, which is now deprecated.
Requiring this interface to be implemented limits interoperability
between distribution's Descriptor and the OCI Descriptor types, which
are identical in every other way, except for the presence of the
Describable interface.
This patch:
- Removes the `Descriptor.Descriptor()` method (no longer implementing
the `Describable` interface).
- Updates ManifestBuilder interface and implementations to accept either
- Updates ManifestBuilder interface and implementations to accept a
`Descriptor`.
After this patch, the caller is responsible for changing a describable
type into a descriptor;
builder.AppendReference(describable.Descriptor())
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-04-30 17:53:17 +02:00
|
|
|
// Describable is an interface for descriptors.
|
|
|
|
//
|
|
|
|
// Implementations of Describable are generally objects which can be
|
|
|
|
// described, not simply descriptors.
|
2015-08-21 06:50:15 +02:00
|
|
|
type Describable interface {
|
Descriptor: do not implement Describable interface
Commit cb6f0023500c3d2afb8c9f3ee4a0097526192156 implemented a generic
Manifest interface to represent manifests in the registry and remove
references to schema specific manifests.
As part of this refactor, the Describable interface was introduced,
which allowed for a single ManifestBuilder interface to handle both
schema1 and schema2 manifests. Implementations of Describable are
generally objects which can be described, not simply descriptors, but
for convenience, this interface was also implemented on Descriptor in
2ff77c00bad887928be04367f0dd58f6aed5b756.
This interface served its purpose, but no longer needed for most cases;
schema2 (and OCI) descriptors do not need this method, making it only
needed for `schema1.Reference`, which is now deprecated.
Requiring this interface to be implemented limits interoperability
between distribution's Descriptor and the OCI Descriptor types, which
are identical in every other way, except for the presence of the
Describable interface.
This patch:
- Removes the `Descriptor.Descriptor()` method (no longer implementing
the `Describable` interface).
- Updates ManifestBuilder interface and implementations to accept either
- Updates ManifestBuilder interface and implementations to accept a
`Descriptor`.
After this patch, the caller is responsible for changing a describable
type into a descriptor;
builder.AppendReference(describable.Descriptor())
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-04-30 17:53:17 +02:00
|
|
|
// Descriptor returns the descriptor.
|
2024-09-06 11:59:19 +02:00
|
|
|
Descriptor() v1.Descriptor
|
2015-08-21 06:50:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ManifestMediaTypes returns the supported media types for manifests.
|
|
|
|
func ManifestMediaTypes() (mediaTypes []string) {
|
|
|
|
for t := range mappings {
|
2016-01-21 00:22:38 +01:00
|
|
|
if t != "" {
|
|
|
|
mediaTypes = append(mediaTypes, t)
|
|
|
|
}
|
2015-08-21 06:50:15 +02:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalFunc implements manifest unmarshalling a given MediaType
|
2024-09-06 11:59:19 +02:00
|
|
|
type UnmarshalFunc func([]byte) (Manifest, v1.Descriptor, error)
|
2015-08-21 06:50:15 +02:00
|
|
|
|
2019-02-05 01:01:04 +01:00
|
|
|
var mappings = make(map[string]UnmarshalFunc)
|
2015-08-21 06:50:15 +02:00
|
|
|
|
2016-01-26 23:20:23 +01:00
|
|
|
// UnmarshalManifest looks up manifest unmarshal functions based on
|
2015-08-21 06:50:15 +02:00
|
|
|
// MediaType
|
2024-09-06 11:59:19 +02:00
|
|
|
func UnmarshalManifest(ctHeader string, p []byte) (Manifest, v1.Descriptor, error) {
|
2016-01-20 18:59:19 +01:00
|
|
|
// Need to look up by the actual media type, not the raw contents of
|
2016-01-18 18:59:50 +01:00
|
|
|
// the header. Strip semicolons and anything following them.
|
2017-01-18 07:15:40 +01:00
|
|
|
var mediaType string
|
2016-01-20 18:59:19 +01:00
|
|
|
if ctHeader != "" {
|
|
|
|
var err error
|
2017-01-18 07:15:40 +01:00
|
|
|
mediaType, _, err = mime.ParseMediaType(ctHeader)
|
2016-01-20 18:59:19 +01:00
|
|
|
if err != nil {
|
2024-09-06 11:59:19 +02:00
|
|
|
return nil, v1.Descriptor{}, err
|
2016-01-20 18:59:19 +01:00
|
|
|
}
|
2016-01-18 18:59:50 +01:00
|
|
|
}
|
|
|
|
|
2017-01-18 07:15:40 +01:00
|
|
|
unmarshalFunc, ok := mappings[mediaType]
|
2015-08-21 06:50:15 +02:00
|
|
|
if !ok {
|
2016-01-21 18:34:06 +01:00
|
|
|
unmarshalFunc, ok = mappings[""]
|
|
|
|
if !ok {
|
2024-09-06 11:59:19 +02:00
|
|
|
return nil, v1.Descriptor{}, fmt.Errorf("unsupported manifest media type and no default available: %s", mediaType)
|
2016-01-21 18:34:06 +01:00
|
|
|
}
|
2015-08-21 06:50:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return unmarshalFunc(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
// RegisterManifestSchema registers an UnmarshalFunc for a given schema type. This
|
|
|
|
// should be called from specific
|
2017-01-18 07:15:40 +01:00
|
|
|
func RegisterManifestSchema(mediaType string, u UnmarshalFunc) error {
|
|
|
|
if _, ok := mappings[mediaType]; ok {
|
|
|
|
return fmt.Errorf("manifest media type registration would overwrite existing: %s", mediaType)
|
2015-08-21 06:50:15 +02:00
|
|
|
}
|
2017-01-18 07:15:40 +01:00
|
|
|
mappings[mediaType] = u
|
2015-08-21 06:50:15 +02:00
|
|
|
return nil
|
|
|
|
}
|