From 192fe186e08f86ecfd66fcaf036d6d3a697b7581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20Echterh=C3=B6lter?= Date: Thu, 21 Nov 2024 10:14:58 +0100 Subject: [PATCH 1/5] feat: moving portal chart to this repo --- .github/workflows/portal.yaml | 28 ++ charts/portal/.helmignore | 21 ++ charts/portal/Chart.lock | 6 + charts/portal/Chart.yaml | 9 + charts/portal/README.MD | 12 + charts/portal/charts/common-0.1.3.tgz | Bin 0 -> 490 bytes charts/portal/templates/deploy.yaml | 108 ++++++ charts/portal/templates/external-secrets.yaml | 33 ++ .../templates/istio-destination-rule.yaml | 12 + .../templates/istio-peerauthentication.yaml | 13 + .../templates/istio-virtual-service.yaml | 37 ++ charts/portal/templates/rbac.yaml | 23 ++ charts/portal/templates/sa.yaml | 7 + charts/portal/templates/service.yaml | 13 + charts/portal/templates/sidecar.yaml | 13 + charts/portal/test-values.yaml | 14 + .../tests/__snapshot__/deploy_test.yaml.snap | 72 ++++ .../external-secrets_test.yaml.snap | 22 ++ .../istio-virtual_service_test.yaml.snap | 31 ++ .../tests/__snapshot__/istio_test.yaml.snap | 349 ++++++++++++++++++ .../virtual_service_test.yaml.snap | 1 + charts/portal/tests/deploy_test.yaml | 13 + .../portal/tests/external-secrets_test.yaml | 10 + .../tests/istio-virtual_service_test.yaml | 9 + charts/portal/tests/istio_test.yaml | 18 + charts/portal/values.yaml | 24 ++ 26 files changed, 898 insertions(+) create mode 100644 .github/workflows/portal.yaml create mode 100644 charts/portal/.helmignore create mode 100644 charts/portal/Chart.lock create mode 100644 charts/portal/Chart.yaml create mode 100644 charts/portal/README.MD create mode 100644 charts/portal/charts/common-0.1.3.tgz create mode 100644 charts/portal/templates/deploy.yaml create mode 100644 charts/portal/templates/external-secrets.yaml create mode 100644 charts/portal/templates/istio-destination-rule.yaml create mode 100644 charts/portal/templates/istio-peerauthentication.yaml create mode 100644 charts/portal/templates/istio-virtual-service.yaml create mode 100644 charts/portal/templates/rbac.yaml create mode 100644 charts/portal/templates/sa.yaml create mode 100644 charts/portal/templates/service.yaml create mode 100644 charts/portal/templates/sidecar.yaml create mode 100644 charts/portal/test-values.yaml create mode 100644 charts/portal/tests/__snapshot__/deploy_test.yaml.snap create mode 100644 charts/portal/tests/__snapshot__/external-secrets_test.yaml.snap create mode 100644 charts/portal/tests/__snapshot__/istio-virtual_service_test.yaml.snap create mode 100644 charts/portal/tests/__snapshot__/istio_test.yaml.snap create mode 100644 charts/portal/tests/__snapshot__/virtual_service_test.yaml.snap create mode 100644 charts/portal/tests/deploy_test.yaml create mode 100644 charts/portal/tests/external-secrets_test.yaml create mode 100644 charts/portal/tests/istio-virtual_service_test.yaml create mode 100644 charts/portal/tests/istio_test.yaml create mode 100644 charts/portal/values.yaml diff --git a/.github/workflows/portal.yaml b/.github/workflows/portal.yaml new file mode 100644 index 000000000..63f6f3caf --- /dev/null +++ b/.github/workflows/portal.yaml @@ -0,0 +1,28 @@ +name: Build portal Workflow +on: + push: + paths: + - 'charts/portal/**' + - '.github/workflows/portal.yaml' + +jobs: + pipeline: + concurrency: + group: portal-${{ github.ref }} + cancel-in-progress: true + uses: openmfp/gha/.github/workflows/pipeline-chart.yml@main + with: + chartFolder: charts + chartName: portal + additionalTestFilesCommand: '' + chartRepos: 'bitnami=https://charts.bitnami.com/bitnami,openfga=https://openfga.github.io/helm-charts' + secrets: inherit + + updateVersionFile: + if: ${{ github.ref == 'refs/heads/main' }} + needs: [pipeline] + uses: openmfp/gha/.github/workflows/job-update-version-file.yml@main + secrets: inherit + with: + componentVersionKey: "portal" + version: ${{ needs.pipeline.outputs.version }} diff --git a/charts/portal/.helmignore b/charts/portal/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/charts/portal/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/charts/portal/Chart.lock b/charts/portal/Chart.lock new file mode 100644 index 000000000..831646171 --- /dev/null +++ b/charts/portal/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: file://../common + version: 0.1.3 +digest: sha256:458eeb38012b33fb226ca0cb45ecbcdd21e2a28025619bc0b01dd71a079c9882 +generated: "2024-10-11T11:24:57.022871+02:00" diff --git a/charts/portal/Chart.yaml b/charts/portal/Chart.yaml new file mode 100644 index 000000000..80f9a1b1c --- /dev/null +++ b/charts/portal/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +appVersion: "0.164.0" +description: Helm Chart for the openmfp Portal +name: portal +version: 0.69.87 +dependencies: + - name: common + repository: file://../common + version: 0.1.3 diff --git a/charts/portal/README.MD b/charts/portal/README.MD new file mode 100644 index 000000000..0de306dd9 --- /dev/null +++ b/charts/portal/README.MD @@ -0,0 +1,12 @@ +# Helm chart of the jukebox + +## Execute the linting in the pipeline + +```shell +helm lint -f test-values.yaml +``` + +## Debug the chart output +```shell +helm template --debug . -f test-values.yaml +``` diff --git a/charts/portal/charts/common-0.1.3.tgz b/charts/portal/charts/common-0.1.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..cb2f0848c22ddd4f284cc552885c4680897a9388 GIT binary patch literal 490 zcmVDc zVQyr3R8em|NM&qo0PI%HirX*{_E}Fc7z*tnT3NBZkXz}cP$;E^y%xopYz2~RBsmb$ zefQ$nF0s93$2pNgE7X+JU_0Cv2bNs&XX*E zWSnP3QSyXkJTG|y>U{8(e{sYb)%Y>_&ZzW^_sJ9bv?uFz|mTREzFP4PcJ{ z-9F&|W0pn!-vUGaJ?cgYkM7|s8ZZ6+qtHlwbCGJ8%YR;k{l6%ddCdPUa5yYrgIj43 z(mwOFYwam4US3FdDYsD7#tUg2(0)wlY6IwJR45$wr$M-}()cZ;uUtA2{tn)@rh;-g zN}_VVc(ph_oM@g=V>UlM9rxrkCOhbw1~u_>V(#}Q?wzUY;GF+bi)Z}QD)j{`i~a&l zV2=Ns7Xkmvg2nmoCOGBFv#QrZ(Vzg*jtIdww;})w=!d|=q0=B*<$*r+b3`Bxug8nt g#G5mLDcA1(Qz9ZFBK`yX2mk>8|8dqgasUzl0Aerd4gdfE literal 0 HcmV?d00001 diff --git a/charts/portal/templates/deploy.yaml b/charts/portal/templates/deploy.yaml new file mode 100644 index 000000000..6e4970f06 --- /dev/null +++ b/charts/portal/templates/deploy.yaml @@ -0,0 +1,108 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "entity.name" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ include "entity.name" . }} +spec: + strategy: + rollingUpdate: + maxSurge: {{ .Values.deployment.maxSurge }} + maxUnavailable: {{ .Values.deployment.maxUnavailable }} + revisionHistoryLimit: 3 + selector: + matchLabels: + app: {{ include "entity.name" . }} + template: + metadata: + labels: + app: {{ include "entity.name" . }} + spec: + serviceAccountName: {{ include "entity.name" . }} + securityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + containers: + - name: {{ include "entity.name" . }} + image: {{ .Values.image.name }}:{{ .Chart.AppVersion }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + securityContext: + readOnlyRootFilesystem: true + env: + - name: HTTP_PROTOCOL + value: {{ .Values.http.protocol }} + {{- range $key, $idp := .Values.trust }} + - name: OIDC_CLIENT_ID_{{ $key | upper | replace "-" "_" }} + value: "{{ $idp.loginAudience | default $idp.audience }}" + - name: OIDC_CLIENT_SECRET_{{ $key | upper | replace "-" "_" }} + valueFrom: + secretKeyRef: + name: portal-client-secret-{{ $idp.secretKey | default $key }} + key: {{ $idp.secretKeyRef | default "secret" }} + {{ if $idp.discoveryEndpoint }} + - name: DISCOVERY_ENDPOINT_{{ $key | upper | replace "-" "_" }} + value: {{ $idp.discoveryEndpoint }} + {{- else }} + - name: TOKEN_URL_{{ $key | upper | replace "-" "_" }} + value: {{ $idp.tokenUrl | default $idp.trustedIssuer }} + - name: AUTH_SERVER_URL_{{ $key | upper | replace "-" "_" }} + value: {{ $idp.authDomain | default $idp.trustedIssuer }} + {{- end }} + {{- if $idp.baseDomains }} + - name: BASE_DOMAINS_{{ $key | upper | replace "-" "_" }} + value: {{ $idp.baseDomains }} + {{- end }} + {{- end }} + {{- if .Values.trust }} + - name: IDP_NAMES + {{- $keys := keys .Values.trust | sortAlpha }} + value: "{{ join "," $keys }}" + {{- end }} + {{- if .Values.developmentLandcsape }} + - name: DEVELOPMENT_INSTANCE + value: "{{ .Values.developmentLandcsape }}" + {{- end }} + {{- if .Values.featureToggles }} + - name: FEATURE_TOGGLES + value: "{{ .Values.featureToggles }}" + {{- end }} + - name: PORT + value: "{{ .Values.port }}" + - name: REGION + value: {{ .Values.region }} + - name: IMAGE_TAG + value: "{{ .Chart.AppVersion }}" + - name: IMAGE_NAME + value: "{{ .Values.image.name }}" + {{- if .Values.cookieDomain }} + - name: COOKIE_DOMAIN + value: {{ .Values.cookieDomain }} + {{- end }} + {{- if .Values.crdGatewayApiUrl }} + - name: CRD_GATEWAY_API_URL + value: {{ .Values.crdGatewayApiUrl }} + {{- end }} + {{- if .Values.frontendPort }} + - name: FRONTEND_PORT + value: "{{ .Values.frontendPort }}" + {{- end }} + {{- if .Values.environment }} + - name: ENVIRONMENT + value: "{{ .Values.environment }}" + {{- end }} + {{- if .Values.validWebcomponentUrls }} + - name: VALID_WEBCOMPONENT_URLS + value: '{{ .Values.validWebcomponentUrls }}' + {{- end }} + resources: + limits: + cpu: "1" + memory: 512Mi + requests: + cpu: 40m + memory: 50Mi + ports: + - name: http + containerPort: {{ .Values.port }} \ No newline at end of file diff --git a/charts/portal/templates/external-secrets.yaml b/charts/portal/templates/external-secrets.yaml new file mode 100644 index 000000000..21248179d --- /dev/null +++ b/charts/portal/templates/external-secrets.yaml @@ -0,0 +1,33 @@ +{{- if .Values.externalSecrets.enabled -}} +{{- $namespace := .Release.Namespace}} +{{- $secretKeys := list }} +{{- range $key, $idp := .Values.trust }} + {{- $keyToAdd := $idp.secretKey | default $key }} + {{- if not (has $idp.secretKey $secretKeys) }} + {{- $secretKeys = append $secretKeys $keyToAdd }} + {{- end }} +{{- end }} +{{- range $key := $secretKeys }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ $.Release.Name }}-portal-client-secret-{{ $key }} + namespace: {{ $namespace }} +spec: + refreshInterval: 10m + secretStoreRef: + kind: SecretStore + name: environment-store + target: + creationPolicy: Owner + deletionPolicy: Retain + name: portal-client-secret-{{ $key }} + data: + - remoteRef: + conversionStrategy: Default + key: dxp-core-team/manual-secrets/portal-client-secrets + property: {{ $key }} + secretKey: secret +--- +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/portal/templates/istio-destination-rule.yaml b/charts/portal/templates/istio-destination-rule.yaml new file mode 100644 index 000000000..6c210d77b --- /dev/null +++ b/charts/portal/templates/istio-destination-rule.yaml @@ -0,0 +1,12 @@ +{{- if .Values.istio.enabled -}} +apiVersion: "networking.istio.io/v1alpha3" +kind: "DestinationRule" +metadata: + name: {{ include "entity.name" . }} + namespace: {{ .Release.Namespace }} +spec: + host: {{ include "entity.name" . }}.{{ .Release.Namespace }}.svc.cluster.local + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +{{- end -}} \ No newline at end of file diff --git a/charts/portal/templates/istio-peerauthentication.yaml b/charts/portal/templates/istio-peerauthentication.yaml new file mode 100644 index 000000000..c12e10607 --- /dev/null +++ b/charts/portal/templates/istio-peerauthentication.yaml @@ -0,0 +1,13 @@ +{{- if .Values.istio.enabled -}} +apiVersion: "security.istio.io/v1beta1" +kind: "PeerAuthentication" +metadata: + name: {{ include "entity.name" . }} + namespace: {{ .Release.Namespace }} +spec: + selector: + matchLabels: + app: {{ include "entity.name" . }} + mtls: + mode: STRICT +{{- end -}} \ No newline at end of file diff --git a/charts/portal/templates/istio-virtual-service.yaml b/charts/portal/templates/istio-virtual-service.yaml new file mode 100644 index 000000000..f2a3bc134 --- /dev/null +++ b/charts/portal/templates/istio-virtual-service.yaml @@ -0,0 +1,37 @@ +{{- if .Values.istio.enabled -}} +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: {{ include "entity.name" . }} + namespace: {{ .Release.Namespace }} +spec: + gateways: + - {{ .Release.Namespace }}/gateway + hosts: + {{- if (.Values.istio.virtualService).hosts }} +{{ .Values.istio.virtualService.hosts | toYaml | nindent 2}} + {{- else }} + {{ range $domainName := .Values.baseDomains }} + - {{ $domainName }} + {{- range $key, $idp := $.Values.trust }} + - {{ $key }}.{{ $domainName }} + {{- end }} + {{- end }} + {{- end }} + http: + - corsPolicy: + allowHeaders: + - Authorization + - Content-Type + - '*' + allowMethods: + - GET + - POST + - PUT + - DELETE + route: + - destination: + host: {{ include "entity.name" . }}.{{ .Release.Namespace }}.svc.cluster.local + port: + number: 8080 +{{- end -}} \ No newline at end of file diff --git a/charts/portal/templates/rbac.yaml b/charts/portal/templates/rbac.yaml new file mode 100644 index 000000000..8b6f9fbf4 --- /dev/null +++ b/charts/portal/templates/rbac.yaml @@ -0,0 +1,23 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: contentconfigurations-reader +rules: + - apiGroups: ["core.openmfp.io"] + resources: ["contentconfigurations"] + verbs: ["get", "watch", "list"] + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: read-contentconfigurations-global +subjects: + - kind: ServiceAccount + name: {{ include "entity.name" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: contentconfigurations-reader + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/charts/portal/templates/sa.yaml b/charts/portal/templates/sa.yaml new file mode 100644 index 000000000..a86085722 --- /dev/null +++ b/charts/portal/templates/sa.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "entity.name" . }} + namespace: {{ .Release.Namespace }} +imagePullSecrets: + - name: {{ .Values.image.pullSecret }} diff --git a/charts/portal/templates/service.yaml b/charts/portal/templates/service.yaml new file mode 100644 index 000000000..93d46a049 --- /dev/null +++ b/charts/portal/templates/service.yaml @@ -0,0 +1,13 @@ +kind: Service +apiVersion: v1 +metadata: + name: {{ include "entity.name" . }} + namespace: {{ .Release.Namespace }} +spec: + selector: + app: {{ include "entity.name" . }} + ports: + - name: http + protocol: TCP + port: 8080 + type: ClusterIP diff --git a/charts/portal/templates/sidecar.yaml b/charts/portal/templates/sidecar.yaml new file mode 100644 index 000000000..5a283ba2b --- /dev/null +++ b/charts/portal/templates/sidecar.yaml @@ -0,0 +1,13 @@ +{{- if .Values.istio.enabled -}} +apiVersion: networking.istio.io/v1beta1 +kind: Sidecar +metadata: + name: {{ include "entity.name" . }} + namespace: {{ .Release.Namespace }} +spec: + workloadSelector: + labels: + app: {{ include "entity.name" . }} + outboundTrafficPolicy: + mode: ALLOW_ANY +{{- end -}} \ No newline at end of file diff --git a/charts/portal/test-values.yaml b/charts/portal/test-values.yaml new file mode 100644 index 000000000..2ae9544b5 --- /dev/null +++ b/charts/portal/test-values.yaml @@ -0,0 +1,14 @@ +image: + tag: 12345 + +baseDomains: + - portal.example.com + - portal2.example.com + +trust: + portal: + baseDomains: "portal.example.com,portal2.example.com" + authDomain: https://auth.example.com + discoveryEndpoint: https://auth.example.com/.well-known/openid-configuration + loginAudience: "12345" + oidcClientSecretName: portal \ No newline at end of file diff --git a/charts/portal/tests/__snapshot__/deploy_test.yaml.snap b/charts/portal/tests/__snapshot__/deploy_test.yaml.snap new file mode 100644 index 000000000..176a2317e --- /dev/null +++ b/charts/portal/tests/__snapshot__/deploy_test.yaml.snap @@ -0,0 +1,72 @@ +matches the snapshot: + 1: | + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app: RELEASE-NAME-portal + name: RELEASE-NAME-portal + namespace: NAMESPACE + spec: + revisionHistoryLimit: 3 + selector: + matchLabels: + app: RELEASE-NAME-portal + strategy: + rollingUpdate: + maxSurge: 5 + maxUnavailable: 0 + template: + metadata: + labels: + app: RELEASE-NAME-portal + spec: + containers: + - env: + - name: HTTP_PROTOCOL + value: https + - name: OIDC_CLIENT_ID_PORTAL + value: "12345" + - name: OIDC_CLIENT_SECRET_PORTAL + valueFrom: + secretKeyRef: + key: secret + name: portal-client-secret-portal + - name: DISCOVERY_ENDPOINT_PORTAL + value: https://auth.example.com/.well-known/openid-configuration + - name: BASE_DOMAINS_PORTAL + value: portal.example.com,portal2.example.com + - name: IDP_NAMES + value: portal + - name: FEATURE_TOGGLES + value: enableSessionAutoRefresh=true + - name: PORT + value: "8080" + - name: REGION + value: null + - name: IMAGE_TAG + value: 1.0.0 + - name: IMAGE_NAME + value: ghcr.io/openmfp/portal + - name: VALID_WEBCOMPONENT_URLS + value: .? + image: ghcr.io/openmfp/portal:1.0.0 + imagePullPolicy: IfNotPresent + name: RELEASE-NAME-portal + ports: + - containerPort: 8080 + name: http + resources: + limits: + cpu: "1" + memory: 512Mi + requests: + cpu: 40m + memory: 50Mi + securityContext: + readOnlyRootFilesystem: true + securityContext: + fsGroup: 2000 + runAsGroup: 3000 + runAsUser: 1000 + serviceAccountName: RELEASE-NAME-portal diff --git a/charts/portal/tests/__snapshot__/external-secrets_test.yaml.snap b/charts/portal/tests/__snapshot__/external-secrets_test.yaml.snap new file mode 100644 index 000000000..9af794cf2 --- /dev/null +++ b/charts/portal/tests/__snapshot__/external-secrets_test.yaml.snap @@ -0,0 +1,22 @@ +matches the snapshot: + 1: | + apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + name: RELEASE-NAME-portal-client-secret-portal + namespace: NAMESPACE + spec: + data: + - remoteRef: + conversionStrategy: Default + key: dxp-core-team/manual-secrets/portal-client-secrets + property: portal + secretKey: secret + refreshInterval: 10m + secretStoreRef: + kind: SecretStore + name: environment-store + target: + creationPolicy: Owner + deletionPolicy: Retain + name: portal-client-secret-portal diff --git a/charts/portal/tests/__snapshot__/istio-virtual_service_test.yaml.snap b/charts/portal/tests/__snapshot__/istio-virtual_service_test.yaml.snap new file mode 100644 index 000000000..61a6bfb54 --- /dev/null +++ b/charts/portal/tests/__snapshot__/istio-virtual_service_test.yaml.snap @@ -0,0 +1,31 @@ +virtual service match the snapshot: + 1: | + apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: RELEASE-NAME-portal + namespace: NAMESPACE + spec: + gateways: + - NAMESPACE/gateway + hosts: + - portal.example.com + - portal.portal.example.com + - portal2.example.com + - portal.portal2.example.com + http: + - corsPolicy: + allowHeaders: + - Authorization + - Content-Type + - '*' + allowMethods: + - GET + - POST + - PUT + - DELETE + route: + - destination: + host: RELEASE-NAME-portal.NAMESPACE.svc.cluster.local + port: + number: 8080 diff --git a/charts/portal/tests/__snapshot__/istio_test.yaml.snap b/charts/portal/tests/__snapshot__/istio_test.yaml.snap new file mode 100644 index 000000000..25f5b37c9 --- /dev/null +++ b/charts/portal/tests/__snapshot__/istio_test.yaml.snap @@ -0,0 +1,349 @@ +matches the snapshot: + 1: | + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app: RELEASE-NAME-portal + name: RELEASE-NAME-portal + namespace: NAMESPACE + spec: + revisionHistoryLimit: 3 + selector: + matchLabels: + app: RELEASE-NAME-portal + strategy: + rollingUpdate: + maxSurge: 5 + maxUnavailable: 0 + template: + metadata: + labels: + app: RELEASE-NAME-portal + spec: + containers: + - env: + - name: HTTP_PROTOCOL + value: https + - name: OIDC_CLIENT_ID_PORTAL + value: "12345" + - name: OIDC_CLIENT_SECRET_PORTAL + valueFrom: + secretKeyRef: + key: secret + name: portal-client-secret-portal + - name: DISCOVERY_ENDPOINT_PORTAL + value: https://auth.example.com/.well-known/openid-configuration + - name: BASE_DOMAINS_PORTAL + value: portal.example.com,portal2.example.com + - name: IDP_NAMES + value: portal + - name: FEATURE_TOGGLES + value: enableSessionAutoRefresh=true + - name: PORT + value: "8080" + - name: REGION + value: null + - name: IMAGE_TAG + value: 1.0.0 + - name: IMAGE_NAME + value: ghcr.io/openmfp/portal + - name: VALID_WEBCOMPONENT_URLS + value: .? + image: ghcr.io/openmfp/portal:1.0.0 + imagePullPolicy: IfNotPresent + name: RELEASE-NAME-portal + ports: + - containerPort: 8080 + name: http + resources: + limits: + cpu: "1" + memory: 512Mi + requests: + cpu: 40m + memory: 50Mi + securityContext: + readOnlyRootFilesystem: true + securityContext: + fsGroup: 2000 + runAsGroup: 3000 + runAsUser: 1000 + serviceAccountName: RELEASE-NAME-portal + 2: | + apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + name: RELEASE-NAME-portal-client-secret-portal + namespace: NAMESPACE + spec: + data: + - remoteRef: + conversionStrategy: Default + key: dxp-core-team/manual-secrets/portal-client-secrets + property: portal + secretKey: secret + refreshInterval: 10m + secretStoreRef: + kind: SecretStore + name: environment-store + target: + creationPolicy: Owner + deletionPolicy: Retain + name: portal-client-secret-portal + 3: | + apiVersion: networking.istio.io/v1alpha3 + kind: DestinationRule + metadata: + name: RELEASE-NAME-portal + namespace: NAMESPACE + spec: + host: RELEASE-NAME-portal.NAMESPACE.svc.cluster.local + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + 4: | + apiVersion: security.istio.io/v1beta1 + kind: PeerAuthentication + metadata: + name: RELEASE-NAME-portal + namespace: NAMESPACE + spec: + mtls: + mode: STRICT + selector: + matchLabels: + app: RELEASE-NAME-portal + 5: | + apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: RELEASE-NAME-portal + namespace: NAMESPACE + spec: + gateways: + - NAMESPACE/gateway + hosts: + - portal.example.com + - portal.portal.example.com + - portal2.example.com + - portal.portal2.example.com + http: + - corsPolicy: + allowHeaders: + - Authorization + - Content-Type + - '*' + allowMethods: + - GET + - POST + - PUT + - DELETE + route: + - destination: + host: RELEASE-NAME-portal.NAMESPACE.svc.cluster.local + port: + number: 8080 + 6: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: contentconfigurations-reader + rules: + - apiGroups: + - core.openmfp.io + resources: + - contentconfigurations + verbs: + - get + - watch + - list + 7: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: read-contentconfigurations-global + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: contentconfigurations-reader + subjects: + - kind: ServiceAccount + name: RELEASE-NAME-portal + namespace: NAMESPACE + 8: | + apiVersion: v1 + imagePullSecrets: + - name: github + kind: ServiceAccount + metadata: + name: RELEASE-NAME-portal + namespace: NAMESPACE + 9: | + apiVersion: v1 + kind: Service + metadata: + name: RELEASE-NAME-portal + namespace: NAMESPACE + spec: + ports: + - name: http + port: 8080 + protocol: TCP + selector: + app: RELEASE-NAME-portal + type: ClusterIP + 10: | + apiVersion: networking.istio.io/v1beta1 + kind: Sidecar + metadata: + name: RELEASE-NAME-portal + namespace: NAMESPACE + spec: + outboundTrafficPolicy: + mode: ALLOW_ANY + workloadSelector: + labels: + app: RELEASE-NAME-portal +matches the snapshot with istio disabled: + 1: | + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app: RELEASE-NAME-portal + name: RELEASE-NAME-portal + namespace: NAMESPACE + spec: + revisionHistoryLimit: 3 + selector: + matchLabels: + app: RELEASE-NAME-portal + strategy: + rollingUpdate: + maxSurge: 5 + maxUnavailable: 0 + template: + metadata: + labels: + app: RELEASE-NAME-portal + spec: + containers: + - env: + - name: HTTP_PROTOCOL + value: https + - name: OIDC_CLIENT_ID_PORTAL + value: "12345" + - name: OIDC_CLIENT_SECRET_PORTAL + valueFrom: + secretKeyRef: + key: secret + name: portal-client-secret-portal + - name: DISCOVERY_ENDPOINT_PORTAL + value: https://auth.example.com/.well-known/openid-configuration + - name: BASE_DOMAINS_PORTAL + value: portal.example.com,portal2.example.com + - name: IDP_NAMES + value: portal + - name: FEATURE_TOGGLES + value: enableSessionAutoRefresh=true + - name: PORT + value: "8080" + - name: REGION + value: null + - name: IMAGE_TAG + value: 1.0.0 + - name: IMAGE_NAME + value: ghcr.io/openmfp/portal + - name: VALID_WEBCOMPONENT_URLS + value: .? + image: ghcr.io/openmfp/portal:1.0.0 + imagePullPolicy: IfNotPresent + name: RELEASE-NAME-portal + ports: + - containerPort: 8080 + name: http + resources: + limits: + cpu: "1" + memory: 512Mi + requests: + cpu: 40m + memory: 50Mi + securityContext: + readOnlyRootFilesystem: true + securityContext: + fsGroup: 2000 + runAsGroup: 3000 + runAsUser: 1000 + serviceAccountName: RELEASE-NAME-portal + 2: | + apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + name: RELEASE-NAME-portal-client-secret-portal + namespace: NAMESPACE + spec: + data: + - remoteRef: + conversionStrategy: Default + key: dxp-core-team/manual-secrets/portal-client-secrets + property: portal + secretKey: secret + refreshInterval: 10m + secretStoreRef: + kind: SecretStore + name: environment-store + target: + creationPolicy: Owner + deletionPolicy: Retain + name: portal-client-secret-portal + 3: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: contentconfigurations-reader + rules: + - apiGroups: + - core.openmfp.io + resources: + - contentconfigurations + verbs: + - get + - watch + - list + 4: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: read-contentconfigurations-global + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: contentconfigurations-reader + subjects: + - kind: ServiceAccount + name: RELEASE-NAME-portal + namespace: NAMESPACE + 5: | + apiVersion: v1 + imagePullSecrets: + - name: github + kind: ServiceAccount + metadata: + name: RELEASE-NAME-portal + namespace: NAMESPACE + 6: | + apiVersion: v1 + kind: Service + metadata: + name: RELEASE-NAME-portal + namespace: NAMESPACE + spec: + ports: + - name: http + port: 8080 + protocol: TCP + selector: + app: RELEASE-NAME-portal + type: ClusterIP diff --git a/charts/portal/tests/__snapshot__/virtual_service_test.yaml.snap b/charts/portal/tests/__snapshot__/virtual_service_test.yaml.snap new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/charts/portal/tests/__snapshot__/virtual_service_test.yaml.snap @@ -0,0 +1 @@ +{} diff --git a/charts/portal/tests/deploy_test.yaml b/charts/portal/tests/deploy_test.yaml new file mode 100644 index 000000000..2472af1b5 --- /dev/null +++ b/charts/portal/tests/deploy_test.yaml @@ -0,0 +1,13 @@ +suite: deploy +templates: + - deploy.yaml +chart: + version: 1.0.0 + appVersion: 1.0.0 +tests: + - it: matches the snapshot + values: + - ../test-values.yaml + template: deploy.yaml + asserts: + - matchSnapshot: {} diff --git a/charts/portal/tests/external-secrets_test.yaml b/charts/portal/tests/external-secrets_test.yaml new file mode 100644 index 000000000..01123e39e --- /dev/null +++ b/charts/portal/tests/external-secrets_test.yaml @@ -0,0 +1,10 @@ +suite: external-secrets +templates: + - external-secrets.yaml +tests: + - it: matches the snapshot + values: + - ../test-values.yaml + template: external-secrets.yaml + asserts: + - matchSnapshot: {} diff --git a/charts/portal/tests/istio-virtual_service_test.yaml b/charts/portal/tests/istio-virtual_service_test.yaml new file mode 100644 index 000000000..478bfe100 --- /dev/null +++ b/charts/portal/tests/istio-virtual_service_test.yaml @@ -0,0 +1,9 @@ +suite: virtual service +templates: + - istio-virtual-service.yaml +values: + - ../test-values.yaml +tests: + - it: virtual service match the snapshot + asserts: + - matchSnapshot: {} diff --git a/charts/portal/tests/istio_test.yaml b/charts/portal/tests/istio_test.yaml new file mode 100644 index 000000000..e5f10aa9e --- /dev/null +++ b/charts/portal/tests/istio_test.yaml @@ -0,0 +1,18 @@ +suite: deploy +chart: + version: 1.0.0 + appVersion: 1.0.0 +tests: + - it: matches the snapshot + values: + - ../test-values.yaml + asserts: + - matchSnapshot: {} + - it: matches the snapshot with istio disabled + values: + - ../test-values.yaml + set: + istio: + enabled: false + asserts: + - matchSnapshot: {} diff --git a/charts/portal/values.yaml b/charts/portal/values.yaml new file mode 100644 index 000000000..493032ede --- /dev/null +++ b/charts/portal/values.yaml @@ -0,0 +1,24 @@ +image: + name: ghcr.io/openmfp/portal + pullPolicy: IfNotPresent + pullSecret: github + +deployment: + maxUnavailable: 0 + maxSurge: 5 + +port: 8080 + +istio: + enabled: true + +externalSecrets: + enabled: true + +http: + protocol: https + +importContent: true + +validWebcomponentUrls: ".?" +featureToggles: "enableSessionAutoRefresh=true" From 34dfc63419d8f141bdf5fb41a09b4a3b6ba2800d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20Echterh=C3=B6lter?= Date: Thu, 21 Nov 2024 10:25:39 +0100 Subject: [PATCH 2/5] feat: removing gateway parameter --- charts/portal/templates/deploy.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/charts/portal/templates/deploy.yaml b/charts/portal/templates/deploy.yaml index 6e4970f06..1b4efff89 100644 --- a/charts/portal/templates/deploy.yaml +++ b/charts/portal/templates/deploy.yaml @@ -80,10 +80,6 @@ spec: - name: COOKIE_DOMAIN value: {{ .Values.cookieDomain }} {{- end }} - {{- if .Values.crdGatewayApiUrl }} - - name: CRD_GATEWAY_API_URL - value: {{ .Values.crdGatewayApiUrl }} - {{- end }} {{- if .Values.frontendPort }} - name: FRONTEND_PORT value: "{{ .Values.frontendPort }}" From d8a45ee2f1e0a84dd8ffeb81f407fc47b815be90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20Echterh=C3=B6lter?= Date: Thu, 21 Nov 2024 13:54:19 +0100 Subject: [PATCH 3/5] chore: upstream changes --- charts/portal/Chart.lock | 6 +- charts/portal/Chart.yaml | 4 +- charts/portal/charts/common-0.1.4.tgz | Bin 0 -> 22091 bytes charts/portal/templates/deploy.yaml | 12 +-- .../templates/istio-destination-rule.yaml | 6 +- .../templates/istio-peerauthentication.yaml | 6 +- .../templates/istio-virtual-service.yaml | 10 +-- charts/portal/templates/rbac.yaml | 2 +- charts/portal/templates/sa.yaml | 2 +- charts/portal/templates/service.yaml | 4 +- charts/portal/templates/sidecar.yaml | 6 +- .../tests/__snapshot__/istio_test.yaml.snap | 71 +----------------- .../tests/istio-virtual_service_test.yaml | 4 + charts/portal/tests/istio_test.yaml | 3 + 14 files changed, 39 insertions(+), 97 deletions(-) create mode 100644 charts/portal/charts/common-0.1.4.tgz diff --git a/charts/portal/Chart.lock b/charts/portal/Chart.lock index 831646171..fa76da0ce 100644 --- a/charts/portal/Chart.lock +++ b/charts/portal/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common repository: file://../common - version: 0.1.3 -digest: sha256:458eeb38012b33fb226ca0cb45ecbcdd21e2a28025619bc0b01dd71a079c9882 -generated: "2024-10-11T11:24:57.022871+02:00" + version: 0.1.4 +digest: sha256:05e31c3eb487f942d4ac07ce0dfe4e0620779b589ef481cdd6534c73a7f0ca27 +generated: "2024-11-20T11:36:34.0773803+02:00" diff --git a/charts/portal/Chart.yaml b/charts/portal/Chart.yaml index 80f9a1b1c..03b4b89dd 100644 --- a/charts/portal/Chart.yaml +++ b/charts/portal/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 appVersion: "0.164.0" description: Helm Chart for the openmfp Portal name: portal -version: 0.69.87 +version: 0.69.88 dependencies: - name: common repository: file://../common - version: 0.1.3 + version: 0.1.4 diff --git a/charts/portal/charts/common-0.1.4.tgz b/charts/portal/charts/common-0.1.4.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a82fafeec0502ae20bfb9161a66a82c8e4c551cf GIT binary patch literal 22091 zcmV(zK<2+6iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0POm8R9sEAH;&_)-~E>g_n`eSncO9bcu)&s#2U>H;!;LML_2|`%F!4AmZ?&Sc=Ac#G{ z;%99DtYC0}ijz4A4h11W2s|jz9wZLuoS#QUGl z@IUfj$)E7=41_p=5dW7ZfPaSnpVxoDzX+eefAIhBkUxz-5@hcH0U|*N9#abt9H|C` z0rI{de);-8H_KcCPa#$SYwpYK28|L+hF4=#Wu$O;Sv0T_PO0{7n+ z00V%_%M0&Msz4_Q62Qu>_iM)ZD`hrr&@XiWE9;-1TSH*xKnUAE)MNXzSrF9n=k@<| zXZ-)6{5}3bP$U@XrVg|R{daNyyZkf!3kvi70slfm0>b~n|Gz{20sem#0QXOZ_ZQ%U ztpFAu;0#n>hc*-T$|X|LFny7t7z{A8Ze_ z25CA$AUYrmI0*SKm<0am`p^Hz^JOF?T@M{z3 z;qhl$@cXL&2X(;T(SbiI{D%kp56M5kKLQDc{fn6YFZrk6e?$cSh<{%G|Lp(%E%J}> z|5pX@UoijQ)c#A(|F;_dVf+6t%AfI%Kyv-|p^t~#1_ZGOTSH-R(7(vXKf}L}z#rFt zK@lOL|KR`MA&dY`AQB0JLlFQZ4Df5%0WLNmD8Sqa46y`5tpN@|3p=1S2*HiV2zX%w zMgR~_4h}Fl5&=NifFKaSPq+i@fk+D*Fw~k800%*UNU$>q-~dG0{8c*;YKg}PfP$=n zNH7cvV0D0ltiY}yOMnX)X#;q~#tqPbLfil_=x=ZS3<=->f&(C6D2N-6`>Bqp4iW|j z;V}Z_e=Avlp1cmg5)4P+aa)6tJiq<^3LlT#+#SyI+wboUHr6~pe}2D3I74~Dc>Xu+75*OozcyMBn1$WH%Ev#$zW}e`AMr0F z!22Kk|2xDI)5JDX9cS`@Ka~%Kx4sw7Yz(^R}P5d{2i1YApbK?O3e>mf@ z1Y3g;NO1td2FNcYEY2%nE+)ilB_s?4frLQjqCi2Qu$4J4zp${FrHCMi&q_p8NYskg zLRidFfKQko2oe@B=LZQ32v~_&@C%Cy<5`2CAUF^SvJ?j}@bmHua`EwT@$B%9Egff`5JiUg5vPzuU_F(gyUWd@VuFAPCF>1m_04umQQTz(D{o)B@sU`P2JPzd*pBr&+h3 z2>|~-&!6NA`jbrnkTx&`=&u|Dp_YH;`M2bLx`zL>2M0r~@fZOPU?#}@NS^cDZ7C`7v&A;iMU&s1?6)fKG3=oX?tMvcW)!e@x{pk(> zb+R`H!2t*xm=nbEr(H1A0uHhVL6IO!00?Md13-f9K>#d0)e>zbU^k%C=zV( zyW&qXtTsrb145jK2LZBo2En;uaBCj6zx_7`-an@Phctgy<*#7=Jh0}VpSJ(poBwt1 z;4%Im_RsIV^H-j@|2FBL!}wQ;<1zjhssAe2-@|}|tRTNC@GtrOF)J_v;Dq@3CLSZ; z8S>{X9Q1Py`B{y>^|KQK1OOv{k$Oib81m=70qEfH=ShZvkDE`Jo0kC(?{BHcU%n^) znSA^m&G^~$4;jh-^epP0|wRtU+)r3{u#DvTR^mr|Ggut(K#Dq2U^n}&)A+|uMrP~WF znAA@efU)>E(hR!%1Mj-l}oO3nK zo%_=A@-oTd%GGXWSlIT^ozbkPB+jg-|Ezxl+N{5kKaSC?q^Exa4odMIcG-1+X!|07 z6>Z|Ksziq6Oy;R~W zjnbAdC;*sr3XmwpS=2u>Yn!8OWk4}}!$yYT)Q!BDqoatX=?T7ANMG_OlY(+fb?ZZShkNHQDS6j=*DQa_f9p`1p2LMh5adW5u)9Q5dxalOONrxhorr9g zq4ANvl^MFbzV^Jnqq_46c6EoN^tV1B^5FH|o9IFJQQt+P5WrylnIexKpa@`lh~k(N zqNDhHd!5;cit-`Az7;@uJ~3q)N1H|DQH$xj#}>Y~AJ>TDP*BlGCF^_UqE^ba<8w&X z4I{iwU-L2Vn!hf2d+Qy3(Vh0rr|iesvm4_ypN&1A{pDtl+}nj7nPqx&>~f4|WOdaT zN~&Dzfln*b!O+1_d;1;BHU0tOF8J=oa5d^>S)~&%<`ml9C<;=>@8G>1FR?0$FZw|k zhP(T1B?`Pc5Z!mW*|j5c6t%y3;e5@1jh^h5&hBnb;o>g(n&*HpK>p$Cu3Ub#*|E=k z^z-*uGIH}WE16+uGS~YH3_cxqB_=4hWvI8+mbV0l%}*{wgdPCS6B&GyFX-iNU8p&I zObYJmb?&0BiSKwtyJ0k5>hH)W#|g~A`zV-qVV>6l*T=`VZZ{jGWQ$jXw|BHp2widg z+gmj~C{gxM&V_bR^f^kUT1KhN?Fh*hljBJ%kF0UB#1U(AjN_u4Hn z+l*-W4E*u|G^%=l*}aW2bTadh-mQRVgkQ1b9uW-k`o^S5-Xr~v<5Y^3+REoggy4O1 zoG3opN=^D5O#s1*jkwjAwy(vmrUm?F>F%3F(rVuiW9 zL_xH)EJVJ(QNBol;@5g@rt^r1Ub&?$E=);QcG4)Cu;2a>YX^^ID~K5Y8SLX~K}W+s zNICMwbamsx7;wdSjls*+dTPdsLm*6n`t{J^@W9alfjDpg!;eD`4#Ex&Py%0L)LvXn z*48T2)_%WbY1z4ht@#As`K+Zb`uO|MnQ;60w8-4~%>OJ`jRha?);rkTfzPcRPAnbZ zCQ-r);NiqM#*-O-}m{c-QZlp`LGBk)zb0-Hgqd+JuUsm=n63d- zz04>M9N3iSgpqQm>pln9hHx2Ud7tTkCp%nxo2ZdQN(V5>&7r9z36ve$#b(%n?CG9Q z!JJ0D3^oqrF!m_fZ^y^>*4WM4Yy3*SG^trY7H5ZW^Db|+#kA%Yj#cVXEr2PH%FBUm zZFrpN{OHt5vy^s{jzAdOSI$ZgMYMz9o`Z`6)}$ZAy8;BexMIB-I3HqtB(r_&F}vea zxT|4xsdInz`}qWpH-DvRa5FXb&N`0p)h6K{N~uF>m6HRejqk4Psl%J8{ZN?!Uc=U< zNM2%fb;`*>%zK#PvRq;Yx3>b!6PY@9Iw>;sNBX=zv@dlIG-iB0t@{|$s$Sl;UtXJ} z%ebQ5dJW429}#*i5#OE>noveVj$)zcO z%-x>BiBIwM%H^Hi*5b8Oz)DRU`ceYj9fkDm_K(b{FpWj}`MX1Wyld;5I~SY*ntRI& z1avQnCS^mnjI2UGpt0|@UFSDU8?94c6G`0%q6*pDqw3Nc+C?{hu3zWCKFs7qSz4Ue zO?0i+BcTv$F;XYMBxWG@&7vmsP&^PG)`%QtzxuYE*cp*6YEoBg^x038avJ4Af}JeL zen%&S!KBY*sc4BKqzH3~5tjLZUIB#2h)v2^%K^Q5Wt)eFdRZbNi@o)LnKem*vML_# zqW_eVRhdOIX`l8(bKI)DuV&+ce%2*T*0#F{*jGx3URpdBz(R-F=9bz^q$cxBl;nn@ z5L-b0**A`bcc+DkqLj)}{`Hzf#=~>&hsQY4A9J9_lf-kH(z=XqsZO)2a-K4t4C(YN zB7kOCNbJi*G_>o;Caj<*Me@ASlMBIS4o)QDbTM`4DBodhQB2LBxHA*?-`$;$XS@t+ zKI9ETLfq!64-US!hS|2d++<0nu5&WWo>h6baCinWKaGp_efXi9cKY16bq4h0p{ZXm zCSUInHXk24&%!rsi_N#hh8Pv4N*y+DOdBd@^@Y1l-levrd882dYZEi**S_iH1--pa z=ne?7A|k4^AwB$zqp|PuwdnjUFGz>Txo5s@rr(ID;?VB%cVf}^Vk3v~B20k`o~eYe zu)9G^+u@mf7YU}a)kUu3o83U`tf;lqZyh&++fk15VZsIr&|X|s!+!lLp|KP{%SvB{ z1@1bFzU|$Jh*TxQ0rM$)YkPY+X&9Xy>%_<)k%=9^lke#(F0vkUO~%R`W9#fUZ>VLI zk|z4(qC>^u`+5?xll%|BT!qa~2n~dPj;&DVh)z_VrE^ zcwz#d!X$KiGEqaOd4zfjh+r5lC2q}`V)GtzFxaP(c^&EVY;OhciB{Ecf7Y;*;j$Y% zf9Y6edw)QYY21(+#LvJ_@nTvdUXNIoi@WL#tshz`2bXatfcazve{@V9t$0}vu%<|0 zjR4y)0+OZOnQ!jo={UiMRcV14e)67qzOs1s@!+HZ-<6jW zQJ*b)3~_qJvte9MQTOrDysC4g1L97(7#?Nl#+jx-R#ij_8K7}X^i&!|m{-voHaU9k zhdlJ9Tcuw0^u>FkaoZLi({WejdKIO0`))q96ZkjZy?7J$I%`@fndO)7N4wE1jwiTq zCx4E5?MvLH@k6;O03dEg@l?ET`?6F2kg|&Q&4UMtOQ5OF`2`O?ZfB{^igS zg-hCr@{=Y1T4@AZ*L2sqMe(N}MBS?^u@x(V&B`L9Jy?%KmIyo<-|gVvQyb*!a18IIBQpRQ`GJ;2VKz>!HvYu((M)T#?{9>?2@n8y=h~?S7x5Jj)g*jlxX~d#Q=uKjm5JSFu%@; zhTLWOxwd!2>ReeA5pkaE5Q&{f?7Aoq8qtie?zd;P-h>h}i#ntEKt&8IlSgejU+7|2 zNwK9(C$q%wQpANwm|+^+b;S_2-6ODx9=;1sdB_UJ`**3&j_Tz1vo4pILo4w#<^40Z z0ek&b+dEBGy^qQ__SoP=>HC*aNoO|FN;T@N-WBev{O34stN1z=6I-(8VE`FpFzGrk z6oUzsZgmG@?qxTIXmBz2MYP`r<~xh^cXlH^#kp811h->&IX9P`t?R|e=V z3eG329G=VhKrH;VH$&2qR% zNv(44Q;K_A#D3I>pY+}IfxQj(SB&t=FflFu7hkqM*w@)|eHbAy>n5%Ffx$fVwUfuS zAiE(xVl!Y|lh82mppMg|S<*cVoEj`)ZCR&sWK8e?F-v8fNrzbymfsL%RG}4q80ST@ ze!qUs;OZ^%NoKvA*;3At)LV4wrji=DA!;&`*ScTKB@H!;%B8{zG|k<3RRwf{Y0xXr z_@?*6-^|DvZlsKNi)(N4xLcmLihjmluuGl2+LS_NbnC%@ImKNiq9bvo`Jc~sEBZl0 zr5}17lbjn;#_A^IP3bmzzl3o}xB_X2>&KLlSCD}xYNqsQ0TzQ!n@qq4Ht`u6yvv^?3X*5pIHaNx|V(_ zdn9RfHl8-|wQ*JL+hy{aY7sAd(ws*ZYIdFrm}Y0P_V--|%6L5Jf)*MX(u_~Jd7cI= zM=0+(y*`#pF1oX-t(ed!B=R-u-sFQx%;di*rSn(7%&0)(jl_zjvAmCpj*LEU$rp0@ zROj|V?on_5v{74O$u;H9wDL9iykYUoys4zWMPBzX2_0rMp^C59i>3{xxA*bCg*`XR zmBBB47sJ4`VRigISqDYG@Em=~`mrE5No9(vPi~3&^Rd;V8pGqhBHE}}XEL}3PhQGY zL^6FDT4SB=2E&jzGmlH~$m;}7rz6JteUQfL1GdG#g~$GWhx_1-wDw?aK92_ zAl&e%!?M<<8dj3Wc^ej)h1Jn(`AwdFJ2`YZrhKXK;57wZRtd=_r%4s1g3QhHk7p0h zjvUQ&sj;WNi zuKOZ~!TqeH^&C@Ekd|fK4Qk8`&R_QSA7Hpqbmo1B@67Yi7?#X5a>P6&`6NU-SKI$< zpMzR1NlO<6PkTmu_=8N1CbISW6@)SjVp|;{Gb}pWY}NtEpVGNT`_66XFdHUBIOk*{ zMhzol#_mOrF*$#xV6#^seq=WI99B)`US9ha{kp+*Vsl{mXeS4`DiD8@m15)-*tY9f zDQXR18zup#1W8k~`Gn;1Tk` zs+c?)pYI225GYy2D6-;K#FH(Qgryr#N&7si4fu4&H|qMG>hUhb6|A`^)tA`NZ>DPk zRrvwQgW9#0zb|{5^B777Al-OBYwe2V?<8O0EQHY+ggfL|6rEoCxNNq-EwSxOU51L9 zDif)x%}9N2;uwiX{UD0GTv}Blyrf+lD{3_}Cv?=6Z+>B@-Wa*B9@3M!f80>eB)X^E zyd>^(5n?Epj)VqI`VtlmwDppQlbIkBYM?5~%kD#rTlY0BOy^D8sZN@RWt*~mbQ@#) zHESCM>~m9pjG_+I=;~?Ro4=9*;o$q67YIe#xn*YQS0%8S{dkLCz7$DL`+BJKHHWH! zA7_@_LxJX~Y&K2p=u+PMo|k&d>`z{8993){mSNlR@_HZemoJOr#OGhk?9SG7T-4y> z;l9j$(zjKj(oQ$N&;@{e!_%t1pw=(2I51T_X?*s8Ry%P2Lrm8Kai##283AA_eG|-nn&zu1qQg=PC{HbB~a)ZUwYk2$S&F9T9JkTco$~w0%-x z2>SY%Z%s$b8}_9tp+Er(t)}Eh0u3+jg|p-5f$2W0t9>Jvs5U*5t7rC#2AT$|%cxUyZ~KH7X}_c|Bd2wwkZr26(_#s=BygCt!0@hu5rhjkNsT~;*m=vi@B^EjcX zI$ZM}yqV6o;x#6+Y6^n8g^birpLy$*KiHQ#i}ZCpcC>MaYum1udf2C#B`SXbhJMZu zkAte?7JW}F7O$Z2Y&)Yinv^>$lPP5DYX~BgW(ubM_&8xr&Y?>92z7`55T&dO)L5p z79LdK!zBQ|DpR8m76|&gx`Fl3(K?^ZZ^@PkFq6<%%tqR-cSABq zOIV%~eN0H_bI!2zCZFW;o=~z6qW$Gkj6>3#Ucs9$%78M2ud%pR?qAH~zK$vT!rqMN zyeLJJ&n%qgd~V#c=jEC~O+zmQ5O*smQ+_8Yd0;RpHmq1Y&-2JO@{3@x$^zq7uXQ*} zdyi9DIF;O7%4iulVmn;M{3X_4aPmv?y14F`i?rOwqfznHM2M6Ynh`lV6*Ro}khWut ztoIr2o#wi1SZq)YS@@RWuI(tN_PSHl8>fwBQ)Yq+{jJE_AH+>D_YcHPy-3MZ-2I$N zt)6eD&FE`BJ9$-`d(`fXF=A4;Ww4FZ93!rmFY0nf?X^VBQ;Z@!msbl(y2wx}|M+wV zWHh;Fq;oEzhpbD(`N3x(PIWh6gbj$+dBRW zDnUbq-^=)yOJcWcj3y=8oae6`J_HmnDCf3IYz$EeUGZl-8DZ+W>tTkQJXSh!!W6?@ zl0pqGDWsP9lp5h`s(lrho%@nS1$-lnGvKlGWTc>fpsG&=bs6+}%kt#=xGSZ@V%iylIklHNqjU}qb=WgPBb3L|#Pf8MOh)Z6!k z*>&-{d!}P+_k(rva%IP`_;h$xP$U>(slKjsu2AgyHLjC|8~pVC4R+iMT;HxwvsHdx zU)a#I<*CsKu?jh>h4Pp5w}bd_`5s`Ul`qY}foqSyP&+F%q`Y{3Ajpw0`!GLJb9;a| z^YUaEyT%&tOyTX7RgK6MYef3AFN#sx1mfGN6pfc?QO83>DR>{J?pN4>!~{Y)yXZ1n#->P4SPD_ z$1DN@+1mWfPR;~{$Bo&tqZDt9tmB{Ob$iKSZ`>DY*)=VmC`r19J=FR6GqLRt}}GERzG z4~}Y19E14^+sB1`UG-Y<3iX_W80i^peWh(x@Mz(ytYo|`LozBik=!BEqIFnoB{|H~ zvCUah9dj2F8kN@ylp7|plzNjXK$%Y;KYH}2>0s*HR~mZC>$c71#~Lax8(!>kMc(a- zD@oIQ*CW@-b0?-%2r-TL{<8d~-L;}-GV@wo*7O_Z^j)VQfwaSwmZ`pj7!nf(hbQ^l zbK#aOOocz#mkalVRNl5t6Z${Qseb8NMPxMJ)+wS^R!>1R_gI%{7_r)4uZS^9tt%$k zI(46lgL^7JQD5qv^IJZw3a;KE%(bzOv=?IAYL4{9G3Sqn ziezTfjJ795Pw$|25kOdFe0p3Bh7x^n!LY&on=Yd^Ec+w}r6-!zw%0x3# zo*DPZj=n|nK2F*`Q#!0{x8?kZMI5248VK)Q;!#&>Yq7WOQoC^;Cx2)R8OB+2O>Hbm zGH#W7PnNN;ZZ9*&qgz^s;u*QanQ1)e=hz{|HB7ns!tISCW?%tUOqfOcOy`lURj9;; zjpKzi*Ru0f;gD!5REu5b$}9|BCRfUS>)bfjQ}}SE;{%8mS;;-&cpkjo>y^UVsZ2fp zA_hbt;bKHP_ElX#^Nc6dD8{;AgKRbLRpdjts;s`(_-i%>(uTDzAC*%Xx{Vn>R4#yQ z4007sb=E&ge{AUY9Us)6D9lVpx--mupsimfWQe8X<`QZ^HouF^BtctH>K}WoIV(tS z8lMp?jIFO)j4kq!ys-ec3gZ6bcJIEt{o9mh&#hZ`5}EGhn4pwipa%ukjZ~{Dr-*LV zpGmycD`awog;vRCvW{sh)@I}B((1Jjx2M)-7MpiRA9WI9k@eF+=icr=#3;BYksK2| zMkZ_jT_Io|C+^_`=3u+A28#W_F&G)ot;ouYNtoj3*0e#H?V9h+@3rjsQ~^3rd->1_cUwEovj!?`C!Q50 z{btqG1*-nS3;$NvX0L;7T&~EL&(nF9DOU~XI+Uw#t+egMd94+~Jv0GCeNnE;6=?Ay z3aos4&SWH(oU|#K_}*=WD_+S=_Cz9RFvjEPnmN^*0CVZ6k4ym+5=}g0El2z$Ss)*` zSRumF3ds!#*jP$xeX1W_4n^<>-RU_0ryo|ISc~>O)z_MfMg4e@ zEqE1WKgoWDm#AKZxAtI_yZ@D>q>A8XU>x=lAC1LCroBFKy2LquYA9EjQ{7}+3k}=#a9ryTlUMG$w z5)XIYd1`1!ImI+qk)ZBMaf{x41vykOPyg^W4F#98Han=R`ydQ%!Lj;r;M}`~5o>SNh7gWR4Om8yc9%IsRz-j^A#1}y8*0;rJgn%_f3%X(Uhs2 zmalHWvWUMKD!wvw-;w}roBgS?h}dyY+I_T~fx+T|shEcK1E@b<)3=c|!A_y)vPB`uO_6 z(u&e?=Btk$V%=Wia*MZGje*P&xev=o7~|%&zJ==7=TGJeANAF;lVZuXTI#Kvi5B1T{YNV>q9$A{XFg&jFQ&OHEa#mst^e8chh z$eu__mGsVsrt;m^rTJjkgGoP^LoL8``Ym%aKrfHzgUER?{
    rFS4zvx1%3mE$GVo9>XY#Y{A`x1Y5bOlI&s;UdQZF`aB|(30AE2ZhP53z8=cQWw@E*AZhsC z3AVnaNCM8xTH51+*GzCv1B*}SGE);?f>S51s?958CZYO7Whp{#xW6VxPHgf? z{+0W4j=-t`U(GQBr`G3dQFOtBFDUl5B^C-KOcRv&s9#~0&!l{n6{*#0=6+G=ImTkW z@eW`TbvE@@*ot&v9&y&jT9B4W{@Kpvfh+uJ)?)@vgDj2PjULPFGPk`tCCAJ&}ovo&%*mXFC3 ztCytVc{Y)%_dX=Mi;Ez#OJY@@3>~vqr042Bq_IN2)wOhf!l-1l|`W@x7ld1yy0R@8;44mZbAqu%OrzL~d%kg1MDCg-Z= z3~7ZT(>Eb25A^ae*`7Be-L&@XT1^Dc!k)*MWL%+LgPvEdS2YQMEnlnzojP(Sa6hUg z4FBQ=LGE`_?w6WidevYtD(0!#Lqc*UWFe347wEW`hz15FL7zU`=Q0)_FTA>O$0 zFfi=@;vD_{@?}S2sYx2|OKBGFgk93(nC;$WYc@8*D5TmwzWV3NNj#YqTufB{I)s^D z4C|&fimOL94?|dfOsf!*X(7g4x`6#Ll3HIF%(_>KphRP;N{-)fbo1qeOq&=Z+h?P_ z`3=8GeI9oWTR#xyj#VFAk!2sv^a{*LO6h4w?A=ZYKAUsI-RgPFN9{7kq`qGO2hQP- zoGKD7KhC3xOncz zujLe_brW8JMu_M7+pKkvWNuu}md_J`2==v<1U$cqLA-dZsgil7@C&M}&}O#QG#`O3 znatEn<>T#MjjJnSZ(YpPubaml$?=0qCTOO<@PV;W76|PtZYnqn`;uuBBM^j zc0&%^En(^LPMP$?Q>ru*lQPdr?yBpJgW(jq0f&Nq+V%ZXC1NVBH*v}Vr>|?N3Pf@W7KtY?cRFcp^M9itniG^>Twa~2mhXk z@3v!DHN`6BXOOZG#TLG+HlhjyXEU6Cdk>K6;L&eMV-B z@g&(fx_nXG{QC>}9~@MTL75BYufi2$8%xbz9*3QHkoVm|zPyJJB!$vH%uRwB%v^$u zT|PFO^+c?Dwial6I3tda)<1C!eT%Ge=@cNJ+`yt{Xvn&~=LDWNTs4njY|vzlIhzQ} zd+@Px$O|)N&C*bd;p_Ak4nsyq^m1VBOqY{k;K+<*7qWdw`Kh(M)ys(UOKmhi?@>a@ zj0c{@&ONVsRQEO9@>wq8wVN|~FJTPPTid*;z7RGlZNcx{dePWD*iovGe50UHThbq+ zVHBH$gElKBrL!9d$p9{--gd)0>C3{vNGv9q-osUx&lK=%z;qoKBHyx`oo znxb}APQTHV7qgS19&^@U8v#~+#Sn##Cwr9U$&53w{DVfyJOg3sNQt_->UehC!p15V zBzz65F?Ab4MKxbUy+z_$2ChSER*rL^w!3g@*dl#sWHo;h)N*%Z=?=C>Zo?Q%G~KE^f4QtxfWoyLaT2X8CvS z0KO%G5qtOC+*MyFPcAe0)YBn#rx34wYrXpuJf9TUxyX;06?y zYTlkWrNUS@@r@^(3c|AR!A<4|`ZFw#fX}|B5qbSO=WneaS*Rv-yb*eTDMzdrwbkvF z*+{fUR6542kOh*l$w=@Q%vZL(X*zN^r~EQHK_zQvJvr`ZF>{p6*@*H!o#U)35UQJU zdqiH*v?d7DW|sEZd1F2ju!og>=vCIao(^EH8T6BMVcdDs-Y+^pP6H?a(F*bNUskhg zXF3s7G%6T2Me(Wm;yal#UL~(hSC}+LSz@w3fh4G^@(|jSr}S2^?mlLGI}&q1!~==h zc~~RUo7J7!U2g3y>urQ1NAfMHbD&2pYMT8sLz;Trem%SGr^SZK$tz{_yO&SD`AP9j z9vZty2SnGCJ#R(#NRRqrQU1w*c*P5L?jBr_Vde^p9u<`=6J;dG8^1v|+omLRV|pgf<}f zh^1;qrm<(K;z!L<52Ot5{yjY68-C)@b<`idLuniP&+O^)C>ZmMhgXQ#A1|AAzEh{B zw5wv#pSk1byL6p=p*myqG7epAD`d1+k7baKDQ#G{=?Lp>-D@A5d^KpK$E)vC8}=vs zcaq4~!6Q~U*kd^zYxAvq$QJW+zbI$^U}ac`*VCr3GmB1bea|s4+tvLO(JX8}w^`gw zqc*yP0Jic~aFQ&TompD9koWBOA@F#e8sbGprFpE^7?S` zmQpN%uK8e%(XLIzk8t1~!L9cO+nShU&C%@ikgdei+>b_A%_iiVjEN3&3^TZ=9VL|} z_&w%2>bA3`tvv?N_t+ui!D=ogNejwqECUr(CaFQZrdwdLAA^&S&WLJVRhCyXZ}l$A zpS%|pi^mNlk7{#iDp4IAF*(G!KhOx~btFB=E-zaVIL-Q|Z?G)t-T}0RR=P}^22_?0 zB`*lcU(7W#_&MKAzj)boHKKo~30LRX*;zX2NPfPw{?3r-^I4jKj`dfz4?Fdsk7Cf9 zIa7ovC=z>W-t-F&z^&-TA0hbmw!u{8Pw!4U2QJ6Br;L4^-RnhNj})M&cS7|73Tdtu zIAk!}L|Ib>8XdObq4zV-RGDu>%vGl@?ShBKK4AE*h_jGk-wz;7S&Voi*{DlVJg4nM zJb=T&{vo1dN2P(_hbv)vOeQIRe8)h1AZ11P$L@>!;c9tQL5G}Wq0!IhxArv3pDJOW zuCJHAy$}FU6mGC(H@@mB3R;Ac; zV`XZW9V;=^4D~ve;6s@U{px!a6lzJO(BwsIJD(EtA`0JwS)vXH^jve15JKznHbSF5 z1+Ca%<_NS#3mA20QI)BNj1* z$txb59}Ab1&~-bcQ|=EQ&#)`-gvrKpx{ztve&SPJ*&1B)E606PH2A%BvpOxitXBa$ z4*e~-wo76{5Jt#jsu(29DnUqA>hWW;QpHZ7m?v#ZVmojD{g7TEVO@IgjN_+80;w*~ zHv(UI2Maoq1k@;>&h7=2RAUHznR=u{41S31b?xpn8D4oQD3zgQXF=Rp@#w*~Sesb2 zsI7qHg?{tyIVXcx|k#zsHC$0`)BMj%Z-hq~H%Oyx9`#*Z_5Rw%$sv&xs~nFg27 zyiYv>U7en&nk;|T4;-J|%lz`O^b@bzy`~=^x=kJu8dPV22L9+Y*Oh}9sz^s$kagbV z1C`i__e%4?nm|I_U8m)2tl;YEEj!nZ3-y%-by6Qa(X@QG!8S(Km)<9BVtQC5#2Tn> zK^N%(@#^ujZfdves%dfWj55E2{eis~P*Ufuxr^+3^7e>Ezk&N1FZwRE>6Zcp8Hr+K(=wFFfHG3r(N+)r zmR|~VK2hoz_u_NSv5(+ClaW-#Uw*W$_TjWKLug4j&RB`+xK#-yhv6v&Zha z`=HY|-pxINR|xl|lC+zV83%Ftlr~`{;m%kK4*R#uyo}vWgh08WxyI6#vIzBRak(5{ zuN=BNv?iu-sKvXLU zK6YT839D^02Il8};3s1P3O2N&cllU@v5*$eh$+eX&>^U@e7IA$LBo1nW`{$yFqy}m zr}jdcy>?VF*`=e1Sos>w8tJU-H?4JZ#n~zyyD}`hy%)vEauj&O-V0XnaU}%5kix|D zwY@U!or4wLP1H?iTCM-~s)h{@z}j@hR?#DF`2dHCO@6;Fh-58m{4o6_qR%G0mRyZK zUtr~7RIE;mt+_H#C|1>p3AmDYmCjNBxw7irg$UL+)GC8SI282d#xXxJF|l6k{ZNhu zo?Mq!gyQ*O$-?|9&n(~9VMetJxm{rc@mQO*Lf)%sLF#&Byv<%5*`x|AK0TlWhn%a- z(WtBb{?TTu2`5iuv61+)*b5%U4F6tov>62xdylE_Y4k-&)ldmkax|=v@HzKq#>j}) z=b(KRkC3JvCg1i#=2QcCocd-P38`4t!onxNOno7Q&}vm#rMpSPNMd$+G+!_4z$`8S z`&bzd5B8O?}kc^AhRFL*c983Ys2f zP&3HkT-o>1&e5l1A&rdXLQf15{?yUMOoa@z|BzD-cMO&>ew}Lo$8R(6ie=>P%KyrZ zG2BOW>ej0zlX4F+XVmS@qZ;XDa(kX+`*Hq3@Wrh0nB)cK;8alkK1PA30@CQkbcFRI z<0hlC4u9+Xb#jcAHhyN|4I)O-G5lk*)Q29c@4VnAQqJlplM;!p&#O9yG&S3E)8ADk zB+gh49JM}6DKf9M#hWYC*GMmN5icjs;ZiUm8#6IRS7Vz>nv88=4DNT}vEVNmnG^v` zxC%8XuQ4HQpO5xVep6@?`9x2YoSaRbv67|_a;-j`;8Ye~e-2Xj@hqv2_&Ij!{O zjIHkC(45BS?t7He_>m^yRkyI}#FQD|5{QDZF_EY7bXh~7qD}F{szKxJFxK8B_rPjuF289fZ(V$J?V86Z>o9$3D{~8^kY+qF z>x!ahD3hJo&f@+cZ1;8brr2UaIOcLvp^HoOU|G+3FgWc{-K6Vs!7gfj;_6w2ut?)j z%QMmJuOal9uClMH$YR1mYj6egA!gO(EpmRWos&@;a#FVC*osmD_ZOVuQ-Ye!A+uV} z1`x3ws<$2mIn{cg|4E)ilq7uJD`Fh+A^oI`C};NM5A) z4Ngo(`{wK{S;akfBNuP9*XS=w-&2EB1E$S)%-$q@r{vgzJZ_Fq&S8x{`AmS>b@a`; zjrLK*W!w?kit)n$Ecp+4Q~FP`_?E8|8}ZokFh};-_xDUWH!783o(XM4>h3r1lHwkG zb(6|W>!>eUvrSKUwl-3p^2w*`tQZm(mBFH0%cB47Ii&6U{*S1xVaE?&h0Y4j=ZRzz zb+daz++r}v1oayAIYTny(bXp-5TmHyb{Kz*U~@*)ZC#Oknx)}9g>GStr5d!V_VaPX zBY)!g;DCq7|?84?V4`0#0m_UdQg|wjVVwA zBYbk`iJFh~(`{_kn{CsA_!L_o!*ZUzBw@ydy#Fwa{~AAh;$j{`Cqd}T`d)={E0R&f zl#EpZ#rWb}V%kAU8Y@Fpt#_j1h1gB)ch^rjN+SbC`Mbg_huT*o*sUkRCy>;7hSB;< zJMLSa2bfmMPVaO>6G~Ko8!v+&-vkQVDBYy2k{$&_fn_!p0WucN>Aha|QU$o{OwD05 zSw-P`Igz&4l_aezYKR&0j|RM0j22&w%aV~67u=c;U9zg!pf#f3ZA%lK{9gVFpmFQD zGS{U2n2vSEb#B-)gy^kSZ_d_LRuw64DUtG7DCqsz@-8dCt0|cazlx<dZrXgGEx8M|9=i++#h10xCd z?svth6g`8dp&}zn*uMxkV`q-IR?@B2adiUi7&-26tioLa#8SVFsBNluBh&S;yj1!S z1##~_+tLEuI}pN1!6NU;FC9ch_L_*iTwAJ-8|f>Ta&b>NL-XlLS$+Wco}5gkLI1<-znCX)!8lW!rsK))gGosEz*mQxO{r~Ev@5*VJbtYpK}@c>XD}u?E zQJh!$+OLiA_5|4D-AoUoHAnSF6vzEN@i>#N-%oQI+ib&Uh+>Ou?|o+@o(mP- zsvJ!Fk>-5$4s&7_3w%56^~ZdHy;QQ-uh{LVwKp1_c@W+yav?btaZc>b zOz&Q9|Nq!K�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 GiU0u7jJ}Wn literal 0 HcmV?d00001 diff --git a/charts/portal/templates/deploy.yaml b/charts/portal/templates/deploy.yaml index 1b4efff89..6fa839a41 100644 --- a/charts/portal/templates/deploy.yaml +++ b/charts/portal/templates/deploy.yaml @@ -1,10 +1,10 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "entity.name" . }} + name: {{ include "common.entity.name" . }} namespace: {{ .Release.Namespace }} labels: - app: {{ include "entity.name" . }} + app: {{ include "common.entity.name" . }} spec: strategy: rollingUpdate: @@ -13,19 +13,19 @@ spec: revisionHistoryLimit: 3 selector: matchLabels: - app: {{ include "entity.name" . }} + app: {{ include "common.entity.name" . }} template: metadata: labels: - app: {{ include "entity.name" . }} + app: {{ include "common.entity.name" . }} spec: - serviceAccountName: {{ include "entity.name" . }} + serviceAccountName: {{ include "common.entity.name" . }} securityContext: runAsUser: 1000 runAsGroup: 3000 fsGroup: 2000 containers: - - name: {{ include "entity.name" . }} + - name: {{ include "common.entity.name" . }} image: {{ .Values.image.name }}:{{ .Chart.AppVersion }} imagePullPolicy: {{ .Values.image.pullPolicy }} securityContext: diff --git a/charts/portal/templates/istio-destination-rule.yaml b/charts/portal/templates/istio-destination-rule.yaml index 6c210d77b..cbfa097fc 100644 --- a/charts/portal/templates/istio-destination-rule.yaml +++ b/charts/portal/templates/istio-destination-rule.yaml @@ -1,11 +1,11 @@ -{{- if .Values.istio.enabled -}} +{{- if eq (include "common.istioEnabled" .) "true" -}} apiVersion: "networking.istio.io/v1alpha3" kind: "DestinationRule" metadata: - name: {{ include "entity.name" . }} + name: {{ include "common.entity.name" . }} namespace: {{ .Release.Namespace }} spec: - host: {{ include "entity.name" . }}.{{ .Release.Namespace }}.svc.cluster.local + host: {{ include "common.entity.name" . }}.{{ .Release.Namespace }}.svc.cluster.local trafficPolicy: tls: mode: ISTIO_MUTUAL diff --git a/charts/portal/templates/istio-peerauthentication.yaml b/charts/portal/templates/istio-peerauthentication.yaml index c12e10607..57be5b47c 100644 --- a/charts/portal/templates/istio-peerauthentication.yaml +++ b/charts/portal/templates/istio-peerauthentication.yaml @@ -1,13 +1,13 @@ -{{- if .Values.istio.enabled -}} +{{- if eq (include "common.istioEnabled" .) "true" -}} apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: - name: {{ include "entity.name" . }} + name: {{ include "common.entity.name" . }} namespace: {{ .Release.Namespace }} spec: selector: matchLabels: - app: {{ include "entity.name" . }} + app: {{ include "common.entity.name" . }} mtls: mode: STRICT {{- end -}} \ No newline at end of file diff --git a/charts/portal/templates/istio-virtual-service.yaml b/charts/portal/templates/istio-virtual-service.yaml index f2a3bc134..f9a7262f0 100644 --- a/charts/portal/templates/istio-virtual-service.yaml +++ b/charts/portal/templates/istio-virtual-service.yaml @@ -1,15 +1,15 @@ -{{- if .Values.istio.enabled -}} +{{- if eq (include "common.istioEnabled" .) "true" -}} apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: - name: {{ include "entity.name" . }} + name: {{ include "common.entity.name" . }} namespace: {{ .Release.Namespace }} spec: gateways: - {{ .Release.Namespace }}/gateway hosts: - {{- if (.Values.istio.virtualService).hosts }} -{{ .Values.istio.virtualService.hosts | toYaml | nindent 2}} + {{- if (.Values.virtualService).hosts }} +{{ .Values.virtualService.hosts | toYaml | nindent 2}} {{- else }} {{ range $domainName := .Values.baseDomains }} - {{ $domainName }} @@ -31,7 +31,7 @@ spec: - DELETE route: - destination: - host: {{ include "entity.name" . }}.{{ .Release.Namespace }}.svc.cluster.local + host: {{ include "common.entity.name" . }}.{{ .Release.Namespace }}.svc.cluster.local port: number: 8080 {{- end -}} \ No newline at end of file diff --git a/charts/portal/templates/rbac.yaml b/charts/portal/templates/rbac.yaml index 8b6f9fbf4..443444e1f 100644 --- a/charts/portal/templates/rbac.yaml +++ b/charts/portal/templates/rbac.yaml @@ -15,7 +15,7 @@ metadata: name: read-contentconfigurations-global subjects: - kind: ServiceAccount - name: {{ include "entity.name" . }} + name: {{ include "common.entity.name" . }} namespace: {{ .Release.Namespace }} roleRef: kind: ClusterRole diff --git a/charts/portal/templates/sa.yaml b/charts/portal/templates/sa.yaml index a86085722..939d253d4 100644 --- a/charts/portal/templates/sa.yaml +++ b/charts/portal/templates/sa.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "entity.name" . }} + name: {{ include "common.entity.name" . }} namespace: {{ .Release.Namespace }} imagePullSecrets: - name: {{ .Values.image.pullSecret }} diff --git a/charts/portal/templates/service.yaml b/charts/portal/templates/service.yaml index 93d46a049..94190ee6a 100644 --- a/charts/portal/templates/service.yaml +++ b/charts/portal/templates/service.yaml @@ -1,11 +1,11 @@ kind: Service apiVersion: v1 metadata: - name: {{ include "entity.name" . }} + name: {{ include "common.entity.name" . }} namespace: {{ .Release.Namespace }} spec: selector: - app: {{ include "entity.name" . }} + app: {{ include "common.entity.name" . }} ports: - name: http protocol: TCP diff --git a/charts/portal/templates/sidecar.yaml b/charts/portal/templates/sidecar.yaml index 5a283ba2b..3d172bd63 100644 --- a/charts/portal/templates/sidecar.yaml +++ b/charts/portal/templates/sidecar.yaml @@ -1,13 +1,13 @@ -{{- if .Values.istio.enabled -}} +{{- if eq (include "common.istioEnabled" .) "true" -}} apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: - name: {{ include "entity.name" . }} + name: {{ include "common.entity.name" . }} namespace: {{ .Release.Namespace }} spec: workloadSelector: labels: - app: {{ include "entity.name" . }} + app: {{ include "common.entity.name" . }} outboundTrafficPolicy: mode: ALLOW_ANY {{- end -}} \ No newline at end of file diff --git a/charts/portal/tests/__snapshot__/istio_test.yaml.snap b/charts/portal/tests/__snapshot__/istio_test.yaml.snap index 25f5b37c9..749ad78d9 100644 --- a/charts/portal/tests/__snapshot__/istio_test.yaml.snap +++ b/charts/portal/tests/__snapshot__/istio_test.yaml.snap @@ -92,59 +92,6 @@ matches the snapshot: deletionPolicy: Retain name: portal-client-secret-portal 3: | - apiVersion: networking.istio.io/v1alpha3 - kind: DestinationRule - metadata: - name: RELEASE-NAME-portal - namespace: NAMESPACE - spec: - host: RELEASE-NAME-portal.NAMESPACE.svc.cluster.local - trafficPolicy: - tls: - mode: ISTIO_MUTUAL - 4: | - apiVersion: security.istio.io/v1beta1 - kind: PeerAuthentication - metadata: - name: RELEASE-NAME-portal - namespace: NAMESPACE - spec: - mtls: - mode: STRICT - selector: - matchLabels: - app: RELEASE-NAME-portal - 5: | - apiVersion: networking.istio.io/v1alpha3 - kind: VirtualService - metadata: - name: RELEASE-NAME-portal - namespace: NAMESPACE - spec: - gateways: - - NAMESPACE/gateway - hosts: - - portal.example.com - - portal.portal.example.com - - portal2.example.com - - portal.portal2.example.com - http: - - corsPolicy: - allowHeaders: - - Authorization - - Content-Type - - '*' - allowMethods: - - GET - - POST - - PUT - - DELETE - route: - - destination: - host: RELEASE-NAME-portal.NAMESPACE.svc.cluster.local - port: - number: 8080 - 6: | apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: @@ -158,7 +105,7 @@ matches the snapshot: - get - watch - list - 7: | + 4: | apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: @@ -171,7 +118,7 @@ matches the snapshot: - kind: ServiceAccount name: RELEASE-NAME-portal namespace: NAMESPACE - 8: | + 5: | apiVersion: v1 imagePullSecrets: - name: github @@ -179,7 +126,7 @@ matches the snapshot: metadata: name: RELEASE-NAME-portal namespace: NAMESPACE - 9: | + 6: | apiVersion: v1 kind: Service metadata: @@ -193,18 +140,6 @@ matches the snapshot: selector: app: RELEASE-NAME-portal type: ClusterIP - 10: | - apiVersion: networking.istio.io/v1beta1 - kind: Sidecar - metadata: - name: RELEASE-NAME-portal - namespace: NAMESPACE - spec: - outboundTrafficPolicy: - mode: ALLOW_ANY - workloadSelector: - labels: - app: RELEASE-NAME-portal matches the snapshot with istio disabled: 1: | apiVersion: apps/v1 diff --git a/charts/portal/tests/istio-virtual_service_test.yaml b/charts/portal/tests/istio-virtual_service_test.yaml index 478bfe100..2d302f27a 100644 --- a/charts/portal/tests/istio-virtual_service_test.yaml +++ b/charts/portal/tests/istio-virtual_service_test.yaml @@ -5,5 +5,9 @@ values: - ../test-values.yaml tests: - it: virtual service match the snapshot + set: + global: + istio: + enabled: true asserts: - matchSnapshot: {} diff --git a/charts/portal/tests/istio_test.yaml b/charts/portal/tests/istio_test.yaml index e5f10aa9e..fe1897498 100644 --- a/charts/portal/tests/istio_test.yaml +++ b/charts/portal/tests/istio_test.yaml @@ -4,6 +4,9 @@ chart: appVersion: 1.0.0 tests: - it: matches the snapshot + set: + istio: + enabled: false values: - ../test-values.yaml asserts: From eade14c045caa65bc984ac760fa61fe0cff05a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20Echterh=C3=B6lter?= Date: Thu, 21 Nov 2024 14:24:18 +0100 Subject: [PATCH 4/5] feat: update common --- charts/portal/charts/common-0.1.3.tgz | Bin 490 -> 0 bytes charts/portal/charts/common-0.1.4.tgz | Bin 22091 -> 22092 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 charts/portal/charts/common-0.1.3.tgz diff --git a/charts/portal/charts/common-0.1.3.tgz b/charts/portal/charts/common-0.1.3.tgz deleted file mode 100644 index cb2f0848c22ddd4f284cc552885c4680897a9388..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 490 zcmVDc zVQyr3R8em|NM&qo0PI%HirX*{_E}Fc7z*tnT3NBZkXz}cP$;E^y%xopYz2~RBsmb$ zefQ$nF0s93$2pNgE7X+JU_0Cv2bNs&XX*E zWSnP3QSyXkJTG|y>U{8(e{sYb)%Y>_&ZzW^_sJ9bv?uFz|mTREzFP4PcJ{ z-9F&|W0pn!-vUGaJ?cgYkM7|s8ZZ6+qtHlwbCGJ8%YR;k{l6%ddCdPUa5yYrgIj43 z(mwOFYwam4US3FdDYsD7#tUg2(0)wlY6IwJR45$wr$M-}()cZ;uUtA2{tn)@rh;-g zN}_VVc(ph_oM@g=V>UlM9rxrkCOhbw1~u_>V(#}Q?wzUY;GF+bi)Z}QD)j{`i~a&l zV2=Ns7Xkmvg2nmoCOGBFv#QrZ(Vzg*jtIdww;})w=!d|=q0=B*<$*r+b3`Bxug8nt g#G5mLDcA1(Qz9ZFBK`yX2mk>8|8dqgasUzl0Aerd4gdfE diff --git a/charts/portal/charts/common-0.1.4.tgz b/charts/portal/charts/common-0.1.4.tgz index a82fafeec0502ae20bfb9161a66a82c8e4c551cf..29a625d47190a50e27dbd9987cac2d5bc9e922a7 100644 GIT binary patch delta 21241 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 delta 21240 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�!d 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 Date: Thu, 21 Nov 2024 14:31:20 +0100 Subject: [PATCH 5/5] feat: using imagePull common snippet --- charts/portal/templates/sa.yaml | 3 +-- charts/portal/values.yaml | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/portal/templates/sa.yaml b/charts/portal/templates/sa.yaml index 939d253d4..2eaf7c467 100644 --- a/charts/portal/templates/sa.yaml +++ b/charts/portal/templates/sa.yaml @@ -3,5 +3,4 @@ kind: ServiceAccount metadata: name: {{ include "common.entity.name" . }} namespace: {{ .Release.Namespace }} -imagePullSecrets: - - name: {{ .Values.image.pullSecret }} +{{- include "common.imagePullSecret" . }} diff --git a/charts/portal/values.yaml b/charts/portal/values.yaml index 493032ede..b2db85e0a 100644 --- a/charts/portal/values.yaml +++ b/charts/portal/values.yaml @@ -1,7 +1,8 @@ image: name: ghcr.io/openmfp/portal pullPolicy: IfNotPresent - pullSecret: github + +imagePullSecret: github deployment: maxUnavailable: 0