From 2220348419c7d8c07fc3313ef6516c67031eeaf4 Mon Sep 17 00:00:00 2001 From: Andrej Shadura Date: Fri, 22 Apr 2022 10:27:56 +0200 Subject: [PATCH 1/2] Search exits with 0 on error, so we need to always restart it. The default is "unexpected" which means exit codes 0 or 2 are considered success, however search can crash and exit with 0. Signed-off-by: Andrej Shadura --- docker/services/frontend/search.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/services/frontend/search.conf b/docker/services/frontend/search.conf index 46fc79a76d..aa83f2624c 100644 --- a/docker/services/frontend/search.conf +++ b/docker/services/frontend/search.conf @@ -4,6 +4,7 @@ directory=/obs/src/api stdout_logfile=/obs/src/api/log/%(program_name)s-stdout.log redirect_stderr=true autostart=true +autorestart=true stopsignal=KILL killasgroup=true stopasgroup=true -- GitLab From ac982ce84ebad728515e7aced7e3e5e11490d789 Mon Sep 17 00:00:00 2001 From: Andrej Shadura Date: Thu, 14 Apr 2022 15:16:15 +0200 Subject: [PATCH 2/2] Add Helm charts Add a charts with two subcharts, for the frontend and the backend. Workers are not covered since we want to run them externally and connect them using a proxy. Settings for the backend and frontend themselves are specified through the "global" section, while settings for MariaDB and memcached should go into "frontend". The extraConfig setting allows adding configuration code to BSConfig.local.pm. The permanent backend storage stores both data and the configuration in subdirectories. All hosts have r/w+worker access to the backend by default. Signed-off-by: Andrej Shadura --- helm/open-build-service/.helmignore | 23 +++ helm/open-build-service/Chart.lock | 9 ++ helm/open-build-service/Chart.yaml | 30 ++++ .../charts/backend/.helmignore | 23 +++ .../charts/backend/Chart.yaml | 24 +++ .../charts/backend/templates/NOTES.txt | 6 + .../charts/backend/templates/_helpers.tpl | 71 +++++++++ .../charts/backend/templates/configmap.yaml | 10 ++ .../charts/backend/templates/deployment.yaml | 129 ++++++++++++++++ .../charts/backend/templates/hpa.yaml | 28 ++++ .../charts/backend/templates/pvc.yaml | 16 ++ .../charts/backend/templates/service.yaml | 19 +++ .../backend/templates/serviceaccount.yaml | 12 ++ .../templates/tests/test-connection.yaml | 15 ++ .../charts/backend/values.yaml | 86 +++++++++++ .../charts/frontend/.helmignore | 23 +++ .../charts/frontend/Chart.lock | 9 ++ .../charts/frontend/Chart.yaml | 32 ++++ .../charts/frontend/charts/mariadb-10.0.3.tgz | Bin 0 -> 44042 bytes .../frontend/charts/memcached-6.0.14.tgz | Bin 0 -> 33534 bytes .../charts/frontend/templates/NOTES.txt | 22 +++ .../charts/frontend/templates/_helpers.tpl | 86 +++++++++++ .../charts/frontend/templates/deployment.yaml | 145 ++++++++++++++++++ .../charts/frontend/templates/hpa.yaml | 28 ++++ .../charts/frontend/templates/ingress.yaml | 61 ++++++++ .../charts/frontend/templates/service.yaml | 15 ++ .../frontend/templates/serviceaccount.yaml | 12 ++ .../templates/tests/test-connection.yaml | 15 ++ .../charts/frontend/values.yaml | 95 ++++++++++++ helm/open-build-service/templates/NOTES.txt | 22 +++ .../open-build-service/templates/_helpers.tpl | 69 +++++++++ helm/open-build-service/values.yaml | 101 ++++++++++++ 32 files changed, 1236 insertions(+) create mode 100644 helm/open-build-service/.helmignore create mode 100644 helm/open-build-service/Chart.lock create mode 100644 helm/open-build-service/Chart.yaml create mode 100644 helm/open-build-service/charts/backend/.helmignore create mode 100644 helm/open-build-service/charts/backend/Chart.yaml create mode 100644 helm/open-build-service/charts/backend/templates/NOTES.txt create mode 100644 helm/open-build-service/charts/backend/templates/_helpers.tpl create mode 100644 helm/open-build-service/charts/backend/templates/configmap.yaml create mode 100644 helm/open-build-service/charts/backend/templates/deployment.yaml create mode 100644 helm/open-build-service/charts/backend/templates/hpa.yaml create mode 100644 helm/open-build-service/charts/backend/templates/pvc.yaml create mode 100644 helm/open-build-service/charts/backend/templates/service.yaml create mode 100644 helm/open-build-service/charts/backend/templates/serviceaccount.yaml create mode 100644 helm/open-build-service/charts/backend/templates/tests/test-connection.yaml create mode 100644 helm/open-build-service/charts/backend/values.yaml create mode 100644 helm/open-build-service/charts/frontend/.helmignore create mode 100644 helm/open-build-service/charts/frontend/Chart.lock create mode 100644 helm/open-build-service/charts/frontend/Chart.yaml create mode 100644 helm/open-build-service/charts/frontend/charts/mariadb-10.0.3.tgz create mode 100644 helm/open-build-service/charts/frontend/charts/memcached-6.0.14.tgz create mode 100644 helm/open-build-service/charts/frontend/templates/NOTES.txt create mode 100644 helm/open-build-service/charts/frontend/templates/_helpers.tpl create mode 100644 helm/open-build-service/charts/frontend/templates/deployment.yaml create mode 100644 helm/open-build-service/charts/frontend/templates/hpa.yaml create mode 100644 helm/open-build-service/charts/frontend/templates/ingress.yaml create mode 100644 helm/open-build-service/charts/frontend/templates/service.yaml create mode 100644 helm/open-build-service/charts/frontend/templates/serviceaccount.yaml create mode 100644 helm/open-build-service/charts/frontend/templates/tests/test-connection.yaml create mode 100644 helm/open-build-service/charts/frontend/values.yaml create mode 100644 helm/open-build-service/templates/NOTES.txt create mode 100644 helm/open-build-service/templates/_helpers.tpl create mode 100644 helm/open-build-service/values.yaml diff --git a/helm/open-build-service/.helmignore b/helm/open-build-service/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/helm/open-build-service/.helmignore @@ -0,0 +1,23 @@ +# 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 +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/open-build-service/Chart.lock b/helm/open-build-service/Chart.lock new file mode 100644 index 0000000000..cb15473b6d --- /dev/null +++ b/helm/open-build-service/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: frontend + repository: "" + version: x.x.x +- name: backend + repository: "" + version: x.x.x +digest: sha256:c5faf90e435b1f01602084bc06fc933ca6f436f63a6669ad6aadbe29e6033c18 +generated: "2022-04-13T22:01:53.992970003+02:00" diff --git a/helm/open-build-service/Chart.yaml b/helm/open-build-service/Chart.yaml new file mode 100644 index 0000000000..9ac45f1a1f --- /dev/null +++ b/helm/open-build-service/Chart.yaml @@ -0,0 +1,30 @@ +apiVersion: v2 +name: open-build-service +description: Open Build Service + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +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.1.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 +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "2.10.11" + +dependencies: + - name: frontend + version: x.x.x + - name: backend + version: x.x.x diff --git a/helm/open-build-service/charts/backend/.helmignore b/helm/open-build-service/charts/backend/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/helm/open-build-service/charts/backend/.helmignore @@ -0,0 +1,23 @@ +# 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 +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/open-build-service/charts/backend/Chart.yaml b/helm/open-build-service/charts/backend/Chart.yaml new file mode 100644 index 0000000000..285b21b114 --- /dev/null +++ b/helm/open-build-service/charts/backend/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: backend +description: Open Build Service (backend) + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +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.1.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 +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "2.10.11" diff --git a/helm/open-build-service/charts/backend/templates/NOTES.txt b/helm/open-build-service/charts/backend/templates/NOTES.txt new file mode 100644 index 0000000000..a308698eb8 --- /dev/null +++ b/helm/open-build-service/charts/backend/templates/NOTES.txt @@ -0,0 +1,6 @@ +1. Get the application URL by running these commands: + + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "backend.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT diff --git a/helm/open-build-service/charts/backend/templates/_helpers.tpl b/helm/open-build-service/charts/backend/templates/_helpers.tpl new file mode 100644 index 0000000000..b2345ebfe0 --- /dev/null +++ b/helm/open-build-service/charts/backend/templates/_helpers.tpl @@ -0,0 +1,71 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "backend.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "backend.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 "backend.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "backend.labels" -}} +helm.sh/chart: {{ include "backend.chart" . }} +{{ include "backend.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "backend.selectorLabels" -}} +app.kubernetes.io/name: {{ include "backend.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "backend.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "backend.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "frontend.hostname" -}} +{{- coalesce (index .Values "global" "frontend" "host") (printf "%s-%s" .Release.Name "frontend" | trunc 63 | trimSuffix "-") -}} +{{- end -}} + diff --git a/helm/open-build-service/charts/backend/templates/configmap.yaml b/helm/open-build-service/charts/backend/templates/configmap.yaml new file mode 100644 index 0000000000..5eb34bb349 --- /dev/null +++ b/helm/open-build-service/charts/backend/templates/configmap.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "backend.fullname" . }}-config +data: + BSConfig.local.pm: {{ + printf "%s\n%s\n1;\n" "$ipaccess->{\".*\"} = \"rw,worker\";" ( + default "" .Values.global.backend.extraConfig + ) | quote + }} diff --git a/helm/open-build-service/charts/backend/templates/deployment.yaml b/helm/open-build-service/charts/backend/templates/deployment.yaml new file mode 100644 index 0000000000..8fc777d0a0 --- /dev/null +++ b/helm/open-build-service/charts/backend/templates/deployment.yaml @@ -0,0 +1,129 @@ +{{- $arches := default + (list "x86_64" "i586" "armv7hl" "aarch64") + .Values.global.backend.architectures +-}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "backend.fullname" . }} + labels: + {{- include "backend.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "backend.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "backend.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "backend.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: OBS_BACKEND_HOST + value: {{ include "backend.fullname" . | quote }} + - name: OBS_FRONTEND_HOST + value: {{ include "frontend.hostname" . | quote }} + - name: OBS_ARCHES + value: {{ $arches | join " " | quote }} + ports: + - name: repserver + containerPort: 5252 + protocol: TCP + - name: srcserver + containerPort: 5352 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: repserver + httpGet: + path: / + port: srcserver + readinessProbe: + httpGet: + path: / + port: repserver + httpGet: + path: / + port: srcserver + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: backend + mountPath: /srv/obs + subPath: data + - name: backend + mountPath: /etc/obs + subPath: config + - name: backend-logs + mountPath: /srv/obs/log + - name: backend-extraconfig + mountPath: /etc/obs/BSConfig.local.pm + subPath: BSConfig.local.pm + {{- $logs := list + "dispatcher" + "dodup" + "publisher" + "rep_server" + "src_server" + "warden" + -}} + {{- range $arch := $arches -}} + {{- $logs = append $logs (printf "scheduler_%s" $arch) -}} + {{- end -}} + {{- range $service := $logs }} + - name: {{ $.Chart.Name }}-{{ $service | kebabcase }}-log + image: busybox + args: + - sh + - -c + - tail -n+1 -F /srv/obs/log/{{ $service }}.log + volumeMounts: + - name: backend-logs + mountPath: /srv/obs/log + {{- end }} + volumes: + - name: backend + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (printf "%s-storage" (include "backend.fullname" .)) }} + {{- else }} + emptyDir: {} + {{- end }} + - name: backend-logs + emptyDir: {} + - name: backend-extraconfig + configMap: + name: {{ include "backend.fullname" . }}-config + optional: true + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/helm/open-build-service/charts/backend/templates/hpa.yaml b/helm/open-build-service/charts/backend/templates/hpa.yaml new file mode 100644 index 0000000000..fe4dba9732 --- /dev/null +++ b/helm/open-build-service/charts/backend/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "backend.fullname" . }} + labels: + {{- include "backend.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "backend.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/helm/open-build-service/charts/backend/templates/pvc.yaml b/helm/open-build-service/charts/backend/templates/pvc.yaml new file mode 100644 index 0000000000..420e9347ae --- /dev/null +++ b/helm/open-build-service/charts/backend/templates/pvc.yaml @@ -0,0 +1,16 @@ +{{- if (and .Values.persistence.enabled (not .Values.persistence.existingClaim)) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "backend.fullname" . }}-storage + labels: + {{- include "backend.labels" . | nindent 4 }} +spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} +{{- end }} diff --git a/helm/open-build-service/charts/backend/templates/service.yaml b/helm/open-build-service/charts/backend/templates/service.yaml new file mode 100644 index 0000000000..ca22b4a803 --- /dev/null +++ b/helm/open-build-service/charts/backend/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "backend.fullname" . }} + labels: + {{- include "backend.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: 5252 + targetPort: repserver + protocol: TCP + name: repserver + - port: 5352 + targetPort: srcserver + protocol: TCP + name: srcserver + selector: + {{- include "backend.selectorLabels" . | nindent 4 }} diff --git a/helm/open-build-service/charts/backend/templates/serviceaccount.yaml b/helm/open-build-service/charts/backend/templates/serviceaccount.yaml new file mode 100644 index 0000000000..a43e942508 --- /dev/null +++ b/helm/open-build-service/charts/backend/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "backend.serviceAccountName" . }} + labels: + {{- include "backend.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/open-build-service/charts/backend/templates/tests/test-connection.yaml b/helm/open-build-service/charts/backend/templates/tests/test-connection.yaml new file mode 100644 index 0000000000..52d1df1bee --- /dev/null +++ b/helm/open-build-service/charts/backend/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "backend.fullname" . }}-test-connection" + labels: + {{- include "backend.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "backend.fullname" . }}:5252'] + restartPolicy: Never diff --git a/helm/open-build-service/charts/backend/values.yaml b/helm/open-build-service/charts/backend/values.yaml new file mode 100644 index 0000000000..243ae48b46 --- /dev/null +++ b/helm/open-build-service/charts/backend/values.yaml @@ -0,0 +1,86 @@ +# Default values for open-build-service-backend. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: registry.gitlab.collabora.com/obs/open-build-service/backend + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: latest + +global: + frontend: {} + # host: frontend + backend: {} + # architectures: ["x86_64", "aarch64"] + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +## Enable persistence using Persistent Volume Claims +## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ +## +persistence: + ## @param persistence.enabled Enable persistence using Persistent Volume Claims + ## + enabled: true + ## @param persistence.existingClaim The name of an existing PVC to use for persistence + ## + existingClaim: "" + ## @param persistence.accessModes Persistent Volume Access Modes + ## + accessModes: + - ReadWriteOnce + ## @param persistence.size Size of data volume + ## + size: 8Gi diff --git a/helm/open-build-service/charts/frontend/.helmignore b/helm/open-build-service/charts/frontend/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/helm/open-build-service/charts/frontend/.helmignore @@ -0,0 +1,23 @@ +# 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 +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/open-build-service/charts/frontend/Chart.lock b/helm/open-build-service/charts/frontend/Chart.lock new file mode 100644 index 0000000000..531659ee68 --- /dev/null +++ b/helm/open-build-service/charts/frontend/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: mariadb + repository: https://charts.bitnami.com/bitnami + version: 10.0.3 +- name: memcached + repository: https://charts.bitnami.com/bitnami + version: 6.0.14 +digest: sha256:dff66f6416ad3e3df2d7c70c1f5f835679c6ebb4cf289826b02a1649b34e6f60 +generated: "2022-04-14T15:07:25.590867379+02:00" diff --git a/helm/open-build-service/charts/frontend/Chart.yaml b/helm/open-build-service/charts/frontend/Chart.yaml new file mode 100644 index 0000000000..9dfa58cc6a --- /dev/null +++ b/helm/open-build-service/charts/frontend/Chart.yaml @@ -0,0 +1,32 @@ +apiVersion: v2 +name: frontend +description: Open Build Service (frontend) + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +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.1.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 +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "2.10.11" + +dependencies: + - name: mariadb + repository: https://charts.bitnami.com/bitnami + version: ~10.0 + - name: memcached + repository: https://charts.bitnami.com/bitnami + version: ~6.0 diff --git a/helm/open-build-service/charts/frontend/charts/mariadb-10.0.3.tgz b/helm/open-build-service/charts/frontend/charts/mariadb-10.0.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..4017b988cd13f3e617ed1fb77ac0b05d88e5537f GIT binary patch literal 44042 zcmV)MK)AmjiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMZ(b{sddAlSe86qr)an)IrQAChQy&3MkGNZIDLC2>j0zB@gA zNK_`O3T9R!8$eR3mb7PIV_$EdWDmYFflMGjs)`h4Gw*GSl?enQ0)apv5C|+F#W0@i z9?v1=qa|D|KQo-;fuY$?Cl>M?(O{r z>}?*E`jayb>0kENZmUY%SMtC#B^+{0Qa0WKAc7pt2wjfB3FL4B8QOvw{uNP%Nje6% z2U{@9il6&?qZgz7XInAKP#U8&!ibHxh9HFtGzJk_EJ(Tq07V&Lm`kv8&NDXN-Hn92 zvC#zc6fW>6B8y%9_Z9#g&LlQNpx+G(Shq#nqYtAGTQOo0#Tl2ceuRua1r#M1P7?GK zum~pVFPO#vLAC^(fSe&fGL#M($!UZ{c}YJ^Kx}9RfGrtEixGG&#>dG^aDnJ8q5w01 zQ!a>&!IV(2z)YYsj40+fg2_`bNAPwzObCoYMoFAU0=5Rnwg7+(yhlkQ{uKbwVuIor zr!xVUfCXf17^5s9OB4e}ru;pmXas)7vw5-v@D^f8Qh`^L$p*v#kZhDTg>kR8~d{h!Y`C=H-7_ zsBHl)ZZEa?s9&Z*)yWb}18&3=ysH0S9PU5r|ND40t-3A!yuUZv--_`JF+K)t z4i8=&j-MaGy@UPlCkNBXGb<&`_IvLTQig*3OS0$U~sT^us_`2AMU-l+) z_46!Gk_!}3#F?}c87CCZ&~XA8+Y-(EhlHSEj~oyc?wra7ss0$KYq#fCHx&VspQSEl z!cc@MfRsWHL>pNHO}_(?d?}2~cqz1VBuuPZEYvejXIoF6Y$+hZ(srmCgTY`6fG1DD ztI=$v{;HxrR=!LgNj4wD9;5ZSeaSW4WS<1LE`lfl3h*|=!UAqF<6!QQVpIQJ{Ygd5lb-@V{ zwlp|FQjQ)OJNED{pI#D*-p=BQjZn$EJ8l7a>p%fSniq*$y_q|I@# z&GN}m84>_eB)cLaDZ??MD3(1^YiA5Tey-v13!I>&Kp|1THrBd=UTK&`a}?(ZqC(1n z{12H*1yy_j+l0>%71}Tbv10y?z$eBmgFKppjKorTQZy|stDB;GMwslzBx1W9vKzJw z;{{H!=#HW8mfb={4i|aCah9NA(LCD~Bsh3h!~=cc6rRX+CO8tRMUWt00y6m>MO-pb zEkwb4%;%CmilnLs+eqkOVTDQU1UOn`3FJs}&H^omx@h%PD%Eq0;VdPL;|MHBi~vq0 zSk=q|rCii63%w>W(t1Xt?S2~}2{sOa-xj@}Q8Gb#HkybsOw|#pUNkN`TKsJa=s_2w zbjN5g-OLzFVZu-oLI&8e{+E+-5DR3=C9H>b-I|6W2p8IwB?x6rZ9+O@;7I&umDWUU z(-cmpIK_PFs^Y@a;8n?b)m@a5+P)^(V(qNf)^fQ}^E~WwIFmwaXp~?^#f0cU_f4>- zyjiW(YM2kTIvma_g~gj~yjbL1N|iuOY6*%23#9L7rv@g=ljMvfII1=+K7dSq@m4aX zz(s~4JY53qg6LxlC}1&~L`*fy2AfAjL`(cbhy7aq=!mW4H~eV{uOuBXFVTDk^SZLFU_VZ0L-o##h_WZg zz-~)5^)^$!!ej}Up;7mUP@y#oZ=2~q7CGah0~RpNW%Y<6sX_J7lpUPG2<>#ENlgsp zERd0SSPb}GL4=}fm{EKSIVvP-SDSVp;37+me$7^~?6R6sCwg9W6Q?;6J-Q@0crS%7 z!8b^JVF>A&2B%X(7jkk3V)7<4)d}E~1D?~AftN=YKMPI0ODK4A^!ilE^h~)+%Qb~T zNPabHx*Q*nMsv(j#B*9YPMw$A*Nnq7h6zd0H6RpRQTI%hb#K{3cPFr{RnTuKUyoe{Vci!FuH97-!fPkmB` zZ_tu~YqK%sXfc6D@xkI*@m;oE6e(U8O96*Rem+hKjZh&h%0VH-L*i+S28#ZbV?nEF zqOd=l>b^CHQADQ9k2paLye4_dh4P8T30h*QQ9jD>}w{2?#}D80p$q+&4u zZUw!Q1XmR6@o+s7Rw7Oj$RM9f z$y5ERW<=Rdf~(h00Zf=!tIERHsP2TTO1Hs_u^ahsHHfS6Oo>njCn#O7o0NqqqTJozuX6P)f& zAe$HOP&6lCa6$l+o2@vVjRtbf;s9@;^;jCluVDttzY0HwOF7tnLpT}(<4I%S+5x5P zKR@)k=h93LXB00411sz0*QzsppPxM0%G6ueOw=z6=R)Bx)Q+WconJUJJa`m^w%HEY z&Ka8Ki5iefBj^#U)YJ+Du-J=88ljA{U54l_ju0EBh`%TF2B))K7{^1Da*7cfav~Rkh(|-w02>OKmwyg* zTf2q?3%4LoU7q}dNeA^meLS^_DLsMH-%+GJgvD_27(6nDLfShwlULov;iqHBE_gHJ>0<@$$;+4!gY!ESIi6jt((B1V#1B;TSB zLeFA;rNxc*mPU_wsI#`wHbnH+qWH5y@L^ps{&wi*6VPmnX zF}Q$Pv13sf_mvs4add0%!kf33ug2gvp|COkMjKUg1ioqL}0>nNgzsgbEg#=R%q3Pz*xTGlq7OL#e%;3 zM4>a(t>Dsi=;Eo|>cXtjFD?}}^4&2MbBr-Y&x!OzzLWLEr1LgCK?&lfxEkuq42|8Q zUT#sl#2KUcg~&Jf$DYI{if!?_Pf0Cf?N$uf=~Ou6#I&Y@X- zcPCwMd1+t>EyTztL%pE zgkR@hlwUP2jAb~pLanN8L=#ovxeFr1e{0x^mlafvmag<}y`+CG@{uFe_Xaz-GA&4X z?1=LXTKZ9zS^rggZG{QCwi$6(<07&<^h_-|=(4{Q=t*&Y-qzBCb` zOBgyjGTujs?gR4^fFV$H?AKo%*i@O$3oV_Ed>Gn-nja`RF1GEv4+_T`s}F~kkqney zq^A9z`Uki=X5kr5HUI8=+iolt_qtAS3KD=XP=X>(D0owJb$G_?%{ObGSZWF;TNA9a zb%ntph$trsqS^?#wEn*9{^by-T=r#&L4mo2R8SvzF+lKD*Za!Y+~zywEiP=@cFR1V^uJSikrLL}2X5_E6C2d5&btwQCUOip?4{R9J8t1{}_W4@`msWEoSA|31Jj8mnkL` z^Q8=Ll>_Nazp=t{?@|{CrW+)N8AWK3IqIN>U@28qw9ZHj7>aU*JxMwG&`~0qV^j>x zp@zBpgdr{i52{~=Q$mMOR1b~!3ti(_Rj5V=R?%-+WVOSevY#l)Gob!^dQ!NX7bH)) zu-r(JFA)1i?R?48f7Xz$fK$dr5oX9~t``2fl`+`g+uQedPU&iY5M5MM4Y`xm*HCx0 zQ+I3=*A+a?(<3GW59EKW?g}=zLIZC|dQJ$J5m3j4x-UU~!+@y=bVXoSv>eyoRzgxz zP*=zaaNrh2o5bfER>Viky=lbsafk#jFz-0;S@u&z7Fo`fV_gPaYc>BH0y$Fwa78?& zjK8+_#?3ZT8L+KmX%hr*kqQNno7-X*i7?4EdeNNV2o-&+!dNb4>4Xu0(}*Iu6%);2 z8mWINXL3uEI2+nF62SRFr}7?>UnN7NUg|MTjv-m&&%LXhCk(S(qrN$r4N`l)kp{EGH9hZxNDYV<>tI*m_XKA zmVqeCqfTv{RVXNI|E3{kL|ToPFE(5P0Sl_WcepqoJ5=vCVERID z9Ws3Zb{I5$L3SKAeZh7dICZcxO2m2@GT(ZQoIUTz*$<4IXUzkrHi>I7_6nr?wF`iL zBH15)t5Eg_*+DG(1MMi7{Q-9rO%GscVcBnc3Fou>mrWH9c45s#^{6w)H0o$)*5L+S zI;!X|_K>dQ;LbO_kZ>TkU~%qrULB3nX6%oL3pKtCp`TVK3M20slEaTlxk&x#8MBl#Zv|8{TxSgEx0&R$FM{}c^urJ zp=0bMTnSEvq3hfL83S0mAMjKivs4h~Vr?qq9L0J;_Mboo<&9)SG@m1V)J3@l^b1va ztus6Fu-ERv^F1eu8EnfXtmz8P?;Y(!t@mCT+l(aEVwmrlccSBjG8}`0idASs2#Ja` z%YIDYtiEFh%kT{oyDC<~U@A&$^G-#|cezHBuVq+k`P+Hf|`9--3*446410NZWT7?tftgFl_>(=_o@ zCryjmCi?I8tN&ru(Xot!;lNjIFnFq`U!8)1`P0&r@bXk+0k&1{0-Z*KP}5YJC&^Qg zl3H_emH?QQ&N>;N5X}jZqHVz|TSs&R!1gRV5M$%$w~MFxlrN0|NlQpS{r%Nb@frMY z;BAJ|3l5{39jC*pnQhv8%??{^@3csc5vz{fI;=$=wl*$J@Yf{vMAXz9SEYe0?zCG% zQJP6iOTw1?jbe`8rcoCy!0^B8domuW#s799W5w?=`2Hu{r3n*3QiPHeu}-$OsVQ>< z+SIq4!?L!HpS0Y=0A|@3ES5uCnFCn8qe|Eza4OA;Dlv(@mGF06PGCWqnI;UqX ztz?99Hj)Pux-=$=+l|TUMu|u$V^Ex*2)CM&7@hTNSq2PR&G(2g_8i30?{=REZpje4 zDrE(V73zYMgrO}mobN(aS-9vab)v?+@6cdEVEhs$Fpa#eRzBmYBRK#waQ%x_nKW5Yu+EI%5R%_W0?U3hAY{a+k#=S zXGt+5RFCWLs=N_HgNRF;Ojsjv)wwwoN;-%25NED^>Y=3=y*)bqLP9@>=}etpq{_Jn zxwMS+kunv{Srrf?4wwO35KQB1F{;>Hi4u~>L!C{54yTx+_b^Fzp9s62;)oA5m?@!> zpN5@7jh-*wH^cxZ0(gIKr2cGsq)#_ho*EEk^4*LQSPcWmoG(Ew~Jf0~ZPZ{snXJ?n@sjXM+ zo!)p-dRpR1(8Cf>MoL@j31U|-X#ou3DpU86v?=beoTepcdvo27!UCs9<$VA+#fy9a z(tI&NbT>mZLMazZ`#>bK(&I8K8RJ^y%S5`$fi2|09Hy}`v|BbiJOLcxhj*!cYr%(A zu+#%QPdg*%G#m6NQlwV?KVz|GU;cs@m{)KVh?!y<8>1kKTMCLCZWlVR`=UJ6;A=we zm3fm!sFBi;Ho{xr$&)Q+-n*$Iiq|IZ&areby(vg5_dE<-%XMa_50VwDyK^P@)pApm z)ND38MTuA6{1oeAWvM9f`daf;*aFy?slwsxW3Gxyu8PM56c0QB zg%*b|pH-q9aI5E)2#m#h%`8#U(Ue=FoE0ClOIW7FI{76od@SuguiRyZiIT$Aa!i!c z@({92IMlS|nYcsLJ7=13+3!!F;NaPuZNjnv|A6@>DzX~PI8k9(YtD)Fx%L%gohWtC z1J65A_C{Og3D!uGC-=mf9SvHtPc&j~=bxw`-jac$0c)Qtcl{g`jdWD9PJvdI~Zuu&jDD-8l=+H!a&I(VXD>d>p<*o40{Fu4o51hHe-oWgeyTT(Y zA+5P${)%7=f3^%3o{h_|Er*3=53Z8MB2axpc`O3ZSI=Y-0Ju&rivY-VvsnbdKIXG{ zF!?O(@P?H#T7&>>DyKyV{u)^=LLk@5YY_svc4mtZ;6HwD3ww%RF}p<&#K!Vl1Y1}q z!$lD2dO0qFVAs!b5d{4w$a7(>)z->%(PWW!$aPUgWA$to?T9qzyQpHaPR5INTv~Eo z)NGJVX1xe6Qy%kPe4TkO>>#OH=8Lks|2VlXDg>{b{USUR?lJ#`pO{T#z-ZD#Ejcj! zNNpqwMpvx9mOL1iFT8gqjCvS+TP_UetW`tK3qMwOkrg7)k}ofWwWIKu8RE-lhVb{C zFE>O}$E}eaB7lG=KSUD(8_N(8kYqbYM56?E%n}i3=Hcdvs7wYM%oO2lF?P)r;YDZD z*&;l%RIhvyC6eo9j0kb4C1-@Sf>=FkM5yg>-iXpK-#c@Jg|RPpM2XAV*(2&L`SM3J zHn?I2iF(VS91@MKKiDi1b^7XgBpNC6WRd`ARG#~_GD=v7k=5y$hGY|UyaMSaO60!! zgcEg||FkJ5n!A66q!ZRToyW8jZD}XGf_Tq~C+axdZ|aG9`;W;d)=xgs%GIwc{e&A^ z_z)6MSSyvyq@bvU6oM{EC|or9r=h5X1WVn{<|I#KoDjrm5%KB_>E^5x6{J?kJK;l1 zYnTO$o%9n9TFtp8>|Lz~l5OJr<!Nkc+MY>)r97T~>Ol@s2#=vM8s6g+k+!c0f z)dUvyH&^6UG?@`=v6ieL?q*vtF|%8xaF_9g{^rtZK)9+HR~clqd`h@IAvmT`62ndP`$8&67ly<7km3<_zu@&<^gJY&q!K6Xa3gkg8b++Nf{& zrps_EIVaL1=`!Jx+@KU3nU94frh6K2`Mp&0^j5~mI)w^s8k#UF>B$ptP7(xOLSd2| zNrS74q{=A#U6}JZq4?iQ0n-VLq$r9%TmcksjM)7)N9qIsF}*7~I%i0Ys4_;7P$3Fc zX;XMRBT@Uu&k$W;rUrdwT%K0^5#{Hx_^f;;R{b$Jo(s!Qa+$oBIZo0T%w+7hmg2gr zOfowoSVe%Afw?AhT%Tf_QnJw9=S27dP0vX1u#S?$(Awv!Yu@$1=mbD>wH)X})Hd6x z&~;rS?7DCuRU^Qf5SH7oBZ_92ak{K@kuE>XtUguywWdNx=ow*H?gw;-Z>n@^fx}s6 z(4y=%UMzC16fc~qUgRHJar~q8GYd+ZI)TJRH)EE>T|XRWWd3;tOH_Iov{Wo!bHC}+#ZAKJ~f-8BvGC(I1}^lFh&y$)8YQ! zkRH5HAt5Cz#^7}NhH!a2F)f@(9@nWsQ^>qT@yw!io9RDfPA_ROq$*t9%v#!RkW^Lh1@yI7v$o^nJh z`NI~fzN@PB%R)iR&>;Y&zj+uz3bH!f4hq$Pt*Fsg2D1ijS*=>=$XaEuDs-z0rB(OseC^}s~ffQ+8gaZ8#xMW|Ha{>0=pvxX5_&(<^Q2lsr<8M z(+ge{a%PSlR*ZSoVlhqyM_5FmOxhq8CIe3a0dWilf7{=CKJY7q51hgyIeUWY55aI4kt9KpT9jPLV^Rww)`>#p>I6Vexd~1a zGP}}S!EvkYRz6x}UCS->InrR!j1sYIOEBY|3yu~zl?m>eYy2xmba_P) z%Sg&lhYGwyKd3UJ7;-o%^C32uZtt|5AsQ%_Av!h1(5;XGd4gIV^y^o86yq6U{7Nj> zuB2Jfv;Hb|1lK#)dk=9NQB$0tD^MHll1Wz?;rITuQ41}xq!YdCxPR<^+tMLM&H`fpXFHZLp)_@dUwS$ zhW_fCI$`LCzQ*}NKftw47y3c2eYVgK_Uk!W=s%eiI?2^Ca4M&e9@fZN`2=JDz{bu$ z2H>xA`Y`}qanU{iU3Z9n@es% ztG`s-lf^tNtw(vr2Rm0_6tz9Eh=B%wCleW+F3qLX+V)ndEQ#{IaY$#V+~4Iy?tntI zIrlr6=zZ?gb}HG3nO3^vC8IBIVFFIgACQ{}Fx>|_d}M-D_qc&0roNDD)~!he#pnm) ziJ-DYa1c#0CcFRIkr1 zYG2!LI?#;M8Df?2+5029hJSa`=OiUmr|`D_mWP(~uDGiD4Kq1NNhW3nrc1es}{q%oFZgcY(9Cq;)(UH8i`j>=0As1)|AI?%Aan) zqjUPE13QvHl64uY^_>oYi`lF=jaBSCXr780u$(a~A~+IL8Y>d? znwUCst{TTEV!@Fzig{S;M3v&p|O^UM#Ftl>%vwIWh5P=&K=?#$8Q>sG*tsvJ` zB&(@J*>|3rSxqXpM6gYT4>Tr{$sKtMdu~lO-k06Z6!LsaL)ir0H}s zx{QsDv}PM5!4;)uSqMn*qcl`nK7Q!Z5L}E{>MBO*^0-VubV*+6gQaEyMAi8(Mky9k zUCw7jo~BSIP{j*|W4%|Yj&ME&=tG1ubuQ%O%>~%b2<70#vqp7lqt`=gQtOfhR8x@P z1f?>SfuU5Lwp6t0X#q32FCCFZ2DzNSM_6Xsv48OF@bJanU-tH&Kim86FJNzTD1@J!aY+BNw{}}q;=YpS;}!se zzp8E@jKN^ec{bkN6#_8S!a(S3SN-{9@KhA%%M6LKN&%{O86_E_93wUugO75^4j_%@ zn4^g26cul+`s$KiSzo=!JdqzvNQMKTC^jW@F;IJ0#k&}>h+?@DD*)7QFq8S35|Scy zkC_#Cb*&ujpPy=^b3XSWYZ2=rdzACJu+$Ya_f&8*(jK14_mmKR1{r%#XzY9m^Ulvd z0Z0boN=Qyw4?aFdp6F|Zy=Y5`2LIZX2fqBsHyD}almkb?sD=dziB znYPvVC_hR7gUG3Z-C``0Qn*rQhBO($~@=C9LkkC*{SsGW2az7NF5)_%$f?`XInI zXAbGZx3x5|R~CCQ@?i+%W*EF>|7#{%?c?b+*Pdw)Qjwk0T=6tb$&*J_ukZziIDA?SqBkgpdTmw9-A{_FNL``B3YCDw5ed@$0|=__-oS4F9{z zeb6$_0=-Z)dm%vf;s-@(EY;+IB{;4OO@*d>{~8Mx?1#R>4+9yD8~FY%#ay)U6RyJ# zj6~2fJpg+sT3xbhB&SmP^H%6r+juSfaJ@$CMLnZ#w=wJCM~Dvv{g#5Q(*OD1l|en1 z@S{3-R0sC=uUZ|{PQrIl3!$;+m+MBE4vwFyEX&jQWop(&qw5_*0H(DRBt&NQF=^(& zlq4~tzD1B&^_ZM0I_gZOAd#jSH|Lk9So&@e<2Y4rf)-xu5RWb#_Nh|Kd@4dnOdL*( zIK&CNn=UFE)?u}t_RUe7#%|Hot;_>X=jbejb?E&TpKdr;pE=;JRCWXZOptLUvaD5G z7p$zr>~R7(h4ShUe^hhPVn0o~2|cD!+Mo{G690SLM6mq-Cf^v_ee?G6)y0T^;2UeB z+5f-y-Tw1~y8nOw(f@xR&+*Sk=a=Bk(d$=Z@bM!U9nT@W5K=Wf@UCdZfvw!nZ%>1&8?r1Iznuc z_{*e`lO;eOWM12JCRuWmPf)}YFhg9G7!Jz-T_GsvNJ_-03=#YM84MEuvuxy^lQT#8 zf2dZI=p0!wgCv#*q0K4i7)|n-gPM(*c-avvj=_HyqXfMD5nTTK3Y@(?`5$071QW>S zTU)0oAT(Cih*^Yc!7lFu*Ee*j>6mGZ^l5Sw0g#zq1b2wh5DXqG(RQ znMo}0@nb3GCTXU2yA{bZ2Vev~e;$P}8nN3*e$?WxqeD)JOg;Pg^Z4UO5D}Ol7NMe$ zX~TC#K~ot)k5*vlUqwmVXX>~u25L-8nlH-a2|lXJ#Ikouck|^8&7}%PjTbn@ zj4Q)6qDV$K!bJ7+JH1CXmfMzF02Ds-G5G7YEq*!$RwwEE__0W(>ab4dWl}5yLjrzh zBozkd4}*^~4aP_p9tv!RW@GB}0DKZ-9vwah!(ogf5~H21txIBJd4vX7lAIPBV3M}| z5jf9N0HuDCVM{_uMKCpI=b+ADtrbA2qG+Bvy{}cfq`cDcIzc}e4(S36hnz3L5Q|?( zs-7Rdd4p~d{RRwGt}Ec@jr?ZV(rJ7T%{*18LjVp&z~zZ?jhkbG+Z4fgS4^X5ryyDh z)o^|vqZ|x#xjjD2fK>|Sd|qThkwV*d@NNO{tV(?SegaAUkfh17BlQ~}?H%d2$L}Qp zc{Zak)|1v8B@1P686kf=5tE&oiOuMR45&5e1jWWr@=Z_`d}DISs(UB3q4ABx%Z`iq zraTfQT3~bXJ_Qq$koN^Y&)>eiygEC&xcKeu`NL`jn1ban}6rQxXbh?(K~)O7M5t^^^F{NlyP7nh_IWvnIe>GkCtAdG1`bu7-3C2Ivh`24vu#vXL z3yr41u);7`QZ)eEt@?h)wa`oCsx{RGpCc_)Wt$_k$oSG;5;&v`z_zsRgS2`Ouylp> z=a*jLK0ZxP-T!knM@fb#6U)cVw9yj(xxc?x_5ZxsKYaB6+{^RvVmcc-!IW1qS-#efq-exbN3*L@J zu{Qp$eX=ecCH`RBoTkIw(%a4N%i-83rBYPu*A32PBD)s7s_dO{JOA7cfTz>td+1_<2x*G9v4D2YT#S7 z2}?y69B|4Mkn8$u(6x%AZY}*Mstq*_wkB*?;_tL6 z&`I}^!Cu=orl?Ooy40%)S+k&pXB!7#cRADi>LO%e-l@VD+QC(orkV%NWyOxCgvUp> zwvZf?MTQfZYy%kYBfzOVg28Y)OAuHf#^4O8eAtmFIE6TAFu|&hN7M3OH6-aZlqRY7 z3(PWsWBIPGQQQ`s;pnIq2dH_?F^vmhV(dFseH{<`63TZ7WeUj{J?;4=}kI39bXI+sa6mxZ>fUeOPJJ?DYK21GjsBAMR9w~kpX21##0$UY2YPUEt zAvkh7z{jO+y;Wen`(g0m!-o%ponZHTX%E)pv(8iZ|H`b^LwVK85-v930&a=_+uJ{^ zp8tPwcyRdW|Gke#jASY=3^f`{_Wy|t2@=!ka5(h&Sz2Su-0h*qEujbc)W^S_S9Cd4 znPJw`1TEwL;Q6!a{?B*cJ==R6|M&5DyaxVMvD<`(N_5KK)Lz$0@go%m%&?9i9{WO| zBACGmPB6zcsAWyapG30Pu+^+rcqwTCzsC8Rd$z?~8$=9>Tq|?1B z6OG0Kty&;&Z7r$l>SWJ$k#=1Syn((BKubRZPgrreN-RSQs;Jo)5~^5a=Nj?#QMDUr z!Pml;Wk}xQUCYJh$z|5Nvkp~rNN#!bwDuF?e@!*0t#6@tJPIB=iD-TwW$Sog*7PsI(KP^^<6?lyqyTIey+D z=1*s&)aQTg5#BAli)$|fTIT=#XM4}9^Z)*f=a2LMeLQ;PhIc_~j^I&ka=zWy6Kt^) z=$~9WhV*VZmzVe>A3uSA<%FY6O}zC33K3akBt+hkGxohF=a0tr(fjlD*_M60Kb`IV)g47zk{oZ4J=(gBo@%M~(OAEd zrMbMtuAS25WM3W7;^qlAY(=d!+&Z8SLDoCTX?-J(qA;ofSJD1+Pzk-UoL`+eV_zcU z@WgXz#24U(jovDJ@cRVAGfR)Fyu#wX(p_6CgIar#tc31^8$T;iaVJBo=WS#UXw>z@ z{GkoVj^UqyF|r!-8)xexcCVu&bx4Ea;2y`M0#p zTE)E1h0cN-oW#TWpK-|1G*1{>HxRg4|35$6+pop{y?D(3a6eBUKdUVf0Wa%?E^=`X z6TqY5|Ed+gxfNjy_T{fzETrjY%s8RTU+@BRud?+OdCKVPe75KKr_!8x{?EyV%B(Y{vNyQ|h&8h6V%Uu4sb<|xh+L}hxz;;6XuwgBV2ma1esoXWQy@Q%C6^kQC5 z8!`^1jI8Gu8MXEvoKA6y`O=z>^qbA}TLHggr|C4(6;ul07OJfgKV3!GlNqs6AIi%x zyqZ#jJEMppF5xHzHL#L^h1}zN_P~>Bm*Y+2XMtQF$CSjVGlHUU8-_MOh2BUM1cMv2 z>{R*&Ew%8lPUTh65QU+E?*m-lwz1!CM*N+2R@Ylqu$&}_R*eVivAb#e`zMJWe2EE~9Fn{NAP-0RJ2% z6t&y_%I$V)uM6!YzCckfp(%da*LRrd)G44kmWV}OJGAn)CGg3tiqyJHhF$Ov&%QAEK!8=2KYQ*KL#qSQ;D;9wpOfeha~E zp5;2p-p8(2YL!*Kzy()cQtD=nW|jiAd7P^)^g(t5e81Q0z4~xm!r3sY4(tsw+Q3cl z6h+G@K|d36Q^CIYwiyyCO|3%=N^kuW#LLsmH%G5euTEaQeD_mD1xvKFCyJ(!F2R6P zf#^V9w>fZPYL)&|m!&ler^h4a<+x1Imowzvp;4)0=y-i}etLBB^2)i7+TV!!v%S3yYl~h6zg$$}X{- zG7T;VYcg2&)T{LNS4eBD-Gq(o!0%`wHyivO2d>@7@$1IVI`4MX_^uE84*WWPT^Gj4 zq(ks(iZtZ$Zw9-1m-@&RXezC=I*xw0!EUR)tmHWZwjXH8{*_dHmBvqUCUcxUd$xC2 z7YsX#MVDoFv&uQ6WD=-omuPVA*v0xebb!1$y4p2f4=`x(0t2rn71qaMTpAapa1-CfX`9tfl|ZbuiFviVDQ&4$ia>W z&J=rIO2LBh0;lED7a$$FLi=?dWqN=xeCr*@Glp@9&27yzg zVH7y!9*4mnco_WR^mLoBY-S+1ZQj91pa{meWhl618peWK@NqEwfd|96+tsb|vYFvf zX?5N4(0!1!@3V$N*dI4nyKSxl?+PezOP}|1XyvR#$4SrDz_nOj@i;^&r^}4sln+%S zqdsnC&l=9n1X*8uRBz`B5hDvU;P3NNiAuXFQDvwnJztwiv}0ZTuDE{p9aRZ6{v!KU ztA11)-`u)O&0np7cxNsIr;&C12o*}IS(iM~Lb`|rxFIm1az|~C00pOJYoJ1H!|-8j z&WY(X9-gvtW>sLPvgrtru_V9mfCnSQ&oG?Cq_H6HPXLq1jsFc8!Q3A3P-1~7+FoTX-DNG1H?F@N z*u8aF)43ndQJuyzMuQ~~FMPwH;_WNya)rID=SpuRUX`OEt2-yd2v})7j3d~0=YGcn zNfq2>0OkoccX8Q`bYgPcTEE@joKWK{YxIQUe|uv&J%Xe`j-mvz@?^XPtg%bLV3v>xOv*y)_f7{r>mcmOH_SGA zY~9;hrvw8Zt&5YK4*b%Y$R3|B@igTByN&KA|LfuYch&p<4)^vS^S|E96w%6-wSeZY|5IX|3&3Se99)O=135FPAvsPKlw=!{T4*wG| zBH#tE1_sJQ>cvBS+RT!qx%K7?Cmiam9XnsxzuI*9_z{E?`)N!hppmTGSf*Sa)vrVc zfI~V%Tx|y0csQcmN#m3Xq_^zvH03eW^->MKjbu}9$6D5!cikAsWsQY6rbq?MuEFw+Aa`~RRcE% zoRg%@;Sjok^~-o0923Kqo48cG}#nm1F|zPku)c*As!W3!&vu(ih%@2qxDT>P$!LoB3r7l-%WfPALAjM0RxZy;!Df0brRU zy~J<$Ro<0Z*Z;*us+EgXR&S%#{@<_e|9$uT@&2#-c|L|N@hQY0bd8U9=dg&z?6`MW zw(`X_d5_zLAC>+_l)e!Ub$oIRJ`J}lx40#MPW198U<0(nS-$jG`Wl}m{jYDBRyV#5 z^$pW2%mpp_|HbpeivQ=}V1NJMQUBk^a!VUQb>I0fHr2(*w#Qc<@3UvSyEp zh}=C3f0NmZ%dIBWxKD_3wuH8qdMzxy;ath-WBTyx6kHpX(>qr&qz(?>od z{*zGmmLR-YK-+Ra^r>`A)fcm)WD3vgpwagANIm(?hoKAs{jgIZsh47eBcgOniAoF( z>e%?$Q3iuQR&kJ$Ef@9a2I&iOo!A227-9*`9N~ELj=Im8?0Pz=g7?70%t}`QRp*2y z`8n-FhcG5cP~xoOv+&~>J&Ru(=V5m3^kCoIEbmIZBN|d#Hvko_7a{ z$1(mpbY+XYWx=a%wP5?TDfPBysh5G*&A^LO%o?B$DOzrNT?4sia*xAbQ`mBm8|xN$ zvNyMIA{%fy>Oz9`$bD0hSNoxenGj6hR6&!!t`YS>uN4gr17Q;4ZrU^F^OX z4W>ucDGuj`Zggx;#=r`HZ-%jyhqH$*2ImAVMO_VyrP&XfoBSqeHg$jE)D&nBGW(yJ zN-lEbN#l?VE8?g34oSnG+$|`~{1ikgxYUt)*_4BaDl3tTH-Yh-9df9alueZ0K8F6xE(2#4IuF5>5<{!(BsvyVP1Yi0*%$i>;q&;F^-o zQ2!@5xJ=@v`eDF=5;*U@JvLG+8+mf%2NQnkU!qEOR_l)VpGK0`tK>)U;`p0dDw_ul zk}vQ}??ZJN6=6WE)1=PAuN*F(+e2gGVF&C)$RPQc5T?6k`~sSU>A)s>%?sIUNte9B zy%l*q;GY|=ozM@*A`FnXLBMJN<=o4I(Z%w1U)j|)gSm@qP#Z(nXC!%13+(cZahqv4J#{>Oz zakM?M&Q8!C}**jFLw#uNrE0!nGDaX$F7nxqwz=-uVYAU_-@@jv~*-@)tm zd2;c*`Fk$)lP;*W{2c+XDuJ0^J5%fL@8g91r{3r9(u(`cPM(2&x7X{(apj|-OSVkp zN>Vn?FR!?z&KM-~hhVDo%+&t61wU8!LmNFAjrRLH8C{9f;$exARd-swMwawY(t%IrAhpke znPLrqmzTfm^C6>zfF77@rU&~0o8qdgpQG8u!}l)Hi9_RtdJW=f%w+N7q=$t@FMh7R zer|6EuYlh&?7MdiX*B1sGoO{|=lYI*T$8vcgTL4F#nr{blbdDqbu{e%6pAZ2jxEB9 zdE-^R#`$$^s!n&`2(PLpdc&mT2qUmL(ecMzpo6+uO@p?I?OSeh+o&Y;nXsJz9Z^fryd>{zk0yJA&zlvX zx>4qbQ(V$sPLMeYv1}Z2`$`WMSq|r62dJ$>$@j;&6c-H;ZE!0Ulahs-j*yaBDC=Dc zI0AlBSlj;lhV04q)^m3fPdDv% zpZ=c9yMme(X{{FsxZ)WugvhzC>EnP*{-Xkhk^lLF0n7T+oG4nD{7Wus3iEyEcYg&u-+iS2HSZS-Cuc-y0_ zEE9D^M6|#A(>hEsyF3kK%hD_6(^%NJ!tl-x+>)RJ3S_1%Vs!8$mhA^1?x-s}c?oHX zIk3F-u~nM0+m|K-jw975)kmP&cOo(J@xNP7k1+3|QXsgaQN|_)i!tib;(^KndUth z>Y}}q&2T4QrO*%k*COG})bA{?>t-{lS1-{+0oEI62~*qG^4j}AnwO;>b{^=75?{CC)^oW01pXmztm0LCt5jRhj|Q1zPhTcYBj z0UVk!vbj#tpNo;4UeS8=&(o1jKN>sFtZd#lq6F) zhJ@KC9)xo^r{-3Z!y+CL3c%UlIO*kv0mn6~nUqqS(vB$i1-Ws28*;lHH#29zN_6R! zWP?6xBH|{S!j(UCHd7E5JOIH!eS6L(6|vIWKt-CHn4HlEhX8-H6ufsd7pErTPit>o zEk5AvvYc<{SwPG;)rUYtVe$j8{&-9CDsa=wxfaj`c-7By{xX=2t7JL&t0K>WU&CKX z=nfj0oUqyoczbALg4Fdj)b`)*c&=E{OMwybapNkj|4b4a$ z?SnA{Vj?@;i@4=fwh9l^agResvnkL|c9yVWaLSh}En(+hMh4|St(OKjEk&{eZTe;mViEQ5CK={{SvWB+~a;?3W-Kv-Tf2S4W0p?gW zSL3DB`&*oTZS4v&wmz*M`7&p}_5O~!DrZ2ko9GybTHqw*q<?eU?b&bM|JX(>@dF+4{2IizSW~ZbsT;9y7O4nn07|=u}eEz^2 zPYPDyQP96$%nIJY4taJMfMOH#GgXf0n_iUAD67gaV7ORCoRAt3)k5r?5{UD_g0LuL zNXK%=OKhe(=b3x6E1ZweR}TPR`8Xjo0VJGIY3*rAQ*C(S(!T(9V!kfEcYm^dqhGx~ zUU`A6V_ZelpgBO~Kzmg=M(3w)1i9Rt;cesqEm=L?UQp zoMOe*^W($I;FM@~e88j15`hK@jDoS$n>f=xwfN-SUh!t55x{$8@$c1I@t8M+4NE)#qz~guzS<37M_?_${f_hd_R!0i#7if2*I585%?yI1C%9|r2 z2vYe5dA_ zX1f-cL>+)goy<-Qs#wWJa?k$97=cCF-YFIRQ5|4-3*SvqcHpoRA!`x%x(zS8AK@{#H`kMU6fDa z`*$a0i@yNS@{8DFv3%gjMZV?Ko-n0S@yY~~?mrC@@k_L0^#uN&irow7`uDlsF7rdF z;~g;dkcisA7IR)rF^XSXSwTwih5Ri33IX`pltX!OY!F`C!S}D%TL1J|d}$3@9QSA- zSs|@Rz>&Ko(J5<^&xu|~8BWeYYRA@2FIkv>SZ5e(9O!;=tWuLC=u$bbcC;CIL2Y7~ zirp(j6|uoM5=AUx7@X8BOZd0-#JFvN__x5!56X{>`#pbCq2XW@!B8@uGSP4(6HLV) z+!vu8Sr8O`m}sWLxR^|uy|MXOps#gT|KMuVVRR33iWBL{+BlN{YBd?Vh?>1oDDQqcq#G37X# zp!B|S-`A)Bt>ZJXomb^4yW`z*ejsme_0x%R>_qtznJ}B3uUdrlVYf-d%k6AU!nwz# zTnN|`W?)aSaWAqS(No7xO1u00cM_D11bD_~h=LBKp-u%{#XjkOM7ATbX$tiy;+{n^ zEe462u=1|%A3PnF9?vji+md-sp zKA)UK@FDk8C?hr0D2u;QX6JcOnvs^Aq?st!+N8?cer+7X&s2@CfOZzPVF4-SsW`K= zGP^W|@C{cK^(Lg$$UktSkwusY!6Q` z35W-RtRVAPL}W>es}0xbSUWt}5GeWO`__Je>h(Fepz_r!&-BNG)%PU}m&d~Ks?I^H zuS?(He~P3Mhyf zmlMvr8Jy&VTseBHm+ihsju0*P#!0ldq!FxUhKgitjM65n9dCnt`F+pdJ7>d|fc5{+ z|D?a^ONSa9ajcXAoGGnyXW{!(-Qqd!z$}$9)iFA1*^x;-661xQDb>It`CRiO9HwSJ0hXbKX8_9*EnZqp&$#9oP78P0b>Ts{7gdB|E!Ep}TqhK3Ba8jVpt- zh@6&MwJl>|WmkA8@YOT}zz1R#@$kZY(bfmiyC&bDMcn1V-F%ATu{An)?J>kERL(^1 zr6vL0qLtHhFz#I~B|~wii^#xQROcVxK^b%2Us3L5~2*?f!Y+=!D*`d2fO1Ln`i& zG6^7Mw#-?aoQ-LA39&{0*Zut1ZN4-E&sech5X&&^>>E$G^%k;77bi9WDT32LUyH>? zfc7%BLN@m_r$qe?X2uB7;5>Y^(9frq9JcSrNH=6GVaI8ca-!%>()_4IQ-IrKy0?*C zD7ZK8dhwy%;-|-_60jYXFjIf;JS%oBT){*jZ<=gll!htMDTh0~^C&Q}XdLlbgE_}< z;gt$r#{i?q?~lDq1qzN73!Hhu36uenvSTc*eD2?aj?XRi&H39KlHdErux;f~8<%%j zQC&7gslJduaWDZEy61#VVwKb}xRi5QsZN-=+^8(pn=3kW%0NIZ$e^C)ipq_*x~8j2 z{OWmW`=P#p&-@X&EMxRHY>cqEkNH!z^XPr;oN_&SS`9VVOlK?NM2wKHU%W6x;u$!@@TSvP&MQ4IsOuKd zkFSr7v0yr5&M#Q>K4>Dt>jWrSfL?P&A3EasntStwCh9dp`GXE{6~WS}V($NG({IAe zY&KN~`QhHOqO6Kc`XW?$g;TO0| zywwDEOQqAd;&@puc_)I;9l^|+s*N(M&O~%1YURfEDgDRgQrEz2WNtGzomgg=!`qMn z*e4G<;erESsl-Qkh!0RcGQ|2x8y^+jEc3Wsi4D^{mdvbUec*fE_J2dr=ld{h)vFm2MxZ!n=*dEk74Ry8kL7&85EM*EuvZ!xqpdM%#W1`GH~&Ha1Db8u7f? zaZA+A9nn}8?4f$9+;s>U*{1{|thpo;ZLp|GNv50ie-8G@ISV^YvP-&SJx;$?(WiK^ zu6fM8*2b7PFC&rQCYKf9lpWw3BBz{YN|y4B@msVX*lq#)$g?CTu0N0zLye4*p^sq7 zd&!;ZUIYuKf~n8*B>!PZ1Nm?3NlJw4z`~=HW%9NtZbof+}n_~MP5GRVT7hFtOAb9!6jRy&r~nQ`T&sy zm-gK|Xk8+PCpb(QsdItF=N_XzRq*gn_wD97heJOnLyMF>@ERIv*o6|_VPpB%@_`*< z8~g^%+w%funX75PR{ekQFAY%9^xQY`KTpplVGEla^=LU2B6&VT{oPIRGQ8X3X8^mI zf|zCH6+zN59~#mhfHo^WAdK&o48V&y12n**lzi$mbdJI6XOV`L0Xm+zk`@n}-34|= zfTD;a$5fQrkZ(%Eh2w3)kNiG2{C9|}G9*eav2>T{wH&f~{JQVr4~VvR&(k*}uVs5a}|h(=Bu%eAoCGKgDxT zw;B9b5y*CrdPExh-kEltC!fim;!xKay#oNWuE1s3|DEBR?2h=<4~$$(m(6k6zr!Eu z4EAgbyVoI7=ThXlXn;YFTVXe&Ux`SMR=V7@5ptj9z`PKb9IkSC#P|oa|6G+g(=PLm z=l_aP7q~oPe_kiGoRKgyTX6O8W-Me>O5#U~tznS*!3jkpKumSZm;M^gi}>;`_D62L zfCpG#XHB({0o1f!;jW+BH}23sJB*#sJ41p0F@7ZH{$IuqFd6KvvMXgd=nD(#cmlL- zRN`MB5To`-2a-;d91=j7uLjxhofV0D1z<+v zm~udKdE$th+sj{tPYwa#Z(QAyalP$kzXS#VQ0p9s_ViuG4sGUTI3T{{(t(F{^Ri(O z8KGaHciHzJ(i$hIOeMsecXDMdi7PHOo_-<4V_8Ri)lb-ZdAo1Nc6W6eH)%EmkWVx3!LLnrt>6xSuQzrNQqWEt z=Kla>!l=(eyWyO-@SySOz(f30Z;N-wVSp6$?nmKt z0mkT7^Ds8X3H*+tDjB-UoVf?(c||g{@!;seUGS#+K^XeM zQp-Ly{5#$j*k0h6!==2@p#EZTl+x{qtE{5Ws{D=&xC{Sd2?PZmV#1{^KMT=aAD|+I zw2bU?Tvabo?PeWLJadfhGQv@=dJ|!a`ciFE=~={x=x`54liOH{3JMDKLzI*Mp|fzi ze6l21L{{dA9K3!wW#JdafW5%x5Nr$QKs626(B>S7^#ED*WDs>^6XO)7#He{v9cWsY ziOp~t>XtnRmSX#%y zd;?;!DP7-T^$qhG>!P~_*HxE2vzn-3BU9(`vWF%yKlV1odP5uv`9xli+Bb-F0asja z#^ag4+(Eu3$;IutBW7eFGi`ZBjh8pt^1M{WGR}`d#$fcPZ@!T5F3I6NT(f#o4xSN8 zeraO=oH>>HtAM$d7#;t91{VG0-O}SU!(ipvcX}zb>VM`pv9k}r&u?_d0hYnx@L%B< zJdA!9=9!=S9P+DBy8WKwv*dPjm`2Rz^9a~4aiquD_%vE9yPdS(7`rc*_qO_CeZw8` zX2@gea?4e3pnmD*<4Ni(-rMSW@xwz#oDye+zcJvH zt!Z*$L?OW;t<>IS3t}d5*GR*4K?adCMA!o7hBRRS2SZH*hr^>N;PJ#jL|2a#9`RUL zfazNn@a}BEw|(m>Q2EJvbLAT_>aY13+nZ1tw@@c8;QRjjyTC@k_NJ@1OytIjzGGem zkWE>P3Xk}9C1ANz2s?LI#{y)DBTVTG%Env83lttM$Pfqwk4TFfSW29NOe8osH~|fW z^MXJ46P^MpxYS<(ok0ZZm~lenlmR;Xn@-?Z12pHx%exl~Y}kB%SMUJwQ`@Ph2pezt z74T2fynA>c1)bMlhOE#(fpxH8Hr_wJAO)5B-hEo&ebI;e#K#ywdd~}>GfY4oFN1nV z*lT;qO^e!3@(u8|@sR{QQ8$8BWBHfLt1)jmH~tq zbq@2KfjBo;w-G!%^2=`7Q3EYHU>6so!aFA*>p*5TO7{^OL2QF#?b)8D;T4VDU)O;J zRr~|F;d5ER*cR&c@qi1cWdw7>XS_ggtkxV$18bNy{Tjjl3;6=`S)Jvu7W~=2X@q$C zvkz>J05p@)V_#+@@(x<1LW4U-G^f(a-$w`1ZRHu*4kldRbT~WhHhE1Pke+9 zl)LKmnxtp=oG~wdFOxmZtSF>@!Nfu7g#sFlfm9~u={)MRUyrcdg5S3{;rX2PL;xYZy#lNHmficyN%%CWs zqcMiU3DL9yYBC$Fo$7a04>1Emj-yx*x#FZr7Eb4N!fBe|VIR;d#axmDQ|YiH8G-OQ zQ0)MW69VP|k1_vN@+@p}I(|ytqAH#`J{|aU#G7oEUZXv$+lcJt9 zpuG4dm4*%P;JZKLPq@jiaoqXydJU7AexyZTSB2>jmcfkO`kUm;W_=4wtOygf|CQ4q zqC=WNI>B>@+rgdMM6df*((c;d`87k)WefQN;qn*tO3Zswyl!*W9>ZP5IYv_ckoKm{ zJ@NXs^E&(DMEgO`wx;sOc*ndNsfW(CH;n-@hZKGo$uxp@oHL!8*Nn6meBi9os`>d6 zIRV6B7xO%$uT9j_g4=Q%L=W`gV*m+M+kNbXi~k1rJy$bS4&C15rEytougV4YqU-#v1rJsTB@!M8C7`#W?i|iAeP~&}Rdx0FV4|*;7HBOm zb>o@jLeB8&C$dzNJ$7jw&#VJ$=;A#jM`p)PX<7|l$Mw2T!P1b$muLfQD{tEt8ni~3764f$xh#pFzJqhezR!om^=Z+|}vXiHhXCRJ-d$}V< zx03^gcd1`VIj(9rwx);KW4sqr!+I<+_9WHitPpWBUzBOoxW#cX`8I&JY-JNy>uX<0 zoCK~JD-N+z3semM1J%e?MXpFENW)*1H6TQ1BV6$^gw{NS{v7u}!*!7`Lzvh@JB#pD zA19!L&p_WZBZ~PA2U_YE>L)bg2Gb0}|Sza(&u4X`1 z6wtkWYCs9ovrsa)Dn=L!Irs@t`iC>~=tPj41Ckm*J$R$vd zr8+$@%i9cG*D9cD2`v|Rd8iuJtn}d}qL9jBQXBc1<{4)9ukLaT68+LRux$G~uERBu#+m5tM%Z|PF~Vy89k z!)NO(BD6EQ#)*1CbLq14y!v0sfQL?oR_=3+KqthE&ZtLo=GIc9v-?oCu5iP# zOPU#&eKM-WRmr%3HLoVSuf$*5^hDW;Y+K?oS-a<-CDsZ;Fge++T6w|^ks}dVXZ(xL zgJs+%SZap^gvwy2=c|qPnS8xsN89TruWQ4!*7r9XOfZY+=+UcSPj|ws!>tqgY-!9= zEGc0M4y^Co7^yksyVmW@ly*)WxKh;_j6*8(M*_@1Qg%9KpeXI2iEoLL%8q(Is z6hk2-N>u!v%DuG_M~VU>qkCg{7C%7(@StZ|WV~4zIxI*kGL5i8B9z?U$0}nr-mRzK z@0(CY{9!jl{I22)Tt%6QoN^N0-bbKqW-q~pY&dcC8Q`ypyKvL##FX9>y%136{ddAM zBr_Sj{ldB|dA!T>;O*}&h&W`L2h12p)H9E-FNkO0g)jq4XW!173!K4{O46(ZPUZY| zAx+nTOx-MS#bc9n(&>>|Pq-vV;s`k8&!}u!jQD}YR8ZgW-QIpL4^Z7R#>2g;1)kwt zl2(4W*itX55vqcB?lV(0G?~!H%MZUINGM=}KL;kBGEfs2IMID1=?<`iX(*+yrrbE& zas$^`EB|>U&yc#FywXc|f9B$}nmJi*5J*c(|Cw>A6hnq>@_A5ydd6T`841s;6c(T? zyn#|`FEiAMEUgeSDor$pqIAhpYWp3nPvu&tO2kcVPY@Tprv<~J&Mukm162(0d|6CT zbl)*W1@2dAtk3q*$hlFE1pYmrc1hO*rZ+=nDJIyG#$`y8t>Vqe3@RbRtB@V_ygL^H zX~7n7w+HnFsRP7`!P8>6%v1Y&*S%ZdL#VFN#2RVcW)H0gp6VkaR8m%@u-ouiE`^@VVx3Lz zqhI~ytpFvtBu&3sv|-Mp!F#wUc0ib=eowT3T<2{l3Pqd^5qpC}19?I7v5J2d$+JeJ zzntkcFY`z_7KJ+#sm6O@UP$o%hl)GQ95Y(VH6DR8 zl6gAX-A8iHN}Q5yBolTEawn1tylsA%WEyJJBulyC4C^9N)Ehtl(n{OOJRByNHT;CG z{>1;d`9yx~-nq!q%5o-cyid@MjT+<>Wy^Zn4nw?@99f!IA+C#SL1}V zc6t$j{w490PujS|Im@NeiGJ1;tYu^b_NS*&)F3!Y*;`)sErE%X<>v!LXuVC56Palq zOGn|I;AyeCws(%RNq;sbn3mQQBs{H_yFm?iiq(W)K1QR^(k?~OluSoW%u&pO-8)Y& zGgb{V0=Mq!S*x9SzG3cc#UQD2wi#4@91$iCjq%)Z_9xPUcIXRy7#^s@K{~O=cmc|W zNOF(Oyz;p^uVnow&a8+c<2(do3K~bum}5f)@JWgfymdEg`H_(Ht(a)6onxkhG~qpWZQ8io0nmOK)kyIDg z#YD{13~Go3l1Fe|f&*P!*w$wm5y}mFO*DNnk+orIzU~An%go0d7i?JAqY#G**al)g zct|$d$wA)nQ3eg{R^D$}T}48Qc6sOYuYMI$=)5ph4GW9$@QUk=^AaRmwj&*x!H{!* z)NiR0SW(C<;&TDXjHJmq=bZuv(GgsgHHd;hvfv_B1tdI$2{X*xF~}{XWHjuiy5&Cn z-~p+9y~DIM@5=x{@5Urr7B$~8uwqyRFh$K~9eHjDptk&C z@3EC{R)b|{i=e7)@Pi7iPa1xiJ@zwlZLGf3@QWDs$R(En$0%_@>=l^yJ`*J({x|!0*68NGE`LVI-Kx zORzGEqCy7dVB!kd&pLzs&39$BZ0#lZX{9BV_c=Ve>&BJkNLp_Dca*ZRr%QdJGvn%! z3oYW%FT1QW1rrLA(3Pn{&dZkwlY^w>I7xC?8C*szAu@v(al;ZfohB36!tdCI2T?K7HmWJOPiv- z;CjMWtmJjoqtcL-9fH@HgO!7mxc|3^z-umMG?sbqJ$zU?Q> z8abjSYpglDaWjNrr5LSkHFv+TQlgc4NuL>ozcO%FC0i_X$2Xk}QEfGafik^T^1)Bc zxtvo9XKyB9BY#8&9z=xAg7Vz^{R*JuwF9QR^8oT8g{(1brdDdPw#EnhKHZP~^N0ii zRe=Oc5?cV^%6HD`tBODVf&uN*8P(x5#b>RkAo%15?_*JP-i(@3d$M6I7Z)RvetIrdmmfqW93i!Kp#3zoGN zp#Ik0cjsZSB_T{mA$lh2L$FjpWt2WbSNAP_S3}P-__ndmMNv@-8i#2U{Z|Tqxl6qz z?zH*ul}B~YhDTYgL4LP@*UQN?W37V0ztU~3{Jy_D!PK;=SZU787|9c1OaIc!I4M}u zXxO@HT_1YNU%>qthDMGT*vMBgszQ(|l1hPr)Tkc)Dfzvo0*|fGbcRJsRj}3(l8UOLt{Paj-ealsHJIDx3bvjf!wH%CR%Zl5cb6FHK2EP|DjNC>lzdSsvF-YBCAoppCU|4S{(hmm8JXIpQkHrKaT#hiTK~nhhyWb{d1i$gq1MH15@uGN_7iX>j3+ z0QiN4Gteg} zX%0;hEbix*Lg*8<@V);v}*x)06i+~>8g?KX8w^HT5f-0eA;DHa>scJ?rJbBIW3p#|sz)9CiaZ@LNn zo^NKDU=IP5Dc0&{8@X+3d`ER~%0Jrdtru9aS!F( zDC;#{` zvVVMrd)<=v;9d#lZ^5db<2jVs39$vu23m!81Y3j~I&G(ec`hu4gmg0TPZ=8)@FMZC zHlGa}3vi}c8&2Xr(F`snc?OBD*!?-;sj!2^kfbhS4lMwbwCK1F_uUW6TF*`QkQVF4 ziy3!PVeYMAzJ)n~S6TE~16Y}vH#CbU!f3YKZ4e5rb2bP^Lk1n-#$jq~u>jh;ATQqH zWT5Sj{Ii7-=C+~4E>m?aaZ*m75o*P#6n%x<0;V~*MS&_HBb6k4S9sLgk;00BDFXk;|)oLI=A38*YNk>$AO z!tlYbK}D9^*@zJQiy&kirUB-p^ib0~;2D(V20}gPs|fVE{~gTg2&=(A3xPkC4Ca$} zRBe6v=!}A04y7{d(59}jg>HQnqDvL?GH$z6Tz_W6%&Z6o%Wq#9Q1ASwoM~(n#s$4t zS8EKyUm^yJ?C9}{{m?S3(8#EwXymRVl-t?J;9iI58^F3%o_ZI29K_Rd%Hd_DE`+?~ zc~*LBfBrBtw$Z)RdXvltWh^dip=yGE0z_y2zQgmoiM3cvy^ueAxo5D%tcwaNuTeHp z0D~;1-xPo_dYYa=38H1au=vB7Tm(Pi{2fY$=Um5bpGm!`=I$LU!GW8*W=FO~5WbW06>EMO$bl&3k%xf@QUo&4&8wZX1;rj5>zGzOot}8JI6)C0iXs)$c zH9K|nqKl_izx(kTlgWzU0-WKYUfO~%z5Kzco}Xbv{G|44W!B!J_AxJPf$r&DaeMqk zcraGtI+}oE(f-;tugB-TH-0w2x@)TyV{uQUmrmxC!ETBKi8QSHYoU>v9v*YvIF-8U= z-tvuL*FBD>OJ7iYD#9(h~wC(?s+#T6vLTJt{4Ns z;%DS1)a3H;5x;5swuz-Ji$oOIG2AwK#Z9I-DeGm^#qpImY6`S$n_Q}?JAG=12#6`2 z(7;Bqwe4UK9>lT`!W9r+0oG6BIXJHIbY{>h!Me!4N^j$_MwnP=^q2%vy0I?&PHHC0S8ie7!Ltg}X4F?tDd9Nr1NK9~o+cLs0`w@!2a7+RM0s!}e5qE&EudfS0#Gu4y z01iJMKMnyNzyCi=fWjx_;AlerKj`b-wW@9lVzQHfjouf{<#9jKSp;rU;SOJftcyA# zeE$Oa7Pe+-FjGB2OU$jC>LaN-6Ef*EBu+J8czCwlJ`WLm;@M&}s^x!Fg3>hF$Nzk? zP@F=^3=)Z$Xxgn0b_adIxTJ~4s!3g69;USl78im3kuLFEsrAgEYb8`s!MQOgm&`xr zM?>863Q}1}IY}krbPmBCMK&Pr#{G?)H0l|>(q?^uWlsolMcsxAnZ6RyIv;-pPm4@!7E05}M0IoKRo(@ZDc9-#2k<$Hq%{_qN8LITgYyq+@Q(8zI7TeIUA zTAWE7Qar~a8<{Az^lVVdQt3^UvWbf$x5ndn5X3hHtPHEr#Oc^fJ7RI^YlkpoFq2o+ z974leRuQ%8y+s5=cTOpXqcTgbr$A$(@{RuEooKXjlut{<@kR?ZHx`OCC!2;w6eb(z zRj4Nuilm5vQ>`Rwa)IA+Gs5Gibdg;oWil8g6J0P+i6bLbKLapN*;=isQYK*C-9Z2jw8c;D3%N+| z)_LaNtvqR1U85iI8q%U1VSZO`Lwgg(*mlTL0NFy5=9?@O)9tEk@zh12&k5^HWO*S3a2HcGt>{0ezJ-l zwfx_7^#TSc+_~eVY;adGbv=o!Q@>lnuA1WihGgqW@CAPi-AHVwD?J;=_~jz=d)Q|< zSkh}$?XY9aRA(N%5L{Td;arR7OiX~_NMZ#RC~I> zeP$mbd70~;xjYIoEc2TM4vNp~80*zX6dQ(JZGi}Vg`TQNxCqqOW5d+ckhQ}`MA)Ef z#oXd#4Cf6V-mb0*qyFS(EL=6LPv9?%HIK@=aqOKc4KHA&m}kg5bv`GqHn59!mS^P> z;>$Tz;!;`na}E8b^X5OX8T5MSrm?vBNdyvfl!a_1A1e%GVoKrnsQvVXoWEEB&l>WZ<BrL84sx|i<~UB;*7IAG14~v*10z$os_O)A677Ek-bf+45EZsKuId9slU*h3&$)o zW%+CE;F%%T&FckE01v*X-zxFdPI*}bo-W*|=z&pf>`F^ZclG`RnjQ!0ZFq_E_UX)+ zx3irtI{RnG{v?oeqm}Eo#vDvbR7XbRl?TU7B-`c(hm}p$QnP(|gIsGw9?3%^X?PbR zH>uUz-AdHNP=W)ZlKzyHgzUS)7RBGGrCzY)sc9g5WK*41qEUPP7lN1<4SmEKwFnCJ z-`^}?o4j|ux;}dpP95mfz7frvJDu{qKmR8mOFAD@^Nl@(Kbro*6!Pr}&tUyZ4f`d$ z|97@EV&b%nv4e!^WE|qHlmC1_2g9@%`9izrDxMvfxV|Nt+cf;_14FDme(>y$QRxm& z@1UfnrtGjfTid`GAM^Af4Yg^EOinLk@Qi6=HB;AYQ^d`Lsp<3~iRemJ1C%bh?1kU| zdrM?23{*TQYEs2e$c+CNhv_dD7IMNqVslysVh$lffdPgE2+)sz>*&Ved3NC3?6)pO zBG7g^S%m?7u?TV)S=4U3AwKq$oGT@%#8Mq)mCs`RKlxL|z|d?M9>oiU1*f_p>g*j% zOL%m`#m9v=fM=|Cqw%AhKS6a(d`(I&;8ziD*<;mfbW0*c@J-&=j@^R&QO!5 zQfOHSXKAc2?E$sVfHUm~jrgy(MQ_0D{+$u~_v`rK{(dgtlq1jnn-EFgf^`OC zG4rI%xX-! zmzEbR0Prp9&NCrWh+=GjhpPdDTlDfNbG{@EIpxZN#4Wy5JC@!8x0ic zqpzGB2gZ)C1!Hi6?DpA!&imRP;Pl;4r?N^f?mFSXX_a%}u z&MvL!SK}HeQRvF;`s1BoC}3p|S6XHLI+PZ^{VJ;9818pQGdQ-ZW5GYUz**ApeeLMy zSo~}fLw*0_J%G{R^yn$-{hHZA0dLUD)6>_d`eq#9M{`Y&ysL4z7gmr9l9?-#IPq(e?je>YrQ)yVstt2LfW9z)X@5N@IaC#{mvoL( zOy^=NV1K{h`mz+SV6dqe=gO;MiMCVQcd%1TKGftF!etU+k^QXOo0Sn)nBt!+ADPqB zQnNZienJyW)3571>+ad?S*!o)8-Z?8|9klG(UYqF_vq1G{_m|k8|Z(Y$*(JZn@ap9 zlAxx37|MbF_0TTT+6Mf2%9t#oW~}}rXGFI~J$-s-Rf@LVxIBW>(>R$@A^B42Olk*= z+?bJl#3vnZ#t=T z=KC@xsP|_v__H{IK$udqDqdjP?OqY+$#%2i!!G_LLtHQ5!Vz=~1mWha)1vit#Avsu zM{@+#smgSrlhRKXX{x^x))~=XL9Thxyh5~2F>a;X;a>Z@gMLBP5Z z6;T3s3a3?C^C{58CHo}h<0y17NwpE4BAn-H-Acbkjf7bKD<}rghSGa!0ySmM^v~%~rR^zy@2gjL=5c~w?)pi+2*yzgo;ntM^u zv2@oSNscq&u9GTC>O;w;;__7I?!?9)is0%-L^DaIq~_{;p%CZ$InT_6X6m&)TC>dV z)CrcgJ3woTQCd_jWiS)%t*+6p1zLl&h_}6MbSXxl#kndAE`SN@YA-<^;ic2Ha|Hufgpg z80;DAiRq=M_waQjTmQ@>wB3dvgTHPZWKfGTfMSTN!wEEUt`<9BruIC=LV&cn7Cw(F zy={os`sb@-I5tP`jbQgn@4#R7S*!nS_+%{3#|Q}Wy%R}}`31Q&U-$lkJ`Z(nTx1m2r(>f_ma%JnwqXVNvdpW_TqNfM5i z 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

