Add `StrictPostBuildSubstitutions` feature flag

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
This commit is contained in:
Stefan Prodan 2024-04-08 19:08:33 +03:00
parent b2daff1783
commit 4f471c7dab
No known key found for this signature in database
GPG Key ID: 3299AEB0E4085BAF
6 changed files with 118 additions and 8 deletions

4
go.mod
View File

@ -23,7 +23,7 @@ require (
github.com/fluxcd/pkg/apis/kustomize v1.4.0
github.com/fluxcd/pkg/apis/meta v1.4.0
github.com/fluxcd/pkg/http/fetch v0.10.0
github.com/fluxcd/pkg/kustomize v1.8.0
github.com/fluxcd/pkg/kustomize v1.9.0
github.com/fluxcd/pkg/runtime v0.46.0
github.com/fluxcd/pkg/ssa v0.38.0
github.com/fluxcd/pkg/tar v0.6.0
@ -96,12 +96,12 @@ require (
github.com/docker/docker v24.0.9+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/drone/envsubst v1.0.3 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.8.0 // indirect
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fluxcd/pkg/envsubst v1.0.0 // indirect
github.com/fluxcd/pkg/sourceignore v0.6.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/getsops/gopgagent v0.0.0-20170926210634-4d7ea76ff71a // indirect

8
go.sum
View File

@ -116,8 +116,6 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
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
github.com/fluxcd/pkg/apis/kustomize v1.4.0/go.mod h1:bZklVWB11tELMss89qYzgg4ClzhFzp0Hm4/8EiHgKew=
github.com/fluxcd/pkg/apis/meta v1.4.0 h1:nNdgB6FFHP3cubxZCViaCFDUVlAbpq9+hvKEIveOGMg=
github.com/fluxcd/pkg/apis/meta v1.4.0/go.mod h1:81sZ01ShTuLc1C3M1dFJNkINareBysvmrO1b8zJFFKs=
github.com/fluxcd/pkg/envsubst v1.0.0 h1:LD86BRNSCGJrvyrH2aX5/pit7RfbFpkzRXogwcazLVk=
github.com/fluxcd/pkg/envsubst v1.0.0/go.mod h1:VAcb4OxcRdsDix1TRtr/mtTqFGHmNQaOvXQO2REArFQ=
github.com/fluxcd/pkg/http/fetch v0.10.0 h1:Uh1ZrPa4B4EDgi+NFrY7qP6g9vg1O6JHKg3+iJLtt1w=
github.com/fluxcd/pkg/http/fetch v0.10.0/go.mod h1:zZOsAqn7iODap40PVq29mcCPEKjDodYvamEaoN6tV/Q=
github.com/fluxcd/pkg/kustomize v1.8.0 h1:Vf1UwnoP3yScaLi/QrDjgN2d2nI6LcmX4tNRoH+sypY=
github.com/fluxcd/pkg/kustomize v1.8.0/go.mod h1:yszv9tkYrnC01mcGPct8+bdxpTyxf69k1kmSvk7w0zs=
github.com/fluxcd/pkg/kustomize v1.9.0 h1:bqS3mXiK1q5TpUtIO5I5b+v/0r96NGJBiearKGUhicA=
github.com/fluxcd/pkg/kustomize v1.9.0/go.mod h1:PBerk0KzZN/IXaGociVp4MSMvsUQB0jR1P2SqSdixz0=
github.com/fluxcd/pkg/runtime v0.46.0 h1:+pxFwTk8j8lZIS9Vyc8EJbgvmFp9JqeT6pfLo/0iP98=
github.com/fluxcd/pkg/runtime v0.46.0/go.mod h1:d9BaIjqoHL71fYeZsssrt08UFONGN2WQRaJ/Ay2d1Cc=
github.com/fluxcd/pkg/sourceignore v0.6.0 h1:kD6QXL/upPEX66UpR669yK1Bxr/GtjzmZiqBeYpunUQ=

View File

@ -98,6 +98,7 @@ type KustomizationReconciler struct {
KubeConfigOpts runtimeClient.KubeConfigOptions
ConcurrentSSA int
DisallowedFieldManagers []string
StrictSubstitutions bool
}
// KustomizationReconcilerOptions contains options for the KustomizationReconciler.
@ -622,9 +623,10 @@ func (r *KustomizationReconciler) build(ctx context.Context,
// run variable substitutions
if obj.Spec.PostBuild != nil {
outRes, err := generator.SubstituteVariables(ctx, r.Client, u, res, false)
outRes, err := generator.SubstituteVariables(ctx, r.Client, u, res,
generator.SubstituteWithStrict(r.StrictSubstitutions))
if err != nil {
return nil, fmt.Errorf("var substitution failed for '%s': %w", res.GetName(), err)
return nil, fmt.Errorf("post build failed for '%s': %w", res.GetName(), err)
}
if outRes != nil {

View File

@ -455,3 +455,96 @@ metadata:
g.Expect(resultSA.Annotations["enabled"]).To(Equal("true"))
})
}
func TestKustomizationReconciler_VarsubStrict(t *testing.T) {
reconciler.StrictSubstitutions = true
defer func() {
reconciler.StrictSubstitutions = false
}()
ctx := context.Background()
g := NewWithT(t)
id := "vars-" + randStringRunes(5)
revision := "v1.0.0/" + randStringRunes(7)
err := createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
err = createKubeConfigSecret(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
manifests := func(name string) []testserver.File {
return []testserver.File{
{
Name: "service-account.yaml",
Body: fmt.Sprintf(`
apiVersion: v1
kind: ServiceAccount
metadata:
name: %[1]s
namespace: %[1]s
labels:
default: ${default:=test}
missing: ${missing}
`, name),
},
}
}
artifact, err := testServer.ArtifactFromFiles(manifests(id))
g.Expect(err).NotTo(HaveOccurred())
repositoryName := types.NamespacedName{
Name: randStringRunes(5),
Namespace: id,
}
err = applyGitRepository(repositoryName, artifact, revision)
g.Expect(err).NotTo(HaveOccurred())
inputK := &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: id,
Namespace: id,
},
Spec: kustomizev1.KustomizationSpec{
KubeConfig: &meta.KubeConfigReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
Prune: true,
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Kind: sourcev1.GitRepositoryKind,
Name: repositoryName.Name,
},
PostBuild: &kustomizev1.PostBuild{
Substitute: map[string]string{
"test": "test",
},
},
Wait: true,
},
}
g.Expect(k8sClient.Create(ctx, inputK)).Should(Succeed())
var resultK kustomizev1.Kustomization
t.Run("fails to reconcile", func(t *testing.T) {
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(inputK), &resultK)
for _, c := range resultK.Status.Conditions {
if c.Reason == kustomizev1.BuildFailedReason {
return true
}
}
return false
}, timeout, interval).Should(BeTrue())
})
ready := apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
g.Expect(ready.Message).To(ContainSubstring("variable not set"))
g.Expect(k8sClient.Delete(context.Background(), &resultK)).To(Succeed())
}

