Skip to main content

Write Your Own Checks With z/OS Health Checker

IBM provides a set of check routines for IBM Health Checker for z/OS that examine specific settings or values for potential problems and here are the general steps.

A photo of a white keyboard, with a stethoscope laying over it.

The IBM Health Checker for z/OS is a component of MVS that provides the framework for checking z/OS system and sysplex configuration parameters and the system environment. This helps determine where an installation may be deviating from suggested settings or where there might be configuration problems. IBM provides a set of check routines—over 200 to date—for IBM Health Checker for z/OS that examine specific settings or values for potential problems. Check routines can also be provided by ISVs, or written by users themselves.

As a follow-up to the article, "Healthy Status," that was published in the January/February 2017 Tech Corner section of IBM Systems Magazine, this article is the first of a multi-part series that will describe the general steps of planning and developing your own health check. This first part will provide a minimal, but fully functional, sample health check written in System REXX that summarizes the topics discussed.

The General Process

In a nutshell, the basic steps to create your own health check are:

  • Provide the “inspection” code (i.e., the health check routine)
  • Tell Health Checker where to find it
  • Health Checker takes care of the rest

First, decide how and where the health check routine is provided to Health Checker, and finally executed. For simplicity in this article, the code example is written in System REXX, and therefore the "check locale" is REXX. Health Checker will run REXX checks in one of the System REXX (AXR) address spaces. Note that REXX checks will run authorized. In the next article in this series, we will describe other, more advanced environments where a check routine can run: “Local” and “Remote, non-REXX.”

The Health Check Routine Outline

The objective of a health check is to identify potential problems before they impact your installation’s availability or, in the worst-case scenario, cause outages. The health check outputs messages that help an installation analyze health-related aspects of the system. Your health check routine follows a basic outline each time it is invoked by the Health Checker framework:

  • Connect: Establish handshake with Health Checker
  • Parse Parameters: Interpret new/updated check PARM value(s), if supplied
  • Analyze: Check “the” specific configuration setting the check covers
  • Report: Present findings (success or failure, with additional details for each)
  • Disconnect: Final handshake with Health Checker

The main line from the attached full REXX check sample routine follows that outline:

CALL Connect_to_Health_Checker

parmRelease = Retrieve_Check_Parameter()
  
systemRelease = Retrieve_System_Release()

IF (systemRelease = parmRelease)
THEN CALL Issue_CheckSuccess_Message
ELSE CALL Issue_CheckException_Message systemRelease parmRelease

CALL Disconnect_from_Health_Checker

The following sections will show more details from the called sub-routines while explaining various check concepts.

Connect: Handshake with Health Checker

A REXX check is submitted by Health Checker to run in a System REXX address space, and therefore “remote” from the Health Checker address space.

For that reason, your REXX check routine will initially invoke the HZSLSTRT function to indicate that this remote exec has received control and started running. The HZSLSTRT function is also invoked to receive useful check information from its health check control block (the HZSPQE) in special REXX variables that are prefixed with "HZS," such as the following. The Health Checker User’s Guide.

  • HZS_PQE_LOOKATPARMS: A Boolean value indicating whether the check should look at its current parameter string, either because check parameter values have changed since the last time this check ran, or because it is the first time the check has run at all
  • HZS_PQE_PARMAREA: The current check PARM string (the “check parameters”), if any
  • HZS_PQE_FUNCTION_CODE: Gives the check a chance to distinguish between its first run and a secondary run. The possible values are “INITRUN” and “RUN,” respectively.
  • HZS_HANDLE: Identifies the REXX check when communicating with Health Checker. The system uses this handle as implicit input for all of the Health Checker callable functions such as HZSLSTRT, HZSLFMSG, and HZSLSTOP. The REXX check should never alter this field, and will probably never even need to reference it, except in cases when encapsulating calls to those functions in REXX PROCEDUREs. In this case, make sure to use the REXX EXPOSE statement to allow the use of HZS_HANDLE inside the PROCEDURE.
  • HZS_PQE_DEBUG: A Boolean value indicating whether the user turned debug on for the check. When in DEBUG mode the check should provide additional information in particular about failing function calls.
