-
Notifications
You must be signed in to change notification settings - Fork 263
/
ocidownloader.go
115 lines (98 loc) · 3.91 KB
/
ocidownloader.go
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
package ociinstaller
import (
"context"
"encoding/json"
"log"
"strings"
"github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus"
"oras.land/oras-go/v2"
"oras.land/oras-go/v2/content"
"oras.land/oras-go/v2/content/file"
"oras.land/oras-go/v2/content/memory"
"oras.land/oras-go/v2/registry/remote"
"oras.land/oras-go/v2/registry/remote/auth"
"oras.land/oras-go/v2/registry/remote/credentials"
"oras.land/oras-go/v2/registry/remote/retry"
)
type ociDownloader struct {
resolver remotes.Resolver
Images []*SteampipeImage
}
// NewOciDownloader creates and returns a ociDownloader instance
func NewOciDownloader() *ociDownloader {
// oras uses containerd, which uses logrus and is set up to log
// warning and above. Set to ErrrLevel to get rid of unwanted error message
logrus.SetLevel(logrus.ErrorLevel)
return &ociDownloader{
resolver: docker.NewResolver(docker.ResolverOptions{}),
}
}
/*
Pull downloads the image from the given `ref` to the supplied `destDir`
Returns
imageDescription, configDescription, config, imageLayers, error
*/
func (o *ociDownloader) Pull(ctx context.Context, ref string, mediaTypes []string, destDir string) (*ocispec.Descriptor, *ocispec.Descriptor, []byte, []ocispec.Descriptor, error) {
split := strings.Split(ref, ":")
tag := split[len(split)-1]
log.Println("[TRACE] ociDownloader.Pull:", "preparing to pull ref", ref, "tag", tag, "destDir", destDir)
// Create the target file store
memoryStore := memory.New()
fileStore, err := file.NewWithFallbackStorage(destDir, memoryStore)
if err != nil {
return nil, nil, nil, nil, err
}
defer fileStore.Close()
// Connect to the remote repository
repo, err := remote.NewRepository(ref)
if err != nil {
return nil, nil, nil, nil, err
}
// Get credentials from the docker credentials store
storeOpts := credentials.StoreOptions{}
credStore, err := credentials.NewStoreFromDocker(storeOpts)
if err != nil {
return nil, nil, nil, nil, err
}
// Prepare the auth client for the registry and credential store
repo.Client = &auth.Client{
Client: retry.DefaultClient,
Cache: auth.DefaultCache,
Credential: credentials.Credential(credStore), // Use the credential store
}
// Copy from the remote repository to the file store
log.Println("[TRACE] ociDownloader.Pull:", "pulling...")
copyOpt := oras.DefaultCopyOptions
manifestDescriptor, err := oras.Copy(ctx, repo, tag, fileStore, tag, copyOpt)
if err != nil {
log.Println("[TRACE] ociDownloader.Pull:", "failed to pull", ref, err)
return nil, nil, nil, nil, err
}
log.Println("[TRACE] ociDownloader.Pull:", "manifest", manifestDescriptor.Digest, manifestDescriptor.MediaType)
// FIXME: this seems redundant as oras.Copy() already downloads all artifacts, but that's the only I found
// to access the manifest config. Also, it shouldn't be an issue as files are not re-downloaded.
manifestJson, err := content.FetchAll(ctx, fileStore, manifestDescriptor)
if err != nil {
log.Println("[TRACE] ociDownloader.Pull:", "failed to fetch manifest", manifestDescriptor)
return nil, nil, nil, nil, err
}
log.Println("[TRACE] ociDownloader.Pull:", "manifest content", string(manifestJson))
// Parse the fetched manifest
var manifest ocispec.Manifest
err = json.Unmarshal(manifestJson, &manifest)
if err != nil {
log.Println("[TRACE] ociDownloader.Pull:", "failed to unmarshall manifest", manifestJson)
return nil, nil, nil, nil, err
}
// Fetch the config from the file store
configData, err := content.FetchAll(ctx, fileStore, manifest.Config)
if err != nil {
log.Println("[TRACE] ociDownloader.Pull:", "failed to fetch config", manifest.Config.MediaType, err)
return nil, nil, nil, nil, err
}
log.Println("[TRACE] ociDownloader.Pull:", "config", string(configData))
return &manifestDescriptor, &manifest.Config, configData, manifest.Layers, err
}