Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/registry-facade/pkg/registry/resolver.go
2499 views
1
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package registry
6
7
import (
8
"context"
9
"encoding/json"
10
11
"github.com/containerd/containerd/remotes"
12
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
13
redis "github.com/redis/go-redis/v9"
14
)
15
16
type RedisCachedResolver struct {
17
Client *redis.Client
18
Provider ResolverProvider
19
20
d remotes.Resolver
21
}
22
23
var (
24
_ remotes.Resolver = &RedisCachedResolver{}
25
_ ResolverProvider = (&RedisCachedResolver{}).Factory
26
)
27
28
type resolverResult struct {
29
Name string
30
Desc ociv1.Descriptor
31
}
32
33
// Resolve attempts to resolve the reference into a name and descriptor.
34
//
35
// The argument `ref` should be a scheme-less URI representing the remote.
36
// Structurally, it has a host and path. The "host" can be used to directly
37
// reference a specific host or be matched against a specific handler.
38
//
39
// The returned name should be used to identify the referenced entity.
40
// Dependending on the remote namespace, this may be immutable or mutable.
41
// While the name may differ from ref, it should itself be a valid ref.
42
//
43
// If the resolution fails, an error will be returned.
44
func (rcr *RedisCachedResolver) Resolve(ctx context.Context, ref string) (name string, desc ociv1.Descriptor, err error) {
45
raw, _ := rcr.Client.Get(ctx, "resolve."+ref).Result()
46
if raw != "" {
47
var res resolverResult
48
if err := json.Unmarshal([]byte(raw), &res); err == nil {
49
return res.Name, res.Desc, nil
50
}
51
}
52
53
name, desc, err = rcr.resolver().Resolve(ctx, ref)
54
if err != nil {
55
return
56
}
57
58
if raw, err := json.Marshal(resolverResult{Name: name, Desc: desc}); err == nil {
59
rcr.Client.Set(ctx, "resolve."+ref, string(raw), 0)
60
}
61
62
return
63
}
64
65
// Fetcher returns a new fetcher for the provided reference.
66
// All content fetched from the returned fetcher will be
67
// from the namespace referred to by ref.
68
func (rcr *RedisCachedResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
69
return rcr.resolver().Fetcher(ctx, ref)
70
}
71
72
// Pusher returns a new pusher for the provided reference
73
// The returned Pusher should satisfy content.Ingester and concurrent attempts
74
// to push the same blob using the Ingester API should result in ErrUnavailable.
75
func (rcr *RedisCachedResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) {
76
return rcr.resolver().Pusher(ctx, ref)
77
}
78
79
func (rcr *RedisCachedResolver) resolver() remotes.Resolver {
80
if rcr.d == nil {
81
rcr.d = rcr.Provider()
82
}
83
return rcr.d
84
}
85
86
func (rcr *RedisCachedResolver) Factory() remotes.Resolver {
87
return &RedisCachedResolver{
88
Client: rcr.Client,
89
Provider: rcr.Provider,
90
d: rcr.Provider(),
91
}
92
}
93
94