diff --git a/swh/templates/storage/configmap.yaml b/swh/templates/storage/configmap.yaml new file mode 100644 index 0000000000000000000000000000000000000000..41c41b577b549b9276017cbf639545e48262fabf --- /dev/null +++ b/swh/templates/storage/configmap.yaml @@ -0,0 +1,25 @@ +{{ if .Values.storage.enabled -}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.namespace }} + name: storage-configuration-template +data: + config.yml.template: | + storage: + cls: {{ .Values.storage.storageClass }} + hosts: + {{- range $seed := .Values.storage.cassandra.seeds }} + - {{ $seed }} + {{- end }} + keyspace: {{ .Values.storage.cassandra.keySpace }} + consistency_level: {{ .Values.storage.cassandra.consistencyLevel }} + {{- if .Values.storage.specific_options -}} + {{- range $option, $value := .Values.storage.specific_options }} + {{ $option }}: {{ $value }} + {{- end }} + {{- end }} + objstorage: + cls: noop +{{- end -}} diff --git a/swh/templates/storage/deployment.yaml b/swh/templates/storage/deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2fb05c9164bb0549bb112f359283eef56909487e --- /dev/null +++ b/swh/templates/storage/deployment.yaml @@ -0,0 +1,127 @@ +{{ if .Values.storage.enabled -}} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: {{ .Values.namespace }} + name: storage + labels: + app: storage +spec: + revisionHistoryLimit: 2 + replicas: {{ .Values.storage.replicas | default 1 }} + selector: + matchLabels: + app: storage + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + template: + metadata: + labels: + app: storage + annotations: + checksum/config: {{ include (print $.Template.BasePath "/storage/configmap.yaml") . | sha256sum }} + spec: + {{- if .Values.storage.affinity }} + affinity: + {{- toYaml .Values.storage.affinity | nindent 8 }} + {{- end }} + initContainers: + - name: prepare-configuration + image: debian:bullseye + imagePullPolicy: Always + command: + - /bin/bash + args: + - -c + - eval echo "\"$(</etc/swh/configuration-template/config.yml.template)\"" > /etc/swh/config.yml + volumeMounts: + - name: configuration + mountPath: /etc/swh + - name: configuration-template + mountPath: /etc/swh/configuration-template + {{- if .Values.storage.cassandra.initKeyspace }} + - name: init-database + image: {{ .Values.swh_storage_image }}:{{ .Values.swh_storage_image_version }} + imagePullPolicy: Always + command: + - /bin/bash + args: + - -c + - eval "echo \"from swh.storage.cassandra import create_keyspace; create_keyspace(['{{ first .Values.storage.cassandra.seeds }}'], 'swh')\" | python3" + {{- end }} + containers: + - name: storage + resources: + requests: + memory: {{ .Values.storage.requestedMemory | default "512Mi" }} + cpu: {{ .Values.storage.requestedCpu | default "500m" }} + image: {{ .Values.swh_storage_image }}:{{ .Values.swh_storage_image_version }} + imagePullPolicy: Always + ports: + - containerPort: 5002 + name: rpc + readinessProbe: + httpGet: + path: / + port: rpc + initialDelaySeconds: 15 + failureThreshold: 30 + periodSeconds: 5 + livenessProbe: + httpGet: + path: / + port: rpc + initialDelaySeconds: 10 + periodSeconds: 5 + command: + - /bin/bash + args: + - -c + - /opt/swh/entrypoint.sh + env: + {{ if .Values.storage.gunicorn -}} + - name: THREADS + value: {{ .Values.storage.gunicorn.threads | default 5 | quote }} + - name: WORKERS + value: {{ .Values.storage.gunicorn.workers | default 2 | quote }} + - name: TIMEOUT + value: {{ .Values.storage.gunicorn.timeout | default 60 | quote }} + {{ end -}} + - name: STATSD_HOST + value: {{ .Values.statsdExternalHost | default "prometheus-statsd-exporter" }} + - name: STATSD_PORT + value: {{ .Values.statsdPort | default "9125" | quote }} + - name: LOG_LEVEL + value: {{ .Values.storage.logLevel | quote }} + {{- if .Values.storage.sentry.enabled }} + - name: SWH_SENTRY_ENVIRONMENT + value: {{ .Values.sentry.environment }} + - name: SWH_MAIN_PACKAGE + value: swh.storage + - name: SWH_SENTRY_DSN + valueFrom: + secretKeyRef: + name: {{ .Values.storage.sentry.secretKeyRef }} + key: {{ .Values.storage.sentry.secretKeyName }} + # 'name' secret should exist & include key + # if the setting doesn't exist, sentry pushes will be disabled + optional: true + - name: SWH_SENTRY_DISABLE_LOGGING_EVENTS + value: "true" + {{- end }} + volumeMounts: + - name: configuration + mountPath: /etc/swh + volumes: + - name: configuration + emptyDir: {} + - name: configuration-template + configMap: + name: storage-configuration-template + items: + - key: "config.yml.template" + path: "config.yml.template" +{{- end -}} diff --git a/swh/templates/storage/service.yaml b/swh/templates/storage/service.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c11cacbbd1e71a265a636a27df2f11385016f98f --- /dev/null +++ b/swh/templates/storage/service.yaml @@ -0,0 +1,15 @@ +{{ if .Values.storage.enabled -}} +--- +apiVersion: v1 +kind: Service +metadata: + name: storage + namespace: {{ .Values.namespace }} +spec: + type: ClusterIP + selector: + app: storage + ports: + - port: 5002 + targetPort: 5002 +{{ end }} diff --git a/swh/tests/storage_confimap_test.yaml b/swh/tests/storage_confimap_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7e13891397870c6fc80a6b9f2835ff64d6d517ce --- /dev/null +++ b/swh/tests/storage_confimap_test.yaml @@ -0,0 +1,28 @@ +suite: test storage configmap deployment +templates: + - storage/configmap.yaml +tests: + - it: storage configmap is deployed when activated + set: + storage.enabled: true + asserts: + - containsDocument: + kind: ConfigMap + apiVersion: v1 + - equal: + path: metadata.namespace + value: swh + # not testable as there is a dot in the entry name + # - contains: + # path: data.config.yml + # content: + # debug: false + # count: 1 + - it: storage namespace + set: + storage.enabled: true + namespace: mynamespace + asserts: + - equal: + path: metadata.namespace + value: mynamespace \ No newline at end of file diff --git a/swh/tests/storage_deployment_test.yaml b/swh/tests/storage_deployment_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..798fa75def56d1e1ed00da0161dede8e3aa93105 --- /dev/null +++ b/swh/tests/storage_deployment_test.yaml @@ -0,0 +1,134 @@ +suite: test storage deployment +templates: + - storage/configmap.yaml + - storage/deployment.yaml +tests: + - it: Storage is deployed + templates: + - storage/deployment.yaml + set: + storage.enabled: true + swh_storage_image: image + swh_storage_image_version: version + storage.requestedMemory: memory + storage.requestedCpu: cpu + asserts: + - hasDocuments: + count: 1 + - equal: + path: metadata.namespace + value: swh + - equal: + path: spec.replicas + value: 1 + - equal: + path: spec.template.spec.containers[0].resources.requests.memory + value: memory + - equal: + path: spec.template.spec.containers[0].resources.requests.cpu + value: cpu + - equal: + path: spec.template.spec.containers[0].image + value: image:version + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "LOG_LEVEL")].value + value: "INFO" + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "STATSD_HOST")].value + value: prometheus-statsd-exporter + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "STATSD_PORT")].value + value: "9125" + - isNull: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "THREADS")] + - isNull: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "WORKERS")] + - isNull: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "TIMEOUT")] + - isNull: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_SENTRY_ENVIRONMENT")] + - isNull: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_MAIN_PACKAGE")] + - isNull: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_SENTRY_DSN")] + - it: Storage gunicorn workers configuration + templates: + - storage/deployment.yaml + set: + storage.enabled: true + swh_storage_image: image + swh_storage_image_version: version + storage.gunicorn.threads: 101 + storage.gunicorn.workers: 102 + storage.gunicorn.timeout: 103 + asserts: + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "THREADS")].value + value: "101" + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "WORKERS")].value + value: "102" + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "TIMEOUT")].value + value: "103" + - it: Storage statsd overridden configuration + templates: + - storage/deployment.yaml + set: + storage.enabled: true + swh_storage_image: image + swh_storage_image_version: version + statsdExternalHost: my-statsd-host + statsdPort: 9999 + asserts: + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "STATSD_HOST")].value + value: my-statsd-host + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "STATSD_PORT")].value + value: "9999" + - it: Storage sentry default configuration + templates: + - storage/deployment.yaml + set: + storage.enabled: true + storage.sentry.enabled: true + swh_storage_image: image + swh_storage_image_version: version + asserts: + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_SENTRY_ENVIRONMENT")].value + value: production + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_MAIN_PACKAGE")].value + value: swh.storage + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_SENTRY_DSN")].valueFrom.secretKeyRef.name + value: common-secrets + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_SENTRY_DSN")].valueFrom.secretKeyRef.key + value: storage-sentry-dsn + - it: Storage sentry overridden configuration + templates: + - storage/deployment.yaml + set: + sentry.environment: my-environment + storage.enabled: true + storage.sentry.enabled: true + storage.sentry.secretKeyRef: my-secret + storage.sentry.secretKeyName: my-key + swh_storage_image: image + swh_storage_image_version: version + asserts: + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_SENTRY_ENVIRONMENT")].value + value: my-environment + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_MAIN_PACKAGE")].value + value: swh.storage + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_SENTRY_DSN")].valueFrom.secretKeyRef.name + value: my-secret + - equal: + path: spec.template.spec.containers[?(@.name == "storage")].env[?(@.name == "SWH_SENTRY_DSN")].valueFrom.secretKeyRef.key + value: my-key \ No newline at end of file diff --git a/swh/tests/storage_global_test.yaml b/swh/tests/storage_global_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..39c94140e0ef0694327d06ccfe6bec3bb36a055d --- /dev/null +++ b/swh/tests/storage_global_test.yaml @@ -0,0 +1,12 @@ +suite: test storage deployment +templates: + - storage/deployment.yaml + - storage/configmap.yaml + - storage/service.yaml +tests: + - it: Storage is not deployed by default + values: + - ../values.yaml + asserts: + - hasDocuments: + count: 0 \ No newline at end of file diff --git a/swh/tests/storage_service_test.yaml b/swh/tests/storage_service_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a3e0bef01b151f202509b77d45524a4293450d9b --- /dev/null +++ b/swh/tests/storage_service_test.yaml @@ -0,0 +1,15 @@ +suite: test swh-storage service deployment +templates: + - storage/service.yaml +tests: + - it: swh-storage service is deployed when activated + set: + storage.enabled: true + namespace: mynamespace + asserts: + - containsDocument: + kind: Service + apiVersion: v1 + - equal: + path: metadata.namespace + value: mynamespace \ No newline at end of file diff --git a/swh/values.yaml b/swh/values.yaml index c7c91ccaa7bd8cc3f4c9ffd0c54d360bb8c296ff..7a94753ee14142b25d943d26658cdac7620c87b0 100644 --- a/swh/values.yaml +++ b/swh/values.yaml @@ -159,13 +159,49 @@ indexers: listers: enabled: false +storage: + enabled: false + logLevel: INFO + replicas: 1 + requestedCpu: 50m + requestedMemory: 100Mi + autoScaling: + maxReplicaCount: 1 + storageClass: cassandra +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: "swh/storage" +# operator: In +# values: +# - "true" +# gunicorn: +# threads: 5 +# workers: 2 +# timeout: 60 + sentry: + enabled: false + # name of the secret containing the $secretKeyName value + # it defines the sentry token, host and projet to access + # like https://token@sentry.host/id + secretKeyRef: common-secrets + secretKeyName: storage-sentry-dsn + cassandra: + initKeyspace: false # only to bootstrap a new cassandra database + seeds: + - seed1 + keySpace: swh + consistencyLevel: LOCAL_QUORUM + statsd_exporter: enabled: false image: prom/statsd-exporter imageVersion: "v0.22.7" memcached: - # Deploy a memcached instance used by the webapp and graphql for sessions caching + # Deploy a memcached instance used by the webapp and storage for sessions caching enabled: false image: memcached:1.6.18 memory: 256m @@ -175,3 +211,4 @@ memcached: # Activate the deployment of the memcached exporter and ServiceMonitor enabled: true image: quay.io/prometheus/memcached-exporter:v0.11.1 +