Skip to content

Commit

Permalink
Refactor options parsing. Introduce shutdown and reboot actions. (#8)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrei Kvapil <[email protected]>
  • Loading branch information
kvaps authored Jan 26, 2024
1 parent 427f7e2 commit e0269e1
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 85 deletions.
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ sudo mv ./talos-bootstrap /usr/local/bin/talos-bootstrap

```
USAGE:
talosctl ACTION
talos-bootstrap ACTION [OPTIONS]
ACTIONS:
-a Add a node to a new or existing cluster.
-u Upgrade a node in an existing cluster.
-r Reset and remove a node from an existing cluster.
-d Dashboard for a node in an existing cluster.
help Show this help message.
install Setup a node for a new or existing cluster.
upgrade Upgrade a node in an existing cluster.
reset Reset and remove a node from an existing cluster.
reboot Reboot a node.
shutdown Shutdown a node.
dashboard Open dashboard for a node.
OPTIONS:
-n, --node <address> Node address
```

### Customizations
Expand Down
204 changes: 124 additions & 80 deletions talos-bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,52 @@
# - https://google.github.io/styleguide/shell.xml
#

case "$1" in
-a)
OP=install
OPTS="-i"
node=
OP=
while [ $# -gt 0 ]; do
key="$1"
case $key in
-n | --node)
node="$2"
shift
shift
;;
-u)
OP=upgrade
OPTS="--talosconfig=talosconfig"
-*)
echo "flag provided but not defined: ${1}" >&2
exit 1
;;
-d)
OP=dashboard
OPTS="--talosconfig=talosconfig"
*)
if [ -z "$OP" ]; then
OP="${1}"
shift
else
echo "exactly one action required" >&2
exit 1
fi
;;
-r)
OP=reset
esac
done

case "$OP" in
install)
OPTS="-i"
;;
upgrade|dashboard|reboot|shutdown|reset)
OPTS="--talosconfig=talosconfig"
;;
*)
printf "USAGE:\n\t%s\n" "talosctl ACTION"
printf "ACTIONS:\n"
printf "\t%s\t%s\n" "-a" "Add a node to a new or existing cluster."
printf "\t%s\t%s\n" "-u" "Upgrade a node in an existing cluster."
printf "\t%s\t%s\n" "-r" "Reset and remove a node from an existing cluster."
printf "\t%s\t%s\n" "-d" "Dashboard for a node in an existing cluster."
exit 0
printf "USAGE:\n\t%s\n" "talos-bootstrap ACTION [OPTIONS]"
printf "\nACTIONS:\n"
printf "\t%s\t\t%s\n" "help" "Show this help message."
printf "\t%s\t\t%s\n" "install" "Setup a node for a new or existing cluster."
printf "\t%s\t\t%s\n" "upgrade" "Upgrade a node in an existing cluster."
printf "\t%s\t\t%s\n" "reset" "Reset and remove a node from an existing cluster."
printf "\t%s\t\t%s\n" "reboot" "Reboot a node."
printf "\t%s\t%s\n" "shutdown" "Shutdown a node."
printf "\t%s\t%s\n" "dashboard" "Open dashboard for a node."
printf "\nOPTIONS:\n"
printf "\t%s <%s>\t%s\n" "-n, --node" "address" "Node address"
exit 1
;;
esac

Expand Down Expand Up @@ -64,72 +85,78 @@ else
cluster_name=$(dialog --keep-tite --title talos-bootstrap --inputbox "Enter cluster name:" 8 40 "${default_cluster_name}" 3>&1 1>&2 2>&3) || exit 0
fi

# Screen: Enter networks to scan
default_scan_networks=$(ip -o route | awk '$3 !~ /^(docker|cni)/ && $2 == "dev" {print $1}' | awk '$1=$1' RS=" " OFS=" ")
scan_networks=$(dialog --keep-tite --title talos-bootstrap --inputbox "Enter networks to scan:" 8 80 "${default_scan_networks}" 3>&1 1>&2 2>&3) || exit 0
scan_networks=$(echo "${scan_networks}" | awk -F, '{$1=$1}1' OFS=' ')
if [ -n "${node}" ]; then
talosctl -e "${node}" -n "${node}" get machinestatus ${OPTS} >/dev/null || exit $?
else
# Screen: Enter networks to scan
default_scan_networks=$(ip -o route | awk '$3 !~ /^(docker|cni)/ && $2 == "dev" {print $1}' | awk '$1=$1' RS=" " OFS=" ")
scan_networks=$(dialog --keep-tite --title talos-bootstrap --inputbox "Enter networks to scan:" 8 80 "${default_scan_networks}" 3>&1 1>&2 2>&3) || exit 0
scan_networks=$(echo "${scan_networks}" | awk -F, '{$1=$1}1' OFS=' ')

