From f3c30dfd5886c8fa4dd27ac25e5cf1e5760e3f65 Mon Sep 17 00:00:00 2001 From: TechCarmat Date: Tue, 2 Nov 2021 12:59:39 +0100 Subject: [PATCH 001/146] Update release.yaml Related to #90 --- .github/workflows/release.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d9f74a6d..c44c0272 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,9 +1,9 @@ name: Release Helm charts on: - release: - types: [published] - + push: + branches: + - main jobs: sync-branch: @@ -16,7 +16,7 @@ jobs: uses: devmasx/merge-branch@v1.3.1 with: type: now - from_branch: ${{ github.base_ref }} + from_branch: main target_branch: gh-pages github_token: ${{ github.token }} From 55df4fab2e432b015ccd1ea3dafaa2a1993ce75b Mon Sep 17 00:00:00 2001 From: TechCarmat Date: Thu, 25 Nov 2021 14:51:51 +0100 Subject: [PATCH 002/146] Removing keycloak --- scaleout/stackn/README.md | 35 +- scaleout/stackn/revamp-values.yaml | 707 ++++++++++++++++++ scaleout/stackn/templates/_helper.tpl | 69 +- .../templates/celery-beat-deployment.yaml | 102 --- .../templates/celery-worker-deployment.yaml | 107 --- .../stackn/templates/studio-deployment.yaml | 6 +- .../templates/studio-settings-configmap.yaml | 165 ++-- 7 files changed, 799 insertions(+), 392 deletions(-) create mode 100644 scaleout/stackn/revamp-values.yaml delete mode 100644 scaleout/stackn/templates/celery-beat-deployment.yaml delete mode 100644 scaleout/stackn/templates/celery-worker-deployment.yaml diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 851838aa..9de2852e 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -11,13 +11,14 @@ Current chart version is 0.2.0 ## Chart Requirements -| Repository | Name | Version | Optional | -|------------|------|---------|----------| -| https://charts.bitnami.com/bitnami | postgresql | 11.6.14 | No -| https://charts.bitnami.com/bitnami | postgresql-ha | 9.2.0 | Yes -| https://grafana.github.io/helm-charts | grafana | 6.8.4 | Yes -| https://prometheus-community.github.io/helm-charts | prometheus | 13.8.0 | Yes -| https://stakater.github.io/stakater-charts | reloader | v0.0.86 | No +| Repository | Name | Version | +|------------|------|---------| +| https://charts.bitnami.com/bitnami | postgresql | 10.4.2 | +| https://charts.bitnami.com/bitnami | postgresql-ha | 7.3.0 | +| https://grafana.github.io/helm-charts | grafana | 6.8.4 | +| https://grafana.github.io/helm-charts | loki-stack | 2.3.1 | +| https://prometheus-community.github.io/helm-charts | prometheus | 13.8.0 | +| https://stakater.github.io/stakater-charts | reloader | v0.0.86 | ## Configuration @@ -52,19 +53,11 @@ Minimal requirement: `global.postgresql.storageClass` | Key | Type | Default | Description | |-----|------|---------|-------------| -| global.studio.existingSecret | string | `""` | Use existing secret. See basic-secrets.yaml. | -| global.studio.storageClass | string | `""` | StorageClassName for PVC. Overrides `studio.storage.storageClass`. If `studio.storage.storageClass` is unset (default) will inherent from `global.postgresql.storageClass` | -| global.studio.superUser | string | `admin` | Django superUser. Obs will always be `admin` until fixed. | -| global.studio.superuserEmail | string | `'admin@test.com'` | Django superUser email. Obs will always be `admin@test.com` until fixed. | -| global.studio.superuserPassword | string | `""` | Django superUser password. If left empty, will generate. | -| global.postgresql.auth.username | string | `stackn` | Postgres user will be created | -| global.postgresql.auth.password | string | `""` | Postgres password for user above. If empty, will be generated and stored in secret `stackn-studio-postgres` | -| global.postgresql.auth.database | string | `stackn` | Postgres database will be created | -| global.postgresql.auth.postgresPassword | string | `""` | Postgres password for postgres user If empty, will be generated and stored in secret `stackn-studio-postgres` | -| global.postgresql.auth.existingSecret | string | `""` | will not create secret `stackn-studio-postgres`. Instead use existing secret for postgres| -| global.postgresql.storageClass | string | `""` | StorageClassName for PVC | - - +| global.existingSecret | string | `""` | | +| global.storageClass | string | `"microk8s-hostpath"` | | +| global.studio.superUser | string | `""` | | +| global.studio.superuserEmail | string | `""` | | +| global.studio.superuserPassword | string | `""` | | ## Values @@ -117,6 +110,8 @@ Minimal requirement: `kubeconfig` | ingress.image.repository | string | `"scaleoutsystems/ingress:develop"` | | | ingress.tls[0].hosts[0] | string | `"studio."` | | | ingress.tls[0].secretName | string | `"prod-ingress"` | | +| labs.ingress.secretName | string | `"prod-ingress"` | | +| loki-stack.enabled | bool | `false` | | | namespace | string | `"default"` | | | postgresql-ha.enabled | bool | `false` | | | postgresql.enabled | bool | `true` | | diff --git a/scaleout/stackn/revamp-values.yaml b/scaleout/stackn/revamp-values.yaml new file mode 100644 index 00000000..40dd51b5 --- /dev/null +++ b/scaleout/stackn/revamp-values.yaml @@ -0,0 +1,707 @@ +# This is a YAML-formatted file. +# Declare variables to be passed into STACKn templates. + +# REQUIREMENT: +# - set a storage class with ability to serve ReadWriteMany +# Name: storageClassName, and/or set anchor &śtorage_class +# Description: Set a storage class for the resources that are reused for multi-mount-points in cluster. To reduce wasteful copying we allow to use the same dataset volume to be mounted multiple times. +# Default: microk8s-hostpath, use nfs-client for docker-for-desktop +# - replace , search and replace +# - cluster_config , kubernetes cluster + +#NOTES +# - For local development/testing consider setting "oidc.verify_ssl" to false + +#Set global values to overide default +global: + studio: + superUser: "" + superuserPassword: "" + superuserEmail: "" + existingSecret: "" + storageClass: &storage_class microk8s-hostpath + +### A Postgres database for STACKn ### +# Here we use https://charts.bitnami.com/bitnami postgresql chart + +# Postgres deploy with a single-pod database: +postgresql: + enabled: true + postgresqlUsername: stackn + postgresqlPassword: "" + postgresqlDatabase: stackn + existingSecret: "" + fullnameOverride: stackn-studio-postgres + service: + port: 5432 + persistence: + enabled: true + size: 20Gi + storageClass: *storage_class + accessModes: + - ReadWriteMany + +# Will be added in future realease, for now keep "enabled:false" +postgresql-ha: + enabled: false + +### DEPLOY SECRETS WITH private helm chart 'secrets' from platform/secrets +## Name: imagePullSecret +## Description: Secret to pull images from our private repository. +imagePullSecrets: + - name: regcred + +## to create a regcred +## kubectl create secret docker-registry regcred --docker-server= --docker-username= --docker-password= + +#Set stoargeClass +storageClassName: *storage_class +namespace: default +existingSecret: "" + +studio: + servicename: studio + replicas: 1 + debug: true + static: + replicas: 1 + image: ghcr.io/morganekmefjord/stackn/ingress:master #This image can be built from Dockerfile.nginx inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + resources: + limits: + cpu: 1 + memory: 512Mi + requests: + cpu: 100m + memory: 256Mi + image: #tell which image to deploy for studio + repository: ghcr.io/morganekmefjord/stackn/studio:revamp_auth #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + pullPolicy: Always # used to ensure that each time we redeploy always pull the latest image + resources: + limits: + cpu: 1000m + memory: 4Gi + requests: + cpu: 400m + memory: 2Gi + storage: + StorageClassName: *storage_class + size: 2Gi + media: + storage: + storageClassName: *storage_class + size: 5Gi + accessModes: ReadWriteMany + superUser: admin + superuserPassword: "" + superuserEmail: admin@test.com + +celeryWorkers: + replicas: 2 + resources: + requests: + cpu: 100m + memory: 1Gi + limits: + cpu: 1000m + memory: 8Gi + +# Enable ingress if you want your to access the studio solution from a kubernetes host/localhost. +domain: studio.10.0.145.40.nip.io +ingress: + enabled: true + image: #tell which image to deploy for studio + repository: ghcr.io/morganekmefjord/stackn/ingress:master #This image can be built from Dockerfile.nginx inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + pullPolicy: Always + annotations: {} + hosts: + - host: studio.10.0.145.40.nip.io + + # setup TLS if you have a platform certificate or use 'tls-acme' if you have certbot deployed and want to generate a certificate. + tls: + - secretName: prod-ingress + hosts: + - studio.10.0.145.40.nip.io + +service: + type: ClusterIP #override if you want to use NodePort instead to access cluster services + +# default credentials for rabbitmq. override in production! +rabbit: + username: admin + password: "" + +chartcontroller: + enabled: false + image: + repository: scaleoutsystems/chart-controller:master + pullPolicy: Always + branch: master + resources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 200m + memory: 512Mi + #addSecret -- if true create chart-controller-secret from cluster_config, if false it must be added manually + addSecret: true + + +### Cluster config ### +# kubectl config view --raw +cluster_config: |- + apiVersion: v1 + clusters: + - cluster: + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREekNDQWZlZ0F3SUJBZ0lVU2FuRGtzSzFOVEVhMWVHOWFYREhVbmFpM3hFd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0Z6RVZNQk1HQTFVRUF3d01NVEF1TVRVeUxqRTRNeTR4TUI0WERUSXhNRGt5TWpFeU5UazFOMW9YRFRNeApNRGt5TURFeU5UazFOMW93RnpFVk1CTUdBMVVFQXd3TU1UQXVNVFV5TGpFNE15NHhNSUlCSWpBTkJna3Foa2lHCjl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFyTnA4SWh0cTRRWHRPTklJcWxlTnlZbjdXTVZvMWxkR3ZzSmcKYnRlV29Zb1E1MFlEMitMdHRZWFM4WG5mYytHMEpLN3FTM3lyNWMvcEhpNTh5SGZ4QU5Vd3lsNEgwT01Lb2cwVwpKempXcTNQNWRVTGpMWDBZTy93ZzcrRmVBcGJ5SHUzcWVsTGJQNHJUUnBUU0xva2o2ZVJtS25MRUZVQ1YwZG55CjVTY0JtZ3pEbzdGVHM1ZzVTSUdpQ1NDa1ZTMmlvZE4xUWlTOTlnQi8yMVBSdXl3WXZLbVlSZENVRDVFMUVlL3AKZjVPQVh2ZTJkVEg2TytOUTQrS21UQnh1TC9Wd1pJR3NnQ3pTQURBNFFiQ1poa0FBdGd6R2RqaU1RRDBLbUh2WApqanVZMlNWVkcrS2Naa2puT2xNc0pZQk5aSjRmc3FQcXZxK055WHJ3V280aERGbkZZUUlEQVFBQm8xTXdVVEFkCkJnTlZIUTRFRmdRVW9lTjNSWlRiMk16Q0Z0Rkh5QU9jRjZtQWEwRXdId1lEVlIwakJCZ3dGb0FVb2VOM1JaVGIKMk16Q0Z0Rkh5QU9jRjZtQWEwRXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQwpBUUVBYm9LMWlTWmhzREdweEU3Y2dGazdLbmdRNDRuNGh3UXJENG9tNkdtZjBvalFyQ1JPaGRSaXBCb0oxZWdyCkJiRCtmcVNyTTFNdjd5QXIwMkVPQS85d2lrNkRrenl2RERGR1lyNVJHOUIwc2FFcmN4cVZjQzR3OVAvM3lKZFUKczZWVWlBUWhuNkJHYjJ0RW5rU0R0VVI4b0Y4Uyt6eStCY0VDOVl2SWNkbWZCS3hsMTg3dG0wRmpvVmhCNjBKbQoxNlhtMHhZbjhOekJWVmYvUlNIQ2ZzUW1Oa1dVdUUxQXFadU0vaXVKeitHRlpHczVJellONUxYR3JEREYxczJRClV3eERHL21QTFhDMVhjakxYVHNPcTc0QjRWOXNnQm1MTkdEMjdYdjhueFBGeEl2amEwb21xM0R4MW9qSmcxU1QKakIrVko0Qm1uSVQ0emlaTCtTMTR1WVpkeWc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + server: https://10.0.145.40:16443 + name: microk8s-cluster + contexts: + - context: + cluster: microk8s-cluster + user: admin + name: microk8s + current-context: microk8s + kind: Config + preferences: {} + users: + - name: admin + user: + token: RDdLMnk3dUcrTDAxY2NMM3N3UEk5VTMyREZOTTcrNlFxZkF3bWFUODZpdz0K + +# Django fixtures for defining: +# - app categories +# - object types (to categorize “objects”, often model objects). We might for instance want a few different +# categories such as “models”, “tensorflow models”, and “FEDn Compute Packages”). An object is a pointer to a file stored in S3. +# - Periodic Celery tasks. These are controlled from the Django database. By default, we have three tasks: One that syncs MLflow +# models to STACKn objects, one that checks app statuses, and one that checks resource usage. +fixtures: |- + [ + { + "model": "projects.projecttemplate", + "pk": 1, + "fields": { + "name": "STACKn Default", + "slug": "default", + "description": "Default project template.", + "template": { + "flavors": { + "Medium": { + "cpu": { + "requirement": "100m", + "limit": "1000m" + }, + "mem": { + "requirement": "1Gi", + "limit": "8Gi" + }, + "gpu": { + "requirement": "0", + "limit": "0" + }, + "ephmem": { + "requirement": "50Mi", + "limit": "100Mi" + } + } + }, + "environments": { + "Jupyter Notebook": { + "repository": "scaleoutsystems", + "image": "jupyter-stackn:v0.1.5", + "app": "lab" + }, + "Default Serving": { + "repository": "scaleoutsystems", + "image": "default-python:latest", + "app": "fastapi-serve" + }, + "MLflow Serving": { + "repository": "scaleoutsystems", + "image": "mlflow-serve:latest", + "app": "mlflow-serve" + }, + "Ubuntu": { + "repository": "scaleoutsystems", + "image": "wetty-ubuntu:v0.1.2", + "app": "ubuntu-terminal" + }, + "Dask": { + "repository": "daskdev", + "image": "dask", + "app": "dask-cluster" + }, + "FEDn Reducer": { + "repository": "scaleoutsystems", + "image": "fedn-reducer:master", + "app": "reducer" + }, + "FEDn Combiner": { + "repository": "scaleoutsystems", + "image": "fedn-combiner:master", + "app": "combiner" + } + }, + "apps": { + "minio-vol": { + "slug": "volume", + "volume.size": "5Gi", + "permission": "project" + }, + "reg-vol": { + "slug": "volume", + "volume.size": "5Gi", + "permission": "project" + }, + "project-vol": { + "slug": "volume", + "volume.size": "5Gi", + "permission": "project" + }, + "project-minio": { + "slug": "minio", + "app:volume": ["minio-vol"], + "credentials.access_key": "accesskey2", + "credentials.secret_key": "secretkey193", + "permission": "project" + }, + "project-registry": { + "slug": "docker_registry", + "app:volume": ["reg-vol"], + "credentials.username": "username123", + "credentials.password": "pass999111222", + "permission": "project" + } + }, + "settings": { + "project-S3": "project-minio" + } + } + } + }, + { + "model": "projects.projecttemplate", + "pk": 2, + "fields": { + "name": "FEDn MNIST", + "slug": "fedn-mnist", + "description": "FEDn MNIST project template.", + "template": { + "flavors": { + "CPU": { + "cpu": { + "requirement": "100m", + "limit": "4000m" + }, + "mem": { + "requirement": "1Gi", + "limit": "16Gi" + }, + "gpu": { + "requirement": "0", + "limit": "0" + }, + "ephmem": { + "requirement": "50Mi", + "limit": "100Mi" + } + } + }, + "environments": { + "Jupyter STACKn": { + "repository": "scaleoutsystems", + "image": "jupyter-stackn:v0.1.5", + "app": "lab" + }, + "Ubuntu": { + "repository": "scaleoutsystems", + "image": "wetty-ubuntu:v0.1.2", + "app": "ubuntu-terminal" + }, + "Dask": { + "repository": "daskdev", + "image": "dask", + "app": "dask-cluster" + }, + "FEDn Reducer": { + "repository": "scaleoutsystems", + "image": "fedn-reducer:master", + "app": "reducer" + }, + "FEDn Combiner": { + "repository": "scaleoutsystems", + "image": "fedn-combiner:master", + "app": "combiner" + }, + "MNIST Client": { + "repository": "scaleoutsystems", + "image": "mnist-client:v0.6.0", + "app": "fedn-client" + } + }, + "apps": { + "minio-vol": { + "slug": "volume", + "volume.size": "20Gi", + "permission": "private" + }, + "reg-vol": { + "slug": "volume", + "volume.size": "20Gi", + "permission": "private" + }, + "project-vol": { + "slug": "volume", + "volume.size": "20Gi", + "permission": "private" + }, + "mongodb-vol": { + "slug": "volume", + "volume.size": "5Gi", + "permission": "private" + }, + "combiner-vol": { + "slug": "volume", + "volume.size": "5Gi", + "permission": "private" + }, + "S3 store": { + "slug": "minio", + "app:volume": ["minio-vol"], + "credentials.access_key": "accesskey2", + "credentials.secret_key": "secretkey193" + }, + "FEDn MongoDB": { + "slug": "mongodb", + "app:volume": ["mongodb-vol"], + "credentials.username": "admin", + "credentials.password": "password" + }, + "FEDn MongoExpress": { + "slug": "mongo-express", + "app:mongodb": ["FEDn MongoDB"] + }, + "Docker Registry": { + "slug": "docker_registry", + "app:volume": ["reg-vol"], + "credentials.username": "username123", + "credentials.password": "pass999111222" + }, + "Reducer": { + "slug": "reducer", + "S3": "S3 store", + "environment": "FEDn Reducer", + "app:mongodb": ["FEDn MongoDB"], + "app:docker_registry": ["Docker Registry"], + "reducer.pullPolicy": "IfNotPresent" + }, + "Combiner": { + "slug": "combiner", + "app:volume": ["combiner-vol"], + "app:reducer": ["Reducer"], + "environment": "FEDn Combiner", + "combiner.pullPolicy": "IfNotPresent" + } + }, + "settings": { + "project-S3": "S3 store" + } + } + } + }, + { + "model": "apps.appcategories", + "pk": "compute", + "fields": { + "name": "Compute" + } + }, + { + "model": "apps.appcategories", + "pk": "fedn", + "fields": { + "name": "FEDn" + } + }, + { + "model": "apps.appcategories", + "pk": "develop", + "fields": { + "name": "Develop" + } + }, + { + "model": "apps.appcategories", + "pk": "serve", + "fields": { + "name": "Serve" + } + }, + { + "model": "apps.appcategories", + "pk": "store", + "fields": { + "name": "Store" + } + }, + { + "model": "apps.apps", + "pk": 1, + "fields": { + "name": "Jupyter Lab", + "slug": "lab", + "category": "compute", + "table_field": { + "url": "https://{{ release }}.{{ global.domain }}" + }, + "description": "", + "priority": "500", + "settings": { + "apps": { + "Persistent Volume": "many" + }, + "flavor": "one", + "environment": { + "name": "from", + "title": "Image", + "quantity": "one", + "type": "match" + }, + "permissions": { + "public": { + "value": "false", + "option": "false" + }, + "project": { + "value": "true", + "option": "true" + }, + "private": { + "value": "false", + "option": "true" + } + }, + "export-cli": "True" + }, + "chart": "apps/lab/chart", + "logo": "apps/lab/logo.png", + "updated_on": "2021-03-10T19:45:03.927Z", + "created_on": "2021-02-19T21:34:37.815Z" + } + }, + { + "model": "apps.apps", + "pk": 2, + "fields": { + "name": "Persistent Volume", + "slug": "volume", + "category": "store", + "table_field": {}, + "description": "", + "priority": "600", + "settings": { + "volume": { + "size": { + "type": "string", + "default": "1Gi", + "title": "Size" + }, + "storageClass": { + "type": "string", + "default": "", + "title": "StorageClass" + }, + "accessModes": { + "type": "string", + "default": "ReadWriteMany", + "title": "AccessModes" + } + }, + "permissions": { + "public": { + "value": "false", + "option": "false" + }, + "project": { + "value": "true", + "option": "true" + }, + "private": { + "value": "false", + "option": "true" + } + } + }, + "chart": "apps/volume/chart", + "logo": "apps/volume/logo.png", + "updated_on": "2021-03-10T19:45:03.927Z", + "created_on": "2021-02-19T21:34:37.815Z" + } + }, + { + "model": "django_celery_beat.intervalschedule", + "pk": 1, + "fields": { + "every": 3, + "period": "seconds" + } + }, + { + "model": "django_celery_beat.intervalschedule", + "pk": 2, + "fields": { + "every": 15, + "period": "seconds" + } + }, + { + "model": "django_celery_beat.periodictask", + "pk": 1, + "fields": { + "name": "celery.backend_cleanup", + "task": "celery.backend_cleanup", + "interval": 1, + "crontab": null, + "solar": null, + "clocked": null, + "args": "[]", + "kwargs": "{}", + "queue": null, + "exchange": null, + "routing_key": null, + "headers": "{}", + "priority": null, + "expires": null, + "expire_seconds": 43200, + "one_off": false, + "start_time": null, + "enabled": true, + "last_run_at": null, + "total_run_count": 0, + "date_changed": "2021-02-26T13:49:34.038Z", + "description": "" + } + }, + { + "model": "django_celery_beat.periodictask", + "pk": 2, + "fields": { + "name": "check_resource_usage", + "task": "apps.tasks.get_resource_usage", + "interval": 2, + "crontab": null, + "solar": null, + "clocked": null, + "args": "[]", + "kwargs": "{}", + "queue": null, + "exchange": null, + "routing_key": null, + "headers": "{}", + "priority": null, + "expires": null, + "expire_seconds": null, + "one_off": false, + "start_time": null, + "enabled": true, + "last_run_at": "2021-02-26T14:03:34.731Z", + "total_run_count": 45, + "date_changed": "2021-02-26T14:03:40.178Z", + "description": "" + } + }, + { + "model": "django_celery_beat.periodictask", + "pk": 3, + "fields": { + "name": "check_app_status", + "task": "apps.tasks.check_status", + "interval": 1, + "crontab": null, + "solar": null, + "clocked": null, + "args": "[]", + "kwargs": "{}", + "queue": null, + "exchange": null, + "routing_key": null, + "headers": "{}", + "priority": null, + "expires": null, + "expire_seconds": null, + "one_off": false, + "start_time": null, + "enabled": true, + "last_run_at": "2021-02-26T14:03:37.169Z", + "total_run_count": 174, + "date_changed": "2021-02-26T14:03:40.168Z", + "description": "" + } + }, + { + "model": "models.objecttype", + "pk": 1, + "fields": { + "name": "Model", + "slug": "model", + "apps": [] + } + }, + { + "model": "models.objecttype", + "pk": 2, + "fields": { + "name": "FEDn Client", + "slug": "fedn-client", + "apps": [] + } + }, + { + "model": "models.objecttype", + "pk": 3, + "fields": { + "name": "MLFlow Model", + "slug": "mlflow-model", + "apps": [] + } + } + ] + +docker-registry: + enabled: false + ingress: + enabled: true + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: "5500m" + hosts: + - registry.10.0.145.40.nip.io + tls: + - secretName: prod-ingress + hosts: + - registry.10.0.145.40.nip.io + + persistence: + enabled: true + accessMode: ReadWriteOnce + size: 2Gi + storageClass: *storage_class + +reloader: + enabled: true + namespace: default + reloader: + watchGlobally: false + +labs: + ingress: + secretName: prod-ingress + +prometheus: + enabled: false + +loki-stack: + enabled: false + +grafana: + enabled: false + diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index 03775630..0f85d97d 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -70,61 +70,13 @@ Return STACKn studio superuser email {{/* -Return STACKn studio postgres password +Get the password secret. */}} -{{- define "stackn.studio.postgres.password" -}} -{{- if .Values.postgresql.global.postgresql.auth.password -}} - {{- .Values.postgresql.global.postgresql.auth.password -}} -{{- else -}} - {{- randAlphaNum 10 -}} -{{- end -}} -{{- end -}} - -{{/* -Return STACKn studio postgresql-postgres password -*/}} -{{- define "stackn.studio.postgresql-postgres.password" -}} -{{- if .Values.postgresql.global.postgresql.auth.postgresPassword -}} - {{- .Values.postgresql.global.postgresql.auth.postgresPassword -}} -{{- else -}} - {{- randAlphaNum 10 -}} -{{- end -}} -{{- end -}} - -{{/* -Return postgres secret -*/}} -{{- define "stackn.postgres.secretName" -}} -{{- if .Values.postgresql.enabled }} - {{- include "postgresql.secretName" .Subcharts.postgresql -}} -{{- else -}} - {* HOLDER FOR HA MODE IN FUTURE RELEASE *} -{{- end -}} -{{- end -}} - -{{/* -Return STACKn studio storageClass -*/}} -{{- define "stackn.studio.storageclass" -}} -{{- if .Values.global.studio.storageClass }} - {{- .Values.global.studio.storageClass -}} -{{- else if .Values.studio.storage.storageClass -}} - {{- .Values.studio.storage.storageClass -}} -{{- else -}} - {{- .Values.global.postgresql.storageClass -}} -{{- end -}} -{{- end -}} - -{{/* -Return STACKn studio media storageClass -*/}} -{{- define "stackn.studio.media.storageclass" -}} -{{- if .Values.global.studio.storageClass }} - {{- .Values.global.studio.storageClass -}} -{{- else if .Values.studio.media.storage.storageClass -}} - {{- .Values.studio.media.storage.storageClass -}} +{{- define "stackn.studio.postgresql.secretName" -}} +{{- if .Values.postgresql.existingSecret -}} + {{- printf "%s" (tpl .Values.existingSecret $) -}} {{- else -}} - {{- .Values.global.postgresql.storageClass -}} + {{- printf "%s" .Values.postgresql.fullnameOverride -}} {{- end -}} {{- end -}} @@ -150,3 +102,14 @@ Return STACKn rabbit username admin {{- end -}} {{- end -}} + +{{/* +Return STACKn oidc client secret +*/}} +{{- define "stackn.oidc.clientsecret" -}} +{{- if .Values.oidc.client_secret }} + {{- .Values.oidc.client_secret -}} +{{- else -}} + a-client-secret +{{- end -}} +{{- end -}} diff --git a/scaleout/stackn/templates/celery-beat-deployment.yaml b/scaleout/stackn/templates/celery-beat-deployment.yaml deleted file mode 100644 index aabce71e..00000000 --- a/scaleout/stackn/templates/celery-beat-deployment.yaml +++ /dev/null @@ -1,102 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-celery-beat - name: {{ .Release.Name }}-celery-beat - name: {{ .Release.Name }}-celery-beat -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - name: {{ .Release.Name }}-celery-beat - template: - metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-celery-beat - name: {{ .Release.Name }}-celery-beat - spec: - initContainers: - - name: wait-for-db - image: postgres - command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 5; done;'] - resources: - limits: - cpu: "100m" - memory: "512Mi" - requests: - cpu: "100m" - memory: "512Mi" - - name: wait-for-studio - image: busybox - command: ['sh', '-c', "until nslookup {{ .Release.Name }}-{{ .Values.studio.servicename }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for {{ .Release.Name }}-{{ .Values.studio.servicename }} service; sleep 30; done"] - resources: - limits: - cpu: "100m" - memory: "512Mi" - requests: - cpu: "100m" - memory: "512Mi" - containers: - - args: - - sh - - ./scripts/run_beat.sh - env: - - name: BASE_PATH - value: "/app" - - name: KUBECONFIG - value: {{ .Values.studio.kubeconfig_file | quote }} - - name: GET_HOSTS_FROM - value: dns - - name: POSTGRES_DB - value: {{ .Values.postgresql.global.postgresql.auth.database }} - - name: POSTGRES_USER - value: {{ .Values.postgresql.global.postgresql.auth.database }} - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "stackn.postgres.secretName" . }} - key: password - - name: RABBITMQ_DEFAULT_PASS - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: rabbit-password - image: {{ .Values.studio.image.repository }} - imagePullPolicy: {{ .Values.studio.image.pullPolicy }} - name: {{ .Release.Name }}-celery-beat - resources: - limits: - cpu: "500m" - memory: "4Gi" - requests: - cpu: "100m" - memory: "512Mi" - volumeMounts: - - mountPath: /app/studio/settings.py - subPath: settings.py - name: {{ .Release.Name}}-settings-configmap - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - volumes: - - name: {{ .Release.Name}}-settings-configmap - configMap: - name: {{ .Release.Name}}-settings-configmap - items: - - key: settings.py - path: settings.py - -status: {} diff --git a/scaleout/stackn/templates/celery-worker-deployment.yaml b/scaleout/stackn/templates/celery-worker-deployment.yaml deleted file mode 100644 index a55914a0..00000000 --- a/scaleout/stackn/templates/celery-worker-deployment.yaml +++ /dev/null @@ -1,107 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - reloader.stakater.com/auto: "true" - labels: - io.kompose.service: {{ .Release.Name }}-celery-worker - name: {{ .Release.Name }}-celery-worker - name: {{ .Release.Name }}-celery-worker -spec: - replicas: {{ .Values.celeryWorkers.replicas | default 2 }} - strategy: - type: Recreate - selector: - matchLabels: - name: {{ .Release.Name }}-celery-worker - template: - metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-celery-worker - name: {{ .Release.Name }}-celery-worker - spec: - initContainers: - - name: wait-for-db - image: postgres - command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 5; done;'] - resources: - limits: - cpu: "100m" - memory: "512Mi" - requests: - cpu: "100m" - memory: "512Mi" - - name: wait-for-studio - image: busybox - command: ['sh', '-c', "until nslookup {{ .Release.Name }}-{{ .Values.studio.servicename }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for {{ .Release.Name }}-{{ .Values.studio.servicename }} service; sleep 5; done"] - resources: - limits: - cpu: "100m" - memory: "512Mi" - requests: - cpu: "100m" - memory: "512Mi" - containers: - - args: - - sh - - ./scripts/run_worker.sh - env: - - name: BASE_PATH - value: "/app" - - name: GET_HOSTS_FROM - value: dns - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "stackn.postgres.secretName" . }} - key: password - - name: RABBITMQ_DEFAULT_PASS - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: rabbit-password - - name: KUBECONFIG - value: {{ .Values.studio.kubeconfig_file | quote }} - image: {{ .Values.studio.image.repository }} - imagePullPolicy: {{ .Values.studio.image.pullPolicy }} - name: {{ .Release.Name }}-celery-worker - resources: - limits: - cpu: {{ .Values.celeryWorkers.resources.limits.cpu }} - memory: {{ .Values.celeryWorkers.resources.limits.memory }} - requests: - cpu: {{ .Values.celeryWorkers.resources.requests.cpu }} - memory: {{ .Values.celeryWorkers.resources.requests.memory }} - volumeMounts: - - name: config - mountPath: {{ .Values.studio.kubeconfig_dir | quote }} - readOnly: true - - mountPath: /app/studio/settings.py - subPath: settings.py - name: {{ .Release.Name}}-settings-configmap - - name: mediavol - mountPath: {{ .Values.studio.media.mount_path }} - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - volumes: - - name: config - secret: - secretName: {{ .Release.Name }}-chart-controller-secret - - name: {{ .Release.Name}}-settings-configmap - configMap: - name: {{ .Release.Name}}-settings-configmap - items: - - key: settings.py - path: settings.py - - name: mediavol - persistentVolumeClaim: - claimName: {{ .Release.Name }}-studio-media - -status: {} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 3995632d..8302ff3d 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -23,7 +23,7 @@ spec: initContainers: - name: wait-for-db image: postgres - command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 2; done;'] + command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local --port={{ .Values.postgresql.service.port }}; do echo waiting for database; sleep 2; done;'] resources: limits: cpu: "100m" @@ -56,8 +56,8 @@ spec: - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: - name: {{ include "stackn.postgres.secretName" . }} - key: password + name: {{ include "stackn.studio.postgresql.secretName" . }} + key: postgresql-password - name: RABBITMQ_DEFAULT_PASS valueFrom: secretKeyRef: diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 0f26d86d..082e6d68 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -17,13 +17,11 @@ data: """ import os - import sys + + AUTHENTICATION_BACKENDS = [ - 'social_core.backends.github.GithubOAuth2', - 'social_core.backends.google.GoogleOAuth2', - 'django.contrib.auth.backends.ModelBackend', - 'guardian.backends.ObjectPermissionBackend', + 'django.contrib.auth.backends.ModelBackend', ] # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -54,51 +52,42 @@ data: # Application definition - # Application definition - DEFAULT_APPS = [ + INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django_filters', + 'corsheaders', + 'rest_framework', + 'rest_framework.authtoken', + 'api', + 'monitor', + 'projects', + 'models', + 'deployments', + 'apps', + 'portal', + 'tagulous', + 'django_celery_beat', + 'oauth2_provider', ] - THIRD_PARTY_APPS = [ - # add apps which you install using pip - "crispy_forms", - 'corsheaders', - 'django_celery_beat', - 'django_extensions', # for executing runscript among others - 'django_filters', - 'oauth2_provider', - 'rest_framework', - 'rest_framework.authtoken', - 'social_django', - 'tagulous', - 'guardian', - ] - - LOCAL_APPS = [ - # add local apps which you create using startapp - 'api', - 'apps', - 'common', - 'deployments', - 'monitor', - 'models', - 'projects', - 'portal', - ] - - # # Application definition - INSTALLED_APPS = DEFAULT_APPS + THIRD_PARTY_APPS + LOCAL_APPS - OAUTH2_PROVIDER = { # this is the list of available scopes 'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'} } + REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.TokenAuthentication', + #'rest_framework.permissions.IsAuthenticated', + 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', + ], + } + MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -108,47 +97,11 @@ data: 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'corsheaders.middleware.CorsMiddleware', - 'social_django.middleware.SocialAuthExceptionMiddleware', # Add ] - REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.TokenAuthentication', - #'rest_framework.permissions.IsAuthenticated', - 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', - ], - } - - # Django guardian 403 templates - GUARDIAN_RENDER_403 = True - GUARDIAN_TEMPLATE_403 = '403.html' - - # Main Url conf for loading all the routing path in Studio - ROOT_URLCONF = 'studio.urls' - - # IMPORTANT: Must be encrypted as secrets in K8S - # Github - SOCIAL_AUTH_GITHUB_KEY = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GITHUB_SECRET = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GITHUB_SCOPE = ['user:email'] # Ask for the user's email - - # Google - SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['user:email'] # Ask for the user's email - - # Tagulous serialization settings - SERIALIZATION_MODULES = { - 'xml': 'tagulous.serializers.xml_serializer', - 'json': 'tagulous.serializers.json', - 'python': 'tagulous.serializers.python', - 'yaml': 'tagulous.serializers.pyyaml', - } - STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - # other finders 'compressor.finders.CompressorFinder', ) @@ -181,6 +134,7 @@ data: WSGI_APPLICATION = 'studio.wsgi.application' ASGI_APPLICATION = 'studio.asgi.application' + # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases @@ -188,11 +142,11 @@ data: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', - 'NAME': '{{ .Values.postgresql.global.postgresql.auth.database }}', - 'USER': '{{ .Values.postgresql.global.postgresql.auth.username }}', + 'NAME': '{{ .Values.postgresql.postgresqlDatabase }}', + 'USER': '{{ .Values.postgresql.postgresqlUsername }}', 'PASSWORD': os.environ.get('POSTGRES_PASSWORD'), 'HOST': '{{ .Values.postgresql.fullnameOverride }}', - 'PORT': '{{ .Values.postgresql.primary.service.ports.postgresql }}', + 'PORT': '{{ .Values.postgresql.service.port }}', } } @@ -231,11 +185,29 @@ data: MEDIA_URL = {{ .Values.studio.media.mount_path | quote }} MEDIA_ROOT = {{ .Values.studio.media.mount_path | quote }} - # Related to user registration and authetication workflow - LOGIN_REDIRECT_URL = '/' - LOGIN_URL = 'login' - LOGOUT_URL = 'logout' - INACTIVE_USERS = False + MEDIA_URL = '/media/' + MEDIA_ROOT = '/media/' + + import socket + + # TODO remove after refactor + #API_HOSTNAME = 'localhost' + #API_PORT = 8080 + + #GIT_REPOS_ROOT = os.path.join(REPO_DIR, 'repos') + #GIT_REPOS_URL = '/repos/' + + #LOKI_SVC = 'http://{{ .Release.Name }}-loki:3100' + #PROMETHEUS_SVC = 'http://{{ .Release.Name }}-prometheus-server' + #CHART_CONTROLLER_URL = 'http://{{ .Release.Name }}-chart-controller' + + REGISTRY_SVC = '{{ .Release.Name }}-docker-registry' + STUDIO_URL = 'http://{{ .Release.Name }}-studio:8080' + + try: + from .settings_local import * + except ImportError as e: + pass # Specific to Studio stack: # Redis settings @@ -261,32 +233,11 @@ data: # For Model Objects creation (check models/models.py, pre_save_model() ) VERSION_BACKEND = 'studio.version.Version' - # Other Helm/k8s deployment settings - CHART_CONTROLLER_URL = 'http://{{ .Release.Name }}-chart-controller' #Not used - CHART_FOLDER = "/app/charts/apps" EXTERNAL_KUBECONF = True - KUBECONFIG = {{ .Values.studio.kubeconfig_file | quote }} NAMESPACE = {{ .Values.namespace | default "default" | quote }} - #PROMETHEUS_SVC = 'http://{{ .Release.Name }}-prometheus-server' - REGISTRY_SVC = '{{ .Release.Name }}-docker-registry' - STORAGECLASS = {{ include "stackn.studio.storageclass" . | quote }} + STORAGECLASS = {{ .Values.storageClassName | default "aws-efs" | quote }} - # Local dependecies Models - PROJECTS_MODEL = 'projects.Project' - APPINSTANCE_MODEL = 'apps.AppInstance' - APPS_MODEL = 'apps.Apps' - APPCATEGORIES_MODEL = 'apps.AppCategories' - MODELS_MODEL = 'models.Model' - - # App statuses - APPS_STATUS_SUCCESS = ['Running', 'Succeeded', 'Success'] - APPS_STATUS_WARNING = ['Pending', 'Installed', - 'Waiting', 'Installing', 'Created'] - - DOMAIN = {{ .Values.domain | quote }} - AUTH_DOMAIN = '{{ .Release.Name }}-studio.default.svc.cluster.local' - AUTH_PROTOCOL = 'http' - STUDIO_URL = 'http://{{ .Release.Name }}-studio:8080' - # To enable sticky sessions for k8s ingress - SESSION_COOKIE_DOMAIN = {{ .Values.session_cookie_domain | quote }} - \ No newline at end of file + try: + from .settings_local import * + except ImportError as e: + pass From c5b642e540f0b95fd191b039fe700c8698c62272 Mon Sep 17 00:00:00 2001 From: carmat88 Date: Tue, 7 Dec 2021 13:59:47 +0100 Subject: [PATCH 003/146] Allowing easier deployment of stackn --- scaleout/stackn/.values-utility-script.sh.swp | Bin 0 -> 12288 bytes scaleout/stackn/revamp-values.yaml | 707 ------------------ scaleout/stackn/templates/_helper.tpl | 22 +- scaleout/stackn/templates/basic-secrets.yaml | 2 + .../templates/chart-controller-secret.yaml | 2 +- .../stackn/templates/studio-deployment.yaml | 8 +- .../templates/studio-settings-configmap.yaml | 17 +- scaleout/stackn/values-utility-script.sh | 33 - scaleout/stackn/values.yaml | 89 ++- 9 files changed, 81 insertions(+), 799 deletions(-) create mode 100644 scaleout/stackn/.values-utility-script.sh.swp delete mode 100644 scaleout/stackn/revamp-values.yaml delete mode 100755 scaleout/stackn/values-utility-script.sh diff --git a/scaleout/stackn/.values-utility-script.sh.swp b/scaleout/stackn/.values-utility-script.sh.swp new file mode 100644 index 0000000000000000000000000000000000000000..62cb7ef26763acd62277cde9ddfca59941120078 GIT binary patch literal 12288 zcmeI2L5~zw5XT?fR8S)xIn?$}vb)K4H;aaBfF;?;vaCcf2qs1idDC4p{W9IJJMX=o zae~SLu3WtO1x)lqaPaQUlV>0XZhipk_3IH_T-Yn7X7kVNOxM(_`u(d9ld0jU&-Xro z&16H+<6R*h{P>f6W3VnJza15sG?jGz!pk4SQf8B)F7f4I;`@*=wV5ojZe5xc(m4C< zwRMz8r&C$BXyewYQn`6-Gou=p*y0uG`7#q=0tXRj-6-BXe)EIV8>f88aNfC(@GCcp$3hDQ^h4_W^ zGpQoIPdY*R^|%oCNh8t{>G3fk9+4iB?vQp#mq>rmS@%eHNi$M+_G`$FOJ)L0fC(@G zCcp%k025#Wha`YmQA2dG)))z4F^5<|WYhEWx;61+)5ck?M{0Z_9b{!|9hzI=jdUDA zk~*xKQaZF@gVqN-Q6$srP?g3dSvP76E zS9GCrSWoE#2I+X1N~7e^@BRL}%B{g_r7}}fBT1+mzJ;N*c;-X;#~FxoSoun?tWk-( zsL}Xj6byYD=s(mQ9mCaYH+Ig#3_)7kR!DV72a5whS&${wlh3Ig+8`zjIY^!NNm_&S z6-NZ%Ul3l%T4PW<`0U2^M^`lDbtQ?zOqC@J@hl9g`7PBXnxyLJ1#?0;wN;Th&xZzU zs(Ea1Dyt?ATg<_UaQb%Bpw5*ZLrCt=%xNb&m&PVZ67@v}(|lOS@7q$jZ`%|1tI=K3 z&Y13F`+a_{#NOx5KK#ZRnK`1f_bJHSptXJg_NS!XP~VoOp&QZcke8|fL+jcIV|27C z-u;n}ayEhZQk3HqB3QY4eQRsuwryx-dv$PnU9LwEt(|KOB?9^7#@F9, search and replace -# - cluster_config , kubernetes cluster - -#NOTES -# - For local development/testing consider setting "oidc.verify_ssl" to false - -#Set global values to overide default -global: - studio: - superUser: "" - superuserPassword: "" - superuserEmail: "" - existingSecret: "" - storageClass: &storage_class microk8s-hostpath - -### A Postgres database for STACKn ### -# Here we use https://charts.bitnami.com/bitnami postgresql chart - -# Postgres deploy with a single-pod database: -postgresql: - enabled: true - postgresqlUsername: stackn - postgresqlPassword: "" - postgresqlDatabase: stackn - existingSecret: "" - fullnameOverride: stackn-studio-postgres - service: - port: 5432 - persistence: - enabled: true - size: 20Gi - storageClass: *storage_class - accessModes: - - ReadWriteMany - -# Will be added in future realease, for now keep "enabled:false" -postgresql-ha: - enabled: false - -### DEPLOY SECRETS WITH private helm chart 'secrets' from platform/secrets -## Name: imagePullSecret -## Description: Secret to pull images from our private repository. -imagePullSecrets: - - name: regcred - -## to create a regcred -## kubectl create secret docker-registry regcred --docker-server= --docker-username= --docker-password= - -#Set stoargeClass -storageClassName: *storage_class -namespace: default -existingSecret: "" - -studio: - servicename: studio - replicas: 1 - debug: true - static: - replicas: 1 - image: ghcr.io/morganekmefjord/stackn/ingress:master #This image can be built from Dockerfile.nginx inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi - image: #tell which image to deploy for studio - repository: ghcr.io/morganekmefjord/stackn/studio:revamp_auth #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) - pullPolicy: Always # used to ensure that each time we redeploy always pull the latest image - resources: - limits: - cpu: 1000m - memory: 4Gi - requests: - cpu: 400m - memory: 2Gi - storage: - StorageClassName: *storage_class - size: 2Gi - media: - storage: - storageClassName: *storage_class - size: 5Gi - accessModes: ReadWriteMany - superUser: admin - superuserPassword: "" - superuserEmail: admin@test.com - -celeryWorkers: - replicas: 2 - resources: - requests: - cpu: 100m - memory: 1Gi - limits: - cpu: 1000m - memory: 8Gi - -# Enable ingress if you want your to access the studio solution from a kubernetes host/localhost. -domain: studio.10.0.145.40.nip.io -ingress: - enabled: true - image: #tell which image to deploy for studio - repository: ghcr.io/morganekmefjord/stackn/ingress:master #This image can be built from Dockerfile.nginx inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) - pullPolicy: Always - annotations: {} - hosts: - - host: studio.10.0.145.40.nip.io - - # setup TLS if you have a platform certificate or use 'tls-acme' if you have certbot deployed and want to generate a certificate. - tls: - - secretName: prod-ingress - hosts: - - studio.10.0.145.40.nip.io - -service: - type: ClusterIP #override if you want to use NodePort instead to access cluster services - -# default credentials for rabbitmq. override in production! -rabbit: - username: admin - password: "" - -chartcontroller: - enabled: false - image: - repository: scaleoutsystems/chart-controller:master - pullPolicy: Always - branch: master - resources: - limits: - cpu: 200m - memory: 512Mi - requests: - cpu: 200m - memory: 512Mi - #addSecret -- if true create chart-controller-secret from cluster_config, if false it must be added manually - addSecret: true - - -### Cluster config ### -# kubectl config view --raw -cluster_config: |- - apiVersion: v1 - clusters: - - cluster: - certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREekNDQWZlZ0F3SUJBZ0lVU2FuRGtzSzFOVEVhMWVHOWFYREhVbmFpM3hFd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0Z6RVZNQk1HQTFVRUF3d01NVEF1TVRVeUxqRTRNeTR4TUI0WERUSXhNRGt5TWpFeU5UazFOMW9YRFRNeApNRGt5TURFeU5UazFOMW93RnpFVk1CTUdBMVVFQXd3TU1UQXVNVFV5TGpFNE15NHhNSUlCSWpBTkJna3Foa2lHCjl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFyTnA4SWh0cTRRWHRPTklJcWxlTnlZbjdXTVZvMWxkR3ZzSmcKYnRlV29Zb1E1MFlEMitMdHRZWFM4WG5mYytHMEpLN3FTM3lyNWMvcEhpNTh5SGZ4QU5Vd3lsNEgwT01Lb2cwVwpKempXcTNQNWRVTGpMWDBZTy93ZzcrRmVBcGJ5SHUzcWVsTGJQNHJUUnBUU0xva2o2ZVJtS25MRUZVQ1YwZG55CjVTY0JtZ3pEbzdGVHM1ZzVTSUdpQ1NDa1ZTMmlvZE4xUWlTOTlnQi8yMVBSdXl3WXZLbVlSZENVRDVFMUVlL3AKZjVPQVh2ZTJkVEg2TytOUTQrS21UQnh1TC9Wd1pJR3NnQ3pTQURBNFFiQ1poa0FBdGd6R2RqaU1RRDBLbUh2WApqanVZMlNWVkcrS2Naa2puT2xNc0pZQk5aSjRmc3FQcXZxK055WHJ3V280aERGbkZZUUlEQVFBQm8xTXdVVEFkCkJnTlZIUTRFRmdRVW9lTjNSWlRiMk16Q0Z0Rkh5QU9jRjZtQWEwRXdId1lEVlIwakJCZ3dGb0FVb2VOM1JaVGIKMk16Q0Z0Rkh5QU9jRjZtQWEwRXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQwpBUUVBYm9LMWlTWmhzREdweEU3Y2dGazdLbmdRNDRuNGh3UXJENG9tNkdtZjBvalFyQ1JPaGRSaXBCb0oxZWdyCkJiRCtmcVNyTTFNdjd5QXIwMkVPQS85d2lrNkRrenl2RERGR1lyNVJHOUIwc2FFcmN4cVZjQzR3OVAvM3lKZFUKczZWVWlBUWhuNkJHYjJ0RW5rU0R0VVI4b0Y4Uyt6eStCY0VDOVl2SWNkbWZCS3hsMTg3dG0wRmpvVmhCNjBKbQoxNlhtMHhZbjhOekJWVmYvUlNIQ2ZzUW1Oa1dVdUUxQXFadU0vaXVKeitHRlpHczVJellONUxYR3JEREYxczJRClV3eERHL21QTFhDMVhjakxYVHNPcTc0QjRWOXNnQm1MTkdEMjdYdjhueFBGeEl2amEwb21xM0R4MW9qSmcxU1QKakIrVko0Qm1uSVQ0emlaTCtTMTR1WVpkeWc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== - server: https://10.0.145.40:16443 - name: microk8s-cluster - contexts: - - context: - cluster: microk8s-cluster - user: admin - name: microk8s - current-context: microk8s - kind: Config - preferences: {} - users: - - name: admin - user: - token: RDdLMnk3dUcrTDAxY2NMM3N3UEk5VTMyREZOTTcrNlFxZkF3bWFUODZpdz0K - -# Django fixtures for defining: -# - app categories -# - object types (to categorize “objects”, often model objects). We might for instance want a few different -# categories such as “models”, “tensorflow models”, and “FEDn Compute Packages”). An object is a pointer to a file stored in S3. -# - Periodic Celery tasks. These are controlled from the Django database. By default, we have three tasks: One that syncs MLflow -# models to STACKn objects, one that checks app statuses, and one that checks resource usage. -fixtures: |- - [ - { - "model": "projects.projecttemplate", - "pk": 1, - "fields": { - "name": "STACKn Default", - "slug": "default", - "description": "Default project template.", - "template": { - "flavors": { - "Medium": { - "cpu": { - "requirement": "100m", - "limit": "1000m" - }, - "mem": { - "requirement": "1Gi", - "limit": "8Gi" - }, - "gpu": { - "requirement": "0", - "limit": "0" - }, - "ephmem": { - "requirement": "50Mi", - "limit": "100Mi" - } - } - }, - "environments": { - "Jupyter Notebook": { - "repository": "scaleoutsystems", - "image": "jupyter-stackn:v0.1.5", - "app": "lab" - }, - "Default Serving": { - "repository": "scaleoutsystems", - "image": "default-python:latest", - "app": "fastapi-serve" - }, - "MLflow Serving": { - "repository": "scaleoutsystems", - "image": "mlflow-serve:latest", - "app": "mlflow-serve" - }, - "Ubuntu": { - "repository": "scaleoutsystems", - "image": "wetty-ubuntu:v0.1.2", - "app": "ubuntu-terminal" - }, - "Dask": { - "repository": "daskdev", - "image": "dask", - "app": "dask-cluster" - }, - "FEDn Reducer": { - "repository": "scaleoutsystems", - "image": "fedn-reducer:master", - "app": "reducer" - }, - "FEDn Combiner": { - "repository": "scaleoutsystems", - "image": "fedn-combiner:master", - "app": "combiner" - } - }, - "apps": { - "minio-vol": { - "slug": "volume", - "volume.size": "5Gi", - "permission": "project" - }, - "reg-vol": { - "slug": "volume", - "volume.size": "5Gi", - "permission": "project" - }, - "project-vol": { - "slug": "volume", - "volume.size": "5Gi", - "permission": "project" - }, - "project-minio": { - "slug": "minio", - "app:volume": ["minio-vol"], - "credentials.access_key": "accesskey2", - "credentials.secret_key": "secretkey193", - "permission": "project" - }, - "project-registry": { - "slug": "docker_registry", - "app:volume": ["reg-vol"], - "credentials.username": "username123", - "credentials.password": "pass999111222", - "permission": "project" - } - }, - "settings": { - "project-S3": "project-minio" - } - } - } - }, - { - "model": "projects.projecttemplate", - "pk": 2, - "fields": { - "name": "FEDn MNIST", - "slug": "fedn-mnist", - "description": "FEDn MNIST project template.", - "template": { - "flavors": { - "CPU": { - "cpu": { - "requirement": "100m", - "limit": "4000m" - }, - "mem": { - "requirement": "1Gi", - "limit": "16Gi" - }, - "gpu": { - "requirement": "0", - "limit": "0" - }, - "ephmem": { - "requirement": "50Mi", - "limit": "100Mi" - } - } - }, - "environments": { - "Jupyter STACKn": { - "repository": "scaleoutsystems", - "image": "jupyter-stackn:v0.1.5", - "app": "lab" - }, - "Ubuntu": { - "repository": "scaleoutsystems", - "image": "wetty-ubuntu:v0.1.2", - "app": "ubuntu-terminal" - }, - "Dask": { - "repository": "daskdev", - "image": "dask", - "app": "dask-cluster" - }, - "FEDn Reducer": { - "repository": "scaleoutsystems", - "image": "fedn-reducer:master", - "app": "reducer" - }, - "FEDn Combiner": { - "repository": "scaleoutsystems", - "image": "fedn-combiner:master", - "app": "combiner" - }, - "MNIST Client": { - "repository": "scaleoutsystems", - "image": "mnist-client:v0.6.0", - "app": "fedn-client" - } - }, - "apps": { - "minio-vol": { - "slug": "volume", - "volume.size": "20Gi", - "permission": "private" - }, - "reg-vol": { - "slug": "volume", - "volume.size": "20Gi", - "permission": "private" - }, - "project-vol": { - "slug": "volume", - "volume.size": "20Gi", - "permission": "private" - }, - "mongodb-vol": { - "slug": "volume", - "volume.size": "5Gi", - "permission": "private" - }, - "combiner-vol": { - "slug": "volume", - "volume.size": "5Gi", - "permission": "private" - }, - "S3 store": { - "slug": "minio", - "app:volume": ["minio-vol"], - "credentials.access_key": "accesskey2", - "credentials.secret_key": "secretkey193" - }, - "FEDn MongoDB": { - "slug": "mongodb", - "app:volume": ["mongodb-vol"], - "credentials.username": "admin", - "credentials.password": "password" - }, - "FEDn MongoExpress": { - "slug": "mongo-express", - "app:mongodb": ["FEDn MongoDB"] - }, - "Docker Registry": { - "slug": "docker_registry", - "app:volume": ["reg-vol"], - "credentials.username": "username123", - "credentials.password": "pass999111222" - }, - "Reducer": { - "slug": "reducer", - "S3": "S3 store", - "environment": "FEDn Reducer", - "app:mongodb": ["FEDn MongoDB"], - "app:docker_registry": ["Docker Registry"], - "reducer.pullPolicy": "IfNotPresent" - }, - "Combiner": { - "slug": "combiner", - "app:volume": ["combiner-vol"], - "app:reducer": ["Reducer"], - "environment": "FEDn Combiner", - "combiner.pullPolicy": "IfNotPresent" - } - }, - "settings": { - "project-S3": "S3 store" - } - } - } - }, - { - "model": "apps.appcategories", - "pk": "compute", - "fields": { - "name": "Compute" - } - }, - { - "model": "apps.appcategories", - "pk": "fedn", - "fields": { - "name": "FEDn" - } - }, - { - "model": "apps.appcategories", - "pk": "develop", - "fields": { - "name": "Develop" - } - }, - { - "model": "apps.appcategories", - "pk": "serve", - "fields": { - "name": "Serve" - } - }, - { - "model": "apps.appcategories", - "pk": "store", - "fields": { - "name": "Store" - } - }, - { - "model": "apps.apps", - "pk": 1, - "fields": { - "name": "Jupyter Lab", - "slug": "lab", - "category": "compute", - "table_field": { - "url": "https://{{ release }}.{{ global.domain }}" - }, - "description": "", - "priority": "500", - "settings": { - "apps": { - "Persistent Volume": "many" - }, - "flavor": "one", - "environment": { - "name": "from", - "title": "Image", - "quantity": "one", - "type": "match" - }, - "permissions": { - "public": { - "value": "false", - "option": "false" - }, - "project": { - "value": "true", - "option": "true" - }, - "private": { - "value": "false", - "option": "true" - } - }, - "export-cli": "True" - }, - "chart": "apps/lab/chart", - "logo": "apps/lab/logo.png", - "updated_on": "2021-03-10T19:45:03.927Z", - "created_on": "2021-02-19T21:34:37.815Z" - } - }, - { - "model": "apps.apps", - "pk": 2, - "fields": { - "name": "Persistent Volume", - "slug": "volume", - "category": "store", - "table_field": {}, - "description": "", - "priority": "600", - "settings": { - "volume": { - "size": { - "type": "string", - "default": "1Gi", - "title": "Size" - }, - "storageClass": { - "type": "string", - "default": "", - "title": "StorageClass" - }, - "accessModes": { - "type": "string", - "default": "ReadWriteMany", - "title": "AccessModes" - } - }, - "permissions": { - "public": { - "value": "false", - "option": "false" - }, - "project": { - "value": "true", - "option": "true" - }, - "private": { - "value": "false", - "option": "true" - } - } - }, - "chart": "apps/volume/chart", - "logo": "apps/volume/logo.png", - "updated_on": "2021-03-10T19:45:03.927Z", - "created_on": "2021-02-19T21:34:37.815Z" - } - }, - { - "model": "django_celery_beat.intervalschedule", - "pk": 1, - "fields": { - "every": 3, - "period": "seconds" - } - }, - { - "model": "django_celery_beat.intervalschedule", - "pk": 2, - "fields": { - "every": 15, - "period": "seconds" - } - }, - { - "model": "django_celery_beat.periodictask", - "pk": 1, - "fields": { - "name": "celery.backend_cleanup", - "task": "celery.backend_cleanup", - "interval": 1, - "crontab": null, - "solar": null, - "clocked": null, - "args": "[]", - "kwargs": "{}", - "queue": null, - "exchange": null, - "routing_key": null, - "headers": "{}", - "priority": null, - "expires": null, - "expire_seconds": 43200, - "one_off": false, - "start_time": null, - "enabled": true, - "last_run_at": null, - "total_run_count": 0, - "date_changed": "2021-02-26T13:49:34.038Z", - "description": "" - } - }, - { - "model": "django_celery_beat.periodictask", - "pk": 2, - "fields": { - "name": "check_resource_usage", - "task": "apps.tasks.get_resource_usage", - "interval": 2, - "crontab": null, - "solar": null, - "clocked": null, - "args": "[]", - "kwargs": "{}", - "queue": null, - "exchange": null, - "routing_key": null, - "headers": "{}", - "priority": null, - "expires": null, - "expire_seconds": null, - "one_off": false, - "start_time": null, - "enabled": true, - "last_run_at": "2021-02-26T14:03:34.731Z", - "total_run_count": 45, - "date_changed": "2021-02-26T14:03:40.178Z", - "description": "" - } - }, - { - "model": "django_celery_beat.periodictask", - "pk": 3, - "fields": { - "name": "check_app_status", - "task": "apps.tasks.check_status", - "interval": 1, - "crontab": null, - "solar": null, - "clocked": null, - "args": "[]", - "kwargs": "{}", - "queue": null, - "exchange": null, - "routing_key": null, - "headers": "{}", - "priority": null, - "expires": null, - "expire_seconds": null, - "one_off": false, - "start_time": null, - "enabled": true, - "last_run_at": "2021-02-26T14:03:37.169Z", - "total_run_count": 174, - "date_changed": "2021-02-26T14:03:40.168Z", - "description": "" - } - }, - { - "model": "models.objecttype", - "pk": 1, - "fields": { - "name": "Model", - "slug": "model", - "apps": [] - } - }, - { - "model": "models.objecttype", - "pk": 2, - "fields": { - "name": "FEDn Client", - "slug": "fedn-client", - "apps": [] - } - }, - { - "model": "models.objecttype", - "pk": 3, - "fields": { - "name": "MLFlow Model", - "slug": "mlflow-model", - "apps": [] - } - } - ] - -docker-registry: - enabled: false - ingress: - enabled: true - annotations: - nginx.ingress.kubernetes.io/proxy-body-size: "5500m" - hosts: - - registry.10.0.145.40.nip.io - tls: - - secretName: prod-ingress - hosts: - - registry.10.0.145.40.nip.io - - persistence: - enabled: true - accessMode: ReadWriteOnce - size: 2Gi - storageClass: *storage_class - -reloader: - enabled: true - namespace: default - reloader: - watchGlobally: false - -labs: - ingress: - secretName: prod-ingress - -prometheus: - enabled: false - -loki-stack: - enabled: false - -grafana: - enabled: false - diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index 0f85d97d..8b7229cd 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -70,17 +70,29 @@ Return STACKn studio superuser email {{/* -Get the password secret. +Return STACKn studio postgres password */}} -{{- define "stackn.studio.postgresql.secretName" -}} -{{- if .Values.postgresql.existingSecret -}} - {{- printf "%s" (tpl .Values.existingSecret $) -}} +{{- define "stackn.studio.postgres.password" -}} +{{- if .Values.postgresql.postgresqlPassword -}} + {{- .Values.postgresql.postgresqlPassword -}} +{{- else -}} + {{- randAlphaNum 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Return STACKn studio postgresql-postgres password +*/}} +{{- define "stackn.studio.postgresql-postgres.password" -}} +{{- if .Values.postgresql.postgresqlPostgresPassword -}} + {{- .Values.postgresql.postgresqlPostgresPassword -}} {{- else -}} - {{- printf "%s" .Values.postgresql.fullnameOverride -}} + {{- randAlphaNum 10 -}} {{- end -}} {{- end -}} + {{/* Return STACKn rabbit password */}} diff --git a/scaleout/stackn/templates/basic-secrets.yaml b/scaleout/stackn/templates/basic-secrets.yaml index a6da9c53..c307c15d 100644 --- a/scaleout/stackn/templates/basic-secrets.yaml +++ b/scaleout/stackn/templates/basic-secrets.yaml @@ -10,4 +10,6 @@ type: Opaque data: studio-superuser-password: {{ include "stackn.studio.superuser.password" . | b64enc | quote }} rabbit-password: {{ include "stackn.rabbit.password" . | b64enc | quote }} + postgresql-password: {{ include "stackn.studio.postgres.password" . | b64enc | quote }} + postgresql-postgres-password: {{ include "stackn.studio.postgresql-postgres.password" . | b64enc | quote }} {{- end -}} \ No newline at end of file diff --git a/scaleout/stackn/templates/chart-controller-secret.yaml b/scaleout/stackn/templates/chart-controller-secret.yaml index 988d3327..e7393061 100644 --- a/scaleout/stackn/templates/chart-controller-secret.yaml +++ b/scaleout/stackn/templates/chart-controller-secret.yaml @@ -5,5 +5,5 @@ metadata: name: {{ .Release.Name }}-chart-controller-secret type: Opaque data: - config: {{ .Values.kubeconfig }} + config: YXBpVmVyc2lvbjogdjEKY2x1c3RlcnM6Ci0gY2x1c3RlcjoKICAgIGNlcnRpZmljYXRlLWF1dGhvcml0eS1kYXRhOiBMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VSRWVrTkRRV1psWjBGM1NVSkJaMGxWUTIxSGJESlRkMEkwZURZMWNGZDViWEEwTkVseGNXaEZWbVpqZDBSUldVcExiMXBKYUhaalRrRlJSVXdLUWxGQmQwWjZSVlpOUWsxSFFURlZSVUYzZDAxTlZFRjFUVlJWZVV4cVJUUk5lVFI0VFVJMFdFUlVTWGhOVkVWNVRXcEJORTE2U1hkT2JHOVlSRlJOZUFwTlZFVjVUVVJCTkUxNlNYZE9iRzkzUm5wRlZrMUNUVWRCTVZWRlFYZDNUVTFVUVhWTlZGVjVUR3BGTkUxNU5IaE5TVWxDU1dwQlRrSm5hM0ZvYTJsSENqbDNNRUpCVVVWR1FVRlBRMEZST0VGTlNVbENRMmRMUTBGUlJVRnhRVzVYUm1FNWVHSldVSEJVUm5Gb1RtSkZRa05IT1RoUFpHSlhaWEJ3TTBkREsxQUtUa2hRYnpGUWVsaG5NMFZrYWpkbVkwTlFSRzFRUlZsd2FVc3ZZVWh6VW1oUFkxQXpaME12UVc4eVIyeFNOR0oyVTB0bFlrWjRTbEZyYTNCNGNFazJVQXBtVG1reWRrOVlaa1V6T1ZsRGNqbE9ibmN4ZW1WcFdqTTBkMmROUm1sMFpVSnRiMlV3WkRKMlVtdHFVekZhTVRsdk5VeG1lRVJ0YzIxbVJYWk5ZbWR0Q25jNUswSkVPRW8xVm1VcllXNW1lVUVyYjFrdlZFMUJWbGhUTXprck1FMURhVzFuVDJaUFNpdGliMnc0WlRSRFlsWkxWRUZFT1dwcVNGVkRRamR5T0VrS1JGTllkMmhNTWpscWFIb3ZPREZ5VDA5aU9YRmFOV1pqYVVwRE1EVmFRemRtYzJJM01XaHBhR3hrVkhZMlVVMTFURk5MWWpWblVWTllNMkYxT1ZwUmJncDRSR00yV0Uxc1JtWXhVRU5vTDFjMFpIRjNaalJFYVZjMGN6bDRiR2h5YVhRM09IQnRhR3BLYUhCMU5FUnBhRFpJZDBsRVFWRkJRbTh4VFhkVlZFRmtDa0puVGxaSVVUUkZSbWRSVlVSalJsbzRaMkpwYjJ0eE1rdGxaRFp3VTNsS1drOTRhVTl0WjNkSWQxbEVWbEl3YWtKQ1ozZEdiMEZWUkdOR1dqaG5ZbWtLYjJ0eE1rdGxaRFp3VTNsS1drOTRhVTl0WjNkRWQxbEVWbEl3VkVGUlNDOUNRVlYzUVhkRlFpOTZRVTVDWjJ0eGFHdHBSemwzTUVKQlVYTkdRVUZQUXdwQlVVVkJibTVPT1Vzck5rTmtSMjVTVlZneVlUazFjMVpTWkZreVVpOXlaMVl4ZUhCa1pXWTFNVFlyVkVOTk5tWkRiVVZHYVZSV1dHOUhjME0zZGtoM0NucFZWazVTYTNaUVNYVmpWUzlFZVZCaWIycHhSVkpYYjJsclduUlVZMDFwVlZOaWVUZGFSM294YjA1WVoycHBTUzlsTkRsQ04yWmlVMDVtUTI5dlJ6a0tjazU1TURKUlFYbHRUWHByTmpOQ1YxSk1ZbEpJZVRkeE4yWnNXRlJRVVhaWGJteHBZMk5tVWpCdmVFVlZUMGRLZVhwbVNEWXZSeXRVZGtSaVRHMHdid3BHVEN0NVVIWnNPREIxYzBWcU1taEZaM2ROVDB3M09VOTJSbkIxYUdOMGRHNXFjM0UxWTBsdFZFRldZVlY2T0doS1JqRXJObkJVWlRSbkt6ZHBVSGxHQ25GRWJHOHdhWEZQTVdNNWJFdGlVVFZVVHl0SU5EVkdORVZUVWpONE5WUmlkbVUxUmpCWFUwZEthakJ0U0d3MUwwaEJhM1JtYVRoWFNtSmxSSEJKWm5JS1FpdFZNVTFrUmxkdlpVazRNMkZ1TkZjNGNuTXdRMHg1UVVFOVBRb3RMUzB0TFVWT1JDQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENnPT0KICAgIHNlcnZlcjogaHR0cHM6Ly8xOTIuMTY4LjAuMzI6MTY0NDMKICBuYW1lOiBtaWNyb2s4cy1jbHVzdGVyCmNvbnRleHRzOgotIGNvbnRleHQ6CiAgICBjbHVzdGVyOiBtaWNyb2s4cy1jbHVzdGVyCiAgICB1c2VyOiBhZG1pbgogIG5hbWU6IG1pY3JvazhzCmN1cnJlbnQtY29udGV4dDogbWljcm9rOHMKa2luZDogQ29uZmlnCnByZWZlcmVuY2VzOiB7fQp1c2VyczoKLSBuYW1lOiBhZG1pbgogIHVzZXI6CiAgICB0b2tlbjogYzBoMFRsVnlNRzVYUjFBcmMxVnFaek0xZWtkR1IzbE5jWGRXU0hFd1YwdHJUV1ZNVlZsa1VtVndPRDBLCg== {{- end }} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 8302ff3d..142e92ab 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -40,8 +40,6 @@ spec: - name: DEBUG value: "true" {{ end }} - - name: INIT - value: {{ .Values.studio.init | quote }} - name: DJANGO_SUPERUSER value: {{ include "stackn.studio.superuser" . }} - name: DJANGO_SUPERUSER_EMAIL @@ -56,7 +54,7 @@ spec: - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: - name: {{ include "stackn.studio.postgresql.secretName" . }} + name: {{ include "stackn.secretName" . }} key: postgresql-password - name: RABBITMQ_DEFAULT_PASS valueFrom: @@ -64,13 +62,13 @@ spec: name: {{ include "stackn.secretName" . }} key: rabbit-password - name: KUBECONFIG - value: {{ .Values.studio.kubeconfig_file | quote }} + value: "/app/chartcontroller/kubeconfig/config" image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio volumeMounts: - name: kubeconfig - mountPath: {{ .Values.studio.kubeconfig_dir | quote }} + mountPath: "/app/chartcontroller/kubeconfig/" readOnly: true - mountPath: /app/studio/settings.py subPath: settings.py diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 082e6d68..32344309 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -64,12 +64,13 @@ data: 'rest_framework', 'rest_framework.authtoken', 'api', + 'apps', + 'deployments', 'monitor', - 'projects', 'models', - 'deployments', - 'apps', + 'projects', 'portal', + 'register', 'tagulous', 'django_celery_beat', 'oauth2_provider', @@ -99,6 +100,16 @@ data: 'corsheaders.middleware.CorsMiddleware', ] + ROOT_URLCONF = 'studio.urls' + + # Tagulous serialization settings + SERIALIZATION_MODULES = { + 'xml': 'tagulous.serializers.xml_serializer', + 'json': 'tagulous.serializers.json', + 'python': 'tagulous.serializers.python', + 'yaml': 'tagulous.serializers.pyyaml', + } + STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', diff --git a/scaleout/stackn/values-utility-script.sh b/scaleout/stackn/values-utility-script.sh deleted file mode 100755 index f0cc4455..00000000 --- a/scaleout/stackn/values-utility-script.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -# v0.1.0 -# Script can be improved by for example taking into account that this works only first time -# Later times strings such as and will already be overwritten - -set -e - -echo "Running the utility script for setting up variables within the values.yaml file..." -# Extract currently assigned IP address (which is connected to Internet!) - -echo "Extracting IP address..." -my_ip=$(ip route get 8.8.8.8 | awk -F"src " 'NR==1{split($2,a," ");print a[1]}') -echo "Your current IP address is: $my_ip" - -# Extract used network interface - Just for sysadmin purposes -#my_interface=$(ip route get 8.8.8.8 | awk -F"dev " 'NR==1{split($2,a," ");print a[1]}') - -# Replace field with extracted IP adress in values.yaml file -echo "Replacing $my_ip inside the values.yaml file..." -echo "Appending nip.io wildcardars..." -sed -i "s//$my_ip.nip.io/g" ./values.yaml -echo "Your current STACKn domain will be: $my_ip.nip.io" - - -# Generate k8s cluster config file - NOTE: we assume that microk8s is already installed and configured -cluster_config=$(microk8s.config | base64 | tr -d '\n') - -# Replace field in the chart-controller-secret.yaml file with the above create variable -sed -i "s//$cluster_config/g" ./templates/chart-controller-secret.yaml - -echo "Done" - diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 1b6f7070..b19f4df9 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -10,21 +10,14 @@ #Set global values to overide default global: studio: - superUser: "" ##these are currently not handled by stackn: default: admin + superUser: "" superuserPassword: "" - superuserEmail: "" ##these are currently not handled by stackn: default: admin@test.com - existingSecret: "" - storageClass: "" - postgresql: - auth: - username: stackn - password: "" - postgresPassword: "" - database: stackn - existingSecret: "" - storageClass: - + superuserEmail: "" + existingSecret: + storageClass: &storage_class microk8s-hostpath +#Set stoargeClass +storageClassName: *storage_class namespace: default existingSecret: "" @@ -32,13 +25,9 @@ studio: servicename: studio replicas: 1 debug: true - init: true - kubeconfig_file: /app/chartcontroller/kubeconfig/config - kubeconfig_dir: /app/chartcontroller/kubeconfig/ static: replicas: 1 - image: ghcr.io/scaleoutsystems/stackn/ingress:v0.6.0 - pullPolicy: IfNotPresent + image: ghcr.io/morganekmefjord/stackn/ingress:master #This image can be built from Dockerfile.nginx inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) resources: limits: cpu: 1 @@ -47,8 +36,8 @@ studio: cpu: "100m" memory: "256Mi" image: #tell which image to deploy for studio - repository: ghcr.io/scaleoutsystems/stackn/studio:v0.6.0 #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) - pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image + repository: scaleoutsystems/carmat-dev:revamp #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + pullPolicy: Always # used to ensure that each time we redeploy always pull the latest image resources: limits: cpu: "1000m" @@ -57,33 +46,32 @@ studio: cpu: "400m" memory: "2Gi" storage: - storageClass: "" + StorageClassName: *storage_class + size: "2Gi" media: storage: - storageClass: "" + storageClassName: *storage_class size: "5Gi" accessModes: ReadWriteMany - mount_path: /app/media/ superUser: admin superuserPassword: "" superuserEmail: admin@test.com -#kubernetes config -kubeconfig: "" - # Enable ingress if you want your to access the studio solution from a kubernetes host/localhost. -domain: studio.127.0.0.1.nip.io -session_cookie_domain: .127.0.0.1.nip.io +domain: studio. ingress: enabled: true + image: #tell which image to deploy for studio + repository: ghcr.io/morganekmefjord/stackn/ingress:master #This image can be built from Dockerfile.nginx inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + pullPolicy: Always annotations: {} hosts: - - host: studio.127.0.0.1.nip.io + - host: studio. # setup TLS if you have a platform certificate or use 'tls-acme' if you have certbot deployed and want to generate a certificate. tls: - secretName: prod-ingress hosts: - - studio.127.0.0.1.nip.io + - studio. ### A Postgres database for STACKn ### # Here we use https://charts.bitnami.com/bitnami postgresql chart @@ -91,16 +79,20 @@ ingress: # Postgres deploy with a single-pod database: postgresql: enabled: true + postgresqlUsername: stackn + postgresqlPassword: stackn + postgresqlPostgresPassword: stackn #NOTE! To be changed in production! + postgresqlDatabase: stackn + existingSecret: stackn fullnameOverride: stackn-studio-postgres - primary: - service: - ports: - postgresql: 5432 - persistence: - enabled: true - size: "10Gi" - accessModes: - - ReadWriteMany + service: + port: 5432 + persistence: + enabled: true + size: "20Gi" + storageClass: *storage_class + accessModes: + - ReadWriteMany # Will be added in future realease, for now keep "enabled:false" postgresql-ha: @@ -130,6 +122,16 @@ rabbit: username: admin password: "" +reloader: + enabled: true + namespace: default + reloader: + watchGlobally: false + +labs: + ingress: + secretName: prod-ingress + chartcontroller: enabled: false #addSecret -- if true create chart-controller-secret from cluster_config, if false it must be added manually @@ -141,11 +143,8 @@ docker-registry: prometheus: enabled: false -grafana: +loki-stack: enabled: false -reloader: - enabled: true - namespace: default - reloader: - watchGlobally: false +grafana: + enabled: false From 82c785b0a6564c6123ef45cd225242ed7e4be723 Mon Sep 17 00:00:00 2001 From: carmat88 Date: Tue, 7 Dec 2021 18:50:59 +0100 Subject: [PATCH 004/146] Adding crispy form in studio settings --- scaleout/stackn/templates/studio-settings-configmap.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 32344309..246a5a6e 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -65,6 +65,7 @@ data: 'rest_framework.authtoken', 'api', 'apps', + "crispy_forms", 'deployments', 'monitor', 'models', @@ -146,6 +147,8 @@ data: WSGI_APPLICATION = 'studio.wsgi.application' ASGI_APPLICATION = 'studio.asgi.application' + # Django Crispy Forms + django-crispy-forms # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases From 5e5df0b292c862567285b5f80ef06f189147ec5f Mon Sep 17 00:00:00 2001 From: TechCarmat Date: Fri, 10 Dec 2021 12:40:45 +0100 Subject: [PATCH 005/146] Delete .values-utility-script.sh.swp --- scaleout/stackn/.values-utility-script.sh.swp | Bin 12288 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 scaleout/stackn/.values-utility-script.sh.swp diff --git a/scaleout/stackn/.values-utility-script.sh.swp b/scaleout/stackn/.values-utility-script.sh.swp deleted file mode 100644 index 62cb7ef26763acd62277cde9ddfca59941120078..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2L5~zw5XT?fR8S)xIn?$}vb)K4H;aaBfF;?;vaCcf2qs1idDC4p{W9IJJMX=o zae~SLu3WtO1x)lqaPaQUlV>0XZhipk_3IH_T-Yn7X7kVNOxM(_`u(d9ld0jU&-Xro z&16H+<6R*h{P>f6W3VnJza15sG?jGz!pk4SQf8B)F7f4I;`@*=wV5ojZe5xc(m4C< zwRMz8r&C$BXyewYQn`6-Gou=p*y0uG`7#q=0tXRj-6-BXe)EIV8>f88aNfC(@GCcp$3hDQ^h4_W^ zGpQoIPdY*R^|%oCNh8t{>G3fk9+4iB?vQp#mq>rmS@%eHNi$M+_G`$FOJ)L0fC(@G zCcp%k025#Wha`YmQA2dG)))z4F^5<|WYhEWx;61+)5ck?M{0Z_9b{!|9hzI=jdUDA zk~*xKQaZF@gVqN-Q6$srP?g3dSvP76E zS9GCrSWoE#2I+X1N~7e^@BRL}%B{g_r7}}fBT1+mzJ;N*c;-X;#~FxoSoun?tWk-( zsL}Xj6byYD=s(mQ9mCaYH+Ig#3_)7kR!DV72a5whS&${wlh3Ig+8`zjIY^!NNm_&S z6-NZ%Ul3l%T4PW<`0U2^M^`lDbtQ?zOqC@J@hl9g`7PBXnxyLJ1#?0;wN;Th&xZzU zs(Ea1Dyt?ATg<_UaQb%Bpw5*ZLrCt=%xNb&m&PVZ67@v}(|lOS@7q$jZ`%|1tI=K3 z&Y13F`+a_{#NOx5KK#ZRnK`1f_bJHSptXJg_NS!XP~VoOp&QZcke8|fL+jcIV|27C z-u;n}ayEhZQk3HqB3QY4eQRsuwryx-dv$PnU9LwEt(|KOB?9^7#@F9 Date: Fri, 10 Dec 2021 15:40:29 +0100 Subject: [PATCH 006/146] Formatting and updating studio configmap --- .../templates/studio-settings-configmap.yaml | 129 ++++++++++-------- 1 file changed, 70 insertions(+), 59 deletions(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 246a5a6e..9046675e 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -18,9 +18,9 @@ data: import os - - AUTHENTICATION_BACKENDS = [ + 'social_core.backends.github.GithubOAuth2', + 'social_core.backends.google.GoogleOAuth2', 'django.contrib.auth.backends.ModelBackend', ] @@ -30,6 +30,11 @@ data: # Crispy Forms CRISPY_TEMPLATE_PACK="bootstrap4" + # Crispy Forms + CRISPY_TEMPLATE_PACK="bootstrap4" + + DOMAIN = {{ .Values.domain | quote }} + STUDIO_HOST = "https://{{ .Values.domain }}" # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ @@ -52,44 +57,49 @@ data: # Application definition - INSTALLED_APPS = [ + # Application definition + DEFAULT_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - 'django_filters', + ] + + THIRD_PARTY_APPS = [ + # add apps which you install using pip + "crispy_forms", 'corsheaders', + 'django_celery_beat', + 'django_filters', + 'oauth2_provider', 'rest_framework', 'rest_framework.authtoken', + 'social_django', + 'tagulous', + ] + + LOCAL_APPS =[ + # add local apps which you create using startapp 'api', 'apps', - "crispy_forms", + 'common', 'deployments', 'monitor', 'models', 'projects', 'portal', - 'register', - 'tagulous', - 'django_celery_beat', - 'oauth2_provider', ] + # # Application definition + INSTALLED_APPS = DEFAULT_APPS + THIRD_PARTY_APPS + LOCAL_APPS + OAUTH2_PROVIDER = { # this is the list of available scopes 'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'} } - REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.TokenAuthentication', - #'rest_framework.permissions.IsAuthenticated', - 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', - ], - } - MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -99,10 +109,31 @@ data: 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'corsheaders.middleware.CorsMiddleware', + 'social_django.middleware.SocialAuthExceptionMiddleware', # Add ] + REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.TokenAuthentication', + #'rest_framework.permissions.IsAuthenticated', + 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', + ], + } + + # Main Url conf for loading all the routing path in Studio ROOT_URLCONF = 'studio.urls' + # IMPORTANT: Must be encrypted as secrets in K8S + # Github + SOCIAL_AUTH_GITHUB_KEY = 'to-be-fetched-from-k8s-secrets' + SOCIAL_AUTH_GITHUB_SECRET = 'to-be-fetched-from-k8s-secrets' + SOCIAL_AUTH_GITHUB_SCOPE = ['user:email'] # Ask for the user's email + + # Google + SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'to-be-fetched-from-k8s-secrets' + SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'to-be-fetched-from-k8s-secrets' + SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['user:email'] # Ask for the user's email + # Tagulous serialization settings SERIALIZATION_MODULES = { 'xml': 'tagulous.serializers.xml_serializer', @@ -114,6 +145,7 @@ data: STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + # other finders 'compressor.finders.CompressorFinder', ) @@ -126,7 +158,7 @@ data: TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'common/templates')], + 'DIRS': [os.path.join(REPO_DIR, 'templates'), os.path.join(REPO_DIR, 'common/templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -146,9 +178,6 @@ data: WSGI_APPLICATION = 'studio.wsgi.application' ASGI_APPLICATION = 'studio.asgi.application' - - # Django Crispy Forms - django-crispy-forms # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases @@ -192,50 +221,31 @@ data: # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ - #STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ] + STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ] STATIC_URL = '/static/' - STATIC_ROOT = os.path.join(BASE_DIR, 'static/') + STATIC_ROOT = os.path.join(REPO_DIR, 'static/') # Media Files for Studio apps - MEDIA_URL = {{ .Values.studio.media.mount_path | quote }} - MEDIA_ROOT = {{ .Values.studio.media.mount_path | quote }} - MEDIA_URL = '/media/' MEDIA_ROOT = '/media/' - import socket - - # TODO remove after refactor - #API_HOSTNAME = 'localhost' - #API_PORT = 8080 - - #GIT_REPOS_ROOT = os.path.join(REPO_DIR, 'repos') - #GIT_REPOS_URL = '/repos/' - - #LOKI_SVC = 'http://{{ .Release.Name }}-loki:3100' - #PROMETHEUS_SVC = 'http://{{ .Release.Name }}-prometheus-server' - #CHART_CONTROLLER_URL = 'http://{{ .Release.Name }}-chart-controller' - - REGISTRY_SVC = '{{ .Release.Name }}-docker-registry' - STUDIO_URL = 'http://{{ .Release.Name }}-studio:8080' - - try: - from .settings_local import * - except ImportError as e: - pass + # Related to user registration and authetication workflow + LOGIN_REDIRECT_URL = '/' + LOGIN_URL = 'login' + LOGOUT_URL = 'logout' # Specific to Studio stack: # Redis settings REDIS_PORT = 6379 REDIS_DB = 0 REDIS_HOST = os.environ.get('REDIS_PORT_6379_TCP_ADDR', '{{ .Release.Name }}-redis') - #CHANNEL_LAYERS = { - # 'default': { - # 'BACKEND': 'channels_redis.core.RedisChannelLayer', - # 'CONFIG': { - # 'hosts': [(REDIS_HOST, REDIS_PORT),], - # }, - # }, - #} + CHANNEL_LAYERS = { + 'default': { + 'BACKEND': 'channels_redis.core.RedisChannelLayer', + 'CONFIG': { + 'hosts': [(REDIS_HOST, REDIS_PORT),], + }, + }, + } # Celery settings CELERY_BROKER_URL = 'amqp://{{ include "stackn.rabbit.username" . }}:{}@{{ .Release.Name }}-rabbit:5672//'.format(os.environ.get("RABBITMQ_DEFAULT_PASS")) CELERY_RESULT_BACKEND = 'redis://%s:%d/%d' % (REDIS_HOST, REDIS_PORT, REDIS_DB) @@ -247,11 +257,12 @@ data: # For Model Objects creation (check models/models.py, pre_save_model() ) VERSION_BACKEND = 'studio.version.Version' + # Other Helm/k8s deployment settings + #CHART_CONTROLLER_URL = 'http://{{ .Release.Name }}-chart-controller' EXTERNAL_KUBECONF = True NAMESPACE = {{ .Values.namespace | default "default" | quote }} + #PROMETHEUS_SVC = 'http://{{ .Release.Name }}-prometheus-server' + REGISTRY_SVC = '{{ .Release.Name }}-docker-registry' STORAGECLASS = {{ .Values.storageClassName | default "aws-efs" | quote }} - - try: - from .settings_local import * - except ImportError as e: - pass + STUDIO_URL = 'http://{{ .Release.Name }}-studio:8080' + \ No newline at end of file From 5df355562b4a4e120926386a34ba1e59eb70fe26 Mon Sep 17 00:00:00 2001 From: TechCarmat Date: Thu, 17 Feb 2022 11:23:13 +0100 Subject: [PATCH 007/146] Update chart-controller-secret.yaml --- scaleout/stackn/templates/chart-controller-secret.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/chart-controller-secret.yaml b/scaleout/stackn/templates/chart-controller-secret.yaml index e7393061..34fc8482 100644 --- a/scaleout/stackn/templates/chart-controller-secret.yaml +++ b/scaleout/stackn/templates/chart-controller-secret.yaml @@ -5,5 +5,5 @@ metadata: name: {{ .Release.Name }}-chart-controller-secret type: Opaque data: - config: YXBpVmVyc2lvbjogdjEKY2x1c3RlcnM6Ci0gY2x1c3RlcjoKICAgIGNlcnRpZmljYXRlLWF1dGhvcml0eS1kYXRhOiBMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VSRWVrTkRRV1psWjBGM1NVSkJaMGxWUTIxSGJESlRkMEkwZURZMWNGZDViWEEwTkVseGNXaEZWbVpqZDBSUldVcExiMXBKYUhaalRrRlJSVXdLUWxGQmQwWjZSVlpOUWsxSFFURlZSVUYzZDAxTlZFRjFUVlJWZVV4cVJUUk5lVFI0VFVJMFdFUlVTWGhOVkVWNVRXcEJORTE2U1hkT2JHOVlSRlJOZUFwTlZFVjVUVVJCTkUxNlNYZE9iRzkzUm5wRlZrMUNUVWRCTVZWRlFYZDNUVTFVUVhWTlZGVjVUR3BGTkUxNU5IaE5TVWxDU1dwQlRrSm5hM0ZvYTJsSENqbDNNRUpCVVVWR1FVRlBRMEZST0VGTlNVbENRMmRMUTBGUlJVRnhRVzVYUm1FNWVHSldVSEJVUm5Gb1RtSkZRa05IT1RoUFpHSlhaWEJ3TTBkREsxQUtUa2hRYnpGUWVsaG5NMFZrYWpkbVkwTlFSRzFRUlZsd2FVc3ZZVWh6VW1oUFkxQXpaME12UVc4eVIyeFNOR0oyVTB0bFlrWjRTbEZyYTNCNGNFazJVQXBtVG1reWRrOVlaa1V6T1ZsRGNqbE9ibmN4ZW1WcFdqTTBkMmROUm1sMFpVSnRiMlV3WkRKMlVtdHFVekZhTVRsdk5VeG1lRVJ0YzIxbVJYWk5ZbWR0Q25jNUswSkVPRW8xVm1VcllXNW1lVUVyYjFrdlZFMUJWbGhUTXprck1FMURhVzFuVDJaUFNpdGliMnc0WlRSRFlsWkxWRUZFT1dwcVNGVkRRamR5T0VrS1JGTllkMmhNTWpscWFIb3ZPREZ5VDA5aU9YRmFOV1pqYVVwRE1EVmFRemRtYzJJM01XaHBhR3hrVkhZMlVVMTFURk5MWWpWblVWTllNMkYxT1ZwUmJncDRSR00yV0Uxc1JtWXhVRU5vTDFjMFpIRjNaalJFYVZjMGN6bDRiR2h5YVhRM09IQnRhR3BLYUhCMU5FUnBhRFpJZDBsRVFWRkJRbTh4VFhkVlZFRmtDa0puVGxaSVVUUkZSbWRSVlVSalJsbzRaMkpwYjJ0eE1rdGxaRFp3VTNsS1drOTRhVTl0WjNkSWQxbEVWbEl3YWtKQ1ozZEdiMEZWUkdOR1dqaG5ZbWtLYjJ0eE1rdGxaRFp3VTNsS1drOTRhVTl0WjNkRWQxbEVWbEl3VkVGUlNDOUNRVlYzUVhkRlFpOTZRVTVDWjJ0eGFHdHBSemwzTUVKQlVYTkdRVUZQUXdwQlVVVkJibTVPT1Vzck5rTmtSMjVTVlZneVlUazFjMVpTWkZreVVpOXlaMVl4ZUhCa1pXWTFNVFlyVkVOTk5tWkRiVVZHYVZSV1dHOUhjME0zZGtoM0NucFZWazVTYTNaUVNYVmpWUzlFZVZCaWIycHhSVkpYYjJsclduUlVZMDFwVlZOaWVUZGFSM294YjA1WVoycHBTUzlsTkRsQ04yWmlVMDVtUTI5dlJ6a0tjazU1TURKUlFYbHRUWHByTmpOQ1YxSk1ZbEpJZVRkeE4yWnNXRlJRVVhaWGJteHBZMk5tVWpCdmVFVlZUMGRLZVhwbVNEWXZSeXRVZGtSaVRHMHdid3BHVEN0NVVIWnNPREIxYzBWcU1taEZaM2ROVDB3M09VOTJSbkIxYUdOMGRHNXFjM0UxWTBsdFZFRldZVlY2T0doS1JqRXJObkJVWlRSbkt6ZHBVSGxHQ25GRWJHOHdhWEZQTVdNNWJFdGlVVFZVVHl0SU5EVkdORVZUVWpONE5WUmlkbVUxUmpCWFUwZEthakJ0U0d3MUwwaEJhM1JtYVRoWFNtSmxSSEJKWm5JS1FpdFZNVTFrUmxkdlpVazRNMkZ1TkZjNGNuTXdRMHg1UVVFOVBRb3RMUzB0TFVWT1JDQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENnPT0KICAgIHNlcnZlcjogaHR0cHM6Ly8xOTIuMTY4LjAuMzI6MTY0NDMKICBuYW1lOiBtaWNyb2s4cy1jbHVzdGVyCmNvbnRleHRzOgotIGNvbnRleHQ6CiAgICBjbHVzdGVyOiBtaWNyb2s4cy1jbHVzdGVyCiAgICB1c2VyOiBhZG1pbgogIG5hbWU6IG1pY3JvazhzCmN1cnJlbnQtY29udGV4dDogbWljcm9rOHMKa2luZDogQ29uZmlnCnByZWZlcmVuY2VzOiB7fQp1c2VyczoKLSBuYW1lOiBhZG1pbgogIHVzZXI6CiAgICB0b2tlbjogYzBoMFRsVnlNRzVYUjFBcmMxVnFaek0xZWtkR1IzbE5jWGRXU0hFd1YwdHJUV1ZNVlZsa1VtVndPRDBLCg== + config: {{- end }} From e8e192b30eb0e4de99b733ca442df23db7300ddb Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 7 Jun 2022 17:42:39 +0200 Subject: [PATCH 008/146] update values --- scaleout/stackn/values.yaml | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index b19f4df9..4157d656 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -10,9 +10,9 @@ #Set global values to overide default global: studio: - superUser: "" + superUser: "" ##these are currently not handled by stackn: default: admin superuserPassword: "" - superuserEmail: "" + superuserEmail: "" ##these are currently not handled by stackn: default: admin@test.com existingSecret: storageClass: &storage_class microk8s-hostpath @@ -27,7 +27,7 @@ studio: debug: true static: replicas: 1 - image: ghcr.io/morganekmefjord/stackn/ingress:master #This image can be built from Dockerfile.nginx inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + image: ghcr.io/scaleoutsystems/stackn/ingress:develop resources: limits: cpu: 1 @@ -36,7 +36,7 @@ studio: cpu: "100m" memory: "256Mi" image: #tell which image to deploy for studio - repository: scaleoutsystems/carmat-dev:revamp #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + repository: ghcr.io/scaleoutsystems/stackn/studio:develop #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) pullPolicy: Always # used to ensure that each time we redeploy always pull the latest image resources: limits: @@ -59,11 +59,10 @@ studio: # Enable ingress if you want your to access the studio solution from a kubernetes host/localhost. domain: studio. +auth_domain: studio. +session_cookie_domain: . ingress: enabled: true - image: #tell which image to deploy for studio - repository: ghcr.io/morganekmefjord/stackn/ingress:master #This image can be built from Dockerfile.nginx inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) - pullPolicy: Always annotations: {} hosts: - host: studio. @@ -89,7 +88,7 @@ postgresql: port: 5432 persistence: enabled: true - size: "20Gi" + size: "10Gi" storageClass: *storage_class accessModes: - ReadWriteMany @@ -122,16 +121,6 @@ rabbit: username: admin password: "" -reloader: - enabled: true - namespace: default - reloader: - watchGlobally: false - -labs: - ingress: - secretName: prod-ingress - chartcontroller: enabled: false #addSecret -- if true create chart-controller-secret from cluster_config, if false it must be added manually From 5eaad969f8b3e9fc583721487bff263f01d46116 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 10 Jun 2022 13:28:03 +0200 Subject: [PATCH 009/146] update charts --- .../stackn/templates/studio-deployment.yaml | 6 +- .../templates/studio-settings-configmap.yaml | 112 +++++++++++------- scaleout/stackn/values.yaml | 20 ++-- 3 files changed, 84 insertions(+), 54 deletions(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 142e92ab..33d5bdc0 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -40,6 +40,8 @@ spec: - name: DEBUG value: "true" {{ end }} + - name: INIT + value: {{ .Values.studio.init | quote }} - name: DJANGO_SUPERUSER value: {{ include "stackn.studio.superuser" . }} - name: DJANGO_SUPERUSER_EMAIL @@ -62,13 +64,13 @@ spec: name: {{ include "stackn.secretName" . }} key: rabbit-password - name: KUBECONFIG - value: "/app/chartcontroller/kubeconfig/config" + value: {{ .Values.studio.kubeconfig_file | quote }} image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio volumeMounts: - name: kubeconfig - mountPath: "/app/chartcontroller/kubeconfig/" + mountPath: {{ .Values.studio.kubeconfig_dir | quote }} readOnly: true - mountPath: /app/studio/settings.py subPath: settings.py diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 9046675e..9502161f 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -17,11 +17,13 @@ data: """ import os + import sys AUTHENTICATION_BACKENDS = [ - 'social_core.backends.github.GithubOAuth2', - 'social_core.backends.google.GoogleOAuth2', - 'django.contrib.auth.backends.ModelBackend', + 'social_core.backends.github.GithubOAuth2', + 'social_core.backends.google.GoogleOAuth2', + 'django.contrib.auth.backends.ModelBackend', + 'guardian.backends.ObjectPermissionBackend', ] # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -30,11 +32,6 @@ data: # Crispy Forms CRISPY_TEMPLATE_PACK="bootstrap4" - # Crispy Forms - CRISPY_TEMPLATE_PACK="bootstrap4" - - DOMAIN = {{ .Values.domain | quote }} - STUDIO_HOST = "https://{{ .Values.domain }}" # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ @@ -68,28 +65,30 @@ data: ] THIRD_PARTY_APPS = [ - # add apps which you install using pip - "crispy_forms", - 'corsheaders', - 'django_celery_beat', - 'django_filters', - 'oauth2_provider', - 'rest_framework', - 'rest_framework.authtoken', - 'social_django', - 'tagulous', + # add apps which you install using pip + "crispy_forms", + 'corsheaders', + 'django_celery_beat', + 'django_extensions', # for executing runscript among others + 'django_filters', + 'oauth2_provider', + 'rest_framework', + 'rest_framework.authtoken', + 'social_django', + 'tagulous', + 'guardian', ] - LOCAL_APPS =[ - # add local apps which you create using startapp - 'api', - 'apps', - 'common', - 'deployments', - 'monitor', - 'models', - 'projects', - 'portal', + LOCAL_APPS = [ + # add local apps which you create using startapp + 'api', + 'apps', + 'common', + 'deployments', + 'monitor', + 'models', + 'projects', + 'portal', ] # # Application definition @@ -120,6 +119,10 @@ data: ], } + # Django guardian 403 templates + GUARDIAN_RENDER_403 = True + GUARDIAN_TEMPLATE_403 = '403.html' + # Main Url conf for loading all the routing path in Studio ROOT_URLCONF = 'studio.urls' @@ -158,7 +161,7 @@ data: TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(REPO_DIR, 'templates'), os.path.join(REPO_DIR, 'common/templates')], + 'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'common/templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -221,31 +224,32 @@ data: # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ - STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ] + #STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ] STATIC_URL = '/static/' - STATIC_ROOT = os.path.join(REPO_DIR, 'static/') + STATIC_ROOT = os.path.join(BASE_DIR, 'static/') # Media Files for Studio apps - MEDIA_URL = '/media/' - MEDIA_ROOT = '/media/' + MEDIA_URL = {{ .Values.studio.media.mount_path | quote }} + MEDIA_ROOT = {{ .Values.studio.media.mount_path | quote }} # Related to user registration and authetication workflow LOGIN_REDIRECT_URL = '/' LOGIN_URL = 'login' LOGOUT_URL = 'logout' + INACTIVE_USERS = False # Specific to Studio stack: # Redis settings REDIS_PORT = 6379 REDIS_DB = 0 REDIS_HOST = os.environ.get('REDIS_PORT_6379_TCP_ADDR', '{{ .Release.Name }}-redis') - CHANNEL_LAYERS = { - 'default': { - 'BACKEND': 'channels_redis.core.RedisChannelLayer', - 'CONFIG': { - 'hosts': [(REDIS_HOST, REDIS_PORT),], - }, - }, - } + #CHANNEL_LAYERS = { + # 'default': { + # 'BACKEND': 'channels_redis.core.RedisChannelLayer', + # 'CONFIG': { + # 'hosts': [(REDIS_HOST, REDIS_PORT),], + # }, + # }, + #} # Celery settings CELERY_BROKER_URL = 'amqp://{{ include "stackn.rabbit.username" . }}:{}@{{ .Release.Name }}-rabbit:5672//'.format(os.environ.get("RABBITMQ_DEFAULT_PASS")) CELERY_RESULT_BACKEND = 'redis://%s:%d/%d' % (REDIS_HOST, REDIS_PORT, REDIS_DB) @@ -258,11 +262,31 @@ data: VERSION_BACKEND = 'studio.version.Version' # Other Helm/k8s deployment settings - #CHART_CONTROLLER_URL = 'http://{{ .Release.Name }}-chart-controller' + CHART_CONTROLLER_URL = 'http://{{ .Release.Name }}-chart-controller' #Not used + CHART_FOLDER = "/app/charts/apps" EXTERNAL_KUBECONF = True + KUBECONFIG = {{ .Values.studio.kubeconfig_file | quote }} NAMESPACE = {{ .Values.namespace | default "default" | quote }} #PROMETHEUS_SVC = 'http://{{ .Release.Name }}-prometheus-server' REGISTRY_SVC = '{{ .Release.Name }}-docker-registry' - STORAGECLASS = {{ .Values.storageClassName | default "aws-efs" | quote }} - STUDIO_URL = 'http://{{ .Release.Name }}-studio:8080' + STORAGECLASS = {{ .Values.storageClassName | default "microk8s-hostpath" | quote }} + + # Local dependecies Models + PROJECTS_MODEL = 'projects.Project' + APPINSTANCE_MODEL = 'apps.AppInstance' + APPS_MODEL = 'apps.Apps' + APPCATEGORIES_MODEL = 'apps.AppCategories' + MODELS_MODEL = 'models.Model' + + # App statuses + APPS_STATUS_SUCCESS = ['Running', 'Succeeded', 'Success'] + APPS_STATUS_WARNING = ['Pending', 'Installed', + 'Waiting', 'Installing', 'Created'] + + DOMAIN = {{ .Values.domain | quote }} + AUTH_DOMAIN = {{ .Values.auth_domain | quote }} + AUTH_PROTOCOL = 'http' + STUDIO_URL = 'http://{{ .Values.domain }}:8080' + # To enable sticky sessions for k8s ingress + SESSION_COOKIE_DOMAIN = {{ .Values.session_cookie_domain | quote }} \ No newline at end of file diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 4157d656..5362833d 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -25,6 +25,9 @@ studio: servicename: studio replicas: 1 debug: true + init: true + kubeconfig_file: /app/chartcontroller/kubeconfig/config + kubeconfig_dir: /app/chartcontroller/kubeconfig/ static: replicas: 1 image: ghcr.io/scaleoutsystems/stackn/ingress:develop @@ -53,24 +56,25 @@ studio: storageClassName: *storage_class size: "5Gi" accessModes: ReadWriteMany + mount_path: /app/media/ superUser: admin superuserPassword: "" superuserEmail: admin@test.com # Enable ingress if you want your to access the studio solution from a kubernetes host/localhost. -domain: studio. -auth_domain: studio. -session_cookie_domain: . +domain: studio.127.0.0.1.nip.io +auth_domain: stackn-studio.default.svc.cluster.local +session_cookie_domain: .127.0.0.1.nip.io ingress: enabled: true annotations: {} hosts: - - host: studio. + - host: studio.127.0.0.1.nip.io # setup TLS if you have a platform certificate or use 'tls-acme' if you have certbot deployed and want to generate a certificate. tls: - secretName: prod-ingress hosts: - - studio. + - studio.127.0.0.1.nip.io ### A Postgres database for STACKn ### # Here we use https://charts.bitnami.com/bitnami postgresql chart @@ -79,10 +83,10 @@ ingress: postgresql: enabled: true postgresqlUsername: stackn - postgresqlPassword: stackn - postgresqlPostgresPassword: stackn #NOTE! To be changed in production! + postgresqlPassword: "" + postgresqlPostgresPassword: "" postgresqlDatabase: stackn - existingSecret: stackn + existingSecret: fullnameOverride: stackn-studio-postgres service: port: 5432 From f0c34e97bca2c01ff4c371e7cb12d5629c827fde Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 10 Jun 2022 13:29:42 +0200 Subject: [PATCH 010/146] k8s config info --- scaleout/stackn/templates/chart-controller-secret.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/chart-controller-secret.yaml b/scaleout/stackn/templates/chart-controller-secret.yaml index 34fc8482..600e397b 100644 --- a/scaleout/stackn/templates/chart-controller-secret.yaml +++ b/scaleout/stackn/templates/chart-controller-secret.yaml @@ -5,5 +5,5 @@ metadata: name: {{ .Release.Name }}-chart-controller-secret type: Opaque data: - config: + config: #See values-utility-script.sh {{- end }} From 3ef5ce76ac94e6d2f0e83a52c6cbf9cd029d16cc Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 4 Jul 2022 12:43:50 +0200 Subject: [PATCH 011/146] update stackn README.md --- scaleout/stackn/README.md | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 9de2852e..01530177 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -11,35 +11,31 @@ Current chart version is 0.2.0 ## Chart Requirements -| Repository | Name | Version | -|------------|------|---------| -| https://charts.bitnami.com/bitnami | postgresql | 10.4.2 | -| https://charts.bitnami.com/bitnami | postgresql-ha | 7.3.0 | -| https://grafana.github.io/helm-charts | grafana | 6.8.4 | -| https://grafana.github.io/helm-charts | loki-stack | 2.3.1 | -| https://prometheus-community.github.io/helm-charts | prometheus | 13.8.0 | -| https://stakater.github.io/stakater-charts | reloader | v0.0.86 | +| Repository | Name | Version | Optional | +|------------|------|---------|----------| +| https://charts.bitnami.com/bitnami | postgresql | 10.4.2 | No +| https://charts.bitnami.com/bitnami | postgresql-ha | 7.3.0 | Yes +| https://grafana.github.io/helm-charts | grafana | 6.8.4 | Yes +| https://grafana.github.io/helm-charts | loki-stack | 2.3.1 | Yes +| https://prometheus-community.github.io/helm-charts | prometheus | 13.8.0 | Yes +| https://stakater.github.io/stakater-charts | reloader | v0.0.86 | No ## Configuration -By default STACKn has been configured with a dns wildcard domain for localhost. To change this replace all occurences of studio.127.0.0.1.nip.io in values.yaml. +By default STACKn has been configured with a dns wildcard domain for localhost. To change this replace all occurences of studio.127.0.0.1.nip.io in values.yaml. Futher, the k8s StorageClass is by default microk8s-hostpath. Change this value in accordance to your k8s cluster. -STACKn requires access to manipulate and create recourses in the k8s cluster. Thus, it needs the cluster config as a secret in ./templates/chart-controller-secret.yaml. - -By default no StorageClassName is set and needs to provided in the values.yaml or by using `--set` argument. - -### Quick deployment +STACKn requires access to manipulate and create recourses in the k8s cluster. Thus, it need the cluster config provided in ./templates/chart-controller-secret.yaml. For example if you are using +microk8s: ```bash -# Generate k8s cluster config file - NOTE: we assume a k8s cluster is already installed and configured -cluster_config=$(cat ~/.kube/config | base64 | tr -d '\n') +# Generate k8s cluster config file - NOTE: we assume that microk8s is already installed and configured +cluster_config=$(microk8s.config | base64 | tr -d '\n') -# Deploy STACKn from this repository -helm install --set kubeconfig=$cluster_config --set global.postgresql.storageClass= stackn . +# Replace field in the chart-controller-secret.yaml file with the above create variable +sed -i "s//$cluster_config/g" ./templates/chart-controller-secret.yaml ``` All resources will by default be created in the Namescape "default". -STACKn studio will be avaliable at http://studio.127.0.0.1.nip.io ## Deploy an SSL certificate From 29b004e8f6c59b3b43122d9fa2c705f3ce83f77c Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 5 Jul 2022 09:35:19 +0200 Subject: [PATCH 012/146] update README.md --- scaleout/stackn/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 01530177..0d87e363 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -149,7 +149,8 @@ Minimal requirement: `kubeconfig` | studio.resources.requests.cpu | string | `"400m"` | | | studio.resources.requests.memory | string | `"2Gi"` | | | studio.servicename | string | `"studio"` | | -| studio.static.image | string | `"ghcr.io/scaleoutsystems/stackn/ingress:develop"` | | +| studio.static.image | string | `"scaleoutsystems/ingress:develop"` | | +| studio.static.pullPolicy | string | `IfNotPresent` | | | studio.static.replicas | int | `1` | | | studio.static.resources.limits.cpu | int | `1` | | | studio.static.resources.limits.memory | string | `"512Mi"` | | From 01a4bd4ce7fe5c4207763bc889d205a8d2750ed7 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 6 Jul 2022 14:13:22 +0200 Subject: [PATCH 013/146] update charts --- scaleout/stackn/templates/_helper.tpl | 55 +++++++++++++----- scaleout/stackn/templates/basic-secrets.yaml | 2 - .../templates/chart-controller-secret.yaml | 2 +- .../stackn/templates/studio-deployment.yaml | 6 +- .../templates/studio-settings-configmap.yaml | 14 ++--- scaleout/stackn/values.yaml | 57 +++++++++++-------- 6 files changed, 85 insertions(+), 51 deletions(-) diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index 8b7229cd..03775630 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -73,8 +73,8 @@ Return STACKn studio superuser email Return STACKn studio postgres password */}} {{- define "stackn.studio.postgres.password" -}} -{{- if .Values.postgresql.postgresqlPassword -}} - {{- .Values.postgresql.postgresqlPassword -}} +{{- if .Values.postgresql.global.postgresql.auth.password -}} + {{- .Values.postgresql.global.postgresql.auth.password -}} {{- else -}} {{- randAlphaNum 10 -}} {{- end -}} @@ -84,13 +84,49 @@ Return STACKn studio postgres password Return STACKn studio postgresql-postgres password */}} {{- define "stackn.studio.postgresql-postgres.password" -}} -{{- if .Values.postgresql.postgresqlPostgresPassword -}} - {{- .Values.postgresql.postgresqlPostgresPassword -}} +{{- if .Values.postgresql.global.postgresql.auth.postgresPassword -}} + {{- .Values.postgresql.global.postgresql.auth.postgresPassword -}} {{- else -}} {{- randAlphaNum 10 -}} {{- end -}} {{- end -}} +{{/* +Return postgres secret +*/}} +{{- define "stackn.postgres.secretName" -}} +{{- if .Values.postgresql.enabled }} + {{- include "postgresql.secretName" .Subcharts.postgresql -}} +{{- else -}} + {* HOLDER FOR HA MODE IN FUTURE RELEASE *} +{{- end -}} +{{- end -}} + +{{/* +Return STACKn studio storageClass +*/}} +{{- define "stackn.studio.storageclass" -}} +{{- if .Values.global.studio.storageClass }} + {{- .Values.global.studio.storageClass -}} +{{- else if .Values.studio.storage.storageClass -}} + {{- .Values.studio.storage.storageClass -}} +{{- else -}} + {{- .Values.global.postgresql.storageClass -}} +{{- end -}} +{{- end -}} + +{{/* +Return STACKn studio media storageClass +*/}} +{{- define "stackn.studio.media.storageclass" -}} +{{- if .Values.global.studio.storageClass }} + {{- .Values.global.studio.storageClass -}} +{{- else if .Values.studio.media.storage.storageClass -}} + {{- .Values.studio.media.storage.storageClass -}} +{{- else -}} + {{- .Values.global.postgresql.storageClass -}} +{{- end -}} +{{- end -}} {{/* @@ -114,14 +150,3 @@ Return STACKn rabbit username admin {{- end -}} {{- end -}} - -{{/* -Return STACKn oidc client secret -*/}} -{{- define "stackn.oidc.clientsecret" -}} -{{- if .Values.oidc.client_secret }} - {{- .Values.oidc.client_secret -}} -{{- else -}} - a-client-secret -{{- end -}} -{{- end -}} diff --git a/scaleout/stackn/templates/basic-secrets.yaml b/scaleout/stackn/templates/basic-secrets.yaml index c307c15d..a6da9c53 100644 --- a/scaleout/stackn/templates/basic-secrets.yaml +++ b/scaleout/stackn/templates/basic-secrets.yaml @@ -10,6 +10,4 @@ type: Opaque data: studio-superuser-password: {{ include "stackn.studio.superuser.password" . | b64enc | quote }} rabbit-password: {{ include "stackn.rabbit.password" . | b64enc | quote }} - postgresql-password: {{ include "stackn.studio.postgres.password" . | b64enc | quote }} - postgresql-postgres-password: {{ include "stackn.studio.postgresql-postgres.password" . | b64enc | quote }} {{- end -}} \ No newline at end of file diff --git a/scaleout/stackn/templates/chart-controller-secret.yaml b/scaleout/stackn/templates/chart-controller-secret.yaml index 600e397b..988d3327 100644 --- a/scaleout/stackn/templates/chart-controller-secret.yaml +++ b/scaleout/stackn/templates/chart-controller-secret.yaml @@ -5,5 +5,5 @@ metadata: name: {{ .Release.Name }}-chart-controller-secret type: Opaque data: - config: #See values-utility-script.sh + config: {{ .Values.kubeconfig }} {{- end }} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 33d5bdc0..3995632d 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -23,7 +23,7 @@ spec: initContainers: - name: wait-for-db image: postgres - command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local --port={{ .Values.postgresql.service.port }}; do echo waiting for database; sleep 2; done;'] + command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 2; done;'] resources: limits: cpu: "100m" @@ -56,8 +56,8 @@ spec: - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: postgresql-password + name: {{ include "stackn.postgres.secretName" . }} + key: password - name: RABBITMQ_DEFAULT_PASS valueFrom: secretKeyRef: diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 9502161f..0f26d86d 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -188,11 +188,11 @@ data: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', - 'NAME': '{{ .Values.postgresql.postgresqlDatabase }}', - 'USER': '{{ .Values.postgresql.postgresqlUsername }}', + 'NAME': '{{ .Values.postgresql.global.postgresql.auth.database }}', + 'USER': '{{ .Values.postgresql.global.postgresql.auth.username }}', 'PASSWORD': os.environ.get('POSTGRES_PASSWORD'), 'HOST': '{{ .Values.postgresql.fullnameOverride }}', - 'PORT': '{{ .Values.postgresql.service.port }}', + 'PORT': '{{ .Values.postgresql.primary.service.ports.postgresql }}', } } @@ -269,7 +269,7 @@ data: NAMESPACE = {{ .Values.namespace | default "default" | quote }} #PROMETHEUS_SVC = 'http://{{ .Release.Name }}-prometheus-server' REGISTRY_SVC = '{{ .Release.Name }}-docker-registry' - STORAGECLASS = {{ .Values.storageClassName | default "microk8s-hostpath" | quote }} + STORAGECLASS = {{ include "stackn.studio.storageclass" . | quote }} # Local dependecies Models PROJECTS_MODEL = 'projects.Project' @@ -282,11 +282,11 @@ data: APPS_STATUS_SUCCESS = ['Running', 'Succeeded', 'Success'] APPS_STATUS_WARNING = ['Pending', 'Installed', 'Waiting', 'Installing', 'Created'] - + DOMAIN = {{ .Values.domain | quote }} - AUTH_DOMAIN = {{ .Values.auth_domain | quote }} + AUTH_DOMAIN = '{{ .Release.Name }}-studio.default.svc.cluster.local' AUTH_PROTOCOL = 'http' - STUDIO_URL = 'http://{{ .Values.domain }}:8080' + STUDIO_URL = 'http://{{ .Release.Name }}-studio:8080' # To enable sticky sessions for k8s ingress SESSION_COOKIE_DOMAIN = {{ .Values.session_cookie_domain | quote }} \ No newline at end of file diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 5362833d..6d4e60f4 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -13,11 +13,18 @@ global: superUser: "" ##these are currently not handled by stackn: default: admin superuserPassword: "" superuserEmail: "" ##these are currently not handled by stackn: default: admin@test.com - existingSecret: - storageClass: &storage_class microk8s-hostpath + existingSecret: "" + storageClass: "" + postgresql: + auth: + username: stackn + password: "" + postgresPassword: "" + database: stackn + existingSecret: "" + storageClass: + -#Set stoargeClass -storageClassName: *storage_class namespace: default existingSecret: "" @@ -31,6 +38,7 @@ studio: static: replicas: 1 image: ghcr.io/scaleoutsystems/stackn/ingress:develop + pullPolicy: IfNotPresent resources: limits: cpu: 1 @@ -40,7 +48,7 @@ studio: memory: "256Mi" image: #tell which image to deploy for studio repository: ghcr.io/scaleoutsystems/stackn/studio:develop #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) - pullPolicy: Always # used to ensure that each time we redeploy always pull the latest image + pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image resources: limits: cpu: "1000m" @@ -49,11 +57,10 @@ studio: cpu: "400m" memory: "2Gi" storage: - StorageClassName: *storage_class - size: "2Gi" + storageClass: "" media: storage: - storageClassName: *storage_class + storageClass: "" size: "5Gi" accessModes: ReadWriteMany mount_path: /app/media/ @@ -61,9 +68,11 @@ studio: superuserPassword: "" superuserEmail: admin@test.com +#kubernetes config +kubeconfig: "" + # Enable ingress if you want your to access the studio solution from a kubernetes host/localhost. -domain: studio.127.0.0.1.nip.io -auth_domain: stackn-studio.default.svc.cluster.local +domain: studio.127.0.0.1.nip.io session_cookie_domain: .127.0.0.1.nip.io ingress: enabled: true @@ -82,20 +91,16 @@ ingress: # Postgres deploy with a single-pod database: postgresql: enabled: true - postgresqlUsername: stackn - postgresqlPassword: "" - postgresqlPostgresPassword: "" - postgresqlDatabase: stackn - existingSecret: fullnameOverride: stackn-studio-postgres - service: - port: 5432 - persistence: - enabled: true - size: "10Gi" - storageClass: *storage_class - accessModes: - - ReadWriteMany + primary: + service: + ports: + postgresql: 5432 + persistence: + enabled: true + size: "10Gi" + accessModes: + - ReadWriteMany # Will be added in future realease, for now keep "enabled:false" postgresql-ha: @@ -141,3 +146,9 @@ loki-stack: grafana: enabled: false + +reloader: + enabled: true + namespace: default + reloader: + watchGlobally: false From 6d736863eaa2c0ed0cd13a9e96cf2a0b9b360845 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 1 Jul 2022 17:42:59 +0200 Subject: [PATCH 014/146] update README.md --- scaleout/stackn/README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 0d87e363..f457c217 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -49,11 +49,11 @@ Minimal requirement: `global.postgresql.storageClass` | Key | Type | Default | Description | |-----|------|---------|-------------| -| global.existingSecret | string | `""` | | -| global.storageClass | string | `"microk8s-hostpath"` | | -| global.studio.superUser | string | `""` | | -| global.studio.superuserEmail | string | `""` | | -| global.studio.superuserPassword | string | `""` | | +| global.existingSecret | string | `""` | Use existing secret. See basic-secrets.yaml. | +| global.storageClass | string | `"microk8s-hostpath"` | K8s storageClass for PVC. | +| global.studio.superUser | string | `admin` | Django superUser. Obs will always be `admin` until fixed. | +| global.studio.superuserEmail | string | `'admin@test.com'` | Django superUser email. Obs will always be `admin@test.com` until fixed. | +| global.studio.superuserPassword | string | `""` | Django superUser password. If left empty, will generate. | ## Values @@ -149,8 +149,7 @@ Minimal requirement: `kubeconfig` | studio.resources.requests.cpu | string | `"400m"` | | | studio.resources.requests.memory | string | `"2Gi"` | | | studio.servicename | string | `"studio"` | | -| studio.static.image | string | `"scaleoutsystems/ingress:develop"` | | -| studio.static.pullPolicy | string | `IfNotPresent` | | +| studio.static.image | string | `"ghcr.io/scaleoutsystems/stackn/ingress:develop"` | | | studio.static.replicas | int | `1` | | | studio.static.resources.limits.cpu | int | `1` | | | studio.static.resources.limits.memory | string | `"512Mi"` | | From ad0b3a3d61e0dfecd8f7303e98d9e014f4a9dc10 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 6 Jul 2022 14:41:46 +0200 Subject: [PATCH 015/146] update README.md --- scaleout/stackn/README.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index f457c217..74ad9da9 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -13,8 +13,8 @@ Current chart version is 0.2.0 | Repository | Name | Version | Optional | |------------|------|---------|----------| -| https://charts.bitnami.com/bitnami | postgresql | 10.4.2 | No -| https://charts.bitnami.com/bitnami | postgresql-ha | 7.3.0 | Yes +| https://charts.bitnami.com/bitnami | postgresql | 11.6.14 | No +| https://charts.bitnami.com/bitnami | postgresql-ha | 9.2.0 | Yes | https://grafana.github.io/helm-charts | grafana | 6.8.4 | Yes | https://grafana.github.io/helm-charts | loki-stack | 2.3.1 | Yes | https://prometheus-community.github.io/helm-charts | prometheus | 13.8.0 | Yes @@ -22,20 +22,24 @@ Current chart version is 0.2.0 ## Configuration -By default STACKn has been configured with a dns wildcard domain for localhost. To change this replace all occurences of studio.127.0.0.1.nip.io in values.yaml. Futher, the k8s StorageClass is by default microk8s-hostpath. Change this value in accordance to your k8s cluster. +By default STACKn has been configured with a dns wildcard domain for localhost. To change this replace all occurences of studio.127.0.0.1.nip.io in values.yaml. -STACKn requires access to manipulate and create recourses in the k8s cluster. Thus, it need the cluster config provided in ./templates/chart-controller-secret.yaml. For example if you are using -microk8s: +STACKn requires access to manipulate and create recourses in the k8s cluster. Thus, it needs the cluster config as a secret in ./templates/chart-controller-secret.yaml. + +By default no StorageClassName is set and needs to provided in the values.yaml or by using `--set` argument. + +### Quick deployment ```bash -# Generate k8s cluster config file - NOTE: we assume that microk8s is already installed and configured -cluster_config=$(microk8s.config | base64 | tr -d '\n') +# Generate k8s cluster config file - NOTE: we assume a k8s cluster is already installed and configured +cluster_config=$(cat ~/.kube/config | base64 | tr -d '\n') -# Replace field in the chart-controller-secret.yaml file with the above create variable -sed -i "s//$cluster_config/g" ./templates/chart-controller-secret.yaml +# Deploy STACKn from this repository +helm install --set kubeconfig=$cluster_config --set global.postgresql.storageClass= stackn . ``` All resources will by default be created in the Namescape "default". +STACKn studio will be avaliable at http://studio.127.0.0.1.nip.io ## Deploy an SSL certificate @@ -49,11 +53,19 @@ Minimal requirement: `global.postgresql.storageClass` | Key | Type | Default | Description | |-----|------|---------|-------------| -| global.existingSecret | string | `""` | Use existing secret. See basic-secrets.yaml. | -| global.storageClass | string | `"microk8s-hostpath"` | K8s storageClass for PVC. | +| global.studio.existingSecret | string | `""` | Use existing secret. See basic-secrets.yaml. | +| global.studio.storageClass | string | `""` | StorageClassName for PVC. Overrides `studio.storage.storageClass`. If `studio.storage.storageClass` is unset (default) will inherent from `global.postgresql.storageClass` | | global.studio.superUser | string | `admin` | Django superUser. Obs will always be `admin` until fixed. | | global.studio.superuserEmail | string | `'admin@test.com'` | Django superUser email. Obs will always be `admin@test.com` until fixed. | | global.studio.superuserPassword | string | `""` | Django superUser password. If left empty, will generate. | +| global.postgresql.auth.username | string | `stackn` | Postgres user will be created | +| global.postgresql.auth.password | string | `""` | Postgres password for user above. If empty, will be generated and stored in secret `stackn-studio-postgres` | +| global.postgresql.auth.database | string | `stackn` | Postgres database will be created | +| global.postgresql.auth.postgresPassword | string | `""` | Postgres password for postgres user If empty, will be generated and stored in secret `stackn-studio-postgres` | +| global.postgresql.auth.existingSecret | string | `""` | will not create secret `stackn-studio-postgres`. Instead use existing secret for postgres| +| global.postgresql.storageClass | string | `""` | StorageClassName for PVC | + + ## Values From 97e2e8894ea80f23a1c441bb451b528640ece1ca Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 6 Jul 2022 17:21:02 +0200 Subject: [PATCH 016/146] remove loki-stack --- scaleout/stackn/values.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 6d4e60f4..65fb2740 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -141,9 +141,6 @@ docker-registry: prometheus: enabled: false -loki-stack: - enabled: false - grafana: enabled: false From 97856272e763093cea47940a658e060453fac9de Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 6 Jul 2022 17:27:28 +0200 Subject: [PATCH 017/146] update README.md --- scaleout/stackn/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 74ad9da9..65ca58d0 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -16,7 +16,6 @@ Current chart version is 0.2.0 | https://charts.bitnami.com/bitnami | postgresql | 11.6.14 | No | https://charts.bitnami.com/bitnami | postgresql-ha | 9.2.0 | Yes | https://grafana.github.io/helm-charts | grafana | 6.8.4 | Yes -| https://grafana.github.io/helm-charts | loki-stack | 2.3.1 | Yes | https://prometheus-community.github.io/helm-charts | prometheus | 13.8.0 | Yes | https://stakater.github.io/stakater-charts | reloader | v0.0.86 | No From 13e0ff0a96dca94ab30881d8644d52972abd9f49 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 6 Jul 2022 17:42:53 +0200 Subject: [PATCH 018/146] update README.md --- scaleout/stackn/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 65ca58d0..851838aa 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -117,8 +117,6 @@ Minimal requirement: `kubeconfig` | ingress.image.repository | string | `"scaleoutsystems/ingress:develop"` | | | ingress.tls[0].hosts[0] | string | `"studio."` | | | ingress.tls[0].secretName | string | `"prod-ingress"` | | -| labs.ingress.secretName | string | `"prod-ingress"` | | -| loki-stack.enabled | bool | `false` | | | namespace | string | `"default"` | | | postgresql-ha.enabled | bool | `false` | | | postgresql.enabled | bool | `true` | | From 657334d884a7984000cc4fe2f897c9734624f8eb Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 6 Jul 2022 17:55:55 +0200 Subject: [PATCH 019/146] update gh workflows --- .github/workflows/code-checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-checks.yaml b/.github/workflows/code-checks.yaml index 61aeb89e..80e1b71f 100644 --- a/.github/workflows/code-checks.yaml +++ b/.github/workflows/code-checks.yaml @@ -14,7 +14,7 @@ on: jobs: check-code: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 From 8b2314ae721349ef13e8645858b3a5667e2e3cc1 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 8 Jul 2022 17:20:15 +0200 Subject: [PATCH 020/146] remove on push --- .github/workflows/release.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c44c0272..839b9eed 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,9 +1,9 @@ name: Release Helm charts on: - push: - branches: - - main + release: + types: [published] + jobs: sync-branch: From 2885991f4c1863111bc401274c413ea056c9b818 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 14 Jul 2022 16:35:41 +0200 Subject: [PATCH 021/146] Release/v0.6.0 (#97) --- .github/workflows/release.yaml | 2 +- scaleout/stackn/values.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 839b9eed..d9f74a6d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -16,7 +16,7 @@ jobs: uses: devmasx/merge-branch@v1.3.1 with: type: now - from_branch: main + from_branch: ${{ github.base_ref }} target_branch: gh-pages github_token: ${{ github.token }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 65fb2740..1b6f7070 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -37,7 +37,7 @@ studio: kubeconfig_dir: /app/chartcontroller/kubeconfig/ static: replicas: 1 - image: ghcr.io/scaleoutsystems/stackn/ingress:develop + image: ghcr.io/scaleoutsystems/stackn/ingress:v0.6.0 pullPolicy: IfNotPresent resources: limits: @@ -47,7 +47,7 @@ studio: cpu: "100m" memory: "256Mi" image: #tell which image to deploy for studio - repository: ghcr.io/scaleoutsystems/stackn/studio:develop #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + repository: ghcr.io/scaleoutsystems/stackn/studio:v0.6.0 #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image resources: limits: From 8be8d4d6edf35d39da7ed1f9245d790977088a66 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 6 Sep 2022 15:08:19 +0200 Subject: [PATCH 022/146] fix .Subcharts reference not working for certain helm versions --- scaleout/stackn/templates/_helper.tpl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index 03775630..d3cd9f96 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -96,7 +96,11 @@ Return postgres secret */}} {{- define "stackn.postgres.secretName" -}} {{- if .Values.postgresql.enabled }} - {{- include "postgresql.secretName" .Subcharts.postgresql -}} + {{- if include "postgresql.secretName" .Subcharts.postgresql -}} + {{- include "postgresql.secretName" .Subcharts.postgresql -}} + {{- else -}} + {{- .Values.postgresql.fullnameOverride -}} + {{- end -}} {{- else -}} {* HOLDER FOR HA MODE IN FUTURE RELEASE *} {{- end -}} From 131e342239c385d8f88eb99a8581597db9891586 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 6 Sep 2022 15:10:37 +0200 Subject: [PATCH 023/146] bump beta version --- scaleout/stackn/Chart.yaml | 2 +- scaleout/stackn/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index fbdb0ca4..f624e2ec 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 appVersion: "0.6.0" description: A Helm chart for deploying STACKn by Scaleout name: stackn -version: 0.2.0 +version: 0.2.1-beta maintainers: - email: morgan@scaleoutsystems.com name: Morgan Ekmefjord diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 851838aa..4ef2b29f 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -7,7 +7,7 @@ STACKn A Helm chart for deploying STACKn by Scaleout -Current chart version is 0.2.0 +Current chart version is 0.2.1-beta ## Chart Requirements From ba12687c9ccdac836b3b1a32da94c9cedb02c619 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 6 Sep 2022 15:16:07 +0200 Subject: [PATCH 024/146] remove beta (rancher can not fetch beta charts) --- scaleout/stackn/Chart.yaml | 2 +- scaleout/stackn/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index f624e2ec..07b24693 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 appVersion: "0.6.0" description: A Helm chart for deploying STACKn by Scaleout name: stackn -version: 0.2.1-beta +version: 0.2.1 maintainers: - email: morgan@scaleoutsystems.com name: Morgan Ekmefjord diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 4ef2b29f..0567bc37 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -7,7 +7,7 @@ STACKn A Helm chart for deploying STACKn by Scaleout -Current chart version is 0.2.1-beta +Current chart version is 0.2.1 ## Chart Requirements From 31f3bd837e73aad12337f98891c834bdbd8ecc1b Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 6 Sep 2022 16:08:45 +0200 Subject: [PATCH 025/146] remove .Subchart interface --- scaleout/stackn/templates/_helper.tpl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index d3cd9f96..376d2dc3 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -96,11 +96,7 @@ Return postgres secret */}} {{- define "stackn.postgres.secretName" -}} {{- if .Values.postgresql.enabled }} - {{- if include "postgresql.secretName" .Subcharts.postgresql -}} - {{- include "postgresql.secretName" .Subcharts.postgresql -}} - {{- else -}} {{- .Values.postgresql.fullnameOverride -}} - {{- end -}} {{- else -}} {* HOLDER FOR HA MODE IN FUTURE RELEASE *} {{- end -}} From 869bfc9e8c473f75fe210c8f8e9984950fc4d9da Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 6 Sep 2022 17:16:31 +0200 Subject: [PATCH 026/146] update secret name --- scaleout/stackn/templates/_helper.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index 376d2dc3..fbfb7efb 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -25,7 +25,7 @@ Get the STACKn password secret. {{- else if .Values.existingSecret -}} {{- printf "%s" (tpl .Values.existingSecret $) -}} {{- else -}} - stackn + {{- include "common.names.fullname" . -}} {{- end -}} {{- end -}} From 56fae337abaaff1e9080c7dd97b31b099e9330e9 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 27 Feb 2023 17:49:09 +0100 Subject: [PATCH 027/146] apply changes from studio-deploy-charts --- scaleout/stackn/Chart.yaml | 6 +- scaleout/stackn/charts/common-2.0.4.tgz | Bin 0 -> 14652 bytes scaleout/stackn/charts/grafana-6.8.4.tgz | Bin 27568 -> 0 bytes .../stackn/charts/postgresql-ha-9.2.0.tgz | Bin 60888 -> 0 bytes scaleout/stackn/charts/prometheus-13.8.0.tgz | Bin 35636 -> 0 bytes scaleout/stackn/requirements.yaml | 30 ++-- scaleout/stackn/templates/_helper.tpl | 4 +- scaleout/stackn/templates/basic-secrets.yaml | 4 +- .../templates/celery-flower-deployment.yaml | 95 +++++++++++ .../templates/celery-flower-service.yaml | 13 ++ .../stackn/templates/nginx-deployment.yaml | 2 + .../stackn/templates/rabbit-deployment.yaml | 3 +- .../stackn/templates/redis-deployment.yaml | 1 + .../templates/studio-admin-rolebinding.yaml | 4 +- .../stackn/templates/studio-deployment.yaml | 36 +++- .../templates/studio-settings-configmap.yaml | 161 ++++++++---------- scaleout/stackn/values.yaml | 36 +++- 17 files changed, 273 insertions(+), 122 deletions(-) create mode 100644 scaleout/stackn/charts/common-2.0.4.tgz delete mode 100644 scaleout/stackn/charts/grafana-6.8.4.tgz delete mode 100644 scaleout/stackn/charts/postgresql-ha-9.2.0.tgz delete mode 100644 scaleout/stackn/charts/prometheus-13.8.0.tgz create mode 100644 scaleout/stackn/templates/celery-flower-deployment.yaml create mode 100644 scaleout/stackn/templates/celery-flower-service.yaml diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index 07b24693..d284c51d 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v1 appVersion: "0.6.0" -description: A Helm chart for deploying STACKn by Scaleout -name: stackn -version: 0.2.1 +description: A Helm chart for deploying studio +name: studio +version: 0.3.0 maintainers: - email: morgan@scaleoutsystems.com name: Morgan Ekmefjord diff --git a/scaleout/stackn/charts/common-2.0.4.tgz b/scaleout/stackn/charts/common-2.0.4.tgz new file mode 100644 index 0000000000000000000000000000000000000000..54b9a53fac7ea10fea36b00b3534bbedfd1c7989 GIT binary patch literal 14652 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 literal 0 HcmV?d00001 diff --git a/scaleout/stackn/charts/grafana-6.8.4.tgz b/scaleout/stackn/charts/grafana-6.8.4.tgz deleted file mode 100644 index 52228f2245af6796066053311d87afc986ba13d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27568 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

PA z79wNc*R!0L3!L;TcGfhbH|zODluDMBj+%plw9#3DU`Wxp&=AH)aLr?tNVNchk}XBW zJY_##%sb(?T~)t7%f-w-En{Ri)%4UhI)zO$MN`0dnK>Z#)U7sI1H0#2bMzF$g5b%z zk)m~J3T7pW3czg{C0hH;SR$eY4JeSot-Z85Rh}YTmvWhL%n>}e>(9U><$XQ%$YHxa zP9KB8U~n`V!Qa7P(Ed9Z9u6K1M}yI5bT}N19zIYBqk{)z@Nv4|{?+Pk{$TLIeYGd| zKl1I6ZyBl@@DlX_&}mO42rJ53YWJ0=VSp+I}XI(N8NBb<;AM5$}k~s-uC<)8E>A^qDsmxJUvfU9dxIW17!G^n;P9|VhWlMz zn)P);jFG>Plbp$_>?&{IX}40?Ds%1qe(U_Y_SWA#gmla&L~Y72Aw`|%evYK8#ScQ{ z6<>u38F-nzvr5j3^Nvltq6N!4(orMs$3~s?Z+>>Q&h-Mwb6*9vqVtaSvG=tic{ZgT(UFC%Ei=pWq>(_hh?~Zl)sAt z)}^&3MzQ#5yA(Id#82n%t6F@cR_&)I+#l(?`TYNQ*MQsj|D(h9`G55A zV03@}-^KR<=f6=%AFBCUiH1>1A8tpV&1k-0zhF|W*tpRX+Ef&3gv&;Hj-riSXBxZR zIxqNSn~+`mzyo4Nbpf)kI~lFmSW~D82HH`RHS==fSiz7S5l-_0?Rq@5kr_U1e zR1Yd$-uS!`K1s-v*=#lo2=UB7v7l?S>Y$-xB5G5uai&w#qG`ISk-{x?!jdh8Tw~e` zu4Ta($;+#AxLM^;Rru5ZZ+#t9r_+$>L;AQ4{|AGEHvSI>_wv6x`QBZB>Ji+3_uu_@ X|J{F|;`>hk00960W8W{H09*n93YrZ< diff --git a/scaleout/stackn/charts/postgresql-ha-9.2.0.tgz b/scaleout/stackn/charts/postgresql-ha-9.2.0.tgz deleted file mode 100644 index 26b02f842594a06e4cb505a141a69dbc00b5af89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60888 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 diff --git a/scaleout/stackn/charts/prometheus-13.8.0.tgz b/scaleout/stackn/charts/prometheus-13.8.0.tgz deleted file mode 100644 index 7f8764802a86a79270bff04ca04013c6c75918b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35636 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%0AvpPvCesx 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 diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index 526a90b3..a990650b 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -15,27 +15,33 @@ dependencies: # repository: "https://argoproj.github.io/argo-helm" # condition: argo.enabled - - name: prometheus - version: 13.8.0 - repository: https://prometheus-community.github.io/helm-charts - condition: prometheus.enabled + # - name: prometheus + # version: 13.8.0 + # repository: https://prometheus-community.github.io/helm-charts + # condition: prometheus.enabled - - name: grafana - version: 6.8.4 - repository: https://grafana.github.io/helm-charts - condition: grafana.enabled + # - name: grafana + # version: 6.8.4 + # repository: https://grafana.github.io/helm-charts + # condition: grafana.enabled - name: reloader version: v0.0.86 repository: https://stakater.github.io/stakater-charts condition: reloader.enabled - - name: postgresql-ha - version: 9.2.0 - repository: https://charts.bitnami.com/bitnami - condition: postgresql-ha.enabled + # - name: postgresql-ha + # version: 9.2.0 + # repository: https://charts.bitnami.com/bitnami + # condition: postgresql-ha.enabled - name: postgresql version: 11.6.14 repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled + + - name: common + repository: https://charts.bitnami.com/bitnami + tags: + - bitnami-common + version: 2.x.x diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index fbfb7efb..4bc9de45 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -25,7 +25,7 @@ Get the STACKn password secret. {{- else if .Values.existingSecret -}} {{- printf "%s" (tpl .Values.existingSecret $) -}} {{- else -}} - {{- include "common.names.fullname" . -}} + {{ include "common.names.fullname" . }} {{- end -}} {{- end -}} @@ -96,7 +96,7 @@ Return postgres secret */}} {{- define "stackn.postgres.secretName" -}} {{- if .Values.postgresql.enabled }} - {{- .Values.postgresql.fullnameOverride -}} + {{- include "postgresql.secretName" .Subcharts.postgresql -}} {{- else -}} {* HOLDER FOR HA MODE IN FUTURE RELEASE *} {{- end -}} diff --git a/scaleout/stackn/templates/basic-secrets.yaml b/scaleout/stackn/templates/basic-secrets.yaml index a6da9c53..c3f9a721 100644 --- a/scaleout/stackn/templates/basic-secrets.yaml +++ b/scaleout/stackn/templates/basic-secrets.yaml @@ -8,6 +8,6 @@ metadata: namespace: {{ .Release.Namespace }} type: Opaque data: - studio-superuser-password: {{ include "stackn.studio.superuser.password" . | b64enc | quote }} - rabbit-password: {{ include "stackn.rabbit.password" . | b64enc | quote }} + studio-superuser-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-superuser-password" "providedValues" (list "global.studio.superuserPassword" "studio.superuserPassword") "context" $) }} + rabbit-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "rabbit-password" "providedValues" (list "rabbit.password") "context" $) }} {{- end -}} \ No newline at end of file diff --git a/scaleout/stackn/templates/celery-flower-deployment.yaml b/scaleout/stackn/templates/celery-flower-deployment.yaml new file mode 100644 index 00000000..99d26506 --- /dev/null +++ b/scaleout/stackn/templates/celery-flower-deployment.yaml @@ -0,0 +1,95 @@ +{{- if .Values.celeryFlower.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + reloader.stakater.com/auto: "true" + labels: + io.kompose.service: {{ .Release.Name }}-celery-flower + name: {{ .Release.Name }}-celery-flower + name: {{ .Release.Name }}-celery-flower +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + name: {{ .Release.Name }}-celery-flower + template: + metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.20.0 () + creationTimestamp: null + labels: + io.kompose.service: {{ .Release.Name }}-celery-flower + name: {{ .Release.Name }}-celery-flower + spec: + containers: + - args: + - sh + - ./scripts/run_flower.sh + env: + - name: BASE_PATH + value: "/app" + - name: GET_HOSTS_FROM + value: dns + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "stackn.postgres.secretName" . }} + key: password + - name: POSTGRES_USER + value: {{ .Values.postgresql.global.postgresql.auth.user }} + - name: RABBITMQ_DEFAULT_PASS + valueFrom: + secretKeyRef: + name: {{ template "stackn.secretName" . }} + key: rabbit-password + - name: RABBITMQ_HOST + value: {{ .Release.Name }}-rabbit + - name: RABBITMQ_USER + value: {{ include "stackn.rabbit.username" . }} + - name: REDIS_HOST + value: {{ .Release.Name }}-redis + {{- if .Values.chartcontroller.addSecret }} + - name: KUBECONFIG + value: {{ .Values.studio.kubeconfig_file | quote }} + {{- end }} + image: {{ .Values.studio.image.repository }} + imagePullPolicy: {{ .Values.studio.image.pullPolicy }} + name: {{ .Release.Name }}-celery-worker + resources: + limits: + cpu: {{ .Values.celeryWorkers.resources.limits.cpu }} + memory: {{ .Values.celeryWorkers.resources.limits.memory }} + requests: + cpu: {{ .Values.celeryWorkers.resources.requests.cpu }} + memory: {{ .Values.celeryWorkers.resources.requests.memory }} + volumeMounts: + {{- if .Values.chartcontroller.addSecret }} + - name: config + mountPath: {{ .Values.studio.kubeconfig_dir | quote }} + readOnly: true + {{- end }} + - mountPath: /app/studio/settings.py + subPath: settings.py + name: {{ .Release.Name}}-settings-configmap + imagePullSecrets: + - name: ghcrsecret + restartPolicy: Always + volumes: + {{- if .Values.chartcontroller.addSecret }} + - name: config + secret: + secretName: {{ .Release.Name }}-chart-controller-secret + {{- end }} + - name: {{ .Release.Name}}-settings-configmap + configMap: + name: {{ .Release.Name}}-settings-configmap + items: + - key: settings.py + path: settings.py + +status: {} +{{- end }} diff --git a/scaleout/stackn/templates/celery-flower-service.yaml b/scaleout/stackn/templates/celery-flower-service.yaml new file mode 100644 index 00000000..05d4cfec --- /dev/null +++ b/scaleout/stackn/templates/celery-flower-service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-celery-flower +spec: + ports: + - name: "5556" + port: 5556 + targetPort: 5556 + selector: + name: {{ .Release.Name }}-celery-flower +status: + loadBalancer: {} diff --git a/scaleout/stackn/templates/nginx-deployment.yaml b/scaleout/stackn/templates/nginx-deployment.yaml index 108a1162..52486247 100644 --- a/scaleout/stackn/templates/nginx-deployment.yaml +++ b/scaleout/stackn/templates/nginx-deployment.yaml @@ -49,4 +49,6 @@ spec: requests: cpu: {{ .Values.studio.static.resources.requests.cpu }} memory: {{ .Values.studio.static.resources.requests.cpu }} + imagePullSecrets: + - name: ghcrsecret diff --git a/scaleout/stackn/templates/rabbit-deployment.yaml b/scaleout/stackn/templates/rabbit-deployment.yaml index 99ee3c56..842b5075 100644 --- a/scaleout/stackn/templates/rabbit-deployment.yaml +++ b/scaleout/stackn/templates/rabbit-deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: annotations: + reloader.stakater.com/auto: "true" kompose.cmd: kompose convert kompose.version: 1.20.0 () creationTimestamp: null @@ -34,7 +35,7 @@ spec: key: rabbit-password - name: RABBITMQ_DEFAULT_USER value: {{ include "stackn.rabbit.username" . }} - image: rabbitmq:3.8 + image: {{ .Values.rabbit.image }} name: {{ .Release.Name }}-rabbit ports: - containerPort: 5672 diff --git a/scaleout/stackn/templates/redis-deployment.yaml b/scaleout/stackn/templates/redis-deployment.yaml index 7223f095..34e58a64 100644 --- a/scaleout/stackn/templates/redis-deployment.yaml +++ b/scaleout/stackn/templates/redis-deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: annotations: + reloader.stakater.com/auto: "true" kompose.cmd: kompose convert kompose.version: 1.20.0 () creationTimestamp: null diff --git a/scaleout/stackn/templates/studio-admin-rolebinding.yaml b/scaleout/stackn/templates/studio-admin-rolebinding.yaml index 016c005a..ac9f8021 100644 --- a/scaleout/stackn/templates/studio-admin-rolebinding.yaml +++ b/scaleout/stackn/templates/studio-admin-rolebinding.yaml @@ -2,7 +2,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: stackn-admin - namespace: default + namespace: {{ .Values.namespace }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole @@ -10,5 +10,5 @@ roleRef: subjects: - kind: ServiceAccount name: default - namespace: default + namespace: {{ .Values.namespace }} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 3995632d..0c28944e 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -20,10 +20,22 @@ spec: io.kompose.service: {{ .Release.Name }}-studio name: {{ .Release.Name }}-studio spec: + securityContext: + fsGroup: 1000 initContainers: + - name: volume-permissions + image: busybox + command: ['sh', '-c', 'chown -R 1000 /app/media && chgrp -R 1000 /app/media'] + volumeMounts: + - mountPath: {{ .Values.studio.media.mount_path }} + name: mediavol + securityContext: + runAsUser: 0 + runAsGroup: 0 + runAsNonRoot: false - name: wait-for-db image: postgres - command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }}.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 2; done;'] + command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }} --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 2; done;'] resources: limits: cpu: "100m" @@ -36,12 +48,18 @@ spec: - sh - scripts/run_web.sh env: - {{ if .Values.studio.debug }} - name: DEBUG + {{ if .Values.studio.debug }} value: "true" + {{ else }} + value: "false" {{ end }} - name: INIT value: {{ .Values.studio.init | quote }} + - name: STUDIO_STORAGECLASS + value: {{ include "stackn.studio.storageclass" . }} + - name: STUDIO_ACCESSMODE + value: {{ .Values.accessmode }} - name: DJANGO_SUPERUSER value: {{ include "stackn.studio.superuser" . }} - name: DJANGO_SUPERUSER_EMAIL @@ -58,20 +76,26 @@ spec: secretKeyRef: name: {{ include "stackn.postgres.secretName" . }} key: password + - name: POSTGRES_USER + value: {{ .Values.postgresql.global.postgresql.auth.user }} - name: RABBITMQ_DEFAULT_PASS valueFrom: secretKeyRef: name: {{ include "stackn.secretName" . }} key: rabbit-password + {{- if .Values.chartcontroller.addSecret }} - name: KUBECONFIG value: {{ .Values.studio.kubeconfig_file | quote }} + {{- end }} image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio volumeMounts: + {{- if .Values.chartcontroller.addSecret }} - name: kubeconfig mountPath: {{ .Values.studio.kubeconfig_dir | quote }} readOnly: true + {{- end }} - mountPath: /app/studio/settings.py subPath: settings.py name: {{ .Release.Name}}-settings-configmap @@ -85,15 +109,17 @@ spec: cpu: {{ .Values.studio.resources.requests.cpu }} memory: {{ .Values.studio.resources.requests.memory }} - {{- with .Values.imagePullSecrets }} + imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} + - name: ghcrsecret + restartPolicy: Always volumes: + {{- if .Values.chartcontroller.addSecret }} - name: kubeconfig secret: secretName: {{ .Release.Name }}-chart-controller-secret + {{- end }} - name: {{ .Release.Name}}-settings-configmap configMap: name: {{ .Release.Name}}-settings-configmap diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 0f26d86d..a737209c 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -18,15 +18,15 @@ data: import os import sys + from pathlib import Path + AUTHENTICATION_BACKENDS = [ - 'social_core.backends.github.GithubOAuth2', - 'social_core.backends.google.GoogleOAuth2', - 'django.contrib.auth.backends.ModelBackend', - 'guardian.backends.ObjectPermissionBackend', + 'django.contrib.auth.backends.ModelBackend', + 'guardian.backends.ObjectPermissionBackend', ] - # Build paths inside the project like this: os.path.join(BASE_DIR, ...) + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Crispy Forms @@ -54,51 +54,31 @@ data: # Application definition - # Application definition - DEFAULT_APPS = [ + INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', + 'rest_framework.authtoken', + 'rest_framework', 'django.contrib.staticfiles', + 'corsheaders', + 'django_celery_beat', + 'django_extensions', # for executing runscript among others + 'django_filters', + 'tagulous', + 'guardian', + 'crispy_forms', + "portal", + "projects", + "models", + "monitor", + "apps", + "api", + "customtags", ] - THIRD_PARTY_APPS = [ - # add apps which you install using pip - "crispy_forms", - 'corsheaders', - 'django_celery_beat', - 'django_extensions', # for executing runscript among others - 'django_filters', - 'oauth2_provider', - 'rest_framework', - 'rest_framework.authtoken', - 'social_django', - 'tagulous', - 'guardian', - ] - - LOCAL_APPS = [ - # add local apps which you create using startapp - 'api', - 'apps', - 'common', - 'deployments', - 'monitor', - 'models', - 'projects', - 'portal', - ] - - # # Application definition - INSTALLED_APPS = DEFAULT_APPS + THIRD_PARTY_APPS + LOCAL_APPS - - OAUTH2_PROVIDER = { - # this is the list of available scopes - 'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'} - } - MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -107,18 +87,25 @@ data: 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'corsheaders.middleware.CorsMiddleware', - 'social_django.middleware.SocialAuthExceptionMiddleware', # Add + 'corsheaders.middleware.CorsMiddleware' ] + REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.TokenAuthentication', - #'rest_framework.permissions.IsAuthenticated', - 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', + 'rest_framework.authentication.TokenAuthentication' ], } + # Default primary key field type + # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field + + #Setting this will remove a warning about CorsModel primary keys filed, however a + # permission denied error is introduced + # when django tries to apply a new migration to corsheaders package. This is because + # the web server is started as stackn user but the migrations folder in corsheader is root + #DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + # Django guardian 403 templates GUARDIAN_RENDER_403 = True GUARDIAN_TEMPLATE_403 = '403.html' @@ -126,17 +113,6 @@ data: # Main Url conf for loading all the routing path in Studio ROOT_URLCONF = 'studio.urls' - # IMPORTANT: Must be encrypted as secrets in K8S - # Github - SOCIAL_AUTH_GITHUB_KEY = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GITHUB_SECRET = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GITHUB_SCOPE = ['user:email'] # Ask for the user's email - - # Google - SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'to-be-fetched-from-k8s-secrets' - SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['user:email'] # Ask for the user's email - # Tagulous serialization settings SERIALIZATION_MODULES = { 'xml': 'tagulous.serializers.xml_serializer', @@ -152,6 +128,12 @@ data: 'compressor.finders.CompressorFinder', ) + STATIC_URL = '/static/' + #Use in production and together with Nginx + STATIC_ROOT = os.path.join(BASE_DIR, 'static/') + #STATICFILES_DIRS = ( os.path.join('static'), ) + + TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', @@ -161,7 +143,7 @@ data: TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'common/templates')], + 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -169,8 +151,6 @@ data: 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', - 'social_django.context_processors.backends', # Add - 'social_django.context_processors.login_redirect', # Add ], 'libraries': { 'custom_tags': 'models.templatetags.custom_tags', @@ -187,7 +167,7 @@ data: DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.postgresql', + 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': '{{ .Values.postgresql.global.postgresql.auth.database }}', 'USER': '{{ .Values.postgresql.global.postgresql.auth.username }}', 'PASSWORD': os.environ.get('POSTGRES_PASSWORD'), @@ -222,34 +202,26 @@ data: USE_L10N = True USE_TZ = True - # Static files (CSS, JavaScript, Images) - # https://docs.djangoproject.com/en/2.2/howto/static-files/ - #STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ] - STATIC_URL = '/static/' - STATIC_ROOT = os.path.join(BASE_DIR, 'static/') # Media Files for Studio apps MEDIA_URL = {{ .Values.studio.media.mount_path | quote }} MEDIA_ROOT = {{ .Values.studio.media.mount_path | quote }} + #From studio + #MEDIA_URL = '/media/' + #MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') + # Related to user registration and authetication workflow LOGIN_REDIRECT_URL = '/' LOGIN_URL = 'login' LOGOUT_URL = 'logout' - INACTIVE_USERS = False + INACTIVE_USERS = {{ if .Values.studio.inactive_users }}True{{ else }}False{{ end }} # Specific to Studio stack: # Redis settings REDIS_PORT = 6379 REDIS_DB = 0 REDIS_HOST = os.environ.get('REDIS_PORT_6379_TCP_ADDR', '{{ .Release.Name }}-redis') - #CHANNEL_LAYERS = { - # 'default': { - # 'BACKEND': 'channels_redis.core.RedisChannelLayer', - # 'CONFIG': { - # 'hosts': [(REDIS_HOST, REDIS_PORT),], - # }, - # }, - #} + # Celery settings CELERY_BROKER_URL = 'amqp://{{ include "stackn.rabbit.username" . }}:{}@{{ .Release.Name }}-rabbit:5672//'.format(os.environ.get("RABBITMQ_DEFAULT_PASS")) CELERY_RESULT_BACKEND = 'redis://%s:%d/%d' % (REDIS_HOST, REDIS_PORT, REDIS_DB) @@ -262,21 +234,30 @@ data: VERSION_BACKEND = 'studio.version.Version' # Other Helm/k8s deployment settings - CHART_CONTROLLER_URL = 'http://{{ .Release.Name }}-chart-controller' #Not used CHART_FOLDER = "/app/charts/apps" EXTERNAL_KUBECONF = True KUBECONFIG = {{ .Values.studio.kubeconfig_file | quote }} NAMESPACE = {{ .Values.namespace | default "default" | quote }} - #PROMETHEUS_SVC = 'http://{{ .Release.Name }}-prometheus-server' - REGISTRY_SVC = '{{ .Release.Name }}-docker-registry' STORAGECLASS = {{ include "stackn.studio.storageclass" . | quote }} - # Local dependecies Models - PROJECTS_MODEL = 'projects.Project' - APPINSTANCE_MODEL = 'apps.AppInstance' - APPS_MODEL = 'apps.Apps' - APPCATEGORIES_MODEL = 'apps.AppCategories' - MODELS_MODEL = 'models.Model' + # App dependencies + + # Apps + APPS_MODEL = "apps.Apps" + APPINSTANCE_MODEL = "apps.AppInstance" + APPCATEGORIES_MODEL ="apps.AppCategories" + + # Models + MODELS_MODEL = "models.Model" + + # Projects + PROJECTS_MODEL = "projects.Project" + PROJECTLOG_MODEL = "projects.ProjectLog" + ENVIRONMENT_MODEL = "projects.Environment" + RELEASENAME_MODEL = "projects.ReleaseName" + # Portal + PUBLISHEDMODEL_MODEL = "portal.PublishedModel" + PUBLICMODELOBJECT_MODEL = "portal.PublicModelObject" # App statuses APPS_STATUS_SUCCESS = ['Running', 'Succeeded', 'Success'] @@ -284,9 +265,15 @@ data: 'Waiting', 'Installing', 'Created'] DOMAIN = {{ .Values.domain | quote }} - AUTH_DOMAIN = '{{ .Release.Name }}-studio.default.svc.cluster.local' + AUTH_DOMAIN = '{{ .Release.Name }}-studio.{{ .Values.namespace | default "default" }}.svc.{{ .Values.cluster_domain | default "cluster.local"}}' AUTH_PROTOCOL = 'http' STUDIO_URL = 'http://{{ .Release.Name }}-studio:8080' # To enable sticky sessions for k8s ingress SESSION_COOKIE_DOMAIN = {{ .Values.session_cookie_domain | quote }} - \ No newline at end of file + CSRF_TRUSTED_ORIGINS = ['https://*{{ .Values.session_cookie_domain }}','https://*.127.0.0.1'] + [{{ .Values.studio.csrf_trusted_origins | quote}}] + + # Email + EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend" + EMAIL_FILE_PATH = os.path.join(BASE_DIR, 'sent_emails') + + VERSION = {{ .Values.studio.version | quote }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 1b6f7070..e6d28056 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -17,10 +17,10 @@ global: storageClass: "" postgresql: auth: - username: stackn + username: studio password: "" postgresPassword: "" - database: stackn + database: studio existingSecret: "" storageClass: @@ -33,11 +33,13 @@ studio: replicas: 1 debug: true init: true - kubeconfig_file: /app/chartcontroller/kubeconfig/config - kubeconfig_dir: /app/chartcontroller/kubeconfig/ + inactive_users: False + csrf_trusted_origins: + kubeconfig_file: /app/kubeconfig/config + kubeconfig_dir: /app/kubeconfig/ static: replicas: 1 - image: ghcr.io/scaleoutsystems/stackn/ingress:v0.6.0 + image: ghcr.io/scaleoutsystems/stackn/studio:develop pullPolicy: IfNotPresent resources: limits: @@ -47,7 +49,7 @@ studio: cpu: "100m" memory: "256Mi" image: #tell which image to deploy for studio - repository: ghcr.io/scaleoutsystems/stackn/studio:v0.6.0 #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + repository: ghcr.io/scaleoutsystems/stackn/ingress:develop #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image resources: limits: @@ -67,10 +69,17 @@ studio: superUser: admin superuserPassword: "" superuserEmail: admin@test.com + version: studio #kubernetes config kubeconfig: "" +#storage access mode +accessmode: ReadWriteMany + +#the cluster domain name (default usually cluster.local) +cluster_domain: cluster.local + # Enable ingress if you want your to access the studio solution from a kubernetes host/localhost. domain: studio.127.0.0.1.nip.io session_cookie_domain: .127.0.0.1.nip.io @@ -91,7 +100,13 @@ ingress: # Postgres deploy with a single-pod database: postgresql: enabled: true - fullnameOverride: stackn-studio-postgres + fullnameOverride: studio-postgres + commonAnnotations: {"reloader.stakater.com/auto": "true"} + auth: + username: + password: + postgresPassword: + database: studio primary: service: ports: @@ -101,6 +116,7 @@ postgresql: size: "10Gi" accessModes: - ReadWriteMany + storageClass: # Will be added in future realease, for now keep "enabled:false" postgresql-ha: @@ -125,15 +141,19 @@ celeryWorkers: cpu: "1000m" memory: "8Gi" +celeryFlower: + enabled: true + # default credentials for rabbitmq. override in production! rabbit: + image: rabbitmq:3-management username: admin password: "" chartcontroller: enabled: false #addSecret -- if true create chart-controller-secret from cluster_config, if false it must be added manually - addSecret: true + addSecret: false docker-registry: enabled: false From 205796696e51457aa5884e2ff072253f9b573a37 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 1 Mar 2023 09:36:23 +0100 Subject: [PATCH 028/146] add common app --- scaleout/stackn/templates/studio-settings-configmap.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index a737209c..0636cc9b 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -70,6 +70,7 @@ data: 'tagulous', 'guardian', 'crispy_forms', + 'common', "portal", "projects", "models", From 0f8c2383de0d961ce4ec40b8317ffde44e60813f Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 1 Mar 2023 09:52:08 +0100 Subject: [PATCH 029/146] add network policies --- .gitignore | 3 + .../templates/celery-flower-deployment.yaml | 1 + .../stackn/templates/network-policies.yaml | 159 ++++++++++++++++++ .../stackn/templates/rabbit-deployment.yaml | 2 + .../stackn/templates/redis-deployment.yaml | 2 + .../stackn/templates/studio-deployment.yaml | 3 + scaleout/stackn/values.yaml | 13 ++ 7 files changed, 183 insertions(+) create mode 100644 scaleout/stackn/templates/network-policies.yaml diff --git a/.gitignore b/.gitignore index 422e58fd..3c2ec14d 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,6 @@ dmypy.json static/open-iconic/ repos/ + +#Other +values-local.yaml diff --git a/scaleout/stackn/templates/celery-flower-deployment.yaml b/scaleout/stackn/templates/celery-flower-deployment.yaml index 99d26506..16f0d5af 100644 --- a/scaleout/stackn/templates/celery-flower-deployment.yaml +++ b/scaleout/stackn/templates/celery-flower-deployment.yaml @@ -24,6 +24,7 @@ spec: labels: io.kompose.service: {{ .Release.Name }}-celery-flower name: {{ .Release.Name }}-celery-flower + app: stackn-studio spec: containers: - args: diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml new file mode 100644 index 00000000..5b199068 --- /dev/null +++ b/scaleout/stackn/templates/network-policies.yaml @@ -0,0 +1,159 @@ +{{- if .Values.networkPolicy.enable }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny-ingress + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: {} + policyTypes: + - Ingress +--- + +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny-egress + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: {} + policyTypes: + - Egress +--- +#Requires that kube-system namespace has label name: kube-system. To create label: +# $ kubectl label namespace kube-system name=kube-system +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-dns-access + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: {} + policyTypes: + - Egress + egress: + - to: + - namespaceSelector: + matchLabels: + name: kube-system + ports: + - protocol: UDP + port: 53 +--- +# Certain services (such as celery-workers) need to allow egress to k8s api-server +# To get the IP and port (usually 6443) of the api-server: +# $ kubectl get endpoints kubernetes +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ .Release.Name }}-allow-api-access + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + allow-api-access: "true" + policyTypes: + - Egress + egress: + - to: + - ipBlock: + cidr: {{ .Values.networkPolicy.kubernetes.cidr }} + ports: + - protocol: TCP + port: {{ .Values.networkPolicy.kubernetes.port }} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-egress-to-studio + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + app: stackn-studio + policyTypes: + - Egress + egress: + - to: + - podSelector: + matchLabels: + app: stackn-studio + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-ingress-from-studio + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + app: stackn-studio + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: stackn-studio +--- +# To limit this egress rule for internal IPs, set +# .Values.networkPolicy.internal_cidr +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-internet-egress + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + networking/allow-internet-egress: "true" + policyTypes: + - Egress + egress: + - to: + - ipBlock: + cidr: 0.0.0.0/0 + except: + {{- range $cidr := .Values.networkPolicy.internal_cidr }} + - {{ $cidr }} + {{- end }} + +--- +#This rule might not be needed, but is here for utility. Currently no resources use this rule. +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-internet-ingress + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + networking/allow-internet-ingress: "true" + policyTypes: + - Ingress + ingress: + - from: + - ipBlock: + cidr: 0.0.0.0/0 + except: + {{- range $cidr := .Values.networkPolicy.internal_cidr }} + - {{ $cidr }} + {{- end }} +--- +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + namespace: {{ .Values.namespace | default "default" }} + name: allow-ingress-controller +spec: + podSelector: {} + ingress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Values.networkPolicy.ingress_controller_namespace }} # <- This should allow traffic from ingress namespace +{{- end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/rabbit-deployment.yaml b/scaleout/stackn/templates/rabbit-deployment.yaml index 842b5075..5c7edd38 100644 --- a/scaleout/stackn/templates/rabbit-deployment.yaml +++ b/scaleout/stackn/templates/rabbit-deployment.yaml @@ -9,6 +9,7 @@ metadata: labels: io.kompose.service: {{ .Release.Name }}-rabbit name: {{ .Release.Name }}-rabbit + app: stackn-studio name: {{ .Release.Name }}-rabbit spec: replicas: 1 @@ -25,6 +26,7 @@ spec: labels: io.kompose.service: {{ .Release.Name }}-rabbit name: {{ .Release.Name }}-rabbit + app: stackn-studio spec: containers: - env: diff --git a/scaleout/stackn/templates/redis-deployment.yaml b/scaleout/stackn/templates/redis-deployment.yaml index 34e58a64..4f8088e9 100644 --- a/scaleout/stackn/templates/redis-deployment.yaml +++ b/scaleout/stackn/templates/redis-deployment.yaml @@ -9,6 +9,7 @@ metadata: labels: io.kompose.service: {{ .Release.Name }}-redis name: {{ .Release.Name }}-redis + app: stackn-studio name: {{ .Release.Name }}-redis spec: replicas: 1 @@ -25,6 +26,7 @@ spec: labels: io.kompose.service: {{ .Release.Name }}-redis name: {{ .Release.Name }}-redis + app: stackn-studio spec: containers: - image: redis diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 0c28944e..23958da8 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -19,6 +19,9 @@ spec: labels: io.kompose.service: {{ .Release.Name }}-studio name: {{ .Release.Name }}-studio + web: studio-web + app: stackn-studio + allow-api-access: "true" spec: securityContext: fsGroup: 1000 diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index e6d28056..d89eeba4 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -28,6 +28,18 @@ global: namespace: default existingSecret: "" +networkPolicy: + enable: false + kubernetes: + cidr: # To get kubernetes api server endpoints run: $ kubectl get endpoints kubernetes + port: 6443 + internal_cidr: # in-cluster IpBlock cidr, used in allow-internet-[egress|ingress] policy, e.g: + - 10.0.0.0/8 + - 192.168.0.0/16 + - 172.0.0.0/20 + ingress_controller_namespace: kube-system + + studio: servicename: studio replicas: 1 @@ -117,6 +129,7 @@ postgresql: accessModes: - ReadWriteMany storageClass: + podLabels: {"app": "stackn-studio"} # Will be added in future realease, for now keep "enabled:false" postgresql-ha: From 1f5a1af90d58778df936fcb4db4016c2889f6ab2 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 1 Mar 2023 10:11:24 +0100 Subject: [PATCH 030/146] use bitnami for redis and rabbitmq + add securityContext --- scaleout/stackn/charts/rabbitmq-11.9.1.tgz | Bin 0 -> 57316 bytes scaleout/stackn/charts/redis-17.7.4.tgz | Bin 0 -> 92455 bytes scaleout/stackn/requirements.yaml | 12 +- scaleout/stackn/templates/_helper.tpl | 28 ++- .../templates/celery-flower-deployment.yaml | 6 +- .../stackn/templates/network-policies.yaml | 159 ------------------ .../stackn/templates/rabbit-deployment.yaml | 48 ------ scaleout/stackn/templates/rabbit-service.yaml | 22 --- .../stackn/templates/redis-deployment.yaml | 39 ----- scaleout/stackn/templates/redis-service.yaml | 19 --- .../stackn/templates/studio-deployment.yaml | 32 +++- .../templates/studio-settings-configmap.yaml | 8 +- scaleout/stackn/values.yaml | 35 +++- 13 files changed, 104 insertions(+), 304 deletions(-) create mode 100644 scaleout/stackn/charts/rabbitmq-11.9.1.tgz create mode 100644 scaleout/stackn/charts/redis-17.7.4.tgz delete mode 100644 scaleout/stackn/templates/network-policies.yaml delete mode 100644 scaleout/stackn/templates/rabbit-deployment.yaml delete mode 100644 scaleout/stackn/templates/rabbit-service.yaml delete mode 100644 scaleout/stackn/templates/redis-deployment.yaml delete mode 100644 scaleout/stackn/templates/redis-service.yaml diff --git a/scaleout/stackn/charts/rabbitmq-11.9.1.tgz b/scaleout/stackn/charts/rabbitmq-11.9.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2c6b1abd495162be9e633d70cabc1cb84b207f1e GIT binary patch literal 57316 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� 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 l+k6&F-SMB$Eh^8?^Yi>XKTq%Ze*pjh|NmDc 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

    qK%(tYsRnD|5?N1HKqZr#wqc}K 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 literal 0 HcmV?d00001 diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index a990650b..320c66c9 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -40,8 +40,18 @@ dependencies: repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled + - name: redis + version: 17.7.4 + repository: https://charts.bitnami.com/bitnami + condition: redis.enabled + + - name: rabbitmq + version: 11.9.1 + repository: https://charts.bitnami.com/bitnami + condition: rabbitmq.enabled + - name: common repository: https://charts.bitnami.com/bitnami tags: - bitnami-common - version: 2.x.x + version: 2.0.4 diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index 4bc9de45..c96319b8 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -102,6 +102,21 @@ Return postgres secret {{- end -}} {{- end -}} +{{/* +Return redis secret +*/}} +{{- define "stackn.redis.secretName" -}} +{{- include "redis.secretName" .Subcharts.redis -}} +{{- end -}} + + +{{/* +Return redis secret password key +*/}} +{{- define "stackn.redis.secretPasswordKey" -}} +{{- include "redis.secretPasswordKey" .Subcharts.redis -}} +{{- end -}} + {{/* Return STACKn studio storageClass */}} @@ -144,9 +159,14 @@ Return STACKn rabbit password Return STACKn rabbit username */}} {{- define "stackn.rabbit.username" -}} -{{- if .Values.rabbit.username -}} - {{- .Values.rabbit.username -}} -{{- else -}} - admin +{{- .Values.rabbitmq.auth.username -}} {{- end -}} + +{{/* +Return STACKn rabbit secret +*/}} +{{- define "stackn.rabbit.secretName" -}} +{{- include "rabbitmq.secretPasswordName" .Subcharts.rabbitmq -}} {{- end -}} + + diff --git a/scaleout/stackn/templates/celery-flower-deployment.yaml b/scaleout/stackn/templates/celery-flower-deployment.yaml index 16f0d5af..d1bbc9b0 100644 --- a/scaleout/stackn/templates/celery-flower-deployment.yaml +++ b/scaleout/stackn/templates/celery-flower-deployment.yaml @@ -24,12 +24,16 @@ spec: labels: io.kompose.service: {{ .Release.Name }}-celery-flower name: {{ .Release.Name }}-celery-flower - app: stackn-studio spec: containers: - args: - sh - ./scripts/run_flower.sh + {{- if .Values.studio.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.studio.securityContext.runAsUser }} + runAsGroup: {{ .Values.studio.securityContext.runAsGroup }} + {{- end }} env: - name: BASE_PATH value: "/app" diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml deleted file mode 100644 index 5b199068..00000000 --- a/scaleout/stackn/templates/network-policies.yaml +++ /dev/null @@ -1,159 +0,0 @@ -{{- if .Values.networkPolicy.enable }} -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny-ingress - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress ---- - -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny-egress - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: {} - policyTypes: - - Egress ---- -#Requires that kube-system namespace has label name: kube-system. To create label: -# $ kubectl label namespace kube-system name=kube-system -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-dns-access - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: {} - policyTypes: - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - name: kube-system - ports: - - protocol: UDP - port: 53 ---- -# Certain services (such as celery-workers) need to allow egress to k8s api-server -# To get the IP and port (usually 6443) of the api-server: -# $ kubectl get endpoints kubernetes -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: {{ .Release.Name }}-allow-api-access - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - allow-api-access: "true" - policyTypes: - - Egress - egress: - - to: - - ipBlock: - cidr: {{ .Values.networkPolicy.kubernetes.cidr }} - ports: - - protocol: TCP - port: {{ .Values.networkPolicy.kubernetes.port }} ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-egress-to-studio - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - app: stackn-studio - policyTypes: - - Egress - egress: - - to: - - podSelector: - matchLabels: - app: stackn-studio - ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-ingress-from-studio - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - app: stackn-studio - policyTypes: - - Ingress - ingress: - - from: - - podSelector: - matchLabels: - app: stackn-studio ---- -# To limit this egress rule for internal IPs, set -# .Values.networkPolicy.internal_cidr -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-internet-egress - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - networking/allow-internet-egress: "true" - policyTypes: - - Egress - egress: - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - {{- range $cidr := .Values.networkPolicy.internal_cidr }} - - {{ $cidr }} - {{- end }} - ---- -#This rule might not be needed, but is here for utility. Currently no resources use this rule. -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-internet-ingress - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - networking/allow-internet-ingress: "true" - policyTypes: - - Ingress - ingress: - - from: - - ipBlock: - cidr: 0.0.0.0/0 - except: - {{- range $cidr := .Values.networkPolicy.internal_cidr }} - - {{ $cidr }} - {{- end }} ---- -kind: NetworkPolicy -apiVersion: networking.k8s.io/v1 -metadata: - namespace: {{ .Values.namespace | default "default" }} - name: allow-ingress-controller -spec: - podSelector: {} - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: {{ .Values.networkPolicy.ingress_controller_namespace }} # <- This should allow traffic from ingress namespace -{{- end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/rabbit-deployment.yaml b/scaleout/stackn/templates/rabbit-deployment.yaml deleted file mode 100644 index 5c7edd38..00000000 --- a/scaleout/stackn/templates/rabbit-deployment.yaml +++ /dev/null @@ -1,48 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - reloader.stakater.com/auto: "true" - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-rabbit - name: {{ .Release.Name }}-rabbit - app: stackn-studio - name: {{ .Release.Name }}-rabbit -spec: - replicas: 1 - strategy: {} - selector: - matchLabels: - name: {{ .Release.Name }}-rabbit - template: - metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-rabbit - name: {{ .Release.Name }}-rabbit - app: stackn-studio - spec: - containers: - - env: - - name: RABBITMQ_DEFAULT_PASS - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: rabbit-password - - name: RABBITMQ_DEFAULT_USER - value: {{ include "stackn.rabbit.username" . }} - image: {{ .Values.rabbit.image }} - name: {{ .Release.Name }}-rabbit - ports: - - containerPort: 5672 - - containerPort: 15672 - resources: {} - hostname: rabbit - restartPolicy: Always -status: {} diff --git a/scaleout/stackn/templates/rabbit-service.yaml b/scaleout/stackn/templates/rabbit-service.yaml deleted file mode 100644 index fbe6d077..00000000 --- a/scaleout/stackn/templates/rabbit-service.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-rabbit - name: {{ .Release.Name }}-rabbit -spec: - ports: - - name: "5672" - port: 5672 - targetPort: 5672 - - name: "15672" - port: 15672 - targetPort: 15672 - selector: - io.kompose.service: {{ .Release.Name }}-rabbit -status: - loadBalancer: {} diff --git a/scaleout/stackn/templates/redis-deployment.yaml b/scaleout/stackn/templates/redis-deployment.yaml deleted file mode 100644 index 4f8088e9..00000000 --- a/scaleout/stackn/templates/redis-deployment.yaml +++ /dev/null @@ -1,39 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - reloader.stakater.com/auto: "true" - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-redis - name: {{ .Release.Name }}-redis - app: stackn-studio - name: {{ .Release.Name }}-redis -spec: - replicas: 1 - strategy: {} - selector: - matchLabels: - name: {{ .Release.Name }}-redis - template: - metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-redis - name: {{ .Release.Name }}-redis - app: stackn-studio - spec: - containers: - - image: redis - name: {{ .Release.Name }}-redis - ports: - - containerPort: 6379 - resources: {} - hostname: redis - restartPolicy: Always -status: {} diff --git a/scaleout/stackn/templates/redis-service.yaml b/scaleout/stackn/templates/redis-service.yaml deleted file mode 100644 index 0bf46bdb..00000000 --- a/scaleout/stackn/templates/redis-service.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-redis - name: {{ .Release.Name }}-redis -spec: - ports: - - name: "6379" - port: 6379 - targetPort: 6379 - selector: - io.kompose.service: {{ .Release.Name }}-redis -status: - loadBalancer: {} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 23958da8..0a8beb9f 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -24,7 +24,7 @@ spec: allow-api-access: "true" spec: securityContext: - fsGroup: 1000 + fsGroup: {{ .Values.studio.securityContext.fsGroup }} initContainers: - name: volume-permissions image: busybox @@ -81,11 +81,16 @@ spec: key: password - name: POSTGRES_USER value: {{ .Values.postgresql.global.postgresql.auth.user }} + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "stackn.redis.secretName" . }} + key: {{ include "stackn.redis.secretPasswordKey" . }} - name: RABBITMQ_DEFAULT_PASS valueFrom: secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: rabbit-password + name: {{ include "stackn.rabbit.secretName" . }} + key: rabbitmq-password {{- if .Values.chartcontroller.addSecret }} - name: KUBECONFIG value: {{ .Values.studio.kubeconfig_file | quote }} @@ -111,8 +116,25 @@ spec: requests: cpu: {{ .Values.studio.resources.requests.cpu }} memory: {{ .Values.studio.resources.requests.memory }} - - + {{- if .Values.studio.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.studio.securityContext.runAsUser }} + runAsGroup: {{ .Values.studio.securityContext.runAsGroup }} + {{- end }} + {{- if .Values.studio.readinessProbe.enabled }} + readinessProbe: + tcpSocket: + port: {{ .Values.studio.readinessProbe.tcpSocket.port }} + initialDelaySeconds: {{ .Values.studio.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.studio.readinessProbe.periodSeconds }} + {{- end }} + {{- if .Values.studio.livenessProbe.enabled }} + livenessProbe: + tcpSocket: + port: {{ .Values.studio.livenessProbe.tcpSocket.port }} + initialDelaySeconds: {{ .Values.studio.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.studio.livenessProbe.periodSeconds }} + {{- end }} imagePullSecrets: - name: ghcrsecret diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 0636cc9b..81e7ad1f 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -221,11 +221,11 @@ data: # Redis settings REDIS_PORT = 6379 REDIS_DB = 0 - REDIS_HOST = os.environ.get('REDIS_PORT_6379_TCP_ADDR', '{{ .Release.Name }}-redis') + REDIS_HOST = os.environ.get('REDIS_PORT_6379_TCP_ADDR', '{{ .Release.Name }}-redis-master') #TODO: fetch service dns from bitnami/redis instead # Celery settings - CELERY_BROKER_URL = 'amqp://{{ include "stackn.rabbit.username" . }}:{}@{{ .Release.Name }}-rabbit:5672//'.format(os.environ.get("RABBITMQ_DEFAULT_PASS")) - CELERY_RESULT_BACKEND = 'redis://%s:%d/%d' % (REDIS_HOST, REDIS_PORT, REDIS_DB) + CELERY_BROKER_URL = 'amqp://{{ include "stackn.rabbit.username" . }}:{}@{{ include "common.names.fullname" .Subcharts.rabbitmq }}:{{ .Values.rabbitmq.containerPorts.amqp }}//'.format(os.environ.get("RABBITMQ_DEFAULT_PASS")) + CELERY_RESULT_BACKEND = 'redis://:%s@%s:%d/%d' % (os.environ.get("REDIS_PASSWORD"),REDIS_HOST, REDIS_PORT, REDIS_DB) CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json' CELERY_ACCEPT_CONTENT = ['json'] @@ -277,4 +277,4 @@ data: EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend" EMAIL_FILE_PATH = os.path.join(BASE_DIR, 'sent_emails') - VERSION = {{ .Values.studio.version | quote }} + VERSION = {{ .Values.studio.version | quote }} \ No newline at end of file diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index d89eeba4..af2adc95 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -82,7 +82,24 @@ studio: superuserPassword: "" superuserEmail: admin@test.com version: studio - + securityContext: + enabled: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + readinessProbe: + enabled: true + tcpSocket: + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 10 + livenessProbe: + enabled: true + tcpSocket: + port: 8080 + initialDelaySeconds: 20 + periodSeconds: 20 + #kubernetes config kubeconfig: "" @@ -129,7 +146,21 @@ postgresql: accessModes: - ReadWriteMany storageClass: - podLabels: {"app": "stackn-studio"} + podLabels: {"app":"stackn-studio"} + +redis: + enabled: true + master: + podLabels: {"app":"stackn-studio"} + replica: + replicaCount: 1 + podLabels: {"app":"stackn-studio"} + +rabbitmq: + enabled: true + podLabels: {"app":"stackn-studio"} + + # Will be added in future realease, for now keep "enabled:false" postgresql-ha: From 19a938a0b8d13a2931f6a9559f225bbd5cc9ff29 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 1 Mar 2023 10:18:20 +0100 Subject: [PATCH 031/146] Bug/SK-367 | change redirect to /projects after login --- scaleout/stackn/templates/studio-settings-configmap.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 81e7ad1f..57793b0d 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -212,7 +212,7 @@ data: #MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') # Related to user registration and authetication workflow - LOGIN_REDIRECT_URL = '/' + LOGIN_REDIRECT_URL = '/projects' LOGIN_URL = 'login' LOGOUT_URL = 'logout' INACTIVE_USERS = {{ if .Values.studio.inactive_users }}True{{ else }}False{{ end }} From 47e875a37c79fcd1a8db72452a1ff5b9ac8b19bf Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 1 Mar 2023 10:23:14 +0100 Subject: [PATCH 032/146] Bug/SK-375 | Remove warning: Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField' --- scaleout/stackn/templates/studio-settings-configmap.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 57793b0d..b852e305 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -105,7 +105,9 @@ data: # permission denied error is introduced # when django tries to apply a new migration to corsheaders package. This is because # the web server is started as stackn user but the migrations folder in corsheader is root - #DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + # solution for now: setting AutoField as default (below) + # then setting BigAutoField on app level (ex /projects/apps.py) + DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # Django guardian 403 templates GUARDIAN_RENDER_403 = True From af45cff23630052135d2955c718dd9f877ee8fc1 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 1 Mar 2023 12:20:11 +0100 Subject: [PATCH 033/146] add networkpolicies --- .../stackn/templates/network-policies.yaml | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 scaleout/stackn/templates/network-policies.yaml diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml new file mode 100644 index 00000000..5b199068 --- /dev/null +++ b/scaleout/stackn/templates/network-policies.yaml @@ -0,0 +1,159 @@ +{{- if .Values.networkPolicy.enable }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny-ingress + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: {} + policyTypes: + - Ingress +--- + +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny-egress + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: {} + policyTypes: + - Egress +--- +#Requires that kube-system namespace has label name: kube-system. To create label: +# $ kubectl label namespace kube-system name=kube-system +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-dns-access + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: {} + policyTypes: + - Egress + egress: + - to: + - namespaceSelector: + matchLabels: + name: kube-system + ports: + - protocol: UDP + port: 53 +--- +# Certain services (such as celery-workers) need to allow egress to k8s api-server +# To get the IP and port (usually 6443) of the api-server: +# $ kubectl get endpoints kubernetes +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ .Release.Name }}-allow-api-access + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + allow-api-access: "true" + policyTypes: + - Egress + egress: + - to: + - ipBlock: + cidr: {{ .Values.networkPolicy.kubernetes.cidr }} + ports: + - protocol: TCP + port: {{ .Values.networkPolicy.kubernetes.port }} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-egress-to-studio + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + app: stackn-studio + policyTypes: + - Egress + egress: + - to: + - podSelector: + matchLabels: + app: stackn-studio + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-ingress-from-studio + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + app: stackn-studio + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: stackn-studio +--- +# To limit this egress rule for internal IPs, set +# .Values.networkPolicy.internal_cidr +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-internet-egress + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + networking/allow-internet-egress: "true" + policyTypes: + - Egress + egress: + - to: + - ipBlock: + cidr: 0.0.0.0/0 + except: + {{- range $cidr := .Values.networkPolicy.internal_cidr }} + - {{ $cidr }} + {{- end }} + +--- +#This rule might not be needed, but is here for utility. Currently no resources use this rule. +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-internet-ingress + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + networking/allow-internet-ingress: "true" + policyTypes: + - Ingress + ingress: + - from: + - ipBlock: + cidr: 0.0.0.0/0 + except: + {{- range $cidr := .Values.networkPolicy.internal_cidr }} + - {{ $cidr }} + {{- end }} +--- +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + namespace: {{ .Values.namespace | default "default" }} + name: allow-ingress-controller +spec: + podSelector: {} + ingress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Values.networkPolicy.ingress_controller_namespace }} # <- This should allow traffic from ingress namespace +{{- end }} \ No newline at end of file From 69f5897031ce470e619fb624c48961e5d2a3be3e Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 2 Mar 2023 08:56:12 +0100 Subject: [PATCH 034/146] add common annotations --- scaleout/stackn/templates/nginx-deployment.yaml | 2 +- scaleout/stackn/values.yaml | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/templates/nginx-deployment.yaml b/scaleout/stackn/templates/nginx-deployment.yaml index 52486247..8dbf40f7 100644 --- a/scaleout/stackn/templates/nginx-deployment.yaml +++ b/scaleout/stackn/templates/nginx-deployment.yaml @@ -48,7 +48,7 @@ spec: memory: {{ .Values.studio.static.resources.limits.memory }} requests: cpu: {{ .Values.studio.static.resources.requests.cpu }} - memory: {{ .Values.studio.static.resources.requests.cpu }} + memory: {{ .Values.studio.static.resources.requests.memory }} imagePullSecrets: - name: ghcrsecret diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index af2adc95..e270c7fc 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -150,6 +150,7 @@ postgresql: redis: enabled: true + commonAnnotations: {"reloader.stakater.com/auto": "true"} master: podLabels: {"app":"stackn-studio"} replica: @@ -158,7 +159,10 @@ redis: rabbitmq: enabled: true - podLabels: {"app":"stackn-studio"} + commonAnnotations: {"reloader.stakater.com/auto": "true"} + podLabels: {"app":"stackn-studio","allow-api-access": "true"} + persistence: + enabled: false From 87394ece38f82a7bc568810770414a7923dfeb4f Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 3 Mar 2023 15:42:16 +0100 Subject: [PATCH 035/146] Feature/SK-379 | Add service account and role/rolebinding --- .../templates/celery-flower-deployment.yaml | 1 + .../stackn/templates/nginx-deployment.yaml | 1 + scaleout/stackn/templates/role.yaml | 18 +++++++++++++++++ scaleout/stackn/templates/rolebinding.yaml | 20 +++++++++++++++++++ .../stackn/templates/service-account.yaml | 10 ++++++++++ .../templates/studio-admin-rolebinding.yaml | 14 ------------- .../stackn/templates/studio-deployment.yaml | 1 + scaleout/stackn/values.yaml | 8 ++++++++ 8 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 scaleout/stackn/templates/role.yaml create mode 100644 scaleout/stackn/templates/rolebinding.yaml create mode 100644 scaleout/stackn/templates/service-account.yaml delete mode 100644 scaleout/stackn/templates/studio-admin-rolebinding.yaml diff --git a/scaleout/stackn/templates/celery-flower-deployment.yaml b/scaleout/stackn/templates/celery-flower-deployment.yaml index d1bbc9b0..88b85ff4 100644 --- a/scaleout/stackn/templates/celery-flower-deployment.yaml +++ b/scaleout/stackn/templates/celery-flower-deployment.yaml @@ -25,6 +25,7 @@ spec: io.kompose.service: {{ .Release.Name }}-celery-flower name: {{ .Release.Name }}-celery-flower spec: + automountServiceAccountToken: false containers: - args: - sh diff --git a/scaleout/stackn/templates/nginx-deployment.yaml b/scaleout/stackn/templates/nginx-deployment.yaml index 8dbf40f7..2c813df3 100644 --- a/scaleout/stackn/templates/nginx-deployment.yaml +++ b/scaleout/stackn/templates/nginx-deployment.yaml @@ -25,6 +25,7 @@ spec: type: app pod: nginx-static spec: + automountServiceAccountToken: false volumes: - name: rp-conf configMap: diff --git a/scaleout/stackn/templates/role.yaml b/scaleout/stackn/templates/role.yaml new file mode 100644 index 00000000..9fcf4b98 --- /dev/null +++ b/scaleout/stackn/templates/role.yaml @@ -0,0 +1,18 @@ +{{- if .Values.rbac.create }} +kind: Role +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ printf "%s-chart-controller" (include "common.names.fullname" .) }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + - apiGroups: ["", "apps", "networking.k8s.io"] + resources: ["*"] + verbs: ["*"] +{{- end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/rolebinding.yaml b/scaleout/stackn/templates/rolebinding.yaml new file mode 100644 index 00000000..c9818226 --- /dev/null +++ b/scaleout/stackn/templates/rolebinding.yaml @@ -0,0 +1,20 @@ +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +kind: RoleBinding +metadata: + name: {{ printf "%s-chart-controller" (include "common.names.fullname" .) }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ printf "%s-chart-controller" (include "common.names.fullname" .) }} +subjects: +- kind: ServiceAccount + name: {{ include "common.names.fullname" .}} + namespace: {{ .Values.namespace }} \ No newline at end of file diff --git a/scaleout/stackn/templates/service-account.yaml b/scaleout/stackn/templates/service-account.yaml new file mode 100644 index 00000000..bbeb880e --- /dev/null +++ b/scaleout/stackn/templates/service-account.yaml @@ -0,0 +1,10 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.serviceAccount.automountServiceAccountToken }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} +metadata: + name: {{ include "common.names.fullname" .}} + namespace: {{ .Values.namespace | default .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/studio-admin-rolebinding.yaml b/scaleout/stackn/templates/studio-admin-rolebinding.yaml deleted file mode 100644 index ac9f8021..00000000 --- a/scaleout/stackn/templates/studio-admin-rolebinding.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: stackn-admin - namespace: {{ .Values.namespace }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: admin -subjects: -- kind: ServiceAccount - name: default - namespace: {{ .Values.namespace }} - diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 0a8beb9f..31a5240d 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -23,6 +23,7 @@ spec: app: stackn-studio allow-api-access: "true" spec: + automountServiceAccountToken: false securityContext: fsGroup: {{ .Values.studio.securityContext.fsGroup }} initContainers: diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index e270c7fc..84677708 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -27,6 +27,14 @@ global: namespace: default existingSecret: "" +serviceAccount: + create: true + automountServiceAccountToken: true +rbac: + create: true + +commonLabels: {} +commonAnnotations: {} networkPolicy: enable: false From c4bd972887e2d12d04b0a81a2556ab0cc3555cd4 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 3 Mar 2023 16:31:52 +0100 Subject: [PATCH 036/146] Add additionals to securityContext --- scaleout/stackn/templates/celery-flower-deployment.yaml | 5 +++++ scaleout/stackn/templates/studio-deployment.yaml | 5 +++++ scaleout/stackn/values.yaml | 2 ++ 3 files changed, 12 insertions(+) diff --git a/scaleout/stackn/templates/celery-flower-deployment.yaml b/scaleout/stackn/templates/celery-flower-deployment.yaml index 88b85ff4..1f77b9a2 100644 --- a/scaleout/stackn/templates/celery-flower-deployment.yaml +++ b/scaleout/stackn/templates/celery-flower-deployment.yaml @@ -34,6 +34,11 @@ spec: securityContext: runAsUser: {{ .Values.studio.securityContext.runAsUser }} runAsGroup: {{ .Values.studio.securityContext.runAsGroup }} + allowPrivilegeEscalation: {{ .Values.studio.securityContext.allowPrivilegeEscalation }} + privileged: {{ .Values.studio.securityContext.privileged }} + capabilities: + drop: + - all {{- end }} env: - name: BASE_PATH diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 31a5240d..4f3fb1a1 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -121,6 +121,11 @@ spec: securityContext: runAsUser: {{ .Values.studio.securityContext.runAsUser }} runAsGroup: {{ .Values.studio.securityContext.runAsGroup }} + allowPrivilegeEscalation: {{ .Values.studio.securityContext.allowPrivilegeEscalation }} + privileged: {{ .Values.studio.securityContext.privileged }} + capabilities: + drop: + - all {{- end }} {{- if .Values.studio.readinessProbe.enabled }} readinessProbe: diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 84677708..74b11ed5 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -95,6 +95,8 @@ studio: runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 + allowPrivilegeEscalation: false + privileged: false readinessProbe: enabled: true tcpSocket: From db3a9740cdbc5269733319ec265e45e9e6e6cc58 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 7 Mar 2023 14:16:18 +0100 Subject: [PATCH 037/146] Add autoscaling api to role --- scaleout/stackn/templates/role.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/role.yaml b/scaleout/stackn/templates/role.yaml index 9fcf4b98..4088f6c7 100644 --- a/scaleout/stackn/templates/role.yaml +++ b/scaleout/stackn/templates/role.yaml @@ -12,7 +12,7 @@ metadata: annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} {{- end }} rules: - - apiGroups: ["", "apps", "networking.k8s.io"] + - apiGroups: ["", "apps", "networking.k8s.io", "autoscaling"] resources: ["*"] verbs: ["*"] {{- end }} \ No newline at end of file From 3838a27cdda2705c50c0c81990ccd10c84704105 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 8 Mar 2023 17:55:38 +0100 Subject: [PATCH 038/146] network policies for lab and minio --- .../stackn/templates/network-policies.yaml | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml index 5b199068..4e3bdd55 100644 --- a/scaleout/stackn/templates/network-policies.yaml +++ b/scaleout/stackn/templates/network-policies.yaml @@ -81,7 +81,57 @@ spec: - podSelector: matchLabels: app: stackn-studio - +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-egress-to-studio-web + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + networking/allow-egress-to-studio-web: "true" + policyTypes: + - Egress + egress: + - to: + - podSelector: + matchLabels: + web: studio-web +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-ingress-from-project-to-studio-web + namespace: default +spec: + podSelector: + matchLabels: + web: studio-web + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: lab +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-egress-from-celery-worker-to-project + namespace: default +spec: + podSelector: + matchLabels: + name: {{ .Release.Name }}-celery-worker + policyTypes: + - Egress + egress: + - to: + - podSelector: + matchLabels: + app: mlflow --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy From 28801c31199b129f9900549d684ef9c41d4bd09e Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 14 Mar 2023 13:22:42 +0100 Subject: [PATCH 039/146] fix serve static and media via ngnix --- scaleout/stackn/templates/nginx-conf.yaml | 53 ++++--------------- .../stackn/templates/nginx-deployment.yaml | 8 +++ .../templates/studio-settings-configmap.yaml | 10 ++-- 3 files changed, 22 insertions(+), 49 deletions(-) diff --git a/scaleout/stackn/templates/nginx-conf.yaml b/scaleout/stackn/templates/nginx-conf.yaml index dee66d58..f18954c8 100644 --- a/scaleout/stackn/templates/nginx-conf.yaml +++ b/scaleout/stackn/templates/nginx-conf.yaml @@ -6,51 +6,16 @@ metadata: data: # Configuration values can be set as key-value properties nginx.conf: |- - user nginx; - worker_processes 1; - - error_log /var/log/nginx/error.log warn; - pid /var/run/nginx.pid; - - events { - worker_connections 1024; - } - + pid /tmp/nginx.pid; + worker_processes 4; + events { worker_connections 512; } http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - access_log /var/log/nginx/access.log main; - sendfile on; - #tcp_nopush on; - keepalive_timeout 65; - - #gzip on; - - upstream django { - server {{ .Release.Name }}-{{ .Values.studio.servicename }}:8080; - } - - map $http_upgrade $connection_upgrade { - default upgrade; - '' close; - } - + include /etc/nginx/mime.types; server { - listen 80 default_server; - listen [::]:80 default_server; - - server_name _; - client_max_body_size 0; - location / { - proxy_pass http://django; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - - - } + listen 8081; + client_max_body_size 0; + large_client_header_buffers 4 128k; + location / { + } } } diff --git a/scaleout/stackn/templates/nginx-deployment.yaml b/scaleout/stackn/templates/nginx-deployment.yaml index 2c813df3..f4b7d250 100644 --- a/scaleout/stackn/templates/nginx-deployment.yaml +++ b/scaleout/stackn/templates/nginx-deployment.yaml @@ -37,6 +37,14 @@ spec: - name: static image: {{ .Values.studio.static.image }} imagePullPolicy: {{ .Values.studio.static.pullPolicy }} + # securityContext: + # runAsUser: 101 + # runAsGroup: 101 + # allowPrivilegeEscalation: false + # privileged: false + # capabilities: + # drop: + # - all volumeMounts: - name: rp-conf mountPath: /etc/nginx/nginx.conf diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index b852e305..b650caca 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -48,7 +48,7 @@ data: if DEBUG: ALLOWED_HOSTS = ['*'] else: - ALLOWED_HOSTS = ['{{ .Values.domain }}'] + ALLOWED_HOSTS = ['{{ .Values.domain }}', '{{ .Release.Name }}-{{ .Values.studio.servicename }}'] EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' @@ -206,12 +206,12 @@ data: USE_TZ = True # Media Files for Studio apps - MEDIA_URL = {{ .Values.studio.media.mount_path | quote }} - MEDIA_ROOT = {{ .Values.studio.media.mount_path | quote }} + #MEDIA_URL = {{ .Values.studio.media.mount_path | quote }} + #MEDIA_ROOT = {{ .Values.studio.media.mount_path | quote }} #From studio - #MEDIA_URL = '/media/' - #MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') + MEDIA_URL = '/media/' + MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') # Related to user registration and authetication workflow LOGIN_REDIRECT_URL = '/projects' From 12e2fb475dda91ead651de53f69c3d5b02a7086f Mon Sep 17 00:00:00 2001 From: Niklas Date: Fri, 10 Mar 2023 17:02:10 +0100 Subject: [PATCH 040/146] Feature/SK-389 | Manage migration files for 0.7.0 --- .../stackn/templates/studio-settings-configmap.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index b650caca..508ea8cd 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -279,4 +279,12 @@ data: EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend" EMAIL_FILE_PATH = os.path.join(BASE_DIR, 'sent_emails') - VERSION = {{ .Values.studio.version | quote }} \ No newline at end of file + VERSION = {{ .Values.studio.version | quote }} + + MIGRATION_MODULES = { + 'apps': 'studio.migrations.apps', + 'models': 'studio.migrations.models', + 'monitor': 'studio.migrations.monitor', + 'portal': 'studio.migrations.portal', + 'projects': 'studio.migrations.projects' + } \ No newline at end of file From 77cf8930782f5aae888aeb5344e78ece8ca7dff8 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 16 Mar 2023 16:20:10 +0100 Subject: [PATCH 041/146] Add values for adding custom apps and migrations --- .../templates/studio-settings-configmap.yaml | 19 ++++++++++++++++++- scaleout/stackn/values.yaml | 13 +++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 508ea8cd..9c0ec6ea 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -80,6 +80,16 @@ data: "customtags", ] + {{ if .Values.studio.custom_apps.enabled }} + CUSTOM_APPS = [{{- range .Values.studio.custom_apps.apps }}{{. | quote }},{{- end }}] + INSTALLED_APPS = INSTALLED_APPS + CUSTOM_APPS + {{ end }} + + {{ if .Values.studio.auth_user_model.override }} + AUTH_USER_MODEL = {{ .Values.studio.auth_user_model.model | quote }} + {{ end }} + + MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -287,4 +297,11 @@ data: 'monitor': 'studio.migrations.monitor', 'portal': 'studio.migrations.portal', 'projects': 'studio.migrations.projects' - } \ No newline at end of file + } + + {{ if .Values.studio.custom_migrations.enabled }} + {{- range $key, $value := .Values.studio.custom_migrations.apps }} + MIGRATION_MODULES[{{$key | quote }}] = {{$value | quote }} + {{- end }} + {{- end }} + \ No newline at end of file diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 74b11ed5..8555715a 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -54,6 +54,19 @@ studio: debug: true init: true inactive_users: False + custom_apps: + enabled: false + apps: + - "control" + - "user" + custom_migrations: + enabled: false + apps: + user: "studio.migrations.user" + control: "studio.migrations.control" + auth_user_model: + override: false + model: "user.User" csrf_trusted_origins: kubeconfig_file: /app/kubeconfig/config kubeconfig_dir: /app/kubeconfig/ From db39fb08e69bf200c154609a9501169ada957184 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 20 Mar 2023 16:17:44 +0100 Subject: [PATCH 042/146] fix compability with studio --- .gitignore | 2 +- README.md | 6 ++++++ scaleout/stackn/templates/network-policies.yaml | 17 +++++++++++++++++ .../templates/studio-settings-configmap.yaml | 2 -- scaleout/stackn/values.yaml | 5 ++--- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 3c2ec14d..2d947efd 100644 --- a/.gitignore +++ b/.gitignore @@ -134,4 +134,4 @@ static/open-iconic/ repos/ #Other -values-local.yaml +values-local* diff --git a/README.md b/README.md index fdc8330b..74e42502 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,12 @@ This repository contains Helm charts maintained by Scaleout Systems AB. The repo **Note:** The main branch is now the new default branch. For getting the latest version of these charts please clone the main branch and not the master. +## TODO + +```bash +kubectl label namespace kube-system name=kube-system +``` + ## Getting started To be able to deploy Helm chrats from this repository you first need to add this repository as a source of charts. diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml index 4e3bdd55..83a66aa4 100644 --- a/scaleout/stackn/templates/network-policies.yaml +++ b/scaleout/stackn/templates/network-policies.yaml @@ -135,6 +135,23 @@ spec: --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy +metadata: + name: allow-egress-from-studio-web-to-project + namespace: default +spec: + podSelector: + matchLabels: + web: studio-web + policyTypes: + - Egress + egress: + - to: + - podSelector: + matchLabels: + app: fedn-reducer +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy metadata: name: allow-ingress-from-studio namespace: {{ .Values.namespace | default "default" }} diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 9c0ec6ea..61b9f54c 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -69,8 +69,6 @@ data: 'django_filters', 'tagulous', 'guardian', - 'crispy_forms', - 'common', "portal", "projects", "models", diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 8555715a..db5dfd15 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -55,10 +55,9 @@ studio: init: true inactive_users: False custom_apps: - enabled: false + enabled: true apps: - - "control" - - "user" + - "common" custom_migrations: enabled: false apps: From 6b69ffef19c36a006c3faa2c7a8d4db80ba46cc3 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 21 Mar 2023 16:06:43 +0100 Subject: [PATCH 043/146] add setting for resource limit --- .../templates/studio-settings-configmap.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 61b9f54c..6d99ead6 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -302,4 +302,23 @@ data: MIGRATION_MODULES[{{$key | quote }}] = {{$value | quote }} {{- end }} {{- end }} + + # Defines how many apps a user is allowed to create within one project + APPS_PER_USER_LIMIT = { + "vscode": 1, + "volumeK8s": 1, + "pytorch-serve": 1, + "tensorflow-serve": 1, + "mlflow-serve": 1, + "mlflow": 1, + "minio": 1, + "jupyter-lab": 1, + "mongo-express": 1, + "reducer": 2, + "docker-registry": 1, + "combiner": 2, + "mongodb": 1, + } + + PROJECTS_PER_USER_LIMIT = 3 \ No newline at end of file From 067dadeeaa288ec177ace4ceaeabf0866cdefd7c Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 21 Mar 2023 17:57:48 +0100 Subject: [PATCH 044/146] remove crispy forms setting --- scaleout/stackn/templates/studio-settings-configmap.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 6d99ead6..3265543a 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -29,9 +29,6 @@ data: # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - # Crispy Forms - CRISPY_TEMPLATE_PACK="bootstrap4" - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ From 29716c450e15689bd89ad5f240e4f892b2ddbb58 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 22 Mar 2023 14:49:01 +0100 Subject: [PATCH 045/146] namespace from values --- scaleout/stackn/templates/network-policies.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml index 83a66aa4..34905f88 100644 --- a/scaleout/stackn/templates/network-policies.yaml +++ b/scaleout/stackn/templates/network-policies.yaml @@ -103,7 +103,7 @@ apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-ingress-from-project-to-studio-web - namespace: default + namespace: {{ .Values.namespace | default "default" }} spec: podSelector: matchLabels: @@ -120,7 +120,7 @@ apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-from-celery-worker-to-project - namespace: default + namespace: {{ .Values.namespace | default "default" }} spec: podSelector: matchLabels: @@ -137,7 +137,7 @@ apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-from-studio-web-to-project - namespace: default + namespace: {{ .Values.namespace | default "default" }} spec: podSelector: matchLabels: From 700e78a152622e92b1602261add4b3aa0442c12c Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 22 Mar 2023 18:01:36 +0100 Subject: [PATCH 046/146] default values update --- scaleout/stackn/values.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index db5dfd15..3f2227c9 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -184,7 +184,7 @@ rabbitmq: commonAnnotations: {"reloader.stakater.com/auto": "true"} podLabels: {"app":"stackn-studio","allow-api-access": "true"} persistence: - enabled: false + enabled: true @@ -235,7 +235,8 @@ grafana: enabled: false reloader: - enabled: true + enabled: false namespace: default reloader: watchGlobally: false + fullnameOverride: stackn-studio From d16b30c6a5fd274eba494c09c69769511d877fb2 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 22 Mar 2023 18:09:27 +0100 Subject: [PATCH 047/146] remove fullnameoveride for reloader --- scaleout/stackn/values.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 3f2227c9..bcd42f2b 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -239,4 +239,3 @@ reloader: namespace: default reloader: watchGlobally: false - fullnameOverride: stackn-studio From fbd191660cc949995b3237262785daaad4b9f896 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 23 Mar 2023 17:28:55 +0100 Subject: [PATCH 048/146] add NP for reloader --- .../stackn/templates/network-policies.yaml | 21 +++++++++++++++++++ scaleout/stackn/values.yaml | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml index 34905f88..9e1d4627 100644 --- a/scaleout/stackn/templates/network-policies.yaml +++ b/scaleout/stackn/templates/network-policies.yaml @@ -65,6 +65,27 @@ spec: - protocol: TCP port: {{ .Values.networkPolicy.kubernetes.port }} --- +{{- if .Values.reloader.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: reloader-allow-api-access + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + app: {{ .Release.Name }}-reloader + policyTypes: + - Egress + egress: + - to: + - ipBlock: + cidr: {{ .Values.networkPolicy.kubernetes.cidr }} + ports: + - protocol: TCP + port: {{ .Values.networkPolicy.kubernetes.port }} +--- +{{- end }} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index bcd42f2b..0967cb7d 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -40,7 +40,7 @@ networkPolicy: enable: false kubernetes: cidr: # To get kubernetes api server endpoints run: $ kubectl get endpoints kubernetes - port: 6443 + port: 6443 internal_cidr: # in-cluster IpBlock cidr, used in allow-internet-[egress|ingress] policy, e.g: - 10.0.0.0/8 - 192.168.0.0/16 @@ -235,7 +235,7 @@ grafana: enabled: false reloader: - enabled: false + enabled: true namespace: default reloader: watchGlobally: false From 4cb8b43ebe8bc11911fbfcf077cf407448749a8d Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 23 Mar 2023 17:54:42 +0100 Subject: [PATCH 049/146] add ingress/egress rule for reloader --- .../stackn/templates/network-policies.yaml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml index 9e1d4627..c27fa567 100644 --- a/scaleout/stackn/templates/network-policies.yaml +++ b/scaleout/stackn/templates/network-policies.yaml @@ -85,6 +85,40 @@ spec: - protocol: TCP port: {{ .Values.networkPolicy.kubernetes.port }} --- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-egress-to-reloader + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + app: {{ .Release.Name }}-reloader + policyTypes: + - Egress + egress: + - to: + - podSelector: + matchLabels: + app: {{ .Release.Name }}-reloader +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-ingress-from-reloader + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + app: {{ .Release.Name }}-reloader + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: {{ .Release.Name }}-reloader +--- {{- end }} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy From b19d3a351df7e9e6e3dd3d30408fb7b64d9bc758 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 23 Mar 2023 21:18:39 +0100 Subject: [PATCH 050/146] update reloader version --- scaleout/stackn/charts/reloader-v0.0.86.tgz | Bin 4504 -> 0 bytes scaleout/stackn/charts/reloader-v1.0.15.tgz | Bin 0 -> 7246 bytes scaleout/stackn/requirements.yaml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 scaleout/stackn/charts/reloader-v0.0.86.tgz create mode 100644 scaleout/stackn/charts/reloader-v1.0.15.tgz diff --git a/scaleout/stackn/charts/reloader-v0.0.86.tgz b/scaleout/stackn/charts/reloader-v0.0.86.tgz deleted file mode 100644 index b3399b0ce505998287d00761020ce3f1dc6f8a88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4504 zcmV;J5ohiniwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PH<~ZyPtV{d+&fK<)wYp}Ug&vnQZHbE(@4dUcFAcZY|EhlbuA zNvyf#mgL%2U4QonlFR+2m9&l(r_G7~#3F|?!{KmdNDem=nIH+u;j1~3I$DsFeX;E_ z8jVILM@RPG(P-5EcYJho_{I2WbZ{~rpPn9^d@&jyoSvS10i&&R(ou4yiTq;pWLoXP z{YeVR=)X}aD)gOmLMPHu;394AqOxw!0g}y*+^ab>sXplKqAUIs-S137Z zRKZ-NIDxs=nVJlTGpgtLRTPVKs5H4I8s*R<3TSNbdQeGjBL|)cOo=kT ziBhQ5@D{IzUYkQHa-M|a(I~r%GCm8gad9hTq9#FD4j~BZ9H)eGO(;icfiNYMO<<0U ziElk=!$$zXi5c8wQCR^?qUMOnw#l*nTQ zEkJMtAt4nKL18RWD^q=ikSk2!c8(mfoH5F0KvOb9<&a36R(_#kC8A=Oh*%9ZQP*l1 z3qGZ@Tw<7sBs31g8u6jQ7+Q2;Cg}~)7)qQ`rR8F1@dx0jUF3{iI<_Y8zyB8m6)7{C zxlp>3jRdD8XF3S{5;D+Ky_7TYRxl=VgKtWhLRQDwx~I2a6I4_=8hC7>`PZXOv`8pPDvO9yD=?K%elOw7I)G9}t||3wKN0NfHC z&wsF!$QBdOGB>b$aEaRVHot*RVIgvulN$sAnMllh=920KWP;In;o<@0Q(;UnNF>P{ z&K7Tl(BD&rYN0e5OWtm{v<=lj8O}(&FaiaTS0t`lQp4sy$rUm+f%}I5Y6|P%xk&I5 z8OB;jSF;B(6L}KNgqSh3ZeVtep#jWX5ovZLO}=GUA`Ouow{<+ICpj!ACT#%nu&MfKSo z#@7Ef`!+}a4rQv^0HG7%*OKH-OQDcY zCdCakrU-nTQ#8z^$g>H=B8|$R%GmR%3A-FfGwwM(wbj-_dh9OHDkG>e;&QE;%&M5F zU?*qn!WxDNyq=y5eIZdH*M$Tw^DGlm!&FGXJ1q$yzoAlaGdplYBqdi2m76EzH=d6@ zFvb*=>#pEOT!8gQkP#|@sC9VkjPMGT^GJ_J2Cp^DtSg(N>!9F@7>8zdLby=gom$gU zhNqq$odV$t&yuUGn3_^#$#!_MTnIf!>98uZN-~jn(zbHq7t&>hF`X_zq6?#~HA1D; zkkOQCW#`IZPc|(hkD<1N9E!TRiL-nHgYjsT)>lP}sgP!^9gh!wqE(CMr3*thg7LxE z9zn&AUpkpcyu{lpD=P`cXPBh!P?z9wn=GW0z9uCucyF;289|3PYQ}am8JO=5Qm8>n3eHpu1rX1 zFi&&FY`YIbgUTKS&L9}(2!kmjGi&)XqLjD!<)H;~Ef<-f)&ww^tS zJ+qUMl57HlbYWtM%&cD%OO#E661rH=OQ5daz;)1af-PpY*q8d5waVk9L6r{?lm{+6 zU7=ydKHMT>UzwoS}u+zb6*+7 zbE4A1m|)7$M6R;H?RwkJHS%u?Pu*PZb(zo`n6V@8r$W5#t$3w11v($2@D#P2SLz( z7;d}W9D_53#u*f`r^PZSS%y6NGuf(L*?#G;|3A->Whhmov+W!O zZ?OLdr^jvke|&g)w6p)uQSR@De}x;GPHbd8r402V!*5a}mUxa6`0McDAuv$E*zl z;pEW%Nz==GI;D3o2nX;xFma2rM2bAIe>+ZJxy=PBX_@`Q0)EX2GuxvCNS4_#M8SX1 zQL*sa&@$suaD_23L8KBX!jI)ij~jWhktPz|p4Oi(Q3Wrq7Veno{L;W08?7>o_X`1a z%E#|+DjCsfDH7jUip9gM1Xw4xQeI3|n7*`wntaoLYJAU3Qm&^k_=^hvq6QGXMTSJ7 z>*>(;;-;9r)=YMY$_3?-)j8LnWZ4An@5`NGr(7d=cnEB#2@LM<8v}fJ2&gvDlj<`yGDGg*IJ-IZCR@tOez_@-;w`Wvvs#lyEY`B)nQ|?7ULN+lx`P&Jf%l ze2wlk4-(E-X<-%5G~lCR8*h4;t8l^qs-pY0G2LFF}ba>M8|0jo|-Tm*glwzG5$G)_N8drkwVyRtTkvJ+& zkoKW68t@`|MKW?l8Pyb3^z!0$VOLf3529dTJCa<_g`~gPbrM~FZEfPsc(CuRWtEn+ z4m!BMch=z%eXdZGak(@e9)fGilL@?XYX4R+4E#245;V^~4Y_5z*0Ja#_#G%ukZU*s zYqg@2+`!eNhU!i|%AZ*|^5$Ih5rUkFOp0IJ@CnQ2q$PxUKF4}FRH*t$Ko&T+I`DOK z)MGAGRYx!tTw$$BX`*qOv$FC@Ot0b;?=*5dK~Ld#Tk`zW-udH~_3_^o(Lq^;|PL|O~2hbFagl^lP)#4*5!E`zV1X&JP6{z#MAB^s~YV6PiC zj6iT)Y4`mYtK;d# zTlqeyb~@m4+}*w48d?_2UnEU>0c$d|H;GV`^1YEyitmM`%A&8v@hD^6m==2|wuUD1 z8+)3!zZuM(g7yHk_vQQW0)O4K$+T&x`}J|w^8U>Tq)l+LSIb|)mo6!O^37T)`VlRO zf(s2VFwOL$z|FD!z2W{Mlc{uf08OcKtw+6v<$n zLV;~a<$Ed8Nv+Z+$Nh+lVq;b>723Ka8dy!Sk8oBK?o16& zcWB-tWkILVb6Iwc>c@Zm{p{`e*}JpLpU+?Zbar|1^3~Z^hUH_ZsNC}Q7*&bRKAV{= zaXZ&KtC1|7!A13C!?!VdgB+E*km3sKd>R}-RBv?(dY0#5idxcGHJdE%24#sPq1#5j zc}lw)6#W)oolC%<|KW6|Sp!Ib;RdSo%cH8WLO;7?s0r+Jq1WVaUWRoZ7~3x`Ksz z*FlR^L+tD5w{JY#Jd}4Zp%$S7{-(GAeIm`qwP+u*aoORClq)sqpj#S?}8JuYb>|%KKg(UfC8_JqAsnuEB1gGFW1DX-Xb7f_8jTvhNz6%zKG{+l-T3 ziw?F;^^=({aBpAMM8@+~OuN=C2)rP&ZSL*9zEe>w-?sV5+A+x4Nl=hw(g}>uCv%ktLd|GudtNc_VK8bu^ue7z9LYeX@6b-`Z3qW_dD>l z=V;4UHXn4k^VHDI#a)fC*X~Nbqq2Oo>q=*=_Ft9uuq#FBxc}Q;;%`wl=Kmg#+V4M4 zcJF_lr_}O4Uf7e2^(O)QT^pv)D-UFs0Q?8KXxt?Lf4T(VT2Q&m1m0x=?=pcu$Fd^+ z+fL$dQ8woP9-OxGzYY#}@!zwQUHsP-|Lqch|A1lO^CSTO*JS>>(qaD#KDKuRu*v=( zkJ{h=KR!Gi?d<<^lnw9v+xE1~4lZ>2`BH7oQN> zf*aUm|BuE;?fC!nX!rfUXDJ&@SL-`38@z#!bXrK=e+>||zqW6%Eq{T3*$S-cUR}!_ zv@F4MJ0&lrNBgF(j-SLuc}5=NsakzLz4`y3;QDhhjn|4w%Q z|JO5>`uPuRIIgKa=N!dCqEPmurZ?jO?3>Oj%tY}`W`95gOXoVP&^CQbfu>>GKb}4G zOh3jRw)#}`o)EwHWRusA0hSI69@DwTsNXx3-w$_@^-?GdWsdT|Cn*p5GVVX`?E~@Z zbKgA}uXpa@Z(6J;>J(G^Y0#ab; q+e`cDU;95BR3EzyT+?pt@5-+1%C3Bd<^KZ!0RR6#)IaP1d;kDDc zVQyr3R8em|NM&qo0PKBxa~n7EVE*Q(=%W0qSbH8m^vv=uTdUY|;<6*DBxO@qshkYX zfFz=s!34la=F0l+S9lKQ!IwnI-Yn-2Tf{WF8;wSz0W^9Tjwy;T>%N{KCOT7;#NVv@ z>GgWOgS|cVf3Mf8{@<5>_xJXCJBPam{loq@z5dSO!Ol0(TRSHWPtFBm-}D|$tJ=8# zkOyVtUzl-1(*fM{TPVxCpPgQ(zu$^54;jgXDm*v(0-@9w5ECSTaGJ9aD~^{E_D!{O-T1#jagOEzs1?@;JWGYz^SI-&?JM zlx)p}a?!{}ghwckMN19I(;LhfiSPj0?baxd<65B`X%Z>nM{G>bX&lpBk{zL#V^w~d z;gnCvNO*1qy$Nm*gg%}NS%wa^CkDV(-gr+Tkn2z64mLQ?A z{=rr0EfV46N2R~9cDX)ZxooIg8@NCBRODlM#K~{8k2CUCtRG4s5JY)uh{EDcB8BlmNpb*p_bu=&f`;FMcbd&x z!Y4CZ3mgkKPjzg=;d?7yaF7G&tKTV&ie5LA!kFe!XH4lh#%f9%U*kXmW|YQGPXqa@ zWvU#dfJP&dN}+Lq(tjgkZBUlQ1V>8P6AW)$vpS~c@h6mIF}Ae9;VDWqmq!idvORz1 zgyHB-&PY1G2q!qorBQpQblVgkf5Ks|T&Yssa_cWKOL!F^&|P!%8skpcZjyAwP;g7xHD>KvZ2+3dsXz_7<4=SOu7R8!q(Z0?tCp{&gZ9ZN21rdf z;wLnfYBwl)+PwIMV>W<;{r%lNjm25(iwZiect!aLr@LaBp?W*&9J)DIzKU2dkBbqbPi6*UjiM{SuEx zIF!cjgc^Os`nAu3n)FmR7xvusfVQbt&KaXOM9yJgT}$&~%xInsAf!phdB4(M7*UoO zkecf$3)Kv4v1{MfIjzpg)o%qFm+OM^8qSnm9KgHL2^D7ybDRnzfr~uLC=+Tzz@G#| za`qyOrm}b71~DRy64(8N)0;w@$s}qX8JY1v!Wfx3_pWq4c_n z@7LoWemXsUfA!1x2Z`1|UF9sU(>{9h=H2DH)03kQSMN^Vo=W(mC?Zl(Q4H_W5rvps zV|X3sazO~v2ay6uF^+KL;TsVgN9*YdC44F-m}#tB8i$NVR^qC#5IB}YQ#uH`Ctj)f zGejxy42NViE#}V(B!8vV7lo5TrA!^k4o+_*r)uoLNII0aID(;md5xz)(ke>jLpWr% zLtUSp)??R<0R!BfM$q%ow4{sfiKiCu(kMTOzfUr{@Rg zX)u}E<*Ly~j@b^y4u96Z|TDeZKh)JnX%M>}fHANs?(R>9+V(6n3i@R%_6cnh;PIAb`JQW-csNi>L?QW#F? z4UXg#G|ENJWJ!z>$7-^49*ca9ZfMSA=^2eI9%~k)nrgWdZWmeHvSplbqswv*zr}I< z3MhkAF4-d`UG8`q(L9aH>R&7e%wpVVk=j4-^~i|8Q(0}qjLvQqwFb5gBpqAJ_!hVzZ5i349bW*ZW2vjc=^fPP$B5!{wY#A-Vi;VF!yP)^0oc4#@y6KU{#_ zhf~U98Bu$CmJ{Pq=pO07+odRP!RZLZG;2Oh2r0vqcMDMlb~)4?#&l>;2;R^zmotsx zt&1|!Nun(gbIr49qSqd~%H4t?Mhvq{dW}=LHXJ;?efL*UEf3d!ov=MsmMQ`*V zX8O%IbY}$}l5&CKSP!qM96h0Ne+4yrUT$C-#Z~r4t{{~fSmLE^)-}nts3hB8HQx=UFA4nsVm3al5>rOq~oGNMJwE?fY&f} zULm?A%T)Qbr6qf1IJ`0(>UQaO1zo*Wq9q*w3iWQ%HO86eVUF>q0epL%5AoH@2;qdL z9E;C|xBEGx(PuYNd`@YEKXZWu9_2B|V!QLdzIE8N!)Yb^+m%{gU0wa|dCnyxLzXhHmEZ+~aM692Wg-|KJUzn{9)h$=jTvwGh)c0`M z$fVLc4;vTKFLv0}JDlc8djP+AWdLpCN|itrunudgmV2{o+k5l7``gAT=>O%v_pSRc z-Ki@)Zu}PkekZ4w#}^&(Nvw;;qWJIr;b#1QsV7jYCIlagxRs9(YDf6vh|-TX8118r zG%URj+-bwd4qVE`8HyskRbPx9={h9REtOMogand4sPeIWvMqqSJLvpNPed+stbQ`l zaWvtxTN|}qVNulUn1ZMeT5K)b|wyVY7=40_R4mVrJ-c}4-4gM6>`x@6g=+jE~* z04gBVp6HJ9*e-+=rB|BCj7H`JWsC(ds$+HYERyy@FUb*v6O@jnPYAYwMK@6wm!hyt zP?q7e)B4iNzj>PM|J4M?8D_jAvh`dASYZEm_Ye0f_J4o(@Ni@QpX0f^>;4UHNHS0d z;Uf}b=~I25NU?+yJb=G-@9$d@s&)J+LuuqTGVMNsx)0E4DY(|%T_9}|Npa!+1roXq zfx;6wlhx5T&Q!3LwRwKjJbaex{xpPxUG*nPF7nZce1dk+hR+bwTg)6%oJQ(z&8ZH2 z2jpmt@;IKtpE-)vzL{Lmsy1|5zhX^A!3#-CwnwgTLzHt2oF*9FyTzl4v(gb?h+!R) zVz*BShnHq&>CMT7gjG>j84kCNfEwjvg9!>5k&zQg^)i8jnF%mYZcbh?FEG7OjT(Hv zeAn2T86&9}LHmDr@ISl_opXJ@uWM?wOL1d*uhNqZqS9Mf9i?-+KFYFzoHnifYLsgS z?(bWw(g50Wj`bRNe;*Vj=JFfd-?v*PSV3Vgx9l_gnNuOFwkDVnfyNamyHV%?qAaUK z^d=}pV;lv;>B7o0RXn2+pj40|j<#hqI!XnxG3;83mBK*_AY*uh*-G*30o-CT zo`?bTdp*0oVR2q!me_D9#bi0wUu}*x2Dn2J9gVWgTZI*&&+k&NSnp&Eypmu!1<}BQ zW;CYb>3bE9UGB08ZiEoJ*rq2boot6^&%|7D?;HuI^C;)My0lifMuRPQ_fI$oidj(A7D z>+ng}jP$@eZL5xXeQf6q$(ab|+Y7&mUwZEUrrG~9=N{?~!dk9_F7W^McJ`|4|AXCL zZ{zld3#<9Y6#m)w5~WRHK&>@$zN}Dxu2Qqjt7W? zjcLZ{A6gJ7&L(J;gX zFAjPh#_yx$*)+o4<>@(s4k=|3N&TsAW;=8YeiOfX@i32L)8`K{G5E$wZa&$Xc716l z=`Z}u_y30^jYv9vF^dneSNq38ieO6V8tv$G{*AvLN$HOL))~m=k^^dTTkAmyWM$moAdQ; zsj_5O8vhOU-@BQ+o@`(X@_+624{G~A{r=|s?^zz-Xi8^Y+ElIGMPS1E?cgjMQMaG{Ln=QxmRYVWfBvZ9mpWB^qAowEb-Cqw zV1v`mIA21|Ga6L~sgX#8mf`iM@lUcpgLF{-kW}!H1A~H%X_w5^L#w(;;ojK zrKsJIvSq=HG6z|WH<#|t+xpT8&~#ABqH$`^%m+&W3p7??EOyws0c|s;Erq2>u~xKW zMNeUc5r)$nwYT3i!YW|;pk@g`6|A)coK0o54KMMZi#9{l?VGuFz>}7jT29J=sW@2` z9rX%c=mcbg@8|Y~l}k;a%5lO;CZ-0{w%<)b(NQ)S%efff9#u~RX=Z9rjianq@WRUh zCL1(2+@xIffg&+6#f?INbx7qcqsgFjBSe#YkEdn_!hZ_1z9dRm<)b2*W)ojd*hXSD zo!kqPmTn25xomKAdf*yQB`S+`u7G8gFC*V(#3d2ShCEQhvqZkClIo;` w|VuSot z`56+EhQYp~EXW9!G?GoNdjHE0$LA-;k4(hpy@;l+W7A zY@eOJQT(o-)tRKelxR$WL#GmE4r**pgzy70or7~$q@1(w%9#67T-m=;v)?X{wtA+-l?YX<&m&dIytopbQeB@&zgMABPvf`} zp=$LKtrDq9Udkmq-y|qld;gcYc}fMSPZvsb9;Sv2rYjaw%!gfGmHw!$PKb7NorvUxeK+yCg+y%&Q95G+11J zl*dN^?I4KhI2fsy-!~ZzziPWes-zF|=vPBFt30?cqd?F=1AlKqI3G!~6xX>7+0a#Z zB;`VX8z>iXnjYyU@i*XlFkdr5Oq&@C?2$<$TTQ5%`6|km;IKXztBb&K%+Iq+OHQs0tsy*+V1b2ewwPs9%iGH(r}D;mL_!5L z4Ri=>BVQF%kK?QQ4X|09Nw@$>Ksnh-$VT33=$7Yh6}M)#=(vHMBRPj|dETUNI#xF( z#ZvJE+t6R~P|)$O-vtx&z54JBUNv$4!w{oDKY2^g*_jo#wIcQ7cuU1RtAVHP)(^KbpU<=pc^C~xp z;IRusy{aqi0;>J%H-vc~?1EV*Z4HVe`Yj_T<*c4%02kFK+uKx|9X}DFFU>7 z&i*F;^EsYbhPxpFr499mO02#9GG!4sdRDJmiXdGfc)-RpmGf3MnZ+i4{aV_LtudPK zFJjJ`$G^!n{w(p|z1_Y2di?k1{?GF~X8gZw98o6EwHx@gt2sqZ`i@R-tN-h|P$$8$-FDG9=vNqa0GYB=fq`0=`!;rc3ad`VrdI7;nk< za+RwF(wcDztPk~$?T4B4eVWR#o<0C<+Y`XH^BjjU+TKgJ+tzG|2z@uro&k@*K#rFxk1)WvQVmWp2D5B;giB4_|W%$y5 zuwYJ;N(ta+%=ngw2fGq;wPftJc0EhGFCl;Yddtp(ZFun*QL#E7Yz7An#2YCuMYocI zT-U7TC2!54y;l%(l>eYZlOKK6`y>~2A5EQN=-hIR_KOY?KZT!FIc<#L1CC#_6N-=%gP1~G*t$W~`1W;emMMHi0`ti37 zHz}mN1T&kwO`E(;o4ie%yiJ?DO`B(i|G%EZPv%+R|L^qrht>Vxot=&U|18hO|8MgD zHwmD=!exL<0JVnYz{65VZE{C#p1;`BF#nrRNv&@Oa8drpgM(i6`#(E7oBZ$3@+=X! z=iRgqD$}bw>D44&)TOY|}bNACAv2uTD>{&W}Hw9=$Oi zx2TjZ49S~=@G}e#_HY`OuX0Pj#XqfCmEntbC+|zV%7WF|RA`=t!(Weo`04cY{nan$ zA4-gR<*W1SBYhgSkKVj_clqx0iN(9?%~eH{y)bvYiQWd7R@&J>izSjhO}C_d|t?=8qXU6WI0%BZB_yPy7Dyo zXX{H?)Bo5Mm@dzSjY(>}^kRBSeSgYZgZU9mj0zgkcmS8L&vdYjil#U#0-e5&Ro86$ zZ$4PIhG}5&{@+e@|L<^bP4K+ zPP4g~bx)_OA*^>R4QLUTv!QMW$EF$SSjJrOub1cpkXkAMCL3y$k%-S%k1cGCqCqeqXuL~>C=v&2P` z3f;$DCYg=w`7e}Icv=2ZNn^#QzgSWsyZYslnFwZGFu~<(CABpdtbVzq!o!*`m{hQ@ z@sddevv;55Er}h8O7VJVJ>Nx>D&Z%)Y*Hb#(uI>s-LK%%Nrj_ly?9dXvf9lPvAK5g zjGnpk|J1k4bv*LAX)N&ndcB(ex7$BF*!X|X@od5AuP4Xn7ci2u!iX|>pARuhvB12g zUu{-~f8obl|8e1e`|U~=JWKrNZm)L#>tMIPiT`|-hv!7#(#PIfZYMxH(Us2u%Jc6BPJZuJdVFiM-`;MvOb6?=IUDy^ae9VBK)8Z86u7&pbJOK z!-Zcc@ly>G*S%j^54lAG;lKrnV+lqgy?RM0M0i9}9L;R~7n1oLjVJs#$%@a8JzSz2 c$8Ym&p3Sp){<_cq4*&rF|Kb~b+W^b}0D4p~ZU6uP literal 0 HcmV?d00001 diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index 320c66c9..c05c461a 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -26,7 +26,7 @@ dependencies: # condition: grafana.enabled - name: reloader - version: v0.0.86 + version: v1.0.15 repository: https://stakater.github.io/stakater-charts condition: reloader.enabled From f752647110855b01b94cf5c1ad87f6eb91e853c8 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 23 Mar 2023 21:21:58 +0100 Subject: [PATCH 051/146] merge default-deny-egress with allow dns --- scaleout/stackn/templates/network-policies.yaml | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml index c27fa567..0bbaa04f 100644 --- a/scaleout/stackn/templates/network-policies.yaml +++ b/scaleout/stackn/templates/network-policies.yaml @@ -10,24 +10,12 @@ spec: policyTypes: - Ingress --- - -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny-egress - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: {} - policyTypes: - - Egress ---- #Requires that kube-system namespace has label name: kube-system. To create label: # $ kubectl label namespace kube-system name=kube-system apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: - name: allow-dns-access + name: default-deny-egress namespace: {{ .Values.namespace | default "default" }} spec: podSelector: @@ -42,6 +30,8 @@ spec: ports: - protocol: UDP port: 53 + - protocol: TCP + port: 53 --- # Certain services (such as celery-workers) need to allow egress to k8s api-server # To get the IP and port (usually 6443) of the api-server: From 642ab93c24795cda20b3b82193d80a27ddf173f6 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 27 Mar 2023 19:34:25 +0200 Subject: [PATCH 052/146] remove media from workers + media mount to studio during debug --- scaleout/stackn/templates/studio-deployment.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 4f3fb1a1..c05c3a05 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -27,6 +27,7 @@ spec: securityContext: fsGroup: {{ .Values.studio.securityContext.fsGroup }} initContainers: + {{ if .Values.studio.debug }} - name: volume-permissions image: busybox command: ['sh', '-c', 'chown -R 1000 /app/media && chgrp -R 1000 /app/media'] @@ -37,6 +38,7 @@ spec: runAsUser: 0 runAsGroup: 0 runAsNonRoot: false + {{ end }} - name: wait-for-db image: postgres command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }} --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 2; done;'] @@ -51,6 +53,8 @@ spec: - args: - sh - scripts/run_web.sh + ports: + - containerPort: 8080 env: - name: DEBUG {{ if .Values.studio.debug }} @@ -108,8 +112,10 @@ spec: - mountPath: /app/studio/settings.py subPath: settings.py name: {{ .Release.Name}}-settings-configmap + {{ if .Values.studio.debug }} - name: mediavol mountPath: {{ .Values.studio.media.mount_path }} + {{ end }} resources: limits: cpu: {{ .Values.studio.resources.limits.cpu }} @@ -157,6 +163,8 @@ spec: items: - key: settings.py path: settings.py + {{ if .Values.studio.debug }} - name: mediavol persistentVolumeClaim: claimName: {{ .Release.Name }}-studio-media + {{ end }} \ No newline at end of file From f84bb63711376a841d83b05d95f4b43bde24feee Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 27 Mar 2023 19:36:23 +0200 Subject: [PATCH 053/146] allow host full dns name --- scaleout/stackn/templates/studio-settings-configmap.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 3265543a..ee8e09cb 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -45,7 +45,7 @@ data: if DEBUG: ALLOWED_HOSTS = ['*'] else: - ALLOWED_HOSTS = ['{{ .Values.domain }}', '{{ .Release.Name }}-{{ .Values.studio.servicename }}'] + ALLOWED_HOSTS = ['{{ .Values.domain }}', '{{ .Release.Name }}-{{ .Values.studio.servicename }}', '{{ .Release.Name }}-studio.{{ .Values.namespace | default "default" }}.svc.{{ .Values.cluster_domain | default "cluster.local"}}'] EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' From d2ba614dd4a8641bee8d2fc3ea3fab8a04ec290b Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 5 Apr 2023 15:50:02 +0200 Subject: [PATCH 054/146] add setting for kube api request timeout --- scaleout/stackn/templates/studio-settings-configmap.yaml | 1 + scaleout/stackn/values.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index ee8e09cb..8b9822a4 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -246,6 +246,7 @@ data: EXTERNAL_KUBECONF = True KUBECONFIG = {{ .Values.studio.kubeconfig_file | quote }} NAMESPACE = {{ .Values.namespace | default "default" | quote }} + KUBE_API_REQUEST_TIMEOUT = {{ .Values.studio.kube_api_request_timeout }} STORAGECLASS = {{ include "stackn.studio.storageclass" . | quote }} # App dependencies diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 0967cb7d..e69cf1fd 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -69,6 +69,7 @@ studio: csrf_trusted_origins: kubeconfig_file: /app/kubeconfig/config kubeconfig_dir: /app/kubeconfig/ + kube_api_request_timeout: 1 static: replicas: 1 image: ghcr.io/scaleoutsystems/stackn/studio:develop From b99d42a98400ab5e01091fd9fbd62fdbedf856b7 Mon Sep 17 00:00:00 2001 From: niklastheman Date: Wed, 12 Apr 2023 14:49:20 +0200 Subject: [PATCH 055/146] Feature/SK-417 | Start using mailgun for reset password (#98) * Added Django secret * Email service added * Added egress to studio app to enable emails to be sent --- scaleout/stackn/templates/basic-secrets.yaml | 6 +++++ .../templates/celery-flower-deployment.yaml | 20 +++++++++++++++++ .../stackn/templates/studio-deployment.yaml | 21 ++++++++++++++++++ .../templates/studio-settings-configmap.yaml | 22 ++++++++++++++----- scaleout/stackn/values.yaml | 14 ++++++++++++ 5 files changed, 78 insertions(+), 5 deletions(-) diff --git a/scaleout/stackn/templates/basic-secrets.yaml b/scaleout/stackn/templates/basic-secrets.yaml index c3f9a721..4e9a0fcd 100644 --- a/scaleout/stackn/templates/basic-secrets.yaml +++ b/scaleout/stackn/templates/basic-secrets.yaml @@ -10,4 +10,10 @@ type: Opaque data: studio-superuser-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-superuser-password" "providedValues" (list "global.studio.superuserPassword" "studio.superuserPassword") "context" $) }} rabbit-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "rabbit-password" "providedValues" (list "rabbit.password") "context" $) }} + django-secret-key: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "django-secret-key" "providedValues" (list "studio.djangoSecret") "length" 50 "strong" true "context" $) }} + {{ if .Values.studio.emailService.enabled }} + email-host-user: {{ .Values.studio.emailService.hostUser | b64enc }} + email-host-password: {{ .Values.studio.emailService.hostPassword | b64enc }} + email-api-key: {{ .Values.studio.emailService.apiKey | b64enc }} + {{ end }} {{- end -}} \ No newline at end of file diff --git a/scaleout/stackn/templates/celery-flower-deployment.yaml b/scaleout/stackn/templates/celery-flower-deployment.yaml index 1f77b9a2..deb10f9a 100644 --- a/scaleout/stackn/templates/celery-flower-deployment.yaml +++ b/scaleout/stackn/templates/celery-flower-deployment.yaml @@ -67,6 +67,26 @@ spec: - name: KUBECONFIG value: {{ .Values.studio.kubeconfig_file | quote }} {{- end }} + - name: DJANGO_SECRET + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: django-secret-key + - name: EMAIL_HOST_USER + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: email-host-user + - name: EMAIL_HOST_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: email-host-password + - name: EMAIL_API_KEY + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: email-api-key image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-celery-worker diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index c05c3a05..406a2d3f 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -22,6 +22,7 @@ spec: web: studio-web app: stackn-studio allow-api-access: "true" + networking/allow-internet-egress: "true" spec: automountServiceAccountToken: false securityContext: @@ -100,6 +101,26 @@ spec: - name: KUBECONFIG value: {{ .Values.studio.kubeconfig_file | quote }} {{- end }} + - name: DJANGO_SECRET + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: django-secret-key + - name: EMAIL_HOST_USER + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: email-host-user + - name: EMAIL_HOST_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: email-host-password + - name: EMAIL_API_KEY + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: email-api-key image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 8b9822a4..aaf4829c 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -33,7 +33,7 @@ data: # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! - SECRET_KEY = 'pyey3^@n)$id1tc3_g7xcb55n7ii1989jy#&%!yk^z(u1us4@*' + SECRET_KEY = os.environ["DJANGO_SECRET"] # SECURITY WARNING: don't run with debug turned on in production {{ if .Values.studio.debug }} @@ -47,8 +47,6 @@ data: else: ALLOWED_HOSTS = ['{{ .Values.domain }}', '{{ .Release.Name }}-{{ .Values.studio.servicename }}', '{{ .Release.Name }}-studio.{{ .Values.namespace | default "default" }}.svc.{{ .Values.cluster_domain | default "cluster.local"}}'] - EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' - # Application definition INSTALLED_APPS = [ @@ -282,9 +280,23 @@ data: CSRF_TRUSTED_ORIGINS = ['https://*{{ .Values.session_cookie_domain }}','https://*.127.0.0.1'] + [{{ .Values.studio.csrf_trusted_origins | quote}}] # Email + {{ if .Values.studio.emailService.enabled }} + EMAIL_HOST = {{ .Values.studio.emailService.host | quote}} + EMAIL_PORT = {{ .Values.studio.emailService.port }} + EMAIL_HOST_USER = os.environ["EMAIL_HOST_USER"] + EMAIL_HOST_PASSWORD = os.environ["EMAIL_HOST_PASSWORD"] + EMAIL_USE_TLS = True + + EMAIL_DOMAIN_NAME = {{ .Values.studio.emailService.domainName | quote}} + EMAIL_API_KEY = os.environ["EMAIL_API_KEY"] + EMAIL_MAILGUN_API = "https://api.mailgun.net/v3" + EMAIL_NOTIFY_ON_ACCOUNT_REGISTER_LIST = [{{- range .Values.studio.emailService.notifyOnAccountRegisterList }}{{. | quote }},{{- end }}] + DEFAULT_FROM_EMAIL = {{ .Values.studio.emailService.smtpEmailFrom | quote}} + {{ else }} EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend" EMAIL_FILE_PATH = os.path.join(BASE_DIR, 'sent_emails') - + {{ end }} + VERSION = {{ .Values.studio.version | quote }} MIGRATION_MODULES = { @@ -302,7 +314,7 @@ data: {{- end }} # Defines how many apps a user is allowed to create within one project - APPS_PER_USER_LIMIT = { + APPS_PER_PROJECT_LIMIT = { "vscode": 1, "volumeK8s": 1, "pytorch-serve": 1, diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index e69cf1fd..8d46e25f 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -122,6 +122,20 @@ studio: port: 8080 initialDelaySeconds: 20 periodSeconds: 20 + djangoSecret: '' + emailService: + enabled: false + host: '' + port: 587 + hostUser: '' + hostPassword: '' + smtpEmailFrom: '' + domainName: '' + apiKey: '' + notifyOnAccountRegisterList: + - '' + + #kubernetes config kubeconfig: "" From e9ad6d9d0776ac98220cbd29561da6f98d58bf17 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 13 Apr 2023 17:40:44 +0200 Subject: [PATCH 056/146] update postgres to latest version --- scaleout/stackn/charts/postgresql-11.6.14.tgz | Bin 56788 -> 0 bytes scaleout/stackn/charts/postgresql-12.2.7.tgz | Bin 0 -> 56233 bytes scaleout/stackn/requirements.yaml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 scaleout/stackn/charts/postgresql-11.6.14.tgz create mode 100644 scaleout/stackn/charts/postgresql-12.2.7.tgz diff --git a/scaleout/stackn/charts/postgresql-11.6.14.tgz b/scaleout/stackn/charts/postgresql-11.6.14.tgz deleted file mode 100644 index 4fe5253dd12c74d7e34e3d30a50e2cf79fe1a8d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56788 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%0APsFL(ZJM~RI0+ynJrFhwlC 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 z zf3iu`N(uF#e>09{?8BUw9=na5mtGIvI4?auik+AL>oma!NHG~RaC&^g951Hi3-Y<+ z;Q+ywDo4o|$D1&p1gQ0lP>IU6S&Nex`>YkJqMx)r zHAR^niGL3$8OOq;C>;YK8DJmu5Whvj;AlovJq70yW>m8`TY5_@T{Ex#V86; z&^v5 zGX7?mBjz|R5be-@(zj;jcCy*;n}jjAI8LnLU(Kd)lsV;BM)#bXYbKSU!a z-!#GL2oBICAv{$AiUyc*Iu+x^r!hJJOvXVD00Ck?#WEN=0LR3?k$WzxxE1ALK~w}j zA@M~p;>7#5NhPQCawnY4r z@F8TjCE;qmwX3#~gySxXpZ3oPzo3Yrh;J!=)CN3D8G@9;sRID!NWlWLIWbryWq5Mbg$tyc7ff@nY8_lhPJr@W`a)!f~gRw zudKCLMQ}98aNKYkjstxkG4=}yP#wF6vLqOhAk6@-X!0x1E>bW=t& zRaj*{3!fz@Kk}E~EXX!_gQhcE zys@C-c^lLRpwdjkuV1D7oTj~xAjO)SQQ65~H=Do*dq+`Eu(R{)lPizk@l23&j~&}~ z`(gKN+nptLZRh<6ZC$3`z4veB*qru-Md}mkir0k;r)WqRBysa;M)A&x(cr%VK$r9{xNMbKG|2s&#JK_@Q)10}qV2NVXvQ;{a*nt+bi_S%l~>v;su z$OMggh=NXc7won7+Pf-*p6nS^7~DbzWC$X{qdtx>8=@c$@dua>$2|$S2<6p4Op|fQ z$IK;tmk*Jv0oI*ez=xQD5&S}^L3Tu_r&9iy=&*KRlAU&c2%`aFVs#9$!ZO7B6e-Yi zOa=&?2%|t~Oeo~ai4AbSkL0lQ5#(bkNCg3so1v7K&--F<7~f_f|bktOSuC9hLC}taNY?G zkWgqC#zWXc9Q$%cNe_2OMr42@Bu4%gPL&@lR)8T&@LUTU(>it}lr=z9C&J2Ip0Szj zYNFsolZ1AiYN$bb&Z;cRmjr!EMgWSgDP1HHGHa5-`t;1%mGsz9gbdLZ2Yq3>U^E4o zu`y!vH>rGdJ&&}aG9N{dVj>KLu-ST~H0Wa24hUkRd1JE7e1y?d3}nhi+6x&c*FT-V zzXl%{S3d1_0o*CsP0b literal 0 HcmV?d00001 diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index c05c461a..2892f8b1 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -36,7 +36,7 @@ dependencies: # condition: postgresql-ha.enabled - name: postgresql - version: 11.6.14 + version: 12.2.7 repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled From f6ec71100c10d3e706f7263f96cf664f175eca08 Mon Sep 17 00:00:00 2001 From: Niklas Date: Thu, 13 Apr 2023 15:32:09 +0200 Subject: [PATCH 057/146] Added email endpoint to as option specified in values --- scaleout/stackn/templates/studio-settings-configmap.yaml | 2 +- scaleout/stackn/values.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index aaf4829c..d86ef1c5 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -289,7 +289,7 @@ data: EMAIL_DOMAIN_NAME = {{ .Values.studio.emailService.domainName | quote}} EMAIL_API_KEY = os.environ["EMAIL_API_KEY"] - EMAIL_MAILGUN_API = "https://api.mailgun.net/v3" + EMAIL_MAILGUN_API = {{ .Values.studio.emailService.apiEndpoint | quote}} EMAIL_NOTIFY_ON_ACCOUNT_REGISTER_LIST = [{{- range .Values.studio.emailService.notifyOnAccountRegisterList }}{{. | quote }},{{- end }}] DEFAULT_FROM_EMAIL = {{ .Values.studio.emailService.smtpEmailFrom | quote}} {{ else }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 8d46e25f..d85d9f2f 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -131,6 +131,7 @@ studio: hostPassword: '' smtpEmailFrom: '' domainName: '' + apiEndpoint: '' apiKey: '' notifyOnAccountRegisterList: - '' From 352b593cd8674ea70124cc0387edbf515b888a1b Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 14 Apr 2023 13:55:41 +0200 Subject: [PATCH 058/146] change strategy type to Recreate for nginx --- scaleout/stackn/templates/nginx-deployment.yaml | 2 ++ scaleout/stackn/values.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/scaleout/stackn/templates/nginx-deployment.yaml b/scaleout/stackn/templates/nginx-deployment.yaml index f4b7d250..7a7b22bc 100644 --- a/scaleout/stackn/templates/nginx-deployment.yaml +++ b/scaleout/stackn/templates/nginx-deployment.yaml @@ -13,6 +13,8 @@ spec: app: stackn-studio type: app pod: nginx-static + strategy: + type: {{ .Values.studio.static.strategy.type }} template: metadata: annotations: diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index d85d9f2f..5114d650 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -72,6 +72,8 @@ studio: kube_api_request_timeout: 1 static: replicas: 1 + strategy: + type: Recreate image: ghcr.io/scaleoutsystems/stackn/studio:develop pullPolicy: IfNotPresent resources: From 67a84f3a62405561787734d64ece5c443e37eddc Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 14 Apr 2023 15:19:50 +0200 Subject: [PATCH 059/146] strategy type for studio RollingUpdate --- scaleout/stackn/templates/studio-deployment.yaml | 2 +- scaleout/stackn/values.yaml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 406a2d3f..c6283fdb 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -10,7 +10,7 @@ metadata: spec: replicas: {{ .Values.studio.replicas }} strategy: - type: Recreate + type: {{ .Values.studio.strategy.type }} selector: matchLabels: name: {{ .Release.Name }}-studio diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 5114d650..a41ea9d4 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -51,6 +51,8 @@ networkPolicy: studio: servicename: studio replicas: 1 + strategy: + type: RollingUpdate debug: true init: true inactive_users: False From d8cb1354667d6e8d363a6acece58da78fdbe0589 Mon Sep 17 00:00:00 2001 From: Niklas Date: Fri, 14 Apr 2023 15:42:52 +0200 Subject: [PATCH 060/146] Added STUDIO_ACCESSMODE setting to django app --- scaleout/stackn/templates/studio-settings-configmap.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index d86ef1c5..29256fa7 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -331,4 +331,6 @@ data: } PROJECTS_PER_USER_LIMIT = 3 + + STUDIO_ACCESSMODE = os.environ.get("STUDIO_ACCESSMODE", "") \ No newline at end of file From 25f646f667a15186690b721c03d7d7eddca17b16 Mon Sep 17 00:00:00 2001 From: niklastheman Date: Mon, 17 Apr 2023 10:58:11 +0200 Subject: [PATCH 061/146] Added EMAIL_TEMPLATE_PROTOCOL setting (#99) --- scaleout/stackn/templates/studio-settings-configmap.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 29256fa7..f6ee1554 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -296,6 +296,7 @@ data: EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend" EMAIL_FILE_PATH = os.path.join(BASE_DIR, 'sent_emails') {{ end }} + EMAIL_TEMPLATE_PROTOCOL = "https" VERSION = {{ .Values.studio.version | quote }} From 53d3edfc6bb008e384338177590f7bc9bed7b54b Mon Sep 17 00:00:00 2001 From: niklastheman Date: Thu, 20 Apr 2023 15:39:08 +0200 Subject: [PATCH 062/146] Added Last-Modified header in the HTTP response for the static files (#100) --- scaleout/stackn/templates/nginx-conf.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scaleout/stackn/templates/nginx-conf.yaml b/scaleout/stackn/templates/nginx-conf.yaml index f18954c8..c7bf4483 100644 --- a/scaleout/stackn/templates/nginx-conf.yaml +++ b/scaleout/stackn/templates/nginx-conf.yaml @@ -16,6 +16,8 @@ data: client_max_body_size 0; large_client_header_buffers 4 128k; location / { + etag on; + expires max; } } } From 47ceaaa0f7065ce2ad5e48e2aa634617633052c8 Mon Sep 17 00:00:00 2001 From: Niklas Date: Mon, 24 Apr 2023 15:20:39 +0200 Subject: [PATCH 063/146] New network policy added --- scaleout/stackn/templates/network-policies.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml index 0bbaa04f..74e60027 100644 --- a/scaleout/stackn/templates/network-policies.yaml +++ b/scaleout/stackn/templates/network-policies.yaml @@ -197,6 +197,23 @@ spec: --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy +metadata: + name: allow-egress-from-studio-web-to-minio + namespace: {{ .Values.namespace | default "default" }} +spec: + podSelector: + matchLabels: + web: studio-web + policyTypes: + - Egress + egress: + - to: + - podSelector: + matchLabels: + app: minio +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy metadata: name: allow-ingress-from-studio namespace: {{ .Values.namespace | default "default" }} From 5bd06e1438b3888aded41c6148046cf099af91ba Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 20 Apr 2023 15:51:57 +0200 Subject: [PATCH 064/146] Update README --- scaleout/stackn/README.md | 235 ++++++++++++++++---------------------- 1 file changed, 98 insertions(+), 137 deletions(-) diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 0567bc37..7aadfdef 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -7,38 +7,42 @@ STACKn A Helm chart for deploying STACKn by Scaleout -Current chart version is 0.2.1 +Current chart version is 0.3.0 ## Chart Requirements | Repository | Name | Version | Optional | |------------|------|---------|----------| -| https://charts.bitnami.com/bitnami | postgresql | 11.6.14 | No -| https://charts.bitnami.com/bitnami | postgresql-ha | 9.2.0 | Yes -| https://grafana.github.io/helm-charts | grafana | 6.8.4 | Yes -| https://prometheus-community.github.io/helm-charts | prometheus | 13.8.0 | Yes -| https://stakater.github.io/stakater-charts | reloader | v0.0.86 | No - +| https://charts.bitnami.com/bitnami | postgresql | 12.2.7 | No +| https://charts.bitnami.com/bitnami | redis | 17.7.4 | No +| https://charts.bitnami.com/bitnami | rabbitmq | 11.9.1 | No +| https://charts.bitnami.com/bitnami | common | 2.0.4 | No +| https://stakater.github.io/stakater-charts | reloader | v1.0.15 | Yes + +## Notes +When using PVC's together with postgres, rabbitmq and and redis, credentials will to not sync if secrets are updated (for example if password values are left blank). If this happens, the solution +is to redeploy and delete previous created PVCs. To avoid the same problem again, either set password values or use existing secrets. The subcharts for postgres, rabbitmq and redis all come with a value +to set existing secret. Existing secrets is the recommended approch if are going to version control your values (GitOps) to avoid raw passwords in your version history. + +You can read more about the issue here: https://github.com/bitnami/charts/issues/2061 +Obs that stakater/reloader does not solve the issue. ## Configuration By default STACKn has been configured with a dns wildcard domain for localhost. To change this replace all occurences of studio.127.0.0.1.nip.io in values.yaml. -STACKn requires access to manipulate and create recourses in the k8s cluster. Thus, it needs the cluster config as a secret in ./templates/chart-controller-secret.yaml. - By default no StorageClassName is set and needs to provided in the values.yaml or by using `--set` argument. ### Quick deployment ```bash -# Generate k8s cluster config file - NOTE: we assume a k8s cluster is already installed and configured -cluster_config=$(cat ~/.kube/config | base64 | tr -d '\n') - # Deploy STACKn from this repository -helm install --set kubeconfig=$cluster_config --set global.postgresql.storageClass= stackn . +helm install --set global.postgresql.storageClass= studio . ``` All resources will by default be created in the Namescape "default". -STACKn studio will be avaliable at http://studio.127.0.0.1.nip.io +STACKn studio will be avaliable at https://studio.127.0.0.1.nip.io +Obs that you might have to make changes to your particular ingress controller (nginx is supported in this chart) to connect to the URL. +If the ingress does not work for any reason, you can try to port-forward the studio service port to your localhost. ## Deploy an SSL certificate @@ -47,132 +51,89 @@ For production you need a domain name with a wildcard SSL certificate. If your d kubectl create secret tls prod-ingress --cert fullchain.pem --key privkey.pem ``` -## Global values -Minimal requirement: `global.postgresql.storageClass` - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| global.studio.existingSecret | string | `""` | Use existing secret. See basic-secrets.yaml. | -| global.studio.storageClass | string | `""` | StorageClassName for PVC. Overrides `studio.storage.storageClass`. If `studio.storage.storageClass` is unset (default) will inherent from `global.postgresql.storageClass` | -| global.studio.superUser | string | `admin` | Django superUser. Obs will always be `admin` until fixed. | -| global.studio.superuserEmail | string | `'admin@test.com'` | Django superUser email. Obs will always be `admin@test.com` until fixed. | -| global.studio.superuserPassword | string | `""` | Django superUser password. If left empty, will generate. | -| global.postgresql.auth.username | string | `stackn` | Postgres user will be created | -| global.postgresql.auth.password | string | `""` | Postgres password for user above. If empty, will be generated and stored in secret `stackn-studio-postgres` | -| global.postgresql.auth.database | string | `stackn` | Postgres database will be created | -| global.postgresql.auth.postgresPassword | string | `""` | Postgres password for postgres user If empty, will be generated and stored in secret `stackn-studio-postgres` | -| global.postgresql.auth.existingSecret | string | `""` | will not create secret `stackn-studio-postgres`. Instead use existing secret for postgres| -| global.postgresql.storageClass | string | `""` | StorageClassName for PVC | - - - -## Values - -Minimal requirement: `kubeconfig` - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| celeryWorkers.replicas | int | `2` | | -| celeryWorkers.resources.limits.cpu | string | `"1000m"` | | -| celeryWorkers.resources.limits.memory | string | `"8Gi"` | | -| celeryWorkers.resources.requests.cpu | string | `"100m"` | | -| celeryWorkers.resources.requests.memory | string | `"1Gi"` | | -| chartcontroller.branch | string | `"develop"` | | -| chartcontroller.enabled | bool | `false` | | -| chartcontroller.image.pullPolicy | string | `"Always"` | | -| chartcontroller.image.repository | string | `"registry./chart-controller:develop"` | | -| kubeconfig | string | `""` | Encoded (base64) kubernetes config | -| docker-registry.enabled | bool | `false` | | -| docker-registry.ingress.enabled | bool | `true` | | -| docker-registry.ingress.hosts[0] | string | `"registry."` | | -| docker-registry.ingress.tls[0].hosts[0] | string | `"registry."` | | -| docker-registry.ingress.tls[0].secretName | string | `"prod-ingress"` | | -| docker-registry.persistence.accessMode | string | `"ReadWriteOnce"` | | -| docker-registry.persistence.enabled | bool | `true` | | -| docker-registry.persistence.size | string | `"2Gi"` | | -| docker-registry.persistence.storageClass | string | `"microk8s-hostpath"` | | -| domain | string | `studio.` | | -| auth_domain | string | `"stackn-studio.default.svc.cluster.local"` | | -| session_cookie_domain | string | `.` | | -| existingSecret | string | `""` | | -| fixtures | string | `""` | | -| grafana."grafana.ini".server.domain | string | `"grafana."` | | -| grafana."grafana.ini".server.root_url | string | `"%(protocol)s://%(domain)s/"` | | -| grafana."grafana.ini".server.serve_from_sub_path | bool | `true` | | -| grafana.enabled | bool | `false` | | -| grafana.ingress.enabled | bool | `true` | | -| grafana.ingress.hosts[0] | string | `"grafana."` | | -| grafana.ingress.path | string | `"/"` | | -| grafana.ingress.tls[0].hosts[0] | string | `"grafana."` | | -| grafana.ingress.tls[0].secretName | string | `"prod-ingress"` | | -| grafana.persistence.enabled | bool | `true` | | -| grafana.persistence.size | string | `"2Gi"` | | -| grafana.persistence.storageClassName | string | `"microk8s-hostpath"` | | -| grafana.persistence.type | string | `"pvc"` | | -| imagePullSecrets[0].name | string | `"regcred"` | | -| ingress.annotations | object | `{}` | | -| ingress.enabled | bool | `true` | | -| ingress.hosts[0].host | string | `"studio."` | | -| ingress.image.pullPolicy | string | `"Always"` | | -| ingress.image.repository | string | `"scaleoutsystems/ingress:develop"` | | -| ingress.tls[0].hosts[0] | string | `"studio."` | | -| ingress.tls[0].secretName | string | `"prod-ingress"` | | -| namespace | string | `"default"` | | -| postgresql-ha.enabled | bool | `false` | | -| postgresql.enabled | bool | `true` | | -| postgresql.existingSecret | string | `""` | | -| postgresql.fullnameOverride | string | `"stackn-studio-postgres"` | | -| postgresql.persistence.accessModes[0] | string | `"ReadWriteMany"` | | -| postgresql.persistence.enabled | bool | `true` | | -| postgresql.persistence.size | string | `"20Gi"` | | -| postgresql.persistence.storageClass | string | `"microk8s-hostpath"` | | -| postgresql.postgresqlDatabase | string | `"stackn"` | | -| postgresql.postgresqlPassword | string | `""` | | -| postgresql.postgresqlUsername | string | `"stackn"` | | -| prometheus.enabled | bool | `false` | | -| prometheus.server.ingress.enabled | bool | `true` | | -| prometheus.server.ingress.hosts[0] | string | `"prometheus."` | | -| prometheus.server.ingress.tls[0].hosts[0] | string | `"prometheus."` | | -| prometheus.server.ingress.tls[0].secretName | string | `"prod-ingress"` | | -| prometheus.server.persistentVolume.size | string | `"2Gi"` | | -| prometheus.server.persistentVolume.storageClass | string | `"microk8s-hostpath"` | | -| rabbit.password | string | `""` | | -| rabbit.username | string | `"admin"` | | -| reloader.enabled | bool | `true` | | -| reloader.namespace | string | `"default"` | | -| reloader.reloader.watchGlobally | bool | `false` | | -| service.type | string | `"ClusterIP"` | | -| storageClassName | string | `"microk8s-hostpath"` | | -| studio.debug | bool | `true` | | -| studio.init | bool | `true` | | -| studio.kubeconfig_file | string | `/app/chartcontroller/kubeconfig/config` | | -| studio.kubeconfig_dir | string | `/app/chartcontroller/kubeconfig/` | | -| studio.image.pullPolicy | string | `"Always"` | | -| studio.image.repository | string | `"ghcr.io/scaleoutsystems/stackn/studio:develop"` | | -| studio.media.storage.accessModes | string | `"ReadWriteMany"` | | -| studio.media.storage.size | string | `"5Gi"` | | -| studio.media.storage.storageClassName | string | `"microk8s-hostpath"` | | -| studio.replicas | int | `1` | | -| studio.resources.limits.cpu | string | `"1000m"` | | -| studio.resources.limits.memory | string | `"4Gi"` | | -| studio.resources.requests.cpu | string | `"400m"` | | -| studio.resources.requests.memory | string | `"2Gi"` | | -| studio.servicename | string | `"studio"` | | -| studio.static.image | string | `"ghcr.io/scaleoutsystems/stackn/ingress:develop"` | | -| studio.static.replicas | int | `1` | | -| studio.static.resources.limits.cpu | int | `1` | | -| studio.static.resources.limits.memory | string | `"512Mi"` | | -| studio.static.resources.requests.cpu | string | `"100m"` | | -| studio.static.resources.requests.memory | string | `"256Mi"` | | -| studio.storage.StorageClassName | string | `"microk8s-hostpath"` | | -| studio.storage.size | string | `"2Gi"` | | -| studio.superUser | string | `"admin"` | | -| studio.superuserEmail | string | `"admin@test.com"` | | -| studio.superuserPassword | string | `""` | | +This secret should be in the same namespace as studio deployment. + +## Enabling network policies +If networkPolicy.enable = true, you have to make sure the correct kubernetes endpoint IP is provided in networkPolicy.kubernetes.cidr, and the correct port networkPolicy.kubernetes.port. This is to enable access of some services to the kubernetes API server through a created Service Account. To get your cluster's kubernetes endpoint run: +``` +kubectl get endpoints kubernetes +``` +To allow for within-cluster DNS, the kube-system namespace need the label: +``` +kubectl label namespace kube-system name=kube-system +``` + +Further, for ingress resources you need to set networkPolicy.ingress_controller_namespace. If value can vary depending on your cluster configuration, but for NGINX ingress controller it's usually "ingress-nginx". + +## Example deployment +``` +global: + studio: + superuserPassword: adminstudio # Django superuser password, username is admin + postgresql: + auth: + username: studio + password: studiopostgrespass + postgresPassword: postgres + database: studio + storageClass: local-path + +namespace: default +networkPolicy: + enable: true + kubernetes: + cidr: 127.0.0.1/32 # To get kubernetes api server endpoints run: $ kubectl get endpoints kubernetes + port: 6443 + internal_cidr: # in-cluster IpBlock cidr, used in allow-internet-[egress|ingress] policy, e.g: + - 10.0.0.0/8 + - 192.168.0.0/16 + - 172.0.0.0/20 + +studio: + debug: false + inactive_users: false #Users that sign-up can be inactive by default if desired + csrf_trusted_origins: "https://studio.127.0.0.1.nip.io:8082" #extra trusted origin for django server, for example if you port-forward to port 8082 + image: # using a local image registry with hostname k3d-registry + repository: k3d-registry:35187/stackn:develop #This image can be built from Dockerfile (https://github.com/scaleoutsystems/stackn) + pullPolicy: Always # used to ensure that each time we redeploy always pull the latest image + static: + image: k3d-registry:35187/stackn-nginx:develop #This image can be built from Dockerfile.nginx (https://github.com/scaleoutsystems/stackn) + media: + storage: + accessModes: ReadWriteOnce + +accessmode: ReadWriteOnce + +# Postgres deploy with a single-pod database: +postgresql: + primary: + persistence: + size: "2Gi" + accessModes: + - ReadWriteOnce + storageClass: local-path + +rabbit: + password: rabbitmqpass + +redis: + master: + persistence: + enabled: false + replica: + persistence: + enabled: false + +celeryFlower: + enabled: false + +reloader: + enabled: true +``` + ## Maintainers | Name | Email | Url | | ---- | ------ | --- | -| Morgan Ekmefjord | morgan@scaleoutsystems.com | | | Fredrik Wrede | fredrik@scaleoutsystems.com | | From c05a1a809273f823dadb69c76c439f780a6b595f Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 20 Apr 2023 16:04:30 +0200 Subject: [PATCH 065/146] update main README and chart version --- README.md | 5 ----- scaleout/stackn/Chart.yaml | 4 +--- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/README.md b/README.md index 74e42502..7e21d2b4 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,6 @@ This repository contains Helm charts maintained by Scaleout Systems AB. The repo **Note:** The main branch is now the new default branch. For getting the latest version of these charts please clone the main branch and not the master. -## TODO - -```bash -kubectl label namespace kube-system name=kube-system -``` ## Getting started To be able to deploy Helm chrats from this repository you first need to add this repository as a source of charts. diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index d284c51d..061d2cea 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -1,10 +1,8 @@ apiVersion: v1 -appVersion: "0.6.0" +appVersion: "0.7.0" description: A Helm chart for deploying studio name: studio version: 0.3.0 maintainers: - - email: morgan@scaleoutsystems.com - name: Morgan Ekmefjord - email: fredrik@scaleoutsystems.com name: Fredrik Wrede From e8e8e4c8c1a614a09a5e929dbfc63401e8072c4e Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 20 Apr 2023 16:09:36 +0200 Subject: [PATCH 066/146] fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e21d2b4..8dece4ff 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This repository contains Helm charts maintained by Scaleout Systems AB. The repo ## Getting started -To be able to deploy Helm chrats from this repository you first need to add this repository as a source of charts. +To be able to deploy Helm charts from this repository you first need to add this repository as a source of charts. ```bash $ helm repo add scaleout https://scaleoutsystems.github.io/charts/scaleout/stackn From 0b23ac72e24ce69e4b8257c4f5d79d8a80f5ee1a Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 28 Apr 2023 14:50:24 +0200 Subject: [PATCH 067/146] add enable_project_extra_settings --- scaleout/stackn/templates/studio-settings-configmap.yaml | 6 +++++- scaleout/stackn/values.yaml | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index f6ee1554..1bbae3d7 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -334,4 +334,8 @@ data: PROJECTS_PER_USER_LIMIT = 3 STUDIO_ACCESSMODE = os.environ.get("STUDIO_ACCESSMODE", "") - \ No newline at end of file + {{ if .Values.studio.enable_project_extra_settings }} + ENABLE_PROJECT_EXTRA_SETTINGS = True + {{ else }} + ENABLE_PROJECT_EXTRA_SETTINGS = False + {{ end }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index a41ea9d4..196b4bad 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -55,6 +55,7 @@ studio: type: RollingUpdate debug: true init: true + enable_project_extra_settings: false inactive_users: False custom_apps: enabled: true From 39e8b7801401664f8fdfbeba686db980a7969007 Mon Sep 17 00:00:00 2001 From: Niklas Date: Thu, 4 May 2023 15:19:46 +0200 Subject: [PATCH 068/146] DISABLED_APP_INSTANCE_FIELDS setting and values added --- scaleout/stackn/templates/studio-settings-configmap.yaml | 5 ++++- scaleout/stackn/values.yaml | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 1bbae3d7..51fcc09c 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -338,4 +338,7 @@ data: ENABLE_PROJECT_EXTRA_SETTINGS = True {{ else }} ENABLE_PROJECT_EXTRA_SETTINGS = False - {{ end }} + {{ end }} + {{ if .Values.studio.disabledAppInstanceFields.enabled }} + DISABLED_APP_INSTANCE_FIELDS = [{{- range .Values.studio.disabledAppInstanceFields.fields }}{{. | quote }},{{- end }}] + {{- end }} \ No newline at end of file diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 196b4bad..c3332866 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -140,6 +140,10 @@ studio: apiKey: '' notifyOnAccountRegisterList: - '' + disabledAppInstanceFields: + enabled: false + fields: + - '' From 6716cb8724db96e9afcd7d5859d6db5edf74244c Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 12 Jun 2023 15:25:26 +0200 Subject: [PATCH 069/146] Feature/SK-476 | Enable RWX accessmode for PVC in projects (#103) --- scaleout/stackn/templates/media-vol.yaml | 2 +- scaleout/stackn/templates/nginx-deployment.yaml | 2 +- scaleout/stackn/templates/studio-deployment.yaml | 6 ++++-- scaleout/stackn/values.yaml | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/scaleout/stackn/templates/media-vol.yaml b/scaleout/stackn/templates/media-vol.yaml index 579c60b6..f39274f8 100644 --- a/scaleout/stackn/templates/media-vol.yaml +++ b/scaleout/stackn/templates/media-vol.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: {{ .Release.Name }}-studio-media + name: {{ .Release.Name }}-{{ .Values.studio.media.storage.claimName }} annotations: "helm.sh/resource-policy": keep spec: diff --git a/scaleout/stackn/templates/nginx-deployment.yaml b/scaleout/stackn/templates/nginx-deployment.yaml index 7a7b22bc..3e25624b 100644 --- a/scaleout/stackn/templates/nginx-deployment.yaml +++ b/scaleout/stackn/templates/nginx-deployment.yaml @@ -34,7 +34,7 @@ spec: name: {{ .Release.Name }}-static-config - name: mediavol persistentVolumeClaim: - claimName: {{ .Release.Name }}-studio-media + claimName: {{ .Release.Name }}-{{ .Values.studio.media.storage.claimName }} containers: - name: static image: {{ .Values.studio.static.image }} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index c6283fdb..86abd74b 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -106,6 +106,7 @@ spec: secretKeyRef: name: {{ include "stackn.secretName" . }} key: django-secret-key + {{ if .Values.studio.emailService.enabled }} - name: EMAIL_HOST_USER valueFrom: secretKeyRef: @@ -121,6 +122,7 @@ spec: secretKeyRef: name: {{ include "stackn.secretName" . }} key: email-api-key + {{ end }} image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio @@ -187,5 +189,5 @@ spec: {{ if .Values.studio.debug }} - name: mediavol persistentVolumeClaim: - claimName: {{ .Release.Name }}-studio-media - {{ end }} \ No newline at end of file + claimName: {{ .Release.Name }}-{{ .Values.studio.media.storage.claimName }} + {{ end }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index c3332866..30e707fc 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -103,6 +103,7 @@ studio: storageClass: "" size: "5Gi" accessModes: ReadWriteMany + claimName: studio-media mount_path: /app/media/ superUser: admin superuserPassword: "" From f68daaeb76885d503c6446521848eca2a207d422 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 12 Jun 2023 17:19:30 +0200 Subject: [PATCH 070/146] Feature/SK-495 | Remove if debug for media mount in studio deployment manifest (#104) --- scaleout/stackn/templates/studio-deployment.yaml | 2 +- scaleout/stackn/values.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 86abd74b..accf452e 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -186,7 +186,7 @@ spec: items: - key: settings.py path: settings.py - {{ if .Values.studio.debug }} + {{ if .Values.studio.media.storage.mountStudio }} - name: mediavol persistentVolumeClaim: claimName: {{ .Release.Name }}-{{ .Values.studio.media.storage.claimName }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 30e707fc..1645e09a 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -104,6 +104,7 @@ studio: size: "5Gi" accessModes: ReadWriteMany claimName: studio-media + mountStudio: false mount_path: /app/media/ superUser: admin superuserPassword: "" From ebbe72fbf9f3569af6e3f94f31d13e3f44aab02e Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 12 Jun 2023 17:44:18 +0200 Subject: [PATCH 071/146] Feature/SK-495 | Fix to previous PR (#105) --- scaleout/stackn/templates/studio-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index accf452e..8a9b2c85 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -135,7 +135,7 @@ spec: - mountPath: /app/studio/settings.py subPath: settings.py name: {{ .Release.Name}}-settings-configmap - {{ if .Values.studio.debug }} + {{ if .Values.studio.media.storage.mountStudio }} - name: mediavol mountPath: {{ .Values.studio.media.mount_path }} {{ end }} From 8d0d0e9a744422ea4a5fb096191f15b261063d07 Mon Sep 17 00:00:00 2001 From: Niklas Date: Wed, 14 Jun 2023 15:47:27 +0200 Subject: [PATCH 072/146] volumeK8s: 5 (#102) --- scaleout/stackn/templates/studio-settings-configmap.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 51fcc09c..8ea1f381 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -317,7 +317,7 @@ data: # Defines how many apps a user is allowed to create within one project APPS_PER_PROJECT_LIMIT = { "vscode": 1, - "volumeK8s": 1, + "volumeK8s": 5, "pytorch-serve": 1, "tensorflow-serve": 1, "mlflow-serve": 1, From dd34b5d788010ab5bc82af935898c0517652b7a5 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 2 Nov 2023 14:33:25 +0100 Subject: [PATCH 073/146] changes related to studio upcoming v0.8.0 --- scaleout/stackn/templates/network-policies.yaml | 4 ++-- scaleout/stackn/templates/studio-settings-configmap.yaml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml index 74e60027..064c5606 100644 --- a/scaleout/stackn/templates/network-policies.yaml +++ b/scaleout/stackn/templates/network-policies.yaml @@ -193,7 +193,7 @@ spec: - to: - podSelector: matchLabels: - app: fedn-reducer + app: fedn-api-server --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy @@ -285,4 +285,4 @@ spec: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: {{ .Values.networkPolicy.ingress_controller_namespace }} # <- This should allow traffic from ingress namespace -{{- end }} \ No newline at end of file +{{- end }} diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 8ea1f381..60ef621c 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -341,4 +341,5 @@ data: {{ end }} {{ if .Values.studio.disabledAppInstanceFields.enabled }} DISABLED_APP_INSTANCE_FIELDS = [{{- range .Values.studio.disabledAppInstanceFields.fields }}{{. | quote }},{{- end }}] - {{- end }} \ No newline at end of file + {{- end }} + FEDN_LOCAL_CONTROLLER = os.environ.get("FEDN_LOCAL_CONTROLLER", None) \ No newline at end of file From c1cb69f97bf47c3665431cbe71114b0eef071835 Mon Sep 17 00:00:00 2001 From: Niklas Date: Wed, 8 Nov 2023 14:08:10 +0100 Subject: [PATCH 074/146] grpc domain added --- scaleout/stackn/templates/studio-settings-configmap.yaml | 1 + scaleout/stackn/values.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 60ef621c..063135eb 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -272,6 +272,7 @@ data: 'Waiting', 'Installing', 'Created'] DOMAIN = {{ .Values.domain | quote }} + GRPC_DOMAIN = {{ .Values.grpc_domain | quote }} AUTH_DOMAIN = '{{ .Release.Name }}-studio.{{ .Values.namespace | default "default" }}.svc.{{ .Values.cluster_domain | default "cluster.local"}}' AUTH_PROTOCOL = 'http' STUDIO_URL = 'http://{{ .Release.Name }}-studio:8080' diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 1645e09a..e61d209f 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -160,6 +160,7 @@ cluster_domain: cluster.local # Enable ingress if you want your to access the studio solution from a kubernetes host/localhost. domain: studio.127.0.0.1.nip.io +grpc_domain: grpc.studio.127.0.0.1.nip.io session_cookie_domain: .127.0.0.1.nip.io ingress: enabled: true From d03818144232b784307f0cbf244da6be4ca1f99e Mon Sep 17 00:00:00 2001 From: Niklas Date: Wed, 8 Nov 2023 14:39:34 +0100 Subject: [PATCH 075/146] grpc ingress added --- scaleout/stackn/templates/grpc-ingress.yaml | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 scaleout/stackn/templates/grpc-ingress.yaml diff --git a/scaleout/stackn/templates/grpc-ingress.yaml b/scaleout/stackn/templates/grpc-ingress.yaml new file mode 100644 index 00000000..c4c53d63 --- /dev/null +++ b/scaleout/stackn/templates/grpc-ingress.yaml @@ -0,0 +1,29 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-ingress + annotations: + nginx.ingress.kubernetes.io/auth-url: http://studio-studio.default.svc.cluster.local:8080/auth/ + nginx.ingress.kubernetes.io/configuration-snippet: | + if ($http_grpc_server) { grpc_pass grpc://$http_grpc_server.default.svc.cluster.local:80; } + nginx.ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/proxy-set-headers: X-Forwarded-Proto:$scheme + labels: + io.kompose.service: {{ .Release.Name }}-ingress +spec: + ingressClassName: nginx + tls: + - hosts: + - {{ .Values.grpc_domain }} + secretName: prod-ingress + rules: + - host: {{ .Values.grpc_domain }} + http: + paths: + - path: / + backend: + service: + name: {{ $.Release.Name }}-studio + port: + number: 8080 + pathType: Prefix \ No newline at end of file From b1332025fb47069d2c18499d3294ab541d284eca Mon Sep 17 00:00:00 2001 From: Niklas Date: Wed, 8 Nov 2023 16:09:40 +0100 Subject: [PATCH 076/146] grpc ingress name fix --- scaleout/stackn/templates/grpc-ingress.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/grpc-ingress.yaml b/scaleout/stackn/templates/grpc-ingress.yaml index c4c53d63..7b43298f 100644 --- a/scaleout/stackn/templates/grpc-ingress.yaml +++ b/scaleout/stackn/templates/grpc-ingress.yaml @@ -1,7 +1,7 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: {{ .Release.Name }}-ingress + name: {{ .Release.Name }}-grpc-ingress annotations: nginx.ingress.kubernetes.io/auth-url: http://studio-studio.default.svc.cluster.local:8080/auth/ nginx.ingress.kubernetes.io/configuration-snippet: | From 63f99801485fab2d51ba49cf4a14cc74815251a3 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 9 Nov 2023 14:11:04 +0100 Subject: [PATCH 077/146] add grpc timeouts --- scaleout/stackn/templates/grpc-ingress.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/grpc-ingress.yaml b/scaleout/stackn/templates/grpc-ingress.yaml index 7b43298f..1a4bb592 100644 --- a/scaleout/stackn/templates/grpc-ingress.yaml +++ b/scaleout/stackn/templates/grpc-ingress.yaml @@ -8,6 +8,9 @@ metadata: if ($http_grpc_server) { grpc_pass grpc://$http_grpc_server.default.svc.cluster.local:80; } nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-set-headers: X-Forwarded-Proto:$scheme + nginx.ingress.kubernetes.io/server-snippet: | + grpc_read_timeout 86400s; + grpc_send_timeout 86400s; labels: io.kompose.service: {{ .Release.Name }}-ingress spec: @@ -26,4 +29,4 @@ spec: name: {{ $.Release.Name }}-studio port: number: 8080 - pathType: Prefix \ No newline at end of file + pathType: Prefix From 5db2a32836f2c65450cfcead9b574b455380da55 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 10 Nov 2023 16:07:31 +0100 Subject: [PATCH 078/146] update label for kube-system namespace --- scaleout/stackn/templates/network-policies.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml index 064c5606..d5d9ab3e 100644 --- a/scaleout/stackn/templates/network-policies.yaml +++ b/scaleout/stackn/templates/network-policies.yaml @@ -10,8 +10,6 @@ spec: policyTypes: - Ingress --- -#Requires that kube-system namespace has label name: kube-system. To create label: -# $ kubectl label namespace kube-system name=kube-system apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: @@ -26,7 +24,7 @@ spec: - to: - namespaceSelector: matchLabels: - name: kube-system + kubernetes.io/metadata.name: kube-system ports: - protocol: UDP port: 53 From c039d5c5b0eac509c007a789ccb4011b10e2edf0 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 10 Nov 2023 16:20:39 +0100 Subject: [PATCH 079/146] merge 0.4.1-beta changes --- scaleout/stackn/Chart.yaml | 4 +- scaleout/stackn/README.md | 6 +- .../templates/celery-flower-deployment.yaml | 26 +- .../stackn/templates/nginx-deployment.yaml | 2 +- .../stackn/templates/studio-deployment.yaml | 3 +- .../templates/studio-settings-configmap.yaml | 2 +- scaleout/stackn/values.yaml | 295 ++++++++++-------- 7 files changed, 173 insertions(+), 165 deletions(-) diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index 061d2cea..b0b98dda 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v1 -appVersion: "0.7.0" +appVersion: "0.7.4" description: A Helm chart for deploying studio name: studio -version: 0.3.0 +version: 0.4.1-beta.1 maintainers: - email: fredrik@scaleoutsystems.com name: Fredrik Wrede diff --git a/scaleout/stackn/README.md b/scaleout/stackn/README.md index 7aadfdef..eba92632 100644 --- a/scaleout/stackn/README.md +++ b/scaleout/stackn/README.md @@ -7,7 +7,7 @@ STACKn A Helm chart for deploying STACKn by Scaleout -Current chart version is 0.3.0 +Current chart version is 0.4.1 ## Chart Requirements @@ -58,10 +58,6 @@ If networkPolicy.enable = true, you have to make sure the correct kubernetes end ``` kubectl get endpoints kubernetes ``` -To allow for within-cluster DNS, the kube-system namespace need the label: -``` -kubectl label namespace kube-system name=kube-system -``` Further, for ingress resources you need to set networkPolicy.ingress_controller_namespace. If value can vary depending on your cluster configuration, but for NGINX ingress controller it's usually "ingress-nginx". diff --git a/scaleout/stackn/templates/celery-flower-deployment.yaml b/scaleout/stackn/templates/celery-flower-deployment.yaml index deb10f9a..2cb6b661 100644 --- a/scaleout/stackn/templates/celery-flower-deployment.yaml +++ b/scaleout/stackn/templates/celery-flower-deployment.yaml @@ -63,30 +63,6 @@ spec: value: {{ include "stackn.rabbit.username" . }} - name: REDIS_HOST value: {{ .Release.Name }}-redis - {{- if .Values.chartcontroller.addSecret }} - - name: KUBECONFIG - value: {{ .Values.studio.kubeconfig_file | quote }} - {{- end }} - - name: DJANGO_SECRET - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: django-secret-key - - name: EMAIL_HOST_USER - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: email-host-user - - name: EMAIL_HOST_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: email-host-password - - name: EMAIL_API_KEY - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: email-api-key image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-celery-worker @@ -107,7 +83,7 @@ spec: subPath: settings.py name: {{ .Release.Name}}-settings-configmap imagePullSecrets: - - name: ghcrsecret + - name: {{ .Values.imagePullSecrets.name }} restartPolicy: Always volumes: {{- if .Values.chartcontroller.addSecret }} diff --git a/scaleout/stackn/templates/nginx-deployment.yaml b/scaleout/stackn/templates/nginx-deployment.yaml index 3e25624b..92d7e5fc 100644 --- a/scaleout/stackn/templates/nginx-deployment.yaml +++ b/scaleout/stackn/templates/nginx-deployment.yaml @@ -61,5 +61,5 @@ spec: cpu: {{ .Values.studio.static.resources.requests.cpu }} memory: {{ .Values.studio.static.resources.requests.memory }} imagePullSecrets: - - name: ghcrsecret + - name: {{ .Values.imagePullSecrets.name }} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 8a9b2c85..68e1ca21 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -171,8 +171,7 @@ spec: periodSeconds: {{ .Values.studio.livenessProbe.periodSeconds }} {{- end }} imagePullSecrets: - - name: ghcrsecret - + - name: {{ .Values.imagePullSecrets.name }} restartPolicy: Always volumes: {{- if .Values.chartcontroller.addSecret }} diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 063135eb..4dfb82dd 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -242,7 +242,7 @@ data: # Other Helm/k8s deployment settings CHART_FOLDER = "/app/charts/apps" EXTERNAL_KUBECONF = True - KUBECONFIG = {{ .Values.studio.kubeconfig_file | quote }} + KUBECONFIG = "/app/kubeconfig/config" # Deprecated, uses ServiceAccount instead NAMESPACE = {{ .Values.namespace | default "default" | quote }} KUBE_API_REQUEST_TIMEOUT = {{ .Values.studio.kube_api_request_timeout }} STORAGECLASS = {{ include "stackn.studio.storageclass" . | quote }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index e61d209f..c652f623 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -1,136 +1,137 @@ # This is a YAML-formatted file. # Declare variables to be passed into STACKn templates. -# REQUIREMENT: -# - set a storage class with ability to serve ReadWriteMany -# Name: storageClassName, and/or set anchor &śtorage_class -# Description: Set a storage class for the resources that are reused for multi-mount-points in cluster. To reduce wasteful copying we allow to use the same dataset volume to be mounted multiple times. -# Default: microk8s-hostpath, use nfs-client for docker-for-desktop +# NOTES: +# - set a storage class everywhere you can see storageClass: "" +# - if you want to use an existing secret, set the name of the secret everywhere you see existingSecret: "" +# furthermore, the Bitnami subcharts (postgresql, redis, rabbitmq) also usually have a existingSecret value +# - Bitnami subcharts (postgresql, redis, rabbitmq) also usually have existingStorage values +# - if NetworkPolicy is enabled, set the kubernetes api server endpoints and port +# - Please set all values named password, the chart do have features to generate passwords, +# but this is not always working as expected during upgrades. +# - Please do not change values with "Do not change unless you know what you are doing." #Set global values to overide default global: studio: - superUser: "" ##these are currently not handled by stackn: default: admin - superuserPassword: "" - superuserEmail: "" ##these are currently not handled by stackn: default: admin@test.com - existingSecret: "" - storageClass: "" - postgresql: + superUser: "" # these are currently not handled by stackn: default: admin + superuserPassword: "" # password for Django superuser + superuserEmail: "" # these are currently not handled by stackn: default: admin@test.com + existingSecret: "" # name of existing secret containing superuserPassword and superuserEmail (optional) + storageClass: "" # storage class for persistent storage + postgresql: # global postgresql chart values auth: - username: studio - password: "" - postgresPassword: "" - database: studio - existingSecret: "" + username: studio # username for postgresql + password: "" # password for postgresql + postgresPassword: "" # password for postgresql + database: studio # database name for postgresql + existingSecret: "" # name of existing secret containing postgresPassword (optional) storageClass: -namespace: default -existingSecret: "" -serviceAccount: - create: true - automountServiceAccountToken: true -rbac: - create: true +namespace: default # namespace to deploy stackn in +existingSecret: "" # name of existing secret, should replace basic-secrets.yaml +serviceAccount: # service account for stackn + create: true # create service account + automountServiceAccountToken: true # automount service account token +rbac: # rbac for stackn + create: true # create rbac -commonLabels: {} -commonAnnotations: {} +commonLabels: {} # common labels for stackn +commonAnnotations: {} # common annotations for stackn -networkPolicy: - enable: false - kubernetes: +networkPolicy: # network policy for stackn + enable: false # enable network policy + kubernetes: cidr: # To get kubernetes api server endpoints run: $ kubectl get endpoints kubernetes - port: 6443 + port: 6443 # port for kubernetes api server internal_cidr: # in-cluster IpBlock cidr, used in allow-internet-[egress|ingress] policy, e.g: - 10.0.0.0/8 - 192.168.0.0/16 - 172.0.0.0/20 - ingress_controller_namespace: kube-system + ingress_controller_namespace: kube-system # namespace for ingress controller -studio: - servicename: studio - replicas: 1 - strategy: - type: RollingUpdate - debug: true - init: true - enable_project_extra_settings: false - inactive_users: False - custom_apps: +studio: # studio values + servicename: studio # name of studio service + replicas: 1 # number of studio replicas + strategy: # strategy for studio + type: RollingUpdate # type of strategy + debug: true # debug mode for studio Django server + init: true # init studio script (deprecated) + enable_project_extra_settings: false # enable project extra settings. Do not change unless you know what you are doing. + inactive_users: False # inactive users by default. When set to True, users will be inactive by default and need to be activated by an admin. + custom_apps: # custom apps for studio. Do not change unless you know what you are doing. enabled: true apps: - "common" - custom_migrations: + custom_migrations: # custom migrations for studio. Do not change unless you know what you are doing. enabled: false apps: user: "studio.migrations.user" control: "studio.migrations.control" - auth_user_model: + auth_user_model: # auth user model for studio. Do not change unless you know what you are doing. override: false model: "user.User" - csrf_trusted_origins: - kubeconfig_file: /app/kubeconfig/config - kubeconfig_dir: /app/kubeconfig/ - kube_api_request_timeout: 1 - static: - replicas: 1 - strategy: - type: Recreate - image: ghcr.io/scaleoutsystems/stackn/studio:develop - pullPolicy: IfNotPresent - resources: - limits: - cpu: 1 - memory: "512Mi" - requests: - cpu: "100m" - memory: "256Mi" + csrf_trusted_origins: # csrf trusted origins for studio. Add extra trusted origins for CSRF protection. + kube_api_request_timeout: 1 # timeout for kubernetes api requests, such as request to create/delete resources + static: # static values for studio, ngnix server for serving static files and media files + replicas: 1 # number of static replicas + strategy: # strategy for static + type: Recreate # type of strategy + image: ghcr.io/scaleoutsystems/stackn/studio:develop # image for static + pullPolicy: IfNotPresent # pull policy for static + resources: # resources for static + limits: # limits for static + cpu: 1 # cpu limit for static + memory: "512Mi" # memory limit for static + requests: # requests for static + cpu: "100m" # cpu request for static + memory: "256Mi" # memory request for static image: #tell which image to deploy for studio repository: ghcr.io/scaleoutsystems/stackn/ingress:develop #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image - resources: - limits: - cpu: "1000m" - memory: "4Gi" - requests: - cpu: "400m" - memory: "2Gi" - storage: - storageClass: "" - media: - storage: - storageClass: "" - size: "5Gi" - accessModes: ReadWriteMany - claimName: studio-media - mountStudio: false - mount_path: /app/media/ - superUser: admin - superuserPassword: "" - superuserEmail: admin@test.com - version: studio - securityContext: - enabled: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 + resources: # resources for studio + limits: # limits for studio + cpu: "1000m" # cpu limit for studio + memory: "1Gi" # memory limit for studio + requests: # requests for studio + cpu: "20m" # cpu request for studio + memory: "100Mi" # memory request for studio + storage: # storage for studio + storageClass: "" # storage class for studio + media: # media for studio + storage: # storage for media + storageClass: "" # storage class for media + size: "5Gi" # size for media + accessModes: ReadWriteMany # access modes for media + claimName: studio-media # claim name for media + mount_path: /app/media/ # mount path for media + superUser: admin # super user in Django admin for studio + superuserPassword: "" # password for Django superuser + superuserEmail: admin@test.com # email for Django superuser + version: studio # version for studio, this will show in the studio UI + securityContext: # security context for studio. Do not change unless you know what you are doing. + enabled: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 allowPrivilegeEscalation: false - privileged: false - readinessProbe: + privileged: false + readinessProbe: # readiness probe for studio. Do not change unless you know what you are doing. enabled: true tcpSocket: port: 8080 initialDelaySeconds: 20 periodSeconds: 10 - livenessProbe: + livenessProbe: # liveness probe for studio. Do not change unless you know what you are doing. enabled: true tcpSocket: port: 8080 initialDelaySeconds: 20 periodSeconds: 20 - djangoSecret: '' - emailService: + djangoSecret: '' # django secret for studio (optional, will be generated if not set) + emailService: # email service for studio. Please concact Scaleout if you want to use this feature. enabled: false host: '' port: 587 @@ -142,41 +143,56 @@ studio: apiKey: '' notifyOnAccountRegisterList: - '' - disabledAppInstanceFields: + disabledAppInstanceFields: # disabled app instance fields for studio. Do not change unless you know what you are doing. enabled: false fields: - '' + # Celery workers for studio +celeryWorkers: + replicas: 3 # number of celery workers, recommended to have at least 3 + resources: + requests: + cpu: "100m" + memory: "250Mi" + limits: + cpu: "1200m" + memory: "2Gi" +# Celery task UI for studio +celeryFlower: + enabled: false - -#kubernetes config -kubeconfig: "" +# Pull secrets for studio, used to pull images from private repositories such as Harbor +# To create a pull secret run: $ kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= +imagePullSecrets: + name: ghcrsecret -#storage access mode +#Genreal storage access mode accessmode: ReadWriteMany -#the cluster domain name (default usually cluster.local) +# the cluster domain name (default cluster.local) cluster_domain: cluster.local # Enable ingress if you want your to access the studio solution from a kubernetes host/localhost. domain: studio.127.0.0.1.nip.io -grpc_domain: grpc.studio.127.0.0.1.nip.io -session_cookie_domain: .127.0.0.1.nip.io +grpc_domain: grpc.studio.127.0.0.1.nip.io # domain for grpc servers (combiners in FL) +session_cookie_domain: .127.0.0.1.nip.io # domain for session cookie, should be .domain ingress: enabled: true annotations: {} hosts: - host: studio.127.0.0.1.nip.io - # setup TLS if you have a platform certificate or use 'tls-acme' if you have certbot deployed and want to generate a certificate. tls: - - secretName: prod-ingress + - secretName: prod-ingress # name of the secret containing the TLS certificate. Please contact Scaleout for details. hosts: - studio.127.0.0.1.nip.io ### A Postgres database for STACKn ### -# Here we use https://charts.bitnami.com/bitnami postgresql chart +# Here we use https://charts.bitnami.com/bitnami postgresql chart +# Please see the documentation for this Bitnami chart for more details on values: +# https://github.com/bitnami/charts/tree/main/bitnami/postgresql +# Please also observe the version we are using in requirements.yaml -# Postgres deploy with a single-pod database: postgresql: enabled: true fullnameOverride: studio-postgres @@ -196,16 +212,48 @@ postgresql: accessModes: - ReadWriteMany storageClass: - podLabels: {"app":"stackn-studio"} + podLabels: {"app":"stackn-studio"} # Do not change unless you know what you are doing. + resources: + requests: + cpu: "100m" + memory: "256Mi" + limits: + cpu: "1000m" + memory: "1Gi" + +## Redis chart for stateful caching ## +# Please see the documentation for this Bitnami chart for more details on values: +# https://github.com/bitnami/charts/tree/main/bitnami/redis +# Please also observe the version we are using in requirements.yaml redis: enabled: true - commonAnnotations: {"reloader.stakater.com/auto": "true"} + commonAnnotations: {"reloader.stakater.com/auto": "true"} # Required for reloader to work master: - podLabels: {"app":"stackn-studio"} + podLabels: {"app":"stackn-studio"} # Do not change unless you know what you are doing. + resources: + requests: + cpu: "100m" + memory: "256Mi" + limits: + cpu: "1000m" + memory: "1Gi" replica: replicaCount: 1 podLabels: {"app":"stackn-studio"} + resources: + requests: + cpu: "100m" + memory: "256Mi" + limits: + cpu: "1000m" + memory: "1Gi" + + +## RabbitMQ chart for messaging queue ## +# Please see the documentation for this Bitnami chart for more details on values: +# https://github.com/bitnami/charts/tree/main/bitnami/rabbitmq +# Please also observe the version we are using in requirements.yaml rabbitmq: enabled: true @@ -213,55 +261,44 @@ rabbitmq: podLabels: {"app":"stackn-studio","allow-api-access": "true"} persistence: enabled: true - - - -# Will be added in future realease, for now keep "enabled:false" -postgresql-ha: - enabled: false - -### DEPLOY SECRETS WITH private helm chart 'secrets' from platform/secrets -## Name: imagePullSecret -## Description: Secret to pull images from our private repository. -imagePullSecrets: - - name: regcred - -## to create a regcred -## kubectl create secret docker-registry regcred --docker-server= --docker-username= --docker-password= - -celeryWorkers: - replicas: 2 resources: requests: cpu: "100m" - memory: "1Gi" + memory: "256Mi" limits: cpu: "1000m" - memory: "8Gi" + memory: "1Gi" -celeryFlower: - enabled: true -# default credentials for rabbitmq. override in production! + +# Will be added in future realease, for now keep "enabled:false" +postgresql-ha: + enabled: false + +# default credentials for rabbitmq. Deprecated. Using Bitnamis chart for rabbitmq. Will be removed in future release. rabbit: image: rabbitmq:3-management username: admin password: "" +# Deprecated. Will be removed in future release. chartcontroller: enabled: false - #addSecret -- if true create chart-controller-secret from cluster_config, if false it must be added manually addSecret: false +# Deprecated. Will be removed in future release. docker-registry: enabled: false +# Deprecated. Will be removed in future release. Should be deployed seperatly in a different namespace. prometheus: enabled: false +# Deprecated. Will be removed in future release. Should be deployed seperatly in a different namespace. grafana: enabled: false +# Enable reloader for (see reloader.stakater.com) auto reload of deployments when configmaps change reloader: enabled: true namespace: default From 0a7996b1f7b357b4e7f7b7700399a095e0d583cf Mon Sep 17 00:00:00 2001 From: Niklas Date: Mon, 13 Nov 2023 11:19:15 +0100 Subject: [PATCH 080/146] limit reducer to 1 (#106) --- scaleout/stackn/templates/studio-settings-configmap.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 4dfb82dd..2f3dbbc6 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -326,7 +326,7 @@ data: "minio": 1, "jupyter-lab": 1, "mongo-express": 1, - "reducer": 2, + "reducer": 1, "docker-registry": 1, "combiner": 2, "mongodb": 1, From 0a1da6e4ffa5247328daac896e06e9b56bbff511 Mon Sep 17 00:00:00 2001 From: Niklas Date: Tue, 28 Nov 2023 10:29:07 +0100 Subject: [PATCH 081/146] updated config map to include new app systems (also including migrations). removed usage of customtags which no longer exists (#107) --- scaleout/stackn/templates/studio-settings-configmap.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 2f3dbbc6..466d121c 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -70,7 +70,7 @@ data: "monitor", "apps", "api", - "customtags", + "system", ] {{ if .Values.studio.custom_apps.enabled }} @@ -306,7 +306,8 @@ data: 'models': 'studio.migrations.models', 'monitor': 'studio.migrations.monitor', 'portal': 'studio.migrations.portal', - 'projects': 'studio.migrations.projects' + 'projects': 'studio.migrations.projects', + 'system': 'studio.migrations.system' } {{ if .Values.studio.custom_migrations.enabled }} From bd6466263a597f9967e28c1a8ade0e511d754af0 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 12 Dec 2023 17:24:52 +0100 Subject: [PATCH 082/146] add support for jwt --- .../stackn/templates/studio-deployment.yaml | 15 ++++++ .../templates/studio-settings-configmap.yaml | 47 +++++++++++++++++++ scaleout/stackn/values.yaml | 5 ++ 3 files changed, 67 insertions(+) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 68e1ca21..7618f169 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -69,6 +69,21 @@ spec: value: {{ include "stackn.studio.storageclass" . }} - name: STUDIO_ACCESSMODE value: {{ .Values.accessmode }} + {{ if .Values.studio.jwt_auth.enabled }} + - name: ENABLE_JWT + value: true + {{ end }} + {{ if .Values.studio.jwt_auth.existingSecret }} + - name: SIGNING_KEY + valueFrom: + secretKeyRef: + name: {{ Values.studio.jwt_auth.existingSecret }} + key: private_key + {{ end }} + {{ if .Values.studio.jwt_auth.public_key }} + - name: VERIFYING_KEY + value: {{ .Values.studio.jwt_auth.public_key | quote }} + {{ end }} - name: DJANGO_SUPERUSER value: {{ include "stackn.studio.superuser" . }} - name: DJANGO_SUPERUSER_EMAIL diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 466d121c..778b5952 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -26,6 +26,53 @@ data: 'guardian.backends.ObjectPermissionBackend', ] + # JWT settings + # https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html + # To generate a new key pair with RS256 algorithm: + # ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key + # openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub + ENABLE_JWT = os.environ.get("ENABLE_JWT", False) + if ENABLE_JWT: + SIMPLE_JWT = { + "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), + "REFRESH_TOKEN_LIFETIME": timedelta(days=1), + "ROTATE_REFRESH_TOKENS": False, + "BLACKLIST_AFTER_ROTATION": False, + "UPDATE_LAST_LOGIN": False, + + "ALGORITHM": {{ .Values.studio.jwt_auth.algorithm | quote }}, + "SIGNING_KEY": os.environ.get("SIGNING_KEY", ""), + "VERIFYING_KEY": os.environ.get("VERIFYING_KEY", ""), + "AUDIENCE": None, + "ISSUER": None, + "JSON_ENCODER": None, + "JWK_URL": None, + "LEEWAY": 0, + "AUTH_HEADER_TYPES": ("Bearer",), + "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION", + "USER_ID_FIELD": "id", + "USER_ID_CLAIM": "user_id", + "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule", + + "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",), + "TOKEN_TYPE_CLAIM": "token_type", + "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser", + + "JTI_CLAIM": "jti", + + "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp", + "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5), + "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1), + + "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer", + "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer", + "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer", + "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer", + "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer", + "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer", + } + + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index c652f623..1b4fe006 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -73,6 +73,11 @@ studio: # studio values auth_user_model: # auth user model for studio. Do not change unless you know what you are doing. override: false model: "user.User" + jwt_auth: # Use JWT authentication for REST and client authentication. Needs exsiting secret with private key. + enabled: false + algorithm: RS256 + public_key: "" # If algorithm is RS256, set RSA public key here + existingSecret: "" # name of existing secret containing private key, need "private_key" key csrf_trusted_origins: # csrf trusted origins for studio. Add extra trusted origins for CSRF protection. kube_api_request_timeout: 1 # timeout for kubernetes api requests, such as request to create/delete resources static: # static values for studio, ngnix server for serving static files and media files From 17882954066d6644e7a0ea3a4f25f83eca3905aa Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 12 Dec 2023 17:41:57 +0100 Subject: [PATCH 083/146] fix --- scaleout/stackn/templates/studio-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 7618f169..c6689c46 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -77,7 +77,7 @@ spec: - name: SIGNING_KEY valueFrom: secretKeyRef: - name: {{ Values.studio.jwt_auth.existingSecret }} + name: {{ .Values.studio.jwt_auth.existingSecret }} key: private_key {{ end }} {{ if .Values.studio.jwt_auth.public_key }} From 6445a7146d276bca39ba5d315878c78afffaad50 Mon Sep 17 00:00:00 2001 From: Niklas Date: Wed, 20 Dec 2023 14:09:53 +0100 Subject: [PATCH 084/146] discord settings added (#108) --- scaleout/stackn/templates/studio-settings-configmap.yaml | 6 +++++- scaleout/stackn/values.yaml | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 778b5952..f69d87c9 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -391,4 +391,8 @@ data: {{ if .Values.studio.disabledAppInstanceFields.enabled }} DISABLED_APP_INSTANCE_FIELDS = [{{- range .Values.studio.disabledAppInstanceFields.fields }}{{. | quote }},{{- end }}] {{- end }} - FEDN_LOCAL_CONTROLLER = os.environ.get("FEDN_LOCAL_CONTROLLER", None) \ No newline at end of file + FEDN_LOCAL_CONTROLLER = os.environ.get("FEDN_LOCAL_CONTROLLER", None) + + DISCORD_ALERT_ON_NEW_USER = {{ if .Values.studio.discord.alert_on_new_user }}True{{ else }}False{{ end }} + DISCORD_ALTERT_WEBHOOK_URL = {{ .Values.studio.discord.alert_webhook_url | quote }} + DISCORD_ALERT_ON_NEW_USER_MESSAGE = {{ .Values.studio.discord.alert_on_new_user_message | quote }} \ No newline at end of file diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 1b4fe006..7c166f31 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -152,6 +152,11 @@ studio: # studio values enabled: false fields: - '' + discord: + alert_on_new_user: false + alert_webhook_url: '' + alert_on_new_user_message: '' + # Celery workers for studio celeryWorkers: replicas: 3 # number of celery workers, recommended to have at least 3 From 0f7f88d0b1d8da61eabe241c8bc81dd9c47b5411 Mon Sep 17 00:00:00 2001 From: Niklas Date: Fri, 29 Dec 2023 18:08:19 +0100 Subject: [PATCH 085/146] =?UTF-8?q?Feature/SK-486=20|=C2=A0Implement=20kub?= =?UTF-8?q?ernetes=20event=20listener=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Event listener username and password (secret) added * Added event listener * Security context added to event listener deployment * Added security context to container * ContainerCreating added to warning statuses in config map * Initial app statuses synk endpoint added to values * updated eventlistener deployment --- scaleout/stackn/templates/basic-secrets.yaml | 1 + .../templates/event-listener-deployment.yaml | 77 +++++++++++++++++++ .../stackn/templates/studio-deployment.yaml | 7 ++ .../templates/studio-settings-configmap.yaml | 2 +- scaleout/stackn/values.yaml | 75 ++++++++++-------- 5 files changed, 130 insertions(+), 32 deletions(-) create mode 100644 scaleout/stackn/templates/event-listener-deployment.yaml diff --git a/scaleout/stackn/templates/basic-secrets.yaml b/scaleout/stackn/templates/basic-secrets.yaml index 4e9a0fcd..4321c9da 100644 --- a/scaleout/stackn/templates/basic-secrets.yaml +++ b/scaleout/stackn/templates/basic-secrets.yaml @@ -9,6 +9,7 @@ metadata: type: Opaque data: studio-superuser-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-superuser-password" "providedValues" (list "global.studio.superuserPassword" "studio.superuserPassword") "context" $) }} + studio-event-listener-user-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-event-listener-user-password" "providedValues" (list "global.studio.eventListenerUserPassword" "studio.eventListenerUserPassword") "context" $) }} rabbit-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "rabbit-password" "providedValues" (list "rabbit.password") "context" $) }} django-secret-key: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "django-secret-key" "providedValues" (list "studio.djangoSecret") "length" 50 "strong" true "context" $) }} {{ if .Values.studio.emailService.enabled }} diff --git a/scaleout/stackn/templates/event-listener-deployment.yaml b/scaleout/stackn/templates/event-listener-deployment.yaml new file mode 100644 index 00000000..add755f6 --- /dev/null +++ b/scaleout/stackn/templates/event-listener-deployment.yaml @@ -0,0 +1,77 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + name: studio-event-listener + name: studio-event-listener +spec: + replicas: 1 + strategy: + type: RollingUpdate + selector: + matchLabels: + name: studio-event-listener + template: + metadata: + labels: + name: studio-event-listener + app: stackn-studio + allow-api-access: "true" + spec: + automountServiceAccountToken: true + serviceAccountName: studio + imagePullSecrets: + - name: ghcrsecret + containers: + - image: {{ .Values.eventListener.image.repository }} + imagePullPolicy: {{ .Values.eventListener.image.pullPolicy }} + name: studio-event-listener + resources: + limits: + cpu: 100m + memory: 200Mi + requests: + cpu: 50m + memory: 20Mi + {{- if .Values.studio.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.studio.securityContext.runAsUser }} + runAsGroup: {{ .Values.studio.securityContext.runAsGroup }} + allowPrivilegeEscalation: {{ .Values.studio.securityContext.allowPrivilegeEscalation }} + privileged: {{ .Values.studio.securityContext.privileged }} + capabilities: + drop: + - all + {{- end }} + env: + - name: EVENT_LISTENER_USERNAME + value: {{ .Values.studio.eventListenerUsername | quote }} + - name: EVENT_LISTENER_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: studio-event-listener-user-password + - name: STUDIO_SERVICE_NAME + value: {{ .Values.eventListener.studioServiceName | quote }} + - name: STUDIO_SERVICE_PORT + value: {{ .Values.eventListener.studioServicePort | quote }} + - name: APP_STATUS_ENDPOINT + value: {{ .Values.eventListener.appStatusEndpoint | quote }} + - name: APP_STATUSES_ENDPOINT + value: {{ .Values.eventListener.appStatusesEndpoint | quote }} + - name: TOKEN_ENDPOINT + value: {{ .Values.eventListener.tokenEndpoint | quote }} + restartPolicy: Always + securityContext: + fsGroup: {{ .Values.studio.securityContext.fsGroup }} + initContainers: + - name: wait-for-studio + image: busybox:1.28.4 + command: ['sh', '-c', "until nslookup {{ .Release.Name }}-{{ .Values.studio.servicename }}; do echo waiting for {{ .Release.Name }}-{{ .Values.studio.servicename }} service; sleep 30; done"] + resources: + limits: + cpu: "100m" + memory: "512Mi" + requests: + cpu: "100m" + memory: "512Mi" diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index c6689c46..53010794 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -93,6 +93,13 @@ spec: secretKeyRef: name: {{ include "stackn.secretName" . }} key: studio-superuser-password + - name: EVENT_LISTENER_USERNAME + value: {{ .Values.studio.eventListenerUsername | quote }} + - name: EVENT_LISTENER_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: studio-event-listener-user-password - name: GET_HOSTS_FROM value: dns - name: POSTGRES_PASSWORD diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index f69d87c9..f7a2e930 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -316,7 +316,7 @@ data: # App statuses APPS_STATUS_SUCCESS = ['Running', 'Succeeded', 'Success'] APPS_STATUS_WARNING = ['Pending', 'Installed', - 'Waiting', 'Installing', 'Created'] + 'Waiting', 'Installing', 'Created', 'ContainerCreating'] DOMAIN = {{ .Values.domain | quote }} GRPC_DOMAIN = {{ .Values.grpc_domain | quote }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 7c166f31..6b78a98f 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -14,12 +14,13 @@ #Set global values to overide default global: studio: - superUser: "" # these are currently not handled by stackn: default: admin - superuserPassword: "" # password for Django superuser - superuserEmail: "" # these are currently not handled by stackn: default: admin@test.com - existingSecret: "" # name of existing secret containing superuserPassword and superuserEmail (optional) - storageClass: "" # storage class for persistent storage - postgresql: # global postgresql chart values + superUser: "" ##these are currently not handled by stackn: default: admin + superuserPassword: "" + superuserEmail: "" ##these are currently not handled by stackn: default: admin@test.com + existingSecret: "" + storageClass: "" + eventListenerUserPassword: "" + postgresql: auth: username: studio # username for postgresql password: "" # password for postgresql @@ -96,31 +97,32 @@ studio: # studio values image: #tell which image to deploy for studio repository: ghcr.io/scaleoutsystems/stackn/ingress:develop #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image - resources: # resources for studio - limits: # limits for studio - cpu: "1000m" # cpu limit for studio - memory: "1Gi" # memory limit for studio - requests: # requests for studio - cpu: "20m" # cpu request for studio - memory: "100Mi" # memory request for studio - storage: # storage for studio - storageClass: "" # storage class for studio - media: # media for studio - storage: # storage for media - storageClass: "" # storage class for media - size: "5Gi" # size for media - accessModes: ReadWriteMany # access modes for media - claimName: studio-media # claim name for media - mount_path: /app/media/ # mount path for media - superUser: admin # super user in Django admin for studio - superuserPassword: "" # password for Django superuser - superuserEmail: admin@test.com # email for Django superuser - version: studio # version for studio, this will show in the studio UI - securityContext: # security context for studio. Do not change unless you know what you are doing. - enabled: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 + resources: + limits: + cpu: "1000m" + memory: "4Gi" + requests: + cpu: "20m" + memory: "2Gi" + storage: + storageClass: "" + media: + storage: + storageClass: "" + size: "5Gi" + accessModes: ReadWriteMany + mount_path: /app/media/ + superUser: admin + superuserPassword: "" + superuserEmail: admin@test.com + eventListenerUsername: "" + eventListenerUserPassword: "" + version: studio + securityContext: + enabled: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 allowPrivilegeEscalation: false privileged: false readinessProbe: # readiness probe for studio. Do not change unless you know what you are doing. @@ -281,6 +283,17 @@ rabbitmq: +eventListener: + studioServiceName: "studio-studio" + studioServicePort: "8080" + appStatusEndpoint: "api/app/status" + appStatusesEndpoint: "api/app/statuses" + tokenEndpoint: "api/token-auth/" + image: #tell which image to deploy for studio + repository: "" #sha-da2cfdc #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + pullPolicy: Always # used to ensure that each time we redeploy always pull the latest image + + # Will be added in future realease, for now keep "enabled:false" postgresql-ha: enabled: false From c0f6c74dacf12d05024dff317e0cd0ec18a3712c Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Wed, 7 Feb 2024 13:24:05 +0100 Subject: [PATCH 086/146] Remove celery and chart controller, add argo cd settings to Studio. --- scaleout/stackn/requirements.yaml | 34 ------ .../templates/celery-flower-deployment.yaml | 102 ------------------ .../templates/celery-flower-service.yaml | 13 --- .../templates/chart-controller-secret.yaml | 9 -- .../stackn/templates/studio-deployment.yaml | 8 ++ .../templates/studio-settings-configmap.yaml | 7 +- scaleout/stackn/values.yaml | 63 +---------- 7 files changed, 19 insertions(+), 217 deletions(-) delete mode 100644 scaleout/stackn/templates/celery-flower-deployment.yaml delete mode 100644 scaleout/stackn/templates/celery-flower-service.yaml delete mode 100644 scaleout/stackn/templates/chart-controller-secret.yaml diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index 2892f8b1..53598fc8 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -1,40 +1,11 @@ # version x.x.x corresponds to "latest" dependencies: - # - name: openfaas - # version: 5.6.5 - # repository: "https://openfaas.github.io/faas-netes/" - # condition: openfaas.enabled - - # - name: argo-events - # version: 0.14.0 - # repository: "https://argoproj.github.io/argo-helm" - # condition: argo-events.enabled - - # - name: argo - # version: 0.7.3 - # repository: "https://argoproj.github.io/argo-helm" - # condition: argo.enabled - - # - name: prometheus - # version: 13.8.0 - # repository: https://prometheus-community.github.io/helm-charts - # condition: prometheus.enabled - - # - name: grafana - # version: 6.8.4 - # repository: https://grafana.github.io/helm-charts - # condition: grafana.enabled - name: reloader version: v1.0.15 repository: https://stakater.github.io/stakater-charts condition: reloader.enabled - # - name: postgresql-ha - # version: 9.2.0 - # repository: https://charts.bitnami.com/bitnami - # condition: postgresql-ha.enabled - - name: postgresql version: 12.2.7 repository: https://charts.bitnami.com/bitnami @@ -44,11 +15,6 @@ dependencies: version: 17.7.4 repository: https://charts.bitnami.com/bitnami condition: redis.enabled - - - name: rabbitmq - version: 11.9.1 - repository: https://charts.bitnami.com/bitnami - condition: rabbitmq.enabled - name: common repository: https://charts.bitnami.com/bitnami diff --git a/scaleout/stackn/templates/celery-flower-deployment.yaml b/scaleout/stackn/templates/celery-flower-deployment.yaml deleted file mode 100644 index 2cb6b661..00000000 --- a/scaleout/stackn/templates/celery-flower-deployment.yaml +++ /dev/null @@ -1,102 +0,0 @@ -{{- if .Values.celeryFlower.enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - reloader.stakater.com/auto: "true" - labels: - io.kompose.service: {{ .Release.Name }}-celery-flower - name: {{ .Release.Name }}-celery-flower - name: {{ .Release.Name }}-celery-flower -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - name: {{ .Release.Name }}-celery-flower - template: - metadata: - annotations: - kompose.cmd: kompose convert - kompose.version: 1.20.0 () - creationTimestamp: null - labels: - io.kompose.service: {{ .Release.Name }}-celery-flower - name: {{ .Release.Name }}-celery-flower - spec: - automountServiceAccountToken: false - containers: - - args: - - sh - - ./scripts/run_flower.sh - {{- if .Values.studio.securityContext.enabled }} - securityContext: - runAsUser: {{ .Values.studio.securityContext.runAsUser }} - runAsGroup: {{ .Values.studio.securityContext.runAsGroup }} - allowPrivilegeEscalation: {{ .Values.studio.securityContext.allowPrivilegeEscalation }} - privileged: {{ .Values.studio.securityContext.privileged }} - capabilities: - drop: - - all - {{- end }} - env: - - name: BASE_PATH - value: "/app" - - name: GET_HOSTS_FROM - value: dns - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "stackn.postgres.secretName" . }} - key: password - - name: POSTGRES_USER - value: {{ .Values.postgresql.global.postgresql.auth.user }} - - name: RABBITMQ_DEFAULT_PASS - valueFrom: - secretKeyRef: - name: {{ template "stackn.secretName" . }} - key: rabbit-password - - name: RABBITMQ_HOST - value: {{ .Release.Name }}-rabbit - - name: RABBITMQ_USER - value: {{ include "stackn.rabbit.username" . }} - - name: REDIS_HOST - value: {{ .Release.Name }}-redis - image: {{ .Values.studio.image.repository }} - imagePullPolicy: {{ .Values.studio.image.pullPolicy }} - name: {{ .Release.Name }}-celery-worker - resources: - limits: - cpu: {{ .Values.celeryWorkers.resources.limits.cpu }} - memory: {{ .Values.celeryWorkers.resources.limits.memory }} - requests: - cpu: {{ .Values.celeryWorkers.resources.requests.cpu }} - memory: {{ .Values.celeryWorkers.resources.requests.memory }} - volumeMounts: - {{- if .Values.chartcontroller.addSecret }} - - name: config - mountPath: {{ .Values.studio.kubeconfig_dir | quote }} - readOnly: true - {{- end }} - - mountPath: /app/studio/settings.py - subPath: settings.py - name: {{ .Release.Name}}-settings-configmap - imagePullSecrets: - - name: {{ .Values.imagePullSecrets.name }} - restartPolicy: Always - volumes: - {{- if .Values.chartcontroller.addSecret }} - - name: config - secret: - secretName: {{ .Release.Name }}-chart-controller-secret - {{- end }} - - name: {{ .Release.Name}}-settings-configmap - configMap: - name: {{ .Release.Name}}-settings-configmap - items: - - key: settings.py - path: settings.py - -status: {} -{{- end }} diff --git a/scaleout/stackn/templates/celery-flower-service.yaml b/scaleout/stackn/templates/celery-flower-service.yaml deleted file mode 100644 index 05d4cfec..00000000 --- a/scaleout/stackn/templates/celery-flower-service.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ .Release.Name }}-celery-flower -spec: - ports: - - name: "5556" - port: 5556 - targetPort: 5556 - selector: - name: {{ .Release.Name }}-celery-flower -status: - loadBalancer: {} diff --git a/scaleout/stackn/templates/chart-controller-secret.yaml b/scaleout/stackn/templates/chart-controller-secret.yaml deleted file mode 100644 index 988d3327..00000000 --- a/scaleout/stackn/templates/chart-controller-secret.yaml +++ /dev/null @@ -1,9 +0,0 @@ -{{- if .Values.chartcontroller.addSecret }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Release.Name }}-chart-controller-secret -type: Opaque -data: - config: {{ .Values.kubeconfig }} -{{- end }} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 53010794..73030506 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -145,6 +145,14 @@ spec: name: {{ include "stackn.secretName" . }} key: email-api-key {{ end }} + {{ if .Values.studio.argocd.enabled }} + - name: ARGO_CD_ENABLED + value: true + - name: ARGO_CD_API_URL + value: {{ Values.studio.argocd.url }} + - name: ARGO_CD_TOKEN + value: {{ Values.studio.argocd.token }} + {{ end }} image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index f7a2e930..c17db54c 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -395,4 +395,9 @@ data: DISCORD_ALERT_ON_NEW_USER = {{ if .Values.studio.discord.alert_on_new_user }}True{{ else }}False{{ end }} DISCORD_ALTERT_WEBHOOK_URL = {{ .Values.studio.discord.alert_webhook_url | quote }} - DISCORD_ALERT_ON_NEW_USER_MESSAGE = {{ .Values.studio.discord.alert_on_new_user_message | quote }} \ No newline at end of file + DISCORD_ALERT_ON_NEW_USER_MESSAGE = {{ .Values.studio.discord.alert_on_new_user_message | quote }} + + # Argo CD API URL and Token + ARGO_CD_ENABLED = os.environ.get("ARGO_CD_ENABLED", False) + ARGO_CD_API_URL = os.environ.get("ARGO_CD_API_URL", None) + ARGO_CD_TOKEN = os.environ.get("ARGO_CD_TOKEN", None) diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 6b78a98f..54d7f306 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -158,22 +158,12 @@ studio: # studio values alert_on_new_user: false alert_webhook_url: '' alert_on_new_user_message: '' - - # Celery workers for studio -celeryWorkers: - replicas: 3 # number of celery workers, recommended to have at least 3 - resources: - requests: - cpu: "100m" - memory: "250Mi" - limits: - cpu: "1200m" - memory: "2Gi" - -# Celery task UI for studio -celeryFlower: - enabled: false + argocd: + enabled: true + url: '' + token: '' + # Pull secrets for studio, used to pull images from private repositories such as Harbor # To create a pull secret run: $ kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= imagePullSecrets: @@ -262,27 +252,6 @@ redis: memory: "1Gi" -## RabbitMQ chart for messaging queue ## -# Please see the documentation for this Bitnami chart for more details on values: -# https://github.com/bitnami/charts/tree/main/bitnami/rabbitmq -# Please also observe the version we are using in requirements.yaml - -rabbitmq: - enabled: true - commonAnnotations: {"reloader.stakater.com/auto": "true"} - podLabels: {"app":"stackn-studio","allow-api-access": "true"} - persistence: - enabled: true - resources: - requests: - cpu: "100m" - memory: "256Mi" - limits: - cpu: "1000m" - memory: "1Gi" - - - eventListener: studioServiceName: "studio-studio" studioServicePort: "8080" @@ -298,28 +267,6 @@ eventListener: postgresql-ha: enabled: false -# default credentials for rabbitmq. Deprecated. Using Bitnamis chart for rabbitmq. Will be removed in future release. -rabbit: - image: rabbitmq:3-management - username: admin - password: "" - -# Deprecated. Will be removed in future release. -chartcontroller: - enabled: false - addSecret: false - -# Deprecated. Will be removed in future release. -docker-registry: - enabled: false - -# Deprecated. Will be removed in future release. Should be deployed seperatly in a different namespace. -prometheus: - enabled: false - -# Deprecated. Will be removed in future release. Should be deployed seperatly in a different namespace. -grafana: - enabled: false # Enable reloader for (see reloader.stakater.com) auto reload of deployments when configmaps change reloader: From 4886d986fed09309b5f5b6bcdb47d8ecdab350a5 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Mon, 12 Feb 2024 15:01:43 +0100 Subject: [PATCH 087/146] Fixed some problems in studio-deployment --- .../stackn/templates/studio-deployment.yaml | 25 +++---------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 73030506..b1a93702 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -114,15 +114,6 @@ spec: secretKeyRef: name: {{ include "stackn.redis.secretName" . }} key: {{ include "stackn.redis.secretPasswordKey" . }} - - name: RABBITMQ_DEFAULT_PASS - valueFrom: - secretKeyRef: - name: {{ include "stackn.rabbit.secretName" . }} - key: rabbitmq-password - {{- if .Values.chartcontroller.addSecret }} - - name: KUBECONFIG - value: {{ .Values.studio.kubeconfig_file | quote }} - {{- end }} - name: DJANGO_SECRET valueFrom: secretKeyRef: @@ -147,21 +138,16 @@ spec: {{ end }} {{ if .Values.studio.argocd.enabled }} - name: ARGO_CD_ENABLED - value: true + value: "true" - name: ARGO_CD_API_URL - value: {{ Values.studio.argocd.url }} + value: {{ .Values.studio.argocd.url | default "" }} - name: ARGO_CD_TOKEN - value: {{ Values.studio.argocd.token }} + value: {{ .Values.studio.argocd.token | default "" }} {{ end }} image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio volumeMounts: - {{- if .Values.chartcontroller.addSecret }} - - name: kubeconfig - mountPath: {{ .Values.studio.kubeconfig_dir | quote }} - readOnly: true - {{- end }} - mountPath: /app/studio/settings.py subPath: settings.py name: {{ .Release.Name}}-settings-configmap @@ -204,11 +190,6 @@ spec: - name: {{ .Values.imagePullSecrets.name }} restartPolicy: Always volumes: - {{- if .Values.chartcontroller.addSecret }} - - name: kubeconfig - secret: - secretName: {{ .Release.Name }}-chart-controller-secret - {{- end }} - name: {{ .Release.Name}}-settings-configmap configMap: name: {{ .Release.Name}}-settings-configmap From 408f1d51425d23ec973ce23412b8f2cc39a9f13b Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Mon, 12 Feb 2024 16:49:38 +0100 Subject: [PATCH 088/146] Various fixes --- scaleout/stackn/charts/rabbitmq-11.9.1.tgz | Bin 57316 -> 0 bytes scaleout/stackn/templates/_helper.tpl | 43 ------------------ scaleout/stackn/templates/basic-secrets.yaml | 1 + .../stackn/templates/ingress-platform.yaml | 2 +- .../stackn/templates/studio-deployment.yaml | 5 +- .../templates/studio-settings-configmap.yaml | 20 -------- 6 files changed, 6 insertions(+), 65 deletions(-) delete mode 100644 scaleout/stackn/charts/rabbitmq-11.9.1.tgz diff --git a/scaleout/stackn/charts/rabbitmq-11.9.1.tgz b/scaleout/stackn/charts/rabbitmq-11.9.1.tgz deleted file mode 100644 index 2c6b1abd495162be9e633d70cabc1cb84b207f1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57316 zcmV)NK)1giiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0POwyb{n^nC=Tzx`4l*`=Sa$^NlCsXJmWbdOLC$W>oSs@eEZ8} zNnkffVyoHc0BFhFjvwu;^GN3vehY<51AQS|7dzQ|+%r3-x`9HWP$(1%g({B6V=Cvr z4fkf4%fSNA)4x3Sv$eIg_44_1_;+h-tNQQu^JhDM*?#`))y}h5&tJWK_Lr^gXItAl ze?eQ1j!DB)2#NV$wjSJ8wR8U<56&_sv7{^$qaH#rmSoEKVuTK}3CBY6B9;XwJ%myk zlS~jXLc2MRXC&GgZ1r$Xe8J?37 zirIY5vK~U5sF? zgAcugh?vt{!mBgj^P~SnR3MxomXiz#R`8ghDai=OX_OZ{XM&(P5du#M8gq6{IFd6g zRjq^wI?YJZLukS{idiP8kR+3vXhx^AbP?ejOjA5gEeM)Tk%&o#Ib{N^kC~hyvB=^X zXBjIL9tpzUi;Y2V#uRldA*NK$im^`sLz|)Ggbe4HX6}QX$UPdX{#p<|5wQ?NilLA= zz80>+kj|&>j|e_SJ3Ct+cAh;SBuk!y(JdZ7&JsG?+c-Bkkln6OOVup8Kyd3SsueM*l zc=3E^5^rsfza!s$JAU!%Rh)b~-roA|MY2VbZ+Bk4N}fF*fA?zqlDznK8*gvFdO4nq zza`I;c-+&nT9Rah`a4@Y&!VlJXnW^kXJ_>M+tG_}2QOYcd;V(c`FGF%|NZ|a6ZnCT zoBuaBEr|Fm3gFWDzx{ISRbBtvdAa>{{(p(*$rJP+g2YNmLf@xsj8l|jj^{)YE_zR% z*q8e(R>}~at2I9?aheh=$R^5|BwAaNGb+$6O;f~f26`YeyqEhdgE=6{v-<**t6_PJD^`ECjnx2!G6R9;a zAsNS0vX^3^y4O=J{RaRs;0FPeMgnp3v8ArxWLVu+L;^m8I2H(l&Wbt54G?{NEwpq0 zozhlMl~@LC75&80Vouh@hU%P#q4epXQzO*x_YivW1RV^f1O2Ot`AEN3n)rNSEB;6p z`tvcK6DVLo`!&%ozxGf-XlStKGow@34;xs{sFa>o4~5L)qe^fxDOW6|D<(i-Sgm+X zFC3~}#n7WIz#F*HsI=2CytaZ}F6&k7ms%x>r`6Kx)jFNe3khtkutS(DC~9R^6D8TG z!O?4N6_j~PGnhiRcwyIKj0c0kz|3Add8sHVy@}`q2_iQern1D-TKjpCrl%~Wajo;} z3(DbBV=X%u&T|se$pY!IitaKQ3<=1%n4)tcmDrHHAgT)sR-ju}qzOvtHBny#A&7jC z93z@d7@x!b7qJYbYzlK8pp8KPu@l1Z4`mgtsJ6v`EvnuAMhO{HoJHH)5#Q<|Wc49C zy~M*%1sI1C$%1DBz1cngL5Z*-jbYzNm4C&x^law143*EG0bie49E z!ZRX?7*IA$SS*HxAUv8DG$BK1K@6YdoJ5LYXf}=XJKLF(`9{cZOE+}_Rsfu)3nXkG z4G$qUsR<|}@hn@;3n9^%pgGP8fDv<|bWlrG;L9AxWYDc+5{qjwbZcCcvm|oc*P-f( z?p%~}dV?i#6Jcm%@&`Q6Q(^>gejkyXSEO+udiOy44@IuO466Q~SZQ!BxneNMRC!5( zK2B7)4fdo+Q&kN~GS3x8}Lw{I^m$2sKTi< z&IJ01YwMh{sa>TYSIME-Bd5Kcfv#A#|8Ac<`hdQh!D zLLWbQ@CD&FG$!3SdPZ=P5+Q6&;1JbP1Eeb90hf1pOj3c&KV5sEi(BLmGEfT=il-S9 zlE!Gx5@N-XhB8;e@5z&1S?Gu*R%RHC!fyitV3RiR>k7r3voSHs{aBR|x{lJERpSa> z_1hLOgiA=aVP%hLCRllz5wgJc%)gSA1EG*9ZGH`XH?0{Ms^dy7ij~r zxle1Vwrz@L6Pi)E@I~j03Avk6EQmn+t~Sb90-q4p-&Bny3rNhenB-Cn4bzDzBl4E< zYnn}mI7uRsNluA~B!k6;$T(8qMWkjQ{ESRXO6l!+SXJgR+ES%Ho%|NM6 zu+%vyIL}iH!hUVgR_<$9e?qbw%2}qkIl94|swwW2Guz+@e$~;EuU`yZ z+hD1t`^X9s7o410lz*NPIU`)_>Jr3)>xJu=u9GeX=t6C=)cBotwbBwyLO_tflBdMrn%XX`q1zeB?3yoO#hQ@{Jsq<&X{Mitcp-U4u(hcZk$j*+ z;cUxkT@)Rd*LKGTgmH9;IZ4z^z^Op%pp+YY5!SN_B-52U%d%v+Lf2%Wmmfq1Q!`(h zQ5eBgjo2iz-y@BSTfJJUHL;3b>E1Dxk8yncUJ!2AR{IVn1j2Dlg!td+4M8}$p@Jlv z+K>hS?9iq`9V!q;ITHdn2&hiw0&yy?|3|pe`t3I@x*AoU;%vId*fk~S0RBL+{tI+B zN%)**L@^z(dqO7@0@k;TB}7{%aGJ7PZL(9VZjq@OY`B}?c!rp&`o%cW?^4V7n6cFT z?Zks2X}WNsMkCTSmb0RdM`uP1EA{(5vq{v9MzWYMU@=m|;u$HbV^BR09SV^SW^$g^ z$tF`#)fF$^og-1?IpY#}#=GXaxRC67dys?dFZG?xv0CV0pH9+Aq)*%ddQ7;a6W}P( z40eKPsoKnTr3K*z>IcGPZ0s0s; zBOpYo4GrQa!s%pz&SzlD`6VZWs~w!KOOd86 zXwN3)+63C1HZ-6g$)Y=8!+&Pl94mDL_I+mhnD=IKSRqyi)VaZHvar4Qkt`JVD&<`7 z)au2Rj&4xUCLgK|Hr>0_88Ju7_rlmvh2BD9fm|VUXpE_MpeZ@|#-AKrAgBQ}H7)O{&Md82 zAx@*5Za_n^N0SQCrIEKqn(ob%Y`1D2WhlIEJZo72|=bb*1Fem6BjrgJ!JlK6Nh`>&_G!6EtT z6Q*>0B?(G91e{vMI770?hyrTQNe18lz!E~T9H|CNp|AB~V-G`u#n(iF3kPC6(FPEF!)SuWL{++`sZu+~3*eiR z^VO3Dr{E4P>~awX>Nd$Y@J1`ONN z!AjKhE_MkB4dDVT;98XEDr|zb2G5a@I7_tO$@8s$QE$uHaJGA-YacVUJjs$RZ4VGg zL9lP+c}lfCK_3`ti8;^`b70w-p%|xe0jG+xfz5S$e>Fl1r$T!aso#dQ8vRYRBOi>= z&Wo2vZ!CF@m3C|J++RWSw3sSQ?;RCV_0N*QzL(6f16mh)56H4~q4X@AN@CoaIGM8> zM?&$xfM7UDs6MN9z!b7qa71>h-(0~7pZToD-b{?kInMBuz$)zCDIMrCp(0ia!s7D! zTTwleDl#e;rJYD$8z`n94b{V;~?YR@o)B1=g4gGSA<7<*7muZ4?Esf2QhStr&cq_c~R+>#i zkyXC0N~&^WsYG0cii~{7L1Ri6NX!Ze)5LXTon~Pvy>Mfb=yGMWPpin_BvCapv}7wE|#e!T8Vr zML~M+W>+gPm6idPHTda+@US7r9yC?T$q?uHP{Ft?3l9D!Sk_YKcc~zc25~VH$Q!fR4Y;0O22A`_YLsj`l|M0&bh>D z3gvQXi>w!dOo~*?JMHBY7eX@Q+o=6@tv5q>N)J8@OPYZ1o#2E2LI^yi6A~}tl>ETh zwQlB?Q>pZ{8~wqV1&{^upr?H2r!AcEOM9!L8}$79eo%D zFuvzFCZ~i`mYkEADZSIUDJsQ8H$yYUGw|*DTY+vdmBQZPGZa!P!v`uYMuKFC-NYb4 zrx{LRGrOBDklL0ikmN&5giteJd&|MMCki50N|rA!c%V2ME+TH56i+TPi!>P83I%}{t351lJ_oIp>Ey6k;V*wxp z$pnR6iyEnoDmE3Nu;=*glyNBnIbpuQhXJ1dmM{N$kuIs8Q1Fy#`KosbyuAR)=gE@l zL~`N7JY%T8&yZkq zB4{9ncDRAzL{BCpR89)=zCQeR-;=d zYHY)esut|vc3}_n!`Z#Gv%MOkO>$^2m@szR3coda`a+aG2P#)5k&}26<($qjr=Zch zs{q;&HxSl)m09`ZN$G$_ZZB1Hm&R)qp>TGqh2+_DC&em|s;;^IQvQqHV*gq$B%uQy zsEp>kX@ofWt)QGFZp{mTsYdo0tb>kaiVVDN)r?d77<8+~N&SU6K?zfg4Q5Wgpv~1H z9>Co6%qRh7SFpXu$&K3kC6!Oc0$}~$UEgG!U#4)M>e6`nRW2x<6M~j(HcGET*lbiS zKi>Gl+8^idps|zO1#0k=p~~067{}Kso1!CQiWciI$lbCKU@ zwFZXbhi{j+ma&ASc+uc&kq{h9INKHI7*A8OCJ;`iYS%WK51g7t1(YA4A0Uc?f5!>v zGG{`9%ad>ih^9^7v{A!LZOqI@7lK!)zx1KslFsO21D4rMl{ur<)@}nuZv_otgjnVs zMXrXeqzo&hg?wItjLdhx1@mfzww4dYH6b}xT6x1@=*^vgQFrCc893^p@}1fKA=K*y z6KI5fk96_(*11&eS_0=xxKsqAdI>&iuaVkG{iJUehmNVAKJ^g#_%TvDGT8m7*&Y-P z9SJwWkIv-+;Mhjh+lEHN!m3e{B>@Juc!Qx0iUlS+=UJ}bT)MeBsMuPK-4CJH#vI#V zjBSK-{jC^)JNRqlIVqc7Hr7xx;xbMN&We0MGfDUjPSI<$y|ubH%hJVV%BGjMn8SMd z+VZol=qw(W))o>{d8wgiCDB{V8c?)iG^mVjlUbtP+!HO@td$YYmzk0b@cL4}zBI4V zYc!`>q+i1Pu(ssD{j%(Z;@fpH&*h?-(>H8KbnQzm$(GEE1_o~MBQ3j`3ewcVv>?Dh zcY;-pP<6NExSq;|O+Xb+7B{2CqUbO%A$slEx3+Sw37Fs}K7 z+}|hF8=qjBUed{B#`KJg32!1*qf=oGSd3M5;Jw#q$Z}b~U91X-VT><5=bJ%J=2b}D z;Akg}6|k?L~k?RR0zwaL^(jDk}Suxjws0G|?x)(f7VVlGIn(gy0Q!u?8RMLC7* zI?WRD0j-NXr4kMZ`=fpde*X5i2qY&XAuz4VwyA+w4R_)j}s!9}&^6ZI-IRU7M_OrY-*? zS=feK*|dt`5{7L6dk4~sYnuCNV>1z){%Kr=GnSFo!Y%ruJtwtlcq2MD-BD>84!`>H zMX-%9#*$v!(4KNI36nxtW4k-xc3%cE_SZAF-)lS(=z>bS>zzf*xSd@D-djC{B$GJ3 z)DSM6KiQ=<5MF8zG(giBQGJb*y;(>iNe5%; zz_mNr*&bi)og!_>F>y-VK-A5Q&bSw}(P{#OCK{kvqup{Swp1IG(pm=3a$sfQ72vFa ztP?m}xD94$5?c$ zCaQ1x!CqH?T_K2RTjFa1XWwKpA+a>4hHbT~?h_4-yMu;h=L`Dywnq9fK{(H~X*swR zR6TuYbO8(rY|qZ?M-ATbg`#{&bj=tI=MW(wuKY8Yx)IhIJa5c4t?IA>zK!V9rw9r_ z4JxiLC!CN=5O@RU`uZBZ*gAT%oakM7y@l+W=IU34hD+GK!Pc~d_ZyCNx=nxv8ZYO_ z#)G1zyl87I;W8}z)1Q!j;0cL^pt1RYv>6wzn>#vcQK{6?CBPfu$rJQ$fAPUbYDLUJq_-$Wl{mI;Y7xd~S0 zPoFj&jMnF4>DUagYcPKOq=EeU>DPhj_2C4De6wZ5;A&;lmkO_A@CH&1DOI+yhHC9L zyu%mVq0_Tu(0kHrC-o{0>pBCQnN4$K^|HE}XYSy0petN$488cq$Zz$s%0LfgG)eY$|5%w;u_3c(8W@1QbcNq(;gw)fa z5;jr7S$_dF_o8gtsGPE=@Xj}bB<(+FD~aS z0n>ym#O7}WEPxGDNj{Wh>d2wd-N10up%5+zv>N6Mkw%x%Wrx_@j}UmVA*$fWC( zAehH9D~LP}ah$9{w1dxYT~r6?s%g?R6oAQZTfk^@_Z!6x`^PB9a)xeagp&#|a~V^k zY{?q>!e~&<%{WuH{;ws$9LsoC>I~qj0Ry^TP$lK@d{;NGwi25t&NdN|v6AUh*Cl#A zLu(Bd_qAZ93}uu;@c;ea|MUO;@Beu)EBxtuYB6danZ|=eUqA;1T$E-(BwB0KY1T|H z@pKbOmeY9C-Ivri!u3{hj`JLDo84(b2FSQuUkzPoT|nv~gAyBzr|iR^xt=>3P+IBv z#qQaKs_7}&ieTq$l}l^z`8CbK6mfq3E{Mj1))j5A4lm7uSSDhl8LTnO8p!3U2!Rr4 zqGh69{MWo-6l)6nnrCueYX;wJg#Q^NgkFcC0DOl=O!$r#BKY7!FIr$4527y90>(QD zL3_JFB$0{vFt9O?Dl>0y7lCswY&wkWU4q_{emE5N^o8^$EX!8-hkVqfU$f$cd(i;o7>D8a3A27TFZ2tE`u%*ik;!wF7Kvedf2S|e7_M#H5W{rx^Y6KK%$!;Xi&THYbpo$XU@ZW;7~ ziVaxWnCq=r3R6Jqn>G@=2{QqqI|gnuAM5LX{>3+KOCU)Zb2D%+EbpqBFmxt1N@>Tb z1~jYG9_#yvN)$Jd%mr!(@>K2=jx5odu1fm%JkUqqW;PfM%0EjYyYTM8^$!2jDTkyh z#&8U`q9ApGA|34gz03r`;Fy>O9{quu|7JpZM~V^t9pxIlCPi;~!&Zp&{5bUI5=%95 zO6zG2MsIF~?}55}T+GLWD<*b&nfdO8AXfnVS|haW!E+H;fFAEnpa^sC#|y}!qeY;; zkc?mV>!EI1U*gG=0z%Lo{}=4jgHV9U}bNXlwq6Pc(^MqL~U+~niot* z?aa`)peda4SPO&QQ0O~OlFo^lI)uYD$W6=OVTg~MB}dL4YeGU(f!0nqm^jV|P8Mql z&`B1PYCv2rX-sp_TS8mVCTyME)l96^*PLa7=Rq^5b^jNLs|`I$^^t&fES?p1G^~iHq3)J`nHW9TMgx#3+JUT}rHyJ!dI=1@Je!)f`s&- z4WDR)BGWk4SA;_>jgi#;d9ldDcmd|-%$c_9o8B;vPO^QH5=p|?OF=PzB`LA0a-Tor z{}3*$;a25FP9eGmB+RSj4+^MsH?O>R* zB(iNqHfkKpGy_+AQ@NX|7<{6WH9*=Rsb`&er4$)Ku@H2cK?;J5C1m&nJj~&5iw#)Ga3-mHW9M(s zy@u{*k~WdR2la?_=sd=cPKR1QM@Zq<)AyAVQXTcj$5#C}Kuf)-;1t*q>fg1LZ9>R0;%c+FL<8ZuF9Pn`kN z&rCQfjgtvy`3U{eKR&p)Jlp-b|7+Ext-AV_rbN47l?Lwi2J4*VhQ{y~3J7V61=HIf zX?ti2cUXupIiX#Q?z^leF`MTFWbZWRu#hqAXSGw(X+&M53mfvwTDq;tEj+=M45b9$ zc%FISSQJxM0BZ4!(U=5o0>d+gy00<}Bd&m_G*cyT^0z`Cc+C}j7aL7$7A9CO z*tH6tF3^}`APfYKTXQXqv^mNdhr??g5VN?Xs(Be$CQ4>#gyYykLxMj@;=ybO)+>=T znq`p3RU_lHOBCk?aPZdLz0!9{Mrh}IS_U?OT1qqVVOlsA-MfNy^%UTq4qa9W8yQR+ zlkGDvHK3HeVGMPxQ}v-1JJbKzTFDsK z_eqKuHrU{yeuwl;85;)BC%|%;c@Vl#NAlZ74^@0~oGQMFXbPPlnEXTctmw6a1@tJy8?db@;>>*S|*&Ghtnf)Da z{#p3n6>gjW;n((RcbfuTp{|?+T>*8N23jX{ZB0f64i2+H&($ zhXAO&F1zOA-4LmCuguB4n z$`Z6s1ut~A(>Fyj)!tg+)v|7^&5JDZa!~uMo{aUGVloboY4T(|Fy3N%Eg9O2O}Gs= zRoe5Y*0q~_s1@uv&0N+e*nQ87Im*D{X_ylplT6ywo-8qUl8j>zCvymAYn+H&Oa&jL z5_PpE@rUBQ< z#}rv6gj{59VCd8GptW$=!*3x6xDi$a3Q-R21Ynb{a6v6?OQof(dMa;^)5CHagt?6; zOj1#Ur3t;diLkyEK?Rz+yu3O^03=?ro;;HxO|`eOwcp!-tfjAQE56`YseXloxM0^L zL%W4!5qveSmQci9gOO0k_^*{)m5-uP> zM@*`+ATK{v1aSGG^&BL@68i-Wm!JN$w>oW-4_`>e@sxl=iK>mx^$Vom1d|)u)SlFC zGMd0go5%;GJyZV8fA#OKhVe=2NByQs{r;xO<7XBffs#dr=QP&$_5@{_4PC3C6`8>R zt$RM68wfZb8p?_^-9#CyH3rsQL~ZO~eLFs$F(y2hXq^qswoLc{q4jCLgII=ke?H&T zDdI3skXii@Lf`**u&F+x|A|g=lATK&UvId(o*oi4K@$v&Ju!Ai$IcbO3vN>Kmqb5# zBV%hjb1Bp`9#YO;ig2Ef(0rjZgz_?~cShWXoX+!q1UI1-)95*m^oylDqvS_fS>M!% zkkb2q=2Vgso5-qhE|^a5rI^mqsm*8JNDWO4C}{@xVrJ6g!AXtvDT=X6_F&g+gRtUJBUW9EZG|IMbh`?}BlN8~iD;Ze-b(E+6P=u78_r$)b=gjF!@{uS zQgI#W&PUoI>im3v*_!Uwu!9dd69um=U{9W)AKj|%6b%L2(={8FOzrpORX+DC2VPqy zT>0T?uMv>iXxW4G-T801xgEa;9fAapdKoe9I#<^YkJQm3Ea4Qret)NShEN>NVWPg@^iwp}rw%eQ3MZH=zzo_k0^Gk+?95U12G@cNw4DCReJYSE?sis-{?K zNU~JTtOR%T{KQMuQAf38o_;SN*jUT(cdgmV2VDSkVu&t)I&nrPKzC)4E-(rmz0#hin7yA|cYg$2@)YPe0_Iz7lnjkXVX-$V7eftM74AU;SePrhw`k8<=VZ5X(X#oGL@D00JXj!6X>> zRY({PYeAxc8J!Ww!U))=$}$0~RM{lpf-0vpT8DH}iN&V&*(+C}&w$9YpZYi3!F9sQ8pz2im`lqWmLdQDF zwx2#}NrT4U->M_4F3Q>7l=s=1fco1<3;8j(j<%gKk$4dD489d12SheU$Ovr>;QxkO zZClF~effdl1Ty5gAD^Rhj**j03~-vys$H}lifmxF5%SUp=}mRa<_(>+c(-;|5Fseb z+@+aw{daharp}q0c2n9{%-2VZqrMKna(LQz=8W>yCOFlSxPZKmMn*WVPitAyh8z2+EQb0p9)5?m8uPMx1X06Y(YU<94qV5|Q__mh zOJfUQ_5|~y9WQHnSF>+`{>lnCjJ2@}gbnT?8Cn~D1M$lkPjve0!iIbWo6YXKHx6U( zrgdqw(dN*0ye<|wL5Bu{w$FMtDqCWN4wXny1c0&8iFs+<2-b=empKw5n%S;b>1&&6 z5JV}9aoX5Ka3WaF3tTxIRP7yB+8dw?W>dxa5t(oynK@L2AhmglV}c-(m%cbfxQy)1 z!I#w9gcNQl)`uH(IIj5PNp#HyzNTyzHjoN&*i7x)C z(`9=XXy2Q-C=Ov0-RUZ192bO%3J;$W%o#}+h-KkiD(g{+#tXZ+nWPL{hnF!~4?-ph zVE#bTxd%&-bP@?VRg?}0=(XVWCY_u^+1KC;;7s&>EVcT$m(|L6OfD3YC$bGn!5C?_ zfXoF}KE*aYt2ymz?Lz7MFJBv^np(pJ+BJCC80Y2k!^c!|%ohOP^RluF`qBDWa8urc({n1JlL_I9*$lOU zPC^fsck&|DT~so^F6bXVhXf(_-;%h6Ri>hmfi6;ij?98Nqg@r+W{ehF#|^V8vW;0P zg8i|DhBhkTo<7O1EpJ%Zz=6gpeR6RyLTlG#u?7d~YhLL!kP_rWu6KAeL#GEvCUZeh zTc>GbuQ@UKP39bW-WX8wWHNtXSjLDJj&3th6dJE5ERC z(Z=0M;H?5`M+C^|Q0G25R%38{a?yYVB2@KZvwaD%ve^0}>b4a+&tASj30~N?p<%d} z>eN|pMayi^FTGm(EwDlgni!`?D$q==&$06&DI+Blbat@2e{?XI+dT4|1ex_Kj4W(u z#-*~}aV2ms1R}9{(G9Ds=gq5Ub9saa?ae#h2_$z$ziw*{ZTFryw{T1~* zYAk7c@8Im>@a^H=?!`gpb{p&TkfTi7Es3rqLKG9}aZosHln$0MMVL5-%u@rx;-4_5n6>Z7}LwmHtn`BAOXx8LN_DCT+Ej7Zh zop2iOrFNxkC}NHw#G9I({e}W2`Hh!3v)LW$)2BLh?fKIY%cx|0xivCooG>vgTaWBC zDU}caXQ1ic)Q2l9y_uhS9Io^;(-=w0BxVl%>akdNr{j_sWDjoN}Mv6pYhy; zNwI#?`Yp|jC%@-w2NgZr$H_r*E*L9Of>XO2oCX-Vmr8vDgq-t|yE38~C}`eR z8=+@gqFeJCioLJw<6zUf>L@QBS)hi_O_sR!t!&roybshzMyD?bzjh_m-`E(|1z74c z@9vderJ2^bv`R2=)`Xi;xv&0}Qa8LL)qxm>x3p)V7ynZYb4VY*o%D_j ziq$3(P1mb*wNCe|?xA}<(Kc_Z zb$F>xoQ@fEu1zZoOF6BqcDPkq0K*!33_RVE-B%Z@U{Y?UjF9v8orc?VZcmp;CP9ML zuq(ZSgf+)kw?HMYRGM7Er4?jL6|wxKlLl7tacW}I<=*9rqRr9?o99j4W2LzmHnb;$ zgKjA6E%;qwUd)KnmpDOib<8llFdKTBi5%>EV4|@6jBklxbK(h}2&Y8tQKp>a1IdO^ z8?sM0(P_8+&f*JIMrL0*|81Y$X60w3Ho&|z2wxWYMcz6-c9q*&60IF0f=5x#!WuJ87;dStc z%3^{(euVwqQ{!Ff-hcYkN1r}zgwPTqVoo85#i+CbWGo>7wt! zj;i{(ctQ`Jmp$Cx@|n8>0CtPk{|#+#{maIGWnDSMNs!$)2k*{D6`b1{>VmN&oGtc( zBaybr?wvDSFp1N9PWkPvtv_UZFBn5}oGpU$lFu~Ep$D@9GlNuiO&Dm3Y}`#aDAwpQ z*xEMKeCBYNQHfkovWBCFN`c@$JlZQWsIl7&oM00)g~;5?HR9V`Rc z3LT;6Oi+k}(H*|6(y0ZBr=3AdJnaNCp;IDcXRxNY@kG4E3nXTE=f%qr#)HAYrS#62 ztollCB0AAwbzo!3Y#c~!TkeKz?qctCMp#v`3HG`+VKahSqkY2SYr-SPKE@wOJFMY~ zuVv2$5HyBoU1wx~3@9`2?Z}UiwOyHiBQevVLy)4&2yJgi2^mwIMcdmE|5o33*W=*t zaV@gA8m7<|Fc%E;MF}0ba7~Sg;}^(xsa7c=*ESJJh07VYb~rg^5>nq}a;?!wx8i;Y z#GZk>fsvvx&8CryM^l;WB#}nR9xBAzy-KgrRN0yO#!kdyE(C-sg)mQ}su(ICuVcRl1#5-I*%O z)6x_WcOA}#BoF}NGo^t5*qki0V8kG%nuxb(PVqBc$SLF@{vl?yuL9)kZI z?tAyye41DWSe6JUNPV-_`%915&aSR2;A7mg`By+n(M*) zhPv=xEnKkY_uqPOgyb}vIym|pl_`95J7)zYEHhzz-ghpE`uS9r=;v67TgH=zwd_o3;_y?uYqF3ah9+-+TM!PN{wSkw3p^HoE3AzX^b>RN<}rk{Qa_HJ^x?R%|2YH z*z=Egn+B@V(Xx~JkkoZG1muc0^tI1PmJqIBD6zH62`TyXU=C1R{5dIntv@~4N+J$;ig>pjjlr2IOy$FY0ri??zkAN6= zABMImXG{fcoIhqPB{=KG(j~WO+lSx9WxQW6Zhi5pL0gdyRN8Nx#e)9*ev+f!%((*9 zsm~>Qio0n@KWK`;7DyemOjrARfnRXeLp_g(xExjQ9J?{ zZt(cFRIR5Yy4%7Zx&^iMvqJA>BwIqZm81*FXFQm_u3LZPieFM4Mum!d_O4*vGfr|G zU$;6yyB6zBv`j>_L_nbxLJIkU$~xRN2q_c@s_I{@BCMzW_o?G1>7V#<`#*c`CWgl+ z7YFA9`9VHb8_V~9+b_4b>ifT)?XUa4FY)aCuzPlaj(3j^;QUYf3l5G=*be>mr-QTe z!;@pbz)wnZV3{hjdwSYbVmHsdLcNb4BlOe@3V=qh5#wmR>0XHmM7)94)o#X?sD_~4 zK))lnUB(wJw^JaFX#1y&RG>)V_RTl;FlG$S!*K8Jc1BZUVpRP>RG=||tNx(9lLUS9 zjqVnmxJD9+rx_EH#z!nE9UVV?>RmWMGprzytOP_eR91wmg9EgiraB#$(AWNS4I5V* z?7;eLa;|$A0Vb%HU*Mg7h@93 z6itcLC8DTws#HvDd}v`N=(nFfp(t%|W49;sudCGno!#;RSk4lCDc_jJ6EZHQ0ct*G z>Saf)Bt`$GW-vN=i!OdRK&L1B|Bj*vjj@>ZdWT-b7_$qNhOwP`YZJg}ML`&h%n^fS zpB}87LzYYDLvG5K=@3XJ`2xF zh6@1`qts(Gp&v-%>gdEB##`JT*->e7qyQ1&p4d?(h6ci8R@6t%WPqEnB7=Bj_NX*r zu^1S609Ow*j_Gj5ZX?NtlCxr*5;0>;Ml+Jm!QLr#{4_CqQnnF+!={K}m5v;SraadS zEe5?_xh2#t{Q5$!iI-!xjW)!Cxx=nlKTuUZeNvt9C&Uuhv_ad98i<>C;7Ov`dPYNR zCMEkW+u4k*0)^`~vllP0;UtO;LheBL*#R z6>|jLJ^Ig69Zdi)P}#boxMXN9h-ePd}_!zdKz|S*!Nb|V7UDN(2qIfK3sHo zI_mXwjHE*ys7&H(qJ$2)MRS@Jl9acqDmATz-}Z6Bple0^ySJ8y=Tg+WVJHISKrIs9&?KA@7CLVSj zg*qh~h=cxT8&S7+UO`mv?PVm@8eDH@U}@wXTq@aKrr~5T-AIDopS>HjQq>D73|H|d zI3}9Fc4yR7RN<{eH5P)!R0quzWuQgL!eB@?4!EA`#LsxS7zZR!e}`3 zR^f(VrNe&N*3+^_2raLsG+R+53`s&zgwc@5cnG2JV02G%k|B)7oZSlJ;)^Q-?u|$5 zsQa6x`z+>Pm+8;FOjpr9zu3Jv|7>`diFqE3eHS@>4@Kl|a;n;Z@keQD00{eFRp+Y` z^N***JcLtMDmstDuVFJS(UVM6%`c%~-A_gNlc`#dG&n)0I}FVirNSzFy5JnBmcEu* zF%VSayoE-HfWq~2`%MrUZG{xU#|wMC_)BZ;tD==HA)+f2==JsBd8&tZ;wT4r=u+nO zE@mX#L`cdzeg}KWp2AsjAkqbQaLh{4K6{|AdrDn_JpDL66(Z`ry zpL;$H=l_>8lID=DH%}j>jpgV6JI|hNJ+GYqzj(g&>g)Ocmv}yY9Dajt=zOGul+%X1uktLpy5&CARr~2@l-Wibv*OE&6J5@5K>m;O5L5T((bb8nF4`jVS1 zWKM(OuQSGERhIRqDI4Roe69c9@K?NO3FaljXubK$Me9Y$jU`=d5tk3{bekA{C>i$Q zswFy{>*Vj|)~1Oj4J+`f@$_yHuIgp(7xnw9{)F@TaEw=Ue&de4w-!cOiQQ=9G~zfm zIrvc_NDsAl+|=0B74$)9R2pO|3VkJ)6d!u-9e)bCccbN^&{^R!GKtBFmHpB+Zu)uZ53Os%skXb>oQL}0eQL+ zG#wDD5pah=2>`AnoIVNfOg8_Ry$jKF`3I3K0P)8Ytjue)j9M}k=J@EfL)gA*5a~K+QRTaX@!A_`q!`G3 zSz6!k?~>j5J({ZqR&Q$2XLtwTcW@O`oA18*zfII%JtCRA>@;3LIx&b5i*>w}Ug@oX z!2t;EAf|t8Z`rD1Atad(dhZ29g=lm^lI)FwUan<1R_w(Faz^wk#aBzDg{|+%sl(xn zUL%@Gw9d(td^ppc-%V50U;kw*`tH|%-57k+M+4M<`f>YH-)R_63#BuTUZYwyU2A>t z%|=b z+#S|(fIqgw+uB+(GE1v1ulxP#y2}AvbOf**%IRI8EC+RPXHWsW(1=+Io;^0tX$pDu zZ5%J5W-vn-37Sn)g62dhL848&<^yL${8!9_p)CfAyx2i zjAp3+Us>NP8hPe#SJqZWZV~*i41%Sdqn~!)9q#X59G)DH{wsr}(N_8$xTu4&@{{SH z4LHUoE(9Km(7XNJQ=84IGe;VBX;2o_hpM9=oSqOa-ccdnk!&hwz`i64Ynf8zk|qe> z&rY$FglDQo%y3FXOu}la*kzJk=B8lnV+o@~mvOYNW+Nzw>r>f;D0yGfvC3Ll^Yv6Phm~PIBg)_0fNs{Y(@IB9YH+klMECyP?Q0Tfe@Z zFCz6S(y#hWr4?yk_n&?HUE|k)9IyLv_WJ2Z>&5?RGl^f@sOU-jn(=ABb!y&qnwmJ9 zGdi82TPskz&(}t2T-inGxj=sNwDwvheb(E@W5LowlK#fVU8-@CVo7hHS}+ybssz)c zkpz&=eSm;?mU4GX!-o$a`Wu0Y;qO43 zDmHFLs{x-(&5b)#awQ?5?|)^54ZrASy-qUJL{saWZ(Gsfm} zRkwr(*}qRu_EAc1NII}dF~D~ZUh5hda`@b4I^dBxoPD@dSTYDrLZW@J9hE!O0N#7u z-x@rxmTnp9*ZrOEXEQ_H~z=ftJ}~b*f%(Xmb42Lb7%qVRQNuF170jKhr_U`e+^Lg9$GX za6PrXpB`jmqoR7$)4134nQH3iiZtFLU=x^L!O!3 zdN^CyqmVM3^qj;qoKZ0sK>~gf=HExg)6FK^@iV#Zu}pH7ri5$vHzWEX6_#sJ{gHw% zv6_S?rW`^MdM|WyS5;D70S{bN5Cs-x%}JpLt}&bIKge}lcAH8+yT40+ zDRP!2Ah3fRf+5HslsG6swI)vX8n~)65X}6myH8AK9gWa#A!k4W!${rdV!1PWnE4kM zl6`M4rL|t}uGom1OT~DvBwkw~t!#EK_#;_VrlBoRn}dpse$)~*yB>39-Dkp_8ji=A zOYLhd|K>>BGH)$8x>h@`TE^h2)&%T-Qt+B3ALMda!AMRAelG6o&MZs_`yNSIb{Ih)(l zBG2siG$mk4Show*_DeL-`~3~{J6PWR)2^p%{5L3WcD4PR?LO*TxSneu{M>*W$JK*B zfKfSz(|*VBW$+_epx@E><@1EZt55J$_jl8LhL4N6?#;5(x%$y>E#BTic#63Cn6n{d zpD&R0ZZOa?Ry7))Fghk|8cO4>;RxSv^3&{_E8!iRM}5rzeYCxW`ahCIzcDW11}aG# zIygkgKcB5vMFUkBb)4}R@6HE8q&jl87@T(Za*(MwcNJ~DRfAKCxmwkM^{@yB=q@$e zN%rW&ybK+(YQVbyxmFAFGDFTE?L+sE{51G~>YYVo_s8hN^W}@J zuknAs$m7}NL-`ahTQ}UaO>S@&lOz+0D8fXP(#F}QXhdo8&UIf*XuA%LH^Q*qv|)X0$&eXxyZ=~ zo#gnpg7hqdSa*r8ys4p<9!xBojL`4VT?V10V?KvhB2bNAJ||hctaAv}2cvcJAY?z8 zW*?;o&CT7pC!UV`N6W6S&%>XF^&b@JD5c_27XQ`jzgq6A>;KmC7hl)^FY%bYt>I(b{I}-k$C>=A=l{!{7dy54Upp_q&i^m* zd|Vka%va?b1VM~*JftVE_ZvsD*MZn{aWtQmchkU{r_Q# zWfR!tVPPwHcipBu3T5xGHwn-bIf=auNz*~J`FAhHLcnSNI{6LtC09tao)3% zjiY>W^R2b{3lkQkibAa$2#s-kP1+(uTbQPhoBrnVptb^cG1BzCC?54lJgUQBTy_C0 z0^#A0%`)*3DzU*B|Gu z>$cE4vHHcGwb<2+ev#gT&FjI7{^*_3Kj+i9|EJO%!pw302xfp4`~U4{JI|{2zn3q* zp8tK3rzQ-X<5KG}o<2Z0!g<3!zH*dzcR#1Ed;EW%13k?e4{F}$$E6K_T`2DNG|2yq z$Xmv*bC%M0@df-pp6$HYs>%PCTVLh>mv}1j#Eku^9(&IUtVRE^|M^aq;Sg}mKK#`p z{NH}Hum;wgCFdk1v1DBDy5?BMvv;e9$txF*)XTt(s)0U1yJ^a95zWSsrKY@uE6l#n zghTi2H;l_sdvsBf&$Xw=6LfHTwBNlVq^a|)DxE5L8?{b#5-Q}KDtOUk1EZ9GgQ7C2 z6+sVdW&l@j!r43|V`Y5pPVPI8%0RhamAcRWH0XbMGJd?X|G#wD z|G#`u_5XeTV(07r|BE~op`^y%TuHm*(SP2e*=fb`lqLIA@B&=>-xSHT%@6pi&iCI@ z=WF1?In8$6jW(#~zX{fl=HknU0yXf5_ZhA<5xlE6(oiL6Ml4fY@29tZ<~6WM{=1c& z7b*Gt_TQcDSJnOhtF32W<^LCX8jj(raVKlRBprV!Ewas3Y|b(&8K>EF5Hn5~2#TRI zBA*689&s&L5mVV;6gF0MtxQZ|mXCk_)uV=73u(%&#J%utM7wKK_c=5FhguG&oE5pS z3*#-7vsE^UBd1+dMmb(Ur%%Y%umDm&)K7_`sK4~|M&d) z%j*8`)%Mr>A7A9Dh(|ugv9|%#YxNmR$({Cs0HvFa-!toxEXf(oWW)*9a^~xK@qeq` zpz}+P5YFlMdJ#mw^!vX;zg#>w_0BSjFduISAH#Dfws%T2x&eo?`v@Vtr$?&L&(#B9+zGJB&$n<{5K&Lzu5iH zXRn@D?SC(x?>ze||G&iJT`8!=Mr_Io)f7XqIpNkus{`q>I51z&fBrj(`eh+sy7HO5 zgJmUIWMiN;vW69Iwvcsn@vbJBP-tB)wp~Nex?0P9)K6`svzMrEg3%_rFE-aL{z1;q)|9y$)W0#b*?TTEmD_gG6t=^n{RqHz4{cRa5|8DCY#Nt0n z{EY@Qmk{6)PNSDVzwd2UTu3%o(87sx!LCWx-p~&dG6u=W%%RB@W=i9zs>_7e-{6*O4n-sU!O_O zXlXuuJjG*q3lCg}|4eGqKZ$D7GG6yraqh$xExJzU7-@fFV;HWYFF~ztnr4#l8~-w#ebWVndhL6nq3>f|&^cj+cL^|f z-36f*IQPVA#xll3p@ES1vI|CyFz$&DCm;loazvu-JFxElE5FfSYD$=#g_n)ZJZOEM`^@i^IER_*^@ zJbS)Xi~s&?=d1nqi#&Jn=kgh&<(}ucDRTbLb-wTQ{PC{4)PX)m)Z{e^n&*I+J=1fxSqQId2`R(rd7D*Fb$U35mG@KP;djO#(pVYrizYqk_d;E z)KU7qnPI@3aw3RqMmGhEFqmyP=(uY@BwKA2C9JZ3S3g^nk>vf zi>2jsk+z|xf&_*~_wr$k=|g|GK~Hu5yk>9k-#!f60Di}*v;K~=J()lgyz=?AidlI$FOkF=MhHyiS>r|2kns2D0?O z{#d3!=!4>X6mc_H(b-BC={)>Rz&|51bQ$I^NZ!@UZ1>hs-!<2`0B`TqyICKTMvU%( zOjiV2h~M6#3kea{^CCqw7(=2|PZSbmndnlxx$ zT_i}myjZ5L-)FKW6i+iIB#n<)(x@qx>ej} zpsPM6kztj70EMCcBcpg{oK_Gvr4te_;*|Wr*mVV4_w8XQSDLshL0eD?gm})$xny}Y zB0l+0TD$8!Ui;9t2`axkHp zgxzKXF+;!p`oEBzk*pD>dhP};lHK>xrLb0-t#^aiWcln*a4P)u3Z#8P#>KQ*(0gN% z3ewsmi+n6oBqYl(ah^98p3qhNO|qM29p%m8#qsXZ;pP6poA=*WfCI;lmUMXCyVd4* zdbxbsXd{Zn>FBSQrziWDho?>WybaP)loTLoVgkf8e$z^jkXRP5HK+iuG=02#bnxhn z+jDPlKv>oK`RVT7XGQ^ha2oOW@!Rvu^MkXW4)+dPN%3V}Et+xM-QPbuI6uF<`0Hsq zj&A);3n2+yY{5ywi4aZMaxM6?-8XLzFOL56^6kOy#rv~^%eU`#zdv8u$b?{7aPl_A z)kUre^vT)Y!R4EilZ(|8Z$U&K^)uFQ>d%Dnn7m<3w#_WFyg^=bo1wH3l1G_V$~*jz zPxhDbhf$dSs9tr@2af7F%UQLpgw&2Y>sJG+rj%>@x#fvl4%E*=kMRX zJ^cT*AoqFjXtQrT4(%G+s+*>2O&uK{oFDF9?jN4DwAEoJI()ibM}4Dt3|zr?`@5%? z2gkc_-nGxpB@CV>ICnbja>j0~vWhN%-o?B2Nxcd;nTl2TH8-l5?%-^-G=Wx>P*mIA z-_hR~%}{@{f3LQ~F`N7%c{_*AM?#0Ey*>SgK3PJc~l3nIl zDoQsEZ3BB(N1SyKwC_$jh;D$igw484wfFB1j}9*`k5AqnzB^dmWRcQ2mB(yCQ?j(} zs=p2X;F4yXTZfU=WYCm8LQ&n{J30CB@D7@mcJlg>ELya!<>3ugUG2A4 zbHMSRYqA)%1c6$`8{T5h$rz_NiwRnvO0?eSX!<*%ncP6zt5^HIckjT@@v2y$6PqMS6>VMFH66aZ?(^?Do zW&QqKbI%g!4zte^ZbfI_z5o7j3Cq^cy7RP{(oEDYL6lE}dvF2XRJ!Ks8GCYc^#1tp z;;$>QYi;6g>tO|9aIihdZhpe`#pxlYvjA>K!&$psq|Rzfy0Ldur+RGjsyA|F>kXRw z^mgy4A(q}lhQ)*({QuZ{^Zqt&B~kSJ%};@$bHD6-k2$}JhMygbt z5_#;8Cx4W!WbWqUtX#sf@TOYQ)$cc=Lay3xxr(dbuaH=ZRXeU!doA`&(n+*x*QPFR z8z+_hz8jz@M*lC5V_sNvE?-prnAO(gAJiIPR5RZbB3_4cO0|6#2NG7qaiPPF%ga*t z>xoSRzprF0au-$J&@v&}YWE1cgIfR$s|1+@&L|wh-S(4CXg#P{C=QNC2h~xJ-#(W}H;;ajaxy;fU zz7pP>O>k9Vq&0ZThpWK{WNpZc{3HsHufR<*OfOh?MP!+GY%Otjw6*(hSO2rS;0E3} z-}9JYCGW9Y^cB;Gh)jn`l!)ayjkybMcd@NLtk+lnV%}#pFf6Lvg@jjBY@evU=Ri)_ z%17-$`9`?P^+4r?>YWa0h$U$}glXW_C%risluhg95neY<>!L>XTBBMMzzj#d$Tjb2 z=5HZ?)vZBoWN(sqdWa;?swU3`HR`wCs@u3eUFdv0ZMxQt@$vv%zGq}e5$M7s1Kt-5bZYhur#Q3wvk3)d*Nh#c*~tE4RZU+s{>mbMm7L?O-J+n zYXyx+h&Sh1>-t;Cr&cfQ=6nWi;<-sQr=0yxLP<*6rrniGgtvyOWsSiyHdEhf2d0ut zDnk}9tytL=w#>M$9OL6$1fx%%s=d^9-P88xg4dN2=UjGCH^llMRT7(I2O6#Kvp7B; zYX^neL2N?B5Wn~Ki6ABARhgr!r@p?kHbe~YtzhUo?u9_{dc7jkMS8s=)0*Czc(rNv zR^hx=J4fxzXGoxVVZG^H%FBO~8cwTrQ%73i*6VzAr#f5>Qu8$L7dsXX!mNG%r9RHKV8 zriZ($!6FWAs);vVNikUp)}k`Lup&MeV2|9z(bgw#^Cq#7BEBTER0nS4dgHPDnnmOg z?LB?`cnSQxv*O0I_ClWp&3z%&y+(IkFs{F3QUZDPg7QQ3(e_)mSr$4r>+v|obh1GA z?pvvGh3~32^*2O4D?OwX}##$d!2)1Q-Qgh=j8-jZsP$KYSJw-y1tR~bdcap2WOEQ^ zX-VfsVXqx0e`G|I&ACD{ZX-u)4W9I0wGL8sg&lQQK^S9^XKeC1tED~aj$$^zasE>O zy}cmERFfooNg>ygTD7Ar#T~tT9e(}-%%AzG%l~{G_H0beMiM~JtN;AyNxA;dlZOw# z*8jhgr>(Bv+*19w8>{t&<$(SI(<@ht0s33!kA~Kz0q?vT;PRPdTM5vspPn`XYyjT2 z?w5o7V>R=%@wGoWJ4B}}A)SI>Vy|ikw7{rVQ2e6gWS5qm%={0^jdd9Y?U&~K{5&&M zT^}!P1a8$o+_U95U11>sLG(FOhtVEbQO9?ERkhvz@=K=yKbCamDhM6w37#NjXjH_hIQ$ zR5V`{*|ts_HPh&6r!_shx2O!18;kr=4^Q_M!_jjcTFSeNf){%qIT(vS)&g2=(hP0e zcNbv4JIBe$8Uvf&*7|+U?Q(u8x4Koj7=5=}8lJL#Fn?+oDU?kg`D{T9`EA z+qKZv(5m=Z{!xvt@~1gR=aF}R)#<&A#fme0*-|8TG5wUJlW5iR|E4Wef6WS}V=$7izfsD^9Y(eT8|hPe8#PjYAl5s z;hWr9934LM-KAtKx|LpR8fEu+h}CB!k{lo9?)<$FchSQqkMmZ9OVdunc&vVC>^z|{ z+KSa#qN&L?bgxEVWwH85f4%(s_yX2Dh*kBtryGj^4wP6yRLcMB||E5my6sm5XO zt;PhnJpc}`W_a_3!Dc|v|EdGwCo-*pKnGB62ml+ITNxkM6QEVpZB^4nhMZtYE^Xkl zT0RSiE{LpLI9N}K;IAU&s|Z<0gnVoXfybF-KahlQEUi_;mpGjKkx@<})ICDiIHpmx z2OYcZM@d6Q1^4N{)x^M8zj69SfyI2uvoI)1ge(fePrhnX7}^s#3yd7%13tCyVU9(ih&$-Je~ z9&@}rJ@Kmo@c9*hg0TI#Y*15;{Re~yi1`hxAweg2aq<2_GEO@8 z&@t?+=vcj15S5986U`XBqJxK4KSjs`fq%2EWyb2<+K zag%l)1Ot54c@W4++IjH*ckZFLm{XPsbn@b*=maLEPbZ)e!MnO0XTSd$1*BX5=P!?5 zynY!>qRo%dy8aIyJ*=+(gNKiwd|m%{@%-n%^?E&o)3j%begHqb{x8(){j<}#m;Y^~ zK!gTU^jzmS?R4B*DiBT(OG#o9TdA`I;W+N48BduYXhMX*BZ3B;T@jAt7)$k4M1(f6 z4;e=xOH8JY9W@PBLVYEq`eiqX?nxFq2-zgX2_*sqD9VKT zPBogKh!Fv16FN!bDZD;@AE?@n}i}OyW-|wqg zU@_@@gOo~uI7u18QG_Pb9{k(VEgWMmMPL%%D$3d9xAs$-2#MoZe+lPO+lfn$s|M_- z@lO)TS(Js4J*@*ohXK%lF)1X+sX!RLt4`mD%5gUEhu_VMwC_qz$gVp1Ruc1Wqllz2 zn=0xcmZ;8uaz?7W`-0(W+Xh3ROsJVtllAUL5>N8>3h_XUw=H`hcef=VJf zogT{ZMf<`2cmL@0bO#TEgJ4hnb@mpeoLy6)7?<0P-!gEPM1;pvSPsdMVfsM6aljNMUTy6^4WRKn^vOUWPv>v}xWl`)W5LF_8pb`;+9cX6<~L&+;#- zB<5tou8BaFKYY@%Ny-wENP(~rETmu)cC4d0Nl#M@A9xI9_}`IH{do`l02ysO>UKIa z1g4nUXNF!7oi$9&&LYnY!2uf0Iy2O3dQi)|_Aj8{zRt^|>t>&m5fze8`+9VP;0s74 zjGzVLrb#`#{cg99s{Nj2ajfrdM8DFn>rvaX^t}zjpb=os@l^Hu?zd9ECN0r%jD_f< z0=yUAD-d~SE`t}+DZIACb`f4Zp>AQG0IKsRcKIn?`LVoE`MsVumgkClsC&CUW>zAnJKuejRk^yivpxL*#09sk4=$Al~c+~gWmq3$vgtq8p zl1b2SB_0V-1vydDkR%a_wpRx2VX(g+eAkP}fa0XLzu)6~eIK-lj);)`2GI0dyNli6 zDH3CR@c79g#z7DS=*(=>40Zv~h0RjiL3D@&kvr&y#xb&qilHBcuwAkhkaN(|ERJ;? zVcmqPw_W6Qv4bVVd^#9PK9qtKs?*%}sG=$rO`GisN{i%N=*H zcbAziSMC-_D0MbehsDbIV@28925G(MYyC!%!-BpDNqlms?-nD)=Xh2ohx7SafF3R6 zsP`jU8?9BJmC13H4T$lyn)~?-eb0DEOvsLZy1Ldqpe=nY1T#R0Q#_zCm6QnUq9cgh z_`;}%bVYI$+#Tk0F!L#3f{~E%1^Kd`9I*f@)-6IAAO~#mFW_9h0CyaLmcoWcGhl-qqUhmk?B+0@IK44y6o^gGUw|Z#&h#aW())Airi6OinqR}8Pc)EDE|meSVYj4 zqDsoyfCzmg9H=%zhZo@_(#AVu{<94XS4AY*{ASa1U}^oPh8zawCUP7blqAd7h$2OP zH<25Ook9OIJW7;yMNCNAU09;lkpuHl^O{jR%Se3jw6Nr$iB8Y6AVq*2VL6$^5XOYnbc83#(^YXKX~j@Q_ZCkB?arb8KLOVY zNtMz9$C{X7@OQH*(eiHc+EUuV@$$ zjHLq{Uj5v(>YP?;TY}gybzuG%dQK3IuBjl=j=orjZtYCQg>R@p7^O@IU>M*hDyN83 zarJMTA;)T3sU`=HaWXn)?25Kq!(Ku|6hcdVu9t*QXaY{3u#O@+91^ZHlLTtsU=GR} zyCI;=Dz!IDbYu|l7Qx{dG5B&^`NluS1=2>sCR00c|j&QbtlId)MB@MykAxJ#z8Lve}D!*dr#!y`5 zS)Uw3OyiT`DLW%N?y+{U{Gzryk>4xsXzW>%7>6Z$dgnwJJVkVf!k8*iq6UETAGnjL z#HC7fT&E3aLQ)$lP#)A>HgSrZ}Y8Kdg>X?duj%uSIR`ou!5xSERUP9CxVs=VVB@ zH6+*IPZLWk0qzx4drU7*{x6Ok<&)hE{Va^%jL;@^ERbuBPK*Q15*UNmd;5fd9;X9f z7U!|`$x#R;Z?u(qTftE##|%{Kt>dF@G{}-D23J@4`HX@&q-%3WIkiBww;7b*AiS_a zei`_eo=uVCC(>dibmXvmh~nkHC^^d8NbMlCXO=o%k*xmQe@D-z$?<&_$H(K+rG9Sy zVH`{`YEva83Yk4udxQ_OI7XrB$KE;kwA<>N6a@Y40R3Y0S%}b}2})xe!lvF2F=Qv} zD-BmGo52F)SX1w?S0~5KB6SJw7!WjJSpsT$A|%0)2`tjsDda*nQ9TVgo1kJ!5XMn) za&{Z$s*x-!b4Sct?wKlsoMAb(c)7)(rOtg}5BM<~LG))}-1n5m3WPX6dj9<6^7Vhc zfA!{vi#{UBHRUXUTbpalDX27?d1k2JTap@@99c{!RGu=3UR~UD{2G5i-_w{l*Gk5} zq>HB+>OXn>_~DbK7s~{HIIpHlnQ#a{eF?U&w|o;?aDqlu*6G(3a2!GnT|t zrG4O760YwQbkv{yR{RI-z&MKF$_>Y^vrG`<(RgNnTiU!n%dPeAz0g_rTS^FjA5jr1 zZEO1e>RZvzeZ#VZ%IVpBy5!_IwqH3MwthZ;CAJmT1A-!Ulf(>1c?73(i9vAVh-3OM ze2Z}pD~r;?EX*C`CAgE;@dQmqYPXd>@?a4`;EvrBB*i-WUrfcVyB_=8q4e(e0~}tF zBzhl5IBh`F_d2G@X#P!$+gb9{nfv}-jNM?Wxc~A$B^-mJZG%l*n#qhg#lwAP;r8?gnUThf+?ONG0r52QAd|8niN|h z#v{VF=bq5ld^SN2@T*qh{zsfdF-(RkMx}w*y_H+XPf8aPIXM|H0U67C^QJFe3^ujPjWO1U25+kZD zy82e28%(9JY0C`TsFTeHDlPhgB(N)8(KtqejuISiUJIF_{{F$<3I}{R!o5tc-{N+| zAo7lIbtZ5>1SuJ^5dQ+)vA+p&kaW@(&+=z^W~l$@;gj#yUM!|C z>R*66zI(L40y)$X^aAeS7YZDu;A@RJq-jv!B7K1`0`&44#~IlFut3;lce!oDR|BLg zD(N0M=4oLNWo@-CceMW^X|l53;gMsW76z_zWv#2fYm$>e)t{8nMD|pl(IANWmQ3b0 zihLkp2BebZ+b2mU#N-||0Wd{1ZAn6}rLH)GtCklh9p&Ne0hB41-A%&1G6an=y+!qMPBgUy5PXcEkp#s_m=toG|?&q%r^T>n=2{Dvn zBT{$eOUVj3Vw#Ky59(HqyI3&J$3h8FiS!p=)IIIS$)Q9&%Va5l!_eWPOb63?<7ln= z%us(xTUZl0t_VqSTo8fKK<+-bE{uU`cnU8yI*?CJxg)(kPKXSus~i^ zTr#{nWo&J|W0Bo<*1ErHGgyT#1A=gxYN1(h+`rA;cZ1|;W|0=|XrP5Ag!)%W!MSBd zSv_JQy2eRJqD2^_ojYt#pF!)YfpnAPXkd^Q?r5L|5Ud=Ge?_MGxPktlzgd@$)zh~U zEHh5NkMaD=$yt8L;w%>EM*U?v(5V=pMowfsC-b0TxNCFn>nza;wu}xBnH)B|dR7nM zh;X_{Is)XYVXs~sow=L@U*fa6e}^JR#_1v-&NLmokbCVo`B^MHt9T^AWVkLeIulB+i+ea||$E`r+1H~0!v#quuTm!O?3PoDC#&7knb9b>gY@qQJzVRCQA7*KKxp^!l%{=0?0d{Nwneh zwjMbYK+z(ppI@9>D+dlkmL<{=Mi9)yv5klHxaf14j@Kkddb0pI&in)wnuwM#Uz9vu zlN?x(g}CE67DTZKRPDSO6HZD*(dk_btJo#6IkV29&ziD>M&DBs&rh-kt=s~EDyF$+ z3JJkLWNc+L+Cc(Ojx>=@@r3N4Fxf#whT8!;k@{Omek;f5ew4h|rNG}~DLEZvlH6Ad zZ`A|eS8{BS99ZX`5c+O)@7ErL?i<44(GHRJA}*#)m5 z8|(z9DNU9t#ZpU-HMG(t^M*w>ACzC}?u&ZXCkOa3HhQ|4L4FnlU0fcWUn+Wd!S#w= zF1{d=Y=9hBG;K_gWe2&qqA64-y|{Q)NR)-P6sKcdCW#dip4^#lZ2{7C$#LCI3O$IX zmv@MRv;#EKdZ#|*-}f?h-B+ZsKO`(6_t!^tA=FmQ8|KL2&*y8k9h_k~E+?$`1yl`v zu7&nGkDj7}$xrcRte6?<@3K@@%E<02baxf#RiV&Kjz&xRg=Ylwh@!vxGAIGhdK;}G z$MMnkG$yUVbTf2(R7hSjG+zWZ`(8;CIX*(*=K%IVbDU|R|K{kqJ~`am zt=ZFr=^rbR+bYISv&n#PC7_%Y#C+>lV!IWJ_e-%4x=5H!165r{#jn-57biNgOQJSW z_vH>E!6-moAsN5wZhVzg_g9_4hDEPkikIeUG&6L@lpf%c!Q4u9;U>V}aJbApCpen+ zbHEoVLgsmNDhy)yq|p<1(}0(Rv;};T+Il6xasJ7zL*D>+mPS|-mqDR93)auj5DC)~ z@?U{9JkKuZ3Ed4oGt@t4aZHnu2En8y@m)jV^4R=Z4*MGijD(ex?`NwW=v_8Dn~TGCJ&>`vzHk2m$4W3&XXaT?zN#_A?08b?C-8J+x`$-Y-ghiwX zb?pM3p;H!-GRaMby4!`kf#NlQms6vAfWu;hEaFg6{DQQh|YE$j_|OBNG8x0WuN zq07ACodaISDw3rvW~1pv$_b8+S)%rITCuSxz;#2UTOzM%4I)VBRygEL2sC9GcW!ui z!jcixLdiJkMNnwEW%q3WJcXPUP=4x|C6auQwYPNDG;?ZSypQa+$b7s$f$Jzo5xUy*_ zinjvozT6n#OHmw#KV``|2P$uSaDLN*#34vtpHxX0Tlpm5-V*|<(6@QEx&F9DgfRjR%)fn-B7o5V_!RJjAt6~*T-&L*+aBvtMP@Y<^sod$7^s*+0;zx}Pi zSqFIOy0Hp)qpH#>Rc;xV2B}g2yirxDmnwHd{RXL00K8FEX^<)axj;t0cLI5XR4D-7 zsH!wdl{)~vL8=r0Z&XzprOMp^UME#_QrcI(u2g?{RY`bj^(&O#I*->K-8A6m1#w&} z4l95=5q`^%w*r3Q&3MCM8B$e4wPT$)*yh2#WqLOPu0*#>pVW3idlW@Fla_aqm#mlz zIAym`X`sRADQHB(`H5;Z;HL52!ro-9jRt|fZ=B;7uDAT%hzi*HF`j%hcpRGds8eVB0# zS!Wg+#32BVKm45FR?zbVP;&sEV5nC#!4c$#axwO60baRv(;i#r&yS8*bk(w5-=f2o zbIDr56RXK7YJ-pK+=vRouW3k32-=**mzR07>xvB_*-_p@(XzQrVrzFquY;?-j7-t* z!8$AyyI5rkEnJ%a>fnNm?&@DfDqONFlJu2;%_QqV16{#fw{lUUQnj-V(@RR(R(j!9 z$D$eX9FMdNZn-`W)bJ5s_}-vIS~kY4a>5bzY^b zJs!QZ_&6h6KoYBvEFnc!kQr6yO#fxObXY+aw0>fwevW$iWL>=pjj+VX`@&RrID30s zrfd^_h4F-B9FGXNGWFpw`SuuH=pPaMT9hF$ymmRy$7_xdsE${36qq6FIgopf;3Ut* z?zlptw`R~*C+o_17|uJdS)?66G=4|=5Cp%@Ll2aru2S@W;Z%}0Nl3c6u2h{r1Nm`` z=|st#Go7oU0V|CZG!`q-b5aaW(|24D2(N^g!Q{qNgSJ(Zu`hpTs9%i?nG4E1h$x3?oLaeWhE}s`gzIYjLjOgICRC3<&-Gni`xMSl|Jxs$a@17$r6{Ur z1-Z14x91%G)Y9(dhm?toFC*$41wNZwdk#XQ1YJzK`iw5_3xH7A!W;c*6&ZfY281U> z5@Gc&?Nobb&kXgCwS&&dSqaDj5-H=dJ}JNq9Zmj7O~##LU~s7JsgH7zE+FL9wYQxp z6+<7r0;H2q5{^Qg6hEeNjQX*8Edm*)=ov~_QYbp#vSAgFh^UZfwTR4YIds(oQZYb+ zDV_K8Zt`v|ii9aBP=iOI#5pv&BhZ&ef~1qEX(k*JFV9}TKrd`LTBpB(^Ag+V7xw=UM66MSe28qj87oQE0mYO6rNYqsxXV?!S?7NhB~+7ix2wD( zGDH2blxa^$TybGlnVn@T(tkVsfW>Z{3_ zC=UQx9m|g<=^wWab_vpE149cEMd?(7gpyTXG7?qkR79dqR()|uRHai9iHfYc{bzY3 zstda`6UAkI7tabaQ4z5XGf^jSKQ9uH2BWsXQl+jE`H(U}?46GlxVQPVq)aIw5i=Y; z$1zSq!Y?3B;T$I;BKq1R{MT&J66QX9sw%H7Di$2RDamn#;NJB3hLw*CRvpMN_5_EE=19NU3oY!h!PZ%_#aiY!gh6+M%c4lcjkykH&We1O`7p{zG+ka4 zkZ8Wq&XKsw+!*U3@gu=eOhoPsY=8J{*er^KAVN@<995&o)l9&C6wU7erq#eU~NO9btY&sQoHdY zPVuIx3q1rx@&`l6LI&u+Sq9E#39)JU zO^Pzf(EZ&9kQkfsh;Um-3tqzg(9x^sjxMHnOx%!}eTMqGZ5O#d5|_32b~AKhhSGQB zcY0fALFk`M(ikQjLQisF~kN9pzD$I4eNVqy^F$-~A^1!r6wCxk# z!p0>BD22{R37r64GE*_AknR#^l8s1W5;W|fG{zx8keXL#Fd$s^%(=2C#TQ-JvN4;L zTiBKK;SLQujcUQrL_1&9%(3$WSYaj>TG)cb!wWh}sshSODClwtdaG6Yc_D0!wUFai zBS(eDb0OoaJH#%E1f1-CWHk}q+7YEDJ*F$EV-qN;L$|$~uEAmT^e*$x69pucEUiJ} zC_$KWJk{WNXkb2|l4Cvv!R5L4T8TR#s=28a<4J=ofq5Jg1kTGKF*b$7c@|f*nKsUZ zb|9>PS~COds#i-PQJWH9BOzl^v#RfixfVr2G-gqqp<^Ao0n*9K`>V)mQ>WhUvnUeg zzcm@v+>WiC5rOZmKby^qdK49^c>m)c?#&sc~yawC)o{B)}qO%}efN_ktz& zrL7fiEjKz3m|ER_-RxUKqSZmAgoKkexwI|lPQ@9poZlUCHtFUv7ZR79GHFWTSaO=X>K8~-AG5BoNn2=j@b!>8ATrM``*1Q;-I@auAZ0rk^w{Z&=tlTsi zdVxsFvWf4b%ZmgXi1_T+9m)bAHSV#KqTXl`Zh; zt}p!x_C@$?xq3WQr$mo{@S)N!bP4VSo>l1gI~zcj-U9tD&AeKtf4z+|t>8$^M?^Yn zd|p9az5JaGkf~hhEv8^~_&9;VX_8keo}qL7qqZjsQ=mJBETsY~jZv6Hx^9^)v3Q_oe4KdaEM=GxAB6L=|Y z6(vhR-w}K@mR1X2opp6BAQyr!m+I=^Qm?;M43D|JvG}LWHSYCw8LSq;Dxg}`B{D8P6~%fL`qk=JxlX0a-j*S8+SGDky9=$~5`4UB z3(Sk0!^<5_Fr@%kgWh0@ekAc^S*u6${-#f!Ckd6v*-@5wAV9XL8gEtk(LUxnD)lh^+keAt3Y{+AeH2_;; zTL-i1lbvL!?@|gM)}@1PGgvhsMkjbg0!~I$NZybOUZ*PaFw))h(!3u8{UF=Vl6~{xayE-2X8XAX#B4OQ`EO5*NgVgv5tDe-YUx-MF^NZ; z#wbT@f4>)z0mVsgf4|4Swc$Xmh(%PLIGS)<95LOG^|ZXfQzXXt;PI0~jDsL>#itW( zqNF0f5#2#_hy;;4dShiap_V>lj#@0+t%#*r9Jf_gS`;zW&+XJ*nxX#5@RUg?W06#9 zi?kuuTv{(TD(Lmwb27r*?dtn1ETA41+(mBuX*M1=Aht+q@V3RPLgYM zjX70nhHxGpG(qpm88v>}8cUgq!`glyu{Zsf_{b|oidcYGCt9laH$rYoD8+UhJx!hhPQH@g_(0*3OXGtO$ZLho)?R@GAmg6y`CTvU6JWC zsI&8K$NlrSKEiyI>1$ht`ePDLpz1u1o@LC84C(B%TJ|p){Tv6MC3& zf;8;Nz^jWDLDxPW{h-tNCpvv|`SK9GNkX&NLa9{siLTH{q8&ux?}SN|G9jqaqt)RY z)MgkJr%>2YL2_T%E0B@wzF%wvampBPI{&yC6zl0Htm>LMs1MMSoUb5r;tMZ zJbJCj!D69w6PH&n=yZ-u1xc8z9fZ+;AH9ABC7w+xLGA2kP9CQ4lofxTkTE8PRA� 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 l+k6&F-SMB$Eh^8?^Yi>XKTq%Ze*pjh|Nm Date: Mon, 12 Feb 2024 15:37:26 +0100 Subject: [PATCH 089/146] fix studio cm --- scaleout/stackn/templates/studio-settings-configmap.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 3a43a04f..faf9f9a8 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -106,9 +106,10 @@ data: 'rest_framework', 'django.contrib.staticfiles', 'corsheaders', + 'django_extensions', # for executing runscript among others + 'django_filters', 'guardian', "projects", - "models", "apps", "api", "system", @@ -263,7 +264,7 @@ data: LOGOUT_URL = 'logout' INACTIVE_USERS = {{ if .Values.studio.inactive_users }}True{{ else }}False{{ end }} - # For Model Objects creation (check models/models.py, pre_save_model() ) + # Specific to Studio stack: VERSION_BACKEND = 'studio.version.Version' # Other Helm/k8s deployment settings From bb85dc1a423a664921e93b7072db3a5d668fd405 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 12 Feb 2024 16:48:36 +0100 Subject: [PATCH 090/146] remove redis and rabbitmq --- scaleout/stackn/charts/redis-17.7.4.tgz | Bin 92455 -> 0 bytes scaleout/stackn/requirements.yaml | 5 --- scaleout/stackn/templates/_helper.tpl | 3 +- .../stackn/templates/studio-deployment.yaml | 5 --- scaleout/stackn/values.yaml | 33 ++---------------- 5 files changed, 4 insertions(+), 42 deletions(-) delete mode 100644 scaleout/stackn/charts/redis-17.7.4.tgz diff --git a/scaleout/stackn/charts/redis-17.7.4.tgz b/scaleout/stackn/charts/redis-17.7.4.tgz deleted file mode 100644 index 7679d02fd87438f3c32a13b8dd4222f160d6431b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92455 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

      qK%(tYsRnD|5?N1HKqZr#wqc}K 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 diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index 53598fc8..ba368972 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -10,11 +10,6 @@ dependencies: version: 12.2.7 repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled - - - name: redis - version: 17.7.4 - repository: https://charts.bitnami.com/bitnami - condition: redis.enabled - name: common repository: https://charts.bitnami.com/bitnami diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index d8800158..174c6753 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -102,6 +102,7 @@ Return postgres secret {{- end -}} {{- end -}} + {{/* Return STACKn studio storageClass */}} @@ -126,4 +127,4 @@ Return STACKn studio media storageClass {{- else -}} {{- .Values.global.postgresql.storageClass -}} {{- end -}} -{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 9ec1eb29..dc3e6e31 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -109,11 +109,6 @@ spec: key: password - name: POSTGRES_USER value: {{ .Values.postgresql.global.postgresql.auth.user }} - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "stackn.redis.secretName" . }} - key: {{ include "stackn.redis.secretPasswordKey" . }} - name: DJANGO_SECRET valueFrom: secretKeyRef: diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 54d7f306..bc8f7842 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -4,8 +4,8 @@ # NOTES: # - set a storage class everywhere you can see storageClass: "" # - if you want to use an existing secret, set the name of the secret everywhere you see existingSecret: "" -# furthermore, the Bitnami subcharts (postgresql, redis, rabbitmq) also usually have a existingSecret value -# - Bitnami subcharts (postgresql, redis, rabbitmq) also usually have existingStorage values +# furthermore, the Bitnami subcharts (postgresql) also usually have a existingSecret value +# - Bitnami subcharts (postgresql) also usually have existingStorage values # - if NetworkPolicy is enabled, set the kubernetes api server endpoints and port # - Please set all values named password, the chart do have features to generate passwords, # but this is not always working as expected during upgrades. @@ -223,35 +223,6 @@ postgresql: cpu: "1000m" memory: "1Gi" -## Redis chart for stateful caching ## -# Please see the documentation for this Bitnami chart for more details on values: -# https://github.com/bitnami/charts/tree/main/bitnami/redis -# Please also observe the version we are using in requirements.yaml - -redis: - enabled: true - commonAnnotations: {"reloader.stakater.com/auto": "true"} # Required for reloader to work - master: - podLabels: {"app":"stackn-studio"} # Do not change unless you know what you are doing. - resources: - requests: - cpu: "100m" - memory: "256Mi" - limits: - cpu: "1000m" - memory: "1Gi" - replica: - replicaCount: 1 - podLabels: {"app":"stackn-studio"} - resources: - requests: - cpu: "100m" - memory: "256Mi" - limits: - cpu: "1000m" - memory: "1Gi" - - eventListener: studioServiceName: "studio-studio" studioServicePort: "8080" From 3b81e0e21566bf4f3b97d29fa0832a1c7e008158 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 12 Feb 2024 18:21:38 +0100 Subject: [PATCH 091/146] remove rabbit-parrword --- scaleout/stackn/templates/basic-secrets.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/scaleout/stackn/templates/basic-secrets.yaml b/scaleout/stackn/templates/basic-secrets.yaml index 8f960988..21552c96 100644 --- a/scaleout/stackn/templates/basic-secrets.yaml +++ b/scaleout/stackn/templates/basic-secrets.yaml @@ -10,7 +10,6 @@ type: Opaque data: studio-superuser-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-superuser-password" "providedValues" (list "global.studio.superuserPassword" "studio.superuserPassword") "context" $) }} studio-event-listener-user-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-event-listener-user-password" "providedValues" (list "global.studio.eventListenerUserPassword" "studio.eventListenerUserPassword") "context" $) }} - rabbit-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "rabbit-password" "providedValues" (list "rabbit.password") "context" $) }} django-secret-key: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "django-secret-key" "providedValues" (list "studio.djangoSecret") "length" 50 "strong" true "context" $) }} {{ if .Values.studio.emailService.enabled }} email-host-user: {{ .Values.studio.emailService.hostUser | b64enc }} From 42321a398b9dc0c66dcce69c6306d88c91da10a9 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 12 Feb 2024 20:03:35 +0100 Subject: [PATCH 092/146] argocd token as in secret --- scaleout/stackn/templates/basic-secrets.yaml | 1 + scaleout/stackn/templates/studio-deployment.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/basic-secrets.yaml b/scaleout/stackn/templates/basic-secrets.yaml index 21552c96..642d2c51 100644 --- a/scaleout/stackn/templates/basic-secrets.yaml +++ b/scaleout/stackn/templates/basic-secrets.yaml @@ -10,6 +10,7 @@ type: Opaque data: studio-superuser-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-superuser-password" "providedValues" (list "global.studio.superuserPassword" "studio.superuserPassword") "context" $) }} studio-event-listener-user-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-event-listener-user-password" "providedValues" (list "global.studio.eventListenerUserPassword" "studio.eventListenerUserPassword") "context" $) }} + studio-argocd-token: {{ .Values.argocd.token | b64enc }} django-secret-key: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "django-secret-key" "providedValues" (list "studio.djangoSecret") "length" 50 "strong" true "context" $) }} {{ if .Values.studio.emailService.enabled }} email-host-user: {{ .Values.studio.emailService.hostUser | b64enc }} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index dc3e6e31..bb7935ec 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -140,7 +140,7 @@ spec: valueFrom: secretKeyRef: name: {{ include "stackn.secretName" . }} - key: argo-cd-token + key: studio-argocd-token {{ end }} image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} From 6b4220136a0e63f18e1840aadb83fbc8d617a52a Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 12 Feb 2024 21:29:51 +0100 Subject: [PATCH 093/146] edit studio cm --- scaleout/stackn/templates/studio-settings-configmap.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index faf9f9a8..54c9222b 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -290,9 +290,6 @@ data: PROJECTLOG_MODEL = "projects.ProjectLog" ENVIRONMENT_MODEL = "projects.Environment" RELEASENAME_MODEL = "projects.ReleaseName" - # Portal - PUBLISHEDMODEL_MODEL = "portal.PublishedModel" - PUBLICMODELOBJECT_MODEL = "portal.PublicModelObject" # App statuses APPS_STATUS_SUCCESS = ['Running', 'Succeeded', 'Success'] @@ -331,9 +328,6 @@ data: MIGRATION_MODULES = { 'apps': 'studio.migrations.apps', - 'models': 'studio.migrations.models', - 'monitor': 'studio.migrations.monitor', - 'portal': 'studio.migrations.portal', 'projects': 'studio.migrations.projects', 'system': 'studio.migrations.system' } @@ -382,3 +376,4 @@ data: ARGO_CD_ENABLED = os.environ.get("ARGO_CD_ENABLED", False) ARGO_CD_API_URL = os.environ.get("ARGO_CD_API_URL", None) ARGO_CD_TOKEN = os.environ.get("ARGO_CD_TOKEN", None) + S3HOST = os.environ.get("S3HOST", "minio-fedn") From 7b1b8a91501fb898cb2e2e71270e0fef6351414f Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Wed, 14 Feb 2024 15:55:35 +0100 Subject: [PATCH 094/146] Fixes --- scaleout/stackn/requirements.yaml | 5 + .../stackn/templates/network-policies.yaml | 570 +++++++++--------- .../stackn/templates/studio-deployment.yaml | 2 + .../templates/studio-settings-configmap.yaml | 3 +- scaleout/stackn/values.yaml | 9 + 5 files changed, 303 insertions(+), 286 deletions(-) diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index ba368972..3059e095 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -16,3 +16,8 @@ dependencies: tags: - bitnami-common version: 2.0.4 + + # - name: minio-operator + # version: 4.3.7 + # repository: https://operator.min.io + # condition: minio.enabled diff --git a/scaleout/stackn/templates/network-policies.yaml b/scaleout/stackn/templates/network-policies.yaml index d5d9ab3e..bfbaee76 100644 --- a/scaleout/stackn/templates/network-policies.yaml +++ b/scaleout/stackn/templates/network-policies.yaml @@ -1,286 +1,286 @@ -{{- if .Values.networkPolicy.enable }} -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny-ingress - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny-egress - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: {} - policyTypes: - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 ---- -# Certain services (such as celery-workers) need to allow egress to k8s api-server -# To get the IP and port (usually 6443) of the api-server: -# $ kubectl get endpoints kubernetes -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: {{ .Release.Name }}-allow-api-access - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - allow-api-access: "true" - policyTypes: - - Egress - egress: - - to: - - ipBlock: - cidr: {{ .Values.networkPolicy.kubernetes.cidr }} - ports: - - protocol: TCP - port: {{ .Values.networkPolicy.kubernetes.port }} ---- -{{- if .Values.reloader.enabled }} -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: reloader-allow-api-access - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - app: {{ .Release.Name }}-reloader - policyTypes: - - Egress - egress: - - to: - - ipBlock: - cidr: {{ .Values.networkPolicy.kubernetes.cidr }} - ports: - - protocol: TCP - port: {{ .Values.networkPolicy.kubernetes.port }} ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-egress-to-reloader - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - app: {{ .Release.Name }}-reloader - policyTypes: - - Egress - egress: - - to: - - podSelector: - matchLabels: - app: {{ .Release.Name }}-reloader ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-ingress-from-reloader - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - app: {{ .Release.Name }}-reloader - policyTypes: - - Ingress - ingress: - - from: - - podSelector: - matchLabels: - app: {{ .Release.Name }}-reloader ---- -{{- end }} -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-egress-to-studio - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - app: stackn-studio - policyTypes: - - Egress - egress: - - to: - - podSelector: - matchLabels: - app: stackn-studio ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-egress-to-studio-web - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - networking/allow-egress-to-studio-web: "true" - policyTypes: - - Egress - egress: - - to: - - podSelector: - matchLabels: - web: studio-web ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-ingress-from-project-to-studio-web - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - web: studio-web - policyTypes: - - Ingress - ingress: - - from: - - podSelector: - matchLabels: - app: lab ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-egress-from-celery-worker-to-project - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - name: {{ .Release.Name }}-celery-worker - policyTypes: - - Egress - egress: - - to: - - podSelector: - matchLabels: - app: mlflow ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-egress-from-studio-web-to-project - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - web: studio-web - policyTypes: - - Egress - egress: - - to: - - podSelector: - matchLabels: - app: fedn-api-server ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-egress-from-studio-web-to-minio - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - web: studio-web - policyTypes: - - Egress - egress: - - to: - - podSelector: - matchLabels: - app: minio ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-ingress-from-studio - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - app: stackn-studio - policyTypes: - - Ingress - ingress: - - from: - - podSelector: - matchLabels: - app: stackn-studio ---- -# To limit this egress rule for internal IPs, set -# .Values.networkPolicy.internal_cidr -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-internet-egress - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - networking/allow-internet-egress: "true" - policyTypes: - - Egress - egress: - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - {{- range $cidr := .Values.networkPolicy.internal_cidr }} - - {{ $cidr }} - {{- end }} +# {{- if .Values.networkPolicy.enable }} +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: default-deny-ingress +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: {} +# policyTypes: +# - Ingress +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: default-deny-egress +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: {} +# policyTypes: +# - Egress +# egress: +# - to: +# - namespaceSelector: +# matchLabels: +# kubernetes.io/metadata.name: kube-system +# ports: +# - protocol: UDP +# port: 53 +# - protocol: TCP +# port: 53 +# --- +# # Certain services (such as celery-workers) need to allow egress to k8s api-server +# # To get the IP and port (usually 6443) of the api-server: +# # $ kubectl get endpoints kubernetes +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: {{ .Release.Name }}-allow-api-access +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# allow-api-access: "true" +# policyTypes: +# - Egress +# egress: +# - to: +# - ipBlock: +# cidr: {{ .Values.networkPolicy.kubernetes.cidr }} +# ports: +# - protocol: TCP +# port: {{ .Values.networkPolicy.kubernetes.port }} +# --- +# {{- if .Values.reloader.enabled }} +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: reloader-allow-api-access +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# app: {{ .Release.Name }}-reloader +# policyTypes: +# - Egress +# egress: +# - to: +# - ipBlock: +# cidr: {{ .Values.networkPolicy.kubernetes.cidr }} +# ports: +# - protocol: TCP +# port: {{ .Values.networkPolicy.kubernetes.port }} +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-to-reloader +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# app: {{ .Release.Name }}-reloader +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# app: {{ .Release.Name }}-reloader +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-ingress-from-reloader +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# app: {{ .Release.Name }}-reloader +# policyTypes: +# - Ingress +# ingress: +# - from: +# - podSelector: +# matchLabels: +# app: {{ .Release.Name }}-reloader +# --- +# {{- end }} +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-to-studio +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# app: stackn-studio +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# app: stackn-studio +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-to-studio-web +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# networking/allow-egress-to-studio-web: "true" +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# web: studio-web +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-ingress-from-project-to-studio-web +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# web: studio-web +# policyTypes: +# - Ingress +# ingress: +# - from: +# - podSelector: +# matchLabels: +# app: lab +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-from-celery-worker-to-project +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# name: {{ .Release.Name }}-celery-worker +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# app: mlflow +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-from-studio-web-to-project +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# web: studio-web +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# app: fedn-api-server +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-egress-from-studio-web-to-minio +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# web: studio-web +# policyTypes: +# - Egress +# egress: +# - to: +# - podSelector: +# matchLabels: +# app: minio +# --- +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-ingress-from-studio +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# app: stackn-studio +# policyTypes: +# - Ingress +# ingress: +# - from: +# - podSelector: +# matchLabels: +# app: stackn-studio +# --- +# # To limit this egress rule for internal IPs, set +# # .Values.networkPolicy.internal_cidr +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-internet-egress +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# networking/allow-internet-egress: "true" +# policyTypes: +# - Egress +# egress: +# - to: +# - ipBlock: +# cidr: 0.0.0.0/0 +# except: +# {{- range $cidr := .Values.networkPolicy.internal_cidr }} +# - {{ $cidr }} +# {{- end }} ---- -#This rule might not be needed, but is here for utility. Currently no resources use this rule. -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-internet-ingress - namespace: {{ .Values.namespace | default "default" }} -spec: - podSelector: - matchLabels: - networking/allow-internet-ingress: "true" - policyTypes: - - Ingress - ingress: - - from: - - ipBlock: - cidr: 0.0.0.0/0 - except: - {{- range $cidr := .Values.networkPolicy.internal_cidr }} - - {{ $cidr }} - {{- end }} ---- -kind: NetworkPolicy -apiVersion: networking.k8s.io/v1 -metadata: - namespace: {{ .Values.namespace | default "default" }} - name: allow-ingress-controller -spec: - podSelector: {} - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: {{ .Values.networkPolicy.ingress_controller_namespace }} # <- This should allow traffic from ingress namespace -{{- end }} +# --- +# #This rule might not be needed, but is here for utility. Currently no resources use this rule. +# apiVersion: networking.k8s.io/v1 +# kind: NetworkPolicy +# metadata: +# name: allow-internet-ingress +# namespace: {{ .Values.namespace | default "default" }} +# spec: +# podSelector: +# matchLabels: +# networking/allow-internet-ingress: "true" +# policyTypes: +# - Ingress +# ingress: +# - from: +# - ipBlock: +# cidr: 0.0.0.0/0 +# except: +# {{- range $cidr := .Values.networkPolicy.internal_cidr }} +# - {{ $cidr }} +# {{- end }} +# --- +# kind: NetworkPolicy +# apiVersion: networking.k8s.io/v1 +# metadata: +# namespace: {{ .Values.namespace | default "default" }} +# name: allow-ingress-controller +# spec: +# podSelector: {} +# ingress: +# - from: +# - namespaceSelector: +# matchLabels: +# kubernetes.io/metadata.name: {{ .Values.networkPolicy.ingress_controller_namespace }} # <- This should allow traffic from ingress namespace +# {{- end }} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index bb7935ec..10fb6f58 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -142,6 +142,8 @@ spec: name: {{ include "stackn.secretName" . }} key: studio-argocd-token {{ end }} + - name: S3HOST + value: {{ .Values.minio.host }} image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 54c9222b..82e6358a 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -201,7 +201,6 @@ data: 'django.contrib.messages.context_processors.messages', ], 'libraries': { - 'custom_tags': 'models.templatetags.custom_tags', } }, }, @@ -377,3 +376,5 @@ data: ARGO_CD_API_URL = os.environ.get("ARGO_CD_API_URL", None) ARGO_CD_TOKEN = os.environ.get("ARGO_CD_TOKEN", None) S3HOST = os.environ.get("S3HOST", "minio-fedn") + CHART_PATH = os.environ.get("CHART_PATH", "{{ .Values.studio.project.path }}") + CHART_REVISION = os.environ.get("CHART_REVISION", "{{ .Values.studio.project.revision }}") diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index bc8f7842..f4cc9565 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -163,6 +163,10 @@ studio: # studio values enabled: true url: '' token: '' + + project: + path: "charts/apps/fedn-project/chart" + revision: "feature/SK-626" # Pull secrets for studio, used to pull images from private repositories such as Harbor # To create a pull secret run: $ kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= @@ -245,3 +249,8 @@ reloader: namespace: default reloader: watchGlobally: false + +minio: + enabled: true + host: "" + secretName: minio-fedn From 6aa9c4e52520d2c91f5841430a7fd2a167289dd7 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 13 Feb 2024 12:58:34 +0100 Subject: [PATCH 095/146] mongodb --- scaleout/stackn/.helmignore | 2 ++ scaleout/stackn/charts/common-2.14.1.tgz | Bin 0 -> 13947 bytes scaleout/stackn/charts/mongodb-14.4.6.tgz | Bin 0 -> 83193 bytes scaleout/stackn/requirements.yaml | 7 ++++++- scaleout/stackn/values.yaml | 16 ++++++++++++++-- 5 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 scaleout/stackn/charts/common-2.14.1.tgz create mode 100644 scaleout/stackn/charts/mongodb-14.4.6.tgz diff --git a/scaleout/stackn/.helmignore b/scaleout/stackn/.helmignore index fe7f356e..0cfdee50 100644 --- a/scaleout/stackn/.helmignore +++ b/scaleout/stackn/.helmignore @@ -25,3 +25,5 @@ stackn-*.tgz .vscode/ modules/ examples/ +# Values file +.values-* diff --git a/scaleout/stackn/charts/common-2.14.1.tgz b/scaleout/stackn/charts/common-2.14.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..f443a7c4b9bb8917a2448f681e6dd00c53efbc81 GIT binary patch literal 13947 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 (JCQ{ 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 literal 0 HcmV?d00001 diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index 3059e095..e75e6628 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -15,7 +15,12 @@ dependencies: repository: https://charts.bitnami.com/bitnami tags: - bitnami-common - version: 2.0.4 + version: 2.14.1 + + - name: mongodb + repository: https://charts.bitnami.com/bitnami + version: 14.4.6 + condition: mongodb.enabled # - name: minio-operator # version: 4.3.7 diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index f4cc9565..1877d555 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -227,14 +227,26 @@ postgresql: cpu: "1000m" memory: "1Gi" +## MongoDB chart for FEDn statestore +# Please see the documentation for this Bitnami chart for more details on values: +# https://github.com/bitnami/charts/tree/main/bitnami/mongodb +# Please also observe the version we are using in requirements.yaml + +mongodb: + enabled: true + commonAnnotations: {"reloader.stakater.com/auto": "true"} + podLabels: {"app":"stackn-studio","allow-api-access": "true"} + + + eventListener: studioServiceName: "studio-studio" studioServicePort: "8080" appStatusEndpoint: "api/app/status" appStatusesEndpoint: "api/app/statuses" tokenEndpoint: "api/token-auth/" - image: #tell which image to deploy for studio - repository: "" #sha-da2cfdc #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + image: + repository: ghcr.io/scaleoutsystems/studio-kube-controller:main pullPolicy: Always # used to ensure that each time we redeploy always pull the latest image From 79143bbe406626ed8f22fb6c21a5b7725687d07c Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 14 Feb 2024 14:25:20 +0100 Subject: [PATCH 096/146] remove minio --- scaleout/stackn/requirements.yaml | 5 ----- scaleout/stackn/values.yaml | 5 ----- 2 files changed, 10 deletions(-) diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index e75e6628..a660b45c 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -21,8 +21,3 @@ dependencies: repository: https://charts.bitnami.com/bitnami version: 14.4.6 condition: mongodb.enabled - - # - name: minio-operator - # version: 4.3.7 - # repository: https://operator.min.io - # condition: minio.enabled diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 1877d555..111aaaf4 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -261,8 +261,3 @@ reloader: namespace: default reloader: watchGlobally: false - -minio: - enabled: true - host: "" - secretName: minio-fedn From f5760b6abefa871bc885aff03c30c030a09644d2 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 14 Feb 2024 15:00:45 +0100 Subject: [PATCH 097/146] S3 --- scaleout/stackn/templates/studio-deployment.yaml | 7 +++++++ scaleout/stackn/templates/studio-settings-configmap.yaml | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 10fb6f58..1e8a54d7 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -131,6 +131,13 @@ spec: name: {{ include "stackn.secretName" . }} key: email-api-key {{ end }} + - name: S3HOST + value: {{ .Values.minio.host }} + - name: S3PORT + value: {{ .Values.minio.port }} + - name: S3SECRET_NAME + value: {{ .Values.minio.secretName }} + {{ if .Values.studio.argocd.enabled }} - name: ARGO_CD_ENABLED value: "true" diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 82e6358a..6b54e4c1 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -376,5 +376,5 @@ data: ARGO_CD_API_URL = os.environ.get("ARGO_CD_API_URL", None) ARGO_CD_TOKEN = os.environ.get("ARGO_CD_TOKEN", None) S3HOST = os.environ.get("S3HOST", "minio-fedn") - CHART_PATH = os.environ.get("CHART_PATH", "{{ .Values.studio.project.path }}") - CHART_REVISION = os.environ.get("CHART_REVISION", "{{ .Values.studio.project.revision }}") + S3PORT = os.environ.get("S3PORT", "9000") + S3SECRET_NAME = os.environ.get("S3SECRET_NAME", "minio-fedn") From 61dd45763cefeb0a1f327f872fd622e2f54a8473 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Thu, 15 Feb 2024 10:17:28 +0100 Subject: [PATCH 098/146] update common --- scaleout/stackn/charts/common-2.0.4.tgz | Bin 14652 -> 0 bytes scaleout/stackn/requirements.yaml | 6 ++++++ 2 files changed, 6 insertions(+) delete mode 100644 scaleout/stackn/charts/common-2.0.4.tgz diff --git a/scaleout/stackn/charts/common-2.0.4.tgz b/scaleout/stackn/charts/common-2.0.4.tgz deleted file mode 100644 index 54b9a53fac7ea10fea36b00b3534bbedfd1c7989..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14652 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 diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index a660b45c..1ba1a957 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -16,6 +16,12 @@ dependencies: tags: - bitnami-common version: 2.14.1 + + # - name: minio-operator + # version: 4.3.7 + # repository: https://operator.min.io + # condition: minio.enabled + # version: 2.14.1 - name: mongodb repository: https://charts.bitnami.com/bitnami From a8906ec7f113711b39ccfe244457eb5340d967c0 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Thu, 15 Feb 2024 13:03:17 +0100 Subject: [PATCH 099/146] Fix --- scaleout/stackn/templates/studio-deployment.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 1e8a54d7..c8621b61 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -134,7 +134,7 @@ spec: - name: S3HOST value: {{ .Values.minio.host }} - name: S3PORT - value: {{ .Values.minio.port }} + value: "{{ .Values.minio.port }}" - name: S3SECRET_NAME value: {{ .Values.minio.secretName }} @@ -149,8 +149,6 @@ spec: name: {{ include "stackn.secretName" . }} key: studio-argocd-token {{ end }} - - name: S3HOST - value: {{ .Values.minio.host }} image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio From 81fb2e7a455d368e9245f6c4fe4b242c52b27a04 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Fri, 16 Feb 2024 15:30:45 +0100 Subject: [PATCH 100/146] Updated Studio deployment with S3 creds as environment variables. --- scaleout/stackn/templates/studio-deployment.yaml | 11 ++++++++++- .../stackn/templates/studio-settings-configmap.yaml | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index c8621b61..d1a844ea 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -137,7 +137,16 @@ spec: value: "{{ .Values.minio.port }}" - name: S3SECRET_NAME value: {{ .Values.minio.secretName }} - + - name: S3ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.minio.secretName }} + key: accessKey + - name: S3SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.minio.secretName }} + key: secretKey {{ if .Values.studio.argocd.enabled }} - name: ARGO_CD_ENABLED value: "true" diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 6b54e4c1..db231430 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -378,3 +378,8 @@ data: S3HOST = os.environ.get("S3HOST", "minio-fedn") S3PORT = os.environ.get("S3PORT", "9000") S3SECRET_NAME = os.environ.get("S3SECRET_NAME", "minio-fedn") + S3ACCESS_KEY = os.environ.get("S3ACCESS_KEY", "") + S3SECRET_KEY = os.environ.get("S3SECRET_KEY", "") + CHART_PATH = os.environ.get("CHART_PATH", "{{ .Values.studio.project.path }}") + CHART_REVISION = os.environ.get("CHART_REVISION", "{{ .Values.studio.project.revision }}") + \ No newline at end of file From 1d0151c08ccf978465cbb4eed0b79a9f73749f0f Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 16 Feb 2024 17:37:00 +0100 Subject: [PATCH 101/146] mongodb --- scaleout/stackn/templates/basic-secrets.yaml | 2 +- scaleout/stackn/templates/studio-deployment.yaml | 11 +++++++++++ .../stackn/templates/studio-settings-configmap.yaml | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/basic-secrets.yaml b/scaleout/stackn/templates/basic-secrets.yaml index 642d2c51..f2611177 100644 --- a/scaleout/stackn/templates/basic-secrets.yaml +++ b/scaleout/stackn/templates/basic-secrets.yaml @@ -10,7 +10,7 @@ type: Opaque data: studio-superuser-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-superuser-password" "providedValues" (list "global.studio.superuserPassword" "studio.superuserPassword") "context" $) }} studio-event-listener-user-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "studio-event-listener-user-password" "providedValues" (list "global.studio.eventListenerUserPassword" "studio.eventListenerUserPassword") "context" $) }} - studio-argocd-token: {{ .Values.argocd.token | b64enc }} + studio-argocd-token: {{ .Values.studio.argocd.token | b64enc }} django-secret-key: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "django-secret-key" "providedValues" (list "studio.djangoSecret") "length" 50 "strong" true "context" $) }} {{ if .Values.studio.emailService.enabled }} email-host-user: {{ .Values.studio.emailService.hostUser | b64enc }} diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index d1a844ea..8e423ee4 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -158,6 +158,17 @@ spec: name: {{ include "stackn.secretName" . }} key: studio-argocd-token {{ end }} + - name: MONGO_SERVICE_HOST + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: MONGO_SERVICE_PORT + value: {{ .Values.mongodb.service.ports.mongodb }} + - name: MONGO_USERNAME + value: {{ .Values.mongodb.auth.rootUser }} + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.fullname" .Subcharts.mongodb }} + key: mongodb-root-password image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index db231430..47936e89 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -382,4 +382,8 @@ data: S3SECRET_KEY = os.environ.get("S3SECRET_KEY", "") CHART_PATH = os.environ.get("CHART_PATH", "{{ .Values.studio.project.path }}") CHART_REVISION = os.environ.get("CHART_REVISION", "{{ .Values.studio.project.revision }}") + MONGO_SERVICE_HOST = os.environ.get("MONGO_SERVICE_HOST", "mongo") + MONGO_SERVICE_PORT = os.environ.get("MONGO_SERVICE_PORT", "27017") + MONGO_USERNAME = os.environ.get("MONGO_USERNAME", "admin") + MONGO_PASSWORD = os.environ.get("MONGO_PASSWORD") \ No newline at end of file From 26575ef9926399e0766b47a61ad6eabd2ef083dc Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 19 Feb 2024 12:48:51 +0100 Subject: [PATCH 102/146] mongodb enbaled --- scaleout/stackn/templates/studio-deployment.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 8e423ee4..a6c42439 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -158,6 +158,7 @@ spec: name: {{ include "stackn.secretName" . }} key: studio-argocd-token {{ end }} + {{ if .Values.mongodb.enabled }} - name: MONGO_SERVICE_HOST value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} - name: MONGO_SERVICE_PORT @@ -169,6 +170,7 @@ spec: secretKeyRef: name: {{ include "mongodb.fullname" .Subcharts.mongodb }} key: mongodb-root-password + {{ end }} image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio From 07b0a64ed874d3c156ec6e8d862dfccb606fc42b Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 19 Feb 2024 12:53:37 +0100 Subject: [PATCH 103/146] fix --- scaleout/stackn/templates/studio-settings-configmap.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 47936e89..2cf1ba71 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -385,5 +385,5 @@ data: MONGO_SERVICE_HOST = os.environ.get("MONGO_SERVICE_HOST", "mongo") MONGO_SERVICE_PORT = os.environ.get("MONGO_SERVICE_PORT", "27017") MONGO_USERNAME = os.environ.get("MONGO_USERNAME", "admin") - MONGO_PASSWORD = os.environ.get("MONGO_PASSWORD") + MONGO_PASSWORD = os.environ.get("MONGO_PASSWORD", None) \ No newline at end of file From 67a76cd9b62ab443d3b6e4068b744a6140af72c1 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 19 Feb 2024 13:04:51 +0100 Subject: [PATCH 104/146] default to secret key jwt --- scaleout/stackn/templates/studio-settings-configmap.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 2cf1ba71..56467e4d 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -41,7 +41,7 @@ data: "UPDATE_LAST_LOGIN": False, "ALGORITHM": {{ .Values.studio.jwt_auth.algorithm | quote }}, - "SIGNING_KEY": os.environ.get("SIGNING_KEY", ""), + "SIGNING_KEY": os.environ.get("SIGNING_KEY", SECRET_KEY), "VERIFYING_KEY": os.environ.get("VERIFYING_KEY", ""), "AUDIENCE": None, "ISSUER": None, From 6b134882ed6ebe9c2052a34b3402153957081e9c Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 19 Feb 2024 13:39:13 +0100 Subject: [PATCH 105/146] fix --- scaleout/stackn/templates/studio-settings-configmap.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index 56467e4d..b758c8e2 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -31,8 +31,8 @@ data: # To generate a new key pair with RS256 algorithm: # ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key # openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub - ENABLE_JWT = os.environ.get("ENABLE_JWT", False) - if ENABLE_JWT: + ENABLE_JWT = os.environ.get("ENABLE_JWT", "false") + if ENABLE_JWT.lower() == "true": SIMPLE_JWT = { "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), "REFRESH_TOKEN_LIFETIME": timedelta(days=1), From 128bd9f027a54afe95a3fead115d6a10ceb6cbf2 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 19 Feb 2024 14:39:03 +0100 Subject: [PATCH 106/146] fix --- scaleout/stackn/templates/studio-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index a6c42439..e732e7dd 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -162,7 +162,7 @@ spec: - name: MONGO_SERVICE_HOST value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} - name: MONGO_SERVICE_PORT - value: {{ .Values.mongodb.service.ports.mongodb }} + value: {{ .Values.mongodb.service.ports.mongodb | quote }} - name: MONGO_USERNAME value: {{ .Values.mongodb.auth.rootUser }} - name: MONGO_PASSWORD From ce5bf02c782be2ee6ab0054b2fe5abf8c39e901e Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 19 Feb 2024 15:42:13 +0100 Subject: [PATCH 107/146] add express --- .../templates/mongo-express-deployment.yaml | 62 +++++++++++++++++++ .../templates/mongo-express-service.yaml | 12 ++++ scaleout/stackn/values.yaml | 6 +- 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 scaleout/stackn/templates/mongo-express-deployment.yaml create mode 100644 scaleout/stackn/templates/mongo-express-service.yaml diff --git a/scaleout/stackn/templates/mongo-express-deployment.yaml b/scaleout/stackn/templates/mongo-express-deployment.yaml new file mode 100644 index 00000000..341b5983 --- /dev/null +++ b/scaleout/stackn/templates/mongo-express-deployment.yaml @@ -0,0 +1,62 @@ +{{ if .Values.mongoexpress.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-mongo-express + namespace: {{ .Values.namespace }} + annotations: + reloader.stakater.com/auto: "true" +spec: + replicas: {{ .Values.mongoexpress.replicas }} + selector: + matchLabels: + release: {{ .Release.Name }} + app: stackn-studio + pod: mongo-express + template: + metadata: + labels: + release: {{ .Release.Name }} + app: stackn-studio + networking/allow-internet-egress: "false" + type: app + pod: mongo-express + spec: + automountServiceAccountToken: false + enableServiceLinks: false + initContainers: + - name: wait-for-db + image: busybox + env: + - name: DB_SERVICE + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: DB_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + command: ["sh", "-c", "until nc -z $DB_SERVICE $DB_PORT > /dev/null; do echo Waiting for master.; sleep 2; done;"] + containers: + - name: mongo-express + image: mongo-express:latest + env: + - name: ME_CONFIG_MONGODB_ENABLE_ADMIN + value: "true" + - name: ME_CONFIG_BASICAUTH + value: "false" + - name: ME_CONFIG_BASICAUTH_USERNAME + value: "" + - name: ME_CONFIG_BASICAUTH_PASSWORD + value: "" + - name: ME_CONFIG_MONGODB_AUTH_USERNAME + value: {{ .Values.mongodb.auth.rootUser }} + - name: ME_CONFIG_MONGODB_AUTH_PASSWORD + From: + secretKeyRef: + name: {{ include "mongodb.fullname" .Subcharts.mongodb }} + key: mongodb-root-password + - name: ME_CONFIG_MONGODB_SERVER + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: ME_CONFIG_MONGODB_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8081 +{{- end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/mongo-express-service.yaml b/scaleout/stackn/templates/mongo-express-service.yaml new file mode 100644 index 00000000..c2871b36 --- /dev/null +++ b/scaleout/stackn/templates/mongo-express-service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-mongo-express + namespace: {{ .Values.namespace }} +spec: + ports: + - port: {{ .Values.mongoexpress.service.port }} + targetPort: 8081 + protocol: TCP + selector: + release: {{ .Release.Name }} \ No newline at end of file diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 111aaaf4..7057712e 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -237,7 +237,11 @@ mongodb: commonAnnotations: {"reloader.stakater.com/auto": "true"} podLabels: {"app":"stackn-studio","allow-api-access": "true"} - +mongoexpress: + enabled: true + replicas: 1 + service: + port: 8081 eventListener: studioServiceName: "studio-studio" From 9538bbeeb61ba002cb11cc6c09b3d08271b55138 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 19 Feb 2024 16:18:38 +0100 Subject: [PATCH 108/146] fix --- scaleout/stackn/templates/mongo-express-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/mongo-express-deployment.yaml b/scaleout/stackn/templates/mongo-express-deployment.yaml index 341b5983..e0413b6c 100644 --- a/scaleout/stackn/templates/mongo-express-deployment.yaml +++ b/scaleout/stackn/templates/mongo-express-deployment.yaml @@ -48,7 +48,7 @@ spec: - name: ME_CONFIG_MONGODB_AUTH_USERNAME value: {{ .Values.mongodb.auth.rootUser }} - name: ME_CONFIG_MONGODB_AUTH_PASSWORD - From: + valueFrom: secretKeyRef: name: {{ include "mongodb.fullname" .Subcharts.mongodb }} key: mongodb-root-password From dc57d142fa3baf030697160c6ab6eddae96737ac Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Wed, 21 Feb 2024 10:09:01 +0100 Subject: [PATCH 109/146] Left over conflict in helper --- scaleout/stackn/templates/_helper.tpl | 2 -- 1 file changed, 2 deletions(-) diff --git a/scaleout/stackn/templates/_helper.tpl b/scaleout/stackn/templates/_helper.tpl index 174c6753..fc782151 100644 --- a/scaleout/stackn/templates/_helper.tpl +++ b/scaleout/stackn/templates/_helper.tpl @@ -101,8 +101,6 @@ Return postgres secret {* HOLDER FOR HA MODE IN FUTURE RELEASE *} {{- end -}} {{- end -}} - - {{/* Return STACKn studio storageClass */}} From d16b271ac25b2184455c1d0b10419de5be85ba56 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Wed, 21 Feb 2024 13:13:22 +0100 Subject: [PATCH 110/146] Make argo cd configurable --- scaleout/stackn/templates/studio-deployment.yaml | 12 ++++++++++++ .../stackn/templates/studio-settings-configmap.yaml | 8 ++++++-- scaleout/stackn/values.yaml | 8 ++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index e732e7dd..339ee84a 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -152,12 +152,24 @@ spec: value: "true" - name: ARGO_CD_API_URL value: {{ .Values.studio.argocd.url | default "" }} + - name: ARGO_CD_PROJECT + value: {{ .Values.studio.argocd.project | default "default" }} + - name: ARGO_CD_APP_NAMESPACE + value: {{ .Values.studio.argocd.namespace | default "default" }} + - name: ARGO_CD_SERVER + value: {{ .Values.studio.argocd.server | default "https://kubernetes.default.svc" }} - name: ARGO_CD_TOKEN valueFrom: secretKeyRef: name: {{ include "stackn.secretName" . }} key: studio-argocd-token {{ end }} + - name: CHART_REPO + value: {{ .Values.studio.project.repo }} + - name: CHART_PATH + value: {{ .Values.studio.project.path }} + - name: CHART_REVISION + value: {{ .Values.studio.project.revision }} {{ if .Values.mongodb.enabled }} - name: MONGO_SERVICE_HOST value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml index b758c8e2..2d4be8f7 100644 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ b/scaleout/stackn/templates/studio-settings-configmap.yaml @@ -375,13 +375,17 @@ data: ARGO_CD_ENABLED = os.environ.get("ARGO_CD_ENABLED", False) ARGO_CD_API_URL = os.environ.get("ARGO_CD_API_URL", None) ARGO_CD_TOKEN = os.environ.get("ARGO_CD_TOKEN", None) + ARGO_CD_PROJECT = os.environ.get("ARGO_CD_PROJECT", "default") + ARGO_CD_APP_NAMESPACE = os.environ.get("ARGO_CD_APP_NAMESPACE", "default") + ARGO_CD_SERVER = os.environ.get("ARGO_CD_SERVER", "https://kubernetes.default.svc") S3HOST = os.environ.get("S3HOST", "minio-fedn") S3PORT = os.environ.get("S3PORT", "9000") S3SECRET_NAME = os.environ.get("S3SECRET_NAME", "minio-fedn") S3ACCESS_KEY = os.environ.get("S3ACCESS_KEY", "") S3SECRET_KEY = os.environ.get("S3SECRET_KEY", "") - CHART_PATH = os.environ.get("CHART_PATH", "{{ .Values.studio.project.path }}") - CHART_REVISION = os.environ.get("CHART_REVISION", "{{ .Values.studio.project.revision }}") + CHART_REPO = os.environ.get("CHART_REPO", "harbor.scaleoutsystems.com/chart") + CHART_PATH = os.environ.get("CHART_PATH", "fedn") + CHART_REVISION = os.environ.get("CHART_REVISION", "0.1.0") MONGO_SERVICE_HOST = os.environ.get("MONGO_SERVICE_HOST", "mongo") MONGO_SERVICE_PORT = os.environ.get("MONGO_SERVICE_PORT", "27017") MONGO_USERNAME = os.environ.get("MONGO_USERNAME", "admin") diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 7057712e..79ac6966 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -163,10 +163,14 @@ studio: # studio values enabled: true url: '' token: '' + project: "default" + namespace: "default" + server: "https://kubernetes.default.svc" project: - path: "charts/apps/fedn-project/chart" - revision: "feature/SK-626" + repo: "harbor.scaleoutsystems.com/chart" + path: "fedn" + revision: "0.1.0" # Pull secrets for studio, used to pull images from private repositories such as Harbor # To create a pull secret run: $ kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= From 654b8eb50581c0ae602b04e9357f4ca673d86586 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Wed, 21 Feb 2024 13:24:33 +0100 Subject: [PATCH 111/146] Make Studio track 0.x.y series of FEDn helm chart. --- scaleout/stackn/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 79ac6966..32018d48 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -170,7 +170,7 @@ studio: # studio values project: repo: "harbor.scaleoutsystems.com/chart" path: "fedn" - revision: "0.1.0" + revision: "0.*" # Pull secrets for studio, used to pull images from private repositories such as Harbor # To create a pull secret run: $ kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= From 133da6342c8b0bd727067862e741bdbd6a841fb8 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 21 Feb 2024 13:50:52 +0100 Subject: [PATCH 112/146] update version --- scaleout/stackn/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index b0b98dda..c2e55ef8 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v1 -appVersion: "0.7.4" +appVersion: "0.10.0" description: A Helm chart for deploying studio name: studio -version: 0.4.1-beta.1 +version: 0.5.0 maintainers: - email: fredrik@scaleoutsystems.com name: Fredrik Wrede From 093ce43c15379c2213ed9f32711611843279cc18 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Wed, 21 Feb 2024 21:39:18 +0100 Subject: [PATCH 113/146] Fix imagepullsecret in event listener deployment. --- scaleout/stackn/templates/event-listener-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/event-listener-deployment.yaml b/scaleout/stackn/templates/event-listener-deployment.yaml index add755f6..6a532b24 100644 --- a/scaleout/stackn/templates/event-listener-deployment.yaml +++ b/scaleout/stackn/templates/event-listener-deployment.yaml @@ -21,7 +21,7 @@ spec: automountServiceAccountToken: true serviceAccountName: studio imagePullSecrets: - - name: ghcrsecret + - name: {{ .Values.imagePullSecrets.name }} containers: - image: {{ .Values.eventListener.image.repository }} imagePullPolicy: {{ .Values.eventListener.image.pullPolicy }} From 7a8d72fa810036c72ac5f7e3b94e7ff98ea3699e Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Wed, 21 Feb 2024 22:41:35 +0100 Subject: [PATCH 114/146] Fix quotes around revision. --- scaleout/stackn/requirements.yaml | 6 ------ scaleout/stackn/templates/studio-deployment.yaml | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/scaleout/stackn/requirements.yaml b/scaleout/stackn/requirements.yaml index 1ba1a957..a660b45c 100644 --- a/scaleout/stackn/requirements.yaml +++ b/scaleout/stackn/requirements.yaml @@ -16,12 +16,6 @@ dependencies: tags: - bitnami-common version: 2.14.1 - - # - name: minio-operator - # version: 4.3.7 - # repository: https://operator.min.io - # condition: minio.enabled - # version: 2.14.1 - name: mongodb repository: https://charts.bitnami.com/bitnami diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 339ee84a..602bfac8 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -169,7 +169,7 @@ spec: - name: CHART_PATH value: {{ .Values.studio.project.path }} - name: CHART_REVISION - value: {{ .Values.studio.project.revision }} + value: {{ .Values.studio.project.revision | quote}} {{ if .Values.mongodb.enabled }} - name: MONGO_SERVICE_HOST value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} From b8df1f0c6de5c0c7cf2ffc1f060a2cdfabf2efc8 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Thu, 22 Feb 2024 09:55:15 +0100 Subject: [PATCH 115/146] Set correct images in values --- scaleout/stackn/values.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 32018d48..74cc51d3 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -85,7 +85,7 @@ studio: # studio values replicas: 1 # number of static replicas strategy: # strategy for static type: Recreate # type of strategy - image: ghcr.io/scaleoutsystems/stackn/studio:develop # image for static + image: harbor.scaleoutsystems.com/studio/studio-nginx:0.10.0-beta.1 # image for static pullPolicy: IfNotPresent # pull policy for static resources: # resources for static limits: # limits for static @@ -95,7 +95,7 @@ studio: # studio values cpu: "100m" # cpu request for static memory: "256Mi" # memory request for static image: #tell which image to deploy for studio - repository: ghcr.io/scaleoutsystems/stackn/ingress:develop #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + repository: harbor.scaleoutsystems.com/studio/studio:0.10.0-beta.1 #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image resources: limits: @@ -168,9 +168,9 @@ studio: # studio values server: "https://kubernetes.default.svc" project: - repo: "harbor.scaleoutsystems.com/chart" - path: "fedn" - revision: "0.*" + repo: "harbor.scaleoutsystems.com" + path: "chart/fedn" + revision: "*" # Pull secrets for studio, used to pull images from private repositories such as Harbor # To create a pull secret run: $ kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= @@ -254,8 +254,8 @@ eventListener: appStatusesEndpoint: "api/app/statuses" tokenEndpoint: "api/token-auth/" image: - repository: ghcr.io/scaleoutsystems/studio-kube-controller:main - pullPolicy: Always # used to ensure that each time we redeploy always pull the latest image + repository: harbor.scaleoutsystems.com/studio/studio-kube-controller:0.10.0-beta.1 + pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image # Will be added in future realease, for now keep "enabled:false" From c64a75efce4a590a4b20474015eaa24687a1d076 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Thu, 22 Feb 2024 10:40:14 +0100 Subject: [PATCH 116/146] Bumped minor version so that cluster pulls new chart (after fixes in values). --- scaleout/stackn/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index c2e55ef8..f9ec157b 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 appVersion: "0.10.0" description: A Helm chart for deploying studio name: studio -version: 0.5.0 +version: 0.5.1 maintainers: - email: fredrik@scaleoutsystems.com name: Fredrik Wrede From db0c3e5e0d06476eb907d577ae1e11951993f672 Mon Sep 17 00:00:00 2001 From: stefanhellander <59477428+stefanhellander@users.noreply.github.com> Date: Fri, 1 Mar 2024 14:12:19 +0100 Subject: [PATCH 117/146] Feature/SK-698 | Removes settings configmap and adds corresponding env vars to Studio (#109) * Add env variables to deployment and remove settings.py in configmap. * Moved harbor and minio under studio in values.yaml --- scaleout/stackn/Chart.yaml | 2 +- scaleout/stackn/templates/basic-secrets.yaml | 3 + .../stackn/templates/studio-deployment.yaml | 118 +++++- .../templates/studio-settings-configmap.yaml | 393 ------------------ scaleout/stackn/values.yaml | 10 + 5 files changed, 114 insertions(+), 412 deletions(-) delete mode 100644 scaleout/stackn/templates/studio-settings-configmap.yaml diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index f9ec157b..c2e55ef8 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 appVersion: "0.10.0" description: A Helm chart for deploying studio name: studio -version: 0.5.1 +version: 0.5.0 maintainers: - email: fredrik@scaleoutsystems.com name: Fredrik Wrede diff --git a/scaleout/stackn/templates/basic-secrets.yaml b/scaleout/stackn/templates/basic-secrets.yaml index f2611177..06aea97e 100644 --- a/scaleout/stackn/templates/basic-secrets.yaml +++ b/scaleout/stackn/templates/basic-secrets.yaml @@ -18,4 +18,7 @@ data: email-api-key: {{ .Values.studio.emailService.apiKey | b64enc }} argo-cd-token: {{ .Values.studio.argocd.token | b64enc }} {{ end }} + {{ if .Values.studio.harbor.enabled }} + harbor-creds: {{ printf "%s:%s" .Values.studio.harbor.username .Values.studio.harbor.password | b64enc | b64enc }} + {{ end }} {{- end -}} \ No newline at end of file diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 602bfac8..aead48ae 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -63,12 +63,82 @@ spec: {{ else }} value: "false" {{ end }} + - name: DOMAIN + value: {{ .Values.domain }} + - name: AUTH_DOMAIN + value: {{ .Release.Name }}-studio.{{ .Values.namespace | default "default"}}.svc.{{ .Values.cluster_domain | default "cluster.local"}} + - name: STUDIO_URL + value: http://{{ .Release.Name }}-studio:8080 + - name: GRPC_DOMAIN + value: {{ .Values.grpc_domain | quote }} + - name: RELEASE_NAME + value: {{ .Release.Name }} + - name: SERVICE_NAME + value: {{ .Values.studio.servicename }} + - name: NAMESPACE + value: {{ .Values.namespace | default "default" }} + - name: CLUSTER_DOMAIN + value: {{ .Values.cluster_domain | default "cluster.local"}} + - name: STORAGE_CLASS + value: {{ .Values.studio.storage.storageClass }} - name: INIT value: {{ .Values.studio.init | quote }} - - name: STUDIO_STORAGECLASS - value: {{ include "stackn.studio.storageclass" . }} + - name: CSRF_TRUSTED_ORIGINS + value: {{ .Values.studio.csrf_trusted_origins | quote}} + - name: KUBE_API_REQUEST_TIMEOUT + value: {{ .Values.studio.kube_api_request_timeout | quote }} + - name: EMAIL_SERVICE_ENABLED + value: {{ .Values.studio.emailService.enabled | quote}} + - name: EMAIL_HOST + value: {{ .Values.studio.emailService.host | quote}} + - name: EMAIL_PORT + value: {{ .Values.studio.emailService.port | quote }} + - name: EMAIL_DOMAIN_NAME + value: {{ .Values.studio.emailService.domainName | quote}} + - name: EMAIL_MAILGUN_API + value: {{ .Values.studio.emailService.apiEndpoint | quote}} + - name: NOTIFY_ON_ACCOUNT_REGISTER_LIST + value: "{{ range $index, $elem := .Values.studio.emailService.notifyOnAccountRegisterList }}{{ if $index }},{{ end }}{{ $elem }}{{ end }}" + - name: VERSION + value: {{ .Values.studio.version | quote }} + - name: DEFAULT_FROM_EMAIL + value: {{ .Values.studio.emailService.smtpEmailFrom | quote}} + - name: SESSION_COOKIE_DOMAIN + value: {{ .Values.session_cookie_domain | quote }} - name: STUDIO_ACCESSMODE value: {{ .Values.accessmode }} + - name: CUSTOM_MIGRATIONS + value: "{{- if .Values.studio.custom_migrations.enabled }}{{- range $key, $value := .Values.studio.custom_migrations.apps }}{{ $key }}:{{ $value }},{{- end }}{{- end }}" + - name: ENABLE_PROJECT_EXTRA_SETTINGS + value: {{ .Values.studio.enable_project_extra_settings | quote }} + - name: DISCORD_ALERT_ON_NEW_USER + {{ if .Values.studio.discord.alert_on_new_user }} + value: "true" + {{ else }} + value: "false" + {{ end }} + - name: DISCORD_ALERT_WEBHOOK_URL + value: {{ .Values.studio.discord.alert_webhook_url | quote }} + - name: DISCORD_ALERT_ON_NEW_USER_MESSAGE + value: {{ .Values.studio.discord.alert_on_new_user_message | quote }} + - name: INACTIVE_USERS + {{ if .Values.studio.inactive_users }} + value: "true" + {{ else }} + value: "false" + {{ end }} + - name: CUSTOM_APPS + value: "{{- if .Values.studio.custom_apps.enabled }}{{- range .Values.studio.custom_apps.apps }}{{ . }},{{- end }}{{- end }}" + - name: AUTH_USER_MODEL + {{ if .Values.studio.auth_user_model.override }} + value: {{ .Values.studio.auth_user_model.model | quote }} + {{ else }} + value: "" + {{ end }} + {{ if .Values.studio.disabledAppInstanceFields.enabled }} + - name: DISABLED_APP_INSTANCE_FIELDS + value: "{{- range .Values.studio.disabledAppInstanceFields.fields }}{{ . }},{{- end }}" + {{- end }} {{ if .Values.studio.jwt_auth.enabled }} - name: ENABLE_JWT value: true @@ -84,6 +154,8 @@ spec: - name: VERIFYING_KEY value: {{ .Values.studio.jwt_auth.public_key | quote }} {{ end }} + - name: JWT_AUTH_ALGORITHM + value: {{ .Values.studio.jwt_auth.algorithm | quote }} - name: DJANGO_SUPERUSER value: {{ include "stackn.studio.superuser" . }} - name: DJANGO_SUPERUSER_EMAIL @@ -102,13 +174,19 @@ spec: key: studio-event-listener-user-password - name: GET_HOSTS_FROM value: dns + - name: POSTGRES_NAME + value: {{ .Values.postgresql.auth.database }} + - name: POSTGRES_USER + value: {{ .Values.postgresql.auth.username }} + - name: POSTGRES_HOST + value: {{ .Values.postgresql.fullnameOverride }} + - name: POSTGRES_PORT + value: {{ .Values.postgresql.primary.service.ports.postgresql | quote }} - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: {{ include "stackn.postgres.secretName" . }} key: password - - name: POSTGRES_USER - value: {{ .Values.postgresql.global.postgresql.auth.user }} - name: DJANGO_SECRET valueFrom: secretKeyRef: @@ -132,20 +210,20 @@ spec: key: email-api-key {{ end }} - name: S3HOST - value: {{ .Values.minio.host }} + value: {{ .Values.studio.minio.host }} - name: S3PORT - value: "{{ .Values.minio.port }}" + value: "{{ .Values.studio.minio.port }}" - name: S3SECRET_NAME - value: {{ .Values.minio.secretName }} + value: {{ .Values.studio.minio.secretName }} - name: S3ACCESS_KEY valueFrom: secretKeyRef: - name: {{ .Values.minio.secretName }} + name: {{ .Values.studio.minio.secretName }} key: accessKey - name: S3SECRET_KEY valueFrom: secretKeyRef: - name: {{ .Values.minio.secretName }} + name: {{ .Values.studio.minio.secretName }} key: secretKey {{ if .Values.studio.argocd.enabled }} - name: ARGO_CD_ENABLED @@ -183,13 +261,23 @@ spec: name: {{ include "mongodb.fullname" .Subcharts.mongodb }} key: mongodb-root-password {{ end }} + {{ if .Values.studio.harbor.enabled }} + - name: HARBOR_ENABLED + value: "true" + - name: HARBOR_CREDS + valueFrom: + secretKeyRef: + name: {{ include "stackn.secretName" . }} + key: harbor-creds + - name: HARBOR_HOST + value: {{ .Values.studio.project.repo }} + - name: HARBOR_PATH + value: {{ .Values.studio.project.path }} + {{ end }} image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio volumeMounts: - - mountPath: /app/studio/settings.py - subPath: settings.py - name: {{ .Release.Name}}-settings-configmap {{ if .Values.studio.media.storage.mountStudio }} - name: mediavol mountPath: {{ .Values.studio.media.mount_path }} @@ -229,12 +317,6 @@ spec: - name: {{ .Values.imagePullSecrets.name }} restartPolicy: Always volumes: - - name: {{ .Release.Name}}-settings-configmap - configMap: - name: {{ .Release.Name}}-settings-configmap - items: - - key: settings.py - path: settings.py {{ if .Values.studio.media.storage.mountStudio }} - name: mediavol persistentVolumeClaim: diff --git a/scaleout/stackn/templates/studio-settings-configmap.yaml b/scaleout/stackn/templates/studio-settings-configmap.yaml deleted file mode 100644 index 2d4be8f7..00000000 --- a/scaleout/stackn/templates/studio-settings-configmap.yaml +++ /dev/null @@ -1,393 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Release.Name }}-settings-configmap -data: - settings.py: |- - """ - Django settings for studio project. - - Generated by 'django-admin startproject' using Django 2.2.6. - - For more information on this file, see - https://docs.djangoproject.com/en/2.2/topics/settings/ - - For the full list of settings and their values, see - https://docs.djangoproject.com/en/2.2/ref/settings/ - """ - - import os - import sys - from pathlib import Path - - - AUTHENTICATION_BACKENDS = [ - 'django.contrib.auth.backends.ModelBackend', - 'guardian.backends.ObjectPermissionBackend', - ] - - # JWT settings - # https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html - # To generate a new key pair with RS256 algorithm: - # ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key - # openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub - ENABLE_JWT = os.environ.get("ENABLE_JWT", "false") - if ENABLE_JWT.lower() == "true": - SIMPLE_JWT = { - "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), - "REFRESH_TOKEN_LIFETIME": timedelta(days=1), - "ROTATE_REFRESH_TOKENS": False, - "BLACKLIST_AFTER_ROTATION": False, - "UPDATE_LAST_LOGIN": False, - - "ALGORITHM": {{ .Values.studio.jwt_auth.algorithm | quote }}, - "SIGNING_KEY": os.environ.get("SIGNING_KEY", SECRET_KEY), - "VERIFYING_KEY": os.environ.get("VERIFYING_KEY", ""), - "AUDIENCE": None, - "ISSUER": None, - "JSON_ENCODER": None, - "JWK_URL": None, - "LEEWAY": 0, - "AUTH_HEADER_TYPES": ("Bearer",), - "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION", - "USER_ID_FIELD": "id", - "USER_ID_CLAIM": "user_id", - "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule", - - "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",), - "TOKEN_TYPE_CLAIM": "token_type", - "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser", - - "JTI_CLAIM": "jti", - - "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp", - "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5), - "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1), - - "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer", - "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer", - "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer", - "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer", - "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer", - "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer", - } - - - # Build paths inside the project like this: BASE_DIR / 'subdir'. - BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - # Quick-start development settings - unsuitable for production - # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ - - # SECURITY WARNING: keep the secret key used in production secret! - SECRET_KEY = os.environ["DJANGO_SECRET"] - - # SECURITY WARNING: don't run with debug turned on in production - {{ if .Values.studio.debug }} - DEBUG = True - {{ else }} - DEBUG = False - {{ end }} - - if DEBUG: - ALLOWED_HOSTS = ['*'] - else: - ALLOWED_HOSTS = ['{{ .Values.domain }}', '{{ .Release.Name }}-{{ .Values.studio.servicename }}', '{{ .Release.Name }}-studio.{{ .Values.namespace | default "default" }}.svc.{{ .Values.cluster_domain | default "cluster.local"}}'] - - # Application definition - - INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'rest_framework.authtoken', - 'rest_framework', - 'django.contrib.staticfiles', - 'corsheaders', - 'django_extensions', # for executing runscript among others - 'django_filters', - 'guardian', - "projects", - "apps", - "api", - "system", - ] - - {{ if .Values.studio.custom_apps.enabled }} - CUSTOM_APPS = [{{- range .Values.studio.custom_apps.apps }}{{. | quote }},{{- end }}] - INSTALLED_APPS = INSTALLED_APPS + CUSTOM_APPS - {{ end }} - - {{ if .Values.studio.auth_user_model.override }} - AUTH_USER_MODEL = {{ .Values.studio.auth_user_model.model | quote }} - {{ end }} - - - MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'corsheaders.middleware.CorsMiddleware' - ] - - - REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.TokenAuthentication' - ], - } - - # Default primary key field type - # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field - - #Setting this will remove a warning about CorsModel primary keys filed, however a - # permission denied error is introduced - # when django tries to apply a new migration to corsheaders package. This is because - # the web server is started as stackn user but the migrations folder in corsheader is root - # solution for now: setting AutoField as default (below) - # then setting BigAutoField on app level (ex /projects/apps.py) - DEFAULT_AUTO_FIELD = "django.db.models.AutoField" - - # Django guardian 403 templates - GUARDIAN_RENDER_403 = True - GUARDIAN_TEMPLATE_403 = '403.html' - - # Main Url conf for loading all the routing path in Studio - ROOT_URLCONF = 'studio.urls' - - # Tagulous serialization settings - SERIALIZATION_MODULES = { - 'xml': 'tagulous.serializers.xml_serializer', - 'json': 'tagulous.serializers.json', - 'python': 'tagulous.serializers.python', - 'yaml': 'tagulous.serializers.pyyaml', - } - - STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - # other finders - 'compressor.finders.CompressorFinder', - ) - - STATIC_URL = '/static/' - #Use in production and together with Nginx - STATIC_ROOT = os.path.join(BASE_DIR, 'static/') - #STATICFILES_DIRS = ( os.path.join('static'), ) - - - TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - 'django.template.loaders.eggs.Loader', - ) - - TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates')], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - 'libraries': { - } - }, - }, - ] - - WSGI_APPLICATION = 'studio.wsgi.application' - ASGI_APPLICATION = 'studio.asgi.application' - - # Database - # https://docs.djangoproject.com/en/2.2/ref/settings/#databases - - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': '{{ .Values.postgresql.global.postgresql.auth.database }}', - 'USER': '{{ .Values.postgresql.global.postgresql.auth.username }}', - 'PASSWORD': os.environ.get('POSTGRES_PASSWORD'), - 'HOST': '{{ .Values.postgresql.fullnameOverride }}', - 'PORT': '{{ .Values.postgresql.primary.service.ports.postgresql }}', - } - } - - # Password validation - # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators - - AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, - ] - - # Internationalization - # https://docs.djangoproject.com/en/2.2/topics/i18n/ - LANGUAGE_CODE = 'en-us' - TIME_ZONE = 'UTC' - USE_I18N = True - USE_L10N = True - USE_TZ = True - - # Media Files for Studio apps - #MEDIA_URL = {{ .Values.studio.media.mount_path | quote }} - #MEDIA_ROOT = {{ .Values.studio.media.mount_path | quote }} - - #From studio - MEDIA_URL = '/media/' - MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') - - # Related to user registration and authetication workflow - LOGIN_REDIRECT_URL = '/projects' - LOGIN_URL = 'login' - LOGOUT_URL = 'logout' - INACTIVE_USERS = {{ if .Values.studio.inactive_users }}True{{ else }}False{{ end }} - - # Specific to Studio stack: - VERSION_BACKEND = 'studio.version.Version' - - # Other Helm/k8s deployment settings - CHART_FOLDER = "/app/charts/apps" - EXTERNAL_KUBECONF = True - KUBECONFIG = "/app/kubeconfig/config" # Deprecated, uses ServiceAccount instead - NAMESPACE = {{ .Values.namespace | default "default" | quote }} - KUBE_API_REQUEST_TIMEOUT = {{ .Values.studio.kube_api_request_timeout }} - STORAGECLASS = {{ include "stackn.studio.storageclass" . | quote }} - - # App dependencies - - # Apps - APPS_MODEL = "apps.Apps" - APPINSTANCE_MODEL = "apps.AppInstance" - APPCATEGORIES_MODEL ="apps.AppCategories" - - # Models - MODELS_MODEL = "models.Model" - - # Projects - PROJECTS_MODEL = "projects.Project" - PROJECTLOG_MODEL = "projects.ProjectLog" - ENVIRONMENT_MODEL = "projects.Environment" - RELEASENAME_MODEL = "projects.ReleaseName" - - # App statuses - APPS_STATUS_SUCCESS = ['Running', 'Succeeded', 'Success'] - APPS_STATUS_WARNING = ['Pending', 'Installed', - 'Waiting', 'Installing', 'Created', 'ContainerCreating'] - - DOMAIN = {{ .Values.domain | quote }} - GRPC_DOMAIN = {{ .Values.grpc_domain | quote }} - AUTH_DOMAIN = '{{ .Release.Name }}-studio.{{ .Values.namespace | default "default" }}.svc.{{ .Values.cluster_domain | default "cluster.local"}}' - AUTH_PROTOCOL = 'http' - STUDIO_URL = 'http://{{ .Release.Name }}-studio:8080' - # To enable sticky sessions for k8s ingress - SESSION_COOKIE_DOMAIN = {{ .Values.session_cookie_domain | quote }} - CSRF_TRUSTED_ORIGINS = ['https://*{{ .Values.session_cookie_domain }}','https://*.127.0.0.1'] + [{{ .Values.studio.csrf_trusted_origins | quote}}] - - # Email - {{ if .Values.studio.emailService.enabled }} - EMAIL_HOST = {{ .Values.studio.emailService.host | quote}} - EMAIL_PORT = {{ .Values.studio.emailService.port }} - EMAIL_HOST_USER = os.environ["EMAIL_HOST_USER"] - EMAIL_HOST_PASSWORD = os.environ["EMAIL_HOST_PASSWORD"] - EMAIL_USE_TLS = True - - EMAIL_DOMAIN_NAME = {{ .Values.studio.emailService.domainName | quote}} - EMAIL_API_KEY = os.environ["EMAIL_API_KEY"] - EMAIL_MAILGUN_API = {{ .Values.studio.emailService.apiEndpoint | quote}} - EMAIL_NOTIFY_ON_ACCOUNT_REGISTER_LIST = [{{- range .Values.studio.emailService.notifyOnAccountRegisterList }}{{. | quote }},{{- end }}] - DEFAULT_FROM_EMAIL = {{ .Values.studio.emailService.smtpEmailFrom | quote}} - {{ else }} - EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend" - EMAIL_FILE_PATH = os.path.join(BASE_DIR, 'sent_emails') - {{ end }} - EMAIL_TEMPLATE_PROTOCOL = "https" - - VERSION = {{ .Values.studio.version | quote }} - - MIGRATION_MODULES = { - 'apps': 'studio.migrations.apps', - 'projects': 'studio.migrations.projects', - 'system': 'studio.migrations.system' - } - - {{ if .Values.studio.custom_migrations.enabled }} - {{- range $key, $value := .Values.studio.custom_migrations.apps }} - MIGRATION_MODULES[{{$key | quote }}] = {{$value | quote }} - {{- end }} - {{- end }} - - # Defines how many apps a user is allowed to create within one project - APPS_PER_PROJECT_LIMIT = { - "vscode": 1, - "volumeK8s": 5, - "pytorch-serve": 1, - "tensorflow-serve": 1, - "mlflow-serve": 1, - "mlflow": 1, - "minio": 1, - "jupyter-lab": 1, - "mongo-express": 1, - "reducer": 1, - "docker-registry": 1, - "combiner": 2, - "mongodb": 1, - } - - PROJECTS_PER_USER_LIMIT = 3 - - STUDIO_ACCESSMODE = os.environ.get("STUDIO_ACCESSMODE", "") - {{ if .Values.studio.enable_project_extra_settings }} - ENABLE_PROJECT_EXTRA_SETTINGS = True - {{ else }} - ENABLE_PROJECT_EXTRA_SETTINGS = False - {{ end }} - {{ if .Values.studio.disabledAppInstanceFields.enabled }} - DISABLED_APP_INSTANCE_FIELDS = [{{- range .Values.studio.disabledAppInstanceFields.fields }}{{. | quote }},{{- end }}] - {{- end }} - FEDN_LOCAL_CONTROLLER = os.environ.get("FEDN_LOCAL_CONTROLLER", None) - - DISCORD_ALERT_ON_NEW_USER = {{ if .Values.studio.discord.alert_on_new_user }}True{{ else }}False{{ end }} - DISCORD_ALTERT_WEBHOOK_URL = {{ .Values.studio.discord.alert_webhook_url | quote }} - DISCORD_ALERT_ON_NEW_USER_MESSAGE = {{ .Values.studio.discord.alert_on_new_user_message | quote }} - - # Argo CD API URL and Token - ARGO_CD_ENABLED = os.environ.get("ARGO_CD_ENABLED", False) - ARGO_CD_API_URL = os.environ.get("ARGO_CD_API_URL", None) - ARGO_CD_TOKEN = os.environ.get("ARGO_CD_TOKEN", None) - ARGO_CD_PROJECT = os.environ.get("ARGO_CD_PROJECT", "default") - ARGO_CD_APP_NAMESPACE = os.environ.get("ARGO_CD_APP_NAMESPACE", "default") - ARGO_CD_SERVER = os.environ.get("ARGO_CD_SERVER", "https://kubernetes.default.svc") - S3HOST = os.environ.get("S3HOST", "minio-fedn") - S3PORT = os.environ.get("S3PORT", "9000") - S3SECRET_NAME = os.environ.get("S3SECRET_NAME", "minio-fedn") - S3ACCESS_KEY = os.environ.get("S3ACCESS_KEY", "") - S3SECRET_KEY = os.environ.get("S3SECRET_KEY", "") - CHART_REPO = os.environ.get("CHART_REPO", "harbor.scaleoutsystems.com/chart") - CHART_PATH = os.environ.get("CHART_PATH", "fedn") - CHART_REVISION = os.environ.get("CHART_REVISION", "0.1.0") - MONGO_SERVICE_HOST = os.environ.get("MONGO_SERVICE_HOST", "mongo") - MONGO_SERVICE_PORT = os.environ.get("MONGO_SERVICE_PORT", "27017") - MONGO_USERNAME = os.environ.get("MONGO_USERNAME", "admin") - MONGO_PASSWORD = os.environ.get("MONGO_PASSWORD", None) - \ No newline at end of file diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 74cc51d3..f6bd36fa 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -171,6 +171,16 @@ studio: # studio values repo: "harbor.scaleoutsystems.com" path: "chart/fedn" revision: "*" + + minio: + enabled: true + host: "" + secretName: minio-fedn + + harbor: + enabled: true + username: "" + password: "" # Pull secrets for studio, used to pull images from private repositories such as Harbor # To create a pull secret run: $ kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= From 9c7cd24f2db0396d729570379c53623778ed50e4 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 1 Mar 2024 14:30:19 +0100 Subject: [PATCH 118/146] jwt-auth-endpoint --- scaleout/stackn/templates/grpc-ingress.yaml | 2 +- scaleout/stackn/values.yaml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/grpc-ingress.yaml b/scaleout/stackn/templates/grpc-ingress.yaml index 1a4bb592..afacd2fc 100644 --- a/scaleout/stackn/templates/grpc-ingress.yaml +++ b/scaleout/stackn/templates/grpc-ingress.yaml @@ -3,7 +3,7 @@ kind: Ingress metadata: name: {{ .Release.Name }}-grpc-ingress annotations: - nginx.ingress.kubernetes.io/auth-url: http://studio-studio.default.svc.cluster.local:8080/auth/ + nginx.ingress.kubernetes.io/auth-url: http://studio-studio.default.svc.cluster.local:8080{{ .Values.studio.auth.endpoint }} nginx.ingress.kubernetes.io/configuration-snippet: | if ($http_grpc_server) { grpc_pass grpc://$http_grpc_server.default.svc.cluster.local:80; } nginx.ingress.kubernetes.io/proxy-body-size: "0" diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index f6bd36fa..cd272310 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -74,6 +74,8 @@ studio: # studio values auth_user_model: # auth user model for studio. Do not change unless you know what you are doing. override: false model: "user.User" + auth: # auth endpoint for studio. Do not change unless you know what you are doing. + endpoint: /auth/ # if JWT is enabled, this should be /api/token/verify jwt_auth: # Use JWT authentication for REST and client authentication. Needs exsiting secret with private key. enabled: false algorithm: RS256 From 34d5ab82c96d513672807a1a4a79cce55e4f1849 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Fri, 1 Mar 2024 15:34:17 +0100 Subject: [PATCH 119/146] add jwt --- scaleout/stackn/templates/studio-deployment.yaml | 4 +++- scaleout/stackn/values.yaml | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index aead48ae..9d7b0bdf 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -142,7 +142,6 @@ spec: {{ if .Values.studio.jwt_auth.enabled }} - name: ENABLE_JWT value: true - {{ end }} {{ if .Values.studio.jwt_auth.existingSecret }} - name: SIGNING_KEY valueFrom: @@ -156,6 +155,9 @@ spec: {{ end }} - name: JWT_AUTH_ALGORITHM value: {{ .Values.studio.jwt_auth.algorithm | quote }} + - name: JWT_STATELESS_USER_AUTH + value: {{ .Values.studio.jwt_auth.statelessUser }} + {{ end }} - name: DJANGO_SUPERUSER value: {{ include "stackn.studio.superuser" . }} - name: DJANGO_SUPERUSER_EMAIL diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index cd272310..dd7839df 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -78,9 +78,10 @@ studio: # studio values endpoint: /auth/ # if JWT is enabled, this should be /api/token/verify jwt_auth: # Use JWT authentication for REST and client authentication. Needs exsiting secret with private key. enabled: false - algorithm: RS256 + algorithm: HS256 public_key: "" # If algorithm is RS256, set RSA public key here existingSecret: "" # name of existing secret containing private key, need "private_key" key + statelessUser: false # If true, user will be stateless, i.e. when verifying token, user will not be fetched from database csrf_trusted_origins: # csrf trusted origins for studio. Add extra trusted origins for CSRF protection. kube_api_request_timeout: 1 # timeout for kubernetes api requests, such as request to create/delete resources static: # static values for studio, ngnix server for serving static files and media files From f4f46f510ba59a7567dc57ff2fad93151132282d Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 4 Mar 2024 13:27:38 +0100 Subject: [PATCH 120/146] fix volume check --- scaleout/stackn/templates/studio-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 9d7b0bdf..74873b0d 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -318,8 +318,8 @@ spec: imagePullSecrets: - name: {{ .Values.imagePullSecrets.name }} restartPolicy: Always - volumes: {{ if .Values.studio.media.storage.mountStudio }} + volumes: - name: mediavol persistentVolumeClaim: claimName: {{ .Release.Name }}-{{ .Values.studio.media.storage.claimName }} From a43c6cb02b5ba674ff142fe198afec69aab86f3f Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 4 Mar 2024 13:54:22 +0100 Subject: [PATCH 121/146] fix --- scaleout/stackn/templates/studio-deployment.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 74873b0d..367832dd 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -279,11 +279,11 @@ spec: image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio + {{ if .Values.studio.media.storage.mountStudio }} volumeMounts: - {{ if .Values.studio.media.storage.mountStudio }} - name: mediavol mountPath: {{ .Values.studio.media.mount_path }} - {{ end }} + {{ end }} resources: limits: cpu: {{ .Values.studio.resources.limits.cpu }} From 66135714cebc2f42de4ba6227e2da3b12852800a Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 4 Mar 2024 15:43:36 +0100 Subject: [PATCH 122/146] fix --- scaleout/stackn/templates/studio-deployment.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 367832dd..f665d765 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -141,7 +141,7 @@ spec: {{- end }} {{ if .Values.studio.jwt_auth.enabled }} - name: ENABLE_JWT - value: true + value: "true" {{ if .Values.studio.jwt_auth.existingSecret }} - name: SIGNING_KEY valueFrom: @@ -155,8 +155,9 @@ spec: {{ end }} - name: JWT_AUTH_ALGORITHM value: {{ .Values.studio.jwt_auth.algorithm | quote }} + {{ if .Values.studio.jwt_auth.statelessUser }} - name: JWT_STATELESS_USER_AUTH - value: {{ .Values.studio.jwt_auth.statelessUser }} + value: "true" {{ end }} - name: DJANGO_SUPERUSER value: {{ include "stackn.studio.superuser" . }} From d9ea5757c0b37e195dcbc0bf5c078dc21b8c7e50 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Mon, 4 Mar 2024 17:17:10 +0100 Subject: [PATCH 123/146] fix --- scaleout/stackn/templates/studio-deployment.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index f665d765..251def62 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -159,6 +159,7 @@ spec: - name: JWT_STATELESS_USER_AUTH value: "true" {{ end }} + {{ end }} - name: DJANGO_SUPERUSER value: {{ include "stackn.studio.superuser" . }} - name: DJANGO_SUPERUSER_EMAIL @@ -324,4 +325,4 @@ spec: - name: mediavol persistentVolumeClaim: claimName: {{ .Release.Name }}-{{ .Values.studio.media.storage.claimName }} - {{ end }} + {{ end }} \ No newline at end of file From 8bbe0f03ed5e88e8eb9321131498bde7874b34eb Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 19 Mar 2024 16:45:21 +0100 Subject: [PATCH 124/146] remove media-vol from studio --- scaleout/stackn/templates/studio-deployment.yaml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 251def62..59279961 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -28,18 +28,6 @@ spec: securityContext: fsGroup: {{ .Values.studio.securityContext.fsGroup }} initContainers: - {{ if .Values.studio.debug }} - - name: volume-permissions - image: busybox - command: ['sh', '-c', 'chown -R 1000 /app/media && chgrp -R 1000 /app/media'] - volumeMounts: - - mountPath: {{ .Values.studio.media.mount_path }} - name: mediavol - securityContext: - runAsUser: 0 - runAsGroup: 0 - runAsNonRoot: false - {{ end }} - name: wait-for-db image: postgres command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }} --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 2; done;'] From e2ba434d950847d264fb6c69f8250e4fb5211dee Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 19 Mar 2024 14:53:23 +0100 Subject: [PATCH 125/146] remove auth-url --- scaleout/stackn/templates/grpc-ingress.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/scaleout/stackn/templates/grpc-ingress.yaml b/scaleout/stackn/templates/grpc-ingress.yaml index afacd2fc..4cdce93a 100644 --- a/scaleout/stackn/templates/grpc-ingress.yaml +++ b/scaleout/stackn/templates/grpc-ingress.yaml @@ -3,7 +3,6 @@ kind: Ingress metadata: name: {{ .Release.Name }}-grpc-ingress annotations: - nginx.ingress.kubernetes.io/auth-url: http://studio-studio.default.svc.cluster.local:8080{{ .Values.studio.auth.endpoint }} nginx.ingress.kubernetes.io/configuration-snippet: | if ($http_grpc_server) { grpc_pass grpc://$http_grpc_server.default.svc.cluster.local:80; } nginx.ingress.kubernetes.io/proxy-body-size: "0" From ebd4911f6c9d03d796207924ea8f758e788bf195 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 19 Mar 2024 17:19:24 +0100 Subject: [PATCH 126/146] remove debug mode --- scaleout/stackn/templates/ingress-platform.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/scaleout/stackn/templates/ingress-platform.yaml b/scaleout/stackn/templates/ingress-platform.yaml index 56c67831..abd8e255 100644 --- a/scaleout/stackn/templates/ingress-platform.yaml +++ b/scaleout/stackn/templates/ingress-platform.yaml @@ -36,15 +36,9 @@ spec: - path: /static/ backend: service: - {{ if $.Values.studio.debug }} - name: {{ $.Release.Name }}-studio - port: - number: 8080 - {{ else }} name: {{ $.Release.Name }}-static port: number: 8081 - {{ end }} pathType: ImplementationSpecific - path: /media/ backend: From 9b3ffe7e2e86d0d606e96f365e19ea88c8ea42bd Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 27 Mar 2024 15:22:45 +0100 Subject: [PATCH 127/146] update event listener --- scaleout/stackn/templates/event-listener-deployment.yaml | 9 --------- scaleout/stackn/values.yaml | 5 ++--- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/scaleout/stackn/templates/event-listener-deployment.yaml b/scaleout/stackn/templates/event-listener-deployment.yaml index 6a532b24..6eb8c050 100644 --- a/scaleout/stackn/templates/event-listener-deployment.yaml +++ b/scaleout/stackn/templates/event-listener-deployment.yaml @@ -44,13 +44,6 @@ spec: - all {{- end }} env: - - name: EVENT_LISTENER_USERNAME - value: {{ .Values.studio.eventListenerUsername | quote }} - - name: EVENT_LISTENER_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "stackn.secretName" . }} - key: studio-event-listener-user-password - name: STUDIO_SERVICE_NAME value: {{ .Values.eventListener.studioServiceName | quote }} - name: STUDIO_SERVICE_PORT @@ -59,8 +52,6 @@ spec: value: {{ .Values.eventListener.appStatusEndpoint | quote }} - name: APP_STATUSES_ENDPOINT value: {{ .Values.eventListener.appStatusesEndpoint | quote }} - - name: TOKEN_ENDPOINT - value: {{ .Values.eventListener.tokenEndpoint | quote }} restartPolicy: Always securityContext: fsGroup: {{ .Values.studio.securityContext.fsGroup }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index dd7839df..03f5b56f 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -263,9 +263,8 @@ mongoexpress: eventListener: studioServiceName: "studio-studio" studioServicePort: "8080" - appStatusEndpoint: "api/app/status" - appStatusesEndpoint: "api/app/statuses" - tokenEndpoint: "api/token-auth/" + appStatusEndpoint: "api/internal/app/status" + appStatusesEndpoint: "api/internal/app/statuses" image: repository: harbor.scaleoutsystems.com/studio/studio-kube-controller:0.10.0-beta.1 pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image From ce1d11bb5ba5f44a1ffaf106173b15445349f0ac Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 27 Mar 2024 15:43:11 +0100 Subject: [PATCH 128/146] update ingress annotations --- scaleout/stackn/templates/grpc-ingress.yaml | 6 ++++++ scaleout/stackn/templates/ingress-platform.yaml | 7 ++++--- scaleout/stackn/values.yaml | 1 - 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/scaleout/stackn/templates/grpc-ingress.yaml b/scaleout/stackn/templates/grpc-ingress.yaml index 4cdce93a..51eeb195 100644 --- a/scaleout/stackn/templates/grpc-ingress.yaml +++ b/scaleout/stackn/templates/grpc-ingress.yaml @@ -4,6 +4,12 @@ metadata: name: {{ .Release.Name }}-grpc-ingress annotations: nginx.ingress.kubernetes.io/configuration-snippet: | + if ($request_uri ~* "^/fedn.Connector/AcceptingClients") { return 403; } + if ($request_uri ~* "^/fedn.Connector/ListActiveClients") { return 403; } + if ($request_uri ~* "^/fedn.Control/Start") { return 403; } + if ($request_uri ~* "^/fedn.Control/Stop") { return 403; } + if ($request_uri ~* "^/fedn.Control/FlushAggregationQueue") { return 403; } + if ($request_uri ~* "^/fedn.Control/SetAggregator") { return 403; } if ($http_grpc_server) { grpc_pass grpc://$http_grpc_server.default.svc.cluster.local:80; } nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-set-headers: X-Forwarded-Proto:$scheme diff --git a/scaleout/stackn/templates/ingress-platform.yaml b/scaleout/stackn/templates/ingress-platform.yaml index abd8e255..c3a5d725 100644 --- a/scaleout/stackn/templates/ingress-platform.yaml +++ b/scaleout/stackn/templates/ingress-platform.yaml @@ -4,9 +4,10 @@ kind: Ingress metadata: name: {{ .Release.Name }}-ingress annotations: - {{- with .Values.ingress.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} + nginx.ingress.kubernetes.io/configuration-snippet: | + if ($request_uri ~ ^/api/internal) { return 403; } + nginx.ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/proxy-set-headers: X-Forwarded-Proto:$scheme labels: io.kompose.service: {{ .Release.Name }}-ingress spec: diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 03f5b56f..1cf97378 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -202,7 +202,6 @@ grpc_domain: grpc.studio.127.0.0.1.nip.io # domain for grpc servers (combiners i session_cookie_domain: .127.0.0.1.nip.io # domain for session cookie, should be .domain ingress: enabled: true - annotations: {} hosts: - host: studio.127.0.0.1.nip.io tls: From cf9ae41ac790aeea98360bc3b29a1d1c9f4e3a14 Mon Sep 17 00:00:00 2001 From: stefanhellander <59477428+stefanhellander@users.noreply.github.com> Date: Mon, 8 Apr 2024 10:33:57 +0200 Subject: [PATCH 129/146] Feature/SK-718 | Adds option to install postgres cluster via CloudnativePG plus other clean up (#110) A few changes: If the Cloudnative PG operator is installed on the cluster, then either the chart can install a postgres cluster, or if the user has already installed a cluster, then Studio can connect to it. The only settings that you need to change are studio.cloudnativepg.enabled and studio.cloudnativepg.create_new, no need to set passwords for Postgres. If a Minio cluster is installed via the Minio operator, and named "minio-fedn", then no changes to the values file are required, and the user no longer needs to then create a secret manually (assuming that the name of the user secret is the default one set by Minio and not changed by the user). If postgres and the Minio cluster is set up as above then backups will be stored in a bucket in that Minio instance. Can be configured to be a different Minio store. Removed mediavol. Added environment variables to Studio deployment that are needed for doing log aggregation of FEDn logs in Studio. --- .../templates/cloudnativepg-cluster.yaml | 58 +++++++++++++++++ scaleout/stackn/templates/media-vol.yaml | 13 ---- .../stackn/templates/nginx-deployment.yaml | 6 -- .../stackn/templates/studio-deployment.yaml | 62 ++++++++++++++----- scaleout/stackn/values.yaml | 30 ++++++--- 5 files changed, 126 insertions(+), 43 deletions(-) create mode 100644 scaleout/stackn/templates/cloudnativepg-cluster.yaml delete mode 100644 scaleout/stackn/templates/media-vol.yaml diff --git a/scaleout/stackn/templates/cloudnativepg-cluster.yaml b/scaleout/stackn/templates/cloudnativepg-cluster.yaml new file mode 100644 index 00000000..2be95b49 --- /dev/null +++ b/scaleout/stackn/templates/cloudnativepg-cluster.yaml @@ -0,0 +1,58 @@ +{{ if and .Values.studio.cloudnativepg.enabled .Values.studio.cloudnativepg.create_new }} +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: {{ .Values.studio.cloudnativepg.clusterName }} +spec: + instances: {{ .Values.studio.cloudnativepg.spec.instances }} + storage: + size: {{ .Values.studio.cloudnativepg.spec.storage.size }} + {{ if .Values.studio.minio_backup.enabled }} + backup: + barmanObjectStore: + destinationPath: s3://studio-backups + serverName: {{ .Values.studio.cloudnativepg.clusterName }} + endpointURL: http://{{ .Values.studio.minio_backup.host }}:{{ .Values.studio.minio_backup.port }} + s3Credentials: + accessKeyId: + name: {{ .Values.studio.minio_backup.secretName }} + key: CONSOLE_ACCESS_KEY + secretAccessKey: + name: {{ .Values.studio.minio_backup.secretName }} + key: CONSOLE_SECRET_KEY + {{ end }} +--- +# Base backup runs at midnight every day +{{ if .Values.studio.minio_backup.enabled}} +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: base-backup +spec: + schedule: "0 0 0 * * *" + backupOwnerReference: self + cluster: + name: studio-db +{{ end }} +{{ end }} + + + +# Example of how to bootstrap from backups for a cluster +# called studio-cluster2 + # bootstrap: + # recovery: + # source: studio-cluster2 + + # externalClusters: + # - name: studio-cluster2 + # barmanObjectStore: + # destinationPath: s3://studio-backups + # endpointURL: http://minio-fedn-hl:9000 + # s3Credentials: + # accessKeyId: + # name: aws-creds + # key: ACCESS_KEY_ID + # secretAccessKey: + # name: aws-creds + # key: ACCESS_SECRET_KEY \ No newline at end of file diff --git a/scaleout/stackn/templates/media-vol.yaml b/scaleout/stackn/templates/media-vol.yaml deleted file mode 100644 index f39274f8..00000000 --- a/scaleout/stackn/templates/media-vol.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ .Release.Name }}-{{ .Values.studio.media.storage.claimName }} - annotations: - "helm.sh/resource-policy": keep -spec: - accessModes: - - {{ .Values.studio.media.storage.accessModes | default "ReadWriteMany"}} - storageClassName: {{ include "stackn.studio.media.storageclass" . }} - resources: - requests: - storage: {{ .Values.studio.media.storage.size | default "5Gi" }} diff --git a/scaleout/stackn/templates/nginx-deployment.yaml b/scaleout/stackn/templates/nginx-deployment.yaml index 92d7e5fc..ed2f0d59 100644 --- a/scaleout/stackn/templates/nginx-deployment.yaml +++ b/scaleout/stackn/templates/nginx-deployment.yaml @@ -32,9 +32,6 @@ spec: - name: rp-conf configMap: name: {{ .Release.Name }}-static-config - - name: mediavol - persistentVolumeClaim: - claimName: {{ .Release.Name }}-{{ .Values.studio.media.storage.claimName }} containers: - name: static image: {{ .Values.studio.static.image }} @@ -51,8 +48,6 @@ spec: - name: rp-conf mountPath: /etc/nginx/nginx.conf subPath: nginx.conf - - name: mediavol - mountPath: /etc/nginx/html/media resources: limits: cpu: {{ .Values.studio.static.resources.limits.cpu }} @@ -62,4 +57,3 @@ spec: memory: {{ .Values.studio.static.resources.requests.memory }} imagePullSecrets: - name: {{ .Values.imagePullSecrets.name }} - diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 59279961..bba665ca 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -30,7 +30,22 @@ spec: initContainers: - name: wait-for-db image: postgres + {{ if .Values.studio.cloudnativepg.enabled }} + env: + - name: POSTGRES_PORT + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: port + - name: POSTGRES_HOST + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: host + command: ['sh', '-c', 'until pg_isready --host=$POSTGRES_HOST --port=$POSTGRES_PORT; do echo waiting for database; sleep 2; done;'] + {{ else }} command: ['sh', '-c', 'until pg_isready --host={{ .Values.postgresql.fullnameOverride }} --port={{ .Values.postgresql.primary.service.ports.postgresql }}; do echo waiting for database; sleep 2; done;'] + {{ end }} resources: limits: cpu: "100m" @@ -166,6 +181,33 @@ spec: key: studio-event-listener-user-password - name: GET_HOSTS_FROM value: dns + {{ if .Values.studio.cloudnativepg.enabled }} + - name: POSTGRES_NAME + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: dbname + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: user + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: password + - name: POSTGRES_PORT + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: port + - name: POSTGRES_HOST + valueFrom: + secretKeyRef: + name: {{ .Values.studio.cloudnativepg.clusterName }}-app + key: host + {{ else }} - name: POSTGRES_NAME value: {{ .Values.postgresql.auth.database }} - name: POSTGRES_USER @@ -179,6 +221,7 @@ spec: secretKeyRef: name: {{ include "stackn.postgres.secretName" . }} key: password + {{ end }} - name: DJANGO_SECRET valueFrom: secretKeyRef: @@ -204,19 +247,17 @@ spec: - name: S3HOST value: {{ .Values.studio.minio.host }} - name: S3PORT - value: "{{ .Values.studio.minio.port }}" - - name: S3SECRET_NAME - value: {{ .Values.studio.minio.secretName }} + value: "{{ .Values.studio.minio.port | default 9000 }}" - name: S3ACCESS_KEY valueFrom: secretKeyRef: name: {{ .Values.studio.minio.secretName }} - key: accessKey + key: CONSOLE_ACCESS_KEY - name: S3SECRET_KEY valueFrom: secretKeyRef: name: {{ .Values.studio.minio.secretName }} - key: secretKey + key: CONSOLE_SECRET_KEY {{ if .Values.studio.argocd.enabled }} - name: ARGO_CD_ENABLED value: "true" @@ -269,11 +310,6 @@ spec: image: {{ .Values.studio.image.repository }} imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio - {{ if .Values.studio.media.storage.mountStudio }} - volumeMounts: - - name: mediavol - mountPath: {{ .Values.studio.media.mount_path }} - {{ end }} resources: limits: cpu: {{ .Values.studio.resources.limits.cpu }} @@ -308,9 +344,3 @@ spec: imagePullSecrets: - name: {{ .Values.imagePullSecrets.name }} restartPolicy: Always - {{ if .Values.studio.media.storage.mountStudio }} - volumes: - - name: mediavol - persistentVolumeClaim: - claimName: {{ .Release.Name }}-{{ .Values.studio.media.storage.claimName }} - {{ end }} \ No newline at end of file diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 1cf97378..b66444ee 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -109,12 +109,6 @@ studio: # studio values memory: "2Gi" storage: storageClass: "" - media: - storage: - storageClass: "" - size: "5Gi" - accessModes: ReadWriteMany - mount_path: /app/media/ superUser: admin superuserPassword: "" superuserEmail: admin@test.com @@ -175,15 +169,35 @@ studio: # studio values path: "chart/fedn" revision: "*" + # Secret should have entries CLUSTER_ACCESS_KEY and CLUSTER_SECRET_KEY minio: enabled: true - host: "" - secretName: minio-fedn + host: minio-fedn-hl + secretName: minio-fedn-user-0 + port: "9000" + + # Secret should have entries CLUSTER_ACCESS_KEY and CLUSTER_SECRET_KEY + minio_backup: + enabled: true + host: minio-fedn-hl + secretName: minio-fedn-user-0 + port: "9000" harbor: enabled: true username: "" password: "" + + # If you have installed the CloudnativePG operator, enable this and set the clusterName. + # You should also disable postgres below. + cloudnativepg: + enabled: false # Set to true if you want to use a CloudnativePG cluster + create_new: true # Set to true if you want to create a new postgres cluster. + clusterName: studio-db + spec: + instances: 3 + storage: + size: 20Gi # Pull secrets for studio, used to pull images from private repositories such as Harbor # To create a pull secret run: $ kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= From 71a54ec945d40375dbe79990810ecacf6ea78260 Mon Sep 17 00:00:00 2001 From: stefanhellander <59477428+stefanhellander@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:27:03 +0200 Subject: [PATCH 130/146] Added mongodb backup and restore jobs (#111) --- .../stackn/templates/mongodb-backup-job.yaml | 47 ++++++++++++++++ .../stackn/templates/mongorestorejob.yaml | 55 +++++++++++++++++++ scaleout/stackn/values.yaml | 12 +++- 3 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 scaleout/stackn/templates/mongodb-backup-job.yaml create mode 100644 scaleout/stackn/templates/mongorestorejob.yaml diff --git a/scaleout/stackn/templates/mongodb-backup-job.yaml b/scaleout/stackn/templates/mongodb-backup-job.yaml new file mode 100644 index 00000000..01468855 --- /dev/null +++ b/scaleout/stackn/templates/mongodb-backup-job.yaml @@ -0,0 +1,47 @@ +{{ if .Values.mongodb.backups.enabled }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: mongodb-backup-to-minio +spec: + schedule: {{ .Values.mongodb.backups.backupSchedule | default "*/30 * * * *" | quote}} + jobTemplate: + spec: + template: + spec: + imagePullSecrets: + - name: {{ .Values.imagePullSecrets.name }} + containers: + - name: mongo-backup + image: {{ .Values.mongodb.backups.image }} + imagePullPolicy: Always + env: + - name: MONGO_SERVICE_HOST + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: MONGO_SERVICE_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + - name: MONGO_USERNAME + value: {{ .Values.mongodb.auth.rootUser | quote }} + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.fullname" .Subcharts.mongodb }} + key: mongodb-root-password + - name: S3HOST + value: http://{{ .Values.studio.minio_backup.host }} + - name: S3PORT + value: {{ .Values.studio.minio_backup.port | quote }} + - name : S3BUCKET + value: mongodb-backups + - name: S3ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.minio_backup.secretName }} + key: CONSOLE_ACCESS_KEY + - name: S3SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.minio_backup.secretName }} + key: CONSOLE_SECRET_KEY + restartPolicy: OnFailure +{{ end }} \ No newline at end of file diff --git a/scaleout/stackn/templates/mongorestorejob.yaml b/scaleout/stackn/templates/mongorestorejob.yaml new file mode 100644 index 00000000..8edfa4e6 --- /dev/null +++ b/scaleout/stackn/templates/mongorestorejob.yaml @@ -0,0 +1,55 @@ +{{ if .Values.mongodb.restoreFromFile.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + name: mongodb-restore-job +spec: + template: + spec: + imagePullSecrets: + - name: {{ .Values.imagePullSecrets.name }} + initContainers: + - name: wait-for-db + image: busybox + env: + - name: DB_SERVICE + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: DB_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + command: ["sh", "-c", "until nc -z $DB_SERVICE $DB_PORT > /dev/null; do echo Waiting for master.; sleep 2; done;"] + containers: + - name: mongo-restore + image: {{ .Values.mongodb.restoreFromFile.image }} + imagePullPolicy: Always + env: + - name: MONGO_SERVICE_HOST + value: {{ include "mongodb.service.nameOverride" .Subcharts.mongodb }} + - name: MONGO_SERVICE_PORT + value: {{ .Values.mongodb.service.ports.mongodb | quote }} + - name: MONGO_USERNAME + value: {{ .Values.mongodb.auth.rootUser | quote }} + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.fullname" .Subcharts.mongodb }} + key: mongodb-root-password + - name: S3HOST + value: http://{{ .Values.studio.minio_backup.host }} + - name: S3PORT + value: {{ .Values.studio.minio_backup.port | quote }} + - name : S3BUCKET + value: mongodb-backups + - name: S3ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.minio_backup.secretName }} + key: CONSOLE_ACCESS_KEY + - name: S3SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.studio.minio_backup.secretName }} + key: CONSOLE_SECRET_KEY + - name: BACKUPFILENAME + value: {{ .Values.mongodb.restoreFromFile.backupFileName }} + restartPolicy: OnFailure +{{ end }} \ No newline at end of file diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index b66444ee..9634d77a 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -179,8 +179,8 @@ studio: # studio values # Secret should have entries CLUSTER_ACCESS_KEY and CLUSTER_SECRET_KEY minio_backup: enabled: true - host: minio-fedn-hl - secretName: minio-fedn-user-0 + host: minio-system-hl.minio-system.svc.cluster.local + secretName: minio-system-user-0 port: "9000" harbor: @@ -263,6 +263,14 @@ postgresql: # Please also observe the version we are using in requirements.yaml mongodb: + backups: + enabled: false + image: harbor.scaleoutsystems.com/studio/mongo-backup:0.1.0 + backupSchedule: "*/30 * * * *" # backup schedule for mongodb + restoreFromFile: + enabled: false + image: harbor.scaleoutsystems.com/studio/mongo-restore:0.1.0 + backupFileName: "" enabled: true commonAnnotations: {"reloader.stakater.com/auto": "true"} podLabels: {"app":"stackn-studio","allow-api-access": "true"} From debc252e9131961b3a72c61a51f4af18291defc3 Mon Sep 17 00:00:00 2001 From: stefanhellander <59477428+stefanhellander@users.noreply.github.com> Date: Fri, 12 Apr 2024 16:33:05 +0200 Subject: [PATCH 131/146] Feature/SK-786 | Updated to ensure FEDn connects to replica set if mongodb configured that way (#112) Updated so that fedn will connect to replicaset if mongodb is set up as such. --- scaleout/stackn/templates/studio-deployment.yaml | 6 ++++++ scaleout/stackn/values.yaml | 1 + 2 files changed, 7 insertions(+) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index bba665ca..04df3c2a 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -293,6 +293,12 @@ spec: secretKeyRef: name: {{ include "mongodb.fullname" .Subcharts.mongodb }} key: mongodb-root-password + - name: MONGO_ARCHITECTURE + value: {{ .Values.mongodb.architecture | default "standalone" }} + - name: MONGO_REPLICA_COUNT + value: {{ .Values.mongodb.replicaCount | default "1" | quote }} + - name: MONGO_REPLICA_SET_NAME + value: {{ .Values.mongodb.replicaSetName | default "rs0" }} {{ end }} {{ if .Values.studio.harbor.enabled }} - name: HARBOR_ENABLED diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 9634d77a..b64cdeb6 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -272,6 +272,7 @@ mongodb: image: harbor.scaleoutsystems.com/studio/mongo-restore:0.1.0 backupFileName: "" enabled: true + replicaSetName: "rs0" commonAnnotations: {"reloader.stakater.com/auto": "true"} podLabels: {"app":"stackn-studio","allow-api-access": "true"} From 78e7133537acb8b50425f7143667738ae6d6871d Mon Sep 17 00:00:00 2001 From: Niklas Date: Fri, 13 Sep 2024 08:46:40 +0200 Subject: [PATCH 132/146] Added WELCOME_EMAIL_ON_NEW_USER (#113) --- scaleout/stackn/templates/studio-deployment.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 04df3c2a..ba4d5fe7 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -102,6 +102,12 @@ spec: value: {{ .Values.studio.emailService.apiEndpoint | quote}} - name: NOTIFY_ON_ACCOUNT_REGISTER_LIST value: "{{ range $index, $elem := .Values.studio.emailService.notifyOnAccountRegisterList }}{{ if $index }},{{ end }}{{ $elem }}{{ end }}" + - name: WELCOME_EMAIL_ON_NEW_USER + {{ if .Values.studio.welcomeEmail.enabled }} + value: "true" + {{ else }} + value: "false" + {{ end }} - name: VERSION value: {{ .Values.studio.version | quote }} - name: DEFAULT_FROM_EMAIL From 7888b4034bb8cb9e62bc3688b8dd248483dace6b Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Mon, 16 Sep 2024 11:17:08 +0200 Subject: [PATCH 133/146] Bumped versions --- scaleout/stackn/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index c2e55ef8..85cbb0f9 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v1 -appVersion: "0.10.0" +appVersion: "0.14.5" description: A Helm chart for deploying studio name: studio -version: 0.5.0 +version: 0.5.3 maintainers: - email: fredrik@scaleoutsystems.com name: Fredrik Wrede From f5e097801a22a745e9fceaf1b0dd10f0e28b4b39 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Mon, 16 Sep 2024 13:55:13 +0200 Subject: [PATCH 134/146] set welcome email to disabled by default in values.yaml --- scaleout/stackn/values.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index b64cdeb6..6887d019 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -147,6 +147,8 @@ studio: # studio values apiKey: '' notifyOnAccountRegisterList: - '' + welcomeEmail: + enabled: false disabledAppInstanceFields: # disabled app instance fields for studio. Do not change unless you know what you are doing. enabled: false fields: From fbd05e192b4ebdec416c592c860ec2d7e440e87d Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Fri, 20 Sep 2024 17:17:04 +0200 Subject: [PATCH 135/146] Fix condition in mongo restore job manifest --- scaleout/stackn/Chart.yaml | 2 +- scaleout/stackn/templates/mongorestorejob.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index 85cbb0f9..594a3e98 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 appVersion: "0.14.5" description: A Helm chart for deploying studio name: studio -version: 0.5.3 +version: 0.5.4 maintainers: - email: fredrik@scaleoutsystems.com name: Fredrik Wrede diff --git a/scaleout/stackn/templates/mongorestorejob.yaml b/scaleout/stackn/templates/mongorestorejob.yaml index 8edfa4e6..761e3115 100644 --- a/scaleout/stackn/templates/mongorestorejob.yaml +++ b/scaleout/stackn/templates/mongorestorejob.yaml @@ -1,4 +1,4 @@ -{{ if .Values.mongodb.restoreFromFile.enabled }} +{{ if eq .Values.mongodb.restoreFromFile.enabled true }} apiVersion: batch/v1 kind: Job metadata: From d77cfe3f21c4178ba77b6090c54b5a178e4a8518 Mon Sep 17 00:00:00 2001 From: stefanhellander <59477428+stefanhellander@users.noreply.github.com> Date: Wed, 2 Oct 2024 15:56:59 +0200 Subject: [PATCH 136/146] Added sentry configs (#114) --- scaleout/stackn/templates/studio-deployment.yaml | 10 ++++++++++ scaleout/stackn/values.yaml | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index ba4d5fe7..d071fcdb 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -102,6 +102,16 @@ spec: value: {{ .Values.studio.emailService.apiEndpoint | quote}} - name: NOTIFY_ON_ACCOUNT_REGISTER_LIST value: "{{ range $index, $elem := .Values.studio.emailService.notifyOnAccountRegisterList }}{{ if $index }},{{ end }}{{ $elem }}{{ end }}" + {{ if .Values.studio.sentry.enabled }} + - name: SENTRY_ENABLED + value: "true" + - name: SENTRY_STUDIO_DSN + value: "{{ .Values.studio.sentry.studio_dsn }}" + - name: SENTRY_CONTROLLER_DSN + value: "{{ .Values.studio.sentry.controller_dsn }}" + - name: SENTRY_COMBINER_DSN + value: "{{ .Values.studio.sentry.combiner_dsn }}" + {{ end }} - name: WELCOME_EMAIL_ON_NEW_USER {{ if .Values.studio.welcomeEmail.enabled }} value: "true" diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 6887d019..e4e80326 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -166,6 +166,12 @@ studio: # studio values namespace: "default" server: "https://kubernetes.default.svc" + sentry: + enabled: false + studio_dsn: "" + controller_dsn: "" + combiner_dsn: "" + project: repo: "harbor.scaleoutsystems.com" path: "chart/fedn" From 416ca0cebc0d4829528f6658f2809c7a8ee6df7f Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Wed, 2 Oct 2024 16:19:33 +0200 Subject: [PATCH 137/146] Added sentry environment as env variable --- scaleout/stackn/templates/studio-deployment.yaml | 2 ++ scaleout/stackn/values.yaml | 1 + 2 files changed, 3 insertions(+) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index d071fcdb..e3d5ee34 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -111,6 +111,8 @@ spec: value: "{{ .Values.studio.sentry.controller_dsn }}" - name: SENTRY_COMBINER_DSN value: "{{ .Values.studio.sentry.combiner_dsn }}" + - name: SENTRY_ENVIRONMENT + value: "{{ .Values.studio.sentry.environment }}" {{ end }} - name: WELCOME_EMAIL_ON_NEW_USER {{ if .Values.studio.welcomeEmail.enabled }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index e4e80326..daef111f 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -171,6 +171,7 @@ studio: # studio values studio_dsn: "" controller_dsn: "" combiner_dsn: "" + environment: "" project: repo: "harbor.scaleoutsystems.com" From 27f8833a944f8922cdc86b9c0eaa06e3d9e6eb3d Mon Sep 17 00:00:00 2001 From: stefanhellander <59477428+stefanhellander@users.noreply.github.com> Date: Tue, 5 Nov 2024 13:12:49 +0100 Subject: [PATCH 138/146] Update in mongodb backup job manifest (#115) --- scaleout/stackn/templates/mongodb-backup-job.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scaleout/stackn/templates/mongodb-backup-job.yaml b/scaleout/stackn/templates/mongodb-backup-job.yaml index 01468855..2c3ab8a8 100644 --- a/scaleout/stackn/templates/mongodb-backup-job.yaml +++ b/scaleout/stackn/templates/mongodb-backup-job.yaml @@ -28,20 +28,20 @@ spec: name: {{ include "mongodb.fullname" .Subcharts.mongodb }} key: mongodb-root-password - name: S3HOST - value: http://{{ .Values.studio.minio_backup.host }} + value: {{ .Values.studio.minio_backup.host }} - name: S3PORT value: {{ .Values.studio.minio_backup.port | quote }} - name : S3BUCKET - value: mongodb-backups + value: studio-mongodb-backups - name: S3ACCESS_KEY valueFrom: secretKeyRef: name: {{ .Values.studio.minio_backup.secretName }} - key: CONSOLE_ACCESS_KEY + key: access_key - name: S3SECRET_KEY valueFrom: secretKeyRef: name: {{ .Values.studio.minio_backup.secretName }} - key: CONSOLE_SECRET_KEY + key: secret_key restartPolicy: OnFailure {{ end }} \ No newline at end of file From 45639db967bbde193a6ab749c86a1f239b443d23 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Tue, 5 Nov 2024 13:28:06 +0100 Subject: [PATCH 139/146] Updated restore jobs (not used normally) --- scaleout/stackn/templates/cloudnativepg-cluster.yaml | 6 +++--- scaleout/stackn/templates/mongorestorejob.yaml | 6 +++--- scaleout/stackn/values.yaml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/scaleout/stackn/templates/cloudnativepg-cluster.yaml b/scaleout/stackn/templates/cloudnativepg-cluster.yaml index 2be95b49..3161b2c0 100644 --- a/scaleout/stackn/templates/cloudnativepg-cluster.yaml +++ b/scaleout/stackn/templates/cloudnativepg-cluster.yaml @@ -12,14 +12,14 @@ spec: barmanObjectStore: destinationPath: s3://studio-backups serverName: {{ .Values.studio.cloudnativepg.clusterName }} - endpointURL: http://{{ .Values.studio.minio_backup.host }}:{{ .Values.studio.minio_backup.port }} + endpointURL: {{ .Values.studio.minio_backup.host }}:{{ .Values.studio.minio_backup.port }} s3Credentials: accessKeyId: name: {{ .Values.studio.minio_backup.secretName }} - key: CONSOLE_ACCESS_KEY + key: access_key secretAccessKey: name: {{ .Values.studio.minio_backup.secretName }} - key: CONSOLE_SECRET_KEY + key: secret_key {{ end }} --- # Base backup runs at midnight every day diff --git a/scaleout/stackn/templates/mongorestorejob.yaml b/scaleout/stackn/templates/mongorestorejob.yaml index 761e3115..ee13fcff 100644 --- a/scaleout/stackn/templates/mongorestorejob.yaml +++ b/scaleout/stackn/templates/mongorestorejob.yaml @@ -34,7 +34,7 @@ spec: name: {{ include "mongodb.fullname" .Subcharts.mongodb }} key: mongodb-root-password - name: S3HOST - value: http://{{ .Values.studio.minio_backup.host }} + value: {{ .Values.studio.minio_backup.host }} - name: S3PORT value: {{ .Values.studio.minio_backup.port | quote }} - name : S3BUCKET @@ -43,12 +43,12 @@ spec: valueFrom: secretKeyRef: name: {{ .Values.studio.minio_backup.secretName }} - key: CONSOLE_ACCESS_KEY + key: access_key - name: S3SECRET_KEY valueFrom: secretKeyRef: name: {{ .Values.studio.minio_backup.secretName }} - key: CONSOLE_SECRET_KEY + key: secret_key - name: BACKUPFILENAME value: {{ .Values.mongodb.restoreFromFile.backupFileName }} restartPolicy: OnFailure diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index daef111f..9ddee1bf 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -185,10 +185,10 @@ studio: # studio values secretName: minio-fedn-user-0 port: "9000" - # Secret should have entries CLUSTER_ACCESS_KEY and CLUSTER_SECRET_KEY + # Secret should have entries access_key and secret_key minio_backup: enabled: true - host: minio-system-hl.minio-system.svc.cluster.local + host: http://minio-system-hl.minio-system.svc.cluster.local secretName: minio-system-user-0 port: "9000" From b961433070f3ac640ee97022b244f3fbb0f12fda Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Fri, 8 Nov 2024 22:19:24 +0100 Subject: [PATCH 140/146] Added option to set recaptcha enabled --- scaleout/stackn/templates/studio-deployment.yaml | 14 ++++++++++++++ scaleout/stackn/values.yaml | 3 +++ 2 files changed, 17 insertions(+) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index e3d5ee34..aca77c84 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -293,6 +293,20 @@ spec: name: {{ include "stackn.secretName" . }} key: studio-argocd-token {{ end }} + {{ if .Values.studio.recaptcha.enabled }} + - name: RECAPTCHA_ENABLED + value: "true" + - name: RECAPTCHA_SITE_KEY + valueFrom: + secretKeyRef: + name: recaptcha-keys + key: site-key + - name: RECAPTCHA_SECRET_KEY + valueFrom: + secretKeyRef: + name: recaptcha-keys + key: secret-key + {{ end }} - name: CHART_REPO value: {{ .Values.studio.project.repo }} - name: CHART_PATH diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 9ddee1bf..fc45dc6a 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -166,6 +166,9 @@ studio: # studio values namespace: "default" server: "https://kubernetes.default.svc" + recaptcha: + enabled: false + sentry: enabled: false studio_dsn: "" From 07c7f3d696df52463f0969b1e64f19eeebcb3357 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Wed, 20 Nov 2024 16:36:21 +0100 Subject: [PATCH 141/146] update grpc ingress port --- scaleout/stackn/templates/grpc-ingress.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/grpc-ingress.yaml b/scaleout/stackn/templates/grpc-ingress.yaml index 51eeb195..fa35b421 100644 --- a/scaleout/stackn/templates/grpc-ingress.yaml +++ b/scaleout/stackn/templates/grpc-ingress.yaml @@ -10,7 +10,7 @@ metadata: if ($request_uri ~* "^/fedn.Control/Stop") { return 403; } if ($request_uri ~* "^/fedn.Control/FlushAggregationQueue") { return 403; } if ($request_uri ~* "^/fedn.Control/SetAggregator") { return 403; } - if ($http_grpc_server) { grpc_pass grpc://$http_grpc_server.default.svc.cluster.local:80; } + if ($http_grpc_server) { grpc_pass grpc://$http_grpc_server.default.svc.cluster.local:12080; } nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-set-headers: X-Forwarded-Proto:$scheme nginx.ingress.kubernetes.io/server-snippet: | From 904a634cd3186fd53695da9da22bca784e7044a8 Mon Sep 17 00:00:00 2001 From: Stefan Hellander Date: Fri, 31 Jan 2025 17:07:02 +0100 Subject: [PATCH 142/146] Updated version number --- scaleout/stackn/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index 594a3e98..968668e0 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 appVersion: "0.14.5" description: A Helm chart for deploying studio name: studio -version: 0.5.4 +version: 0.5.5 maintainers: - email: fredrik@scaleoutsystems.com name: Fredrik Wrede From a32be3c665d20c45a3a7be40422d7e47c7a6b42a Mon Sep 17 00:00:00 2001 From: stefanhellander <59477428+stefanhellander@users.noreply.github.com> Date: Tue, 11 Feb 2025 12:10:13 +0100 Subject: [PATCH 143/146] Feature/SK-1350 | Changed how we handle app versions (#116) --- scaleout/stackn/Chart.yaml | 4 +- .../stackn/templates/deployment-frontend.yaml | 81 +++++++++++++++++++ .../templates/event-listener-deployment.yaml | 2 +- .../stackn/templates/ingress-frontend.yaml | 32 ++++++++ .../stackn/templates/ingress-platform.yaml | 9 +++ .../stackn/templates/mongodb-backup-job.yaml | 2 +- scaleout/stackn/templates/nginx-conf.yaml | 2 + .../stackn/templates/nginx-deployment.yaml | 4 +- scaleout/stackn/templates/nginx-service.yaml | 2 + .../stackn/templates/service-frontend.yaml | 11 +++ .../stackn/templates/studio-deployment.yaml | 4 +- scaleout/stackn/values.yaml | 68 +++++++++++++++- 12 files changed, 210 insertions(+), 11 deletions(-) create mode 100644 scaleout/stackn/templates/deployment-frontend.yaml create mode 100644 scaleout/stackn/templates/ingress-frontend.yaml create mode 100644 scaleout/stackn/templates/service-frontend.yaml diff --git a/scaleout/stackn/Chart.yaml b/scaleout/stackn/Chart.yaml index 968668e0..7fbb322e 100644 --- a/scaleout/stackn/Chart.yaml +++ b/scaleout/stackn/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v1 -appVersion: "0.14.5" +appVersion: "0.17.0" description: A Helm chart for deploying studio name: studio -version: 0.5.5 +version: 0.5.6 maintainers: - email: fredrik@scaleoutsystems.com name: Fredrik Wrede diff --git a/scaleout/stackn/templates/deployment-frontend.yaml b/scaleout/stackn/templates/deployment-frontend.yaml new file mode 100644 index 00000000..486994c3 --- /dev/null +++ b/scaleout/stackn/templates/deployment-frontend.yaml @@ -0,0 +1,81 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: fedn-frontend +spec: + replicas: {{ .Values.frontend.replicas }} + selector: + matchLabels: + app: fedn-frontend + strategy: + type: {{ .Values.frontend.strategy.type }} + template: + metadata: + labels: + app: fedn-frontend + spec: + automountServiceAccountToken: {{ .Values.frontend.automountServiceAccountToken }} + {{- if .Values.frontend.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.frontend.securityContext.runAsUser }} + runAsGroup: {{ .Values.frontend.securityContext.runAsGroup }} + fsGroup: {{ .Values.frontend.securityContext.fsGroup }} + allowPrivilegeEscalation: {{ .Values.frontend.securityContext.allowPrivilegeEscalation }} + privileged: {{ .Values.frontend.securityContext.privileged }} + readOnlyRootFilesystem: {{ .Values.frontend.securityContext.readOnlyRootFilesystem }} + runAsNonRoot: {{ .Values.frontend.securityContext.runAsNonRoot }} + capabilities: + drop: + - ALL + {{- end }} + imagePullSecrets: + - name: {{ .Values.frontend.image.pullSecret }} + containers: + - name: fedn-frontend + imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} + image: {{ .Values.frontend.image.repository | default "harbor.scaleoutsystems.com/fedn/fedn-front-end:main" }} + ports: + - containerPort: 3000 + env: + {{ if .Values.frontend.debug }} + - name: NODE_ENV + value: "development" + {{ end }} + - name: API_URL + value: {{ printf "http://%s-%s:8080" .Release.Name .Values.studio.servicename | quote }} + - name: NEXT_PUBLIC_API_DOMAIN + value: {{ .Values.domain | quote }} + - name: NEXT_PUBLIC_USE_FEDN_PROXY + value: "true" + {{ if .Values.frontend.recaptcha.enabled }} + - name: RECAPTCHA_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.frontend.recaptcha.existingSecret }} + key: {{ .Values.frontend.recaptcha.existingSecretKey }} + - name: NEXT_PUBLIC_RECAPTCHA_SITE_KEY + value: {{ .Values.frontend.recaptcha.siteKey }} + - name: NEXT_PUBLIC_RECAPTCHA_ACTION) + value: {{ .Values.frontend.recaptcha.action }} + {{ end }} + resources: + limits: + cpu: {{ .Values.frontend.resources.limits.cpu }} + memory: {{ .Values.frontend.resources.limits.memory }} + requests: + cpu: {{ .Values.frontend.resources.requests.cpu }} + memory: {{ .Values.frontend.resources.requests.memory }} + {{- if .Values.frontend.readinessProbe.enabled }} + readinessProbe: + tcpSocket: + port: {{ .Values.frontend.readinessProbe.tcpSocket.port }} + initialDelaySeconds: {{ .Values.frontend.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.frontend.readinessProbe.periodSeconds }} + {{- end }} + {{- if .Values.frontend.livenessProbe.enabled }} + livenessProbe: + tcpSocket: + port: {{ .Values.frontend.livenessProbe.tcpSocket.port }} + initialDelaySeconds: {{ .Values.frontend.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.frontend.livenessProbe.periodSeconds }} + {{- end }} diff --git a/scaleout/stackn/templates/event-listener-deployment.yaml b/scaleout/stackn/templates/event-listener-deployment.yaml index 6eb8c050..5a1a915e 100644 --- a/scaleout/stackn/templates/event-listener-deployment.yaml +++ b/scaleout/stackn/templates/event-listener-deployment.yaml @@ -23,7 +23,7 @@ spec: imagePullSecrets: - name: {{ .Values.imagePullSecrets.name }} containers: - - image: {{ .Values.eventListener.image.repository }} + - image: "{{ .Values.eventListener.image.repository | default "harbor.scaleoutsystems.com/studio/studio-kube-controller:{{ .Chart.AppVersion }}" }}" imagePullPolicy: {{ .Values.eventListener.image.pullPolicy }} name: studio-event-listener resources: diff --git a/scaleout/stackn/templates/ingress-frontend.yaml b/scaleout/stackn/templates/ingress-frontend.yaml new file mode 100644 index 00000000..1dab263c --- /dev/null +++ b/scaleout/stackn/templates/ingress-frontend.yaml @@ -0,0 +1,32 @@ +{{- if .Values.frontend.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: fedn-frontend-ingress + namespace: default + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +spec: + ingressClassName: nginx + rules: + {{- range .Values.frontend.ingress.hosts }} + - host: {{ . | quote }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ $.Values.frontend.service.name }} + port: + number: {{ $.Values.frontend.service.port }} + {{- end }} + {{- if .Values.frontend.ingress.tls.enabled }} + tls: + - hosts: + {{- range .Values.frontend.ingress.tls.hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .Values.frontend.ingress.tls.existingSecret }} + {{- end }} +{{- end }} diff --git a/scaleout/stackn/templates/ingress-platform.yaml b/scaleout/stackn/templates/ingress-platform.yaml index c3a5d725..d0be4cda 100644 --- a/scaleout/stackn/templates/ingress-platform.yaml +++ b/scaleout/stackn/templates/ingress-platform.yaml @@ -28,12 +28,20 @@ spec: http: paths: - path: / + backend: + service: + name: fedn-frontend-service + port: + number: 80 + pathType: ImplementationSpecific + - path: /api/ backend: service: name: {{ $.Release.Name }}-studio port: number: 8080 pathType: ImplementationSpecific + {{- if $.Values.studio.static.enabled }} - path: /static/ backend: service: @@ -48,6 +56,7 @@ spec: port: number: 8081 pathType: ImplementationSpecific + {{- end }} {{- end }} {{- end }} diff --git a/scaleout/stackn/templates/mongodb-backup-job.yaml b/scaleout/stackn/templates/mongodb-backup-job.yaml index 2c3ab8a8..e5077abf 100644 --- a/scaleout/stackn/templates/mongodb-backup-job.yaml +++ b/scaleout/stackn/templates/mongodb-backup-job.yaml @@ -32,7 +32,7 @@ spec: - name: S3PORT value: {{ .Values.studio.minio_backup.port | quote }} - name : S3BUCKET - value: studio-mongodb-backups + value: {{ .Values.studio.minio_backup.mongodb_bucket }} - name: S3ACCESS_KEY valueFrom: secretKeyRef: diff --git a/scaleout/stackn/templates/nginx-conf.yaml b/scaleout/stackn/templates/nginx-conf.yaml index c7bf4483..4c9a8112 100644 --- a/scaleout/stackn/templates/nginx-conf.yaml +++ b/scaleout/stackn/templates/nginx-conf.yaml @@ -1,3 +1,4 @@ +{{ if .Values.studio.static.enabled }} kind: ConfigMap apiVersion: v1 metadata: @@ -21,3 +22,4 @@ data: } } } +{{ end }} diff --git a/scaleout/stackn/templates/nginx-deployment.yaml b/scaleout/stackn/templates/nginx-deployment.yaml index ed2f0d59..b285a655 100644 --- a/scaleout/stackn/templates/nginx-deployment.yaml +++ b/scaleout/stackn/templates/nginx-deployment.yaml @@ -1,3 +1,4 @@ +{{ if .Values.studio.static.enabled }} apiVersion: apps/v1 kind: Deployment metadata: @@ -34,7 +35,7 @@ spec: name: {{ .Release.Name }}-static-config containers: - name: static - image: {{ .Values.studio.static.image }} + image: '{{ .Values.studio.static.image | default (printf "harbor.scaleoutsystems.com/studio/studio-nginx:%s" .Chart.AppVersion) }}' imagePullPolicy: {{ .Values.studio.static.pullPolicy }} # securityContext: # runAsUser: 101 @@ -57,3 +58,4 @@ spec: memory: {{ .Values.studio.static.resources.requests.memory }} imagePullSecrets: - name: {{ .Values.imagePullSecrets.name }} +{{ end }} diff --git a/scaleout/stackn/templates/nginx-service.yaml b/scaleout/stackn/templates/nginx-service.yaml index cafaf874..34cefc08 100644 --- a/scaleout/stackn/templates/nginx-service.yaml +++ b/scaleout/stackn/templates/nginx-service.yaml @@ -1,3 +1,4 @@ +{{- if .Values.studio.static.enabled }} apiVersion: v1 kind: Service metadata: @@ -12,3 +13,4 @@ spec: pod: nginx-static status: loadBalancer: {} +{{ end }} diff --git a/scaleout/stackn/templates/service-frontend.yaml b/scaleout/stackn/templates/service-frontend.yaml new file mode 100644 index 00000000..e2aca416 --- /dev/null +++ b/scaleout/stackn/templates/service-frontend.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.frontend.service.name }} +spec: + type: LoadBalancer + ports: + - port: {{ .Values.frontend.service.port }} + targetPort: 3000 + selector: + app: fedn-frontend \ No newline at end of file diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index aca77c84..9b1b970c 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -121,7 +121,7 @@ spec: value: "false" {{ end }} - name: VERSION - value: {{ .Values.studio.version | quote }} + value: "{{ .Values.studio.version | default .Chart.AppVersion }}" - name: DEFAULT_FROM_EMAIL value: {{ .Values.studio.emailService.smtpEmailFrom | quote}} - name: SESSION_COOKIE_DOMAIN @@ -345,7 +345,7 @@ spec: - name: HARBOR_PATH value: {{ .Values.studio.project.path }} {{ end }} - image: {{ .Values.studio.image.repository }} + image: '{{ .Values.studio.image.repository | default (printf "harbor.scaleoutsystems.com/studio/studio:%s" .Chart.AppVersion) }}' imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio resources: diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index fc45dc6a..0239c7e6 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -52,6 +52,64 @@ networkPolicy: # network policy for stackn - 172.0.0.0/20 ingress_controller_namespace: kube-system # namespace for ingress controller +frontend: + service: + name: fedn-frontend-service # name of frontend service + port: 80 # port for frontend service + replicas: 1 # number of frontend replicas + strategy: # strategy for frontend + type: RollingUpdate # type of strategy + image: # image for frontend + repository: harbor.scaleoutsystems.com/fedn/fedn-front-end:main + pullPolicy: Always # pull policy for frontend + pullSecret: harborsecret # pull secret for frontend + resources: # resources for frontend + limits: # limits for frontend + cpu: "1000m" # cpu limit for frontend + memory: "1Gi" # memory limit for frontend + requests: # requests for frontend + cpu: "100m" # cpu request for frontend + memory: "128Mi" # memory request for frontend + recaptcha: # recaptcha for frontend + enabled: false # enable recaptcha for frontend + existingSecret: "google-recaptcha-secret" # name of existing secret containing recaptcha secret + existingSecretKey: "key" # key in existing secret containing recaptcha secret + siteKey: "" # site key for recaptcha + action: "userRegister" # action for recaptcha + securityContext: # security context for frontend + enabled: true + runAsUser: 1001 + runAsGroup: 1001 + fsGroup: 1001 + runAsNonRoot: true + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + privileged: false + readinessProbe: # readiness probe for frontend + enabled: true + tcpSocket: + port: 3000 + initialDelaySeconds: 20 + periodSeconds: 10 + livenessProbe: # liveness probe for frontend + enabled: true + tcpSocket: + port: 3000 + initialDelaySeconds: 20 + periodSeconds: 20 + automountServiceAccountToken: false # automount service account token for frontend + debug: false # dev mode for frontend + ingress: # ingress for frontend + enabled: true # enable ingress for frontend + hosts: + - "fedn.scaleoutsystems.com" # host for frontend + tls: # tls for frontend + enabled: true # enable tls for frontend + hosts: + - "fedn.scaleoutsystems.com" + existingSecret: "fedn-tls" # name of existing secret containing tls certificate + + studio: # studio values servicename: studio # name of studio service @@ -85,10 +143,11 @@ studio: # studio values csrf_trusted_origins: # csrf trusted origins for studio. Add extra trusted origins for CSRF protection. kube_api_request_timeout: 1 # timeout for kubernetes api requests, such as request to create/delete resources static: # static values for studio, ngnix server for serving static files and media files + enabled: false # enable static for studio replicas: 1 # number of static replicas strategy: # strategy for static type: Recreate # type of strategy - image: harbor.scaleoutsystems.com/studio/studio-nginx:0.10.0-beta.1 # image for static + # image: harbor.scaleoutsystems.com/studio/studio-nginx:0.17.0 # image for static, use this value if you want to override default (usually you should not) pullPolicy: IfNotPresent # pull policy for static resources: # resources for static limits: # limits for static @@ -98,7 +157,7 @@ studio: # studio values cpu: "100m" # cpu request for static memory: "256Mi" # memory request for static image: #tell which image to deploy for studio - repository: harbor.scaleoutsystems.com/studio/studio:0.10.0-beta.1 #This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) + repository: harbor.scaleoutsystems.com/studio/studio:0.17.0 # This image can be built from Dockerfile inside stackn/components/studio (https://github.com/scaleoutsystems/stackn) pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image resources: limits: @@ -114,7 +173,7 @@ studio: # studio values superuserEmail: admin@test.com eventListenerUsername: "" eventListenerUserPassword: "" - version: studio + #version: studio securityContext: enabled: true runAsUser: 1000 @@ -194,6 +253,7 @@ studio: # studio values host: http://minio-system-hl.minio-system.svc.cluster.local secretName: minio-system-user-0 port: "9000" + mongodb_bucket: studio-mongodb-backups harbor: enabled: true @@ -300,7 +360,7 @@ eventListener: appStatusEndpoint: "api/internal/app/status" appStatusesEndpoint: "api/internal/app/statuses" image: - repository: harbor.scaleoutsystems.com/studio/studio-kube-controller:0.10.0-beta.1 + repository: harbor.scaleoutsystems.com/studio/studio-kube-controller:main pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image From c7dff236810649ff85a47318120bb702576b38bd Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 11 Feb 2025 13:57:14 +0100 Subject: [PATCH 144/146] update pullSecret for event listener --- scaleout/stackn/templates/event-listener-deployment.yaml | 2 +- scaleout/stackn/values.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scaleout/stackn/templates/event-listener-deployment.yaml b/scaleout/stackn/templates/event-listener-deployment.yaml index 5a1a915e..763a2b9d 100644 --- a/scaleout/stackn/templates/event-listener-deployment.yaml +++ b/scaleout/stackn/templates/event-listener-deployment.yaml @@ -21,7 +21,7 @@ spec: automountServiceAccountToken: true serviceAccountName: studio imagePullSecrets: - - name: {{ .Values.imagePullSecrets.name }} + - name: {{ .Values.eventListener.image.pullSecret }} containers: - image: "{{ .Values.eventListener.image.repository | default "harbor.scaleoutsystems.com/studio/studio-kube-controller:{{ .Chart.AppVersion }}" }}" imagePullPolicy: {{ .Values.eventListener.image.pullPolicy }} diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 0239c7e6..3102461c 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -362,6 +362,7 @@ eventListener: image: repository: harbor.scaleoutsystems.com/studio/studio-kube-controller:main pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image + pullSecret: ghcrsecret # Will be added in future realease, for now keep "enabled:false" From 44ffaf41c9661f49a5674fa107cb91a1c23a12d4 Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 11 Feb 2025 14:00:17 +0100 Subject: [PATCH 145/146] fix --- scaleout/stackn/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaleout/stackn/values.yaml b/scaleout/stackn/values.yaml index 3102461c..bb84c4fc 100644 --- a/scaleout/stackn/values.yaml +++ b/scaleout/stackn/values.yaml @@ -362,7 +362,7 @@ eventListener: image: repository: harbor.scaleoutsystems.com/studio/studio-kube-controller:main pullPolicy: IfNotPresent # used to ensure that each time we redeploy always pull the latest image - pullSecret: ghcrsecret + pullSecret: harborsecret # pull secret for event listener # Will be added in future realease, for now keep "enabled:false" From 6851cc06d80a2695d4bd3e29178bd032aad5083d Mon Sep 17 00:00:00 2001 From: Fredrik Wrede Date: Tue, 11 Feb 2025 15:32:33 +0100 Subject: [PATCH 146/146] add FRONTEND_DOMAIN --- scaleout/stackn/templates/studio-deployment.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scaleout/stackn/templates/studio-deployment.yaml b/scaleout/stackn/templates/studio-deployment.yaml index 9b1b970c..18001182 100644 --- a/scaleout/stackn/templates/studio-deployment.yaml +++ b/scaleout/stackn/templates/studio-deployment.yaml @@ -345,6 +345,10 @@ spec: - name: HARBOR_PATH value: {{ .Values.studio.project.path }} {{ end }} + {{ if .Values.frontend.ingress.enabled }} + - name: FRONTEND_DOMAIN + value: {{ (index .Values.frontend.ingress.hosts 0) }} + {{ end }} image: '{{ .Values.studio.image.repository | default (printf "harbor.scaleoutsystems.com/studio/studio:%s" .Chart.AppVersion) }}' imagePullPolicy: {{ .Values.studio.image.pullPolicy }} name: {{ .Release.Name }}-studio