CI/CD for zOS with Zowe and circleCI

+
Photo by Martin Robles on Unsplash https://unsplash.com/@martinrobles
Photo by Martin Robles on Unsplash https://unsplash.com/@martinrobles

liquid ice unfreezing the mainframe.

For most developers COBOL and mainframe is considered a mammoth frozen since the ice ages.

After I read some articles about COBOL, The programming language that doesn’t want to die and the issues due to COVID-19 in the unemployment systems in the US, I wondered if it was possible to set up CI/CD without proprietary mainframe tooling.

Much to my surprise I found the open mainframe project. They build tools and even a Cobol integration with Visual Studio Code.
So I decided to give it a try and see how far I would come.
My idea was:

  • write some Cobol code in VSCode using the plugins
  • get it running on a mainframe
  • script the deployment
  • create a pipeline in CircleCI (CircleCI was popping up so much on my timelines I had to try it out)

So lets see if we can unfreeze the mammoth. All the code is in a GitHub repo.

credits

While doing the research I stumbled upon two great sources.

I really recommend reading these post if you want to dive in deeper.

phase 1 get the tools, write some code

  • mainframe access

First I needed access to a mainframe. Since I didn’t have one lingering around, I registered at IBM to get access to a mainframe for training purpose. After registering I got a mail with a mainframe ID and instructions on how to get a password. I only had to run a slack application on the Open Mainframe Project Slack workspace. Also in the mail was the information I needed for my Zowe profile, like URL and ports.

  • install prerequisites

For using the extensions and CLI you need nodeJS v8 or higher and a java SDK 8 or higher.

  • zowe CLI and extensions

Zowe, in their own words, is an open source project created to host technologies that benefit the Z platform from all members of the Z community. Zowe can be seen as a set of API’s and command line instructions to connect to mainframes.

I used the ZOWE CLI

In VSCode I used

  • Zowe explorer for exploring the mainframe files
  • IBM Z Open Editor which gave me syntax checking and highlighting and autocomplete and most important some vertical lines to divide the different areas. Although this helped me very much, Creating COBOL code remains cumbersome.

Another extension is Code4z which even gives you a debugger.
The extension can be installed from the marketplace.

  • configure

Both ZoweCLI and Zowe explorer need a profile, but fortunately these profiles are shared. I set up my profile in the Zowe explorer and then used it in ZoweCLI.

First I configured the security in VSCode by, Go to the security setting (CTRL+, -> Extensions -> Zowe Explorer Settings -> Zowe Security:CredentialKey) and give it the value Zowe-Plugin. Note that not setting this will store the usernames and passwords as plain text.

Then I created a profile in the Zowe explorer by clicking on the + next to the DATA SETS node and filling the URL, port, user and password in the wizzard. When using the IBM labs mainframe make sure to accept selfsigned certificates.

When using the IBM lab mainframe you can search for datasets by clicking the search icon next to the profile name. If everything is correct, you will see the datasets needed to do the labs in the Cobol course.

After that, I imported the profile in the CLI by running zowe scs update. (PS you need to install the pluging). You can check the profile with zowe profiles list zosmf --sc.

For more information about the Zowe profiles see the documentation.

  • code

So I wrote these three legendary pieces of code:

  • a cobol programm

1
2
3
4
5
       IDENTIFICATION DIVISION.
       PROGRAM-ID. SAYIT.
       PROCEDURE DIVISION.
           DISPLAY "The melting point of water depends on the pressure"
           STOP RUN.
  • a job to compile the code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//UNFREJOB JOB 101,DUDEBOWSKI 
//***************************************************/
//COBRUN  EXEC IGYWCL
//COBOL.SYSIN  DD DSN=&SYSUID..CBL(UNFREEZE),DISP=SHR
//***************************************************/
// IF RC = 0 THEN
//***************************************************/
//RUN     EXEC PGM=UNFREEZE
//STEPLIB   DD DSN=&SYSUID..LOAD,DISP=SHR
//SYSOUT    DD SYSOUT=*,OUTLIM=15000
//***************************************************/
// ELSE
// ENDIF
  • a job to execute it once compiles

1
2
3
4
5
6
7
8
9
//EXECUNFR  JOB 101,DUDEBOWSKI,CLASS=A, 
//             MSGCLASS=X,MSGLEVEL=0,NOTIFY=&SYSUID
//*
//JOBLIB   DD DSN=&SYSUID..LOAD,DISP=SHR
//*
//RUN      EXEC PGM=UNFREEZE
//SYSIN    DD DUMMY
//SYSPRINT DD SYSOUT=*
//

It isn’t much, but it’s enough to do my PoC. For a more elaborate (and more valuable) example please look at Jessielaine blogs. She created some scripts to automatically generate the Compiler, JCL and Cobol programs If you want to learn more Cobol you can do the open mainframe Cobol course or got to the tutorials for COBOL or JCL.

phase 2 run it

Now I have the tools and some code lets try to run it on the mainframe.

Copy files to mainframe

In my code repository I mimmicked the structure on the mainframe. The Cobol program is in the folder CBl and the job in the folder JCL. With these commands

