diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 72a6e43..933e17a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -77,3 +77,26 @@ jobs: working-directory: . run: | make e2e + + helm-unit-tests: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Helm + uses: azure/setup-helm@v4.2.0 + with: + version: v3.17.0 + + - name: Install unittest plugin + run: | + helm plugin install https://github.com/helm-unittest/helm-unittest + + - name: Chart init + run: | + make helm-version + + - name: Run helm unit tests + run: | + make helm-test diff --git a/Makefile b/Makefile index 835e14c..900a623 100644 --- a/Makefile +++ b/Makefile @@ -193,6 +193,12 @@ helm-install: helm-version helm-publish: helm-version helm push $(HELM_DIST_FOLDER)/kagent-tools-$(VERSION).tgz $(HELM_REPO)/tools/helm +.PHONY: helm-test +helm-test: helm-version + mkdir -p tmp + helm plugin ls | grep unittest || helm plugin install https://github.com/helm-unittest/helm-unittest.git + helm unittest helm/kagent-tools + .PHONY: create-kind-cluster create-kind-cluster: docker pull kindest/node:v$(KIND_IMAGE_VERSION) || true diff --git a/helm/kagent-tools/templates/deployment.yaml b/helm/kagent-tools/templates/deployment.yaml index 48ac0d7..ec8b8a8 100644 --- a/helm/kagent-tools/templates/deployment.yaml +++ b/helm/kagent-tools/templates/deployment.yaml @@ -23,6 +23,32 @@ spec: imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + affinity: + {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- range . }} + - {{ toYaml . | nindent 10 | trim }} + {{- if not (hasKey . "labelSelector") }} + labelSelector: + matchLabels: + {{- include "kagent.selectorLabels" $ | nindent 14 }} + {{- end }} + {{- end }} + {{- end }} + + securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} serviceAccountName: {{ include "kagent.fullname" . }} diff --git a/helm/kagent-tools/tests/deployment_test.yaml b/helm/kagent-tools/tests/deployment_test.yaml new file mode 100644 index 0000000..397fd41 --- /dev/null +++ b/helm/kagent-tools/tests/deployment_test.yaml @@ -0,0 +1,142 @@ +suite: test controller deployment +templates: + - deployment.yaml +tests: + - it: should render deployment with default values + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: metadata.name + value: RELEASE-NAME + - equal: + path: spec.replicas + value: 1 + - hasDocuments: + count: 1 + + - it: should render deployment with custom replica count + template: deployment.yaml + set: + replicaCount: 3 + asserts: + - equal: + path: spec.replicas + value: 3 + + - it: should have correct container image + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].name + value: tools + pattern: "^cr\\.kagent\\.dev/kagent-dev/kagent/tools:.+" + + - it: should use global tag when set + template: deployment.yaml + set: + tools: + image: + tag: "v1.0.0" + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: ghcr.io/kagent-dev/kagent/tools:v1.0.0 + + - it: should have correct resources + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].resources.requests.cpu + value: 100m + - equal: + path: spec.template.spec.containers[0].resources.requests.memory + value: 128Mi + - equal: + path: spec.template.spec.containers[0].resources.limits.cpu + value: 1000m + - equal: + path: spec.template.spec.containers[0].resources.limits.memory + value: 512Mi + + - it: should have correct service account name + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: RELEASE-NAME + + - it: should have correct container port + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].ports[0].containerPort + value: 8084 + + - it: should set nodeSelector + set: + nodeSelector: + role: AI + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + role: AI + + - it: should set tolerations + set: + tolerations: + - key: role + operator: Equal + value: AI + effect: NoSchedule + asserts: + - contains: + any: true + path: spec.template.spec.tolerations + content: + key: role + value: AI + effect: NoSchedule + operator: Equal + + - it: should render custom node affinity from values + set: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/e2e-az-name + operator: In + values: + - e2e-az1 + asserts: + - equal: + path: spec.template.spec.affinity + value: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/e2e-az-name + operator: In + values: + - e2e-az1 + + - it: should render topologySpreadConstraints with labelSelector fallback + set: + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: zone + whenUnsatisfiable: ScheduleAnyway + asserts: + - equal: + path: spec.template.spec.topologySpreadConstraints[0].topologyKey + value: zone + - equal: + path: spec.template.spec.topologySpreadConstraints[0].labelSelector.matchLabels + value: + app.kubernetes.io/name: kagent-tools + app.kubernetes.io/instance: RELEASE-NAME diff --git a/helm/kagent-tools/values.yaml b/helm/kagent-tools/values.yaml index 6d68f55..40262a7 100644 --- a/helm/kagent-tools/values.yaml +++ b/helm/kagent-tools/values.yaml @@ -50,6 +50,29 @@ securityContext: {} # readOnlyRootFilesystem: true # runAsNonRoot: true # runAsUser: 1000 + +# Node taints which will be tolerated for Pod. +tolerations: [] + +# Node labels to match for Pod. +nodeSelector: {} + +# Affinity settings for Pod. +affinity: {} +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: kubernetes.io/e2e-az-name +# operator: In +# values: +# - e2e-az1 + +# Topology spread constraints for Pod. +topologySpreadConstraints: [] +# - maxSkew: 1 +# topologyKey: topology.kubernetes.io/zone +# whenUnsatisfiable: DoNotSchedule otel: tracing: