Skip to content

Commit 4f471c7

Browse files
committed
Add StrictPostBuildSubstitutions feature flag
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
1 parent b2daff1 commit 4f471c7

File tree

6 files changed

+118
-8
lines changed

6 files changed

+118
-8
lines changed

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ require (
2323
github.com/fluxcd/pkg/apis/kustomize v1.4.0
2424
github.com/fluxcd/pkg/apis/meta v1.4.0
2525
github.com/fluxcd/pkg/http/fetch v0.10.0
26-
github.com/fluxcd/pkg/kustomize v1.8.0
26+
github.com/fluxcd/pkg/kustomize v1.9.0
2727
github.com/fluxcd/pkg/runtime v0.46.0
2828
github.com/fluxcd/pkg/ssa v0.38.0
2929
github.com/fluxcd/pkg/tar v0.6.0
@@ -96,12 +96,12 @@ require (
9696
github.com/docker/docker v24.0.9+incompatible // indirect
9797
github.com/docker/go-connections v0.4.0 // indirect
9898
github.com/docker/go-units v0.4.0 // indirect
99-
github.com/drone/envsubst v1.0.3 // indirect
10099
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
101100
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
102101
github.com/evanphx/json-patch/v5 v5.8.0 // indirect
103102
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
104103
github.com/fatih/color v1.16.0 // indirect
104+
github.com/fluxcd/pkg/envsubst v1.0.0 // indirect
105105
github.com/fluxcd/pkg/sourceignore v0.6.0 // indirect
106106
github.com/fsnotify/fsnotify v1.7.0 // indirect
107107
github.com/getsops/gopgagent v0.0.0-20170926210634-4d7ea76ff71a // indirect

go.sum

+4-4
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh
116116
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
117117
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
118118
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
119-
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
120-
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
121119
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
122120
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
123121
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -143,10 +141,12 @@ github.com/fluxcd/pkg/apis/kustomize v1.4.0 h1:SXoGN9M31fW5tO+wpKMnyHXbjxGUqDo7Y
143141
github.com/fluxcd/pkg/apis/kustomize v1.4.0/go.mod h1:bZklVWB11tELMss89qYzgg4ClzhFzp0Hm4/8EiHgKew=
144142
github.com/fluxcd/pkg/apis/meta v1.4.0 h1:nNdgB6FFHP3cubxZCViaCFDUVlAbpq9+hvKEIveOGMg=
145143
github.com/fluxcd/pkg/apis/meta v1.4.0/go.mod h1:81sZ01ShTuLc1C3M1dFJNkINareBysvmrO1b8zJFFKs=
144+
github.com/fluxcd/pkg/envsubst v1.0.0 h1:LD86BRNSCGJrvyrH2aX5/pit7RfbFpkzRXogwcazLVk=
145+
github.com/fluxcd/pkg/envsubst v1.0.0/go.mod h1:VAcb4OxcRdsDix1TRtr/mtTqFGHmNQaOvXQO2REArFQ=
146146
github.com/fluxcd/pkg/http/fetch v0.10.0 h1:Uh1ZrPa4B4EDgi+NFrY7qP6g9vg1O6JHKg3+iJLtt1w=
147147
github.com/fluxcd/pkg/http/fetch v0.10.0/go.mod h1:zZOsAqn7iODap40PVq29mcCPEKjDodYvamEaoN6tV/Q=
148-
github.com/fluxcd/pkg/kustomize v1.8.0 h1:Vf1UwnoP3yScaLi/QrDjgN2d2nI6LcmX4tNRoH+sypY=
149-
github.com/fluxcd/pkg/kustomize v1.8.0/go.mod h1:yszv9tkYrnC01mcGPct8+bdxpTyxf69k1kmSvk7w0zs=
148+
github.com/fluxcd/pkg/kustomize v1.9.0 h1:bqS3mXiK1q5TpUtIO5I5b+v/0r96NGJBiearKGUhicA=
149+
github.com/fluxcd/pkg/kustomize v1.9.0/go.mod h1:PBerk0KzZN/IXaGociVp4MSMvsUQB0jR1P2SqSdixz0=
150150
github.com/fluxcd/pkg/runtime v0.46.0 h1:+pxFwTk8j8lZIS9Vyc8EJbgvmFp9JqeT6pfLo/0iP98=
151151
github.com/fluxcd/pkg/runtime v0.46.0/go.mod h1:d9BaIjqoHL71fYeZsssrt08UFONGN2WQRaJ/Ay2d1Cc=
152152
github.com/fluxcd/pkg/sourceignore v0.6.0 h1:kD6QXL/upPEX66UpR669yK1Bxr/GtjzmZiqBeYpunUQ=

internal/controller/kustomization_controller.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ type KustomizationReconciler struct {
9898
KubeConfigOpts runtimeClient.KubeConfigOptions
9999
ConcurrentSSA int
100100
DisallowedFieldManagers []string
101+
StrictSubstitutions bool
101102
}
102103

103104
// KustomizationReconcilerOptions contains options for the KustomizationReconciler.
@@ -622,9 +623,10 @@ func (r *KustomizationReconciler) build(ctx context.Context,
622623

623624
// run variable substitutions
624625
if obj.Spec.PostBuild != nil {
625-
outRes, err := generator.SubstituteVariables(ctx, r.Client, u, res, false)
626+
outRes, err := generator.SubstituteVariables(ctx, r.Client, u, res,
627+
generator.SubstituteWithStrict(r.StrictSubstitutions))
626628
if err != nil {
627-
return nil, fmt.Errorf("var substitution failed for '%s': %w", res.GetName(), err)
629+
return nil, fmt.Errorf("post build failed for '%s': %w", res.GetName(), err)
628630
}
629631

630632
if outRes != nil {

internal/controller/kustomization_varsub_test.go

+93
Original file line numberDiff line numberDiff line change
@@ -455,3 +455,96 @@ metadata:
455455
g.Expect(resultSA.Annotations["enabled"]).To(Equal("true"))
456456
})
457457
}
458+
459+
func TestKustomizationReconciler_VarsubStrict(t *testing.T) {
460+
reconciler.StrictSubstitutions = true
461+
defer func() {
462+
reconciler.StrictSubstitutions = false
463+
}()
464+
465+
ctx := context.Background()
466+
467+
g := NewWithT(t)
468+
id := "vars-" + randStringRunes(5)
469+
revision := "v1.0.0/" + randStringRunes(7)
470+
471+
err := createNamespace(id)
472+
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
473+
474+
err = createKubeConfigSecret(id)
475+
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
476+
477+
manifests := func(name string) []testserver.File {
478+
return []testserver.File{
479+
{
480+
Name: "service-account.yaml",
481+
Body: fmt.Sprintf(`
482+
apiVersion: v1
483+
kind: ServiceAccount
484+
metadata:
485+
name: %[1]s
486+
namespace: %[1]s
487+
labels:
488+
default: ${default:=test}
489+
missing: ${missing}
490+
`, name),
491+
},
492+
}
493+
}
494+
495+
artifact, err := testServer.ArtifactFromFiles(manifests(id))
496+
g.Expect(err).NotTo(HaveOccurred())
497+
498+
repositoryName := types.NamespacedName{
499+
Name: randStringRunes(5),
500+
Namespace: id,
501+
}
502+
503+
err = applyGitRepository(repositoryName, artifact, revision)
504+
g.Expect(err).NotTo(HaveOccurred())
505+
506+
inputK := &kustomizev1.Kustomization{
507+
ObjectMeta: metav1.ObjectMeta{
508+
Name: id,
509+
Namespace: id,
510+
},
511+
Spec: kustomizev1.KustomizationSpec{
512+
KubeConfig: &meta.KubeConfigReference{
513+
SecretRef: meta.SecretKeyReference{
514+
Name: "kubeconfig",
515+
},
516+
},
517+
Interval: metav1.Duration{Duration: reconciliationInterval},
518+
Path: "./",
519+
Prune: true,
520+
SourceRef: kustomizev1.CrossNamespaceSourceReference{
521+
Kind: sourcev1.GitRepositoryKind,
522+
Name: repositoryName.Name,
523+
},
524+
PostBuild: &kustomizev1.PostBuild{
525+
Substitute: map[string]string{
526+
"test": "test",
527+
},
528+
},
529+
Wait: true,
530+
},
531+
}
532+
g.Expect(k8sClient.Create(ctx, inputK)).Should(Succeed())
533+
534+
var resultK kustomizev1.Kustomization
535+
t.Run("fails to reconcile", func(t *testing.T) {
536+
g.Eventually(func() bool {
537+
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(inputK), &resultK)
538+
for _, c := range resultK.Status.Conditions {
539+
if c.Reason == kustomizev1.BuildFailedReason {
540+
return true
541+
}
542+
}
543+
return false
544+
}, timeout, interval).Should(BeTrue())
545+
})
546+
547+
ready := apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
548+
g.Expect(ready.Message).To(ContainSubstring("variable not set"))
549+
g.Expect(k8sClient.Delete(context.Background(), &resultK)).To(Succeed())
550+
}

internal/features/features.go

+8
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ const (
3939
// DisableFailFastBehavior controls whether the fail-fast behavior when
4040
// waiting for resources to become ready should be disabled.
4141
DisableFailFastBehavior = "DisableFailFastBehavior"
42+
43+
// StrictPostBuildSubstitutions controls whether the post-build substitutions
44+
// should fail if a variable without a default value is declared in files
45+
// but is missing from the input vars.
46+
StrictPostBuildSubstitutions = "StrictPostBuildSubstitutions"
4247
)
4348

4449
var features = map[string]bool{
@@ -51,6 +56,9 @@ var features = map[string]bool{
5156
// DisableFailFastBehavior
5257
// opt-in from v1.1
5358
DisableFailFastBehavior: false,
59+
// StrictPostBuildSubstitutions
60+
// opt-in from v1.3
61+
StrictPostBuildSubstitutions: false,
5462
}
5563

5664
// FeatureGates contains a list of all supported feature gates and

main.go

+7
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,12 @@ func main() {
228228
failFast = false
229229
}
230230

231+
strictSubstitutions, err := features.Enabled(features.StrictPostBuildSubstitutions)
232+
if err != nil {
233+
setupLog.Error(err, "unable to check feature gate "+features.StrictPostBuildSubstitutions)
234+
os.Exit(1)
235+
}
236+
231237
if err = (&controller.KustomizationReconciler{
232238
ControllerName: controllerName,
233239
DefaultServiceAccount: defaultServiceAccount,
@@ -242,6 +248,7 @@ func main() {
242248
PollingOpts: pollingOpts,
243249
StatusPoller: polling.NewStatusPoller(mgr.GetClient(), mgr.GetRESTMapper(), pollingOpts),
244250
DisallowedFieldManagers: disallowedFieldManagers,
251+
StrictSubstitutions: strictSubstitutions,
245252
}).SetupWithManager(ctx, mgr, controller.KustomizationReconcilerOptions{
246253
DependencyRequeueInterval: requeueDependency,
247254
HTTPRetry: httpRetry,

0 commit comments

Comments
 (0)