Connect_to_Health_Checker: 
/*
 * FUNCTION: Establish handshake with Health 
Checker and with that
 *           provide HZS_* variables. 
 *           Will EXIT the exec if errors are 
encountered.
 */
 
 HZSLSTRT_RC = HZSLSTRT()
 IF (HZSLSTRT_RC <> 0 & HZS_PQE_DEBUG = 1) THEN
  DO
   SAY "HZSLSTRT RC"  HZSLSTRT_RC
   SAY "HZSLSTRT RSN" HZSLSTRT_RSN
   SAY "HZSLSTRT SYSTEMDIAG" HZSLSTRT_SYSTEMDIAG
   EXIT /* ...because without HZSLSTART 
the check will not be able
           to communicate with Health Checker */
  END

  RETURN

Examine Input Parameters

After successfully establishing a handshake with the Health Checker, the REXX check routine should validate input parameters, if any are supplied.

The HZS_PQE_LOOKATPARMS variable makes things easy, and allows the check to only (re-)parse the PARM string if it was updated by the user between check runs, or if the check is called for first time. After each new actual parsing, the check can store the found values into the HZS_PQE_CHKWORK variable, which Health Checker will preserve across check calls.

Retrieve_Check_Parameter: 
/* 
 * FUNCTION: Validate and parse the check's PARM string for the 
 *          "desired" z/OS release, 
 *          -or- 
 *          if PARM is unchanged from 
the previous check run, 
 *          just return the previously 
parsed and saved value. 
 * RETURNS: On success, the desired z/OS 
release in format "v.r".
 *         On error: (1) report a BAD PARM error to Health Checker
 *                   (2) disable the check
 *                   (3) disconnect from Health Checker
 *                   (4) EXIT the exec right here and do not return
 */

  /* Try to re-use previously parsed value */
  IF (HZS_PQE_LOOKATPARMS = 0) 
  THEN parmRelease = HZS_PQE_CHKWORK
  ELSE /* Need to (re-) parse current PARM string */
   DO
     <...> - see below
     HZS_PQE_CHKWORK = parmRelease
    END
  END /* need to (re-) parse PARM string */
 
  RETURN parmRelease

When parsing the PARM string, we must be prepared to encounter malformed input. In that case, we need to tell the user and Health Checker, that something’s wrong. Health Checker will then disable the check until the user fixes the PARM string.

Note that an update to the PARM string will let Health Checker re-enable the check and kick off a fresh check run.

We use the callable function HZSLFMSG with a special REQUEST and REASON combination, which allows us to issue common pre-defined error messages.

  ...
  ELSE /* Need to (re-) parse current PARM string */
   DO
   /* Expected PARM string format is PARM('ZOS_RELEASE(v.r)') */
   PARSE UPPER VAR HZS_PQE_PARMAREA parmName "(" zVer "." zRel ")"

   IF (parmName <> "ZOS_RELEASE") THEN
   DO
    /* Issue "HZS1201E parm IS REQUIRED BUT WAS NOT SPECIFIED" */
    HZSLFMSG_Request  = "HZSMSG"
    HZSLFMSG_Reason   = "PARS1201"
    HZSLFMSG_insert.0 = 1
    HZSLFMSG_insert.1 = "ZOS_RELEASE"
    CALL HZSLFMSG
    IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 
    THEN CALL Issue_HZSLFSMG_DiagInfo

    /* STOP the check with a BADPARM state */
    HZSLFMSG_REQUEST = "STOP"
    HZSLFMSG_REASON  = "BADPARM"
    CALL HZSLFMSG
    IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 
    THEN CALL Issue_HZSLFSMG_DiagInfo

    /* EXIT: SYSPROG needs to fix PARM string first 
             before we can do anything */
    CALL Disconnect_from_Health_Checker
    EXIT
   END /* parm not ZOS_RELEASE */
   ELSE 
    DO
     parmRelease = SPACE(zVer "." zRel,0)
     HZS_PQE_CHKWORK = parmRelease
    END
  END /* need to (re-) parse PARM string */

Based on the above, this is how a parameter error (a missing trailing E in ZOS_RELEASE) would look like in the check’s message buffer:

