Skip to content

Commit d910975

Browse files
[Enabler] [zos_encode] Support for GDS in zos_encode (#1531)
* Update validation to use new data set class * Add support for GDG/GDS * Add negative GDS test * Add more GDS tests * Fix dest validations * Update docs * Add more negative tests * Add tests for GDS destinations * Add GDS support for backups * Add tests for GDS backup support * Add test for data set with special symbols * Add changelog fragment * Update docs --------- Co-authored-by: Fernando Flores <[email protected]>
1 parent cc108c7 commit d910975

File tree

5 files changed

+513
-22
lines changed

5 files changed

+513
-22
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
minor_changes:
2+
- zos_encode - add support for encoding generation data sets (GDS), as well
3+
as using a GDS for backup.
4+
(https://github.com/ansible-collections/ibm_zos_core/pull/1531).

docs/source/modules/zos_encode.rst

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,27 +54,31 @@ encoding
5454

5555

5656
src
57-
The location can be a UNIX System Services (USS) file or path, PS (sequential data set), PDS, PDSE, member of a PDS or PDSE, or KSDS (VSAM data set).
57+
The location can be a UNIX System Services (USS) file or path, PS (sequential data set), PDS, PDSE, member of a PDS or PDSE, a generation data set (GDS) or KSDS (VSAM data set).
5858

5959
The USS path or file must be an absolute pathname.
6060

6161
If \ :emphasis:`src`\ is a USS directory, all files will be encoded.
6262

63+
Encoding a whole generation data group (GDG) is not supported.
64+
6365
| **required**: True
6466
| **type**: str
6567
6668

6769
dest
6870
The location where the converted characters are output.
6971

70-
The destination \ :emphasis:`dest`\ can be a UNIX System Services (USS) file or path, PS (sequential data set), PDS, PDSE, member of a PDS or PDSE, or KSDS (VSAM data set).
72+
The destination \ :emphasis:`dest`\ can be a UNIX System Services (USS) file or path, PS (sequential data set), PDS, PDSE, member of a PDS or PDSE, a generation data set (GDS) or KSDS (VSAM data set).
7173

7274
If the length of the PDSE member name used in \ :emphasis:`dest`\ is greater than 8 characters, the member name will be truncated when written out.
7375

7476
If \ :emphasis:`dest`\ is not specified, the \ :emphasis:`src`\ will be used as the destination and will overwrite the \ :emphasis:`src`\ with the character set in the option \ :emphasis:`to\_encoding`\ .
7577

7678
The USS file or path must be an absolute pathname.
7779

80+
If \ :emphasis:`dest`\ is a data set, it must be already allocated.
81+
7882
| **required**: False
7983
| **type**: str
8084
@@ -100,6 +104,8 @@ backup_name
100104

101105
\ :literal:`backup\_name`\ will be returned on either success or failure of module execution such that data can be retrieved.
102106

107+
If \ :emphasis:`backup\_name`\ is a generation data set (GDS), it must be a relative positive name (for example, \ :literal:`HLQ.USER.GDG(+1)`\ ).
108+
103109
| **required**: False
104110
| **type**: str
105111
@@ -253,6 +259,24 @@ Examples
253259
from: ISO8859-1
254260
to: IBM-1047
255261

262+
- name: Convert file encoding from a USS file to a generation data set
263+
zos_encode:
264+
src: /zos_encode/test.data
265+
dest: USER.TEST.GDG(0)
266+
encoding:
267+
from: ISO8859-1
268+
to: IBM-1047
269+
270+
- name: Convert file encoding from a USS file to a data set while using a GDG for backup
271+
zos_encode:
272+
src: /zos_encode/test.data
273+
dest: USER.TEST.PS
274+
encoding:
275+
from: ISO8859-1
276+
to: IBM-1047
277+
backup: true
278+
backup_name: USER.BACKUP.GDG(+1)
279+
256280

257281

258282

plugins/module_utils/encode.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ def mvs_convert_encoding(
511511
if src_type == "PO":
512512
temp_src = mkdtemp()
513513
rc, out, err = copy.copy_pds2uss(src, temp_src)
514-
if src_type == "VSAM":
514+
if src_type == "KSDS":
515515
reclen, space_u = self.listdsi_data_set(src.upper())
516516
# RDW takes the first 4 bytes in the VB format, hence we need to add an extra buffer to the vsam max recl.
517517
reclen += 4
@@ -520,7 +520,7 @@ def mvs_convert_encoding(
520520
temp_src_fo = NamedTemporaryFile()
521521
temp_src = temp_src_fo.name
522522
rc, out, err = copy.copy_ps2uss(temp_ps, temp_src)
523-
if dest_type == "PS" or dest_type == "VSAM":
523+
if dest_type == "PS" or dest_type == "KSDS":
524524
temp_dest_fo = NamedTemporaryFile()
525525
temp_dest = temp_dest_fo.name
526526
if dest_type == "PO":
@@ -530,7 +530,7 @@ def mvs_convert_encoding(
530530
if not dest_type:
531531
convert_rc = True
532532
else:
533-
if dest_type == "VSAM":
533+
if dest_type == "KSDS":
534534
reclen, space_u = self.listdsi_data_set(dest.upper())
535535
# RDW takes the first 4 bytes or records in the VB format, hence we need to add an extra buffer to the vsam max recl.
536536
reclen += 4

plugins/modules/zos_encode.py

Lines changed: 114 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,26 @@
5555
src:
5656
description:
5757
- The location can be a UNIX System Services (USS) file or path,
58-
PS (sequential data set), PDS, PDSE, member of a PDS or PDSE, or
59-
KSDS (VSAM data set).
58+
PS (sequential data set), PDS, PDSE, member of a PDS or PDSE, a
59+
generation data set (GDS) or KSDS (VSAM data set).
6060
- The USS path or file must be an absolute pathname.
6161
- If I(src) is a USS directory, all files will be encoded.
62+
- Encoding a whole generation data group (GDG) is not supported.
6263
required: true
6364
type: str
6465
dest:
6566
description:
6667
- The location where the converted characters are output.
6768
- The destination I(dest) can be a UNIX System Services (USS) file or path,
68-
PS (sequential data set), PDS, PDSE, member of a PDS or PDSE, or
69-
KSDS (VSAM data set).
69+
PS (sequential data set), PDS, PDSE, member of a PDS or PDSE, a
70+
generation data set (GDS) or KSDS (VSAM data set).
7071
- If the length of the PDSE member name used in I(dest) is greater
7172
than 8 characters, the member name will be truncated when written out.
7273
- If I(dest) is not specified, the I(src) will be used as the destination
7374
and will overwrite the I(src) with the character set in the
7475
option I(to_encoding).
7576
- The USS file or path must be an absolute pathname.
77+
- If I(dest) is a data set, it must be already allocated.
7678
required: false
7779
type: str
7880
backup:
@@ -99,6 +101,8 @@
99101
by IBM Z Open Automation Utilities.
100102
- C(backup_name) will be returned on either success or failure of module
101103
execution such that data can be retrieved.
104+
- If I(backup_name) is a generation data set (GDS), it must be a relative
105+
positive name (for example, V(HLQ.USER.GDG(+1\))).
102106
required: false
103107
type: str
104108
backup_compress:
@@ -249,6 +253,24 @@
249253
encoding:
250254
from: ISO8859-1
251255
to: IBM-1047
256+
257+
- name: Convert file encoding from a USS file to a generation data set
258+
zos_encode:
259+
src: /zos_encode/test.data
260+
dest: USER.TEST.GDG(0)
261+
encoding:
262+
from: ISO8859-1
263+
to: IBM-1047
264+
265+
- name: Convert file encoding from a USS file to a data set while using a GDG for backup
266+
zos_encode:
267+
src: /zos_encode/test.data
268+
dest: USER.TEST.PS
269+
encoding:
270+
from: ISO8859-1
271+
to: IBM-1047
272+
backup: true
273+
backup_name: USER.BACKUP.GDG(+1)
252274
"""
253275

254276
RETURN = r"""
@@ -494,6 +516,8 @@ def run_module():
494516
is_mvs_dest = False
495517
ds_type_src = None
496518
ds_type_dest = None
519+
src_data_set = None
520+
dest_data_set = None
497521
convert_rc = False
498522
changed = False
499523

@@ -503,20 +527,79 @@ def run_module():
503527

504528
try:
505529
# Check the src is a USS file/path or an MVS data set
506-
is_uss_src, is_mvs_src, ds_type_src = check_file(src)
507-
if is_uss_src:
508-
verify_uss_path_exists(src)
530+
# is_uss_src, is_mvs_src, ds_type_src = check_file(src)
531+
532+
if path.sep in src:
533+
is_uss_src = True
534+
# ds_type_src = "USS"
535+
verify_uss_path_exists(src) # This can raise an exception.
536+
else:
537+
is_mvs_src = True
538+
src_data_set = data_set.MVSDataSet(src)
539+
is_name_member = data_set.is_member(src_data_set.name)
540+
dest_exists = False
541+
542+
if not is_name_member:
543+
dest_exists = data_set.DataSet.data_set_exists(src_data_set.name)
544+
else:
545+
dest_exists = data_set.DataSet.data_set_exists(data_set.extract_dsname(src_data_set.name))
546+
547+
if not dest_exists:
548+
raise EncodeError(
549+
"Data set {0} is not cataloged, please check data set provided in "
550+
"the src option.".format(data_set.extract_dsname(src_data_set.raw_name))
551+
)
552+
553+
if is_name_member:
554+
if not data_set.DataSet.data_set_member_exists(src_data_set.name):
555+
raise EncodeError("Cannot find member {0} in {1}".format(
556+
data_set.extract_member(src_data_set.raw_name),
557+
data_set.extract_dsname(src_data_set.raw_name)
558+
))
559+
ds_type_src = "PS"
560+
else:
561+
ds_type_src = data_set.DataSet.data_set_type(src_data_set.name)
562+
563+
if not ds_type_src:
564+
raise EncodeError("Unable to determine data set type of {0}".format(src_data_set.raw_name))
565+
509566
result["src"] = src
510567

511568
# Check the dest is a USS file/path or an MVS data set
512569
# if the dest is not specified, the value in the src will be used
513570
if not dest:
514-
dest = src
571+
if src_data_set:
572+
dest = src_data_set.name
573+
else:
574+
dest = src
575+
515576
is_uss_dest = is_uss_src
516577
is_mvs_dest = is_mvs_src
517578
ds_type_dest = ds_type_src
518579
else:
519-
is_uss_dest, is_mvs_dest, ds_type_dest = check_file(dest)
580+
if path.sep in dest:
581+
is_uss_dest = True
582+
else:
583+
is_mvs_dest = True
584+
dest_data_set = data_set.MVSDataSet(dest)
585+
is_name_member = data_set.is_member(dest_data_set.name)
586+
587+
if not is_name_member:
588+
dest_exists = data_set.DataSet.data_set_exists(dest_data_set.name)
589+
else:
590+
dest_exists = data_set.DataSet.data_set_exists(data_set.extract_dsname(dest_data_set.name))
591+
592+
if not dest_exists:
593+
raise EncodeError(
594+
"Data set {0} is not cataloged, please check data set provided in "
595+
"the dest option.".format(data_set.extract_dsname(dest_data_set.raw_name))
596+
)
597+
598+
if is_name_member:
599+
ds_type_dest = "PS"
600+
else:
601+
ds_type_dest = data_set.DataSet.data_set_type(dest_data_set.name)
602+
520603
if (not is_uss_dest) and (path.sep in dest):
521604
try:
522605
if path.isfile(src) or ds_type_src in ["PS", "VSAM"]:
@@ -532,14 +615,28 @@ def run_module():
532615
raise EncodeError("Failed when creating the {0}".format(dest))
533616
result["dest"] = dest
534617

618+
if ds_type_dest == "GDG":
619+
raise EncodeError("Encoding of a whole generation data group is not yet supported.")
620+
621+
new_src = src_data_set.name if src_data_set else src
622+
new_dest = dest_data_set.name if dest_data_set else dest
623+
535624
# Check if the dest is required to be backup before conversion
536625
if backup:
626+
if backup_name:
627+
backup_data_set = data_set.MVSDataSet(backup_name)
628+
if backup_data_set.is_gds_active:
629+
raise EncodeError(
630+
f"The generation data set {backup_name} cannot be used as backup. "
631+
"Please use a new generation for this purpose."
632+
)
633+
537634
if is_uss_dest:
538635
backup_name = zos_backup.uss_file_backup(
539-
dest, backup_name, backup_compress
636+
new_dest, backup_name, backup_compress
540637
)
541638
if is_mvs_dest:
542-
backup_name = zos_backup.mvs_file_backup(dest, backup_name, tmphlq)
639+
backup_name = zos_backup.mvs_file_backup(new_dest, backup_name, tmphlq)
543640
result["backup_name"] = backup_name
544641

545642
eu = encode.EncodeUtils()
@@ -564,12 +661,12 @@ def run_module():
564661

565662
if is_uss_src and is_uss_dest:
566663
convert_rc = eu.uss_convert_encoding_prev(
567-
src, dest, from_encoding, to_encoding
664+
new_src, new_dest, from_encoding, to_encoding
568665
)
569666
else:
570667
convert_rc = eu.mvs_convert_encoding(
571-
src,
572-
dest,
668+
new_src,
669+
new_dest,
573670
from_encoding,
574671
to_encoding,
575672
src_type=ds_type_src,
@@ -578,12 +675,12 @@ def run_module():
578675

579676
if convert_rc:
580677
if is_uss_dest:
581-
eu.uss_tag_encoding(dest, to_encoding)
678+
eu.uss_tag_encoding(new_dest, to_encoding)
582679

583680
changed = True
584-
result = dict(changed=changed, src=src, dest=dest, backup_name=backup_name)
681+
result = dict(changed=changed, src=new_src, dest=new_dest, backup_name=backup_name)
585682
else:
586-
result = dict(src=src, dest=dest, changed=changed, backup_name=backup_name)
683+
result = dict(src=new_src, dest=new_dest, changed=changed, backup_name=backup_name)
587684
except encode.TaggingError as e:
588685
module.fail_json(
589686
msg=e.msg,

0 commit comments

Comments
 (0)