<<

SUGI 29 Posters

Paper 168-29

Swimming through and tapping out a CA-7 Mainframe Scheduler on a Server David Steves and Denise Figliozzi SunTrust Bank, Atlanta, Georgia

Abstract In a large organization, security concerns often preclude CA7 mainframe scheduler tools from being available to SAS developers. New and inventive ways must be discovered to submit mainframe (MVS) jobs on a reliable basis. One method involves the invocation of a UNIX Cron Job and SAS Connect logic.

The combination of using the CRON feature on the UNIX server with the many SAS features has made this a very reliable and successful technique. This paper will review how to create a CRON job and configure a mainframe job with JCL to enable the program to emulate a CA7 scheduler. To illustrate how mainframe jobs are submitted concurrently, (or independently contingent on availability on the mainframe), we will look SAS production code.

Introduction In a financial company, we are sometimes forced to invent processes that us circumvent misguided company policies. Sometimes during financial reporting periods programmers are not able to schedule jobs in production through CA7.

If a programmer wants to submit a SAS job at 3:00 a.m., he would have to physically logon to the mainframe and manually submit the program. The process below will illustrate an easy alternative for scheduling. This process will only work if the userid has RACF access to mainframe files. We will illustrate some easy concepts in the UNIX environment that, in combination with other SAS Connect logic, allow us to submit programs.

What is CRON? In the UNIX world, CRON is a tried and true scheduler for running UNIX scripts. This crontab file represents the (of day) a job will execute. The crontab file will always be located on the root drive. To utilize the CRON feature, we must add/edit entries into a crontab. SUGI 29 Posters

Paper 168-29

CRON job set up in UNIX Step 1: UNIX Command: /var/spool/cron/crontabs

Step 2: Edit root file (crontabs)

The structure of the file will be in 6 parts:

Column 1: minute Column 2: hour Column 3: day of month Column 4: month of year Column 5: day of week Column 6: command

• All columns must be populated with an asterisk (*) if null • Military time is used • Day of the week translates to: Sunday=0 through Saturday=6 • User may need administrator privileges to edit this file . Step 3: Start and restart the CRON for the new settings to be captured.

To stop CRON: -ef | cron (will show you the process id for root file) - 9 process id (kills the process id for root file) /etc/cron.d/FIFO (this will erase the lock file)

To start CRON: /usr/sbin/cron & (restarts the CRON with new settings)

Example of crontab

# 0 4 * * 1,2,3,4,5 /gs/dailyagent.run 30 4 * * 1,2,3,4,5 /gs/dailyagent.run 0 5 * * 1,2,3,4,5 /gs/dailyagent.run 30 5 * * 1,2,3,4,5 /gs/dailyagent.run 00 6 * * 1,2,3,4,5 /gs/dailyagent.run 30 6 * * 1,2,3,4,5 /gs/dailyagent.run 00 7 * * 1,2,3,4,5 /gs/dailyagent.run SUGI 29 Posters

Paper 168-29

15 7 * * 1,2,3,4,5 /gs/dailyagent.run 30 7 * * 1,2,3,4,5 /gs/dailyagent.run 45 7 * * 1,2,3,4,5 /gs/dailyagent.run 00 8 * * 1,2,3,4,5 /gs/dailyagent.run 15 8 * * 1,2,3,4,5 /gs/dailyagent.run 30 8 * * 1,2,3,4,5 /gs/dailyagent.run 45 8 * * 1,2,3,4,5 /gs/dailyagent.run 00 9 * * 1,2,3,4,5 /gs/dailyagent.run 15 9 * * 1,2,3,4,5 /gs/dailyagent.run 30 9 * * 1,2,3,4,5 /gs/dailyagent.run 45 9 * * 1,2,3,4,5 /gs/dailyagt3.run 00 11 * * 1,2,3,4,5 /gs/dailyagt4.run

• Note that dailyagent.run commences every ½ hour from 4:00 a.m. until 7:00 a.m. After 7:00 a.m., dailyagent.run executes in 15 minute intervals and finishes at 9:30 a.m.

Analyzing the dailyagent.run program Essentially, a script examines a flag file and if no flag file exists then the UNIX script submits a mainframe job through a SASTSO connect script. Once the mainframe job has completed, a flag file is FTP’d back to the UNIX box. As the CRON cycle continues, a job starts again in 30 minutes and spawns the necessary code to re-submit a particular mainframe job as needed.

Sample Code of UNIX script:

#! /bin/ksh # dailyagent.run # ------; # Started 11/02/2001 by david steves ; # # Sas Portion: # ------

> dailyagent.sas << EOT

*********************************************************************** *** The next few lines validate the existence of a file *** *************************************************************

%let thefile4='/transfer/pingcomp.txt';

SUGI 29 Posters

Paper 168-29

filename testit4 pipe "if [ ! -f &thefile4 ]; then 'no'; else echo ''; fi";

data _null_; infile testit4 pad missover lrecl=3; input answer $3.; put answer=; call symput('exists',answer); run;

*********************************************************************** *** If the file exists, then validate if the file contains data. *** ***********************************************************************

%macro exist; %if &exists =yes %then %do; filename telldt4 '/transfer/pingcomp.txt'; data trndate4; infile telldt4 obs=1; input @1 result $1. @3 rundate mmddyy10.; run;

data _null_; if 0 then set trndate4 nobs=nobs; put nobs=; call symput('numcnt',left(put(nobs,8.))); run;

