From 474e44127f2a51f4b7cdc00c94e4bdabe3749dfb Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Tue, 18 Mar 2025 14:26:03 -0500 Subject: [PATCH 01/32] Add wg-easy application example with helmfile and taskfile flow --- .gitignore | 5 + applications/wg-easy/Taskfile.yaml | 300 ++++++++++++++++++ .../wg-easy/cert-manager-issuers/Chart.yaml | 6 + .../helmChart-cert-manager-issuers.yaml | 13 + .../templates/issuers.yaml | 53 ++++ .../wg-easy/cert-manager-issuers/values.yaml | 7 + applications/wg-easy/cert-manager/Chart.yaml | 10 + .../replicated/helmChart-cert-manager.yaml | 13 + .../cert-manager/templates/issuers.yaml | 53 ++++ applications/wg-easy/cert-manager/values.yaml | 30 ++ .../wg-easy/charts/templates/Chart.yaml | 6 + .../templates/traefik-route-tcp.yaml | 21 ++ .../templates/templates/traefik-routes.yaml | 106 +++++++ .../wg-easy/charts/templates/values.yaml | 27 ++ applications/wg-easy/helmfile.yaml | 58 ++++ .../wg-easy/replicated/application.yaml | 26 ++ applications/wg-easy/replicated/cluster.yaml | 13 + applications/wg-easy/replicated/config.yaml | 4 + applications/wg-easy/taskfiles/utils.yml | 173 ++++++++++ applications/wg-easy/traefik/Chart.yaml | 11 + .../traefik/replicated/helmChart-traefik.yaml | 13 + .../traefik/templates/certificate.yaml | 64 ++++ .../traefik/templates/tls-options.yaml | 8 + applications/wg-easy/traefik/values.yaml | 21 ++ applications/wg-easy/wg-easy/Chart.yaml | 13 + .../wg-easy/wg-easy/replicated/config.yaml | 37 +++ .../wg-easy/replicated/helmChart-wg-easy.yaml | 38 +++ applications/wg-easy/wg-easy/values.yaml | 40 +++ 28 files changed, 1169 insertions(+) create mode 100644 applications/wg-easy/Taskfile.yaml create mode 100644 applications/wg-easy/cert-manager-issuers/Chart.yaml create mode 100644 applications/wg-easy/cert-manager-issuers/replicated/helmChart-cert-manager-issuers.yaml create mode 100644 applications/wg-easy/cert-manager-issuers/templates/issuers.yaml create mode 100644 applications/wg-easy/cert-manager-issuers/values.yaml create mode 100644 applications/wg-easy/cert-manager/Chart.yaml create mode 100644 applications/wg-easy/cert-manager/replicated/helmChart-cert-manager.yaml create mode 100644 applications/wg-easy/cert-manager/templates/issuers.yaml create mode 100644 applications/wg-easy/cert-manager/values.yaml create mode 100644 applications/wg-easy/charts/templates/Chart.yaml create mode 100644 applications/wg-easy/charts/templates/templates/traefik-route-tcp.yaml create mode 100644 applications/wg-easy/charts/templates/templates/traefik-routes.yaml create mode 100644 applications/wg-easy/charts/templates/values.yaml create mode 100644 applications/wg-easy/helmfile.yaml create mode 100644 applications/wg-easy/replicated/application.yaml create mode 100644 applications/wg-easy/replicated/cluster.yaml create mode 100644 applications/wg-easy/replicated/config.yaml create mode 100644 applications/wg-easy/taskfiles/utils.yml create mode 100644 applications/wg-easy/traefik/Chart.yaml create mode 100644 applications/wg-easy/traefik/replicated/helmChart-traefik.yaml create mode 100644 applications/wg-easy/traefik/templates/certificate.yaml create mode 100644 applications/wg-easy/traefik/templates/tls-options.yaml create mode 100644 applications/wg-easy/traefik/values.yaml create mode 100644 applications/wg-easy/wg-easy/Chart.yaml create mode 100644 applications/wg-easy/wg-easy/replicated/config.yaml create mode 100644 applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml create mode 100644 applications/wg-easy/wg-easy/values.yaml diff --git a/.gitignore b/.gitignore index 5c32dd1..5450c6c 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,8 @@ Thumbs.db *.pyo *.pyd __pycache__/ + +# wg-easy specific +applications/wg-easy/release/ +applications/wg-easy/*/charts/ +applications/wg-easy/*/Chart.lock diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml new file mode 100644 index 0000000..412b640 --- /dev/null +++ b/applications/wg-easy/Taskfile.yaml @@ -0,0 +1,300 @@ +version: "3" + +includes: + utils: ./taskfiles/utils.yml + +vars: + # Cluster configuration + CLUSTER_NAME: '{{.CLUSTER_NAME | default "test-cluster"}}' + K8S_VERSION: '{{.K8S_VERSION | default "1.32.2"}}' + DISK_SIZE: '{{.DISK_SIZE | default "100"}}' + INSTANCE_TYPE: '{{.INSTANCE_TYPE | default "r1.small"}}' + DISTRIBUTION: '{{.DISTRIBUTION | default "k3s"}}' + KUBECONFIG_FILE: './kubeconfig-{{.CLUSTER_NAME}}' + + # Ports configuration + EXPOSE_PORTS: + - port: 443 + protocol: https + - port: 80 + protocol: http + + # GCP default configuration + GCP_PROJECT: '{{.GCP_PROJECT | default "replicated-qa"}}' + GCP_ZONE: '{{.GCP_ZONE | default "us-central1-a"}}' + VM_NAME: '{{.VM_NAME | default (printf "%s-dev" (or (env "GUSER") "user"))}}' + +tasks: + default: + desc: Show available tasks + cmds: + - task -s --list + + create-cluster: + desc: Create a test cluster using Replicated Compatibility Matrix (use EMBEDDED=true for embedded clusters) + run: once + silent: true + vars: + EMBEDDED: '{{.EMBEDDED | default "false"}}' + LICENSE_ID: '{{if eq .EMBEDDED "true"}}{{.LICENSE_ID | default "2cmqT1dBVHZ3aSH21kPxWtgoYGr"}}{{end}}' + TIMEOUT: '{{if eq .EMBEDDED "true"}}420{{else}}300{{end}}' + status: + - replicated cluster ls --output json | jq -e '.[] | select(.name == "{{.CLUSTER_NAME}}")' > /dev/null + cmds: + - | + if [ "{{.EMBEDDED}}" = "true" ]; then + echo "Creating embedded cluster {{.CLUSTER_NAME}} with license ID {{.LICENSE_ID}}..." + replicated cluster create --distribution embedded-cluster --name {{.CLUSTER_NAME}} --license-id {{.LICENSE_ID}} + else + echo "Creating cluster {{.CLUSTER_NAME}} with distribution {{.DISTRIBUTION}}..." + replicated cluster create --name {{.CLUSTER_NAME}} --distribution {{.DISTRIBUTION}} --version {{.K8S_VERSION}} --disk {{.DISK_SIZE}} --instance-type {{.INSTANCE_TYPE}} + fi + - task: utils:wait-for-cluster + vars: + TIMEOUT: "{{.TIMEOUT}}" + + test: + desc: Run a basic test suite + silent: true + cmds: + - echo "Running basic tests..." + - echo "This is a placeholder for actual tests" + - sleep 5 + - echo "Tests completed!" + + get-kubeconfig: + desc: Get kubeconfig for the test cluster + silent: true + run: once + cmds: + - | + echo "Getting kubeconfig for cluster {{.CLUSTER_NAME}}..." + replicated cluster kubeconfig --name {{.CLUSTER_NAME}} --output-path {{.KUBECONFIG_FILE}} + status: + - test -f {{.KUBECONFIG_FILE}} + deps: + - create-cluster + + update-dependencies: + desc: Update Helm dependencies for all charts + silent: true + cmds: + - echo "Updating Helm dependencies for all charts..." + - | + # Find all charts and update their dependencies + for chart_dir in $(find . -maxdepth 2 -name "Chart.yaml" | xargs dirname); do + echo "Updating dependency $chart_dir" + helm dependency update "$chart_dir" + done + - echo "All dependencies updated!" + + expose-ports: + desc: Expose configured ports and capture exposed URLs + silent: true + run: once + status: + - | + CLUSTER_ID=$(replicated cluster ls --output json | jq -r '.[] | select(.name == "{{.CLUSTER_NAME}}") | .id') + if [ -z "$CLUSTER_ID" ]; then + exit 1 + fi + + # Check if all ports are already exposed + expected_count={{len .EXPOSE_PORTS}} + port_checks="" + {{range $i, $port := .EXPOSE_PORTS}} + port_checks="${port_checks}(.upstream_port == {{$port.port}} and .exposed_ports[0].protocol == \"{{$port.protocol}}\") or " + {{end}} + # Remove trailing "or " + port_checks="${port_checks% or }" + + PORT_COUNT=$(replicated cluster port ls $CLUSTER_ID --output json | jq -r ".[] | select($port_checks) | .upstream_port" | wc -l | tr -d ' ') + [ "$PORT_COUNT" -eq "$expected_count" ] + cmds: + - task: utils:port-operations + vars: + OPERATION: "expose" + deps: + - create-cluster + + deploy-helm: + desc: Deploy all charts using helmfile + silent: true + cmds: + - echo "Installing all charts via helmfile" + - | + # Get cluster ID + CLUSTER_ID=$(replicated cluster ls --output json | jq -r '.[] | select(.name == "{{.CLUSTER_NAME}}") | .id') + if [ -z "$CLUSTER_ID" ]; then + echo "Error: Could not find cluster with name {{.CLUSTER_NAME}}" + exit 1 + fi + + # Get exposed URLs + ENV_VARS=$(task utils:port-operations OPERATION=getenv CLUSTER_NAME={{.CLUSTER_NAME}}) + + # Deploy with helmfile + echo "Using $ENV_VARS" + KUBECONFIG={{.KUBECONFIG_FILE}} $ENV_VARS helmfile sync --wait + - echo "All charts deployed!" + deps: + - get-kubeconfig + - expose-ports + - remove-k3s-traefik + + remove-k3s-traefik: + desc: Remove pre-installed Traefik from k3s clusters + silent: true + cmds: + - | + # Only run for k3s distributions + if [ "{{.DISTRIBUTION}}" = "k3s" ]; then + task utils:traefik-operations OPERATION=remove KUBECONFIG_FILE={{.KUBECONFIG_FILE}} + else + echo "Not a k3s cluster, skipping Traefik removal." + fi + deps: + - get-kubeconfig + + delete-cluster: + desc: Delete all test clusters with matching name and clean up kubeconfig + silent: true + cmds: + - echo "Deleting clusters named {{.CLUSTER_NAME}}..." + - | + CLUSTER_IDS=$(replicated cluster ls | grep "{{.CLUSTER_NAME}}" | awk '{print $1}') + if [ -z "$CLUSTER_IDS" ]; then + echo "No clusters found with name {{.CLUSTER_NAME}}" + exit 0 + fi + + for id in $CLUSTER_IDS; do + echo "Deleting cluster ID: $id" + replicated cluster rm "$id" + done + - | + # Clean up kubeconfig file + if [ -f "{{.KUBECONFIG_FILE}}" ]; then + echo "Removing kubeconfig file {{.KUBECONFIG_FILE}}" + rm "{{.KUBECONFIG_FILE}}" + fi + - echo "All matching clusters deleted and kubeconfig cleaned up!" + + prepare-release: + desc: Prepare release files by copying replicated YAML files and packaging Helm charts + silent: true + cmds: + - echo "Preparing release files..." + - rm -rf ./release + - mkdir -p ./release + + # Copy all non-config.yaml files + - echo "Copying non-config YAML files to release folder..." + - find . -path '*/replicated/*.yaml' -not -name 'config.yaml' -exec cp {} ./release/ \; + - find ./replicated -name '*.yaml' -not -name 'config.yaml' -exec cp {} ./release/ \; 2>/dev/null || true + + # Merge config.yaml files + - echo "Merging config.yaml files..." + - | + # Start with an empty config file + echo "{}" > ./release/config.yaml + + # Merge all app config.yaml files first (excluding root replicated) + for config_file in $(find . -path '*/replicated/config.yaml' | grep -v "^./replicated/"); do + echo "Merging $config_file..." + yq eval-all '. as $item ireduce ({}; . * $item)' ./release/config.yaml "$config_file" > ./release/config.yaml.new + mv ./release/config.yaml.new ./release/config.yaml + done + + # Merge root config.yaml last + if [ -f "./replicated/config.yaml" ]; then + echo "Merging root config.yaml last..." + yq eval-all '. as $item ireduce ({}; . * $item)' ./release/config.yaml "./replicated/config.yaml" > ./release/config.yaml.new + mv ./release/config.yaml.new ./release/config.yaml + fi + + # Package Helm charts + - echo "Packaging Helm charts..." + - | + # Find top-level directories containing Chart.yaml files + for chart_dir in $(find . -maxdepth 2 -name "Chart.yaml" | xargs dirname); do + echo "Packaging chart: $chart_dir" + # Navigate to chart directory, package it, and move the resulting .tgz to release folder + (cd "$chart_dir" && helm package . && mv *.tgz ../release/) + done + + - echo "Release files prepared in ./release/ directory" + + release-create: + desc: Create and promote a release for home-cluster using the Replicated CLI + silent: true + requiredVars: + - CHANNEL + vars: + RELEASE_NOTES: '{{.RELEASE_NOTES | default "Release created via task release-create"}}' + cmds: + - echo "Creating and promoting release for home-cluster to channel {{.CHANNEL}}..." + - | + # Create and promote the release in one step + echo "Creating release from files in ./release directory..." + replicated release create --app home-cluster --yaml-dir ./release --release-notes "{{.RELEASE_NOTES}}" --promote {{.CHANNEL}} + + echo "Release created and promoted to channel {{.CHANNEL}}" + deps: + - prepare-release + + create-gcp-vm: + desc: Create a simple GCP VM instance + silent: true + vars: + GCP_MACHINE_TYPE: '{{.GCP_MACHINE_TYPE | default "e2-standard-2"}}' + GCP_DISK_SIZE: '{{.GCP_DISK_SIZE | default "100"}}' + GCP_DISK_TYPE: '{{.GCP_DISK_TYPE | default "pd-standard"}}' + GCP_IMAGE_FAMILY: '{{.GCP_IMAGE_FAMILY | default "ubuntu-2204-lts"}}' + GCP_IMAGE_PROJECT: '{{.GCP_IMAGE_PROJECT | default "ubuntu-os-cloud"}}' + status: + - gcloud compute instances describe {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} &>/dev/null + cmds: + - task: utils:gcp-operations + vars: + OPERATION: "create" + + delete-gcp-vm: + desc: Delete the GCP VM instance for K8s and VPN + silent: true + status: + - "! gcloud compute instances describe {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} &>/dev/null" + cmds: + - task: utils:gcp-operations + vars: + OPERATION: "delete" + + setup-embedded-cluster: + desc: Setup Replicated embedded cluster on the GCP VM + silent: true + vars: + CHANNEL: '{{.CHANNEL | default "unstable"}}' + AUTH_TOKEN: '{{.AUTH_TOKEN | default "2uJbnRgxrmrhqBDF1Sd7wcYFDPh"}}' + deps: + - create-gcp-vm + status: + - | + # Check if the home-cluster tarball has already been downloaded and extracted + gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} --command="test -d ./home-cluster" &>/dev/null + cmds: + - task: utils:gcp-operations + vars: + OPERATION: "setup-embedded" + + full-test-cycle: + desc: Create cluster, get kubeconfig, expose ports, update dependencies, deploy charts, test, and delete + silent: true + cmds: + - task: create-cluster + - task: get-kubeconfig + - task: expose-ports + - task: remove-k3s-traefik + - task: update-dependencies + - task: deploy-helm + - task: test + - task: delete-cluster \ No newline at end of file diff --git a/applications/wg-easy/cert-manager-issuers/Chart.yaml b/applications/wg-easy/cert-manager-issuers/Chart.yaml new file mode 100644 index 0000000..b94c9b7 --- /dev/null +++ b/applications/wg-easy/cert-manager-issuers/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: cert-manager-issuers +description: A Helm chart for cert-manager issuers +type: application +version: 1.0.0 +appVersion: "1.0.0" diff --git a/applications/wg-easy/cert-manager-issuers/replicated/helmChart-cert-manager-issuers.yaml b/applications/wg-easy/cert-manager-issuers/replicated/helmChart-cert-manager-issuers.yaml new file mode 100644 index 0000000..3fabd0c --- /dev/null +++ b/applications/wg-easy/cert-manager-issuers/replicated/helmChart-cert-manager-issuers.yaml @@ -0,0 +1,13 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: cert-manager-issuers +spec: + chart: + name: cert-manager-issuers + chartVersion: '1.0.0' + weight: 1 + helmUpgradeFlags: + - --wait + namespace: cert-manager + builder: {} diff --git a/applications/wg-easy/cert-manager-issuers/templates/issuers.yaml b/applications/wg-easy/cert-manager-issuers/templates/issuers.yaml new file mode 100644 index 0000000..898c10f --- /dev/null +++ b/applications/wg-easy/cert-manager-issuers/templates/issuers.yaml @@ -0,0 +1,53 @@ +{{- if .Values.local.letsencrypt.staging }} +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + acme: + email: {{ .Values.local.letsencrypt.email }} + server: https://acme-staging-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-staging-account-key + solvers: + - dns01: + cloudflare: + apiTokenSecretRef: + name: cloudflare-token + key: token +{{- end }} +{{- if .Values.local.letsencrypt.production }} +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-production + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + acme: + email: {{ .Values.local.letsencrypt.email }} + server: https://acme-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-production-account-key + solvers: + - dns01: + cloudflare: + apiTokenSecretRef: + name: cloudflare-token + key: token +{{- end }} +{{- if .Values.local.letsencrypt.selfSigned }} +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: selfsigned-cluster-issuer + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + selfSigned: {} +{{- end }} diff --git a/applications/wg-easy/cert-manager-issuers/values.yaml b/applications/wg-easy/cert-manager-issuers/values.yaml new file mode 100644 index 0000000..b0ab9dd --- /dev/null +++ b/applications/wg-easy/cert-manager-issuers/values.yaml @@ -0,0 +1,7 @@ +local: + letsencrypt: + production: false + staging: false + selfSigned: true + email: admin@example.com + acme_host: 'dns.example.com' diff --git a/applications/wg-easy/cert-manager/Chart.yaml b/applications/wg-easy/cert-manager/Chart.yaml new file mode 100644 index 0000000..f2d6482 --- /dev/null +++ b/applications/wg-easy/cert-manager/Chart.yaml @@ -0,0 +1,10 @@ +name: cert-manager +apiVersion: v2 +version: 1.0.0 +dependencies: + - name: cert-manager + version: '1.14.5' + repository: https://charts.jetstack.io + - name: templates + version: '*' + repository: file://../charts/templates diff --git a/applications/wg-easy/cert-manager/replicated/helmChart-cert-manager.yaml b/applications/wg-easy/cert-manager/replicated/helmChart-cert-manager.yaml new file mode 100644 index 0000000..495eeec --- /dev/null +++ b/applications/wg-easy/cert-manager/replicated/helmChart-cert-manager.yaml @@ -0,0 +1,13 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: cert-manager +spec: + chart: + name: cert-manager + chartVersion: '1.0.0' + weight: 0 + helmUpgradeFlags: + - --wait + namespace: cert-manager + builder: {} diff --git a/applications/wg-easy/cert-manager/templates/issuers.yaml b/applications/wg-easy/cert-manager/templates/issuers.yaml new file mode 100644 index 0000000..898c10f --- /dev/null +++ b/applications/wg-easy/cert-manager/templates/issuers.yaml @@ -0,0 +1,53 @@ +{{- if .Values.local.letsencrypt.staging }} +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + acme: + email: {{ .Values.local.letsencrypt.email }} + server: https://acme-staging-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-staging-account-key + solvers: + - dns01: + cloudflare: + apiTokenSecretRef: + name: cloudflare-token + key: token +{{- end }} +{{- if .Values.local.letsencrypt.production }} +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-production + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + acme: + email: {{ .Values.local.letsencrypt.email }} + server: https://acme-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-production-account-key + solvers: + - dns01: + cloudflare: + apiTokenSecretRef: + name: cloudflare-token + key: token +{{- end }} +{{- if .Values.local.letsencrypt.selfSigned }} +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: selfsigned-cluster-issuer + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + selfSigned: {} +{{- end }} diff --git a/applications/wg-easy/cert-manager/values.yaml b/applications/wg-easy/cert-manager/values.yaml new file mode 100644 index 0000000..60c98f7 --- /dev/null +++ b/applications/wg-easy/cert-manager/values.yaml @@ -0,0 +1,30 @@ +cert-manager: + global: + leaderElection: + # Override the namespace used to store the ConfigMap for leader election + namespace: "cert-manager" + installCRDs: true + extraArgs: + - --cluster-resource-namespace=cert-manager + - --enable-certificate-owner-ref=true + resources: + requests: + cpu: 5m + memory: 45Mi + webhook: + resources: + requests: + cpu: 5m + memory: 22Mi + cainjector: + resources: + requests: + cpu: 5m + memory: 101Mi +local: + letsencrypt: + production: false + staging: false + selfSigned: false + email: admin@example.com + acme_host: 'dns.example.com' diff --git a/applications/wg-easy/charts/templates/Chart.yaml b/applications/wg-easy/charts/templates/Chart.yaml new file mode 100644 index 0000000..ff801ee --- /dev/null +++ b/applications/wg-easy/charts/templates/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: latest +description: Common templates +name: templates +version: 1.0.0 +kubeVersion: ">=1.16.0-0" diff --git a/applications/wg-easy/charts/templates/templates/traefik-route-tcp.yaml b/applications/wg-easy/charts/templates/templates/traefik-route-tcp.yaml new file mode 100644 index 0000000..3a47c8f --- /dev/null +++ b/applications/wg-easy/charts/templates/templates/traefik-route-tcp.yaml @@ -0,0 +1,21 @@ +{{- range .Values.traefikRouteTCP }} +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRouteTCP +metadata: + {{- if .routeName }} + name: {{ .routeName }} + {{- else }} + name: {{ .serviceName }} + {{- end }} +spec: + entryPoints: + {{- range .entryPoints }} + - "{{ . }}" + {{- end }} + routes: + - match: HostSNI(`*`) + services: + - name: {{ .serviceName }} + port: {{ .servicePort }} +{{- end }} diff --git a/applications/wg-easy/charts/templates/templates/traefik-routes.yaml b/applications/wg-easy/charts/templates/templates/traefik-routes.yaml new file mode 100644 index 0000000..17dfa12 --- /dev/null +++ b/applications/wg-easy/charts/templates/templates/traefik-routes.yaml @@ -0,0 +1,106 @@ +{{- define "authUrl" -}} + {{- $auth := .auth | default dict -}} + {{- $host := default "auth" $auth.host -}} + {{- printf "http://keycloak-service.keycloak.svc:8080/realms/%s/protocol/openid-connect/certs" $host -}} +{{- end -}} + +{{- define "getMiddlewareName" -}} + {{- $host := .host | splitList "." -}} + {{- $firstPart := index $host 0 -}} + {{- $path := .path | default "" | trimPrefix "/" | replace "/" "-" -}} + {{- if $path -}} + {{- printf "%s-%s" $firstPart $path -}} + {{- else -}} + {{- $firstPart -}} + {{- end -}} +{{- end -}} + +{{- range $host, $routeConfig := .Values.traefikRoutes }} +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: {{ $host | splitList "." | first }} +spec: + entryPoints: + - websecure + routes: + {{- range $route := $routeConfig.routes | default (list (dict "path" "")) }} + - kind: Rule + match: Host(`{{ $routeConfig.hostName | default $host }}`){{ if .path }} && Path(`{{ .path }}`){{ end }}{{ if .pathPrefix }} && PathPrefix(`{{ .pathPrefix }}`){{ end }} + {{- if or .redirectPath .authGroups }} + middlewares: + {{- if .redirectPath }} + - name: {{ include "getMiddlewareName" (dict "host" $host "path" (or .path .pathPrefix)) }}-redirect + {{- end }} + {{- if .authGroups }} + - name: {{ include "getMiddlewareName" (dict "host" $host "path" (or .path .pathPrefix)) }}-auth + - name: {{ include "getMiddlewareName" (dict "host" $host "path" (or .path .pathPrefix)) }}-inject-groups + - name: {{ include "getMiddlewareName" (dict "host" $host "path" (or .path .pathPrefix)) }}-authz + {{- end }} + {{- end }} + services: + {{- if .redirectPath }} + - kind: TraefikService + name: noop@internal + {{- else }} + - kind: {{ $routeConfig.serviceType | default "Service" }} + name: {{ $routeConfig.serviceName }} + {{- if not $routeConfig.serviceType }} + port: {{ $routeConfig.servicePort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} + +{{- range $host, $routeConfig := .Values.traefikRoutes }} + {{- range $route := $routeConfig.routes }} + {{- if .redirectPath }} +--- +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: {{ include "getMiddlewareName" (dict "host" $host "path" (or .path .pathPrefix)) }}-redirect +spec: + redirectRegex: + regex: ^https?://{{ $routeConfig.hostName | default $host | replace "." "\\." }}{{ or .path .pathPrefix | default "/" | replace "/" "\\/" }}/?$ + replacement: https://{{ $routeConfig.hostName | default $host }}{{ .redirectPath }} + permanent: true + {{- end }} + + {{- if .authGroups }} +--- +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: {{ include "getMiddlewareName" (dict "host" $host "path" (or .path .pathPrefix)) }}-auth +spec: + forwardAuth: + address: http://oauth2-proxy.oauth2-proxy.svc.cluster.local:80 + trustForwardHeader: true + authResponseHeaders: + - Authorization +--- +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: {{ include "getMiddlewareName" (dict "host" $host "path" (or .path .pathPrefix)) }}-inject-groups +spec: + headers: + customRequestHeaders: + X-Required-Groups: {{ join "," .authGroups | quote }} +--- +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: {{ include "getMiddlewareName" (dict "host" $host "path" (or .path .pathPrefix)) }}-authz +spec: + plugin: + jwt: + OpaUrl: http://opa.opa.svc:8181/v1/data/keycloak/authz + Required: true + Keys: + - {{ include "authUrl" (dict "auth" $routeConfig.auth) }} + {{- end }} + {{- end }} +{{- end }} diff --git a/applications/wg-easy/charts/templates/values.yaml b/applications/wg-easy/charts/templates/values.yaml new file mode 100644 index 0000000..9340364 --- /dev/null +++ b/applications/wg-easy/charts/templates/values.yaml @@ -0,0 +1,27 @@ +#traefikRoutes: +# host.example.com: +# serviceName: my-serviceName +# servicePort: my-servicePort +# #Optional: Override the auth settings +# #auth: +# # domain: example.com +# # host: auth +# # realm: example.com +# routes: +# - path: / +# - path: /login +# auth: true +# - path: /admin +# auth: true +# authGroups: +# - admin +# - superuser +# - path: /old-path +# redirectPath: /new-path +# - pathPrefix: /docs +# auth: true +# traefikRouteTCP: +# - serviceName: +# servicePort: +# entryPoints: +# - diff --git a/applications/wg-easy/helmfile.yaml b/applications/wg-easy/helmfile.yaml new file mode 100644 index 0000000..14595b0 --- /dev/null +++ b/applications/wg-easy/helmfile.yaml @@ -0,0 +1,58 @@ +# Global configuration +helmDefaults: + verify: false + wait: true + timeout: 600 + atomic: true + cleanupOnFail: true + +releases: + # Install cert-manager with CRDs but without issuers + - name: cert-manager + namespace: cert-manager + chart: ./cert-manager + createNamespace: true + wait: true + installed: true + skipDeps: true + + # Install issuers separately after cert-manager is ready + - name: cert-manager-issuers + namespace: cert-manager + chart: ./cert-manager-issuers + createNamespace: true + wait: true + installed: true + skipDeps: true + needs: + - cert-manager/cert-manager + + - name: traefik + namespace: traefik + chart: ./traefik + createNamespace: true + wait: true + installed: true + skipDeps: true + needs: + - cert-manager/cert-manager-issuers + + - name: wg-easy + namespace: wg-easy + chart: ./wg-easy + createNamespace: true + wait: true + installed: true + skipDeps: true + needs: + - traefik/traefik + values: + - wg-easy: + wireguard: + host: '{{ env "TF_EXPOSED_URL" }}' + - templates: + traefikRoutes: + web-tls: + hostName: '{{ env "TF_EXPOSED_URL" }}' + web: + hostName: '{{ env "TF_EXPOSED_HTTP_URL" }}' diff --git a/applications/wg-easy/replicated/application.yaml b/applications/wg-easy/replicated/application.yaml new file mode 100644 index 0000000..c2113d9 --- /dev/null +++ b/applications/wg-easy/replicated/application.yaml @@ -0,0 +1,26 @@ +apiVersion: kots.io/v1beta1 +kind: Application +metadata: + name: wg-easy +spec: + title: wg-easy + icon: https://www.logo.wine/a/logo/WireGuard/WireGuard-Icon-Logo.wine.svg + #releaseNotes: These are our release notes + allowRollback: true + #additionalImages: + # - jenkins/jenkins:lts + additionalNamespaces: + - "cert-manager" + - "traefik" + - "wg-easy" + - "*" + #ports: + # - serviceName: wg-easy/web + # servicePort: 51821 + # applicationUrl: "http://web" + statusInformers: + - wg-easy/deployment/public + - traefik/deployment/traefik + - cert-manager/deployment/cert-manager + - cert-manager/deployment/cert-manager-cainjector + - cert-manager/deployment/cert-manager-webhook diff --git a/applications/wg-easy/replicated/cluster.yaml b/applications/wg-easy/replicated/cluster.yaml new file mode 100644 index 0000000..7a3deb7 --- /dev/null +++ b/applications/wg-easy/replicated/cluster.yaml @@ -0,0 +1,13 @@ +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + version: 2.1.3+k8s-1.29 + unsupportedOverrides: + k0s: |- + config: + spec: + workerProfiles: + - name: default + values: + allowedUnsafeSysctls: + - net.ipv4.ip_forward diff --git a/applications/wg-easy/replicated/config.yaml b/applications/wg-easy/replicated/config.yaml new file mode 100644 index 0000000..d941c4b --- /dev/null +++ b/applications/wg-easy/replicated/config.yaml @@ -0,0 +1,4 @@ +apiVersion: kots.io/v1beta1 +kind: Config +metadata: + name: wg-easy diff --git a/applications/wg-easy/taskfiles/utils.yml b/applications/wg-easy/taskfiles/utils.yml new file mode 100644 index 0000000..8b746cf --- /dev/null +++ b/applications/wg-easy/taskfiles/utils.yml @@ -0,0 +1,173 @@ +version: "3" + +tasks: + wait-for-cluster: + desc: Wait for cluster to be in running state + internal: true + silent: true + vars: + CLUSTER_NAME: '{{.CLUSTER_NAME}}' + TIMEOUT: '{{.TIMEOUT | default "300"}}' + cmds: + - | + echo "Waiting for cluster {{.CLUSTER_NAME}} (timeout {{.TIMEOUT}}s)..." + start=$(date +%s) + attempt=1 + while true; do + CLUSTER_STATUS=$(replicated cluster ls --output json | jq -r '.[] | select(.name == "{{.CLUSTER_NAME}}") | .status') + + if [ "$CLUSTER_STATUS" = "running" ]; then + elapsed=$(($(date +%s) - start)) + echo "Cluster {{.CLUSTER_NAME}} is ready! (took $elapsed seconds)" + break + fi + + elapsed=$(($(date +%s) - start)) + if [ $elapsed -ge {{.TIMEOUT}} ]; then + echo "Timeout after {{.TIMEOUT}} seconds waiting for cluster to be ready" + exit 1 + fi + + printf "\rWaiting... %ds elapsed (attempt %d) - Current status: %s " "$elapsed" "$attempt" "$CLUSTER_STATUS" + sleep 5 + attempt=$((attempt+1)) + done + + traefik-operations: + desc: Operations for managing Traefik + internal: true + silent: true + vars: + OPERATION: '{{.OPERATION}}' + KUBECONFIG_FILE: '{{.KUBECONFIG_FILE}}' + cmds: + - | + if [ "{{.OPERATION}}" = "remove" ]; then + echo "Checking for pre-installed Traefik in k3s cluster..." + + # Check if traefik is installed in kube-system namespace + TRAEFIK_CHARTS=$(KUBECONFIG={{.KUBECONFIG_FILE}} helm list -n kube-system -o json | jq -r '.[] | select(.name | contains("traefik")) | .name') + + if [ -n "$TRAEFIK_CHARTS" ]; then + echo "Found pre-installed Traefik charts in kube-system namespace. Removing..." + + for chart in $TRAEFIK_CHARTS; do + echo "Uninstalling chart: $chart" + KUBECONFIG={{.KUBECONFIG_FILE}} helm uninstall $chart -n kube-system --wait + done + + echo "Pre-installed Traefik removed successfully!" + else + echo "No pre-installed Traefik charts found in kube-system namespace." + fi + fi + + port-operations: + desc: Expose and check status of ports + internal: true + silent: true + vars: + OPERATION: '{{.OPERATION | default "expose"}}' + CLUSTER_NAME: '{{.CLUSTER_NAME}}' + cmds: + - | + set -e + CLUSTER_ID=$(replicated cluster ls --output json | jq -r '.[] | select(.name == "{{.CLUSTER_NAME}}") | .id') + if [ -z "$CLUSTER_ID" ]; then + echo "Error: Could not find cluster with name {{.CLUSTER_NAME}}" + exit 1 + fi + + if [ "{{.OPERATION}}" = "expose" ]; then + echo "Exposing ports for cluster {{.CLUSTER_NAME}} (ID: $CLUSTER_ID)..." + + {{range .EXPOSE_PORTS}} + echo "Exposing port {{.port}} for {{.protocol}}..." + replicated cluster port expose $CLUSTER_ID --port {{.port}} --protocol {{.protocol}} + {{end}} + elif [ "{{.OPERATION}}" = "getenv" ]; then + # Get TF_EXPOSED_URL for HTTPS + TF_EXPOSED_URL=$(replicated cluster port ls $CLUSTER_ID --output json | jq -r '.[] | select(.upstream_port == 443 and .exposed_ports[0].protocol == "https") | .hostname' | head -n 1) + + # Get TF_EXPOSED_HTTP_URL for HTTP + TF_EXPOSED_HTTP_URL=$(replicated cluster port ls $CLUSTER_ID --output json | jq -r '.[] | select(.upstream_port == 80 and .exposed_ports[0].protocol == "http") | .hostname' | head -n 1) + + if [ -z "$TF_EXPOSED_URL" ]; then + echo "Error: Could not determine TF_EXPOSED_URL. HTTPS port is not properly exposed." + echo "Please ensure the HTTPS port is exposed before deploying." + exit 1 + fi + + if [ -z "$TF_EXPOSED_HTTP_URL" ]; then + echo "Error: Could not determine TF_EXPOSED_HTTP_URL. HTTP port is not properly exposed." + echo "Please ensure the HTTP port is exposed before deploying." + exit 1 + fi + + echo "TF_EXPOSED_URL=$TF_EXPOSED_URL TF_EXPOSED_HTTP_URL=$TF_EXPOSED_HTTP_URL" + fi + + gcp-operations: + desc: GCP VM operations + internal: true + silent: true + vars: + OPERATION: '{{.OPERATION}}' + GCP_PROJECT: '{{.GCP_PROJECT}}' + GCP_ZONE: '{{.GCP_ZONE}}' + VM_NAME: '{{.VM_NAME}}' + cmds: + - | + if [ -z "{{.GCP_PROJECT}}" ]; then + echo "Error: GCP_PROJECT is required. Please specify with GCP_PROJECT=your-project-id" + exit 1 + fi + + if [ "{{.OPERATION}}" = "create" ]; then + echo "Creating GCP VM instance {{.VM_NAME}}..." + + # Create the VM + gcloud compute instances create {{.VM_NAME}} \ + --project={{.GCP_PROJECT}} \ + --zone={{.GCP_ZONE}} \ + --machine-type={{.GCP_MACHINE_TYPE}} \ + --image-family={{.GCP_IMAGE_FAMILY}} \ + --image-project={{.GCP_IMAGE_PROJECT}} \ + --boot-disk-size={{.GCP_DISK_SIZE}}GB \ + --boot-disk-type={{.GCP_DISK_TYPE}} \ + --labels=expires-on=never,owner={{or (env "GUSER") "user"}} + + # Get the external IP + EXTERNAL_IP=$(gcloud compute instances describe {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} --format='get(networkInterfaces[0].accessConfigs[0].natIP)') + + echo "VM {{.VM_NAME}} created successfully with IP: $EXTERNAL_IP" + echo "You can SSH into the VM with: gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}}" + + elif [ "{{.OPERATION}}" = "delete" ]; then + echo "Deleting GCP VM instance {{.VM_NAME}}..." + + # Delete the VM + gcloud compute instances delete {{.VM_NAME}} \ + --project={{.GCP_PROJECT}} \ + --zone={{.GCP_ZONE}} \ + --quiet + + echo "VM {{.VM_NAME}} deleted successfully" + + elif [ "{{.OPERATION}}" = "setup-embedded" ]; then + echo "Setting up embedded cluster on GCP VM {{.VM_NAME}}..." + + # Run installation commands on the VM + echo "Installing embedded cluster on VM..." + gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} --command=" + set -e + echo 'Downloading home-cluster installer...' + curl -f 'https://replicated.app/embedded/home-cluster/{{.CHANNEL}}' -H 'Authorization: {{.AUTH_TOKEN}}' -o home-cluster-{{.CHANNEL}}.tgz + + echo 'Extracting installer...' + tar -xvzf home-cluster-{{.CHANNEL}}.tgz + " + + echo "Embedded cluster setup initiated on VM {{.VM_NAME}}" + echo "You can SSH into the VM with: gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}}" + fi \ No newline at end of file diff --git a/applications/wg-easy/traefik/Chart.yaml b/applications/wg-easy/traefik/Chart.yaml new file mode 100644 index 0000000..c73b0b6 --- /dev/null +++ b/applications/wg-easy/traefik/Chart.yaml @@ -0,0 +1,11 @@ +name: traefik +version: 1.0.0 +appVersion: latest +apiVersion: v2 +dependencies: + - name: traefik + version: '28.0.0' + repository: https://traefik.github.io/charts + - name: templates + version: '*' + repository: file://../charts/templates diff --git a/applications/wg-easy/traefik/replicated/helmChart-traefik.yaml b/applications/wg-easy/traefik/replicated/helmChart-traefik.yaml new file mode 100644 index 0000000..428fcbe --- /dev/null +++ b/applications/wg-easy/traefik/replicated/helmChart-traefik.yaml @@ -0,0 +1,13 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: traefik +spec: + chart: + name: traefik + chartVersion: '1.0.0' + weight: 2 + helmUpgradeFlags: + - --wait + namespace: traefik + builder: {} diff --git a/applications/wg-easy/traefik/templates/certificate.yaml b/applications/wg-easy/traefik/templates/certificate.yaml new file mode 100644 index 0000000..b4798e7 --- /dev/null +++ b/applications/wg-easy/traefik/templates/certificate.yaml @@ -0,0 +1,64 @@ +{{ if .Values.certs.selfSigned }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: traefik-self-signed +spec: + commonName: traefik + secretName: traefik-self-signed + issuerRef: + name: selfsigned-cluster-issuer + kind: ClusterIssuer + group: cert-manager.io +{{- end }} +{{- if .Values.certs.installProduction }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: traefik-cert +spec: + secretName: traefik-cert + duration: 2160h0m0s + renewBefore: 720h0m0s + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - server auth + - client auth + dnsNames: + {{- range .Values.certs.dnsNames }} + - {{ . | quote }} + {{- end }} + issuerRef: + name: letsencrypt-production + kind: ClusterIssuer +{{- end }} +{{- if .Values.certs.installStaging }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: traefik-cert-staging +spec: + secretName: traefik-cert-staging + duration: 2160h0m0s + renewBefore: 720h0m0s + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - server auth + - client auth + dnsNames: + {{- range .Values.certs.dnsNames }} + - {{ . | quote }} + {{- end }} + issuerRef: + name: letsencrypt-staging + kind: ClusterIssuer +{{- end }} diff --git a/applications/wg-easy/traefik/templates/tls-options.yaml b/applications/wg-easy/traefik/templates/tls-options.yaml new file mode 100644 index 0000000..a34cff6 --- /dev/null +++ b/applications/wg-easy/traefik/templates/tls-options.yaml @@ -0,0 +1,8 @@ +apiVersion: traefik.io/v1alpha1 +kind: TLSOption +metadata: + name: default + namespace: traefik +spec: + minVersion: VersionTLS12 + #maxVersion: VersionTLS13 diff --git a/applications/wg-easy/traefik/values.yaml b/applications/wg-easy/traefik/values.yaml new file mode 100644 index 0000000..e2567d7 --- /dev/null +++ b/applications/wg-easy/traefik/values.yaml @@ -0,0 +1,21 @@ +certs: + selfSigned: true + installProduction: false + installStaging: false + dnsNames: [] +traefik: + service: + type: NodePort + ports: + web: + nodePort: 80 + redirectTo: + port: websecure + websecure: + nodePort: 443 + tlsStore: + default: + certificates: + - secretName: traefik-self-signed + defaultCertificate: + secretName: traefik-self-signed diff --git a/applications/wg-easy/wg-easy/Chart.yaml b/applications/wg-easy/wg-easy/Chart.yaml new file mode 100644 index 0000000..1688310 --- /dev/null +++ b/applications/wg-easy/wg-easy/Chart.yaml @@ -0,0 +1,13 @@ +name: wg-easy +version: 1.0.0 +apiVersion: v2 +dependencies: + - name: wg-easy + version: '1.0.0' + repository: https://chris-sanders.github.io/helm-charts + - name: templates + version: '*' + repository: file://../charts/templates + #- name: replicated + # repository: oci://registry.replicated.com/library + # version: 1.1.1 diff --git a/applications/wg-easy/wg-easy/replicated/config.yaml b/applications/wg-easy/wg-easy/replicated/config.yaml new file mode 100644 index 0000000..2290ec1 --- /dev/null +++ b/applications/wg-easy/wg-easy/replicated/config.yaml @@ -0,0 +1,37 @@ +apiVersion: kots.io/v1beta1 +kind: Config +metadata: + name: not-used +spec: + groups: + - name: wireguard-config + title: Wireguard + description: Wireguard configuration + items: + #- name: accept + # title: Systemd has been updated + # help_text: | + # Add `--profile=ip-forward` to k0scontroller.service + # Run `systemd daemon-reload` + # Restart `k0scontroller.service` + # type: bool + # required: true + - name: password + title: Admin password + type: password + required: true + - name: domain + title: IP or domain + help_text: Domain or IP which the vpn is accessible on + type: text + required: true + #- name: web-port + # title: Web port + # help_text: This is the port the admin UI will be served on + # type: text + # default: "51821" + - name: vpn-port + title: vpn port + help_text: This port must be accessible remotely + type: text + default: "20000" diff --git a/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml b/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml new file mode 100644 index 0000000..4dc2141 --- /dev/null +++ b/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml @@ -0,0 +1,38 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: wg-easy +spec: + chart: + name: wg-easy + chartVersion: '1.0.0' + #chartVersion: '*' + weight: 3 + + # helmUpgradeFlags specifies additional flags to pass to the `helm upgrade` command. + helmUpgradeFlags: + - --skip-crds + - --timeout + - 30s + - --history-max=15 + - --wait + + values: + wg-easy: + services: + vpn: + # TODO: Template for stand alone KOTS install? + #type: NodePort + ports: + udp: + nodePort: repl{{ ConfigOption `vpn-port` | ParseInt }} + wireguard: + password: repl{{ ConfigOption `password` }} + host: repl{{ ConfigOption `domain` }} + port: repl{{ ConfigOption `vpn-port` | ParseInt }} + templates: + traefikRoutes: + web-tls: + hostName: repl{{ ConfigOption `domain` }} + namespace: wg-easy + builder: {} diff --git a/applications/wg-easy/wg-easy/values.yaml b/applications/wg-easy/wg-easy/values.yaml new file mode 100644 index 0000000..888672e --- /dev/null +++ b/applications/wg-easy/wg-easy/values.yaml @@ -0,0 +1,40 @@ +wg-easy: + global: + fullNameOverride: public + apps: + wg-easy: + fullNameOverride: public + containers: + wg-container: + resources: + requests: + cpu: 5m + memory: 35Mi + persistence: + config: + persistentVolumeClaim: + spec: + resources: + requests: + storage: 1Gi + services: + vpn: + type: NodePort + wireguard: + password: "testpass" + host: "example.com" + port: 51820 # This is used in the postUp + defaultAddress: "10.10.10.x" + defaultDns: "1.1.1.1" + allowedIps: "0.0.0.0/5, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3, 64.0.0.0/2, 128.0.0.0/3, 160.0.0.0/5, 168.0.0.0/6, 172.0.0.0/12, 172.32.0.0/11, 172.64.0.0/10, 172.128.0.0/9, 173.0.0.0/8, 174.0.0.0/7, 176.0.0.0/4, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, 224.0.0.0/3" + postUp: "iptables -A FORWARD -i wg0 -o eth0 -d 192.168.0.0/16,172.16.0.0/12,10.0.0.0/8 -j DROP; iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o eth0 -j MASQUERADE; iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT" +templates: + traefikRoutes: + web-tls: + hostName: "example.com" + serviceName: public-web + servicePort: 51821 + #web: + # hostName: "example.com" + # serviceName: public-web + # servicePort: 51821 From af84286142234b42893e87da9adb58bf294b1fa7 Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Tue, 18 Mar 2025 17:44:25 -0500 Subject: [PATCH 02/32] Update port configuration and expose utility tasks - Change web/HTTPS ports from 80/443 to 30080/30443 - Configure explicit nodePort values for Traefik - Make utility tasks public by removing internal flags - Fix helmfile command execution with eval - Enable web route configuration in wg-easy values --- applications/wg-easy/Taskfile.yaml | 6 +++--- applications/wg-easy/helmfile.yaml | 7 +++++++ applications/wg-easy/taskfiles/utils.yml | 6 ++---- applications/wg-easy/wg-easy/values.yaml | 8 ++++---- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 412b640..d4af6cd 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -14,9 +14,9 @@ vars: # Ports configuration EXPOSE_PORTS: - - port: 443 + - port: 30443 protocol: https - - port: 80 + - port: 30080 protocol: http # GCP default configuration @@ -135,7 +135,7 @@ tasks: # Deploy with helmfile echo "Using $ENV_VARS" - KUBECONFIG={{.KUBECONFIG_FILE}} $ENV_VARS helmfile sync --wait + eval "KUBECONFIG={{.KUBECONFIG_FILE}} $ENV_VARS helmfile sync --wait" - echo "All charts deployed!" deps: - get-kubeconfig diff --git a/applications/wg-easy/helmfile.yaml b/applications/wg-easy/helmfile.yaml index 14595b0..7f391ec 100644 --- a/applications/wg-easy/helmfile.yaml +++ b/applications/wg-easy/helmfile.yaml @@ -36,6 +36,13 @@ releases: skipDeps: true needs: - cert-manager/cert-manager-issuers + values: + - traefik: + ports: + web: + nodePort: 30080 + websecure: + nodePort: 30443 - name: wg-easy namespace: wg-easy diff --git a/applications/wg-easy/taskfiles/utils.yml b/applications/wg-easy/taskfiles/utils.yml index 8b746cf..688c14c 100644 --- a/applications/wg-easy/taskfiles/utils.yml +++ b/applications/wg-easy/taskfiles/utils.yml @@ -35,7 +35,6 @@ tasks: traefik-operations: desc: Operations for managing Traefik - internal: true silent: true vars: OPERATION: '{{.OPERATION}}' @@ -64,7 +63,6 @@ tasks: port-operations: desc: Expose and check status of ports - internal: true silent: true vars: OPERATION: '{{.OPERATION | default "expose"}}' @@ -87,10 +85,10 @@ tasks: {{end}} elif [ "{{.OPERATION}}" = "getenv" ]; then # Get TF_EXPOSED_URL for HTTPS - TF_EXPOSED_URL=$(replicated cluster port ls $CLUSTER_ID --output json | jq -r '.[] | select(.upstream_port == 443 and .exposed_ports[0].protocol == "https") | .hostname' | head -n 1) + TF_EXPOSED_URL=$(replicated cluster port ls $CLUSTER_ID --output json | jq -r '.[] | select(.upstream_port == 30443 and .exposed_ports[0].protocol == "https") | .hostname' | head -n 1) # Get TF_EXPOSED_HTTP_URL for HTTP - TF_EXPOSED_HTTP_URL=$(replicated cluster port ls $CLUSTER_ID --output json | jq -r '.[] | select(.upstream_port == 80 and .exposed_ports[0].protocol == "http") | .hostname' | head -n 1) + TF_EXPOSED_HTTP_URL=$(replicated cluster port ls $CLUSTER_ID --output json | jq -r '.[] | select(.upstream_port == 30080 and .exposed_ports[0].protocol == "http") | .hostname' | head -n 1) if [ -z "$TF_EXPOSED_URL" ]; then echo "Error: Could not determine TF_EXPOSED_URL. HTTPS port is not properly exposed." diff --git a/applications/wg-easy/wg-easy/values.yaml b/applications/wg-easy/wg-easy/values.yaml index 888672e..e033dfa 100644 --- a/applications/wg-easy/wg-easy/values.yaml +++ b/applications/wg-easy/wg-easy/values.yaml @@ -34,7 +34,7 @@ templates: hostName: "example.com" serviceName: public-web servicePort: 51821 - #web: - # hostName: "example.com" - # serviceName: public-web - # servicePort: 51821 + web: + hostName: "example.com" + serviceName: public-web + servicePort: 51821 From bcecd93503c808d1389c2f04b4591a055819073b Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Wed, 19 Mar 2025 15:52:59 -0500 Subject: [PATCH 03/32] Parameterize application name with default value of wg-easy --- applications/wg-easy/Taskfile.yaml | 18 ++++++++++-------- applications/wg-easy/taskfiles/utils.yml | 6 +++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index d4af6cd..ecab11a 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -4,6 +4,9 @@ includes: utils: ./taskfiles/utils.yml vars: + # Application configuration + APP_NAME: '{{.APP_NAME | default "wg-easy"}}' + # Cluster configuration CLUSTER_NAME: '{{.CLUSTER_NAME | default "test-cluster"}}' K8S_VERSION: '{{.K8S_VERSION | default "1.32.2"}}' @@ -226,18 +229,17 @@ tasks: - echo "Release files prepared in ./release/ directory" release-create: - desc: Create and promote a release for home-cluster using the Replicated CLI + desc: Create and promote a release using the Replicated CLI silent: true - requiredVars: - - CHANNEL vars: + CHANNEL: '{{.CHANNEL | default "Unstable"}}' RELEASE_NOTES: '{{.RELEASE_NOTES | default "Release created via task release-create"}}' cmds: - - echo "Creating and promoting release for home-cluster to channel {{.CHANNEL}}..." + - echo "Creating and promoting release for {{.APP_NAME}} to channel {{.CHANNEL}}..." - | # Create and promote the release in one step echo "Creating release from files in ./release directory..." - replicated release create --app home-cluster --yaml-dir ./release --release-notes "{{.RELEASE_NOTES}}" --promote {{.CHANNEL}} + replicated release create --app {{.APP_NAME}} --yaml-dir ./release --release-notes "{{.RELEASE_NOTES}}" --promote {{.CHANNEL}} echo "Release created and promoted to channel {{.CHANNEL}}" deps: @@ -273,14 +275,14 @@ tasks: desc: Setup Replicated embedded cluster on the GCP VM silent: true vars: - CHANNEL: '{{.CHANNEL | default "unstable"}}' + CHANNEL: '{{.CHANNEL | default "Unstable"}}' AUTH_TOKEN: '{{.AUTH_TOKEN | default "2uJbnRgxrmrhqBDF1Sd7wcYFDPh"}}' deps: - create-gcp-vm status: - | - # Check if the home-cluster tarball has already been downloaded and extracted - gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} --command="test -d ./home-cluster" &>/dev/null + # Check if the application tarball has already been downloaded and extracted + gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} --command="test -d ./{{.APP_NAME}}" &>/dev/null cmds: - task: utils:gcp-operations vars: diff --git a/applications/wg-easy/taskfiles/utils.yml b/applications/wg-easy/taskfiles/utils.yml index 688c14c..af743cc 100644 --- a/applications/wg-easy/taskfiles/utils.yml +++ b/applications/wg-easy/taskfiles/utils.yml @@ -159,11 +159,11 @@ tasks: echo "Installing embedded cluster on VM..." gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} --command=" set -e - echo 'Downloading home-cluster installer...' - curl -f 'https://replicated.app/embedded/home-cluster/{{.CHANNEL}}' -H 'Authorization: {{.AUTH_TOKEN}}' -o home-cluster-{{.CHANNEL}}.tgz + echo 'Downloading {{.APP_NAME}} installer...' + curl -f 'https://replicated.app/embedded/{{.APP_NAME}}/{{.CHANNEL}}' -H 'Authorization: {{.AUTH_TOKEN}}' -o {{.APP_NAME}}-{{.CHANNEL}}.tgz echo 'Extracting installer...' - tar -xvzf home-cluster-{{.CHANNEL}}.tgz + tar -xvzf {{.APP_NAME}}-{{.CHANNEL}}.tgz " echo "Embedded cluster setup initiated on VM {{.VM_NAME}}" From fa167e38e16e87782f53d12e8b5128dfe6698b6c Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Wed, 19 Mar 2025 15:58:52 -0500 Subject: [PATCH 04/32] Update kubeconfig file naming convention --- applications/wg-easy/Taskfile.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index ecab11a..741a7a9 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -13,7 +13,7 @@ vars: DISK_SIZE: '{{.DISK_SIZE | default "100"}}' INSTANCE_TYPE: '{{.INSTANCE_TYPE | default "r1.small"}}' DISTRIBUTION: '{{.DISTRIBUTION | default "k3s"}}' - KUBECONFIG_FILE: './kubeconfig-{{.CLUSTER_NAME}}' + KUBECONFIG_FILE: './{{.CLUSTER_NAME}}.kubeconfig' # Ports configuration EXPOSE_PORTS: From 6370519376f9eb9133b48ad6f1001ba3e86a8580 Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Wed, 19 Mar 2025 16:10:39 -0500 Subject: [PATCH 05/32] Try splitting sdk into it's own chart and deploying --- .gitignore | 1 + applications/wg-easy/helmfile.yaml | 13 +++++++++++- .../wg-easy/replicated-sdk/Chart.yaml | 10 +++++++++ .../replicated/helmChart-replicated-sdk.yaml | 21 +++++++++++++++++++ .../wg-easy/replicated-sdk/values.yaml | 1 + applications/wg-easy/wg-easy/Chart.yaml | 3 --- 6 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 applications/wg-easy/replicated-sdk/Chart.yaml create mode 100644 applications/wg-easy/replicated-sdk/replicated/helmChart-replicated-sdk.yaml create mode 100644 applications/wg-easy/replicated-sdk/values.yaml diff --git a/.gitignore b/.gitignore index 5450c6c..1e928c8 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ Thumbs.db __pycache__/ # wg-easy specific +*.kubeconfig applications/wg-easy/release/ applications/wg-easy/*/charts/ applications/wg-easy/*/Chart.lock diff --git a/applications/wg-easy/helmfile.yaml b/applications/wg-easy/helmfile.yaml index 7f391ec..7e439a4 100644 --- a/applications/wg-easy/helmfile.yaml +++ b/applications/wg-easy/helmfile.yaml @@ -43,6 +43,17 @@ releases: nodePort: 30080 websecure: nodePort: 30443 + + # Install replicated-sdk + - name: replicated-sdk + namespace: replicated-sdk + chart: ./replicated-sdk + createNamespace: true + wait: true + installed: true + skipDeps: true + needs: + - traefik/traefik - name: wg-easy namespace: wg-easy @@ -52,7 +63,7 @@ releases: installed: true skipDeps: true needs: - - traefik/traefik + - replicated-sdk/replicated-sdk values: - wg-easy: wireguard: diff --git a/applications/wg-easy/replicated-sdk/Chart.yaml b/applications/wg-easy/replicated-sdk/Chart.yaml new file mode 100644 index 0000000..f933f47 --- /dev/null +++ b/applications/wg-easy/replicated-sdk/Chart.yaml @@ -0,0 +1,10 @@ +name: replicated-sdk +version: 1.0.0 +apiVersion: v2 +dependencies: + - name: templates + version: '*' + repository: file://../charts/templates + - name: replicated + repository: oci://registry.replicated.com/library + version: 1.1.1 \ No newline at end of file diff --git a/applications/wg-easy/replicated-sdk/replicated/helmChart-replicated-sdk.yaml b/applications/wg-easy/replicated-sdk/replicated/helmChart-replicated-sdk.yaml new file mode 100644 index 0000000..ebd668c --- /dev/null +++ b/applications/wg-easy/replicated-sdk/replicated/helmChart-replicated-sdk.yaml @@ -0,0 +1,21 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: replicated-sdk +spec: + chart: + name: replicated-sdk + chartVersion: '1.0.0' + weight: 1 + + # helmUpgradeFlags specifies additional flags to pass to the `helm upgrade` command. + helmUpgradeFlags: + - --skip-crds + - --timeout + - 30s + - --history-max=15 + - --wait + + values: {} + namespace: replicated-sdk + builder: {} \ No newline at end of file diff --git a/applications/wg-easy/replicated-sdk/values.yaml b/applications/wg-easy/replicated-sdk/values.yaml new file mode 100644 index 0000000..32fbdcb --- /dev/null +++ b/applications/wg-easy/replicated-sdk/values.yaml @@ -0,0 +1 @@ +# Values for replicated-sdk chart \ No newline at end of file diff --git a/applications/wg-easy/wg-easy/Chart.yaml b/applications/wg-easy/wg-easy/Chart.yaml index 1688310..5a78dd3 100644 --- a/applications/wg-easy/wg-easy/Chart.yaml +++ b/applications/wg-easy/wg-easy/Chart.yaml @@ -8,6 +8,3 @@ dependencies: - name: templates version: '*' repository: file://../charts/templates - #- name: replicated - # repository: oci://registry.replicated.com/library - # version: 1.1.1 From dea4cafe398bbec9775d16a1510f27cca882541e Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Wed, 19 Mar 2025 16:36:43 -0500 Subject: [PATCH 06/32] Roll back sdk in helmfile will need a seperate path through replicated release for that --- applications/wg-easy/helmfile.yaml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/applications/wg-easy/helmfile.yaml b/applications/wg-easy/helmfile.yaml index 7e439a4..0243768 100644 --- a/applications/wg-easy/helmfile.yaml +++ b/applications/wg-easy/helmfile.yaml @@ -44,16 +44,17 @@ releases: websecure: nodePort: 30443 + # TODO: Can't use this until using an actual release? # Install replicated-sdk - - name: replicated-sdk - namespace: replicated-sdk - chart: ./replicated-sdk - createNamespace: true - wait: true - installed: true - skipDeps: true - needs: - - traefik/traefik + #- name: replicated-sdk + # namespace: replicated-sdk + # chart: ./replicated-sdk + # createNamespace: true + # wait: true + # installed: true + # skipDeps: true + # needs: + # - traefik/traefik - name: wg-easy namespace: wg-easy @@ -63,7 +64,7 @@ releases: installed: true skipDeps: true needs: - - replicated-sdk/replicated-sdk + - traefik/traefik values: - wg-easy: wireguard: From d4a148c1d1023528c81511f0f138f23bd40d4f07 Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Wed, 19 Mar 2025 17:08:00 -0500 Subject: [PATCH 07/32] Using environments to enable local vs SaaS release testing, but I don't like it --- applications/wg-easy/helmfile.yaml | 53 +++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/applications/wg-easy/helmfile.yaml b/applications/wg-easy/helmfile.yaml index 0243768..4adc18e 100644 --- a/applications/wg-easy/helmfile.yaml +++ b/applications/wg-easy/helmfile.yaml @@ -6,11 +6,35 @@ helmDefaults: atomic: true cleanupOnFail: true +environments: + default: + values: + - chartSources: + certManager: ./cert-manager + certManagerIssuers: ./cert-manager-issuers + traefik: ./traefik + wgEasy: ./wg-easy + replicatedSDK: ./replicated-sdk + - extras: + enableReplicatedSDK: false + replicated: + values: + - app: '{{ env "APP" | default "wg-easy" }}' + - channel: '{{ env "CHANNEL" | default "Unstable" }}' + - chartSources: + certManager: 'oci://registry.replicated.com/{{ env "APP" | default "wg-easy" }}/{{ env "CHANNEL" | default "Unstable" }}/cert-manager' + certManagerIssuers: 'oci://registry.replicated.com/{{ env "APP" | default "wg-easy" }}/{{ env "CHANNEL" | default "Unstable" }}/cert-manager-issuers' + traefik: 'oci://registry.replicated.com/{{ env "APP" | default "wg-easy" }}/{{ env "CHANNEL" | default "Unstable" }}/traefik' + wgEasy: 'oci://registry.replicated.com/{{ env "APP" | default "wg-easy" }}/{{ env "CHANNEL" | default "Unstable" }}/wg-easy' + replicatedSDK: 'oci://registry.replicated.com/{{ env "APP" | default "wg-easy" }}/{{ env "CHANNEL" | default "Unstable" }}/replicated-sdk' + - extras: + enableReplicatedSDK: true +--- releases: # Install cert-manager with CRDs but without issuers - name: cert-manager namespace: cert-manager - chart: ./cert-manager + chart: {{ .Values.chartSources.certManager }} createNamespace: true wait: true installed: true @@ -19,7 +43,7 @@ releases: # Install issuers separately after cert-manager is ready - name: cert-manager-issuers namespace: cert-manager - chart: ./cert-manager-issuers + chart: {{ .Values.chartSources.certManagerIssuers }} createNamespace: true wait: true installed: true @@ -29,7 +53,7 @@ releases: - name: traefik namespace: traefik - chart: ./traefik + chart: {{ .Values.chartSources.traefik }} createNamespace: true wait: true installed: true @@ -44,21 +68,20 @@ releases: websecure: nodePort: 30443 - # TODO: Can't use this until using an actual release? - # Install replicated-sdk - #- name: replicated-sdk - # namespace: replicated-sdk - # chart: ./replicated-sdk - # createNamespace: true - # wait: true - # installed: true - # skipDeps: true - # needs: - # - traefik/traefik + # Install replicated-sdk (only in replicated environment) + - name: replicated-sdk + namespace: replicated-sdk + chart: {{ .Values.chartSources.replicatedSDK }} + createNamespace: true + wait: true + installed: {{ .Values.extras.enableReplicatedSDK }} + skipDeps: true + needs: + - traefik/traefik - name: wg-easy namespace: wg-easy - chart: ./wg-easy + chart: {{ .Values.chartSources.wgEasy }} createNamespace: true wait: true installed: true From 10147013ce1a7ef30b76cf08016600a86f4e86a6 Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Fri, 21 Mar 2025 10:21:54 -0500 Subject: [PATCH 08/32] First pass at docs --- applications/wg-easy/README.md | 91 +++++++ applications/wg-easy/doc-todo-list.md | 134 ++++++++++ applications/wg-easy/docs/chart-structure.md | 132 ++++++++++ .../wg-easy/docs/development-workflow.md | 246 ++++++++++++++++++ applications/wg-easy/docs/examples.md | 228 ++++++++++++++++ .../wg-easy/docs/replicated-integration.md | 141 ++++++++++ applications/wg-easy/docs/task-reference.md | 125 +++++++++ 7 files changed, 1097 insertions(+) create mode 100644 applications/wg-easy/README.md create mode 100644 applications/wg-easy/doc-todo-list.md create mode 100644 applications/wg-easy/docs/chart-structure.md create mode 100644 applications/wg-easy/docs/development-workflow.md create mode 100644 applications/wg-easy/docs/examples.md create mode 100644 applications/wg-easy/docs/replicated-integration.md create mode 100644 applications/wg-easy/docs/task-reference.md diff --git a/applications/wg-easy/README.md b/applications/wg-easy/README.md new file mode 100644 index 0000000..b6ef8dd --- /dev/null +++ b/applications/wg-easy/README.md @@ -0,0 +1,91 @@ +# WG-Easy Helm Chart Development Pattern + +This repository demonstrates a structured approach to developing and deploying Helm charts with Replicated integration. It focuses on a progressive development workflow that builds complexity incrementally, allowing developers to get fast feedback at each stage. + +## Core Principles + +The WG-Easy Helm Chart pattern is built on five fundamental principles: + +### 1. Progressive Complexity + +Start simple with individual chart validation and progressively move to more complex environments. This allows issues to be caught early when they are easier to fix. + +- Begin with local chart validation +- Move to single chart deployments +- Progress to multi-chart integration +- Finally test in production-like environments + +### 2. Fast Feedback Loops + +Get immediate feedback at each development stage by automating testing and validation. This shortens the overall development cycle. + +- Automated chart validation +- Quick cluster creation and deployment +- Standardized testing at each stage +- Fast iteration between changes + +### 3. Reproducible Steps + +Ensure consistent environments and processes across all stages of development, eliminating "works on my machine" issues. + +- Consistent chart configurations +- Automated environment setup +- Deterministic dependency management +- Standardized deployment procedures + +### 4. Modular Configuration + +Allow different components to own their configuration independently, which can be merged at release time. + +- Per-chart configuration files +- Automatic configuration merging +- Clear ownership boundaries +- Simplified collaborative development + +### 5. Automation First + +Use tools to automate repetitive tasks, reducing human error and increasing development velocity. + +- Task-based workflow automation +- Helmfile for orchestration +- Automated validation and testing +- Streamlined release process + +## Repository Structure + +``` +applications/wg-easy/ +├── charts/templates/ # Common templates shared across charts +├── cert-manager/ # Wrapped cert-manager chart +├── cert-manager-issuers/ # Chart for cert-manager issuers +├── replicated/ # Root Replicated configuration +├── replicated-sdk/ # Replicated SDK chart +├── taskfiles/ # Task utility functions +├── traefik/ # Wrapped Traefik chart +├── wg-easy/ # Main application chart +├── helmfile.yaml # Defines chart installation order +└── Taskfile.yaml # Main task definitions +``` + +## Architecture Overview + +![Architecture Diagram](docs/architecture.png) + +Key components: +- **Taskfile**: Orchestrates the workflow with automated tasks +- **Helmfile**: Manages chart dependencies and installation order +- **Wrapped Charts**: Encapsulate upstream charts for consistency +- **Shared Templates**: Provide reusable components across charts +- **Replicated Integration**: Enables enterprise distribution + +## Learn More + +- [Chart Structure Guide](docs/chart-structure.md) +- [Development Workflow](docs/development-workflow.md) +- [Task Reference](docs/task-reference.md) +- [Replicated Integration](docs/replicated-integration.md) +- [Example Patterns](docs/examples.md) + +--- + +This pattern is designed to be adaptable to different applications and requirements. Feel free to modify it to suit your specific needs. \ No newline at end of file diff --git a/applications/wg-easy/doc-todo-list.md b/applications/wg-easy/doc-todo-list.md new file mode 100644 index 0000000..b3201a4 --- /dev/null +++ b/applications/wg-easy/doc-todo-list.md @@ -0,0 +1,134 @@ +# WG-Easy Helm Chart Pattern Documentation Plan + +This document outlines specific work items for implementing the updated documentation strategy for the WG-Easy Helm Chart development pattern. + +## General Implementation Guidelines + +- [x] Use GitHub Markdown syntax for all documents +- [x] Test all documents in GitHub preview to ensure proper rendering +- [x] Use relative links for cross-document references +- [x] Maintain consistent terminology across all documents +- [x] Apply appropriate heading levels (h1 for document title, h2 for major sections) +- [x] Include code blocks with proper language specification +- [x] Use GitHub-specific features where appropriate (collapsible sections, task lists, tables) + +## Image Creation + +- [x] Create Architecture Diagram showing component relationships + - Include chart wrapping concept + - Show relationship between charts and templates + - Visualize dependency flow + +- [x] Create Workflow Diagram illustrating progressive complexity + - Show the 7 stages of development + - Highlight validation points + - Indicate approximate time requirements for each step + +- [x] Create Configuration Flow Diagram showing modular configuration + - Illustrate how per-chart configs are merged + - Show release preparation flow + - Include chart dependency relationships + +## README.md + +- [x] Rewrite introduction to focus on core principles and pattern benefits +- [x] Replace testing emphasis with progressive development workflow +- [x] Add placeholder for Architecture Diagram +- [x] Create concise overview of repository structure +- [x] Add clear explanation of each core principle with brief examples: + - Progressive Complexity + - Fast Feedback Loops + - Reproducible Steps + - Modular Configuration + - Automation First +- [x] Add links to supporting documentation +- [x] REMOVE: Detailed installation instructions +- [x] REMOVE: Extensive testing methodology +- [x] REMOVE: Exhaustive workflow details + +## docs/chart-structure.md + +- [x] Focus content on explaining the modular chart approach +- [x] Add detailed explanation of chart wrapping benefits +- [x] Improve directory structure explanation with visual aids +- [x] Add examples of how charts are composed +- [x] Explain shared templates concept with examples +- [x] Describe how modular configuration works +- [x] Include diagram placeholder +- [x] REMOVE: "Best Practices" section +- [x] REMOVE: Overly detailed examples not illustrating the pattern + +## docs/development-workflow.md (NEW - replacing getting-started.md) + +- [x] Create new document focused on workflow stages +- [x] Add clear introduction explaining progressive complexity approach +- [x] Detail each workflow stage with examples: + 1. Defining chart dependencies and verification + 2. Configuring with values.yaml and templates + 3. Local validation with helm template + 4. Single chart install/uninstall + 5. Integration testing with helmfile + 6. Release preparation + 7. Embedded cluster testing +- [x] Include specific command examples for each stage +- [x] Add explanation of how each stage supports fast feedback +- [x] Include workflow diagram placeholder +- [x] Explain when to move from one stage to the next +- [x] REMOVE FROM OLD DOC: Detailed installation instructions +- [x] REMOVE FROM OLD DOC: Peripheral topics not related to workflow + +## docs/task-reference.md (Replacing tasks.md) + +- [x] Reorganize tasks by purpose (development, release, testing) +- [x] Add brief description for each task focusing on what it accomplishes +- [x] Include examples of common task combinations +- [x] Explain how tasks support the automation-first principle +- [x] Group related tasks together +- [x] Add cross-references to development workflow stages +- [x] REMOVE: Verbose command details +- [x] REMOVE: Installation instructions +- [x] REMOVE: Extensive options documentation duplicating Taskfile.yaml + +## docs/replicated-integration.md + +- [x] Condense to focus on integration with overall pattern +- [x] Add brief overview of Replicated's role +- [x] Explain modular configuration with Replicated +- [x] Describe key integration points in the workflow +- [x] Add references to official Replicated documentation +- [x] Integrate with workflow stages where appropriate +- [x] REMOVE: "Best Practices" section +- [x] REMOVE: Detailed configuration examples +- [x] REMOVE: Content duplicating Replicated's documentation + +## Documents to Remove Entirely + +- [x] Remove docs/testing.md + - Extract any relevant concepts and merge into main documents if applicable + +## Examples to Include + +- [x] Progressive Complexity Example: + - Complete workflow from single chart to release + - Validation points at each stage + - Issue isolation demonstration + +- [x] Modular Configuration Example: + - Per-chart config.yaml maintenance + - Config merging during release preparation + - Team ownership benefits + +- [x] Chart Wrapping Example: + - Simple chart wrapping upstream chart + - Benefits explanation + - Environment consistency demonstration + +## Final Review Checklist + +- [x] Ensure documentation is beginner-friendly but valuable for experienced users +- [x] Verify all links work correctly +- [x] Check that all GitHub Markdown renders correctly +- [x] Confirm core principles are consistently emphasized +- [x] Validate that examples are clear and illustrative +- [x] Ensure removed content doesn't result in information gaps +- [x] Check for consistent terminology throughout diff --git a/applications/wg-easy/docs/chart-structure.md b/applications/wg-easy/docs/chart-structure.md new file mode 100644 index 0000000..d405289 --- /dev/null +++ b/applications/wg-easy/docs/chart-structure.md @@ -0,0 +1,132 @@ +# Chart Structure Guide + +This document explains the modular chart approach used in the WG-Easy Helm chart pattern. + +## Modular Chart Architecture + +![Chart Structure](architecture.png) + +The WG-Easy pattern is built around a modular approach to Helm charts, where upstream charts are wrapped in local charts and enhanced with shared templates and customizations. + +### Directory Structure + +``` +applications/wg-easy/ +├── charts/templates/ # Common templates shared across charts +│ ├── traefik-routes.yaml # Templates for Traefik IngressRoutes +│ └── traefik-route-tcp.yaml # Templates for Traefik TCP routes +├── cert-manager/ # Wrapped cert-manager chart +├── cert-manager-issuers/ # Chart for cert-manager issuers +├── replicated/ # Root Replicated configuration +├── replicated-sdk/ # Replicated SDK chart +├── traefik/ # Wrapped Traefik chart +├── wg-easy/ # Main application chart +├── helmfile.yaml # Defines chart installation order +└── Taskfile.yaml # Main task definitions +``` + +## Chart Wrapping Concept + +Chart wrapping is a core technique in this pattern where upstream Helm charts are encapsulated in local charts rather than used directly. This provides several key benefits: + +### Example: +```yaml +# cert-manager/Chart.yaml +apiVersion: v2 +name: cert-manager +version: 1.0.0 +dependencies: + - name: cert-manager + version: '1.14.5' + repository: https://charts.jetstack.io + - name: templates + version: '*' + repository: file://../charts/templates +``` + +### Customization Control + +Wrapper charts allow you to extend or modify the upstream chart's behavior: + +1. **Custom Templates**: Add your own Kubernetes resources alongside the upstream chart +2. **Value Overrides**: Set defaults appropriate for your environment +3. **Additional Resources**: Include related resources that complement the main chart + +### Version Management + +Wrapped charts give you precise control over dependency versions: + +1. **Version Pinning**: Lock dependencies to specific versions for stability +2. **Upgrade Management**: Test upgrades in isolation before promoting to production +3. **Compatibility Assurance**: Ensure all components work together + +## Shared Templates + +The pattern uses a shared templates chart (`charts/templates/`) that contains reusable components: + +```yaml +# From the wg-easy/values.yaml file showing templates usage +templates: + traefikRoutes: + web: + enabled: true + entryPoint: web + rule: "Host(`{{ .Values.wireguard.host }}`)" + service: wg-easy + port: 51821 +``` + +This approach provides: + +1. **Consistency**: Standard implementations across charts +2. **Maintainability**: Single source of truth for common patterns +3. **Simplicity**: Easy reuse of complex configurations + +## Chart Composition + +The charts are composed together using Helmfile, which manages dependencies and installation order: + +```yaml +# Example from helmfile.yaml +releases: + - name: cert-manager + namespace: cert-manager + chart: ./cert-manager + createNamespace: true + wait: true + + - name: cert-manager-issuers + namespace: cert-manager + chart: ./cert-manager-issuers + createNamespace: true + wait: true + needs: + - cert-manager/cert-manager +``` + +This ensures that charts are installed in the correct order with proper dependencies. + +## Modular Configuration + +Each chart can define its own configuration that is merged during release preparation: + +``` +traefik/ +├── values.yaml # Default chart values +└── replicated/ + └── config.yaml # Traefik-specific configuration + └── helmChart-traefik.yaml # Installation instructions + +wg-easy/ +├── values.yaml # Default chart values +└── replicated/ + └── config.yaml # WG-Easy-specific configuration + └── helmChart-wg-easy.yaml # Installation instructions +``` + +Benefits of this approach: + +1. **Team Ownership**: Different teams can own their component configurations +2. **Clear Boundaries**: Separation of concerns between components +3. **Simplified Maintenance**: Changes to one component don't affect others +4. **Automatic Merging**: During release, all configs are combined into a single file diff --git a/applications/wg-easy/docs/development-workflow.md b/applications/wg-easy/docs/development-workflow.md new file mode 100644 index 0000000..5b213eb --- /dev/null +++ b/applications/wg-easy/docs/development-workflow.md @@ -0,0 +1,246 @@ +# Development Workflow + +This document outlines the progressive development workflow for the WG-Easy Helm chart pattern, guiding you through each stage from initial chart configuration to complete application deployment. + +## Progressive Complexity Approach + +The core philosophy of this workflow is to start simple and add complexity incrementally, providing fast feedback at each stage. This allows developers to: + +- Identify and fix issues early when they're easier to debug +- Get rapid feedback on changes without waiting for full deployments +- Build confidence in changes through progressive validation +- Maintain high velocity while ensuring quality + +![Workflow Diagram](workflow-diagram.png) + +## Workflow Stages + +### Stage 1: Chart Dependencies and Verification + +Begin by defining and verifying chart dependencies. + +1. Define or update dependencies in `Chart.yaml`: + + ```yaml + # Example: cert-manager/Chart.yaml + dependencies: + - name: cert-manager + version: '1.14.5' + repository: https://charts.jetstack.io + - name: templates + version: '*' + repository: file://../charts/templates + ``` + +2. Update dependencies: + + ```bash + task update-dependencies + # Or for a single chart: + helm dependency update ./cert-manager + ``` + +3. Verify charts were downloaded: + + ```bash + ls -la ./cert-manager/charts/ + ``` + +**Validation point**: Dependencies should be successfully downloaded to the `/charts` directory. + +### Stage 2: Configuration with values.yaml and Templates + +Configure chart values and create or modify templates. + +1. Update the chart's `values.yaml` with appropriate defaults: + + ```yaml + # Example: traefik/values.yaml + certs: + selfSigned: true + traefik: + service: + type: NodePort + ports: + web: + nodePort: 80 + ``` + +2. Create or customize templates: + + ```yaml + # Example: Adding a template for TLS configuration + apiVersion: traefik.containo.us/v1alpha1 + kind: TLSOption + metadata: + name: default + namespace: traefik + spec: + minVersion: VersionTLS12 + ``` + +**Validation point**: Configuration values are properly defined and templates are syntactically correct. + +### Stage 3: Local Validation with helm template + +Validate chart templates locally without deploying to a cluster. + +1. Run helm template to render the chart and inspect manifests: + ```bash + helm template ./cert-manager | less + ``` + +**Validation point**: Generated Kubernetes manifests should be valid and contain the expected resources. + +### Stage 4: Single Chart Install/Uninstall + +Deploy individual charts to a test cluster to verify functionality. + +1. Create a test cluster if needed: + + ```bash + task create-cluster + task get-kubeconfig + ``` + +2. Install a single chart: + + ```bash + helm install cert-manager ./cert-manager -n cert-manager --create-namespace + ``` + +3. Verify the deployment: + + ```bash + kubectl get pods -n cert-manager + ``` + +4. Test chart functionality: + + ```bash + # Example: Test cert-manager with a test certificate + kubectl apply -f ./some-test-certificate.yaml + kubectl get certificate -A + ``` + +5. Uninstall when done or making changes and repeat step 2: + + ```bash + helm uninstall cert-manager -n cert-manager + ``` + +**Validation point**: Chart should deploy successfully and function as expected. + +### Stage 5: Integration Testing with helmfile + +Test multiple charts working together using Helmfile orchestration. + +1. Ensure helmfile.yaml is configured with the correct dependencies: + + ```yaml + releases: + - name: cert-manager + namespace: cert-manager + chart: ./cert-manager + # ... + - name: cert-manager-issuers + namespace: cert-manager + chart: ./cert-manager-issuers + # ... + needs: + - cert-manager/cert-manager + ``` + +2. Deploy all charts: + + ```bash + task deploy-helm + ``` + +3. Verify cross-component integration: + + ```bash + # Check if issuers are correctly using cert-manager + kubectl get clusterissuers + kubectl get issuers -A + + # Verify Traefik routes + kubectl get ingressroutes -A + ``` + +**Validation point**: All components should deploy in the correct order and work together. + +### Stage 6: Release Preparation + +Prepare a release package for distribution. + +1. Generate release files: + + ```bash + task prepare-release + ``` + +2. Inspect the generated release files: + + ```bash + ls -la ./release/ + ``` + +3. Create a release: + + ```bash + task release-create + ``` + +**Validation point**: Release files should be correctly generated and the release should be created successfully. + +### Stage 7: Test installing a helm based release + +TODO: Finish implementing helm based release testing + +### Stage 8: Embedded Cluster Testing + +Test the full application and configuration screen in a using an embedded cluster. + +1. Create a VM for testing: + + ```bash + task create-gcp-vm + ``` + +2. Set up an embedded cluster: + + ```bash + task setup-embedded-cluster + ``` + +3. Verify the application: + + ```bash + # Test accessing the application frontend + echo "Application URL: https://" + ``` + +**Validation point**: Verify configuration workflow, preflight, and other Embedded Cluster configurations. + +## Moving Between Stages + +The workflow is designed to be iterative. Here are guidelines for when to move from one stage to the next: + +- **Move forward** when the current stage validation passes without issues +- **Move backward** when problems are detected to diagnose and fix at a simpler level +- **Stay in a stage** if you're making changes focused on that particular level of complexity + +## Fast Feedback Examples + +Each stage provides fast feedback: + +1. **Chart Dependencies**: Immediate feedback on dependency resolution (seconds) +2. **Values Configuration**: Immediate feedback on configuration structure (seconds) +3. **Template Validation**: Fast feedback on template rendering (seconds) +4. **Single Chart Install**: Quick feedback on chart functionality (1-2 minutes) +5. **Integration Testing**: Feedback on component interaction (5-10 minutes) +6. **Release Preparation**: Feedback on release packaging (seconds) +7. **Embedded Testing**: Full system feedback (10-15 minutes) + +This progressive approach allows you to catch and fix issues at the earliest possible stage, minimizing the time spent debugging complex problems in fully deployed environments. diff --git a/applications/wg-easy/docs/examples.md b/applications/wg-easy/docs/examples.md new file mode 100644 index 0000000..728ac01 --- /dev/null +++ b/applications/wg-easy/docs/examples.md @@ -0,0 +1,228 @@ +# WG-Easy Development Pattern Examples + +This document provides practical examples of the key concepts in the WG-Easy Helm chart pattern. + +## Progressive Complexity Example + +This example demonstrates the complete workflow from working with a single chart to creating a full release. + +### Stage 1-2: Chart Dependencies and Configuration + +```yaml +# cert-manager/Chart.yaml +apiVersion: v2 +name: cert-manager +version: 1.0.0 +dependencies: + - name: cert-manager + version: '1.14.5' + repository: https://charts.jetstack.io + - name: templates + version: '*' + repository: file://../charts/templates +``` + +```bash +# Update dependencies +helm dependency update ./cert-manager + +# Verify dependencies were downloaded +ls -la ./cert-manager/charts/ +``` + +### Stage 3: Local Validation + +```bash +# Render templates locally to verify +helm template ./cert-manager --output-dir ./rendered-templates + +# Verify the output +ls -la ./rendered-templates/cert-manager/templates/ +``` + +### Stage 4: Single Chart Install + +```bash +# Create a test cluster +task create-cluster +task get-kubeconfig + +# Install the single chart +helm install cert-manager ./cert-manager -n cert-manager --create-namespace + +# Validate deployment +kubectl get pods -n cert-manager +``` + +### Stage 5: Integration Testing + +```bash +# Deploy multiple charts using helmfile +task deploy-helm + +# Verify integration points +kubectl get clusterissuers +kubectl get ingressroutes -A +``` + +### Stage 6-7: Release Preparation and Testing + +```bash +# Prepare release files +task prepare-release + +# Create a release +task release-create + +# Test in embedded environment +task create-gcp-vm +task setup-embedded-cluster +``` + +### Validation Points + +The example demonstrates validation at each stage: + +1. **Dependencies**: Verify charts are downloaded correctly +2. **Template Rendering**: Ensure templates produce valid Kubernetes resources +3. **Single Chart**: Confirm chart installs and runs properly in isolation +4. **Integration**: Validate charts work together as expected +5. **Release**: Verify proper packaging and release creation +6. **Production Environment**: Confirm full system functionality + +### Issue Isolation Example + +If an issue is discovered during integration testing (Stage 5): + +1. **Identify Components**: Determine which charts are involved +2. **Scale Back**: Return to Stage 4 to test each chart individually +3. **Find Root Cause**: Isolate the specific chart or interaction causing the issue +4. **Fix and Validate**: Make changes and validate at the simpler level first +5. **Progress Again**: Move back through the stages to ensure the fix works in the full system + +## Modular Configuration Example + +This example shows how per-chart configuration is maintained and merged during release. + +### Per-Chart Configuration + +```yaml +# traefik/replicated/config.yaml +apiVersion: kots.io/v1beta1 +kind: Config +metadata: + name: not-used +spec: + groups: + - name: traefik-config + title: Traefik + items: + - name: domain + title: Domain + type: text + required: true +``` + +```yaml +# wg-easy/replicated/config.yaml +apiVersion: kots.io/v1beta1 +kind: Config +metadata: + name: not-used +spec: + groups: + - name: wireguard-config + title: Wireguard + items: + - name: password + title: Admin password + type: password + required: true +``` + +### Configuration Merging + +During release preparation, these files are automatically merged: + +```bash +task prepare-release +``` + +This produces a combined `config.yaml` in the release directory with all options from both components. + +### Team Ownership Benefits + +This approach allows: + +1. **Distributed Responsibilities**: The Traefik team manages Traefik options, WG-Easy team manages WG-Easy options +2. **Independent Updates**: Teams can update their configuration without coordinating changes +3. **Clear Boundaries**: Configuration ownership follows component ownership +4. **Reduced Conflicts**: Fewer merge conflicts in version control + +## Chart Wrapping Example + +This example demonstrates wrapping an upstream chart and the benefits it provides. + +### Simple Chart Wrapping + +```yaml +# traefik/Chart.yaml - Wrapper chart +apiVersion: v2 +name: traefik +version: 1.0.0 +dependencies: + - name: traefik + version: '28.0.0' + repository: https://helm.traefik.io/traefik + - name: templates + version: '*' + repository: file://../charts/templates +``` + +```yaml +# traefik/values.yaml - Our custom defaults +traefik: + service: + type: NodePort + ports: + web: + nodePort: 80 + redirectTo: websecure + websecure: + nodePort: 443 +``` + +### Custom Templates + +```yaml +# traefik/templates/certificate.yaml - Custom resource +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: traefik-cert + namespace: traefik +spec: + secretName: traefik-cert + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + {{- range .Values.certs.dnsNames }} + - {{ . | quote }} + {{- end }} +``` + +### Benefits + +1. **Extended Functionality**: Add custom resources that aren't part of the upstream chart +2. **Version Management**: Control which version of the upstream chart is used +3. **Simplified Updates**: Test upstream chart updates in isolation +4. **Custom Defaults**: Set defaults that match your use case + +### Environment Consistency + +The wrapper chart ensures consistency by: + +1. **Shared Templates**: Reuse common patterns +2. **Explicit Dependencies**: Clear relationship between components +3. **Controlled Customization**: Customizations applied in a standard way diff --git a/applications/wg-easy/docs/replicated-integration.md b/applications/wg-easy/docs/replicated-integration.md new file mode 100644 index 0000000..d3dc168 --- /dev/null +++ b/applications/wg-easy/docs/replicated-integration.md @@ -0,0 +1,141 @@ +# Replicated Integration + +This document explains how the WG-Easy Helm chart pattern integrates with the Replicated platform, focusing on key integration points and modular configuration. + +## Replicated Overview + +Replicated is a platform that enables software vendors to deliver and manage Kubernetes applications to enterprise customers. In the context of this development pattern, Replicated provides: + +1. **Distribution**: Package and ship your application securely +2. **Configuration Management**: User-friendly configuration interfaces +3. **Licensing**: Control access through license files +4. **Embedded Kubernetes**: Deploy to environments without existing clusters +5. **Updates**: Manage application versions and updates + +## Integration Points + +The WG-Easy pattern integrates with Replicated at the following key points in the development workflow: + +### 1. Chart Structure Integration + +Each chart includes a `replicated` directory containing: + +``` +cert-manager/replicated/ +├── helmChart-cert-manager.yaml # Installation instructions +└── config.yaml # Component-specific configuration +``` + +### 2. Modular Configuration + +Each chart can define its own `config.yaml` with component-specific configuration options: + +```yaml +# Example: wg-easy/replicated/config.yaml +apiVersion: kots.io/v1beta1 +kind: Config +metadata: + name: not-used +spec: + groups: + - name: wireguard-config + title: Wireguard + description: Wireguard configuration + items: + - name: password + title: Admin password + type: password + required: true + - name: domain + title: IP or domain + help_text: Domain or IP which the vpn is accessible on + type: text + required: true +``` + +During release preparation, these individual `config.yaml` files are automatically merged into a single configuration file. + +### 3. Chart Installation + +The `helmChart-*.yaml` files define how each Helm chart is installed by Replicated installers: + +```yaml +# Example: traefik/replicated/helmChart-traefik.yaml +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: traefik +spec: + chart: + name: traefik + chartVersion: '1.0.0' + weight: 2 + helmUpgradeFlags: + - --wait + namespace: traefik + values: + traefik: + ports: + web: + nodePort: 80 + websecure: + nodePort: 443 +``` + +### 4. Release Workflow + +The integration with Replicated's release process is handled by the `prepare-release` and `release-create` tasks: + +```bash +# Prepare release files +task prepare-release + +# Create and promote a release +task release-create CHANNEL=Beta +``` + +The `prepare-release` task: + +1. Copies all Replicated YAML files to a release directory +2. Merges all `config.yaml` files from different components +3. Packages all Helm charts + +## Modular Configuration Benefits + +This modular configuration approach provides several benefits: + +1. **Team Ownership**: Different teams can own their component's configuration +2. **Isolation**: Changes to one component's configuration don't affect others +3. **Simplified Development**: Focus on your component without worrying about the full configuration +4. **Automatic Merging**: Configuration merging is automated at release time + +## Embedded Cluster Support + +Replicated's embedded Kubernetes capability is configured via the `cluster.yaml` file: + +```yaml +apiVersion: embeddedcluster.replicated.com/v1beta1 +kind: Config +spec: + version: 2.1.3+k8s-1.29 + unsupportedOverrides: + k0s: |- + config: + spec: + workerProfiles: + - name: default + values: + allowedUnsafeSysctls: + - net.ipv4.ip_forward +``` + +This enables running the application in environments without a pre-existing Kubernetes cluster. + +## Further Replicated Documentation + +For detailed information about Replicated's capabilities and options, refer to the official documentation: + +- [Replicated KOTS Documentation](https://docs.replicated.com/reference/kots-cli) +- [Helm Chart Integration](https://docs.replicated.com/vendor/helm-installing) +- [Configuration Options](https://docs.replicated.com/vendor/config-screen) +- [Embedded Clusters](https://docs.replicated.com/vendor/embedded-clusters) diff --git a/applications/wg-easy/docs/task-reference.md b/applications/wg-easy/docs/task-reference.md new file mode 100644 index 0000000..2f470fa --- /dev/null +++ b/applications/wg-easy/docs/task-reference.md @@ -0,0 +1,125 @@ +# Task Reference + +This document provides a concise reference for the tasks available in the WG-Easy Helm chart development pattern, organized by their purpose in the development workflow. + +## Development Tasks + +These tasks support the iterative development process, focusing on fast feedback loops. + +| Task | Description | Related Workflow Stage | +|------|-------------|------------------------| +| `update-dependencies` | Updates Helm dependencies for all charts in the repository | Stage 1: Dependencies | +| `deploy-helm` | Deploys all charts using helmfile with proper sequencing | Stage 5: Integration Testing | +| `expose-ports` | Exposes the configured ports on the cluster for testing | Stage 4-5: Chart Installation/Integration | +| `remove-k3s-traefik` | Removes pre-installed Traefik from k3s clusters to avoid conflicts | Stage 4-5: Chart Installation/Integration | + +### Common Development Combinations + +**Complete Update and Deploy:** +```bash +task update-dependencies && task deploy-helm +``` + +**Single Chart Testing:** +```bash +helm dependency update ./traefik +helm install traefik ./traefik -n traefik --create-namespace +``` + +## Environment Tasks + +These tasks help manage the development and testing environments. + +| Task | Description | Related Workflow Stage | +|------|-------------|------------------------| +| `create-cluster` | Creates a test Kubernetes cluster using Replicated's Compatibility Matrix | Stage 4: Single Chart Install | +| `get-kubeconfig` | Retrieves the kubeconfig for the test cluster | Stage 4: Single Chart Install | +| `delete-cluster` | Deletes the test cluster and cleans up resources | Stage 4-5: Cleanup | +| `create-gcp-vm` | Creates a GCP VM instance for embedded cluster testing | Stage 7: Embedded Testing | +| `delete-gcp-vm` | Deletes the GCP VM instance after testing | Stage 7: Cleanup | +| `setup-embedded-cluster` | Sets up a Replicated embedded cluster on the GCP VM | Stage 7: Embedded Testing | + +### Common Environment Combinations + +**Create Test Environment:** +```bash +task create-cluster && task get-kubeconfig +OR +task get-kubeconfig +``` + +While tasks can be run in order, they also have dependencies. Running the get-kubeconfig task for example will also create a cluster if the test cluster hasn't been created already. + +**Cleanup After Testing:** +```bash +task delete-cluster +``` + +Creating a cluster can take up to 5 minutes and helm charts should be uninstalled/reinstalled while developing rather than removing the entire cluster to iterate in seconds rather than minutes. + +## Release Tasks + +These tasks support preparing and creating releases. + +| Task | Description | Related Workflow Stage | +|------|-------------|------------------------| +| `prepare-release` | Packages charts and merges configuration files for release | Stage 6: Release Preparation | +| `release-create` | Creates and promotes a release using the Replicated CLI | Stage 6: Release Preparation | +| `test` | Runs basic validation tests against the deployed application | Stage 5-7: Validation | + +TODO: The test task is a placeholder currently it just sleeps and returns positive. + +### Release Process Example + +```bash +task prepare-release && task release-create CHANNEL=Beta +``` + +## Automation Tasks + +These tasks provide end-to-end automation combining multiple individual tasks. + +| Task | Description | Related Workflow Stages | +|------|-------------|-------------------------| +| `full-test-cycle` | Runs a complete test cycle from cluster creation to deletion | Stages 4-5: Full Testing | + +This task performs the following sequence: + +1. Creates a cluster +2. Gets the kubeconfig +3. Exposes ports +4. Removes pre-installed Traefik +5. Updates dependencies +6. Deploys all charts +7. Runs tests +8. Deletes the cluster + +## Task Parameters + +Many tasks accept parameters to customize their behavior. Here are the most commonly used parameters: + +| Parameter | Used With | Description | Default | +|-----------|-----------|-------------|---------| +| `CLUSTER_NAME` | `create-cluster`, `get-kubeconfig` | Name for the cluster | "test-cluster" | +| `K8S_VERSION` | `create-cluster` | Kubernetes version | "1.32.2" | +| `DISTRIBUTION` | `create-cluster` | Cluster distribution | "k3s" | +| `CHANNEL` | `release-create` | Channel to promote to | "Unstable" | +| `RELEASE_NOTES` | `release-create` | Notes for the release | "" | +| `GCP_PROJECT` | `create-gcp-vm` | GCP project ID | Required | +| `GCP_ZONE` | `create-gcp-vm` | GCP zone | "us-central1-a" | + +Parameters in the Taskfile.yaml try to always have defaults so that it works out of the box but allows customization for common values. + +## Supporting the Development Workflow + +These tasks are designed to support the progressive complexity approach: + +1. **Early Stages** - Use `update-dependencies` and helm commands directly +2. **Middle Stages** - Use `create-cluster`, `deploy-helm`, and `test` +3. **Later Stages** - Use `prepare-release`, `release-create`, and embedded cluster tasks + +This organization allows developers to focus on the appropriate level of complexity at each stage of development. + +## Cross-References to Workflow Stages + +Refer to the [Development Workflow](development-workflow.md) document for details on each stage and when to use specific tasks. From c226706e95eab45a28d69fbca2cd7338e63bc28d Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Wed, 26 Mar 2025 14:47:08 -0500 Subject: [PATCH 09/32] docs(wg-easy): Add prerequisites section to development workflow --- .gitignore | 1 + applications/wg-easy/docs/development-workflow.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/.gitignore b/.gitignore index 1e928c8..d535bc6 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ __pycache__/ applications/wg-easy/release/ applications/wg-easy/*/charts/ applications/wg-easy/*/Chart.lock +.aider* diff --git a/applications/wg-easy/docs/development-workflow.md b/applications/wg-easy/docs/development-workflow.md index 5b213eb..eacf2b5 100644 --- a/applications/wg-easy/docs/development-workflow.md +++ b/applications/wg-easy/docs/development-workflow.md @@ -13,6 +13,20 @@ The core philosophy of this workflow is to start simple and add complexity incre ![Workflow Diagram](workflow-diagram.png) +## Prerequisites + +Before starting the development workflow, ensure you have the following tools installed: + +- **Task:** The task runner used in this project. ([Installation Guide](https://taskfile.dev/installation/)) +- **Replicated CLI:** For managing test clusters and application releases. ([Installation Guide](https://docs.replicated.com/reference/replicated-cli-installing)) +- **Helm:** The Kubernetes package manager. ([Installation Guide](https://helm.sh/docs/intro/install/)) +- **Helmfile:** For orchestrating Helm chart deployments. ([Installation Guide](https://github.com/helmfile/helmfile#installation)) +- **kubectl:** The Kubernetes command-line tool. ([Installation Guide](https://kubernetes.io/docs/tasks/tools/install-kubectl/)) +- **jq:** A command-line JSON processor. ([Download Page](https://stedolan.github.io/jq/download/)) +- **yq:** A command-line YAML processor. ([Installation Guide](https://github.com/mikefarah/yq#install)) +- **gcloud CLI:** Google Cloud command-line interface (optional, only required for GCP-specific tasks). ([Installation Guide](https://cloud.google.com/sdk/docs/install)) +- **Standard Unix Utilities:** `find`, `xargs`, `grep`, `awk`, `wc`, `tr`, `cp`, `mv`, `rm`, `mkdir`, `echo`, `sleep`, `test`, `eval` (typically available by default on Linux and macOS). + ## Workflow Stages ### Stage 1: Chart Dependencies and Verification From 6f7d25e04212aa2d5eefc806a72abc690bda80d9 Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Wed, 26 Mar 2025 16:56:38 -0500 Subject: [PATCH 10/32] Refactor Taskfile to improve k3s traefik removal workflow --- applications/wg-easy/Taskfile.yaml | 67 +++++++++---------- applications/wg-easy/taskfiles/utils.yml | 83 ++++++++++++++++-------- 2 files changed, 85 insertions(+), 65 deletions(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 741a7a9..96678ab 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -36,7 +36,7 @@ tasks: create-cluster: desc: Create a test cluster using Replicated Compatibility Matrix (use EMBEDDED=true for embedded clusters) run: once - silent: true + silent: false vars: EMBEDDED: '{{.EMBEDDED | default "false"}}' LICENSE_ID: '{{if eq .EMBEDDED "true"}}{{.LICENSE_ID | default "2cmqT1dBVHZ3aSH21kPxWtgoYGr"}}{{end}}' @@ -58,29 +58,37 @@ tasks: test: desc: Run a basic test suite - silent: true + silent: false cmds: - echo "Running basic tests..." - echo "This is a placeholder for actual tests" - sleep 5 - echo "Tests completed!" - get-kubeconfig: - desc: Get kubeconfig for the test cluster - silent: true + setup-kubeconfig: + desc: Get kubeconfig and prepare cluster for application deployment + silent: false run: once cmds: - - | - echo "Getting kubeconfig for cluster {{.CLUSTER_NAME}}..." - replicated cluster kubeconfig --name {{.CLUSTER_NAME}} --output-path {{.KUBECONFIG_FILE}} + - task: utils:get-kubeconfig + - task: utils:remove-k3s-traefik status: - - test -f {{.KUBECONFIG_FILE}} + - | + # Check if kubeconfig exists + test -f {{.KUBECONFIG_FILE}} && \ + # For k3s, also check if traefik is removed + if [ "{{.DISTRIBUTION}}" = "k3s" ]; then + KUBECONFIG={{.KUBECONFIG_FILE}} helm list -n kube-system -o json | \ + jq -e 'map(select(.name == "traefik" or .name == "traefik-crd")) | length == 0' >/dev/null + else + true + fi deps: - create-cluster update-dependencies: desc: Update Helm dependencies for all charts - silent: true + silent: false cmds: - echo "Updating Helm dependencies for all charts..." - | @@ -93,7 +101,7 @@ tasks: expose-ports: desc: Expose configured ports and capture exposed URLs - silent: true + silent: false run: once status: - | @@ -122,7 +130,7 @@ tasks: deploy-helm: desc: Deploy all charts using helmfile - silent: true + silent: false cmds: - echo "Installing all charts via helmfile" - | @@ -141,27 +149,13 @@ tasks: eval "KUBECONFIG={{.KUBECONFIG_FILE}} $ENV_VARS helmfile sync --wait" - echo "All charts deployed!" deps: - - get-kubeconfig + - setup-kubeconfig - expose-ports - - remove-k3s-traefik - remove-k3s-traefik: - desc: Remove pre-installed Traefik from k3s clusters - silent: true - cmds: - - | - # Only run for k3s distributions - if [ "{{.DISTRIBUTION}}" = "k3s" ]; then - task utils:traefik-operations OPERATION=remove KUBECONFIG_FILE={{.KUBECONFIG_FILE}} - else - echo "Not a k3s cluster, skipping Traefik removal." - fi - deps: - - get-kubeconfig delete-cluster: desc: Delete all test clusters with matching name and clean up kubeconfig - silent: true + silent: false cmds: - echo "Deleting clusters named {{.CLUSTER_NAME}}..." - | @@ -185,7 +179,7 @@ tasks: prepare-release: desc: Prepare release files by copying replicated YAML files and packaging Helm charts - silent: true + silent: false cmds: - echo "Preparing release files..." - rm -rf ./release @@ -230,7 +224,7 @@ tasks: release-create: desc: Create and promote a release using the Replicated CLI - silent: true + silent: false vars: CHANNEL: '{{.CHANNEL | default "Unstable"}}' RELEASE_NOTES: '{{.RELEASE_NOTES | default "Release created via task release-create"}}' @@ -247,7 +241,7 @@ tasks: create-gcp-vm: desc: Create a simple GCP VM instance - silent: true + silent: false vars: GCP_MACHINE_TYPE: '{{.GCP_MACHINE_TYPE | default "e2-standard-2"}}' GCP_DISK_SIZE: '{{.GCP_DISK_SIZE | default "100"}}' @@ -263,7 +257,7 @@ tasks: delete-gcp-vm: desc: Delete the GCP VM instance for K8s and VPN - silent: true + silent: false status: - "! gcloud compute instances describe {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} &>/dev/null" cmds: @@ -273,7 +267,7 @@ tasks: setup-embedded-cluster: desc: Setup Replicated embedded cluster on the GCP VM - silent: true + silent: false vars: CHANNEL: '{{.CHANNEL | default "Unstable"}}' AUTH_TOKEN: '{{.AUTH_TOKEN | default "2uJbnRgxrmrhqBDF1Sd7wcYFDPh"}}' @@ -290,13 +284,12 @@ tasks: full-test-cycle: desc: Create cluster, get kubeconfig, expose ports, update dependencies, deploy charts, test, and delete - silent: true + silent: false cmds: - task: create-cluster - - task: get-kubeconfig + - task: setup-kubeconfig - task: expose-ports - - task: remove-k3s-traefik - task: update-dependencies - task: deploy-helm - task: test - - task: delete-cluster \ No newline at end of file + - task: delete-cluster diff --git a/applications/wg-easy/taskfiles/utils.yml b/applications/wg-easy/taskfiles/utils.yml index af743cc..9a77b90 100644 --- a/applications/wg-easy/taskfiles/utils.yml +++ b/applications/wg-easy/taskfiles/utils.yml @@ -1,6 +1,60 @@ version: "3" tasks: + get-kubeconfig: + desc: Get kubeconfig for the test cluster (internal) + internal: true + silent: false + run: once + cmds: + - | + echo "Getting kubeconfig for cluster {{.CLUSTER_NAME}}..." + replicated cluster kubeconfig --name {{.CLUSTER_NAME}} --output-path {{.KUBECONFIG_FILE}} + status: + - test -f {{.KUBECONFIG_FILE}} + + remove-k3s-traefik: + desc: Remove pre-installed Traefik from k3s clusters (internal) + internal: true + silent: false + run: once + status: + - | + # Only check if we need to run this for k3s distributions + if [ "{{.DISTRIBUTION}}" != "k3s" ]; then + exit 0 # Not a k3s cluster, so we're "done" + fi + + # Check if traefik is already removed by looking for the helm releases + KUBECONFIG={{.KUBECONFIG_FILE}} helm list -n kube-system -o json | \ + jq -e 'map(select(.name == "traefik" or .name == "traefik-crd")) | length == 0' >/dev/null + cmds: + - | + # Only run for k3s distributions + if [ "{{.DISTRIBUTION}}" = "k3s" ]; then + echo "Checking for pre-installed Traefik in k3s cluster..." + + # Check if traefik is installed in kube-system namespace + TRAEFIK_CHARTS=$(KUBECONFIG={{.KUBECONFIG_FILE}} helm list -n kube-system -o json | jq -r '.[] | select(.name == "traefik" or .name == "traefik-crd") | .name') + + if [ -n "$TRAEFIK_CHARTS" ]; then + echo "Found pre-installed Traefik charts in kube-system namespace. Removing..." + + for chart in $TRAEFIK_CHARTS; do + echo "Uninstalling chart: $chart" + KUBECONFIG={{.KUBECONFIG_FILE}} helm uninstall $chart -n kube-system --wait + done + + echo "Pre-installed Traefik removed successfully!" + else + echo "No pre-installed Traefik charts found in kube-system namespace." + fi + else + echo "Not a k3s cluster, skipping Traefik removal." + fi + deps: + - get-kubeconfig + wait-for-cluster: desc: Wait for cluster to be in running state internal: true @@ -33,33 +87,6 @@ tasks: attempt=$((attempt+1)) done - traefik-operations: - desc: Operations for managing Traefik - silent: true - vars: - OPERATION: '{{.OPERATION}}' - KUBECONFIG_FILE: '{{.KUBECONFIG_FILE}}' - cmds: - - | - if [ "{{.OPERATION}}" = "remove" ]; then - echo "Checking for pre-installed Traefik in k3s cluster..." - - # Check if traefik is installed in kube-system namespace - TRAEFIK_CHARTS=$(KUBECONFIG={{.KUBECONFIG_FILE}} helm list -n kube-system -o json | jq -r '.[] | select(.name | contains("traefik")) | .name') - - if [ -n "$TRAEFIK_CHARTS" ]; then - echo "Found pre-installed Traefik charts in kube-system namespace. Removing..." - - for chart in $TRAEFIK_CHARTS; do - echo "Uninstalling chart: $chart" - KUBECONFIG={{.KUBECONFIG_FILE}} helm uninstall $chart -n kube-system --wait - done - - echo "Pre-installed Traefik removed successfully!" - else - echo "No pre-installed Traefik charts found in kube-system namespace." - fi - fi port-operations: desc: Expose and check status of ports @@ -168,4 +195,4 @@ tasks: echo "Embedded cluster setup initiated on VM {{.VM_NAME}}" echo "You can SSH into the VM with: gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}}" - fi \ No newline at end of file + fi From c8640e315bc24b76b54b4ec5f29cca705c34446e Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Wed, 26 Mar 2025 16:58:55 -0500 Subject: [PATCH 11/32] Update documentation to reference setup-kubeconfig instead of get-kubeconfig --- applications/wg-easy/docs/development-workflow.md | 2 +- applications/wg-easy/docs/examples.md | 2 +- applications/wg-easy/docs/task-reference.md | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/applications/wg-easy/docs/development-workflow.md b/applications/wg-easy/docs/development-workflow.md index eacf2b5..a5b06fd 100644 --- a/applications/wg-easy/docs/development-workflow.md +++ b/applications/wg-easy/docs/development-workflow.md @@ -114,7 +114,7 @@ Deploy individual charts to a test cluster to verify functionality. ```bash task create-cluster - task get-kubeconfig + task setup-kubeconfig ``` 2. Install a single chart: diff --git a/applications/wg-easy/docs/examples.md b/applications/wg-easy/docs/examples.md index 728ac01..b353408 100644 --- a/applications/wg-easy/docs/examples.md +++ b/applications/wg-easy/docs/examples.md @@ -45,7 +45,7 @@ ls -la ./rendered-templates/cert-manager/templates/ ```bash # Create a test cluster task create-cluster -task get-kubeconfig +task setup-kubeconfig # Install the single chart helm install cert-manager ./cert-manager -n cert-manager --create-namespace diff --git a/applications/wg-easy/docs/task-reference.md b/applications/wg-easy/docs/task-reference.md index 2f470fa..7a27b28 100644 --- a/applications/wg-easy/docs/task-reference.md +++ b/applications/wg-easy/docs/task-reference.md @@ -33,7 +33,7 @@ These tasks help manage the development and testing environments. | Task | Description | Related Workflow Stage | |------|-------------|------------------------| | `create-cluster` | Creates a test Kubernetes cluster using Replicated's Compatibility Matrix | Stage 4: Single Chart Install | -| `get-kubeconfig` | Retrieves the kubeconfig for the test cluster | Stage 4: Single Chart Install | +| `setup-kubeconfig` | Retrieves and sets up the kubeconfig for the test cluster | Stage 4: Single Chart Install | | `delete-cluster` | Deletes the test cluster and cleans up resources | Stage 4-5: Cleanup | | `create-gcp-vm` | Creates a GCP VM instance for embedded cluster testing | Stage 7: Embedded Testing | | `delete-gcp-vm` | Deletes the GCP VM instance after testing | Stage 7: Cleanup | @@ -43,9 +43,9 @@ These tasks help manage the development and testing environments. **Create Test Environment:** ```bash -task create-cluster && task get-kubeconfig +task create-cluster && task setup-kubeconfig OR -task get-kubeconfig +task setup-kubeconfig ``` While tasks can be run in order, they also have dependencies. Running the get-kubeconfig task for example will also create a cluster if the test cluster hasn't been created already. @@ -86,7 +86,7 @@ These tasks provide end-to-end automation combining multiple individual tasks. This task performs the following sequence: 1. Creates a cluster -2. Gets the kubeconfig +2. Sets up the kubeconfig 3. Exposes ports 4. Removes pre-installed Traefik 5. Updates dependencies @@ -100,7 +100,7 @@ Many tasks accept parameters to customize their behavior. Here are the most comm | Parameter | Used With | Description | Default | |-----------|-----------|-------------|---------| -| `CLUSTER_NAME` | `create-cluster`, `get-kubeconfig` | Name for the cluster | "test-cluster" | +| `CLUSTER_NAME` | `create-cluster`, `setup-kubeconfig` | Name for the cluster | "test-cluster" | | `K8S_VERSION` | `create-cluster` | Kubernetes version | "1.32.2" | | `DISTRIBUTION` | `create-cluster` | Cluster distribution | "k3s" | | `CHANNEL` | `release-create` | Channel to promote to | "Unstable" | From e0e157860939af797cf941199705b0b7af6a7429 Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Wed, 26 Mar 2025 17:54:28 -0500 Subject: [PATCH 12/32] refactor: Enhance GCP VM creation and SSH connection with robust retry and timeout logic --- applications/wg-easy/Taskfile.yaml | 16 +++++++- applications/wg-easy/taskfiles/utils.yml | 50 ++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 96678ab..16f6783 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -254,6 +254,11 @@ tasks: - task: utils:gcp-operations vars: OPERATION: "create" + GCP_MACHINE_TYPE: '{{.GCP_MACHINE_TYPE}}' + GCP_DISK_SIZE: '{{.GCP_DISK_SIZE}}' + GCP_DISK_TYPE: '{{.GCP_DISK_TYPE}}' + GCP_IMAGE_FAMILY: '{{.GCP_IMAGE_FAMILY}}' + GCP_IMAGE_PROJECT: '{{.GCP_IMAGE_PROJECT}}' delete-gcp-vm: desc: Delete the GCP VM instance for K8s and VPN @@ -264,13 +269,16 @@ tasks: - task: utils:gcp-operations vars: OPERATION: "delete" + GCP_PROJECT: '{{.GCP_PROJECT}}' + GCP_ZONE: '{{.GCP_ZONE}}' + VM_NAME: '{{.VM_NAME}}' setup-embedded-cluster: desc: Setup Replicated embedded cluster on the GCP VM silent: false vars: CHANNEL: '{{.CHANNEL | default "Unstable"}}' - AUTH_TOKEN: '{{.AUTH_TOKEN | default "2uJbnRgxrmrhqBDF1Sd7wcYFDPh"}}' + AUTH_TOKEN: '{{.AUTH_TOKEN | default "2usDXzovcJNcpn54yS5tFQVNvCq"}}' deps: - create-gcp-vm status: @@ -281,6 +289,12 @@ tasks: - task: utils:gcp-operations vars: OPERATION: "setup-embedded" + APP_NAME: '{{.APP_NAME}}' + CHANNEL: '{{.CHANNEL}}' + AUTH_TOKEN: '{{.AUTH_TOKEN}}' + GCP_PROJECT: '{{.GCP_PROJECT}}' + GCP_ZONE: '{{.GCP_ZONE}}' + VM_NAME: '{{.VM_NAME}}' full-test-cycle: desc: Create cluster, get kubeconfig, expose ports, update dependencies, deploy charts, test, and delete diff --git a/applications/wg-easy/taskfiles/utils.yml b/applications/wg-easy/taskfiles/utils.yml index 9a77b90..7b3a14d 100644 --- a/applications/wg-easy/taskfiles/utils.yml +++ b/applications/wg-easy/taskfiles/utils.yml @@ -167,6 +167,32 @@ tasks: echo "VM {{.VM_NAME}} created successfully with IP: $EXTERNAL_IP" echo "You can SSH into the VM with: gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}}" + + # Wait for VM to be fully in RUNNING state (should be immediate, but just in case) + echo "Verifying VM is in RUNNING state..." + start=$(date +%s) + attempt=1 + timeout=30 # 30 seconds timeout + + while true; do + VM_STATUS=$(gcloud compute instances describe {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} --format='get(status)' 2>/dev/null || echo "PENDING") + + if [ "$VM_STATUS" = "RUNNING" ]; then + elapsed=$(($(date +%s) - start)) + echo "VM {{.VM_NAME}} is in RUNNING state! (took $elapsed seconds)" + break + fi + + elapsed=$(($(date +%s) - start)) + if [ $elapsed -ge $timeout ]; then + echo "Timeout after $timeout seconds waiting for VM to be ready" + exit 1 + fi + + printf "\rWaiting... %ds elapsed (attempt %d) - Current status: %s " "$elapsed" "$attempt" "$VM_STATUS" + sleep 1 + attempt=$((attempt+1)) + done elif [ "{{.OPERATION}}" = "delete" ]; then echo "Deleting GCP VM instance {{.VM_NAME}}..." @@ -182,6 +208,30 @@ tasks: elif [ "{{.OPERATION}}" = "setup-embedded" ]; then echo "Setting up embedded cluster on GCP VM {{.VM_NAME}}..." + # Wait for SSH to be ready with retry logic + echo "Waiting for SSH to be ready on VM {{.VM_NAME}}..." + start=$(date +%s) + attempt=1 + timeout=60 # 60 seconds timeout for SSH + + while true; do + if gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} --command="echo 'SSH is ready'" &>/dev/null; then + elapsed=$(($(date +%s) - start)) + echo "SSH connection established successfully! (took $elapsed seconds)" + break + fi + + elapsed=$(($(date +%s) - start)) + if [ $elapsed -ge $timeout ]; then + echo "Timeout after $timeout seconds waiting for SSH to be ready" + exit 1 + fi + + printf "\rWaiting... %ds elapsed (attempt %d) - SSH not ready yet " "$elapsed" "$attempt" + sleep 2 + attempt=$((attempt+1)) + done + # Run installation commands on the VM echo "Installing embedded cluster on VM..." gcloud compute ssh {{.VM_NAME}} --project={{.GCP_PROJECT}} --zone={{.GCP_ZONE}} --command=" From 7385254240fc0acec337f5f02948371409d04ca4 Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Mon, 7 Apr 2025 09:31:00 +1200 Subject: [PATCH 13/32] add verify kubeconfig --- applications/wg-easy/Taskfile.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 16f6783..1b0f1fa 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -65,6 +65,25 @@ tasks: - sleep 5 - echo "Tests completed!" + + verify-kubeconfig: + desc: Verify kubeconfig + silent: false + run: once + cmds: + - | + if [ -f {{.KUBECONFIG_FILE}} ]; then + echo "Getting Cluster ID From Replicated Cluster list" + CLUSTER_ID=$(replicated cluster ls --output json | jq -r '.[] | select(.name == "{{.CLUSTER_NAME}}") | .id') + echo "Getting Cluster ID From Kubeconfig" + CLUSTER_ID_KUBECONFIG=$(grep "current-context:" {{.KUBECONFIG_FILE}} | cut -d'-' -f3) + if [ "$CLUSTER_ID" != "$CLUSTER_ID_KUBECONFIG" ]; then + echo "{{.CLUSTER_NAME}} Cluster ID between Replicated ($CLUSTER_ID) and Kubeconfig ($CLUSTER_ID_KUBECONFIG) mismatch" + echo "Removing old kubeconfig file" + rm -f {{.KUBECONFIG_FILE}} + fi + fi + setup-kubeconfig: desc: Get kubeconfig and prepare cluster for application deployment silent: false @@ -85,6 +104,7 @@ tasks: fi deps: - create-cluster + - verify-kubeconfig update-dependencies: desc: Update Helm dependencies for all charts From cd3c281aecc40e37bb19b1790640264c110c0631 Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Mon, 7 Apr 2025 18:08:56 +1200 Subject: [PATCH 14/32] add list cluster and use dotenv to update chart release version --- applications/wg-easy/Taskfile.yaml | 20 +++++++++++++++++++ .../wg-easy/replicated/helmChart-wg-easy.yaml | 3 +-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 1b0f1fa..71fd697 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -56,6 +56,15 @@ tasks: vars: TIMEOUT: "{{.TIMEOUT}}" + list-cluster: + desc: List the cluster + silent: false + cmds: + - | + CLUSTER_ID=$(replicated cluster ls --output json | jq -r '.[] | select(.name == "{{.CLUSTER_NAME}}") | .id') + EXPIRES=$(replicated cluster ls --output json | jq -r '.[] | select(.name == "{{.CLUSTER_NAME}}") | .expires_at') + echo "{{.CLUSTER_NAME}} Cluster ID: ($CLUSTER_ID) Expires: ($EXPIRES)" + test: desc: Run a basic test suite silent: false @@ -197,6 +206,17 @@ tasks: fi - echo "All matching clusters deleted and kubeconfig cleaned up!" + update-version: + desc: Update the version in the .env file + dotenv: ['.env'] + silent: false + cmds: + - echo "Creating new version with Replicated using version $VERSION" + - | + sed -i '' 's|chartVersion: [0-9a-zA-Z.-]*|chartVersion: '$VERSION'|g' wg-easy/replicated/helmChart-wg-easy.yaml; \ + sed -i '' 's|^version: [0-9a-zA-Z.-]*|version: '$VERSION'|' wg-easy/Chart.yaml; \ + echo "Updated version and appVersion to $VERSION in chart files" + prepare-release: desc: Prepare release files by copying replicated YAML files and packaging Helm charts silent: false diff --git a/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml b/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml index 4dc2141..28900c8 100644 --- a/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml +++ b/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml @@ -5,8 +5,7 @@ metadata: spec: chart: name: wg-easy - chartVersion: '1.0.0' - #chartVersion: '*' + chartVersion: 1.0.0 weight: 3 # helmUpgradeFlags specifies additional flags to pass to the `helm upgrade` command. From 80cd890ae413ca962d10d5192d8a9d12b294c8b6 Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Tue, 8 Apr 2025 17:39:25 +1200 Subject: [PATCH 15/32] update taskfile to fix promote fail and add release lint inspect --- applications/wg-easy/Taskfile.yaml | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 71fd697..aef4d45 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -261,24 +261,38 @@ tasks: done - echo "Release files prepared in ./release/ directory" - + deps: + - update-version + + release-create: desc: Create and promote a release using the Replicated CLI silent: false - vars: - CHANNEL: '{{.CHANNEL | default "Unstable"}}' - RELEASE_NOTES: '{{.RELEASE_NOTES | default "Release created via task release-create"}}' + dotenv: ['.env'] cmds: - - echo "Creating and promoting release for {{.APP_NAME}} to channel {{.CHANNEL}}..." + - echo "Creating and promoting release for $APP_NAME to channel $CHANNEL..." - | # Create and promote the release in one step echo "Creating release from files in ./release directory..." - replicated release create --app {{.APP_NAME}} --yaml-dir ./release --release-notes "{{.RELEASE_NOTES}}" --promote {{.CHANNEL}} - - echo "Release created and promoted to channel {{.CHANNEL}}" + replicated release create --app $APP_NAME --yaml-dir ./release --release-notes "$RELEASE_NOTES" --promote $CHANNEL --version $VERSION + echo "Release version $VERSION created and promoted to channel $CHANNEL" deps: - prepare-release + release-inspect: + desc: Inspect the release + silent: false + dotenv: ['.env'] + cmds: + - | + release_sequence=$(replicated channel inspect $CHANNEL --output json | jq -r '.releaseSequence') + echo "Release sequence: $release_sequence" + app_id=$(replicated app ls --output json | jq -r '.[] | select(.app.name == "'$APP_NAME'") | .app.id') + echo "App ID: $app_id" + curl -X GET "https://api.replicated.com/vendor/v3/app/$app_id/release/$release_sequence" \ + -H "Authorization: Bearer $REPLICATED_API_TOKEN" \ + -H "Content-Type: application/json" + create-gcp-vm: desc: Create a simple GCP VM instance silent: false From 6b3a4eb6226c3d48ccf9073452dc8fce846d8418 Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Tue, 8 Apr 2025 17:39:46 +1200 Subject: [PATCH 16/32] add example env --- applications/wg-easy/.env | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 applications/wg-easy/.env diff --git a/applications/wg-easy/.env b/applications/wg-easy/.env new file mode 100644 index 0000000..ca0275d --- /dev/null +++ b/applications/wg-easy/.env @@ -0,0 +1,4 @@ +VERSION=0.0.4 +CHANNEL=wg-easy +APP_NAME=wg-easy +RELEASE_NOTES="Release created via task release-create" From dc74ba1a43c99822e21fcb7dae871da7467ee0d7 Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Tue, 8 Apr 2025 17:40:04 +1200 Subject: [PATCH 17/32] add development md --- DEVELOPMENT.md | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 DEVELOPMENT.md diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 0000000..31fd7a2 --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,93 @@ +## Issues +#### 1. Replicated CLI didn't report the release was not promoted to channel, instead it showed the release was created and promoted. This was confusing. + +When you run `replicated release create --app $APP_NAME --yaml-dir ./release --release-notes "$RELEASE_NOTES" --promote $CHANNEL`. +Without the `--version` flag, the release will not be promoted to the channel. + +But in the output of the Replicated CLI, it shows the release was created and promoted. +``` +replicated release create --app dexter-test3 --yaml-dir ./release --release-notes "dddd" --promote replicated-test + +Creating release from files in ./release directory... + + • Reading manifests from ./release ✓ + • Creating Release ✓ + • SEQUENCE: 118 + • Promoting ✓ + • Channel 2v70WgeXccBVgLyFzKt8qmN03Ow successfully set to release 118 + +Release created and promoted to channel replicated-test +``` +It shows the release was created and promoted to the channel. But in fact, the release was not promoted to the channel when customer check the channel page. + +Improvement: +- Add a warning when the release was not promoted to the channel without the `--version` flag. + +#### 2. Replicated CLI didn't return the linting errors when using `replicated release inspect xxx`. +In the vendor portal, the release contains errors in the templates. For example, +``` +wg-easy/charts/wg-easy/templates/replicated-library.yaml +Line 13 | Error: yaml: line 13: did not find expected key +Error invalid-yaml. +``` + +When you run `replicated release inspect xxx`, it didn't return the linting errors when the release contains errors in the templates. + +But when you curl Replicated API, you can get the linting errors. +``` +"lintResult": { + "lintExpressions": [ + { + "rule": "invalid-yaml", + "type": "error", + "message": "yaml: line 13: did not find expected key", + "path": "wg-easy/charts/wg-easy/templates/replicated-library.yaml", + "positions": [ + { + "start": { + "line": 13 + } + } + ] + } + ], + "isLintingComplete": false +}, +``` + +Improvement: +- Return the linting errors when using `replicated release inspect xxx` + +#### 3. Missing `Replicated app inspect` command. +In our documentation, we have `replicated app inspect` [command](https://help.replicated.com/docs/reference/cli/replicated-app-inspect/). But when we run `replicated app inspect app-name`, it returns the error: +``` +Example: + # List all applications + replicated app ls + + # Create a new application + replicated app create "My New App" + + # View details of a specific application + replicated app inspect "My App Name" + + # Delete an application + replicated app delete "App to Remove" + + # Update an application's settings + replicated app update "My App" --channel stable + + # List applications with custom output format + replicated app ls --output json + +Available Commands: + create Create a new application + ls List applications + rm Delete an application +``` +The available commands are `create`, `ls`, `rm`, and `update`. But `inspect` is not one of them. + +Improvement: +- Add the `inspect` command to the `replicated app` command. + + From dc97b5067dba8b7ce90a0f0ac763ef7eb87f254b Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Wed, 9 Apr 2025 18:31:46 +1200 Subject: [PATCH 18/32] remove delelopment md --- DEVELOPMENT.md | 93 -------------------------------------------------- 1 file changed, 93 deletions(-) delete mode 100644 DEVELOPMENT.md diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md deleted file mode 100644 index 31fd7a2..0000000 --- a/DEVELOPMENT.md +++ /dev/null @@ -1,93 +0,0 @@ -## Issues -#### 1. Replicated CLI didn't report the release was not promoted to channel, instead it showed the release was created and promoted. This was confusing. - -When you run `replicated release create --app $APP_NAME --yaml-dir ./release --release-notes "$RELEASE_NOTES" --promote $CHANNEL`. -Without the `--version` flag, the release will not be promoted to the channel. - -But in the output of the Replicated CLI, it shows the release was created and promoted. -``` -replicated release create --app dexter-test3 --yaml-dir ./release --release-notes "dddd" --promote replicated-test - -Creating release from files in ./release directory... - - • Reading manifests from ./release ✓ - • Creating Release ✓ - • SEQUENCE: 118 - • Promoting ✓ - • Channel 2v70WgeXccBVgLyFzKt8qmN03Ow successfully set to release 118 - -Release created and promoted to channel replicated-test -``` -It shows the release was created and promoted to the channel. But in fact, the release was not promoted to the channel when customer check the channel page. - -Improvement: -- Add a warning when the release was not promoted to the channel without the `--version` flag. - -#### 2. Replicated CLI didn't return the linting errors when using `replicated release inspect xxx`. -In the vendor portal, the release contains errors in the templates. For example, -``` -wg-easy/charts/wg-easy/templates/replicated-library.yaml -Line 13 | Error: yaml: line 13: did not find expected key -Error invalid-yaml. -``` - -When you run `replicated release inspect xxx`, it didn't return the linting errors when the release contains errors in the templates. - -But when you curl Replicated API, you can get the linting errors. -``` -"lintResult": { - "lintExpressions": [ - { - "rule": "invalid-yaml", - "type": "error", - "message": "yaml: line 13: did not find expected key", - "path": "wg-easy/charts/wg-easy/templates/replicated-library.yaml", - "positions": [ - { - "start": { - "line": 13 - } - } - ] - } - ], - "isLintingComplete": false -}, -``` - -Improvement: -- Return the linting errors when using `replicated release inspect xxx` - -#### 3. Missing `Replicated app inspect` command. -In our documentation, we have `replicated app inspect` [command](https://help.replicated.com/docs/reference/cli/replicated-app-inspect/). But when we run `replicated app inspect app-name`, it returns the error: -``` -Example: - # List all applications - replicated app ls - - # Create a new application - replicated app create "My New App" - - # View details of a specific application - replicated app inspect "My App Name" - - # Delete an application - replicated app delete "App to Remove" - - # Update an application's settings - replicated app update "My App" --channel stable - - # List applications with custom output format - replicated app ls --output json - -Available Commands: - create Create a new application - ls List applications - rm Delete an application -``` -The available commands are `create`, `ls`, `rm`, and `update`. But `inspect` is not one of them. - -Improvement: -- Add the `inspect` command to the `replicated app` command. - - From a6dc20c9ccc299e5ec0c5d4bb52d6492c4a45ab4 Mon Sep 17 00:00:00 2001 From: hedge-sparrow Date: Fri, 11 Apr 2025 10:57:31 +0100 Subject: [PATCH 19/32] Use REPLICATED_APP for app name we already have to have this set to work with the replicated CLI --- applications/wg-easy/Taskfile.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 16f6783..23fd3b6 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -5,7 +5,7 @@ includes: vars: # Application configuration - APP_NAME: '{{.APP_NAME | default "wg-easy"}}' + APP_NAME: '{{.REPLICATED_APP | default "wg-easy"}}' # Cluster configuration CLUSTER_NAME: '{{.CLUSTER_NAME | default "test-cluster"}}' From ef8b566f55b5e5b66d952ec841805b6a6f9f99fb Mon Sep 17 00:00:00 2001 From: hedge-sparrow Date: Fri, 11 Apr 2025 10:58:31 +0100 Subject: [PATCH 20/32] Consistent naming for release tasks --- applications/wg-easy/Taskfile.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 23fd3b6..1205f9c 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -177,7 +177,7 @@ tasks: fi - echo "All matching clusters deleted and kubeconfig cleaned up!" - prepare-release: + release-prepare: desc: Prepare release files by copying replicated YAML files and packaging Helm charts silent: false cmds: From 63cbc82e30dc5d431d6e2bd9742d610060623b5f Mon Sep 17 00:00:00 2001 From: hedge-sparrow Date: Fri, 11 Apr 2025 11:02:22 +0100 Subject: [PATCH 21/32] task dep --- applications/wg-easy/Taskfile.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 1205f9c..f4613f1 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -237,7 +237,7 @@ tasks: echo "Release created and promoted to channel {{.CHANNEL}}" deps: - - prepare-release + - release-prepare create-gcp-vm: desc: Create a simple GCP VM instance From bbe5982ec930aa75179ee30a6b90fbc79c978636 Mon Sep 17 00:00:00 2001 From: hedge-sparrow Date: Fri, 11 Apr 2025 11:32:10 +0100 Subject: [PATCH 22/32] update docs --- applications/wg-easy/docs/development-workflow.md | 2 +- applications/wg-easy/docs/examples.md | 4 ++-- applications/wg-easy/docs/replicated-integration.md | 6 +++--- applications/wg-easy/docs/task-reference.md | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/applications/wg-easy/docs/development-workflow.md b/applications/wg-easy/docs/development-workflow.md index a5b06fd..741ccce 100644 --- a/applications/wg-easy/docs/development-workflow.md +++ b/applications/wg-easy/docs/development-workflow.md @@ -191,7 +191,7 @@ Prepare a release package for distribution. 1. Generate release files: ```bash - task prepare-release + task release-prepare ``` 2. Inspect the generated release files: diff --git a/applications/wg-easy/docs/examples.md b/applications/wg-easy/docs/examples.md index b353408..a537a1a 100644 --- a/applications/wg-easy/docs/examples.md +++ b/applications/wg-easy/docs/examples.md @@ -69,7 +69,7 @@ kubectl get ingressroutes -A ```bash # Prepare release files -task prepare-release +task release-prepare # Create a release task release-create @@ -145,7 +145,7 @@ spec: During release preparation, these files are automatically merged: ```bash -task prepare-release +task release-prepare ``` This produces a combined `config.yaml` in the release directory with all options from both components. diff --git a/applications/wg-easy/docs/replicated-integration.md b/applications/wg-easy/docs/replicated-integration.md index d3dc168..acba761 100644 --- a/applications/wg-easy/docs/replicated-integration.md +++ b/applications/wg-easy/docs/replicated-integration.md @@ -84,17 +84,17 @@ spec: ### 4. Release Workflow -The integration with Replicated's release process is handled by the `prepare-release` and `release-create` tasks: +The integration with Replicated's release process is handled by the `release-prepare` and `release-create` tasks: ```bash # Prepare release files -task prepare-release +task release-prepare # Create and promote a release task release-create CHANNEL=Beta ``` -The `prepare-release` task: +The `release-prepare` task: 1. Copies all Replicated YAML files to a release directory 2. Merges all `config.yaml` files from different components diff --git a/applications/wg-easy/docs/task-reference.md b/applications/wg-easy/docs/task-reference.md index 7a27b28..2e45c7b 100644 --- a/applications/wg-easy/docs/task-reference.md +++ b/applications/wg-easy/docs/task-reference.md @@ -63,7 +63,7 @@ These tasks support preparing and creating releases. | Task | Description | Related Workflow Stage | |------|-------------|------------------------| -| `prepare-release` | Packages charts and merges configuration files for release | Stage 6: Release Preparation | +| `release-prepare` | Packages charts and merges configuration files for release | Stage 6: Release Preparation | | `release-create` | Creates and promotes a release using the Replicated CLI | Stage 6: Release Preparation | | `test` | Runs basic validation tests against the deployed application | Stage 5-7: Validation | @@ -72,7 +72,7 @@ TODO: The test task is a placeholder currently it just sleeps and returns positi ### Release Process Example ```bash -task prepare-release && task release-create CHANNEL=Beta +task release-prepare && task release-create CHANNEL=Beta ``` ## Automation Tasks @@ -116,7 +116,7 @@ These tasks are designed to support the progressive complexity approach: 1. **Early Stages** - Use `update-dependencies` and helm commands directly 2. **Middle Stages** - Use `create-cluster`, `deploy-helm`, and `test` -3. **Later Stages** - Use `prepare-release`, `release-create`, and embedded cluster tasks +3. **Later Stages** - Use `release-prepare`, `release-create`, and embedded cluster tasks This organization allows developers to focus on the appropriate level of complexity at each stage of development. From 855b901ca5928ba63e977a51ae801b68b659cad2 Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Mon, 14 Apr 2025 18:15:12 +1200 Subject: [PATCH 23/32] add design md to use AI for choosing right tools and start to create a development workflow --- applications/wg-easy/docs/design.md | 41 +++++++++ .../wg-easy/docs/memory_bank/tools_choose.md | 92 +++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 applications/wg-easy/docs/design.md create mode 100644 applications/wg-easy/docs/memory_bank/tools_choose.md diff --git a/applications/wg-easy/docs/design.md b/applications/wg-easy/docs/design.md new file mode 100644 index 0000000..04cffb8 --- /dev/null +++ b/applications/wg-easy/docs/design.md @@ -0,0 +1,41 @@ +# Helm Chart Design + +## Objective + +Provide a design for the Helm chart with a clear, reproducible workflow for iterative Helm chart development, testing, and promoting releases. The workflow leverages the Replicated CLI to create a release, inspect the release, and promote the release to a channel. + +## Available Tools + +- [Replicated CLI](https://help.replicated.com/docs/reference/cli/replicated/) +- [Taskfile](https://taskfile.dev/) +- [Terraform](https://www.terraform.io/) +- [just](https://github.com/casey/just) +- Bash +- [helmfile](https://github.com/helmfile/helmfile) + +## Helm Chart Components + +- **wg-easy**: The Helm chart for the wg-easy application. The Helm chart is located `applications/wg-easy/wg-easy` +- **cert-manager**: The Helm chart for the cert-manager application. The Helm chart is located `applications/cert-manager/cert-manager` +- **traefik**: The Helm chart for the traefik application. The Helm chart is located `applications/traefik/traefik` +- **replicated-sdk**: The Helm chart for the replicated-sdk application. The Helm chart is located `applications/replicated-sdk/replicated-sdk` + +## Key Principles + +- **Progressive Complexity** – Start simple, add complexity incrementally. +- **Fast Feedback** – Immediate validation of changes. +- **Reproducibility** – Simple to recreate locally. +- **Modular Configuration** – Clear separation of values per component. +- **Automation** – Minimize repetitive tasks. + +## Design Steps + +1. Review the existing Helm chart and the Replicated CLI commands. +2. Choose Best Tools based on the complexity of the Helm chart and the Replicated CLI commands. +3. Explain why we choose the tools we do and compare them to other tools. Save the decision document to `docs/memory_bank/` folder with the file name `tools_choose.md`. In the document, we should include the following information: + - Why we choose the tools we do + - Compare the chosen tools to other tools + - What are the alternatives to the chosen tools + - What are the trade-offs of the chosen tools + - What are the best practices for using the chosen tools + - What are the limitations of the chosen tools diff --git a/applications/wg-easy/docs/memory_bank/tools_choose.md b/applications/wg-easy/docs/memory_bank/tools_choose.md new file mode 100644 index 0000000..2ac6c3a --- /dev/null +++ b/applications/wg-easy/docs/memory_bank/tools_choose.md @@ -0,0 +1,92 @@ +# Tools Selection for Helm Chart Workflow + +This document explains the tools selected for our Helm chart development, testing, and release workflow, along with the rationale behind each choice. + +## Selected Tools + +### 1. Replicated CLI + +**Selected:** Yes + +**Rationale:** The Replicated CLI is essential for our workflow as it provides direct integration with the Replicated platform. It enables us to create, inspect, and promote releases, which are core requirements for our Helm chart deployment process. + +**Alternatives:** There are no direct alternatives for Replicated platform integration. + +### 2. Taskfile + +**Selected:** Yes + +**Rationale:** Taskfile provides a simple, YAML-based task runner that is cross-platform, making it ideal for orchestrating our workflow. It offers features like dependencies between tasks, custom variables, and parallel execution. Its simplicity and readability make it accessible to all team members. + +**Alternatives:** +- Make: While powerful, Make has syntax that is less intuitive and has inconsistencies across different operating systems. +- just: While similar to Taskfile, we chose Taskfile for its more extensive documentation and wider adoption. + +### 3. Bash Scripts + +**Selected:** Yes + +**Rationale:** Bash scripts are used for specific automation tasks within our workflow. They provide flexibility for custom logic and seamless integration with command-line tools. + +**Alternatives:** +- PowerShell: Less portable across different operating systems. +- Python scripts: Would introduce an additional dependency that may not be necessary for simple automation tasks. + +### 4. helmfile + +**Selected:** Yes + +**Rationale:** helmfile allows us to declaratively configure multiple Helm charts in a single file, making it easier to manage deployments of related charts (wg-easy, cert-manager, traefik, and replicated-sdk). It supports templating and environment-specific configurations, which helps maintain consistency across different environments. + +**Alternatives:** +- Plain Helm commands: Would require more manual steps and lack the declarative approach. +- Flux/ArgoCD: Too heavyweight for local development workflows. + +### 5. Terraform + +**Selected:** No + +**Rationale:** While Terraform is an excellent tool for infrastructure provisioning, our current workflow focuses primarily on application deployment using Helm charts rather than infrastructure provisioning. We may incorporate Terraform in the future if our workflow expands to include infrastructure management. + +**When it might be used:** If we need to provision cloud resources or manage infrastructure beyond Kubernetes deployments. + +## Tools Not Selected + +### 1. just + +**Why it wasn't chosen:** While 'just' is a modern command runner alternative to Make with a simpler syntax and cross-platform support, we ultimately chose Taskfile over 'just' for several reasons: + +1. **Ecosystem maturity:** Taskfile has a larger user base and more extensive documentation at this time. +2. **YAML-based configuration:** Taskfile uses YAML which is already widely used in our Kubernetes and Helm workflows, creating consistency across configuration files. +3. **Feature set:** Taskfile offers task dependencies, includes, and parallel execution in a way that better matches our specific workflow needs. +4. **Team familiarity:** More team members were already familiar with Taskfile's syntax and usage patterns. + +'just' remains a strong alternative that could be reconsidered in the future if our requirements change or if it adds features that would significantly benefit our workflow. + +### 2. Terraform + +**Why it wasn't chosen:** Terraform is a powerful infrastructure-as-code tool, but was not selected for our current Helm chart workflow for several reasons: + +1. **Scope mismatch:** Our workflow primarily focuses on application deployment via Helm charts rather than infrastructure provisioning. Terraform's core strength is managing cloud resources and infrastructure, which is beyond our current scope. + +2. **Complexity overhead:** Incorporating Terraform would add significant complexity to what is primarily an application deployment workflow. This conflicts with our key principle of "Progressive Complexity." + +3. **Deployment targets:** Our Helm charts are designed to be deployed to existing Kubernetes clusters, which don't require Terraform for management in our current workflow. + +4. **Learning curve:** Terraform has a steeper learning curve compared to the other tools in our stack, and would require additional team training for minimal immediate benefit. + +5. **State management:** Terraform's state management adds operational complexity that's unnecessary for our current deployment needs. + +Terraform would become valuable if we expand our workflow to include: +- Provisioning Kubernetes clusters on cloud providers +- Managing related infrastructure (databases, storage, networking) +- Creating complete environments from scratch +- Implementing multi-cloud deployment strategies + +We may incorporate Terraform in a future iteration as our infrastructure needs become more complex. + +## Conclusion + +Our tool selection emphasizes simplicity, cross-platform compatibility, and automation to enable a reproducible workflow for Helm chart development, testing, and releases. The combination of Taskfile for orchestration, Bash for custom logic, helmfile for managing multiple Helm charts, and the Replicated CLI for platform integration provides a balanced approach that minimizes complexity while meeting all our requirements. + +The tools were chosen based on the key principles of Progressive Complexity, Fast Feedback, Reproducibility, Modular Configuration, and Automation as outlined in our design document. From cd5ffcb4dd39663cafd699bd57b5b473fd1999d8 Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Mon, 14 Apr 2025 21:02:01 +1200 Subject: [PATCH 24/32] Remove unrelated change and update doc --- applications/wg-easy/.env | 4 ---- applications/wg-easy/Taskfile.yaml | 18 +++--------------- applications/wg-easy/docs/task-reference.md | 2 ++ 3 files changed, 5 insertions(+), 19 deletions(-) delete mode 100644 applications/wg-easy/.env diff --git a/applications/wg-easy/.env b/applications/wg-easy/.env deleted file mode 100644 index ca0275d..0000000 --- a/applications/wg-easy/.env +++ /dev/null @@ -1,4 +0,0 @@ -VERSION=0.0.4 -CHANNEL=wg-easy -APP_NAME=wg-easy -RELEASE_NOTES="Release created via task release-create" diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index aef4d45..1c1c104 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -268,7 +268,9 @@ tasks: release-create: desc: Create and promote a release using the Replicated CLI silent: false - dotenv: ['.env'] + vars: + CHANNEL: '{{.CHANNEL | default "Unstable"}}' + RELEASE_NOTES: '{{.RELEASE_NOTES | default "Release created via task release-create"}}' cmds: - echo "Creating and promoting release for $APP_NAME to channel $CHANNEL..." - | @@ -279,20 +281,6 @@ tasks: deps: - prepare-release - release-inspect: - desc: Inspect the release - silent: false - dotenv: ['.env'] - cmds: - - | - release_sequence=$(replicated channel inspect $CHANNEL --output json | jq -r '.releaseSequence') - echo "Release sequence: $release_sequence" - app_id=$(replicated app ls --output json | jq -r '.[] | select(.app.name == "'$APP_NAME'") | .app.id') - echo "App ID: $app_id" - curl -X GET "https://api.replicated.com/vendor/v3/app/$app_id/release/$release_sequence" \ - -H "Authorization: Bearer $REPLICATED_API_TOKEN" \ - -H "Content-Type: application/json" - create-gcp-vm: desc: Create a simple GCP VM instance silent: false diff --git a/applications/wg-easy/docs/task-reference.md b/applications/wg-easy/docs/task-reference.md index 7a27b28..058e312 100644 --- a/applications/wg-easy/docs/task-reference.md +++ b/applications/wg-easy/docs/task-reference.md @@ -38,6 +38,8 @@ These tasks help manage the development and testing environments. | `create-gcp-vm` | Creates a GCP VM instance for embedded cluster testing | Stage 7: Embedded Testing | | `delete-gcp-vm` | Deletes the GCP VM instance after testing | Stage 7: Cleanup | | `setup-embedded-cluster` | Sets up a Replicated embedded cluster on the GCP VM | Stage 7: Embedded Testing | +| `list-cluster` | List the test cluster with the cluster id, name, and expiration date | Stage 4: Single Chart Install | +| `verify-kubeconfig` | Verifies the kubeconfig for the test cluster | Stage 4: Single Chart Install | ### Common Environment Combinations From 56f7bb00589285ab80b96c6cb6b7267cc906821f Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Mon, 14 Apr 2025 21:06:41 +1200 Subject: [PATCH 25/32] rollback unrelated change --- applications/wg-easy/docs/design.md | 41 --------- .../wg-easy/docs/memory_bank/tools_choose.md | 92 ------------------- .../wg-easy/replicated/helmChart-wg-easy.yaml | 1 + 3 files changed, 1 insertion(+), 133 deletions(-) delete mode 100644 applications/wg-easy/docs/design.md delete mode 100644 applications/wg-easy/docs/memory_bank/tools_choose.md diff --git a/applications/wg-easy/docs/design.md b/applications/wg-easy/docs/design.md deleted file mode 100644 index 04cffb8..0000000 --- a/applications/wg-easy/docs/design.md +++ /dev/null @@ -1,41 +0,0 @@ -# Helm Chart Design - -## Objective - -Provide a design for the Helm chart with a clear, reproducible workflow for iterative Helm chart development, testing, and promoting releases. The workflow leverages the Replicated CLI to create a release, inspect the release, and promote the release to a channel. - -## Available Tools - -- [Replicated CLI](https://help.replicated.com/docs/reference/cli/replicated/) -- [Taskfile](https://taskfile.dev/) -- [Terraform](https://www.terraform.io/) -- [just](https://github.com/casey/just) -- Bash -- [helmfile](https://github.com/helmfile/helmfile) - -## Helm Chart Components - -- **wg-easy**: The Helm chart for the wg-easy application. The Helm chart is located `applications/wg-easy/wg-easy` -- **cert-manager**: The Helm chart for the cert-manager application. The Helm chart is located `applications/cert-manager/cert-manager` -- **traefik**: The Helm chart for the traefik application. The Helm chart is located `applications/traefik/traefik` -- **replicated-sdk**: The Helm chart for the replicated-sdk application. The Helm chart is located `applications/replicated-sdk/replicated-sdk` - -## Key Principles - -- **Progressive Complexity** – Start simple, add complexity incrementally. -- **Fast Feedback** – Immediate validation of changes. -- **Reproducibility** – Simple to recreate locally. -- **Modular Configuration** – Clear separation of values per component. -- **Automation** – Minimize repetitive tasks. - -## Design Steps - -1. Review the existing Helm chart and the Replicated CLI commands. -2. Choose Best Tools based on the complexity of the Helm chart and the Replicated CLI commands. -3. Explain why we choose the tools we do and compare them to other tools. Save the decision document to `docs/memory_bank/` folder with the file name `tools_choose.md`. In the document, we should include the following information: - - Why we choose the tools we do - - Compare the chosen tools to other tools - - What are the alternatives to the chosen tools - - What are the trade-offs of the chosen tools - - What are the best practices for using the chosen tools - - What are the limitations of the chosen tools diff --git a/applications/wg-easy/docs/memory_bank/tools_choose.md b/applications/wg-easy/docs/memory_bank/tools_choose.md deleted file mode 100644 index 2ac6c3a..0000000 --- a/applications/wg-easy/docs/memory_bank/tools_choose.md +++ /dev/null @@ -1,92 +0,0 @@ -# Tools Selection for Helm Chart Workflow - -This document explains the tools selected for our Helm chart development, testing, and release workflow, along with the rationale behind each choice. - -## Selected Tools - -### 1. Replicated CLI - -**Selected:** Yes - -**Rationale:** The Replicated CLI is essential for our workflow as it provides direct integration with the Replicated platform. It enables us to create, inspect, and promote releases, which are core requirements for our Helm chart deployment process. - -**Alternatives:** There are no direct alternatives for Replicated platform integration. - -### 2. Taskfile - -**Selected:** Yes - -**Rationale:** Taskfile provides a simple, YAML-based task runner that is cross-platform, making it ideal for orchestrating our workflow. It offers features like dependencies between tasks, custom variables, and parallel execution. Its simplicity and readability make it accessible to all team members. - -**Alternatives:** -- Make: While powerful, Make has syntax that is less intuitive and has inconsistencies across different operating systems. -- just: While similar to Taskfile, we chose Taskfile for its more extensive documentation and wider adoption. - -### 3. Bash Scripts - -**Selected:** Yes - -**Rationale:** Bash scripts are used for specific automation tasks within our workflow. They provide flexibility for custom logic and seamless integration with command-line tools. - -**Alternatives:** -- PowerShell: Less portable across different operating systems. -- Python scripts: Would introduce an additional dependency that may not be necessary for simple automation tasks. - -### 4. helmfile - -**Selected:** Yes - -**Rationale:** helmfile allows us to declaratively configure multiple Helm charts in a single file, making it easier to manage deployments of related charts (wg-easy, cert-manager, traefik, and replicated-sdk). It supports templating and environment-specific configurations, which helps maintain consistency across different environments. - -**Alternatives:** -- Plain Helm commands: Would require more manual steps and lack the declarative approach. -- Flux/ArgoCD: Too heavyweight for local development workflows. - -### 5. Terraform - -**Selected:** No - -**Rationale:** While Terraform is an excellent tool for infrastructure provisioning, our current workflow focuses primarily on application deployment using Helm charts rather than infrastructure provisioning. We may incorporate Terraform in the future if our workflow expands to include infrastructure management. - -**When it might be used:** If we need to provision cloud resources or manage infrastructure beyond Kubernetes deployments. - -## Tools Not Selected - -### 1. just - -**Why it wasn't chosen:** While 'just' is a modern command runner alternative to Make with a simpler syntax and cross-platform support, we ultimately chose Taskfile over 'just' for several reasons: - -1. **Ecosystem maturity:** Taskfile has a larger user base and more extensive documentation at this time. -2. **YAML-based configuration:** Taskfile uses YAML which is already widely used in our Kubernetes and Helm workflows, creating consistency across configuration files. -3. **Feature set:** Taskfile offers task dependencies, includes, and parallel execution in a way that better matches our specific workflow needs. -4. **Team familiarity:** More team members were already familiar with Taskfile's syntax and usage patterns. - -'just' remains a strong alternative that could be reconsidered in the future if our requirements change or if it adds features that would significantly benefit our workflow. - -### 2. Terraform - -**Why it wasn't chosen:** Terraform is a powerful infrastructure-as-code tool, but was not selected for our current Helm chart workflow for several reasons: - -1. **Scope mismatch:** Our workflow primarily focuses on application deployment via Helm charts rather than infrastructure provisioning. Terraform's core strength is managing cloud resources and infrastructure, which is beyond our current scope. - -2. **Complexity overhead:** Incorporating Terraform would add significant complexity to what is primarily an application deployment workflow. This conflicts with our key principle of "Progressive Complexity." - -3. **Deployment targets:** Our Helm charts are designed to be deployed to existing Kubernetes clusters, which don't require Terraform for management in our current workflow. - -4. **Learning curve:** Terraform has a steeper learning curve compared to the other tools in our stack, and would require additional team training for minimal immediate benefit. - -5. **State management:** Terraform's state management adds operational complexity that's unnecessary for our current deployment needs. - -Terraform would become valuable if we expand our workflow to include: -- Provisioning Kubernetes clusters on cloud providers -- Managing related infrastructure (databases, storage, networking) -- Creating complete environments from scratch -- Implementing multi-cloud deployment strategies - -We may incorporate Terraform in a future iteration as our infrastructure needs become more complex. - -## Conclusion - -Our tool selection emphasizes simplicity, cross-platform compatibility, and automation to enable a reproducible workflow for Helm chart development, testing, and releases. The combination of Taskfile for orchestration, Bash for custom logic, helmfile for managing multiple Helm charts, and the Replicated CLI for platform integration provides a balanced approach that minimizes complexity while meeting all our requirements. - -The tools were chosen based on the key principles of Progressive Complexity, Fast Feedback, Reproducibility, Modular Configuration, and Automation as outlined in our design document. diff --git a/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml b/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml index 28900c8..e238cc4 100644 --- a/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml +++ b/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml @@ -6,6 +6,7 @@ spec: chart: name: wg-easy chartVersion: 1.0.0 + #chartVersion: '*' weight: 3 # helmUpgradeFlags specifies additional flags to pass to the `helm upgrade` command. From 975225554af02157f0ba6fd10a6274ce32e0899a Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Mon, 14 Apr 2025 21:07:44 +1200 Subject: [PATCH 26/32] remove unrelated change --- applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml b/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml index e238cc4..4dc2141 100644 --- a/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml +++ b/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml @@ -5,7 +5,7 @@ metadata: spec: chart: name: wg-easy - chartVersion: 1.0.0 + chartVersion: '1.0.0' #chartVersion: '*' weight: 3 From 9defd37519648e4cac889d1c8ba36a303c36608f Mon Sep 17 00:00:00 2001 From: Dexter Yan Date: Mon, 14 Apr 2025 21:10:13 +1200 Subject: [PATCH 27/32] update doc --- applications/wg-easy/docs/task-reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/wg-easy/docs/task-reference.md b/applications/wg-easy/docs/task-reference.md index 058e312..5b32a52 100644 --- a/applications/wg-easy/docs/task-reference.md +++ b/applications/wg-easy/docs/task-reference.md @@ -39,7 +39,7 @@ These tasks help manage the development and testing environments. | `delete-gcp-vm` | Deletes the GCP VM instance after testing | Stage 7: Cleanup | | `setup-embedded-cluster` | Sets up a Replicated embedded cluster on the GCP VM | Stage 7: Embedded Testing | | `list-cluster` | List the test cluster with the cluster id, name, and expiration date | Stage 4: Single Chart Install | -| `verify-kubeconfig` | Verifies the kubeconfig for the test cluster | Stage 4: Single Chart Install | +| `verify-kubeconfig` | Verifies the kubeconfig for the test cluster and removes the cluster if it is expired | Stage 4: Single Chart Install | ### Common Environment Combinations From 359d678313ac59ddd054b6d17a381abd14c04094 Mon Sep 17 00:00:00 2001 From: hedge-sparrow Date: Mon, 14 Apr 2025 17:25:45 +0100 Subject: [PATCH 28/32] more - naming --- applications/wg-easy/Taskfile.yaml | 34 +++++++++---------- .../wg-easy/docs/development-workflow.md | 10 +++--- applications/wg-easy/docs/examples.md | 2 +- applications/wg-easy/docs/task-reference.md | 34 +++++++++---------- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index f4613f1..741fd45 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -33,7 +33,7 @@ tasks: cmds: - task -s --list - create-cluster: + cluster-create: desc: Create a test cluster using Replicated Compatibility Matrix (use EMBEDDED=true for embedded clusters) run: once silent: false @@ -84,9 +84,9 @@ tasks: true fi deps: - - create-cluster + - cluster-create - update-dependencies: + dependencies-update: desc: Update Helm dependencies for all charts silent: false cmds: @@ -99,7 +99,7 @@ tasks: done - echo "All dependencies updated!" - expose-ports: + ports-expose: desc: Expose configured ports and capture exposed URLs silent: false run: once @@ -126,9 +126,9 @@ tasks: vars: OPERATION: "expose" deps: - - create-cluster + - cluster-create - deploy-helm: + helm-deploy: desc: Deploy all charts using helmfile silent: false cmds: @@ -150,10 +150,10 @@ tasks: - echo "All charts deployed!" deps: - setup-kubeconfig - - expose-ports + - ports-expose - delete-cluster: + cluster-delete: desc: Delete all test clusters with matching name and clean up kubeconfig silent: false cmds: @@ -239,7 +239,7 @@ tasks: deps: - release-prepare - create-gcp-vm: + gcp-vm-create: desc: Create a simple GCP VM instance silent: false vars: @@ -260,7 +260,7 @@ tasks: GCP_IMAGE_FAMILY: '{{.GCP_IMAGE_FAMILY}}' GCP_IMAGE_PROJECT: '{{.GCP_IMAGE_PROJECT}}' - delete-gcp-vm: + gcp-vm-delete: desc: Delete the GCP VM instance for K8s and VPN silent: false status: @@ -273,14 +273,14 @@ tasks: GCP_ZONE: '{{.GCP_ZONE}}' VM_NAME: '{{.VM_NAME}}' - setup-embedded-cluster: + embedded-cluster-setup: desc: Setup Replicated embedded cluster on the GCP VM silent: false vars: CHANNEL: '{{.CHANNEL | default "Unstable"}}' AUTH_TOKEN: '{{.AUTH_TOKEN | default "2usDXzovcJNcpn54yS5tFQVNvCq"}}' deps: - - create-gcp-vm + - gcp-vm-create status: - | # Check if the application tarball has already been downloaded and extracted @@ -300,10 +300,10 @@ tasks: desc: Create cluster, get kubeconfig, expose ports, update dependencies, deploy charts, test, and delete silent: false cmds: - - task: create-cluster + - task: cluster-create - task: setup-kubeconfig - - task: expose-ports - - task: update-dependencies - - task: deploy-helm + - task: ports-expose + - task: dependencies-update + - task: helm-deploy - task: test - - task: delete-cluster + - task: cluster-delete diff --git a/applications/wg-easy/docs/development-workflow.md b/applications/wg-easy/docs/development-workflow.md index 741ccce..a457942 100644 --- a/applications/wg-easy/docs/development-workflow.md +++ b/applications/wg-easy/docs/development-workflow.md @@ -49,7 +49,7 @@ Begin by defining and verifying chart dependencies. 2. Update dependencies: ```bash - task update-dependencies + task dependencies-update # Or for a single chart: helm dependency update ./cert-manager ``` @@ -113,7 +113,7 @@ Deploy individual charts to a test cluster to verify functionality. 1. Create a test cluster if needed: ```bash - task create-cluster + task cluster-create task setup-kubeconfig ``` @@ -168,7 +168,7 @@ Test multiple charts working together using Helmfile orchestration. 2. Deploy all charts: ```bash - task deploy-helm + task helm-deploy ``` 3. Verify cross-component integration: @@ -219,13 +219,13 @@ Test the full application and configuration screen in a using an embedded cluste 1. Create a VM for testing: ```bash - task create-gcp-vm + task gcp-vm-create ``` 2. Set up an embedded cluster: ```bash - task setup-embedded-cluster + task embedded-cluster-setup ``` 3. Verify the application: diff --git a/applications/wg-easy/docs/examples.md b/applications/wg-easy/docs/examples.md index a537a1a..301753b 100644 --- a/applications/wg-easy/docs/examples.md +++ b/applications/wg-easy/docs/examples.md @@ -44,7 +44,7 @@ ls -la ./rendered-templates/cert-manager/templates/ ```bash # Create a test cluster -task create-cluster +task cluster-create task setup-kubeconfig # Install the single chart diff --git a/applications/wg-easy/docs/task-reference.md b/applications/wg-easy/docs/task-reference.md index 2e45c7b..5b15514 100644 --- a/applications/wg-easy/docs/task-reference.md +++ b/applications/wg-easy/docs/task-reference.md @@ -8,9 +8,9 @@ These tasks support the iterative development process, focusing on fast feedback | Task | Description | Related Workflow Stage | |------|-------------|------------------------| -| `update-dependencies` | Updates Helm dependencies for all charts in the repository | Stage 1: Dependencies | -| `deploy-helm` | Deploys all charts using helmfile with proper sequencing | Stage 5: Integration Testing | -| `expose-ports` | Exposes the configured ports on the cluster for testing | Stage 4-5: Chart Installation/Integration | +| `dependencies-update` | Updates Helm dependencies for all charts in the repository | Stage 1: Dependencies | +| `helm-deploy` | Deploys all charts using helmfile with proper sequencing | Stage 5: Integration Testing | +| `ports-expose` | Exposes the configured ports on the cluster for testing | Stage 4-5: Chart Installation/Integration | | `remove-k3s-traefik` | Removes pre-installed Traefik from k3s clusters to avoid conflicts | Stage 4-5: Chart Installation/Integration | ### Common Development Combinations @@ -32,18 +32,18 @@ These tasks help manage the development and testing environments. | Task | Description | Related Workflow Stage | |------|-------------|------------------------| -| `create-cluster` | Creates a test Kubernetes cluster using Replicated's Compatibility Matrix | Stage 4: Single Chart Install | +| `cluster-create` | Creates a test Kubernetes cluster using Replicated's Compatibility Matrix | Stage 4: Single Chart Install | | `setup-kubeconfig` | Retrieves and sets up the kubeconfig for the test cluster | Stage 4: Single Chart Install | -| `delete-cluster` | Deletes the test cluster and cleans up resources | Stage 4-5: Cleanup | -| `create-gcp-vm` | Creates a GCP VM instance for embedded cluster testing | Stage 7: Embedded Testing | -| `delete-gcp-vm` | Deletes the GCP VM instance after testing | Stage 7: Cleanup | -| `setup-embedded-cluster` | Sets up a Replicated embedded cluster on the GCP VM | Stage 7: Embedded Testing | +| `cluster-delete` | Deletes the test cluster and cleans up resources | Stage 4-5: Cleanup | +| `gcp-vm-create` | Creates a GCP VM instance for embedded cluster testing | Stage 7: Embedded Testing | +| `gcp-vm-delete` | Deletes the GCP VM instance after testing | Stage 7: Cleanup | +| `embedded-cluster-setup` | Sets up a Replicated embedded cluster on the GCP VM | Stage 7: Embedded Testing | ### Common Environment Combinations **Create Test Environment:** ```bash -task create-cluster && task setup-kubeconfig +task cluster-create && task setup-kubeconfig OR task setup-kubeconfig ``` @@ -52,7 +52,7 @@ While tasks can be run in order, they also have dependencies. Running the get-ku **Cleanup After Testing:** ```bash -task delete-cluster +task cluster-delete ``` Creating a cluster can take up to 5 minutes and helm charts should be uninstalled/reinstalled while developing rather than removing the entire cluster to iterate in seconds rather than minutes. @@ -100,13 +100,13 @@ Many tasks accept parameters to customize their behavior. Here are the most comm | Parameter | Used With | Description | Default | |-----------|-----------|-------------|---------| -| `CLUSTER_NAME` | `create-cluster`, `setup-kubeconfig` | Name for the cluster | "test-cluster" | -| `K8S_VERSION` | `create-cluster` | Kubernetes version | "1.32.2" | -| `DISTRIBUTION` | `create-cluster` | Cluster distribution | "k3s" | +| `CLUSTER_NAME` | `cluster-create`, `setup-kubeconfig` | Name for the cluster | "test-cluster" | +| `K8S_VERSION` | `cluster-create` | Kubernetes version | "1.32.2" | +| `DISTRIBUTION` | `cluster-create` | Cluster distribution | "k3s" | | `CHANNEL` | `release-create` | Channel to promote to | "Unstable" | | `RELEASE_NOTES` | `release-create` | Notes for the release | "" | -| `GCP_PROJECT` | `create-gcp-vm` | GCP project ID | Required | -| `GCP_ZONE` | `create-gcp-vm` | GCP zone | "us-central1-a" | +| `GCP_PROJECT` | `gcp-vm-create` | GCP project ID | Required | +| `GCP_ZONE` | `gcp-vm-create` | GCP zone | "us-central1-a" | Parameters in the Taskfile.yaml try to always have defaults so that it works out of the box but allows customization for common values. @@ -114,8 +114,8 @@ Parameters in the Taskfile.yaml try to always have defaults so that it works out These tasks are designed to support the progressive complexity approach: -1. **Early Stages** - Use `update-dependencies` and helm commands directly -2. **Middle Stages** - Use `create-cluster`, `deploy-helm`, and `test` +1. **Early Stages** - Use `dependencies-update` and helm commands directly +2. **Middle Stages** - Use `cluster-create`, `helm-deploy`, and `test` 3. **Later Stages** - Use `release-prepare`, `release-create`, and embedded cluster tasks This organization allows developers to focus on the appropriate level of complexity at each stage of development. From ee7b6d88c649d93fe3cf00dac68f049be6d765ab Mon Sep 17 00:00:00 2001 From: hedge-sparrow Date: Tue, 15 Apr 2025 14:27:35 +0100 Subject: [PATCH 29/32] scrape namespaces from helmChart resources --- applications/wg-easy/Taskfile.yaml | 4 ++++ applications/wg-easy/replicated/application.yaml | 11 ++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 741fd45..940b942 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -189,6 +189,10 @@ tasks: - echo "Copying non-config YAML files to release folder..." - find . -path '*/replicated/*.yaml' -not -name 'config.yaml' -exec cp {} ./release/ \; - find ./replicated -name '*.yaml' -not -name 'config.yaml' -exec cp {} ./release/ \; 2>/dev/null || true + + # extract namespaces from helmChart files + - yq ea '[.spec.namespace] | unique' */replicated/helmChart-*.yaml | yq '.spec.additionalNamespaces *= load("/dev/stdin") | .spec.additionalNamespaces += "*" ' replicated/application.yaml > release/application.yaml.new + - mv release/application.yaml.new release/application.yaml # Merge config.yaml files - echo "Merging config.yaml files..." diff --git a/applications/wg-easy/replicated/application.yaml b/applications/wg-easy/replicated/application.yaml index c2113d9..b9f6f1b 100644 --- a/applications/wg-easy/replicated/application.yaml +++ b/applications/wg-easy/replicated/application.yaml @@ -9,11 +9,12 @@ spec: allowRollback: true #additionalImages: # - jenkins/jenkins:lts - additionalNamespaces: - - "cert-manager" - - "traefik" - - "wg-easy" - - "*" + # additionalNamespaces should be populated by the Task file + # additionalNamespaces: + # - "cert-manager" + # - "traefik" + # - "wg-easy" + # - "*" #ports: # - serviceName: wg-easy/web # servicePort: 51821 From 4014ccf67553d322d4a2b20029a274d072700352 Mon Sep 17 00:00:00 2001 From: hedge-sparrow Date: Tue, 15 Apr 2025 15:47:06 +0100 Subject: [PATCH 30/32] remove additionalNamespaces from global appliation manifest --- applications/wg-easy/replicated/application.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/applications/wg-easy/replicated/application.yaml b/applications/wg-easy/replicated/application.yaml index b9f6f1b..0e2484e 100644 --- a/applications/wg-easy/replicated/application.yaml +++ b/applications/wg-easy/replicated/application.yaml @@ -9,12 +9,7 @@ spec: allowRollback: true #additionalImages: # - jenkins/jenkins:lts - # additionalNamespaces should be populated by the Task file - # additionalNamespaces: - # - "cert-manager" - # - "traefik" - # - "wg-easy" - # - "*" + #additionalNamespaces should be populated by the Task file #ports: # - serviceName: wg-easy/web # servicePort: 51821 From f9fdf56f0416a67c92ef1de71655f7405c3ce7c5 Mon Sep 17 00:00:00 2001 From: hedge-sparrow Date: Wed, 16 Apr 2025 16:16:40 +0100 Subject: [PATCH 31/32] Add script to automatically set helmChart versions from Chart.yaml --- applications/wg-easy/Taskfile.yaml | 3 +++ .../helmChart-cert-manager-issuers.yaml | 1 - .../replicated/helmChart-cert-manager.yaml | 1 - .../replicated/helmChart-replicated-sdk.yaml | 3 +-- .../traefik/replicated/helmChart-traefik.yaml | 1 - applications/wg-easy/versions.sh | 16 ++++++++++++++++ .../wg-easy/replicated/helmChart-wg-easy.yaml | 2 -- 7 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 applications/wg-easy/versions.sh diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index 940b942..bcfe9e1 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -193,6 +193,9 @@ tasks: # extract namespaces from helmChart files - yq ea '[.spec.namespace] | unique' */replicated/helmChart-*.yaml | yq '.spec.additionalNamespaces *= load("/dev/stdin") | .spec.additionalNamespaces += "*" ' replicated/application.yaml > release/application.yaml.new - mv release/application.yaml.new release/application.yaml + + # set helmChart versions from associated helm Chart.yaml + - bash versions.sh # Merge config.yaml files - echo "Merging config.yaml files..." diff --git a/applications/wg-easy/cert-manager-issuers/replicated/helmChart-cert-manager-issuers.yaml b/applications/wg-easy/cert-manager-issuers/replicated/helmChart-cert-manager-issuers.yaml index 3fabd0c..9b92a27 100644 --- a/applications/wg-easy/cert-manager-issuers/replicated/helmChart-cert-manager-issuers.yaml +++ b/applications/wg-easy/cert-manager-issuers/replicated/helmChart-cert-manager-issuers.yaml @@ -5,7 +5,6 @@ metadata: spec: chart: name: cert-manager-issuers - chartVersion: '1.0.0' weight: 1 helmUpgradeFlags: - --wait diff --git a/applications/wg-easy/cert-manager/replicated/helmChart-cert-manager.yaml b/applications/wg-easy/cert-manager/replicated/helmChart-cert-manager.yaml index 495eeec..94ebeb2 100644 --- a/applications/wg-easy/cert-manager/replicated/helmChart-cert-manager.yaml +++ b/applications/wg-easy/cert-manager/replicated/helmChart-cert-manager.yaml @@ -5,7 +5,6 @@ metadata: spec: chart: name: cert-manager - chartVersion: '1.0.0' weight: 0 helmUpgradeFlags: - --wait diff --git a/applications/wg-easy/replicated-sdk/replicated/helmChart-replicated-sdk.yaml b/applications/wg-easy/replicated-sdk/replicated/helmChart-replicated-sdk.yaml index ebd668c..acbc2e6 100644 --- a/applications/wg-easy/replicated-sdk/replicated/helmChart-replicated-sdk.yaml +++ b/applications/wg-easy/replicated-sdk/replicated/helmChart-replicated-sdk.yaml @@ -5,7 +5,6 @@ metadata: spec: chart: name: replicated-sdk - chartVersion: '1.0.0' weight: 1 # helmUpgradeFlags specifies additional flags to pass to the `helm upgrade` command. @@ -18,4 +17,4 @@ spec: values: {} namespace: replicated-sdk - builder: {} \ No newline at end of file + builder: {} diff --git a/applications/wg-easy/traefik/replicated/helmChart-traefik.yaml b/applications/wg-easy/traefik/replicated/helmChart-traefik.yaml index 428fcbe..74d08de 100644 --- a/applications/wg-easy/traefik/replicated/helmChart-traefik.yaml +++ b/applications/wg-easy/traefik/replicated/helmChart-traefik.yaml @@ -5,7 +5,6 @@ metadata: spec: chart: name: traefik - chartVersion: '1.0.0' weight: 2 helmUpgradeFlags: - --wait diff --git a/applications/wg-easy/versions.sh b/applications/wg-easy/versions.sh new file mode 100644 index 0000000..6beeb9f --- /dev/null +++ b/applications/wg-easy/versions.sh @@ -0,0 +1,16 @@ +#!/bin/env bash +# Set versions for helmChart resources from their associated Chart.yaml files + +set -euo pipefail + +while read directory; do + + echo $directory + parent=$(basename $(dirname $directory)) + + helmChartName="helmChart-$parent.yaml" + export version=$(yq -r '.version' $parent/Chart.yaml ) + + yq '.spec.chart.chartVersion = strenv(version) | .spec.chart.chartVersion style="single"' $directory/$helmChartName | tee release/$helmChartName + +done < <(find . -maxdepth 2 -mindepth 2 -type d -name replicated) diff --git a/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml b/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml index 4dc2141..9f5199c 100644 --- a/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml +++ b/applications/wg-easy/wg-easy/replicated/helmChart-wg-easy.yaml @@ -5,8 +5,6 @@ metadata: spec: chart: name: wg-easy - chartVersion: '1.0.0' - #chartVersion: '*' weight: 3 # helmUpgradeFlags specifies additional flags to pass to the `helm upgrade` command. From 43f1709906d9dc7462ce5c01c9ee06673882b7de Mon Sep 17 00:00:00 2001 From: hedge-sparrow Date: Wed, 16 Apr 2025 16:48:14 +0100 Subject: [PATCH 32/32] Inline version script --- applications/wg-easy/Taskfile.yaml | 14 +++++++++++++- applications/wg-easy/versions.sh | 16 ---------------- 2 files changed, 13 insertions(+), 17 deletions(-) delete mode 100644 applications/wg-easy/versions.sh diff --git a/applications/wg-easy/Taskfile.yaml b/applications/wg-easy/Taskfile.yaml index bcfe9e1..4e666c5 100644 --- a/applications/wg-easy/Taskfile.yaml +++ b/applications/wg-easy/Taskfile.yaml @@ -195,7 +195,19 @@ tasks: - mv release/application.yaml.new release/application.yaml # set helmChart versions from associated helm Chart.yaml - - bash versions.sh + - echo "Setting helmChart versions..." + - | + while read directory; do + + echo $directory + parent=$(basename $(dirname $directory)) + + helmChartName="helmChart-$parent.yaml" + export version=$(yq -r '.version' $parent/Chart.yaml ) + + yq '.spec.chart.chartVersion = strenv(version) | .spec.chart.chartVersion style="single"' $directory/$helmChartName | tee release/$helmChartName + + done < <(find . -maxdepth 2 -mindepth 2 -type d -name replicated) # Merge config.yaml files - echo "Merging config.yaml files..." diff --git a/applications/wg-easy/versions.sh b/applications/wg-easy/versions.sh deleted file mode 100644 index 6beeb9f..0000000 --- a/applications/wg-easy/versions.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/env bash -# Set versions for helmChart resources from their associated Chart.yaml files - -set -euo pipefail - -while read directory; do - - echo $directory - parent=$(basename $(dirname $directory)) - - helmChartName="helmChart-$parent.yaml" - export version=$(yq -r '.version' $parent/Chart.yaml ) - - yq '.spec.chart.chartVersion = strenv(version) | .spec.chart.chartVersion style="single"' $directory/$helmChartName | tee release/$helmChartName - -done < <(find . -maxdepth 2 -mindepth 2 -type d -name replicated)