1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-14 20:10:05 +00:00

chore: added tests for mv_jobflow

This commit is contained in:
Trevor Moody
2021-05-12 13:59:21 +01:00
168 changed files with 10044 additions and 2253 deletions

View File

@@ -9,8 +9,8 @@
@param path= The full path of the folder to be created
@param access_token_var= The global macro variable to contain the access token
@param grant_type= valid values are "password" or "authorization_code" (unquoted).
The default is authorization_code.
@param grant_type= (authorization_code) Valid values are "password" or
"authorization_code" (unquoted).
@version VIYA V.03.04
@@ -39,7 +39,6 @@
%let &access_token_var=;
%end;
%put &sysmacroname: grant_type=&grant_type;
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
and &grant_type ne sas_services
)
@@ -85,12 +84,15 @@ options noquotelenmax;
%local libref1;
%let libref1=%mf_getuniquelibref();
libname &libref1 JSON fileref=&fname1;
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 404)
%mp_abort(
iftrue=(
&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 404
)
,mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%if &SYS_PROCHTTP_STATUS_CODE=200 %then %do;
%put &sysmacroname &newpath exists so grab the follow on link ;
%*put &sysmacroname &newpath exists so grab the follow on link ;
data _null_;
set &libref1..links;
if rel='createChild' then

View File

@@ -5,7 +5,8 @@
Code is passed in as one or more filerefs.
%* Step 1 - compile macros ;
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
%* Step 2 - Create some SAS code and add it to a job;
@@ -38,13 +39,13 @@
needs to be attached to the beginning of the job
@param code= Fileref(s) of the actual code to be added
@param access_token_var= The global macro variable to contain the access token
@param grant_type= valid values are "password" or "authorization_code" (unquoted).
The default is authorization_code.
@param grant_type= valid values are "password" or "authorization_code"
(unquoted). The default is authorization_code.
@param replace= select NO to avoid replacing any existing job in that location
@param contextname= Choose a specific context on which to run the Job. Leave
blank to use the default context. From Viya 3.5 it is possible to configure
a shared context - see
https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
@version VIYA V.03.04
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe)
@@ -71,7 +72,6 @@
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%end;
%put &sysmacroname: grant_type=&grant_type;
/* initial validation checking */
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
@@ -154,7 +154,7 @@ proc http method='GET'
'Accept'='application/vnd.sas.collection+json'
'Accept-Language'='string';
%if &debug=1 %then %do;
debug level = 3;
debug level = 3;
%end;
run;
/*data _null_;infile &fname2;input;putlog _infile_;run;*/
@@ -191,13 +191,13 @@ data _null_;
file &fname3 TERMSTR=' ';
length string $32767;
string=cats('{"version": 0,"name":"'
,"&name"
,'","type":"Compute","parameters":[{"name":"_addjesbeginendmacros"'
,"&name"
,'","type":"Compute","parameters":[{"name":"_addjesbeginendmacros"'
,',"type":"CHARACTER","defaultValue":"false"}');
context=quote(cats(symget('contextname')));
if context ne '""' then do;
string=cats(string,',{"version": 1,"name": "_contextName","defaultValue":'
,context,',"type":"CHARACTER","label":"Context Name","required": false}');
,context,',"type":"CHARACTER","label":"Context Name","required": false}');
end;
string=cats(string,'],"code":"');
put string;
@@ -267,7 +267,7 @@ proc http method='POST'
%end;
"Accept"="application/vnd.sas.job.definition+json";
%if &debug=1 %then %do;
debug level = 3;
debug level = 3;
%end;
run;
/*data _null_;infile &fname4;input;putlog _infile_;run;*/

View File

@@ -5,7 +5,8 @@
Code is passed in as one or more filerefs.
%* Step 1 - compile macros ;
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
%* Step 2 - Create some code and add it to a web service;
@@ -18,7 +19,7 @@
run;
%* send data back;
%webout(OPEN)
%webout(ARR,example1) * Array format, fast, suitable for large tables ;
%webout(ARR,example1) * Array format, fast, suitable for large tables;
%webout(OBJ,example2) * Object format, easier to work with ;
%webout(CLOSE)
;;;;
@@ -38,21 +39,26 @@
@li mf_isblank.sas
@li mv_deletejes.sas
@param path= The full path (on SAS Drive) where the service will be created
@param name= The name of the service
@param desc= The description of the service
@param precode= Space separated list of filerefs, pointing to the code that
needs to be attached to the beginning of the service
@param code= Fileref(s) of the actual code to be added
@param access_token_var= The global macro variable to contain the access token
@param grant_type= valid values are "password" or "authorization_code" (unquoted).
The default is authorization_code.
@param replace= select NO to avoid replacing any existing service in that location
@param adapter= the macro uses the sasjs adapter by default. To use another
adapter, add a (different) fileref here.
@param contextname= Choose a specific context on which to run the Job. Leave
@param [in] path= The full path (on SAS Drive) where the service will be
created
@param [in] name= The name of the service
@param [in] desc= The description of the service
@param [in] precode= Space separated list of filerefs, pointing to the code
that needs to be attached to the beginning of the service
@param [in] code= Fileref(s) of the actual code to be added
@param [in] access_token_var= The global macro variable to contain the access
token
@param [in] grant_type= valid values are "password" or "authorization_code"
(unquoted). The default is authorization_code.
@param [in] replace=(YES) Select NO to avoid replacing any existing service in
that location
@param [in] adapter= the macro uses the sasjs adapter by default. To use
another adapter, add a (different) fileref here.
@param [in] contextname= Choose a specific context on which to run the Job. Leave
blank to use the default context. From Viya 3.5 it is possible to configure
a shared context - see https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
a shared context - see
https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
@param [in] mdebug=(0) set to 1 to enable DEBUG messages
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
@@ -68,9 +74,17 @@
,grant_type=sas_services
,replace=YES
,adapter=sasjs
,debug=0
,mdebug=0
,contextname=
,debug=0 /* @TODO - Deprecate */
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
@@ -80,7 +94,6 @@
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%end;
%put &sysmacroname: grant_type=&grant_type;
/* initial validation checking */
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
@@ -124,7 +137,7 @@ proc http method='GET' out=&fname1 &oauth_bearer
headers "Authorization"="Bearer &&&access_token_var";
%end;
run;
%if &debug %then %do;
%if &mdebug=1 %then %do;
data _null_;
infile &fname1;
input;
@@ -143,7 +156,8 @@ libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..links;
if rel='members' then call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
if rel='members' then
call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
else if rel='self' then call symputx('parentFolderUri',href,'l');
run;
data _null_;
@@ -162,8 +176,8 @@ proc http method='GET'
%end;
'Accept'='application/vnd.sas.collection+json'
'Accept-Language'='string';
%if &debug=1 %then %do;
debug level = 3;
%if &mdebug=1 %then %do;
debug level = 3;
%end;
run;
/*data _null_;infile &fname2;input;putlog _infile_;run;*/
@@ -200,33 +214,34 @@ data _null_;
file &fname3 TERMSTR=' ';
length string $32767;
string=cats('{"version": 0,"name":"'
,"&name"
,'","type":"Compute","parameters":[{"name":"_addjesbeginendmacros"'
,"&name"
,'","type":"Compute","parameters":[{"name":"_addjesbeginendmacros"'
,',"type":"CHARACTER","defaultValue":"false"}');
context=quote(cats(symget('contextname')));
if context ne '""' then do;
string=cats(string,',{"version": 1,"name": "_contextName","defaultValue":'
,context,',"type":"CHARACTER","label":"Context Name","required": false}');
,context,',"type":"CHARACTER","label":"Context Name","required": false}');
end;
string=cats(string,'],"code":"');
put string;
run;
/**
* Add webout macro
* These put statements are auto generated - to change the macro, change the
* source (mv_webout) and run `build.py`
*/
filename sasjs temp lrecl=3000;
* Add webout macro
* These put statements are auto generated - to change the macro, change the
* source (mv_webout) and run `build.py`
*/
filename &adapter temp lrecl=3000;
data _null_;
file sasjs;
file &adapter;
put "/* Created on %sysfunc(datetime(),datetime19.) by &sysuserid */";
/* WEBOUT BEGIN */
put ' ';
put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=PROCJSON,dbg=0 ';
put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP,dbg=0 ';
put ')/*/STORE SOURCE*/; ';
put '%put output location=&jref; ';
put '%if &action=OPEN %then %do; ';
put ' OPTIONS NOBOMFILE; ';
put ' data _null_;file &jref encoding=''utf-8''; ';
put ' put ''{"START_DTTM" : "'' "%sysfunc(datetime(),datetime20.3)" ''"''; ';
put ' run; ';
@@ -254,9 +269,68 @@ data _null_;
put ' %put &sysmacroname: &ds NOT FOUND!!!; ';
put ' %return; ';
put ' %end; ';
put ' %if &fmt=Y %then %do; ';
put ' %put converting every variable to a formatted variable; ';
put ' /* see mp_ds2fmtds.sas for source */ ';
put ' proc contents noprint data=&ds ';
put ' out=_data_(keep=name type length format formatl formatd varnum); ';
put ' run; ';
put ' proc sort; ';
put ' by varnum; ';
put ' run; ';
put ' %local fmtds; ';
put ' %let fmtds=%scan(&syslast,2,.); ';
put ' /* prepare formats and varnames */ ';
put ' data _null_; ';
put ' set &fmtds end=last; ';
put ' name=upcase(name); ';
put ' /* fix formats */ ';
put ' if type=2 or type=6 then do; ';
put ' length fmt $49.; ';
put ' if format='''' then fmt=cats(''$'',length,''.''); ';
put ' else if formatl=0 then fmt=cats(format,''.''); ';
put ' else fmt=cats(format,formatl,''.''); ';
put ' newlen=max(formatl,length); ';
put ' end; ';
put ' else do; ';
put ' if format='''' then fmt=''best.''; ';
put ' else if formatl=0 then fmt=cats(format,''.''); ';
put ' else if formatd=0 then fmt=cats(format,formatl,''.''); ';
put ' else fmt=cats(format,formatl,''.'',formatd); ';
put ' /* needs to be wide, for datetimes etc */ ';
put ' newlen=max(length,formatl,24); ';
put ' end; ';
put ' /* 32 char unique name */ ';
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
put ' ';
put ' call symputx(cats(''name'',_n_),name,''l''); ';
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' if last then call symputx(''nobs'',_n_,''l''); ';
put ' run; ';
put ' data &fmtds; ';
put ' /* rename on entry */ ';
put ' set &ds(rename=( ';
put ' %local i; ';
put ' %do i=1 %to &nobs; ';
put ' &&name&i=&&newname&i ';
put ' %end; ';
put ' )); ';
put ' %do i=1 %to &nobs; ';
put ' length &&name&i $&&len&i; ';
put ' &&name&i=left(put(&&newname&i,&&fmt&i)); ';
put ' drop &&newname&i; ';
put ' %end; ';
put ' if _error_ then call symputx(''syscc'',1012); ';
put ' run; ';
put ' %let ds=&fmtds; ';
put ' %end; /* &fmt=Y */ ';
put ' data _null_;file &jref mod ; ';
put ' put "["; call symputx(''cols'',0,''l''); ';
put ' proc sort data=sashelp.vcolumn(where=(libname=''WORK'' & memname="%upcase(&ds)")) ';
put ' proc sort ';
put ' data=sashelp.vcolumn(where=(libname=''WORK'' & memname="%upcase(&ds)")) ';
put ' out=_data_; ';
put ' by varnum; ';
put ' ';
@@ -295,7 +369,8 @@ data _null_;
put ' %end; ';
put ' %end; ';
put ' run; ';
put ' /* write to temp loc to avoid _webout truncation - https://support.sas.com/kb/49/325.html */ ';
put ' /* write to temp loc to avoid _webout truncation ';
put ' - https://support.sas.com/kb/49/325.html */ ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod; ';
put ' set &tempds; ';
@@ -331,11 +406,11 @@ data _null_;
put '%end; ';
put ' ';
put '%else %if &action=CLOSE %then %do; ';
put ' data _null_;file &jref encoding=''utf-8''; ';
put ' data _null_;file &jref encoding=''utf-8'' mod; ';
put ' put "}"; ';
put ' run; ';
put '%end; ';
put '%mend; ';
put '%mend mp_jsonout; ';
put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y); ';
put '%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name ';
put ' sasjs_tables SYS_JES_JOB_URI; ';
@@ -410,7 +485,8 @@ data _null_;
put ' if _n_=1 then call symputx(''input_statement'',_infile_); ';
put ' list; ';
put ' data &table; ';
put ' infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd termstr=crlf; ';
put ' infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd ';
put ' termstr=crlf; ';
put ' input &input_statement; ';
put ' run; ';
put ' %end; ';
@@ -442,7 +518,7 @@ data _null_;
put ' /* setup webout */ ';
put ' OPTIONS NOBOMFILE; ';
put ' %if "X&SYS_JES_JOB_URI.X"="XX" %then %do; ';
put ' filename _webout temp lrecl=999999 mod; ';
put ' filename _webout temp lrecl=999999 mod; ';
put ' %end; ';
put ' %else %do; ';
put ' filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" ';
@@ -451,7 +527,8 @@ data _null_;
put ' ';
put ' /* setup temp ref */ ';
put ' %if %upcase(&fref) ne _WEBOUT %then %do; ';
put ' filename &fref temp lrecl=999999 permission=''A::u::rwx,A::g::rw-,A::o::---'' mod; ';
put ' filename &fref temp lrecl=999999 permission=''A::u::rwx,A::g::rw-,A::o::---'' ';
put ' mod; ';
put ' %end; ';
put ' ';
put ' /* setup json */ ';
@@ -461,7 +538,7 @@ data _null_;
put '%end; ';
put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt ';
put ' ,jref=&fref,engine=PROCJSON,dbg=%str(&_debug) ';
put ' ,jref=&fref,engine=DATASTEP,dbg=%str(&_debug) ';
put ' ) ';
put '%end; ';
put '%else %if &action=CLOSE %then %do; ';
@@ -554,11 +631,12 @@ data _null_;
run;
/* insert the code, escaping double quotes and carriage returns */
%&dbg.put &sysmacroname: Creating final input file;
%local x fref freflist;
%let freflist= &adapter &precode &code ;
%do x=1 %to %sysfunc(countw(&freflist));
%let fref=%scan(&freflist,&x);
%put &sysmacroname: adding &fref;
%&dbg.put &sysmacroname: adding &fref fileref;
data _null_;
length filein 8 fileid 8;
filein = fopen("&fref","I",1,"B");
@@ -586,6 +664,14 @@ run;
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'\');rc =fwrite(fileid);
end;
else if rec='01'x then do; /* Unprintable */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
end;
else do;
rc =fput(fileid,rec);
rc =fwrite(fileid);
@@ -602,7 +688,12 @@ data _null_;
put '"}';
run;
/* now we can create the job!! */
%if &mdebug=1 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then %do;
%put &sysmacroname: input about to be POSTed;
data _null_;infile &fname3;input;putlog _infile_;run;
%end;
%&dbg.put &sysmacroname: Creating the actual service!;
%local fname4;
%let fname4=%mf_getuniquefileref();
proc http method='POST'
@@ -615,22 +706,18 @@ proc http method='POST'
"Authorization"="Bearer &&&access_token_var"
%end;
"Accept"="application/vnd.sas.job.definition+json";
%if &debug=1 %then %do;
debug level = 3;
%if &mdebug=1 %then %do;
debug level = 3;
%end;
run;
/*data _null_;infile &fname4;input;putlog _infile_;run;*/
%if &mdebug=1 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then %do;
%put &sysmacroname: output from POSTing job definition;
data _null_;infile &fname4;input;putlog _infile_;run;
%end;
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 201)
,mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
/* clear refs */
filename &fname1 clear;
filename &fname2 clear;
filename &fname3 clear;
filename &fname4 clear;
filename &adapter clear;
libname &libref1 clear;
/* get the url so we can give a helpful log message */
%local url;
@@ -645,6 +732,19 @@ data _null_;
call symputx('url',url);
run;
%if &mdebug=1 %then %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%else %do;
/* clear refs */
filename &fname1 clear;
filename &fname2 clear;
filename &fname3 clear;
filename &fname4 clear;
filename &adapter clear;
libname &libref1 clear;
%end;
%put &sysmacroname: Job &name successfully created in &path;
%put &sysmacroname:;
@@ -654,4 +754,4 @@ run;
%put &sysmacroname:;
%put &sysmacroname:;
%mend;
%mend mv_createwebservice;

