Skip to content

Commit cd9c18d

Browse files
committed
Add helm chart as blob to extension
It appears that there is currently no way for the extension to retrieve the image pull secret to download the helm chart from an oci repository.
1 parent 1863583 commit cd9c18d

8 files changed

Lines changed: 103 additions & 21 deletions

File tree

pkg/apis/config/types.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,11 @@ type AdditionalSeedManagedResource struct {
9595
Helm HelmConfig
9696
}
9797

98-
// HelmConfig specifies a Helm chart to pull from an OCI repository and render with values.
98+
// HelmConfig specifies a Helm chart source and render values.
99+
// Exactly one of OCIRepository or Chart must be set.
99100
type HelmConfig struct {
100-
OCIRepository gardencorev1.OCIRepository
101+
OCIRepository *gardencorev1.OCIRepository
102+
Chart *string
101103
Values *runtime.RawExtension
102104
}
103105

pkg/apis/config/v1alpha1/types.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,16 @@ type AdditionalSeedManagedResource struct {
110110
Helm HelmConfig `json:"helm"`
111111
}
112112

113-
// HelmConfig specifies a Helm chart to pull from an OCI repository and render with values.
113+
// HelmConfig specifies a Helm chart source and render values.
114+
// Exactly one of OCIRepository or Chart must be set.
114115
type HelmConfig struct {
115116
// OCIRepository defines where to pull the chart from.
116-
OCIRepository gardencorev1.OCIRepository `json:"ociRepository"`
117+
// +optional
118+
OCIRepository *gardencorev1.OCIRepository `json:"ociRepository,omitempty"`
119+
120+
// Chart is a base64-encoded, gzipped tar archive of the Helm chart.
121+
// +optional
122+
Chart *string `json:"chart,omitempty"`
117123

118124
// Values are the Helm values to use when rendering the chart.
119125
// +optional

pkg/apis/config/v1alpha1/zz_generated.conversion.go

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/config/v1alpha1/zz_generated.deepcopy.go

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/config/validation/validation.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,14 @@ func validateAdditionalConfig(additional *config.AdditionalConfig, fldPath *fiel
119119
names[res.Name] = true
120120
}
121121

122-
if res.Helm.OCIRepository.Ref == nil || *res.Helm.OCIRepository.Ref == "" {
123-
allErrs = append(allErrs, field.Required(idxPath.Child("helm").Child("ociRepository").Child("ref"), "OCI repository ref must not be empty"))
122+
helmPath := idxPath.Child("helm")
123+
hasOCI := res.Helm.OCIRepository != nil && res.Helm.OCIRepository.Ref != nil && *res.Helm.OCIRepository.Ref != ""
124+
hasChart := res.Helm.Chart != nil && *res.Helm.Chart != ""
125+
126+
if hasOCI && hasChart {
127+
allErrs = append(allErrs, field.Forbidden(helmPath, "only one of ociRepository or chart may be set"))
128+
} else if !hasOCI && !hasChart {
129+
allErrs = append(allErrs, field.Required(helmPath, "one of ociRepository.ref or chart must be set"))
124130
}
125131
}
126132

pkg/apis/config/validation/validation_test.go

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ var _ = Describe("ValidateConfiguration", func() {
196196
{
197197
Name: "my-nginx",
198198
Helm: config.HelmConfig{
199-
OCIRepository: gardencorev1.OCIRepository{
199+
OCIRepository: &gardencorev1.OCIRepository{
200200
Ref: ptr.To("registry-1.docker.io/bitnamicharts/nginx:25.0.5"),
201201
},
202202
},
@@ -212,7 +212,14 @@ var _ = Describe("ValidateConfiguration", func() {
212212
Expect(ValidateConfiguration(conf)).To(BeEmpty())
213213
})
214214

215-
It("should pass for valid seed managed resources", func() {
215+
It("should pass for valid seed managed resources with OCI ref", func() {
216+
Expect(ValidateConfiguration(conf)).To(BeEmpty())
217+
})
218+
219+
It("should pass for valid seed managed resources with inline chart", func() {
220+
conf.Falco.Additional.SeedManagedResources[0].Helm = config.HelmConfig{
221+
Chart: ptr.To("H4sIAAAAAAAAA+3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAB+BjG/"),
222+
}
216223
Expect(ValidateConfiguration(conf)).To(BeEmpty())
217224
})
218225

@@ -249,29 +256,49 @@ var _ = Describe("ValidateConfiguration", func() {
249256
))
250257
})
251258

252-
It("should reject nil OCI repository ref", func() {
259+
It("should reject when neither OCI ref nor chart is set", func() {
260+
conf.Falco.Additional.SeedManagedResources[0].Helm = config.HelmConfig{}
261+
Expect(ValidateConfiguration(conf)).To(ConsistOf(
262+
PointTo(MatchFields(IgnoreExtras, Fields{
263+
"Type": Equal(field.ErrorTypeRequired),
264+
"Field": Equal("falco.additional.seedManagedResources[0].helm"),
265+
})),
266+
))
267+
})
268+
269+
It("should reject when both OCI ref and chart are set", func() {
270+
conf.Falco.Additional.SeedManagedResources[0].Helm.Chart = ptr.To("H4sIAAAAAAAAA+3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAB+BjG/")
271+
Expect(ValidateConfiguration(conf)).To(ConsistOf(
272+
PointTo(MatchFields(IgnoreExtras, Fields{
273+
"Type": Equal(field.ErrorTypeForbidden),
274+
"Field": Equal("falco.additional.seedManagedResources[0].helm"),
275+
})),
276+
))
277+
})
278+
279+
It("should reject nil OCI repository ref when no chart set", func() {
253280
conf.Falco.Additional.SeedManagedResources[0].Helm.OCIRepository.Ref = nil
254281
Expect(ValidateConfiguration(conf)).To(ConsistOf(
255282
PointTo(MatchFields(IgnoreExtras, Fields{
256283
"Type": Equal(field.ErrorTypeRequired),
257-
"Field": Equal("falco.additional.seedManagedResources[0].helm.ociRepository.ref"),
284+
"Field": Equal("falco.additional.seedManagedResources[0].helm"),
258285
})),
259286
))
260287
})
261288

262-
It("should reject empty OCI repository ref", func() {
289+
It("should reject empty OCI repository ref when no chart set", func() {
263290
conf.Falco.Additional.SeedManagedResources[0].Helm.OCIRepository.Ref = ptr.To("")
264291
Expect(ValidateConfiguration(conf)).To(ConsistOf(
265292
PointTo(MatchFields(IgnoreExtras, Fields{
266293
"Type": Equal(field.ErrorTypeRequired),
267-
"Field": Equal("falco.additional.seedManagedResources[0].helm.ociRepository.ref"),
294+
"Field": Equal("falco.additional.seedManagedResources[0].helm"),
268295
})),
269296
))
270297
})
271298

272299
It("should report multiple errors at once", func() {
273300
conf.Falco.Additional.SeedManagedResources[0].Name = ""
274-
conf.Falco.Additional.SeedManagedResources[0].Helm.OCIRepository.Ref = nil
301+
conf.Falco.Additional.SeedManagedResources[0].Helm = config.HelmConfig{}
275302
Expect(ValidateConfiguration(conf)).To(HaveLen(2))
276303
})
277304
})

pkg/apis/config/zz_generated.deepcopy.go

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/controller/additional/reconciler.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package additional
66

77
import (
88
"context"
9+
"encoding/base64"
910
"encoding/json"
1011
"errors"
1112
"fmt"
@@ -83,7 +84,7 @@ func (r *Reconciler) Deploy(ctx context.Context) error {
8384
return nil
8485
}
8586

86-
if r.renderer == nil || r.helmRegistry == nil {
87+
if r.renderer == nil {
8788
return fmt.Errorf("chart renderer not initialized — restConfig was nil at construction time")
8889
}
8990

@@ -104,9 +105,26 @@ func (r *Reconciler) Deploy(ctx context.Context) error {
104105
}
105106

106107
func (r *Reconciler) deployResource(ctx context.Context, res config.AdditionalSeedManagedResource, mrName string, labels map[string]string) error {
107-
archive, err := r.helmRegistry.Pull(ctx, &res.Helm.OCIRepository)
108-
if err != nil {
109-
return fmt.Errorf("failed to pull chart: %w", err)
108+
var archive []byte
109+
var err error
110+
111+
switch {
112+
case res.Helm.Chart != nil && *res.Helm.Chart != "":
113+
archive, err = base64.StdEncoding.DecodeString(*res.Helm.Chart)
114+
if err != nil {
115+
return fmt.Errorf("failed to decode inline chart: %w", err)
116+
}
117+
case res.Helm.OCIRepository != nil:
118+
if r.helmRegistry == nil {
119+
return fmt.Errorf("helm registry not initialized — restConfig was nil at construction time")
120+
}
121+
pullCtx := context.WithValue(ctx, oci.ContextKeySecretNamespace, r.namespace)
122+
archive, err = r.helmRegistry.Pull(pullCtx, res.Helm.OCIRepository)
123+
if err != nil {
124+
return fmt.Errorf("failed to pull chart: %w", err)
125+
}
126+
default:
127+
return fmt.Errorf("neither chart nor ociRepository set for resource %s", res.Name)
110128
}
111129

112130
var values map[string]interface{}

0 commit comments

Comments
 (0)