diff --git a/argo-cd-order/README.md b/argo-cd-order/README.md new file mode 100644 index 00000000..136df578 --- /dev/null +++ b/argo-cd-order/README.md @@ -0,0 +1,83 @@ +## Introduction + +argo-cd-order is a module for ordering argocd sync operations +For more details: https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/ + + +How to use + +``` +kcl mod add argo-cd-order +``` + +Write the code + +``` +import argo_cd_order as ArgoCdOrder +import yaml +import manifests +import k8s.api.core.v1 as k8core +import file +import argoproj.v1alpha1 as argoproj + + +testApp = ArgoCdOrder.make({ + preSync = [ + k8core.Namespace { + metadata.name = "test-namespace" + } + k8core.ConfigMap { + metadata = { + name = "test-configmap" + namespace = "test-namespace" + annotations = { + hello = "world" + } + } + } + ] + yaml.decode_all(file.read("./knative-operator.yaml")) + sync = [ + argoproj.Application { + metadata = { + name = "testApp" + namespace = "argocd" + } + spec = { + destination = { + namespace = "test-namespace" + server = "https://kubernetes.default.svc" + } + project = "default" + source = { + chart = "hello" + repoURL = "https://cloudecho.github.io/charts/" + targetRevision = "0.1.2" + helm = { + values = yaml.encode({}) + releaseName = "my-hello" + } + + + } + syncPolicy = { + automated = {} + syncOptions = [ + "CreateNamespace=true" + ] + } + + } + } + ] + + postSync = [] + +}) + +manifests.yaml_stream([ + testApp +]) + + +``` + diff --git a/argo-cd-order/kcl.mod b/argo-cd-order/kcl.mod new file mode 100644 index 00000000..7386832a --- /dev/null +++ b/argo-cd-order/kcl.mod @@ -0,0 +1,7 @@ +[package] +name = "argo-cd-order" +edition = "v0.1.0" +version = "0.1.0" + +[dependencies] +json_merge_patch = { oci = "oci://ghcr.io/kcl-lang/json_merge_patch", tag = "0.1.0" } diff --git a/argo-cd-order/main.k b/argo-cd-order/main.k new file mode 100644 index 00000000..6d4ba318 --- /dev/null +++ b/argo-cd-order/main.k @@ -0,0 +1,60 @@ +import json_merge_patch as p +WAVE_MIN = 0 + +validatedAnnotations = lambda a: {str:str} { + assert a["argocd.argoproj.io/hook"] in ["preSync", "sync", "postSync"] + assert int(a["argocd.argoproj.io/sync-wave"]) >= WAVE_MIN + a +} + +schema ArgoCdManifest: + [str]: any + metadata: ArgoCdManifestMetadata + +schema ArgoCdManifestMetadata: + [str]: any + annotations: ArgoCdManifestMetadataAnnotations + +schema ArgoCdManifestMetadataAnnotations: + """ + When Argo CD starts a sync, it orders the resources in the following precedence: + + 1. The phase + 2. The wave they are in (lower values first) + 3. By kind (e.g. namespaces first and then other Kubernetes resources, followed by custom resources) + 4. By name + """ + [str]: any + "argocd.argoproj.io/sync-wave": str + "argocd.argoproj.io/hook": str + +preparePhase = lambda phase: str, phaseResources: [any] -> [ArgoCdManifest] { + [ + p.merge(resource, { metadata.annotations = validatedAnnotations({ + "argocd.argoproj.io/sync-wave" = str(sync_wave) + "argocd.argoproj.io/hook" = phase + })}) + for sync_wave, resource in phaseResources if resource != None + + ] +} + +schema ArgoCdOrder: + """ + + Argo CD executes a sync operation in a number of steps. + At a high-level, there are three phases pre-sync, sync and post-sync. + For more details: https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/ + + """ + preSync: [any] + sync: [any] + postSync: [any] + +make = lambda argoCdApp: ArgoCdOrder -> [[ArgoCdManifest]] { + [ + preparePhase(phase, argoCdApp[phase]) + for phase in argoCdApp + ] +} +