Skip to content

Commit e0c5276

Browse files
authored
[zos_job_submit] Fix TYPRUN=COPY, TYPRUN=HOLD and TYPRUN=JCLHOLD handling (#2229)
* Fix TYPRUN handling * Add changelog fragment * Remove commented code * Update module documentation
1 parent 72afe25 commit e0c5276

File tree

4 files changed

+83
-50
lines changed

4 files changed

+83
-50
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
minor_changes:
2+
- zos_job_submit - Adds support for jobs with TYPRUN=JCLHOLD and TYPRUN=HOLD.
3+
(https://github.com/ansible-collections/ibm_zos_core/pull/2229).
4+
trivial:
5+
- zos_job_submit - Fixes a regression on ZOAU v1.3.6.0 where a job submitted
6+
with TYPRUN=COPY would return an error.
7+
(https://github.com/ansible-collections/ibm_zos_core/pull/2229).

docs/source/modules/zos_job_submit.rst

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ jobs
383383
"asid": 0,
384384
"class": "K",
385385
"content_type": "JOB",
386+
"cpu_time": 1,
386387
"creation_date": "2023-05-03",
387388
"creation_time": "12:13:00",
388389
"ddnames": [
@@ -579,10 +580,12 @@ jobs
579580
"stepname": "DLORD6"
580581
}
581582
],
583+
"execution_node": "STL1",
582584
"execution_time": "00:00:10",
583585
"job_class": "K",
584586
"job_id": "JOB00361",
585587
"job_name": "DBDGEN00",
588+
"origin_node": "STL1",
586589
"owner": "OMVSADM",
587590
"priority": 1,
588591
"program_name": "IEBGENER",
@@ -763,7 +766,9 @@ jobs
763766

764767
Job status `TYPRUN=SCAN` indicates that the job had the TYPRUN parameter with SCAN option.
765768

766-
Job status `NOEXEC` indicates that the job had the TYPRUN parameter with COPY option.
769+
Job status `TYPRUN=COPY` indicates that the job had the TYPRUN parameter with COPY option.
770+
771+
Job status `HOLD` indicates that the job had the TYPRUN parameter with either the HOLD or JCLHOLD options.
767772

768773
Jobs where status can not be determined will result in None (NULL).
769774

@@ -858,4 +863,34 @@ jobs
858863
| **type**: str
859864
| **sample**: IEBGENER
860865
866+
system
867+
The job entry system that MVS uses to do work.
868+
869+
| **type**: str
870+
| **sample**: STL1
871+
872+
subsystem
873+
The job entry subsystem that MVS uses to do work.
874+
875+
| **type**: str
876+
| **sample**: STL1
877+
878+
cpu_time
879+
Sum of the CPU time used by each job step, in microseconds.
880+
881+
| **type**: int
882+
| **sample**: 5
883+
884+
execution_node
885+
Execution node that picked the job and executed it.
886+
887+
| **type**: str
888+
| **sample**: STL1
889+
890+
origin_node
891+
Origin node that submitted the job.
892+
893+
| **type**: str
894+
| **sample**: STL1
895+
861896

plugins/modules/zos_job_submit.py

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,8 @@
272272
- Job status `SYS` indicates a system failure.
273273
- Job status `?` indicates status can not be determined.
274274
- Job status `TYPRUN=SCAN` indicates that the job had the TYPRUN parameter with SCAN option.
275-
- Job status `NOEXEC` indicates that the job had the TYPRUN parameter with COPY option.
275+
- Job status `TYPRUN=COPY` indicates that the job had the TYPRUN parameter with COPY option.
276+
- Job status `HOLD` indicates that the job had the TYPRUN parameter with either the HOLD or JCLHOLD options.
276277
- Jobs where status can not be determined will result in None (NULL).
277278
type: str
278279
sample: AC
@@ -1116,8 +1117,9 @@ def run_module():
11161117
result["execution_time"] = job_output_txt[0].get("execution_time")
11171118

11181119
result["duration"] = duration
1120+
job_msg = job_output_txt[0].get("ret_code", {}).get("msg")
11191121

1120-
if duration >= wait_time_s:
1122+
if duration >= wait_time_s and job_msg != "HOLD":
11211123
result["failed"] = True
11221124
result["changed"] = False
11231125
_msg = ("The JCL submitted with job id {0} but appears to be a long "
@@ -1161,19 +1163,13 @@ def run_module():
11611163
job_ret_code.update({"msg_txt": _msg})
11621164
raise Exception(_msg)
11631165

1164-
if job_ret_code_code is not None and job_ret_code_msg == 'NOEXEC':
1165-
job_dd_names = job_output_txt[0].get("ddnames")
1166-
jes_jcl_dd = search_dictionaries("ddname", "JESJCL", job_dd_names)
1167-
# These are the conditions for a job run with TYPRUN=COPY.
1168-
if not jes_jcl_dd:
1169-
job_ret_code.update({"msg": "TYPRUN=COPY"})
1170-
_msg = ("The job was run with TYPRUN=COPY. "
1171-
"This way, the steps are not executed, but the JCL is validated and stored "
1172-
"in the JES spool. "
1173-
"Please review the job log for further details.")
1174-
job_ret_code.update({"msg_txt": _msg})
1175-
1176-
if job_ret_code_code is None or job_ret_code.get("msg") == 'NOEXEC':
1166+
if job_ret_code_msg == 'HOLD':
1167+
_msg = ("The job was run with TYPRUN=HOLD or TYPRUN=JCLHOLD "
1168+
"to request special job processing. This will result in no completion, "
1169+
"no return code, no job steps and changed will be set to false.")
1170+
job_ret_code.update({"msg_txt": _msg})
1171+
is_changed = False
1172+
elif job_ret_code_code is None and job_ret_code.get("msg") == 'NOEXEC':
11771173
# If there is no job_ret_code_code (Job return code) it may NOT be an error,
11781174
# some jobs will never return have an RC, eg Started tasks(which are not supported),
11791175
# so further analyze the
@@ -1183,21 +1179,21 @@ def run_module():
11831179
jes_jcl_dd = search_dictionaries("ddname", "JESJCL", job_dd_names)
11841180

11851181
# Its possible jobs don't have a JESJCL which are active and this would
1186-
# cause an index out of range error.
1182+
# mean the job had TYPRUN=COPY.
11871183
if not jes_jcl_dd:
1188-
_msg_detail = " for status {0}.".format(job_ret_code_msg) if job_ret_code_msg else "."
1189-
_msg = ("The job return code was not available in the job log, "
1190-
"please review the job log{0}".format(_msg_detail))
1184+
job_ret_code.update({"msg": "TYPRUN=COPY"})
1185+
_msg = ("The job was run with TYPRUN=COPY. "
1186+
"This way, the steps are not executed, but the JCL is validated and stored "
1187+
"in the JES spool. "
1188+
"Please review the job log for further details.")
11911189
job_ret_code.update({"msg_txt": _msg})
1192-
raise Exception(_msg)
1193-
1194-
jes_jcl_dd_content = jes_jcl_dd[0].get("content")
1195-
jes_jcl_dd_content_str = " ".join(jes_jcl_dd_content)
1196-
# The regex can be r"({0})\s*=\s*(COPY|HOLD|JCLHOLD|SCAN)" once zoau support is in.
1197-
special_processing_keyword = re.search(r"({0})\s*=\s*(SCAN)"
1198-
.format("|".join(JOB_SPECIAL_PROCESSING)), jes_jcl_dd_content_str)
1190+
else:
1191+
jes_jcl_dd_content = jes_jcl_dd[0].get("content")
1192+
jes_jcl_dd_content_str = " ".join(jes_jcl_dd_content)
1193+
# The regex can be r"({0})\s*=\s*(COPY|HOLD|JCLHOLD|SCAN)" once zoau support is in.
1194+
special_processing_keyword = re.search(r"({0})\s*=\s*(SCAN)"
1195+
.format("|".join(JOB_SPECIAL_PROCESSING)), jes_jcl_dd_content_str)
11991196

1200-
if job_ret_code_msg == 'NOEXEC':
12011197
job_ret_code.update({"msg": special_processing_keyword[0]})
12021198
job_ret_code.update({"code": None})
12031199
job_ret_code.update({"msg_code": None})
@@ -1206,19 +1202,17 @@ def run_module():
12061202
"return code or job steps and changed will be false."
12071203
.format(job_submitted_id, special_processing_keyword[0])})
12081204
is_changed = False
1209-
else:
1210-
# The job_ret_code_code is None at this point, but the job_ret_code_msg_code could be populated
1211-
# so check both and provide a proper response.
1205+
elif job_ret_code_code is None:
1206+
# The job_ret_code_code is None at this point, but the job_ret_code_msg_code could be populated
1207+
# so check both and provide a proper response.
12121208

1213-
if job_ret_code_msg_code is None:
1214-
_msg_detail = " for status {0}.".format(job_ret_code_msg) if job_ret_code_msg else "."
1215-
_msg = ("The job return code was not available in the job log, "
1216-
"please review the job log{0}".format(_msg_detail))
1217-
job_ret_code.update({"msg_txt": _msg})
1218-
raise Exception(_msg)
1209+
if job_ret_code_msg_code is None:
1210+
_msg_detail = " for status {0}.".format(job_ret_code_msg) if job_ret_code_msg else "."
1211+
_msg = ("The job return code was not available in the job log, "
1212+
"please review the job log{0}".format(_msg_detail))
1213+
job_ret_code.update({"msg_txt": _msg})
1214+
raise Exception(_msg)
12191215

1220-
# raise Exception("The job return code was not available in the job log, "
1221-
# "please review the job log and error {0}.".format(job_ret_code_msg))
12221216
elif job_ret_code_code != 0 and max_rc is None:
12231217
_msg = ("The job return code {0} was non-zero in the "
12241218
"job output, this job has failed.".format(str(job_ret_code_code)))

tests/functional/modules/test_zos_job_submit_func.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,8 +1014,8 @@ def test_job_submit_local_jcl_typrun_copy(ansible_zos_module):
10141014
"to": "IBM-1047"
10151015
},)
10161016
for result in results.contacted.values():
1017-
# With ZOAU 1.3.3 changes now code and return msg_code are 0 and 0000 respectively.
1018-
# assert result.get("changed") is False
1017+
# With ZOAU 1.3.6 changes now code and return msg_code are both None, now
1018+
# being consistent with the rest of the possible TYPRUN cases.
10191019
# When running a job with TYPRUN=COPY, a copy of the JCL will be kept in the JES spool, so
10201020
# effectively, the system is changed even though the job didn't run.
10211021
assert result.get("changed") is True
@@ -1024,12 +1024,9 @@ def test_job_submit_local_jcl_typrun_copy(ansible_zos_module):
10241024
r'The job was run with TYPRUN=COPY.',
10251025
repr(result.get("jobs")[0].get("ret_code").get("msg_txt"))
10261026
)
1027-
assert result.get("jobs")[0].get("ret_code").get("code") == 0
1027+
assert result.get("jobs")[0].get("ret_code").get("code") is None
10281028
assert result.get("jobs")[0].get("ret_code").get("msg") == 'TYPRUN=COPY'
1029-
assert result.get("jobs")[0].get("ret_code").get("msg_code") == '0000'
1030-
# assert result.get("jobs")[0].get("ret_code").get("code") is None
1031-
# assert result.get("jobs")[0].get("ret_code").get("msg") is None
1032-
# assert result.get("jobs")[0].get("ret_code").get("msg_code") is None
1029+
assert result.get("jobs")[0].get("ret_code").get("msg_code") is None
10331030

