{{- if .Values.webapp.serviceAccount.create }} apiVersion: v1 kind: ServiceAccount metadata: name: {{ include "trigger-v4.webappServiceAccountName" . }} labels: {{- $component := "webapp" }} {{- include "trigger-v4.componentLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 4 }} {{- with .Values.webapp.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} {{- end }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: {{ include "trigger-v4.fullname" . }}-webapp-token-syncer labels: {{- $component := "webapp" }} {{- include "trigger-v4.componentLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 4 }} rules: - apiGroups: [""] resources: ["secrets"] verbs: ["create", "get", "update", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: {{ include "trigger-v4.fullname" . }}-webapp-token-syncer labels: {{- $component := "webapp" }} {{- include "trigger-v4.componentLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 4 }} subjects: - kind: ServiceAccount name: {{ include "trigger-v4.webappServiceAccountName" . }} namespace: {{ .Release.Namespace }} roleRef: kind: Role name: {{ include "trigger-v4.fullname" . }}-webapp-token-syncer apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "trigger-v4.fullname" . }}-webapp labels: {{- $component := "webapp" }} {{- include "trigger-v4.componentLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 4 }} spec: replicas: {{ .Values.webapp.replicaCount }} selector: matchLabels: {{- include "trigger-v4.componentSelectorLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 6 }} template: metadata: annotations: kubectl.kubernetes.io/default-container: webapp {{- with .Values.webapp.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} labels: {{- include "trigger-v4.componentSelectorLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 8 }} spec: serviceAccountName: {{ include "trigger-v4.webappServiceAccountName" . }} {{- with .Values.global.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} securityContext: fsGroup: 1000 {{- with .Values.webapp.podSecurityContext }} {{- toYaml . | nindent 8 }} {{- end }} initContainers: - name: volume-permissions image: {{ include "trigger-v4.webapp.volumePermissions.image" . }} imagePullPolicy: {{ .Values.webapp.volumePermissions.image.pullPolicy }} command: ['sh', '-c', 'mkdir -p /home/node/shared'] securityContext: runAsUser: 1000 volumeMounts: - name: shared mountPath: /home/node/shared containers: - name: token-syncer image: {{ include "trigger-v4.webapp.tokenSyncer.image" . }} imagePullPolicy: {{ .Values.webapp.tokenSyncer.image.pullPolicy }} securityContext: runAsUser: 1000 runAsNonRoot: true command: - /bin/bash - -c - | TOKEN_FILE="/home/node/shared/worker_token" SECRET_NAME="{{ include "trigger-v4.fullname" . }}-worker-token" NAMESPACE="{{ .Release.Namespace }}" echo "Token syncer starting..." echo "Monitoring: $TOKEN_FILE" echo "Target secret: $SECRET_NAME" while true; do if [ -f "$TOKEN_FILE" ]; then TOKEN=$(cat "$TOKEN_FILE") if [ ! -z "$TOKEN" ]; then echo "Token file found, creating/updating secret..." # Create or update the secret kubectl create secret generic "$SECRET_NAME" \ --from-literal=token="$TOKEN" \ --namespace="$NAMESPACE" \ --dry-run=client -o yaml | kubectl apply -f - if [ $? -eq 0 ]; then echo "Secret successfully created/updated" # Continue monitoring for updates sleep 30 else echo "Failed to create/update secret, retrying in 5s..." sleep 5 fi else echo "Token file exists but is empty, waiting..." sleep 2 fi else echo "Waiting for token file..." sleep 2 fi done volumeMounts: - name: shared mountPath: /home/node/shared - name: webapp securityContext: {{- toYaml .Values.webapp.securityContext | nindent 12 }} image: {{ include "trigger-v4.image" . }} imagePullPolicy: {{ .Values.webapp.image.pullPolicy }} command: - ./scripts/entrypoint.sh ports: - name: http containerPort: {{ .Values.webapp.service.targetPort }} protocol: TCP {{- if .Values.webapp.livenessProbe.enabled }} livenessProbe: httpGet: path: /healthcheck port: http initialDelaySeconds: {{ .Values.webapp.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.webapp.livenessProbe.periodSeconds }} timeoutSeconds: {{ .Values.webapp.livenessProbe.timeoutSeconds }} failureThreshold: {{ .Values.webapp.livenessProbe.failureThreshold }} successThreshold: {{ .Values.webapp.livenessProbe.successThreshold }} {{- end }} {{- if .Values.webapp.readinessProbe.enabled }} readinessProbe: httpGet: path: /healthcheck port: http initialDelaySeconds: {{ .Values.webapp.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.webapp.readinessProbe.periodSeconds }} timeoutSeconds: {{ .Values.webapp.readinessProbe.timeoutSeconds }} failureThreshold: {{ .Values.webapp.readinessProbe.failureThreshold }} successThreshold: {{ .Values.webapp.readinessProbe.successThreshold }} {{- end }} {{- if .Values.webapp.startupProbe.enabled }} startupProbe: httpGet: path: /healthcheck port: http initialDelaySeconds: {{ .Values.webapp.startupProbe.initialDelaySeconds }} periodSeconds: {{ .Values.webapp.startupProbe.periodSeconds }} timeoutSeconds: {{ .Values.webapp.startupProbe.timeoutSeconds }} failureThreshold: {{ .Values.webapp.startupProbe.failureThreshold }} successThreshold: {{ .Values.webapp.startupProbe.successThreshold }} {{- end }} resources: {{- toYaml .Values.webapp.resources | nindent 12 }} env: - name: APP_ORIGIN value: {{ .Values.webapp.appOrigin | quote }} - name: LOGIN_ORIGIN value: {{ .Values.webapp.loginOrigin | quote }} - name: API_ORIGIN value: {{ .Values.webapp.apiOrigin | quote }} - name: ELECTRIC_ORIGIN value: {{ include "trigger-v4.electric.url" . | quote }} {{- if include "trigger-v4.s2.enabled" . }} # Realtime streams v2, backed by S2 (bundled s2-lite or an external endpoint) - name: REALTIME_STREAMS_DEFAULT_VERSION value: {{ .Values.s2.defaultStreamVersion | quote }} - name: REALTIME_STREAMS_S2_ENDPOINT value: {{ include "trigger-v4.s2.url" . | quote }} - name: REALTIME_STREAMS_S2_BASIN value: {{ .Values.s2.basin | quote }} - name: REALTIME_STREAMS_S2_SKIP_ACCESS_TOKENS value: {{ .Values.s2.skipAccessTokens | quote }} {{- if and .Values.s2.external.endpoint .Values.s2.external.existingSecret }} - name: REALTIME_STREAMS_S2_ACCESS_TOKEN valueFrom: secretKeyRef: name: {{ .Values.s2.external.existingSecret }} key: {{ .Values.s2.external.existingSecretAccessTokenKey }} {{- else if .Values.s2.external.accessToken }} - name: REALTIME_STREAMS_S2_ACCESS_TOKEN value: {{ .Values.s2.external.accessToken | quote }} {{- end }} {{- end }} {{- if include "trigger-v4.postgres.useSecretUrl" . }} - name: DATABASE_URL valueFrom: secretKeyRef: name: {{ include "trigger-v4.postgres.external.secretName" . }} key: {{ include "trigger-v4.postgres.external.databaseUrlKey" . }} - name: DIRECT_URL valueFrom: secretKeyRef: name: {{ include "trigger-v4.postgres.external.secretName" . }} key: {{ include "trigger-v4.postgres.external.directUrlKey" . }} {{- else }} - name: DATABASE_URL value: {{ include "trigger-v4.postgres.connectionString" . | quote }} - name: DIRECT_URL value: {{ include "trigger-v4.postgres.directUrl" . | quote }} {{- end }} {{- if and (include "trigger-v4.webapp.connectivityCheckEnabled" .) (include "trigger-v4.postgres.host" .) }} - name: DATABASE_HOST value: {{ include "trigger-v4.postgres.host" . | quote }} {{- end }} - name: REDIS_HOST value: {{ include "trigger-v4.redis.host" . | quote }} - name: REDIS_PORT value: {{ include "trigger-v4.redis.port" . | quote }} {{- if and .Values.redis.external.host .Values.redis.external.existingSecret }} - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: {{ include "trigger-v4.redis.external.secretName" . }} key: {{ include "trigger-v4.redis.external.passwordKey" . }} {{- else if include "trigger-v4.redis.password" . }} - name: REDIS_PASSWORD value: {{ include "trigger-v4.redis.password" . | quote }} {{- end }} - name: REDIS_TLS_DISABLED value: {{ include "trigger-v4.redis.tlsDisabled" . | quote }} - name: APP_LOG_LEVEL value: {{ .Values.webapp.logLevel | quote }} - name: DEV_OTEL_EXPORTER_OTLP_ENDPOINT value: "{{ .Values.webapp.appOrigin }}/otel" - name: DEPLOY_REGISTRY_HOST value: {{ include "trigger-v4.registry.host" . | quote }} - name: DEPLOY_REGISTRY_NAMESPACE value: {{ .Values.registry.repositoryNamespace | quote }} - name: OBJECT_STORE_BASE_URL value: {{ include "trigger-v4.s3.url" . | quote }} - name: GRACEFUL_SHUTDOWN_TIMEOUT value: {{ .Values.webapp.gracefulShutdownTimeout | quote }} {{- if .Values.webapp.bootstrap.enabled }} - name: TRIGGER_BOOTSTRAP_ENABLED value: "1" - name: TRIGGER_BOOTSTRAP_WORKER_GROUP_NAME value: {{ .Values.webapp.bootstrap.workerGroupName | quote }} - name: TRIGGER_BOOTSTRAP_WORKER_TOKEN_PATH value: {{ .Values.webapp.bootstrap.workerTokenPath | quote }} {{- end }} {{- if .Values.webapp.limits.taskPayloadOffloadThreshold }} - name: TASK_PAYLOAD_OFFLOAD_THRESHOLD value: {{ .Values.webapp.limits.taskPayloadOffloadThreshold | quote }} {{- end }} {{- if .Values.webapp.limits.taskPayloadMaximumSize }} - name: TASK_PAYLOAD_MAXIMUM_SIZE value: {{ .Values.webapp.limits.taskPayloadMaximumSize | quote }} {{- end }} {{- if .Values.webapp.limits.batchTaskPayloadMaximumSize }} - name: BATCH_TASK_PAYLOAD_MAXIMUM_SIZE value: {{ .Values.webapp.limits.batchTaskPayloadMaximumSize | quote }} {{- end }} {{- if .Values.webapp.limits.taskRunMetadataMaximumSize }} - name: TASK_RUN_METADATA_MAXIMUM_SIZE value: {{ .Values.webapp.limits.taskRunMetadataMaximumSize | quote }} {{- end }} {{- if .Values.webapp.limits.defaultEnvExecutionConcurrencyLimit }} - name: DEFAULT_ENV_EXECUTION_CONCURRENCY_LIMIT value: {{ .Values.webapp.limits.defaultEnvExecutionConcurrencyLimit | quote }} {{- end }} {{- if .Values.webapp.limits.defaultOrgExecutionConcurrencyLimit }} - name: DEFAULT_ORG_EXECUTION_CONCURRENCY_LIMIT value: {{ .Values.webapp.limits.defaultOrgExecutionConcurrencyLimit | quote }} {{- end }} {{- if or .Values.secrets.enabled .Values.secrets.existingSecret }} - name: SESSION_SECRET valueFrom: secretKeyRef: name: {{ include "trigger-v4.secretsName" . }} key: SESSION_SECRET - name: MAGIC_LINK_SECRET valueFrom: secretKeyRef: name: {{ include "trigger-v4.secretsName" . }} key: MAGIC_LINK_SECRET - name: ENCRYPTION_KEY valueFrom: secretKeyRef: name: {{ include "trigger-v4.secretsName" . }} key: ENCRYPTION_KEY - name: MANAGED_WORKER_SECRET valueFrom: secretKeyRef: name: {{ include "trigger-v4.secretsName" . }} key: MANAGED_WORKER_SECRET {{- if .Values.s3.deploy }} {{- if .Values.s3.auth.existingSecret }} - name: OBJECT_STORE_ACCESS_KEY_ID valueFrom: secretKeyRef: name: {{ include "trigger-v4.s3.auth.secretName" . }} key: {{ include "trigger-v4.s3.auth.accessKeyIdKey" . }} - name: OBJECT_STORE_SECRET_ACCESS_KEY valueFrom: secretKeyRef: name: {{ include "trigger-v4.s3.auth.secretName" . }} key: {{ include "trigger-v4.s3.auth.secretAccessKeyKey" . }} {{- else }} - name: OBJECT_STORE_ACCESS_KEY_ID valueFrom: secretKeyRef: name: {{ include "trigger-v4.secretsName" . }} key: s3-auth-access-key-id - name: OBJECT_STORE_SECRET_ACCESS_KEY valueFrom: secretKeyRef: name: {{ include "trigger-v4.secretsName" . }} key: s3-auth-secret-access-key {{- end }} {{- else }} {{- if .Values.s3.external.existingSecret }} - name: OBJECT_STORE_ACCESS_KEY_ID valueFrom: secretKeyRef: name: {{ include "trigger-v4.s3.external.secretName" . }} key: {{ include "trigger-v4.s3.external.accessKeyIdKey" . }} - name: OBJECT_STORE_SECRET_ACCESS_KEY valueFrom: secretKeyRef: name: {{ include "trigger-v4.s3.external.secretName" . }} key: {{ include "trigger-v4.s3.external.secretAccessKeyKey" . }} {{- else if .Values.s3.external.accessKeyId }} - name: OBJECT_STORE_ACCESS_KEY_ID valueFrom: secretKeyRef: name: {{ include "trigger-v4.secretsName" . }} key: s3-access-key-id - name: OBJECT_STORE_SECRET_ACCESS_KEY valueFrom: secretKeyRef: name: {{ include "trigger-v4.secretsName" . }} key: s3-secret-access-key {{- end }} {{- end }} {{- end }} {{- if .Values.webapp.observability }} {{- if .Values.webapp.observability.tracing.exporterUrl }} - name: INTERNAL_OTEL_TRACE_EXPORTER_URL value: {{ .Values.webapp.observability.tracing.exporterUrl | quote }} {{- end }} {{- if .Values.webapp.observability.tracing.exporterAuthHeaders }} - name: INTERNAL_OTEL_TRACE_EXPORTER_AUTH_HEADERS value: {{ .Values.webapp.observability.tracing.exporterAuthHeaders | quote }} {{- end }} - name: INTERNAL_OTEL_TRACE_LOGGING_ENABLED value: {{ .Values.webapp.observability.tracing.loggingEnabled | quote }} - name: INTERNAL_OTEL_TRACE_SAMPLING_RATE value: {{ .Values.webapp.observability.tracing.samplingRate | quote }} - name: INTERNAL_OTEL_TRACE_INSTRUMENT_PRISMA_ENABLED value: {{ .Values.webapp.observability.tracing.instrumentPrismaEnabled | quote }} - name: INTERNAL_OTEL_TRACE_DISABLED value: {{ .Values.webapp.observability.tracing.disabled | quote }} {{- if .Values.webapp.observability.logging.exporterUrl }} - name: INTERNAL_OTEL_LOG_EXPORTER_URL value: {{ .Values.webapp.observability.logging.exporterUrl | quote }} {{- end }} {{- if .Values.webapp.observability.metrics.exporterUrl }} - name: INTERNAL_OTEL_METRIC_EXPORTER_URL value: {{ .Values.webapp.observability.metrics.exporterUrl | quote }} {{- end }} {{- if .Values.webapp.observability.metrics.exporterAuthHeaders }} - name: INTERNAL_OTEL_METRIC_EXPORTER_AUTH_HEADERS value: {{ .Values.webapp.observability.metrics.exporterAuthHeaders | quote }} {{- end }} - name: INTERNAL_OTEL_METRIC_EXPORTER_ENABLED value: {{ .Values.webapp.observability.metrics.exporterEnabled | quote }} - name: INTERNAL_OTEL_METRIC_EXPORTER_INTERVAL_MS value: {{ .Values.webapp.observability.metrics.exporterIntervalMs | quote }} {{- end }} {{- if and .Values.clickhouse.external.host .Values.clickhouse.external.existingSecret }} - name: CLICKHOUSE_PASSWORD valueFrom: secretKeyRef: name: {{ include "trigger-v4.clickhouse.external.secretName" . }} key: {{ include "trigger-v4.clickhouse.external.passwordKey" . }} {{- end }} - name: CLICKHOUSE_URL value: {{ include "trigger-v4.clickhouse.url" . | quote }} - name: CLICKHOUSE_LOG_LEVEL value: {{ .Values.webapp.clickhouse.logLevel | quote }} - name: RUN_REPLICATION_ENABLED value: "1" - name: RUN_REPLICATION_CLICKHOUSE_URL value: {{ include "trigger-v4.clickhouse.replication.url" . | quote }} - name: RUN_REPLICATION_LOG_LEVEL value: {{ .Values.webapp.runReplication.logLevel | quote }} {{- if not .Values.telemetry.enabled }} - name: TRIGGER_TELEMETRY_DISABLED value: "1" {{- end }} {{- with .Values.webapp.extraEnvVars }} {{- toYaml . | nindent 12 }} {{- end }} volumeMounts: - name: shared mountPath: /home/node/shared {{- with .Values.webapp.extraVolumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} volumes: - name: shared {{- if .Values.persistence.shared.enabled }} persistentVolumeClaim: claimName: {{ include "trigger-v4.fullname" . }}-shared {{- else }} emptyDir: {} {{- end }} {{- with .Values.webapp.extraVolumes }} {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.webapp.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.webapp.affinity }} affinity: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.webapp.tolerations }} tolerations: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.webapp.topologySpreadConstraints }} topologySpreadConstraints: {{- tpl (toYaml .) $ | nindent 8 }} {{- end }} --- apiVersion: v1 kind: Service metadata: name: {{ include "trigger-v4.fullname" . }}-webapp labels: {{- $component := "webapp" }} {{- include "trigger-v4.componentLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 4 }} spec: type: {{ .Values.webapp.service.type }} ports: - port: {{ .Values.webapp.service.port }} targetPort: http protocol: TCP name: http selector: {{- include "trigger-v4.componentSelectorLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 4 }} --- {{- if .Values.persistence.shared.enabled }} apiVersion: v1 kind: PersistentVolumeClaim metadata: name: {{ include "trigger-v4.fullname" . }}-shared {{- if .Values.persistence.shared.retain }} annotations: "helm.sh/resource-policy": keep {{- end }} labels: {{- include "trigger-v4.labels" . | nindent 4 }} spec: accessModes: - {{ .Values.persistence.shared.accessMode }} resources: requests: storage: {{ .Values.persistence.shared.size }} {{- $storageClass := .Values.persistence.shared.storageClass | default .Values.global.storageClass }} {{- if $storageClass }} storageClassName: {{ $storageClass | quote }} {{- end }} {{- end }}