XCOM Data Transport

 View Only

Integrating XCOM for z/OS with Python

By Austin Willoughby posted Sep 11, 2023 12:28 PM

  

You use XCOM load module XCOMJOB to schedule or execute transfers with XCOM for z/OS, v12.0.  You can integrate invoking XCOMJOB into your workflows to complete transfers as part of your workflow.  If you're interested in invoking XCOM for z/OS using Python on z/OS, you can use the example in this blog to help you get started.  This blog example uses a PuTTY connection to the z/OS shell in the USS environment and the following Python version to run the example script.

$ python --version
Python 3.9.16

The script invokes the IBM z/OS Open Automation Utilities (zoautil_py) to simplify some of the system operations needed to setup required datasets before calling XCOMJOB.  The script file has also been tagged as IBM-1047 EBCDIC.

$ ls -ltT *.py
t IBM-1047    T=on  -rwxr-xr-x   1 USER001 GROUP01    6347 Sep 11 11:53 gdgtst03.py

The following command is used to specify parameters to invoke the script:

python gdgtst03.py USER001 USER001.DEMO.ZOSSRC.GDG.S000001 USER001.DEMO.ZOSTRG.GDG.S000001 127.0.0.1 8044 XCOM.XCOM120.GA.CBXGLOAD

The example script does a listcat of the source GDG to get the absolute generations and then loops over each absolute generation and creates a transfer for each source absolute generation to a target GDG relative generation.  Following the transfer(s), the source and target generation and version values might not match, but the purpose is to move all generations of the source GDG to the target GDG.

Here is the full script source:

