UNPKG

@zowe/cli

Version:

Zowe CLI is a command line interface (CLI) that provides a simple and streamlined way to interact with IBM z/OS.

271 lines 14.2 kB
"use strict"; /* * 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. * */ 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 }); const imperative_1 = require("@zowe/imperative"); const util_1 = require("util"); const GetJobs_1 = require("./GetJobs"); const JobStatus_1 = require("./types/JobStatus"); const utils_1 = require("../../../utils"); /** * APIs for monitoring the status of a job. Use these APIs to wait for a job to enter the specified status. All APIs * in monitor jobs invoke z/OSMF jobs REST endpoints to obtain job status information. * @export * @class MonitorJobs */ class MonitorJobs { /** * Given an IJob (has jobname/jobid), waits for the status of the job to be "OUTPUT". This API will poll for * the OUTPUT status once every 3 seconds indefinitely. If the polling interval/duration is NOT sufficient, use * "waitForStatusCommon" to adjust. * * See JSDoc for "waitForStatusCommon" for full details on polling and other logic. * * @static * @param {AbstractSession} session - a Rest client session for z/OSMF * @param {IJob} job - the z/OS job to wait for (see z/OSMF Jobs APIs for details) * @returns {Promise<IJob>} - the promise to be fulfilled with IJob object (or rejected with an ImperativeError) * @memberof MonitorJobs */ static waitForJobOutputStatus(session, job) { imperative_1.ImperativeExpect.toNotBeNullOrUndefined(job, "IJob object (containing jobname and jobid) required"); return MonitorJobs.waitForStatusCommon(session, { jobname: job.jobname, jobid: job.jobid, status: JobStatus_1.JOB_STATUS.OUTPUT }); } /** * Given the jobname/jobid, waits for the status of the job to be "OUTPUT". This API will poll for the OUTPUT status * once every 3 seconds indefinitely. If the polling interval/duration is NOT sufficient, use * "waitForStatusCommon" to adjust. * * See JSDoc for "waitForStatusCommon" for full details on polling and other logic. * * @static * @param {AbstractSession} session - a Rest client session for z/OSMF * @param {string} jobname - the z/OS jobname of the job to wait for output status (see z/OSMF Jobs APIs for details) * @param {string} jobid - the z/OS jobid of the job to wait for output status (see z/OSMF Jobs APIS for details) * @returns {Promise<IJob>} - the promise to be fulfilled with IJob object (or rejected with an ImperativeError) * @memberof MonitorJobs */ static waitForOutputStatus(session, jobname, jobid) { return MonitorJobs.waitForStatusCommon(session, { jobname, jobid, status: JobStatus_1.JOB_STATUS.OUTPUT }); } /** * Given jobname/jobid, checks for the desired "status" (default is "OUTPUT") continuously (based on the interval * and attempts specified). * * The "order" of natural job status is INPUT > ACTIVE > OUTPUT. If the requested status is earlier in the sequence * than the current status of the job, then the method returns immediately (since the job will never enter the * requested status) with the current status of the job. * * @static * @param {AbstractSession} session - a Rest client session for z/OSMF * @param {IMonitorJobWaitForParms} parms - monitor jobs parameters (see interface for details) * @returns {Promise<IJob>} - the promise to be fulfilled with IJob object (or rejected with an ImperativeError) * @memberof MonitorJobs */ static waitForStatusCommon(session, parms) { return __awaiter(this, void 0, void 0, function* () { // Validate that required parameters are specified imperative_1.ImperativeExpect.toNotBeNullOrUndefined(parms, "IMonitorJobParms object required"); imperative_1.ImperativeExpect.keysToBeDefinedAndNonBlank(parms, ["jobname"]); imperative_1.ImperativeExpect.keysToBeDefinedAndNonBlank(parms, ["jobid"]); imperative_1.ImperativeExpect.toNotBeNullOrUndefined(session, "Required session must be defined"); if (parms.status != null) { imperative_1.ImperativeExpect.toBeOneOf(parms.status, JobStatus_1.JOB_STATUS_ORDER); } if (parms.attempts != null) { imperative_1.ImperativeExpect.keysToBeOfType(parms, "number", ["attempts"]); if (parms.attempts < 0) { throw new imperative_1.ImperativeError({ msg: `Expect Error: "attempts" must be a positive integer` }); } } if (parms.watchDelay != null) { imperative_1.ImperativeExpect.keysToBeOfType(parms, "number", ["watchDelay"]); if (parms.watchDelay < 0) { throw new imperative_1.ImperativeError({ msg: `Expect Error: "watchDelay" must be a positive integer` }); } } // Log the API call (& full parms at trace level) this.log.info(`Monitor Jobs - "waitForStatusCommon" API request: ` + `jobname ${parms.jobname}, jobid ${parms.jobid}, attempts ${parms.attempts}, watch delay ${parms.watchDelay}`); this.log.trace(`Parameters:\n${util_1.inspect(parms)}`); // set defaults if not supplied if (parms.status == null) { parms.status = MonitorJobs.DEFAULT_STATUS; } if (parms.attempts == null) { parms.attempts = MonitorJobs.DEFAULT_ATTEMPTS; } // Wait for the expected status (or timeout) let response; try { response = yield MonitorJobs.pollForStatus(session, parms); } catch (pollStatusErr) { // If a poll error occurred - reject the promise if (pollStatusErr instanceof imperative_1.ImperativeError) { const details = pollStatusErr.mDetails; details.msg = this.constructErrorMsg(parms, pollStatusErr.message); this.log.error(`${details.msg}`); throw new imperative_1.ImperativeError(details); } else { const msg = this.constructErrorMsg(parms, pollStatusErr.message); this.log.error(`${msg}`); throw new imperative_1.ImperativeError({ msg }); } } // Return the response this.log.trace(`Monitor Jobs - "waitForStatusCommon" complete - found expected status of ${parms.status}`); return response; }); } /** * "Polls" (sets timeouts and continuously checks) for the status of the job to match the desired status. * @private * @static * @param {AbstractSession} session - a Rest client session for z/OSMF * @param {IMonitorJobWaitForParms} parms - The monitor jobs parms (see interface for details) * @returns {Promise<IJob>} - Fulfill when the status changes as expected * @memberof MonitorJobs */ static pollForStatus(session, parms) { return __awaiter(this, void 0, void 0, function* () { // Timeout value const timeoutVal = parms.watchDelay || MonitorJobs.DEFAULT_WATCH_DELAY; // Define loop control parameters let expectedStatus = false; let job; let attempt = 0; let shouldContinue = false; // Catch any errors that might happen in MonitorJobs.checkStatus. // Try instantiated outside the for loop because it gets created once for the entire // loop operation, as opposed to once per operation of the loop. try { do { // Check the status of the job attempt++; this.log.debug(`Polling for jobname "${parms.jobname}" jobid "${parms.jobid}" status "${parms.status}" ` + `- attempt "${attempt}" (max attempts "${parms.attempts}") ...`); // Check the status of the job [expectedStatus, job] = yield MonitorJobs.checkStatus(session, parms); // Logic is done this way because we don't need to sleep if we are // exiting the loop on this operation. shouldContinue = !expectedStatus && (parms.attempts > 0 && attempt < parms.attempts); // Wait for the next poll if we didn't get the proper status. if (shouldContinue) { // Set a timer which will check the status on expiry this.log.trace(`Setting timeout for next poll...`); yield utils_1.sleep(timeoutVal); } } while (shouldContinue); } catch (e) { this.log.error("Received error while polling"); this.log.error(e); throw e; } // One of the conditions that will cause the loop to end. If this specific // condition was encountered, then we timed out and exhausted all of our attempts // without successfully retrieving the job. if (!expectedStatus && parms.attempts > 0 && attempt >= parms.attempts) { throw new imperative_1.ImperativeError({ msg: `Error Details: Reached max poll attempts of "${parms.attempts}"` }); } // The only way we get here is by successfully getting the job. this.log.debug(`Expected status "${parms.status}" found for jobname "${parms.jobname}" jobid "${parms.jobid}" ` + `- attempt "${attempt}" (max attempts "${parms.attempts}") ...`); return job; }); } /** * Checks the status of the job for the expected status (OR that the job has progressed passed the expected status). * @private * @static * @param {AbstractSession} session - the session to initiate the z/OSMF getJobStatus request * @param {IMonitorJobWaitForParms} parms - the monitor jobs parameters containing the jobname, jobid, status, etc. * @returns {Promise<boolean>} - promise to fulfill when the job status is obtained (or imperative error) * @memberof MonitorJobs */ static checkStatus(session, parms) { return __awaiter(this, void 0, void 0, function* () { // Log an get the status of the job this.log.debug(`Checking for "${parms.status}" status for jobname "${parms.jobname}", jobid "${parms.jobid}"...`); const job = yield GetJobs_1.GetJobs.getStatusCommon(session, parms); this.log.debug(`jobname "${parms.jobname}" jobid "${parms.jobid}" has current status of "${job.status}".`); // Ensure that the job status is defined & known if (job.status == null || JobStatus_1.JOB_STATUS_ORDER.indexOf(job.status.toUpperCase()) < 0) { this.log.error(`An unknown status of "${job.status}" for jobname ${job.jobname}, jobid ${job.jobid}, was received.`); throw new imperative_1.ImperativeError({ msg: `Error Details: An unknown status "${job.status}" was received.` }); } // If the status matches exactly OR the jobs current status is further than the requested status (for // example, if the jobs status is ACTIVE and the requested status is INPUT) fulfill. if (JobStatus_1.JOB_STATUS_ORDER.indexOf(job.status) >= JobStatus_1.JOB_STATUS_ORDER.indexOf(parms.status)) { this.log.debug(`The current status (${job.status}) for jobname ${job.jobname}, jobid ${job.jobid} ` + `is greater than or equal to the expected of "${parms.status}"`); return [true, job]; } return [false, job]; }); } /** * Constructs the default error message (to be thrown via ImperativeError) for the monitor jobs APIs * @private * @static * @param {IMonitorJobWaitForParms} parms - The parameters passed to the API * @param {string} details - Additional error details string * @returns {string} - The error string to be thrown via ImperativeError * @memberof MonitorJobs */ static constructErrorMsg(parms, details) { return `Error obtaining status for jobname "${parms.jobname}" jobid "${parms.jobid}".\n${details}`; } } exports.MonitorJobs = MonitorJobs; /** * The default amount of time (in milliseconds) to wait until the next job status poll. * @static * @memberof MonitorJobs */ MonitorJobs.DEFAULT_WATCH_DELAY = 3000; // 3000 is 3 seconds /** * Default expected job status ("OUTPUT") * @static * @memberof MonitorJobs */ MonitorJobs.DEFAULT_STATUS = JobStatus_1.JOB_STATUS.OUTPUT; /** * Default number of poll attempts to check for the specified job status. * @static * @memberof MonitorJobs */ MonitorJobs.DEFAULT_ATTEMPTS = Infinity; /** * Obtain an instance of the app logger (Brightside). * @private * @static * @type {Logger} * @memberof MonitorJobs */ MonitorJobs.log = imperative_1.Logger.getAppLogger(); //# sourceMappingURL=MonitorJobs.js.map