View File

@@ -44,7 +44,7 @@
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%end;
%put &sysmacroname: grant_type=&grant_type;
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
and &grant_type ne sas_services
)

View File

@@ -39,7 +39,7 @@
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%end;
%put &sysmacroname: grant_type=&grant_type;
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
and &grant_type ne sas_services
)

View File

@@ -1,24 +1,24 @@
/**
@file mv_getaccesstoken.sas
@brief deprecated - replaced by mv_tokenrefresh.sas
/**
@file mv_getaccesstoken.sas
@brief deprecated - replaced by mv_tokenrefresh.sas
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4>
@li mv_tokenrefresh.sas
<h4> SAS Macros </h4>
@li mv_tokenrefresh.sas
**/
**/
%macro mv_getaccesstoken(client_id=someclient
,client_secret=somesecret
,grant_type=authorization_code
,code=
,user=
,pass=
,access_token_var=ACCESS_TOKEN
,refresh_token_var=REFRESH_TOKEN
);
%macro mv_getaccesstoken(client_id=someclient
,client_secret=somesecret
,grant_type=authorization_code
,code=
,user=
,pass=
,access_token_var=ACCESS_TOKEN
,refresh_token_var=REFRESH_TOKEN
);
%mv_tokenrefresh(client_id=&client_id
,client_secret=&client_secret

View File

@@ -1,19 +1,19 @@
/**
@file
@brief deprecated - replaced by mv_registerclient.sas
/**
@file
@brief deprecated - replaced by mv_registerclient.sas
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4>
@li mv_registerclient.sas
<h4> SAS Macros </h4>
@li mv_registerclient.sas
**/
**/
%macro mv_getapptoken(client_id=someclient
,client_secret=somesecret
,grant_type=authorization_code
);
%macro mv_getapptoken(client_id=someclient
,client_secret=somesecret
,grant_type=authorization_code
);
%mv_registerclient(client_id=&client_id
,client_secret=&client_secret

View File

@@ -54,7 +54,7 @@
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%end;
%put &sysmacroname: grant_type=&grant_type;
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
and &grant_type ne sas_services
)

View File

@@ -5,22 +5,25 @@
Example:
%mv_getjobcode(
path=/Public/jobs
path=/Public/jobs
,name=some_job
,outfile=/tmp/some_job.sas
)
@param [in] access_token_var= The global macro variable to contain the access token
@param [in] access_token_var= The global macro variable to contain the access
token
@param [in] grant_type= valid values:
* password
* authorization_code
* detect - will check if access_token exists, if not will use sas_services if
a SASStudioV session else authorization_code. Default option.
* sas_services - will use oauth_bearer=sas_services
@li password
@liauthorization_code
@li detect - will check if access_token exists, if not will use sas_services
if a SASStudioV session else authorization_code. Default option.
@li sas_services - will use oauth_bearer=sas_services
@param [in] path= The SAS Drive path of the job
@param [in] name= The name of the job
@param [out] outref= A fileref to which to write the source code
@param [out] outfile= A file to which to write the source code
@param [in] mdebug=(0) set to 1 to enable DEBUG messages
@param [out] outref=(0) A fileref to which to write the source code (will be
created with a TEMP engine)
@param [out] outfile=(0) A file to which to write the source code
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
@@ -39,7 +42,15 @@
,contextName=SAS Job Execution compute context
,access_token_var=ACCESS_TOKEN
,grant_type=sas_services
,mdebug=0
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
@@ -129,22 +140,34 @@ data _null_;
outfile:write(job)
io.close(infile)
io.close(outfile)
';
';
run;
%inc "&fpath3..lua";
/* export to desired destination */
data _null_;
%if &outref=0 %then %do;
%if "&outref"="0" %then %do;
data _null_;
file "&outfile" lrecl=32767;
%end;
%else %do;
%end;
%else %do;
filename &outref temp;
data _null_;
file &outref;
%end;
%end;
infile &fname2;
input;
put _infile_;
&dbg. putlog _infile_;
run;
filename &fname1 clear;
filename &fname2 clear;
filename &fname3 clear;
%mend;
%if &mdebug=1 %then %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%else %do;
/* clear refs */
filename &fname1 clear;
filename &fname2 clear;
filename &fname3 clear;
%end;
%mend mv_getjobcode;

View File

@@ -1,20 +1,19 @@
/**
@file
@brief Extract the log from a completed SAS Viya Job
@details Extracts log from a Viya job and writes it out to a fileref
@details Extracts log from a Viya job and writes it out to a fileref.
To query the job, you need the URI. Sample code for achieving this
is provided below.
## Example
First, compile the macros:
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%* First, compile the macros;
filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
Next, create a job (in this case, a web service):
%* Next, create a job (in this case, a web service);
filename ft15f001 temp;
parmcards4;
data ;
@@ -30,39 +29,52 @@
;;;;
%mv_createwebservice(path=/Public/temp,name=demo)
Execute it:
%* Execute it;
%mv_jobexecute(path=/Public/temp
,name=demo
,outds=work.info
)
Wait for it to finish, and grab the uri:
data _null_;
%* Wait for it to finish;
data work.info;
set work.info;
if method='GET' and rel='self';
where method='GET' and rel='state';
run;
%mv_jobwaitfor(ALL,inds=work.info,outds=work.jobstates)
%* and grab the uri;
data _null_;
set work.jobstates;
call symputx('uri',uri);
run;
Finally, fetch the log:
%* Finally, fetch the log;
%mv_getjoblog(uri=&uri,outref=mylog)
This macro is used by the mv_jobwaitfor.sas macro, which is generally a more
convenient way to wait for the job to finish before fetching the log.
If the remote session calls `endsas` then it is not possible to get the log
from the provided uri, and so the log from the parent session is fetched
instead. This happens for a 400 response, eg below:
@param [in] access_token_var= The global macro variable to contain the access token
ErrorResponse[version=2,status=400,err=5113,id=,message=The session
requested is currently in a failed or stopped state.,detail=[path:
/compute/sessions/LONGURI-ses0006/jobs/LONGURI/log/content, traceId: 63
51aa617d01fd2b],remediation=Correct the errors in the session request,
and create a new session.,targetUri=<null>,errors=[],links=[]]
@param [in] access_token_var= The global macro variable to contain the access
token
@param [in] mdebug= set to 1 to enable DEBUG messages
@param [in] grant_type= valid values:
@li password
@li authorization_code
@li detect - will check if access_token exists, if not will use sas_services if
a SASStudioV session else authorization_code. Default option.
@li detect - will check if access_token exists, if not will use sas_services
if a SASStudioV session else authorization_code. Default option.
@li sas_services - will use oauth_bearer=sas_services.
@param [in] uri= The uri of the running job for which to fetch the status,
in the format `/jobExecution/jobs/$UUID/state` (unquoted).
in the format `/jobExecution/jobs/$UUID` (unquoted).
@param [out] outref= The output fileref to which to APPEND the log (is always
appended).
@@ -84,6 +96,13 @@
,grant_type=sas_services
,mdebug=0
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
@@ -113,7 +132,7 @@ data _null_;
call symputx('errflg',1);
call symputx('errmsg',
"URI should be in format /jobExecution/jobs/$$$$UUID$$$$"
!!" but is actually like: &uri",'l');
!!" but is actually like:"!!uri,'l');
end;
run;
@@ -146,6 +165,10 @@ proc http method='GET' out=&fname1 &oauth_bearer
%end;
;
run;
%if &mdebug=1 %then %do;
%put &sysmacroname: fetching log loc from &uri;
data _null_;infile &fname1;input;putlog _infile_;run;
%end;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
%do;
data _null_;infile &fname1;input;putlog _infile_;run;
@@ -174,7 +197,7 @@ data _null_;
outfile:write(logloc)
io.close(infile)
io.close(outfile)
';
';
run;
%inc "&fpath3..lua";
/* get log path*/
@@ -183,43 +206,74 @@ run;
data _null_;
infile &fname2;
input;
uri=_infile_;
uri=cats(_infile_);
if length(uri)<12 then do;
call symputx('errflg',1);
call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
end;
if scan(uri,1) ne 'files' or scan(uri,2) ne 'files' then do;
else if (scan(uri,1,'/') ne 'compute' or scan(uri,2,'/') ne 'sessions')
and (scan(uri,1,'/') ne 'files' or scan(uri,2,'/') ne 'files')
then do;
call symputx('errflg',1);
call symputx('errmsg',
"URI should be in format /files/files/$$$$UUID$$$$"
!!" but is actually like: &uri",'l');
"URI should be in format /compute/sessions/$$$$UUID$$$$/jobs/$$$$UUID$$$$"
!!" or /files/files/$$$$UUID$$$$"
!!" but is actually like:"!!uri,'l');
end;
else do;
call symputx('errflg',0,'l');
call symputx('logloc',uri,'l');
end;
call symputx('errflg',0,'l');
call symputx('logloc',uri,'l');
run;
%mp_abort(iftrue=(&errflg=1)
%mp_abort(iftrue=(%str(&errflg)=1)
,mac=&sysmacroname
,msg=%str(&errmsg)
)
/* we have a log uri - now fetch the log */
%&dbg.put &sysmacroname: querying &base_uri&logloc/content;
proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&logloc/content";
url="&base_uri&logloc/content?limit=10000";
headers
%if &grant_type=authorization_code %then %do;
"Authorization"="Bearer &&&access_token_var"
%end;
;
run;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
%do;
%if &mdebug=1 %then %do;
%put &sysmacroname: fetching log content from &base_uri&logloc/content;
data _null_;infile &fname1;input;putlog _infile_;run;
%end;
%if &SYS_PROCHTTP_STATUS_CODE=400 %then %do;
/* fetch log from parent session */
%let logloc=%substr(&logloc,1,%index(&logloc,%str(/jobs/))-1);
%&dbg.put &sysmacroname: Now querying &base_uri&logloc/log/content;
proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&logloc/log/content?limit=10000";
headers
%if &grant_type=authorization_code %then %do;
"Authorization"="Bearer &&&access_token_var"
%end;
;
run;
%if &mdebug=1 %then %do;
%put &sysmacroname: fetching log content from &base_uri&logloc/log/content;
data _null_;infile &fname1;input;putlog _infile_;run;
%end;
%end;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201
%then %do;
%if &mdebug ne 1 %then %do; /* have already output above */
data _null_;infile &fname1;input;putlog _infile_;run;
%end;
%mp_abort(mac=&sysmacroname
,msg=%str(logfetch: &SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%end;
data _null_;
file "&fpath3..lua";
put '
@@ -228,7 +282,7 @@ data _null_;
io.input(infile)
local resp=json.decode(io.read())
for i, v in pairs(resp["items"]) do
outfile:write(v.line,"\n")
outfile:write(v.line,"\n")
end
io.close(infile)
io.close(outfile)
@@ -259,9 +313,10 @@ run;
filename &fname3 clear;
%end;
%else %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%mend;
%mend mv_getjoblog;

232
viya/mv_getjobresult.sas Normal file
View File

@@ -0,0 +1,232 @@
/**
@file
@brief Extract the result from a completed SAS Viya Job
@details Extracts result from a Viya job and writes it out to a fileref
and/or a JSON-engine library.
To query the job, you need the URI. Sample code for achieving this
is provided below.
## Example
First, compile the macros:
filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
Next, create a job (in this case, a web service):
filename ft15f001 temp;
parmcards4;
data test;
rand=ranuni(0)*1000;
do x=1 to rand;
y=rand*4;
output;
end;
run;
proc sort data=&syslast
by descending y;
run;
%webout(OPEN)
%webout(OBJ, test)
%webout(CLOSE)
;;;;
%mv_createwebservice(path=/Public/temp,name=demo)
Execute it:
%mv_jobexecute(path=/Public/temp
,name=demo
,outds=work.info
)
Wait for it to finish, and grab the uri:
data _null_;
set work.info;
if method='GET' and rel='self';
call symputx('uri',uri);
run;
Finally, fetch the result (In this case, WEBOUT):
%mv_getjobresult(uri=&uri,result=WEBOUT_JSON,outref=myweb,outlib=myweblib)
@param [in] access_token_var= The global macro variable containing the access
token
@param [in] mdebug= set to 1 to enable DEBUG messages
@param [in] grant_type= valid values:
@li password
@li authorization_code
@li detect - will check if access_token exists, if not will use sas_services
if a SASStudioV session else authorization_code. Default option.
@li sas_services - will use oauth_bearer=sas_services.
@param [in] uri= The uri of the running job for which to fetch the status,
in the format `/jobExecution/jobs/$UUID` (unquoted).
@param [out] result= (WEBOUT_JSON) The result type to capture. Resolves
to "_[column name]" from the results table when parsed with the JSON libname
engine. Example values:
@li WEBOUT_JSON
@li WEBOUT_TXT
@param [out] outref= (0) The output fileref to which to write the results
@param [out] outlib= (0) The output library to which to assign the results
(assumes the data is in JSON format)
@version VIYA V.03.05
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4>
@li mp_abort.sas
@li mp_binarycopy.sas
@li mf_getplatform.sas
@li mf_existfileref.sas
**/
%macro mv_getjobresult(uri=0
,contextName=SAS Job Execution compute context
,access_token_var=ACCESS_TOKEN
,grant_type=sas_services
,mdebug=0
,result=WEBOUT_JSON
,outref=0
,outlib=0
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
%else %let grant_type=sas_services;
%end;
%if &grant_type=sas_services %then %do;
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%end;
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
and &grant_type ne sas_services
)
,mac=&sysmacroname
,msg=%str(Invalid value for grant_type: &grant_type)
)
/* validation in datastep for better character safety */
%local errmsg errflg;
data _null_;
uri=symget('uri');
if length(uri)<12 then do;
call symputx('errflg',1);
call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
end;
if scan(uri,-1)='state' or scan(uri,1) ne 'jobExecution' then do;
call symputx('errflg',1);
call symputx('errmsg',
"URI should be in format /jobExecution/jobs/$$$$UUID$$$$"
!!" but is actually like: &uri",'l');
end;
run;
%mp_abort(iftrue=(&errflg=1)
,mac=&sysmacroname
,msg=%str(&errmsg)
)
%if &outref ne 0 and %mf_existfileref(&outref) ne 1 %then %do;
filename &outref temp;
%end;
options noquotelenmax;
%local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI);
/* fetch job info */
%local fname1;
%let fname1=%mf_getuniquefileref();
proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&uri";
headers "Accept"="application/json"
%if &grant_type=authorization_code %then %do;
"Authorization"="Bearer &&&access_token_var"
%end;
;
run;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
%do;
data _null_;infile &fname1;input;putlog _infile_;run;
%mp_abort(mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%end;
%if &mdebug=1 %then %do;
data _null_;
infile &fname1 lrecl=32767;
input;
putlog _infile_;
run;
%end;
/* extract results link */
%local lib1 resuri;
%let lib1=%mf_getuniquelibref();
libname &lib1 JSON fileref=&fname1;
data _null_;
set &lib1..results;
call symputx('resuri',_&result,'l');
&dbg putlog "&sysmacroname results: " (_all_)(=);
run;
%mp_abort(iftrue=("&resuri"=".")
,mac=&sysmacroname
,msg=%str(Variable _&result did not exist in the response json)
)
/* extract results */
%local fname2;
%let fname2=%mf_getuniquefileref();
proc http method='GET' out=&fname2 &oauth_bearer
url="&base_uri&resuri/content?limit=10000";
headers "Accept"="application/json"
%if &grant_type=authorization_code %then %do;
"Authorization"="Bearer &&&access_token_var"
%end;
;
run;
%if &mdebug=1 %then %do;
data _null_;
infile &fname2 lrecl=32767;
input;
putlog _infile_;
run;
%end;
%if &outref ne 0 %then %do;
filename &outref temp;
%mp_binarycopy(inref=&fname2,outref=&outref)
%end;
%if &outlib ne 0 %then %do;
libname &outlib JSON fileref=&fname2;
%end;
%if &mdebug=0 %then %do;
filename &fname1 clear;
filename &fname2 clear;
libname &lib1 clear;
%end;
%else %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%mend mv_getjobresult;

View File

@@ -1,24 +1,24 @@
/**
@file mv_getrefreshtoken.sas
@brief deprecated - replaced by mv_tokenauth.sas
/**
@file mv_getrefreshtoken.sas
@brief deprecated - replaced by mv_tokenauth.sas
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4>
@li mv_tokenauth.sas
<h4> SAS Macros </h4>
@li mv_tokenauth.sas
**/
**/
%macro mv_getrefreshtoken(client_id=someclient
,client_secret=somesecret
,grant_type=authorization_code
,code=
,user=
,pass=
,access_token_var=ACCESS_TOKEN
,refresh_token_var=REFRESH_TOKEN
);
%macro mv_getrefreshtoken(client_id=someclient
,client_secret=somesecret
,grant_type=authorization_code
,code=
,user=
,pass=
,access_token_var=ACCESS_TOKEN
,refresh_token_var=REFRESH_TOKEN
);
%mv_tokenauth(client_id=&client_id
,client_secret=&client_secret

View File

@@ -65,7 +65,7 @@ proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri/identities/users/&user/memberships?limit=10000";
headers
%if &grant_type=authorization_code %then %do;
"Authorization"="Bearer &&&access_token_var"
"Authorization"="Bearer &&&access_token_var"
%end;
"Accept"="application/json";
run;

View File

@@ -37,11 +37,11 @@
@param access_token_var= The global macro variable to contain the access token
@param grant_type= valid values:
* password
* authorization_code
* detect - will check if access_token exists, if not will use sas_services if
a SASStudioV session else authorization_code. Default option.
* sas_services - will use oauth_bearer=sas_services
* password
* authorization_code
* detect - will check if access_token exists, if not will use sas_services if
a SASStudioV session else authorization_code. Default option.
* sas_services - will use oauth_bearer=sas_services
@param outds= The library.dataset to be created that contains the list of groups

View File

@@ -23,24 +23,25 @@
,paramstring=%str("macvarname":"macvarvalue","answer":42)
)
@param [in] access_token_var= The global macro variable to contain the access token
@param [in] access_token_var= The global macro variable to contain the access
token
@param [in] grant_type= valid values:
* password
* authorization_code
* detect - will check if access_token exists, if not will use sas_services if
a SASStudioV session else authorization_code. Default option.
* sas_services - will use oauth_bearer=sas_services
@li password
@li authorization_code
@li detect - will check if access_token exists, if not will use sas_services
if a SASStudioV session else authorization_code. Default option.
@li sas_services - will use oauth_bearer=sas_services
@param [in] path= The SAS Drive path to the job being executed
@param [in] name= The name of the job to execute
@param [in] paramstring= A JSON fragment with name:value pairs, eg: `"name":"value"`
or "name":"value","name2":42`. This will need to be wrapped in `%str()`.
@param [in] paramstring= A JSON fragment with name:value pairs, eg:
`"name":"value"` or "name":"value","name2":42`. This will need to be
wrapped in `%str()`.
@param [in] contextName= Context name with which to run the job.
Default = `SAS Job Execution compute context`
@param [out] outds= The output dataset containing links (Default=work.mv_jobexecute)
@param [in] mdebug= set to 1 to enable DEBUG messages
@param [out] outds= (work.mv_jobexecute) The output dataset containing links
@version VIYA V.03.04
@@ -62,7 +63,15 @@
,grant_type=sas_services
,paramstring=0
,outds=work.mv_jobexecute
,mdebug=0
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
@@ -164,9 +173,14 @@ data &outds;
_program="&path/&name";
run;
/* clear refs */
filename &fname0 clear;
filename &fname1 clear;
libname &libref;
%mend;
%if &mdebug=1 %then %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%else %do;
/* clear refs */
filename &fname0 clear;
filename &fname1 clear;
libname &libref;
%end;
%mend mv_jobexecute;

View File

@@ -13,7 +13,7 @@
@li FLOW_ID - Numeric value, provides sequential ordering capability. Is
optional, will default to 0 if not provided.
@li _CONTEXTNAME - Dictates which context should be used to run the job. If
blank (or not provided), it defaults to `SAS Job Execution compute context`.
blank, or not provided, will default to `SAS Job Execution compute context`.
Any additional variables provided in this table are converted into macro
variables and passed into the relevant job.
@@ -103,15 +103,13 @@
@li password
@li authorization_code
@li detect - will check if access_token exists, if not will use
sas_services if a SASStudioV session else authorization_code.
Default option.
sas_services if a SASStudioV session else authorization_code. Default
option.
@li sas_services - will use oauth_bearer=sas_services
@param [in] inds= The input dataset containing a list of jobs and
parameters
@param [in] maxconcurrency= The max number of parallel jobs to run.
Default=8.
@param [in] raise_err=0 Set to 1 to raise SYSCC when a job does not
complete succcessfully
@param [in] inds= The input dataset containing a list of jobs and parameters
@param [in] maxconcurrency= The max number of parallel jobs to run. Default=8.
@param [in] raise_err=0 Set to 1 to raise SYSCC when a job does not complete
succcessfully
@param [in] mdebug= set to 1 to enable DEBUG messages
@param [out] outds= The output dataset containing the results
@param [out] outref= The output fileref to which to append the log file(s).
@@ -138,6 +136,13 @@
,raise_err=0
,mdebug=0
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
@@ -189,7 +194,7 @@ select count(*) into: missings
where flow_id is null or _program is null;
%mp_abort(iftrue=(&missings>0)
,mac=&sysmacroname
,msg=%str(input dataset contains &missings missing values for FLOW_ID or _PROGRAM)
,msg=%str(input dataset has &missings missing values for FLOW_ID or _PROGRAM)
)
%if %mf_nobs(&inds)=0 %then %do;
@@ -374,6 +379,7 @@ data;run;%let jdswaitfor=&syslast;
%end;
%if &mdebug=1 %then %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;

View File

@@ -1,6 +1,6 @@
/**
@file
@brief Takes a dataset of running jobs and waits for ANY or ALL of them to complete
@brief Takes a table of running jobs and waits for ANY/ALL of them to complete
@details Will poll `/jobs/{jobId}/state` at set intervals until ANY or ALL
jobs are completed. Completion is determined by reference to the returned
_state_, as per the following table:
@@ -55,13 +55,14 @@
%mv_deletejes(path=/Public/temp,name=demo)
@param [in] access_token_var= The global macro variable to contain the access token
@param [in] access_token_var= The global macro variable to contain the access
token
@param [in] grant_type= valid values:
- password
- authorization_code
- detect - will check if access_token exists, if not will use sas_services if
a SASStudioV session else authorization_code. Default option.
- detect - will check if access_token exists, if not will use sas_services
if a SASStudioV session else authorization_code. Default option.
- sas_services - will use oauth_bearer=sas_services
@param [in] action=Either ALL (to wait for every job) or ANY (if one job
@@ -72,9 +73,11 @@
should be in a `_program` variable.
@param [in] raise_err=0 Set to 1 to raise SYSCC when a job does not complete
succcessfully
@param [in] mdebug= set to 1 to enable DEBUG messages
@param [out] outds= The output dataset containing the list of states by job
(default=work.mv_jobexecute)
@param [out] outref= A fileref to which the spawned job logs should be appended.
@param [out] outref= A fileref to which the spawned job logs should be
appended.
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
@@ -97,7 +100,15 @@
,outds=work.mv_jobwaitfor
,outref=0
,raise_err=0
,mdebug=0
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
@@ -155,7 +166,8 @@ run;
%let fname0=%mf_getuniquefileref();
data &outds;
format _program uri $128. state $32. stateDetails $32. timestamp datetime19. jobparams $32767.;
format _program uri $128. state $32. stateDetails $32. timestamp datetime19.
jobparams $32767.;
stop;
run;
@@ -168,8 +180,8 @@ run;
"Authorization"="Bearer &&&access_token_var"
%end; ;
run;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
%do;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201
%then %do;
data _null_;infile &fname0;input;putlog _infile_;run;
%mp_abort(mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
@@ -205,7 +217,7 @@ run;
%let joburi&i=0; /* do not re-check */
/* fetch log */
%if %str(&outref) ne 0 %then %do;
%mv_getjoblog(uri=&plainuri,outref=&outref)
%mv_getjoblog(uri=&plainuri,outref=&outref,mdebug=&mdebug)
%end;
%end;
%else %if &status=idle or &status=pending or &status=running %then %do;
@@ -220,12 +232,13 @@ run;
%end;
%if (&raise_err) %then %do;
%if (&status = canceled or &status = failed or %length(&stateDetails)>0) %then %do;
%if (&status = canceled or &status = failed or %length(&stateDetails)>0)
%then %do;
%if ("&stateDetails" = "%str(war)ning") %then %let SYSCC=4;
%else %let SYSCC=5;
%put %str(ERR)OR: Job &&jobname&i. did not complete successfully. &stateDetails;
%put %str(ERR)OR: Job &&jobname&i. did not complete. &stateDetails;
%return;
%end;
%end;
%end;
%end;
@@ -238,7 +251,12 @@ run;
%end;
%end;
/* clear refs */
filename &fname0 clear;
%mend;
%if &mdebug=1 %then %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%else %do;
/* clear refs */
filename &fname0 clear;
%end;
%mend mv_jobwaitfor;

View File

@@ -4,15 +4,17 @@
@details When building apps on SAS Viya, an client id and secret is required.
This macro will obtain the Consul Token and use that to call the Web Service.
more info: https://developer.sas.com/reference/auth/#register
and: http://proc-x.com/2019/01/authentication-to-sas-viya-a-couple-of-approaches/
more info: https://developer.sas.com/reference/auth/#register
and:
http://proc-x.com/2019/01/authentication-to-sas-viya-a-couple-of-approaches
The default viyaroot location is /opt/sas/viya/config
Usage:
%* compile macros;
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
%* specific client with just openid scope;
@@ -33,7 +35,8 @@
@param client_id= The client name. Auto generated if blank.
@param client_secret= Client secret Auto generated if client is blank.
@param scopes= list of space-seperated unquoted scopes (default is openid)
@param grant_type= valid values are "password" or "authorization_code" (unquoted)
@param grant_type= valid values are "password" or "authorization_code"
(unquoted)
@param outds= the dataset to contain the registered client id and secret
@param access_token_validity= The duration of validity of the access token
in seconds. A value of DEFAULT will omit the entry (and use system default)
@@ -78,15 +81,16 @@
,refresh_token_validity=DEFAULT
,outjson=_null_
);
%local consul_token fname1 fname2 fname3 libref access_token url;
%local consul_token fname1 fname2 fname3 libref access_token url tokloc;
%if client_name=DEFAULT %then %let client_name=
Generated by %mf_getuser() on %sysfunc(datetime(),datetime19.) using SASjs;
options noquotelenmax;
/* first, get consul token needed to get client id / secret */
%let tokloc=/etc/SASSecurityCertificateFramework/tokens/consul/default;
data _null_;
infile "%mf_loc(VIYACONFIG)/etc/SASSecurityCertificateFramework/tokens/consul/default/client.token";
infile "%mf_loc(VIYACONFIG)&tokloc/client.token";
input token:$64.;
call symputx('consul_token',token);
run;
@@ -97,8 +101,9 @@ run;
/* request the client details */
%let fname1=%mf_getuniquefileref();
proc http method='POST' out=&fname1
url="&base_uri/SASLogon/oauth/clients/consul?callback=false%str(&)serviceId=app";
headers "X-Consul-Token"="&consul_token";
url="&base_uri/SASLogon/oauth/clients/consul?callback=false%str(&)%trim(
)serviceId=app";
headers "X-Consul-Token"="&consul_token";
run;
%let libref=%mf_getuniquelibref();
@@ -111,8 +116,8 @@ data _null_;
run;
/**
* register the new client
*/
* register the new client
*/
%let fname2=%mf_getuniquefileref();
%if x&client_id.x=xx %then %do;
%let client_id=client_%sysfunc(ranuni(0),hex16.);
@@ -122,7 +127,8 @@ run;
%let scopes=%sysfunc(coalescec(&scopes,openid));
%let scopes=%mf_getquotedstr(&scopes,QUOTE=D,indlm=|);
%let grant_type=%mf_getquotedstr(&grant_type,QUOTE=D,indlm=|);
%let required_user_groups=%mf_getquotedstr(&required_user_groups,QUOTE=D,indlm=|);
%let required_user_groups=
%mf_getquotedstr(&required_user_groups,QUOTE=D,indlm=|);
data _null_;
file &fname2;
@@ -139,9 +145,11 @@ data _null_;
if reqd_groups = '""' then reqd_groups ='';
else reqd_groups=cats(',"required_user_groups":[',reqd_groups,']');
autoapprove=trim(symget('autoapprove'));
if not missing(autoapprove) then autoapprove=cats(',"autoapprove":',autoapprove);
if not missing(autoapprove) then autoapprove=
cats(',"autoapprove":',autoapprove);
use_session=trim(symget('use_session'));
if not missing(use_session) then use_session=cats(',"use_session":',use_session);
if not missing(use_session) then use_session=
cats(',"use_session":',use_session);
put '{' clientid ;
put clientsecret ;
@@ -206,10 +214,12 @@ run;
%put GRANT_TYPE=&grant_type;
%put;
%if %index(%superq(grant_type),authorization_code) %then %do;
/* cannot use base_uri here as it includes the protocol which may be incorrect externally */
%put NOTE: The developer must also register below and select 'openid' to get the grant code:;
/* cannot use base_uri here as it includes the protocol which may be incorrect
externally */
%put NOTE: Visit the link below and select 'openid' to get the grant code:;
%put NOTE- ;
%put NOTE- &url/SASLogon/oauth/authorize?client_id=&client_id%str(&)response_type=code;
%put NOTE- &url/SASLogon/oauth/authorize?client_id=&client_id%str(&)%trim(
)response_type=code;
%put NOTE- ;
%end;

