Skip to content

Changes already merged to staging1.16 for 761 and 2123 #2215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelogs/fragments/2207-SYSIN-support-zos_job_output.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
minor_changes:
- zos_job_output - Adds support to query SYSIN DDs from a job with new option input.
(https://github.com/ansible-collections/ibm_zos_core/pull/2207)
16 changes: 16 additions & 0 deletions changelogs/fragments/2213-test-case-conditional-failure-2-19.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
trivial:
- test_zos_copy_func.py - modified test case `test_job_script_async`
to resolve porting issues to ansible 2.19.
(https://github.com/ansible-collections/ibm_zos_core/pull/2213).

- test_zos_job_submit_func.py - modified test case `test_job_submit_async`
to resolve porting issues to ansible 2.19.
(https://github.com/ansible-collections/ibm_zos_core/pull/2213).

- test_zos_script_func.py - modified test case `test_job_script_async`
to resolve porting issues to ansible 2.19.
(https://github.com/ansible-collections/ibm_zos_core/pull/2213).

- test_zos_unarchive_func.py - modified test case `test_zos_unarchive_async`
to resolve porting issues to ansible 2.19.
(https://github.com/ansible-collections/ibm_zos_core/pull/2213).
14 changes: 10 additions & 4 deletions plugins/module_utils/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
])


def job_output(job_id=None, owner=None, job_name=None, dd_name=None, dd_scan=True, duration=0, timeout=0, start_time=timer()):
def job_output(job_id=None, owner=None, job_name=None, dd_name=None, sysin=False, dd_scan=True, duration=0, timeout=0, start_time=timer()):
"""Get the output from a z/OS job based on various search criteria.
Keyword Parameters
Expand All @@ -71,6 +71,8 @@ def job_output(job_id=None, owner=None, job_name=None, dd_name=None, dd_scan=Tru
The job name search for (default: {None}).
dd_name : str
The data definition to retrieve (default: {None}).
sysin : bool
The input DD to retrieve SYSIN value (default: {False}).
dd_scan : bool
Whether or not to pull information from the dd's for this job {default: {True}}.
duration : int
Expand Down Expand Up @@ -112,6 +114,7 @@ def job_output(job_id=None, owner=None, job_name=None, dd_name=None, dd_scan=Tru
job_name=job_name,
dd_name=dd_name,
duration=duration,
sysin=sysin,
dd_scan=dd_scan,
timeout=timeout,
start_time=start_time
Expand All @@ -128,6 +131,7 @@ def job_output(job_id=None, owner=None, job_name=None, dd_name=None, dd_scan=Tru
owner=owner,
job_name=job_name,
dd_name=dd_name,
sysin=sysin,
dd_scan=dd_scan,
duration=duration,
timeout=timeout,
Expand Down Expand Up @@ -300,7 +304,7 @@ def _parse_steps(job_str):
return stp


def _get_job_status(job_id="*", owner="*", job_name="*", dd_name=None, dd_scan=True, duration=0, timeout=0, start_time=timer()):
def _get_job_status(job_id="*", owner="*", job_name="*", dd_name=None, sysin=False, dd_scan=True, duration=0, timeout=0, start_time=timer()):
"""Get job status.
Parameters
Expand All @@ -313,6 +317,8 @@ def _get_job_status(job_id="*", owner="*", job_name="*", dd_name=None, dd_scan=T
The job name search for (default: {None}).
dd_name : str
The data definition to retrieve (default: {None}).
sysin : bool
The input DD SYSIN (default: {False}).
dd_scan : bool
Whether or not to pull information from the dd's for this job {default: {True}}.
duration : int
Expand Down Expand Up @@ -418,7 +424,7 @@ def _get_job_status(job_id="*", owner="*", job_name="*", dd_name=None, dd_scan=T
list_of_dds = []

try:
list_of_dds = jobs.list_dds(entry.job_id)
list_of_dds = jobs.list_dds(entry.job_id, sysin=sysin)
except exceptions.DDQueryException:
is_dd_query_exception = True

Expand All @@ -437,7 +443,7 @@ def _get_job_status(job_id="*", owner="*", job_name="*", dd_name=None, dd_scan=T
try:
# Note, in the event of an exception, eg job has TYPRUN=HOLD
# list_of_dds will still be populated with valuable content
list_of_dds = jobs.list_dds(entry.job_id)
list_of_dds = jobs.list_dds(entry.job_id, sysin=sysin)
is_jesjcl = True if search_dictionaries("dd_name", "JESJCL", list_of_dds) else False
is_job_error_status = True if entry.status in JOB_ERROR_STATUSES else False
except exceptions.DDQueryException:
Expand Down
17 changes: 16 additions & 1 deletion plugins/modules/zos_job_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
like "*".
- If there is no dd_name, or if dd_name="?", output of all the dds under
the given job will be displayed.
- If SYSIN DDs are needed, C(input) should be set to C(true).
version_added: "1.0.0"
author:
- "Jack Ho (@jacklotusho)"
Expand Down Expand Up @@ -62,6 +63,12 @@
type: str
required: false
aliases: [ ddname ]
input:
description:
- Whether to include SYSIN DDs as part of the output.
type: bool
default: false
required: false
attributes:
action:
Expand Down Expand Up @@ -91,6 +98,11 @@
job_name: "*"
owner: "IBMUSER"
dd_name: "?"
- name: Query a job's output including SYSIN DDs
zos_job_output:
job_id: "JOB00548"
input: true
"""

RETURN = r"""
Expand Down Expand Up @@ -496,6 +508,7 @@ def run_module():
job_id=dict(type="str", required=False),
job_name=dict(type="str", required=False),
owner=dict(type="str", required=False),
input=dict(type="bool", required=False, default=False),
dd_name=dict(type="str", required=False, aliases=['ddname']),
)

Expand All @@ -505,6 +518,7 @@ def run_module():
job_id=dict(type="job_identifier", required=False),
job_name=dict(type="job_identifier", required=False),
owner=dict(type="str", required=False),
input=dict(type="bool", required=False, default=False),
dd_name=dict(type="str", required=False, aliases=['ddname']),
)

Expand All @@ -524,14 +538,15 @@ def run_module():
job_id = module.params.get("job_id")
job_name = module.params.get("job_name")
owner = module.params.get("owner")
sysin = module.params.get("input")
dd_name = module.params.get("dd_name")

if not job_id and not job_name and not owner:
module.fail_json(msg="Please provide a job_id or job_name or owner", stderr="", **results)

try:
results = {}
results["jobs"] = job_output(job_id=job_id, owner=owner, job_name=job_name, dd_name=dd_name)
results["jobs"] = job_output(job_id=job_id, owner=owner, job_name=job_name, dd_name=dd_name, sysin=sysin)
for job in results["jobs"]:
if "job_not_found" in job:
results["changed"] = False
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/modules/test_zos_copy_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@
async_status:
jid: "{{{{ copy_output.ansible_job_id }}}}"
register: job_result
until: job_result.finished
until: job_result.finished | bool
retries: 10
delay: 30
Expand Down
55 changes: 53 additions & 2 deletions tests/functional/modules/test_zos_job_output_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
__metaclass__ = type

from shellescape import quote
from ibm_zos_core.tests.helpers.dataset import get_tmp_ds_name


JCL_FILE_CONTENTS = """//HELLO JOB (T043JM,JM00,1,0,0,0),'HELLO WORLD - JRM',CLASS=R,
Expand All @@ -30,6 +31,19 @@
//
"""

JCL_FILE_CONTENTS_SYSIN = """//SYSINS JOB (T043JM,JM00,1,0,0,0),'SYSINS - JRM',CLASS=R,
// MSGCLASS=X,MSGLEVEL=1,NOTIFY=OMVSADM
//STEP1 EXEC PGM=BPXBATCH,PARM='SH sleep 1'
//STDOUT DD SYSOUT=*
//STDERR DD SYSOUT=*
//LISTCAT EXEC PGM=IDCAMS,REGION=4M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
LISTCAT ENTRIES('{0}') ALL
/*
//
"""

TEMP_PATH = "/tmp/jcl"

def test_zos_job_output_no_job_id(ansible_zos_module):
Expand Down Expand Up @@ -249,7 +263,7 @@ def test_zos_job_output_job_exists(ansible_zos_module):
hosts.all.file(path=TEMP_PATH, state="absent")


def test_zos_job_output_job_exists_with_filtered_ddname(ansible_zos_module):
def test_zos_job_output_job_exists_with_filtered_dd_name(ansible_zos_module):
try:
hosts = ansible_zos_module
hosts.all.file(path=TEMP_PATH, state="directory")
Expand All @@ -261,7 +275,7 @@ def test_zos_job_output_job_exists_with_filtered_ddname(ansible_zos_module):
)
hosts.all.file(path=TEMP_PATH, state="absent")
dd_name = "JESMSGLG"
results = hosts.all.zos_job_output(job_name="HELLO", ddname=dd_name)
results = hosts.all.zos_job_output(job_name="HELLO", dd_name=dd_name)
for result in results.contacted.values():
assert result.get("changed") is True
assert result.get("msg", False) is False
Expand Down Expand Up @@ -310,6 +324,43 @@ def test_zos_job_output_job_exists_with_filtered_ddname(ansible_zos_module):
hosts.all.file(path=TEMP_PATH, state="absent")


def test_zos_job_output_job_exists_with_sysin(ansible_zos_module):
try:
hosts = ansible_zos_module
hosts.all.file(path=TEMP_PATH, state="directory")
data_set_name = get_tmp_ds_name()
result = hosts.all.zos_data_set(
name=data_set_name,
type="seq",
state="present"
)
print(f"job_submit_result: {result.contacted.values()}")
hosts.all.shell(
cmd=f"echo {quote(JCL_FILE_CONTENTS_SYSIN.format(data_set_name))} > {TEMP_PATH}/SYSIN"
)
result = hosts.all.zos_job_submit(
src=f"{TEMP_PATH}/SYSIN", remote_src=True, volume=None
)
print(f"job_submit_result: {result.contacted.values()}")
hosts.all.file(path=TEMP_PATH, state="absent")
sysin = True
results = hosts.all.zos_job_output(job_name="SYSINS", input=sysin)
for result in results.contacted.values():
print(f"job_output_result: {result}")
assert result.get("changed") is True
for job in result.get("jobs"):
assert len(job.get("dds")) >= 1
sysin_found = False
for ddname_entry in job.get("dds"):
if ddname_entry.get("dd_name") == "SYSIN":
sysin_found = True
break
assert sysin_found
finally:
hosts.all.zos_data_set(name=data_set_name, state="absent")
hosts.all.file(path=TEMP_PATH, state="absent")


def test_zos_job_submit_job_id_and_owner_included(ansible_zos_module):
hosts = ansible_zos_module
results = hosts.all.zos_job_output(job_id="STC00*", owner="MASTER")
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/modules/test_zos_job_submit_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@
async_status:
jid: "{{{{ job_task.ansible_job_id }}}}"
register: job_result
until: job_result.finished
until: job_result.finished | bool
retries: 20
delay: 5
"""
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/modules/test_zos_script_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
async_status:
jid: "{{{{ job_task.ansible_job_id }}}}"
register: job_result
until: job_result.finished
until: job_result.finished | bool
retries: 20
delay: 5
"""
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/modules/test_zos_unarchive_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
async_status:
jid: "{{{{ job_task.ansible_job_id }}}}"
register: job_result
until: job_result.finished
until: job_result.finished | bool
retries: 20
delay: 5
"""
Expand Down