From 757a1946258d26bd7487bb84736ea57fdb81ed3a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mois=C3=A9s=20Calzado?=
 <56086628+moicalcob@users.noreply.github.com>
Date: Tue, 6 Aug 2024 16:44:52 +0200
Subject: [PATCH] Inject feature flags in the Helm chart deployments (#590)

* Inject feature flags in needed deployments

* Add feature-flags file

* Inject FFs file in workspace-api

* Fix

* New fix

* Fix volume

* Fix

* Add file in all needed backend services

* Mount in workspace-wwww

* Change workspace www image and add env var

* Fix

* Allow overriding featureFlags

* Try fix

* Redeploy if FFs change

* Change checksum name

* Last change

* Fix
---
 chart/README.md                               |   1 +
 chart/feature-flags.yaml                      | 109 ++++++++++++++++++
 chart/templates/_helpers.tpl                  |  14 +++
 chart/templates/feature-flags-configmap.yaml  |  19 +++
 chart/templates/maps-api/deployment.yaml      |  11 ++
 chart/templates/sql-worker/deployment.yaml    |  11 ++
 chart/templates/workspace-api/deployment.yaml |  11 ++
 .../workspace-subscriber/deployment.yaml      |  11 ++
 chart/templates/workspace-www/configmap.yaml  |   1 +
 chart/templates/workspace-www/deployment.yaml |  11 ++
 chart/values.yaml                             |   2 +
 manifests/kots-helm.yaml                      |  13 ++-
 12 files changed, 208 insertions(+), 6 deletions(-)
 create mode 100644 chart/feature-flags.yaml
 create mode 100644 chart/templates/feature-flags-configmap.yaml

diff --git a/chart/README.md b/chart/README.md
index 8d67c456..31c3ce24 100644
--- a/chart/README.md
+++ b/chart/README.md
@@ -77,6 +77,7 @@ To install, upgrade or uninstall this chart, please refer to [the root README.md
 | `cartoConfigValues.dataObservatoryProjectId`      | GCP project ID of the Carto Data Observatory.                                                                                                                                                        | `""`    |
 | `cartoConfigValues.ingressTestingMode`            | Enable router testing mode for the application. This will deploy the router in testing mode serving a simple page to check that it works without routing traffic to other components.                | `false` |
 | `cartoConfigValues.onlyRunRouter`                 | Enable only the router component in the installation. This will just deploy the router component. Useful to check the ingress layer together with the option `cartoConfigValues.ingressTestingMode`. | `false` |
+| `cartoConfigValues.featureFlagsOverrides`         | YAML configuration for overriding feature flags.                                                                                                                                                     | `[]`    |
 
 ### App secret
 
diff --git a/chart/feature-flags.yaml b/chart/feature-flags.yaml
new file mode 100644
index 00000000..c0babbf9
--- /dev/null
+++ b/chart/feature-flags.yaml
@@ -0,0 +1,109 @@
+featureFlags:
+  - name: 2023-builder-hex-code
+    value: true
+  - name: 2023-builder-map-explain-public-title
+    value: true
+  - name: 2023-builder-map-explain-rich-description
+    value: true
+  - name: 2023-builder-map-explain-widget-notes
+    value: true
+  - name: 2023-builder-pie-widget
+    value: true
+  - name: 2023-cartodw-direct-access
+    value: true
+  - name: 2023-custom-schema-imports
+    value: true
+  - name: 2023-enable-sharing-apps
+    value: true
+  - name: 2023-export-do-subscriptions-from-workspace
+    value: true
+  - name: 2023-map-sso-groups-to-roles
+    value: true
+  - name: 2023-measure-tool-builder
+    value: true
+  - name: 2023-oauth-for-snowflake
+    value: true
+  - name: 2023-row-level-security-bq-oauth
+    value: true
+  - name: 2023-search-location-by-coordinates
+    value: true
+  - name: 2023-server-side-export
+    value: true
+  - name: 2023-sql-params-numeric
+    value: true
+  - name: 2023-timeseries-improve-multi-and-split
+    value: true
+  - name: 2023-timeseries-improve-precision
+    value: true
+  - name: 2023-whitelabel-branding
+    value: true
+  - name: 2023-workflows-at-home-page
+    value: true
+  - name: 2023-workflows-data-export
+    value: true
+  - name: 2023-workflows-do
+    value: true
+  - name: 2023-workflows-enrichment
+    value: true
+  - name: 2023-workflows-export
+    value: true
+  - name: 2023-workflows-export-ii
+    value: true
+  - name: 2023-workflows-import
+    value: true
+  - name: 2023-workflows-scheduling
+    value: true
+  - name: 2024-catalog-workflow-templates
+    value: true
+  - name: 2024-custom-basemaps
+    value: true
+  - name: 2024-databricks-rest-connection-enabled
+    value: true
+  - name: 2024-deliver-raw-audit-logs
+    value: false
+  - name: 2024-heatmap-aggregation-in-builder
+    value: true
+  - name: 2024-query-concurrency-control
+    value: true
+  - name: 2024-reduce-number-of-queries
+    value: true
+  - name: 2024-tags-for-resources
+    value: true
+  - name: 2024-workflows-package-extension
+    value: false
+  - name: 2024-workflows-raster-components
+    value: true
+  - name: 2024-zoom-to-layer-in-builder
+    value: true
+  - name: dynamic-tiling-v-2
+    value: true
+  - name: frontend-2022-collaborative-maps
+    value: true
+  - name: frontend-2022-enable-postgres-import
+    value: true
+  - name: frontend-2022-enable-redshift-import-after-bucket-configuration
+    value: true
+  - name: frontend-2022-help-sidebar
+    value: true
+  - name: frontend-2022-new-mini-data-explorer
+    value: true
+  - name: frontend-2022-workflows
+    value: true
+  - name: frontend-2023-connections-with-viewer-credentials
+    value: true
+  - name: frontend-2023-enterprise-sso-just-in-time-provisioning
+    value: true
+  - name: frontend-2023-new-developer-ui-for-tokens
+    value: true
+  - name: frontend-2023-run-table-optimization-from-ui
+    value: true
+  - name: frontend-2023-workflows-all-providers
+    value: true
+  - name: frontend-2023-workflows-on-homepage
+    value: true
+  - name: frontend-2023-workflows-sharing
+    value: true
+  - name: 2024-deprecate-create-tileset-from-dataexplorer-ui
+    value: '2024-07-22T00:00:00.000Z'
+  - name: 2024-deprecate-enrich-table-from-dataexplorer-ui
+    value: '2024-04-04T00:00:00.000Z'
diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl
index a77f6ec6..b1f03ee5 100644
--- a/chart/templates/_helpers.tpl
+++ b/chart/templates/_helpers.tpl
@@ -1400,3 +1400,17 @@ Return the absolute path where the proxy CA cert will be mounted
 {{- define "carto.proxy.configMapMountAbsolutePath" -}}
 {{- printf "%s/%s" (include "carto.proxy.configMapMountDir" .) (include "carto.proxy.configMapMountFilename" .) -}}
 {{- end -}}
+
+{{/*
+Get the feature flags config map name
+*/}}
+{{- define "carto.featureFlags.configMapName" -}}
+{{- printf "%s-%s" .Release.Name "featureflags" -}}
+{{- end -}}
+
+{{/*
+Return the directory where the feature flags config file will be mounted
+*/}}
+{{- define "carto.featureFlags.configMapMountDir" -}}
+{{- print "/tmp/feature-flags.yaml" -}}
+{{- end -}}
diff --git a/chart/templates/feature-flags-configmap.yaml b/chart/templates/feature-flags-configmap.yaml
new file mode 100644
index 00000000..9d276d23
--- /dev/null
+++ b/chart/templates/feature-flags-configmap.yaml
@@ -0,0 +1,19 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ include "carto.featureFlags.configMapName" . }}
+  labels: {{- include "common.labels.standard" . | nindent 4 }}
+    {{- if .Values.commonLabels }}
+    {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }}
+    {{- end }}
+  namespace: {{ .Release.Namespace | quote }}
+  {{- if .Values.commonAnnotations }}
+  annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
+  {{- end }}
+data:
+  feature-flags.yaml: |-
+{{ .Files.Get "feature-flags.yaml" | indent 4 }}
+{{- if .Values.cartoConfigValues.featureFlagsOverrides }}
+    featureFlagsOverrides:
+{{ .Values.cartoConfigValues.featureFlagsOverrides | toYaml | indent 6 }}
+{{- end }}
diff --git a/chart/templates/maps-api/deployment.yaml b/chart/templates/maps-api/deployment.yaml
index 14e6855a..e06713a4 100644
--- a/chart/templates/maps-api/deployment.yaml
+++ b/chart/templates/maps-api/deployment.yaml
@@ -24,6 +24,7 @@ spec:
     metadata:
       annotations:
         checksum/config: {{ include (print $.Template.BasePath "/maps-api/configmap.yaml") . | sha256sum }}
