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