1
2
3 package pallet
4
5 import (
6 "fmt"
7 "strings"
8
9 v1 "github.com/google/go-containerregistry/pkg/v1"
10
11 wh "edge-infra.dev/pkg/f8n/warehouse"
12 "edge-infra.dev/pkg/f8n/warehouse/capability"
13 "edge-infra.dev/pkg/f8n/warehouse/cluster"
14 "edge-infra.dev/pkg/f8n/warehouse/oci"
15 "edge-infra.dev/pkg/f8n/warehouse/oci/layer"
16 "edge-infra.dev/pkg/f8n/warehouse/oci/match"
17 )
18
19
20 const WarehouseKind = wh.PalletKind
21
22
23 type Pallet interface {
24
25 oci.Artifact
26
27 oci.Unwrapper
28
29
30
31 Name() string
32
33
34 Metadata() Metadata
35
36
37
38 Providers() cluster.Providers
39
40
41
42
43
44
45 Supports(provider cluster.Provider) bool
46
47
48
49 Capabilities() capability.Capabilities
50
51
52
53 Renderable() bool
54
55
56
57
58
59
60
61 Image(provider cluster.Provider) (v1.Image, error)
62
63
64
65
66
67
68
69
70
71 Layers(provider cluster.Provider) ([]layer.Layer, error)
72
73
74 Dependencies() ([]Pallet, error)
75
76
77 Parameters() []string
78 }
79
80 type pallet struct {
81 oci.Artifact
82 meta Metadata
83 providers cluster.Providers
84 capabilities capability.Capabilities
85 renderable bool
86 parameters []string
87 }
88
89 func New(a oci.Artifact) (Pallet, error) {
90 switch a := a.(type) {
91 case nil:
92 return nil, fmt.Errorf("%w: pallet.New: non-nil artifact is required",
93 oci.ErrInvalidArtifact)
94
95 case *pallet:
96 return a, nil
97
98
99
100 case oci.Unwrapper:
101 return New(a.Unwrap())
102 }
103
104
105 p := &pallet{Artifact: a}
106
107 annos, err := oci.Annotations(a)
108 if err != nil {
109 return nil, fmt.Errorf("failed to read annotations from oci artifact: %w", err)
110 }
111
112 if annos[wh.AnnotationRender] != "false" {
113 p.renderable = true
114 }
115
116 if annos[wh.AnnotationParameters] != "" {
117 p.parameters = strings.Split(annos[wh.AnnotationParameters], ",")
118 }
119
120 p.meta, err = metadataFromAnnotations(annos)
121 if err != nil {
122 return nil, fmt.Errorf("failed to parse metadata from oci artifact: %w", err)
123 }
124
125 p.providers, err = cluster.ProvidersFromAnnotations(annos)
126 if err != nil {
127 return nil, fmt.Errorf("failed to parse cluster provider information from oci artifact: %w", err)
128 }
129
130 p.capabilities = capability.FromAnnotations(annos)
131
132 return p, nil
133 }
134
135
136 var _ Pallet = (*pallet)(nil)
137
138 func (p *pallet) Name() string {
139 return p.meta.Name
140 }
141
142 func (p *pallet) Metadata() Metadata {
143 return p.meta
144 }
145
146 func (p *pallet) Providers() cluster.Providers {
147 return p.providers
148 }
149
150 func (p *pallet) Supports(t cluster.Provider) bool {
151 for _, provider := range p.providers {
152 if provider == t {
153 return true
154 }
155 }
156 return false
157 }
158
159 func (p *pallet) Capabilities() capability.Capabilities {
160 return p.capabilities
161 }
162
163
164 func (p *pallet) Unwrap() oci.Artifact {
165 return p.Artifact
166 }
167
168 func (p *pallet) Renderable() bool {
169 return p.renderable
170 }
171
172 func (p *pallet) Image(provider cluster.Provider) (v1.Image, error) {
173 if !p.Supports(provider) && provider != "" {
174 return nil, fmt.Errorf("pallet.Image: %w: %s",
175 cluster.ErrUnsupportedProvider, provider)
176 }
177
178 switch a := p.Artifact.(type) {
179 case v1.Image:
180 return a, nil
181 case v1.ImageIndex:
182 if provider == "" {
183 return nil, fmt.Errorf("pallet.Image: %w: a cluster provider is required "+
184 "if the Pallet is a v1.ImageIndex", cluster.ErrUnsupportedProvider)
185 }
186 return match.FindImage(a, match.Multiple(
187 match.Provider(provider),
188 match.RefName(p.Name()),
189 ))
190 default:
191 return nil, fmt.Errorf("pallet.Image: %w", oci.ErrInvalidArtifact)
192 }
193 }
194
195 func (p *pallet) Layers(provider cluster.Provider) ([]layer.Layer, error) {
196 img, err := p.Image(provider)
197 if err != nil {
198 return nil, err
199 }
200
201 return layer.FromImage(img)
202 }
203
204 func (p *pallet) Dependencies() ([]Pallet, error) {
205 switch a := p.Artifact.(type) {
206 case v1.Image:
207 return nil, nil
208 case v1.ImageIndex:
209 manifests, err := match.FindManifests(a, match.Dependencies(p.Name()))
210 if err != nil {
211 return nil, err
212 }
213
214 deps := make([]Pallet, 0, len(manifests))
215 for _, m := range manifests {
216 dep, err := oci.ArtifactFromIdx(a, m)
217 if err != nil {
218 return nil, err
219 }
220 pallet, err := New(dep)
221 if err != nil {
222 return nil, fmt.Errorf("failed to create pallet for dependency: %w", err)
223 }
224 deps = append(deps, pallet)
225 }
226
227 return deps, nil
228 default:
229 return nil, fmt.Errorf("%w", oci.ErrInvalidArtifact)
230 }
231 }
232
233 func (p *pallet) Parameters() []string {
234 return p.parameters
235 }
236
View as plain text