diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1a87c89..396aaa8 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -18,10 +18,11 @@ jobs: run: | git config user.name "$GITHUB_ACTOR" git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + - name: Install Helm - uses: azure/setup-helm@v1 + uses: azure/setup-helm@v3 with: - version: v3.4.0 + version: v3.11.0 - name: Run chart-releaser uses: helm/chart-releaser-action@v1.1.0 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..e41d1aa --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,34 @@ +name: Run tests + +on: + push: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Install Helm + uses: azure/setup-helm@v3 + with: + version: v3.11.0 + + - name: Install helm-unittest + run: | + helm plugin install https://github.com/helm-unittest/helm-unittest.git + + - name: Run tests + run: | + helm unittest charts/* -o test-report.xml -t junit + + - name: Test report + uses: dorny/test-reporter@v1 + if: success() || failure() + with: + name: test report + path: test-report.xml + reporter: java-junit diff --git a/charts/simple-app/CHANGELOG.md b/charts/simple-app/CHANGELOG.md index 175bf66..cb9e3b2 100644 --- a/charts/simple-app/CHANGELOG.md +++ b/charts/simple-app/CHANGELOG.md @@ -1,3 +1,14 @@ +# 0.10.0 + +## Backwards incompatibility + +* Default names for all resources equal to release name +* Delete `Values.probe`. `livenessProbe` and `readinessProbe` import from values file +* Rename `.service.port` -> `.servicePort`, `.service.type` -> `.serviceType` +* Rename `.servicePorts` -> `.extraPorts` +* Add `.extraPorts[*].servicePort` config + + # 0.9.1 * Add support for `.initialDelaySeconds` in `livenessProbe` and `readinessProbe` diff --git a/charts/simple-app/Chart.yaml b/charts/simple-app/Chart.yaml index 0ad3402..3f19335 100644 --- a/charts/simple-app/Chart.yaml +++ b/charts/simple-app/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: "0.9.1" +version: "0.10.0" # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/simple-app/Makefile b/charts/simple-app/Makefile new file mode 100644 index 0000000..5a62a8a --- /dev/null +++ b/charts/simple-app/Makefile @@ -0,0 +1,4 @@ +# helm plugin install https://github.com/helm-unittest/helm-unittest.git + +test: + helm unittest . diff --git a/charts/simple-app/templates/_helpers.tpl b/charts/simple-app/templates/_helpers.tpl index f4677b2..c4aca7a 100644 --- a/charts/simple-app/templates/_helpers.tpl +++ b/charts/simple-app/templates/_helpers.tpl @@ -14,12 +14,7 @@ If release name contains chart name it will be used as a full name. {{- if .Values.fullnameOverride }} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} {{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} {{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} {{- end }} {{- end }} diff --git a/charts/simple-app/templates/deployment.yaml b/charts/simple-app/templates/deployment.yaml index f0291fe..9b15866 100644 --- a/charts/simple-app/templates/deployment.yaml +++ b/charts/simple-app/templates/deployment.yaml @@ -68,52 +68,30 @@ spec: - name: http containerPort: {{ .Values.port }} protocol: TCP - {{- range .Values.servicePorts }} + {{- range .Values.extraPorts }} - name: {{ .name }} containerPort: {{ .port }} protocol: {{ .protocol | default "TCP" }} {{- end }} - {{- if .Values.livenessProbe.enabled }} livenessProbe: + {{- if .Values.livenessProbe }} + {{- with .Values.livenessProbe }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- else }} httpGet: - path: {{ .Values.probe.httpGet.path }} + path: / port: http - {{- if .Values.livenessProbe.initialDelaySeconds }} - initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} - {{- end }} - {{- if .Values.livenessProbe.timeoutSeconds }} - timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} - {{- end }} - {{- if .Values.livenessProbe.periodSeconds }} - periodSeconds: {{ .Values.livenessProbe.periodSeconds }} - {{- end }} - {{- if .Values.livenessProbe.successThreshold }} - successThreshold: {{ .Values.livenessProbe.successThreshold }} - {{- end }} - {{- if .Values.livenessProbe.failureThreshold }} - failureThreshold: {{ .Values.livenessProbe.failureThreshold }} - {{- end }} {{- end }} - {{- if .Values.readinessProbe.enabled }} readinessProbe: + {{- if .Values.readinessProbe }} + {{- with .Values.readinessProbe }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- else }} httpGet: - path: {{ .Values.probe.httpGet.path }} + path: / port: http - {{- if .Values.livenessProbe.initialDelaySeconds }} - initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} - {{- end }} - {{- if .Values.readinessProbe.timeoutSeconds }} - timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} - {{- end }} - {{- if .Values.readinessProbe.periodSeconds }} - periodSeconds: {{ .Values.readinessProbe.periodSeconds }} - {{- end }} - {{- if .Values.readinessProbe.successThreshold }} - successThreshold: {{ .Values.readinessProbe.successThreshold }} - {{- end }} - {{- if .Values.readinessProbe.failureThreshold }} - failureThreshold: {{ .Values.readinessProbe.failureThreshold }} - {{- end }} {{- end }} resources: {{- toYaml .Values.resources | nindent 12 }} diff --git a/charts/simple-app/templates/ingress.yaml b/charts/simple-app/templates/ingress.yaml index e0392df..34ac64b 100644 --- a/charts/simple-app/templates/ingress.yaml +++ b/charts/simple-app/templates/ingress.yaml @@ -1,6 +1,6 @@ {{- if .Values.ingress.enabled -}} {{- $fullName := include "simple-app.fullname" . -}} -{{- $svcPort := .Values.service.port -}} +{{- $svcPort := .Values.servicePort -}} {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} apiVersion: networking.k8s.io/v1 {{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} diff --git a/charts/simple-app/templates/service.yaml b/charts/simple-app/templates/service.yaml index 661a387..bdeae70 100644 --- a/charts/simple-app/templates/service.yaml +++ b/charts/simple-app/templates/service.yaml @@ -5,14 +5,14 @@ metadata: labels: {{- include "simple-app.labels" . | nindent 4 }} spec: - type: {{ .Values.service.type }} + type: {{ .Values.serviceType }} ports: - - port: {{ .Values.service.port }} + - port: {{ .Values.servicePort }} targetPort: http protocol: TCP name: http - {{- range .Values.servicePorts}} - - port: {{ .port }} + {{- range .Values.extraPorts}} + - port: {{ .servicePort | default .port }} targetPort: {{ .name }} protocol: {{ .protocol | default "TCP" }} name: {{ .name }} diff --git a/charts/simple-app/tests/__snapshot__/multiport_test.yaml.snap b/charts/simple-app/tests/__snapshot__/multiport_test.yaml.snap new file mode 100644 index 0000000..f6aeea4 --- /dev/null +++ b/charts/simple-app/tests/__snapshot__/multiport_test.yaml.snap @@ -0,0 +1,116 @@ +All manifests should match snapshot: + 1: | + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app.kubernetes.io/instance: simple + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: simple-app + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: simple-app-0.10.0 + name: simple + spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: simple + app.kubernetes.io/name: simple-app + template: + metadata: + labels: + app.kubernetes.io/instance: simple + app.kubernetes.io/name: simple-app + spec: + containers: + - image: test:1.1.1 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: / + port: http + name: simple-app + ports: + - containerPort: 9000 + name: http + protocol: TCP + - containerPort: 1 + name: port1 + protocol: TCP + - containerPort: 2 + name: port2 + protocol: TCP + readinessProbe: + httpGet: + path: / + port: http + resources: {} + securityContext: {} + volumeMounts: null + securityContext: {} + serviceAccountName: simple + volumes: null + 2: | + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + annotations: null + labels: + app.kubernetes.io/instance: simple + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: simple-app + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: simple-app-0.10.0 + name: simple + spec: + rules: + - host: test.epoch8.co + http: + paths: + - backend: + service: + name: simple + port: + number: 9000 + path: /* + pathType: ImplementationSpecific + 3: | + apiVersion: v1 + kind: Service + metadata: + labels: + app.kubernetes.io/instance: simple + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: simple-app + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: simple-app-0.10.0 + name: simple + spec: + ports: + - name: http + port: 9000 + protocol: TCP + targetPort: http + - name: port1 + port: 1 + protocol: TCP + targetPort: port1 + - name: port2 + port: 22022 + protocol: TCP + targetPort: port2 + selector: + app.kubernetes.io/instance: simple + app.kubernetes.io/name: simple-app + type: ClusterIP + 4: | + apiVersion: v1 + kind: ServiceAccount + metadata: + labels: + app.kubernetes.io/instance: simple + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: simple-app + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: simple-app-0.10.0 + name: simple diff --git a/charts/simple-app/tests/__snapshot__/simple_test.yaml.snap b/charts/simple-app/tests/__snapshot__/simple_test.yaml.snap new file mode 100644 index 0000000..9da4e0e --- /dev/null +++ b/charts/simple-app/tests/__snapshot__/simple_test.yaml.snap @@ -0,0 +1,102 @@ +All manifests should match snapshot: + 1: | + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app.kubernetes.io/instance: simple + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: simple-app + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: simple-app-0.10.0 + name: simple + spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: simple + app.kubernetes.io/name: simple-app + template: + metadata: + labels: + app.kubernetes.io/instance: simple + app.kubernetes.io/name: simple-app + spec: + containers: + - image: test:1.1.1 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: / + port: http + name: simple-app + ports: + - containerPort: 9000 + name: http + protocol: TCP + readinessProbe: + httpGet: + path: / + port: http + resources: {} + securityContext: {} + volumeMounts: null + securityContext: {} + serviceAccountName: simple + volumes: null + 2: | + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + annotations: null + labels: + app.kubernetes.io/instance: simple + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: simple-app + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: simple-app-0.10.0 + name: simple + spec: + rules: + - host: test.epoch8.co + http: + paths: + - backend: + service: + name: simple + port: + number: 80 + path: /* + pathType: ImplementationSpecific + 3: | + apiVersion: v1 + kind: Service + metadata: + labels: + app.kubernetes.io/instance: simple + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: simple-app + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: simple-app-0.10.0 + name: simple + spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: http + selector: + app.kubernetes.io/instance: simple + app.kubernetes.io/name: simple-app + type: ClusterIP + 4: | + apiVersion: v1 + kind: ServiceAccount + metadata: + labels: + app.kubernetes.io/instance: simple + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: simple-app + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: simple-app-0.10.0 + name: simple diff --git a/charts/simple-app/tests/multiport-values.yaml b/charts/simple-app/tests/multiport-values.yaml new file mode 100644 index 0000000..3c50d4c --- /dev/null +++ b/charts/simple-app/tests/multiport-values.yaml @@ -0,0 +1,21 @@ +# yaml-language-server: $schema=../values.schema.json + +image: + repository: test + tag: 1.1.1 + +port: 9000 +servicePort: 9000 + +extraPorts: + - name: port1 + port: 1 + protocol: TCP + - name: port2 + port: 2 + servicePort: 22022 + +domain: test.epoch8.co + +ingress: + enabled: true diff --git a/charts/simple-app/tests/multiport_test.yaml b/charts/simple-app/tests/multiport_test.yaml new file mode 100644 index 0000000..389d520 --- /dev/null +++ b/charts/simple-app/tests/multiport_test.yaml @@ -0,0 +1,66 @@ +suite: simple-app multiport case + +release: + name: simple + namespace: default + +values: + - multiport-values.yaml + +tests: + - it: All manifests should match snapshot + templates: + - deployment.yaml + - service.yaml + - ingress.yaml + - serviceaccount.yaml + asserts: + - matchSnapshot: {} + + - it: Deployment multiple port specification should work correctly + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: spec.template.spec.containers[0].ports + value: + - containerPort: 9000 + name: http + protocol: TCP + - containerPort: 1 + name: port1 + protocol: TCP + - containerPort: 2 + name: port2 + protocol: TCP + + - it: Service multiple port specification should work correctly + template: service.yaml + asserts: + - isKind: + of: Service + - equal: + path: spec.ports + value: + - name: http + port: 9000 + protocol: TCP + targetPort: http + - name: port1 + port: 1 + protocol: TCP + targetPort: port1 + - name: port2 + port: 22022 + protocol: TCP + targetPort: port2 + + - it: Ingress multiple port specification should work correctly + template: ingress.yaml + asserts: + - isKind: + of: Ingress + - equal: + path: spec.rules[0].http.paths[0].backend.service.port.number + value: 9000 diff --git a/charts/simple-app/tests/simple-values.yaml b/charts/simple-app/tests/simple-values.yaml new file mode 100644 index 0000000..57449ab --- /dev/null +++ b/charts/simple-app/tests/simple-values.yaml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=../values.schema.json + +image: + repository: test + tag: 1.1.1 + +port: 9000 + +domain: test.epoch8.co + +ingress: + enabled: true diff --git a/charts/simple-app/tests/simple_test.yaml b/charts/simple-app/tests/simple_test.yaml new file mode 100644 index 0000000..297ac6c --- /dev/null +++ b/charts/simple-app/tests/simple_test.yaml @@ -0,0 +1,168 @@ +suite: simple-app simple case + +values: + - simple-values.yaml + +release: + name: simple + namespace: default + +tests: + - it: All manifests should match snapshot + templates: + - deployment.yaml + - service.yaml + - ingress.yaml + - serviceaccount.yaml + asserts: + - matchSnapshot: {} + + - it: Deployment should be named as release + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: metadata.name + value: simple + + - it: Deployment image tag should be set correctly + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: spec.template.spec.containers[0].image + value: test:1.1.1 + + - it: Deployment simple port specification should work correctly + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: spec.template.spec.containers[0].ports + value: + - containerPort: 9000 + name: http + protocol: TCP + + - it: Deployment should have readinessProbe set correctly by default + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: spec.template.spec.containers[0].readinessProbe.httpGet + value: + path: / + port: http + + - it: Deployment should have livenessProbe set correctly by default + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: spec.template.spec.containers[0].livenessProbe.httpGet + value: + path: / + port: http + + - it: Deployment should use imagePullSecrets if specified + template: deployment.yaml + set: + imagePullSecrets: + - name: test + asserts: + - isKind: + of: Deployment + - equal: + path: spec.template.spec.imagePullSecrets + value: + - name: test + + - it: Deployment should mount shared memory volume if shmMem specified + template: deployment.yaml + set: + shmSize: 1Gi + asserts: + - isKind: + of: Deployment + - equal: + path: spec.template.spec.containers[0].volumeMounts + value: + - mountPath: /dev/shm + name: shared-memory + - equal: + path: spec.template.spec.volumes + value: + - emptyDir: + medium: Memory + sizeLimit: 1Gi + name: shared-memory + + - it: Service should be named as release + template: service.yaml + asserts: + - isKind: + of: Service + - equal: + path: metadata.name + value: simple + + - it: Service simple port specification should work correctly + template: service.yaml + asserts: + - isKind: + of: Service + - equal: + path: spec.ports + value: + - name: http + port: 80 + protocol: TCP + targetPort: http + + - it: Service should use custom port + template: service.yaml + set: + servicePort: 7000 + asserts: + - isKind: + of: Service + - equal: + path: spec.ports[0].port + value: 7000 + + - it: Ingress should be named as release + template: ingress.yaml + set: + domain: example.com + ingress.enabled: true + asserts: + - isKind: + of: Ingress + - equal: + path: metadata.name + value: simple + + - it: Ingress should use default service port if not specified + template: ingress.yaml + asserts: + - isKind: + of: Ingress + - equal: + path: spec.rules[0].http.paths[0].backend.service.port.number + value: 80 + + - it: Ingress should use custom service port + template: ingress.yaml + set: + servicePort: 7000 + asserts: + - isKind: + of: Ingress + - equal: + path: spec.rules[0].http.paths[0].backend.service.port.number + value: 7000 diff --git a/charts/simple-app/values.schema.json b/charts/simple-app/values.schema.json new file mode 100644 index 0000000..76cc0be --- /dev/null +++ b/charts/simple-app/values.schema.json @@ -0,0 +1,191 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "simple-app values schema", + "type": "object", + "properties": { + "nameOverride": { + "type": "string" + }, + "fullnameOverride": { + "type": "string" + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "imagePullSecrets": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + } + }, + "domain": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "servicePort": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "serviceType": { + "type": "string" + }, + "extraPorts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "servicePort": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "protocol": { + "type": "string" + } + } + } + }, + "env": { + "type": "object" + }, + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "shmSize": { + "type": "string" + }, + "volumes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + } + } + } + }, + "configs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, + "livenessProbe": { + "type": "object" + }, + "readinessProbe": { + "type": "object" + }, + "replicaCount": { + "type": "integer" + }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "annotations": { + "type": "object" + } + } + }, + "podAnnotations": { + "type": "object" + }, + "podSecurityContext": { + "type": "object" + }, + "securityContext": { + "type": "object" + }, + "ingress": { + "type": "object" + }, + "resources": { + "type": "object" + }, + "autoscaling": { + "type": "object" + }, + "nodeSelector": { + "type": "object" + }, + "tolerations": { + "type": "array", + "items": { + "type": "object" + } + }, + "affinity": { + "type": "object" + }, + "gke": { + "type": "object", + "properties": { + "managedCertificate": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + } + } + } + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/charts/simple-app/values.yaml b/charts/simple-app/values.yaml index fe1fe2d..11e61c1 100644 --- a/charts/simple-app/values.yaml +++ b/charts/simple-app/values.yaml @@ -1,3 +1,5 @@ +# yaml-language-server: $schema=values.schema.json + # Default values for simple-app. # This is a YAML-formatted file. # Declare variables to be passed into your templates. @@ -15,14 +17,19 @@ image: imagePullSecrets: [] -# Port that container is using -port: 80 +# Port that container listens on +port: 8000 + +# Port that service should listen on +servicePort: 80 +serviceType: ClusterIP # Service type -# Ports to be exposed on the service -servicePorts: [] - # - name: grpc - # port: 50051 # both containerPort and service port - # protocol: TCP +# Extra ports to expose from the container on the service +extraPorts: [] +# - name: grpc +# port: 50051 +# servicePort: "" +# protocol: TCP # Environment variables for container env: {} @@ -50,13 +57,7 @@ configs: [] # } # } -# Default args for health probe -probe: - httpGet: - path: / - -livenessProbe: - enabled: true +livenessProbe: {} # httpGet: # path: / # port: http @@ -67,8 +68,7 @@ livenessProbe: # successThreshold: 1 # failureThreshold: 3 -readinessProbe: - enabled: true +readinessProbe: {} # httpGet: # path: / # port: http @@ -103,16 +103,11 @@ securityContext: {} # runAsNonRoot: true # runAsUser: 1000 -service: - type: ClusterIP - port: 80 - ingress: enabled: false # True if target ingress is Nginx (alters path definition and annotation) nginx: false - className: "" annotations: {}