#
# Sample 
#
import sys
from zoautil_py import mvscmd, datasets
from zoautil_py.types import DDStatement, DatasetDefinition
#
def main():
    if len(sys.argv) <  7:
       print("Calling convention is <program> <user> <source_gdg_base> <target_gdg_base> <ip> <port> <steplib_dsn>")
       return
    else:
       username        = sys.argv[1].upper()
       source_gdg_base = sys.argv[2].upper()
       target_gdg_base = sys.argv[3].upper()
       ipv4_addr       = sys.argv[4].upper()
       xcom_trg_port   = sys.argv[5].upper()
       steplib_dsn     = sys.argv[6].upper()
    #
    print("Let's get a GDG listcat!")
    TEMPHLQ     = username
    CMD_STMT1   = " LISTCAT ENTRIES(" + source_gdg_base + ") - "
    CMD_STMT2   = "    GDG ALL"
    CMD_STMT3   = "SH dgrep NONVSAM-- //'"
    # Initialize DD List
    dd_list = []
    gdg_list = []
    #
    try:
       # Create a temp file for the SYSIN statements
       sysin_dataset_name = datasets.tmp_name(TEMPHLQ)
       if(datasets.exists(sysin_dataset_name)):
          datasets.delete(sysin_dataset_name)
       datasets.create(sysin_dataset_name, type="SEQ", primary_space=("1K"),secondary_space=("1K"))
       # Create a temp file for the SYSPRINT statements
       sysprint_dataset_name = datasets.tmp_name(TEMPHLQ)
       if(datasets.exists(sysprint_dataset_name)):
          datasets.delete(sysprint_dataset_name)
       datasets.create(sysprint_dataset_name, type="SEQ", primary_space=("1K"),secondary_space=("1K"))
       #
       datasets.write(sysin_dataset_name, CMD_STMT1, append=False);
       datasets.write(sysin_dataset_name, CMD_STMT2, append=True);
       dd_list.append(DDStatement("SYSIN", DatasetDefinition(sysin_dataset_name)))
       dd_list.append(DDStatement("SYSPRINT", DatasetDefinition(sysprint_dataset_name)))
       #
       response = mvscmd.execute_authorized(pgm="IDCAMS", pgm_args="", dds=dd_list, verbose=True, debug=True)
       #
       dd_list = []
       # Create a temp file for the STDPARM statements
       stdparm_dataset_name = datasets.tmp_name(TEMPHLQ)
       if(datasets.exists(stdparm_dataset_name)):
          datasets.delete(stdparm_dataset_name)
       datasets.create(stdparm_dataset_name, type="SEQ", primary_space=("1K"),secondary_space=("1K"))
       # Create a temp file for the STDOUT statements
       stdout_dataset_name = datasets.tmp_name(TEMPHLQ)
       if(datasets.exists(stdout_dataset_name)):
          datasets.delete(stdout_dataset_name)
       datasets.create(name=stdout_dataset_name, type="SEQ",
                       record_length=200,block_size=20000,
                       primary_space=("1K"),secondary_space=("1K"))
       #
       CMD_STMT    = CMD_STMT3 + sysprint_dataset_name
       CMD_STMT    = CMD_STMT  + "'"
       datasets.write(stdparm_dataset_name, CMD_STMT, append=False);
       dd_list.append(DDStatement("STDPARM", DatasetDefinition(stdparm_dataset_name)))
       dd_list.append(DDStatement("STDOUT", DatasetDefinition(stdout_dataset_name)))
       #
       response = mvscmd.execute(pgm="BPXBATCH", pgm_args="", dds=dd_list, verbose=True, debug=True)
       #
       all_lines = datasets.read(stdout_dataset_name).split("\n")
       for line in all_lines:
          line = line[line.find("NONVSAM--") + len("NONVSAM--"):]
          absolute_gdg = line.strip()
          gdg_list.append(absolute_gdg)
    finally:
       if(datasets.exists(sysin_dataset_name)):
          datasets.delete(sysin_dataset_name)
       if(datasets.exists(sysprint_dataset_name)):
          datasets.delete(sysprint_dataset_name)
       if(datasets.exists(stdparm_dataset_name)):
          datasets.delete(stdparm_dataset_name)
       if(datasets.exists(stdout_dataset_name)):
          datasets.delete(stdout_dataset_name)
    #
    if len(gdg_list) == 0:
       print("No gdg generations found")
       return
    #
    CFG_DSN     = username + ".XCOM.R120.CBXGPARM"
    for i, gdg_goovoo in enumerate(gdg_list):
       print("Let's submit an XCOM Data Transport transfer for " + gdg_goovoo + "!")
       # Initialize DD List
       dd_list = []
       #
       try:
          # Create a temp file for the SYSIN01 statements
          sysin01_dataset_name = datasets.tmp_name(TEMPHLQ)
          if(datasets.exists(sysin01_dataset_name)):
             datasets.delete(sysin01_dataset_name)
          datasets.create(sysin01_dataset_name, type="SEQ", primary_space=("1K"),secondary_space=("1K"))
          transfer_id = "PYGDG" + f"{(i + 1):03}"
          datasets.write(sysin01_dataset_name, "ID=" + transfer_id, append=False);
          datasets.write(sysin01_dataset_name, "IPNAME=" + ipv4_addr, append=True);
          datasets.write(sysin01_dataset_name, "IPPORT=" + xcom_trg_port, append=True);
          datasets.write(sysin01_dataset_name, "TYPE=SEND", append=True);
          datasets.write(sysin01_dataset_name, "FILEOPT=CREATE", append=True);
          datasets.write(sysin01_dataset_name, "CREATEDELETE=YES", append=True);
          datasets.write(sysin01_dataset_name, "CKPT=0", append=True);
          datasets.write(sysin01_dataset_name, "FILETYPE=FILE", append=True);
          datasets.write(sysin01_dataset_name, "LFILE=" + gdg_goovoo, append=True);
          datasets.write(sysin01_dataset_name, "FILE=" + target_gdg_base + "(+1)", append=True);
          datasets.write(sysin01_dataset_name, "USERID=" + username, append=True);
          datasets.write(sysin01_dataset_name, "PASSWORD=PASSWORD", append=True);

          dd_list.append(DDStatement("STEPLIB", DatasetDefinition(steplib_dsn)))
          dd_list.append(DDStatement("XCOMCNTL", DatasetDefinition(CFG_DSN)))
          dd_list.append(DDStatement("SYSIN01", DatasetDefinition(sysin01_dataset_name)))
          #
          response = mvscmd.execute_authorized(pgm="XCOMJOB", pgm_args="CONFIG=XCOMCNFG,TYPE=EXECUTE", dds=dd_list, verbose=True, debug=True)
          #
          if response.rc != 0:
             print("Stopping due to error, rc: " + int(response.rc))
             break
          print("You transferred " + gdg_goovoo + " to " + target_gdg_base + "(+1) as transfer ID " + transfer_id + "!")
       finally:
          if(datasets.exists(sysin01_dataset_name)):
             datasets.delete(sysin01_dataset_name)
# The following is used to protect the script from
#  being called by mistake
if __name__ == "__main__":
    main()

While this example may not provide exactly the function you need, hopefully it helps you integrate XCOM into your workflows by providing .

0 comments
11 views

Permalink