From 7f527ab54ac69462e1966d1f9a529b1a3b64c4a8 Mon Sep 17 00:00:00 2001 From: arikkfir Date: Sat, 16 Sep 2023 18:41:26 +0300 Subject: [PATCH] Add optional built-in substitution of last attempted revision The purpose of this new feature (which is CLI-conditional, and defaults to false in order to preserve compatibility) is to allow to refer to the revision that is currently being applied in the resource manifests, via the standard substitutions mechanism. By enabling the feature, the controller will always add the FLUX_ARTIFACT_REVISION key to the substitutions map, with the value of the artifact revision as provided by the source controller. If, however, the artifact revision matches the following pattern: ([^@]+)@sha1:(.+) then it will also add the following two keys: - FLUX_ARTIFACT_REF: the 1st group in the pattern, representing the branch or ref part for source-control based revisions (e.g. Git) - FLUX_ARTIFACT_SHA: the 2nd group in the pattern, representing the SHA usually in source-control based revisions (e.g. Git). Signed-off-by: arikkfir --- .../controller/kustomization_controller.go | 26 +++++++++++++++++-- main.go | 4 +++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/internal/controller/kustomization_controller.go b/internal/controller/kustomization_controller.go index 5432d672..b803df79 100644 --- a/internal/controller/kustomization_controller.go +++ b/internal/controller/kustomization_controller.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "os" + "regexp" "sort" "strings" "time" @@ -95,6 +96,7 @@ type KustomizationReconciler struct { DefaultServiceAccount string KubeConfigOpts runtimeClient.KubeConfigOptions ConcurrentSSA int + ImplicitSubstitutions bool } // KustomizationReconcilerOptions contains options for the KustomizationReconciler. @@ -104,6 +106,10 @@ type KustomizationReconcilerOptions struct { RateLimiter ratelimiter.RateLimiter } +var ( + refAndRevisionRE = regexp.MustCompile("([^@]+)@sha1:(.+)") +) + func (r *KustomizationReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, opts KustomizationReconcilerOptions) error { const ( ociRepositoryIndexKey string = ".metadata.ociRepository" @@ -380,7 +386,7 @@ func (r *KustomizationReconciler) reconcile( } // Build the Kustomize overlay and decrypt secrets if needed. - resources, err := r.build(ctx, obj, unstructured.Unstructured{Object: k}, tmpDir, dirPath) + resources, err := r.build(ctx, obj, src.GetArtifact(), unstructured.Unstructured{Object: k}, tmpDir, dirPath) if err != nil { conditions.MarkFalse(obj, meta.ReadyCondition, kustomizev1.BuildFailedReason, err.Error()) return err @@ -573,7 +579,7 @@ func (r *KustomizationReconciler) generate(obj unstructured.Unstructured, } func (r *KustomizationReconciler) build(ctx context.Context, - obj *kustomizev1.Kustomization, u unstructured.Unstructured, + obj *kustomizev1.Kustomization, artifact *sourcev1.Artifact, u unstructured.Unstructured, workDir, dirPath string) ([]byte, error) { dec, cleanup, err := decryptor.NewTempDecryptor(workDir, r.Client, obj) if err != nil { @@ -617,6 +623,22 @@ func (r *KustomizationReconciler) build(ctx context.Context, } } + // add built-in substitutions + if r.ImplicitSubstitutions { + if obj.Spec.PostBuild == nil { + obj.Spec.PostBuild = &kustomizev1.PostBuild{} + } + if obj.Spec.PostBuild.Substitute == nil { + obj.Spec.PostBuild.Substitute = make(map[string]string) + } + obj.Spec.PostBuild.Substitute["FLUX_ARTIFACT_REVISION"] = artifact.Revision + matches := refAndRevisionRE.FindStringSubmatch(artifact.Revision) + if len(matches) == 3 { + obj.Spec.PostBuild.Substitute["FLUX_ARTIFACT_REF"] = matches[1] + obj.Spec.PostBuild.Substitute["FLUX_ARTIFACT_SHA"] = matches[2] + } + } + // run variable substitutions if obj.Spec.PostBuild != nil { outRes, err := generator.SubstituteVariables(ctx, r.Client, u, res, false) diff --git a/main.go b/main.go index 13e8ea91..7eba113f 100644 --- a/main.go +++ b/main.go @@ -75,6 +75,7 @@ func init() { func main() { var ( + implicitSubstitutions bool metricsAddr string eventsAddr string healthAddr string @@ -101,6 +102,8 @@ func main() { flag.IntVar(&concurrent, "concurrent", 4, "The number of concurrent kustomize reconciles.") flag.IntVar(&concurrentSSA, "concurrent-ssa", 4, "The number of concurrent server-side apply operations.") flag.DurationVar(&requeueDependency, "requeue-dependency", 30*time.Second, "The interval at which failing dependencies are reevaluated.") + flag.BoolVar(&implicitSubstitutions, "implicit-substitutions", false, + "Perform substitutions of built-in values such as last-attempted-revision; has side effects of ALWAYS performing substitutions!") flag.BoolVar(&noRemoteBases, "no-remote-bases", false, "Disallow remote bases usage in Kustomize overlays. When this flag is enabled, all resources must refer to local files included in the source artifact.") flag.IntVar(&httpRetry, "http-retry", 9, "The maximum number of retries when failing to fetch artifacts over HTTP.") @@ -223,6 +226,7 @@ func main() { Metrics: metricsH, EventRecorder: eventRecorder, NoCrossNamespaceRefs: aclOptions.NoCrossNamespaceRefs, + ImplicitSubstitutions: implicitSubstitutions, NoRemoteBases: noRemoteBases, FailFast: failFast, ConcurrentSSA: concurrentSSA,