From cdc6b70d78ad9d5e0a675467e7018c0de6a8e5a8 Mon Sep 17 00:00:00 2001 From: Jan Friedenstab <8794084+jfriedenstab@users.noreply.github.com> Date: Fri, 25 Oct 2024 15:21:09 +0200 Subject: [PATCH] feat(web-modeler): add support for configuring Zeebe clusters (#2489) --- charts/camunda-platform-alpha/README.md | 1 + .../templates/camunda/_helpers.tpl | 27 ++- .../web-modeler/configmap-restapi.yaml | 28 ++- .../web-modeler/configmap_restapi_test.go | 182 ++++++++++++++++++ .../test/unit/web-modeler/types.go | 35 +++- charts/camunda-platform-alpha/values.yaml | 3 + 6 files changed, 266 insertions(+), 10 deletions(-) diff --git a/charts/camunda-platform-alpha/README.md b/charts/camunda-platform-alpha/README.md index fdfbbf0c8e..95fff9fb84 100644 --- a/charts/camunda-platform-alpha/README.md +++ b/charts/camunda-platform-alpha/README.md @@ -1492,6 +1492,7 @@ Please see the corresponding [release guide](../../docs/release.md) to find out | `webModeler.restapi.mail.existingSecretPasswordKey` | can be used to provide the name of an existing secret key containing the SMTP password | `smtp-password` | | `webModeler.restapi.mail.fromAddress` | defines the email address that will be displayed as the sender of emails sent by WebModeler | `""` | | `webModeler.restapi.mail.fromName` | defines the name that will be displayed as the sender of emails sent by WebModeler | `Camunda 8` | +| `webModeler.restapi.clusters` | can be used to configure Camunda 8 clusters that will be available in Web Modeler (will override default cluster configuration that is used if `zeebe.enabled=true`) | `[]` | | `webModeler.restapi.podAnnotations` | can be used to define extra restapi pod annotations | `{}` | | `webModeler.restapi.podLabels` | can be used to define extra restapi pod labels | `{}` | | `webModeler.restapi.env` | can be used to set extra environment variables in each restapi container | `[]` | diff --git a/charts/camunda-platform-alpha/templates/camunda/_helpers.tpl b/charts/camunda-platform-alpha/templates/camunda/_helpers.tpl index ff210063b6..d60185ab1b 100644 --- a/charts/camunda-platform-alpha/templates/camunda/_helpers.tpl +++ b/charts/camunda-platform-alpha/templates/camunda/_helpers.tpl @@ -364,10 +364,10 @@ Usage: {{ include "camundaPlatform.getExternalURL" (dict "component" "operate" " {{- if (index .context.Values .component "enabled") -}} {{- if (index .context.Values .component "ingress" "enabled") }} {{- $proto := ternary "https" "http" (index .context.Values .component "ingress" "tls" "enabled") -}} - {{- printf "%s://%s" $proto (index .context.Values .component "ingress" "host") -}} + {{- printf "%s://%s" $proto (index .context.Values .component "ingress" "host") -}} {{- else if $.context.Values.global.ingress.enabled -}} {{ $proto := ternary "https" "http" .context.Values.global.ingress.tls.enabled -}} - {{- printf "%s://%s%s" $proto .context.Values.global.ingress.host (index .context.Values .component "contextPath") -}} + {{- printf "%s://%s%s" $proto .context.Values.global.ingress.host (index .context.Values .component "contextPath") -}} {{- else -}} {{- $portMapping := (dict "operate" "8081" @@ -380,7 +380,7 @@ Usage: {{ include "camundaPlatform.getExternalURL" (dict "component" "operate" " "connectors" "8086" "zeebeGateway" "26500" ) -}} - {{- printf "http://localhost:%s" (get $portMapping .component) -}} + {{- printf "http://localhost:%s" (get $portMapping .component) -}} {{- end -}} {{- end -}} {{- end -}} @@ -411,6 +411,17 @@ Optimize templates. Tasklist templates. ******************************************************************************** */}} + +{{/* +[camunda-platform] Tasklist internal URL. +*/}} +{{ define "camundaPlatform.tasklistURL" }} + {{- if .Values.tasklist.enabled -}} + {{- print "http://" -}}{{- include "tasklist.fullname" . -}}:{{- .Values.tasklist.service.port -}} + {{- .Values.tasklist.contextPath -}} + {{- end -}} +{{- end -}} + {{/* [camunda-platform] Tasklist external URL. */}} @@ -433,13 +444,13 @@ Web Modeler templates. {{- $ingress := .context.Values.webModeler.ingress }} {{- if index $ingress "enabled" }} {{- $proto := ternary "https" "http" (index $ingress .component "tls" "enabled") -}} - {{- printf "%s://%s" $proto (index $ingress .component "host") -}} + {{- printf "%s://%s" $proto (index $ingress .component "host") -}} {{- else if $.context.Values.global.ingress.enabled -}} {{ $proto := ternary "https" "http" .context.Values.global.ingress.tls.enabled -}} {{- if eq .component "websockets" }} - {{- printf "%s://%s%s" $proto .context.Values.global.ingress.host (include "webModeler.websocketContextPath" .context) -}} + {{- printf "%s://%s%s" $proto .context.Values.global.ingress.host (include "webModeler.websocketContextPath" .context) -}} {{- else -}} - {{- printf "%s://%s%s" $proto .context.Values.global.ingress.host (index .context.Values.webModeler "contextPath") -}} + {{- printf "%s://%s%s" $proto .context.Values.global.ingress.host (index .context.Values.webModeler "contextPath") -}} {{- end -}} {{- end -}} {{- end -}} @@ -518,7 +529,7 @@ Zeebe templates. {{- printf "%s://%s%s" $proto .Values.global.ingress.host .Values.zeebeGateway.contextPath -}} {{- else if .Values.zeebeGateway.ingress.rest.enabled -}} {{ $proto := ternary "https" "http" .Values.zeebeGateway.ingress.rest.tls.enabled -}} - {{- printf "%s://%s%s" $proto .Values.zeebeGateway.ingress.rest.host .Values.zeebeGateway.contextPath -}} + {{- printf "%s://%s%s" $proto .Values.zeebeGateway.ingress.rest.host .Values.zeebeGateway.contextPath -}} {{- else -}} {{- printf "http://localhost:8088" -}} {{- end -}} @@ -539,7 +550,7 @@ Zeebe templates. {{- if .Values.zeebe.enabled -}} {{- printf "http://%s:%v%s" - (include "zeebe.fullname.gateway" .) + (include "zeebe.names.gateway" .) .Values.zeebeGateway.service.restPort (.Values.zeebeGateway.contextPath | default "") -}} diff --git a/charts/camunda-platform-alpha/templates/web-modeler/configmap-restapi.yaml b/charts/camunda-platform-alpha/templates/web-modeler/configmap-restapi.yaml index fece45d7e1..d4b308aa51 100644 --- a/charts/camunda-platform-alpha/templates/web-modeler/configmap-restapi.yaml +++ b/charts/camunda-platform-alpha/templates/web-modeler/configmap-restapi.yaml @@ -26,7 +26,7 @@ data: pusher: host: {{ include "webModeler.websockets.fullname" . | quote }} port: {{ .Values.webModeler.websockets.service.port }} - + security: jwt: issuer: @@ -40,6 +40,32 @@ data: server: url: {{ tpl .Values.global.identity.auth.webModeler.redirectUrl $ | quote }} + + {{- if or .Values.zeebe.enabled .Values.webModeler.restapi.clusters }} + clusters: + {{- if .Values.webModeler.restapi.clusters }} + {{- .Values.webModeler.restapi.clusters | toYaml | nindent 10 }} + {{- else}} + - id: "default-cluster" + name: {{ tpl .Values.global.zeebeClusterName . | quote }} + version: {{ include "camundaPlatform.imageTagByParams" (dict "base" .Values.global "overlay" .Values.zeebe) | quote }} + authentication: {{ .Values.global.identity.auth.enabled | ternary "OAUTH" "NONE" | quote }} + url: + zeebe: + grpc: "grpc://{{ tpl .Values.global.zeebeClusterName . }}-gateway:{{ .Values.zeebeGateway.service.grpcPort }}" + rest: {{ include "camundaPlatform.zeebeGatewayRESTURL" . | quote }} + operate: {{ include "camundaPlatform.operateURL" . | quote }} + tasklist: {{ include "camundaPlatform.tasklistURL" . | quote }} + oauth: + url: {{ include "camundaPlatform.authIssuerBackendUrlTokenEndpoint" . | quote }} + audience: + zeebe: {{ include "zeebe.audience" . | quote }} + operate: {{ include "operate.authAudience" . | quote }} + tasklist: {{ include "tasklist.authAudience" . | quote }} + scope: {{ include "zeebe.tokenScope" . | quote }} + {{- end }} + {{- end }} + spring: datasource: url: {{ include "webModeler.restapi.databaseUrl" . | quote }} diff --git a/charts/camunda-platform-alpha/test/unit/web-modeler/configmap_restapi_test.go b/charts/camunda-platform-alpha/test/unit/web-modeler/configmap_restapi_test.go index a54caa51a3..df68615e6b 100644 --- a/charts/camunda-platform-alpha/test/unit/web-modeler/configmap_restapi_test.go +++ b/charts/camunda-platform-alpha/test/unit/web-modeler/configmap_restapi_test.go @@ -194,6 +194,7 @@ func (s *configmapRestAPITemplateTest) TestContainerShouldSetCorrectKeycloakServ // then s.Require().Equal("http://keycloak:80/auth/realms/camunda-platform", configmapApplication.Camunda.Modeler.Security.JWT.Issuer.BackendUrl) } + func (s *configmapRestAPITemplateTest) TestContainerShouldSetCorrectKeycloakServiceUrlWithCustomPort() { // given options := &helm.Options{ @@ -221,6 +222,7 @@ func (s *configmapRestAPITemplateTest) TestContainerShouldSetCorrectKeycloakServ // then s.Require().Equal("http://keycloak:8888/auth/realms/camunda-platform", configmapApplication.Camunda.Modeler.Security.JWT.Issuer.BackendUrl) } + func (s *configmapRestAPITemplateTest) TestContainerShouldSetSmtpCredentials() { // given options := &helm.Options{ @@ -247,6 +249,7 @@ func (s *configmapRestAPITemplateTest) TestContainerShouldSetSmtpCredentials() { // then s.Require().Equal("modeler-user", configmapApplication.Spring.Mail.Username) } + func (s *configmapRestAPITemplateTest) TestContainerShouldSetExternalDatabaseConfiguration() { // given options := &helm.Options{ @@ -276,3 +279,182 @@ func (s *configmapRestAPITemplateTest) TestContainerShouldSetExternalDatabaseCon s.Require().Equal("jdbc:postgresql://postgres.example.com:65432/modeler-database", configmapApplication.Spring.Datasource.Url) s.Require().Equal("modeler-user", configmapApplication.Spring.Datasource.Username) } + +func (s *configmapRestAPITemplateTest) TestContainerShouldConfigureClusterFromSameHelmInstallationWithDefaultValues() { + // given + options := &helm.Options{ + SetValues: map[string]string{ + "webModeler.enabled": "true", + "webModeler.restapi.mail.fromAddress": "example@example.com", + "postgresql.enabled": "false", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", s.namespace), + } + + // when + output := helm.RenderTemplate(s.T(), options, s.chartPath, s.release, s.templates) + var configmap corev1.ConfigMap + var configmapApplication WebModelerRestAPIApplicationYAML + helm.UnmarshalK8SYaml(s.T(), output, &configmap) + + err := yaml.Unmarshal([]byte(configmap.Data["application.yaml"]), &configmapApplication) + if err != nil { + s.Fail("Failed to unmarshal yaml. error=", err) + } + + // then + s.Require().Equal(1, len(configmapApplication.Camunda.Modeler.Clusters)) + s.Require().Equal("default-cluster", configmapApplication.Camunda.Modeler.Clusters[0].Id) + s.Require().Equal("camunda-platform-test-zeebe", configmapApplication.Camunda.Modeler.Clusters[0].Name) + s.Require().Equal("SNAPSHOT", configmapApplication.Camunda.Modeler.Clusters[0].Version) + s.Require().Equal("OAUTH", configmapApplication.Camunda.Modeler.Clusters[0].Authentication) + s.Require().Equal("grpc://camunda-platform-test-zeebe-gateway:26500", configmapApplication.Camunda.Modeler.Clusters[0].Url.Zeebe.Grpc) + s.Require().Equal("http://camunda-platform-test-zeebe-gateway:8080", configmapApplication.Camunda.Modeler.Clusters[0].Url.Zeebe.Rest) + s.Require().Equal("http://camunda-platform-test-operate:80", configmapApplication.Camunda.Modeler.Clusters[0].Url.Operate) + s.Require().Equal("http://camunda-platform-test-tasklist:80", configmapApplication.Camunda.Modeler.Clusters[0].Url.Tasklist) + s.Require().Equal("http://camunda-platform-test-keycloak:80/auth/realms/camunda-platform/protocol/openid-connect/token", configmapApplication.Camunda.Modeler.Clusters[0].Oauth.Url) + s.Require().Equal("zeebe-api", configmapApplication.Camunda.Modeler.Clusters[0].Oauth.Audience.Zeebe) + s.Require().Equal("operate-api", configmapApplication.Camunda.Modeler.Clusters[0].Oauth.Audience.Operate) + s.Require().Equal("tasklist-api", configmapApplication.Camunda.Modeler.Clusters[0].Oauth.Audience.Tasklist) + s.Require().Equal("", configmapApplication.Camunda.Modeler.Clusters[0].Oauth.Scope) +} + +func (s *configmapRestAPITemplateTest) TestContainerShouldConfigureClusterFromSameHelmInstallationWithCustomValues() { + // given + options := &helm.Options{ + SetValues: map[string]string{ + "webModeler.enabled": "true", + "webModeler.restapi.mail.fromAddress": "example@example.com", + "postgresql.enabled": "false", + "global.zeebeClusterName": "test-zeebe", + "global.identity.auth.zeebe.tokenScope": "test-scope", + "global.identity.auth.zeebe.audience": "test-zeebe-api", + "global.identity.auth.operate.audience": "test-operate-api", + "global.identity.auth.tasklist.audience": "test-tasklist-api", + "global.identity.auth.tokenUrl": "https://example.com/auth/realms/test/protocol/openid-connect/token", + "zeebe.image.tag": "8.7.0-alpha1", + "zeebeGateway.contextPath": "/zeebe", + "zeebeGateway.service.grpcPort": "26600", + "zeebeGateway.service.restPort": "8090", + "operate.contextPath": "/operate", + "operate.service.port": "8080", + "tasklist.contextPath": "/tasklist", + "tasklist.service.port": "8080", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", s.namespace), + } + + // when + output := helm.RenderTemplate(s.T(), options, s.chartPath, s.release, s.templates) + var configmap corev1.ConfigMap + var configmapApplication WebModelerRestAPIApplicationYAML + helm.UnmarshalK8SYaml(s.T(), output, &configmap) + + err := yaml.Unmarshal([]byte(configmap.Data["application.yaml"]), &configmapApplication) + if err != nil { + s.Fail("Failed to unmarshal yaml. error=", err) + } + + // then + s.Require().Equal(1, len(configmapApplication.Camunda.Modeler.Clusters)) + s.Require().Equal("default-cluster", configmapApplication.Camunda.Modeler.Clusters[0].Id) + s.Require().Equal("test-zeebe", configmapApplication.Camunda.Modeler.Clusters[0].Name) + s.Require().Equal("8.7.0-alpha1", configmapApplication.Camunda.Modeler.Clusters[0].Version) + s.Require().Equal("OAUTH", configmapApplication.Camunda.Modeler.Clusters[0].Authentication) + s.Require().Equal("grpc://test-zeebe-gateway:26600", configmapApplication.Camunda.Modeler.Clusters[0].Url.Zeebe.Grpc) + s.Require().Equal("http://test-zeebe-gateway:8090/zeebe", configmapApplication.Camunda.Modeler.Clusters[0].Url.Zeebe.Rest) + s.Require().Equal("http://camunda-platform-test-operate:8080/operate", configmapApplication.Camunda.Modeler.Clusters[0].Url.Operate) + s.Require().Equal("http://camunda-platform-test-tasklist:8080/tasklist", configmapApplication.Camunda.Modeler.Clusters[0].Url.Tasklist) + s.Require().Equal("https://example.com/auth/realms/test/protocol/openid-connect/token", configmapApplication.Camunda.Modeler.Clusters[0].Oauth.Url) + s.Require().Equal("test-zeebe-api", configmapApplication.Camunda.Modeler.Clusters[0].Oauth.Audience.Zeebe) + s.Require().Equal("test-operate-api", configmapApplication.Camunda.Modeler.Clusters[0].Oauth.Audience.Operate) + s.Require().Equal("test-tasklist-api", configmapApplication.Camunda.Modeler.Clusters[0].Oauth.Audience.Tasklist) + s.Require().Equal("test-scope", configmapApplication.Camunda.Modeler.Clusters[0].Oauth.Scope) +} + +func (s *configmapRestAPITemplateTest) TestContainerShouldUseClustersFromCustomConfiguration() { + // given + options := &helm.Options{ + SetValues: map[string]string{ + "webModeler.enabled": "true", + "webModeler.restapi.mail.fromAddress": "example@example.com", + "webModeler.restapi.clusters[0].id": "test-cluster-1", + "webModeler.restapi.clusters[0].name": "test cluster 1", + "webModeler.restapi.clusters[0].version": "8.6.0", + "webModeler.restapi.clusters[0].authentication": "NONE", + "webModeler.restapi.clusters[0].url.zeebe.grpc": "grpc://zeebe-gateway.test-1:26500", + "webModeler.restapi.clusters[0].url.zeebe.rest": "http://zeebe-gateway.test-1:8080", + "webModeler.restapi.clusters[0].url.operate": "http://operate.test-1:8080", + "webModeler.restapi.clusters[0].url.tasklist": "http://tasklist.test-1:8080", + "webModeler.restapi.clusters[1].id": "test-cluster-2", + "webModeler.restapi.clusters[1].name": "test cluster 2", + "webModeler.restapi.clusters[1].version": "8.7.0-alpha1", + "webModeler.restapi.clusters[1].authentication": "OAUTH", + "webModeler.restapi.clusters[1].url.zeebe.grpc": "grpc://zeebe-gateway.test-2:26500", + "webModeler.restapi.clusters[1].url.zeebe.rest": "http://zeebe-gateway.test-2:8080", + "webModeler.restapi.clusters[1].url.operate": "http://operate.test-2:8080", + "webModeler.restapi.clusters[1].url.tasklist": "http://tasklist.test-2:8080", + "webModeler.restapi.clusters[1].oauth.url": "http://test-keycloak:80/auth/realms/camunda-platform/protocol/openid-connect/token", + "postgresql.enabled": "false", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", s.namespace), + } + + // when + output := helm.RenderTemplate(s.T(), options, s.chartPath, s.release, s.templates) + var configmap corev1.ConfigMap + var configmapApplication WebModelerRestAPIApplicationYAML + helm.UnmarshalK8SYaml(s.T(), output, &configmap) + + err := yaml.Unmarshal([]byte(configmap.Data["application.yaml"]), &configmapApplication) + if err != nil { + s.Fail("Failed to unmarshal yaml. error=", err) + } + + // then + s.Require().Equal(2, len(configmapApplication.Camunda.Modeler.Clusters)) + s.Require().Equal("test-cluster-1", configmapApplication.Camunda.Modeler.Clusters[0].Id) + s.Require().Equal("test cluster 1", configmapApplication.Camunda.Modeler.Clusters[0].Name) + s.Require().Equal("8.6.0", configmapApplication.Camunda.Modeler.Clusters[0].Version) + s.Require().Equal("NONE", configmapApplication.Camunda.Modeler.Clusters[0].Authentication) + s.Require().Equal("grpc://zeebe-gateway.test-1:26500", configmapApplication.Camunda.Modeler.Clusters[0].Url.Zeebe.Grpc) + s.Require().Equal("http://zeebe-gateway.test-1:8080", configmapApplication.Camunda.Modeler.Clusters[0].Url.Zeebe.Rest) + s.Require().Equal("http://operate.test-1:8080", configmapApplication.Camunda.Modeler.Clusters[0].Url.Operate) + s.Require().Equal("http://tasklist.test-1:8080", configmapApplication.Camunda.Modeler.Clusters[0].Url.Tasklist) + s.Require().Equal("test-cluster-2", configmapApplication.Camunda.Modeler.Clusters[1].Id) + s.Require().Equal("test cluster 2", configmapApplication.Camunda.Modeler.Clusters[1].Name) + s.Require().Equal("8.7.0-alpha1", configmapApplication.Camunda.Modeler.Clusters[1].Version) + s.Require().Equal("OAUTH", configmapApplication.Camunda.Modeler.Clusters[1].Authentication) + s.Require().Equal("grpc://zeebe-gateway.test-2:26500", configmapApplication.Camunda.Modeler.Clusters[1].Url.Zeebe.Grpc) + s.Require().Equal("http://zeebe-gateway.test-2:8080", configmapApplication.Camunda.Modeler.Clusters[1].Url.Zeebe.Rest) + s.Require().Equal("http://operate.test-2:8080", configmapApplication.Camunda.Modeler.Clusters[1].Url.Operate) + s.Require().Equal("http://tasklist.test-2:8080", configmapApplication.Camunda.Modeler.Clusters[1].Url.Tasklist) + s.Require().Equal("http://test-keycloak:80/auth/realms/camunda-platform/protocol/openid-connect/token", configmapApplication.Camunda.Modeler.Clusters[1].Oauth.Url) +} + +func (s *configmapRestAPITemplateTest) TestContainerShouldNotConfigureClustersIfZeebeDisabledAndNoCustomConfiguration() { + // given + options := &helm.Options{ + SetValues: map[string]string{ + "webModeler.enabled": "true", + "webModeler.restapi.mail.fromAddress": "example@example.com", + "postgresql.enabled": "false", + "zeebe.enabled": "false", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", s.namespace), + } + + // when + output := helm.RenderTemplate(s.T(), options, s.chartPath, s.release, s.templates) + var configmap corev1.ConfigMap + var configmapApplication WebModelerRestAPIApplicationYAML + helm.UnmarshalK8SYaml(s.T(), output, &configmap) + + err := yaml.Unmarshal([]byte(configmap.Data["application.yaml"]), &configmapApplication) + if err != nil { + s.Fail("Failed to unmarshal yaml. error=", err) + } + + // then + s.Require().Empty(configmapApplication.Camunda.Modeler.Clusters) +} diff --git a/charts/camunda-platform-alpha/test/unit/web-modeler/types.go b/charts/camunda-platform-alpha/test/unit/web-modeler/types.go index fddd485f51..1a64bf52a9 100644 --- a/charts/camunda-platform-alpha/test/unit/web-modeler/types.go +++ b/charts/camunda-platform-alpha/test/unit/web-modeler/types.go @@ -29,7 +29,8 @@ type IdentityYAML struct { Type string `yaml:"type"` } type ModelerYAML struct { - Security SecurityYAML `yaml:"security"` + Security SecurityYAML `yaml:"security"` + Clusters []ClusterYAML `yaml:"clusters"` } type SecurityYAML struct { @@ -50,6 +51,38 @@ type AudienceYAML struct { PublicAPI string `yaml:"public-api"` } +type ClusterYAML struct { + Id string `yaml:"id"` + Name string `yaml:"name"` + Version string `yaml:"version"` + Authentication string `yaml:"authentication"` + Url UrlYAML `yaml:"url"` + Oauth OAuthYAML `yaml:"oauth"` +} + +type UrlYAML struct { + Zeebe ZeebeUrlYAML `yaml:"zeebe"` + Operate string `yaml:"operate"` + Tasklist string `yaml:"tasklist"` +} + +type ZeebeUrlYAML struct { + Grpc string `yaml:"grpc"` + Rest string `yaml:"rest"` +} + +type OAuthYAML struct { + Url string `yaml:"url"` + Scope string `yaml:"scope"` + Audience OAuthAudienceYAML `yaml:"audience"` +} + +type OAuthAudienceYAML struct { + Zeebe string `yaml:"zeebe"` + Operate string `yaml:"operate"` + Tasklist string `yaml:"tasklist"` +} + // Web App --- type WebModelerWebAppTOML struct { diff --git a/charts/camunda-platform-alpha/values.yaml b/charts/camunda-platform-alpha/values.yaml index 64d2a97036..69a174f7b9 100644 --- a/charts/camunda-platform-alpha/values.yaml +++ b/charts/camunda-platform-alpha/values.yaml @@ -2819,6 +2819,9 @@ webModeler: ## @param webModeler.restapi.mail.fromName defines the name that will be displayed as the sender of emails sent by WebModeler fromName: "Camunda 8" + ## @param webModeler.restapi.clusters can be used to configure Camunda 8 clusters that will be available in Web Modeler (will override default cluster configuration that is used if `zeebe.enabled=true`) + clusters: [] + ## @param webModeler.restapi.podAnnotations can be used to define extra restapi pod annotations podAnnotations: {} ## @param webModeler.restapi.podLabels can be used to define extra restapi pod labels