zowe-cli-cics-deploy-plugin
Version:
IBM CICS Bundle generation and deployment for Zowe CLI
761 lines • 38.9 kB
JavaScript
/*
* 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 IBM Corp, 2019
*
*/
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BundlePusher = void 0;
const imperative_1 = require("@zowe/imperative");
const cli_1 = require("@zowe/cli");
const cics_for_zowe_cli_1 = require("@zowe/cics-for-zowe-cli");
const BundleDeployer_1 = require("../BundleDeploy/BundleDeployer");
const Bundle_1 = require("../BundleContent/Bundle");
const SubtaskWithStatus_1 = require("./SubtaskWithStatus");
const ZosmfConfig_1 = require("./ZosmfConfig");
const SshConfig_1 = require("./SshConfig");
const CmciConfig_1 = require("./CmciConfig");
/**
* Class to represent a CICS Bundle Pusher.
*
* @export
* @class BundlePusher
*/
class BundlePusher {
/**
* Constructor for a BundlePusher.
* @param {IHandlerParameters} params - The Imperative handler parameters
* @param {string} localDirectory - The bundle directory.
* @throws ImperativeError
* @memberof BundlePusher
*/
constructor(params, localDirectory) {
this.sshOutputText = "";
this.path = require("path");
this.fs = require("fs");
this.defaultRemoteNodehomeCmd = "export PATH=\"$PATH:/usr/lpp/IBM/cnj/v8r0/IBM/node-latest-os390-s390x/bin\"";
this.envSetupCommand = "export _BPXK_AUTOCVT=ON";
this.params = params;
this.localDirectory = localDirectory;
this.validateParameters();
// The targetdir may contain escaped slashes, get rid of them
this.params.arguments.targetdir = this.path.posix.normalize(this.params.arguments.targetdir);
// Set an initial bundledir value for validation purposes (we'll replace it with a better value shortly)
this.params.arguments.bundledir = this.path.posix.join(this.params.arguments.targetdir, this.params.arguments.name);
}
performPush() {
return __awaiter(this, void 0, void 0, function* () {
// Start by validating any parameters that will be used by the deploy action,
// this should flush out most input errors before we go on to attempt upload
// of the bundle
const bd = new BundleDeployer_1.BundleDeployer(this.params);
bd.validateDeployParms();
// Check that the current working directory is a CICS bundle
const bundle = new Bundle_1.Bundle(this.localDirectory, true, true);
bundle.validate();
// If the bundle has an id, use it in the target directory name
if (bundle.getId() !== undefined) {
this.params.arguments.bundledir = this.path.posix.join(this.params.arguments.targetdir, bundle.getId()) +
"_" + bundle.getVersion();
}
if (this.params.arguments.silent === undefined) {
const logger = imperative_1.Logger.getAppLogger();
logger.debug("Loading profiles");
}
// Get the profiles
const zosMFProfile = this.getProfile("zosmf");
const sshProfile = this.getProfile("ssh");
let cicsProfile = this.getProfile("cics");
ZosmfConfig_1.ZosmfConfig.mergeProfile(zosMFProfile, this.params);
SshConfig_1.SshConfig.mergeProfile(sshProfile, this.params);
CmciConfig_1.CmciConfig.mergeProfile(cicsProfile, this.params);
// The cics profile is optional, detect whether it has been set (or constructed)
if (Object.keys(cicsProfile).length === 0) {
cicsProfile = undefined;
}
// Now detect any mismatches between the values from the profiles
this.validateProfiles(zosMFProfile, sshProfile, cicsProfile);
if (this.params.arguments.silent === undefined) {
const logger = imperative_1.Logger.getAppLogger();
logger.debug("Creating sessions");
}
// Create a zOSMF session
const zosMFSession = yield this.createZosMFSession(zosMFProfile);
// Create an SSH session
const sshSession = yield this.createSshSession(sshProfile);
// If relevant, start a CICS session
const cicsSession = yield this.createCicsSession(cicsProfile);
// Start a progress bar (but only in non-verbose mode)
this.progressBar = { percentComplete: 0,
statusMessage: "Starting Push operation",
stageName: imperative_1.TaskStage.IN_PROGRESS };
this.startProgressBar();
// Attempt to make the target bundledir
yield this.makeBundleDir(zosMFSession);
// Check that the remote bundledir is suitable.
yield this.validateBundleDirExistsAndIsEmpty(zosMFSession);
// If --overwrite is set then undeploy any existing bundle from CICS
if (this.params.arguments.overwrite) {
yield this.undeployExistingBundle(zosMFSession, bd);
}
// Find all of the package.json files in the Bundle
const packageJsonFiles = [];
this.findAllPackageJSONDirs(this.localDirectory, this.params.arguments.bundledir, packageJsonFiles);
// If --overwrite is set then empty the remote directory structure
if (this.params.arguments.overwrite) {
// Run 'npm uninstall' for each package.json file that exists in the bundle.
// This is a courtesy to give npm a chance to clean up itself, we have seen
// things get installed that are difficult to remove simply by deleting the
// directory.
try {
yield this.runAllNpmUninstalls(sshSession, packageJsonFiles);
}
catch (error) {
// Something went wrong, but never mind, we'll destroy the entire directory in
// a moment.
}
// Now delete the directory
yield this.deleteBundleDirContents(sshSession);
}
// Upload the bundle
yield this.uploadBundle(zosMFSession);
// Run 'npm install' for each package.json file that exists in the bundle
yield this.runAllNpmInstalls(sshSession, packageJsonFiles);
// Run DFHDPLOY to install the bundle (note that this will end the progress bar)
yield this.deployBundle(zosMFSession, bd, cicsSession, bundle);
return "PUSH operation completed";
});
}
validateParameters() {
// Most of the parameters are validated by the bundle deployer, but we have
// to check the --name and --targetdir parameters here, as they are used
// to construct one of the values used by the BundleDeployer.
this.validateName();
this.validateTargetdir();
}
validateName() {
// Name is mandatory
if (this.params.arguments.name === undefined) {
throw new Error("--name parameter is not set");
}
if (typeof this.params.arguments.name !== "string") {
throw new Error("--name parameter is not a string");
}
const MAX_LEN = 8;
if (this.params.arguments.name.length > MAX_LEN) {
throw new Error("--name parameter is too long");
}
if (this.params.arguments.name === "") {
throw new Error("--name parameter is empty");
}
}
validateTargetdir() {
// targetdir is mandatory
if (this.params.arguments.targetdir === undefined) {
throw new Error("--targetdir parameter is not set");
}
if (typeof this.params.arguments.targetdir !== "string") {
throw new Error("--targetdir parameter is not a string");
}
const MAX_LEN = 255;
if (this.params.arguments.targetdir.length > MAX_LEN) {
throw new Error("--targetdir parameter is too long");
}
if (this.params.arguments.targetdir === "") {
throw new Error("--targetdir parameter is empty");
}
}
getProfile(type) {
let profile;
try {
profile = this.params.profiles.get(type);
}
catch (error) {
// Tolerate errors
}
if (profile === undefined) {
profile = {};
}
return profile;
}
issueWarning(msg) {
const warningMsg = "WARNING: " + msg + "\n";
this.issueMessage(warningMsg);
}
issueMessage(msg) {
this.params.response.console.log(Buffer.from(msg));
if (this.params.arguments.silent === undefined) {
const logger = imperative_1.Logger.getAppLogger();
logger.warn(msg);
}
}
validateProfiles(zosmfProfile, sshProfile, cicsProfile) {
// Do the required profiles share the same host name?
let sameHostAndUser = true;
if (zosmfProfile.host !== sshProfile.host) {
sameHostAndUser = false;
this.issueWarning("--ssh-host value '" + sshProfile.host + "' does not match --zosmf-host value '" + zosmfProfile.host + "'.");
}
// Do the required profiles share the same user name?
if (zosmfProfile.user.toUpperCase() !== sshProfile.user.toUpperCase()) {
sameHostAndUser = false;
this.issueWarning("--ssh-user value '" + sshProfile.user + "' does not match --zosmf-user value '" + zosmfProfile.user + "'.");
}
// If the zoSMF user and host are the same then validate that the passwords are the same too.
// It's possible, especially over a password change, that one profile may have been updated
// and not the other. Attemps to use the wrong password could result in the account being revoked.
if (sameHostAndUser) {
if (sshProfile.password !== undefined) {
if (zosmfProfile.password !== sshProfile.password) {
throw new Error("Different passwords are specified for the same user ID in the zosmf and ssh configurations.");
}
}
}
// Is the optional CICS profile compatible?
if (cicsProfile !== undefined) {
sameHostAndUser = true;
if (zosmfProfile.host !== cicsProfile.host) {
sameHostAndUser = false;
this.issueWarning("--cics-host value '" + cicsProfile.host + "' does not match --zosmf-host value '" + zosmfProfile.host + "'.");
}
if (zosmfProfile.user.toUpperCase() !== cicsProfile.user.toUpperCase()) {
sameHostAndUser = false;
this.issueWarning("--cics-user value '" + cicsProfile.user + "' does not match --zosmf-user value '" + zosmfProfile.user + "'.");
}
if (sameHostAndUser) {
if (zosmfProfile.password !== cicsProfile.password) {
throw new Error("Different passwords are specified for the same user ID in the zosmf and cics configurations.");
}
}
}
}
createZosMFSession(zosmfProfile) {
return __awaiter(this, void 0, void 0, function* () {
try {
return cli_1.ZosmfSession.createBasicZosmfSession(zosmfProfile);
}
catch (error) {
throw new Error("Failure occurred creating a zosmf session: " + error.message);
}
});
}
createSshSession(sshProfile) {
return __awaiter(this, void 0, void 0, function* () {
try {
return cli_1.SshSession.createBasicSshSession(sshProfile);
}
catch (error) {
throw new Error("Failure occurred creating an ssh session: " + error.message);
}
});
}
createCicsSession(cicsProfile) {
return __awaiter(this, void 0, void 0, function* () {
if (cicsProfile === undefined) {
return undefined;
}
// At time of writing, the CicsSession object in the @zowe/cics project isn't
// accessible, so the following code is copied out of CicsSession.createBasicCicsSession().
try {
return new imperative_1.Session({
type: "basic",
hostname: cicsProfile.host,
port: cicsProfile.port,
user: cicsProfile.user,
password: cicsProfile.password,
basePath: cicsProfile.basePath,
protocol: cicsProfile.protocol || "http",
rejectUnauthorized: cicsProfile.rejectUnauthorized
});
}
catch (error) {
throw new Error("Failure occurred creating a cics session: " + error.message);
}
});
}
validateBundleDirExistsAndIsEmpty(zosMFSession) {
return __awaiter(this, void 0, void 0, function* () {
try {
this.updateStatus("Accessing contents of remote bundle directory");
const fileListResponse = yield cli_1.List.fileList(zosMFSession, this.params.arguments.bundledir, {});
if (!fileListResponse.success) {
throw new Error("Command Failed.");
}
if (fileListResponse.apiResponse === undefined) {
throw new Error("Command response is empty.");
}
if (fileListResponse.apiResponse.items === undefined) {
throw new Error("Command response items are missing.");
}
// There are always at least two files in all directories: . and ..
const MIN_FILES = 2;
// Check that if there are files in the directory, one of them is called META-INF
let foundMETAINF = false;
if (fileListResponse.apiResponse.items.length > MIN_FILES) {
for (const file of fileListResponse.apiResponse.items) {
if (file.name === "META-INF") {
foundMETAINF = true;
}
}
if (!foundMETAINF) {
throw new Error("The remote directory is already populated and does not contain a bundle.");
}
}
// Check that --overwrite is set if the directory is not empty
if (fileListResponse.apiResponse.items.length > MIN_FILES && this.params.arguments.overwrite !== true) {
throw new Error("The remote directory has existing content and --overwrite has not been set.");
}
}
catch (error) {
throw new Error("A problem occurred accessing remote bundle directory '" + this.params.arguments.bundledir +
"'. Problem is: " + error.message);
}
});
}
undeployExistingBundle(zosMFSession, bd) {
return __awaiter(this, void 0, void 0, function* () {
// End the current progress bar so that UNDEPLOY can create its own
this.updateStatus("Undeploying bundle '" + this.params.arguments.name + "' from CICS");
const targetstateLocal = this.params.arguments.targetstate;
this.params.arguments.targetstate = "DISCARDED";
const subtask = new SubtaskWithStatus_1.SubtaskWithStatus(this.progressBar, imperative_1.TaskProgress.THIRTY_PERCENT);
yield bd.undeployBundle(zosMFSession, subtask);
this.params.arguments.targetstate = targetstateLocal;
// Resume the current progress bar
this.endProgressBar();
this.updateStatus("Undeploy complete");
this.startProgressBar();
});
}
deployBundle(zosMFSession, bd, cicsSession, bundle) {
return __awaiter(this, void 0, void 0, function* () {
// End the current progress bar so that DEPLOY can create its own
this.updateStatus("Deploying bundle '" + this.params.arguments.name + "' to CICS");
const subtask = new SubtaskWithStatus_1.SubtaskWithStatus(this.progressBar, imperative_1.TaskProgress.THIRTY_PERCENT);
let deployError;
let dfhdployOutput = "";
try {
yield bd.deployBundle(zosMFSession, subtask);
}
catch (error) {
// temporarily ignore the error as we might want to generate additional resource
// specific diagnostics even if something went wrong.
deployError = error;
}
dfhdployOutput = bd.getJobOutput();
// End the main progress bar
this.progressBar.percentComplete = imperative_1.TaskProgress.ONE_HUNDRED_PERCENT;
this.endProgressBar();
if (deployError === undefined) {
this.updateStatus("Deploy complete");
}
else {
this.updateStatus("Deploy ended with errors");
}
// Collect general information about the regions in the CICSplex scope
let deployMessages = yield this.generateGeneralDiagnostics(cicsSession);
if (deployError !== undefined && dfhdployOutput.indexOf("DFHRL2067") === -1) {
// If we have an error, but DFHDPLOY did not report that some bundleparts are disabled,
// we can assume bundle didn't install at all. In this case skip generation of
// Node.js diagnostics.
deployMessages += "DFHDPLOY output implied the bundle failed to install. Check the output above for further information. ";
deployMessages += "Consider examining the JESMSGLG, MSGUSR, SYSPRINT and SYSOUT spool files of the CICS region job, ";
deployMessages += "or consult your CICS system programmer.\n";
}
else if (deployMessages !== "" && bundle.containsDefinitionsOfType("http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP")) {
// Generate additional diagnostic output for Node.js
deployMessages += yield this.generateNodejsSpecificDiagnostics(cicsSession);
}
// Report any console messages now
this.issueMessage(deployMessages);
// Now rethrow the original error, if there was one.
if (deployError !== undefined) {
throw deployError;
}
});
}
sshOutput(data) {
// If verbose output is requested then log SSH output directly to the console
if (this.params.arguments.verbose) {
this.params.response.console.log(Buffer.from(data));
}
this.sshOutputText += data;
}
makeBundleDir(zosMFSession) {
return __awaiter(this, void 0, void 0, function* () {
if (this.params.arguments.verbose) {
this.updateStatus("Making remote bundle directory '" + this.params.arguments.bundledir + "'");
}
else {
this.updateStatus("Making remote bundle directory");
}
const WARNING = 4;
const ALREADY_EXISTS = 19;
const EIGHT = 8;
const TARGET_DIR_NOT_EXIST = 93651005;
const NO_PERMISSION = -276865003;
try {
yield cli_1.Create.uss(zosMFSession, this.params.arguments.bundledir, "directory");
}
catch (error) {
if (error.causeErrors !== undefined) {
let cause;
if (typeof error.causeErrors !== "object") {
try {
cause = JSON.parse(error.causeErrors);
}
catch (error) {
// whatever we received here it wasn't JSON. Oh well, never mind.
}
}
else {
cause = error.causeErrors;
}
// Special case some known errors
if (cause !== undefined) {
if (cause.category === 1 &&
cause.rc === WARNING &&
cause.reason === ALREADY_EXISTS) {
// if it already exists, no worries
return;
}
if (cause.category === EIGHT &&
cause.rc === -1 &&
cause.reason === TARGET_DIR_NOT_EXIST) {
throw new Error("The target directory does not exist, consider creating it by issuing: \n" +
"zowe zos-uss issue ssh \"mkdir -p " + this.params.arguments.targetdir + "\"");
}
if (cause.category === EIGHT &&
cause.rc === -1 &&
cause.reason === NO_PERMISSION) {
throw new Error("You are not authorized to create the target bundle directory '" + this.params.arguments.bundledir + "'.");
}
}
}
throw new Error("A problem occurred attempting to create directory '" + this.params.arguments.bundledir + "'. " +
"Problem is: " + error.message);
}
});
}
deleteBundleDirContents(sshSession) {
return __awaiter(this, void 0, void 0, function* () {
this.updateStatus("Removing contents of remote bundle directory");
yield this.runSshCommandInRemoteDirectory(sshSession, this.params.arguments.bundledir, "if [ \"$(ls)\" ]; then rm -r *; fi");
});
}
runSingleNpmInstall(sshSession, remoteDirectory) {
return __awaiter(this, void 0, void 0, function* () {
if (this.params.arguments.verbose) {
this.updateStatus("Running 'npm install' in '" + remoteDirectory + "'");
}
else {
this.updateStatus("Running 'npm install' in remote directory");
}
yield this.runSshCommandInRemoteDirectory(sshSession, remoteDirectory, this.defaultRemoteNodehomeCmd + " && " + this.envSetupCommand + " && npm install");
});
}
runSingleNpmUninstall(sshSession, remoteDirectory) {
return __awaiter(this, void 0, void 0, function* () {
if (this.params.arguments.verbose) {
this.updateStatus("Running 'npm uninstall *' in '" + remoteDirectory + "'");
}
else {
this.updateStatus("Running 'npm uninstall *' in remote directory");
}
// uninstall each module individually
yield this.runSshCommandInRemoteDirectory(sshSession, remoteDirectory, this.defaultRemoteNodehomeCmd + " && " +
this.envSetupCommand + " && " +
"if [ -d \"node_modules\" ] && [ \"$(ls node_modules)\" ]; then npm uninstall `ls -1 node_modules | tr '/\n' ' '`; fi");
});
}
runSshCommandInRemoteDirectory(sshSession, directory, sshCommand) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (this.params.arguments.verbose) {
this.updateStatus("Issuing SSH command '" + sshCommand + "' in remote directory '" + directory + "'");
}
this.sshOutputText = "";
const sshReturnCode = yield cli_1.Shell.executeSshCwd(sshSession, sshCommand, directory, this.sshOutput.bind(this));
const upperCaseOutputText = this.sshOutputText.toUpperCase();
// Note that FSUM9195 can imply that we've tried to delete the
// contents of an empty directory - that's not a problem.
// Check if FSUM9195 is the only FSUM error
let isOnlyFSUM9195 = false;
const countFSUM = (upperCaseOutputText.match(/FSUM/g) || []).length;
const countFSUM9195 = (upperCaseOutputText.match(/FSUM9195/g) || []).length;
if (countFSUM9195 !== 0 &&
countFSUM === countFSUM9195 &&
sshReturnCode === 1) {
isOnlyFSUM9195 = true;
}
// Now check
// A. If exit code is non zero
// B. FSUM9195 is not the only FSUM error
if (sshReturnCode !== 0 && !isOnlyFSUM9195) {
// if we've not already logged the output, log it now
if (this.params.arguments.verbose !== true) {
this.params.response.console.log(Buffer.from(this.sshOutputText));
}
throw new Error("The output from the remote command implied that an error occurred, return code " + sshReturnCode + ".");
}
}
catch (error) {
throw new Error("A problem occurred attempting to run '" + sshCommand + "' in remote directory '" + directory +
"'. Problem is: " + error.message);
}
});
}
uploadBundle(zosMFSession) {
return __awaiter(this, void 0, void 0, function* () {
this.updateStatus("Uploading bundle contents to remote directory");
const uploadOptions = { recursive: true };
uploadOptions.attributes = this.findZosAttributes();
uploadOptions.task = new SubtaskWithStatus_1.SubtaskWithStatus(this.progressBar, imperative_1.TaskProgress.TEN_PERCENT);
try {
yield cli_1.Upload.dirToUSSDirRecursive(zosMFSession, this.localDirectory, this.params.arguments.bundledir, uploadOptions);
}
catch (error) {
throw new Error("A problem occurred uploading the bundle contents to the remote directory '" + this.params.arguments.bundledir +
"'. Problem is: " + error.message);
}
});
}
findZosAttributes() {
const attributesFileName = this.path.join(this.localDirectory, ".zosattributes");
if (this.fs.existsSync(attributesFileName)) {
try {
const attributesFileContents = this.fs.readFileSync(attributesFileName).toString();
return new cli_1.ZosFilesAttributes(attributesFileContents, this.localDirectory);
}
catch (error) {
throw new Error("A problem occurred reading the local .zosattributes file '" + attributesFileName +
"'. Problem is: " + error.message);
}
}
// A project specific .zosattributes has not been found, so use a default
this.issueWarning("No .zosattributes file found in the bundle directory, default values will be applied.");
return new cli_1.ZosFilesAttributes(Bundle_1.Bundle.getTemplateZosAttributesFile());
}
updateStatus(status, percentageIncrease = 3) {
const MAX_PROGRESS_BAR_MESSAGE = 60;
this.progressBar.percentComplete += percentageIncrease;
if (status.length > MAX_PROGRESS_BAR_MESSAGE) {
this.progressBar.statusMessage = status.substring(0, MAX_PROGRESS_BAR_MESSAGE) + "...";
}
else {
this.progressBar.statusMessage = status;
}
if (this.params.arguments.verbose) {
this.params.response.console.log(Buffer.from(status + "\n"));
}
if (this.params.arguments.silent === undefined) {
const logger = imperative_1.Logger.getAppLogger();
logger.debug(status);
}
}
startProgressBar() {
if (this.params.arguments.verbose !== true && this.progressBar !== undefined) {
this.params.response.progress.startBar({ task: this.progressBar });
}
}
endProgressBar() {
if (this.params.arguments.verbose !== true && this.progressBar !== undefined) {
this.params.response.progress.endBar();
}
}
findAllPackageJSONDirs(directoryNameLocal, directoryNameRemote, found) {
// accumulate an array of all directories / sub-directories that contain a package.json file
const files = this.fs.readdirSync(directoryNameLocal);
for (const currentFile of files) {
const localFileName = this.path.join(directoryNameLocal, currentFile);
const remoteFileName = this.path.posix.join(directoryNameRemote, currentFile);
const stat = this.fs.lstatSync(localFileName);
if (stat.isDirectory() && currentFile !== "node_modules") {
// If we've found a sub-directory, and it's not the special node_modules directory, scan it too.
this.findAllPackageJSONDirs(localFileName, remoteFileName, found);
}
else if (currentFile === "package.json") {
// The current directory has a package.json
found.push(directoryNameRemote);
}
}
}
runAllNpmInstalls(sshSession, packageJsonFiles) {
return __awaiter(this, void 0, void 0, function* () {
for (const remoteDirectory of packageJsonFiles) {
yield this.runSingleNpmInstall(sshSession, remoteDirectory);
}
});
}
runAllNpmUninstalls(sshSession, packageJsonFiles) {
return __awaiter(this, void 0, void 0, function* () {
for (const remoteDirectory of packageJsonFiles) {
yield this.runSingleNpmUninstall(sshSession, remoteDirectory);
}
});
}
generateGeneralDiagnostics(cicsSession) {
return __awaiter(this, void 0, void 0, function* () {
let msgBuffer = "";
try {
if (cicsSession !== undefined) {
// Attempt to gather additional Node.js specific information from CICS
this.updateStatus("Gathering scope information");
msgBuffer = yield this.gatherGeneralDiagnosticsFromCics(cicsSession);
}
}
catch (diagnosticsError) {
// Something went wrong generating scope info. Don't trouble the user
// with what might be an exotic error message (e.g. hex dump of an entire HTML page),
// just log the failure.
if (this.params.arguments.silent === undefined) {
const logger = imperative_1.Logger.getAppLogger();
logger.debug(diagnosticsError.message);
}
}
// Something went wrong, suggest a command that can be run to figure out more.
if (msgBuffer === "") {
this.issueMessage("An attempt to query the remote CICSplex using the cics plug-in has failed.\n");
}
return msgBuffer;
});
}
generateNodejsSpecificDiagnostics(cicsSession) {
return __awaiter(this, void 0, void 0, function* () {
let msgBuffer = "";
if (cicsSession === undefined) {
return msgBuffer;
}
try {
// Attempt to gather additional Node.js specific information from CICS
this.updateStatus("Gathering Node.js diagnostics");
msgBuffer = yield this.gatherNodejsDiagnosticsFromCics(cicsSession);
}
catch (diagnosticsError) {
// Something went wrong generating diagnostic info. Don't trouble the user
// with what might be an exotic error message (e.g. hex dump of an entire HTML page),
// just log the failure.
if (this.params.arguments.silent === undefined) {
const logger = imperative_1.Logger.getAppLogger();
logger.debug(diagnosticsError.message);
}
}
// We must have a cics profile in order to have got this far, so suggest a command that can be run to figure out more.
if (msgBuffer === "") {
msgBuffer += "For further information on the state of your NODEJSAPP resources, consider running the following command:\n\n" +
"zowe cics get resource CICSNodejsapp --region-name " + this.params.arguments.scope +
" --criteria \"BUNDLE=" + this.params.arguments.name + "\" --cics-plex " + this.params.arguments.cicsplex + "\n\n";
}
return msgBuffer;
});
}
gatherGeneralDiagnosticsFromCics(cicsSession) {
return __awaiter(this, void 0, void 0, function* () {
// Issue a CMCI get to the target CICSplex
try {
this.updateStatus("Querying regions in scope over CMCI");
const regionData = { name: "CICSRegion",
regionName: this.params.arguments.scope,
cicsPlex: this.params.arguments.cicsplex };
const cmciRegionResponse = yield cics_for_zowe_cli_1.getResource(cicsSession, regionData);
if (cmciRegionResponse === undefined ||
cmciRegionResponse.response === undefined ||
cmciRegionResponse.response.records === undefined ||
cmciRegionResponse.response.records.cicsregion === undefined) {
throw new Error("CICSRegion CMCI output record not found.");
}
const outputRegionRecords = cmciRegionResponse.response.records.cicsregion;
let msgBuffer = "Regions in scope '" + this.params.arguments.scope + "' of CICSplex '" + this.params.arguments.cicsplex + "':\n";
// We may have an array of records if there was more than one Region in the scope
if (Array.isArray(outputRegionRecords)) {
for (const record of outputRegionRecords) {
msgBuffer = this.reportRegionData(record, msgBuffer);
}
}
else {
msgBuffer = this.reportRegionData(outputRegionRecords, msgBuffer);
}
return msgBuffer;
}
catch (error) {
throw new Error("Failure collecting diagnostics for Bundle " + this.params.arguments.name + ": " + error.message);
}
});
}
gatherNodejsDiagnosticsFromCics(cicsSession) {
return __awaiter(this, void 0, void 0, function* () {
try {
// Process each NODEJSAPP in the Scope
this.updateStatus("Querying NODEJSAPP resources over CMCI");
const nodejsData = { name: "CICSNodejsapp",
criteria: "BUNDLE=" + this.params.arguments.name,
regionName: this.params.arguments.scope,
cicsPlex: this.params.arguments.cicsplex };
const cmciNodejsResponse = yield cics_for_zowe_cli_1.getResource(cicsSession, nodejsData);
if (cmciNodejsResponse === undefined ||
cmciNodejsResponse.response === undefined ||
cmciNodejsResponse.response.records === undefined ||
cmciNodejsResponse.response.records.cicsnodejsapp === undefined) {
throw new Error("CICSNodejsapp CMCI output record not found.");
}
const outputNodejsRecords = cmciNodejsResponse.response.records.cicsnodejsapp;
let msgBuffer = "\nNODEJSAPP resources for bundle '" + this.params.arguments.name + "' in scope '" + this.params.arguments.scope + "':\n";
// We may have an array of records if there was more than one NODEJSAPP in the bundle
if (Array.isArray(outputNodejsRecords)) {
for (const record of outputNodejsRecords) {
msgBuffer = this.reportNODEJSAPPData(record, msgBuffer);
}
}
else {
msgBuffer = this.reportNODEJSAPPData(outputNodejsRecords, msgBuffer);
}
return msgBuffer;
}
catch (error) {
throw new Error("Failure collecting diagnostics for Bundle " + this.params.arguments.name + ": " + error.message);
}
});
}
reportRegionData(outputRecord, msgBuffer) {
const MAX_LENGTH = 8;
const applid = outputRecord.applid.padEnd(MAX_LENGTH, " ");
const jobid = outputRecord.jobid.padEnd(MAX_LENGTH, " ");
const jobname = outputRecord.jobname.padEnd(MAX_LENGTH, " ");
const sysname = outputRecord.mvssysname.padEnd(MAX_LENGTH, " ");
return msgBuffer + " Applid: " + applid + " jobname: " + jobname + " jobid: " + jobid + " sysname: " + sysname + "\n";
}
reportNODEJSAPPData(outputRecord, msgBuffer) {
const name = outputRecord.name;
const enablestatus = outputRecord.enablestatus;
const pid = outputRecord.pid;
const region = outputRecord.eyu_cicsname;
let stdout = outputRecord.stdout;
let stderr = outputRecord.stderr;
if (stdout === undefined || stdout.trim() === "") {
stdout = "<not available>";
}
if (stderr === undefined || stderr.trim() === "") {
stderr = "<not available>";
}
return msgBuffer + "NODEJSAPP resource '" + name + "' is in '" + enablestatus + "' state in region '" +
region + "' with process id '" + pid + "'.\n" +
" stdout: " + stdout + "\n" +
" stderr: " + stderr + "\n";
}
}
exports.BundlePusher = BundlePusher;
//# sourceMappingURL=BundlePusher.js.map