• principal_3

    Desde 2015, enseñando sobre el sistema operativo z/OS de IBM en esta web. z/OS se utiliza en máquinas llamadas Mainframe.

  • principal_1

    Para realizar el contenido, utilizo el producto de IBM llamado z/Development and Test Environtment Personal Edition. Este software permite emular un Mainframe y así poder utilizar z/OS para aprender.

  • principal_2

    Es utilizado por grandes empresas (bancos, aseguradoras...). Aquí aprenderás a instalar y configurar productos relacionados con z/OS.

  • principal_4

    ADCD es una distribución de z/OS que contiene productos de IBM como IMS, DB2, CICS, ZOWE, TWS, NetView, System Automation, etc.

Comprobando variables OPC en JCL sin submitirlo y sin modificar paneles

En OPC (TWS), para poder comprobar si las variables de OPC de un JCL son correctas, hay que submitirlo con algún error de sintaxis (para no ejecutar algo de forma indebida) y comprobar si falla por OJCV. En esta ocasión vamos a añadir una nueva opción a OPC que consiste en poder comprobar si las variables de OPC de un JCL son correctas sin tener que submitir ese JCL.

Esta nueva opción va a tener dos versiones, la primera que consiste en dar un comando para ejecutar un REXX y la segunda que consiste en ejecutar otro REXX, pero mediante una opción nueva en un panel. La segunda versión la veremos en otra entrada. 

Esta nueva opción está compuesta por dos programas REXX y un JCL que será un procedimiento catalogado. El primero de esos REXX lo ejecutaremos mediante un comando y se encargará de capturar todos los datos de la pantalla en la que nos encontramos, quedándose con aquellos que necesitamos. Después llamará al segundo programa REXX. El segundo programa tratará esos datos que ha recibido y ejecutará un JCL que llamará al procedimiento catalogado. Este procedimiento ejecuta el programa EQQYCAIN de TWS con los datos obtenidos de los REXX anteriores. Se resuelven las variables de usuario de OPC y también tiene en cuenta las variables que vienen por defecto en OPC.

Si termina con RC=2 es porque todas las variables del JCL son correctas. Si termina con RC=8 es que hay alguna variable que no puede resolver.

En estas páginas de IBM hay más información sobre las opciones que usamos en el procedimiento que hemos creado.

Input to batch command interface

http://www.ibm.com/support/knowledgecenter/SSGSPN_8.6.0/com.ibm.tivoli.itws.doc_8.6/eqqn1mst155.htm#xf45ad

SELECT JCLPREPA

http://www.ibm.com/support/knowledgecenter/SSGSPN_8.6.0/com.ibm.tivoli.itws.doc_8.6/eqqn1mst169.htm#wq817

NOTA: Como este proceso coge datos de la pantalla, es importante tener la emulación configurada con 32x80 líneas, como mínimo.

 

Este primer paso es opcional, pero ayuda bastante. Consiste en modificar uno de los mensajes de error de OPC para que salga por la consola y así poder capturarlo del SYSLOG y guardarlo en un dataset. Si no lo hacemos, tendremos que ir a buscarlo a librería EQQMLOG que tengamos deficida en el controller de OPC.

Para modificarlo, vamos a la librería de mensajes de OPC, en mi caso, TWS860.SEQQMSG0.

 

Editamos el miembro EQQJ53, que contiene el mensaje EQQJ535E y es el que queremos que salga por consola y que se grabe en el LOG del sistema.

 

Buscamos “EQQJ535” y le añadimos “WTO=YES” de la siguiente forma:

EQQJ535 ' ' LINES=1 WTO=YES                    

'E UNDEFINED VARIABLE &VAR LINE &LINE OF &SCTN'

 

Ahora hay que guardar el siguiente procedimiento en una librería. Yo me he creado una nueva particionada en mis librerías de OPC. En mi caso la he llamado OPC.OP1C.UTIL.

Dentro de esa librería, hay que crear el miembro CVARPROC que contendrá el siguiente procedimiento. Este procedimiento crea unos ficheros de salida que son:

XXXXXX.CHECKVAR.EQQMLOG

XXXXXX.CHECKVAR.SYSPRINT

Siendo XXXXXX el usuario que lo ha ejecutado, en mí caso, IBMUSER. Luego revisaremos esos ficheros para saber el JCL está correcto o no.

NOTA: Si no hemos hecho el primer paso opcional, hay que comentar/quitar los pasos que hay dentro del IF (IF1      IF PASOCHEK.RC = 8 THEN…) porque son los que buscan el mensaje en el log.

 

//CVARPROC  PROC

//*

//*   BORRAMOS LOS FICHEROS QUE CONTENDRAN LOS RESULTADOS DE LA

//*   EJECUCION DEL PROCEDIMIENTO

//*

//BORRADTS  EXEC PGM=IEFBR14

//SYSPRINT DD SYSOUT=*

//DDNAME   DD DSN=&SYSUID..CHECKVAR.EQQMLOG,DISP=(MOD,DELETE,DELETE),

//            UNIT=SYSDA,SPACE=(CYL,(0))

//         DD DSN=&SYSUID..CHECKVAR.SYSPRINT,DISP=(MOD,DELETE,DELETE),

//             UNIT=SYSDA,SPACE=(CYL,(0))

//*

//*   CREAMOS LOS FICHEROS QUE CONTENDRAN LOS RESULTADOS DE LA

//*   EJECUCION DEL PROCEDIMIENTO

//*

//CREADTS  EXEC PGM=IEFBR14

//SYSPRINT DD SYSOUT=*

//DDNAME   DD DSN=&SYSUID..CHECKVAR.EQQMLOG,

//            DISP=(NEW,CATLG),DCB=(RECFM=VBA,LRECL=125,BLKSIZE=3120),

//            UNIT=SYSDA,SPACE=(CYL,(1,1),RLSE)

//         DD DSN=&SYSUID..CHECKVAR.SYSPRINT,

//            DISP=(NEW,CATLG),DCB=(RECFM=VBA,LRECL=125,BLKSIZE=3120),

//            UNIT=SYSDA,SPACE=(CYL,(1,1),RLSE)

//*

//* EJECUTAMOS EL PROGRAMA EQQYCAIN DE TWS PASANDOLE LOS DATOS DE LA

//* SYSIN QUE HEMOS GRABADO ANTERIORMENTE PARA QUE COMPRUEBE LA

//* VARIABLE.

//* ESTE PASO TERMINA CON RC=8 SI ALGUNA VARIABLE NO SE PUEDE RESOLVER

//* REVISAREMOS EL FICHERO &SYSUID..CHECKVAR.EQQMLOG

//* SI TERMINA CON RC=2, EL FICHERO &SYSUID..CHECKVAR.SYSPRINT TENDRA

//* DATOS, PERO EL OTRO ESTARA VACIO.

//* EN PARM HAY QUE PONER EL NOMBRE DEL CONTROLLER DE OPC

//*

//PASOCHEK EXEC PGM=EQQYCAIN,COND=(4,LT),REGION=4096K,PARM=OP1C

//STEPLIB  DD DISP=SHR,DSN=TWS860.SEQQLMD0

//EQQMLIB  DD DISP=SHR,DSN=TWS860.SEQQMSG0

//*EQQYPARM DD DISP=SHR,DSN=PROD.INST.PARMLIB(YPARM)

//BATCHL   DD SYSOUT=*

//OI       DD SYSOUT=*

//AD       DD SYSOUT=*

//CPOC     DD SYSOUT=*

//CPOP     DD SYSOUT=*

//CPCOND   DD SYSOUT=*

//DATAFI   DD SYSOUT=*

//EXPORTAD DD SYSOUT=*

//EXPORTOI DD SYSOUT=*

//ERREUR   DD SYSOUT=*

//EQQMLOG  DD DSN=&SYSUID..CHECKVAR.EQQMLOG,DISP=OLD

//*EQQMLOG  DD SYSOUT=*

