Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/commands/argo-deploy-application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ steps:
- argo-app-previous-status:
release-name: << parameters.release-name >>

- run:
name: Prepare HPA transition
environment:
ARGO_PARAMETERS_FILE: /tmp/argo-parameters/parameters.yaml
RELEASE_NAME: << parameters.release-name >>
NAMESPACE: << parameters.namespace >>
command: << include(scripts/argo_hpa_transition.sh) >>

- run:
name: Upsert Argo Application
command: |
Expand Down
99 changes: 99 additions & 0 deletions src/scripts/argo_hpa_transition.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/bin/bash

# This script prepares a Rollout resource for HPA transition by cleaning the
# spec.replicas field from the kubectl last-applied-configuration annotation.
#
# When transitioning from fixed replicas to HPA-managed replicas, kubectl's
# three-way merge interprets the removal of spec.replicas from the desired
# manifest as an intentional deletion, causing Kubernetes to default to 1 replica.
# By removing the field from last-applied-configuration beforehand, the three-way
# merge sees "was absent, still absent" and preserves the live replica count.
#
# Environment variables:
# ARGO_PARAMETERS_FILE - Path to the rendered Helm parameters file
# RELEASE_NAME - Name of the Rollout resource
# NAMESPACE - Kubernetes namespace

# Colors for output
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[1;33m"
NC="\033[0m" # No Color

function usage() {
echo -e "${GREEN}Usage:${NC} Set the following environment variables before running this script:"
echo " ARGO_PARAMETERS_FILE Path to the rendered Helm parameters file (required)"
echo " RELEASE_NAME Name of the Rollout resource (required)"
echo " NAMESPACE Kubernetes namespace (required)"
}

function main() {
local parameters_file="${ARGO_PARAMETERS_FILE}"
local release_name="${RELEASE_NAME}"
local namespace="${NAMESPACE}"

# Validate required variables
local missing_vars=()
[[ -z "$parameters_file" ]] && missing_vars+=("ARGO_PARAMETERS_FILE")
[[ -z "$release_name" ]] && missing_vars+=("RELEASE_NAME")
[[ -z "$namespace" ]] && missing_vars+=("NAMESPACE")

if [[ ${#missing_vars[@]} -gt 0 ]]; then
echo -e "${RED}Error: The following required environment variables are missing:${NC}"
printf ' - %s\n' "${missing_vars[@]}"
usage
exit 2
fi
Comment on lines +35 to +46
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fail fast if ARGO_PARAMETERS_FILE is missing or unreadable.

Right now only the variable is checked; if the file path is wrong, Line 50 will silently evaluate to "not enabled" and skip cleanup, reintroducing the replica-loss bug.

🛠️ Suggested fix
   if [[ ${`#missing_vars`[@]} -gt 0 ]]; then
     echo -e "${RED}Error: The following required environment variables are missing:${NC}"
     printf '  - %s\n' "${missing_vars[@]}"
     usage
     exit 2
   fi
+
+  if [[ ! -r "$parameters_file" ]]; then
+    echo -e "${RED}Error: ARGO_PARAMETERS_FILE '$parameters_file' not found or not readable.${NC}"
+    exit 2
+  fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Validate required variables
local missing_vars=()
[[ -z "$parameters_file" ]] && missing_vars+=("ARGO_PARAMETERS_FILE")
[[ -z "$release_name" ]] && missing_vars+=("RELEASE_NAME")
[[ -z "$namespace" ]] && missing_vars+=("NAMESPACE")
if [[ ${#missing_vars[@]} -gt 0 ]]; then
echo -e "${RED}Error: The following required environment variables are missing:${NC}"
printf ' - %s\n' "${missing_vars[@]}"
usage
exit 2
fi
# Validate required variables
local missing_vars=()
[[ -z "$parameters_file" ]] && missing_vars+=("ARGO_PARAMETERS_FILE")
[[ -z "$release_name" ]] && missing_vars+=("RELEASE_NAME")
[[ -z "$namespace" ]] && missing_vars+=("NAMESPACE")
if [[ ${`#missing_vars`[@]} -gt 0 ]]; then
echo -e "${RED}Error: The following required environment variables are missing:${NC}"
printf ' - %s\n' "${missing_vars[@]}"
usage
exit 2
fi
if [[ ! -r "$parameters_file" ]]; then
echo -e "${RED}Error: ARGO_PARAMETERS_FILE '$parameters_file' not found or not readable.${NC}"
exit 2
fi
🤖 Prompt for AI Agents
In `@src/scripts/argo_hpa_transition.sh` around lines 35 - 46, The validation
currently only checks that the parameters_file variable is set; update the check
so it also fails fast when the file path is missing or not readable. Replace the
single-variable check for parameters_file with a compound test like [[ -z
"$parameters_file" || ! -r "$parameters_file" ]] and add a clear label such as
"ARGO_PARAMETERS_FILE (missing or unreadable)" to missing_vars so the script
exits immediately if the file does not exist or is not readable; keep the rest
of the missing_vars handling (usage and exit 2) unchanged.


# Check if autoscaling is being enabled in this deploy
local hpa_enabled
hpa_enabled=$(grep -A1 'name: autoscaling\.enabled' "$parameters_file" | grep 'value:' | awk '{print $2}' || echo "false")

if [[ "$hpa_enabled" != "true" ]]; then
echo -e "${GREEN}HPA not enabled in this deploy, skipping.${NC}"
return 0
fi
Comment on lines +48 to +55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

HPA enablement parsing is brittle for quoted/uppercase values.

If the parameters file uses value: "true" or value: True, Line 50 returns a non‑true string and the cleanup is skipped. Normalize and strip quotes before comparison.

🛠️ Suggested fix
-  hpa_enabled=$(grep -A1 'name: autoscaling\.enabled' "$parameters_file" | grep 'value:' | awk '{print $2}' || echo "false")
+  hpa_enabled=$(awk '
+    $0 ~ /name: autoscaling\.enabled/ {found=1; next}
+    found && $1=="value:" {
+      gsub(/"/,"",$2);
+      print tolower($2);
+      exit
+    }
+  ' "$parameters_file")
+  hpa_enabled=${hpa_enabled:-false}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Check if autoscaling is being enabled in this deploy
local hpa_enabled
hpa_enabled=$(grep -A1 'name: autoscaling\.enabled' "$parameters_file" | grep 'value:' | awk '{print $2}' || echo "false")
if [[ "$hpa_enabled" != "true" ]]; then
echo -e "${GREEN}HPA not enabled in this deploy, skipping.${NC}"
return 0
fi
# Check if autoscaling is being enabled in this deploy
local hpa_enabled
hpa_enabled=$(awk '
$0 ~ /name: autoscaling\.enabled/ {found=1; next}
found && $1=="value:" {
gsub(/"/,"",$2);
print tolower($2);
exit
}
' "$parameters_file")
hpa_enabled=${hpa_enabled:-false}
if [[ "$hpa_enabled" != "true" ]]; then
echo -e "${GREEN}HPA not enabled in this deploy, skipping.${NC}"
return 0
fi
🤖 Prompt for AI Agents
In `@src/scripts/argo_hpa_transition.sh` around lines 48 - 55, The hpa_enabled
extraction is brittle for quoted or capitalized values; update the hpa_enabled
assignment (the variable computed from "$parameters_file") to strip surrounding
quotes and whitespace and normalize to lowercase before comparing to "true".
Locate the hpa_enabled assignment and replace the current pipeline with one that
extracts the value token, removes surrounding quotes, trims whitespace, and
lowercases it (so values like "true", True, TRUE all normalize to true) and then
keep the existing if [[ "$hpa_enabled" != "true" ]]; check.


echo -e "${YELLOW}HPA enabled — checking if spec.replicas cleanup is needed for Rollout '$release_name' in namespace '$namespace'.${NC}"

# Check if the Rollout exists (might not on first deploy)
if ! kubectl get rollout "$release_name" -n "$namespace" > /dev/null 2>&1; then
echo -e "${GREEN}Rollout '$release_name' not found (likely first deploy), skipping.${NC}"
return 0
fi

# Get the last-applied-configuration annotation
local last_applied
last_applied=$(kubectl get rollout "$release_name" -n "$namespace" \
-o jsonpath='{.metadata.annotations.kubectl\.kubernetes\.io/last-applied-configuration}' 2>/dev/null || echo "")

if [[ -z "$last_applied" ]]; then
echo -e "${GREEN}No last-applied-configuration annotation found, skipping.${NC}"
return 0
fi

# Check if spec.replicas exists in last-applied-configuration
if ! echo "$last_applied" | jq -e '.spec.replicas' > /dev/null 2>&1; then
echo -e "${GREEN}spec.replicas not present in last-applied-configuration, no cleanup needed.${NC}"
return 0
fi

local current_replicas
current_replicas=$(echo "$last_applied" | jq '.spec.replicas')
echo -e "${YELLOW}Removing spec.replicas ($current_replicas) from last-applied-configuration${NC}"
echo "to prevent three-way merge conflict during HPA transition."

# Remove spec.replicas from last-applied-configuration
local cleaned
cleaned=$(echo "$last_applied" | jq -c 'del(.spec.replicas)')

if ! kubectl annotate rollout "$release_name" -n "$namespace" \
"kubectl.kubernetes.io/last-applied-configuration=$cleaned" --overwrite; then
echo -e "${RED}Failed to update last-applied-configuration annotation.${NC}"
return 1
fi

echo -e "${GREEN}Successfully cleaned spec.replicas from last-applied-configuration.${NC}"
}

main "$@"