+        checksum/feature-flags-config: {{ include (print $.Template.BasePath "/feature-flags-configmap.yaml") . | sha256sum }}
         checksum/secret: {{ include (print $.Template.BasePath "/maps-api/secret.yaml") . | sha256sum }}
         cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
         {{- if .Values.mapsApi.podAnnotations }}
@@ -207,6 +208,10 @@ spec:
               mountPath: {{ include "carto.proxy.configMapMountDir" . }}
               readOnly: true
             {{- end }}
+            - name: feature-flags
+              mountPath: {{ include "carto.featureFlags.configMapMountDir" . }}
+              subPath: feature-flags.yaml
+              readOnly: true
           {{- if .Values.mapsApi.extraVolumeMounts }}
           {{- include "common.tplvalues.render" (dict "value" .Values.mapsApi.extraVolumeMounts "context" $) | nindent 12 }}
           {{- end }}
@@ -243,6 +248,12 @@ spec:
           configMap:
             name: {{ include "carto.proxy.configMapName" . }}
         {{- end }}
+        - name: feature-flags
+          configMap:
+            name: {{ template "carto.featureFlags.configMapName" . }}
+            items:
+              - key: feature-flags.yaml
+                path: feature-flags.yaml
         {{- if .Values.mapsApi.extraVolumes }}
         {{- include "common.tplvalues.render" (dict "value" .Values.mapsApi.extraVolumes "context" $) | nindent 8 }}
       {{- end }}
