@leverege/build-tools 2.101.1 → 2.101.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leverege/build-tools",
3
- "version": "2.101.1",
3
+ "version": "2.101.2",
4
4
  "description": "A collection of build / support tools for Leverege developers",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -94,12 +94,12 @@
94
94
  "googleapis": "^171.4.0",
95
95
  "handlebars": "^4.7.9",
96
96
  "ignore": "^7.0.5",
97
- "inquirer": "^13.4.1",
97
+ "inquirer": "^13.4.2",
98
98
  "js-yaml": "^4.1.1",
99
99
  "jsdoc": "^4.0.5",
100
100
  "ms": "^2.1.3",
101
101
  "npm-registry-fetch": "^19.1.1",
102
- "ora": "^9.3.0",
102
+ "ora": "^9.4.0",
103
103
  "p-limit": "^7.3.0",
104
104
  "package-up": "^5.0.0",
105
105
  "readline-sync": "^1.4.10",
@@ -117,6 +117,6 @@
117
117
  "@leverege/eslint-config-leverege": "^5.1.2",
118
118
  "chai": "^6.2.2",
119
119
  "mocha": "^11.7.5",
120
- "npm": "^11.12.1"
120
+ "npm": "^11.13.0"
121
121
  }
122
122
  }
package/src/Utils.mjs CHANGED
@@ -560,6 +560,11 @@ export const parseHelmChart = async ( helmroot = './helm' ) => {
560
560
  } )
561
561
 
562
562
  depsOutOfSync = mismatches.length > 0
563
+
564
+ // One final check - if the helm/charts dir is missing then we also need to update dependencies
565
+ if ( hasDependencies && !chartFiles.includes( 'charts' ) ) {
566
+ depsOutOfSync = true
567
+ }
563
568
  }
564
569
  /* eslint-enable security/detect-non-literal-fs-filename */
565
570
 
package/src/bash-funcs CHANGED
@@ -229,6 +229,33 @@ function waitForIAM() {
229
229
  done
230
230
  }
231
231
 