10341031

10351032
def test_job_submit_local_jcl_typrun_hold(ansible_zos_module):
@@ -1048,11 +1045,11 @@ def test_job_submit_local_jcl_typrun_hold(ansible_zos_module):
10481045
assert result.get("changed") is False
10491046
assert result.get("jobs")[0].get("job_id") is not None
10501047
assert re.search(
1051-
r'long running job',
1048+
r'The job was run with TYPRUN=HOLD or TYPRUN=JCLHOLD',
10521049
repr(result.get("jobs")[0].get("ret_code").get("msg_txt"))
10531050
)
10541051
assert result.get("jobs")[0].get("ret_code").get("code") is None
1055-
assert result.get("jobs")[0].get("ret_code").get("msg") == "AC"
1052+
assert result.get("jobs")[0].get("ret_code").get("msg") == "HOLD"
10561053
assert result.get("jobs")[0].get("ret_code").get("msg_code") is None
10571054

10581055

@@ -1072,11 +1069,11 @@ def test_job_submit_local_jcl_typrun_jclhold(ansible_zos_module):
10721069
assert result.get("changed") is False
10731070
assert result.get("jobs")[0].get("job_id") is not None
10741071
assert re.search(
1075-
r'long running job',
1072+
r'The job was run with TYPRUN=HOLD or TYPRUN=JCLHOLD',
10761073
repr(result.get("jobs")[0].get("ret_code").get("msg_txt"))
10771074
)
10781075
assert result.get("jobs")[0].get("ret_code").get("code") is None
1079-
assert result.get("jobs")[0].get("ret_code").get("msg") == "AC"
1076+
assert result.get("jobs")[0].get("ret_code").get("msg") == "HOLD"
10801077
assert result.get("jobs")[0].get("ret_code").get("msg_code") is None
10811078

10821079

0 commit comments

Comments
 (0)