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