Skip to content

Commit 01dcba1

Browse files
loresusopoiana
authored andcommitted
new(pkg/oci/puller): introduce a new function to retrieve config layer of an artifact
This is necessary since dependencies are stored in the config layer. Signed-off-by: Lorenzo Susini <[email protected]>
1 parent 65d6f5c commit 01dcba1

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

pkg/oci/puller/puller.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"encoding/json"
2020
"fmt"
2121
"io"
22+
"runtime"
2223

2324
v1 "github.com/opencontainers/image-spec/specs-go/v1"
2425
"oras.land/oras-go/v2"
@@ -154,3 +155,75 @@ func manifestFromDesc(ctx context.Context, target oras.Target, desc *v1.Descript
154155

155156
return &manifest, nil
156157
}
158+
159+
// PullConfig fetches only the config layer from a given ref.
160+
func (p *Puller) PullConfigLayer(ctx context.Context, ref string) (io.Reader, error) {
161+
repo, err := repository.NewRepository(ref, repository.WithClient(p.Client))
162+
if err != nil {
163+
return nil, err
164+
}
165+
166+
desc, manifestReader, err := repo.FetchReference(ctx, ref)
167+
if err != nil {
168+
return nil, fmt.Errorf("unable to fetch reference %q", ref)
169+
}
170+
defer manifestReader.Close()
171+
172+
// Resolve to actual manifest if an index is found.
173+
if desc.MediaType == v1.MediaTypeImageIndex {
174+
var index v1.Index
175+
_, indexReader, err := repo.FetchReference(ctx, ref)
176+
if err != nil {
177+
return nil, fmt.Errorf("unable to fetch index for ref %q", ref)
178+
}
179+
180+
indexBytes, err := io.ReadAll(indexReader)
181+
if err = json.Unmarshal(indexBytes, &index); err != nil {
182+
return nil, fmt.Errorf("unable to unmarshal manifest: %w", err)
183+
}
184+
185+
// todo: decide if goos or arch should be passed to this function
186+
found := false
187+
for _, manifest := range index.Manifests {
188+
if manifest.Platform.OS == runtime.GOOS &&
189+
manifest.Platform.Architecture == runtime.GOARCH {
190+
desc = manifest
191+
found = true
192+
break
193+
}
194+
}
195+
196+
if !found {
197+
return nil, fmt.Errorf("unable to find a manifest matching the given platform: %s %s", runtime.GOOS, runtime.GOARCH)
198+
}
199+
200+
manifestReader, err = repo.Fetch(ctx, desc)
201+
if err != nil {
202+
return nil, fmt.Errorf("unable to fetch manifest desc with digest %s: %w", desc.Digest.String(), err)
203+
}
204+
}
205+
206+
var manifest v1.Manifest
207+
manifestBytes, err := io.ReadAll(manifestReader)
208+
if err != nil {
209+
return nil, fmt.Errorf("unable to read bytes from manifest reader for ref %q", ref)
210+
}
211+
212+
if err = json.Unmarshal(manifestBytes, &manifest); err != nil {
213+
return nil, fmt.Errorf("unable to unmarshal manifest: %w", err)
214+
}
215+
216+
configRef := manifest.Config.Digest.String()
217+
218+
descriptor, err := repo.Blobs().Resolve(ctx, configRef)
219+
if err != nil {
220+
return nil, fmt.Errorf("unable to resolve to get descriptor for config blob %q", configRef)
221+
}
222+
223+
rc, err := repo.Fetch(ctx, descriptor)
224+
if err != nil {
225+
return nil, fmt.Errorf("unable to fetch descriptor with digest: %s", desc.Digest.String())
226+
}
227+
228+
return rc, nil
229+
}

0 commit comments

Comments
 (0)