View File

@@ -15,7 +15,8 @@
Usage:
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
@@ -31,13 +32,15 @@
@param outds= A dataset containing access_token and refresh_token
@param client_id= The client name
@param client_secret= client secret
@param grant_type= valid values are "password" or "authorization_code" (unquoted).
The default is authorization_code.
@param code= If grant_type=authorization_code then provide the necessary code here
@param grant_type= valid values are "password" or "authorization_code"
(unquoted). The default is authorization_code.
@param code= If grant_type=authorization_code then provide the necessary code
here
@param user= If grant_type=password then provide the username here
@param pass= If grant_type=password then provide the password here
@param access_token_var= The global macro variable to contain the access token
@param refresh_token_var= The global macro variable to contain the refresh token
@param refresh_token_var= The global macro variable to contain the refresh
token
@param base_uri= The Viya API server location
@version VIYA V.03.04
@@ -88,7 +91,8 @@
,msg=%str(Authorization code required)
)
%mp_abort(iftrue=(&grant_type=password and (%str(&user)=%str() or %str(&pass)=%str()))
%mp_abort(iftrue=(
&grant_type=password and (%str(&user)=%str() or %str(&pass)=%str()))
,mac=&sysmacroname
,msg=%str(username / password required)
)
@@ -99,7 +103,7 @@
data _null_;
file &fref1;
if "&grant_type"='authorization_code' then string=cats(
'grant_type=authorization_code&code=',symget('code'));
'grant_type=authorization_code&code=',symget('code'));
else string=cats('grant_type=password&username=',symget('user')
,'&password=',symget(pass));
call symputx('grantstring',cats("'",string,"'"));
@@ -107,8 +111,8 @@ run;
/*data _null_;infile &fref1;input;put _infile_;run;*/
/**
* Request access token
*/
* Request access token
*/
%if &base_uri=#NOTSET# %then %let base_uri=%mf_getplatform(VIYARESTAPI);
%let fref2=%mf_getuniquefileref();
@@ -123,8 +127,8 @@ run;
/*data _null_;infile &fref2;input;put _infile_;run;*/
/**
* Extract access / refresh tokens
*/
* Extract access / refresh tokens
*/
%let libref=%mf_getuniquelibref();
libname &libref JSON fileref=&fref2;