CHECK(USERCHK,USR_ZOS_CHECK_VER3)                             
SYSPLEX:    PLEX1     SYSTEM: SY40                            
START TIME: 02/19/2017 23:22:17.837516                        
CHECK DATE: 20170123  CHECK SEVERITY: LOW                     
CHECK PARM: ZOS_RELEAS(2.2)                                   
                                                              
                                                              
HZS1201E CHECK(USERCHK,USR_ZOS_CHECK_VER3):                   
PARAMETER ZOS_RELEASE IS REQUIRED BUT WAS NOT SPECIFIED       
                                                              
HZS1001E CHECK(USERCHK,USR_ZOS_CHECK_VER3):                   
AN INSTALLATION PARAMETER ERROR WAS DETECTED.                 
                                                              
END TIME: 02/19/2017 23:22:17.839305  STATUS: PARAMETER ERROR 

Analyze: Inspect Specific Configuration Setting(s)

The primary objective of a health check routine is to gather system information and compare it with suggested, best-practice settings, and then issue appropriate messages reporting the result of the comparison. To retrieve system information, you can invoke System REXX services in your REXX check.

For example, you can invoke System REXX to inspect system control block data, and read data set content. In addition, you can use the AXRCMD function to issue a system command and inspect its output if there is no equivalent, “proper” API/Service available.

If your check is dependent upon parsing the output of a z/OS command, you should take special care to verify that the check works when there’s a new z/OS release. This is because the output and formatting of z/OS commands may change from release to release.

For example, as seen in the REXX exec mainline:

 systemRelease = Retrieve_System_Release()
 IF (systemRelease = parmRelease)
 THEN CALL Issue_CheckSuccess_Message
 ELSE CALL Issue_CheckException_Message systemRelease parmRelease

Our sample check simply looks at the content of a system control block:

 Retrieve_System_Release: 
/*   
 * FUNCTION: Retrieve and RETURN the z/OS release information from 
 *           system control blocks.
 */

  /* Get z/OS version and release from the ECVT system control block.
     See "MVS Data Areas (GA32-0935)" publication */
  CVT  = STORAGE(10,4)
  ECVT = STORAGE(D2X(C2D(CVT)+140),4)
  zOS_Version# = STRIP(STORAGE(D2X(C2D(ECVT)+512),2))
  zOS_Release# = STRIP(STORAGE(D2X(C2D(ECVT)+514),2))
  systemRelease = zOS_version#+0 || "." || zOS_release#+0

  RETURN systemRelease

Report: Present Findings

Check messages are the output of your check routine—they communicate the results uncovered by a check to the user. At a minimum, each REXX check should:

• Issue an EXCEPTION message for an “actual,” “live” setting found not to be in concordance with the setting that the check is looking for, and convey recommendations for actions that can correct the exception. Depending on what the check is designed to do, an exception message may report risks to system performance, function, availability or integrity. A check might also report dynamic changes since the last IPL that pose a potential problem, and which might make the next IPL slower or prone to errors.

 Report a “we checked <…> and all is good” success message, if the check found no exceptions. Success messages are “INFO” messages.

• Create REPORT messages that display more data that the check inspected, and what was found. This is typically used when an exception is found, but can also accompany a success message when VERBOSE or DEBUG mode is enabled.

The messages that your check issues are the most important part of your check, because they report the results found by the check. For all the check types (“locales”), there are several ways to issue check messages:

  • MSGTBL method: Create a separate message table module that defines the check output messages issued by the check routine. Using a message table makes it easier to create consistent, maintainable, and translatable messages, and allows for more advanced message formatting. When using message tables in REXX, you issue the message using REXX callable function HZSLFMSG with REQUEST type CHECKMSG and only reference the message in the message table by its ID, while the actual text and explanation for your check message is stored in, and retrieved from (by the system) your message table. Note that besides static text, the message table can also provide placeholders for data values that can be passed and inserted into the message text at runtime via the same HZSLFMSG call.
  • DIRECTMSG method: Provide message text directly from (“embedded in”) the check routine via the REQUEST type DIRECTMSG of the HZSLFMSG function.
  • HZSMSG method: Use pre-defined messages Health Checker provides via the REQUEST type HZSMSG of the HZSLFMSG function. This enables you to issue standard messages in the case of common error conditions, like parameter string syntax (“parse”) errors.

In our REXX example, we use only DIRECTMSG and HZSMSG for simplicity. The more advanced MSGTBL method will be discussed in the next article in this series.