//EQQDUMP  DD SYSOUT=*

//SYSPRINT DD DSN=&SYSUID..CHECKVAR.SYSPRINT,DISP=OLD

//*SYSPRINT DD SYSOUT=*

//SYSUDUMP DD SYSOUT=*

//SYSOUT   DD SYSOUT=*

//SYSIN    DD DSN=&SYSUID..CHECKVAR.VARSYSIN,DISP=OLD

//*

//*  SI EL PASO PASOCHEK HA TERMINADO CON 8 ES PORQUE EL JCL CONTIENE

//*  ALGUNA VARIABLE QUE NO PUEDE RESOLVERSE.

//*  EN LOS SIGUIENTES PASOS, RECUPERAMOS EL MENSAJE DEL LOG QUE INDICA

//*  LA VARIABLE QUE NO EXISTE Y LO GUARDAMOS EN EL FICHERO

//*  &SYSUID..CHECKVAR.EQQMLOG

//*

//IF1      IF PASOCHEK.RC = 8 THEN

//*

//* EL SIGUIENTE PASO ACCEDE AL LOG Y RECUPERA EL MENSAJE DE ERROR.

//* ES POSIBLE QUE ESTE PASO FALLE POR FALTA DE PERMISOS.

//*

//STEP02  EXEC PGM=SDSF,PARM='++30,256'

//ISFOUT   DD SYSOUT=*

//SYSUDUMP DD SYSOUT=*

//SYSPRINT DD SYSOUT=*

//SYSTSPRT DD SYSOUT=*

//SYSOUT   DD SYSOUT=*

//DATAOUT  DD DSN=&SYSUID..CHECKVAR.DATAOUT,SPACE=(CYL,(1,1),RLSE),

//            DISP=(,CATLG,DELETE),UNIT=SYSDA,

//            DCB=(RECFM=VBA,LRECL=125,BLKSIZE=3120)

//ISFIN    DD *

LOG

FIND EQQJ53 LAST

PRINT FILE DATAOUT

PRINT * 1

PRINT CLOSE

END

/*

//*

//* COGEMOS EL FICHERO QUE CONTIENE EL MENSAJE QUE HEMOS RECUPERADO

//* DEL LOG, LE QUITAMOS EL PRINCIPIO Y LO GUARDAMOS EN EL FICHERO

//* &SYSUID..CHECKVAR.EQQMLOG

//*

//SORT001 EXEC PGM=SORT,PARM=('DYNALLOC=(SYSALLDA,32)')

//SORTIN   DD DSN=&SYSUID..CHECKVAR.DATAOUT,DISP=SHR

//SORTOUT  DD DSN=&SYSUID..CHECKVAR.EQQMLOG,DISP=MOD

//SYSOUT   DD SYSOUT=*

//SYSPRINT DD SYSOUT=*

//SYSIN    DD *

 SORT FIELDS=COPY

 OUTREC FIELDS=(1,4,23,96)

/*

//*

//* BORRAMOS EL FICHEROS DE TABAJO

//*

//BDATAOUT EXEC PGM=IEFBR14

//DD01     DD DSN=&SYSUID..CHECKVAR.DATAOUT,SPACE=(CYL,(0)),

//            DISP=(MOD,DELETE)

//        ENDIF

 

 

 

Ahora vamos a copiar los dos REXX que completan esta nueva opción que estamos añadiendo. Debemos copiarlos en una librería dónde podamos ejecutarlos. Para saber que librería debemos usar, debemos mirar nuestro procedimiento de logon de ISPF y mirar las librerías que están en la DD SYSPROC.

Una forma rápida de hacerlo es ir a SDSF, entrar en ST y buscar nuestro usuario. Entramos con una S y vemos las librerías que aparecen en la DD SYSPROC.

 

NOTA: Podemos saber las librerías que tenemos alocadas con nuestro usuario usando el comando “TSO LISTALC” desde un panel de ISPF.

En mi caso voy a usar la librería ADCD.Z113.CLIST. Creamos un nuevo miembro con el nombre CHEKVAR1 dentro de esta librería y copiamos el siguiente código:

/* REXX */

