From 41ab85c8d14d582c9c9a7e0640256374a7e51fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gardais=20J=C3=A9r=C3=A9my?= Date: Fri, 17 Feb 2023 17:37:16 +0100 Subject: [PATCH] Script to start old iDrac 6/7 virtual console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old consoles that requires Java… --- dell/start-virtual-console.bash | 423 ++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100755 dell/start-virtual-console.bash diff --git a/dell/start-virtual-console.bash b/dell/start-virtual-console.bash new file mode 100755 index 0000000..409757a --- /dev/null +++ b/dell/start-virtual-console.bash @@ -0,0 +1,423 @@ +#!/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 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}" | awk 'BEGIN { FS = ":" } ; /^[a-zA-Z]+.*:[0-9]+$/' >/dev/null; then + ### 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 + define_vars + debug_message "| Define vars" + + 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 + avctkmv_filename="avctKVM.jar" + avctkvm_url="https://${idrac_host}:${idrac_port}/software/${avctkmv_filename}" + debug_message "| Try to download ${RED}${avctkmv_filename}${COLOR_DEBUG} file from URL (${RED}${avctkvm_url}${COLOR_DEBUG})." + wget --timestamping --no-check-certificate --quiet -- "${avctkvm_url}" + is_file_empty "${avctkmv_filename}" "| " \ + && error_message "Downloaded ${avctkmv_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 "${avctkmv_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