View File

@@ -32,12 +32,13 @@
@param outds= A dataset containing access_token and refresh_token
@param client_id= The client name (alternative to inds)
@param client_secret= client secret (alternative to inds)
@param grant_type= valid values are "password" or "authorization_code" (unquoted).
The default is authorization_code.
@param grant_type= valid values are "password" or "authorization_code"
(unquoted). The default is authorization_code.
@param user= If grant_type=password then provide the username here
@param pass= If grant_type=password then provide the password here
@param access_token_var= The global macro variable to contain the access token
@param refresh_token_var= The global macro variable containing the refresh token
@param refresh_token_var= The global macro variable containing the refresh
token
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
@@ -72,7 +73,8 @@ options noquotelenmax;
,msg=%str(Invalid value for grant_type: &grant_type)
)
%mp_abort(iftrue=(&grant_type=password and (%str(&user)=%str() or %str(&pass)=%str()))
%mp_abort(
iftrue=(&grant_type=password and (%str(&user)=%str() or %str(&pass)=%str()))
,mac=&sysmacroname
,msg=%str(username / password required)
)
@@ -92,8 +94,8 @@ options noquotelenmax;
)
/**
* Request access token
*/
* Request access token
*/
%local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI);
@@ -111,8 +113,8 @@ run;
/*data _null_;infile &fref1;input;put _infile_;run;*/
/**
* Extract access / refresh tokens
*/
* Extract access / refresh tokens
*/
%let libref=%mf_getuniquelibref();
libname &libref JSON fileref=&fref1;

