diff --git a/charts/planr-tools/.helmignore b/charts/planr-tools/.helmignore new file mode 100644 index 00000000..21846e96 --- /dev/null +++ b/charts/planr-tools/.helmignore @@ -0,0 +1,17 @@ +.DS_Store +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +*.swp +*.bak +*.tmp +*.orig +*~ +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/planr-tools/Chart.yaml b/charts/planr-tools/Chart.yaml new file mode 100644 index 00000000..cfcafdff --- /dev/null +++ b/charts/planr-tools/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +name: planr-tools +description: A Helm chart for deploying the planr-tools applications +type: application +version: 1.0.0 +appVersion: "5.1.1" +annotations: + artifacthub.io/changes: | + - kind: added + description: Initial release of the planr-tools chart. +sources: + - https://github.com/subshell/helm-charts/tree/main/charts/planr-tools +home: https://gitlab.com/subshell/kunden/planr-tools diff --git a/charts/planr-tools/README.md b/charts/planr-tools/README.md new file mode 100644 index 00000000..59c03807 --- /dev/null +++ b/charts/planr-tools/README.md @@ -0,0 +1,93 @@ +# planr-tools + +This chart deploys the three `planr-tools` applications together: + +* `newsroom-document-creator` +* `newsroom-feed` +* `newsroom-widget` + +Each application is deployed as its own `Deployment`, `Service`, and `ConfigMap`, while the chart offers shared `Ingress` and `HTTPRoute` resources for path-based external access. + +## Prerequisites + +### Sophora credentials secret + +A Kubernetes secret containing the Sophora CMS credentials is required. Create it before installing the chart: + +```sh +kubectl create secret generic planr-tools-sophora-credentials \ + --from-literal=username= \ + --from-literal=password= +``` + +Expected keys: +- `username` — Sophora CMS username +- `password` — Sophora CMS password + +### Ingress controller requirements + +The `Ingress` resource uses `pathType: ImplementationSpecific` with nginx-style regex paths and a `rewrite-target` annotation to strip path prefixes before forwarding to each app. This requires an ingress controller that: + +- Supports regex matching for `pathType: ImplementationSpecific` +- Supports `nginx.ingress.kubernetes.io/rewrite-target` with capture groups + +The nginx ingress controller (`ingressClassName: nginx`) satisfies both requirements and is the default. Other controllers may not be compatible. Consider using `HTTPRoute` instead if you are not using nginx. + +## Example values.yaml + +```yaml +ingress: + enabled: true + ingressClassName: nginx + hosts: + - host: planr-tools.example.com + +httpRoute: + enabled: false + +applications: + documentCreator: + service: + type: ClusterIP + config: + sophora: + client: + server-connection: + urls: https://cms.example.com + username: ${SOPHORA_USERNAME} + password: ${SOPHORA_PASSWORD} + + feed: + service: + type: ClusterIP + config: + sophora: + client: + server-connection: + urls: https://cms.example.com + username: ${SOPHORA_USERNAME} + password: ${SOPHORA_PASSWORD} + + widget: + service: + type: ClusterIP + config: + sophora: + client: + server-connection: + urls: https://cms.example.com + username: ${SOPHORA_USERNAME} + password: ${SOPHORA_PASSWORD} + +commonEnv: + - name: SOPHORA_USERNAME + valueFrom: + secretKeyRef: + name: planr-tools-sophora-credentials + key: username + - name: SOPHORA_PASSWORD + valueFrom: + secretKeyRef: + name: planr-tools-sophora-credentials + key: password +``` diff --git a/charts/planr-tools/templates/_helpers.tpl b/charts/planr-tools/templates/_helpers.tpl new file mode 100644 index 00000000..84bb990c --- /dev/null +++ b/charts/planr-tools/templates/_helpers.tpl @@ -0,0 +1,107 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "planr-tools.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "planr-tools.fullname" -}} +{{- 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 }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "planr-tools.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels. +*/}} +{{- define "planr-tools.labels" -}} +helm.sh/chart: {{ include "planr-tools.chart" .root }} +{{ include "planr-tools.selectorLabels" . }} +{{- if .root.Chart.AppVersion }} +app.kubernetes.io/version: {{ .root.Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .root.Release.Service }} +{{- end }} + +{{/* +Selector labels. +*/}} +{{- define "planr-tools.selectorLabels" -}} +app.kubernetes.io/name: {{ include "planr-tools.name" .root }} +app.kubernetes.io/instance: {{ .root.Release.Name }} +app.kubernetes.io/component: {{ .component.name }} +{{- end }} + +{{/* +Service account name. +*/}} +{{- define "planr-tools.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "planr-tools.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Ordered list of application keys. +Wrapped in a map because fromYaml requires a top-level map, not a bare list. +Usage: range $appKey := (include "planr-tools.app-keys" . | fromYaml).keys +*/}} +{{- define "planr-tools.app-keys" -}} +keys: + - documentCreator + - feed + - widget +{{- end }} + +{{/* +Component fullname. +*/}} +{{- define "planr-tools.componentFullname" -}} +{{- printf "%s-%s" (include "planr-tools.fullname" .root) .component.name | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Component configmap name. +*/}} +{{- define "planr-tools.componentConfigName" -}} +{{- printf "%s-config" (include "planr-tools.componentFullname" .) | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Config checksum. +Computed from the fully rendered application.yml (after tpl), not the raw config map, +so that changes to values referenced inside config templates also trigger pod restarts. +*/}} +{{- define "planr-tools.componentConfigChecksum" -}} +{{- include "planr-tools.render" (dict "value" .component.config "context" .root) | sha256sum }} +{{- end }} + +{{/* +Renders a value that contains templates. +*/}} +{{- define "planr-tools.render" -}} +{{- if typeIs "string" .value }} +{{- tpl .value .context }} +{{- else }} +{{- tpl (.value | toYaml) .context }} +{{- end }} +{{- end -}} diff --git a/charts/planr-tools/templates/configmap.yaml b/charts/planr-tools/templates/configmap.yaml new file mode 100644 index 00000000..afb23829 --- /dev/null +++ b/charts/planr-tools/templates/configmap.yaml @@ -0,0 +1,16 @@ +{{- $root := . -}} +{{- range $appKey := (include "planr-tools.app-keys" $root | fromYaml).keys }} +{{- $component := index $root.Values.applications $appKey }} +{{- if $component.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "planr-tools.componentConfigName" (dict "root" $root "component" $component) }} + labels: + {{- include "planr-tools.labels" (dict "root" $root "component" $component) | nindent 4 }} +data: + application.yml: |- + {{- include "planr-tools.render" (dict "value" $component.config "context" $root) | nindent 4 }} +--- +{{- end }} +{{- end }} diff --git a/charts/planr-tools/templates/deployment.yaml b/charts/planr-tools/templates/deployment.yaml new file mode 100644 index 00000000..c8efbaa1 --- /dev/null +++ b/charts/planr-tools/templates/deployment.yaml @@ -0,0 +1,119 @@ +{{- $root := . -}} +{{- range $appKey := (include "planr-tools.app-keys" $root | fromYaml).keys }} +{{- $component := index $root.Values.applications $appKey }} +{{- if $component.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "planr-tools.componentFullname" (dict "root" $root "component" $component) }} + labels: + {{- include "planr-tools.labels" (dict "root" $root "component" $component) | nindent 4 }} +spec: + replicas: {{ default $root.Values.replicaCount $component.replicaCount }} + selector: + matchLabels: + {{- include "planr-tools.selectorLabels" (dict "root" $root "component" $component) | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include "planr-tools.componentConfigChecksum" (dict "root" $root "component" $component) }} + {{- with $root.Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "planr-tools.selectorLabels" (dict "root" $root "component" $component) | nindent 8 }} + spec: + {{- if $component.hostname }} + hostname: {{ $component.hostname }} + {{- end }} + serviceAccountName: {{ include "planr-tools.serviceAccountName" $root }} + automountServiceAccountToken: {{ $root.Values.serviceAccount.automount }} + {{- with $root.Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml $root.Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ $component.name }} + image: "{{ $component.image.repository }}:{{ $component.image.tag | default $root.Chart.AppVersion }}" + imagePullPolicy: {{ $component.image.pullPolicy }} + securityContext: + {{- toYaml $root.Values.containerSecurityContext | nindent 12 }} + env: + - name: JAVA_OPTS + value: {{ $root.Values.javaOptions | quote }} + {{- with $root.Values.commonEnv }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with $component.env }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if or $root.Values.commonEnvFrom $component.envFrom }} + envFrom: + {{- with $root.Values.commonEnvFrom }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with $component.envFrom }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + ports: + - name: http + containerPort: {{ $component.service.targetPort }} + protocol: TCP + {{- with $root.Values.startupProbe }} + startupProbe: + httpGet: + port: http + path: /actuator/health/liveness + failureThreshold: {{ .failureThreshold }} + initialDelaySeconds: {{ .initialDelaySeconds }} + periodSeconds: {{ .periodSeconds }} + timeoutSeconds: {{ .timeoutSeconds }} + {{- end }} + {{- with $root.Values.livenessProbe }} + livenessProbe: + httpGet: + port: http + path: /actuator/health/liveness + failureThreshold: {{ .failureThreshold }} + initialDelaySeconds: {{ .initialDelaySeconds }} + periodSeconds: {{ .periodSeconds }} + timeoutSeconds: {{ .timeoutSeconds }} + {{- end }} + {{- with $root.Values.readinessProbe }} + readinessProbe: + httpGet: + port: http + path: /actuator/health/readiness + failureThreshold: {{ .failureThreshold }} + initialDelaySeconds: {{ .initialDelaySeconds }} + periodSeconds: {{ .periodSeconds }} + timeoutSeconds: {{ .timeoutSeconds }} + {{- end }} + volumeMounts: + - name: application-config + mountPath: /app/application.yml + subPath: application.yml + resources: + {{- toYaml ($component.resources | default $root.Values.resources) | nindent 12 }} + volumes: + - name: application-config + configMap: + name: {{ include "planr-tools.componentConfigName" (dict "root" $root "component" $component) }} + {{- with $root.Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $root.Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $root.Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +--- +{{- end }} +{{- end }} diff --git a/charts/planr-tools/templates/httproute.yaml b/charts/planr-tools/templates/httproute.yaml new file mode 100644 index 00000000..b94e5e08 --- /dev/null +++ b/charts/planr-tools/templates/httproute.yaml @@ -0,0 +1,48 @@ +{{- if .Values.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "planr-tools.fullname" . }} + labels: + {{- include "planr-tools.labels" (dict "root" . "component" (dict "name" "gateway")) | nindent 4 }} + {{- with .Values.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with .Values.httpRoute.parentRefs }} + parentRefs: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.httpRoute.hostnames }} + hostnames: + {{- range . }} + - {{ . | quote }} + {{- end }} + {{- end }} + rules: + {{- range $appKey := (include "planr-tools.app-keys" $ | fromYaml).keys }} + {{- $component := index $.Values.applications $appKey }} + {{- if $component.enabled }} + - matches: + - path: + type: PathPrefix + value: {{ $component.exposure.path | quote }} + backendRefs: + - name: {{ include "planr-tools.componentFullname" (dict "root" $ "component" $component) }} + port: {{ $component.service.port }} + filters: + {{- if ne $component.exposure.path "/" }} + {{/* Strip the path prefix so apps receive requests at their own root, same as the Ingress rewrite. */}} + - type: URLRewrite + urlRewrite: + path: + type: ReplacePrefixMatch + replacePrefixMatch: / + {{- end }} + {{- with $.Values.httpRoute.filters }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/planr-tools/templates/ingress.yaml b/charts/planr-tools/templates/ingress.yaml new file mode 100644 index 00000000..86612642 --- /dev/null +++ b/charts/planr-tools/templates/ingress.yaml @@ -0,0 +1,72 @@ +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "planr-tools.fullname" . }} + labels: + {{- include "planr-tools.labels" (dict "root" . "component" (dict "name" "ingress")) | nindent 4 }} + annotations: + {{- if eq .Values.ingress.ingressClassName "nginx" }} + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: /$2 + {{- end }} + {{- with .Values.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.ingressClassName }} + ingressClassName: {{ .Values.ingress.ingressClassName }} + {{- end }} + {{- with .Values.ingress.tls }} + tls: + {{- range . }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range $host := .Values.ingress.hosts }} + - host: {{ required "A hostname for the ingress must be provided in .Values.ingress.hosts[].host" $host.host }} + http: + paths: + {{- range $appKey := (include "planr-tools.app-keys" $ | fromYaml).keys }} + {{- $component := index $.Values.applications $appKey }} + {{- if $component.enabled }} + {{- $path := $component.exposure.path }} + {{/* + All three apps share one hostname with path-based routing: + planr-tools.example.com/document-creator/... → document-creator pod + planr-tools.example.com/feed/... → feed pod + planr-tools.example.com/... → widget pod + + Without a rewrite, document-creator would receive requests as + /document-creator/api/v1/... and return 404 — it only knows about /api/v1/... + The nginx rewrite-target annotation above strips the path prefix before forwarding + to the backend, so each app receives requests at its own root (e.g. /api/...) and + is completely unaware that it is being served under a subpath externally. + + To make this work, paths must be regex with two capture groups ($1, $2), because the + rewrite target is "/$2": + - Non-root (e.g. /document-creator): "/document-creator(/|$)(.*)" + $1 = the slash after the prefix (or empty at end of string) + $2 = everything after the prefix → forwarded as "/$2" + - Root (/): "/()(.*)" + $1 = empty (dummy group to keep $2 consistent) + $2 = the full path after the leading slash → forwarded as "/$2" unchanged + + pathType must be ImplementationSpecific for nginx to treat the path as a regex. + */}} + - path: {{ if eq $path "/" }}"/()(.*)"{{ else }}{{ printf "%s(/|$)(.*)" $path | quote }}{{ end }} + pathType: ImplementationSpecific + backend: + service: + name: {{ include "planr-tools.componentFullname" (dict "root" $ "component" $component) }} + port: + number: {{ $component.service.port }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/planr-tools/templates/service.yaml b/charts/planr-tools/templates/service.yaml new file mode 100644 index 00000000..def18ba5 --- /dev/null +++ b/charts/planr-tools/templates/service.yaml @@ -0,0 +1,29 @@ +{{- $root := . -}} +{{- range $appKey := (include "planr-tools.app-keys" $root | fromYaml).keys }} +{{- $component := index $root.Values.applications $appKey }} +{{- if $component.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "planr-tools.componentFullname" (dict "root" $root "component" $component) }} + labels: + {{- include "planr-tools.labels" (dict "root" $root "component" $component) | nindent 4 }} + {{- with $component.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ $component.service.type }} + {{- if $component.service.loadBalancerIP }} + loadBalancerIP: {{ $component.service.loadBalancerIP }} + {{- end }} + ports: + - name: http + port: {{ $component.service.port }} + targetPort: {{ $component.service.targetPort }} + protocol: TCP + selector: + {{- include "planr-tools.selectorLabels" (dict "root" $root "component" $component) | nindent 4 }} +--- +{{- end }} +{{- end }} diff --git a/charts/planr-tools/templates/serviceaccount.yaml b/charts/planr-tools/templates/serviceaccount.yaml new file mode 100644 index 00000000..dacbbeb0 --- /dev/null +++ b/charts/planr-tools/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "planr-tools.serviceAccountName" . }} + labels: + {{- include "planr-tools.labels" (dict "root" . "component" (dict "name" "service-account")) | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/charts/planr-tools/test-values-httproute.yaml b/charts/planr-tools/test-values-httproute.yaml new file mode 100644 index 00000000..6645c300 --- /dev/null +++ b/charts/planr-tools/test-values-httproute.yaml @@ -0,0 +1,16 @@ +httpRoute: + enabled: true + parentRefs: + - name: test-gateway + namespace: gateway-system + hostnames: + - planr-tools.test.example.com + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Test + value: enabled + annotations: + example.com/test: "true" + diff --git a/charts/planr-tools/test-values-ingress.yaml b/charts/planr-tools/test-values-ingress.yaml new file mode 100644 index 00000000..e65eee71 --- /dev/null +++ b/charts/planr-tools/test-values-ingress.yaml @@ -0,0 +1,52 @@ +ingress: + enabled: true + ingressClassName: nginx + hosts: + - host: planr-tools.example.com + +imagePullSecrets: + - name: subshell-registry + +commonEnv: + - name: SPRING_PROFILES_ACTIVE + value: subshell-test-cloud + - name: SOPHORA_URL + value: "" # e.g. https://cms.stable.test.subshell.io + - name: SOPHORA_USERNAME + value: "" # in secret + - name: SOPHORA_PASSWORD + value: "" # in secret + +applications: + documentCreator: + image: + tag: master + config: + sophora: + client: + server-connection: + urls: ${SOPHORA_URL} + username: ${SOPHORA_USERNAME} + password: ${SOPHORA_PASSWORD} + + feed: + image: + tag: master + config: + sophora: + client: + server-connection: + urls: ${SOPHORA_URL} + username: ${SOPHORA_USERNAME} + password: ${SOPHORA_PASSWORD} + + widget: + image: + tag: master + config: + sophora: + client: + server-connection: + urls: ${SOPHORA_URL} + username: ${SOPHORA_USERNAME} + password: ${SOPHORA_PASSWORD} diff --git a/charts/planr-tools/tests/deployment_test.yaml b/charts/planr-tools/tests/deployment_test.yaml new file mode 100644 index 00000000..ca570dc3 --- /dev/null +++ b/charts/planr-tools/tests/deployment_test.yaml @@ -0,0 +1,91 @@ +suite: test deployment +templates: + - deployment.yaml +chart: + version: 1.0.0 + appVersion: 5.1.1 +tests: + - it: should create 3 deployments by default + asserts: + - hasDocuments: + count: 3 + + - it: should create 1 deployment when two apps are disabled + set: + applications.feed.enabled: false + applications.widget.enabled: false + asserts: + - hasDocuments: + count: 1 + + - it: document-creator should have correct name, image and port + documentIndex: 0 + asserts: + - equal: + path: metadata.name + value: RELEASE-NAME-planr-tools-newsroom-document-creator + - equal: + path: spec.template.spec.containers[0].image + value: docker.subshell.com/planr-tools/newsroom-document-creator:5.1.1 + - equal: + path: spec.template.spec.containers[0].ports[0].containerPort + value: 8080 + + - it: feed should have correct name, image and port + documentIndex: 1 + asserts: + - equal: + path: metadata.name + value: RELEASE-NAME-planr-tools-newsroom-feed + - equal: + path: spec.template.spec.containers[0].image + value: docker.subshell.com/planr-tools/newsroom-feed:5.1.1 + - equal: + path: spec.template.spec.containers[0].ports[0].containerPort + value: 8081 + + - it: widget should have correct name, image and port + documentIndex: 2 + asserts: + - equal: + path: metadata.name + value: RELEASE-NAME-planr-tools-newsroom-widget + - equal: + path: spec.template.spec.containers[0].image + value: docker.subshell.com/planr-tools/newsroom-widget:5.1.1 + - equal: + path: spec.template.spec.containers[0].ports[0].containerPort + value: 8082 + + - it: all deployments should have liveness and readiness probes + documentIndex: 0 + asserts: + - equal: + path: spec.template.spec.containers[0].livenessProbe.httpGet.path + value: /actuator/health/liveness + - equal: + path: spec.template.spec.containers[0].readinessProbe.httpGet.path + value: /actuator/health/readiness + - equal: + path: spec.template.spec.containers[0].startupProbe.httpGet.path + value: /actuator/health/liveness + + - it: should mount the application config + documentIndex: 0 + asserts: + - equal: + path: spec.template.spec.containers[0].volumeMounts[0].mountPath + value: /app/application.yml + - equal: + path: spec.template.spec.volumes[0].configMap.name + value: RELEASE-NAME-planr-tools-newsroom-document-creator-config + + - it: should have a checksum annotation for config-driven restarts + documentIndex: 0 + asserts: + - exists: + path: spec.template.metadata.annotations.checksum/config + + - it: should not fail template rendering + asserts: + - notFailedTemplate: {} diff --git a/charts/planr-tools/tests/httproute_test.yaml b/charts/planr-tools/tests/httproute_test.yaml new file mode 100644 index 00000000..9359a024 --- /dev/null +++ b/charts/planr-tools/tests/httproute_test.yaml @@ -0,0 +1,59 @@ +suite: test httproute +templates: + - httproute.yaml +chart: + version: 1.0.0 + appVersion: 5.1.1 +tests: + - it: should not create httproute by default + asserts: + - hasDocuments: + count: 0 + + - it: should create httproute rules for all enabled applications + release: + name: values-test-release + values: + - ./values/httproute.yaml + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: HTTPRoute + apiVersion: gateway.networking.k8s.io/v1 + name: values-test-release-planr-tools + - equal: + path: metadata.annotations + value: + example.com/test: "true" + - equal: + path: spec.hostnames + value: + - planr-tools.example.com + - equal: + path: spec.rules[0].backendRefs[0].name + value: values-test-release-planr-tools-newsroom-document-creator + - equal: + path: spec.rules[1].backendRefs[0].name + value: values-test-release-planr-tools-newsroom-feed + - equal: + path: spec.rules[2].backendRefs[0].name + value: values-test-release-planr-tools-newsroom-widget + - equal: + path: spec.rules[0].matches[0].path.value + value: /document-creator + - equal: + path: spec.rules[1].matches[0].path.value + value: /feed + - equal: + path: spec.rules[2].matches[0].path.value + value: / + - equal: + path: spec.rules[0].filters[0].type + value: URLRewrite + - equal: + path: spec.rules[1].filters[0].type + value: URLRewrite + - notExists: + path: spec.rules[2].filters[0].urlRewrite + - notFailedTemplate: {} diff --git a/charts/planr-tools/tests/ingress_test.yaml b/charts/planr-tools/tests/ingress_test.yaml new file mode 100644 index 00000000..e1f2efb0 --- /dev/null +++ b/charts/planr-tools/tests/ingress_test.yaml @@ -0,0 +1,69 @@ +suite: test ingress +templates: + - ingress.yaml +chart: + version: 1.0.0 + appVersion: 5.1.1 +tests: + - it: should not create ingress by default + asserts: + - hasDocuments: + count: 0 + + - it: should create ingress with nginx annotations and regex paths + release: + name: values-test-release + values: + - ./values/ingress.yaml + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: Ingress + apiVersion: networking.k8s.io/v1 + name: values-test-release-planr-tools + - equal: + path: metadata.annotations["nginx.ingress.kubernetes.io/use-regex"] + value: "true" + - equal: + path: metadata.annotations["nginx.ingress.kubernetes.io/rewrite-target"] + value: /$2 + - equal: + path: metadata.annotations["example.com/test"] + value: "true" + - equal: + path: spec.rules[0].http.paths[0].path + value: "/document-creator(/|$)(.*)" + - equal: + path: spec.rules[0].http.paths[1].path + value: "/feed(/|$)(.*)" + - equal: + path: spec.rules[0].http.paths[2].path + value: "/()(.*)" + - equal: + path: spec.rules[0].http.paths[0].backend.service.name + value: values-test-release-planr-tools-newsroom-document-creator + - equal: + path: spec.rules[0].http.paths[1].backend.service.name + value: values-test-release-planr-tools-newsroom-feed + - equal: + path: spec.rules[0].http.paths[2].backend.service.name + value: values-test-release-planr-tools-newsroom-widget + - equal: + path: spec.rules[0].http.paths[0].pathType + value: ImplementationSpecific + - notFailedTemplate: {} + + - it: should not emit nginx annotations for non-nginx ingress class + release: + name: values-test-release + values: + - ./values/ingress.yaml + set: + ingress.ingressClassName: traefik + asserts: + - notExists: + path: metadata.annotations["nginx.ingress.kubernetes.io/use-regex"] + - notExists: + path: metadata.annotations["nginx.ingress.kubernetes.io/rewrite-target"] + - notFailedTemplate: {} diff --git a/charts/planr-tools/tests/values/httproute.yaml b/charts/planr-tools/tests/values/httproute.yaml new file mode 100644 index 00000000..a3326e67 --- /dev/null +++ b/charts/planr-tools/tests/values/httproute.yaml @@ -0,0 +1,15 @@ +httpRoute: + enabled: true + parentRefs: + - name: my-gateway + namespace: gateway-namespace + hostnames: + - planr-tools.example.com + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Custom-Header + value: custom-value + annotations: + example.com/test: "true" diff --git a/charts/planr-tools/tests/values/ingress.yaml b/charts/planr-tools/tests/values/ingress.yaml new file mode 100644 index 00000000..307c962e --- /dev/null +++ b/charts/planr-tools/tests/values/ingress.yaml @@ -0,0 +1,7 @@ +ingress: + enabled: true + ingressClassName: nginx + hosts: + - host: planr-tools.example.com + annotations: + example.com/test: "true" diff --git a/charts/planr-tools/values.yaml b/charts/planr-tools/values.yaml new file mode 100644 index 00000000..0fe3f192 --- /dev/null +++ b/charts/planr-tools/values.yaml @@ -0,0 +1,189 @@ +replicaCount: 1 + +nameOverride: "" +fullnameOverride: "" + +imagePullSecrets: [] + +javaOptions: "-XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=80.0 -XX:+ExitOnOutOfMemoryError -XX:+PerfDisableSharedMem" + +podAnnotations: {} +podSecurityContext: {} +containerSecurityContext: {} + +nodeSelector: {} +affinity: {} +tolerations: [] + +resources: + limits: {} + requests: {} + +startupProbe: + failureThreshold: 30 + initialDelaySeconds: 10 + timeoutSeconds: 5 + periodSeconds: 5 + +livenessProbe: + failureThreshold: 3 + initialDelaySeconds: 15 + timeoutSeconds: 10 + periodSeconds: 60 + +readinessProbe: + failureThreshold: 5 + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 5 + +serviceAccount: + create: false + automount: true + annotations: {} + name: "" + +commonEnv: [] +commonEnvFrom: [] + +ingress: + enabled: false + ingressClassName: nginx + tls: + hosts: + annotations: {} + +httpRoute: + enabled: false + parentRefs: [] + hostnames: [] + filters: [] + annotations: {} + +applications: + documentCreator: + enabled: true + name: newsroom-document-creator + hostname: "" + image: + repository: docker.subshell.com/planr-tools/newsroom-document-creator + pullPolicy: IfNotPresent + tag: "" + service: + annotations: {} + type: ClusterIP + port: 8080 + targetPort: 8080 + loadBalancerIP: + exposure: + path: /document-creator + env: [] + envFrom: [] + resources: {} + config: + spring: + application: + name: Newsroom-Document-Creator + server: + port: 8080 + logging: + path: logs + management: + endpoints: + web: + base-path: /actuator + exposure: + include: health,info + sophora: + client: + server-connection: + urls: # e.g. https://cms.example.com/ + username: # in secret + password: # in secret + + feed: + enabled: true + name: newsroom-feed + hostname: "" + image: + repository: docker.subshell.com/planr-tools/newsroom-feed + pullPolicy: IfNotPresent + tag: "" + service: + annotations: {} + type: ClusterIP + port: 8081 + targetPort: 8081 + loadBalancerIP: + exposure: + path: /feed + env: [] + envFrom: [] + resources: {} + config: + spring: + application: + name: Newsroom-Feed + resources: + add-mappings: true + server: + port: 8081 + logging: + path: logs + management: + endpoints: + web: + base-path: /actuator + exposure: + include: health,info + sophora: + client: + server-connection: + urls: # e.g. https://cms.example.com/ + username: # in secret + password: # in secret + + widget: + enabled: true + name: newsroom-widget + hostname: "" + image: + repository: docker.subshell.com/planr-tools/newsroom-widget + pullPolicy: IfNotPresent + tag: "" + service: + annotations: {} + type: ClusterIP + port: 8082 + targetPort: 8082 + loadBalancerIP: + exposure: + path: / + env: [] + envFrom: [] + resources: {} + config: + spring: + application: + name: Newsroom-Widget + jackson: + serialization: + write_dates_as_timestamps: false + logging: + path: logs + server: + port: 8082 + compression: + enabled: true + management: + endpoints: + web: + base-path: /actuator + exposure: + include: health,info + sophora: + client: + server-connection: + urls: # e.g. https://cms.example.com/ + username: # in secret + password: # in secret