For example, as seen in the REXX exec mainline:

systemRelease = Retrieve_System_Release()

IF (systemRelease = parmRelease)
THEN CALL Issue_CheckSuccess_Message
ELSE CALL Issue_CheckException_Message systemRelease parmRelease

Success is reported via a simple informational message:

Issue_CheckSuccess_Message:   
/*
 * FUNCTION: Report a "successful check run" to Health Checker
 */
 
  HZSLFMSG_REQUEST        = "DIRECTMSG"
  HZSLFMSG_REASON         = "CHECKINFO"
  HZSLFMSG_DIRECTMSG_ID   = "GNGH002I"
  HZSLFMSG_DIRECTMSG_TEXT = ,
    "The z/OS release found on the system matches",
    "the requested release from the check parameter."

  CALL HZSLFMSG
  IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 
  THEN CALL Issue_HZSLFSMG_DiagInfo
  
  RETURN

Which will look like this in the check’s message buffer:

CHECK(USERCHK,USR_ZOS_CHECK_VER3)                                    
SYSPLEX:    PLEX1     SYSTEM: SY40                                   
START TIME: 02/19/2017 23:03:52.555138                               
CHECK DATE: 20170123  CHECK SEVERITY: LOW                            
CHECK PARM: ZOS_RELEASE(2.2)                                         
                                                                     
                                                                     
GNGH002I The z/OS release found on the system matches the requested  
release from the check parameter.                                    
                                                                     
END TIME: 02/19/2017 23:03:52.555677  STATUS: SUCCESSFUL             

An exception usually contains more details, like an additional explanation or the system programmer response, and is often accompanied by more informational and report messages to show actual versus expected results:

Issue_CheckException_Message: PROCEDURE,
  EXPOSE HZS_HANDLE HZS_PQE_DEBUG
  ARG actualRelease parmRelease
/*
 * FUNCTION: Report that the check found an exception.
 */
 
  /* Flag an exception */
  HZSLFMSG_REQUEST        = "DIRECTMSG"
  HZSLFMSG_REASON         = "CHECKEXCEPTION"
  HZSLFMSG_DIRECTMSG_ID   = "GNGH001E"
  HZSLFMSG_DIRECTMSG_TEXT = ,
                "A not recommended z/OS release has been found."
  HZSLFMSG_DIRECTMSG.EXPL = ,
                "Running with a not recommended z/OS release",
                "can expose you to errors."
  HZSLFMSG_DIRECTMSG.SPRESP =,
                "Configure the system to the recommended z/OS release."

  CALL HZSLFMSG
  IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 
  THEN CALL Issue_HZSLFSMG_DiagInfo

 /* Show a little more detail */
  HZSLFMSG_REQUEST        = "DIRECTMSG"
  HZSLFMSG_REASON         = "CHECKINFO"
  HZSLFMSG_DIRECTMSG_ID   = "GNGH002I"
  HZSLFMSG_DIRECTMSG_TEXT = "Releases that were compared:"
  CALL HZSLFMSG
  IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 
  THEN CALL Issue_HZSLFSMG_DiagInfo

  HZSLFMSG_REQUEST        = "DIRECTMSG"
  HZSLFMSG_REASON         = "CHECKREPORT"
  HZSLFMSG_DIRECTMSG_ID   = "GNGH003R"
  HZSLFMSG_DIRECTMSG_TEXT = "Desired z/OS release: "parmRelease
  CALL HZSLFMSG
  IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 
  THEN CALL Issue_HZSLFSMG_DiagInfo

  HZSLFMSG_REQUEST        = "DIRECTMSG"
  HZSLFMSG_REASON         = "CHECKREPORT"
  HZSLFMSG_DIRECTMSG_ID   = "GNGH003R"
  HZSLFMSG_DIRECTMSG_TEXT = "Actual  z/OS release: "actualRelease
  CALL HZSLFMSG
  IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 
  THEN CALL Issue_HZSLFSMG_DiagInfo

  RETURN

And the message buffer in such an exception case would look like this:

CHECK(USERCHK,USR_ZOS_CHECK_VER3)                                      
SYSPLEX:    PLEX1     SYSTEM: SY40                                     
START TIME: 02/19/2017 23:24:49.444667                                 
CHECK DATE: 20170123  CHECK SEVERITY: LOW                              
CHECK PARM: ZOS_RELEASE(1.13)                                          
* Low Severity Exception *                                             
                                                                       