View File

@@ -1,5 +1,5 @@
/**
@file mv_webout.sas
@file
@brief Send data to/from the SAS Viya Job Execution Service
@details This macro should be added to the start of each Job Execution
Service, **immediately** followed by a call to:
@@ -11,7 +11,7 @@
following syntax:
data some datasets; * make some data ;
retain some columns;
retain some columns;
run;
%mv_webout(OPEN)
@@ -109,7 +109,8 @@
if _n_=1 then call symputx('input_statement',_infile_);
list;
data &table;
infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd termstr=crlf;
infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd
termstr=crlf;
input &input_statement;
run;
%end;
@@ -141,7 +142,7 @@
/* setup webout */
OPTIONS NOBOMFILE;
%if "X&SYS_JES_JOB_URI.X"="XX" %then %do;
filename _webout temp lrecl=999999 mod;
filename _webout temp lrecl=999999 mod;
%end;
%else %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
@@ -150,7 +151,8 @@
/* setup temp ref */
%if %upcase(&fref) ne _WEBOUT %then %do;
filename &fref temp lrecl=999999 permission='A::u::rwx,A::g::rw-,A::o::---' mod;
filename &fref temp lrecl=999999 permission='A::u::rwx,A::g::rw-,A::o::---'
mod;
%end;
/* setup json */
@@ -160,7 +162,7 @@
%end;
%else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt
,jref=&fref,engine=PROCJSON,dbg=%str(&_debug)
,jref=&fref,engine=DATASTEP,dbg=%str(&_debug)
)
%end;
%else %if &action=CLOSE %then %do;