From eb2c970c7bfe7b8c820b3c082297ba324a20af2d Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Wed, 22 Jan 2025 14:16:29 +0100 Subject: [PATCH 01/25] Initial commit Signed-off-by: Martin Zeithaml --- bin/commands/support/.errors | 1 + bin/commands/support/.examples | 3 + bin/commands/support/.help | 2 + bin/commands/support/index.sh | 134 +---------- bin/commands/support/index.ts | 210 ++++++++++++++++++ .../support/verify-fingerprints/cli.js | 14 ++ .../support/verify-fingerprints/index.sh | 119 +--------- .../support/verify-fingerprints/index.ts | 159 +++++++++++++ bin/libs/fs.ts | 12 + bin/libs/node.ts | 24 +- 10 files changed, 420 insertions(+), 258 deletions(-) create mode 100644 bin/commands/support/.errors create mode 100644 bin/commands/support/.examples create mode 100644 bin/commands/support/index.ts create mode 100644 bin/commands/support/verify-fingerprints/cli.js create mode 100644 bin/commands/support/verify-fingerprints/index.ts diff --git a/bin/commands/support/.errors b/bin/commands/support/.errors new file mode 100644 index 0000000000..0f17ba69b4 --- /dev/null +++ b/bin/commands/support/.errors @@ -0,0 +1 @@ +ZWEL0151E|151|Failed to create temporary file %s. Please check permission or volume free space. diff --git a/bin/commands/support/.examples b/bin/commands/support/.examples new file mode 100644 index 0000000000..70ca4042c5 --- /dev/null +++ b/bin/commands/support/.examples @@ -0,0 +1,3 @@ +zwe support -c /path/to/zowe.yaml + +zwe support -c /path/to/zowe.yaml --target-directory /path/to/save/support/results diff --git a/bin/commands/support/.help b/bin/commands/support/.help index 6bb8eb4639..e6ed3e24a9 100644 --- a/bin/commands/support/.help +++ b/bin/commands/support/.help @@ -5,9 +5,11 @@ This command will collect these information: - Environment * z/OS version * Java version + * Java keytool TLS information * Node.js version * External Security Manager * CEE Runtime Options + * Filesystem flags - Zowe configurations * Zowe manifest.json * Zowe configuration file diff --git a/bin/commands/support/index.sh b/bin/commands/support/index.sh index 20c024ef43..23defb60de 100644 --- a/bin/commands/support/index.sh +++ b/bin/commands/support/index.sh @@ -11,136 +11,4 @@ # Copyright Contributors to the Zowe Project. ####################################################################### -print_message_file() { - msg="${1}" - out_file="${2}" - print_message "- ${msg}" - echo "${msg}" >> "${out_file}" -} - -print_level0_message "Collect information for Zowe support" - -############################### -# constants -DATE=`date +%Y-%m-%d-%H-%M-%S` -target_dir="${ZWE_CLI_PARAMETER_TARGET_DIR}" -if [ -z "${target_dir}" ]; then - target_dir=$(get_tmp_dir) -else - curr_pwd=$(pwd) - cd "${target_dir}" - target_dir=$(pwd) - cd "${curr_pwd}" -fi -tmp_file_prefix=zwe-support -tmp_pax="${target_dir}/${tmp_file_prefix}.${DATE}.pax" -tmp_dir=$(create_tmp_file "${tmp_file_prefix}" "${target_dir}") - -############################### -# validate -require_java -require_node -require_zowe_yaml - -############################### -print_message "Started at ${DATE}" -mkdir "${tmp_dir}" -chmod 700 "${tmp_dir}" -print_debug "Temporary directory created: ${tmp_dir}" -print_message - -############################### -print_level1_message "Collecting various environment information" -ENVIRONMENT_FILE="${tmp_dir}/environment_output" -echo "[Environment information]" > "${ENVIRONMENT_FILE}" -ZOS_VERSION=`operator_command "D IPLINFO" | grep -i release | xargs` -if [ -z "${ZOS_VERSION}" ]; then - ZOS_VERSION=`sysvar SYSOSLVL` -fi -JAVA_VERSION=`${JAVA_HOME}/bin/java -version 2>&1 | head -n 1` -NODE_VERSION=`${NODE_HOME}/bin/node --version` -ESM=`"${ZWE_zowe_runtimeDirectory}/bin/utils/getesm"` -CEE_OPTIONS=`tsocmd "OMVS RUNOPTS('RPTOPTS(ON)')" 2>&1` - -print_message_file "z/OS version: ${ZOS_VERSION}" "${ENVIRONMENT_FILE}" -print_message_file "Java version: ${JAVA_VERSION}" "${ENVIRONMENT_FILE}" -print_message_file "NodeJS version: ${NODE_VERSION}" "${ENVIRONMENT_FILE}" -print_message_file "External Security Manager: ${ESM}" "${ENVIRONMENT_FILE}" -print_message_file "CEE Runtime Options: ${CEE_OPTIONS}" "${ENVIRONMENT_FILE}" -print_message - -############################### -print_level1_message "Collecting Zowe configurations" -print_message "- manifest.json" -cp "${ZWE_zowe_runtimeDirectory}/manifest.json" "${tmp_dir}" -print_message "- zowe.yaml" -cp "${ZWE_CLI_PARAMETER_CONFIG}" "${tmp_dir}" -ZWE_zowe_workspaceDirectory=$(read_yaml "${ZWE_CLI_PARAMETER_CONFIG}" ".zowe.workspaceDirectory") -if [ -d "${ZWE_zowe_workspaceDirectory}/.env" ]; then - print_message "- /.env" - mkdir -p "${tmp_dir}/workspace" - cp -r "${ZWE_zowe_workspaceDirectory}/.env" "${tmp_dir}/workspace" -fi -if [ -d "${ZWE_zowe_workspaceDirectory}/api-mediation/api-defs" ]; then - print_message "- /api-mediation/api-defs" - mkdir -p "${tmp_dir}/workspace" - cp -r "${ZWE_zowe_workspaceDirectory}/api-mediation/api-defs" "${tmp_dir}/workspace" -fi -ZWE_zowe_setup_certificate_pkcs12_directory=$(read_yaml "${ZWE_CLI_PARAMETER_CONFIG}" ".zowe.setup.certificate.pkcs12.directory") -if [ -d "${ZWE_zowe_setup_certificate_pkcs12_directory}" ]; then - print_message "- ${ZWE_zowe_setup_certificate_pkcs12_directory}" - mkdir -p "${tmp_dir}/keystore" - cp -r "${ZWE_zowe_setup_certificate_pkcs12_directory}" "${tmp_dir}/keystore" -fi -print_message - -############################### -print_level1_message "Collecting Zowe file fingerprints" -print_message "- copy original fingerprints" -cp -r "${ZWE_zowe_runtimeDirectory}/fingerprint" "${tmp_dir}" -print_message "- verify fingerprints" -result=$(export ZWE_PRIVATE_LOG_FILE="${tmp_dir}/verify-fingerprints.log" && export ZWE_PRIVATE_LOG_LEVEL_ZWELS=TRACE && touch "${ZWE_PRIVATE_LOG_FILE}" && . "${ZWE_zowe_runtimeDirectory}/bin/commands/support/verify-fingerprints/index.sh" 2>/dev/null 1>/dev/null) -print_message - -############################### -job_name=$(read_yaml "${ZWE_CLI_PARAMETER_CONFIG}" ".zowe.job.name") -job_prefix=$(read_yaml "${ZWE_CLI_PARAMETER_CONFIG}" ".zowe.job.prefix") -print_level1_message "Collecting current process information based on the job prefix ${job_prefix} and job name ${job_name}" -PS_OUTPUT_FILE=${tmp_dir}"/ps_output" - -# Collect process information -print_message "- Adding ${PS_OUTPUT_FILE}" -ps -A -o pid,ppid,time,etime,user,jobname,args | grep -e "^[[:space:]]*PID" -e "${job_prefix}" -e "${job_name}" > $PS_OUTPUT_FILE -print_message - -############################### -# TODO: job log -# To avoid of using SDSF, we used to use TSO output command to export job log -# but it always fails with below error for me: -# IKJ56328I JOB ZWE1SV REJECTED - JOBNAME MUST BE YOUR USERID OR MUST START WITH YOUR USERID -# REF: https://www.ibm.com/docs/en/zos/2.3.0?topic=subcommands-output-command -# REF: https://www.ibm.com/docs/en/zos/2.3.0?topic=ikj-ikj56328i - -############################### -# Collect instance logs -log_dir=$(read_yaml "${ZWE_CLI_PARAMETER_CONFIG}" ".zowe.logDirectory") -print_level1_message "Collecting logs from ${log_dir}" -if [ -d "${log_dir}" ]; then - cp -r "${log_dir}" "${tmp_dir}" -fi -print_message - -############################### -print_level1_message "Create support package and clean up" -curr_pwd=$(pwd) -cd "${tmp_dir}" -pax -w -v -o saveext -f "${tmp_pax}" . -compress "${tmp_pax}" -chmod 700 "${tmp_pax}"* -cd "${curr_pwd}" -rm -fr "${tmp_dir}" -print_message - -############################### -# exit message -print_level1_message "Zowe support package is generated as ${tmp_pax}.Z" +_CEE_RUNOPTS="XPLINK(ON)" ${ZWE_zowe_runtimeDirectory}/bin/utils/configmgr -script "${ZWE_zowe_runtimeDirectory}/bin/commands/support/cli.js" diff --git a/bin/commands/support/index.ts b/bin/commands/support/index.ts new file mode 100644 index 0000000000..6e6b62d6fc --- /dev/null +++ b/bin/commands/support/index.ts @@ -0,0 +1,210 @@ +/* + This program and the accompanying materials are made available + under the terms of the Eclipse Public License v2.0 which + accompanies this distribution, and is available at + https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +// TODO: job log +// To avoid of using SDSF, we used to use TSO output command to export job log +// but it always fails with below error for me: +// IKJ56328I JOB ZWE1SV REJECTED - JOBNAME MUST BE YOUR USERID OR MUST START WITH YOUR USERID +// REF: https://www.ibm.com/docs/en/zos/2.3.0?topic=subcommands-output-command +// REF: https://www.ibm.com/docs/en/zos/2.3.0?topic=ikj-ikj56328i + +import * as std from 'cm_std'; +import * as xplatform from 'xplatform' + +import * as common from '../../libs/common'; +import * as config from '../../libs/config'; +import * as fs from '../../libs/fs'; +import * as java from '../../libs/java'; +import * as node from '../../libs/node' +import * as shell from '../../libs/shell'; +import * as zoslib from '../../libs/zos'; +import * as zosfs from '../../libs/zos-fs'; + +// import * as verifyFingerprints from './verify-fingerprints/index'; + +export function execute() { + + common.printLevel0Message('Collect information for Zowe support'); + const isoDate = new Date().toISOString().replace(/T|t|:/g,'-').substring(0,19); + + let targetDirectory = std.getenv('ZWE_CLI_PARAMETER_TARGET_DIR'); + if (targetDirectory) { + targetDirectory = fs.convertToAbsolutePath(targetDirectory); + } else { + targetDirectory = fs.getTmpDir(); + } + + if (!fs.directoryExists(targetDirectory, true)) { + common.printErrorAndExit(`Error ZWELxxxx: "${targetDirectory}" is not a valid directory.`, undefined, 999); + } + + const tmpFilePrefix = 'zwe-support'; + const tmpPax = `${targetDirectory}/${tmpFilePrefix}.${isoDate}.pax`; + const tmpDir = fs.createTmpFile(tmpFilePrefix, targetDirectory); + + common.requireZoweYaml(); + + common.printMessage(`Started at ${isoDate}`); + fs.mkdirp(tmpDir, 0o700); + common.printDebug(`Temporary directory created: ${tmpDir}`); + + common.printLevel1Message('Collecting various environment information'); + const environmentFile =`${tmpDir}/environment.json`; + let environment = {}; + + environment["zos-version"] = zoslib.formatZosVersion(); + + node.optionalNode(); + const nodeHome = std.getenv('NODE_HOME'); + if (nodeHome) { + const nodeVersion = shell.execOutSync('sh', '-c', '${NODE_HOME} -v 2>&1 | head -n 1'); + if (nodeVersion.rc == 0) { + environment["node"] = `${nodeVersion.out}`; + } + } else { + environment["node"] = `not found`; + } + + java.requireJava(); + const javaVersion = shell.execOutSync('sh', '-c', '${JAVA_HOME}/bin/java -version 2>&1 | head -n 1'); + if (javaVersion.rc == 0 && javaVersion.out) { + environment["java"] = javaVersion.out.replace(/\"/g, ''); + const keytoolInfo = shell.execOutSync('sh', '-c', '${JAVA_HOME}/bin/keytool -showinfo -tls 2>&1'); + if (keytoolInfo.rc == 0 && keytoolInfo.out) { + environment["keytool_showinfo_tls"] = keytoolInfo.out.split('\n'); + } + } else { + environment["java"] = 'not found'; + } + + environment["esm"] = `${zos.getEsm()}`; + + // This command is usually failing with rc=12 and FSUM2051I/FSUM2052I messages: + // FSUM2051I The OMVS command failed because the display screen size is not supported.+ + // FSUM2052I The screen size must be at least 12 by 40 but less than 10000 bytes total. The actual primary screen size is 255 by 255 ( + // 65025 bytes). The alternate screen size is 255 by 255 (65025 bytes). + // - tsoCommand will fail and print error -> we will use shell.execOutSync + // - We will take stdout + stderr and try to filter out messages + const ceeOptions = shell.execOutSync('sh', '-c', `tsocmd "OMVS RUNOPTS('RPTOPTS(ON)')" 2>&1`); + if (ceeOptions.out) { + const ceeOptionesLines = ceeOptions.out.split('\n'); + let ceeIndex = 0; + environment["cee_runtime"] = []; + for (let line in ceeOptionesLines) { + if (!(/^FSUM205[1|2]I/).test(ceeOptionesLines[line]) && !(/.*the alternate screen size is.*/i).test(ceeOptionesLines[line])) { + if (ceeOptionesLines[line].trim()) { + environment["cee_runtime"].push(ceeOptionesLines[line]); + } + } + } + } + + const zoweRuntime = std.getenv('ZWE_zowe_runtimeDirectory'); + const fsFlags = zosfs.getFileSystemFlags(zoweRuntime); + if (fsFlags.rc == 0) { + environment["fs_flags"] = (({ rc, ...others }) => others)(fsFlags); // Do not include "rc" + } + + common.printMessage(JSON.stringify(environment, null, 2)); + const saveEnvRc = xplatform.storeFileUTF8(environmentFile, xplatform.AUTO_DETECT, JSON.stringify(environment, null, 2)); + if (saveEnvRc) { + common.printErrorAndExit(`Error ZWEL0151E: Failed to create temporary file "${environmentFile}". Please check permission or volume free space.`, undefined, 151); + } + + common.printLevel1Message('Collecting Zowe configurations'); + common.printMessage(`- manifest.json: ${zoweRuntime}/manifest.json`); + fs.cp(`${zoweRuntime}/manifest.json`, tmpDir); + + const ZOWE_CONFIG=config.getZoweConfig(); + const workspaceDirectory = ZOWE_CONFIG.zowe.workspaceDirectory; + + common.printMessage(`- configuration: ${workspaceDirectory}/.env/.zowe-merged.yaml`); + + // workspace directory must exists, otherwise the merging of configs already failed + fs.cp(`${workspaceDirectory}/.env/.zowe-merged.yaml`, `${tmpDir}/zowe-merged.yaml`); + + common.printMessage(`- zowe.workspaceDirectory: ${workspaceDirectory}/.env`); + fs.mkdirp(`${tmpDir}/workspace`); + fs.cp(`${workspaceDirectory}/.env`, `${tmpDir}/workspace`) + + if (fs.directoryExists(`${workspaceDirectory}/api-mediation/api-defs`)) { + common.printMessage(`- zowe.workspaceDirectory: ${workspaceDirectory}/api-mediation/api-defs`); + fs.cp(`${workspaceDirectory}/api-mediation/api-defs`, `${tmpDir}/workspace/api-mediation`); + } + + const pkcs12Directory = ZOWE_CONFIG.zowe.setup?.certificate?.pkcs12?.directory; + if (fs.directoryExists(pkcs12Directory)) { + common.printMessage(`- zowe.setup.certificate.pkcs12.directory: ${pkcs12Directory}`) + fs.mkdirp(`${tmpDir}/keystore`); + fs.cp(`${pkcs12Directory}`, `${tmpDir}/keystore`); + } + common.printMessage(""); + + common.printLevel1Message("Collecting Zowe file fingerprints"); + const verifyFingerprintsFile = `${tmpDir}/verify-fingerprints.log`; + const supportLogFile = std.getenv('ZWE_PRIVATE_LOG_FILE'); + const supportLogLevel = std.getenv('ZWE_PRIVATE_LOG_LEVEL_ZWELS'); + common.printMessage(`- copy original fingerprints: ${zoweRuntime}/fingerprint`); + fs.cp(`${zoweRuntime}/fingerprint`, tmpDir); + common.printMessage("- verify fingerprints"); + std.setenv('ZWE_PRIVATE_LOG_FILE', `${verifyFingerprintsFile}`); + std.setenv('ZWE_PRIVATE_LOG_LEVEL_ZWELS', 'TRACE'); + fs.createFile(verifyFingerprintsFile, 0o700); + // =========================================================== + // verifyFingerprints.execute(); + // =========================================================== + std.setenv('ZWE_PRIVATE_LOG_FILE',`${supportLogLevel}`); + std.setenv('ZWE_PRIVATE_LOG_LEVEL_ZWELS', `${supportLogLevel}`); + common.printMessage(""); + + // zowe.job.name + prefix are in defaults + const jobName = ZOWE_CONFIG.zowe.job.name; + const jobPrefix = ZOWE_CONFIG.zowe.job.prefix; + + common.printLevel1Message(`Collecting current process information based on the job prefix ${jobPrefix} and job name ${jobName}`); + + const psOutputFile = `${tmpDir}/ps_output`; + const processes = shell.execOutSync('sh', '-c', `ps -A -o pid,ppid,time,etime,user,jobname,args | grep -e "^[[:space:]]*PID" -e "${jobPrefix}" -e "${jobName}"`); + // This process has the argument, which (surprise!) is found by grep, e.g: + // 1234 5678 00:00:00 00:00:00 ADMDIN USERID grep -e ^[[:space:]]*PID -e ZWE1 -e ZWE1SV + if (processes.rc == 0 && processes.out) { + let processesSplit = processes.out.split("\n"); + for (let i = 0; i < processesSplit.length; i++) { + if (processesSplit[i].includes(`grep -e ^[[:space:]]*PID -e ${jobPrefix} -e ${jobName}`)) { + processesSplit = processesSplit.splice(i, 1); + } + } + if (processesSplit.length > 1) { + common.printMessage(`- Adding ${psOutputFile}`); + xplatform.storeFileUTF8(psOutputFile, xplatform.AUTO_DETECT, processesSplit.join("\n")); + } + } + common.printMessage(""); + + const logDirectory=ZOWE_CONFIG.zowe.logDirectory; // This could be /dev/null + if (fs.directoryExists(logDirectory, true)) { + common.printLevel1Message(`Collecting logs from ${logDirectory}`); + fs.mkdirp(`${tmpDir}/logs`); + fs.cp(`${logDirectory}`, `${tmpDir}/logs`); + } + common.printMessage(""); + + common.printLevel1Message('Create support package and clean up'); + shell.execOutSync('sh', '-c', `cd "${tmpDir}" && pax -w -v -o saveext -f "${tmpPax}" . && compress ${tmpPax} && chmod 700 "${tmpPax}.Z"`); + fs.rmrf(tmpDir); + common.printMessage(""); + + if (fs.fileExists(`${tmpPax}.Z`)) { + common.printLevel1Message(`Zowe support package is generated as ${tmpPax}.Z`); + } else { + common.printErrorAndExit(`Error ZWEL0151E: Failed to create file "${tmpPax}.Z". Please check permission or volume free space.`, undefined, 151); + } +} diff --git a/bin/commands/support/verify-fingerprints/cli.js b/bin/commands/support/verify-fingerprints/cli.js new file mode 100644 index 0000000000..f4c250939a --- /dev/null +++ b/bin/commands/support/verify-fingerprints/cli.js @@ -0,0 +1,14 @@ +/* + This program and the accompanying materials are made available + under the terms of the Eclipse Public License v2.0 which + accompanies this distribution, and is available at + https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +import * as index from './index'; + +index.execute(); diff --git a/bin/commands/support/verify-fingerprints/index.sh b/bin/commands/support/verify-fingerprints/index.sh index 3a67cc129b..e49728dd07 100644 --- a/bin/commands/support/verify-fingerprints/index.sh +++ b/bin/commands/support/verify-fingerprints/index.sh @@ -11,121 +11,4 @@ # Copyright Contributors to the Zowe Project. ####################################################################### -print_level0_message "Verify Zowe file fingerprints" - -############################### -# constants -tmp_file_prefix=zwe-support-verify-fingerprints -ZWE_VERSION=$(shell_read_json_config "${ZWE_zowe_runtimeDirectory}/manifest.json" 'version' 'version') - -clean_up_tmp_files() { - print_debug "- Clean up temporary files..." - if [ -n "${all_files}" ]; then - rm -f "${all_files}" - fi - if [ -n "${cust_hashes}" ]; then - rm -f "${cust_hashes}" - fi -} - -############################### -# validation -require_java - -if [ -z "${ZWE_VERSION}" ]; then - print_error_and_exit "Error ZWEL0113E: Failed to find Zowe version. Please validate your Zowe directory." "" 113 -fi -if [ ! -f "${ZWE_zowe_runtimeDirectory}/bin/utils/HashFiles.class" ]; then - print_error_and_exit "Error ZWEL0150E: Failed to find file bin/utils/HashFiles.class. Zowe runtimeDirectory is invalid." "" 150 -fi -if [ ! -f "${ZWE_zowe_runtimeDirectory}/fingerprint/RefRuntimeHash-${ZWE_VERSION}.txt" ]; then - print_error_and_exit "Error ZWEL0150E: Failed to find file fingerprint/RefRuntimeHash-${ZWE_VERSION}.txt. Zowe runtimeDirectory is invalid." "" 150 -fi - -############################### -cd "${ZWE_zowe_runtimeDirectory}" - -print_message "- Create Zowe directory file list" -all_files=$(create_tmp_file "${tmp_file_prefix}") -find . -name ./SMPE -prune \ - -o -name "./ZWE*" -prune \ - -o -name ./fingerprint -prune \ - -o -type f -print > "${all_files}" -if [ ! -f "${all_files}" ]; then - print_error " * Error ZWEL0151E: Failed to create temporary file ${all_files}. Please check permission or volume free space." - clean_up_tmp_files - exit 151 -fi -chmod 700 "${all_files}" -print_debug " * File list created as ${all_files}" - -print_message "- Calculate hashes of Zowe files" -cust_hashes=$(create_tmp_file "${tmp_file_prefix}") -result=$(java -cp "${ZWE_zowe_runtimeDirectory}/bin/utils/" HashFiles "${all_files}" | sort > "${cust_hashes}") -code=$? -if [ -f "${cust_hashes}" ]; then - file_size_check=$(wc -l "${cust_hashes}" | awk '{print $1}') -fi -if [ "${code}" -eq 1 -o ! -f "${cust_hashes}" -o "${file_size_check}" -eq 0 ]; then - print_error " * Error ZWEL0151E: Failed to create temporary file ${cust_hashes}. Please check permission or volume free space." - print_error " * Exit code: ${code}" - print_error " * Output:" - if [ -n "${result}" ]; then - print_error "$(padding_left "${result}" " ")" - fi - clean_up_tmp_files - exit 151 -fi -chmod 700 "${cust_hashes}" -print_debug " * Zowe file hashes created as ${cust_hashes}" - -verify_failed= -while read -r step; do - comm_param=$(echo "${step}" | awk '{print $1}') - step_name=$(echo "${step}" | awk '{print $2}') - - print_message "- Find ${step_name} files" - result=$(comm -${comm_param} "${ZWE_zowe_runtimeDirectory}/fingerprint/RefRuntimeHash-${ZWE_VERSION}.txt" "${cust_hashes}") - if [ ${code} -eq 1 ]; then - print_error " * Error ZWEL0151E: Failed to compare hashes of fingerprint/RefRuntimeHash-${ZWE_VERSION}.txt and current." - print_error " * Exit code: ${code}" - print_error " * Output:" - if [ -n "${result}" ]; then - print_error "$(padding_left "${result}" " ")" - fi - clean_up_tmp_files - exit 151 - fi - - cnt=$(printf "${result}" | wc -l | awk '{print $1}') - print_message " * Number of ${step_name} files: ${cnt}" - - if [ ${cnt} -gt 0 ]; then - verify_failed=true - if [ "${ZWE_PRIVATE_LOG_LEVEL_ZWELS}" = "TRACE" ]; then - print_trace " * All ${step_name} files:" - print_trace "${result}" - elif [ "${ZWE_PRIVATE_LOG_LEVEL_ZWELS}" = "DEBUG" ]; then - print_debug " * First 10 ${step_name} files:" "console" - head_10_result=$(echo "${result}" | head -n 10 | awk '{ print $1 }') - print_debug "$(padding_left "${head_10_result}" " ")" "console" - fi - fi -done </dev/null 1>/dev/null'); + return testJava.rc; +} + +function processCommResult(content, lines) { + let returnedOutput = ''; + if (content) { + let linesSplit = content.split("\n"); + if (lines) { + linesSplit = linesSplit.slice(0, lines); + } + linesSplit.forEach(line => { + const oneLineSplit = line.split(' '); + returnedOutput += `${oneLineSplit[0]}\n` + }) + } + return returnedOutput; +} + +export function execute() { + + common.printLevel0Message('Verify Zowe file fingerprints'); + + if (requireJava()) { + common.printErrorAndExit('No Java found', undefined, 999); + } + + const tmpFilePrefix = 'zwe-support-verify-fingerprints'; + const zoweRuntime = std.getenv('ZWE_zowe_runtimeDirectory'); + const manifest = `${zoweRuntime}/manifest.json` + + let manifestContent = undefined; + let manifestJson = undefined; + if (fs.fileExists(manifest)) { + manifestContent = xplatform.loadFileUTF8(manifest, xplatform.AUTO_DETECT); + } else { + common.printErrorAndExit(`Error ZWEL0150E: Failed to find file "${manifest}". Zowe runtimeDirectory is invalid.`, undefined, 150); + } + if (manifestContent) { + manifestJson = JSON.parse(manifestContent); + } + if (!manifestContent || !manifestJson.version) { + common.printErrorAndExit("Error ZWEL0113E: Failed to find Zowe version. Please validate your Zowe directory.", undefined, 113); + } + const zoweVersion = manifestJson.version; + + if (!fs.fileExists(`${zoweRuntime}/bin/utils/HashFiles.class`)) { + common.printErrorAndExit(`Error ZWEL0150E: Failed to find file "${zoweRuntime}/bin/utils/HashFiles.class". Zowe runtimeDirectory is invalid.`, undefined, 150); + } + + if (!fs.fileExists(`${zoweRuntime}/fingerprint/RefRuntimeHash-${zoweVersion}.txt`)) { + common.printErrorAndExit(`Error ZWEL0150E: Failed to find file "${zoweRuntime}/fingerprint/RefRuntimeHash-${zoweVersion}.txt". Zowe runtimeDirectory is invalid.`, undefined, 150); + } + + common.printMessage('- Create Zowe directory file list'); + const allFiles = fs.createTmpFile(tmpFilePrefix); + shell.execOutSync('sh', '-c', `cd '${zoweRuntime}' && find . -name ./SMPE -prune -o -name "./ZWE*" -prune -o -name ./fingerprint -prune -o -type f -print > "${allFiles}"`); + if (!fs.fileExists(allFiles)) { + common.printErrorAndExit(`Error ZWEL0151E: Failed to create temporary file "${allFiles}". Please check permission or volume free space.`, undefined, 151); + } + + common.printDebug(` * File list created as ${allFiles}`); + shell.execSync('sh', '-c', `chmod 700 "${allFiles}"`); + + common.printMessage('- Calculate hashes of Zowe files'); + + const customHashes = fs.createTmpFile(tmpFilePrefix); + const javaHash = shell.execOutSync('sh', '-c', `cd '${zoweRuntime}' && java -cp "${zoweRuntime}/bin/utils/" HashFiles "${allFiles}" | sort > "${customHashes}"`); + + if (javaHash.rc != 0 || !fs.fileExists(customHashes) || fs.fileSize(customHashes) < 1) { + common.printError(` * Error ZWEL0151E: Failed to create temporary file ${customHashes}. Please check permission or volume free space.`); + common.printError(` * Exit code: java error code=${javaHash.rc}`) + common.printError(` * file exists=${fs.fileExists(customHashes)}`); + if (fs.fileExists(customHashes)) { + common.printError(` * file size=${fs.fileSize(customHashes)}`); + fs.rmrf(allFiles); + fs.rmrf(customHashes); + } + if (javaHash.out) { + common.printError(stringlib.paddingLeft(javaHash.out, " ")); + } + std.exit(151); + } + + common.printDebug(` * Zowe file hashes created as ${customHashes}`); + shell.execSync('sh', '-c', `chmod 700 "${customHashes}"`); + + let verifyFailed = false; + const logLevel = std.getenv('ZWE_PRIVATE_LOG_LEVEL_ZWELS'); + const COMM = [ + [ 3, 'different' ], + [ 13, 'extra' ], + [ 23, 'missing' ] + ] + + COMM.forEach(commSetting => { + const commParameter = commSetting[0]; + const commStepName = commSetting[1] + common.printMessage(`- Find ${commStepName} files`); + const commResult = shell.execOutSync('sh', '-c', `cd '${zoweRuntime}' && comm -${commParameter} "${zoweRuntime}/fingerprint/RefRuntimeHash-${zoweVersion}.txt" "${customHashes}"`); + if (commResult.rc) { + commom.printError(` * Error ZWEL0151E: Failed to compare hashes of fingerprint/RefRuntimeHash-${zoweVersion}.txt and current.`); + commom.printError(` * Exit code: ${commResult.rc}`); + if (commResult.out) { + commom.printError(` * Output:`); + common.printError(`${stringlib.paddingLeft(commResult.out, " ")}`); + } + fs.rmrf(allFiles); + fs.rmrf(customHashes); + std.exit(151); + } + + if (commResult.out) { + const linesReturned = commResult.out.split("\n").length; + common.printMessage(` * Number of ${commStepName} files: ${linesReturned}`); + if (linesReturned) { + verifyFailed = true; + if (logLevel == 'TRACE' ) { + common.printTrace(` * All ${commStepName} files:`); + common.printTrace(processCommResult(commResult.out, undefined)); + } + if (logLevel == 'DEBUG') { + common.printDebug(` * First 10 ${commStepName} files:`); + common.printDebug(stringlib.paddingLeft(processCommResult(commResult.out, 10)," ")); + } + } + } + }); + + fs.rmrf(allFiles); + fs.rmrf(customHashes); + + if (verifyFailed) { + common.printMessage(""); + common.printErrorAndExit('Error ZWEL0181E: Failed to verify Zowe file fingerprints.', undefined, 151); + } else { + common.printLevel1Message('Zowe file fingerprints verification passed.'); + } +} diff --git a/bin/libs/fs.ts b/bin/libs/fs.ts index 632bb2cbd7..1311395725 100644 --- a/bin/libs/fs.ts +++ b/bin/libs/fs.ts @@ -328,3 +328,15 @@ export function areDirectoriesSame(dir1: string, dir2: string): boolean { let abs2 = convertToAbsolutePath(dir2); return (abs1 === abs2) && abs1 !== undefined; } + +export function fileSize(file: string): number { + common.printDebug(`fs.fileSize path="${file}"`); + if (file && typeof(file) == 'string') { + const result = zos.zstat(file); + common.printDebug(`fs.fileSize result="${JSON.stringify(result)}"`); + if (result[1] == 0) { + return result[0].size; + } + } + return -1; +} diff --git a/bin/libs/node.ts b/bin/libs/node.ts index f6c5b43f27..bb8ee6a8b8 100644 --- a/bin/libs/node.ts +++ b/bin/libs/node.ts @@ -3,9 +3,9 @@ under the terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html - + SPDX-License-Identifier: EPL-2.0 - + Copyright Contributors to the Zowe Project. */ @@ -25,7 +25,7 @@ const NODE_MIN_VERSION=18; std.setenv('NODE_STDOUT_CCSID','1047'); std.setenv('NODE_STDERR_CCSID','1047'); std.setenv('NODE_STDIN_CCSID','1047'); - + // Workaround Fix for node 8.16.1 that requires compatibility mode for untagged files std.setenv('__UNTAGGED_READ_MODE','V6'); @@ -61,7 +61,8 @@ export function detectNodeHome(): string|undefined { } let _checkComplete = false; -export function requireNode() { +export function requireNode(required: Boolean | undefined = true): void { + // if undefined => true? if ((_checkComplete === true) && std.getenv('NODE_HOME')) { return; } @@ -78,13 +79,22 @@ export function requireNode() { } } if (!std.getenv('NODE_HOME')) { - common.printErrorAndExit("Error ZWEL0121E: Cannot find node. Set the node.home value in the Zowe YAML, or include node in the PATH environment variable of any accounts that start or manage Zowe", undefined, 121); + if (required == true) { + common.printErrorAndExit("Error ZWEL0121E: Cannot find node. Set the node.home value in the Zowe YAML, or include node in the PATH environment variable of any accounts that start or manage Zowe", undefined, 121); + } else { + _checkComplete = true; + return; + } } ensureNodeIsOnPath(); _checkComplete = true; } +export function optionalNode(): void { + requireNode(false); +} + export function validateNodeHome(nodeHome:string|undefined=std.getenv("NODE_HOME")): boolean { if (!nodeHome) { common.printError("Cannot find node. Please define NODE_HOME environment variable."); @@ -101,7 +111,7 @@ export function validateNodeHome(nodeHome:string|undefined=std.getenv("NODE_HOME common.printError(`Node version check failed with return code: ${shellReturn.rc}: ${version}`); return false; } - + try { if ((version as string).startsWith('v')) { // valid because rc check let parts = (version as string).split('.'); @@ -128,7 +138,7 @@ export function validateNodeHome(nodeHome:string|undefined=std.getenv("NODE_HOME } common.printDebug(`Node check is successful.`); - + return true; } else { common.printError(`Cannot validate node version '${version}'. Unexpected format`); From 415716e3beac9d4b6a1b57b73e9c079e933dcc20 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Wed, 22 Jan 2025 14:38:40 +0100 Subject: [PATCH 02/25] Missing cli Signed-off-by: Martin Zeithaml --- bin/commands/support/cli.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 bin/commands/support/cli.js diff --git a/bin/commands/support/cli.js b/bin/commands/support/cli.js new file mode 100644 index 0000000000..f4c250939a --- /dev/null +++ b/bin/commands/support/cli.js @@ -0,0 +1,14 @@ +/* + This program and the accompanying materials are made available + under the terms of the Eclipse Public License v2.0 which + accompanies this distribution, and is available at + https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +import * as index from './index'; + +index.execute(); From 382c7e714d7f4b11d1399c65d58c4fec0a149f50 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Wed, 22 Jan 2025 14:46:24 +0100 Subject: [PATCH 03/25] Missing import Signed-off-by: Martin Zeithaml --- bin/commands/support/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/commands/support/index.ts b/bin/commands/support/index.ts index 6e6b62d6fc..c7a9196131 100644 --- a/bin/commands/support/index.ts +++ b/bin/commands/support/index.ts @@ -17,6 +17,7 @@ // REF: https://www.ibm.com/docs/en/zos/2.3.0?topic=ikj-ikj56328i import * as std from 'cm_std'; +import * as zos from 'zos'; import * as xplatform from 'xplatform' import * as common from '../../libs/common'; From bfc859d56163dd45ac44b91b1414445e9f213091 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Wed, 22 Jan 2025 14:55:31 +0100 Subject: [PATCH 04/25] Typo in import Signed-off-by: Martin Zeithaml --- bin/commands/support/verify-fingerprints/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/commands/support/verify-fingerprints/index.ts b/bin/commands/support/verify-fingerprints/index.ts index 961915c221..d811fa91ca 100644 --- a/bin/commands/support/verify-fingerprints/index.ts +++ b/bin/commands/support/verify-fingerprints/index.ts @@ -119,10 +119,10 @@ export function execute() { common.printMessage(`- Find ${commStepName} files`); const commResult = shell.execOutSync('sh', '-c', `cd '${zoweRuntime}' && comm -${commParameter} "${zoweRuntime}/fingerprint/RefRuntimeHash-${zoweVersion}.txt" "${customHashes}"`); if (commResult.rc) { - commom.printError(` * Error ZWEL0151E: Failed to compare hashes of fingerprint/RefRuntimeHash-${zoweVersion}.txt and current.`); - commom.printError(` * Exit code: ${commResult.rc}`); + common.printError(` * Error ZWEL0151E: Failed to compare hashes of fingerprint/RefRuntimeHash-${zoweVersion}.txt and current.`); + common.printError(` * Exit code: ${commResult.rc}`); if (commResult.out) { - commom.printError(` * Output:`); + common.printError(` * Output:`); common.printError(`${stringlib.paddingLeft(commResult.out, " ")}`); } fs.rmrf(allFiles); From d16bb77fbbb60926791e94db1e13f1bc2dfc3c43 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Wed, 22 Jan 2025 15:30:26 +0100 Subject: [PATCH 05/25] Help update and types Signed-off-by: Martin Zeithaml --- bin/commands/support/.examples | 2 +- bin/commands/support/verify-fingerprints/index.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/commands/support/.examples b/bin/commands/support/.examples index 70ca4042c5..dc4b4e5837 100644 --- a/bin/commands/support/.examples +++ b/bin/commands/support/.examples @@ -1,3 +1,3 @@ zwe support -c /path/to/zowe.yaml -zwe support -c /path/to/zowe.yaml --target-directory /path/to/save/support/results +zwe support -c /path/to/zowe.yaml --target-dir /path/to/save/support/results diff --git a/bin/commands/support/verify-fingerprints/index.ts b/bin/commands/support/verify-fingerprints/index.ts index d811fa91ca..5604426c67 100644 --- a/bin/commands/support/verify-fingerprints/index.ts +++ b/bin/commands/support/verify-fingerprints/index.ts @@ -22,11 +22,11 @@ function requireJava() { return testJava.rc; } -function processCommResult(content, lines) { +function processCommResult(content: string, lines?: number): string { let returnedOutput = ''; if (content) { let linesSplit = content.split("\n"); - if (lines) { + if (lines && lines > 0) { linesSplit = linesSplit.slice(0, lines); } linesSplit.forEach(line => { From 489c59ecccea2b91a75d0e0e990575024d990505 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Wed, 22 Jan 2025 16:07:00 +0100 Subject: [PATCH 06/25] Wrong error code Signed-off-by: Martin Zeithaml --- bin/commands/support/verify-fingerprints/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/commands/support/verify-fingerprints/index.ts b/bin/commands/support/verify-fingerprints/index.ts index 5604426c67..aab64cedb6 100644 --- a/bin/commands/support/verify-fingerprints/index.ts +++ b/bin/commands/support/verify-fingerprints/index.ts @@ -152,7 +152,7 @@ export function execute() { if (verifyFailed) { common.printMessage(""); - common.printErrorAndExit('Error ZWEL0181E: Failed to verify Zowe file fingerprints.', undefined, 151); + common.printErrorAndExit('Error ZWEL0181E: Failed to verify Zowe file fingerprints.', undefined, 181); } else { common.printLevel1Message('Zowe file fingerprints verification passed.'); } From d307a046215eb18b7fda066cf644cf9f768cdcc6 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Wed, 22 Jan 2025 17:03:22 +0100 Subject: [PATCH 07/25] Do not exit if called from support Signed-off-by: Martin Zeithaml --- bin/commands/support/index.ts | 8 +++----- bin/commands/support/verify-fingerprints/index.ts | 15 +++++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/bin/commands/support/index.ts b/bin/commands/support/index.ts index c7a9196131..63cef0ad99 100644 --- a/bin/commands/support/index.ts +++ b/bin/commands/support/index.ts @@ -29,9 +29,9 @@ import * as shell from '../../libs/shell'; import * as zoslib from '../../libs/zos'; import * as zosfs from '../../libs/zos-fs'; -// import * as verifyFingerprints from './verify-fingerprints/index'; +import * as verifyFingerprints from './verify-fingerprints/index'; -export function execute() { +export function execute(): void { common.printLevel0Message('Collect information for Zowe support'); const isoDate = new Date().toISOString().replace(/T|t|:/g,'-').substring(0,19); @@ -159,9 +159,7 @@ export function execute() { std.setenv('ZWE_PRIVATE_LOG_FILE', `${verifyFingerprintsFile}`); std.setenv('ZWE_PRIVATE_LOG_LEVEL_ZWELS', 'TRACE'); fs.createFile(verifyFingerprintsFile, 0o700); - // =========================================================== - // verifyFingerprints.execute(); - // =========================================================== + verifyFingerprints.execute(true); std.setenv('ZWE_PRIVATE_LOG_FILE',`${supportLogLevel}`); std.setenv('ZWE_PRIVATE_LOG_LEVEL_ZWELS', `${supportLogLevel}`); common.printMessage(""); diff --git a/bin/commands/support/verify-fingerprints/index.ts b/bin/commands/support/verify-fingerprints/index.ts index aab64cedb6..ef1bea8859 100644 --- a/bin/commands/support/verify-fingerprints/index.ts +++ b/bin/commands/support/verify-fingerprints/index.ts @@ -29,15 +29,15 @@ function processCommResult(content: string, lines?: number): string { if (lines && lines > 0) { linesSplit = linesSplit.slice(0, lines); } - linesSplit.forEach(line => { + linesSplit.forEach(line => { const oneLineSplit = line.split(' '); - returnedOutput += `${oneLineSplit[0]}\n` + returnedOutput += `${oneLineSplit[0]}\n` }) } return returnedOutput; } -export function execute() { +export function execute(doNotExit: Boolean): void { common.printLevel0Message('Verify Zowe file fingerprints'); @@ -146,13 +146,16 @@ export function execute() { } } }); - + fs.rmrf(allFiles); fs.rmrf(customHashes); - + if (verifyFailed) { common.printMessage(""); - common.printErrorAndExit('Error ZWEL0181E: Failed to verify Zowe file fingerprints.', undefined, 181); + common.printError('Error ZWEL0181E: Failed to verify Zowe file fingerprints.'); + if (doNotExit != true) { + std.exit(181); + } } else { common.printLevel1Message('Zowe file fingerprints verification passed.'); } From 34fcb11605f790ec818e9924242daaab1e0211ec Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Thu, 23 Jan 2025 12:31:36 +0100 Subject: [PATCH 08/25] Zss PC check Signed-off-by: Martin Zeithaml --- bin/commands/support/.errors | 1 + bin/commands/support/.help | 2 +- bin/commands/support/index.ts | 23 +++++++++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/bin/commands/support/.errors b/bin/commands/support/.errors index 0f17ba69b4..2e6e4943c1 100644 --- a/bin/commands/support/.errors +++ b/bin/commands/support/.errors @@ -1 +1,2 @@ +ZWEL0150E|150|Failed to find file %s. Zowe runtimeDirectory is invalid. ZWEL0151E|151|Failed to create temporary file %s. Please check permission or volume free space. diff --git a/bin/commands/support/.help b/bin/commands/support/.help index e6ed3e24a9..8dbf11129c 100644 --- a/bin/commands/support/.help +++ b/bin/commands/support/.help @@ -10,6 +10,7 @@ This command will collect these information: * External Security Manager * CEE Runtime Options * Filesystem flags + * ZSS Program Controlled extended attribute - Zowe configurations * Zowe manifest.json * Zowe configuration file @@ -19,5 +20,4 @@ This command will collect these information: * Zowe APIML static registration files under "`zowe.workspaceDirectory`/api-mediation/api-defs" - Zowe runtime * Active running Zowe processes - * Zowe job log - Zowe fingerprints and validation result diff --git a/bin/commands/support/index.ts b/bin/commands/support/index.ts index 63cef0ad99..a287fc9e8c 100644 --- a/bin/commands/support/index.ts +++ b/bin/commands/support/index.ts @@ -21,6 +21,7 @@ import * as zos from 'zos'; import * as xplatform from 'xplatform' import * as common from '../../libs/common'; +import * as component from '../../libs/component'; import * as config from '../../libs/config'; import * as fs from '../../libs/fs'; import * as java from '../../libs/java'; @@ -31,6 +32,15 @@ import * as zosfs from '../../libs/zos-fs'; import * as verifyFingerprints from './verify-fingerprints/index'; +function zssCheck(zssBinary: string): string { + if (fs.fileExists(zssBinary)) { + return `${zssBinary} = ${component.hasPCBit(zssBinary)}` + } else { + common.printError(`Error ZWEL0150E: Failed to find file "${zssBinary}". Zowe runtimeDirectory is invalid.`); + return `Missing file: ${zssBinary}` + } +} + export function execute(): void { common.printLevel0Message('Collect information for Zowe support'); @@ -52,6 +62,7 @@ export function execute(): void { const tmpDir = fs.createTmpFile(tmpFilePrefix, targetDirectory); common.requireZoweYaml(); + const ZOWE_CONFIG=config.getZoweConfig(); common.printMessage(`Started at ${isoDate}`); fs.mkdirp(tmpDir, 0o700); @@ -114,6 +125,15 @@ export function execute(): void { environment["fs_flags"] = (({ rc, ...others }) => others)(fsFlags); // Do not include "rc" } + const zssEnabled = ZOWE_CONFIG.components?.zss?.enabled; + if (zssEnabled) { + const zssBinary = `${zoweRuntime}/components/zss/bin/zssServer`; + environment["zss_program_controlled"] = { + "31bit": `${zssCheck(zssBinary)}`, + "64bit": `${zssCheck(`${zssBinary}64`)}` + } + } + common.printMessage(JSON.stringify(environment, null, 2)); const saveEnvRc = xplatform.storeFileUTF8(environmentFile, xplatform.AUTO_DETECT, JSON.stringify(environment, null, 2)); if (saveEnvRc) { @@ -124,7 +144,6 @@ export function execute(): void { common.printMessage(`- manifest.json: ${zoweRuntime}/manifest.json`); fs.cp(`${zoweRuntime}/manifest.json`, tmpDir); - const ZOWE_CONFIG=config.getZoweConfig(); const workspaceDirectory = ZOWE_CONFIG.zowe.workspaceDirectory; common.printMessage(`- configuration: ${workspaceDirectory}/.env/.zowe-merged.yaml`); @@ -160,7 +179,7 @@ export function execute(): void { std.setenv('ZWE_PRIVATE_LOG_LEVEL_ZWELS', 'TRACE'); fs.createFile(verifyFingerprintsFile, 0o700); verifyFingerprints.execute(true); - std.setenv('ZWE_PRIVATE_LOG_FILE',`${supportLogLevel}`); + std.setenv('ZWE_PRIVATE_LOG_FILE',`${supportLogFile}`); std.setenv('ZWE_PRIVATE_LOG_LEVEL_ZWELS', `${supportLogLevel}`); common.printMessage(""); From ae94ffbc7ab692d28f14d069f4eb03c15cdd19ae Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Thu, 23 Jan 2025 14:16:41 +0100 Subject: [PATCH 09/25] Remove item Signed-off-by: Martin Zeithaml --- bin/commands/support/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/commands/support/index.ts b/bin/commands/support/index.ts index a287fc9e8c..520b9c5f65 100644 --- a/bin/commands/support/index.ts +++ b/bin/commands/support/index.ts @@ -197,7 +197,7 @@ export function execute(): void { let processesSplit = processes.out.split("\n"); for (let i = 0; i < processesSplit.length; i++) { if (processesSplit[i].includes(`grep -e ^[[:space:]]*PID -e ${jobPrefix} -e ${jobName}`)) { - processesSplit = processesSplit.splice(i, 1); + processesSplit.splice(i, 1); } } if (processesSplit.length > 1) { From bffe49770f0184cb3444d96698aa289b9285fcaf Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Thu, 23 Jan 2025 14:42:54 +0100 Subject: [PATCH 10/25] Grep update Signed-off-by: Martin Zeithaml --- bin/commands/support/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/commands/support/index.ts b/bin/commands/support/index.ts index 520b9c5f65..49dd5f19ff 100644 --- a/bin/commands/support/index.ts +++ b/bin/commands/support/index.ts @@ -190,13 +190,14 @@ export function execute(): void { common.printLevel1Message(`Collecting current process information based on the job prefix ${jobPrefix} and job name ${jobName}`); const psOutputFile = `${tmpDir}/ps_output`; - const processes = shell.execOutSync('sh', '-c', `ps -A -o pid,ppid,time,etime,user,jobname,args | grep -e "^[[:space:]]*PID" -e "${jobPrefix}" -e "${jobName}"`); + const grepCommand = `grep -i -e "^[[:space:]]*PID" -e "${jobPrefix}" -e "${jobName}"`; + const processes = shell.execOutSync('sh', '-c', `ps -A -o pid,ppid,time,etime,user,jobname,args | ${grepCommand}`); // This process has the argument, which (surprise!) is found by grep, e.g: - // 1234 5678 00:00:00 00:00:00 ADMDIN USERID grep -e ^[[:space:]]*PID -e ZWE1 -e ZWE1SV + // 1234 5678 00:00:00 00:00:00 ADMDIN USERID grep -i -e ^[[:space:]]*PID -e ZWE1 -e ZWE2 if (processes.rc == 0 && processes.out) { let processesSplit = processes.out.split("\n"); for (let i = 0; i < processesSplit.length; i++) { - if (processesSplit[i].includes(`grep -e ^[[:space:]]*PID -e ${jobPrefix} -e ${jobName}`)) { + if (processesSplit[i].includes(grepCommand.replace(/\"/g, ''))) { processesSplit.splice(i, 1); } } From 2d52634c5ecd7defc2fb836cccdd4e512f281e00 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Thu, 23 Jan 2025 16:26:17 +0100 Subject: [PATCH 11/25] Node fix Signed-off-by: Martin Zeithaml --- bin/commands/support/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/commands/support/index.ts b/bin/commands/support/index.ts index 49dd5f19ff..db0463ba62 100644 --- a/bin/commands/support/index.ts +++ b/bin/commands/support/index.ts @@ -77,7 +77,7 @@ export function execute(): void { node.optionalNode(); const nodeHome = std.getenv('NODE_HOME'); if (nodeHome) { - const nodeVersion = shell.execOutSync('sh', '-c', '${NODE_HOME} -v 2>&1 | head -n 1'); + const nodeVersion = shell.execOutSync('sh', '-c', '${NODE_HOME}/bin/node -v 2>&1 | head -n 1'); if (nodeVersion.rc == 0) { environment["node"] = `${nodeVersion.out}`; } @@ -93,8 +93,6 @@ export function execute(): void { if (keytoolInfo.rc == 0 && keytoolInfo.out) { environment["keytool_showinfo_tls"] = keytoolInfo.out.split('\n'); } - } else { - environment["java"] = 'not found'; } environment["esm"] = `${zos.getEsm()}`; From 2ba5f408c263fc4296f9a4b9d547411a8fb9dc2c Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Thu, 23 Jan 2025 16:56:24 +0100 Subject: [PATCH 12/25] zOSMF check Signed-off-by: Martin Zeithaml --- bin/commands/support/index.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/commands/support/index.ts b/bin/commands/support/index.ts index db0463ba62..c0cccf3691 100644 --- a/bin/commands/support/index.ts +++ b/bin/commands/support/index.ts @@ -29,6 +29,7 @@ import * as node from '../../libs/node' import * as shell from '../../libs/shell'; import * as zoslib from '../../libs/zos'; import * as zosfs from '../../libs/zos-fs'; +import * as zosmf from '../../libs/zosmf'; import * as verifyFingerprints from './verify-fingerprints/index'; @@ -78,8 +79,14 @@ export function execute(): void { const nodeHome = std.getenv('NODE_HOME'); if (nodeHome) { const nodeVersion = shell.execOutSync('sh', '-c', '${NODE_HOME}/bin/node -v 2>&1 | head -n 1'); - if (nodeVersion.rc == 0) { + if (nodeVersion.rc == 0 && nodeVersion.out) { environment["node"] = `${nodeVersion.out}`; + const discovery = ZOWE_CONFIG.components?.discovery?.enabled; + const zosmfHost = ZOWE_CONFIG.zOSMF?.host; + const zosmfPort = ZOWE_CONFIG.zOSMF?.port; + if (discovery && zosmfHost && zosmfPort) { + environment["zosmf_check"] = `'https://${zosmfHost}:${zosmfPort}/zosmf/info' => ${zosmf.validateZosmfHostAndPort(zosmfHost, zosmfPort)}`; + } } } else { environment["node"] = `not found`; From dfeefba87ef574b02e0b2cc9d014520c244b40f1 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Fri, 24 Jan 2025 12:52:43 +0100 Subject: [PATCH 13/25] zOSMF check in help Signed-off-by: Martin Zeithaml --- bin/commands/support/.help | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/commands/support/.help b/bin/commands/support/.help index 8dbf11129c..958c33f110 100644 --- a/bin/commands/support/.help +++ b/bin/commands/support/.help @@ -7,6 +7,7 @@ This command will collect these information: * Java version * Java keytool TLS information * Node.js version + * zOSMF status * External Security Manager * CEE Runtime Options * Filesystem flags From 0e0132bd955df2ab29ad249f4426ba2b8f05e44c Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Fri, 24 Jan 2025 15:25:15 +0100 Subject: [PATCH 14/25] Changelog update Signed-off-by: Martin Zeithaml --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2bb8b7dc4..9bcb24cf8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to the Zowe Installer will be documented in this file. ## `3.2.0` +- Enhancement: `zwe support` command collecting more environment details [$4147](https://github.com/zowe/zowe-install-packaging/pull/4147) - Enhancement: Added new library function formatZosVersion() [#4134](https://github.com/zowe/zowe-install-packaging/pull/4134) ## `3.1.0` From c5483aae19941cfccf8935e9dc09f3d2a80681e1 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Mon, 27 Jan 2025 14:24:21 +0100 Subject: [PATCH 15/25] PARMLIB example Signed-off-by: Martin Zeithaml --- bin/commands/support/.examples | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/commands/support/.examples b/bin/commands/support/.examples index dc4b4e5837..7e7dc6d515 100644 --- a/bin/commands/support/.examples +++ b/bin/commands/support/.examples @@ -1,3 +1,5 @@ zwe support -c /path/to/zowe.yaml zwe support -c /path/to/zowe.yaml --target-dir /path/to/save/support/results + +zwe support --config 'FILE(/path/to/zowe.yaml):PARMLIB(ZOWE.PARMLIB(YAML))' From a7146cf140d9feb813e7a7a56b59e1b33527f83d Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Mon, 27 Jan 2025 16:55:45 +0100 Subject: [PATCH 16/25] Node check Signed-off-by: Martin Zeithaml --- bin/commands/support/index.ts | 5 ++++- bin/libs/node.ts | 24 +++++++----------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/bin/commands/support/index.ts b/bin/commands/support/index.ts index c0cccf3691..304128590f 100644 --- a/bin/commands/support/index.ts +++ b/bin/commands/support/index.ts @@ -75,7 +75,10 @@ export function execute(): void { environment["zos-version"] = zoslib.formatZosVersion(); - node.optionalNode(); + const enabledComponents = component.getEnabledComponents(); + if (enabledComponents.includes('app-server')) { + node.requireNode(); + } const nodeHome = std.getenv('NODE_HOME'); if (nodeHome) { const nodeVersion = shell.execOutSync('sh', '-c', '${NODE_HOME}/bin/node -v 2>&1 | head -n 1'); diff --git a/bin/libs/node.ts b/bin/libs/node.ts index bb8ee6a8b8..f6c5b43f27 100644 --- a/bin/libs/node.ts +++ b/bin/libs/node.ts @@ -3,9 +3,9 @@ under the terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html - + SPDX-License-Identifier: EPL-2.0 - + Copyright Contributors to the Zowe Project. */ @@ -25,7 +25,7 @@ const NODE_MIN_VERSION=18; std.setenv('NODE_STDOUT_CCSID','1047'); std.setenv('NODE_STDERR_CCSID','1047'); std.setenv('NODE_STDIN_CCSID','1047'); - + // Workaround Fix for node 8.16.1 that requires compatibility mode for untagged files std.setenv('__UNTAGGED_READ_MODE','V6'); @@ -61,8 +61,7 @@ export function detectNodeHome(): string|undefined { } let _checkComplete = false; -export function requireNode(required: Boolean | undefined = true): void { - // if undefined => true? +export function requireNode() { if ((_checkComplete === true) && std.getenv('NODE_HOME')) { return; } @@ -79,22 +78,13 @@ export function requireNode(required: Boolean | undefined = true): void { } } if (!std.getenv('NODE_HOME')) { - if (required == true) { - common.printErrorAndExit("Error ZWEL0121E: Cannot find node. Set the node.home value in the Zowe YAML, or include node in the PATH environment variable of any accounts that start or manage Zowe", undefined, 121); - } else { - _checkComplete = true; - return; - } + common.printErrorAndExit("Error ZWEL0121E: Cannot find node. Set the node.home value in the Zowe YAML, or include node in the PATH environment variable of any accounts that start or manage Zowe", undefined, 121); } ensureNodeIsOnPath(); _checkComplete = true; } -export function optionalNode(): void { - requireNode(false); -} - export function validateNodeHome(nodeHome:string|undefined=std.getenv("NODE_HOME")): boolean { if (!nodeHome) { common.printError("Cannot find node. Please define NODE_HOME environment variable."); @@ -111,7 +101,7 @@ export function validateNodeHome(nodeHome:string|undefined=std.getenv("NODE_HOME common.printError(`Node version check failed with return code: ${shellReturn.rc}: ${version}`); return false; } - + try { if ((version as string).startsWith('v')) { // valid because rc check let parts = (version as string).split('.'); @@ -138,7 +128,7 @@ export function validateNodeHome(nodeHome:string|undefined=std.getenv("NODE_HOME } common.printDebug(`Node check is successful.`); - + return true; } else { common.printError(`Cannot validate node version '${version}'. Unexpected format`); From 63893216c9e90793a5daaa790cde90537587b197 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Wed, 29 Jan 2025 09:30:42 +0100 Subject: [PATCH 17/25] Typo and indentation Signed-off-by: Martin Zeithaml --- CHANGELOG.md | 2 +- .../support/verify-fingerprints/index.ts | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bcb24cf8c..6fe979a2ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to the Zowe Installer will be documented in this file. ## `3.2.0` -- Enhancement: `zwe support` command collecting more environment details [$4147](https://github.com/zowe/zowe-install-packaging/pull/4147) +- Enhancement: `zwe support` command collecting more environment details [#4147](https://github.com/zowe/zowe-install-packaging/pull/4147) - Enhancement: Added new library function formatZosVersion() [#4134](https://github.com/zowe/zowe-install-packaging/pull/4134) ## `3.1.0` diff --git a/bin/commands/support/verify-fingerprints/index.ts b/bin/commands/support/verify-fingerprints/index.ts index ef1bea8859..71855058d8 100644 --- a/bin/commands/support/verify-fingerprints/index.ts +++ b/bin/commands/support/verify-fingerprints/index.ts @@ -131,19 +131,19 @@ export function execute(doNotExit: Boolean): void { } if (commResult.out) { - const linesReturned = commResult.out.split("\n").length; - common.printMessage(` * Number of ${commStepName} files: ${linesReturned}`); - if (linesReturned) { + const linesReturned = commResult.out.split("\n").length; + common.printMessage(` * Number of ${commStepName} files: ${linesReturned}`); + if (linesReturned) { verifyFailed = true; if (logLevel == 'TRACE' ) { - common.printTrace(` * All ${commStepName} files:`); - common.printTrace(processCommResult(commResult.out, undefined)); + common.printTrace(` * All ${commStepName} files:`); + common.printTrace(processCommResult(commResult.out, undefined)); } if (logLevel == 'DEBUG') { - common.printDebug(` * First 10 ${commStepName} files:`); - common.printDebug(stringlib.paddingLeft(processCommResult(commResult.out, 10)," ")); - } + common.printDebug(` * First 10 ${commStepName} files:`); + common.printDebug(stringlib.paddingLeft(processCommResult(commResult.out, 10)," ")); } + } } }); From 0b7168a61064cdf208810d8a92bd15728df83d78 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Wed, 29 Jan 2025 18:01:04 +0100 Subject: [PATCH 18/25] Check java version to match defined MIN Signed-off-by: Martin Zeithaml --- .../support/verify-fingerprints/.errors | 1 + .../support/verify-fingerprints/.help | 14 ++-- .../support/verify-fingerprints/index.ts | 77 +++++++++++++++++-- 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/bin/commands/support/verify-fingerprints/.errors b/bin/commands/support/verify-fingerprints/.errors index c3d8948d48..94f583e48c 100644 --- a/bin/commands/support/verify-fingerprints/.errors +++ b/bin/commands/support/verify-fingerprints/.errors @@ -1,4 +1,5 @@ ZWEL0113E|113|Failed to find Zowe version. Please validate your Zowe directory. +ZWEL0122E|122|Cannot find java. Please define JAVA_HOME environment variable. ZWEL0150E|150|Failed to find file %s. Zowe runtimeDirectory is invalid. ZWEL0151E|151|Failed to create temporary file %s. Please check permission or volume free space. ZWEL0181E|181|Failed to verify Zowe file fingerprints. diff --git a/bin/commands/support/verify-fingerprints/.help b/bin/commands/support/verify-fingerprints/.help index 70631b94cd..39534656e2 100644 --- a/bin/commands/support/verify-fingerprints/.help +++ b/bin/commands/support/verify-fingerprints/.help @@ -1,13 +1,11 @@ This command will gather the hash (fingerprint) of every file in the `zowe.runtimeDirectory`. The result is then compared with existing hashes. -For best results, it is recommended to set all directories in the `zowe.yaml` configuration file -which reside outside the `zowe.runtimeDirectory`. These are typically `zowe.workspaceDirectory`, -`zowe.logDirectory` and certificates directories. - -Java is required to run the hash utility. Make sure one of the following is set: -* Environment variable `JAVA_HOME` -* Environment variable `PATH` which includes `java`. +Java is required to run the hash utility. Make sure the environment variable `JAVA_HOME` +is set to the directory containing `bin/java`. -Note: The `JAVA_HOME` path is the directory containing `bin/java`. For example, if java is at '/usr/lpp/java/current/bin/java', then set `JAVA_HOME` to '/usr/lpp/java/current'. + +NOTE: For best results, it is recommended to set all directories in the `zowe.yaml` configuration file +which reside outside the `zowe.runtimeDirectory`. These are typically `zowe.workspaceDirectory`, +`zowe.logDirectory` and certificates directories. diff --git a/bin/commands/support/verify-fingerprints/index.ts b/bin/commands/support/verify-fingerprints/index.ts index 71855058d8..62a3057f7f 100644 --- a/bin/commands/support/verify-fingerprints/index.ts +++ b/bin/commands/support/verify-fingerprints/index.ts @@ -17,9 +17,75 @@ import * as fs from '../../../libs/fs'; import * as shell from '../../../libs/shell'; import * as stringlib from '../../../libs/string'; -function requireJava() { - const testJava = shell.execSync('sh', '-c', 'java -version 2>/dev/null 1>/dev/null'); - return testJava.rc; +// This function is a copy of existing ../../../libs/java(validateJavaHome) +// The reason for such terrible approach is, this command could run standalone +// without config: zwe support verify-fingerprints (no parms) +// By importing java we will force to use a config. +// Either: +// * Copy of a function and backward compatibility +// * Import of a function and braking change (config required) + +const JAVA_MIN_VERSION = 17; + +export function validateJavaHome(javaHome:string|undefined=std.getenv("JAVA_HOME")): boolean { + if (!javaHome) { + common.printError("Cannot find java. Please define JAVA_HOME environment variable."); + return false; + } + if (!fs.fileExists(fs.resolvePath(javaHome,`/bin/java`))) { + common.printError(`JAVA_HOME: ${javaHome}/bin does not point to a valid install of Java.`); + return false; + } + + let execReturn = shell.execErrSync(fs.resolvePath(javaHome,`/bin/java`), `-version`); + const version = execReturn.err; + if (execReturn.rc != 0) { + common.printError(`Java version check failed with return code: ${execReturn.rc}: ${version}`); + return false; + } + + try { + let index = 0; + let javaVersionShort; + let versionLines = (version as string).split('\n'); // valid because of above rc check + for (let i = 0; i < versionLines.length; i++) { + if ((index = versionLines[i].indexOf('java version')) != -1) { + //format of: java version "1.8.0_321" OR java version "17.0.10" 2024-01-02 + javaVersionShort = versionLines[i].substring(index+('java version'.length)+2); + javaVersionShort = javaVersionShort.replace(/"/g, ''); + break; + } else if ((index = versionLines[i].indexOf('openjdk version')) != -1) { + javaVersionShort=versionLines[i].substring(index+('openjdk version'.length)+2, versionLines[i].length-1); + break; + } + } + if (!javaVersionShort){ + common.printError("could not find java version"); + return false; + } + let versionParts = javaVersionShort.split('.'); + const javaMajorVersion=Number(versionParts[0]); + const javaMinorVersion=Number(versionParts[1]); + + let tooLow=false; + if (javaMajorVersion !== 1 && javaMajorVersion < JAVA_MIN_VERSION) { + tooLow=true; + } + if (javaMajorVersion === 1 && javaMinorVersion < JAVA_MIN_VERSION) { + tooLow=true; + } + + if (tooLow) { + common.printError(`Java ${javaVersionShort} is less than the minimum level required of Java ${JAVA_MIN_VERSION}.`); + return false; + } + + common.printDebug(`Java ${javaVersionShort} is supported.`); + common.printDebug(`Java check is successful.`); + return true; + } catch (e) { + return false; + } } function processCommResult(content: string, lines?: number): string { @@ -41,8 +107,9 @@ export function execute(doNotExit: Boolean): void { common.printLevel0Message('Verify Zowe file fingerprints'); - if (requireJava()) { - common.printErrorAndExit('No Java found', undefined, 999); + const validJava = validateJavaHome(std.getenv('JAVA_HOME')); + if (!validJava) { + common.printErrorAndExit('Error ZWEL0122E Cannot find java. Please define JAVA_HOME environment variable.', undefined, 122); } const tmpFilePrefix = 'zwe-support-verify-fingerprints'; From 3cd0d31a763b1f4cd220e5afdf43fcc7fb43c68f Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Thu, 30 Jan 2025 09:18:49 +0100 Subject: [PATCH 19/25] Move independent java function to separate module Signed-off-by: Martin Zeithaml --- bin/commands/internal/start/prepare/index.ts | 3 +- .../support/verify-fingerprints/index.ts | 74 +----------------- bin/libs/java.ts | 65 +--------------- bin/libs/java_ci.ts | 77 +++++++++++++++++++ 4 files changed, 83 insertions(+), 136 deletions(-) create mode 100644 bin/libs/java_ci.ts diff --git a/bin/commands/internal/start/prepare/index.ts b/bin/commands/internal/start/prepare/index.ts index 08feceb953..1c944c1243 100644 --- a/bin/commands/internal/start/prepare/index.ts +++ b/bin/commands/internal/start/prepare/index.ts @@ -24,6 +24,7 @@ import * as config from '../../../../libs/config'; import * as component from '../../../../libs/component'; import * as varlib from '../../../../libs/var'; import * as java from '../../../../libs/java'; +import * as javaCI from '../../../../libs/java_ci'; import * as node from '../../../../libs/node'; import * as zosmf from '../../../../libs/zosmf'; @@ -148,7 +149,7 @@ function globalValidate(enabledComponents:string[]): void { // validate java for some core components //TODO this should be a manifest parameter that you require java, not a hardcoded list. What if extensions require it? if (enabledComponents.includes('gateway') || enabledComponents.includes('zaas') || enabledComponents.includes('discovery') || enabledComponents.includes('api-catalog') || enabledComponents.includes('caching-service')) { - let javaOk = java.validateJavaHome(); + let javaOk = javaCI.validateJavaHome(); if (!javaOk) { privateErrors++; common.printFormattedError('ZWELS', "zwe-internal-start-prepare,global_validate", `Could not validate java home`); diff --git a/bin/commands/support/verify-fingerprints/index.ts b/bin/commands/support/verify-fingerprints/index.ts index 62a3057f7f..e3abfa68b1 100644 --- a/bin/commands/support/verify-fingerprints/index.ts +++ b/bin/commands/support/verify-fingerprints/index.ts @@ -14,80 +14,10 @@ import * as xplatform from 'xplatform'; import * as common from '../../../libs/common'; import * as fs from '../../../libs/fs'; +import * as javaCI from '../../../libs/java_ci'; import * as shell from '../../../libs/shell'; import * as stringlib from '../../../libs/string'; -// This function is a copy of existing ../../../libs/java(validateJavaHome) -// The reason for such terrible approach is, this command could run standalone -// without config: zwe support verify-fingerprints (no parms) -// By importing java we will force to use a config. -// Either: -// * Copy of a function and backward compatibility -// * Import of a function and braking change (config required) - -const JAVA_MIN_VERSION = 17; - -export function validateJavaHome(javaHome:string|undefined=std.getenv("JAVA_HOME")): boolean { - if (!javaHome) { - common.printError("Cannot find java. Please define JAVA_HOME environment variable."); - return false; - } - if (!fs.fileExists(fs.resolvePath(javaHome,`/bin/java`))) { - common.printError(`JAVA_HOME: ${javaHome}/bin does not point to a valid install of Java.`); - return false; - } - - let execReturn = shell.execErrSync(fs.resolvePath(javaHome,`/bin/java`), `-version`); - const version = execReturn.err; - if (execReturn.rc != 0) { - common.printError(`Java version check failed with return code: ${execReturn.rc}: ${version}`); - return false; - } - - try { - let index = 0; - let javaVersionShort; - let versionLines = (version as string).split('\n'); // valid because of above rc check - for (let i = 0; i < versionLines.length; i++) { - if ((index = versionLines[i].indexOf('java version')) != -1) { - //format of: java version "1.8.0_321" OR java version "17.0.10" 2024-01-02 - javaVersionShort = versionLines[i].substring(index+('java version'.length)+2); - javaVersionShort = javaVersionShort.replace(/"/g, ''); - break; - } else if ((index = versionLines[i].indexOf('openjdk version')) != -1) { - javaVersionShort=versionLines[i].substring(index+('openjdk version'.length)+2, versionLines[i].length-1); - break; - } - } - if (!javaVersionShort){ - common.printError("could not find java version"); - return false; - } - let versionParts = javaVersionShort.split('.'); - const javaMajorVersion=Number(versionParts[0]); - const javaMinorVersion=Number(versionParts[1]); - - let tooLow=false; - if (javaMajorVersion !== 1 && javaMajorVersion < JAVA_MIN_VERSION) { - tooLow=true; - } - if (javaMajorVersion === 1 && javaMinorVersion < JAVA_MIN_VERSION) { - tooLow=true; - } - - if (tooLow) { - common.printError(`Java ${javaVersionShort} is less than the minimum level required of Java ${JAVA_MIN_VERSION}.`); - return false; - } - - common.printDebug(`Java ${javaVersionShort} is supported.`); - common.printDebug(`Java check is successful.`); - return true; - } catch (e) { - return false; - } -} - function processCommResult(content: string, lines?: number): string { let returnedOutput = ''; if (content) { @@ -107,7 +37,7 @@ export function execute(doNotExit: Boolean): void { common.printLevel0Message('Verify Zowe file fingerprints'); - const validJava = validateJavaHome(std.getenv('JAVA_HOME')); + const validJava = javaCI.validateJavaHome(std.getenv('JAVA_HOME')); if (!validJava) { common.printErrorAndExit('Error ZWEL0122E Cannot find java. Please define JAVA_HOME environment variable.', undefined, 122); } diff --git a/bin/libs/java.ts b/bin/libs/java.ts index df0ac33bf1..f7fa161119 100644 --- a/bin/libs/java.ts +++ b/bin/libs/java.ts @@ -13,11 +13,10 @@ import * as std from 'cm_std'; import * as os from 'cm_os'; import * as fs from './fs'; import * as common from './common'; +import * as javaCI from './java_ci' import * as shell from './shell'; import * as config from './config'; -const JAVA_MIN_VERSION=17; - export function ensureJavaIsOnPath(): void { let path=std.getenv('PATH') || '/bin:.:/usr/bin'; let javaHome=std.getenv('JAVA_HOME'); @@ -30,7 +29,7 @@ export function readConfigJavaHome(configList?: string, skipValidate?: boolean): const zoweConfig = config.getZoweConfig(); if (zoweConfig && zoweConfig.java && zoweConfig.java.home) { if (!skipValidate) { - if (!validateJavaHome(zoweConfig.java.home)) { + if (!javaCI.validateJavaHome(zoweConfig.java.home)) { return ''; } } @@ -79,66 +78,6 @@ export function requireJava() { _javaCheckComplete = true; } -export function validateJavaHome(javaHome:string|undefined=std.getenv("JAVA_HOME")): boolean { - if (!javaHome) { - common.printError("Cannot find java. Please define JAVA_HOME environment variable."); - return false; - } - if (!fs.fileExists(fs.resolvePath(javaHome,`/bin/java`))) { - common.printError(`JAVA_HOME: ${javaHome}/bin does not point to a valid install of Java.`); - return false; - } - - let execReturn = shell.execErrSync(fs.resolvePath(javaHome,`/bin/java`), `-version`); - const version = execReturn.err; - if (execReturn.rc != 0) { - common.printError(`Java version check failed with return code: ${execReturn.rc}: ${version}`); - return false; - } - - try { - let index = 0; - let javaVersionShort; - let versionLines = (version as string).split('\n'); // valid because of above rc check - for (let i = 0; i < versionLines.length; i++) { - if ((index = versionLines[i].indexOf('java version')) != -1) { - //format of: java version "1.8.0_321" - javaVersionShort=versionLines[i].substring(index+('java version'.length)+2, versionLines[i].length-1); - break; - } else if ((index = versionLines[i].indexOf('openjdk version')) != -1) { - javaVersionShort=versionLines[i].substring(index+('openjdk version'.length)+2, versionLines[i].length-1); - break; - } - } - if (!javaVersionShort){ - common.printError("could not find java version"); - return false; - } - let versionParts = javaVersionShort.split('.'); - const javaMajorVersion=Number(versionParts[0]); - const javaMinorVersion=Number(versionParts[1]); - - let tooLow=false; - if (javaMajorVersion !== 1 && javaMajorVersion < JAVA_MIN_VERSION) { - tooLow=true; - } - if (javaMajorVersion === 1 && javaMinorVersion < JAVA_MIN_VERSION) { - tooLow=true; - } - - if (tooLow) { - common.printError(`Java ${javaVersionShort} is less than the minimum level required of Java ${JAVA_MIN_VERSION}.`); - return false; - } - - common.printDebug(`Java ${javaVersionShort} is supported.`); - common.printDebug(`Java check is successful.`); - return true; - } catch (e) { - return false; - } -} - export function getJavaPkcs12KeystoreFlag(javaHome:string|undefined=std.getenv("JAVA_HOME")): string { if (!javaHome) { common.printError("Cannot find java. Please define JAVA_HOME environment variable."); diff --git a/bin/libs/java_ci.ts b/bin/libs/java_ci.ts new file mode 100644 index 0000000000..c5fc4e3e6f --- /dev/null +++ b/bin/libs/java_ci.ts @@ -0,0 +1,77 @@ +/* + This program and the accompanying materials are made available + under the terms of the Eclipse Public License v2.0 which + accompanies this distribution, and is available at + https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +import * as std from 'cm_std'; +import * as fs from './fs'; +import * as common from './common'; +import * as shell from './shell'; + +const JAVA_MIN_VERSION=17; + +export function validateJavaHome(javaHome:string|undefined=std.getenv("JAVA_HOME")): boolean { + if (!javaHome) { + common.printError("Cannot find java. Please define JAVA_HOME environment variable."); + return false; + } + if (!fs.fileExists(fs.resolvePath(javaHome,`/bin/java`))) { + common.printError(`JAVA_HOME: ${javaHome}/bin does not point to a valid install of Java.`); + return false; + } + + let execReturn = shell.execErrSync(fs.resolvePath(javaHome,`/bin/java`), `-version`); + const version = execReturn.err; + if (execReturn.rc != 0) { + common.printError(`Java version check failed with return code: ${execReturn.rc}: ${version}`); + return false; + } + + try { + let index = 0; + let javaVersionShort; + let versionLines = (version as string).split('\n'); // valid because of above rc check + for (let i = 0; i < versionLines.length; i++) { + if ((index = versionLines[i].indexOf('java version')) != -1) { + //format of: java version "1.8.0_321" + javaVersionShort=versionLines[i].substring(index+('java version'.length)+2, versionLines[i].length-1); + break; + } else if ((index = versionLines[i].indexOf('openjdk version')) != -1) { + javaVersionShort=versionLines[i].substring(index+('openjdk version'.length)+2, versionLines[i].length-1); + break; + } + } + if (!javaVersionShort){ + common.printError("could not find java version"); + return false; + } + let versionParts = javaVersionShort.split('.'); + const javaMajorVersion=Number(versionParts[0]); + const javaMinorVersion=Number(versionParts[1]); + + let tooLow=false; + if (javaMajorVersion !== 1 && javaMajorVersion < JAVA_MIN_VERSION) { + tooLow=true; + } + if (javaMajorVersion === 1 && javaMinorVersion < JAVA_MIN_VERSION) { + tooLow=true; + } + + if (tooLow) { + common.printError(`Java ${javaVersionShort} is less than the minimum level required of Java ${JAVA_MIN_VERSION}.`); + return false; + } + + common.printDebug(`Java ${javaVersionShort} is supported.`); + common.printDebug(`Java check is successful.`); + return true; + } catch (e) { + return false; + } +} From 069aef8999d94b6854f39545829224a957a39a32 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Thu, 30 Jan 2025 10:02:42 +0100 Subject: [PATCH 20/25] Missing update Signed-off-by: Martin Zeithaml --- bin/libs/java_ci.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/libs/java_ci.ts b/bin/libs/java_ci.ts index c5fc4e3e6f..de39e5e8df 100644 --- a/bin/libs/java_ci.ts +++ b/bin/libs/java_ci.ts @@ -39,8 +39,9 @@ export function validateJavaHome(javaHome:string|undefined=std.getenv("JAVA_HOME let versionLines = (version as string).split('\n'); // valid because of above rc check for (let i = 0; i < versionLines.length; i++) { if ((index = versionLines[i].indexOf('java version')) != -1) { - //format of: java version "1.8.0_321" - javaVersionShort=versionLines[i].substring(index+('java version'.length)+2, versionLines[i].length-1); + //format of: java version "1.8.0_321" OR java version "17.0.10" 2024-01-02 + javaVersionShort = versionLines[i].substring(index+('java version'.length)+2); + javaVersionShort = javaVersionShort.replace(/"/g, ''); break; } else if ((index = versionLines[i].indexOf('openjdk version')) != -1) { javaVersionShort=versionLines[i].substring(index+('openjdk version'.length)+2, versionLines[i].length-1); From b1992fc02fc29478376471c7c4dba75e95937ca0 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Fri, 31 Jan 2025 10:55:54 +0100 Subject: [PATCH 21/25] Verify java version Signed-off-by: Martin Zeithaml --- bin/commands/support/index.ts | 5 +++-- .../support/verify-fingerprints/index.ts | 16 +++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/bin/commands/support/index.ts b/bin/commands/support/index.ts index 304128590f..96cddb877f 100644 --- a/bin/commands/support/index.ts +++ b/bin/commands/support/index.ts @@ -25,6 +25,7 @@ import * as component from '../../libs/component'; import * as config from '../../libs/config'; import * as fs from '../../libs/fs'; import * as java from '../../libs/java'; +import * as javaCI from '../../libs/java_ci'; import * as node from '../../libs/node' import * as shell from '../../libs/shell'; import * as zoslib from '../../libs/zos'; @@ -96,6 +97,7 @@ export function execute(): void { } java.requireJava(); + javaCI.validateJavaHome(); const javaVersion = shell.execOutSync('sh', '-c', '${JAVA_HOME}/bin/java -version 2>&1 | head -n 1'); if (javaVersion.rc == 0 && javaVersion.out) { environment["java"] = javaVersion.out.replace(/\"/g, ''); @@ -116,7 +118,6 @@ export function execute(): void { const ceeOptions = shell.execOutSync('sh', '-c', `tsocmd "OMVS RUNOPTS('RPTOPTS(ON)')" 2>&1`); if (ceeOptions.out) { const ceeOptionesLines = ceeOptions.out.split('\n'); - let ceeIndex = 0; environment["cee_runtime"] = []; for (let line in ceeOptionesLines) { if (!(/^FSUM205[1|2]I/).test(ceeOptionesLines[line]) && !(/.*the alternate screen size is.*/i).test(ceeOptionesLines[line])) { @@ -186,7 +187,7 @@ export function execute(): void { std.setenv('ZWE_PRIVATE_LOG_FILE', `${verifyFingerprintsFile}`); std.setenv('ZWE_PRIVATE_LOG_LEVEL_ZWELS', 'TRACE'); fs.createFile(verifyFingerprintsFile, 0o700); - verifyFingerprints.execute(true); + verifyFingerprints.execute(true, std.getenv('JAVA_HOME')); std.setenv('ZWE_PRIVATE_LOG_FILE',`${supportLogFile}`); std.setenv('ZWE_PRIVATE_LOG_LEVEL_ZWELS', `${supportLogLevel}`); common.printMessage(""); diff --git a/bin/commands/support/verify-fingerprints/index.ts b/bin/commands/support/verify-fingerprints/index.ts index e3abfa68b1..757b2344a6 100644 --- a/bin/commands/support/verify-fingerprints/index.ts +++ b/bin/commands/support/verify-fingerprints/index.ts @@ -18,13 +18,16 @@ import * as javaCI from '../../../libs/java_ci'; import * as shell from '../../../libs/shell'; import * as stringlib from '../../../libs/string'; +// Originally in shell: "echo $result | head -n 10 | awk '{ print $1 }')" function processCommResult(content: string, lines?: number): string { let returnedOutput = ''; if (content) { let linesSplit = content.split("\n"); + // head -n lines if (lines && lines > 0) { linesSplit = linesSplit.slice(0, lines); } + // awk '{ print $1 }' linesSplit.forEach(line => { const oneLineSplit = line.split(' '); returnedOutput += `${oneLineSplit[0]}\n` @@ -33,13 +36,16 @@ function processCommResult(content: string, lines?: number): string { return returnedOutput; } -export function execute(doNotExit: Boolean): void { +export function execute(doNotExit: Boolean, javaHome: string): void { common.printLevel0Message('Verify Zowe file fingerprints'); - const validJava = javaCI.validateJavaHome(std.getenv('JAVA_HOME')); - if (!validJava) { - common.printErrorAndExit('Error ZWEL0122E Cannot find java. Please define JAVA_HOME environment variable.', undefined, 122); + if (!javaHome) { + javaHome = std.getenv('JAVA_HOME'); + const validJava = javaCI.validateJavaHome(javaHome); + if (!validJava) { + common.printErrorAndExit('Error ZWEL0122E Cannot find java. Please define JAVA_HOME environment variable.', undefined, 122); + } } const tmpFilePrefix = 'zwe-support-verify-fingerprints'; @@ -82,7 +88,7 @@ export function execute(doNotExit: Boolean): void { common.printMessage('- Calculate hashes of Zowe files'); const customHashes = fs.createTmpFile(tmpFilePrefix); - const javaHash = shell.execOutSync('sh', '-c', `cd '${zoweRuntime}' && java -cp "${zoweRuntime}/bin/utils/" HashFiles "${allFiles}" | sort > "${customHashes}"`); + const javaHash = shell.execOutSync('sh', '-c', `cd '${zoweRuntime}' && '${javaHome}/bin/java' -cp '${zoweRuntime}/bin/utils/' HashFiles '${allFiles}' | sort > '${customHashes}'`); if (javaHash.rc != 0 || !fs.fileExists(customHashes) || fs.fileSize(customHashes) < 1) { common.printError(` * Error ZWEL0151E: Failed to create temporary file ${customHashes}. Please check permission or volume free space.`); From faedf57f61b637bf5d7e3d363a3368f6c4d4fe7e Mon Sep 17 00:00:00 2001 From: MarkAckert Date: Wed, 5 Feb 2025 14:07:59 -0500 Subject: [PATCH 22/25] update fingerprints to use JAVA_HOME from playbooks Signed-off-by: MarkAckert --- playbooks/roles/verify/tasks/main.yml | 1 + tests/sanity/test/install/test-installed-files.js | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/playbooks/roles/verify/tasks/main.yml b/playbooks/roles/verify/tasks/main.yml index 2651ceea99..845d42c33d 100644 --- a/playbooks/roles/verify/tasks/main.yml +++ b/playbooks/roles/verify/tasks/main.yml @@ -53,6 +53,7 @@ ZOWE_INSTANCE_ID: "{{ zowe_instance_id }}" ZOWE_ZLUX_HTTPS_PORT: "{{ zowe_zlux_port }}" ZOWE_API_MEDIATION_GATEWAY_HTTP_PORT: "{{ zowe_apiml_gateway_port }}" + ZOWE_JAVA_HOME: "{{ zos_java_home }}" DEBUG: "{{ zowe_sanity_test_debug_mode | default('') }}" # # this should be commented out for live tests # NODE_DEBUG: "http,https" diff --git a/tests/sanity/test/install/test-installed-files.js b/tests/sanity/test/install/test-installed-files.js index 976bcfd202..58170089c6 100644 --- a/tests/sanity/test/install/test-installed-files.js +++ b/tests/sanity/test/install/test-installed-files.js @@ -43,7 +43,12 @@ describe('verify installed files', function() { it('fingerprint should match', async function() { // IMPORT: After 'source' the profile, JAVA_HOME environment variable must exist // note the --config assumes the instance dir, which is set in ansible playbooks - const fingerprintStdout = await sshHelper.executeCommandWithNoError(`touch ~/.profile && . ~/.profile && ${process.env.ZOWE_ROOT_DIR}/bin/zwe support verify-fingerprints --config /ZOWE/tmp/.zowe/zowe.yaml`); + // if we have ZOWE_JAVA_HOME in our env, just use that. + let OPTIONAL_JAVA_HOME = ''; + if (process.env.ZOWE_JAVA_HOME) { + OPTIONAL_JAVA_HOME = `JAVA_HOME=${process.env.ZOWE_JAVA_HOME} `; + } + const fingerprintStdout = await sshHelper.executeCommandWithNoError(`touch ~/.profile && . ~/.profile && ${OPTIONAL_JAVA_HOME} ${process.env.ZOWE_ROOT_DIR}/bin/zwe support verify-fingerprints`); debug('fingerprint show result:', fingerprintStdout); addContext(this, { title: 'fingerprint show result', From eacc10d7809aeef3f20e113514a5ed430db70cf9 Mon Sep 17 00:00:00 2001 From: MarkAckert Date: Wed, 5 Feb 2025 15:31:44 -0500 Subject: [PATCH 23/25] empty output means no issues found via comm, print it Signed-off-by: MarkAckert --- bin/commands/support/verify-fingerprints/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/commands/support/verify-fingerprints/index.ts b/bin/commands/support/verify-fingerprints/index.ts index 757b2344a6..10ee46af5c 100644 --- a/bin/commands/support/verify-fingerprints/index.ts +++ b/bin/commands/support/verify-fingerprints/index.ts @@ -147,6 +147,8 @@ export function execute(doNotExit: Boolean, javaHome: string): void { common.printDebug(stringlib.paddingLeft(processCommResult(commResult.out, 10)," ")); } } + } else { + common.printMessage(` * Number of ${commStepName} files: 0`); } }); From 4da1b2e503c4aeeb125644bb0824a8ab2bb00b23 Mon Sep 17 00:00:00 2001 From: MarkAckert Date: Wed, 5 Feb 2025 16:32:44 -0500 Subject: [PATCH 24/25] add note to changelog Signed-off-by: MarkAckert --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fe979a2ec..c4b875a694 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to the Zowe Installer will be documented in this file. ## `3.2.0` - Enhancement: `zwe support` command collecting more environment details [#4147](https://github.com/zowe/zowe-install-packaging/pull/4147) - Enhancement: Added new library function formatZosVersion() [#4134](https://github.com/zowe/zowe-install-packaging/pull/4134) +- `zwe support verify-fingerprints` no longer requires a `zowe.yaml` to be passed as a command-line parameter. ## `3.1.0` - Bugfix: When logging `zwe` command, sometimes the log has wrong file tag and the log is unreadable. [#4071](https://github.com/zowe/zowe-install-packaging/pull/4071) From 7d2141c2df302579e1de18867bfb5ac95fb17072 Mon Sep 17 00:00:00 2001 From: Martin Zeithaml Date: Thu, 6 Feb 2025 09:30:58 +0100 Subject: [PATCH 25/25] Member name ZWEYAML in example Signed-off-by: Martin Zeithaml --- bin/commands/support/.examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/commands/support/.examples b/bin/commands/support/.examples index 7e7dc6d515..9cf4425974 100644 --- a/bin/commands/support/.examples +++ b/bin/commands/support/.examples @@ -2,4 +2,4 @@ zwe support -c /path/to/zowe.yaml zwe support -c /path/to/zowe.yaml --target-dir /path/to/save/support/results -zwe support --config 'FILE(/path/to/zowe.yaml):PARMLIB(ZOWE.PARMLIB(YAML))' +zwe support --config 'FILE(/path/to/zowe.yaml):PARMLIB(ZOWE.PARMLIB(ZWEYAML))'