GNGH001E A not recommended z/OS release has been found.                
                                                                       
  Explanation:  Running with a not recommended z/OS release can expose
    you to errors.                                                    
                                                                       
  System Programmer Response:  Configure the system to the recommended
    z/OS release.                                          
                                                           
  Check Reason:  Ensure appropriate z/OS release level     
                                                           
GNGH002I Releases that were compared:                      
Desired z/OS release: 1.13                                 
Actual  z/OS release: 2.2            

END TIME: 02/19/2017 23:24:49.446060  STATUS: EXCEPTION-LOW

Disconnect: Final Handshake With Health Checker

At the end of the check routine, the HZSLSTOP function is invoked to indicate that the REXX check has completed running and to flush and save data used across individual check runs:

Disconnect_from_Health_Checker:  
/*
 * FUNCTION: Final handshake with the Health Checker. 
 *         This, amongst other things, flushes and saves the 
 *         HZS_PQE_CHKWORK variable, for use in future check iterations.
 */

  CALL HZSLSTOP
  IF (HZSLSTOP_RC <> 0 & HZS_PQE_DEBUG = 1) THEN
   DO
    SAY "HZSLSTOP RC"  HZSLSTOP_RC
    SAY "HZSLSTOP RSN" HZSLSTOP_RSN
    SAY "HZSLSTOP SYSTEMDIAG" HZSLSTOP_SYSTEMDIAG
   END

  RETURN

Register the Health Check

After you've written your REXX check, you need to tell Health Checker about it by registering it. One way to do this is to use the ADD CHECK statement in an HZSPRMxx parmlib member which defines the check default attributes and parameters:

  1. Create a member HZSPRMyy, where yy is some (still available) suffix of your choosing, in one of the data sets in your system’s PARMLIB concatenation
  2. Insert an ADD CHECK statement in the parmlib member. The “ADDREP = ADD REPLACE” version below is recommended to make debugging and frequent re-adding of the check easier:
ADDREP CHECK(USERCHK,USR_ZOS_CHECK_VER3)
       EXEC(ZRELCK03)
       REXXHLQ(GNG)
       REXXTSO(YES)
       REXXIN(NO)
       REXXTIMELIMIT(60)
       MSGTBL(*NONE)
       ACTIVE
       SEVERITY(LOW)
       INTERVAL(ONETIME)
       PARM('ZOS_RELEASE(2.1)')
       DATE(20170123)
       REASON('Ensure appropriate z/OS release level')

A few notes:

  • CHECK(USERCHK,USR_ ZOS_CHECK_VER3): Specifies the externally visible check name, which consists of the long owner name—up to 16 characters long (the “high-level qualifier” of a check)—and the long check name—which is up to 32 characters long.
  • EXEC(ZRELCK03): Indicates that you are defining a REXX check. It specifies the name of the REXX exec to be run as check routine. The exec must be located in a data set in the System REXX REXXLIB concatenation.
  • REXXHLQ(GNG): A required parameter for REXX checks, specifying the high level qualifier for input and output data sets to be made available to the REXX exec, in particular the REXXOUT data set when running in DEBUG mode.
  • MSGTBL(*NONE): A required parameter. It specifies the module name of the message table that will be used by the check, or, you can specify special value *NONE to indicate that the check exclusively uses DIRECTMSG.
  • PARM(‘ZOS_RELEASE(2.1)’): Specifies the check specific parameters being passed to the check at runtime. This PARM string can be up to 256 characters long and can contain zero, one or more individual parameter values. Especially when more than one value is being used, a Key(value) syntax for each is recommended. For example: PARM(‘PARM1(value1) PARM2(value2)’).

The Health Checker User’s Guide describes the complete syntax of ADD CHECK statement

3. Use the ADD PARMLIB command to let Health Checker process the new parmlib member containing the REXX check definition. For example:

11.32.13 F HZSPROC,ADD,PARMLIB=zz
11.32.13 STC02389 HZS0403I ADD PARMLIB PROCESSING HAS BEEN COMPLETED