diff --git a/chart/templates/sql-worker/deployment.yaml b/chart/templates/sql-worker/deployment.yaml
index 09a0aee9..918d7201 100644
--- a/chart/templates/sql-worker/deployment.yaml
+++ b/chart/templates/sql-worker/deployment.yaml
@@ -30,6 +30,7 @@ spec:
     metadata:
       annotations:
         checksum/config: {{ include (print $.Template.BasePath "/sql-worker/configmap.yaml") . | sha256sum }}
+        checksum/feature-flags-config: {{ include (print $.Template.BasePath "/feature-flags-configmap.yaml") . | sha256sum }}
         checksum/secret: {{ include (print $.Template.BasePath "/sql-worker/secret.yaml") . | sha256sum }}
         cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
         {{- if .Values.sqlWorker.podAnnotations }}
@@ -178,6 +179,10 @@ spec:
               mountPath: {{ include "carto.proxy.configMapMountDir" . }}
               readOnly: true
             {{- end }}
+            - name: feature-flags
+              mountPath: {{ include "carto.featureFlags.configMapMountDir" . }}
+              subPath: feature-flags.yaml
+              readOnly: true
           {{- if .Values.sqlWorker.extraVolumeMounts }}
           {{- include "common.tplvalues.render" (dict "value" .Values.sqlWorker.extraVolumeMounts "context" $) | nindent 12 }}
           {{- end }}
@@ -209,6 +214,12 @@ spec:
           configMap:
             name: {{ include "carto.proxy.configMapName" . }}
         {{- end }}
+        - name: feature-flags
+          configMap:
+            name: {{ template "carto.featureFlags.configMapName" . }}
+            items:
+              - key: feature-flags.yaml
+                path: feature-flags.yaml
         {{- if .Values.sqlWorker.extraVolumes }}
         {{- include "common.tplvalues.render" (dict "value" .Values.sqlWorker.extraVolumes "context" $) | nindent 8 }}
         {{- end }}