232
+ # waitForSAIAM SVC_ACCT PROJECT ROLE MEMBER [TIMEOUT_SECONDS]
233
+ # Like waitForIAM but checks the SA's own IAM policy (for bindings like workloadIdentityUser
234
+ # that are set via `gcloud iam service-accounts add-iam-policy-binding`, not project-level).
235
+ function waitForSAIAM() {
236
+ local svcAcct="$1" project="$2" role="$3" member="$4" timeout="${5:-120}"
237
+ local svcAcctEmail="${svcAcct}@${project}.iam.gserviceaccount.com"
238
+ local start=$(date +%s) delay=2
239
+
240
+ echo "⏳ waiting for SA IAM binding ${role} → ${member} on ${svcAcctEmail} (timeout ${timeout}s)..." >&2
241
+ while true; do
242
+ local found
243
+ found="$(gcloud iam service-accounts get-iam-policy "${svcAcctEmail}" \
244
+ --flatten="bindings[].members" \
245
+ --filter="bindings.role=${role} AND bindings.members=${member}" \
246
+ --format="value(bindings.role)" 2> "$DEVNULL")"
247
+ if [[ -n "$found" ]]; then
248
+ echo "✅ SA IAM binding active: ${role} → ${member}" >&2
249
+ return 0
250
+ fi
251
+ if (( $(date +%s) - start >= timeout )); then
252
+ echo "❌ timed out waiting for SA IAM binding ${role} → ${member}" >&2
253
+ return 1
254
+ fi
255
+ sleep "$delay"; (( delay = delay < 20 ? delay * 2 : 20 ))
256
+ done
257
+ }
258
+
232
259
  function removeHelmRepo(){
233
260
  [ ! -z "$SKIP_RM_HELM_REPO" ] && return
234
261
  helm repo remove $1 &> $DEVNULL
@@ -26,34 +26,33 @@ function installCnpgOperatorEnvironment() {
26
26
  #
27
27
  # kubectl delete serviceaccounts -n $CNPG_NAMESPACE $CNPG_SVC_ACCT &> $DEVNULL
28
28
  # gcloud --quiet iam service-accounts delete $CNPG_SVC_EMAIL --project $GCP_PROJECT_ID&> $DEVNULL
29
- kubectl describe serviceaccounts -n $CNPG_NAMESPACE $CNPG_SVC_ACCT &> $DEVNULL
29
+
30
+ createNamespaceIfNeeded $CNPG_NAMESPACE
31
+
32
+ # Guard against accidental SA deletion on re-runs. Check the GCP SA (not the
33
+ # k8s SA) — consistent with ESO bootstrap pattern and correct for new clusters
34
+ # where the GCP SA exists but the k8s SA does not yet.
35
+ gcloud iam service-accounts describe $CNPG_SVC_EMAIL --project $GCP_PROJECT_ID &> $DEVNULL
30
36
  if [ $? -eq 0 ];
31
37
  then
32
38
  cat<<SKIP_CNPG_SA_CREATION
33
39
 
34
- $YELO_WARN The CNPG SA $CNPG_SVC_ACCT already exists
40
+ $YELO_WARN The CNPG SA `color y $CNPG_SVC_ACCT` already exists - skipping creation
35
41
 
36
- Deleting the SA for the purposes of upgrading the operator is going to
37
- wreck someone's day (probably yours) if the desire is to simply upgrade
38
- in place. To force a clean reinstall, delete both the k8s and gcp SA for
39
- CNPG and try again. (see comments in helmup for more info)
42
+ To force a clean reinstall, delete both the GCP and k8s SAs for CNPG and
43
+ re-run helmup cnpg-operator.
40
44
 
41
45
  SKIP_CNPG_SA_CREATION
42
- return
46
+ else
47
+ printf "\nCreating the gcloud `color g $CNPG_SVC_ACCT` service account (SA)\n"
48
+ gcloud iam service-accounts create $CNPG_SVC_ACCT \
49
+ --project "$GCP_PROJECT_ID" \
50
+ --description "CNPG Operands SA" \
51
+ --display-name "CNPG Operands SA" &> $DEVNULL
52
+ exitOnError $? "Failed to create GCP SA `color y $CNPG_SVC_ACCT`"
53
+ waitForSA "$CNPG_SVC_ACCT" "$GCP_PROJECT_ID" 60
43
54
  fi
44
55
 
45
- # Create the operands namespace and annotate to allow redis access
46
- createNamespaceIfNeeded $CNPG_NAMESPACE
47
-
48
- # Create GCP SA and bind policies
49
- printf "\nCreating the gcloud `color g $CNPG_SVC_ACCT` service account (SA)\n"
50
- gcloud iam service-accounts create $CNPG_SVC_ACCT \
51
- --project "$GCP_PROJECT_ID" \
52
- --description "CNPG Operands SA" \
53
- --display-name "CNPG Operands SA" &> $DEVNULL
54
- warnOnError $? "the GCP SA `color y $CNPG_SVC_ACCT` may already exist"
55
- waitForSA "$CNPG_SVC_ACCT" "$GCP_PROJECT_ID" 60
56
-
57
56
  CNPG_OPS_ROLE="cnpg.operands"
58
57
  printf "\nCreating the `color g $CNPG_OPS_ROLE` IAM role\n"
59
58
  ## Attach roles
@@ -136,7 +135,6 @@ driver: pd.csi.storage.gke.io
136
135
  deletionPolicy: Retain
137
136
  EOSNAPSC
138
137
 
139
- sleep 2 # hold up processing for a moment to allow IAM mods to propagate
140
138
  }
141
139
 
142
140
  # this function is a little convoluted in the way it attempts to install the
@@ -184,7 +182,7 @@ CNPG_FETCH_CLEANUP_CRONJOB_YAML
184
182
  --project="$GCP_PROJECT_ID" \
185
183
  --description="Used for cronjob cleanup with Workload Identity" \
186
184
  --display-name="CNPG Cleanup SA" &> $DEVNULL
187
- warnOnError $? "the GCP SA $CNPG_CLEANUP_SA may already exist"
185
+ warnOnError $? "the GCP SA $CNPG_CLEANUP_SA may already exist"
188
186
  waitForSA "$CNPG_CLEANUP_SA" "$GCP_PROJECT_ID" 60
189
187
 
190
188
  gcloud projects add-iam-policy-binding "$GCP_PROJECT_ID" \
@@ -11,6 +11,8 @@ function installEsoEnvironment() {
11
11
  ESO_SA="eso-sa"
12
12
  ESO_SA_EMAIL="$ESO_SA@$GCP_PROJECT_ID.iam.gserviceaccount.com"
13
13
 
14
+ createNamespaceIfNeeded $ESO_NAMESPACE
15
+
14
16
  # Guard against accidental SA deletion on re-runs (see cnpg-operator for war story)
15
17
  gcloud iam service-accounts describe $ESO_SA_EMAIL --project $GCP_PROJECT_ID &> $DEVNULL
16
18
  if [ $? -eq 0 ];
@@ -50,8 +52,8 @@ SKIP_ESO_SA_CREATION
50
52
  --member "serviceAccount:$GCP_PROJECT_ID.svc.id.goog[$ESO_NAMESPACE/external-secrets]" \
51
53
  --role roles/iam.workloadIdentityUser $ESO_SA_EMAIL
52
54
  warnOnError $? "gcloud workload identity binding may have failed"
53
-
54
- createNamespaceIfNeeded $ESO_NAMESPACE
55
+ waitForSAIAM "$ESO_SA" "$GCP_PROJECT_ID" "roles/iam.workloadIdentityUser" \
56
+ "serviceAccount:$GCP_PROJECT_ID.svc.id.goog[$ESO_NAMESPACE/external-secrets]" 60
55
57
  }
56
58
 
57
59
  installEsoEnvironment
@@ -0,0 +1,105 @@
1
+ # CRD Upgrades — kube-prometheus-stack
2
+
3
+ ## Why this exists
4
+
5
+ Helm can install CustomResourceDefinitions (CRDs) but will not upgrade them
6
+ when you bump chart versions. This chart ships a CRD upgrade job that uses
7
+ server-side apply (SSA) to reconcile CRDs to the versions bundled with the
8
+ chart.
9
+
10
+ ## Default: disabled
11
+
12
+ The CRD upgrade job is disabled by default (`crds.enabled: false`) because it
13
+ requires cluster-admin level permissions to run. Specifically, it creates and
14
+ deletes ClusterRole and ClusterRoleBinding resources as pre-upgrade Helm hooks,
15
+ which requires `container.clusterRoles.delete` in GCP IAM. Only enable it when
16
+ explicitly bumping the chart version, and only a devops engineer should run
17
+ `helmup prom-operator` when it is enabled.
18
+
19
+ ## Settings
20
+
21
+ **`crds.enabled`** — controls whether the chart manages CRDs at all. When
22
+ `false`, the CRD upgrade job and its associated hook resources are not rendered.
23
+ Default: `false`.
24
+
25
+ **`crds.upgradeJob.enabled`** — controls whether the SSA upgrade job hook runs.
26
+ Must be `true` for CRDs to be reconciled on upgrade. Default: `false`.
27
+
28
+ **`crds.upgradeJob.forceConflicts`** — adds `--force-conflicts` to the SSA
29
+ apply, overriding fields owned by another field manager. Use only for a one-time
30
+ conflict resolution. Revert to `false` immediately after. Default: `false`.
31
+
32
+ ## Permissions requirement
33
+
34
+ The upgrade job runs as a pair of Helm pre-upgrade hooks that create a
35
+ ClusterRole and ClusterRoleBinding. Helm's `before-hook-creation` delete policy
36
+ causes it to attempt deletion of these resources before creating them — even if
37
+ they don't yet exist in the cluster. The GCP IAM permission check fires before
38
+ the existence check, so a 403 is returned for users without
39
+ `container.clusterRoles.delete` regardless of whether the resources are present.
40
+
41
+ The `admission-webhooks/job-patch` hooks have the same requirement and are
42
+ always present, making `helmup prom-operator` a full-devops-only operation
43
+ regardless of the CRD upgrade setting.
44
+
45
+ ## Hook lifecycle
46
+
47
+ The ClusterRole and ClusterRoleBinding created by the upgrade job are ephemeral.
48
+ They are deleted automatically after the job succeeds via the
49
+ `hook-delete-policy: hook-succeeded` annotation. You will not see them in
50
+ `kubectl get clusterrole` after a successful run.
51
+
52
+ ## Switching from enabled to disabled
53
+
54
+ If `crds.enabled` was previously `true` and a successful upgrade ran, the CRD
55
+ hook resources are recorded in the Helm release manifest even though they no
56
+ longer exist in the cluster. Switching to `false` and running `helmup` will
57
+ cause Helm to attempt to delete those orphaned hook resources from the previous
58
+ release — again requiring cluster-admin permissions for that one transition run.
59
+
60
+ To verify what hooks are currently stored in the release:
61
+ ```bash
62
+ helm get hooks prometheus-stack -n prometheus | grep ^"# Source"
63
+ ```
64
+
65
+ After a devops engineer runs `helmup prom-operator` with `crds.enabled: false`,
66
+ the hooks will be cleared from the release manifest and subsequent runs will not
67
+ require cluster-admin permissions (beyond the always-present admission-webhook
68
+ hooks).
69
+
70
+ ## Runbook — bumping the chart version
71
+
72
+ 1. **Preflight** — confirm current CRD state:
73
+ ```bash
74
+ kubectl get crd | grep monitoring.coreos.com
75
+ kubectl apply --server-side --dry-run=server -f <crd-dir/>
76
+ ```
77
+
78
+ 2. **Enable** — set both flags in `prometheus-stack.yaml.ovh`:
79
+ ```yaml
80
+ crds:
81
+ enabled: true
82
+ upgradeJob:
83
+ enabled: true
84
+ forceConflicts: false
85
+ ```
86
+
87
+ 3. **Run** — as a devops engineer:
88
+ ```bash
89
+ helmup prom-operator
90
+ ```
91
+
92
+ 4. **If the job fails with field-manager conflicts:**
93
+ - Confirm no other source manages these CRDs
94
+ - Temporarily set `forceConflicts: true` for this run only
95
+ - Revert to `false` immediately after
96
+
97
+ 5. **Post-check:**
98
+ ```bash
99
+ kubectl get crd | grep monitoring.coreos.com
100
+ # verify CRDs show Established: True
101
+ # verify operator pod is healthy
102
+ # verify alerts and rules are normal
103
+ ```
104
+
105
+ 6. **Disable** — revert both flags to `false` before committing.
@@ -17,11 +17,14 @@ function installStackdriverExporterEnvironment() {
17
17
 
18
18
  createNamespaceIfNeeded $SDEXP_NS
19
19
 
20
- # guarantee any previous remnants of the exporter are gone
21
- printf "\n*** Removing the previous $SDEXP_SA installation...\n"
22
- helm uninstall -n $SDEXP_NS "stackdriver-exporter" &> $DEVNULL
23
- kubectl delete serviceaccounts -n $SDEXP_NS $SDEXP_SA &> $DEVNULL
24
- printf "*** Deleting the gcloud SA $SDEXP_EM\n"
20
+ # used to remove this to avoid weird behavior when attempting to reboot
21
+ # the service with udated configs - no longer doing this (for now)
22
+ #
23
+ # guarantee any previous remnants of the exporter are gone
24
+ # printf "\n*** Removing the previous $SDEXP_SA installation...\n"
25
+ # helm uninstall -n $SDEXP_NS "stackdriver-exporter" &> $DEVNULL
26
+ # kubectl delete serviceaccounts -n $SDEXP_NS $SDEXP_SA &> $DEVNULL
27
+ # printf "*** Deleting the gcloud SA $SDEXP_EM\n"
25
28
  # gcloud --quiet iam service-accounts delete $SDEXP_EM \
26
29
  # --project $GCP_PROJECT_ID &> $DEVNULL
27
30
 
@@ -58,18 +61,19 @@ function createGrafanaOAuthSecret() {
58
61
  printf "\nCreating placeholder `color g grafana-google-oauth` secret in prometheus namespace\n"
59
62
  kubectl create secret generic grafana-google-oauth \
60
63
  --namespace prometheus \
61
- --from-literal=GF_AUTH_GOOGLE_CLIENT_ID='' \
62
- --from-literal=GF_AUTH_GOOGLE_CLIENT_SECRET=''
64
+ --from-literal=GF_AUTH_GOOGLE_CLIENT_ID='bootstrap id' \
65
+ --from-literal=GF_AUTH_GOOGLE_CLIENT_SECRET='boostrap secret'
63
66
  warnOnError $? "Failed to create grafana-google-oauth placeholder secret"
64
67
  else
65
68
  printf "\n`color g grafana-google-oauth` secret already exists - skipping\n"
66
69
  fi
67
70
 
68
- # Wire up the ExternalSecret now that ESO is guaranteed to be deployed first
69
- # in the SYSTEM array. This syncs credentials from GCP Secret Manager into the
70
- # grafana-google-oauth secret once the deployment engineer populates them.
71
- showInstalling "Grafana Google OAuth ExternalSecret"
72
- cat<<GRAFANA_OAUTH_SECRET | kubectl apply -f -
71
+ # Wire up the ExternalSecret only if ESO is enabled for this cluster.
72
+ # Set ESO_ENABLED=true in overwhelm.yaml to activate (default: false).
73
+ if [ "${ESO_ENABLED}" = "true" ];
74
+ then
75
+ showInstalling "Grafana Google OAuth ExternalSecret"
76
+ cat<<GRAFANA_OAUTH_SECRET | kubectl apply -f -
73
77
  apiVersion: external-secrets.io/v1
74
78
  kind: ExternalSecret
75
79
  metadata:
@@ -86,11 +90,15 @@ spec:
86
90
  data:
87
91
  - secretKey: GF_AUTH_GOOGLE_CLIENT_ID
88
92
  remoteRef:
89
- key: grafana-google-client-id
93
+ key: GF_AUTH_GOOGLE_CLIENT_ID
90
94
  - secretKey: GF_AUTH_GOOGLE_CLIENT_SECRET
91
95
  remoteRef:
92
- key: grafana-google-client-secret
96
+ key: GF_AUTH_GOOGLE_CLIENT_SECRET
93
97
  GRAFANA_OAUTH_SECRET
98
+ else
99
+ printf "\n`color y '***WARNING:'` ESO_ENABLED is not set - skipping Grafana OAuth ExternalSecret\n"
100
+ printf " Set ESO_ENABLED=true in overwhelm.yaml and re-run helmup prom-operator to wire up the OAuth secret.\n\n"
101
+ fi
94
102
  }
95
103
 
96
104
  installStackdriverExporterEnvironment
@@ -8,7 +8,7 @@ showInstalling "The Prometheus Operator (kube-prometheus-stack)"
8
8
 
9
9
  # https://artifacthub.io/packages/helm/prometheus-community/kube-prometheus-stack
10
10
  OCI_CHART="oci://ghcr.io/prometheus-community/charts/kube-prometheus-stack"
11
- [ -z "$PROMETHEUS_STACK_CHART_VERSION" ] && PROMETHEUS_STACK_CHART_VERSION="82.15.0"
11
+ [ -z "$PROMETHEUS_STACK_CHART_VERSION" ] && PROMETHEUS_STACK_CHART_VERSION="83.7.0"
12
12
  helm upgrade $NS --install prometheus-stack $OCI_CHART \
13
13
  --values prom-operator/prometheus-stack.yaml \
14
14
  --version $PROMETHEUS_STACK_CHART_VERSION $HELM_WHAT
@@ -1,50 +1,13 @@
1
+ #
2
+ # Apparently you must have devops access in order to deploy the prometheus
3
+ # operator since it attempts to create cluster roles during deployment.
4
+ #
1
5
  crds:
2
- # ─────────────────────────────────────────────────────────────────────────────
3
- # CRD MANAGEMENT — kube-prometheus-stack
4
- #
5
- # Why this exists
6
- # Helm can install CustomResourceDefinitions (CRDs) but will not upgrade them
7
- # when you bump chart versions. This chart ships a CRD upgrade job that uses
8
- # server-side apply (SSA) to reconcile CRDs to the versions bundled with the
9
- # chart.
10
- #
11
- # Safe operating model
12
- # ✅ Leave the upgrade job ENABLED if this chart is the sole owner of the
13
- # Prometheus Operator CRDs.
14
- # ⚠️ Keep "forceConflicts" DISABLED unless you hit a specific field-manager
15
- # conflict that you’ve reviewed and want this chart to own.
16
- # ❌ If another source manages CRDs (e.g., a separate CRD chart, GitOps
17
- # bootstrap, platform repo), DISABLE the job to avoid ownership fights.
18
- #
19
- # Settings
20
- # enabled: runs the SSA job on chart upgrade to reconcile CRDs.
21
- # Recommended: true if chart owns the CRDs; false if
22
- # another tool owns them.
23
- #
24
- # forceConflicts: adds `--force-conflicts` to SSA, overriding fields owned by
25
- # another controller. Use only for a one-time conflict
26
- # resolution. Can overwrite annotations and mask real
27
- # incompatibilities if left true.
28
- #
29
- # Recommended defaults
30
- # enabled: true
31
- # forceConflicts: false
32
- #
33
- # Mini-runbook
34
- # 1) Preflight:
35
- # kubectl get crd | grep monitoring.coreos.com
36
- # kubectl apply --server-side --dry-run=server -f <crd-dir/>
37
- # 2) Upgrade with enabled: true, forceConflicts: false.
38
- # 3) If job fails with conflicts:
39
- # - confirm no other source manages these CRDs
40
- # - temporarily set forceConflicts: true for this upgrade only
41
- # - revert to false afterwards
42
- # 4) Post-check: CRDs Established, operator healthy, alerts/rules normal
43
- # ─────────────────────────────────────────────────────────────────────────────
6
+ # See README-CRD-UPGRADES.md — disabled by default, full-devops only
44
7
  enabled: true
45
8
  upgradeJob:
46
9
  enabled: true
47
- forceConflicts: false # See README-CRD-UPGRADES.md
10
+ forceConflicts: false
48
11
 
49
12
  kubeControllerManager:
50
13
  enabled: false
@@ -186,7 +149,7 @@ grafana:
186
149
  envFromSecret: grafana-google-oauth
187
150
  env:
188
151
  GF_SERVER_ROOT_URL: https://${PROJECT_NAME}-monitoring.${HOST}.com
189
- GF_AUTH_GOOGLE_ENABLED: "true"
152
+ GF_AUTH_GOOGLE_ENABLED: "${ESO_ENABLED}"
190
153
  GF_AUTH_GOOGLE_SCOPES: "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email"
191
154
  GF_AUTH_GOOGLE_AUTH_URL: "https://accounts.google.com/o/oauth2/auth"
192
155
  GF_AUTH_GOOGLE_TOKEN_URL: "https://accounts.google.com/o/oauth2/token"
@@ -284,7 +247,7 @@ alertmanager:
284
247
  {{- end }}
285
248
 
286
249
  {{- if .Labels.pod }}
287
- *Pod Link:* *<https://console.cloud.google.com/kubernetes/pod/${GCE_REGION}/${CLUSTER_NAME}/{{ .Labels.namespace }}/{{ .Labels.pod }}?project=${PROJECT_NAME}|`{{ .Labels.pod }}`>*
250
+ *Pod Link:* *<https://console.cloud.google.com/kubernetes/pod/${GCE_REGION}/${CLUSTER_NAME}/{{ .Labels.namespace }}/{{ .Labels.pod }}?project=${PROJECT_ID}|`{{ .Labels.pod }}`>*
288
251
  {{- end }}
289
252
 
290
253
  *Status:* `{{ .Status }}` | *Severity:* `{{ .Labels.severity }}` {{- if .Labels.container }} *Container:* `{{ .Labels.container }}` {{- end }}
@@ -5,7 +5,7 @@
5
5
  fullnameOverride: "prometheus-stack-stackdriver-metrics"
6
6
 
7
7
  stackdriver:
8
- projectId: "${PROJECT_NAME}"
8
+ projectId: "${PROJECT_ID}"
9
9
  metrics:
10
10
  typePrefixes: >
11
11
  agent.googleapis.com/cpu/utilization,
@@ -86,6 +86,8 @@ function installVeleroEnvironment() {
86
86
  --role roles/iam.workloadIdentityUser \
87
87
  $SERVICE_ACCOUNT_EMAIL
88
88
  warnOnError $? "gcloud workload identity binding may have failed"
89
+ waitForSAIAM "velero" "$GCP_PROJECT_ID" "roles/iam.workloadIdentityUser" \
90
+ "serviceAccount:$GCP_PROJECT_ID.svc.id.goog[velero/velero]" 60
89
91
 
90
92
  printf "\nCreate and annotate the k8s SA\n"
91
93
  kubectl create serviceaccount velero --namespace velero
package/src/helmup.sh CHANGED
@@ -135,7 +135,7 @@ SYSTEM=(
135
135
  cnpg-operator
136
136
  preemptible-killer
137
137
  zombie-killer
138
- reflector
138
+ # reflector
139
139
  reloader
140
140
  velero
141
141
  cnpg-db-psql-stack
@@ -218,8 +218,8 @@ WORKLOAD_ID
218
218
  --member "serviceAccount:$GCP_PROJECT_ID.svc.id.goog[${NAMESPACE}/${BOUND_SVC_ACCT}]" \
219
219
  --role roles/iam.workloadIdentityUser $SVC_ACCT_EMAIL
220
220
  warnOnError $? "gcloud workload identity binding may have failed"
221
-
222
- sleep 2 # give the policy a chance to propagate
221
+ waitForSAIAM "$SVC_ACCT" "$GCP_PROJECT_ID" "roles/iam.workloadIdentityUser" \
222
+ "serviceAccount:$GCP_PROJECT_ID.svc.id.goog[${NAMESPACE}/${BOUND_SVC_ACCT}]" 60
223
223
 
224
224
  # Verify the Kubernetes SA and create it if necessary
225
225
  printf "\nChecking for the `color g $NAMESPACE/$SVC_ACCT` k8s SA\n"
@@ -821,6 +821,10 @@ export GCP_PROJECT_ID="$(getProjectIdFromK8sContext)"
821
821
  # Same for the region, but not as prevalent
822
822
  export GCE_REGION=`overwhelm -k GCE_REGION`
823
823
 
824
+ # TODO: Temporary, until ESO is widely deployed, then the ESO_ENABLED logic
825
+ # can be removed from the configs entirely.
826
+ export ESO_ENABLED=`overwhelm -k ESO_ENABLED`
827
+
824
828
  doInstall "${SERVICES[@]}"
825
829
 
826
830
  displayBanner
@@ -17,7 +17,7 @@ const hbsContext = {
17
17
  hbsPartOf : '',
18
18
  hbsServicePreemptible : true,
19
19
  hbsRedisEnabled : true,
20
- hbsAutoScalingEnabled : true
20
+ hbsAutoscalingEnabled : true,
21
21
  }
22
22
 
23
23
  const PRESERVE_SECTIONS = new Set( [
@@ -0,0 +1 @@
1
+ {{ include "leverege.ingressroute" . }}
@@ -0,0 +1,13 @@
1
+ {
2
+ "type": "managed",
3
+ "name": "NPMRC",
4
+ "source": "leverege-registry:DEPRECATED_NPMRC",
5
+ "labels": {
6
+ "env-type": "string"
7
+ },
8
+ "annotations": {
9
+ "description": "a deprecated npmrc key",
10
+ "owner": "platform-team",
11
+ "source": "service-man"
12
+ }
13
+ }
@@ -1,287 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * DEPRECATED - DO NOT MODIFY
4
- */
5
- import fs from 'node:fs'
6
-
7
- import toml from 'toml'
8
- import chalk from 'chalk'
9
-
10
- import {
11
- debug, log, warning,
12
- errorExit,
13
- getGitBranchAndUpstream,
14
- gitRepoIsDirty,
15
- parseHelmChart,
16
- proceed,
17
- shellCmd } from './Utils.mjs'
18
- import Docker from './DockerPy.mjs'
19
-
20
- // refresh-npm-token does not throw so no need to try, but it emits in debug
21
- // const refreshErr = await shellCmd( 'refresh-npm-token' )
22
- // if ( refreshErr && !process.env.BUILD_TOOLS_DEBUG ) {
23
- // log( refreshErr ) // most likely the token refreshed message
24
- // }
25
-
26
- warning( 'docker-to-registry-py has been DEPRECATED - use docker-to-registry' )
27
-
28
- const options = {}
29
- let imageVersion = null
30
- // Expected to be invoked like docker-to-registry-py v1.2.3
31
- for ( let n = 2; n < process.argv.length; n++ ) {
32
- if ( process.argv[n].startsWith( '-' ) ) {
33
- const str = process.argv[n].slice( 1 )
34
- if ( str.indexOf( '=' ) > 0 ) {
35
- const [ key, value ] = str.split( '=' )
36
- options[key] = value
37
- } else {
38
- options[str] = true
39
- }
40
- } else {
41
- imageVersion = process.argv[n]
42
- }
43
- }
44
- if ( !imageVersion ) {
45
- errorExit( '***Error: docker-to-registry-py requires an image version' )
46
- }
47
-
48
- // may use guide-me or guideme to ask for update guidance
49
- const giveGuidance = imageVersion.match( /^guide-*me$/ ) !== null
50
-
51
- const willGitTag = imageVersion.match( /^v\d+\.\d+\.\d+$/ )
52
- const tagInfo = willGitTag ?
53
- chalk.yellow.bold( 'will be git tagged' ) :
54
- chalk.red( 'BETA RELEASE WILL NOT BE GIT TAGGED' )
55
-
56
- const repoIsDirty = await gitRepoIsDirty()
57
-
58
- if ( willGitTag && repoIsDirty ) {
59
- log( `
60
- ${chalk.red.bold( '***ERROR: attempting to tag a non-beta dirty git repository' )}
61
-
62
- You are attempting to create a tagged release image for pushing to the
63
- artifact registry, but there are locally modified files. This is not
64
- allowed since the applied tag will not be relevant to the image version
65
- due to the pending commits.
66
-
67
- Available options for proceeding:
68
-
69
- ${chalk.green.bold( '1) cleanly commit all local mods assuming relevance' )}
70
- ${chalk.yellow( '2) eliminate unwanted local modifications' )}
71
- ${chalk.red( '3) stash anything that is irrelevant to this release' )}
72
-
73
- ` )
74
- process.exit( 1 )
75
- }
76
-
77
- if ( !fs.existsSync( './helm' ) ) {
78
- log( `
79
- ${chalk.red.bold( '***Error: docker-to-registry-py requires a helm chart directory' )}
80
-
81
- The docker-to-registry-py script expects to run in the root directory of a k8s
82
- service, which requires a helm chart directory. It also expects a docker
83
- directory but will build that if it does not exist.
84
-
85
- ` )
86
- process.exit( 1 )
87
- }
88
-
89
- const tomlStr = fs.readFileSync( './pyproject.toml' )
90
- const pyproject = toml.parse( tomlStr )
91
- const repoDescr = {
92
- artifactProject : pyproject.leverege.project || 'leverege-registry',
93
- containerName : pyproject.project.name,
94
- packageVersion : `v${pyproject.project.version}`,
95
- artifactRegistry : pyproject.leverege.registry || 'us-docker.pkg.dev/leverege-registry/stack',
96
- registryFolder : `${pyproject.leverege['registry-folder']}/images/${pyproject.project.name}`,
97
- imageBase : pyproject.leverege['image-base'],
98
- helmChart : await parseHelmChart(),
99
- }
100
-
101
- debug( { repoDescr }, '<==The Repo Description' )
102
-
103
- const dockerInfo = await Docker.generateDockerfile( {
104
- regvers : repoDescr.packageVersion,
105
- imageBase : repoDescr.imageBase,
106
- } )
107
-
108
- debug( { dockerInfo }, '<==The Docker Info' )
109
-
110
- const {
111
- artifactProject,
112
- artifactRegistry,
113
- packageVersion,
114
- containerName,
115
- helmChart,
116
- } = repoDescr
117
-
118
- if ( giveGuidance ) {
119
- await Docker.validateCloudBuildBucket( artifactProject )
120
- }
121
-
122
- const registryFolder = `${artifactRegistry}/images/${containerName}`
123
-
124
- // Update the dependencies...
125
- // log( chalk.green.bold( 'Updating dependencies and workspace...' ) )
126
- // await shellCmd( 'npm install', { stdio : 'inherit' } )
127
-
128
- if ( giveGuidance ) {
129
- await Docker.repoCleanup() // adjusts gitignore files and removes cruft
130
- log( `
131
-
132
-
133
-
134
- ${chalk.green.bold( '-------------------- Potential Helm Chart Mods --------------------' )}
135
-
136
- Moving to the new artifact-registry for docker image storage may also require
137
- helm chart changes depending on how old the current charts are. Charts that
138
- contain helm/values.yaml files resembling this:
139
-
140
- ${chalk.yellow.bold( `serviceConfig:
141
- VERSION: v1.2.3
142
- PREEMPTIBLE: true` )}
143
-
144
- are pre-ignition era charts and should be replaced with the latest helm chart
145
- templates available from ignition. Either dive in or ask devops for a hand
146
- when converting these legacy / deprecated charts.
147
-
148
-
149
- More recently updated helm charts that have already started the migration to
150
- the new approach may already have registry entries like this:
151
-
152
- ${chalk.yellow.bold( `image:
153
- registry: gcr.io/leverege-docker-images
154
- tag: ""` )}
155
-
156
- The above registry statement references the deprecated container registry and
157
- must be adjusted accordingly to resemble:
158
-
159
- ${chalk.green.bold( 'registry: us-docker.pkg.dev/leverege-registry/<registry folder>/images' )}
160
-
161
- There may also be a corresponding modification needed in the helm template
162
- deployment.yaml file in the container image spec:
163
-
164
- ${chalk.green.bold( 'image: {{ .Values.image.registry }}/{{ .Chart.Name }}:{{ default .Chart.AppVersion .Values.image.tag }}' )}
165
-
166
-
167
- ${chalk.magenta.bold( `Upgrading all service charts to the latest ignition template chart structure
168
- is the preferred approach to making the transition to the artifact registry.` )}
169
-
170
- ` )
171
- log( chalk.green.bold( '*** docker-to-registry-py guidance complete - ready for dockerization ***' ) )
172
- process.exit( 0 )
173
- }
174
-
175
- // do chart checks too
176
- let chart
177
- if ( options?.helmChecks !== 'false' ) {
178
- chart = helmChart?.yaml['Chart.yaml']
179
- const values = helmChart?.yaml['values.yaml']
180
- const expectedChartRegistry = `${artifactRegistry}/images`
181
-
182
- if ( expectedChartRegistry !== values.image?.registry ) {
183
- log( `
184
- ${chalk.red.bold( '***Error: mismatched package.json registry and helm/values.yaml' )}
185
-
186
- The registry specified in the package.json leverege stanza does not line up
187
- with the image registry in helm/values.yaml. The naming convention expects
188
- the '/images' suffix to be added to the package.json registry string and then
189
- stored as the image.registry in the helm/values.yaml file.
190
-
191
- Current settings:
192
- package.json registry => ${chalk.yellow.bold( artifactRegistry )}
193
- values.yaml registry => ${chalk.red.bold( values.image?.registry )}
194
-
195
- Expected settings:
196
- values.yaml registry => ${chalk.green.bold( expectedChartRegistry )}
197
- ` )
198
-
199
- if ( !values.image ) {
200
- log( `
201
- ${chalk.yellow.bold( '***DEPRECATED: legacy helm charts detected' )}
202
-
203
- The helm chart structure appears to be based on the pre-ignition helm chart
204
- layouts. The charts must be upgraded before docker-to-registry-py can complete
205
- its job.
206
-
207
- ` )
208
- }
209
-
210
- process.exit( 1 )
211
- }
212
- }
213
-
214
- // Give the summary and the user a chance to proceed or not
215
- log( `
216
- ${chalk.green.bold( 'Build Information:' )}
217
- Container: ${chalk.green.bold( containerName )}
218
- Version: ${chalk.green.bold( imageVersion )} ${tagInfo}
219
- Registry: ${chalk.green.bold( artifactRegistry )}
220
- Image Folder: ${chalk.yellow.bold( registryFolder )}
221
-
222
- ${chalk.green.bold( 'Docker Information:' )}
223
- NodeImage: ${chalk.green.bold( dockerInfo.imageBase || `node:${dockerInfo.nodeimage}` )}
224
- Run User: ${chalk.green.bold( dockerInfo.runuser )}
225
- Previous: ${chalk.yellow.bold( dockerInfo.previousBuild )}
226
- DateStamp: ${chalk.green.bold( dockerInfo.date )}
227
- ` )
228
-
229
- if ( imageVersion !== packageVersion ) {
230
- log( `
231
- ${chalk.yellow.bold( '***WARNING: specified version does not match project version' )}
232
- pyproject.toml => ${chalk.green.bold( packageVersion )}
233
- specified => ${chalk.red.bold( imageVersion )}
234
- ` )
235
-
236
- if ( willGitTag ) {
237
- log( chalk.red.bold( '... and you are attempting to release so NOPE!\n' ) )
238
- process.exit( 1 )
239
- }
240
- }
241
-
242
- const repoInfo = await getGitBranchAndUpstream()
243
-
244
- if ( willGitTag && !repoInfo.upstream ) {
245
- log( `
246
- ${chalk.red.bold( '***ERROR: the current branch must have an upstream' )}
247
-
248
- You are attempting to create a tagged release image for pushing to the
249
- container registry, but the current branch does not have an upstream to
250
- push to. This is not allowed since the applied tag will be stranded here
251
- in your local repository, which is what we are trying to avoid.
252
-
253
- Available options for proceeding:` )
254
- log( chalk.green.bold( `
255
- 1) set an upstream for this branch via:
256
- git push --set-upstream origin ${repoInfo.branch}` ) )
257
- log( chalk.yellow.bold( `
258
- 2) rebase, squash and merge onto a branch with an upstream` ) )
259
-
260
- process.exit( 1 )
261
- }
262
-
263
- if ( willGitTag ) {
264
- if ( chart.appVersion !== imageVersion ) {
265
- log( `
266
- ${chalk.yellow.bold( '***WARNING: the helm/Chart.yaml appVersion does not align with the build version' )}
267
- chart appVersion => ${chalk.yellow.bold( chart.appVersion )}
268
- build version => ${chalk.green.bold( imageVersion )}
269
- ` )
270
- }
271
- }
272
-
273
- await proceed()
274
-
275
- log( chalk.green.bold( 'Building the Docker Image...' ) )
276
- await Docker.buildContainerImage( { ...repoDescr, options, imageVersion } )
277
- log( chalk.blue.bold( 'Done Building the Docker Image...' ) )
278
-
279
- if ( willGitTag ) {
280
- const tagDescription = `docker_${imageVersion}`
281
- const fullImageTag = repoDescr.isMonoRepo ? `${repoDescr.containerName}/${imageVersion}` : imageVersion
282
- log( chalk.green.bold( `Tagging and Pushing ${fullImageTag}\n` ) )
283
- await shellCmd( `git tag -f ${fullImageTag} -m ${tagDescription}` )
284
- await shellCmd( 'git push --follow-tags' )
285
- } else {
286
- log( chalk.yellow.bold( '\n*** Skipped git tagging - beta release' ) )
287
- }