apiVersion: troubleshoot.sh/v1beta3
kind: Preflight
metadata:
  name: templated-from-v1beta2
spec:
  analyzers:
    {{- if .Values.kubernetes.enabled }}
    - docString: |
        Title: Kubernetes Control Plane Requirements
        Requirement:
          - Version:
            - Minimum: {{ .Values.kubernetes.minVersion }}
            - Recommended: {{ .Values.kubernetes.recommendedVersion }}
          - Docs: https://kubernetes.io
        These version targets ensure that required APIs and default behaviors are
          available and patched. Moving below the minimum commonly removes GA APIs
          (e.g., apps/v1 workloads, storage and ingress v1 APIs), changes admission
          defaults, and lacks critical CVE fixes. Running at or above the recommended
          version matches what is exercised most extensively in CI and receives the
          best operational guidance for upgrades and incident response.
      clusterVersion:
        checkName: Kubernetes version
        outcomes:
          - fail:
              when: '< {{ .Values.kubernetes.minVersion }}'
              message: This application requires at least Kubernetes {{ .Values.kubernetes.minVersion }}, and recommends {{ .Values.kubernetes.recommendedVersion }}.
              uri: https://www.kubernetes.io
          - warn:
              when: '< {{ .Values.kubernetes.recommendedVersion }}'
              message: Your cluster meets the minimum version of Kubernetes, but we recommend you update to {{ .Values.kubernetes.recommendedVersion }} or later.
              uri: https://kubernetes.io
          - pass:
              when: '>= {{ .Values.kubernetes.recommendedVersion }}'
              message: Your cluster meets the recommended and required versions of Kubernetes.
    {{- end }}
    {{- if .Values.ingress.enabled }}
    - docString: |
        Title: Required CRDs and Ingress Capabilities
        Requirement:
          - Ingress Controller: Contour
          - CRD must be present:
            - Group: heptio.com
            - Kind: IngressRoute
            - Version: v1beta1 or later served version
        The ingress layer terminates TLS and routes external traffic to Services.
          Contour relies on the IngressRoute CRD to express host/path routing, TLS
          configuration, and policy. If the CRD is not installed and served by the
          API server, Contour cannot reconcile desired state, leaving routes
          unconfigured and traffic unreachable.
      {{- if eq .Values.ingress.type "Contour" }}
      customResourceDefinition:
        checkName: Contour IngressRoute CRD
        customResourceDefinitionName: ingressroutes.contour.heptio.com
        outcomes:
          - fail:
              message: Contour IngressRoute CRD not found; required for ingress routing
          - pass:
              message: Contour IngressRoute CRD present
      {{- end }}
    {{- end }}
    {{- if .Values.runtime.enabled }}
    - docString: |
        Title: Container Runtime Requirements
        Requirement:
          - Runtime: containerd (CRI)
          - Kubelet cgroup driver: systemd
          - CRI socket path: /run/containerd/containerd.sock
        containerd (via the CRI) is the supported runtime for predictable container
          lifecycle management. On modern distros (cgroup v2), kubelet and the OS must
          both use the systemd cgroup driver to avoid resource accounting mismatches
          that lead to unexpected OOMKills and throttling. The CRI socket path must
          match kubelet configuration so the node can start and manage pods.
      containerRuntime:
        outcomes:
          - pass:
              when: '== containerd'
              message: containerd runtime detected
          - fail:
              message: Unsupported container runtime; containerd required
    {{- end }}
    {{- if .Values.storage.enabled }}
    - docString: |
        Title: Default StorageClass Requirements
        Requirement:
          - A StorageClass named "{{ .Values.storage.className }}" must exist (cluster default preferred)
          - AccessMode: ReadWriteOnce (RWO) required (RWX optional)
          - VolumeBindingMode: WaitForFirstConsumer preferred
          - allowVolumeExpansion: true recommended
        A default StorageClass enables dynamic PVC provisioning without manual
          intervention. RWO provides baseline persistence semantics for stateful pods.
          WaitForFirstConsumer defers binding until a pod is scheduled, improving
          topology-aware placement (zonal/az) and reducing unschedulable PVCs.
          AllowVolumeExpansion permits online growth during capacity pressure
          without disruptive migrations.
      storageClass:
        checkName: Default StorageClass
        storageClassName: '{{ .Values.storage.className }}'
        outcomes:
          - fail:
              message: Default StorageClass not found
          - pass:
              message: Default StorageClass present
    {{- end }}
    {{- if .Values.distribution.enabled }}
    - docString: |
        Title: Kubernetes Distribution Support
        Requirement:
          - Unsupported: docker-desktop, microk8s, minikube
          - Supported: eks, gke, aks, kurl, digitalocean, rke2, k3s, oke, kind
        Development or single-node environments are optimized for local testing and
          omit HA control-plane patterns, cloud integration, and production defaults.
          The supported distributions are validated for API compatibility, RBAC
          expectations, admission behavior, and default storage/networking this
          application depends on.
      distribution:
        outcomes:
          - fail:
              when: '== docker-desktop'
              message: The application does not support Docker Desktop Clusters
          - fail:
              when: '== microk8s'
              message: The application does not support Microk8s Clusters
          - fail:
              when: '== minikube'
              message: The application does not support Minikube Clusters
          - pass:
              when: '== eks'
              message: EKS is a supported distribution
          - pass:
              when: '== gke'
              message: GKE is a supported distribution
          - pass:
              when: '== aks'
              message: AKS is a supported distribution
          - pass:
              when: '== kurl'
              message: KURL is a supported distribution
          - pass:
              when: '== digitalocean'
              message: DigitalOcean is a supported distribution
          - pass:
              when: '== rke2'
              message: RKE2 is a supported distribution
          - pass:
              when: '== k3s'
              message: K3S is a supported distribution
          - pass:
              when: '== oke'
              message: OKE is a supported distribution
          - pass:
              when: '== kind'
              message: Kind is a supported distribution
          - warn:
              message: Unable to determine the distribution of Kubernetes
    {{- end }}
    {{- if .Values.nodeChecks.count.enabled }}
    - docString: |
        Title: Node count requirement
        Requirement:
          - Node count: Minimum {{ .Values.cluster.minNodes }} nodes, Recommended {{ .Values.cluster.recommendedNodes }} nodes
        Multiple worker nodes provide scheduling capacity, tolerance to disruptions,
          and safe rolling updates. Operating below the recommendation increases risk
          of unschedulable pods during maintenance or failures and reduces headroom
          for horizontal scaling.
      nodeResources:
        checkName: Node count
        outcomes:
          - fail:
              when: 'count() < {{ .Values.cluster.minNodes }}'
              message: This application requires at least {{ .Values.cluster.minNodes }} nodes.
              uri: https://kurl.sh/docs/install-with-kurl/adding-nodes
          - warn:
              when: 'count() < {{ .Values.cluster.recommendedNodes }}'
              message: This application recommends at least {{ .Values.cluster.recommendedNodes }} nodes.
              uri: https://kurl.sh/docs/install-with-kurl/adding-nodes
          - pass:
              message: This cluster has enough nodes.
    {{- end }}
    {{- if .Values.nodeChecks.cpu.enabled }}
    - docString: |
        Title: Cluster CPU requirement
        Requirement:
          - Total CPU: Minimum {{ .Values.cluster.minCPU }} vCPU
        Aggregate CPU must cover system daemons, controllers, and application pods.
          Insufficient CPU causes prolonged scheduling latency, readiness probe
          failures, and throughput collapse under load.
      nodeResources:
        checkName: Cluster CPU total
        outcomes:
          - fail:
              when: 'sum(cpuCapacity) < {{ .Values.cluster.minCPU }}'
              message: The cluster must contain at least {{ .Values.cluster.minCPU }} cores
              uri: https://kurl.sh/docs/install-with-kurl/system-requirements
          - pass:
              message: There are at least {{ .Values.cluster.minCPU }} cores in the cluster
    {{- end }}
    {{- if .Values.nodeChecks.memory.enabled }}
    - docString: |
        Title: Per-node memory requirement
        Requirement:
          - Per-node memory: Minimum {{ .Values.node.minMemoryGi }} GiB; Recommended {{ .Values.node.recommendedMemoryGi }} GiB
        Nodes must reserve memory for kubelet/system components and per-pod overhead.
          Below the minimum, pods will frequently be OOMKilled or evicted. The
          recommended capacity provides headroom for spikes, compactions, and
          upgrades without destabilizing workloads.
      nodeResources:
        checkName: Per-node memory requirement
        outcomes:
          - fail:
              when: 'min(memoryCapacity) < {{ .Values.node.minMemoryGi }}Gi'
              message: All nodes must have at least {{ .Values.node.minMemoryGi }} GiB of memory.
              uri: https://kurl.sh/docs/install-with-kurl/system-requirements
          - warn:
              when: 'min(memoryCapacity) < {{ .Values.node.recommendedMemoryGi }}Gi'
              message: All nodes are recommended to have at least {{ .Values.node.recommendedMemoryGi }} GiB of memory.
              uri: https://kurl.sh/docs/install-with-kurl/system-requirements
          - pass:
              message: All nodes have at least {{ .Values.node.recommendedMemoryGi }} GiB of memory.
    {{- end }}
    {{- if .Values.nodeChecks.ephemeral.enabled }}
    - docString: |
        Title: Per-node ephemeral storage requirement
        Requirement:
          - Per-node ephemeral storage: Minimum {{ .Values.node.minEphemeralGi }} GiB; Recommended {{ .Values.node.recommendedEphemeralGi }} GiB
        Ephemeral storage backs image layers, writable container filesystems, logs,
          and temporary data. When capacity is low, kubelet enters disk-pressure
          eviction and image pulls fail, causing pod restarts and data loss for
          transient files.
      nodeResources:
        checkName: Per-node ephemeral storage requirement
        outcomes:
          - fail:
              when: 'min(ephemeralStorageCapacity) < {{ .Values.node.minEphemeralGi }}Gi'
              message: All nodes must have at least {{ .Values.node.minEphemeralGi }} GiB of ephemeral storage.
              uri: https://kurl.sh/docs/install-with-kurl/system-requirements
          - warn:
              when: 'min(ephemeralStorageCapacity) < {{ .Values.node.recommendedEphemeralGi }}Gi'
              message: All nodes are recommended to have at least {{ .Values.node.recommendedEphemeralGi }} GiB of ephemeral storage.
              uri: https://kurl.sh/docs/install-with-kurl/system-requirements
          - pass:
              message: All nodes have at least {{ .Values.node.recommendedEphemeralGi }} GiB of ephemeral storage.
    {{- end }}


