scripts/dell/start-virtual-console.bash

420 lines
13 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
#
# Purpose {{{
# This script will try to start an iDrac 6/7 virtual console
# 1. Ask for an host if not given with the option.
# 2. Ask for a user if not given with the option.
# 3. Ask for the password.
#
# Inspired from : https://gist.github.com/xbb/4fd651c2493ad9284dbcb827dc8886d6
#
# 2023-02-15
# }}}
# Flags {{{
## Exit on error {{{
set -o errexit
## }}}
## Exit on unset var {{{
### Use "${VARNAME-}" to test a var that may not have been set
set -o nounset
## }}}
## Pipeline command is treated as failed {{{
### Not available in POSIX sh https://github.com/koalaman/shellcheck/wiki/SC3040
#set -o pipefail
## }}}
## Help with debugging {{{
### Call the script by prefixing it with "TRACE=1 ./script.sh"
if [ "${TRACE-0}" -eq 1 ]; then set -o xtrace; fi
## }}}
# }}}
# Vars {{{
PROGNAME=$(basename "${0}"); readonly PROGNAME
PROGDIR=$(readlink --canonicalize-missing $(dirname "${0}")); readonly PROGDIR
ARGS="${*}"; readonly ARGS
readonly NBARGS="${#}"
[ -z "${DEBUG-}" ] && DEBUG=1
## Export DEBUG for sub-script
export DEBUG
## Default values for some vars
readonly IDRAC_USERNAME_DEFAULT="root"
readonly IDRAC_PORT_DEFAULT="443"
readonly JAVA_DISABLE_ALGO_DEFAULT="SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, EC keySize < 224, anon, NULL, include jdk.disabled.namedCurves"
readonly JAVA_SECURITY_FILENAME="idrac.java.security"
readonly TEMP_DIR_BASE="/tmp"
## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() { # {{{
cat <<- HELP
usage: $PROGNAME [-d|-h] [--user idrac_username] [--host idrac.hostname] [--port port.number] [--temp /path/to/temp/directory]
Try to start an iDrac 6/7 virtual console with given informations.
The password will always be asked and not displayed.
EXAMPLES:
- Start the script and wait for prompt to enter informations
${PROGNAME}
- Start virtual console of a given host
${PROGNAME} --host "oob-myserver.domain.tld"
- Start virtual console with SSH Port forwarding
${PROGNAME} --host "localhost:7200"
- Use specific username
${PROGNAME} --user "admin"
- Store downloaded files and informations in a specific temp directory
${PROGNAME} --temp /tmp/my.idrac.temp.dir
OPTIONS:
-d,--debug
Enable debug messages.
-h,--help
Print this help message.
--host
Define the iDrac host to connect.
Fallback: It will be asked to the user.
-p,--port
Define the iDrac port to use.
The script will try to parse the given value of hostname and extract a port number
Fallback: It will be asked to the user.
Default : ${IDRAC_PORT_DEFAULT}
-u,--user
Define the iDrac username.
Fallback: It will be asked to the user.
Default : ${IDRAC_USERNAME_DEFAULT}
--temp,--temp-dir,--temp-directory
Define the temp directoy to store downloaded files and informations.
Default : ${TEMP_DIR_BASE}/idrac.given_hostname
--java-disable-algo
Override global java security settings.
To allow old console to work on new java environment.
Default : ${JAVA_DISABLE_ALGO_DEFAULT}
For more informations, see : https://gist.github.com/xbb/4fd651c2493ad9284dbcb827dc8886d6?permalink_comment_id=4006481#gistcomment-4006481
HELP
}
# }}}
debug_message() { # {{{
local_debug_message="${1}"
## Print message if DEBUG is enable (=0)
[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG ${PROGNAME}: ${local_debug_message}"
unset local_debug_message
return 0
}
# }}}
error_message() { # {{{
local_error_message="${1}"
local_error_code="${2}"
## Print message
printf '%b\n' "ERROR ${PROGNAME}: ${RED}${local_error_message}${RESET}" >&2
unset local_error_message
exit "${local_error_code:=66}"
}
# }}}
define_vars() { # {{{
## If idrac_host_temp wasn't defined (argument) {{{
if [ -z "${idrac_host_temp-}" ]; then
### Ask the user to enter a username
printf -- '%b' 'Enter iDrac host (eg. "oob-myserver.domain.tld", "localhost:7200"…): '
read -r idrac_host_temp
fi
## }}}
## If idrac_host_temp is still empty {{{
if [ -z "${idrac_host_temp-}" ]; then
error_message "iDrac host can't be empty, please check your input or use --host option. For more informations, see the help message (--help)." 11
fi
## }}}
## If idrac_host_temp contains a port number {{{
if printf '%b' "${idrac_host_temp}" | grep --extended-regexp '^[a-zA-Z]+.*:[0-9]+$' >/dev/null; then
debug_message "- Try to extract hostname and port number from value (${RED}${idrac_host_temp}${COLOR_DEBUG})."
### Extract hostname and port number
idrac_host=$(printf '%b' "${idrac_host_temp}" | awk 'BEGIN { FS = ":" } ; /^[a-zA-Z]+.*:[0-9]+$/ { print $1 }')
idrac_port=$(printf '%b' "${idrac_host_temp}" | awk 'BEGIN { FS = ":" } ; /^[a-zA-Z]+.*:[0-9]+$/ { print $2 }')
else
### Simply use idrac_host_temp as hostname
idrac_host="${idrac_host_temp}"
fi
## }}}
## If idrac_username wasn't defined (argument) {{{
if [ -z "${idrac_username-}" ]; then
### Ask the user to enter a username
printf -- '%b' "Enter iDrac username (default ${RED}${IDRAC_USERNAME_DEFAULT}${RESET}): "
read -r idrac_username
fi
## }}}
## If idrac_username is still empty {{{
if [ -z "${idrac_username-}" ]; then
### Use default value
readonly idrac_username="${IDRAC_USERNAME_DEFAULT}"
fi
## }}}
## If idrac_port wasn't defined (argument or by idrac_host_temp) {{{
if [ -z "${idrac_port-}" ]; then
### Ask the user to enter a port number
printf -- '%b' "Enter iDrac port (default ${RED}${IDRAC_PORT_DEFAULT}${RESET}): "
read -r idrac_port
fi
## }}}
## If idrac_port is still empty {{{
if [ -z "${idrac_port-}" ]; then
idrac_port="${IDRAC_PORT_DEFAULT}"
fi
## }}}
## Ask for idrac_password {{{
printf -- '%b' "Enter iDrac password (it won't be displayed): "
read -r -s idrac_password
printf -- '%b\n' ""
## }}}
## If idrac_password is empty, ask again {{{
if [ -z "${idrac_password-}" ]; then
printf -- '%b' "A password is required to connect iDrac host (it won't be displayed): "
read -r -s idrac_password
printf -- '%b\n' ""
fi
## }}}
## If idrac_password is still empty {{{
if [ -z "${idrac_password-}" ]; then
error_message "iDrac password can't be empty, please check your input. For more informations, see the help message (--help)." 12
fi
## }}}
## If java_disable_algo wasn't defined (argument) {{{
if [ -z "${java_disable_algo-}" ]; then
### Use default value
readonly java_disable_algo="${JAVA_DISABLE_ALGO_DEFAULT}"
fi
## }}}
## If temp_dir wasn't defined (argument) {{{
if [ -z "${temp_dir-}" ]; then
### Use default value
readonly temp_dir="${TEMP_DIR_BASE}/idrac.${idrac_host}"
fi
## }}}
}
# }}}
is_command_available() { # {{{
local_command_available_cmd="${1}"
debug_prefix="${2:-}"
## Return False by default
return_command_available="1"
if [ "$(command -v ${local_command_available_cmd})" ]; then
debug_message "${debug_prefix}is_command_available \
${RED}${local_command_available_cmd}${COLOR_DEBUG} seems present on this host."
return_command_available="0"
else
debug_message "${debug_prefix}is_command_available \
${RED}${local_command_available_cmd}${COLOR_DEBUG} is not available on this host."
return_command_available="1"
fi
unset local_command_available_cmd
unset debug_prefix
return "${return_command_available}"
}
# }}}
is_file_empty() { # {{{
local_file="${1}"
debug_prefix="${2:-}"
## File is empty by default
return_is_file_empty="0"
## Check if the file is empty
if [ ! -s "${local_file}" ]; then
return_is_file_empty="0"
debug_message "${debug_prefix}is_file_empty \
The file ${RED}${local_file}${COLOR_DEBUG} is empty or doesn't exists."
else
return_is_file_empty="1"
debug_message "${debug_prefix}is_file_empty \
The file ${RED}${local_file}${COLOR_DEBUG} exists and has a size greater than zero."
fi
unset local_file
unset debug_prefix
return "${return_is_file_empty}"
}
# }}}
main() { # {{{
debug_message "--- MAIN BEGIN"
## If java command is not available {{{
### Exit with error message
is_command_available "java" "| " \
|| error_message "No java command available. Please install a openjdk-*-jre package with your package manager." 01
## }}}
## If wget command is not available {{{
### Exit with error message
is_command_available "wget" "| " \
|| error_message "No wget command available. Please install =>wget<= package with your package manager." 02
## }}}
## Define all vars
debug_message "| Define vars BEGIN"
define_vars
debug_message "| Define vars END"
debug_message "| Given informations are :
idrac_host: ${RED}${idrac_host}${COLOR_DEBUG}
idrac_port: ${RED}${idrac_port}${COLOR_DEBUG}
idrac_username: ${RED}${idrac_username}${COLOR_DEBUG}
idrac_password: ${RED}HIDDEN${COLOR_DEBUG}
temp_dir: ${RED}${temp_dir}${COLOR_DEBUG}"
## Create and move to temp directory
debug_message "| Create and move to temp directory (${RED}${temp_dir}${COLOR_DEBUG})."
mkdir --parents -- "${temp_dir}"
cd -- "${temp_dir}" || error_message "Can't move to temp directory (${temp_dir})." 21
## Set Java security parameters
debug_message "| Set java security parameters (to ${RED}${JAVA_SECURITY_FILENAME}${COLOR_DEBUG} file)."
true > "${JAVA_SECURITY_FILENAME}"
printf '%b\n' "jdk.tls.disabledAlgorithms=${JAVA_DISABLE_ALGO_DEFAULT}" >> "${JAVA_SECURITY_FILENAME}"
## Try to download main jar file from idrac host
avctkvm_filename="avctKVM.jar"
avctkvm_url="https://${idrac_host}:${idrac_port}/software/${avctkvm_filename}"
debug_message "| Try to download ${RED}${avctkvm_filename}${COLOR_DEBUG} file from URL (${RED}${avctkvm_url}${COLOR_DEBUG})."
wget --timestamping --no-check-certificate --quiet -- "${avctkvm_url}"
is_file_empty "${avctkvm_filename}" "| " \
&& error_message "Downloaded ${avctkvm_filename} file is empty (from ${avctkvm_url} URL)." 22
## Librairies
## TODO? Download avctKVMIOLinux64.jar and avctVMLinux64.jar files to extract librairies (for keyboard…).
## Try to start iDrac console with java
printf '%b\n' "Try to start ${RED}${idrac_host}:${idrac_port}${RESET} virtual console with user (${RED}${idrac_username}${RESET}) and given password."
java -cp "${avctkvm_filename}" -Djava.security.properties=idrac.java.security -Djava.library.path=./lib com.avocent.idrac.kvm.Main ip="${idrac_host}" kmport=5900 vport=5900 user="${idrac_username}" passwd="${idrac_password}" apcp=1 version=2 vmprivilege=true "helpurl=https://${idrac_host}:${idrac_port}/help/contents.html"
cd -- - >/dev/null || error_message "Can't move to previous directory (before ${temp_dir})." 23
debug_message "--- MAIN END"
}
# }}}
# Manage arguments # {{{
# This code can't be in a function due to argument management
if [ ! "${NBARGS}" -eq "0" ]; then
manage_arg="0"
## If the first argument ask for help (h|help|-h|-help|-*h|-*help) {{{
if printf -- '%s' "${1-}" | grep --quiet --extended-regexp -- "^-*h(elp)?$"; then
usage
exit 0
fi
## }}}
## If the first argument is not an option
if ! printf -- '%s' "${1}" | grep --quiet --extended-regexp -- "^-+";
then
## Print help message and exit
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
fi
# Parse all options (start with a "-") one by one
while printf -- '%s' "${1-}" | grep --quiet --extended-regexp -- "^-+"; do
case "${1}" in
-d|--debug ) ## debug
DEBUG=0
debug_message "--- Manage argument BEGIN"
;;
--host ) ## Define idrac_host_temp with given arg
## Move to the next argument
shift
## Define var
readonly idrac_host_temp="${1}"
;;
-p,--port ) ## Define idrac_port with given arg
## Move to the next argument
shift
## Define var
readonly idrac_port="${1}"
;;
-u|--user ) ## Define idrac_username with given arg
## Move to the next argument
shift
## Define var
readonly idrac_username="${1}"
;;
--temp,--temp-dir,--temp-directory ) ## Define temp_dir with given arg
## Move to the next argument
shift
## Define var
readonly temp_dir="${1}"
;;
--java-disable-algo ) ## Define java_disable_algo with given arg
## Move to the next argument
shift
## Define var
readonly java_disable_algo="${1}"
;;
* ) ## unknow option
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
;;
esac
debug_message "| ${RED}${1}${COLOR_DEBUG} option managed."
## Move to the next argument
shift
manage_arg=$((manage_arg+1))
done
debug_message "| ${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
debug_message "| No arguments/options to manage."
fi
debug_message "--- Manage argument END"
# }}}
main
exit 0