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/.
npm install zos-node-accessor # Put latest version in your package.json
npm test # You'll need the dev dependencies to launch tests
- 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.
This accessor leverages z/OS FTP server to interact with z/OS, it requires JESINTERFACELevel
set to 2
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:
- 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
A promise that resolves itself (the connection to z/OS), and rejects on any error.
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
});
allocateDataset(datasetName, allocateParams)
- Allocate dataset.
- 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"}.
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 |
A promise that resolves on success, rejects on error.
connection.allocateDataset('ABC.DEF', {'LRECL': 80, 'RECFM': 'FB', 'BLKSIZE': 320})
.then(function() {
console.log('Success');
})
.catch(function(err) {
// handle error
});
listDataset(dsnOrDir)
- List MVS datasets or USS files
- dsnOrDir - string - Specify a full qualified dataset name, supporting wildcards (* or ?), PDS members (HLQ.JCL(*)) and USS directory.
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
.
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
});
uploadDataset(input, destDataset, dataType, allocateParams)
- Upload a local file to MVS dataset or USS file.
- 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"}.
A promise that resolves on success, rejects on error.
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
});
getDataset(dsn, dataType, stream)
- Get the contents of the MVS dataset or USS file.
- 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
. 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. - 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).
A promise that resolves content of the dataset or file in either Buffer
or ReadableStream
.
connection.getDataset('HQL.AA.JCL', 'ascii')
.then(function(jclBuffer) {
console.log('JCL is:');
console.log(jclBuffer.toString());
})
.catch(function(err) {
// handle error
});
delete(dsn)
- Delete a dataset or USS file.
- dsn - string - Specify a full qualified dataset name to delete, it CAN NOT contain a wildcard (*).
A promise that resolves on success, rejects on error.
connection.deleteDataset('HQL.AA.JCL')
.then(function() {
console.log('Deleted');
})
.catch(function(err) {
// handle error
});
rename(oldDataset, newDataset)
- Renames oldDataset to newDataset.
- oldDataset - string - Old dataset name.
- newDataset - string - New dataset name to rename to.
A promise that resolves on success, rejects on error.
connection.rename('HQL.AA.JCL', 'HQL.BB.JCL')
.then(function() {
console.log('Renamed');
})
.catch(function(err) {
// handle error
});
listJobs(jobNameOrOption)
- List JES jobs matching the given jobName or query option. The following parameters are accepted:
- jobName - specify a JES job name, it can contain a wildcard (*)
- 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
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
connection.listJobs({jobName: 'TSU*', owner: 'MY-NAME'})
.then(function(jobList) {
})
.catch(function(err) {
// handle error
});
submitJCL(JCLText, cfg)
- Submit raw JCL text to JES server, or submitting built-in helper JCLs
-
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:-
- name:
ALLOC
- supported configurations:
{ DSN: 'abc' }
- name:
-
- name:
COPY
- supported configurations:
{ from: 'abc', to: 'edf' }
- name:
-
A promise that resolves the submitted job id.
- 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
});
queryJob(jobNameOrOption, jobId)
- Query job status identified by job name and job id. The following parameters are accepted. (Deprecated, use getJobStatus
for more details.)
- jobName - string - Name of the job.
- jobId - string - Id of the job.
- 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 (*)
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
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');
}
});
getJobStatus(jobIdOrOption)
- Get job status specified by jobId or query option. The following parameters are accepted:
- jobId - string - Specify JES job ID
- 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 (*)
A promise that resolves job status
{
jobname: "HRECALLW",
jobid: "JOB06385",
owner: "USER",
status: "OUTPUT",
class: "A",
rc: 0,
spoolFiles: [
{
id: 2,
stepname: "JES2",
procstep: "N/A",
c: "H",
ddname: "JESJCL",
byteCount: 315
}
]}
connection.getJobStatus(jobId)
.then(function(jobStatus) {
console.log('Job status is:');
console.log(jobStatus);
})
.catch(function(err) {
// handle error
});
getJobLog(jobNameOrOption, jobId)
- Get jes spool files identified by jobName and jobId. The following parameters are accepted:
- 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'
- 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 (*)
A promise that resolves spool files populated by the job
connection.getJobLog(jobName, jobId, 'x')
.then(function(jobLog) {
console.log('Job id is:');
console.log(jobLog);
})
.catch(function(err) {
// handle error
});
deleteJob(jobIdOrOption)
- Purge/delete job by job id. The following parameters are accepted:
- jobId - string - JES job ID
- 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 (*)
A promise that resolves on success, rejects on error.
connection.deleteJob('JOB25186')
.then(function() {
console.log('Deleted');
})
.catch(function(err) {
// handle error
});
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 |