The check definitions are now in place, and our sample check runs accordingly. It should appear, for example, on the SDSF CK ISPF panel (see Figure 1 below; click to view larger).
MF-April17-Extra1Article2-Figure1.jpg
There are multiple ways to automate the registration of the check for every time the system starts. For example:

Add the new HZSPRMxx parmlib suffix to the list of suffixes specified via the HZS= system parameter in your active IEASYSxx parmlib member:

HZS=(xx,yy,zz)

Here xx and yy are the HZSPRMxx members already in use. Update the Health Checker started procedure and add the zz suffix to the list associated with the HZSPRM procedure parameter. Note, however, that HZSPRM=PREV is the recommended value to be used in HZSPROC in z/OS V2R1 and higher. PREV refers back to the IEASYSxx HZS parameter, which otherwise would be ignored when an explicit suffix list is given in HZSPROC.

  • //HZSPROC  PROC HZSPRM='(XX,YY,ZZ)'                             
    //HZSSTEP  EXEC   PGM=HZSINIT,REGION=0K,TIME=NOLIMIT,   
    //      PARM='SET PARMLIB=&HZSPRM'                      
    //STEPLIB  DD  DSN=GNG.WORK.LOAD3,DISP=SHR              
    //HZSPDATA DD   DSN=WTSCYZ0.&SYSNAME..HZSPDATA,DISP=OLD 
    //SYSUDUMP DD SYSOUT=*                                  
    //         PEND                                         
    //         EXEC HZSPROC                                 
    
    

Testing and Debugging

For a developer of System REXX health checks, the REXXOUT feature is important for diagnosing problems. With a REXXOUT data set, you can see:

  • The result of REXX SAY statements
  • The output from a REXX TRACE
  • Messages from any TSO commands that produce uncaptured output

To enable the REXXOUT data set, the health check must be running in DEBUG mode. If the health check is not running in DEBUG mode, the data listed above is not captured anywhere.

For System REXX health checks, the REXXHLQ parameter is required so that IBM Health Checker for z/OS can allocate the REXXOUT data set using that HLQ for the data set name.

The naming convention for the REXXOUT data set is:

rexxhlq.checkname.REXXOUT[.Eentrycode]

For example, if a health check is defined like this:

REXXHLQ(GNG)
EXEC(ZRELCK03)
ENTRYCODE(1)

Then the REXXOUT data set name will be: GNG.ZRELCK03.REXXOUT.E1

If ENTRYCODE is not specified, the REXXOUT data set suffix will just be .REXXOUT.

To use the REXXOUT data set, simply set DEBUG mode ON, run the health check and browse the REXXOUT data set (don’t forget to close the browse session before running the check again). DEBUG mode can, for example, be enabled by overtyping the DEBUG column for the check on the SDSF CK panel. To get the maximum amount of available information about a problem, it is a good idea to enable VERBOSE mode at the same time. Here is an example for how to do both via a system command:

F HZSPROC,UPDATE,CHECK=(USERCHK,USR_ZOS_CHECK_VER3),DEBUG=ON,VERBOSE=YES

Note that on the UPDATE command you can also dynamically override the values specified on the ADD CHECK statement in the HZSPRMxx parmlib member, in particular the PARM string:

F HZSPROC,UPDATE,CHECK=(USERCHK,USR_ZOS_CHECK_VER3),PARM='ZOS_RELEASE(2.1)'

If you're testing changes to the REXX check, you can just use the RUN command to let the system pick up the updated exec and run it fresh (or just use the R line command on the SDSF CK in front of the check):

F HZSPROC,RUN,CHECK=(USERCHK,USR_ZOS_CHECK_VER3)

What's Next?

This article described at a high level, the steps to plan and develop your own health check, using code excerpts. The full source of the minimal, functional REXX check routine example that ties all the concepts discussed above together is provided below.

Stay tuned for the next article in this series where we will discuss some more advanced concepts pertaining to writing checks, which you may find useful in making your checks more robust, flexible and informative.

Sample REXX Health Check

/* REXX

EXEC-NAME: ZRELCK03

DESCRIPTION:

A fully functional sample health check to demonstrate the basic outline for writing your own REXX checks.

FUNCTION:

This check will compare the z/OS release information, as available in system control blocks on the current system, with the "desired"  z/OS release specified via the check's parameter (PARM) string.

 If the values do not match then a check exception is raised, otherwise an informational success message is issued.

 --------------------------------------------------------------------*/

