As part of modernizing development processes to support DevOps and Continuous Delivery, it may be necessary to submit (and receive a response from) a JCL job from a build process running in z/OS UNIX System Services. In this example we consider a scenario where a CICS cloud application must be built and deployed to an existing CICS Platform.
I have a number of CICS projects that were initially created through the CICS Explorer. These projects were imported into RDz and Rational Team Concert is providing the source code control for them.

Projects

We use RTC along with Ant and the CICS TS build toolkit to build these projects and store them on z/FS. You can download the CICS Build Toolkit here. Now we need to create an APPLDEF resource on a CICSplex and install it in order to deploy our application. This is where DFHDPLOY comes in. DFHDPLOY is new utility, included with CICS TS 5.3, that allows a user to submit a batch job that will automatically create an APPLDEF and install it. The picture below shows the DFHDPLOY script that is used to deploy our application.

DFHDPLOYJCL

The issue we have is that the scripting is running on USS while the job is running on JES and the output is available through SDSF. Therefore we need a way to submit this job, and pick up its output, from USS.

To do this we wrote a REXX script that would be invoked from an Ant script. The REXX script is responsible for submitting the DFHDPLOY job and getting its output. In order to successfully run, the REXX script must be defined as executable. Further information on using REXX with USS can be found here. You can download the script used in this example from here.

Say ‘Starting DFHDPLOY script….’

x=OUTTRAP(“SUB.”)
address tso “SUBMIT ‘CTS.GENAPP.DEPLOY.JCL(GENAPP)'”
x=OUTTRAP(“OFF”)

Here we use the REXX ADDRESS TSO support to issue a TSO SUBMIT command to start running our DFHDPLOY job. We use the OUTTRAP function to store the variables returned by the command into a stem variable called SUB. The next thing we need to do is to wait for the job to finish. This is done by the following code:

myjob = word(SUB.1,2)

do until STATUS = “ON OUTPUT QUEUE”

  x=OUTTRAP(“OUT.”)
  address tso “STATUS” myjob
  x=OUTTRAP(“OFF”)

  parse var OUT.1 ‘JOB’ curjob STATUS

end

The first thing we do in this snippet is to get the Job name and Job ID from the SUB stem variable. The name will appear in the myjob variable in the following format JOBNAME(JOBID). Next we enter a loop that will detect if the job has been put on the SDSF output queue. We do this by first setting up a stem variable called OUT and then calling the ADDRESS TSO STATUS command with the contents of myjob. We then parse the output we have been given and put the current status into the STATUS variable. If the status is ON OUTPUT QUEUE we will leave the loop, otherwise we loop around again. Now that we know that the job has finished we need to get its completion code to determine if the deployment has been successful. To do this we perform the following:

parse var curjob jobname ‘(‘ jobid ‘)’

jobfound = “NO”

call sleep 5

call isfcalls “ON”
isfprefix = jobname
isfowner = “*”
address SDSF “ISFEXEC ST”

do jobcount = 1 to JNAME.0
   if JOBID.jobcount = jobid then do
      jobfound = “YES”
      leave jobcount
   end
end

if jobfound = “YES” then do
  say “Found:” JOBID.jobcount
end
else do
  say “Not found”
  exit 12
end

First we parse the job (which is in the following format JOBNAME(JOBID)) into two separate jobname and jobid variables. Next we initialize a variable called jobfound for use later in the code. Next we sleep for 5 seconds. We found we need to do this sleep as there can be a delay between the status reporting the job is on the output queue, and the output actually being there.
Next we set the code up to allow it to perform REXX SDSF commands. We then set the prefix we are going to use to our jobname. We then we call the SDSF ST command from REXX. This command returns us a list of all the jobs that have the same JOBNAME as us, so we now need to find the job that we submitted. To do this we loop through all the jobs that have been given back to us. The number of jobs returned to us is specified in the JNAME stem variable, this varable is created by the ISFEXEC so you do not need to specify an OUTTRAP to declare it.

In the loop we compare the JOBID stem variable with our Job ID. Again you do not need to specify an OUTTRAP for the JOBID stem variable, it is created for you. If we find a matching Job ID we flag that we have found the job and leave the loop. The last step in this snippet is to check we found the job. If we have we continue processing, if we haven’t we exit the REXX script with a return code of 12. The final code snippet shows how the completion code from the job is returned to the script:

parse var RETCODE.jobcount CCname Unformcode

call isfcalls “OFF”

if Unformcode = “0000” then retcode = 0
else retcode = STRIP(Unformcode,’L’,’0′)

exit retcode

Here we parse a stem variable called RETCODE, again this does not need to be specified with an OUTTRAP. The important part of the return string is held in Unformcode, this is numeric completion code for the job. We are then finished with SDSF processing so we set ISFCALLS to OFF. Finally we need to strip the two leading numbers from the completion code to allow them to be used as a REXX return code. We then leave the script, passing back the completion code of the job we have just submitted.

While in this example we’ve used the REXX TSO and SDSF commands to submit (and receive a response from) a DFHDPLOY job, this technique could also be used to submit any JCL from USS.

Join The Discussion

Your email address will not be published. Required fields are marked *