Last active
January 3, 2024 20:30
-
-
Save jakefhyde/8646915941fa84a942397df5fb3ed1c8 to your computer and use it in GitHub Desktop.
Runs an ssh command on all nodes in a rancher v2prov cluster
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # | |
| # Given a command, rancher server url, rancher admin token, namespace and name of a v2prov cluster: | |
| # 1. Get the management cluster name | |
| # 2. Download the kubeconfig | |
| # 3. Get the list of CAPI machines | |
| # 4. For each CAPI machine: | |
| # a. Download the ssh keys to a temp directory | |
| # b. Get the IP address of the node | |
| # b. Run a command on the node via ssh | |
| set -e | |
| function display_help() { | |
| echo "Usage: $(basename $0) --source [source tag] --dest [dest tag]" | |
| echo | |
| echo ' $RANCHER_TOKEN [Required] environment variable containing rancher admin token' | |
| echo ' -s, --server-url [Required] rancher server url' | |
| echo " -c, --cluster [Required] target cluster name (provisioning.cattle.io)" | |
| echo " -r, --run-command [Required] ssh command to run on the nodes" | |
| echo " -n, --namespace [Optional] namespace cluster & machines live in (default: fleet-default)" | |
| echo " -l, --label-selector [Optional] selector to use to filter machines" | |
| echo " -d, --debug [Optional] calls 'set -x'" | |
| echo " -h, --help print this message" | |
| } | |
| POSITIONAL_ARGS=() | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| -s|--server-url) | |
| SERVER_URL="$2" | |
| shift # past argument | |
| shift # past value | |
| ;; | |
| -c|--cluster) | |
| CLUSTER="$2" | |
| shift # past argument | |
| shift # past value | |
| ;; | |
| -n|--namespace) | |
| NAMESPACE="$2" | |
| shift # past argument | |
| shift # past value | |
| ;; | |
| -l|--label-selector) | |
| LABEL_SELECTOR="$2" | |
| shift # past argument | |
| shift # past value | |
| ;; | |
| -r|--run-command) | |
| RUN_COMMAND="$2" | |
| shift # past argument | |
| shift # past value | |
| ;; | |
| -d|--debug) | |
| set -x | |
| shift # past argument | |
| ;; | |
| -h|--help) | |
| display_help | |
| exit 1 | |
| ;; | |
| -*|--*) | |
| echo "Unknown option $1" | |
| display_help | |
| exit 1 | |
| ;; | |
| *) | |
| POSITIONAL_ARGS+=("$1") # save positional arg | |
| shift # past argument | |
| ;; | |
| esac | |
| done | |
| set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters | |
| if [[ -z "$RANCHER_TOKEN" ]]; then | |
| echo '$RANCHER_TOKEN is unset' | |
| display_help | |
| exit 1 | |
| fi | |
| if [[ -z "$SERVER_URL" ]]; then | |
| echo '--server-url is unset' | |
| display_help | |
| exit 1 | |
| fi | |
| if [[ -z "$CLUSTER" ]]; then | |
| echo '--cluster is unset' | |
| display_help | |
| exit 1 | |
| fi | |
| if [[ -z "$RUN_COMMAND" ]]; then | |
| echo '--run-command is unset' | |
| display_help | |
| exit 1 | |
| fi | |
| NAMESPACE=${NAMESPACE:-fleet-default} | |
| runCommand() { | |
| local machineName | |
| machineName="$1" | |
| local runCmd | |
| runCmd="$2" | |
| local nodeName | |
| nodeName="$(kubectl get machine -n "${NAMESPACE}" "$machineName" -o json | jq -r '.status.nodeRef.name')" | |
| local ip | |
| ip="$(kubectl get machine -n "${NAMESPACE}" "$machineName" -o json | jq -r '.status.addresses[0].address')" | |
| echo "Running command '${RUN_COMMAND}' on machine '$machineName' with address '$ip'" | |
| ssh -o "StrictHostKeyChecking no" -i "./${nodeName}/id_rsa" "root@$ip" "${runCmd}" | |
| } | |
| downloadKeys() { | |
| local machineName | |
| machineName="$1" | |
| echo "Downloading ssh key for machine '$machineName'" | |
| curl "https://${SERVER_URL}/v1/cluster.x-k8s.io.machines/${NAMESPACE}/${machineName}/sshkeys" \ | |
| -s \ | |
| -H "cookie: R_SESS=${RANCHER_TOKEN}" \ | |
| --compressed \ | |
| -o "${machineName}.zip" | |
| unzip "${machineName}.zip" > /dev/null | |
| rm "${machineName}.zip" | |
| } | |
| getAllMachines() { | |
| echo "Getting local cluster CAPI machines belonging to cluster '$CLUSTER'" | |
| if [[ -n $LABEL_SELECTOR ]]; then | |
| LABEL_SELECTOR="cluster.x-k8s.io/cluster-name=${CLUSTER},${LABEL_SELECTOR}" | |
| else | |
| LABEL_SELECTOR="cluster.x-k8s.io/cluster-name=${CLUSTER}" | |
| fi | |
| MACHINES=$(kubectl --kubeconfig .kube/config get machines -n "${NAMESPACE}" -l "${LABEL_SELECTOR}" -o jsonpath='{.items[*].metadata.name}') | |
| } | |
| # Unused, but useful | |
| getKubeConfig() { | |
| curl "https://${SERVER_URL}/v3/clusters/${MANAGEMENT_CLUSTER_NAME}?action=generateKubeconfig" \ | |
| -X 'POST' \ | |
| -H 'accept: application/yaml' \ | |
| -H "cookie: R_SESS=${RANCHER_TOKEN}" \ | |
| --compressed | yq -r '.config' > .kube/config | |
| } | |
| getLocalKubeConfig() { | |
| echo "Getting local cluster kubeconfig" | |
| curl "https://${SERVER_URL}/v3/clusters/local?action=generateKubeconfig" \ | |
| -X 'POST' \ | |
| -H 'accept: application/yaml' \ | |
| -H "cookie: R_SESS=${RANCHER_TOKEN}" \ | |
| --compressed | yq -r '.config' > .kube/config | |
| } | |
| getManagementClusterName() { | |
| echo "Getting name of management cluster" | |
| MANAGEMENT_CLUSTER_NAME=$(curl "https://${SERVER_URL}/v1/provisioning.cattle.io.cluster/${NAMESPACE}/${CLUSTER}" \ | |
| -H 'accept: application/json' \ | |
| -H "cookie: R_SESS=${RANCHER_TOKEN}" \ | |
| --compressed | jq -r '.status.clusterName') | |
| } | |
| main() { | |
| cd "$(mktemp -d)" | |
| mkdir -p .kube | |
| getManagementClusterName | |
| getLocalKubeConfig | |
| getAllMachines | |
| for machine in $MACHINES; do | |
| downloadKeys "$machine" | |
| runCommand "$machine" "$RUN_COMMAND" | |
| done | |
| } | |
| main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment