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.

553 lines 30.6 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 rest_1 = require("../../../../../rest"); const ZosFiles_constants_1 = require("../../constants/ZosFiles.constants"); const ZosFiles_messages_1 = require("../../constants/ZosFiles.messages"); const Create_defaults_1 = require("./Create.defaults"); const invoke_1 = require("../invoke"); const path = require("path"); // Do not use import in anticipation of some internationalization work to be done later. const strings = require("../../../cli/-strings-/en").default; /** * Class to handle creation of data sets */ class Create { /** * Create a data set * @param {AbstractSession} session - z/OSMF connection info * @param {CreateDataSetTypeEnum} cmdType - The type of data set we are going to create * @param {string} dataSetName - the name of the data set to create * @param {Partial<ICreateDataSetOptions>} [options={}] - additional options for the creation of the data set * @returns {Promise<IZosFilesResponse>} */ static dataSet(session, cmdType, dataSetName, options) { return __awaiter(this, void 0, void 0, function* () { let validCmdType = true; // Removes undefined properties let tempOptions = !util_1.isNullOrUndefined(options) ? JSON.parse(JSON.stringify(options)) : {}; // Required imperative_1.ImperativeExpect.toNotBeNullOrUndefined(cmdType, ZosFiles_messages_1.ZosFilesMessages.missingDatasetType.message); // Required imperative_1.ImperativeExpect.toNotBeNullOrUndefined(dataSetName, ZosFiles_messages_1.ZosFilesMessages.missingDatasetName.message); switch (cmdType) { case 3 /* DATA_SET_PARTITIONED */: tempOptions = Object.assign(Object.assign({}, Create_defaults_1.CreateDefaults.DATA_SET.PARTITIONED), tempOptions); break; case 4 /* DATA_SET_SEQUENTIAL */: tempOptions = Object.assign(Object.assign({}, Create_defaults_1.CreateDefaults.DATA_SET.SEQUENTIAL), tempOptions); break; case 0 /* DATA_SET_BINARY */: tempOptions = Object.assign(Object.assign({}, Create_defaults_1.CreateDefaults.DATA_SET.BINARY), tempOptions); break; case 1 /* DATA_SET_C */: tempOptions = Object.assign(Object.assign({}, Create_defaults_1.CreateDefaults.DATA_SET.C), tempOptions); break; case 2 /* DATA_SET_CLASSIC */: tempOptions = Object.assign(Object.assign({}, Create_defaults_1.CreateDefaults.DATA_SET.CLASSIC), tempOptions); break; default: validCmdType = false; break; } if (!validCmdType) { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.unsupportedDatasetType.message }); } else { try { // Handle the size option if (!util_1.isNullOrUndefined(tempOptions.size)) { const tAlcunit = tempOptions.size.toString().match(/[a-zA-Z]+/g); if (!util_1.isNullOrUndefined(tAlcunit)) { tempOptions.alcunit = tAlcunit.join("").toUpperCase(); } const tPrimary = tempOptions.size.toString().match(/[0-9]+/g); if (!util_1.isNullOrUndefined(tPrimary)) { tempOptions.primary = +(tPrimary.join("")); if (util_1.isNullOrUndefined(tempOptions.secondary)) { const TEN_PERCENT = 0.10; tempOptions.secondary = Math.round(tempOptions.primary * TEN_PERCENT); } } } else { if (util_1.isNullOrUndefined(tempOptions.secondary)) { if (cmdType !== 0 /* DATA_SET_BINARY */) { tempOptions.secondary = 1; } else { // tslint:disable-next-line:no-magic-numbers tempOptions.secondary = 10; } } } delete tempOptions.size; let response = ""; // Handle the print attributes option if (!util_1.isNullOrUndefined(tempOptions.showAttributes)) { if (tempOptions.showAttributes) { delete tempOptions.showAttributes; response = imperative_1.TextUtils.prettyJson(tempOptions); } else { delete tempOptions.showAttributes; } } const endpoint = ZosFiles_constants_1.ZosFilesConstants.RESOURCE + ZosFiles_constants_1.ZosFilesConstants.RES_DS_FILES + "/" + dataSetName; Create.dataSetValidateOptions(tempOptions); const data = yield rest_1.ZosmfRestClient.postExpectString(session, endpoint, [], JSON.stringify(tempOptions)); return { success: true, commandResponse: response + ZosFiles_messages_1.ZosFilesMessages.dataSetCreatedSuccessfully.message }; } catch (error) { throw error; } } }); } /** * Validate supplied parameters * @static * @param options - additional options for the creation of the data set */ static dataSetValidateOptions(options) { imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options, ZosFiles_messages_1.ZosFilesMessages.missingFilesCreateOptions.message); const tempOptions = options; for (const option in tempOptions) { if (tempOptions.hasOwnProperty(option)) { switch (option) { case "alcunit": // zOSMF defaults to TRK if missing so mimic it's behavior if (util_1.isNullOrUndefined(tempOptions.alcunit)) { tempOptions.alcunit = "TRK"; } // Only CYL and TRK valid switch (tempOptions.alcunit.toUpperCase()) { case "CYL": case "TRK": break; default: throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidAlcunitOption.message + tempOptions.alcunit }); } break; case "avgblk": // no validation at this time break; case "blksize": // zOSMF defaults to TRK if missing so mimic it's behavior if (util_1.isNullOrUndefined(tempOptions.blksize)) { tempOptions.blksize = tempOptions.lrecl; } break; case "lrecl": // Required imperative_1.ImperativeExpect.toNotBeNullOrUndefined(tempOptions.lrecl, ZosFiles_messages_1.ZosFilesMessages.missingRecordLength.message); break; case "dirblk": // Validate non-zero if dsorg is PS if (tempOptions.dirblk !== 0 && tempOptions.dsorg === "PS") { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidPSDsorgDirblkCombination.message }); } // Validate non-zero if 'dsorg' is PO if (tempOptions.dirblk === 0 && tempOptions.dsorg === "PO") { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidPODsorgDirblkCombination.message }); } break; case "dsntype": // Key to create a PDSE. const type = tempOptions.dsntype.toUpperCase(); const availableTypes = ["BASIC", "EXTPREF", "EXTREQ", "HFS", "LARGE", "PDS", "LIBRARY", "PIPE"]; if (availableTypes.indexOf(type) === -1) { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidDsntypeOption.message + tempOptions.dsntype }); } break; case "dsorg": // Only PO and PS valid switch (tempOptions.dsorg.toUpperCase()) { case "PO": case "PS": break; default: throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidDsorgOption.message + tempOptions.dsorg }); } break; case "primary": // Required imperative_1.ImperativeExpect.toNotBeNullOrUndefined(tempOptions.primary, ZosFiles_messages_1.ZosFilesMessages.missingPrimary.message); // Validate maximum allocation quantity if (tempOptions.primary > ZosFiles_constants_1.ZosFilesConstants.MAX_ALLOC_QUANTITY) { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.maximumAllocationQuantityExceeded.message + " for 'primary'." }); } break; case "secondary": // zOSMF defaults to 0 if missing so mimic it's behavior if (util_1.isNullOrUndefined(tempOptions.secondary)) { tempOptions.secondary = 0; } // Validate maximum allocation quantity if (tempOptions.secondary > ZosFiles_constants_1.ZosFilesConstants.MAX_ALLOC_QUANTITY) { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.maximumAllocationQuantityExceeded.message + " for 'secondary'." }); } break; case "recfm": // zOSMF defaults to F if missing so mimic it's behavior if (util_1.isNullOrUndefined(tempOptions.recfm)) { tempOptions.recfm = "F"; } // F, V, or U are required; B, A, M, S, T or additional // VBA works on mainframe but not via zOSMF switch (tempOptions.recfm.toUpperCase()) { case "F": case "FB": case "V": case "VB": case "U": break; default: throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidRecfmOption.message + tempOptions.recfm }); } break; // SMS class values case "mgntclass": case "storeclass": case "dataclass": // no validation break; case "unit": case "volser": // no validation break; default: throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidFilesCreateOption.message + option }); } } } } // ____________________________________________________________________________ /** * Create a VSAM cluster * @param {AbstractSession} session - An established z/OSMF session * @param {string} dataSetName - the name of the dataset for the created cluster * @param {Partial<ICreateVsamOptions>} options - options for the creation of the cluster * @example * ```typescript * * session = ZosmfSession.createBasicZosmfSession(profile); * * // The option keys are defined in ZosFilesCreateOptions, * // ZosFilesCreateExtraOptions and VsamCreateOptions. * // * const createVsamOptions: Partial<ICreateVsamOptions> = { * dsorg: "INDEXED", * size: "640KB", * secondary: 64 * showAttributes: true * })); * * try { * createResponse = await Create.vsam( * session, "SOME.DATASET.NAME", createVsamOptions * ); * } * catch (impErr) { * // handle any error * } * * // use the results in createResponse.commandResponse * ``` * @returns {Promise<IZosFilesResponse>} */ static vsam(session, dataSetName, options) { return __awaiter(this, void 0, void 0, function* () { // We require the dataset name imperative_1.ImperativeExpect.toNotBeNullOrUndefined(dataSetName, ZosFiles_messages_1.ZosFilesMessages.missingDatasetName.message); const idcamsOptions = this.vsamConvertToIdcamsOptions(options); // format the attributes to show, and remove the option let attribText = ""; if (!util_1.isNullOrUndefined(idcamsOptions.showAttributes)) { if (idcamsOptions.showAttributes) { delete idcamsOptions.showAttributes; attribText = strings.COMMON.ATTRIBUTE_TITLE + imperative_1.TextUtils.prettyJson(idcamsOptions); } else { delete idcamsOptions.showAttributes; } } try { this.vsamValidateOptions(idcamsOptions); // We invoke IDCAMS to create the VSAM cluster const idcamsCmds = this.vsamFormIdcamsCreateCmd(dataSetName, idcamsOptions); imperative_1.Logger.getAppLogger().debug("Invoking this IDCAMS command:\n" + idcamsCmds.join("\n")); const idcamsResponse = yield invoke_1.Invoke.ams(session, idcamsCmds); return { success: true, commandResponse: attribText + ZosFiles_messages_1.ZosFilesMessages.dataSetCreatedSuccessfully.message, apiResponse: idcamsResponse }; } catch (error) { const impErr = new imperative_1.ImperativeError({ msg: attribText + error.mDetails.msg, causeErrors: error.mDetails.causeErrors, additionalDetails: error.mDetails.additionalDetails }); imperative_1.Logger.getAppLogger().error(impErr.toString()); throw impErr; } }); } /** * Create a uss file or folder * @param {AbstractSession} session - z/OSMF connection info * @param {string} ussPath - USS path to create file or directory * @param {string} type - the request type "file" or "directory" * @param {string} mode - the characters to describe permissions * @returns {Promise<IZosFilesResponse>} */ static uss(session, ussPath, type, mode) { return __awaiter(this, void 0, void 0, function* () { imperative_1.ImperativeExpect.toNotBeNullOrUndefined(type, ZosFiles_messages_1.ZosFilesMessages.missingRequestType.message); imperative_1.ImperativeExpect.toNotBeEqual(type, "", ZosFiles_messages_1.ZosFilesMessages.missingRequestType.message); ussPath = path.posix.normalize(ussPath); ussPath = ussPath.charAt(0) === "/" ? ussPath.substring(1) : ussPath; ussPath = encodeURIComponent(ussPath); const parameters = `${ZosFiles_constants_1.ZosFilesConstants.RESOURCE}${ZosFiles_constants_1.ZosFilesConstants.RES_USS_FILES}/${ussPath}`; const headers = [rest_1.ZosmfHeaders.X_CSRF_ZOSMF_HEADER, { "Content-Type": "application/json" }]; let payload = { type }; if (mode) { payload = Object.assign(Object.assign({}, payload), { mode }); } const data = yield rest_1.ZosmfRestClient.postExpectString(session, parameters, headers, payload); return { success: true, commandResponse: ZosFiles_messages_1.ZosFilesMessages.ussCreatedSuccessfully.message, apiResponse: data }; }); } static zfs(session, fileSystemName, options) { return __awaiter(this, void 0, void 0, function* () { // We require the file system name imperative_1.ImperativeExpect.toNotBeNullOrUndefined(fileSystemName, ZosFiles_messages_1.ZosFilesMessages.missingFileSystemName.message); // Removes undefined properties const tempOptions = !util_1.isNullOrUndefined(options) ? JSON.parse(JSON.stringify(options)) : {}; let endpoint = ZosFiles_constants_1.ZosFilesConstants.RESOURCE + ZosFiles_constants_1.ZosFilesConstants.RES_ZFS_FILES + "/" + fileSystemName; this.zfsValidateOptions(tempOptions); tempOptions.JSONversion = 1; if (!util_1.isNullOrUndefined(tempOptions.timeout)) { endpoint += `?timeout=${tempOptions.timeout}`; delete tempOptions.timeout; } const jsonContent = JSON.stringify(tempOptions); const headers = [{ "Content-Length": jsonContent.length }]; const data = yield rest_1.ZosmfRestClient.postExpectString(session, endpoint, headers, jsonContent); return { success: true, commandResponse: ZosFiles_messages_1.ZosFilesMessages.zfsCreatedSuccessfully.message, apiResponse: data }; }); } // ____________________________________________________________________________ /** * Convert the options received from the CLI into options that we supply to IDCAMS. * @param {ICreateVsamOptions} cliOptions - The set of options from our CLI * @returns {ICreateVsamOptions} - Options to provide to IDCAMS. */ static vsamConvertToIdcamsOptions(cliOptions) { // Removes undefined properties let idcamsOptions = util_1.isNullOrUndefined(cliOptions) ? {} : JSON.parse(JSON.stringify(cliOptions)); // convert the zowe size into IDCAMS allocationUnit and primarySpace let matchArray; if (idcamsOptions.size) { idcamsOptions.size = idcamsOptions.size.toUpperCase(); matchArray = idcamsOptions.size.match(/[A-Z]+/g); if (matchArray) { // the text part of size is the allocation unit idcamsOptions.alcunit = matchArray[0]; } matchArray = idcamsOptions.size.match(/[0-9]+/g); if (matchArray) { // the numeric part of size is the primary space idcamsOptions.primary = matchArray[0]; } delete idcamsOptions.size; } // start with our default options, and override with any supplied options. idcamsOptions = Object.assign(Object.assign({}, Create_defaults_1.CreateDefaults.VSAM), idcamsOptions); // when secondary is not specified, use 10% of primary if (util_1.isNullOrUndefined(idcamsOptions.secondary)) { const tenPercent = 0.10; idcamsOptions.secondary = Math.round(idcamsOptions.primary * tenPercent); } return idcamsOptions; } // ____________________________________________________________________________ /** * Form the IDCAMS command to create a VSAM cluster * @param {string} dataSetName - the name of the dataset for the created cluster * @param options - options for the creation of the cluster * @returns {string} - The IDCAMS command to be invoked. */ static vsamFormIdcamsCreateCmd(dataSetName, options) { return [ "DEFINE CLUSTER -\n" + "(" + "NAME('" + dataSetName.toUpperCase() + "') -\n" + options.dsorg.toUpperCase() + " -\n" + options.alcunit.toUpperCase() + "(" + options.primary + " " + options.secondary + ")" + " -\n" + (options.retainTo ? "TO(" + options.retainTo + ") -\n" : "") + (options.retainFor ? "FOR(" + options.retainFor + ") -\n" : "") + (options.volumes ? "VOLUMES(" + options.volumes.toUpperCase() + ") -\n" : "") + (options.storeclass ? "STORAGECLASS(" + options.storeclass + ") -\n" : "") + (options.mgntclass ? "MANAGEMENTCLASS(" + options.mgntclass + ") -\n" : "") + (options.dataclass ? "DATACLASS(" + options.dataclass + ") -\n" : "") + ")" ]; } // ____________________________________________________________________________ /** * Validate the options for the command to create a VSAM cluster * @param options - options for the creation of the cluster */ static vsamValidateOptions(options) { imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options, ZosFiles_messages_1.ZosFilesMessages.missingFilesCreateOptions.message); /* If our caller does not supply these options, we supply default values for them, * so they should exist at this point. */ imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options.dsorg, ZosFiles_messages_1.ZosFilesMessages.missingVsamOption.message + "dsorg"); imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options.alcunit, ZosFiles_messages_1.ZosFilesMessages.missingVsamOption.message + "alcunit"); imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options.primary, ZosFiles_messages_1.ZosFilesMessages.missingVsamOption.message + "primary"); imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options.secondary, ZosFiles_messages_1.ZosFilesMessages.missingVsamOption.message + "secondary"); // validate specific options for (const option in options) { if (options.hasOwnProperty(option)) { switch (option) { case "dsorg": if (!ZosFiles_constants_1.ZosFilesConstants.VSAM_DSORG_CHOICES.includes(options.dsorg.toUpperCase())) { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidDsorgOption.message + options.dsorg }); } break; case "alcunit": if (!ZosFiles_constants_1.ZosFilesConstants.VSAM_ALCUNIT_CHOICES.includes(options.alcunit.toUpperCase())) { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidAlcunitOption.message + options.alcunit }); } break; case "primary": case "secondary": // Validate maximum allocation quantity if (options[option] > ZosFiles_constants_1.ZosFilesConstants.MAX_ALLOC_QUANTITY) { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.maximumAllocationQuantityExceeded.message + " " + strings.COMMON.FOR + " '" + option + "' " + strings.COMMON.WITH_VALUE + " = " + options[option] + "." }); } break; case "retainFor": if (options[option] < ZosFiles_constants_1.ZosFilesConstants.MIN_RETAIN_DAYS || options[option] > ZosFiles_constants_1.ZosFilesConstants.MAX_RETAIN_DAYS) { throw new imperative_1.ImperativeError({ msg: imperative_1.TextUtils.formatMessage(ZosFiles_messages_1.ZosFilesMessages.valueOutOfBounds.message, { optionName: option, value: options[option], minValue: ZosFiles_constants_1.ZosFilesConstants.MIN_RETAIN_DAYS, maxValue: ZosFiles_constants_1.ZosFilesConstants.MAX_RETAIN_DAYS }) }); } break; case "retainTo": case "volumes": case "storeclass": case "mgntclass": case "dataclass": // no validation at this time break; default: throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidFilesCreateOption.message + option }); } // end switch } } // end for } // ____________________________________________________________________________ /** * Validate the options for the command to create a z/OS file system * @param options - options for the creation of the file system */ static zfsValidateOptions(options) { imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options, ZosFiles_messages_1.ZosFilesMessages.missingFilesCreateOptions.message); /* If our caller does not supply these options, we supply default values for them, * so they should exist at this point. */ imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options.perms, ZosFiles_messages_1.ZosFilesMessages.missingZfsOption.message + "perms"); imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options.cylsPri, ZosFiles_messages_1.ZosFilesMessages.missingZfsOption.message + "cyls-pri"); imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options.cylsSec, ZosFiles_messages_1.ZosFilesMessages.missingZfsOption.message + "cyls-sec"); imperative_1.ImperativeExpect.toNotBeNullOrUndefined(options.timeout, ZosFiles_messages_1.ZosFilesMessages.missingZfsOption.message + "timeout"); // validate specific options for (const option in options) { if (options.hasOwnProperty(option)) { switch (option) { case "perms": const maxPerm = 777; if ((options.perms < 0) || (options.perms > maxPerm)) { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidPermsOption.message + options.perms }); } break; case "cylsPri": case "cylsSec": // Validate maximum allocation quantity if (options[option] > ZosFiles_constants_1.ZosFilesConstants.MAX_ALLOC_QUANTITY) { throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.maximumAllocationQuantityExceeded.message + " " + strings.COMMON.FOR + " '" + option + "' " + strings.COMMON.WITH_VALUE + " = " + options[option] + "." }); } break; case "owner": case "group": case "storeclass": case "mgntclass": case "dataclass": case "volumes": case "timeout": // no validation at this time break; default: throw new imperative_1.ImperativeError({ msg: ZosFiles_messages_1.ZosFilesMessages.invalidFilesCreateOption.message + option }); } // end switch } } // end for } } exports.Create = Create; //# sourceMappingURL=Create.js.map