1
2
zowe zos-files upload dir-to-pds "./JCL" "<MainframeID>.JCL"  
zowe zos-files upload dir-to-pds "./CBL" "<MainframeID>.CBL"

I synchronized the files between my repository and the mainframe. NOTE: the mainframe id should be replaced with your ID. For the IBM labs mainframe this is in the email you received.

Compile and run

The job compunfr compiles the Cobol code and runs it, The other execunfr that can run the code once compiled. Jobs can be executed by the ZoweCLI by running:

1
2
zowe jobs submit ds "<MainframeID>.jcl(compunfr)" -d . --rfj     
zowe jobs  submit ds "<MainframeID>z82101.jcl(execunfr)" -d . --rfj     

The --rfj parameter let the command return a JSON with the results of the job. This will look like this

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "success": true,
  "exitCode": 0,
  "message": "Submitted JCL contained in \"dataset\": \"z99991.jcl(compunfr)\"",
  "stdout": "jobid:  JOB04807 retcode: CC 0000 jobname: UNFREJOB status:OUTPUT Successfully downloaded output to ././JOB04807",
  "stderr": "",
  "data": {
    "owner": "z99991",
    "phase": 20,
    "subsystem": "JES2",
    "phase-name": "Job is on the hard copy queue",
    "job-correlator": "J0004807SVSCJES2D8400532.......:",
    "type": "JOB",
    "url": "https://192.11.11.111:10443/zosmf/restjobs/jobs/J0004807SVSCJES2D8400532.......%3A",
    "jobid": "JOB04807",
    "class": "A",
    "files-url": "https://192.11.11.111:10443/zosmf/restjobs/jobs/J0004807SVSCJES2D8400532.......%3A/files",
    "jobname": "UNFREJOB",
    "status": "OUTPUT",
    "retcode": "CC 0000"
  }

Return code CC 000 means everything was fine, when the job has errors you will see a different code. Inspect the other files.
The parameter -d Downloads the result to the root of your VSCode project so the output in will be in /JOB<jobid>/RUN/SYSOUT.TXT with this content The melting point of water depends on the pressure.

The Zowe explore also shows the results in the JOBS node. NOTE that these files are cleaned on the IBM lab mainframe.

phase 3 script it

Ideally we want to run all the commands sequential. At first, I put it in a bash script and run it. But this isn’t very flexible and when I was adjusting it for CI it got a bit ugly. I was thinking about using Grunt or Gulp as task-runners, but this added a lot of complexity for such little functionality. In the course and the blogs NPM was used and then it became stupid simple.

Since I already have NPM, I just create a NPM package npm -init and added these scripts The scripts in the NPM package looks like

1
2
3
4
5
6
7
8
  "scripts": {
    "compile": "zowe jobs submit ds \"z82101.jcl(compunfr)\" -d . --rfj ",
    "uploadCBL": "zowe zos-files upload dir-to-pds \"./CBL\" \"$npm_config_mainframeID.CBL\"",
    "uploadJCL": "zowe zos-files upload dir-to-pds \"./JCL\" \"$npm_config_mainframeID.JCL\"",
    "build": "npm run uploadCBL --mainframeID=$npm_config_mainframeID 
               && npm run uploadJCL --mainframeID=$npm_config_mainframeID 
               && npm run compile --mainframeID=$npm_config_mainframeID"
  },

So run everything in one go with

1
 npm run build --mainframeID=<MainframeID>

phase 4 ci in circleci

LinkedIn, Twitter, Stack Overflow, everywhere I looked I saw CircleCI being promoted, so I wanted to give it a go. The onboarding was amazingly simple just signed up with my GitHub credentials.

The pipeline should do the following steps:

  • use a node build container
  • checkout GIT
  • install ZoweCLI
  • install package
  • create Zowe profile
  • run the scripts

So I created this config in ./.circleci/config.yml.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
version: 2
jobs:
  build:
    docker:
      - image: circleci/node:10.0.0
    steps:
      - checkout
      - run:
          name: "Install zoweCLI"
          command: sudo npm i -g @zowe/cli@latest --@zowe:registry=https://registry.npmjs.org --no-package-lock --force --ignore-scripts
      - run:
          name: "Install Package"
          command: npm install .
      - run:
          name: "Create Zowe Profiles"
          command: zowe profiles create zosmf-profile cibuild --host $host --port $port --user $user --password $password --reject-unauthorized false
      - run:
          name: "Run Script "
          command: npm run build --mainframeID=$user

In circleCI Add Projects, I selected Set Up Project for my repo and choose add maually and started a build. Unfortunately this will fail, because I also had to set the variables (like URL, user password for Zowe) in Project SettingsEnvironment Variables. After this got to the pipeline and click rerun. (Or push some changes to git).

So now after every push the build runs and you can see the build results in the pipelines and the current status of the project is: CircleCI. Sometines I did get a permission denied though from CircleCI don’t know why.

conclusion

Using Visualstudio code as your IDE, connecting to a mainframe and scripting builds was really easy. I got it up and running in about one day. Potentially there is a huge benefit in unfreezing the mammoth and use it in a modern development environment.
This can be great for existing code, but I don’t know if creating new applications in COBOL will add value, but time will tell.

Besides using zowe for scripting and automation, you can also use Zowe as an NPM package see this post