node_list_file=$(mktemp)
node_list_file=$(mktemp)

# Screen: Seatching Talos nodes
{
printf "%s\nXXX\n%s\nXXX\n" "10" "Searching Talos nodes in ${scan_networks}..."
candidate_nodes=$(nmap -Pn -n -p 50000 ${scan_networks} -vv | awk '/Discovered open port/ {print $NF}')
# Screen: Seatching Talos nodes
{
printf "%s\nXXX\n%s\nXXX\n" "10" "Searching Talos nodes in ${scan_networks}..."
candidate_nodes=$(nmap -Pn -n -p 50000 ${scan_networks} -vv | awk '/Discovered open port/ {print $NF}')

#echo found:
#printf " - %s\n" $candidate_nodes
#echo found:
#printf " - %s\n" $candidate_nodes

if [ "$OP" != install ]; then
printf "%s\nXXX\n%s\nXXX\n" "40" "Filtering nodes in the cluster..."
else
printf "%s\nXXX\n%s\nXXX\n" "40" "Filtering nodes in maintenance mode..."
fi
nodes=
for node in ${candidate_nodes}; do
if talosctl -e "${node}" -n "${node}" get machinestatus ${OPTS} >/dev/null 2>/dev/null; then
nodes="${nodes} ${node}"
if [ "$OP" != install ]; then
printf "%s\nXXX\n%s\nXXX\n" "40" "Filtering nodes in the cluster..."
else
printf "%s\nXXX\n%s\nXXX\n" "40" "Filtering nodes in maintenance mode..."
fi
done

#echo filtered:
#printf " - %s\n" $nodes

printf "%s\nXXX\n%s\nXXX\n" "60" "Collecting information about the nodes..."
node_list=$(
seen=
for node in ${nodes}; do
mac=$(talosctl -e "${node}" -n "${node}" get hardwareaddresses.net.talos.dev first ${OPTS} -o jsonpath='{.spec.hardwareAddr}')
case " ${seen} " in *" ${mac} "*) continue ;; esac # remove duplicated nodes
seen="${seen} ${mac}"
name="${node}"
hostname=$(talosctl -e "${node}" -n "${node}" get hostname ${OPTS} -o jsonpath='{.spec.hostname}')
if [ -n "${hostname}" ]; then
name="${name} (${hostname})"
nodes=
for node in ${candidate_nodes}; do
if talosctl -e "${node}" -n "${node}" get machinestatus ${OPTS} >/dev/null 2>/dev/null; then
nodes="${nodes} ${node}"
fi
manufacturer=$(talosctl -e "${node}" -n "${node}" get cpu ${OPTS} -o jsonpath='{.spec.manufacturer}' | head -n1)
cpu=$(talosctl -e "${node}" -n "${node}" get cpu ${OPTS} -o jsonpath='{.spec.threadCount}' | awk '{sum+=$1;} END{print sum "-core";}')
ram=$(talosctl -e "${node}" -n "${node}" get ram -o json ${OPTS} | awk '/"sizeMiB":/ {sub(",", ""); sum+=$2} END{print sum/1024 "GB"}')
disks=$(talosctl -e "${node}" -n "${node}" disks ${OPTS} | awk 'NR>1 {sub(/^[^/]*/, ""); print}' | awk -F' +' '{print $1 ":" $9}' | awk -F/ '$2 == "dev" {print $3}' | awk 'gsub(" ", "", $0)' | awk '$1=$1' RS="," OFS=",")
echo "\"${name}\"" "\"${mac}, ${cpu} ${manufacturer:-CPU}, RAM: ${ram}, Disks: [${disks}]\""
done
)

echo "${node_list}" > "${node_list_file}"
} | dialog --keep-tite --title talos-bootstrap --gauge "Please wait" 10 70 0 3>&1 1>&2 2>&3 || exit 0
#echo filtered:
#printf " - %s\n" $nodes

printf "%s\nXXX\n%s\nXXX\n" "60" "Collecting information about the nodes..."
node_list=$(
seen=
for node in ${nodes}; do
mac=$(talosctl -e "${node}" -n "${node}" get hardwareaddresses.net.talos.dev first ${OPTS} -o jsonpath='{.spec.hardwareAddr}')
case " ${seen} " in *" ${mac} "*) continue ;; esac # remove duplicated nodes
seen="${seen} ${mac}"
name="${node}"
hostname=$(talosctl -e "${node}" -n "${node}" get hostname ${OPTS} -o jsonpath='{.spec.hostname}')
if [ -n "${hostname}" ]; then
name="${name} (${hostname})"
fi
manufacturer=$(talosctl -e "${node}" -n "${node}" get cpu ${OPTS} -o jsonpath='{.spec.manufacturer}' | head -n1)
cpu=$(talosctl -e "${node}" -n "${node}" get cpu ${OPTS} -o jsonpath='{.spec.threadCount}' | awk '{sum+=$1;} END{print sum "-core";}')
ram=$(talosctl -e "${node}" -n "${node}" get ram -o json ${OPTS} | awk '/"sizeMiB":/ {sub(",", ""); sum+=$2} END{print sum/1024 "GB"}')
disks=$(talosctl -e "${node}" -n "${node}" disks ${OPTS} | awk 'NR>1 {sub(/^[^/]*/, ""); print}' | awk -F' +' '{print $1 ":" $9}' | awk -F/ '$2 == "dev" {print $3}' | awk 'gsub(" ", "", $0)' | awk '$1=$1' RS="," OFS=",")
echo "\"${name}\"" "\"${mac}, ${cpu} ${manufacturer:-CPU}, RAM: ${ram}, Disks: [${disks}]\""
done
)

