Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b38da5e
feat(pmm-ha): add EKS testing pipeline with ALB, Route53, and Access …
nogueiraanderson Nov 29, 2025
f3ef4fc
refactor: derive AWS account ID and SSO role dynamically
nogueiraanderson Nov 29, 2025
f180443
fix: drop unsupported K8s version 1.34
nogueiraanderson Nov 29, 2025
06e1139
fix(pmm-ha): sanitize SSO role ARN from aws iam list-roles output
nogueiraanderson Nov 30, 2025
0ba9672
feat(pmm-ha): spread nodes across all available AZs dynamically
nogueiraanderson Nov 30, 2025
e4324e6
chore(pmm-ha): remove obvious comments
nogueiraanderson Nov 30, 2025
a3832ce
fix(pmm-ha): use agent-amd64-ol9 for cleanup pipeline
nogueiraanderson Nov 30, 2025
5d62e82
Revert "fix(pmm-ha): use agent-amd64-ol9 for cleanup pipeline"
nogueiraanderson Nov 30, 2025
89bad25
chore(pmm-ha): use cli agent for create pipeline
nogueiraanderson Nov 30, 2025
6f107ce
chore(pmm-ha): rename stage to 'Configure External PMM Access'
nogueiraanderson Nov 30, 2025
b496a5e
chore(pmm-ha): rename stage to 'Setup External Access'
nogueiraanderson Nov 30, 2025
3e61fce
fix(pmm-ha): clean kubeconfig directory before export
nogueiraanderson Dec 1, 2025
1461b4f
fix(pmm-ha-eks): increase node size to xlarge for ClickHouse memory
nogueiraanderson Dec 2, 2025
cac43cc
fix(pmm-ha-eks-cleanup): replace Date.parse with shell date command
nogueiraanderson Dec 2, 2025
bc546ea
fix(pmm-ha-eks): increase ClickHouse memory limits to 10Gi
nogueiraanderson Dec 2, 2025
77929b5
refactor(pmm-ha-eks): move deletion logic to shared library
nogueiraanderson Dec 2, 2025
4415d99
refactor(pmm-ha-eks): use listClusters() consistently in pipelines
nogueiraanderson Dec 2, 2025
559b3ef
fix(pmm-ha-eks): use jq for JSON parsing in listClusters
nogueiraanderson Dec 2, 2025
a459871
fix(pmm-ha-eks): disable stack termination protection before deletion
nogueiraanderson Dec 2, 2025
d21b33f
feat(pmm-ha-eks): add RETENTION_DAYS and PMM_ADMIN_PASSWORD parameters
nogueiraanderson Dec 3, 2025
1d630cb
feat(pmm-ha-eks): include all credentials in artifacts
nogueiraanderson Dec 3, 2025
ad91e73
refactor(pmm-ha-eks): extract credentials logic to shared library
nogueiraanderson Dec 3, 2025
ddaebd1
refactor(pmm-ha-eks): extract validateHelmChart and resolveR53ZoneId …
nogueiraanderson Dec 3, 2025
52d7f09
refactor(pmm-ha-eks): add constants and validateRetentionDays()
nogueiraanderson Dec 3, 2025
131a228
refactor(pmm-ha-eks): organize shared library into logical sections
nogueiraanderson Dec 3, 2025
483e7b4
fix(pmm-ha-eks): use per-cluster kubeconfig in parallel deletions
nogueiraanderson Dec 3, 2025
561e37e
fix(pmm-ha-eks): protect single cluster when SKIP_NEWEST=true
nogueiraanderson Dec 3, 2025
e343215
fix(pmm-ha-eks): always respect delete-after retention tags
nogueiraanderson Dec 3, 2025
2991aa1
docs(pmm-ha-eks): add deletion rules table to deleteAllClusters
nogueiraanderson Dec 3, 2025
f1224a5
fix(pmm-ha-eks): use @Field annotation for shared library constants
nogueiraanderson Dec 3, 2025
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
184 changes: 101 additions & 83 deletions pmm/v3/pmm3-ha-eks-cleanup.groovy
Original file line number Diff line number Diff line change
@@ -1,33 +1,60 @@
/**
* PMM HA EKS Cleanup Pipeline
*
* Manages cleanup of PMM HA test clusters. Supports manual and scheduled runs.
* Deletes Route53 records, ALB ingress, and EKS clusters.
*
* Actions:
* - LIST_ONLY: List all test clusters with age
* - DELETE_CLUSTER: Delete a specific cluster
* - DELETE_ALL: Delete all test clusters (respects SKIP_NEWEST)
* - DELETE_OLD (cron): Delete clusters older than 24 hours
* - CLEANUP_ORPHANS: Delete orphaned VPCs and failed CF stacks
*
* Related:
* - Create: pmm3-ha-eks.groovy
* - Shared library: vars/pmmHaEks.groovy
*/
library changelog: false, identifier: 'lib@fix/pmm-ha-eks-access-entries', retriever: modernSCM([
$class: 'GitSCMSource',
remote: 'https://github.com/Percona-Lab/jenkins-pipelines'
])