/*                                                            */

/* ESTE REXX RECOGE LOS DATOS PASADOS POR EL REXX "CHECKVAR"  */

/* Y EJECUTA UN JCL QUE LLAMA AL PROCEDIMIETO CVARPROC PARA   */

/* COMPROBAR LAS VARIABLES DEL JCL DE OPC                     */

/*                                                            */

PARSE ARG APPID ' ' OPERNUM ' ' DINPUT ' ' TINPUT

/*                                                            */

/* CAMBIAMOS EL FORMATO DE LA FECHA DE YY/MM/DD A YYMMDD      */

/* CAMBIAMOS EL FORMATO DE LA HORA DE HH:MM A HHMM            */

/*                                                            */

DINPUT = TRANSLATE('124578', DINPUT, '12345678')

TINPUT = TRANSLATE('1245', TINPUT, '12345')

/*                                                            */

/* INPUT ARRIVAL EN FORMATO YYMMDDHHMM                        */

/*                                                            */

IARRIVAL=DINPUT||TINPUT

/*                                                            */

/* COMPROBAMOS SI EXISTE EL FICHERO QUE CONTENDRA LA SYSIN    */

/* PARA EL PROCEDIMIETO SI NO EXISTE, LO CREAMOS              */

/*                                                            */

LIBRERIA=SYSDSN(USERID().CHECKVAR.VARSYSIN)

IF LIBRERIA /= "OK" THEN

 DO

  "ALLOCATE F(FICH) DA("USERID()".CHECKVAR.VARSYSIN) NEW DIR(0) REUSE

  DSORG(PS) BLOCK(3200) SPACE(1,1) RECFM(F,B) LRECL(80) BLKSIZE(3120)"

  "FREE F(FICH)"

 END

/*                                                            */

/* ESCRIBIMOS EN LA COLA LOS DATOS QUE CONTENDRA LA SYSIN     */

/* USERID().CHECKVAR.VARSYSIN Y QUE SERA USADA POR EL         */

/* PROCEDIMIENTO CVARPROC                                     */

/*                                                            */

QUEUE "ACTION=SELECT,RESOURCE=JCLPREPA,ADID="||APPID||","

QUEUE "                                IA="||IARRIVAL||","

QUEUE "                                OPNO="||OPERNUM||";"

"ALLOC OLD REU F(OUT) DA('"USERID()".CHECKVAR.VARSYSIN')"

"EXECIO "QUEUED()" DISKW OUT (FINIS"

"FREE F(OUT)"

/*                                                            */

/* ESCRIBIMOS EN LA COLA Y SUBMITIMOS UN JCL QUE LLAMA AL     */

/* PROCEDIMIENTO CVARPROC.                                    */

/* ESTE PROCEDIMIENTO LO HE GUARDADO EN OPC.OP1C.UTIL         */

/* SI SE GUARDA EN OTRA LIBRERIA HAY QUE CAMBIAR LA JCLLIB    */

/*                                                            */

QUEUE "//CHECKVAR JOB (9999),'OPC CHECKVAR',CLASS=A,MSGCLASS=Q,"

QUEUE "// MSGLEVEL=(1,1),REGION=0M,NOTIFY=&SYSUID"

QUEUE "//JCLLIB1 JCLLIB ORDER=OPC.OP1C.UTIL"

QUEUE "//PASO000 EXEC PROC=CVARPROC"

"ALLOC F(JCL) SYSOUT WRITER(INTRDR)"

"EXECIO" QUEUED() "DISKW JCL (FINIS"

"FREE F(JCL)"

EXIT

 

 

Por último, creamos un nuevo miembro con el nombre CHECKVAR dentro de la librería anterior, en mi caso ADCD.Z113.CLIST, y copiamos el siguiente código. Este será el REXX que ejecutemos desde los paneles de OPC.

 /* REXX */

/*                                                            */

