Wednesday, October 7, 2020

Master the Mainframe 2020 | Level 2.9: ZOAU2: Power Through Python

Hiya! Welcome to my blog๐Ÿ˜ƒ

Master the Mainframe has been a lot interesting this year (2020) as we are using Visual Studio Code (for the first time) to establish a connection with z/OS and work with data sets and jobs, thanks to Zowe™ and IBM Z Open Editor extensions. We're now able to use the mouse to scroll through the contents of a data set๐Ÿ˜Ž.

Picture 9.1: Viewing the contents of a data set using IBM Z Open Editor in VS Code.

In this blog post, I want to share my impressions on using Python๐Ÿ and Z Open Automation Utilities (abbreviated to ZOAU) to build an app to validate credit card data (This is the challenge in Level 2.9 of MTM2020). 

๐Ÿ’ก: ZOAU lets you perform many tasks on z/OS without needing to get into JCL. 

Before getting started with Zowe and Python, we will be building the logic using COBOL; we will then compile and run the COBOL program with the help of  JCL.  Then, we will be looking at Python and ZOAU way of building the same logic. In this way, I believe you will be able to understand the differences better. You'll also get answers to  some questions like 'Why Python?', 'Why ZOAU?', 'Why not JCL and COBOL?' and so on..

Fasten your seat belts, let's take-off now! 

The requirement is to read an input file (MTM2020.PUBLIC.CUST16 is the input data set name in MTM2020 system) and print a report with list of records that has got an invalid Credit card number (aka Payment Card Number). 