echo "${node_list}" > "${node_list_file}"
} | dialog --keep-tite --title talos-bootstrap --gauge "Please wait" 10 70 0 3>&1 1>&2 2>&3 || exit 0

node_list=$(cat "${node_list_file}")
node_list=$(cat "${node_list_file}")

if [ -z "${node_list}" ]; then
dialog --keep-tite --title talos-bootstrap --msgbox "No Talos nodes in maintenance mode found!
if [ -z "${node_list}" ]; then
dialog --keep-tite --title talos-bootstrap --msgbox "No Talos nodes in maintenance mode found!
Searched networks: ${scan_networks}" 10 60
exit 1
Searched networks: ${scan_networks}" 10 60
exit 1
fi

# Screen: Node list
node=$(echo "${node_list}" | dialog --keep-tite --title talos-bootstrap --menu "Select node to $OP" 0 0 0 --file /dev/stdin 3>&1 1>&2 2>&3) || exit 0
# cut hostname
node=$(echo "${node}" | awk '{print $1}')
fi

# Screen: Node list
node=$(echo "${node_list}" | dialog --keep-tite --title talos-bootstrap --menu "Select node to $OP" 0 0 0 --file /dev/stdin 3>&1 1>&2 2>&3) || exit 0
# cut hostname
node=$(echo "${node}" | awk '{print $1}')
# --- Management flows beginning

# Run dashboard flow
if [ "$OP" = dashboard ]; then
Expand Down Expand Up @@ -157,6 +184,28 @@ if [ "$OP" = reset ]; then
talosctl -e "${node}" -n "${node}" ${OPTS} ${reset_opt} --wipe-mode="${wipe_mode}" reset
exit $?
fi
# Run reboot flow
if [ "$OP" = reboot ]; then
reboot_mode=$(dialog --keep-tite --title talos-bootstrap --menu "Select reboot option" 15 60 4 \
"default" "Default mode" \
"powercycle" "Skips kexec" 3>&1 1>&2 2>&3) || exit 0
talosctl -e "${node}" -n "${node}" ${OPTS} ${reboot_opt} --mode="${reboot_mode}" reboot
exit $?
fi
# Run shutdown flow
if [ "$OP" = shutdown ]; then
shutdown_option=$(dialog --keep-tite --title talos-bootstrap --menu "Select shutdown option" 15 60 4 \
"1" "Default mode" \
"2" "Force a node to shutdown without a cordon/drain" 3>&1 1>&2 2>&3) || exit 0
case ${shutdown_option} in
1) shutdown_opt="--force=false" ;;
2) shutdown_opt="--force=true" ;;
esac
talosctl -e "${node}" -n "${node}" ${OPTS} ${shutdown_opt} shutdown
exit $?
fi

# --- Management flows end

# Screen: Select role
role=$(dialog --keep-tite --title talos-bootstrap --menu "Select role" 0 0 0 \
Expand Down Expand Up @@ -324,8 +373,8 @@ talosctl apply -e "${bootstrap_ip}" -n "${bootstrap_ip}" -f "${role}.yaml" ${OPT
if [ $? = 124 ]; then
old_is_up=0
fi
if [ "$status" = upgrading ] || [ "$status" = rebooting ]; then
continue
if [ "$status" = upgrading ] || [ "$status" = rebooting ]; then
continue
fi
else
if ! ping -W1 -c1 "${node}" >/dev/null 2>&1; then
Expand Down Expand Up @@ -389,9 +438,4 @@ if [ ! -f kubeconfig ]; then
fi

# Screen: Complete installation
dialog --keep-tite --title talos-bootstrap --msgbox "Installation finished!
You will now be directed to the dashboard" 0 0

# Screen: Talos dashboard
talosctl --talosconfig=talosconfig -e "${node}" -n "${node}" dashboard
dialog --keep-tite --title talos-bootstrap --msgbox "Installation finished!" 5 26

0 comments on commit e0269e1

Please sign in to comment.