View File

@ -39,6 +39,11 @@ const (
// DisableFailFastBehavior controls whether the fail-fast behavior when
// waiting for resources to become ready should be disabled.
DisableFailFastBehavior = "DisableFailFastBehavior"
// StrictPostBuildSubstitutions controls whether the post-build substitutions
// should fail if a variable without a default value is declared in files
// but is missing from the input vars.
StrictPostBuildSubstitutions = "StrictPostBuildSubstitutions"
)
var features = map[string]bool{
@ -51,6 +56,9 @@ var features = map[string]bool{
// DisableFailFastBehavior
// opt-in from v1.1
DisableFailFastBehavior: false,
// StrictPostBuildSubstitutions
// opt-in from v1.3
StrictPostBuildSubstitutions: false,
}
// FeatureGates contains a list of all supported feature gates and

View File

@ -228,6 +228,12 @@ func main() {
failFast = false
}
strictSubstitutions, err := features.Enabled(features.StrictPostBuildSubstitutions)
if err != nil {
setupLog.Error(err, "unable to check feature gate "+features.StrictPostBuildSubstitutions)
os.Exit(1)
}
if err = (&controller.KustomizationReconciler{
ControllerName: controllerName,
DefaultServiceAccount: defaultServiceAccount,
@ -242,6 +248,7 @@ func main() {
PollingOpts: pollingOpts,
StatusPoller: polling.NewStatusPoller(mgr.GetClient(), mgr.GetRESTMapper(), pollingOpts),
DisallowedFieldManagers: disallowedFieldManagers,
StrictSubstitutions: strictSubstitutions,
}).SetupWithManager(ctx, mgr, controller.KustomizationReconcilerOptions{
DependencyRequeueInterval: requeueDependency,
HTTPRetry: httpRetry,