-
Notifications
You must be signed in to change notification settings - Fork 0
BAC-492 - Prevent Rollout From Losing spec.replicas During ArgoCD Syn… #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HPA enablement parsing is brittle for quoted/uppercase values. If the parameters file uses 🛠️ 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| 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 "$@" | ||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fail fast if
ARGO_PARAMETERS_FILEis 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
🤖 Prompt for AI Agents