README
z/OS Node Accessor
A Node module to help Node.JS developers interacting with z/OS easily, taking advantage of z/OS FTP service. It's recommended to be deployed on z/OS, to avoid transferring user account/password in clear-text over network. IBM SDK for Node.js - z/OS is available at https://developer.ibm.com/mainframe/products/ibm-sdk-for-node-js-z-os/.
For a Zowe CLI plugin based on this functionality, see https://github.com/zowe/zowe-cli-ftp-plugin
Installation & Test
npm install zos-node-accessor # Put latest version in your package.json
npm test # You'll need the dev dependencies to launch tests
Features
- List MVS dataset or USS files
- Download/Upload MVS dataset or USS files
- Submit JCL and query its status to track its completion
- Access SYSOUT dataset
- Some simple JCL, like initiating HRECALL, allocating dataset, and so on.
Usage
This accessor leverages z/OS FTP server to interact with z/OS, it requires JESINTERFACELevel
set to 2
Connection
Before connecting to a z/OS server, you need to initialize an instance using the constructor new zosAccessor()
, then call the connect(config)
method, where:
Parameter
- config - object - Configuration passed to the underlying ftp library, valid properties:
- user - string - Username for authentication on z/OS. Default: 'anonymous'
- password - string - Password for authentication on z/OS. Default: 'anonymous@'
- host - string - The hostname or IP address of the z/OS server to connect to. Default: 'localhost'
- port - integer - The port of the z/OS FTP server. Default: 21
- secure - mixed - Set to true for both control and data connection encryption, 'control' for control connection encryption only, or 'implicit' for implicitly encrypted control connection (this mode is deprecated in modern times, but usually uses port 990) Default: false
- secureOptions - object - Additional options to be passed to
tls.connect()
. Default: (none) - connTimeout - integer - How long (in milliseconds) to wait for the control connection to be established. Default: 10000
- pasvTimeout - integer - How long (in milliseconds) to wait for a PASV data connection to be established. Default: 10000
- keepalive - integer - How often (in milliseconds) to send a 'dummy' (NOOP) command to keep the connection alive. Default: 10000
Return
A promise that resolves itself (the connection to z/OS), and rejects on any error.
Example
var Client = require('zos-node-accessor');
var c = new Client();
// connect to localhost:21 as hansome using password
c.connect({user: 'myname', password:'mypassword'})
.then(function(connection) {
// here connection equals to outer c
})
.catch(function(err) {
// handle error
});
MVS dataset or USS files
Allocate
allocateDataset(datasetName, allocateParams)
- Allocate sequential or partition (with the DCB attribut "DSORG=PO") dataset.
Parameter
- datasetName - string - Dataset name to allocate.
- allocateParams - object | string - A string of space separated DCB attributes or an object of DCB attribute key-value pairs, eg. "LRECL=80 RECFM=VB" or {"LRECL": 80, "RECFM": "VB"}. The tested attributes includes BLKsize/BLOCKSize, Directory, DSORG, LRecl, PDSTYPE, PRImary, RECfm, SECondary, and TRacks.
Option Key | Description |
---|---|
SPACETYPE | allocation units |
BLKSIZE | blocksize |
DATACLASS | data class |
DIRECTORY | directory blocks |
DSNTYPE | data set name type |
EATTR | extended attributes |
LRECL | logical record length |
MGMTCLASS | management class |
DCBDSN | model DCB values |
PDSTYPE | PDS type |
PRIMARY | primary space |
RECFM | record format |
RETPD | retention period |
SECONDARY | secondary space |
STORCLASS | storage class |
UNITNAME | unit |
VCOUNT | volume count |
UCOUNT | unit count |
VOLUME | volume serial number |
Return
A promise that resolves on success, rejects on error.
Example
connection.allocateDataset('ABC.DEF', {'LRECL': 80, 'RECFM': 'FB', 'BLKSIZE': 320})
.then(function() {
console.log('Success');
})
.catch(function(err) {
// handle error
});
connection.allocateDataset('ABC.PDS', {'LRECL': 80, 'RECFM': 'FB', 'BLKSIZE': 320, 'DSORG': 'PO', 'DIRECTORY': 20})
.then(function() {
console.log('Success');
})
.catch(function(err) {
// handle error
});
Make directory
makeDirectory(directoryName)
- Make USS directory with the given directory name.
Parameter
- datasetName - string - Dataset name to allocate.
Return
A promise that resolves on success, rejects on error.
Example
connection.makeDirectory('/u/user/my_directory'})
.then(function() {
console.log('Success');
})
.catch(function(err) {
// handle error
});
List
listDataset(dsnOrDir)
- List MVS datasets or USS files
Parameter
- dsnOrDir - string - Specify a full qualified dataset name, supporting wildcards (* or ?), PDS members (HLQ.JCL(*)) and USS directory.
Return
A promise that resolves a list of
dataset entries. Each entry has the property of
Volume
,Unit
,Referred
,Ext
,Used
,Recfm
,Lrecl
,BlkSz
,Dsorg
, andDsname
.USS file entries. Each entry has the property of
name
,size
,owner
,group
, andpermissions
.
Example
connection.listDataset('HQL.*.JCL')
.then(function(list) {
for(var i=0; i<list.length; ++i) {
var entry = list[i];
console.log('name:', entry['Dsname'], 'dsorg', entry['Dsorg']);
}
})
.catch(function(err) {
// handle error
});
connection.listDataset('/u/user1/')
.then(function(list) {
for(var i=0; i<list.length; ++i) {
var entry = list[i];
console.log(entry.name, entry.owner, entry.group, entry.size);
}
})
.catch(function(err) {
// handle error
});
Upload MVS dataset or USS file
uploadDataset(input, destDataset, dataType, allocateParams)
- Upload a local file to MVS dataset or USS file.
Parameter
- input - any - A ReadableStream, a Buffer, or a path to a local file that needs uploading.
- destDataset - string - Dataset name to used to store the uploaded file, if it starts with
/
this file will be uploaded to USS. - dataType - string (default: ascii) - Transfer data type, it should be 'ascii' or 'binary', when transfering 'ascii' files, the end-of-line sequence of input should always be
\r\n
, otherwise the transfered file will get truncated. - allocateParams - object | string - A string of space separated DCB attributes or an object of DCB attribute key-value pairs, eg. "LRECL=80 RECFM=VB" or {"LRECL": 80, "RECFM": "VB"}. The tested attributes: BLKsize/BLOCKSize, LRecl, RECfm, PRImary, SECondary, TRacks.
Return
A promise that resolves on success, rejects on error.
Example
var fs = require('fs');
var input = fs.readFileSync('/etc/hosts', 'utf8').replace(/\r?\n/g, '\r\n');
connection.uploadDataset(input, 'hosts')
.then(function() {
console.log('Success');
})
.catch(function(err) {
// handle error
});
var fs = require('fs');
var input = fs.readFileSync('/etc/hosts', 'utf8').replace(/\r?\n/g, '\r\n');
connection.uploadDataset(input, 'HLQ.HOSTS', "LRECL=80 RECFM=FB")
.then(function() {
console.log('Success');
})
.catch(function(err) {
// handle error
});
Read MVS dataset or USS file
getDataset(dsn, dataType, stream)
- Get the contents of the MVS dataset or USS file.
Parameter
- dsn - string - Specify a full qualified dataset name, or USS file name. It CAN NOT contain any wildcard (*).
- dataType - string (default: 'ascii') - Transfer data type, accepts three options
binary
,ascii
,ascii_strip_eol
,ascii_rdw
orbinary_rdw
. When downloading an ascii dataset, dataType should be eitherascii
orascii_strip_eol
so that the FTP server convertsEBCDIC
characters toASCII
,ascii_strip_eol
tells FTP server not the append a CLRF to the end of each record. Theascii_rdw
orbinary_rdw
can be used to download variable-length dataset like V, VB, VBS, etc. The 4-byte RDW (Record Descriptor Word) is inserted at the beginning of each record. - stream - boolean (default: false) -
true
if you want to obtain a ReadableStream of the data set content, orfalse
to read a full dataset into memory (in Buffer).
Return
A promise that resolves content of the dataset or file in either Buffer
or ReadableStream
.
Example
connection.getDataset('HQL.AA.JCL', 'ascii')
.then(function(jclBuffer) {
console.log('JCL is:');
console.log(jclBuffer.toString());
})
.catch(function(err) {
// handle error
});
Delete
delete(dsn)
- Delete a dataset or USS file.
Parameter
- dsn - string - Specify a full qualified dataset name to delete, it CAN NOT contain a wildcard (*).
Return
A promise that resolves on success, rejects on error.
Example
connection.deleteDataset('HQL.AA.JCL')
.then(function() {
console.log('Deleted');
})
.catch(function(err) {
// handle error
});
Rename
rename(oldDataset, newDataset)
- Renames oldDataset to newDataset.
Parameter
- oldDataset - string - Old dataset name.
- newDataset - string - New dataset name to rename to.
Return
A promise that resolves on success, rejects on error.
Example
connection.rename('HQL.AA.JCL', 'HQL.BB.JCL')
.then(function() {
console.log('Renamed');
})
.catch(function(err) {
// handle error
});
JES jobs
List jobs
listJobs(jobNameOrOption)
- List JES jobs matching the given jobName or query option. The following parameters are accepted:
Parameter
- jobName - specify a JES job name, it can contain a wildcard (*)
Parameter
- option - object - Option which contains:
- jobName - string - specify a JES job name, which is optional and can contain a wildcard (*)
- jobId - string - specify a JES job ID, which is optional
- owner - string - specify a JES job owner, which is optional and can contain a wildcard (*)
- status - string - specify a JES job status, eg. ALL, OUTPUT, which is optional
Return
A promise that resolves an array of jobs, each item in the array is a string separated by space, for JESINTERFACELEVEL=2, those fields are JOBNAME, JOBID, OWNER, STATUS, CLASS
Example
connection.listJobs({jobName: 'TSU*', owner: 'MY-NAME'})
.then(function(jobList) {
})
.catch(function(err) {
// handle error
});
Submit JCL
submitJCL(JCLText, cfg)
- Submit raw JCL text to JES server, or submitting built-in helper JCLs
Parameter
JCLText - string - The raw JCL string to be submitted, or the name of built-in JCLs if
cfg
is specified.cfg - object - configurations to the JCL, if this parameter is specified, then JCLText should be a name of the built-in JCLs, and the
cfg
should contain parameters for that JCL. Following is a list of built-in JCLs and their supported configurations:Allocate dataset
- name:
ALLOC
- supported configurations:
{ DSN: 'abc' }
- name:
Copy dataset
- name:
COPY
- supported configurations:
{ from: 'abc', to: 'edf' }
- name:
Return
A promise that resolves the submitted job id.
Example
- Submit raw JCL
var fs = require('fs');
fs.readFile('./unpaxz.jcl', function(err, jclContent) {
connection.submitJCL(jclContent)
.then(function(jobId) {
console.log('Job id is', jobId);
})
.catch(function(err) {
// handle error
});
});
- Submit a built-in JCL
connection.submitJCL('HRECALLW', {INPUT: 'AA.BB'})
.then(function(jobId) {
console.log('Job id is', jobId);
})
.catch(function(err) {
// handle error
});
Query job
queryJob(jobNameOrOption, jobId)
- Query job status identified by job name and job id. The following parameters are accepted. (Deprecated, use getJobStatus
for more details.)
Parameter
- jobName - string - Name of the job.
- jobId - string - Id of the job.
Parameter
- option - object - Option which contains:
- jobName - string - specify a JES job name, which is optional and can contain a wildcard (*)
- jobId - string - specify a JES job ID, which is required
- owner - string - specify a JES job owner, which is optional and can contain a wildcard (*)
Return
A promise that resolves status of the job, it is one of the following values:
- RC_SUCCESS - Job succeeds
- RC_ACTIVE - Job running
- RC_FAIL - Job fails
- RC_WAITING - Job waiting
- RC_NOT_FOUND - Cannot find job specified by the jobName and jobId
Example
connection.queryJob(jobName, jobId)
.then(function (status) {
switch(status) {
case connection.RC_SUCCESS:
console.log('Job succeeded');
break;
case connection.RC_FAIL:
console.log('Job failed');
break;
case connection.RC_ACTIVE:
console.log('Job running');
break;
case connection.RC_NOT_FOUND:
console.log('Job not found');
break;
default:
console.log('Unknown status');
}
});
Get job status
getJobStatus(jobIdOrOption)
- Get job status specified by jobId or query option. The following parameters are accepted:
Parameter
- jobId - string - Specify JES job ID
Parameter
- option - object - Option which contains:
- jobId - string - specify a JES job ID, which is required
- owner - string - specify a JES job owner, which is optional and can contain a wildcard (*)
Return
A promise that resolves job status
{
jobname: "HRECALLW",
jobid: "JOB06385",
owner: "USER",
status: "OUTPUT",
class: "A",
rc: 0,
retcode: 'RC 0000',
spoolFiles: [
{
id: 2,
stepname: "JES2",
procstep: "N/A",
c: "H",
ddname: "JESJCL",
byteCount: 315
}
]}
Example
connection.getJobStatus(jobId)
.then(function(jobStatus) {
console.log('Job status is:');
console.log(jobStatus);
})
.catch(function(err) {
// handle error
});
Get JES spool files
getJobLog(jobNameOrOption, jobId)
- Get jes spool files identified by jobName and jobId. The following parameters are accepted:
Parameter
- jobName - string - Name of the job. Default: '*'
- jobId - string - Id of the job.
- spoolFileIndex - string | integer - Index of the spool file to get. Number of spool files can be found using
getJobStatus
, specifying 'x' will return all spool files joined with the!! END OF JES SPOOL FILE !!
. Default: 'x'
Parameter
- option - object - Option which contains:
- jobName: Optional job name, default to '*'
- jobId - string - Specify a JES job ID, which is required
- fileId - string - Spool file index (1, 2, 3...) or 'x' returning all spool files joined with the
!! END OF JES SPOOL FILE !!
- owner - string - Specify a JES job owner, which is optional and can contain a wildcard (*)
Return
A promise that resolves spool files populated by the job
Example
connection.getJobLog(jobName, jobId, 'x')
.then(function(jobLog) {
console.log('Job id is:');
console.log(jobLog);
})
.catch(function(err) {
// handle error
});
Delete job
deleteJob(jobIdOrOption)
- Purge/delete job by job id. The following parameters are accepted:
Parameter
- jobId - string - JES job ID
Parameter
- option - object - Option which contains:
- jobId - string - specify a JES job ID, which is required
- owner - string - specify a JES job owner, which is optional and can contain a wildcard (*)
Return
A promise that resolves on success, rejects on error.
Example
connection.deleteJob('JOB25186')
.then(function() {
console.log('Deleted');
})
.catch(function(err) {
// handle error
});
Others
Retrieve Server Status
stat(option)
- Retrieve status information from a remote server. The following parameters are accepted:
Parameter
- option - string - Optional option name like UMASK
Return
A promise that resolves status of the specified option on success, rejects on error. If option
is not specified,
it returns all status information.
Example
connection.stat('UMASK')
.then(function(status) {
console.log(status);
})
.catch(function(err) {
// handle error
});
Submit SITE commands
site(siteCommands)
- Send site-specific information to a server. The following parameters are accepted:
Parameter
- siteCommands - string - Site commands separated with space
Return
A promise that resolves text from server on success, rejects on error.
Example
connection.site('UMASK 007')
.then(function(text) {
console.log(text);
})
.catch(function(err) {
// handle error
});
Module Long Term Support Policy
This module adopts the Module Long Term Support (LTS) policy, with the following End Of Life (EOL) dates:
Module Version | Release Date | Minimum EOL | EOL With | Status |
---|---|---|---|---|
1.x.x | Oct 2018 | Dec 2019 | Current |