/* ESTE REXX SE EJECUTA DESDE LOS SIGUIENTES PANELES DE OPC:  */

/*  EQQMMODP - MODIFYING AN OPERATION IN THE CURRENT PLAN     */

/*  EQQSOPSP - SELECTING APPLICATION OCCURRENCE AND           */

/*             OPERATION INFORMATION                          */

/* SE DEBE HACER CON EL COMANDO "TSO CHECKVAR"                */

/*                                                            */

ADDRESS TSO

"PROFILE NOPREFIX"

/*                                                            */

/* CREAMOS UN DATASET PARA CAPTURAR EL PANEL ACTUAL           */

/*                                                            */

"ALLOCATE DATASET("USERID()".CHECKVAR.PANEL) NEW DIR(0) REUSE

DSORG(PS) BLOCK(3200) SPACE(1,1) RECFM(V,B) LRECL(240) BLKSIZE(3120)"

/*                                                            */

/* LIBERAMOS EL DATASET                                       */

/*                                                            */

"FREE DA("USERID()".CHECKVAR.PANEL)"

/*                                                            */

/* COGEMOS EL NOMBRE DEL PANEL ACTUAL, LOS DATOS QUE CONTIENE */

/* Y LAS DIMENSIONES                                          */

/*                                                            */

"ISPEXEC VGET (ZPANELID)"

"ISPEXEC VGET (ZSCREENI ZSCREENW ZSCREEND)"

SW = ZSCREENW

SD = ZSCREEND

SL = ZSCREEND * ZSCREENW

/*                                                            */

/* COPIAMOS LOS DATOS DEL PANEL A LA COLA                     */

/*                                                            */

DO I = 1 TO SL

  QUEUE SUBSTR(ZSCREENI,I,SW)

  I = I+79

END

/*                                                            */

/* GUARDAMOS LOS DATOS DE LA COLA EN UN DATASET               */

/*                                                            */

"ALLOC OLD REU F(CAPTURE) DA('"USERID()".CHECKVAR.PANEL')"

"EXECIO" QUEUED() " DISKW CAPTURE (FINIS)"

"FREE F(CAPTURE)"

/*                                                            */

/* GUARDAMOS EN UNA VARIABLE LOS DATOS DEL DATASET            */

/*                                                            */

"ALLOC FI(INDD) DA('"USERID()".CHECKVAR.PANEL') SHR REUSE"

"EXECIO * DISKR INDD (STEM LINES. FINIS"

"FREE F(INDD)"

/*                                                            */

/* RECORREMOS LA VARIABLE QUE CONTIENE CADA LINEA DEL PANEL   */

/*                                                            */

DO K = 1 TO LINES.0

  /*  SAY LINES.K   */

 

/*                                                            */

/* SI ENCONTRAMOS LA LINEA APPLICATION, GUARDAMOS EL NOMBRE   */

/* LA APLICACION                                              */

/*                                                            */

  IF INDEX(LINES.K,'Application') > 0 THEN

      APPID = STRIP(SUBWORD(LINES.K,3,1))

/*                                                            */

/* COGEMOS EL NUMERO DE OPERACION                             */

/*                                                            */

  IF INDEX(LINES.K,'Operation') > 0 THEN

      OPER = STRIP(SUBWORD(LINES.K,4,1))

 

  IF INDEX(LINES.K,'nput arrival') > 0 THEN

    DO

/*                                                            */

/*  COMPROBAMOS SI ESTAMOS EN EL PANEL EQQSOPSP, PARA COGER   */

/*  LOS DATOS DE FECHA Y HORA CORRECTAMENTE                   */

/*                                                            */

      IF ZPANELID = 'EQQSOPSP' THEN

        DO

          FECHA = STRIP(SUBWORD(LINES.K,5,1))

          HORA  = STRIP(SUBWORD(LINES.K,6,1))

        END

      ELSE

        DO

          FECHA = STRIP(SUBWORD(LINES.K,4,1))

          HORA  = STRIP(SUBWORD(LINES.K,5,1))

        END

    END

END

/*                                                            */

