Submitting jobs on z/OS can be a tedious process, especially for someone who is unfamiliar with mainframes and z/OS in particular. The available documentation is vast, which can make it tough to get quickly up and running with the job submission process. This is where Ansible comes in. Ansible is an extremely user-friendly infrastructure automation tool developed by Red Hat, that allows automating software provisioning, configuration management and application deployment. I am going to assume you are somewhat familiar with Ansible. If you are new to Ansible and would like to learn the basics of how it works, here is a great place to start.
IBM introduced Red Hat Ansible Certified Content for IBM Z which provides a collection of core Ansible modules that can be used to perform many z/OS related tasks such as submitting jobs, querying and retrieving job output, creating data sets and many more. Each one of these tasks can be done with just a few lines of YAML. For instance, let's say you would like to submit a job specified by HELLO.jcl
file located on USS (Unix System Services). Using the zos_job_submit
module, this can be done quite easily:
- name: Submit a JCL located on USS
zos_job_submit:
src: /path/to/HELLO.jcl
location: USS
wait: true
The wait
parameter tells Ansible whether to wait for the job to finish. The default wait duration is 60 seconds and can be changed by specifying the wait_time_s
parameter. To check the status of the job you just submitted, you can use the zos_job_query
module as follows:
- name: Check the status of HELLO job
zos_job_query:
job_name: HELLO
Which returns a JSON response containing the submitted job's return code, name, ID and other relevant information.
TASK [Response for job query] ***************************************************************************
ok: [<remote_host>] => {
"msg": {
"changed": false,
"failed": false,
"jobs": [
{
"job_id": "JOB00085",
"job_name": "HELLO",
"owner": "OMVSADM",
"ret_code": {
"code": 0,
"msg": "CC 0000"
}
}
],
"message": ""
}
}
You can also check the status of a job using Job ID and owner information. Finally, to retrieve the output of the job, zos_job_output
can be used:
- name: Retrieve output of HELLO job
zos_job_output:
job_name: HELLO
ddname: "JESMSGLG"
You can retrieve the output using either job name, job ID, or a specific DD name such JESMSGLG or SYSPRINT. Note that the output of this task below has been abbreviated for the sake of clarity.
TASK [Response for job output ***************************************************************************
ok: [<remote_host>] => {
"msg": {
"changed": false,
"failed": false,
"jobs": [
{
"class": "R",
"content_type": "JOB",
"ddnames": [
{
"byte_count": "769",
"content": [
"1 J E S 2 J O B L O G -- S Y S T E M S T L 1 -- N O D E S T L 1 ",
"0 ",
" 20.39.40 JOB00085 ---- MONDAY, 08 JUN 2020 ----",
" 20.39.40 JOB00085 IRR010I USERID OMVSADM IS ASSIGNED TO THIS JOB.",
" 20.39.42 JOB00085 $HASP375 JES2 ESTIMATED LINES EXCEEDED",
" 20.39.42 JOB00085 ICH70001I OMVSADM LAST ACCESS AT 20:39:32 ON MONDAY, JUNE 8, 2020",
" 20.39.42 JOB00085 $HASP375 HELLO ESTIMATED LINES EXCEEDED",
" 20.39.42 JOB00085 $HASP373 HELLO STARTED - INIT 3 - CLASS R - SYS STL1",
" 20.39.42 JOB00085 SMF000I HELLO STEP0001 IEBGENER 0000",
" 20.39.42 JOB00085 $HASP395 HELLO ENDED - RC=0000",
"0------ JES2 JOB STATISTICS ------",
"- 08 JUN 2020 JOB EXECUTION DATE",
"- 10 CARDS READ",
"- 53 SYSOUT PRINT RECORDS",
"- 0 SYSOUT PUNCH RECORDS",
"- 6 SYSOUT SPOOL KBYTES",
"- 0.00 MINUTES EXECUTION TIME"
],
"ddname": "JESMSGLG",
"id": "2",
"procstep": "",
"record_count": "17",
"stepname": "JES2"
},
...
...
{
"byte_count": "251",
"content": [
"1DATA SET UTILITY - GENERATE PAGE 0001 ",
"-IEB352I WARNING: ONE OR MORE OF THE OUTPUT DCB PARMS COPIED FROM INPUT ",
" ",
" PROCESSING ENDED AT EOD "
],
"ddname": "SYSPRINT",
"id": "102",
"procstep": "",
"record_count": "4",
"stepname": "STEP0001"
},
{
"byte_count": "49",
"content": [
" HELLO, WORLD "
],
"ddname": "SYSUT2",
"id": "103",
"procstep": "",
"record_count": "1",
"stepname": "STEP0001"
}
],
"job_id": "JOB00085",
"job_name": "HELLO",
"owner": "OMVSADM",
"ret_code": {
"code": 0,
"msg": "CC 0000",
"msg_code": "0000",
"msg_txt": ""
},
"subsystem": "STL1"
}
]
}
}
And that is all there is to it! With less than 10 lines of YAML, you are able to submit a job, query its status and retrieve its output.
Now, what if the JCL is a sequential data set or a partitioned data set member? Using the zos_job_submit
module, the procedure is essentially the same. Simply change the location
parameter from USS
to DATA_SET
:
- name: Submit job from a sequential data set
zos_job_submit:
src: SOME.DATA.SET.JCL
location: DATA_SET
wait: true
The zos_job_submit
module also allows you to submit a JCL file stored on the control node by changing the location
parameter to LOCAL
. To submit a local JCL file, it must first be transferred to the remote z/OS system and, if the local file is an ASCII encoded file, it must be converted to EBCDIC. This module makes this process incredibly simple by using the encoding
parameter and specifying which encoding the local file should be converted from and to.
- name: Submit job from local JCL file
zos_job_submit:
src: /path/to/local/JCL/file
location: LOCAL
encoding:
from: ISO8859-1
to: IBM-1047
An interesting, and highly useful, feature of the zos_job_submit
module is its ability to submit jobs from data sets that are uncataloged. To do so, simply specify the volume in which the data set is allocated:
- name: Submit job from uncataloged data set
zos_job_submit:
src: SOME.UNCAT.DATA.SET
location: DATA_SET
volume: P2SS01
Pretty neat!
If you'd like to see the complete playbook and other sample playbooks, check out the Ansible z/OS Collection Sample Playbooks repository.
For more information about the modules discussed above, refer to the documentation site.
Links