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
SELECT JCLPREPA
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.