Operationalizing Microservices in z/OS

Steven Perva
Theropod
Published in
5 min readMay 9, 2022
A man stands in front of a whiteboard depicting a flowchart and process flow diagram.
Fitting your microservice into the larger ecosystem doesn’t have to be complicated.

🖥🖥🖥

So, you’ve written some really cool code in Node.js or Python for your z/OS system. That’s great! You’re officially ahead of the curve with modern languages on IBM Z! It’s true, with Z Open Automation Utilities (ZOAU) it is extremely easy to create powerful programs in modern languages on z/OS.

Suppose you want to provide your new application as a service on the system, hook it into existing automation, and give others the ability to start your services the same way they start other services in z/OS. Let’s turn that code into a started task! As with all adventures, we need to get equipped first. You’ll want to bring:

  • Some code you wrote (we can give you that)
  • Your favorite Security Admin (if that’s not you)
  • Your systems programmer hat

Let’s start with the code. If you have your own, great. If not, here’s an example service in Python. This code requires the Flask package, a microweb framework in Python:

from flask import Flaskapp = Flask(__name__)
my_port = 61443
@app.route("/")
def index():
return "Hello z/OS!"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=my_port)

Dump this code somewhere in z/OS Unix, customize my_port (try not to use a port under 1024) and you’ve got yourself a microservice. Not too exciting, but I’ll leave the excitement to future you. If you were to run this, assuming you have Python with the Flask package installed, you’d be able to point your browser (or curl if you’re some kind of deranged cyborg) at your z/OS host on the port specified and see, you guessed it:

Hello z/OS!

Boom! You’ve got yourself 1/3rd of the tooling needed to complete this guide. Onwards and upwards!

Creating a Service ID

With all great services come a service ID. A service ID allows your service to be launched outside of your IDs privileges (probably by some other service ID or someone who isn’t you.) I’m going to assume you’re using RACF because that’s what I know and that’s what I use. If you’re not using RACF, chances are you don’t need my advice to make a service ID anyway. So avert your eyes, ye of olde knowledge, this next bit is for the rest of us:

Let’s start by understanding what our service ID should be called. I personally prefer to have one ID per service with a name that matches the service. Since this service is just a simple hello, let’s call our ID HELOSVC ! Seeing as when you personally invoke the code everything works, the real challenge of creating a new service is understanding what minimum permissions your new ID needs to perform the task of your service. Thankfully for us, HELOSVC isn’t a very prolific piece of code and really only needs to be able to run Python, open a socket, and access the file that holds the source code. Now I’m not going to pretend I know how your system is configured, but I’ll assume you stored your Python code somewhere accessible by more than just you. I stored mine at /usr/local/my_api/service.py . Now let’s make ourselves a RACF user to run HELOSVC . Run this command however you’re most comfortable (or ask your security guru to help you out):

ADDUSER HELOSVC DFLTGRP(SYS1) OMVS(AUTOUID)

You’ll probably get some sideways glances for using SYS1 , so if it doesn’t fit well in your test environment feel free to massage it to a more palatable group. Your user should also have an OMVS segment with a UID. AUTOUID is letting z/OS take the wheel and give us one it thinks is swanky. However you fulfill these requirements is irrelevant, all that matters is you come out the other side of this task with a user created!

Creating a Started Task Entry

It’s common for a started task (STC) to also have its own started task entry in the system, alongside its own user ID. We’re going to build one now. If you’ll recall, I like it when my STCs name matches its user ID, so this is the RACF command for creating the HELOSVC STC entry. As with the last command, bust this out the most productive way you can:

RDEFINE STARTED HELOSVC.* STDATA(USER(HELOSVC) GROUP(SYS1))

Now, make sure if your environment strong-armed you into a group that wasn’t SYS1 you update the command accordingly. What this does is create a started task entry named HELOSVCand associate it with the user HELOSVC we just created. Before you celebrate, let’s make sure we refresh the RACLISTed profiles in the STARTED class:

SETROPTS RACLIST(STARTED) REFRESH

Now let’s celebrate. Barring some fancy configurations, we should be set to go! We’re on a roll now, 2 of 3 quests complete!

Every respectable z/OS journey has a touch of systems programming and this epic is no outlier. We’ve got the service, we’ve got the security sorted, now let’s tie a gaudy JCL bow around this beautiful little package and send it out into the world! That starts with creating a PROC.

Ask any sysprog how they feel about writing JCL and they’ll tell you how nobody writes it. I honor that tradition by providing the JCL for the PROC that will start our microservice:

//HELOSVC   PROC                                                      
//*
//************************************************
//* Hello z/OS Microservice
//************************************************
//*
//LAUNCH EXEC PGM=BPXBATCH,REGION=0M,TIME=NOLIMIT,
// PARM='SH python /usr/local/my_api/service.py'
//STDOUT DD SYSOUT=*
//STDERR DD SYSOUT=*

Save this masterpiece in your PROCLIB concatenation (SDSF will tell you what this is in option PROC if you aren’t sure) under the name HELOSVC . Now that we’ve got all the pieces in place, it’s time to light the fires! Hop over to a console somewhere (I use SDSF for this) and fire off a start command for your new service:

START HELOSVC

If you’ve been following along, and I didn’t tell any lies, you should see your service running with the STDOUT and STDERRDD cards reporting the same output as you saw if you launched it under your ID:

* Serving Flask app 'service' (lazy loading)                                      
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:61443 (Press CTRL+C to quit)

Now point your browser back at your system and bask in the glow of your hello message being served up from your newly minted started task. You’ve done it!

This article serves as an illustration of a concept. Practical deployments of this technology should be challenged to adopt best security and integrity practices. Use of this code and the commands outlined in this article should be done at the reader’s discretion.

Additional Resources:

--

--

Steven Perva
Theropod

Mainframe Innovation Specialist. Amadeus of z/OS. Enterprise Troublemaker. IBM Champion for IBM Z 22-23