#!/bin/bash # Declare an associative array to store the images used on each machine declare -A MACHINE_CONTAINER_IMAGES TEST_MACHINES=( "lrineau@bonnard" "lrineau@cgal" "cgaltest@friedrich" "lrineau@rubens" ) machine_title() { printf '\n## %s ##\n' "$1" } machine_info() { HOST=$1 remote_script=$(printf "export PS4='+ %s >> %s'\n" "$HOST" "$PS4")$'\n'$( cat <<'EOF' source /etc/os-release printf '\n- OS: `%s`\n- container implementation: `%s`\n' "$PRETTY_NAME" "$(docker --version)" EOF ) ssh "$HOST" bash -$- -s <<<"$remote_script" } machine_tested_images() { echo echo '```plain' printf '%s\n' "${MACHINE_CONTAINER_IMAGES["$1"]}" echo '```' } docker_is_active_cmd() { systemctl is-active -q docker return $? } declare -xf docker_is_active_cmd docker_cmd() { if docker_is_active_cmd; then docker "$@" else podman --url unix:/var/run/podman/podman.sock "$@" fi } declare -xf docker_cmd list_of_containers_cmd() { docker_cmd ps -a --format '{{.Names}}' --filter name="CGAL-" } declare -xf list_of_containers_cmd container_status_cmd() { docker_cmd inspect --format '{{.State.Status}}' "$1" } declare -xf container_status_cmd container_human_readable_status_cmd() { docker_cmd ps --all --filter name="$1" --format '{{.Status}}' } declare -xf container_human_readable_status_cmd simplify_date_cmd() { date=$1 pattern=' \+[0-9]{4} [+]?[A-Z0-9]{3,}$' if [[ $date =~ $pattern ]]; then date=${date% *} fi echo "$date" } declare -xf simplify_date_cmd container_start_time_cmd() { simplify_date_cmd "$(docker_cmd inspect --format '{{.State.StartedAt}}' "$1")" } declare -xf container_start_time_cmd container_end_time_cmd() { simplify_date_cmd "$(docker_cmd inspect --format '{{.State.FinishedAt}}' "$1")" } declare -xf container_end_time_cmd container_running_time_cmd() { start_time=$(container_start_time_cmd "$1") end_time=$(container_end_time_cmd "$1") status=$(container_status_cmd "$1") if [ "$status" = "running" ]; then end_time=$(date -u '+%Y-%m-%dT%H:%M:%S.%NZ') fi secs=$(($(date -d "$end_time" +%s) - $(date -d "$start_time" +%s))) printf '%02dh:%02dm:%02ds\n' $((secs / 3600)) $((secs % 3600 / 60)) $((secs % 60)) } declare -xf container_running_time_cmd display_one_container_line_cmd() { printf '%s\t%s\t%s\t%s\t%s\n' "$1" "$2" "$3" "$4" "$5" } declare -xf display_one_container_line_cmd list_cgal_test_container_cmd() { # docker_cmd ps -a --filter name=CGAL- display_one_container_line_cmd "CONTAINER" "START TIME" "END TIME" "RUNNING TIME" "STATUS" for container in $(list_of_containers_cmd); do start_time="$(container_start_time_cmd "$container")" end_time="$(container_end_time_cmd "$container")" dur=$(container_running_time_cmd "$container") status="$(container_status_cmd "$container") - $(container_human_readable_status_cmd "$container")" display_one_container_line_cmd "$container" "$start_time" "$end_time" "$dur" "$status" done } declare -xf list_cgal_test_container_cmd display_all_exported_cmd_functions() { functions=$(declare -F | awk '/ -fx .*_cmd$/ {print $3}') for func in $functions; do declare -f "$func" done } machine_list_cgal_test_container() { printf '\n```tsv\n' remote_script=$( display_all_exported_cmd_functions printf "export PS4='+ %s >> %s'\n" "$1" "$PS4" echo list_cgal_test_container_cmd ) ssh "$1" bash -$- -s <<<"$remote_script" printf '```\n' } help() { cat <&2 echo "ERROR: $1" echo help exit 1 } command -v sed >/dev/null || { error_out 'sed is required' } if [[ $1 == --table ]] && ! command -v pandoc >/dev/null; then error_out 'pandoc is required for the option --table' fi if [[ $1 == --column ]] && ! command -v column >/dev/null; then error_out 'column is required for the option --column' fi if [[ $1 == --bat ]] && ! command -v bat >/dev/null; then error_out 'bat is required for the option --bat' fi set_pretty_csv_to_md_table() { pretty_csv() ( echo sed '/```/ d; /^$/ d' | pandoc -f tsv -t gfm ) } set_pretty_csv_to_column() { pretty_csv() { echo column -t -s $'\t' -o $'\t' | sed 's/^\(```[^ ]*\) *\t.*/\1/' } } set_pretty_csv_to_column_and_bat() { pretty_csv() { echo column -t -s $'\t' -o $'\t' | sed 's/^\(```[^ ]*\) *\t.*/\1/' | bat --paging=never --plain -l csv } } set_pretty_csv_to_bat() { pretty_csv() { bat --tabs=50 --paging=never --plain -l csv } } set_pretty_csv_to_cat() { pretty_csv() { cat } } WHAT=() add_to_what() { for i in "$@"; do WHAT+=("$i") done } what_contains() { local item=$1 for i in "${WHAT[@]}"; do if [[ "$i" == "$item" ]]; then return 0 fi done return 1 } for arg in "$@"; do case "$arg" in --table) set_pretty_csv_to_md_table ;; --column) set_pretty_csv_to_column ;; --bat) set_pretty_csv_to_bat ;; --plain) set_pretty_csv_to_cat ;; --images) add_to_what images ;; --containers) add_to_what containers ;; --info) add_to_what info ;; -h | --help) help >&2 exit 0 ;; *) error_out "Unknown option $arg" ;; esac done if [ ${#WHAT[@]} -eq 0 ]; then add_to_what info images containers fi STDOUT_IS_A_TTY= if <&1 tty -s; then STDOUT_IS_A_TTY=1 fi BAT= [ -n "$STDOUT_IS_A_TTY" ] && BAT=$(command -v bat) COLUMN=$(command -v column) PANDOC=$(command -v pandoc) if ! declare -f pretty_csv >/dev/null; then if [ -n "$BAT" ]; then if [ -n "$COLUMN" ]; then set_pretty_csv_to_column_and_bat else set_pretty_csv_to_bat fi elif [ -n "$PANDOC" ]; then set_pretty_csv_to_md_table elif [ -n "$COLUMN" ]; then set_pretty_csv_to_column else set_pretty_csv_to_cat fi fi ERROR_MACHINES="" for machine in "${TEST_MACHINES[@]}"; do USER=${machine%@*} HOST=${machine#*@} # shellcheck disable=SC2029 MACHINE_CONTAINER_IMAGES[$machine]=$(ssh "$HOST" cat "/home/$USER/.config/CGAL/test_cgal_docker_images") || { ERROR_MACHINES="$ERROR_MACHINES $machine" } done if [ -n "$ERROR_MACHINES" ]; then printf '\n> %s\n> %s\n' '[!CAUTION]' 'ERROR:' for machine in $ERROR_MACHINES; do USER=${machine%@*} HOST=${machine#*@} # shellcheck disable=SC2016 printf '> - ERROR: cannot read file `/home/%s/.config/CGAL/test_cgal_docker_images` on ssh host `%s`\n' "$USER" "$HOST" done exit 1 fi cat <