pipeline {
agent {
label 'agent-amd64-ol9'
label 'cli'
}

triggers {
cron('H 0,12 * * *') // Runs twice daily at 00:00 & 12:00
cron('H 0,12 * * *')
}

parameters {
choice(
name: 'ACTION',
choices: ['LIST_ONLY', 'DELETE_CLUSTER', 'DELETE_ALL'],
choices: ['LIST_ONLY', 'DELETE_CLUSTER', 'DELETE_ALL', 'CLEANUP_ORPHANS'],
description: '''
LIST_ONLY - list all test clusters<br/>
DELETE_CLUSTER - delete a specific cluster (requires CLUSTER_NAME)<br/>
DELETE_ALL - delete all test clusters<br/><br/>
DELETE_ALL - delete all test clusters<br/>
CLEANUP_ORPHANS - delete orphaned VPCs and failed CF stacks<br/><br/>
Note: Daily cron automatically deletes clusters older than 1 day.
'''
)
string(name: 'CLUSTER_NAME', defaultValue: '', description: 'Required only for DELETE_CLUSTER')
booleanParam(name: 'SKIP_NEWEST', defaultValue: true, description: 'Skip the most recent cluster (protects in-progress builds)')
}

options {
buildDiscarder(logRotator(numToKeepStr: '30'))
disableConcurrentBuilds()
timeout(time: 60, unit: 'MINUTES')
}

environment {
REGION = "us-east-2"
CLUSTER_PREFIX = "pmm-ha-test-"
REGION = 'us-east-2'
CLUSTER_PREFIX = 'pmm-ha-test-'
R53_ZONE_NAME = 'cd.percona.com'
}

stages {
Expand All @@ -36,14 +63,14 @@ pipeline {
script {
if (currentBuild.getBuildCauses('hudson.triggers.TimerTrigger$TimerTriggerCause')) {
env.ACTION = 'DELETE_OLD'
echo "Triggered by cron - will delete clusters older than 1 day."
echo 'Triggered by cron - will delete clusters older than 1 day.'
} else {
env.ACTION = params.ACTION
echo "Manual run with ACTION=${params.ACTION}"
}

if (env.ACTION == 'DELETE_CLUSTER' && !params.CLUSTER_NAME) {
error("CLUSTER_NAME is required for DELETE_CLUSTER.")
error('CLUSTER_NAME is required for DELETE_CLUSTER.')
}
if (params.CLUSTER_NAME && !params.CLUSTER_NAME.startsWith(env.CLUSTER_PREFIX)) {
error("Cluster name must start with ${env.CLUSTER_PREFIX}")
Expand All @@ -56,29 +83,30 @@ pipeline {
when { expression { env.ACTION == 'LIST_ONLY' } }
steps {
withCredentials([aws(credentialsId: 'pmm-staging-slave')]) {
sh '''
set +x

CLUSTERS=$(aws eks list-clusters --region "$REGION" \
--query "clusters[?starts_with(@, '${CLUSTER_PREFIX}')]" \
--output text)

if [ -z "$CLUSTERS" ]; then
echo "No clusters found with prefix '${CLUSTER_PREFIX}'."
exit 0
fi

for c in $CLUSTERS; do
CREATED=$(aws eks describe-cluster \
--name "$c" --region "$REGION" \
--query "cluster.createdAt" --output text)

CREATED_EPOCH=$(date -d "$CREATED" +%s)
AGE_HOURS=$(( ( $(date +%s) - CREATED_EPOCH ) / 3600 ))

echo "• $c | Created: $CREATED | Age: ${AGE_HOURS}h"
done
'''
script {
def clusters = pmmHaEks.listClusters(env.REGION)

if (!clusters) {
echo "No clusters found with prefix '${env.CLUSTER_PREFIX}'."
return
}

echo "Found ${clusters.size()} cluster(s):"
clusters.each { clusterName ->
def info = sh(
script: """
CREATED=\$(aws eks describe-cluster --name ${clusterName} --region ${env.REGION} \
--query 'cluster.createdAt' --output text)
CREATED_EPOCH=\$(date -d "\${CREATED}" +%s)
AGE_HOURS=\$(( ( \$(date +%s) - CREATED_EPOCH ) / 3600 ))
echo "\${CREATED}|\${AGE_HOURS}"
""",
returnStdout: true
).trim()
def parts = info.split('\\|')
echo "* ${clusterName} | Created: ${parts[0]} | Age: ${parts[1]}h"
}
}
}
}
}
Expand All @@ -87,15 +115,22 @@ pipeline {
when { expression { env.ACTION == 'DELETE_CLUSTER' } }
steps {
withCredentials([aws(credentialsId: 'pmm-staging-slave')]) {
sh '''
if ! aws eks describe-cluster --region "${REGION}" --name "${CLUSTER_NAME}" >/dev/null 2>&1; then
echo "Cluster '${CLUSTER_NAME}' not found in region '${REGION}'."
exit 0
fi

eksctl delete cluster --region "${REGION}" --name "${CLUSTER_NAME}" \
--disable-nodegroup-eviction --wait
'''
script {
def clusterExists = sh(
script: "aws eks describe-cluster --region ${REGION} --name ${params.CLUSTER_NAME} >/dev/null 2>&1",
returnStatus: true
) == 0

if (clusterExists) {
pmmHaEks.deleteCluster(
clusterName: params.CLUSTER_NAME,
region: env.REGION,
r53ZoneName: env.R53_ZONE_NAME
)
} else {
echo "Cluster '${params.CLUSTER_NAME}' not found in region '${REGION}'."
}
}
}
}
}
Expand All @@ -104,20 +139,14 @@ pipeline {
when { expression { env.ACTION == 'DELETE_ALL' } }
steps {
withCredentials([aws(credentialsId: 'pmm-staging-slave')]) {
sh '''
CLUSTERS=$(aws eks list-clusters --region "$REGION" \
--query "clusters[?starts_with(@, '${CLUSTER_PREFIX}')]" --output text)

if [ -z "$CLUSTERS" ]; then
echo "No clusters found with prefix '${CLUSTER_PREFIX}'."
exit 0
fi

for c in $CLUSTERS; do
eksctl delete cluster --region "$REGION" --name "$c" \
--disable-nodegroup-eviction --wait
done
'''
script {
pmmHaEks.deleteAllClusters(
region: env.REGION,
r53ZoneName: env.R53_ZONE_NAME,
skipNewest: params.SKIP_NEWEST,
maxAgeHours: 0 // Delete all regardless of age
)
}
}
}
}
Expand All @@ -126,36 +155,25 @@ pipeline {
when { expression { env.ACTION == 'DELETE_OLD' } }
steps {
withCredentials([aws(credentialsId: 'pmm-staging-slave')]) {
sh '''
CLUSTERS=$(aws eks list-clusters --region "$REGION" \
--query "clusters[?starts_with(@, '${CLUSTER_PREFIX}')]" --output text)

if [ -z "$CLUSTERS" ]; then
echo "No clusters found with prefix '${CLUSTER_PREFIX}'."
exit 0
fi

CUTOFF=$(date -d "1 day ago" +%s)

for c in $CLUSTERS; do
CREATED=$(aws eks describe-cluster --name "$c" --region "$REGION" \
--query "cluster.createdAt" --output text 2>/dev/null || true)

if [ -z "$CREATED" ] || [ "$CREATED" == "None" ]; then
echo "Unable to fetch creation time for $c — skipping."
continue
fi

CREATED_EPOCH=$(date -d "$CREATED" +%s)
script {
pmmHaEks.deleteAllClusters(
region: env.REGION,
r53ZoneName: env.R53_ZONE_NAME,
skipNewest: true, // Always protect newest during cron
maxAgeHours: 24 // Only delete clusters older than 24h
)
}
}
}
}

if [ "$CREATED_EPOCH" -lt "$CUTOFF" ]; then
eksctl delete cluster --region "$REGION" --name "$c" \
--disable-nodegroup-eviction --wait
else
echo "Skipping recent cluster: $c (created within last 24h)"
fi
done
'''
stage('Cleanup Orphan Resources') {
when { expression { env.ACTION == 'CLEANUP_ORPHANS' } }
steps {
withCredentials([aws(credentialsId: 'pmm-staging-slave')]) {
script {
pmmHaEks.cleanupOrphans(region: env.REGION)
}
}
}
}
Expand Down
Loading