From 28bfd7b0b2149e6f08f8281304bf7ddb37976c0b Mon Sep 17 00:00:00 2001 From: Matias Bordese Date: Wed, 2 Nov 2022 01:07:18 -0300 Subject: [PATCH 1/7] Update pg docker developer compose to setup grafana using pg db (#751) * Update pg docker developer compose to setup grafana using pg db * Rework postgres 'create if not exists' grafana db --- docker-compose-developer-pg.yml | 47 +++++++++++++++------------------ 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/docker-compose-developer-pg.yml b/docker-compose-developer-pg.yml index f42f17e3..7c61cf35 100644 --- a/docker-compose-developer-pg.yml +++ b/docker-compose-developer-pg.yml @@ -15,6 +15,11 @@ services: limits: memory: 500m cpus: '0.5' + healthcheck: + test: ["CMD", "pg_isready", "-U", "postgres"] + interval: 10s + timeout: 5s + retries: 5 redis: image: redis @@ -42,37 +47,27 @@ services: - "15672:15672" - "5672:5672" - mysql-to-create-grafana-db: - image: mysql:5.7 - platform: linux/x86_64 - command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - restart: always - ports: - - "3306:3306" - environment: - MYSQL_ROOT_PASSWORD: empty - MYSQL_DATABASE: grafana - deploy: - resources: - limits: - memory: 500m - cpus: '0.5' - healthcheck: - test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ] - timeout: 20s - retries: 10 + postgres_to_create_grafana_db: + image: postgres:14.4 + command: bash -c "PGPASSWORD=empty psql -U postgres -h postgres -tc \"SELECT 1 FROM pg_database WHERE datname = 'grafana'\" | grep -q 1 || PGPASSWORD=empty psql -U postgres -h postgres -c \"CREATE DATABASE grafana\"" + depends_on: + postgres: + condition: service_healthy grafana: image: "grafana/grafana:main" restart: always environment: - GF_DATABASE_TYPE: mysql - GF_DATABASE_HOST: mysql - GF_DATABASE_USER: root + GF_DATABASE_TYPE: postgres + GF_DATABASE_HOST: postgres:5432 + GF_DATABASE_NAME: grafana + GF_DATABASE_USER: postgres GF_DATABASE_PASSWORD: empty - GF_SECURITY_ADMIN_USER: oncall - GF_SECURITY_ADMIN_PASSWORD: oncall + GF_DATABASE_SSL_MODE: disable + GF_SECURITY_ADMIN_USER: ${GRAFANA_USER:-admin} + GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin} GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-oncall-app + GF_INSTALL_PLUGINS: grafana-oncall-app deploy: resources: limits: @@ -83,5 +78,7 @@ services: ports: - "3000:3000" depends_on: - mysql-to-create-grafana-db: + postgres_to_create_grafana_db: + condition: service_completed_successfully + postgres: condition: service_healthy From d3dfaebab73d30de18909f67eae8b374d451cc72 Mon Sep 17 00:00:00 2001 From: David van der Spek Date: Wed, 2 Nov 2022 08:34:41 +0100 Subject: [PATCH 2/7] Helm chart: add support for PostgreSQL (#661) * add support for PostgreSQL Signed-off-by: DavidSpek * disable postgres by default Signed-off-by: DavidSpek * fix external postgres existing secret Signed-off-by: DavidSpek * disable ingress annotations and tls by default Signed-off-by: DavidSpek * fix exec command in notes Signed-off-by: DavidSpek * Add review comments + cleanup README Signed-off-by: DavidSpek Signed-off-by: DavidSpek --- helm/oncall/Chart.lock | 24 +++++ helm/oncall/Chart.yaml | 4 + helm/oncall/README.md | 92 +++++++++++++++--- helm/oncall/charts/postgresql-11.9.10.tgz | Bin 0 -> 57385 bytes helm/oncall/templates/NOTES.txt | 2 +- helm/oncall/templates/_env.tpl | 68 +++++++++++++ helm/oncall/templates/_helpers.tpl | 22 +++++ helm/oncall/templates/celery/_deployment.tpl | 10 ++ helm/oncall/templates/engine/deployment.yaml | 10 ++ helm/oncall/templates/engine/job-migrate.yaml | 14 +++ helm/oncall/templates/secrets.yaml | 12 ++- helm/oncall/values.yaml | 27 ++++- 12 files changed, 266 insertions(+), 19 deletions(-) create mode 100644 helm/oncall/Chart.lock create mode 100644 helm/oncall/charts/postgresql-11.9.10.tgz diff --git a/helm/oncall/Chart.lock b/helm/oncall/Chart.lock new file mode 100644 index 00000000..a91cbcb0 --- /dev/null +++ b/helm/oncall/Chart.lock @@ -0,0 +1,24 @@ +dependencies: +- name: cert-manager + repository: https://charts.jetstack.io + version: v1.8.0 +- name: mariadb + repository: https://charts.bitnami.com/bitnami + version: 11.0.10 +- name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 11.9.10 +- name: rabbitmq + repository: https://charts.bitnami.com/bitnami + version: 10.1.1 +- name: redis + repository: https://charts.bitnami.com/bitnami + version: 16.10.1 +- name: grafana + repository: https://grafana.github.io/helm-charts + version: 6.29.6 +- name: ingress-nginx + repository: https://kubernetes.github.io/ingress-nginx + version: 4.1.4 +digest: sha256:8e17f2f6a087b6db52670458fc0e1cb39b0a3f7962ff7ebbc7be4c982a4e1720 +generated: "2022-10-18T11:22:39.061819+02:00" diff --git a/helm/oncall/Chart.yaml b/helm/oncall/Chart.yaml index f7708ca6..55564328 100644 --- a/helm/oncall/Chart.yaml +++ b/helm/oncall/Chart.yaml @@ -25,6 +25,10 @@ dependencies: version: 11.0.10 repository: https://charts.bitnami.com/bitnami condition: mariadb.enabled + - name: postgresql + version: 11.9.10 + repository: https://charts.bitnami.com/bitnami + condition: postgresql.enabled - name: rabbitmq version: 10.1.1 repository: https://charts.bitnami.com/bitnami diff --git a/helm/oncall/README.md b/helm/oncall/README.md index 87a41f0d..d64e6c89 100644 --- a/helm/oncall/README.md +++ b/helm/oncall/README.md @@ -6,23 +6,27 @@ It will also deploy cert manager and nginx ingress controller, as Grafana OnCall to receive alerts from other monitoring systems. Grafana OnCall engine acts as a backend and can be connected to the Grafana frontend plugin named Grafana OnCall. Architecture diagram can be found [here](https://raw.githubusercontent.com/grafana/oncall/dev/docs/img/architecture_diagram.png) +## Production usage -### Production usage **Default helm chart configuration is not intended for production.** The helm chart includes all the services into a single release, which is not recommended for production usage. It is recommended to run stateful services such as MySQL and RabbitMQ separately from this release or use managed PaaS solutions. It will significantly reduce the overhead of managing them. Here are the instructions on how to set up your own [ingress](#set-up-external-access), [MySQL](#connect-external-mysql), [RabbitMQ](#connect-external-rabbitmq), [Redis](#connect-external-redis) - ### Cluster requirements + * ensure you can run x86-64/amd64 workloads. arm64 architecture is currently not supported * kubernetes version 1.25+ is not supported, if cert-manager is enabled ## Install + ### Prepare the repo -``` + +```bash # Add the repository helm repo add grafana https://grafana.github.io/helm-charts helm repo update ``` + ### Installing the helm chart + ```bash # Install the chart helm install \ @@ -34,7 +38,8 @@ helm install \ ``` Follow the `helm install` output to finish setting up Grafana OnCall backend and Grafana OnCall frontend plugin e.g. -``` + +```bash 👋 Your Grafana OnCall instance has been successfully deployed ❗ Set up a DNS record for your domain (use A Record and "@" to point a root domain to the IP address) @@ -73,6 +78,7 @@ Follow the `helm install` output to finish setting up Grafana OnCall backend and ## Configuration You can edit values.yml to make changes to the helm chart configuration and re-deploy the release with the following command: + ```bash helm upgrade \ --install \ @@ -87,7 +93,7 @@ helm upgrade \ You can set up Slack connection via following variables: -``` +```yaml oncall: slack: enabled: true @@ -103,7 +109,7 @@ oncall: To set up Telegram tokem and webhook url use: -``` +```yaml oncall: telegram: enabled: true @@ -112,13 +118,14 @@ oncall: ``` ### Set up external access + Grafana OnCall can be connected to the external monitoring systems or grafana deployed to the other cluster. Nginx Ingress Controller and Cert Manager charts are included in the helm chart with the default configuration. -If you set the DNS A Record pointing to the external IP address of the installation with the Hostname matching base_url parameter, https will be automatically set up. If grafana is enabled in the chart values, it will also be available on https:///grafana/. See the details in `helm install` output. +If you set the DNS A Record pointing to the external IP address of the installation with the Hostname matching base_url parameter, https will be automatically set up. If grafana is enabled in the chart values, it will also be available on `https:///grafana/`. See the details in `helm install` output. To use a different ingress controller or tls certificate management system, set the following values to false and edit ingress settings -``` +```yaml ingress-nginx: enabled: false @@ -132,18 +139,36 @@ ingress: cert-manager.io/issuer: "letsencrypt-prod" ``` +### Use PostgreSQL instead of MySQL + +It is possible to use PostgreSQL instead of MySQL. To do so, set mariadb.enabled to `false`, +postgresql.enabled to `true` and database.type to `postgresql`. + +```yaml +mariadb: + enabled: false + +postgresql: + enabled: true + +database: + type: postgresql +``` + ### Connect external MySQL It is recommended to use the managed MySQL 5.7 database provided by your cloud provider Make sure to create the database with the following parameters before installing this chart -``` + +```sql CREATE DATABASE oncall CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ``` -To use an external MySQL instance set mysql.enabled to `false` and configure the `externalMysql` parameters. -``` +To use an external MySQL instance set mariadb.enabled to `false` and configure the `externalMysql` parameters. + +```yaml mariadb: - enabled: true + enabled: false # Make sure to create the database with the following parameters: # CREATE DATABASE oncall CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; @@ -155,13 +180,42 @@ externalMysql: password: ``` +### Connect external PostgreSQL + +To use an external PostgreSQL instance set mariadb.enabled to `false`, +postgresql.enabled to `false`, database.type to `postgresql` and configure +the `externalPostgresql` parameters. + +```yaml +mariadb: + enabled: false + +postgresql: + enabled: false + +database: + type: postgresql + +# Make sure to create the database with the following parameters: +# CREATE DATABASE oncall CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +externalPostgresql: + host: + port: + db_name: + user: + password: + existingSecret: "" + passwordKey: password + ``` + ### Connect external RabbitMQ Option 1. Install RabbitMQ separately into the cluster using the [official documentation](https://www.rabbitmq.com/kubernetes/operator/operator-overview.html) Option 2. Use managed solution such as [CloudAMPQ](https://www.cloudamqp.com/) To use an external RabbitMQ instance set rabbitmq.enabled to `false` and configure the `externalRabbitmq` parameters. -``` + +```yaml rabbitmq: enabled: false # Disable the RabbitMQ dependency from the release @@ -175,7 +229,8 @@ externalRabbitmq: ### Connect external Redis To use an external Redis instance set redis.enabled to `false` and configure the `externalRedis` parameters. -``` + +```yaml redis: enabled: false # Disable the Redis dependency from the release @@ -185,7 +240,8 @@ externalRedis: ``` ## Update -```shell + +```bash # Add & upgrade the repository helm repo add grafana https://grafana.github.io/helm-charts helm repo update @@ -203,19 +259,23 @@ helm upgrade \ After re-deploying, please also update the Grafana OnCall plugin on the plugin version page. See [Grafana docs](https://grafana.com/docs/grafana/latest/administration/plugin-management/#update-a-plugin) for more info on updating Grafana plugins. ## Uninstall + ### Uninstalling the helm chart + ```bash helm delete release-oncall ``` ### Clean up PVC's + ```bash kubectl delete pvc data-release-oncall-mariadb-0 data-release-oncall-rabbitmq-0 \ redis-data-release-oncall-redis-master-0 redis-data-release-oncall-redis-replicas-0 \ redis-data-release-oncall-redis-replicas-1 redis-data-release-oncall-redis-replicas-2 ``` - + ### Clean up secrets + ```bash kubectl delete secrets certificate-tls release-oncall-cert-manager-webhook-ca release-oncall-ingress-nginx-admission ``` diff --git a/helm/oncall/charts/postgresql-11.9.10.tgz b/helm/oncall/charts/postgresql-11.9.10.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2e267653efb19bc5fdf9a5e61ea4e4d4a7f1d91d GIT binary patch literal 57385 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 Date: Wed, 2 Nov 2022 11:32:05 +0200 Subject: [PATCH 3/7] =?UTF-8?q?Add=20ability=20to=20set=20more=20env=20var?= =?UTF-8?q?s=20via=20config=20&=20change=20env=20template=20&=20f=E2=80=A6?= =?UTF-8?q?=20(#674)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add ability to set more env vars via config & change env template & fix env spacing * Fix default redirectHost value * Additional Twilio env vars + modified Twilio vars flow * Fix wrong phoneNumber rendering Co-authored-by: Ildar Iskhakov --- helm/oncall/templates/_env.tpl | 43 ++++++++++++++++---- helm/oncall/templates/_helpers.tpl | 18 +++++--- helm/oncall/templates/celery/_deployment.tpl | 22 ++++++---- helm/oncall/templates/engine/deployment.yaml | 23 +++++++---- helm/oncall/values.yaml | 18 +++++++- 5 files changed, 97 insertions(+), 27 deletions(-) diff --git a/helm/oncall/templates/_env.tpl b/helm/oncall/templates/_env.tpl index 93fbc7d8..f8c6fe51 100644 --- a/helm/oncall/templates/_env.tpl +++ b/helm/oncall/templates/_env.tpl @@ -21,7 +21,7 @@ value: "True" - name: UWSGI_LISTEN value: "1024" -{{- end }} +{{- end -}} {{- define "snippet.oncall.slack.env" -}} {{- if .Values.oncall.slack.enabled -}} @@ -36,12 +36,12 @@ - name: SLACK_SIGNING_SECRET value: {{ .Values.oncall.slack.signingSecret | default "" | quote }} - name: SLACK_INSTALL_RETURN_REDIRECT_HOST - value: "https://{{ .Values.base_url }}" + value: {{ .Values.oncall.slack.redirectHost | default (printf "https://%s" .Values.base_url) | quote }} {{- else -}} - name: FEATURE_SLACK_INTEGRATION_ENABLED value: {{ .Values.oncall.slack.enabled | toString | title | quote }} {{- end -}} -{{- end }} +{{- end -}} {{- define "snippet.oncall.telegram.env" -}} {{- if .Values.oncall.telegram.enabled -}} @@ -55,7 +55,36 @@ - name: FEATURE_TELEGRAM_INTEGRATION_ENABLED value: {{ .Values.oncall.telegram.enabled | toString | title | quote }} {{- end -}} -{{- end }} +{{- end -}} + +{{- define "snippet.oncall.twilio.env" -}} +{{- with .Values.oncall.twilio -}} +{{- if .accountSid }} +- name: TWILIO_ACCOUNT_SID + value: {{ .accountSid | quote }} +{{- end -}} +{{- if .authToken }} +- name: TWILIO_AUTH_TOKEN + value: {{ .authToken | quote }} +{{- end -}} +{{- if .phoneNumber }} +- name: TWILIO_NUMBER + value: {{ .phoneNumber | quote }} +{{- end -}} +{{- if .verifySid }} +- name: TWILIO_VERIFY_SERVICE_SID + value: {{ .verifySid | quote }} +{{- end -}} +{{- if .apiKeySid }} +- name: TWILIO_API_KEY_SID + value: {{ .apiKeySid | quote }} +{{- end -}} +{{- if .apiKeySecret }} +- name: TWILIO_API_KEY_SECRET + value: {{ .apiKeySecret | quote }} +{{- end -}} +{{- end -}} +{{- end -}} {{- define "snippet.celery.env" -}} {{- if .Values.celery.worker_queue }} @@ -78,7 +107,7 @@ - name: CELERY_WORKER_SHUTDOWN_INTERVAL value: {{ .Values.celery.worker_shutdown_interval }} {{- end -}} -{{- end }} +{{- end -}} {{- define "snippet.mysql.env" -}} - name: MYSQL_HOST @@ -130,7 +159,7 @@ {{- define "snippet.mysql.user" -}} {{- if and (not .Values.mariadb.enabled) .Values.externalMysql.user -}} -{{- .Values.externalMysql.user | quote}} +{{- .Values.externalMysql.user | quote }} {{- else -}} "root" {{- end -}} @@ -220,7 +249,7 @@ value: {{ include "snippet.rabbitmq.protocol" . }} - name: RABBITMQ_VHOST value: {{ include "snippet.rabbitmq.vhost" . }} -{{- end }} +{{- end -}} {{- define "snippet.rabbitmq.user" -}} {{- if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.user -}} diff --git a/helm/oncall/templates/_helpers.tpl b/helm/oncall/templates/_helpers.tpl index b5f4dbcc..110bc525 100644 --- a/helm/oncall/templates/_helpers.tpl +++ b/helm/oncall/templates/_helpers.tpl @@ -93,12 +93,20 @@ Create the name of the service account to use securityContext: {{ toYaml .Values.init.securityContext| nindent 4}} env: - {{- include "snippet.oncall.env" . | nindent 12 }} - {{- include "snippet.mysql.env" . | nindent 12 }} - {{- include "snippet.rabbitmq.env" . | nindent 12 }} - {{- include "snippet.redis.env" . | nindent 12 }} + {{- include "snippet.oncall.env" . | nindent 4 }} + {{- include "snippet.mysql.env" . | nindent 4 }} + {{- include "snippet.rabbitmq.env" . | nindent 4 }} + {{- include "snippet.redis.env" . | nindent 4 }} {{- if .Values.env }} - {{- toYaml .Values.env | nindent 12 }} + {{- if (kindIs "map" .Values.env) }} + {{- range $key, $value := .Values.env }} + - name: {{ $key }} + value: {{ $value }} + {{- end -}} + {{/* support previous schema */}} + {{- else }} + {{- toYaml .Values.env | nindent 4 }} + {{- end }} {{- end }} {{- end }} diff --git a/helm/oncall/templates/celery/_deployment.tpl b/helm/oncall/templates/celery/_deployment.tpl index e25d4adc..4e09cb30 100644 --- a/helm/oncall/templates/celery/_deployment.tpl +++ b/helm/oncall/templates/celery/_deployment.tpl @@ -28,12 +28,12 @@ spec: securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} initContainers: - {{- if eq .Values.database.type "mysql" }} - {{- include "oncall.mariadb.wait-for-db" . | indent 8 }} - {{- end }} - {{- if eq .Values.database.type "postgresql" }} - {{- include "oncall.postgresql.wait-for-db" . | indent 8 }} - {{- end }} + {{- if eq .Values.database.type "mysql" }} + {{- include "oncall.mariadb.wait-for-db" . | indent 8 }} + {{- end }} + {{- if eq .Values.database.type "postgresql" }} + {{- include "oncall.postgresql.wait-for-db" . | indent 8 }} + {{- end }} containers: - name: {{ .Chart.Name }} securityContext: @@ -56,7 +56,15 @@ spec: {{- include "snippet.rabbitmq.env" . | nindent 12 }} {{- include "snippet.redis.env" . | nindent 12 }} {{- if .Values.env }} - {{- toYaml .Values.env | nindent 12 }} + {{- if (kindIs "map" .Values.env) }} + {{- range $key, $value := .Values.env }} + - name: {{ $key }} + value: {{ $value }} + {{- end -}} + {{/* support previous schema */}} + {{- else }} + {{- toYaml .Values.env | nindent 12 }} + {{- end }} {{- end }} {{- if .Values.celery.livenessProbe.enabled }} livenessProbe: diff --git a/helm/oncall/templates/engine/deployment.yaml b/helm/oncall/templates/engine/deployment.yaml index b06462e4..640bb84b 100644 --- a/helm/oncall/templates/engine/deployment.yaml +++ b/helm/oncall/templates/engine/deployment.yaml @@ -32,12 +32,12 @@ spec: securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} initContainers: - {{- if eq .Values.database.type "mysql" }} - {{- include "oncall.mariadb.wait-for-db" . | indent 8 }} - {{- end }} - {{- if eq .Values.database.type "postgresql" }} - {{- include "oncall.postgresql.wait-for-db" . | indent 8 }} - {{- end }} + {{- if eq .Values.database.type "mysql" }} + {{- include "oncall.mariadb.wait-for-db" . | indent 8 }} + {{- end }} + {{- if eq .Values.database.type "postgresql" }} + {{- include "oncall.postgresql.wait-for-db" . | indent 8 }} + {{- end }} containers: - name: {{ .Chart.Name }} securityContext: @@ -53,6 +53,7 @@ spec: {{- include "snippet.oncall.slack.env" . | nindent 12 }} {{- include "snippet.oncall.telegram.env" . | nindent 12 }} {{- include "snippet.oncall.smtp.env" . | nindent 12 }} + {{- include "snippet.oncall.twilio.env" . | nindent 12 }} {{- if eq .Values.database.type "mysql" }} {{- include "snippet.mysql.env" . | nindent 12 }} {{- end }} @@ -62,7 +63,15 @@ spec: {{- include "snippet.rabbitmq.env" . | nindent 12 }} {{- include "snippet.redis.env" . | nindent 12 }} {{- if .Values.env }} - {{- toYaml .Values.env | nindent 12 }} + {{- if (kindIs "map" .Values.env) }} + {{- range $key, $value := .Values.env }} + - name: {{ $key }} + value: {{ $value }} + {{- end -}} + {{/* support previous schema */}} + {{- else }} + {{- toYaml .Values.env | nindent 12 }} + {{- end }} {{- end }} livenessProbe: httpGet: diff --git a/helm/oncall/values.yaml b/helm/oncall/values.yaml index 5939a9e1..eff39909 100644 --- a/helm/oncall/values.yaml +++ b/helm/oncall/values.yaml @@ -84,6 +84,8 @@ oncall: # requests comming from Slack. # api.slack.com/apps/ -> Basic Information -> App Credentials -> Signing Secret signingSecret: ~ + # OnCall external URL + redirectHost: ~ telegram: enabled: false token: ~ @@ -96,13 +98,27 @@ oncall: password: ~ tls: ~ fromEmail: ~ + twilio: + # Twilio account SID/username to allow OnCall to send SMSes and make phone calls + accountSid: "" + # Twilio password to allow OnCall to send SMSes and make calls + authToken: "" + # Number from which you will receive calls and SMS (NOTE: must be quoted, otherwise would be rendered as float value) + phoneNumber: "" + # SID of Twilio service for number verification. You can create a service in Twilio web interface. + # twilio.com -> verify -> create new service + verifySid: "" + # Twilio API key SID/username to allow OnCall to send SMSes and make phone calls + apiKeySid: "" + # Twilio API key secret/password to allow OnCall to send SMSes and make phone calls + apiKeySecret: "" # Whether to run django database migrations automatically migrate: enabled: true # Additional env variables to add to deployments -env: [] +env: {} # Enable ingress object for external access to the resources ingress: From ed5262f2f5931645d8e69c219f519d1be644c943 Mon Sep 17 00:00:00 2001 From: Ildar Iskhakov Date: Wed, 2 Nov 2022 17:37:41 +0800 Subject: [PATCH 4/7] Add BROKER_TYPE env var to the helm chart (#697) --- helm/oncall/templates/_env.tpl | 8 ++++++-- helm/oncall/templates/secrets.yaml | 2 +- helm/oncall/values.yaml | 3 +++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/helm/oncall/templates/_env.tpl b/helm/oncall/templates/_env.tpl index f8c6fe51..89d1a52c 100644 --- a/helm/oncall/templates/_env.tpl +++ b/helm/oncall/templates/_env.tpl @@ -21,6 +21,8 @@ value: "True" - name: UWSGI_LISTEN value: "1024" +- name: BROKER_TYPE + value: {{ .Values.broker.type | default "rabbitmq" }} {{- end -}} {{- define "snippet.oncall.slack.env" -}} @@ -150,8 +152,8 @@ {{- end -}} {{- define "snippet.mysql.db" -}} -{{- if and (not .Values.mariadb.enabled) .Values.externalMysql.db -}} -{{- required "externalMysql.db is required if not mariadb.enabled" .Values.externalMysql.db | quote}} +{{- if and (not .Values.mariadb.enabled) .Values.externalMysql.db_name -}} +{{- required "externalMysql.db is required if not mariadb.enabled" .Values.externalMysql.db_name | quote}} {{- else -}} "oncall" {{- end -}} @@ -234,6 +236,7 @@ {{- end -}} {{- define "snippet.rabbitmq.env" -}} +{{- if eq .Values.broker.type "rabbitmq" -}} - name: RABBITMQ_USERNAME value: {{ include "snippet.rabbitmq.user" . }} - name: RABBITMQ_PASSWORD @@ -249,6 +252,7 @@ value: {{ include "snippet.rabbitmq.protocol" . }} - name: RABBITMQ_VHOST value: {{ include "snippet.rabbitmq.vhost" . }} +{{- end }} {{- end -}} {{- define "snippet.rabbitmq.user" -}} diff --git a/helm/oncall/templates/secrets.yaml b/helm/oncall/templates/secrets.yaml index 39e48a00..0997c93d 100644 --- a/helm/oncall/templates/secrets.yaml +++ b/helm/oncall/templates/secrets.yaml @@ -21,7 +21,7 @@ data: mariadb-root-password: {{ required "externalMysql.password is required if not mariadb.enabled" .Values.externalMysql.password | b64enc | quote }} {{- end }} --- -{{ if not .Values.rabbitmq.enabled -}} +{{ if and (eq .Values.broker.type "rabbitmq") (not .Values.rabbitmq.enabled) -}} apiVersion: v1 kind: Secret metadata: diff --git a/helm/oncall/values.yaml b/helm/oncall/values.yaml index eff39909..5c30878d 100644 --- a/helm/oncall/values.yaml +++ b/helm/oncall/values.yaml @@ -229,6 +229,9 @@ externalPostgresql: rabbitmq: enabled: true +broker: + type: rabbitmq + externalRabbitmq: host: port: From 12da061d6efb80b9a9da2581bcbca1f160ad676f Mon Sep 17 00:00:00 2001 From: Ildar Iskhakov Date: Wed, 2 Nov 2022 17:40:33 +0800 Subject: [PATCH 5/7] Update Chart.yaml --- helm/oncall/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helm/oncall/Chart.yaml b/helm/oncall/Chart.yaml index 55564328..fd0483fd 100644 --- a/helm/oncall/Chart.yaml +++ b/helm/oncall/Chart.yaml @@ -8,13 +8,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 1.0.6 +version: 1.0.7 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v1.0.40" +appVersion: "v1.0.49" dependencies: - name: cert-manager version: v1.8.0 From 7dce3196bea6e285d2fc5ba86d4eadb487c35a91 Mon Sep 17 00:00:00 2001 From: Maxim Date: Wed, 2 Nov 2022 11:08:58 +0000 Subject: [PATCH 6/7] fix live settings caching columns render --- grafana-plugin/src/pages/livesettings/LiveSettingsPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grafana-plugin/src/pages/livesettings/LiveSettingsPage.tsx b/grafana-plugin/src/pages/livesettings/LiveSettingsPage.tsx index 7028e366..db5cd138 100644 --- a/grafana-plugin/src/pages/livesettings/LiveSettingsPage.tsx +++ b/grafana-plugin/src/pages/livesettings/LiveSettingsPage.tsx @@ -89,13 +89,13 @@ class LiveSettings extends React.Component { width: '20%', title: 'Value', - render: this.renderValue, + render: (item: GlobalSetting) => this.renderValue(item), // to avoid caching previous render result key: 'value', }, { width: '20%', title: 'ENV or default', - render: this.renderDefault, + render: (item: GlobalSetting) => this.renderDefault(item), // to avoid caching previous render result key: 'default', }, { From 0c78d25529f2b5fcb4afbda82a53d85f0f0baca6 Mon Sep 17 00:00:00 2001 From: Maxim Date: Wed, 2 Nov 2022 11:44:42 +0000 Subject: [PATCH 7/7] add selector-max-type stylelint rule --- grafana-plugin/.stylelintrc | 4 ++++ grafana-plugin/package.json | 4 ++-- .../ScheduleBorderedAvatar.module.scss | 6 ++++-- .../src/components/SourceCode/SourceCode.module.scss | 9 +++++---- grafana-plugin/src/components/Text/Text.module.scss | 9 +++++++++ 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/grafana-plugin/.stylelintrc b/grafana-plugin/.stylelintrc index c37d4c08..31c2b181 100644 --- a/grafana-plugin/.stylelintrc +++ b/grafana-plugin/.stylelintrc @@ -3,6 +3,10 @@ "plugins": ["stylelint-prettier"], "rules": { "block-no-empty": [true, { "severity": "warning" }], + "selector-max-type": [ 0, { + "severity": "error", + "ignore": ["child", "compounded", "descendant", "next-sibling"] + }], "selector-pseudo-class-no-unknown": [ true, { diff --git a/grafana-plugin/package.json b/grafana-plugin/package.json index 9398e5c9..ea95dd57 100644 --- a/grafana-plugin/package.json +++ b/grafana-plugin/package.json @@ -5,8 +5,8 @@ "scripts": { "lint": "eslint --cache --ext .js,.jsx,.ts,.tsx --max-warnings=0 ./src", "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --max-warnings=0 --quiet ./src", - "stylelint": "stylelint ./src/**/*.css", - "stylelint:fix": "stylelint --fix ./src/**/*.css", + "stylelint": "stylelint ./src/**/*.{css,scss,module.css,module.scss}", + "stylelint:fix": "stylelint --fix ./src/**/*.{css,scss,module.css,module.scss}", "build": "grafana-toolkit plugin:build", "test": "jest --verbose", "dev": "grafana-toolkit plugin:dev", diff --git a/grafana-plugin/src/components/ScheduleBorderedAvatar/ScheduleBorderedAvatar.module.scss b/grafana-plugin/src/components/ScheduleBorderedAvatar/ScheduleBorderedAvatar.module.scss index 0e179253..d65587a4 100644 --- a/grafana-plugin/src/components/ScheduleBorderedAvatar/ScheduleBorderedAvatar.module.scss +++ b/grafana-plugin/src/components/ScheduleBorderedAvatar/ScheduleBorderedAvatar.module.scss @@ -1,12 +1,14 @@ .root { position: relative; } + .avatar { position: absolute; - top: 0px; - left: 0px; + top: 0; + left: 0; z-index: -1; } + .icon { position: relative; top: -8px; diff --git a/grafana-plugin/src/components/SourceCode/SourceCode.module.scss b/grafana-plugin/src/components/SourceCode/SourceCode.module.scss index ec139080..76c51d24 100644 --- a/grafana-plugin/src/components/SourceCode/SourceCode.module.scss +++ b/grafana-plugin/src/components/SourceCode/SourceCode.module.scss @@ -1,10 +1,6 @@ .root { position: relative; width: 100%; - - &:hover .copyButton { - opacity: 1; - } } .scroller { @@ -24,6 +20,11 @@ right: 15px; transition: opacity 0.2s ease; } + .copyButton { opacity: 0; } + +.root:hover .copyButton { + opacity: 1; +} diff --git a/grafana-plugin/src/components/Text/Text.module.scss b/grafana-plugin/src/components/Text/Text.module.scss index 158155bb..618bb298 100644 --- a/grafana-plugin/src/components/Text/Text.module.scss +++ b/grafana-plugin/src/components/Text/Text.module.scss @@ -6,30 +6,39 @@ &--primary { color: var(--primary-text-color); } + &--secondary { color: var(--secondary-text-color); } + &--disabled { color: var(--disabled-text-color); } + &--warning { color: var(--warning-text-color); } + &--link { color: var(--primary-text-link); } + &--success { color: var(--green-5); } + &--strong { font-weight: bold; } + &--underline { text-decoration: underline; } + &--small { font-size: 12px; } + &--large { font-size: 20px; }