/* BORRAMOS EL DATASET DEL PANEL YA QUE NO HACE FALTA         */

/*                                                            */

"DELETE "USERID()".CHECKVAR.PANEL SCRATCH NONVSAM"

/*                                                            */

/* MOSTRAMOS LOS DATOS QUE HEMOS OBTENIDO Y LLAMAMOS AL REXX  */

/* QUE EJECUTA UN JCL CON LOS DATOS QUE HEMOS OBTENIDO        */

/*                                                            */

/* IMPORTANTE: SE DEBE PONER LA LIBRERIA QUE TENGA ESE REXX   */

/*                                                            */

SAY "SE HAN CAPTURADO LOS SIGUIENTES DATOS:"

SAY "APPID "||APPID||" OPER "||OPER||" FECHA "||FECHA||" HORA "||HORA

"EXEC ADCD.Z113.CLIST(CHEKVAR1) '"APPID" "OPER" "FECHA" "HORA"'"

EXIT

 


 

Una vez copiado todo, vamos a ver cómo funciona. Entramos a OPC y vamos a la opción 5.2 ó 5.4 ya que funciona en ambas, pero es fundamental que estemos dentro de los siguientes paneles para que funcione:

  • EQQMMODP - MODIFYING AN OPERATION IN THE CURRENT PLAN
  • EQQSOPSP - SELECTING APPLICATION OCCURRENCE AND OPERATION INFORMATION

 

 

Elegimos cualquier operación y entramos con i. También podemos entrar con MOD (más adelante hay un ejemplo).

 

Desde ese panel es donde debemos dar el comando “TSO CHECKVAR” ya que coge todos los datos necesarios de ahí.

NOTA: La sesión debe de ser de 32x80 líneas, como mínimo.

 

Vemos que se muestran los datos que se han cogido del panel.

 

Se submitirá un JCL llamado “CHECKVAR” y cuando termine nos aparecerá un mensaje con el resultado, ya que está codificado el NOTIFY.

Nos fijamos que ha terminado con RC=08 porque hay alguna variable que no ha podido resolver. En este caso, debemos revisar el fichero XXXXXX.CHECKVAR.EQQMLOG, ya que el fichero XXXXXX.CHECKVAR.SYSPRINT no tendrá datos.

 

En mi caso, voy a revisar el fichero IBMUSER.CHECKVAR.EQQMLOG.

 

El segundo mensaje que indica la variable que no está definida, es el mensaje que hemos capturado del SYSLOG. Podemos ver el mensaje completo pulsando F11. Si no hemos hecho el primero paso opcional, solo saldrá la primera línea.

 

Podemos comprobar que el dataset XXXXX.CHECKVAR.SYSPRINT no tiene datos.

 

Ahora vamos a probarlo entrando con MOD.

NOTA: Esto funciona entrando desde la opción 5.2 ó 5.4 siempre que estemos en los paneles que se han indicado más arriba.

 

Entramos en OPER.

 

Elegimos la operación que queremos comprobar.

 

Una vez en el panel de la imagen. ejecutamos el comando “TSO CHECKVAR”.

 

En este caso ha terminado con RC=02 porque ha podido resolver todas las variables que tenía el JCL.

 

Ahora revisaremos el fichero XXXXXX.CHECKVAR.SYSPRINT ya que será el que tenga datos.

 

Veremos detalles sobre la operación y el JCL. Las variables &CDD y &CDDD vienen predefinidas en OPC y la otra variable ha sido resuelta con el dato “890326”.

 

Aquí vemos el JCL original con las variables sin resolver.

 

Comprobamos que el fichero XXXXXX.CHECKVAR.EQQMLOG no tiene datos porque las variables son correctas.

 

De forma opcional, se puede mirar en el SDSF la salida "CHECKVAR" que deja este proceso.

En la próxima entrada, incorporaremos esta misma opción, pero, en vez de usar el comando "TSO CHECKVAR", incluiremos una opción nueva en los dos paneles.

 

Publish modules to the "offcanvs" position.