From 21c1f48c91df19135fbf5b3eefdbdfa0f29c2def Mon Sep 17 00:00:00 2001 From: Ryan VanGundy Date: Sat, 2 Aug 2025 11:57:02 -0400 Subject: [PATCH 1/4] Remove workstation config from root windsor.yaml --- windsor.yaml | 61 ---------------------------------------------------- 1 file changed, 61 deletions(-) diff --git a/windsor.yaml b/windsor.yaml index d8855ac7d..71c0990d5 100644 --- a/windsor.yaml +++ b/windsor.yaml @@ -1,62 +1 @@ version: v1alpha1 -contexts: - local: - id: wdau7ykp - provider: local - docker: - enabled: true - registries: - gcr.io: - remote: https://gcr.io - ghcr.io: - remote: https://ghcr.io - quay.io: - remote: https://quay.io - registry-1.docker.io: - remote: https://registry-1.docker.io - local: https://docker.io - registry.k8s.io: - remote: https://registry.k8s.io - registry.test: {} - git: - livereload: - enabled: true - rsync_include: "" - rsync_protect: flux-system - username: local - password: local - webhook_url: http://worker-1.test:30292/hook/5dc88e45e809fb0872b749c0969067e2c1fd142e17aed07573fad20553cc0c59 - verify_ssl: false - image: ghcr.io/windsorcli/git-livereload:v0.2.0 - terraform: - enabled: true - backend: - type: local - vm: - driver: docker-desktop - cluster: - enabled: true - platform: local - driver: talos - controlplanes: - count: 1 - cpu: 2 - memory: 2 - workers: - count: 1 - cpu: 4 - memory: 4 - hostports: - - 8080:30080/tcp - - 8443:30443/tcp - - 9292:30292/tcp - - 8053:30053/udp - volumes: - - ${WINDSOR_PROJECT_ROOT}/.volumes:/var/local - network: - cidr_block: 10.5.0.0/16 - dns: - enabled: true - domain: test - forward: - - 10.5.0.1:8053 From 384e9ea8f2b1ef7bb2875de186b88d366fd16efb Mon Sep 17 00:00:00 2001 From: Ryan VanGundy Date: Sat, 2 Aug 2025 11:57:25 -0400 Subject: [PATCH 2/4] Git ignore all contexts other than _template --- contexts/.gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contexts/.gitignore b/contexts/.gitignore index 509436678..160c29e36 100644 --- a/contexts/.gitignore +++ b/contexts/.gitignore @@ -1,4 +1,5 @@ # Ignore all directories in contexts/ */ -# But allow _template directory +# But allow _template directory and all its contents !/_template/ +!/_template/** From 1918687dcfef4cbd35058e6c6d73f8f2fb837788 Mon Sep 17 00:00:00 2001 From: Ryan VanGundy Date: Sat, 2 Aug 2025 11:59:22 -0400 Subject: [PATCH 3/4] refactor(kustomize): Leverage post build values for parameterization Windsor now supports post-build values in contexts. This PR leverages this feature in both the template and integrated in to the codebase. --- contexts/_template/blueprint.jsonnet | 346 +++++++++--------- contexts/_template/kustomize/values.jsonnet | 26 ++ .../_template/terraform/cluster/talos.jsonnet | 20 +- .../dynamic-localpv/patches/helm-release.yaml | 2 +- .../openebs/dynamic-localpv/storageclass.yaml | 4 +- kustomize/demo/bookinfo/ingress/ingress.yaml | 2 +- kustomize/demo/static/ingress/ingress.yaml | 2 +- kustomize/dns/external-dns/helm-release.yaml | 2 +- .../route53/patches/helm-release.yaml | 4 +- .../loadbalancer/patches/helm-release.yaml | 2 +- .../grafana/ingress/ingress.yaml | 2 +- .../observability/kibana/ingress/ingress.yaml | 2 +- 12 files changed, 232 insertions(+), 182 deletions(-) create mode 100644 contexts/_template/kustomize/values.jsonnet diff --git a/contexts/_template/blueprint.jsonnet b/contexts/_template/blueprint.jsonnet index bf5d8ff2e..2f3a64e65 100644 --- a/contexts/_template/blueprint.jsonnet +++ b/contexts/_template/blueprint.jsonnet @@ -14,6 +14,9 @@ local vmDriver = hlp.getString(context, "vm.driver", ""); local blueprintName = hlp.getString(context, "name", "template"); local repositoryUrl = if rawProvider == "local" then "http://git.test/git/" + hlp.getString(context, "projectName", "core") else ""; +// Helper to concatenate arrays (std.flattenArrays expects array of arrays) +local concat(arrays) = std.foldl(function(x, y) x + y, arrays, []); + // ============================================================================= // BLUEPRINT // ============================================================================= @@ -35,34 +38,34 @@ local repositoryUrl = if rawProvider == "local" then "http://git.test/git/" + hl sources: [], terraform: if provider == "aws" then [ { - path: "network/aws-vpc" + path: "network/aws-vpc", }, { - path: "cluster/aws-eks" + path: "cluster/aws-eks", }, { path: "cluster/aws-eks/additions", - destroy: false + destroy: false, }, { path: "gitops/flux", - destroy: false - } + destroy: false, + }, ] else if provider == "azure" then [ { - path: "network/azure-vnet" + path: "network/azure-vnet", }, { - path: "cluster/azure-aks" + path: "cluster/azure-aks", }, { path: "gitops/flux", - destroy: false - } + destroy: false, + }, ] else [ { path: "cluster/talos", - parallelism: 1 + parallelism: 1, }, { path: "gitops/flux", @@ -71,160 +74,177 @@ local repositoryUrl = if rawProvider == "local" then "http://git.test/git/" + hl git_username: "local", git_password: "local", webhook_token: "abcdef123456", - } else {} - } - ], - kustomize: [ - { - name: "telemetry-base", - path: "telemetry/base", - components: [ - "prometheus", - "prometheus/flux", - "fluentbit", - "fluentbit/prometheus" - ] + } else {}, }, - { - name: "telemetry-resources", - path: "telemetry/resources", - components: [ - "metrics-server", - "prometheus", - "prometheus/flux", - "fluentbit", - "fluentbit/containerd", - "fluentbit/fluentd", - "fluentbit/kubernetes", - "fluentbit/systemd" + ], + kustomize: + concat([ + [ + { + name: "telemetry-base", + path: "telemetry/base", + components: [ + "prometheus", + "prometheus/flux", + "fluentbit", + "fluentbit/prometheus", + ], + }, + { + name: "telemetry-resources", + path: "telemetry/resources", + components: [ + "metrics-server", + "prometheus", + "prometheus/flux", + "fluentbit", + "fluentbit/containerd", + "fluentbit/fluentd", + "fluentbit/kubernetes", + "fluentbit/systemd", + ], + dependsOn: ["telemetry-base"], + }, + { + name: "policy-base", + path: "policy/base", + components: ["kyverno"], + }, + { + name: "policy-resources", + path: "policy/resources", + dependsOn: ["policy-base"], + }, + { + name: "csi", + path: "csi", + components: + if provider == "aws" then ["aws-ebs"] + else if provider == "local" then [ + "openebs", + "openebs/dynamic-localpv", + ] + else [], + dependsOn: ["policy-resources"], + cleanup: ["pvcs"], + }, + { + name: "pki-base", + path: "pki/base", + components: [ + "cert-manager", + "trust-manager", + ], + dependsOn: ["policy-resources"], + }, + { + name: "pki-resources", + path: "pki/resources", + components: [ + "private-issuer/ca", + "public-issuer/selfsigned", + ], + dependsOn: ["pki-base"], + }, + { + name: "ingress", + path: "ingress", + components: + if provider == "aws" then [ + "nginx", + "nginx/flux-webhook", + "nginx/web", + ] else + std.filter( + function(x) x != null, + [ + "nginx", + if vmDriver == "docker-desktop" then "nginx/nodeport" else null, + "nginx/coredns", + "nginx/flux-webhook", + "nginx/web", + ] + ), + dependsOn: ["pki-resources"], + cleanup: ["loadbalancers", "ingresses"], + }, + { + name: "dns", + path: "dns", + components: + if provider == "aws" then [ + "external-dns", + "external-dns/route53", + ] + else if vmDriver == "docker-desktop" then [ + "coredns", + "coredns/etcd", + "external-dns", + "external-dns/localhost", + "external-dns/coredns", + "external-dns/ingress", + ] + else [ + "coredns", + "coredns/etcd", + "external-dns", + "external-dns/coredns", + "external-dns/ingress", + ], + dependsOn: if provider == "aws" then [] else ["pki-base"], + }, + { + name: "gitops", + path: "gitops/flux", + components: ["webhook"], + dependsOn: ["ingress"], + }, ], - dependsOn: ["telemetry-base"] - }, - { - name: "policy-base", - path: "policy/base", - components: ["kyverno"] - }, - { - name: "policy-resources", - path: "policy/resources", - dependsOn: ["policy-base"] - }, - { - name: "csi", - path: "csi", - components: if provider == "aws" then ["aws-ebs"] else if provider == "local" then [ - "openebs", - "openebs/dynamic-localpv" + // Optionally add MetalLB for local non-docker-desktop + if provider == "local" && vmDriver != "docker-desktop" then [ + { + name: "lb-base", + path: "lb/base", + components: ["metallb"], + dependsOn: ["policy-resources"], + }, + { + name: "lb-resources", + path: "lb/resources", + components: ["metallb/layer2"], + dependsOn: ["lb-base"], + }, ] else [], - dependsOn: ["policy-resources"], - cleanup: ["pvcs"] - }, - { - name: "pki-base", - path: "pki/base", - components: [ - "cert-manager", - "trust-manager" + [ + { + name: "observability", + path: "observability", + components: + concat([ + [ + "fluentd", + "fluentd/filters/otel", + "fluentd/outputs/stdout", + ], + if provider == "local" then [ + "fluentd/outputs/quickwit", + "quickwit", + "quickwit/pvc", + ] else [], + [ + "grafana", + "grafana/ingress", + "grafana/prometheus", + "grafana/node", + "grafana/kubernetes", + "grafana/flux", + ], + if provider == "local" then [ + "grafana/quickwit", + ] else [], + ]), + dependsOn: ["csi", "ingress"], + }, ], - dependsOn: ["policy-resources"] - }, - { - name: "pki-resources", - path: "pki/resources", - components: [ - "private-issuer/ca", - "public-issuer/selfsigned" - ], - dependsOn: ["pki-base"] - }, - { - name: "ingress", - path: "ingress", - components: if provider == "aws" then [ - "nginx", - "nginx/flux-webhook", - "nginx/web" - ] else if vmDriver == "docker-desktop" then [ - "nginx", - "nginx/nodeport", - "nginx/coredns", - "nginx/flux-webhook", - "nginx/web" - ] else [ - "nginx", - "nginx/loadbalancer", - "nginx/coredns", - "nginx/flux-webhook", - "nginx/web" - ], - dependsOn: ["pki-resources"], - cleanup: ["loadbalancers", "ingresses"] - }, - { - name: "dns", - path: "dns", - components: if provider == "aws" then [ - "external-dns", - "external-dns/route53" - ] else if vmDriver == "docker-desktop" then [ - "coredns", - "coredns/etcd", - "external-dns", - "external-dns/localhost", - "external-dns/coredns", - "external-dns/ingress" - ] else [ - "coredns", - "coredns/etcd", - "external-dns", - "external-dns/coredns", - "external-dns/ingress" - ], - dependsOn: if provider == "aws" then [] else ["pki-base"] - }, - { - name: "gitops", - path: "gitops/flux", - components: ["webhook"], - dependsOn: ["ingress"] - } - ] + (if provider == "local" && vmDriver != "docker-desktop" then [ - { - name: "lb-base", - path: "lb/base", - components: ["metallb"], - dependsOn: ["policy-resources"] - }, - { - name: "lb-resources", - path: "lb/resources", - components: ["metallb/layer2"], - dependsOn: ["lb-base"] - } - ] else []) + [ - { - name: "observability", - path: "observability", - components: [ - "fluentd", - "fluentd/filters/otel", - "fluentd/outputs/stdout" - ] + (if provider == "local" then [ - "fluentd/outputs/quickwit", - "quickwit", - "quickwit/pvc" - ] else []) + [ - "grafana", - "grafana/ingress", - "grafana/prometheus", - "grafana/node", - "grafana/kubernetes", - "grafana/flux" - ] + (if provider == "local" then [ - "grafana/quickwit" - ] else []), - dependsOn: ["csi", "ingress"] - } - ], -} + ]), +} diff --git a/contexts/_template/kustomize/values.jsonnet b/contexts/_template/kustomize/values.jsonnet new file mode 100644 index 000000000..c149f00ca --- /dev/null +++ b/contexts/_template/kustomize/values.jsonnet @@ -0,0 +1,26 @@ +local context = std.extVar("context"); +local hlp = std.extVar("helpers"); + +// Extracts local volume path from cluster.workers.volumes[0] +local volumes = hlp.getArray(context, "cluster.workers.volumes", []); +local raw_volume = if std.length(volumes) > 0 then volumes[0] else "/var/local"; +local local_volume_path = + if std.type(raw_volume) == "string" then + ( + local split = std.split(raw_volume, ":"); + if std.length(split) > 1 then split[1] else split[0] + ) + else + "/var/local"; + +{ + common: { + external_domain: hlp.getString(context, "dns.domain", "test"), + }, + csi: { + local_volume_path: local_volume_path, + }, + ingress: { + loadbalancer_ip: hlp.getString(context, "network.loadbalancer_ips.start", "10.5.1.1"), + }, +} diff --git a/contexts/_template/terraform/cluster/talos.jsonnet b/contexts/_template/terraform/cluster/talos.jsonnet index b5ddf2498..a5d8e8ed2 100644 --- a/contexts/_template/terraform/cluster/talos.jsonnet +++ b/contexts/_template/terraform/cluster/talos.jsonnet @@ -105,14 +105,18 @@ local commonConfig = { }; // Helper for volume mounts -local createMount(volume) = - local parts = std.split(volume, ":"); - { - destination: parts[1], - type: "bind", - source: parts[1], - options: ["rbind", "rw"] - }; +local createMount(volume) = + if std.type(volume) == "string" then + local parts = std.split(volume, ":"); + local dest = parts[std.length(parts) - 1]; + { + destination: dest, + type: "bind", + source: dest, + options: ["rbind", "rw"] + } + else + error "Volume must be a string"; // Worker config patches using helpers local workerVolumes = hlp.getArray(context, "cluster.workers.volumes", []); diff --git a/kustomize/csi/openebs/dynamic-localpv/patches/helm-release.yaml b/kustomize/csi/openebs/dynamic-localpv/patches/helm-release.yaml index 6f44c6ec0..04eb4fbcd 100644 --- a/kustomize/csi/openebs/dynamic-localpv/patches/helm-release.yaml +++ b/kustomize/csi/openebs/dynamic-localpv/patches/helm-release.yaml @@ -9,4 +9,4 @@ spec: localpv-provisioner: localpv: enabled: true - basePath: ${LOCAL_VOLUME_PATH} + basePath: ${local_volume_path:-/var/local} diff --git a/kustomize/csi/openebs/dynamic-localpv/storageclass.yaml b/kustomize/csi/openebs/dynamic-localpv/storageclass.yaml index a6364fde6..496827e0d 100644 --- a/kustomize/csi/openebs/dynamic-localpv/storageclass.yaml +++ b/kustomize/csi/openebs/dynamic-localpv/storageclass.yaml @@ -9,7 +9,7 @@ metadata: - name: StorageType value: hostpath - name: BasePath - value: ${LOCAL_VOLUME_PATH} + value: ${local_volume_path:-/var/local} provisioner: openebs.io/local reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer @@ -25,7 +25,7 @@ metadata: - name: StorageType value: hostpath - name: BasePath - value: ${LOCAL_VOLUME_PATH} + value: ${local_volume_path:-/var/local} provisioner: openebs.io/local reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer diff --git a/kustomize/demo/bookinfo/ingress/ingress.yaml b/kustomize/demo/bookinfo/ingress/ingress.yaml index bebf4d6cf..38e3f65ab 100644 --- a/kustomize/demo/bookinfo/ingress/ingress.yaml +++ b/kustomize/demo/bookinfo/ingress/ingress.yaml @@ -5,7 +5,7 @@ metadata: namespace: demo-bookinfo spec: rules: - - host: bookinfo.${DOMAIN} + - host: bookinfo.${external_domain:-test} http: paths: - path: / diff --git a/kustomize/demo/static/ingress/ingress.yaml b/kustomize/demo/static/ingress/ingress.yaml index db964cb70..212e2beaf 100644 --- a/kustomize/demo/static/ingress/ingress.yaml +++ b/kustomize/demo/static/ingress/ingress.yaml @@ -5,7 +5,7 @@ metadata: namespace: demo-static spec: rules: - - host: static.${DOMAIN} + - host: static.${external_domain:-test} http: paths: - path: / diff --git a/kustomize/dns/external-dns/helm-release.yaml b/kustomize/dns/external-dns/helm-release.yaml index ce034208f..d8dad86ac 100644 --- a/kustomize/dns/external-dns/helm-release.yaml +++ b/kustomize/dns/external-dns/helm-release.yaml @@ -23,4 +23,4 @@ spec: extraVolumeMounts: [] sources: [] domainFilters: - - "${DOMAIN}" + - "${external_domain:-test}" diff --git a/kustomize/dns/external-dns/route53/patches/helm-release.yaml b/kustomize/dns/external-dns/route53/patches/helm-release.yaml index aebe112af..d9d78907d 100644 --- a/kustomize/dns/external-dns/route53/patches/helm-release.yaml +++ b/kustomize/dns/external-dns/route53/patches/helm-release.yaml @@ -24,8 +24,8 @@ spec: policy: sync registry: txt domainFilters: - - ${DOMAIN} + - ${external_domain:-test} serviceAccount: create: true name: external-dns - annotations: {} + annotations: {} diff --git a/kustomize/ingress/nginx/loadbalancer/patches/helm-release.yaml b/kustomize/ingress/nginx/loadbalancer/patches/helm-release.yaml index 265775b86..5cde31c20 100644 --- a/kustomize/ingress/nginx/loadbalancer/patches/helm-release.yaml +++ b/kustomize/ingress/nginx/loadbalancer/patches/helm-release.yaml @@ -9,4 +9,4 @@ spec: controller: service: type: LoadBalancer - loadBalancerIP: ${LOADBALANCER_IP_START} + loadBalancerIP: ${loadbalancer_ip} diff --git a/kustomize/observability/grafana/ingress/ingress.yaml b/kustomize/observability/grafana/ingress/ingress.yaml index 98cade32a..259a8e5ae 100644 --- a/kustomize/observability/grafana/ingress/ingress.yaml +++ b/kustomize/observability/grafana/ingress/ingress.yaml @@ -5,7 +5,7 @@ metadata: namespace: system-observability spec: rules: - - host: grafana.${DOMAIN} + - host: grafana.${external_domain:-test} http: paths: - path: / diff --git a/kustomize/observability/kibana/ingress/ingress.yaml b/kustomize/observability/kibana/ingress/ingress.yaml index b9f5065c7..05a826f01 100644 --- a/kustomize/observability/kibana/ingress/ingress.yaml +++ b/kustomize/observability/kibana/ingress/ingress.yaml @@ -8,7 +8,7 @@ metadata: spec: ingressClassName: nginx rules: - - host: kibana.${DOMAIN} + - host: kibana.${external_domain:-test} http: paths: - path: / From 44a7f5f841bcf720849218d4fafe5d8b6d860423 Mon Sep 17 00:00:00 2001 From: Ryan VanGundy Date: Sun, 3 Aug 2025 19:33:47 -0400 Subject: [PATCH 4/4] Remove empty values from template output --- contexts/_template/kustomize/values.jsonnet | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contexts/_template/kustomize/values.jsonnet b/contexts/_template/kustomize/values.jsonnet index c149f00ca..bbc71e551 100644 --- a/contexts/_template/kustomize/values.jsonnet +++ b/contexts/_template/kustomize/values.jsonnet @@ -3,7 +3,7 @@ local hlp = std.extVar("helpers"); // Extracts local volume path from cluster.workers.volumes[0] local volumes = hlp.getArray(context, "cluster.workers.volumes", []); -local raw_volume = if std.length(volumes) > 0 then volumes[0] else "/var/local"; +local raw_volume = if std.length(volumes) > 0 then volumes[0] else ""; local local_volume_path = if std.type(raw_volume) == "string" then ( @@ -11,9 +11,9 @@ local local_volume_path = if std.length(split) > 1 then split[1] else split[0] ) else - "/var/local"; + ""; -{ +hlp.removeEmptyKeys({ common: { external_domain: hlp.getString(context, "dns.domain", "test"), }, @@ -21,6 +21,6 @@ local local_volume_path = local_volume_path: local_volume_path, }, ingress: { - loadbalancer_ip: hlp.getString(context, "network.loadbalancer_ips.start", "10.5.1.1"), + loadbalancer_ip: hlp.getString(context, "network.loadbalancer_ips.start", ""), }, -} +})