CALL Connect_to_Health_Checker

parmRelease = Retrieve_Check_Parameter()

systemRelease = Retrieve_System_Release()

IF (systemRelease = parmRelease)

THEN CALL Issue_CheckSuccess_Message

ELSE CALL Issue_CheckException_Message systemRelease parmRelease

CALL Disconnect_from_Health_Checker

EXIT

/*-------------------------------------------------------------------*/

Connect_to_Health_Checker: 

/*

* FUNCTION: Establish handshake with Health Checker and with that

*     provide HZS_* variables. 

*     Will EXIT the exec if errors are encountered.

*/

HZSLSTRT_RC = HZSLSTRT()

IF (HZSLSTRT_RC <> 0 & HZS_PQE_DEBUG = 1) THEN

DO

SAY "HZSLSTRT RC" HZSLSTRT_RC

SAY "HZSLSTRT RSN" HZSLSTRT_RSN

SAY "HZSLSTRT SYSTEMDIAG" HZSLSTRT_SYSTEMDIAG

EXIT /* ...because without HZSLSTART the check will not be able to communicate with Health Checker */

END

RETURN

/*-------------------------------------------------------------------*/

Retrieve_Check_Parameter: 

/* 

* FUNCTION: Validate and parse the check's PARM string for the 

*     "desired" z/OS release, 

*     -or- 

*     if PARM is unchanged from the previous check run, 

*     just return the previously parsed and saved value. 

* RETURNS: On success, the desired z/OS release in format "v.r".

*    On error: (1) report a BAD PARM error to Health Checker

*         (2) disable the check

*         (3) disconnect from Health Checker

*         (4) EXIT the exec right here and do not return

*/

/* Try to re-use previously parsed value */

IF (HZS_PQE_LOOKATPARMS = 0) 

THEN parmRelease = HZS_PQE_CHKWORK

ELSE /* Need to (re-) parse current PARM string */ 

DO

/* Expected PARM string format is PARM('ZOS_RELEASE(v.r)') */

PARSE UPPER VAR HZS_PQE_PARMAREA parmName "(" zVer "." zRel ")"

IF (parmName <> "ZOS_RELEASE") THEN

DO

/* Issue "HZS1201E parm IS REQUIRED BUT WAS NOT SPECIFIED" */

HZSLFMSG_Request = "HZSMSG"

HZSLFMSG_Reason = "PARS1201"

HZSLFMSG_insert.0 = 1

HZSLFMSG_insert.1 = "ZOS_RELEASE"

CALL HZSLFMSG

IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 

THEN CALL Issue_HZSLFSMG_DiagInfo

/* STOP the check with a BADPARM state */

HZSLFMSG_REQUEST = "STOP"

HZSLFMSG_REASON = "BADPARM"

CALL HZSLFMSG

IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 

THEN CALL Issue_HZSLFSMG_DiagInfo /* EXIT: SYSPROG needs to fix PARM string first before we can do anything */

CALL Disconnect_from_Health_Checker

EXIT

END /* parm not ZOS_RELEASE */

ELSE 

DO

parmRelease = SPACE(zVer "." zRel,0)

HZS_PQE_CHKWORK = parmRelease

END

END /* need to (re-) parse PARM string */ 

RETURN parmRelease

/*-------------------------------------------------------------------*/

Retrieve_System_Release: 

/*  

* FUNCTION: Retrieve and RETURN the z/OS release information from 

*     system control blocks.

*/

/* Get z/OS version and release from the ECVT system control block.

See "MVS Data Areas (GA32-0935)" publication */

CVT = STORAGE(10,4)

ECVT = STORAGE(D2X(C2D(CVT)+140),4)

zOS_Version# = STRIP(STORAGE(D2X(C2D(ECVT)+512),2))

zOS_Release# = STRIP(STORAGE(D2X(C2D(ECVT)+514),2))

systemRelease = zOS_version#+0 || "." || zOS_release#+0

RETURN systemRelease

/*-------------------------------------------------------------------*/

Issue_CheckSuccess_Message:  

/*

* FUNCTION: Report a "successful check run" to Health Checker

*/ 

HZSLFMSG_REQUEST    = "DIRECTMSG"

