suite: ControlPlane StatefulSet templates: - statefulset.yaml tests: - it: should not create control-plane set: experimental: isolatedControlPlane: headless: true asserts: - hasDocuments: count: 0 - it: image name set: controlPlane: statefulSet: image: registry: "custom-registry.com" asserts: - equal: path: spec.template.spec.containers[0].image value: custom-registry.com/loft-sh/vcluster-pro:0.0.1 - it: defaultImageRegistry set: controlPlane: advanced: defaultImageRegistry: docker.io asserts: - equal: path: spec.template.spec.containers[0].image value: docker.io/loft-sh/vcluster-pro:0.0.1 - it: custom tag set: controlPlane: statefulSet: image: repository: my-repo tag: "custom-tag" asserts: - equal: path: spec.template.spec.containers[0].image value: ghcr.io/my-repo:custom-tag - it: custom init container set: controlPlane: distro: k3s: enabled: true image: registry: "ghcr.io" repository: "test" tag: "123" asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/test:123 - it: disables serviceLinks for sts etcd pod set: controlPlane: statefulSet: enableServiceLinks: false asserts: - equal: path: spec.template.spec.enableServiceLinks value: false - it: custom init container set: controlPlane: distro: k8s: enabled: true image: registry: "" repository: "k8s-api" tag: "456" asserts: - equal: path: spec.template.spec.initContainers[0].image value: k8s-api:456 - it: custom init container set: controlPlane: distro: k8s: enabled: true image: repository: "k8s-controller" tag: "123" advanced: defaultImageRegistry: "bbb.com" asserts: - equal: path: spec.template.spec.initContainers[0].image value: bbb.com/k8s-controller:123 - it: name & defaults release: name: my-release namespace: my-namespace capabilities: majorVersion: 1 minorVersion: 29 asserts: - hasDocuments: count: 1 - equal: path: kind value: StatefulSet - lengthEqual: path: spec.template.spec.containers count: 1 - equal: path: spec.template.spec.containers[0].image value: ghcr.io/loft-sh/vcluster-pro:0.0.1 - contains: path: spec.template.spec.containers[0].env content: name: VCLUSTER_NAME value: my-release - contains: path: spec.template.spec.containers[0].volumeMounts content: name: data mountPath: /data - contains: path: spec.template.spec.containers[0].volumeMounts content: name: binaries mountPath: /binaries - contains: path: spec.template.spec.containers[0].volumeMounts content: name: certs mountPath: /pki - contains: path: spec.template.spec.containers[0].volumeMounts content: name: helm-cache mountPath: /.cache/helm - equal: path: metadata.name value: my-release - equal: path: metadata.namespace value: my-namespace - equal: path: spec.podManagementPolicy value: Parallel - equal: path: spec.persistentVolumeClaimRetentionPolicy.whenDeleted value: Retain - equal: path: spec.replicas value: 1 - equal: path: spec.template.metadata.labels.app value: vcluster - equal: path: spec.template.spec.terminationGracePeriodSeconds value: 10 - equal: path: spec.volumeClaimTemplates[0].spec.accessModes[0] value: ReadWriteOnce - equal: path: spec.volumeClaimTemplates[0].spec.resources.requests.storage value: 5Gi - it: fail when both backing stores are enabled set: controlPlane: backingStore: etcd: embedded: enabled: true deploy: enabled: true asserts: - failedTemplate: errorMessage: "you can only enable one backingStore at the same time" - it: not persistent when external etcd is enabled set: controlPlane: backingStore: etcd: deploy: enabled: true asserts: - equal: path: kind value: Deployment - notExists: path: spec.volumeClaimTemplates - it: not persistent when k8s and external database set: controlPlane: distro: k8s: enabled: true backingStore: database: external: enabled: true asserts: - equal: path: kind value: Deployment - notExists: path: spec.volumeClaimTemplates - it: persistent when embedded database set: controlPlane: distro: k8s: enabled: true backingStore: database: embedded: enabled: true asserts: - equal: path: kind value: StatefulSet - lengthEqual: path: spec.volumeClaimTemplates count: 1 - it: persistent when k8s and embedded etcd set: controlPlane: backingStore: etcd: embedded: enabled: true distro: k8s: enabled: true asserts: - equal: path: kind value: StatefulSet - lengthEqual: path: spec.volumeClaimTemplates count: 1 - it: persistent when embedded database asserts: - equal: path: kind value: StatefulSet - lengthEqual: path: spec.volumeClaimTemplates count: 1 - it: plugin 1 set: plugins: test: image: test plugin: test123: version: v2 image: test asserts: - lengthEqual: path: spec.template.spec.volumes count: 6 - lengthEqual: path: spec.template.spec.initContainers count: 3 - it: plugin volumes 2 set: controlPlane: distro: k8s: enabled: true plugin: test: version: v2 image: test asserts: - equal: path: kind value: StatefulSet - lengthEqual: path: spec.template.spec.volumes count: 6 - lengthEqual: path: spec.template.spec.initContainers count: 2 - it: plugin volumes 3 set: plugin: test: image: test asserts: - lengthEqual: path: spec.template.spec.volumes count: 5 - lengthEqual: path: spec.template.spec.initContainers count: 1 - it: add volumes set: controlPlane: distro: k3s: enabled: true statefulSet: persistence: addVolumes: - name: myVolume asserts: - contains: path: spec.template.spec.volumes content: name: myVolume - lengthEqual: path: spec.template.spec.volumes count: 7 - it: add templated volumes set: controlPlane: distro: k3s: enabled: true statefulSet: persistence: addVolumes: - name: '{{ .Release.Name }}-myVolume' asserts: - contains: path: spec.template.spec.volumes content: name: RELEASE-NAME-myVolume - lengthEqual: path: spec.template.spec.volumes count: 7 - it: enable k8s set: controlPlane: distro: k8s: enabled: true asserts: - equal: path: kind value: StatefulSet - lengthEqual: path: spec.volumeClaimTemplates count: 1 - it: enable k8s with deploy etcd set: controlPlane: distro: k8s: enabled: true backingStore: etcd: deploy: enabled: true asserts: - equal: path: kind value: Deployment - notExists: path: spec.volumeClaimTemplates - contains: path: spec.template.spec.volumes content: name: data emptyDir: {} - it: enable k8s release: name: my-release namespace: my-namespace set: controlPlane: distro: k8s: enabled: true statefulSet: persistence: volumeClaim: enabled: false volumeClaimTemplates: - metadata: name: data spec: resources: requests: storage: 5Gi asserts: - equal: path: kind value: StatefulSet - equal: path: spec.serviceName value: my-release-headless - contains: path: spec.volumeClaimTemplates content: metadata: name: data spec: resources: requests: storage: 5Gi - it: enable k8s set: controlPlane: distro: k8s: enabled: true release: name: my-release namespace: my-namespace asserts: - equal: path: kind value: StatefulSet - equal: path: spec.serviceName value: my-release-headless - lengthEqual: path: spec.volumeClaimTemplates count: 1 - it: enable k8s with deploy etcd set: controlPlane: distro: k8s: enabled: true backingStore: etcd: deploy: enabled: true asserts: - equal: path: kind value: Deployment - notExists: path: spec.volumeClaimTemplates - contains: path: spec.template.spec.volumes content: name: data emptyDir: {} - it: append distro env set: controlPlane: distro: k3s: enabled: true env: - name: KEY value: VALUE asserts: - equal: path: kind value: StatefulSet - contains: path: spec.template.spec.containers[0].env content: name: KEY value: VALUE - it: should correctly set labels on the statefulset set: controlPlane: statefulSet: labels: my-label: my-value asserts: - equal: path: kind value: StatefulSet - equal: path: metadata.labels["my-label"] value: "my-value" - it: binariesVolume - should set to emptyDir by default asserts: - contains: path: spec.template.spec.volumes content: name: binaries emptyDir: {} - it: binariesVolume - should set the specified volume type correctly set: controlPlane: statefulSet: persistence: binariesVolume: - name: binaries persistentVolumeClaim: claimName: my-pvc asserts: - contains: path: spec.template.spec.volumes content: name: binaries persistentVolumeClaim: claimName: my-pvc - it: dataVolume - should set the specified data volume type correctly set: controlPlane: statefulSet: persistence: dataVolume: - name: data persistentVolumeClaim: claimName: my-custom-pvc asserts: - contains: path: spec.template.spec.volumes content: name: data persistentVolumeClaim: claimName: my-custom-pvc - it: k8s version not set, default tag images used for apiServer and controllerManager set: controlPlane: distro: k8s: enabled: true asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.33.1 - it: k8s override image tag set: controlPlane: distro: k8s: enabled: true image: tag: v99912 asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v99912 - it: k8s version sets image tag for apiServer and controllerManager set: controlPlane: distro: k8s: enabled: true version: v1.35.999 asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.35.999 - it: k8s version set and not overridden by image tag set: controlPlane: distro: k8s: enabled: true version: v1.30.999 image: tag: v99912 asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.30.999 - it: k8s not version set but image tags for apiServer and controllerManager set set: controlPlane: distro: k8s: enabled: true image: tag: v99914 asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v99914 - it: k8s version not set, default tag images used for apiServer and controllerManager (virtual scheduler enabled) chart: version: "test-" set: controlPlane: distro: k8s: enabled: true scheduler: enabled: true asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.33.1 - it: k8s version not set, default tag images used for apiServer and controllerManager (virtual scheduler enabled, deprecated) chart: version: "test-" set: controlPlane: distro: k8s: enabled: true advanced: virtualScheduler: enabled: true asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.33.1 - it: k8s version sets image tag for apiServer and controllerManager (virtual scheduler enabled) set: controlPlane: distro: k8s: enabled: true version: v1.35.999 scheduler: enabled: true asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.35.999 - it: k8s version sets image tag for apiServer and controllerManager (virtual scheduler enabled, deprecated) set: controlPlane: distro: k8s: enabled: true version: v1.35.999 advanced: virtualScheduler: enabled: true asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.35.999 - it: k8s version set but not overridden by image tag for apiServer and controllerManager (virtual scheduler enabled) set: controlPlane: distro: k8s: enabled: true version: v1.30.999 image: tag: v99912 scheduler: enabled: true asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.30.999 - it: k8s version set but not overridden by image tag for apiServer and controllerManager (virtual scheduler enabled, deprecated) set: controlPlane: distro: k8s: enabled: true version: v1.30.999 image: tag: v99912 advanced: virtualScheduler: enabled: true asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.30.999 - it: custom dnsPolicy set: controlPlane: statefulSet: dnsPolicy: "ClusterFirst" asserts: - equal: path: spec.template.spec.dnsPolicy value: "ClusterFirst" - it: custom dnsConfig set: controlPlane: statefulSet: dnsConfig: nameservers: - 192.0.2.1 searches: - ns1.svc.cluster-domain.example options: - name: ndots value: "2" asserts: - equal: path: spec.template.spec.dnsConfig.nameservers[0] value: "192.0.2.1" - equal: path: spec.template.spec.dnsConfig.searches[0] value: "ns1.svc.cluster-domain.example" - equal: path: spec.template.spec.dnsConfig.options[0].name value: "ndots" - equal: path: spec.template.spec.dnsConfig.options[0].value value: "2" - it: must use StatefulSet for embedded etcd set: controlPlane: backingStore: etcd: embedded: enabled: true asserts: - equal: path: kind value: StatefulSet - it: must use StatefulSet for embedded etcd without persistence set: controlPlane: backingStore: etcd: embedded: enabled: true statefulSet: persistence: volumeClaim: enabled: false binariesVolume: - name: binaries emptyDir: medium: Memory asserts: - equal: path: kind value: StatefulSet - it: sync custom resources set: sync: toHost: customResources: test.cert-manager.io: enabled: true patches: - path: spec.dnsNames[*] expression: "value.startsWith('www.') ? value.slice(4) : value" reverseExpression: '"www."+value' asserts: - equal: path: kind value: StatefulSet - it: fails when you set both exportKubeConfig.secret and exportKubeConfig.additionalSecrets set: exportKubeConfig: secret: name: my-secret additionalSecrets: - name: another-secret asserts: - failedTemplate: errorMessage: "exportKubeConfig.secret and exportKubeConfig.additionalSecrets cannot be set at the same time" - it: fails when additional secret does not have at least name or namespace set: exportKubeConfig: additionalSecrets: - name: my-secret context: my-context - server: my-server asserts: - failedTemplate: errorMessage: "additional secret must have name and/or namespace set, found: {\"server\":\"my-server\"}" - it: must use Deployment for external etcd set: controlPlane: backingStore: etcd: external: enabled: true asserts: - equal: path: kind value: Deployment - it: private nodes k8s full image set: controlPlane: distro: k8s: image: tag: v1.35.999 privateNodes: enabled: true asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.35.999-full - it: private nodes k8s full image version set: controlPlane: distro: k8s: version: v1.35.999 privateNodes: enabled: true asserts: - equal: path: spec.template.spec.initContainers[0].image value: ghcr.io/loft-sh/kubernetes:v1.35.999-full - it: sets custom probe configuration set: controlPlane: statefulSet: probes: livenessProbe: enabled: true failureThreshold: 70 initialDelaySeconds: 70 timeoutSeconds: 10 periodSeconds: 9 readinessProbe: enabled: true failureThreshold: 70 timeoutSeconds: 6 periodSeconds: 8 startupProbe: enabled: true failureThreshold: 350 timeoutSeconds: 7 periodSeconds: 8 asserts: - equal: path: spec.template.spec.containers[0].livenessProbe.failureThreshold value: 70 - equal: path: spec.template.spec.containers[0].livenessProbe.initialDelaySeconds value: 70 - equal: path: spec.template.spec.containers[0].livenessProbe.timeoutSeconds value: 10 - equal: path: spec.template.spec.containers[0].livenessProbe.periodSeconds value: 9 - equal: path: spec.template.spec.containers[0].readinessProbe.failureThreshold value: 70 - equal: path: spec.template.spec.containers[0].readinessProbe.timeoutSeconds value: 6 - equal: path: spec.template.spec.containers[0].readinessProbe.periodSeconds value: 8 - equal: path: spec.template.spec.containers[0].startupProbe.failureThreshold value: 350 - equal: path: spec.template.spec.containers[0].startupProbe.timeoutSeconds value: 7 - equal: path: spec.template.spec.containers[0].startupProbe.periodSeconds value: 8 - it: uses default probe values when none are overridden set: controlPlane: statefulSet: probes: livenessProbe: enabled: true readinessProbe: enabled: true startupProbe: enabled: true asserts: - equal: path: spec.template.spec.containers[0].livenessProbe.initialDelaySeconds value: 60 - equal: path: spec.template.spec.containers[0].livenessProbe.periodSeconds value: 2 - equal: path: spec.template.spec.containers[0].livenessProbe.timeoutSeconds value: 3 - equal: path: spec.template.spec.containers[0].livenessProbe.failureThreshold value: 60 - equal: path: spec.template.spec.containers[0].readinessProbe.periodSeconds value: 2 - equal: path: spec.template.spec.containers[0].readinessProbe.timeoutSeconds value: 3 - equal: path: spec.template.spec.containers[0].readinessProbe.failureThreshold value: 60 - equal: path: spec.template.spec.containers[0].startupProbe.periodSeconds value: 6 - equal: path: spec.template.spec.containers[0].startupProbe.timeoutSeconds value: 3 - equal: path: spec.template.spec.containers[0].startupProbe.failureThreshold value: 300 - it: should set logging format to json set: logging: encoding: json asserts: - equal: path: spec.template.spec.containers[0].env[?(@.name=="LOFT_LOG_ENCODING")].value value: json - it: should set default logging format to console asserts: - equal: path: spec.template.spec.containers[0].env[?(@.name=="LOFT_LOG_ENCODING")].value value: console