diff --git a/chart/templates/workspace-api/deployment.yaml b/chart/templates/workspace-api/deployment.yaml
index 993bb5dd..10bc128f 100644
--- a/chart/templates/workspace-api/deployment.yaml
+++ b/chart/templates/workspace-api/deployment.yaml
@@ -24,6 +24,7 @@ spec:
     metadata:
       annotations:
         checksum/config: {{ include (print $.Template.BasePath "/workspace-api/configmap.yaml") . | sha256sum }}
+        checksum/feature-flags-config: {{ include (print $.Template.BasePath "/feature-flags-configmap.yaml") . | sha256sum }}
         checksum/secret: {{ include (print $.Template.BasePath "/workspace-api/secret.yaml") . | sha256sum }}
         cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
         {{- if .Values.workspaceApi.podAnnotations }}
@@ -293,6 +294,10 @@ spec:
               mountPath: {{ include "carto.proxy.configMapMountDir" . }}
               readOnly: true
             {{- end }}
+            - name: feature-flags
+              mountPath: {{ include "carto.featureFlags.configMapMountDir" . }}
+              subPath: feature-flags.yaml
+              readOnly: true
           {{- if .Values.workspaceApi.extraVolumeMounts }}
           {{- include "common.tplvalues.render" (dict "value" .Values.workspaceApi.extraVolumeMounts "context" $) | nindent 12 }}
           {{- end }}
@@ -329,6 +334,12 @@ spec:
           configMap:
             name: {{ include "carto.proxy.configMapName" . }}
         {{- end }}
+        - name: feature-flags
+          configMap:
+            name: {{ template "carto.featureFlags.configMapName" . }}
+            items:
+              - key: feature-flags.yaml
+                path: feature-flags.yaml
         {{- if .Values.workspaceApi.extraVolumes }}
         {{- include "common.tplvalues.render" (dict "value" .Values.workspaceApi.extraVolumes "context" $) | nindent 8 }}
         {{- end }}
diff --git a/chart/templates/workspace-subscriber/deployment.yaml b/chart/templates/workspace-subscriber/deployment.yaml
index 23ea2bd0..e8708480 100644
--- a/chart/templates/workspace-subscriber/deployment.yaml
+++ b/chart/templates/workspace-subscriber/deployment.yaml
@@ -30,6 +30,7 @@ spec:
     metadata:
       annotations:
         checksum/config: {{ include (print $.Template.BasePath "/workspace-subscriber/configmap.yaml") . | sha256sum }}
+        checksum/feature-flags-config: {{ include (print $.Template.BasePath "/feature-flags-configmap.yaml") . | sha256sum }}
         checksum/secret: {{ include (print $.Template.BasePath "/workspace-subscriber/secret.yaml") . | sha256sum }}
         cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
         {{- if .Values.workspaceSubscriber.podAnnotations }}
@@ -181,6 +182,10 @@ spec:
               mountPath: {{ include "carto.proxy.configMapMountDir" . }}
               readOnly: true
             {{- end }}
+            - name: feature-flags
+              mountPath: {{ include "carto.featureFlags.configMapMountDir" . }}
+              subPath: feature-flags.yaml
+              readOnly: true
           {{- if .Values.workspaceSubscriber.extraVolumeMounts }}
           {{- include "common.tplvalues.render" (dict "value" .Values.workspaceSubscriber.extraVolumeMounts "context" $) | nindent 12 }}
           {{- end }}
@@ -209,6 +214,12 @@ spec:
           configMap:
             name: {{ include "carto.proxy.configMapName" . }}
         {{- end }}
+        - name: feature-flags
+          configMap:
+            name: {{ template "carto.featureFlags.configMapName" . }}
+            items:
+              - key: feature-flags.yaml
+                path: feature-flags.yaml
         {{- if .Values.workspaceSubscriber.extraVolumes }}
         {{- include "common.tplvalues.render" (dict "value" .Values.workspaceSubscriber.extraVolumes "context" $) | nindent 8 }}
         {{- end }}
diff --git a/chart/templates/workspace-www/configmap.yaml b/chart/templates/workspace-www/configmap.yaml
index a8e00e2d..c8480be6 100644
--- a/chart/templates/workspace-www/configmap.yaml
+++ b/chart/templates/workspace-www/configmap.yaml
@@ -13,6 +13,7 @@ metadata:
   {{- end }}
 data:
   CARTO_DATA_WAREHOUSE_ENABLED: {{ .Values.cartoConfigValues.cartoDataWarehouseEnabled | quote }}