HZSLFMSG_REASON    = "CHECKINFO"

HZSLFMSG_DIRECTMSG_ID = "GNGH002I"

HZSLFMSG_DIRECTMSG_TEXT = ,

"The z/OS release found on the system matches", "the requested release from the check parameter."

CALL HZSLFMSG

IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 

THEN CALL Issue_HZSLFSMG_DiagInfo  

RETURN

/*-------------------------------------------------------------------*/

Issue_CheckException_Message: PROCEDURE,

EXPOSE HZS_HANDLE HZS_PQE_DEBUG

ARG actualRelease parmRelease

/*

* FUNCTION: Report that the check found an exception.

*/ 

/* Flag an exception */

HZSLFMSG_REQUEST    = "DIRECTMSG"

HZSLFMSG_REASON    = "CHECKEXCEPTION"

HZSLFMSG_DIRECTMSG_ID = "GNGH001E"

HZSLFMSG_DIRECTMSG_TEXT = ,

        "A not recommended z/OS release has been found."

HZSLFMSG_DIRECTMSG.EXPL = ,

        "Running with a not recommended z/OS release", "can expose you to errors."

HZSLFMSG_DIRECTMSG.SPRESP =,

        "Configure the system to the recommended z/OS release."

CALL HZSLFMSG

IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 

THEN CALL Issue_HZSLFSMG_DiagInfo

/* Show a little more detail */

HZSLFMSG_REQUEST    = "DIRECTMSG"

HZSLFMSG_REASON    = "CHECKINFO"

HZSLFMSG_DIRECTMSG_ID = "GNGH002I"

HZSLFMSG_DIRECTMSG_TEXT = "Releases that were compared:"

CALL HZSLFMSG

IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 

THEN CALL Issue_HZSLFSMG_DiagInfo

HZSLFMSG_REQUEST    = "DIRECTMSG"

HZSLFMSG_REASON    = "CHECKREPORT"

HZSLFMSG_DIRECTMSG_ID = "GNGH003R"

HZSLFMSG_DIRECTMSG_TEXT = "Desired z/OS release: "parmRelease

CALL HZSLFMSG

IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 

THEN CALL Issue_HZSLFSMG_DiagInfo

HZSLFMSG_REQUEST    = "DIRECTMSG"

HZSLFMSG_REASON    = "CHECKREPORT"

HZSLFMSG_DIRECTMSG_ID = "GNGH003R"

HZSLFMSG_DIRECTMSG_TEXT = "Actual z/OS release: "actualRelease

CALL HZSLFMSG

IF (HZSLFMSG_RC <> 0 & HZS_PQE_DEBUG = 1) 

THEN CALL Issue_HZSLFSMG_DiagInfo

RETURN

/*-------------------------------------------------------------------*/

Disconnect_from_Health_Checker: 

/*

* FUNCTION: Final handshake with the Health Checker. 

*    This, amongst other things, flushes and saves the 

*    HZS_PQE_CHKWORK variable, for use in future check iterations.

*/

CALL HZSLSTOP

IF (HZSLSTOP_RC <> 0 & HZS_PQE_DEBUG = 1) THEN

DO

SAY "HZSLSTOP RC" HZSLSTOP_RC

SAY "HZSLSTOP RSN" HZSLSTOP_RSN

SAY "HZSLSTOP SYSTEMDIAG" HZSLSTOP_SYSTEMDIAG

END

RETURN

/*-------------------------------------------------------------------*/

Issue_HZSLFSMG_DiagInfo: 

/*

* FUNCTION: Provide some diagnostic information about the last HZSLFMSG

*     call in the REXXOUT dataset (assuming that DEBUG is ON).

*/ 

SAY "HZSLFMSG RC     = " HZSLFMSG_RC

SAY "HZSLFMSG RSN    = " HZSLFMSG_RSN

SAY "HZSLFMSG SYSTEMDIAG = " HZSLFMSG_SYSTEMDIAG

SAY "HZSLFMSG USERRSN  = " HZSLFMSG_USERRSN

SAY "HZSLFMSG ABENDRESULT = " HZSLFMSG_ABENDRESULT

 RETURN

IBM Systems Webinar Icon

View upcoming and on-demand (IBM Z, IBM i, AIX, Power Systems) webinars.
Register now →