|
| 1 | +#!/usr/bin/env bash |
| 2 | +# |
| 3 | +# Copyright 2023 The Kubernetes Authors. |
| 4 | +# |
| 5 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | +# you may not use this file except in compliance with the License. |
| 7 | +# You may obtain a copy of the License at |
| 8 | +# |
| 9 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | +# |
| 11 | +# Unless required by applicable law or agreed to in writing, software |
| 12 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | +# See the License for the specific language governing permissions and |
| 15 | +# limitations under the License. |
| 16 | +# |
| 17 | +# Requires: jq, kubectl, cmk (get https://github.com/apache/cloudstack-cloudmonkey/releases/tag/6.4.0-rc1 or later) |
| 18 | +# |
| 19 | +# About: this tool helps to remove CloudStack affinity groups from CAPC |
| 20 | +# management cluster which are not assigned to any instances. |
| 21 | +# |
| 22 | +# Usage and help: |
| 23 | +# chmod +x cleanup-ag.sh |
| 24 | +# ./cleanup-ag.sh -h |
| 25 | + |
| 26 | +set -o errexit |
| 27 | +set -o nounset |
| 28 | +set -o pipefail |
| 29 | + |
| 30 | +export DRY_RUN=false |
| 31 | +export VERBOSE=false |
| 32 | +export KUBECONFIG=$HOME/.kube/config |
| 33 | + |
| 34 | +debug() { |
| 35 | + if [[ "$VERBOSE" == "true" ]]; then |
| 36 | + echo $@ |
| 37 | + fi |
| 38 | +} |
| 39 | + |
| 40 | +get_affinity_groups() { |
| 41 | + kubectl get cloudstackaffinitygroups -o json -A | jq -r '.items[].metadata.name' |
| 42 | +} |
| 43 | + |
| 44 | +get_cluster() { |
| 45 | + affinityGroup=$1 |
| 46 | + kubectl get cloudstackaffinitygroup $affinityGroup -o json | jq -r '.metadata.labels."cluster.x-k8s.io/cluster-name"' |
| 47 | +} |
| 48 | + |
| 49 | +get_cluster_credentials() { |
| 50 | + cluster=$1 |
| 51 | + kubectl get cloudstackcluster $cluster -o json | jq -r '.spec.failureDomains[].acsEndpoint.name' | uniq |
| 52 | +} |
| 53 | + |
| 54 | +setup_acs_credentials() { |
| 55 | + credential=$1 |
| 56 | + export CS_URL=$(kubectl get secret $credential -o json | jq -r '.data."api-url"' | base64 -D) |
| 57 | + export CS_APIKEY=$(kubectl get secret $credential -o json | jq -r '.data."api-key"' | base64 -D) |
| 58 | + export CS_SECRETKEY=$(kubectl get secret $credential -o json | jq -r '.data."secret-key"' | base64 -D) |
| 59 | + debug "Using CloudStack Control Plane URL: $CS_URL and CloudStack Account: $(run_cmk list users | jq -r '.user[] | .account + " and User: " + .username')" |
| 60 | +} |
| 61 | + |
| 62 | +run_cmk() { |
| 63 | + cmk -u $CS_URL -k $CS_APIKEY -s $CS_SECRETKEY -o json $@ |
| 64 | +} |
| 65 | + |
| 66 | +main() { |
| 67 | + for ag in $(get_affinity_groups); do |
| 68 | + echo "Checking CloudStack Affinity Group: $ag" |
| 69 | + cluster=$(get_cluster $ag) |
| 70 | + for credential in $(get_cluster_credentials $cluster); do |
| 71 | + setup_acs_credentials $credential |
| 72 | + CS_AG_ID=$(kubectl get cloudstackaffinitygroup $ag -o json | jq -r '.spec.id') |
| 73 | + CS_AG_VMS=$(run_cmk list affinitygroups id=$CS_AG_ID | jq -r '.affinitygroup[0].virtualmachineIds') |
| 74 | + if [[ "$CS_AG_VMS" == "null" ]]; then |
| 75 | + echo "Found Affinity Group ($CS_AG_ID) with no instances assigned:" $ag |
| 76 | + if [[ "$DRY_RUN" == "false" ]]; then |
| 77 | + kubectl delete cloudstackaffinitygroup $ag |
| 78 | + echo "Affinity Group ($CS_AG_ID) $ag has been removed" |
| 79 | + else |
| 80 | + echo "[DRY RUN] Affinity Group ($CS_AG_ID) $ag has been removed" |
| 81 | + fi |
| 82 | + fi |
| 83 | + done |
| 84 | + done |
| 85 | +} |
| 86 | + |
| 87 | +help() { |
| 88 | + echo "Usage: $0 [-d|k|h|v]" |
| 89 | + echo |
| 90 | + echo "This cleanup tool helps to remove CloudStack affinity groups from CAPC" |
| 91 | + echo "management cluster which are not assigned to any instances, which may" |
| 92 | + echo "have been created as a side effect of other operations. This tool checks" |
| 93 | + echo "all the cloudstackaffinitygroups using its CloudStack cluster specific" |
| 94 | + echo "credential(s) and uses cmk to check if the affinity group have no" |
| 95 | + echo "instances assigned. In dry-run, it outputs such affinity groups" |
| 96 | + echo "otherwise it deletes them." |
| 97 | + echo |
| 98 | + echo "Options:" |
| 99 | + echo "-d Runs the tools in dry-run mode" |
| 100 | + echo "-k Pass custom kube config, default: \$HOME/.kube/config" |
| 101 | + echo "-h Print this help" |
| 102 | + echo "-v Verbose mode" |
| 103 | + echo |
| 104 | +} |
| 105 | + |
| 106 | +while getopts ":dkvh" option; do |
| 107 | + case $option in |
| 108 | + d) |
| 109 | + export DRY_RUN=true;; |
| 110 | + k) |
| 111 | + export KUBECONFIG=$OPTARG;; |
| 112 | + v) |
| 113 | + export VERBOSE=true;; |
| 114 | + h) |
| 115 | + help |
| 116 | + exit;; |
| 117 | + \?) |
| 118 | + echo "Error: Invalid option provided, please see help docs" |
| 119 | + help |
| 120 | + exit;; |
| 121 | + esac |
| 122 | +done |
| 123 | + |
| 124 | +main |
0 commit comments