@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
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 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