Skip to content

Commit 02f05a1

Browse files
committed
feat: exists and put manifest in containerd content store
1 parent 656b45d commit 02f05a1

File tree

1 file changed

+20
-100
lines changed

1 file changed

+20
-100
lines changed

internal/storage/containerd/manifest.go

Lines changed: 20 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,31 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"github.com/containerd/containerd/v2/core/content"
8-
"github.com/containerd/containerd/v2/core/images"
9-
"github.com/containerd/containerd/v2/core/leases"
10-
"github.com/containerd/errdefs"
117
"github.com/distribution/distribution/v3"
128
"github.com/distribution/distribution/v3/manifest/manifestlist"
139
"github.com/distribution/distribution/v3/manifest/ocischema"
1410
"github.com/distribution/distribution/v3/manifest/schema2"
1511
"github.com/distribution/reference"
1612
"github.com/opencontainers/go-digest"
17-
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
1813
"github.com/sirupsen/logrus"
1914
)
2015

21-
// manifestService implements distribution.ManifestService backed by containerd.
16+
// manifestService implements distribution.ManifestService backed by containerd content store.
2217
type manifestService struct {
23-
client *Client
2418
repo reference.Named
25-
blobStore distribution.BlobStore
19+
blobStore *blobStore
2620
}
2721

28-
// Exists checks if a manifest exists in containerd content store by digest.
22+
// Exists checks if a manifest exists in the blob store by digest.
2923
func (m *manifestService) Exists(ctx context.Context, dgst digest.Digest) (bool, error) {
30-
return content.Exists(ctx, m.client.ContentStore(), ocispec.Descriptor{Digest: dgst})
24+
_, err := m.blobStore.Stat(ctx, dgst)
25+
if errors.Is(err, distribution.ErrBlobUnknown) {
26+
return false, nil
27+
}
28+
return err == nil, err
3129
}
3230

33-
// Get retrieves a manifest by digest.
31+
// Get retrieves a manifest from the blob store by its digest.
3432
func (m *manifestService) Get(
3533
ctx context.Context, dgst digest.Digest, _ ...distribution.ManifestServiceOption,
3634
) (distribution.Manifest, error) {
@@ -57,114 +55,34 @@ func (m *manifestService) Get(
5755
"digest": dgst,
5856
"mediatype": mediaType,
5957
},
60-
).Debug("Got manifest from containerd content store.")
58+
).Debug("Got manifest from blob store.")
6159
}
6260

6361
return manifest, nil
6462
}
6563

66-
// Put stores a manifest.
64+
// Put stores a manifest in the blob store and returns its digest.
6765
func (m *manifestService) Put(
68-
ctx context.Context, manifest distribution.Manifest, options ...distribution.ManifestServiceOption,
66+
ctx context.Context, manifest distribution.Manifest, _ ...distribution.ManifestServiceOption,
6967
) (digest.Digest, error) {
70-
ctx = m.client.Context(ctx)
71-
72-
// Marshal the manifest
7368
mediaType, payload, err := manifest.Payload()
7469
if err != nil {
75-
return "", fmt.Errorf("failed to get manifest payload: %w", err)
70+
return "", fmt.Errorf("get manifest payload: %w", err)
7671
}
7772

78-
// Calculate digest
79-
dgst := digest.FromBytes(payload)
80-
81-
// Create a lease to prevent garbage collection during the operation
82-
lease, err := m.client.LeasesService().Create(ctx, leases.WithRandomID())
73+
desc, err := m.blobStore.Put(ctx, mediaType, payload)
8374
if err != nil {
84-
return "", fmt.Errorf("failed to create lease: %w", err)
85-
}
86-
defer m.client.LeasesService().Delete(ctx, lease)
87-
88-
// Write the manifest to the content store
89-
ref := fmt.Sprintf("%s@%s", m.repo.String(), dgst)
90-
writer, err := m.client.ContentStore().Writer(
91-
ctx,
92-
content.WithRef(ref),
93-
content.WithDescriptor(
94-
ocispec.Descriptor{
95-
MediaType: mediaType,
96-
Digest: dgst,
97-
Size: int64(len(payload)),
98-
},
99-
),
100-
)
101-
if err != nil {
102-
return "", fmt.Errorf("failed to create content writer: %w", err)
75+
return "", fmt.Errorf("put manifest in blob store: %w", err)
10376
}
10477

105-
if _, err := writer.Write(payload); err != nil {
106-
writer.Close()
107-
return "", fmt.Errorf("failed to write manifest: %w", err)
108-
}
109-
110-
if err := writer.Commit(ctx, 0, dgst); err != nil {
111-
if !errdefs.IsAlreadyExists(err) {
112-
return "", fmt.Errorf("failed to commit manifest: %w", err)
113-
}
114-
}
115-
116-
// If this is a tag operation (from docker push), update the image store
117-
for _, option := range options {
118-
if opt, ok := option.(distribution.WithTagOption); ok {
119-
tag := opt.Tag
120-
if err := m.updateImageStore(ctx, m.repo, tag, dgst, mediaType); err != nil {
121-
return "", fmt.Errorf("failed to update image store: %w", err)
122-
}
123-
}
124-
}
125-
126-
return dgst, nil
78+
return desc.Digest, nil
12779
}
12880

129-
// Delete removes a manifest by digest.
130-
func (m *manifestService) Delete(ctx context.Context, dgst digest.Digest) error {
131-
ctx = m.client.Context(ctx)
132-
133-
// For now, we don't support deletion to keep things simple
134-
// Containerd's garbage collection should handle cleanup
81+
// Delete is not supported to keep things simple.
82+
func (m *manifestService) Delete(_ context.Context, _ digest.Digest) error {
13583
return distribution.ErrUnsupported
13684
}
13785

138-
// updateImageStore updates the containerd image store with the manifest.
139-
func (m *manifestService) updateImageStore(
140-
ctx context.Context, repo reference.Named, tag string, dgst digest.Digest, mediaType string,
141-
) error {
142-
// Create the image reference
143-
ref := fmt.Sprintf("%s:%s", repo.String(), tag)
144-
145-
// Create the image
146-
img := images.Image{
147-
Name: ref,
148-
Target: ocispec.Descriptor{
149-
MediaType: mediaType,
150-
Digest: dgst,
151-
Size: 0, // Will be filled by containerd
152-
},
153-
}
154-
155-
// Update or create the image
156-
_, err := m.client.ImageStore().Update(ctx, img)
157-
if err != nil {
158-
// If update fails, try to create
159-
_, err = m.client.ImageStore().Create(ctx, img)
160-
if err != nil && !errdefs.IsAlreadyExists(err) {
161-
return err
162-
}
163-
}
164-
165-
return nil
166-
}
167-
16886
// unmarshalManifest attempts to unmarshal a manifest in various formats.
16987
func unmarshalManifest(blob []byte) (distribution.Manifest, error) {
17088
// Try OCI manifest.
@@ -185,5 +103,7 @@ func unmarshalManifest(blob []byte) (distribution.Manifest, error) {
185103
return &manifestList, nil
186104
}
187105

106+
// TODO: handle oci index? Use distribution.UnmarshalManifest + basic unmarshal to get the media type from blob?
107+
188108
return nil, fmt.Errorf("unknown manifest format")
189109
}

0 commit comments

Comments
 (0)