The input data set conforms to Track 1 Format B of ISO/IEC 7813 format ๐Ÿ‘‰(https://en.wikipedia.org/wiki/ISO/IEC_7813). 

Picture 9.2: A snap from Wikipedia that shows the structure of Track 1 Format B. I've used this structure to come up with the record layout of the input file for COBOL.

Using COBOL program and JCL:

The COBOL program prepared by this Author๐Ÿ˜‰ is as follows: 
Picture 9.3: The COBOL program reads the input file; implements Luhn Algorithm to find if a credit card number is vaild or not; if invalid, the record is written to the output file as a report. 

What the COBOL program does? 

  • An input file is being read (the record layout of the input file, INFILE-REC is based on Track 1 Format B structure of ISO/IEC 7813). 
  • For each record that is being read, control is passed to 100-IS-INVALID-PARA. This para implements the Luhn Algorithm. 
  • The first PERFORM loop within 100-IS-INVALID-PARA computes the sum of digits present in the odd number positions in PYMT-CARD-NUMBER. For example, if the value in the PYMT-CARD-NUMBER data item is 1234567890223457846, then 1 + 3 + 5 + 7 + 9 + 2 + 3 + 5 + 8 + 6 = 49 will be stored in WS-CHECKSUM at the end of the first perform loop. 
  • The second PERFORM loop within 100-IS-INVALID-PARA multiply the digits present in the even number positions, by 2; if the resulting value is greater than 9, then 9 is subtracted from the resulting value (Please don't ask ME why we have to do this. IBM Scientist Hans Peter Luhn, created this algorithm๐Ÿ˜Š); accumulate the resulting value by adding it to WS-CHECKSUM data-item. 
  • After the 2 PERFORM loops, divide the final value in WS-CHECKSUM data item by 10. You should assign a data item for holding the remainder. If the remainder is 0, the value in PYMT-CARD-NUMBER is valid. Else, it is invalid. 
  • When an Invalid credit card number is found, control is passed to 200-WRITE-OUTPUT-PARA to write the whole record with the invalid credit card number, to the output file. When the control is passed to 200-WRITE-OUTPUT-PARA for the first time, the header record and an empty line are written to the output file. 

I was not aware of Luhn algorithm until I started this challenge. A pretty interesting one. The Luhn Algorithm is an efficient method of checking if a credit card number is valid, locally, without needing to have the bank or financial institute process it. This way, cards can be checked directly on a web page for mistakes in typing or copying digits. More information about Luhn algortihm can be found ๐Ÿ‘‰ here.

After finishing the COBOL program, we have to prepare a JCL to compile the program and run it by providing input and output files. The following JCL does that.


After the compilation and execution of the program, we get the following output.

To read an input data set with magnetic stripe data that you might find on a credit card (if it doesn’t have a chip) and to print a report out of it with the list of invalid credit card numbers, what all we did? We wrote a COBOL program, prepared a JCL to compile the program and execute it. I call this the  usual Mainframe Way (not The Milky Way๐Ÿ˜‰). 

Let's do the same task using Zowe™ and Python. This is what Level 2.9 in MTM2020 is all about. 

Using Zowe™ and Python๐Ÿ:

ZOAU supports shell scripts, Python and Node.js. The commands available through Z Open Automation Utilities in Python can be found ๐Ÿ‘‰ here. In Layman's terms, IBM has developed a bridge between z/OS and Python by making these commands available for us to use within the Python scripts. We use ๐Ÿ‘‰ zoautil_py.Datasets module extensively in this challenge. Modules in Python will have a set of functions, classes and variables defined in it. zoautil_py.Datasets module has got several functions like, 
  • create(name, type, size, format, class_name, length, offset) - Used to create a data set in z/OS
  • delete(dataset) - Used to delete a data set in z/OS
  • copy(source, target) - Used to copy the source data set into destination data set
You just have to refer to the corresponding function and pass necessary arguments in your Python script to perform the task it is intended to do. 

Building the logic using Python:

Note: In order to access python scripts from your home directory, /z/zxxxxxyou should be signed up to ๐Ÿ‘‰ MTM2020 and should've finished the challenges till Level 2.4. 
There's already a python script (cc_check.py) available under your home directory (/z/zxxxxx) in Unix Sytem Services (abbreviated to USS). There are LOTS of comments in the script to help you understand what the code is doing. You just have to build, upon this foundation, a logic which would write the invalid credit card number to the output file.  
๐Ÿ’ก: A comment in Python starts with the hash character, #
I've used Trinket to embed Interactive Python in this blog post and I've copy pasted the contents of cc_check.py file in Trinket (And nope! The script shown below isn't the solution for Level 2.9๐Ÿ˜). I'll do my best here to make you understand what needs to be done to complete Level 2.9. 

Note that you may not be able to RUN ๐Ÿƒ this script in Trinket as the ZOAU utilities for Python aren't available in Trinket.
 
 
Lines 1 thru 7: The necessary ZOAU libraries for Python are imported so that you can use them in the script. 

Lines 9 thru 16: The input data set, MTM2020.PUBLIC.CUST16 is being read into a variable called cc_contents. Line #12 uses the os.getenv() method in Python with 'USER' as argument. As the operating system that Python is running under, is z/OS, USERID variable is assigned with your TSO user ID. In Line #13, 2 strings are concatenated with '+' operator and the result is stored in output_dataset variable. Some functions (like exists, delete) in the Datasets module are being used to check if the output data set is already existing in the Mainframe. If yes, then it is deleted.  

Lines 17 and 18: Read๐Ÿ‘€ those comments in the 2 lines as they help you figure out what needs to be done.

Lines 21 thru 28: def keyword in Python is used to define functions. You all know that function is a group of statements which are intended to perform a specific task. This function's name is is_even and this function receives one argument from the caller. The purpose of this function is to check if the number passed as an argument by the caller, is even or odd. If it is even, the function returns 'True' to the caller. Else, it returns 'False'. Your task is to edit this script so that instead of finding the even numbers, it implements the Luhn algorithm to find the six invalid entries in the input file. You may use the sample code in luhn.py file to perform the checking logic. 

Lines 30 thru 35: Each record in the data set is stored as an element in a List named as cc_list. Like how we read records one by one in COBOL, a for loop in Python is being used to read the elements of cc_list, one by one. cc_line variable is used to hold the element in any given iteration of the for loop. Like how we use Reference Modification in COBOL to extract a portion of the string, slicing technique (in Line 33) is being used on the List element to extract the Payment card number. The extracted card number is then passed as an argument to is_even function.
๐Ÿ’ก: List is one of the most frequently used datatype in Python. The elements are stored in a list within a square brackets ([ ]). Lists can have any number of items in it and the elements may be of different data types. Read more about lists and how to access the elements in a list ๐Ÿ‘‰ here.

Lines 38 thru 57: Pretty much self explanatory as there are a lot of comments. Once you're ready to write the 6 invalid credit card numbers to the output file, uncomment line 57. 

And, there you go! refer luhn.py file and implement the Luhn algorithm in the place of is_even function. Bonus: Pay attention whenever you find the word hint in a comment line.

With Python and ZOAU utilities, it required only ~30 lines of code to build the logic that will look for the invalid credit card numbers from a Mainframe Input data set and write a report consisting of the invalid entries to an output data set. Power Through Python๐Ÿ’ช
You just witnessed one of the newest innovations in z/OS, the introduction of IBM Z Open Automation Utilities (ZOA Utilities) in ACTION ๐Ÿ’ฅ. ZOAU is an alternative way of interacting with tasks on z/OS through scripting instead of writing JCL's and submitting jobs. 

Hope you liked this post. Feel free to add your comments below. Thx๐Ÿ‘

Screenshot Courtesy: Mainframe access๐Ÿ’ป obtained via MTM2020 contest run by IBM.


20 comments:

  1. I could clearly see, writing this blog would have more time than attending the challenge itself. This is an example when one loves sharing knowledge.

    ReplyDelete
  2. This is great, I just finished myself the level 3 and, encouraged by getting that sweet level 3 badge I'm about to embark in the development of the Grand Challenge project. Good stuff!

    ReplyDelete
    Replies
    1. Hey QQ.. do we need to submit the GC to receive the L3 badge ?
      I completed all L3 challenges but didn't receive the batch so wondering !
      TIA

      Delete
  3. Can Someone help I am still stuck on this one

    ReplyDelete
    Replies
    1. Could you please share more info describing what you've tried and where you're stuck?

      Delete
    2. Please share more info on what you've tried so far and where you're stuck. I'll do my best to help you out. Alternatively, you can also join the MTM Slack channel (https://mtmcompetition.slack.com/join/shared_invite/zt-kmd5h9pg-kjAkIxtc22jqEZiMnDvMYw#/) and post your questions there.

      Delete
    3. I've tried to connectt o the mtm slack link but it didn't work

      Delete
  4. Hello , I mistakenly deleted oma zoaumerge file on the unix services, please how do i recover it

    ReplyDelete
    Replies
    1. In USS, navigate your way to /z/public and type the command ./copy.sh to get fresh copies of your files.

      Delete
    2. This comment has been removed by the author.

      Delete
  5. Am not able to complete level 2.9

    when I run python3 cc_check.py , it shows an output with error like this


    STDERR from ZOAU library call:
    BGYSC1402E Dynalloc Failure. Error Code: 0x35c, Information Code: 0x02
    STDERR from ZOAU library call:
    cleanup: exit: /z/python/zoau-v1.0.3/bin/dechohelper 74: FSUM7351 not found

    ReplyDelete
    Replies
    1. BGYSC1402E Dynalloc Failure. Error Code: 0x{0}, Information Code: 0x{1}
      Explanation: An unexpected error was encountered when trying to allocate the dataset using DYNALLOC (SVC99).

      User action: See 'Interpreting DYNALLOC return codes' in the 'z/OS MVS Programming: Authorized Assembler Services Guide' for more details.

      I found the following in the aforementioned guide:
      035C:
      Meaning: Invalid PARM speci®ed in text unit. The accompanying
      message IKJ56231I identi®es the text unit in error. (all dynamic
      allocation functions)2
      Application programmer action: See the description of the text unit and
      correct the error.
      Corresponding message: IKJ56231I

      Could you please share the code that you've coded to create the output dataset?
      FYI, I used, Datasets.create(output_dataset,'SEQ') where output_dataset=USERID+".OUTPUT.CCINVALD"

      Delete
    2. >I used, Datasets.create(output_dataset,'SEQ') where output_dataset=USERID+".OUTPUT.CCINVALD"

      Same but didn't work to me. I tried:
      output_dataset=USERID+".OUTPUT.CCINVALID"
      Datasets.create(name=output_dataset, 'SEQ')
      Datasets.create(output_dataset, type="SEQ")
      Datasets.create(output_dataset)

      Delete
    3. By the way I'm not the person who originally asked this, so with 17 hours left some others may be also panicking now

      Delete
  6. Hi when i sumbit chk3 i cant see the output if it is correct or not. Can anyone help me ? I try to sumbit chk and chk2 but the same i just can see the JES2:JESMSGLG and JES2:JESJCL

    ReplyDelete