Skip to content

Commit e80e5b0

Browse files
[Enhancement][2071][zos_mvs_raw]Programs_fails_when_need_access_to_the_first_and_second_columns (#2086)
* Fix line problem * Add prepend spaces option * Resolve read a file * Add test cases to validate the work of columns reserved * Add fragment * Fix lint * Add new space * Fix typo * Update plugins/modules/zos_mvs_raw.py Co-authored-by: Fernando Flores <[email protected]> * Update plugins/modules/zos_mvs_raw.py Co-authored-by: Fernando Flores <[email protected]> * Update plugins/modules/zos_mvs_raw.py Co-authored-by: Fernando Flores <[email protected]> * Update plugins/modules/zos_mvs_raw.py Co-authored-by: Fernando Flores <[email protected]> * Update plugins/modules/zos_mvs_raw.py Co-authored-by: Fernando Flores <[email protected]> * Fix space * Add documentation --------- Co-authored-by: Fernando Flores <[email protected]>
1 parent 7796efc commit e80e5b0

File tree

3 files changed

+112
-15
lines changed

3 files changed

+112
-15
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
minor_changes:
2+
- zos_mvs_raw - Before this addition, you could not put anything in columns 1 or 2, were reserved for JCL processing.
3+
Change now allows add reserved_cols option and validate that the module get access to modify dd_content option
4+
base on the value, if not retain the previous behavior or work.
5+
(https://github.com/ansible-collections/ibm_zos_core/pull/2086)

plugins/modules/zos_mvs_raw.py

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,13 @@
583583
string, list of strings and when using a YAML block indicator.
584584
required: true
585585
type: raw
586+
reserved_cols:
587+
description:
588+
- Determines how many columns at the beginning of the content are reserved with
589+
empty spaces.
590+
type: int
591+
required: false
592+
default: 2
586593
return_content:
587594
description:
588595
- Determines how content should be returned to the user.
@@ -1195,6 +1202,13 @@
11951202
string, list of strings and when using a YAML block indicator.
11961203
required: true
11971204
type: raw
1205+
reserved_cols:
1206+
description:
1207+
- Determines how many columns at the beginning of the content are reserved with
1208+
empty spaces.
1209+
type: int
1210+
required: false
1211+
default: 2
11981212
return_content:
11991213
description:
12001214
- Determines how content should be returned to the user.
@@ -1607,6 +1621,28 @@
16071621
VOLUMES(222222) -
16081622
UNIQUE)
16091623
1624+
- name: Simple FTP connection using frist and second columns.
1625+
zos_mvs_raw:
1626+
program_name: AMAPDUPL
1627+
auth: true
1628+
dds:
1629+
- dd_output:
1630+
dd_name: sysprint
1631+
return_content:
1632+
type: text
1633+
- dd_data_set:
1634+
dd_name: SYSUT1
1635+
data_set_name: myhlq.ds1.output
1636+
disposition: shr
1637+
- dd_input:
1638+
dd_name: sysin
1639+
reserved_cols: 0
1640+
content: |
1641+
USERID=anonymous
1642+
PASSWORD=anonymous
1643+
TARGET_SYS=testcase.boulder.ibm.com
1644+
TARGET_DSN=wessamp.bigfile
1645+
16101646
- name: List data sets matching pattern in catalog,
16111647
save output to a new generation of gdgs.
16121648
zos_mvs_raw:
@@ -1785,6 +1821,7 @@ def run_module():
17851821

17861822
dd_input_base = dict(
17871823
content=dict(type="raw", required=True),
1824+
reserved_cols=dict(type="int", required=False, default=2),
17881825
return_content=dict(
17891826
type="dict",
17901827
options=dict(
@@ -2045,7 +2082,8 @@ def parse_and_validate_args(params):
20452082
)
20462083

20472084
dd_input_base = dict(
2048-
content=dict(type=dd_content, required=True),
2085+
content=dict(type=dd_content, required=True, dependencies=["reserved_cols"]),
2086+
reserved_cols=dict(type="int", required=False, default=2),
20492087
return_content=dict(
20502088
type="dict",
20512089
options=dict(
@@ -2301,15 +2339,16 @@ def dd_content(contents, dependencies):
23012339
return None
23022340
if contents is not None:
23032341
# Empty string can be passed for content but not modify to ensure proper entry
2342+
spaces = dependencies.get("reserved_cols")
23042343
if len(contents) > 0:
2305-
contents = modify_contents(contents)
2344+
contents = modify_contents(contents, spaces)
23062345
return contents
23072346
if isinstance(contents, list):
23082347
return "\n".join(contents)
23092348
return contents
23102349

23112350

2312-
def modify_contents(contents):
2351+
def modify_contents(contents, spaces):
23132352
"""Return the content of dd_input to a valid form for a JCL program.
23142353
23152354
Parameters
@@ -2324,18 +2363,20 @@ def modify_contents(contents):
23242363
"""
23252364
if not isinstance(contents, list):
23262365
contents = list(contents.split("\n"))
2327-
contents = prepend_spaces(contents)
2366+
contents = prepend_spaces(contents, spaces)
23282367
contents = "\n".join(contents)
23292368
return contents
23302369

23312370

2332-
def prepend_spaces(lines):
2371+
def prepend_spaces(lines, spaces=2):
23332372
"""Return the array with two spaces at the beggining.
23342373
23352374
Parameters
23362375
----------
23372376
lines : list
23382377
The list with a line of a program.
2378+
spaces : int
2379+
The number of columns to add as left padding to the content.
23392380
23402381
Raises
23412382
-------
@@ -2351,17 +2392,15 @@ def prepend_spaces(lines):
23512392
for index, line in enumerate(lines):
23522393
if len(line) > 0:
23532394
if len(line) > 80:
2354-
msg = """Length of line {0} is over 80 characters. The maximum length allowed is 80 characters, including 2 spaces at the beginning.
2355-
If the two spaces are not present, the module will add them to ensure columns 1 and 2 are blank. """
2395+
msg = """Length of line {0} is over 80 characters. The maximum length allowed is 80 characters. """
23562396
module.fail_json(msg=msg.format(line))
23572397
else:
2358-
if len(line) > 1 and line[0] != " " and line[1] != " ":
2359-
if len(line) > 78:
2360-
msg = """Length of line {0} is over 80 characters. The maximum length allowed is 80 characters, including 2 spaces at the beginning.
2361-
If the two spaces are not present, the module will add them to ensure columns 1 and 2 are blank. """
2362-
module.fail_json(msg=msg.format(line))
2363-
else:
2364-
lines[index] = " {0}".format(line)
2398+
len_line = len(line)
2399+
lines[index] = line.rjust(len_line + spaces, " ")
2400+
if len(lines[index]) > 80:
2401+
msg = """Length of line {0} is over 80 characters. The maximum length allowed is 80 characters. Including the spaces at the beginning.
2402+
Be aware that the module has reserved {1} columns to the left for JCL processing this value can be modified if the program allows for it."""
2403+
module.fail_json(msg=msg.format(line, spaces))
23652404
return lines
23662405

23672406

tests/functional/modules/test_zos_mvs_raw_func.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,59 @@ def test_disposition_new(ansible_zos_module, verbose):
109109
if idcams_dataset:
110110
hosts.all.zos_data_set(name=idcams_dataset, state="absent")
111111

112+
@pytest.mark.parametrize(
113+
# Added this verbose to test issue https://github.com/ansible-collections/ibm_zos_core/issues/1359
114+
# Where a program will fail if rc != 0 only if verbose was True.
115+
"columns",
116+
[0, 2],
117+
)
118+
def test_dd_content_reserved_columns(ansible_zos_module, columns):
119+
idcams_dataset = None
120+
try:
121+
hosts = ansible_zos_module
122+
default_data_set = get_tmp_ds_name()
123+
idcams_dataset, idcams_listcat_dataset_cmd = get_temp_idcams_dataset(hosts)
124+
idcams_listcat_dataset_cmd = idcams_listcat_dataset_cmd.lstrip()
125+
126+
hosts.all.zos_data_set(name=default_data_set, state="absent")
127+
results = hosts.all.zos_mvs_raw(
128+
program_name="idcams",
129+
auth=True,
130+
dds=[
131+
{
132+
"dd_data_set":{
133+
"dd_name":SYSPRINT_DD,
134+
"data_set_name":default_data_set,
135+
"disposition":"new",
136+
"type":"seq",
137+
"return_content":{
138+
"type":"text"
139+
},
140+
},
141+
},
142+
{
143+
"dd_input":{
144+
"dd_name":SYSIN_DD,
145+
"reserved_cols": columns,
146+
"content":idcams_listcat_dataset_cmd
147+
}
148+
},
149+
],
150+
)
151+
for result in results.contacted.values():
152+
if columns > 0:
153+
assert result.get("ret_code", {}).get("code", -1) == 0
154+
assert len(result.get("dd_names", [])) > 0
155+
assert result.get("failed", False) is False
156+
else:
157+
assert result.get("ret_code", {}).get("code", -1) == 12
158+
assert len(result.get("dd_names", [])) > 0
159+
assert result.get("failed", False) is True
160+
finally:
161+
hosts.all.zos_data_set(name=default_data_set, state="absent")
162+
if idcams_dataset:
163+
hosts.all.zos_data_set(name=idcams_dataset, state="absent")
164+
112165
@pytest.mark.parametrize(
113166
"disposition",
114167
["shr", "mod", "old"],
@@ -1198,7 +1251,7 @@ def test_input_provided_as_list(ansible_zos_module):
11981251
("text", "LISTCAT ENTRIES"),
11991252
(
12001253
"base64",
1201-
"QNPJ4uPDweNAxdXj2cnF4k1",
1254+
"QEBA08ni48PB40DF1ePZycX",
12021255
# the above corresponds to the following bytes:
12031256
# 40 d3 c9 e2 e3 c3 c1 e3 40 c5 d5 e3 d9 c9 c5 e2
12041257
# which translate in ebdic to: " LISTCAT ENTRIES"

0 commit comments

Comments
 (0)