zos-node-accessor

Accessing z/OS dataset and interacting with JES in NodeJS way

Usage no npm install needed!

<script type="module">
  import zosNodeAccessor from 'https://cdn.skypack.dev/zos-node-accessor';
</script>

README

z/OS Node Accessor

Build Status Module LTS Adopted' IBM Support

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, and Dsname.

  • USS file entries. Each entry has the property of name, size, owner, group, and permissions.

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 or binary_rdw. When downloading an ascii dataset, dataType should be either ascii or ascii_strip_eol so that the FTP server converts EBCDIC characters to ASCII, ascii_strip_eol tells FTP server not the append a CLRF to the end of each record. The ascii_rdw or binary_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, or false 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'
      }
      
  • Copy dataset

    • name: COPY
    • supported configurations:
    {
      from: 'abc',
      to: 'edf'
    }
    
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

License

Eclipse Public License (EPL)