Production Ready Macros for SAS Application Developers
https://github.com/sasjs/core
mv_createjob.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Creates a Viya Job
4 @details
5 Code is passed in as one or more filerefs.
6
7 %* Step 1 - compile macros ;
8 filename mc url
9 "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
10 %inc mc;
11
12 %* Step 2 - Create some SAS code and add it to a job;
13 filename ft15f001 temp;
14 parmcards4;
15 data some_code;
16 set sashelp.class;
17 run;
18 ;;;;
19 %mv_createjob(path=/Public/app/sasjstemp/jobs/myjobs,name=myjob)
20
21 The path to the job will then be shown in the log, eg as follows:
22
23 ![viya job location](https://i.imgur.com/XRUDHgA.png)
24
25
26 <h4> SAS Macros </h4>
27 @li mp_abort.sas
28 @li mv_createfolder.sas
29 @li mf_getuniquelibref.sas
30 @li mf_getuniquefileref.sas
31 @li mf_getplatform.sas
32 @li mf_isblank.sas
33 @li mv_deletejes.sas
34
35 @param path= The full path (on SAS Drive) where the job will be created
36 @param name= The name of the job
37 @param desc= The description of the job
38 @param precode= Space separated list of filerefs, pointing to the code that
39 needs to be attached to the beginning of the job
40 @param code= Fileref(s) of the actual code to be added
41 @param access_token_var= The global macro variable to contain the access token
42 @param grant_type= valid values are "password" or "authorization_code"
43 (unquoted). The default is authorization_code.
44 @param replace= select NO to avoid replacing any existing job in that location
45 @param contextname= Choose a specific context on which to run the Job. Leave
46 blank to use the default context. From Viya 3.5 it is possible to configure
47 a shared context - see
48https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
49
50 @version VIYA V.03.04
51 @author [Allan Bowe](https://www.linkedin.com/in/allanbowe)
52
53**/
54
55%macro mv_createjob(path=
56 ,name=
57 ,desc=Created by the mv_createjob.sas macro
58 ,precode=
59 ,code=ft15f001
60 ,access_token_var=ACCESS_TOKEN
61 ,grant_type=sas_services
62 ,replace=YES
63 ,debug=0
64 ,contextname=
65 );
66%local oauth_bearer;
67%if &grant_type=detect %then %do;
68 %if %symexist(&access_token_var) %then %let grant_type=authorization_code;
69 %else %let grant_type=sas_services;
70%end;
71%if &grant_type=sas_services %then %do;
72 %let oauth_bearer=oauth_bearer=sas_services;
73 %let &access_token_var=;
74%end;
75
76/* initial validation checking */
77%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
78 and &grant_type ne sas_services
79 )
80 ,mac=&sysmacroname
81 ,msg=%str(Invalid value for grant_type: &grant_type)
82)
83%mp_abort(iftrue=(%mf_isblank(&path)=1)
84 ,mac=&sysmacroname
85 ,msg=%str(path value must be provided)
86)
87%mp_abort(iftrue=(%length(&path)=1)
88 ,mac=&sysmacroname
89 ,msg=%str(path value must be provided)
90)
91%mp_abort(iftrue=(%mf_isblank(&name)=1)
92 ,mac=&sysmacroname
93 ,msg=%str(name value must be provided)
94)
95
96options noquotelenmax;
97
98* remove any trailing slash ;
99%if "%substr(&path,%length(&path),1)" = "/" %then
100 %let path=%substr(&path,1,%length(&path)-1);
101
102/* ensure folder exists */
103%put &sysmacroname: Path &path being checked / created;
104%mv_createfolder(path=&path)
105
106%local base_uri; /* location of rest apis */
107%let base_uri=%mf_getplatform(VIYARESTAPI);
108
109/* fetching folder details for provided path */
110%local fname1;
111%let fname1=%mf_getuniquefileref();
112proc http method='GET' out=&fname1 &oauth_bearer
113 url="&base_uri/folders/folders/@item?path=&path";
114%if &grant_type=authorization_code %then %do;
115 headers "Authorization"="Bearer &&&access_token_var";
116%end;
117run;
118%if &debug %then %do;
119 data _null_;
120 infile &fname1;
121 input;
122 putlog _infile_;
123 run;
124%end;
125%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200)
126 ,mac=&sysmacroname
127 ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
128)
129
130/* path exists. Grab follow on link to check members */
131%local libref1;
132%let libref1=%mf_getuniquelibref();
133libname &libref1 JSON fileref=&fname1;
134
135data _null_;
136 set &libref1..links;
137 if rel='members' then call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
138 else if rel='self' then call symputx('parentFolderUri',href,'l');
139run;
140data _null_;
141 set &libref1..root;
142 call symputx('folderid',id,'l');
143run;
144%local fname2;
145%let fname2=%mf_getuniquefileref();
146proc http method='GET'
147 out=&fname2
148 &oauth_bearer
149 url=%unquote(%superq(membercheck));
150 headers
151 %if &grant_type=authorization_code %then %do;
152 "Authorization"="Bearer &&&access_token_var"
153 %end;
154 'Accept'='application/vnd.sas.collection+json'
155 'Accept-Language'='string';
156%if &debug=1 %then %do;
157 debug level = 3;
158%end;
159run;
160/*data _null_;infile &fname2;input;putlog _infile_;run;*/
161%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200)
162 ,mac=&sysmacroname
163 ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
164)
165
166%if %upcase(&replace)=YES %then %do;
167 %mv_deletejes(path=&path, name=&name)
168%end;
169%else %do;
170 /* check that job does not already exist in that folder */
171 %local libref2;
172 %let libref2=%mf_getuniquelibref();
173 libname &libref2 JSON fileref=&fname2;
174 %local exists; %let exists=0;
175 data _null_;
176 set &libref2..items;
177 if contenttype='jobDefinition' and upcase(name)="%upcase(&name)" then
178 call symputx('exists',1,'l');
179 run;
180 %mp_abort(iftrue=(&exists=1)
181 ,mac=&sysmacroname
182 ,msg=%str(Job &name already exists in &path)
183 )
184 libname &libref2 clear;
185%end;
186
187/* set up the body of the request to create the service */
188%local fname3;
189%let fname3=%mf_getuniquefileref();
190data _null_;
191 file &fname3 TERMSTR=' ';
192 length string $32767;
193 string=cats('{"version": 0,"name":"'
194 ,"&name"
195 ,'","type":"Compute","parameters":[{"name":"_addjesbeginendmacros"'
196 ,',"type":"CHARACTER","defaultValue":"false"}');
197 context=quote(cats(symget('contextname')));
198 if context ne '""' then do;
199 string=cats(string,',{"version": 1,"name": "_contextName","defaultValue":'
200 ,context,',"type":"CHARACTER","label":"Context Name","required": false}');
201 end;
202 string=cats(string,'],"code":"');
203 put string;
204run;
205
206
207/* insert the code, escaping double quotes and carriage returns */
208%local x fref freflist;
209%let freflist= &precode &code ;
210%do x=1 %to %sysfunc(countw(&freflist));
211 %let fref=%scan(&freflist,&x);
212 %put &sysmacroname: adding &fref;
213 data _null_;
214 length filein 8 fileid 8;
215 filein = fopen("&fref","I",1,"B");
216 fileid = fopen("&fname3","A",1,"B");
217 rec = "20"x;
218 do while(fread(filein)=0);
219 rc = fget(filein,rec,1);
220 if rec='"' then do; /* DOUBLE QUOTE */
221 rc =fput(fileid,'\');rc =fwrite(fileid);
222 rc =fput(fileid,'"');rc =fwrite(fileid);
223 end;
224 else if rec='0A'x then do; /* LF */
225 rc =fput(fileid,'\');rc =fwrite(fileid);
226 rc =fput(fileid,'n');rc =fwrite(fileid);
227 end;
228 else if rec='0D'x then do; /* CR */
229 rc =fput(fileid,'\');rc =fwrite(fileid);
230 rc =fput(fileid,'r');rc =fwrite(fileid);
231 end;
232 else if rec='09'x then do; /* TAB */
233 rc =fput(fileid,'\');rc =fwrite(fileid);
234 rc =fput(fileid,'t');rc =fwrite(fileid);
235 end;
236 else if rec='5C'x then do; /* BACKSLASH */
237 rc =fput(fileid,'\');rc =fwrite(fileid);
238 rc =fput(fileid,'\');rc =fwrite(fileid);
239 end;
240 else if rec='01'x then do; /* Unprintable */
241 rc =fput(fileid,'\');rc =fwrite(fileid);
242 rc =fput(fileid,'u');rc =fwrite(fileid);
243 rc =fput(fileid,'0');rc =fwrite(fileid);
244 rc =fput(fileid,'0');rc =fwrite(fileid);
245 rc =fput(fileid,'0');rc =fwrite(fileid);
246 rc =fput(fileid,'1');rc =fwrite(fileid);
247 end;
248 else if rec='07'x then do; /* Bell Char */
249 rc =fput(fileid,'\');rc =fwrite(fileid);
250 rc =fput(fileid,'u');rc =fwrite(fileid);
251 rc =fput(fileid,'0');rc =fwrite(fileid);
252 rc =fput(fileid,'0');rc =fwrite(fileid);
253 rc =fput(fileid,'0');rc =fwrite(fileid);
254 rc =fput(fileid,'7');rc =fwrite(fileid);
255 end;
256 else if rec='1B'x then do; /* escape char */
257 rc =fput(fileid,'\');rc =fwrite(fileid);
258 rc =fput(fileid,'u');rc =fwrite(fileid);
259 rc =fput(fileid,'0');rc =fwrite(fileid);
260 rc =fput(fileid,'0');rc =fwrite(fileid);
261 rc =fput(fileid,'1');rc =fwrite(fileid);
262 rc =fput(fileid,'B');rc =fwrite(fileid);
263 end;
264 else do;
265 rc =fput(fileid,rec);
266 rc =fwrite(fileid);
267 end;
268 end;
269 rc=fclose(filein);
270 rc=fclose(fileid);
271 run;
272%end;
273
274/* finish off the body of the code file loaded to JES */
275data _null_;
276 file &fname3 mod TERMSTR=' ';
277 put '"}';
278run;
279
280/* now we can create the job!! */
281%local fname4;
282%let fname4=%mf_getuniquefileref();
283proc http method='POST'
284 in=&fname3
285 out=&fname4
286 &oauth_bearer
287 url="&base_uri/jobDefinitions/definitions?parentFolderUri=&parentFolderUri";
288 headers 'Content-Type'='application/vnd.sas.job.definition+json'
289 %if &grant_type=authorization_code %then %do;
290 "Authorization"="Bearer &&&access_token_var"
291 %end;
292 "Accept"="application/vnd.sas.job.definition+json";
293%if &debug=1 %then %do;
294 debug level = 3;
295%end;
296run;
297/*data _null_;infile &fname4;input;putlog _infile_;run;*/
298%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 201)
299 ,mac=&sysmacroname
300 ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
301)
302/* clear refs */
303filename &fname1 clear;
304filename &fname2 clear;
305filename &fname3 clear;
306filename &fname4 clear;
307libname &libref1 clear;
308
309/* get the url so we can give a helpful log message */
310%local url;
311data _null_;
312 if symexist('_baseurl') then do;
313 url=symget('_baseurl');
314 if subpad(url,length(url)-9,9)='SASStudio'
315 then url=substr(url,1,length(url)-11);
316 else url="&systcpiphostname";
317 end;
318 else url="&systcpiphostname";
319 call symputx('url',url);
320run;
321
322
323%put &sysmacroname: Job &name successfully created in &path;
324%put &sysmacroname:;
325%put &sysmacroname: Check it out here:;
326%put &sysmacroname:;%put;
327%put &url/SASJobExecution?_PROGRAM=&path/&name;%put;
328%put &sysmacroname:;
329%put &sysmacroname:;
330
331%mend mv_createjob;