AEnyFJl6QdHKkB(zZ=j-~U<$z_+Y`p1x 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 O0RR6l2L+V?Rs#Sj_{PNm literal 0 HcmV?d00001 diff --git a/helm/open-build-service/charts/frontend/templates/NOTES.txt b/helm/open-build-service/charts/frontend/templates/NOTES.txt new file mode 100644 index 0000000000..81b5583344 --- /dev/null +++ b/helm/open-build-service/charts/frontend/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "frontend.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "frontend.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "frontend.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "frontend.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/helm/open-build-service/charts/frontend/templates/_helpers.tpl b/helm/open-build-service/charts/frontend/templates/_helpers.tpl new file mode 100644 index 0000000000..179333d618 --- /dev/null +++ b/helm/open-build-service/charts/frontend/templates/_helpers.tpl @@ -0,0 +1,86 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "frontend.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "frontend.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 "frontend.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "frontend.labels" -}} +helm.sh/chart: {{ include "frontend.chart" . }} +{{ include "frontend.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "frontend.selectorLabels" -}} +app.kubernetes.io/name: {{ include "frontend.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "frontend.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "frontend.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "frontend.mariadb.fullname" -}} +{{- printf "%s-%s" .Release.Name "mariadb" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "frontend.memcached.fullname" -}} +{{- printf "%s-%s" .Release.Name "memcached" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "backend.hostname" -}} +{{- coalesce (index .Values "global" "backend" "host") (printf "%s-%s" .Release.Name "backend" | trunc 63 | trimSuffix "-") -}} +{{- end -}} diff --git a/helm/open-build-service/charts/frontend/templates/deployment.yaml b/helm/open-build-service/charts/frontend/templates/deployment.yaml new file mode 100644 index 0000000000..9d01829bd5 --- /dev/null +++ b/helm/open-build-service/charts/frontend/templates/deployment.yaml @@ -0,0 +1,145 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "frontend.fullname" . }} + labels: + {{- include "frontend.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "frontend.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "frontend.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "frontend.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: OBS_BACKEND_HOST + value: {{ include "backend.hostname" . | quote }} + {{- if .Values.global.frontend }} + - name: OBS_FRONTEND_WORKERS + value: {{ default 4 .Values.global.frontend.workers | quote }} + {{- end }} + - name: OBS_MEMCACHE_HOST + value: {{ include "frontend.memcached.fullname" . | quote }} + - name: DB_PORT + value: "3306" + - name: DB_HOST + value: {{ include "frontend.mariadb.fullname" . | quote }} + - name: DB_NAME + value: {{ .Values.mariadb.auth.database | quote }} + - name: DB_USER + value: {{ .Values.mariadb.auth.username | quote }} + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "frontend.mariadb.fullname" . | quote }} + key: mariadb-password + - name: DB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "frontend.mariadb.fullname" . | quote}} + key: mariadb-root-password + ports: + - name: http + containerPort: 3000 + protocol: TCP + startupProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 20 + periodSeconds: 20 + failureThreshold: 30 + livenessProbe: + httpGet: + path: / + port: http + failureThreshold: 1 + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: tmp-scratch + mountPath: /tmp + - name: frontend-logs + mountPath: /obs/src/api/log + - name: {{ .Chart.Name }}-weblog + image: busybox + args: + - sh + - -c + - tail -n+1 -F /obs/src/api/log/web-stdout.log + volumeMounts: + - name: frontend-logs + mountPath: /obs/src/api/log + initContainers: + - name: {{ .Chart.Name }}-initbackend + image: busybox + command: + - sh + - -c + - | + until wget --spider {{ include "backend.hostname" . }}:5252 + do + echo waiting for the backend to become ready + sleep 2 + done + echo the backend is ready + - name: {{ .Chart.Name }}-initdb + image: busybox + command: + - sh + - -c + - | + until nslookup {{ include "frontend.mariadb.fullname" . }} + do + echo waiting for the database to start + sleep 5 + done + until nc {{ include "frontend.mariadb.fullname" . }} 3306 -e /bin/true < /dev/null + do + echo waiting for the database to become ready + sleep 2 + done + echo the database is ready + volumes: + - name: tmp-scratch + emptyDir: {} + - name: frontend-logs + emptyDir: {} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/helm/open-build-service/charts/frontend/templates/hpa.yaml b/helm/open-build-service/charts/frontend/templates/hpa.yaml new file mode 100644 index 0000000000..f1ffdc14ad --- /dev/null +++ b/helm/open-build-service/charts/frontend/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "frontend.fullname" . }} + labels: + {{- include "frontend.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "frontend.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/helm/open-build-service/charts/frontend/templates/ingress.yaml b/helm/open-build-service/charts/frontend/templates/ingress.yaml new file mode 100644 index 0000000000..410043aaa3 --- /dev/null +++ b/helm/open-build-service/charts/frontend/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "frontend.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "frontend.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/helm/open-build-service/charts/frontend/templates/service.yaml b/helm/open-build-service/charts/frontend/templates/service.yaml new file mode 100644 index 0000000000..708b0eda39 --- /dev/null +++ b/helm/open-build-service/charts/frontend/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "frontend.fullname" . }} + labels: + {{- include "frontend.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "frontend.selectorLabels" . | nindent 4 }} diff --git a/helm/open-build-service/charts/frontend/templates/serviceaccount.yaml b/helm/open-build-service/charts/frontend/templates/serviceaccount.yaml new file mode 100644 index 0000000000..cc64909118 --- /dev/null +++ b/helm/open-build-service/charts/frontend/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "frontend.serviceAccountName" . }} + labels: + {{- include "frontend.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/open-build-service/charts/frontend/templates/tests/test-connection.yaml b/helm/open-build-service/charts/frontend/templates/tests/test-connection.yaml new file mode 100644 index 0000000000..372ac5eba9 --- /dev/null +++ b/helm/open-build-service/charts/frontend/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "frontend.fullname" . }}-test-connection" + labels: + {{- include "frontend.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "frontend.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/helm/open-build-service/charts/frontend/values.yaml b/helm/open-build-service/charts/frontend/values.yaml new file mode 100644 index 0000000000..5d7c343a5a --- /dev/null +++ b/helm/open-build-service/charts/frontend/values.yaml @@ -0,0 +1,95 @@ +# Default values for open-build-service-frontend. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: registry.gitlab.collabora.com/obs/open-build-service/frontend + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: latest + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +global: + frontend: {} + # workers: 8 + backend: {} + # host: backend + +mariadb: + auth: + username: obs-api + # password: someobs + # rootPassword: someobs + database: obsapi + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 3000 + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/helm/open-build-service/templates/NOTES.txt b/helm/open-build-service/templates/NOTES.txt new file mode 100644 index 0000000000..81b5583344 --- /dev/null +++ b/helm/open-build-service/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "frontend.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "frontend.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "frontend.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "frontend.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/helm/open-build-service/templates/_helpers.tpl b/helm/open-build-service/templates/_helpers.tpl new file mode 100644 index 0000000000..6466a8a832 --- /dev/null +++ b/helm/open-build-service/templates/_helpers.tpl @@ -0,0 +1,69 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "open-build-service.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "open-build-service.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 "open-build-service.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "open-build-service.labels" -}} +helm.sh/chart: {{ include "open-build-service.chart" . }} +{{ include "open-build-service.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "open-build-service.selectorLabels" -}} +app.kubernetes.io/name: {{ include "open-build-service.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "open-build-service.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "open-build-service.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Returns the image repository depending on the chart name. +*/}} +{{- define "image.repository" -}} +{{/* index .Values "globals" "images" .Chart.Name "repository" */}} +{{- end -}} diff --git a/helm/open-build-service/values.yaml b/helm/open-build-service/values.yaml new file mode 100644 index 0000000000..e8c1f8e7f0 --- /dev/null +++ b/helm/open-build-service/values.yaml @@ -0,0 +1,101 @@ +# Default values for open-build-service. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +backend: + image: + repository: registry.gitlab.collabora.com/obs/open-build-service/backend + tag: collabora-staging + +frontend: + image: + repository: registry.gitlab.collabora.com/obs/open-build-service/frontend + tag: collabora-staging + mariadb: + primary: + persistence: + enabled: true + # size: 8Gi + # existingClaim: "" + +global: + frontend: + workers: 4 + # host: frontend + backend: {} + # host: backend + # extraConfig: | + # $ipaccess->{"10.*"} = "rw"; + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} -- GitLab