How to Call Low-Level z/OS Services from Node.js
{Core}
In a previous blog, we’ve seen how you can call low-level services (written in Metal C /HLASM) from Java. Here, we’ll do something similar but from Node.js / JavaScript.
Background / Prerequisites
Before getting started, you’ll have to go through the steps to install Node.js and build a native “Hello World” Node.js application for z/OS. Petr’s blog covers this perfectly.
Disclaimer
The approach below is admittedly a little obscure (using both the njsc++
and xlc
compilers). Hopefully, this blog will be updated in the future, showing a cleaner method of calling HLASM from JavaScript.
N-API Hello World
The end of Petr’s blog cover’s an N-API example.
N-API is a way to call native (C/C++) code from Node.js / JavaScript. To get started, you’ll need several initial source files:
- binding.gyp
- hello.cc
- hello.js
- package.json
Following Petr’s blog, after you have these files, you should be able to run:
npm install && node hello.js
Troubleshooting Tips
Here are a few miscellaneous items that might help if you run into problems:
#1 Use Zowe CLI
You can use the Open Mainframe Project’s Zowe CLI to create and mount your own file system if you run out of space.
Create:
zowe files create zfs IBMUSER.PUBLIC.NATIVE.NODE.ZFS --volumes tsu063
Mount:
zowe files mount fs IBMUSER.PUBLIC.NATIVE.NODE.ZFS /a/ibmuser/native/node --mode rdwr
#2 Use Zowe Explorer
Use Zowe Explorer (a VS Code extension) to edit USS files directly (instead of using SSH):
#3 Update npm Cache Location
If you’re frequently installing npm packages, you may run out of cache space in your default home location. You can adjust this in your home’s .npmrc
file. For example, add this line to adjust the cache to another location /a/ibmuser/native/node
:
cache=/a/ibmuser/native/node/.npm
#4 Update .gyp Location
Similar to above, if you run out of space when running node-gyp
(more about this tool later), adjust the .gyp
folder location used in node-gyp
commands via setting an environmental variable:
export npm_config_devdir=/a/ibmuser/native/node/.gyp
Source Files
Keeping with the Java to Metal C / HLASM example referenced above, we’ll add some code to call WTO from Node.js.
All source files are added into a work directory on USS .../native/node/hello-wto
.
We barrow the key source files from the sample REST API project:
makefile
wto.h
wtoexec.c
wtoexec.h
We won’t go into the details of how this code works here. Instead, we’ll build it AS-IS into object code and then link it into our N-API executable.
We also tailor the N-API source files for our needs:
wto.js
Our JavaScript code will call a native function wto
which accepts a string and arbitrary number as parameters (see wto(...)
):
package.json
Our package will describe our main file as being wto.js
:
binding.gyp
Our main C++ source file will be wto.cc
:
wto.cc
Our N-API code will extract the passed parameters and invoke WTOEXE(...)
.
Generate Your Project — GYP
We use node.gyp
in this project to build part of our native (C++ ) source code.
GYP is a Meta-Build system: a build system that generates other build systems.
node-gyp
is a command line too that bundles GYP
and helps build native addons for Node.js.
We’ll gloss over most of the details of GYP
for the purpose of this project. A few key points:
node-gyp
is a command we’ll run to build native applicationsbindings.gyp
in the project is read by thenode-gyp
commandnode-gyp
outputsmakefile
s among other things- the generated
makefile
will invokenjsc++
to compile native C++ code
Building
Here are the high level steps to build and call HLASM code from JavaScript:
Step 0:
npm install
will download dependencies, specifically bindings
into a node_modules
folder.
Step 1:
make wtoexec.o
will build our metal C / HLASM code into an object file, wtoexec.o
using the xlc
compiler.
njsc++
is used for node-gyp
, but it doesn’t appear to support the metal
option which is needed to build this piece (which is why we use xlc
).
There are two makefile
s in this project. Here, we run the makefile
at the project root. The Makefile
under the /build
directory isn’t run yet, but is called when running node-gyp build
in Step #4.
Step 2:
node-gyp configure
will create a build
directory in your project, including a Makefile
.
Step 3:
Edit the /build/Makefile
to include the wtoexec.o
object created from xlc
😦. This is a bit messy but is meant as a Minimum Viable Product (MVP) example for the time-being:
Step 4:
node-gyp build
this will build wto.cc
and link in wtoexec.o
into a final artifact. If you mistakenly run node-gyp rebuild
, a node-gyp configure
operation runs behind the scenes and will overlay your build/Makefile
.
Step 5:
node wto.js
this will run the JavaScript code and display a 0
if everything is successful.
Scripts
You can write some scripts to make this process a bit smoother. You can see the basis of scripts to automate uploading, build, and running code without directly logging into the system:
Conclusion
Although there is plenty of refinement to make this project clearer, you can see how it is possible to invoke a Metal C / HLASM service from Node.js.
Please comment here or update the repo with a PR if you have ideas for improving this process.
Acknowledgements
Thanks Petr Plavjaník & Vit Tomica for helping put together all of these details!
See Petr’s newest blog for additional background information on building native addons.
If you enjoyed this blog checkout more Zowe blogs here. Or, ask a question and join the conversation on the Open Mainframe Project Slack Channel #Zowe-dev, #Zowe-user or #Zowe-onboarding. If this is your first time using the OMP slack channel register here.