@leverege/build-tools 2.98.1 → 2.99.1

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.
@@ -18,6 +18,16 @@
18
18
  },
19
19
  "outputCapture": "std"
20
20
  },
21
+ {
22
+ "name": "overwhelm tst-dense",
23
+ "type": "node",
24
+ "request": "launch",
25
+ "program": "${workspaceFolder}/src/overwhelm.mjs",
26
+ "args": [],
27
+ "cwd": "/Users/john/Work/leverege/k8s/tst-dense",
28
+ "runtimeExecutable": "node",
29
+ "console": "integratedTerminal"
30
+ },
21
31
  {
22
32
  "name": "push-my-chart rsrc-srvr",
23
33
  "type": "node",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leverege/build-tools",
3
- "version": "2.98.1",
3
+ "version": "2.99.1",
4
4
  "description": "A collection of build / support tools for Leverege developers",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -92,7 +92,7 @@
92
92
  "googleapis": "^171.4.0",
93
93
  "handlebars": "^4.7.8",
94
94
  "ignore": "^7.0.5",
95
- "inquirer": "^13.3.0",
95
+ "inquirer": "^13.3.2",
96
96
  "js-yaml": "^4.1.1",
97
97
  "jsdoc": "^4.0.5",
98
98
  "ms": "^2.1.3",
package/src/Docker.mjs CHANGED
@@ -24,8 +24,8 @@ const DIRNAME = path.dirname( url.fileURLToPath( import.meta.url ) )
24
24
  //
25
25
  // See the latest docker images here => https://hub.docker.com/_/node
26
26
  //
27
- const dockerfileNodeVersion = process.env.DOCKER_BUILD_NODE_VERSION || '24.12.0-alpine3.23'
28
- const dockerfileNpmVersion = process.env.DOCKER_BUILD_NPM_VERSION || '11.6.0'
27
+ const dockerfileNodeVersion = process.env.DOCKER_BUILD_NODE_VERSION || '24.14.0-alpine3.23'
28
+ const dockerfileNpmVersion = process.env.DOCKER_BUILD_NPM_VERSION || '11.9.0'
29
29
 
30
30
  // The contents of these variables were initially located in files that live in
31
31
  // the build-tools repository, but it just became simpler to pull the contents
package/src/bash-funcs CHANGED
@@ -5,14 +5,22 @@
5
5
  # and can now be easily added to a script via bash sourcing:
6
6
  # . `build-tools --bashfun`
7
7
 
8
+ # If the script is being run in an interactive terminal, we want to make sure to
9
+ # reset the terminal settings on exit. This is especially important if the script
10
+ # is killed while running a command that changes the terminal settings (like stty raw).
11
+ if [[ -t 0 ]]; then
12
+ STTY_SAVE=$(stty -g)
13
+ trap 'stty "$STTY_SAVE"' EXIT
14
+ fi
15
+
8
16
  # Typically /dev/null is used to redirect the noise but sometimes we need to
9
17
  # see exactly what certain commands are complaining about. Running any of the
10
18
  # build-tools with BUILD_TOOLS_DEBUG=1 will redirect the noise to stdout.
11
19
  DEVNULL="/dev/null"
12
20
  if [[ -n "${BUILD_TOOLS_DEBUG:-}" ]];
13
21
  then
14
- DEVNULL="/dev/stdout"
15
- printf "\n***BUILD_TOOLS_DEBUG DEVNULL=>$DEVNULL\n"
22
+ DEVNULL="/dev/stderr"
23
+ printf "\n***BUILD_TOOLS_DEBUG DEVNULL=>$DEVNULL\n" >&2
16
24
  fi
17
25
 
18
26
  GITTOP=`git rev-parse --show-toplevel`
@@ -35,7 +43,7 @@ YELO_WARN="`color y '***WARNING:'`"
35
43
  GREEN_INFO=`color g '***INFO:'`
36
44
 
37
45
  function clearScreen() {
38
- [ "$BUILD_TOOLS_DEBUG" != "1" ] && clear
46
+ [[ -z "${BUILD_TOOLS_DEBUG:-}" ]] && clear
39
47
  }
40
48
 
41
49
  function clearlyWarn() {
@@ -71,7 +79,7 @@ function exitOnError() {
71
79
 
72
80
  function yesOrSkipToContinue() {
73
81
  printf "\n Enter \"`color g yes`\" ${1}, \"`color y skip`\" to skip this step, or anything else to exit.\n\n"
74
- read ANS
82
+ read -e ANS
75
83
  [ "$ANS" == 'yes' ] && return 0
76
84
  [ "$ANS" == 'skip' ] && return 2
77
85
  exit 1
@@ -79,12 +87,12 @@ function yesOrSkipToContinue() {
79
87
 
80
88
  function yesToContinue() {
81
89
  printf "\n Enter \"`color g yes`\" ${1}, or anything else to exit.\n\n"
82
- read ANS
90
+ read -e ANS
83
91
  [ "$ANS" != 'yes' ] && exit 1
84
92
  }
85
93
 
86
94
  function proceedOnEnter() {
87
- printf " Hit `color g return` to proceed\n\n" && read ANS
95
+ printf " Hit `color g return` to proceed\n\n" && read -e ANS
88
96
  }
89
97
 
90
98
  function setOrUnset() {
@@ -109,13 +117,13 @@ function getManagedSecret() {
109
117
  printf "Returned =>[$SECRET]\n\n"
110
118
  exit 1
111
119
  fi
112
- echo $SECRET
120
+ echo "$SECRET"
113
121
  }
114
122
 
115
123
  function getProjectIdFromK8sContext() {
116
124
  local currContext=`kubectl config current-context`
117
125
 
118
- IFS='_'
126
+ local IFS='_'
119
127
  read -ra ADDR <<< "$currContext"
120
128
 
121
129
  echo ${ADDR[1]} # project id is the second string split by _
@@ -273,7 +281,7 @@ function ifPluggedIn() {
273
281
  local PLUGIN=
274
282
  HELMUP="helm upgrade --install $SERVICE $CHARTLOC -f $SERVICE/values.yaml $CHARTVER $HELM_WHAT"
275
283
  case "$INVOKED_AS" in
276
- "helmup"|"helmwhat"|"helmcycle" )
284
+ "helmup"|"helmwhat"|"helmcycle"|"helminit" )
277
285
  PLUGIN="$1/helmup.plugin"
278
286
  ;;
279
287
  "helmdn" )
@@ -323,4 +331,4 @@ function commandChecker() {
323
331
  done
324
332
  }
325
333
 
326
- commandChecker git helm jq kubectl service-man
334
+ commandChecker git helm jq kubectl
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable */ // for now, we can relax this rule since ...
3
+ /* eslint-disable security/detect-non-literal-fs-filename */
4
+ import fs from 'node:fs'
5
+
6
+ import { program } from 'commander'
7
+ import chalk from 'chalk'
8
+
9
+ import {
10
+ analyzeRepository,
11
+ condir,
12
+ enableDebug,
13
+ errorExit,
14
+ log,
15
+ } from '../Utils.mjs'
16
+
17
+ program
18
+ .name( 'circle-orb' )
19
+ .description( 'updates a .circle/circle.yml to use the leverge orb' )
20
+ .option( '--debug', 'Enable debug logging - use BUILD_TOOLS_DEBUG=1 for global' )
21
+ .parse()
22
+
23
+ const options = program.opts()
24
+ if ( options.debug ) {
25
+ enableDebug() // enables debugging in the Utils functions
26
+ }
27
+
28
+ const repo = await analyzeRepository()
29
+ if ( !repo.isGitRepo ) {
30
+ errorExit( '***ERROR: This command must be run inside a git repository - run "git init" to proceed' )
31
+ }
32
+ const Container = repo.containerName
33
+ const chartwright = new Chartwright( { Container, debug : options.debug } )
34
+
35
+ // If there isn't an existing helm chart then we just bootstrap the new chart structure
36
+ // from the current helm template and we're done. This will most likely be the case after
37
+ // a new service has been bootstrapped with ignition.
38
+ if ( !repo.helmChart ) {
39
+ await chartwright.bootstrap( { Container } )
40
+ process.exit( 0 )
41
+ }
42
+
43
+ // Safety First: if there is already an older helm chart, we don't want to overwrite it - we
44
+ // want the user to review / intervene before proceeding.
45
+ const packageRoot = repo.currentDir
46
+ if ( fs.existsSync( `${packageRoot}/helm-old` ) ) {
47
+ errorExit( '***ERROR: An old helm chart structure already exists - cannot proceed' )
48
+ }
49
+
50
+ const {
51
+ Chart,
52
+ Values,
53
+ valuesText : ValuesText,
54
+ imageRegistry : Registry,
55
+ } = repo.helmChart
@@ -0,0 +1,24 @@
1
+ # See => https://bitbucket.org/leverege/circle-nodejs-ci/src/development/
2
+ version: 2.1
3
+
4
+ orbs:
5
+ leverege: leverege/circle-nodejs-ci@0.3.0
6
+
7
+ workflows:
8
+ build-and-verify:
9
+ jobs:
10
+ - leverege/install-dependencies:
11
+ context: npm
12
+ - leverege/code-analysis:
13
+ requires:
14
+ - leverege/install-dependencies
15
+ - leverege/code-coverage:
16
+ coverage-threshold: 70
17
+ context: leverege-gcp # 👈 attaches the secure secrets access to GCP_SA_KEY_JSON
18
+ enable-redis: false
19
+ cache-config: '{"type":"inMemory"}' # '{"type":"redis"}'
20
+ requires:
21
+ - leverege/install-dependencies
22
+ - leverege/generate-docs:
23
+ requires:
24
+ - leverege/install-dependencies
@@ -12,10 +12,10 @@ config:
12
12
 
13
13
  # CNPG overrides
14
14
  # stock pgsql
15
- MODEL_SQL_HOST: "cnpg-db-psql-stack-rw.cnpg-operands"
16
- PG_MODELS_HOST: "cnpg-db-psql-stack-rw.cnpg-operands"
15
+ MODEL_SQL_HOST: "cnpg-db-psql-stack-pool-rw.cnpg-operands"
16
+ PG_MODELS_HOST: "cnpg-db-psql-stack-pool-rw.cnpg-operands"
17
17
  # timescale
18
- PG_HOST: "cnpg-db-tsdb-basic-r.cnpg-operands"
18
+ PG_HOST: "cnpg-db-tsdb-basic-pool-r.cnpg-operands"
19
19
  # imagine db is legacy - newer setups use timescale as the db name
20
20
  PG_DATABASE: "timescale"
21
21
  PG_DENSE_HISTORY_DATABASE: "timescale"
@@ -10,7 +10,7 @@ config:
10
10
  LOG_CONFIG: '{"type":"pino","level":"warn"}'
11
11
 
12
12
  # CNPG override
13
- SQL_HOST: "cnpg-db-psql-stack-rw.cnpg-operands" # vs postgres-postgresql
13
+ SQL_HOST: "cnpg-db-psql-stack-pool-rw.cnpg-operands" # vs postgres-postgresql
14
14
 
15
15
  serviceMonitor:
16
16
  enabled: true
@@ -118,3 +118,26 @@ spec:
118
118
  method: volumeSnapshot # barmanObjectStore
119
119
  backupOwnerReference: self
120
120
  immediate: true
121
+ ---
122
+ apiVersion: postgresql.cnpg.io/v1
123
+ kind: Pooler
124
+ metadata:
125
+ name: cnpg-db-psql-stack-pool-rw
126
+ namespace: cnpg-operands
127
+ spec:
128
+ cluster:
129
+ name: cnpg-db-psql-stack
130
+
131
+ instances: 2
132
+ type: rw
133
+ pgbouncer:
134
+ poolMode: transaction
135
+ parameters:
136
+ # https://www.pgbouncer.org/config.html#generic-settings
137
+ max_client_conn: "500"
138
+ default_pool_size: "5"
139
+ # https://www.pgbouncer.org/config.html#log-settings
140
+ log_connections: "0"
141
+ log_disconnections: "0"
142
+ monitoring:
143
+ enablePodMonitor: true
@@ -117,3 +117,26 @@ spec:
117
117
  method: volumeSnapshot # barmanObjectStore
118
118
  backupOwnerReference: self
119
119
  immediate: true
120
+ ---
121
+ apiVersion: postgresql.cnpg.io/v1
122
+ kind: Pooler
123
+ metadata:
124
+ name: cnpg-db-tsdb-basic-pool-rw
125
+ namespace: cnpg-operands
126
+ spec:
127
+ cluster:
128
+ name: cnpg-db-tsdb-basic
129
+
130
+ instances: 2
131
+ type: rw
132
+ pgbouncer:
133
+ poolMode: transaction
134
+ parameters:
135
+ # https://www.pgbouncer.org/config.html#generic-settings
136
+ max_client_conn: "500"
137
+ default_pool_size: "5"
138
+ # https://www.pgbouncer.org/config.html#log-settings
139
+ log_connections: "0"
140
+ log_disconnections: "0"
141
+ monitoring:
142
+ enablePodMonitor: true
@@ -8,7 +8,7 @@ config:
8
8
  NETWORK_ID: 'set-me-in-values-local'
9
9
 
10
10
  # CNPG override
11
- SQL_HOST: "cnpg-db-psql-stack-rw.cnpg-operands" # vs postgres-postgresql
11
+ SQL_HOST: "cnpg-db-psql-stack-pool-rw.cnpg-operands" # vs postgres-postgresql
12
12
 
13
13
  serviceMonitor:
14
- enabled: false
14
+ enabled: true
@@ -7,7 +7,7 @@ config:
7
7
  UPLOADER_BUCKET: "${PROJECT_ID}-geotile-server"
8
8
 
9
9
  # CNPG override
10
- SQL_HOST: "cnpg-db-psql-stack-rw.cnpg-operands" # vs postgres-postgresql
10
+ SQL_HOST: "cnpg-db-psql-stack-pool-rw.cnpg-operands" # vs postgres-postgresql
11
11
  SQL_PASSWORD_SECRET: "cnpg-db-psql-stack-postgres-pw"
12
12
  SQL_PASSWORD_KEY: "password"
13
13
 
@@ -44,12 +44,21 @@ crds:
44
44
  enabled: true
45
45
  upgradeJob:
46
46
  enabled: true
47
- forceConflicts: true # See README-CRD-UPGRADES.md
47
+ forceConflicts: false # See README-CRD-UPGRADES.md
48
48
 
49
49
  kubeControllerManager:
50
50
  enabled: false
51
51
  nodeExporter:
52
52
  enabled: false
53
+
54
+ kubelet:
55
+ serviceMonitor:
56
+ metricRelabelings:
57
+ # prober_probe_duration_seconds is high-cardinality (1 histogram per
58
+ # container probe × node) and not referenced by any alerts or dashboards
59
+ - sourceLabels: [__name__]
60
+ regex: prober_probe_duration_seconds.*
61
+ action: drop
53
62
  defaultRules:
54
63
  create: true
55
64
  rules:
@@ -61,7 +70,7 @@ defaultRules:
61
70
  kubeApiserver: true # GPT Keep an eye on API server availability
62
71
  kubeApiserverAvailability: false
63
72
  kubeApiserverSlos: false
64
- kubelet: true # GPT Consider monitoring kubelet status, especially on scaled nodes
73
+ kubelet: false # GKE manages node/kubelet health; no fat nodes so pod limit irrelevant
65
74
  kubeProxy: false
66
75
  kubePrometheusGeneral: false
67
76
  kubePrometheusNodeRecording: false
@@ -109,7 +118,7 @@ prometheus:
109
118
  accessModes: ["ReadWriteOnce"]
110
119
  resources:
111
120
  requests:
112
- storage: 50Gi # Adjust size as needed
121
+ storage: 64Gi # Adjust size as needed
113
122
 
114
123
  # External access to prometheus may be enabled by creating an htpasswd secret
115
124
  # by running this example command:
@@ -90,14 +90,14 @@ spec:
90
90
  summary: "Postgresql high rollback rate on {{ $labels.release }} - {{ $labels.datname }}"
91
91
  description: "Ratio of transactions being aborted compared to committed is > 2 %"
92
92
 
93
- - alert: PostgresqlCommitRateLow
94
- expr: rate(pg_stat_database_xact_commit[1m]) < 10
95
- for: 5m
96
- labels:
97
- severity: error
98
- annotations:
99
- summary: "Postgresql commit rate low on {{ $labels.release }} - {{ $labels.datname }}"
100
- description: "Postgres seems to be processing very few transactions"
93
+ # - alert: PostgresqlCommitRateLow
94
+ # expr: rate(pg_stat_database_xact_commit[1m]) < 10
95
+ # for: 5m
96
+ # labels:
97
+ # severity: error
98
+ # annotations:
99
+ # summary: "Postgresql commit rate low on {{ $labels.release }} - {{ $labels.datname }}"
100
+ # description: "Postgres seems to be processing very few transactions"
101
101
 
102
102
  - alert: PostgresqlLowXidConsumption
103
103
  expr: rate(pg_txid_current[1m]) < 5
@@ -5,7 +5,7 @@
5
5
  fullnameOverride: "prometheus-stack-stackdriver-metrics"
6
6
 
7
7
  stackdriver:
8
- projectId: "${PROJECT_ID}"
8
+ projectId: "${PROJECT_NAME}"
9
9
  metrics:
10
10
  typePrefixes: >
11
11
  agent.googleapis.com/cpu/utilization,
@@ -15,7 +15,7 @@ config:
15
15
  UPLOADER_LOCATION: "${GCE_REGION}"
16
16
 
17
17
  # CNPG override
18
- SQL_HOST: "cnpg-db-psql-stack-rw.cnpg-operands" # vs postgres-postgresql
18
+ SQL_HOST: "cnpg-db-psql-stack-pool-rw.cnpg-operands" # vs postgres-postgresql
19
19
  # SQL_READ_REPLICATION_CONFIG: '[ { "host": "cnpg-db-psql-stack-r.cnpg-operands" } ]'
20
20
  # TRANSACTION_MAX_RETRIES: "5"
21
21
 
@@ -5,7 +5,7 @@ config:
5
5
  LOG_CONFIG: '{"type":"pino","level":"warn"}'
6
6
 
7
7
  # CNPG override
8
- MODELS_SEQUELIZE_HOST: "cnpg-db-psql-stack-rw.cnpg-operands" # vs postgres-postgresql
8
+ MODELS_SEQUELIZE_HOST: "cnpg-db-psql-stack-pool-rw.cnpg-operands" # vs postgres-postgresql
9
9
  # MODELS_SEQUELIZE_HOST: "cnpg-db-psql-stack-pool-rw.cnpg-operands" # cnpg pooled (pgbouncer)
10
10
 
11
11
  # Limit the SQL connections from the defaults of 10
@@ -5,7 +5,7 @@ config:
5
5
  LOG_CONFIG: '{"type":"pino","level":"warn"}'
6
6
 
7
7
  # CNPG override
8
- SQL_HOST: "cnpg-db-psql-stack-rw.cnpg-operands" # vs postgres-postgresql
8
+ SQL_HOST: "cnpg-db-psql-stack-pool-rw.cnpg-operands" # vs postgres-postgresql
9
9
 
10
10
  serviceMonitor:
11
11
  enabled: true
@@ -15,12 +15,11 @@ showInstalling "Traefik v3 Load Balancer / Router"
15
15
 
16
16
  TRAEFIK_NAMESPACE="traefik"
17
17
 
18
- addHelmRepo traefik https://helm.traefik.io/traefik
18
+ OCI_CHART="oci://ghcr.io/traefik/helm/traefik"
19
19
 
20
- [ -z "$TRAEFIK_CHART_VERSION" ] && TRAEFIK_CHART_VERSION="38"
21
- helm upgrade --install traefik traefik/traefik \
20
+ [ -z "$TRAEFIK_CHART_VERSION" ] && TRAEFIK_CHART_VERSION="38.0.2"
21
+
22
+ helm upgrade --install traefik $OCI_CHART \
22
23
  --namespace $TRAEFIK_NAMESPACE --create-namespace \
23
24
  --values traefik/values.yaml \
24
25
  --version $TRAEFIK_CHART_VERSION $HELM_WHAT
25
-
26
- removeHelmRepo traefik
@@ -28,7 +28,7 @@ resources:
28
28
  metrics:
29
29
  prometheus:
30
30
  serviceMonitor:
31
- enabled: true # initially disabled until prometheus operator is installed
31
+ enabled: false # initially disabled until prometheus operator is installed
32
32
  interval: 30s
33
33
  namespace: prometheus
34
34
 
@@ -10,7 +10,7 @@ config:
10
10
  DENSE_HISTORY_TDB_CACHE_KEY_PREFIX: "timescale-dh"
11
11
  DENSE_HISTORY_MIGRATE_PAGE_SIZE_LIMIT: "50"
12
12
 
13
- PG_HOST: "cnpg-db-tsdb-dense-rw.cnpg-operands"
13
+ PG_HOST: "cnpg-db-tsdb-dense-pool-rw.cnpg-operands"
14
14
  # PG_HOST: "cnpg-db-tsdb-dense-pool-rw.cnpg-operands"
15
15
  # PG_DATABASE: "timescale" # "imagine" is legacy and default
16
16
 
@@ -14,8 +14,8 @@ config:
14
14
  LOG_CONFIG: '{"type":"pino","level":"warn"}'
15
15
 
16
16
  # CNPG override
17
- PG_HOST: "cnpg-db-tsdb-basic-rw.cnpg-operands"
18
- # PG_DATABASE: "timescale" # "imagine" is legacy and default
17
+ PG_HOST: "cnpg-db-tsdb-basic-pool-rw.cnpg-operands"
18
+ PG_DATABASE: "timescale" # "imagine" is legacy and default
19
19
 
20
20
  PG_PASSWORD_SECRET: "cnpg-db-tsdb-basic-postgres-pw"
21
21
  PG_PASSWORD_KEY: "password"
package/src/helmup.sh CHANGED
@@ -5,10 +5,62 @@
5
5
  # indicator to the bash-funcs ifNotFromHelmup function
6
6
  export _FROM_HELMUP_="true"
7
7
 
8
+ INVOKED_AS=`basename $0`
9
+
8
10
  # Load the standard helper functions
9
11
  . `build-tools --bashfun`
10
12
 
11
- if [[ ! -z "$BUILD_TOOLS_DEBUG" ]]; then
13
+ function giveHelp() {
14
+ cat<<HELP
15
+ `color c "Helm Deployment Orchestrator"`
16
+
17
+ Usage: `color g "$INVOKED_AS <service> [service...] [options]"`
18
+
19
+ Options:
20
+ `color g "--dry-run"` Show what helm would do without applying changes
21
+ `color g "--debug"` Enable verbose debug output
22
+ `color g "--help"` Show this help message
23
+
24
+ Invocation Modes:
25
+ `color g "helmup"` Deploy / upgrade one or more services
26
+ `color g "helmdn"` Tear down one or more services
27
+ `color g "helmwhat"` Dry-run a deployment (same as --dry-run)
28
+ `color g "helminit"` Run init scripts for a service
29
+ `color g "helmboot"` Re-run the boot scripts for a service
30
+ `color g "helmcycle"` Cycle (down + up) one or more services
31
+
32
+ Examples:
33
+ `color g "helmup api-server"` # deploy a single service
34
+ `color g "helmup api-server scheduler"` # deploy multiple services
35
+ `color g "helmup transponder-*"` # deploy by glob pattern
36
+ `color g "helmup transponder-rt/5.1.0"` # deploy a specific chart version
37
+ `color g "helmup platform"` # deploy all platform services
38
+ `color g "helmup api-server --dry-run"` # dry run without applying
39
+ `color g "helmdn api-server"` # tear down a service
40
+ `color g "helmcycle api-server"` # helmdn / helmup a service
41
+ HELP
42
+ }
43
+
44
+ # command line parsing is handled in getServiceAndChartInfo which allows us to pull the chart
45
+ for arg in "$@"; do
46
+ case "$arg" in
47
+ --help|-h)
48
+ giveHelp && exit 0
49
+ ;;
50
+ --debug)
51
+ export BUILD_TOOLS_DEBUG=1
52
+ ;;
53
+ --dry-run)
54
+ export HELM_WHAT="--dry-run --debug"
55
+ export K8S_WHAT="--dry-run=server -o yaml"
56
+ ;;
57
+ *)
58
+ SERVICES+=("$arg")
59
+ ;;
60
+ esac
61
+ done
62
+
63
+ if [[ ! -z "$BUILD_TOOLS_DEBUG_XXX" ]]; then
12
64
  cat<<BAD_IDEA
13
65
 
14
66
  `color y "***WARNING: enabling debugging for helmup is a bad idea..."`
@@ -22,8 +74,6 @@ BAD_IDEA
22
74
  exit 1
23
75
  fi
24
76
 
25
- SHELMUP_ARGS=("$*")
26
-
27
77
  # artifact-registry => https://console.cloud.google.com/artifacts?project=leverege-registry
28
78
  REGISTRY_DOMAIN="us-docker.pkg.dev"
29
79
  # open container initiative (oci) => https://opencontainers.org/
@@ -44,7 +94,6 @@ PLATFORM=(
44
94
  imagine
45
95
  message-processor
46
96
  messenger
47
- reason
48
97
  resource-server
49
98
  rule-engine
50
99
  scheduler
@@ -58,10 +107,11 @@ AUXILIARY=(
58
107
  fota-server
59
108
  geotile-server
60
109
  overdose
61
- pgbouncer,
110
+ pgbouncer
62
111
  pubsub-pulse
63
112
  push-notifier
64
113
  pusher
114
+ reason
65
115
  transponder-dh
66
116
  vin-decoder-server
67
117
  )
@@ -237,7 +287,7 @@ function bootstrapLocalSetup() {
237
287
 
238
288
  if [ ! -d "$SERVICE" ];
239
289
  then
240
- mkdir $SERVICE
290
+ mkdir "$SERVICE"
241
291
  else
242
292
  # If the service dir already exists but the helmup.plugin file is missing
243
293
  # then this is most likely a legacy setup - for example, an older setup for
@@ -261,13 +311,13 @@ MISSING_HELMUP_PLUGIN
261
311
 
262
312
  if [ ! -d "$SERVICE_CHART" ];
263
313
  then
264
- rm -rf $SERVICE
314
+ rm -rf "$SERVICE"
265
315
  errorExit "Missing $SERVICE chart => $(color y $SERVICE_CHART)"
266
316
  fi
267
317
 
268
- cp -a $SERVICE_CHART .
318
+ cp -a "$SERVICE_CHART" .
269
319
  # because npm tends to not allow .gitinore files the easy way...
270
- find $SERVICE -type f -name "gitignore" -execdir mv {} .gitignore \;
320
+ find "$SERVICE" -type f -name "gitignore" -execdir mv {} .gitignore \;
271
321
  overwhelm --genvals
272
322
  FIRST_RUN="$SERVICE/helmup.bootstrap"
273
323
  if [ -f "$FIRST_RUN" ];
@@ -286,8 +336,8 @@ SERVICE_BOOTSTRAP
286
336
  exit 1
287
337
  fi
288
338
  fi
289
- git add $SERVICE
290
- ifPluggedIn $SERVICE
339
+ git add "$SERVICE"
340
+ ifPluggedIn "$SERVICE"
291
341
  }
292
342
 
293
343
  # If the service is already plugged in the go - otherwise if this is a first
@@ -318,17 +368,15 @@ function installDefaultConfigs() {
318
368
  INSTALLDEFAULTCONFIGS
319
369
  yesToContinue "to apply the default-configs to the cluster"
320
370
 
321
- kubecmd="kubectl apply -f default-configs.yaml"
322
-
323
- printf "\nRunning => `color y \"$kubecmd\"`\n\n"
324
- eval $kubecmd
325
- sendToSlack "$kubecmd"
371
+ printf "\n`color y \"*** Updating the Default Configs!!!\"` \n\n"
372
+ kubectl apply -f default-configs.yaml
373
+ sendToSlack "Updated the Default ConfigMap!"
326
374
  }
327
375
 
328
376
  function errorIfMissingSecret() {
329
377
  SECRET="$1"
330
378
  kubectl get secret $SECRET &> $DEVNULL
331
- if [[ $? = 1 || SECRET = "" ]];
379
+ if [[ $? = 1 || "${SECRET}" = "" ]];
332
380
  then
333
381
  errorExit "missing secret `color y $SECRET` - did you `color g 'service-man --new-k8s'` ?"
334
382
  fi
@@ -563,17 +611,34 @@ HELMUP_BANNER
563
611
  }
564
612
 
565
613
  function doHelmup() {
566
- local culprit="--set helmup.culprit=\"$(gcloud config get account)\""
567
- local deployT="--set helmup.deployT=\"$(date -u +'%Y-%m-%dT%H:%M:%SZ')\""
568
- local helmup="$@"
569
- local doing="Helming => `color g \"$helmup\"`"
614
+ local culprit="$(gcloud config get account)"
615
+ local deployT="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
616
+ local doing="Helming => `color g \"$*\"`"
570
617
  local from=
571
618
  [ ! -z "$FROM_VERSIONS" ] && from="`color y \"<= from Versions.json\"`"
572
619
  printf "$doing $from\n"
573
- eval "$helmup $culprit $deployT"
620
+ # plugins pass HELMUP as a single quoted string - split it into args without using eval
621
+ [[ $# -eq 1 ]] && set -- $1
622
+ "$@" --set "helmup.culprit=$culprit" --set "helmup.deployT=$deployT"
623
+
624
+ # usually the helm command will run without error but a common failure is caused
625
+ # by the lack of use of our protonVPN profile which causes the i/o timeout from helm
626
+ if [[ $? -ne 0 ]];
627
+ then
628
+ cat<<HELMUP_FAIL
629
+
630
+ $RED_ERROR helmup failed for => `color y "$SERVICE"`
631
+
632
+ `color y "Please investigate the issue, and if it isn't obvious then check your VPN connectivity!"`
633
+
634
+ HELMUP_FAIL
635
+
636
+ exit 1
637
+ fi
638
+
574
639
  case "$INVOKED_AS" in
575
640
  "helmup"|"helmdn")
576
- sendToSlack "$helmup"
641
+ sendToSlack "$*"
577
642
  ;;
578
643
  *)
579
644
  ;;
@@ -588,7 +653,17 @@ FROM_VERSIONS=
588
653
 
589
654
  function doInstall() {
590
655
 
591
- helm repo update &> $DEVNULL
656
+ # we used to do a Chartmuseum update here which means that we incur the cost of
657
+ # updating the index and pulling the charts down every time we install a service
658
+ # which is a lot of overhead for a process that is already pretty slow
659
+ #
660
+ # helm repo update &> $DEVNULL <===DEPRECATED
661
+ #
662
+ # the chart museum is now updated in the background when helmup runs, just before
663
+ # the overwhelm step, so we get the benefits of the updated charts without the
664
+ # overhead on every install - this is, of course, a race condition, but this will
665
+ # all go away once we move to artifact registry and can pull the charts directly
666
+ # from there without the need for a local repo update
592
667
 
593
668
  for PARAM in "$@";
594
669
  do
@@ -598,7 +673,6 @@ function doInstall() {
598
673
  # slap additional helm syntax in there if the version is set
599
674
  [ ! -z "$CHARTVER" ] && CHARTVER="--version $CHARTVER"
600
675
 
601
- INVOKED_AS=`basename $0`
602
676
  # set the dry-run flag on what
603
677
  [ "$INVOKED_AS" == "helmwhat" ] && HELM_WHAT="--dry-run --debug" && K8S_WHAT="--dry-run=server -o yaml"
604
678
 
@@ -688,7 +762,7 @@ REBOOTSTRAP
688
762
  [ ! -d $SERVICE ] && bootstrapLocalSetup $SERVICE
689
763
  CHARTLOC="oci://us-docker.pkg.dev/leverege-registry/stack/charts/transponder" # always use art-reg
690
764
  HELMUP="helm upgrade --install $SERVICE $CHARTLOC --values $SERVICE/values.yaml $CHARTVER $HELM_WHAT"
691
- doHelmup "$HELMUP"
765
+ doHelmup $HELMUP
692
766
  ;;
693
767
 
694
768
  *)
@@ -711,17 +785,6 @@ REBOOTSTRAP
711
785
  fi
712
786
 
713
787
  printf "\n--------------------------------------------------------------\nCharting $SERVICE\n"
714
- if [ ! -x "$(command -v service-man)" ];
715
- then
716
- cat<<NO_SERVICE_MAN
717
-
718
- $RED_ERROR The Leverege service-man utility is missing - install and rerun helmup
719
-
720
- `color g "npm i -g @leverege/service-man"`
721
-
722
- NO_SERVICE_MAN
723
- exit 1
724
- fi
725
788
 
726
789
  if [[ "$SERVICE" == *-canary ]];
727
790
  then
@@ -734,22 +797,7 @@ NO_SERVICE_MAN
734
797
 
735
798
  HELMUP="helm upgrade --install $SERVICE $CHARTLOC -f $SERVICE/values.yaml $CHARTVER $HELM_WHAT"
736
799
 
737
- doHelmup $HELMUP
738
- SAVERR=$?
739
- if [ $SAVERR -ne 0 ];
740
- then
741
- cat<<NOTRUNNING
742
-
743
- $RED_ERROR helm exited with error status: $SAVERR
744
-
745
- $RED_ERROR The $SERVICE chart failed to upgrade or install. There may be an
746
- issue with the service's helm charts, or you may have to follow
747
- the instructions on the wiki under `color g "Helm Charts via Chartmuseum"`
748
- in the `color y "Using the Public Endpoint"` section.
749
-
750
- NOTRUNNING
751
- exit 1
752
- fi
800
+ doHelmup $HELMUP # will exit on failure, otherwise will continue to the next service
753
801
  ;;
754
802
  esac
755
803
  done
@@ -758,7 +806,7 @@ NOTRUNNING
758
806
  }
759
807
 
760
808
  # ---------- helmup MAIN ----------
761
- GITTOP=`git rev-parse --show-toplevel`
809
+ helm repo update &>/dev/null & # see comments in the doInstall function for rationale
762
810
 
763
811
  overwhelm
764
812
  [ $? -ne 0 ] && printf "\n\n***Aborting helmup...\n\n" && exit 1
@@ -768,6 +816,6 @@ export GCP_PROJECT_ID="$(getProjectIdFromK8sContext)"
768
816
  # Same for the region, but not as prevalent
769
817
  export GCE_REGION=`overwhelm -k GCE_REGION`
770
818
 
771
- doInstall $@
819
+ doInstall "${SERVICES[@]}"
772
820
 
773
821
  displayBanner
package/src/overwhelm.mjs CHANGED
@@ -51,6 +51,15 @@ const deprecated = ( deprecation ) => {
51
51
  log( `${chalk.yellow.bold( '***DEPRECATED:' )} ${deprecation}\n` )
52
52
  }
53
53
 
54
+ if ( !fs.existsSync( 'overwhelm.yaml' ) ) {
55
+ log( chalk.red.bold( `
56
+
57
+ ***ERROR overwhelm => missing the overwhelm.yaml file - this command expects
58
+ to execute from within a platform-k8s branch
59
+ ` ) )
60
+ process.exit( 1 )
61
+ }
62
+
54
63
  // See if we are in a monorepo, which changes some of the rules.
55
64
  const gitTop = await shellCmd( 'git rev-parse --show-toplevel' )
56
65
 
@@ -65,17 +74,8 @@ const gitBranch = await shellCmd( 'git rev-parse --abbrev-ref HEAD' )
65
74
 
66
75
  const context = args.context || monoTop || gitBranch
67
76
 
68
- if ( context === 'master' ) {
69
- log( '***ERROR: master context is forbidden; change to a different branch\n\n' )
70
- process.exit( 1 )
71
- }
72
-
73
- if ( !fs.existsSync( 'overwhelm.yaml' ) ) {
74
- log( chalk.red.bold( `
75
-
76
- ***ERROR overwhelm => missing the overwhelm.yaml file - this command expects
77
- to execute from within a platform-k8s branch
78
- ` ) )
77
+ if ( context.match( /^(main|master)$/ ) ) {
78
+ log( `***ERROR: ${context} context is forbidden; change to a different branch\n\n` )
79
79
  process.exit( 1 )
80
80
  }
81
81
 
@@ -92,32 +92,15 @@ if ( !args.key && !args.fetchctx && !args.matchk8s && fs.existsSync( 'values-def
92
92
  }
93
93
  }
94
94
 
95
- // Avoid race condition when running overwhelm for the first time on a new
96
- // cluster and the default-configs.yaml file has yet to be created.
97
- const defaultConfigs = 'default-configs.yaml'
98
- if ( !fs.existsSync( defaultConfigs ) ) {
99
- fs.closeSync( fs.openSync( defaultConfigs, 'w' ) ) // same as unix touch
100
- }
101
-
102
- // Load the default values and then overlay with the project specific yaml
103
- // values. This supports the notion of this type of approach in the
104
- // overwhelm yaml settings:
105
- // default:
106
- // GCE_MACHINE : "n1-standard-2"
107
- //
108
- // my-project:
109
- // GCE_MACHINE : "n1-highcpu-8"
110
- //
111
- // fashion, but it is advised not to set a default region with this
112
- // approach in order to keep us cognizant of exactly where a cluster is
113
- // being formed.
114
- //
95
+ // Load the overwhelm.yaml file with the project specific settings to be rendered
96
+ // into the helm values.yaml files. The overwhelm.yaml file is expected to have a
97
+ // default section and one or more context-specific sections.
115
98
  const yaml = YAML.load( fs.readFileSync( 'overwhelm.yaml', 'utf-8' ) )
116
99
  const over = yaml.default
117
100
 
118
101
  debug( { over, yaml, }, '<==Contents of the over and yaml structs' )
119
102
 
120
- let cfgs = yaml[context]
103
+ const cfgs = yaml[context]
121
104
 
122
105
  // If we just need to check context return 0 if cfgs exists, else error.
123
106
  if ( args.checkctx ) { process.exit( !cfgs ? 1 : 0 ) }
@@ -132,18 +115,7 @@ if ( !cfgs ) {
132
115
  process.exit( 1 )
133
116
  }
134
117
 
135
- // Check to see if we are deriving from another configuration.
136
- if ( cfgs.PROJECT_BASE ) {
137
- const baseName = cfgs.PROJECT_BASE
138
- const tempCfgs = cfgs
139
- cfgs = yaml[baseName]
140
- Object.keys( tempCfgs ).forEach( ( key ) => { cfgs[key] = tempCfgs[key] } )
141
- log( 'PROJECT_BASE still under evaluation' )
142
- log( '\n cfgs=', cfgs )
143
- process.exit( 1 ) // XXX HERE
144
- }
145
-
146
- Object.keys( cfgs ).forEach( ( key ) => { over[key] = cfgs[key] || over[key] } )
118
+ Object.keys( cfgs ).forEach( ( key ) => { over[key] = cfgs[key] ?? over[key] } )
147
119
 
148
120
  // Expand any variables that reference other variable settings. A perfect
149
121
  // example of where this is useful is in the setting of a PROJECT_NAME and
@@ -163,6 +135,11 @@ const varErrors = []
163
135
  Object.keys( over ).forEach( ( key ) => {
164
136
  if ( !over[key] ) return // no value to work with - skip it
165
137
 
138
+ if ( !isString( over[key] ) ) {
139
+ varErrors.push( `${key} : ${over[key]} is not a string` )
140
+ return
141
+ }
142
+
166
143
  // Look for something in the form of "thing-${VAR1}-${VAR2}-${VARn}-stuff"
167
144
  const matches = over[key].match( /\$\{\w+\}/g )
168
145
  if ( !matches ) return
@@ -182,9 +159,9 @@ Object.keys( over ).forEach( ( key ) => {
182
159
  } )
183
160
 
184
161
  if ( varErrors.length > 0 ) {
185
- log( '***ERROR: unkown variable reference(s) in overwhelm.yaml:\n' )
162
+ log( chalk.red.bold( '\n***ERROR: unkown variable reference(s) in overwhelm.yaml:\n' ) )
186
163
  varErrors.forEach( ( error ) => {
187
- log( ` ${error}` )
164
+ log( ` ${chalk.yellow.bold( error )}` )
188
165
  } )
189
166
  log( '' )
190
167
  process.exit( 1 )
@@ -194,8 +171,8 @@ if ( varErrors.length > 0 ) {
194
171
  const yams = glob.sync( 'values-*.yaml' )
195
172
 
196
173
  // A function to apply the replacements to all of the matching yaml which
197
- // will error out if it runs into an unknown OVH<tag>.
198
- const doReplacements = ( yamls, replacements, fileName = 'default-config.yaml' ) => {
174
+ // will error out if it runs into an unknown ${TAG}
175
+ const doReplacements = ( yamls, replacements, fileName = 'unknown-file' ) => {
199
176
  let replYaml = yamls
200
177
 
201
178
  // wrap special chars with quotes if needed, like "#---incident-alerts---"
@@ -217,16 +194,23 @@ const doReplacements = ( yamls, replacements, fileName = 'default-config.yaml' )
217
194
  }
218
195
  } )
219
196
 
220
- // Verify all replaceables have been handled, or error out.
221
- const missed = replYaml.match( /OVH:<(.*)>/g )
222
-
223
- if ( missed ) {
224
- log( '\n***ERROR: missing replacements in overwhelm.yaml for these tags:\n' )
225
- missed.forEach( ( miss ) => {
226
- log( ` TAG: ${miss.match( /OVH:<(.*)>/ )[1]}` )
227
- } )
228
- log( '' )
229
- process.exit( 1 )
197
+ // this feels brittle because we have to treat the default-configs.yaml.ovh file
198
+ // differently due to variables like ${shard} which gets expanded by api-server -
199
+ // it feels brittle because there could be other yaml files that have similar
200
+ // variables that are not meant to be replaced by overwhelm - I might eventually
201
+ // just rip this out ...
202
+ if ( fileName !== 'default-configs.yaml.ovh' ) {
203
+ // Verify all replaceables have been handled, or error out.
204
+ const missed = replYaml.match( /OVH:<(.*)>|\${(.*)}/g )
205
+
206
+ if ( missed ) {
207
+ log( chalk.red.bold( `\n***ERROR: missing replacements in ${fileName} for these tags:\n` ) )
208
+ missed.forEach( ( miss ) => {
209
+ log( ` TAG: ${chalk.yellow.bold( miss )}` )
210
+ } )
211
+ log( '' )
212
+ process.exit( 1 )
213
+ }
230
214
  }
231
215
 
232
216
  // Eat any doubly double quoted values such that
@@ -241,8 +225,7 @@ const doReplacements = ( yamls, replacements, fileName = 'default-config.yaml' )
241
225
 
242
226
  // Collect all of the yaml from the yams...
243
227
  const buildYaml = ( yamls, replacements ) => {
244
- const always = [ defaultConfigs ]
245
- const values = [ ...always, ...yamls ]
228
+ const values = [ ...yamls ]
246
229
  const loaded = []
247
230
  let allYamls = ''
248
231
 
@@ -260,7 +243,7 @@ const buildYaml = ( yamls, replacements ) => {
260
243
  } )
261
244
 
262
245
  // Now apply all of the replacements from the overwhelm file.
263
- return doReplacements( allYamls, replacements )
246
+ return doReplacements( allYamls, replacements, 'from-buildYaml' )
264
247
  }
265
248
 
266
249
  // Call buildYaml to replace the OVH strings in the yaml files.
@@ -280,7 +263,7 @@ if ( args.key ) {
280
263
  }
281
264
 
282
265
  // Find all of the potential target dirs. Utilize .gitignore to ignore files
283
- const ahoy = getDirectories( process.cwd() )
266
+ const ahoy = getDirectories( { path : process.cwd(), respectGitignore : true } )
284
267
 
285
268
  // Verifies that all values in a config block are quoted
286
269
  const validValuesLocalConfig = ( vlf ) => {
@@ -307,7 +290,7 @@ const validValuesLocalConfig = ( vlf ) => {
307
290
  ahoy.forEach( ( dir ) => {
308
291
  if ( !fs.existsSync( `${dir}/.nohelm` ) && !dir.match( /^\..*/ ) ) {
309
292
  // debug( { dir }, 'Generating values' ) // eslint-disable-line no-unused-expressions
310
- let valuesOut = [] // An accumulator for all of the output values.
293
+ let valuesOut = '' // An accumulator for all of the output values.
311
294
 
312
295
  // Add support for localized values for things like keel (or whatever)
313
296
  const valuesLocal = `${dir}/values-local.yaml`
@@ -342,7 +325,7 @@ ahoy.forEach( ( dir ) => {
342
325
 
343
326
  // we can also apply replaceables to all .ovh files in the project
344
327
  glob.sync( '**/*.ovh' ).forEach( ( cfgmap ) => {
345
- const target = cfgmap.replace( /.ovh$/, '' )
328
+ const target = cfgmap.replace( /\.ovh$/, '' )
346
329
  deprecated( `rename deprecated ${cfgmap} OVH file to ${target}` )
347
330
  let valuesOut = fs.readFileSync( cfgmap, { encoding : 'utf-8' } )
348
331
  valuesOut = doReplacements( valuesOut, over, cfgmap )
@@ -1,22 +0,0 @@
1
- apiVersion: postgresql.cnpg.io/v1
2
- kind: Pooler
3
- metadata:
4
- name: cnpg-db-psql-stack-pool-rw
5
- namespace: cnpg-operands
6
- spec:
7
- cluster:
8
- name: cnpg-db-psql-stack
9
-
10
- instances: 1
11
- type: rw
12
- pgbouncer:
13
- poolMode: transaction
14
- parameters:
15
- # https://www.pgbouncer.org/config.html#generic-settings
16
- max_client_conn: "500"
17
- default_pool_size: "5"
18
- # https://www.pgbouncer.org/config.html#log-settings
19
- log_connections: "0"
20
- log_disconnections: "0"
21
- monitoring:
22
- enablePodMonitor: true
@@ -1,22 +0,0 @@
1
- apiVersion: postgresql.cnpg.io/v1
2
- kind: Pooler
3
- metadata:
4
- name: cnpg-db-tsdb-basic-pool-rw
5
- namespace: cnpg-operands
6
- spec:
7
- cluster:
8
- name: cnpg-db-tsdb-basic
9
-
10
- instances: 1
11
- type: rw
12
- pgbouncer:
13
- poolMode: transaction
14
- parameters:
15
- # https://www.pgbouncer.org/config.html#generic-settings
16
- max_client_conn: "500"
17
- default_pool_size: "5"
18
- # https://www.pgbouncer.org/config.html#log-settings
19
- log_connections: "0"
20
- log_disconnections: "0"
21
- monitoring:
22
- enablePodMonitor: true