+  CARTO_FEATURE_FLAGS_FILE_PATH: {{ include "carto.featureFlags.configMapMountDir" . | quote }}
   {{- if $.Values.appConfigValues.bigqueryOauth2ClientId }}
   REACT_APP_BIGQUERY_OAUTH: "true"
   {{- else }}
diff --git a/chart/templates/workspace-www/deployment.yaml b/chart/templates/workspace-www/deployment.yaml
index 781c62ef..6f8ebe79 100644
--- a/chart/templates/workspace-www/deployment.yaml
+++ b/chart/templates/workspace-www/deployment.yaml
@@ -24,6 +24,7 @@ spec:
     metadata:
       annotations:
         checksum/config: {{ include (print $.Template.BasePath "/workspace-www/configmap.yaml") . | sha256sum }}
+        checksum/feature-flags-config: {{ include (print $.Template.BasePath "/feature-flags-configmap.yaml") . | sha256sum }}
         checksum/secret: {{ include (print $.Template.BasePath "/workspace-www/secret.yaml") . | sha256sum }}
         cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
         {{- if .Values.workspaceWww.podAnnotations }}
@@ -164,6 +165,10 @@ spec:
               mountPath: /tmp
             - name: nginx-shared-snippets
               mountPath: /etc/nginx/conf.d/shared-snippets
+            - name: feature-flags
+              mountPath: {{ include "carto.featureFlags.configMapMountDir" . }}
+              subPath: feature-flags.yaml
+              readOnly: true
           {{- if .Values.workspaceWww.extraVolumeMounts }}
           {{- include "common.tplvalues.render" (dict "value" .Values.workspaceWww.extraVolumeMounts "context" $) | nindent 12 }}
           {{- end }}
@@ -179,6 +184,12 @@ spec:
             medium: Memory
         - name: tmp
           emptyDir: {}
+        - name: feature-flags
+          configMap:
+            name: {{ template "carto.featureFlags.configMapName" . }}
+            items:
+              - key: feature-flags.yaml
+                path: feature-flags.yaml
       {{- if .Values.workspaceWww.extraVolumes }}
         {{- include "common.tplvalues.render" (dict "value" .Values.workspaceWww.extraVolumes "context" $) | nindent 8 }}
       {{- end }}
diff --git a/chart/values.yaml b/chart/values.yaml
index f71eacc8..bdb10c3f 100644
--- a/chart/values.yaml
+++ b/chart/values.yaml
@@ -114,6 +114,8 @@ cartoConfigValues:
   ingressTestingMode: false
   ## @param cartoConfigValues.onlyRunRouter Enable only the router component in the installation. This will just deploy the router component. Useful to check the ingress layer together with the option `cartoConfigValues.ingressTestingMode`.
   onlyRunRouter: false
+  ## @param cartoConfigValues.featureFlagsOverrides YAML configuration for overriding feature flags.
+  featureFlagsOverrides: []
 
 ## @section App secret
 ## Global secrets to be edited by the client
diff --git a/manifests/kots-helm.yaml b/manifests/kots-helm.yaml
index a8786d1a..11f1cd09 100644
--- a/manifests/kots-helm.yaml
+++ b/manifests/kots-helm.yaml
@@ -187,12 +187,13 @@ spec:
   ## Values from Advanced Configuration
   optionalValues:
     ## TEMPORAL PATCHED IMAGED
-    # - when: 'true'
-    #   recursiveMerge: true
-    #   values:
-    #     router:
-    #       image:
-    #         tag: "feature_sc_415629_add_ingress_debug_mode_in_carto_self_hosted"
+    - when: 'true'
+      recursiveMerge: true
+      values:
+        workspaceWww:
+          image:
+            registry: registry.self-hosted.carto.com/proxy/carto/gcr.io/carto-artifacts
+            tag: "feature_sc_431460_inject_the_default_value_and_the_overrides"
 
     ## Specify service account if workload identity is disabled
     - when: '{{repl ConfigOptionEquals "enableGoogleWorkloadIdentity" "0" }}'