*********************************************************************** * Check and evaluate the data date. Create a flag that will indicate *** * whether or not to proceed with the mainframe submission . **** *************************************************************

%if &numcnt>0 %then %do; (will fall down this path if there is some of file) data trndate4; infile telldt4 obs=1; input @1 result $1. @3 rundate mmddyy10.; if result in ('Y') and rundate =today() then do; theresult = 2; put theresult =; call symput('results',left(put(theresult,8.)));

end; else do; SUGI 29 Posters

Paper 168-29

theresult = 1; put theresult =; call symput('results',left(put(theresult,8.))); end; run;

%end; %else %do; (will fall down this path if file exists and the flag indicates that the file is not valid or null) data _null_; theresult3 = 1; put theresult3=; call symput('results',left(put(theresult3,8.))); run;

%end; %end;

%else %if &exists =no %then %do; (will fall down this path if no file exists)

data _null_; theresult2 = 1; put tres2=; call symput('results',left(put(theresult2,8.))); run; %end;

%mend exist; %exist;

*********************************************************************** *If the flag file indicates that we need a different file, then we submit ** *** the mainframe code to get a new file. **** ************************************************************* %macro results4; %if &res4=2 %then %do; (will fall through this code if the file is useable) data skippy1; dt = ‘file already exists and is current'; run;

%end; SUGI 29 Posters

Paper 168-29

%else %do; (will fall through this code if the file is not valid )

************************************************************************ **** This code uses a SAS script to log onto the mainframe system *******

filename netrc '/export/home/sugiuser/.netrc';

data testnet; infile netrc obs=1; input @38 t2 $8.; t3 = "'"||t2||"'"; call symput('',t3); run;

filename rlink '/gs/sastso2.scr'; %let mvsga=1x.x9.xxx.x2; options comamid=tcp; signon mvsga;

***** Please note this is a mainframe submission ********* rsubmit;

tso submit ‘sugiuser.prod.sas(compass)';

endrsubmit;

signoff mvsga;

%end; %mend results4; %results4; EOT

# ------# Run Jobs: # ------

************************************************************************ **** The following code creates a SAS log with different time/date **** *** stamps, that can later be used to decipher errors if there are any.** ************************************************************************

SUGI 29 Posters

Paper 168-29

/opt/sas8/sas /gs/dailyagent.sas -log /gs/dailyagent$(date +"%y%m%d.%H%M%S").log - print /gs/dailyagent$(date +"%y%m%d.%H%M%S").lst -linesize 80

Mainframe JCL Code :

*** submission of Mainframe Code ******

Mainframe JCL looks easy to create : ** note on Step030 condition code runs step only if return code < 4.

//UGXX JOB (9999,9999),'D STEVES',MSGCLASS=A, // CLASS=E,NOTIFY=UGXX //* /*ROUTE XEQ PRODDB21 //STEP010 EXEC SAS //NEWFILE1 DSN=UGXX.TM.FTP.COMPASS,DISP=(NEW,CATLG,DELETE), // DCB=(RECFM=VB,LRECL=220) //NEWFILE2 DDDSN=UGXX.TM.FTP.PING.COMPASS,DISP=(NEW,CATLG,DELETE), // DCB=(RECFM=FB,LRECL=80) //SYSIN DD DSN=UGXX.PROD.SAS(COMPASSC),DISP=SHR //* //* This FTP’s the ping file to the UNIX box //STEP020 EXEC PGM=FTP,PARM='12.xx.xxx.22 (',REGION=4096K //STEPLIB DD DSN=SYS2.APF.CEE.SCEERUN,DISP=SHR //SYSFTPD DD DSN=SYSN.TCPIP.PROD.PARMS(FTPSDATA),DISP=SHR //INPUT DD DSN=UGXX.PROD.SAS(FTPCLS),DISP=SHR //OUTPUT DD SYSOUT=* //SYSPRINT DD SYSOUT=* //SYSMDUMP DD SYSOUT=* //ABEND EXEC PGM=ABEND,COND=(0,EQ,STEP020) //* //STEP030 EXEC PGM=FTP,COND=(4,LT),PARM='12.XX.XXX.22 (EXIT', // REGION=4096K //STEPLIB DD DSN=SYS2.APF.CEE.SCEERUN,DISP=SHR //SYSFTPD DD DSN=SYSN.TCPIP.PROD.PARMS(FTPSDATA),DISP=SHR //INPUT DD DSN=UGXX.PROD.SAS(FTPCLS2),DISP=SHR //OUTPUT DD SYSOUT=* //SYSPRINT DD SYSOUT=* //SYSMDUMP DD SYSOUT=* //* //STEP040 EXEC PGM=IEBGENER SUGI 29 Posters

Paper 168-29

//SYSPRINT DD SYSOUT=A //SYSUT1 DD DSN=UGXX.TM.FTP.COMPASS,DISP=SHR //SYSUT2 DD DSN=UGXX.TM.COMPASS.FTP(+1),DISP=(NEW,CATLG,KEEP) //SYSIN DD DUMMY /* //STEP050 EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=A //SYSIN DD * DELETE UGXX.TM.FTP.COMPASS /* //STEP060 EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=A //SYSIN DD * DELETE UGXX.TM.FTP.PING.COMPASS /*

Conclusion We have armed you with the tools that you need to swim through and tap out a pseudo CA7 scheduler on your own. Understanding the flow process will hopefully you aware of an old scheduling tool (CRON) that has many uses inside the UNIX environment.