1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-23 03:01:20 +00:00

Compare commits

..

22 Commits

Author SHA1 Message Date
Allan Bowe
1fdbc7cce9 Merge pull request #193 from sasjs/mm_spkexport
feat: ignorevars option in mm_spkexport, and log update in mf_verifymacvars
2022-03-10 19:28:50 +02:00
munja
312369b200 feat: ignorevars option in mm_spkexport, and log update in mf_verifymacvars 2022-03-10 17:27:30 +00:00
Allan Bowe
c030174bfb Merge pull request #192 from sasjs/bugfix
fix: dependency in mp_loadformat test and strict mode issue in mm_deletelibrary
2022-03-09 16:16:32 +02:00
munja
faf466e79a fix: dependency in mp_loadformat test and strict mode issue in mm_deletelibrary 2022-03-09 14:15:25 +00:00
Allan Bowe
856ffc1b72 Merge pull request #191 from sasjs/allanbowe/mp-loadformat-not-appending-190
fix: ensuring audit table gets loaded in mp_loadformat.
2022-03-08 21:50:42 +02:00
munja
c0924af06b fix: correcting test for mp_loadformat 2022-03-08 19:50:01 +00:00
munja
33cec61a13 fix: quoting mf_getuser in case of commas. Fixes #189 2022-03-08 19:40:22 +00:00
munja
854ff696d8 fix: adding missing dependency in mp_loadformat 2022-03-08 19:33:46 +00:00
Allan Bowe
cc3435d13d fix: ensuring audit table gets loaded in mp_loadformat. Adding test also. Closes #190 2022-03-08 16:52:22 +00:00
Allan Bowe
5ceaac195d Merge pull request #188 from sasjs/hex32
fix: adding explicit $ sign to hex32. format in mp_md5() macro
2022-03-07 22:38:57 +02:00
Allan Bowe
5d5df977a6 fix: adding explicit $ sign to hex32. format in mp_md5() macro 2022-03-07 19:57:25 +00:00
Allan Bowe
245e85ef36 Merge pull request #187 from sasjs/periodproblem
fix: mp_replace and mv_getjobcode were not ingesting periods correctly
2022-03-07 16:27:14 +02:00
munja
b96df6f14f fix: mp_replace and mv_getjobcode were not ingesting periods correctly 2022-03-07 14:25:05 +00:00
Allan Bowe
1932c1e138 Merge pull request #186 from sasjs/issue185
Issue185
2022-03-07 12:45:18 +02:00
munja
f7ee012be3 fix: updating all.sas 2022-03-07 10:45:06 +00:00
munja
b49e11bc79 fix: upgrading mv_deleteviyafolder for viya 4 (and adding test) 2022-03-07 09:36:30 +00:00
munja
f709a11dfb fix: removing lua dependency from mv_getjoblog to enable viya 4 2022-03-06 22:04:51 +00:00
munja
17ed2240d3 fix: removing lua from mv_getjobcode to enable Viya 4 compatibility 2022-03-06 21:01:02 +00:00
munja
a8b5107b1a fix: remove mcf_stpsrv_header function (no longer needed, replaced with mfs_httpheader which is more reliable and faster 2022-03-06 13:44:42 +00:00
munja
735bab5d26 feat: viya4 config 2022-03-06 13:44:16 +00:00
Allan Bowe
86f7876f50 Merge pull request #184 from sasjs/issue181
feat: ms_getfile service (and test).  Closes #181
2022-03-06 14:40:59 +02:00
munja
46c96bc7ec feat: ms_getfile service (and test). Closes #181 2022-03-06 12:40:03 +00:00
28 changed files with 687 additions and 545 deletions

485
all.sas
View File

@@ -1066,7 +1066,8 @@ or %index(&pgm,/tests/testteardown)
%else %if %symexist(&metavar) %then %do; %else %if %symexist(&metavar) %then %do;
%if %length(&&&metavar)=0 %then %let user=&sysuserid; %if %length(&&&metavar)=0 %then %let user=&sysuserid;
/* sometimes SAS will add @domain extension - remove for consistency */ /* sometimes SAS will add @domain extension - remove for consistency */
%else %let user=%scan(&&&metavar,1,@); /* but be sure to quote in case of usernames with commas */
%else %let user=%unquote(%scan(%quote(&&&metavar),1,@));
%end; %end;
%else %let user=&sysuserid; %else %let user=&sysuserid;
@@ -1889,7 +1890,7 @@ Usage:
%goto exit_success; %goto exit_success;
%exit_err: %exit_err:
%put %str(ERR)OR: &abortmsg; %put &abortmsg;
%mf_abort(iftrue=(&mabort ne SOFT), %mf_abort(iftrue=(&mabort ne SOFT),
mac=mf_verifymacvars, mac=mf_verifymacvars,
msg=%str(&abortmsg) msg=%str(&abortmsg)
@@ -7573,6 +7574,11 @@ create table &outds as
outfile=0 outfile=0
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if "%substr(&sysver,1,4)"="V.04" %then %do;
%put %str(ERR)OR: Viya 4 does not support the IO library in lua;
%return;
%end;
%ml_gsubfile() %ml_gsubfile()
%mend mp_gsubfile; %mend mp_gsubfile;
@@ -7932,7 +7938,7 @@ run;
@param [in] salt= Provide a salt (could be, for instance, the dataset name) @param [in] salt= Provide a salt (could be, for instance, the dataset name)
@param [in] iftrue= A condition under which the macro should be executed. @param [in] iftrue= A condition under which the macro should be executed.
@param [out] outds= (work.mf_hashdataset) The output dataset to create. This @param [out] outds= (work.mf_hashdataset) The output dataset to create. This
will contain one column (hashkey) with one observation (a hex32. will contain one column (hashkey) with one observation (a $hex32.
representation of the input hash) representation of the input hash)
|hashkey:$32.| |hashkey:$32.|
|---| |---|
@@ -8635,13 +8641,13 @@ select distinct lowcase(memname)
@li mp_abort.sas @li mp_abort.sas
@li mp_cntlout.sas @li mp_cntlout.sas
@li mp_lockanytable.sas @li mp_lockanytable.sas
@li mp_storediffs.sas
<h4> Related Macros </h4> <h4> Related Macros </h4>
@li mddl_dc_difftable.sas @li mddl_dc_difftable.sas
@li mddl_dc_locktable.sas @li mddl_dc_locktable.sas
@li mp_loadformat.test.sas @li mp_loadformat.test.sas
@li mp_lockanytable.sas @li mp_lockanytable.sas
@li mp_storediffs.sas
@li mp_stackdiffs.sas @li mp_stackdiffs.sas
@@ -8867,6 +8873,9 @@ options ibufsize=&ibufsize;
,mdebug=&mdebug ,mdebug=&mdebug
) )
proc append base=&auditlibds data=&storediffs;
run;
%if &locklibds ne 0 %then %do; %if &locklibds ne 0 %then %do;
%mp_lockanytable(UNLOCK %mp_lockanytable(UNLOCK
,lib=%scan(&auditlibds,1,.) ,lib=%scan(&auditlibds,1,.)
@@ -8890,7 +8899,8 @@ options ibufsize=&ibufsize;
%put &sysmacroname exit vars:; %put &sysmacroname exit vars:;
%put _local_; %put _local_;
%end; %end;
%mend mp_loadformat;/** %mend mp_loadformat;
/**
@file @file
@brief Mechanism for locking tables to prevent parallel modifications @brief Mechanism for locking tables to prevent parallel modifications
@details Uses a control table to enable ANY table to be locked for updates @details Uses a control table to enable ANY table to be locked for updates
@@ -9396,7 +9406,7 @@ put(md5(
&sep put(md5(trim(put(ifn(missing(&var),&var,&var*1),binary64.))),$hex32.) &sep put(md5(trim(put(ifn(missing(&var),&var,&var*1),binary64.))),$hex32.)
%let sep=!!; %let sep=!!;
%end; %end;
),hex32.) ),$hex32.)
%mend mp_md5; %mend mp_md5;
/** /**
@file @file
@@ -9688,7 +9698,7 @@ filename &inref &infile lrecl=1 recfm=n;
data &ds1; data &ds1;
infile &inref; infile &inref;
input sourcechar $ 1. @@; input sourcechar $char1. @@;
format sourcechar hex2.; format sourcechar hex2.;
run; run;
@@ -15081,7 +15091,8 @@ data _null_;
put ' %else %if %symexist(&metavar) %then %do; '; put ' %else %if %symexist(&metavar) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; '; put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
put ' /* sometimes SAS will add @domain extension - remove for consistency */ '; put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
put ' %else %let user=%scan(&&&metavar,1,@); '; put ' /* but be sure to quote in case of usernames with commas */ ';
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); ';
put ' %end; '; put ' %end; ';
put ' %else %let user=&sysuserid; '; put ' %else %let user=&sysuserid; ';
put ' '; put ' ';
@@ -15302,6 +15313,7 @@ filename &fname2 clear;
%local isgone; %local isgone;
data _null_; data _null_;
length type uri $256; length type uri $256;
call missing (of _all_);
rc=metadata_resolve("omsobj:SASLibrary?@Id='&liburi'",type,uri); rc=metadata_resolve("omsobj:SASLibrary?@Id='&liburi'",type,uri);
call symputx('isgone',type,'l'); call symputx('isgone',type,'l');
run; run;
@@ -17714,20 +17726,25 @@ filename __shake clear;
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
@li mf_isblank.sas
@li mf_loc.sas @li mf_loc.sas
@li mm_tree.sas @li mm_tree.sas
@li mf_getuniquefileref.sas
@li mf_isblank.sas
@li mp_abort.sas @li mp_abort.sas
@param metaloc= the metadata folder to export
@param secureref= fileref containing the username / password (should point to @param [in] metaloc= the metadata folder to export
a file in a secure location). Leave blank to substitute $bash type vars. @param [in] secureref= fileref containing the username / password (should
@param outref= fileref to which to write the command point to a file in a secure location). Leave blank to substitute $bash vars.
@param cmdoutloc= the directory to which the command will write the SPK @param [in] excludevars= (0) A space seperated list of macro variable names,
(default=WORK) each of which contains a value that should be used to filter the output
@param cmdoutname= the name of the spk / log files to create (will be objects.
identical just with .spk or .log extension) @param [out] outref= fileref to which to write the command
@param [out] cmdoutloc= (%sysfunc(pathname(work))) The directory to which the
command will write the SPK
@param [out] cmdoutname= (mmxport) The name of the spk / log files to create
(will be identical just with .spk or .log extension)
@version 9.4 @version 9.4
@author Allan Bowe @author Allan Bowe
@@ -17736,6 +17753,7 @@ filename __shake clear;
%macro mm_spkexport(metaloc= %macro mm_spkexport(metaloc=
,secureref= ,secureref=
,excludevars=0
,outref= ,outref=
,cmdoutloc=%sysfunc(pathname(work)) ,cmdoutloc=%sysfunc(pathname(work))
,cmdoutname=mmxport ,cmdoutname=mmxport
@@ -17747,7 +17765,7 @@ filename __shake clear;
%end; %end;
/* set creds */ /* set creds */
%local mmxuser mmxpath; %local mmxuser mmxpath i var;
%let mmxuser=$1; %let mmxuser=$1;
%let mmxpass=$2; %let mmxpass=$2;
%if %mf_isblank(&secureref)=0 %then %do; %if %mf_isblank(&secureref)=0 %then %do;
@@ -17755,38 +17773,47 @@ filename __shake clear;
%end; %end;
/* setup metadata connection options */ /* setup metadata connection options */
%local host port platform_object_path connx_string; %local host port platform_object_path ds;
%let host=%sysfunc(getoption(metaserver)); %let host=%sysfunc(getoption(metaserver));
%let port=%sysfunc(getoption(metaport)); %let port=%sysfunc(getoption(metaport));
%let platform_object_path=%mf_loc(POF); %let platform_object_path=%mf_loc(POF);
%let ds=%mf_getuniquename(prefix=spkexportable);
%let connx_string=%str(-host &host -port &port -user &mmxuser %trim( %mm_tree(root=%str(&metaloc) ,types=EXPORTABLE ,outds=&ds)
)-password &mmxpass);
%mm_tree(root=%str(&metaloc) ,types=EXPORTABLE ,outds=exportable)
%if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref(); %if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref();
data _null_; data _null_;
set exportable end=last; set &ds end=last;
file &outref lrecl=32767; file &outref lrecl=32767;
length str $32767; length str $32767;
if _n_=1 then do; if _n_=1 then do;
put "cd ""&platform_object_path"" \"; put "cd ""&platform_object_path"" \";
put "; ./ExportPackage &connx_string -disableX11 \"; put "; ./ExportPackage -host &host -port &port -user &mmxuser \";
put " -package ""&cmdoutloc/&cmdoutname..spk"" \"; put " -disableX11 -password &mmxpass \"
put " -package ""&cmdoutloc/&cmdoutname..spk"" \";
end; end;
/* exclude particular patterns from the exported SPK */
%if "&excludevars" ne "0" %then %do;
/* ignore top level folder else all subcontent will be exported regardless */
if _n_>1;
%do i=1 %to %sysfunc(countw(&excludevars));
%let var=%scan(&excludevars,&i);
if index(path,symget("&var")) ne 0;
%end;
%end;
str=' -objects '!!cats('"',path,'/',name,"(",publictype,')" \'); str=' -objects '!!cats('"',path,'/',name,"(",publictype,')" \');
put str; put str;
if last then put " -log ""&cmdoutloc/&cmdoutname..log"" 2>&1 "; if last then put " -log ""&cmdoutloc/&cmdoutname..log"" 2>&1 ";
run; run;
%mp_abort(iftrue= (&syscc ne 0) %mp_abort(iftrue= (&syscc ne 0)
,mac=&sysmacroname ,mac=mm_spkexport
,msg=%str(syscc=&syscc) ,msg=%str(syscc=&syscc)
) )
%mend mm_spkexport;/** %mend mm_spkexport;
/**
@file mm_tree.sas @file mm_tree.sas
@brief Returns all folders / subfolder content for a particular root @brief Returns all folders / subfolder content for a particular root
@details Shows all members and SubTrees for a particular root. @details Shows all members and SubTrees for a particular root.
@@ -18854,6 +18881,38 @@ run;
) )
%mend ms_createfile; %mend ms_createfile;
/**
@file
@brief Gets a file from SASjs Drive
@details Fetches a file on SASjs Drive and stores it in the output fileref.
Example:
%ms_getfile(/some/stored/file.ext, outref=myfile)
@param [in] driveloc The full path to the file in SASjs Drive
@param [out] outref= (msgetfil) The fileref to contain the file.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
**/
%macro ms_getfile(driveloc
,outref=msgetfil
,mdebug=0
);
filename &outref temp;
proc http method='GET' out=&outref
url="&_sasjs_apiserverurl/SASjsApi/drive/file?filePath=&driveloc";
%if &mdebug=1 %then %do;
debug level=2;
%end;
run;
%mend ms_getfile;
/** /**
@file @file
@brief Executes a SASjs Server Stored Program @brief Executes a SASjs Server Stored Program
@@ -20499,7 +20558,8 @@ data _null_;
put ' %else %if %symexist(&metavar) %then %do; '; put ' %else %if %symexist(&metavar) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; '; put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
put ' /* sometimes SAS will add @domain extension - remove for consistency */ '; put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
put ' %else %let user=%scan(&&&metavar,1,@); '; put ' /* but be sure to quote in case of usernames with commas */ ';
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); ';
put ' %end; '; put ' %end; ';
put ' %else %let user=&sysuserid; '; put ' %else %let user=&sysuserid; ';
put ' '; put ' ';
@@ -20969,10 +21029,16 @@ libname &libref1a clear;
%mv_deleteviyafolder(path=/Public/test) %mv_deleteviyafolder(path=/Public/test)
@param path= The full path of the folder to be deleted @param [in] path= The full path of the folder to be deleted
@param access_token_var= The global macro variable to contain the access token @param [in] access_token_var= (ACCESS_TOKEN) The global macro variable to
@param grant_type= valid values are "password" or "authorization_code" (unquoted). contain the access token
The default is authorization_code. @param [in] grant_type= (sas_services) Valid values are:
@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] mdebug= (0) Set to 1 to enable DEBUG messages
@version VIYA V.03.04 @version VIYA V.03.04
@@ -20990,6 +21056,7 @@ libname &libref1a clear;
%macro mv_deleteviyafolder(path= %macro mv_deleteviyafolder(path=
,access_token_var=ACCESS_TOKEN ,access_token_var=ACCESS_TOKEN
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0
); );
%local oauth_bearer; %local oauth_bearer;
%if &grant_type=detect %then %do; %if &grant_type=detect %then %do;
@@ -21066,14 +21133,17 @@ run;
%let libref1a=%mf_getuniquelibref(); %let libref1a=%mf_getuniquelibref();
libname &libref1a JSON fileref=&fname1a; libname &libref1a JSON fileref=&fname1a;
data _null_; %if %mf_existds(&libref1a..items_links) %then %do;
set &libref1a..items_links; data _null_;
if href=:'/folders/folders' then return; set &libref1a..items_links;
if rel='deleteResource' then if href=:'/folders/folders' then return;
call execute('proc http method="DELETE" url='!!quote("&base_uri"!!trim(href)) if rel='deleteResource' then
!!'; headers "Authorization"="Bearer &&&access_token_var" ' call execute('proc http method="DELETE" url='
!!' "Accept"="*/*";run; /**/'); !!quote("&base_uri"!!trim(href))
run; !!'; headers "Authorization"="Bearer &&&access_token_var" '
!!' "Accept"="*/*";run; /**/');
run;
%end;
%put &sysmacroname: perform the delete operation ; %put &sysmacroname: perform the delete operation ;
%local fname2; %local fname2;
@@ -21094,12 +21164,15 @@ run;
%end; %end;
%else %put &sysmacroname: &path successfully deleted; %else %put &sysmacroname: &path successfully deleted;
/* clear refs */ %if &mdebug=0 %then %do;
filename &fname1 clear; /* clear refs */
filename &fname2 clear; filename &fname1 clear;
libname &libref1 clear; filename &fname2 clear;
libname &libref1 clear;
%end;
%mend mv_deleteviyafolder;/** %mend mv_deleteviyafolder;
/**
@file mv_getclients.sas @file mv_getclients.sas
@brief Get a list of Viya Clients @brief Get a list of Viya Clients
@details First, be sure you have an access token (which requires an app token). @details First, be sure you have an access token (which requires an app token).
@@ -21477,7 +21550,7 @@ filename &fname1 clear;
,grant_type=sas_services ,grant_type=sas_services
,outds=work.viyagroups ,outds=work.viyagroups
); );
%local oauth_bearer; %local oauth_bearer base_uri fname1 libref1;
%if &grant_type=detect %then %do; %if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code; %if %symexist(&access_token_var) %then %let grant_type=authorization_code;
%else %let grant_type=sas_services; %else %let grant_type=sas_services;
@@ -21495,11 +21568,10 @@ filename &fname1 clear;
) )
options noquotelenmax; options noquotelenmax;
%local base_uri; /* location of rest apis */ /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI); %let base_uri=%mf_getplatform(VIYARESTAPI);
/* fetching folder details for provided path */ /* fetching folder details for provided path */
%local fname1;
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
%let libref1=%mf_getuniquelibref(); %let libref1=%mf_getuniquelibref();
@@ -21523,12 +21595,12 @@ data &outds;
run; run;
/* clear refs */ /* clear refs */
filename &fname1 clear; filename &fname1 clear;
libname &libref1 clear; libname &libref1 clear;
%mend mv_getgroups;/** %mend mv_getgroups;
/**
@file @file
@brief Extract the source code from a SAS Viya Job @brief Extract the source code from a SAS Viya Job
@details Extracts the SAS code from a Job into a fileref or physical file. @details Extracts the SAS code from a Job into a fileref or physical file.
@@ -21563,7 +21635,6 @@ libname &libref1 clear;
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mv_getfoldermembers.sas @li mv_getfoldermembers.sas
@li ml_json.sas
**/ **/
@@ -21574,9 +21645,9 @@ libname &libref1 clear;
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0 ,mdebug=0
); );
%local dbg; %local dbg bufsize varcnt fname1 fname2 errmsg;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname entry vars:; %put &sysmacroname local entry vars:;
%put _local_; %put _local_;
%end; %end;
%else %let dbg=*; %else %let dbg=*;
@@ -21634,7 +21705,6 @@ run;
) )
/* prepare request*/ /* prepare request*/
%local fname1;
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&joburi"; url="&base_uri&joburi";
@@ -21644,37 +21714,95 @@ proc http method='GET' out=&fname1 &oauth_bearer
%end; %end;
; ;
run; 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;
%local fname2 fname3 fpath1 fpath2 fpath3;
%let fname2=%mf_getuniquefileref();
%let fname3=%mf_getuniquefileref();
%let fpath1=%sysfunc(pathname(&fname1));
%let fpath2=%sysfunc(pathname(&fname2));
%let fpath3=%sysfunc(pathname(&fname3));
/* compile the lua JSON module */ %if &mdebug=1 %then %do;
%ml_json() data _null_;
/* read using LUA - this allows the code to be of any length */ infile &fname1;
input;
putlog _infile_;
run;
%end;
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
,mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%let fname2=%mf_getuniquefileref();
filename &fname2 temp ;
/* cannot use lua IO package as not available in Viya 4 */
/* so use data step to read the JSON until the string `"code":"` is found */
data _null_; data _null_;
file "&fpath3..lua"; file &fname2 recfm=n;
put ' infile &fname1 lrecl=1 recfm=n;
infile = io.open (sas.symget("fpath1"), "r") input sourcechar $char1. @@;
outfile = io.open (sas.symget("fpath2"), "w") format sourcechar hex2.;
io.input(infile) retain startwrite 0;
local resp=json.decode(io.read()) if startwrite=0 and sourcechar='"' then do;
local job=resp["code"] reentry:
outfile:write(job) input sourcechar $ 1. @@;
io.close(infile) if sourcechar='c' then do;
io.close(outfile) reentry2:
'; input sourcechar $ 1. @@;
if sourcechar='o' then do;
input sourcechar $ 1. @@;
if sourcechar='d' then do;
input sourcechar $ 1. @@;
if sourcechar='e' then do;
input sourcechar $ 1. @@;
if sourcechar='"' then do;
input sourcechar $ 1. @@;
if sourcechar=':' then do;
input sourcechar $ 1. @@;
if sourcechar='"' then do;
putlog 'code found';
startwrite=1;
input sourcechar $ 1. @@;
end;
end;
else if sourcechar='c' then goto reentry2;
end;
end;
else if sourcechar='"' then goto reentry;
end;
else if sourcechar='"' then goto reentry;
end;
else if sourcechar='"' then goto reentry;
end;
else if sourcechar='"' then goto reentry;
end;
/* once the `"code":"` string is found, write until unescaped `"` is found */
if startwrite=1 then do;
if sourcechar='\' then do;
input sourcechar $ 1. @@;
if sourcechar in ('"','\') then put sourcechar char1.;
else if sourcechar='n' then put '0A'x;
else if sourcechar='r' then put '0D'x;
else if sourcechar='t' then put '09'x;
else if sourcechar='u' then do;
length uni $4;
input uni $ 4. @@;
sourcechar=unicode('\u'!!uni);
put sourcechar char1.;
end;
else do;
call symputx('errmsg',"Uncaught escape char: "!!sourcechar,'l');
call symputx('syscc',99);
stop;
end;
end;
else if sourcechar='"' then stop;
else put sourcechar char1.;
end;
run; run;
%inc "&fpath3..lua";
%mp_abort(iftrue=("&syscc"="99")
,mac=mv_getjobcode
,msg=%str(&errmsg)
)
/* export to desired destination */ /* export to desired destination */
%if "&outref"="0" %then %do; %if "&outref"="0" %then %do;
data _null_; data _null_;
@@ -21699,7 +21827,6 @@ run;
/* clear refs */ /* clear refs */
filename &fname1 clear; filename &fname1 clear;
filename &fname2 clear; filename &fname2 clear;
filename &fname3 clear;
%end; %end;
%mend mv_getjobcode; %mend mv_getjobcode;
@@ -21791,7 +21918,8 @@ run;
@li mp_abort.sas @li mp_abort.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_existfileref.sas @li mf_existfileref.sas
@li ml_json.sas @li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
**/ **/
@@ -21800,7 +21928,7 @@ run;
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0 ,mdebug=0
); );
%local dbg; %local dbg libref1 libref2 loglocation fname1 fname2;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname entry vars:; %put &sysmacroname entry vars:;
%put _local_; %put _local_;
@@ -21859,8 +21987,8 @@ options noquotelenmax;
%let base_uri=%mf_getplatform(VIYARESTAPI); %let base_uri=%mf_getplatform(VIYARESTAPI);
/* prepare request*/ /* prepare request*/
%local fname1;
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
%let fname2=%mf_getuniquefileref();
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&uri"; url="&base_uri&uri";
headers headers
@@ -21880,37 +22008,19 @@ run;
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE) ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
) )
%end; %end;
%local fname2 fname3 fpath1 fpath2 fpath3;
%let fname2=%mf_getuniquefileref();
%let fname3=%mf_getuniquefileref();
%let fpath1=%sysfunc(pathname(&fname1));
%let fpath2=%sysfunc(pathname(&fname2));
%let fpath3=%sysfunc(pathname(&fname3));
/* compile the lua JSON module */ %let libref1=%mf_getuniquelibref();
%ml_json() libname &libref1 JSON fileref=&fname1;
/* read using LUA - this allows the code to be of any length */
data _null_; data _null_;
file "&fpath3..lua"; set &libref1..root;
put ' call symputx('loglocation',loglocation,'l');
infile = io.open (sas.symget("fpath1"), "r")
outfile = io.open (sas.symget("fpath2"), "w")
io.input(infile)
local resp=json.decode(io.read())
local logloc=resp["logLocation"]
outfile:write(logloc)
io.close(infile)
io.close(outfile)
';
run; run;
%inc "&fpath3..lua";
/* get log path*/ /* validate log path*/
%let errflg=1; %let errflg=1;
%let errmsg=No entry in &fname2 fileref; %let errmsg=No loglocation entry in &fname1 fileref;
data _null_; data _null_;
infile &fname2; uri=symget('loglocation');
input;
uri=cats(_infile_);
if length(uri)<12 then do; if length(uri)<12 then do;
call symputx('errflg',1); call symputx('errflg',1);
call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l'); call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
@@ -21937,7 +22047,7 @@ run;
/* we have a log uri - now fetch the log */ /* we have a log uri - now fetch the log */
%&dbg.put &sysmacroname: querying &base_uri&logloc/content; %&dbg.put &sysmacroname: querying &base_uri&logloc/content;
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname2 &oauth_bearer
url="&base_uri&logloc/content?limit=10000"; url="&base_uri&logloc/content?limit=10000";
headers headers
%if &grant_type=authorization_code %then %do; %if &grant_type=authorization_code %then %do;
@@ -21948,14 +22058,14 @@ run;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname: fetching log content from &base_uri&logloc/content; %put &sysmacroname: fetching log content from &base_uri&logloc/content;
data _null_;infile &fname1;input;putlog _infile_;run; data _null_;infile &fname2;input;putlog _infile_;run;
%end; %end;
%if &SYS_PROCHTTP_STATUS_CODE=400 %then %do; %if &SYS_PROCHTTP_STATUS_CODE=400 %then %do;
/* fetch log from parent session */ /* fetch log from parent session */
%let logloc=%substr(&logloc,1,%index(&logloc,%str(/jobs/))-1); %let logloc=%substr(&logloc,1,%index(&logloc,%str(/jobs/))-1);
%&dbg.put &sysmacroname: Now querying &base_uri&logloc/log/content; %&dbg.put &sysmacroname: Now querying &base_uri&logloc/log/content;
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname2 &oauth_bearer
url="&base_uri&logloc/log/content?limit=10000"; url="&base_uri&logloc/log/content?limit=10000";
headers headers
%if &grant_type=authorization_code %then %do; %if &grant_type=authorization_code %then %do;
@@ -21965,47 +22075,32 @@ run;
run; run;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname: fetching log content from &base_uri&logloc/log/content; %put &sysmacroname: fetching log content from &base_uri&logloc/log/content;
data _null_;infile &fname1;input;putlog _infile_;run; data _null_;infile &fname2;input;putlog _infile_;run;
%end; %end;
%end; %end;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201
%then %do; %then %do;
%if &mdebug ne 1 %then %do; /* have already output above */ %if &mdebug ne 1 %then %do; /* have already output above */
data _null_;infile &fname1;input;putlog _infile_;run; data _null_;infile &fname2;input;putlog _infile_;run;
%end; %end;
%mp_abort(mac=&sysmacroname %mp_abort(mac=&sysmacroname
,msg=%str(logfetch: &SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE) ,msg=%str(logfetch: &SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
) )
%end; %end;
data _null_;
file "&fpath3..lua";
put '
infile = io.open (sas.symget("fpath1"), "r")
outfile = io.open (sas.symget("fpath2"), "w")
io.input(infile)
local resp=json.decode(io.read())
for i, v in pairs(resp["items"]) do
outfile:write(v.line,"\n")
end
io.close(infile)
io.close(outfile)
';
run;
%inc "&fpath3..lua";
/* write log out to the specified fileref */ %let libref2=%mf_getuniquelibref();
libname &libref2 JSON fileref=&fname2;
data _null_; data _null_;
infile &fname2 end=last;
file &outref mod; file &outref mod;
if _n_=1 then do; if _n_=1 then do;
put "/** SASJS Viya Job Log Extract start: &uri **/"; put "/** SASJS Viya Job Log Extract start: &uri **/";
end; end;
input; set &libref2..items end=last;
put _infile_;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
putlog _infile_; putlog line;
%end; %end;
put line;
if last then do; if last then do;
put "/** SASJS Viya Job Log Extract end: &uri **/"; put "/** SASJS Viya Job Log Extract end: &uri **/";
end; end;
@@ -22014,7 +22109,8 @@ run;
%if &mdebug=0 %then %do; %if &mdebug=0 %then %do;
filename &fname1 clear; filename &fname1 clear;
filename &fname2 clear; filename &fname2 clear;
filename &fname3 clear; libname &libref1 clear;
libname &libref2 clear;
%end; %end;
%else %do; %else %do;
%put &sysmacroname exit vars:; %put &sysmacroname exit vars:;
@@ -24971,115 +25067,6 @@ endsub;
%end; %end;
%mend mcf_length;/** %mend mcf_length;/**
@file
@brief Provides a replacement for the stpsrv_header function
@details The stpsrv_header is normally a built-in function, used to set the
headers for SAS 9 Stored Processes as documented here:
https://go.documentation.sas.com/doc/en/itechcdc/9.4/stpug/srvhead.htm
The purpose of this custom function is to provide a replacement when running
similar code as a web service against
[sasjs/server](https://github.com/sasjs/server). It operates by creating a
text file with the headers. The location of this text file is determined by
a macro variable (`sasjs_stpsrv_header_loc`) which needs to be injected into
each service by the calling process, eg:
%let sasjs_stpsrv_header_loc = C:/temp/some_uuid/stpsrv_header.txt;
Note - the function works by appending headers to the file. If multiple same-
named headers are provided, they will all be appended - the calling process
needs to pick up the last one. This will mean removing the attribute if the
final record has an empty value.
The function takes the following (positional) parameters:
| PARAMETER | DESCRIPTION |
|------------|-------------|
| name $ | name of the header attribute to create|
| value $ | value of the header attribute|
It returns 0 if successful, or -1 if an error occured.
Usage:
%let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/stpsrv_header.txt;
%mcf_stpsrv_header(wrap=YES, insert_cmplib=YES)
data _null_;
rc=stpsrv_header('Content-type','application/text');
rc=stpsrv_header('Content-disposition',"attachment; filename=file.txt");
run;
data _null_;
infile "&sasjs_stpsrv_header_loc";
input;
putlog _infile_;
run;
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4>
@li mcf_init.sas
<h4> Related Programs </h4>
@li mcf_stpsrv_header.test.sas
@li mp_init.sas
**/
%macro mcf_stpsrv_header(wrap=NO
,insert_cmplib=DEPRECATED
,lib=WORK
,cat=SASJS
,pkg=UTILS
)/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(stpsrv_header)=1 %then %return;
%if &wrap=YES %then %do;
proc fcmp outlib=&lib..&cat..&pkg;
%end;
function stpsrv_header(name $, value $);
length loc $128 val $512;
loc=symget('sasjs_stpsrv_header_loc');
val=trim(name)!!': '!!value;
length fref $8;
rc=filename(fref,loc);
if (rc ne 0) then return( -1 );
fid = fopen(fref,'a');
if (fid = 0) then return( -1 );
rc=fput(fid, val);
rc=fwrite(fid);
rc=fclose(fid);
rc=filename(fref);
return(0);
endsub;
%if &wrap=YES %then %do;
quit;
%end;
/* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat));
%end;
%mend mcf_stpsrv_header;/**
@file @file
@brief Adds a string to a file @brief Adds a string to a file
@details Creates an fcmp function for appending a string to an external file. @details Creates an fcmp function for appending a string to an external file.

View File

@@ -33,7 +33,8 @@
%else %if %symexist(&metavar) %then %do; %else %if %symexist(&metavar) %then %do;
%if %length(&&&metavar)=0 %then %let user=&sysuserid; %if %length(&&&metavar)=0 %then %let user=&sysuserid;
/* sometimes SAS will add @domain extension - remove for consistency */ /* sometimes SAS will add @domain extension - remove for consistency */
%else %let user=%scan(&&&metavar,1,@); /* but be sure to quote in case of usernames with commas */
%else %let user=%unquote(%scan(%quote(&&&metavar),1,@));
%end; %end;
%else %let user=&sysuserid; %else %let user=&sysuserid;

View File

@@ -59,7 +59,7 @@
%goto exit_success; %goto exit_success;
%exit_err: %exit_err:
%put %str(ERR)OR: &abortmsg; %put &abortmsg;
%mf_abort(iftrue=(&mabort ne SOFT), %mf_abort(iftrue=(&mabort ne SOFT),
mac=mf_verifymacvars, mac=mf_verifymacvars,
msg=%str(&abortmsg) msg=%str(&abortmsg)

View File

@@ -48,6 +48,11 @@
outfile=0 outfile=0
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if "%substr(&sysver,1,4)"="V.04" %then %do;
%put %str(ERR)OR: Viya 4 does not support the IO library in lua;
%return;
%end;
%ml_gsubfile() %ml_gsubfile()
%mend mp_gsubfile; %mend mp_gsubfile;

View File

@@ -23,7 +23,7 @@
@param [in] salt= Provide a salt (could be, for instance, the dataset name) @param [in] salt= Provide a salt (could be, for instance, the dataset name)
@param [in] iftrue= A condition under which the macro should be executed. @param [in] iftrue= A condition under which the macro should be executed.
@param [out] outds= (work.mf_hashdataset) The output dataset to create. This @param [out] outds= (work.mf_hashdataset) The output dataset to create. This
will contain one column (hashkey) with one observation (a hex32. will contain one column (hashkey) with one observation (a $hex32.
representation of the input hash) representation of the input hash)
|hashkey:$32.| |hashkey:$32.|
|---| |---|

View File

@@ -40,13 +40,13 @@
@li mp_abort.sas @li mp_abort.sas
@li mp_cntlout.sas @li mp_cntlout.sas
@li mp_lockanytable.sas @li mp_lockanytable.sas
@li mp_storediffs.sas
<h4> Related Macros </h4> <h4> Related Macros </h4>
@li mddl_dc_difftable.sas @li mddl_dc_difftable.sas
@li mddl_dc_locktable.sas @li mddl_dc_locktable.sas
@li mp_loadformat.test.sas @li mp_loadformat.test.sas
@li mp_lockanytable.sas @li mp_lockanytable.sas
@li mp_storediffs.sas
@li mp_stackdiffs.sas @li mp_stackdiffs.sas
@@ -272,6 +272,9 @@ options ibufsize=&ibufsize;
,mdebug=&mdebug ,mdebug=&mdebug
) )
proc append base=&auditlibds data=&storediffs;
run;
%if &locklibds ne 0 %then %do; %if &locklibds ne 0 %then %do;
%mp_lockanytable(UNLOCK %mp_lockanytable(UNLOCK
,lib=%scan(&auditlibds,1,.) ,lib=%scan(&auditlibds,1,.)
@@ -295,4 +298,4 @@ options ibufsize=&ibufsize;
%put &sysmacroname exit vars:; %put &sysmacroname exit vars:;
%put _local_; %put _local_;
%end; %end;
%mend mp_loadformat; %mend mp_loadformat;

View File

@@ -54,5 +54,5 @@ put(md5(
&sep put(md5(trim(put(ifn(missing(&var),&var,&var*1),binary64.))),$hex32.) &sep put(md5(trim(put(ifn(missing(&var),&var,&var*1),binary64.))),$hex32.)
%let sep=!!; %let sep=!!;
%end; %end;
),hex32.) ),$hex32.)
%mend mp_md5; %mend mp_md5;

View File

@@ -70,7 +70,7 @@ filename &inref &infile lrecl=1 recfm=n;
data &ds1; data &ds1;
infile &inref; infile &inref;
input sourcechar $ 1. @@; input sourcechar $char1. @@;
format sourcechar hex2.; format sourcechar hex2.;
run; run;

View File

@@ -1,110 +0,0 @@
/**
@file
@brief Provides a replacement for the stpsrv_header function
@details The stpsrv_header is normally a built-in function, used to set the
headers for SAS 9 Stored Processes as documented here:
https://go.documentation.sas.com/doc/en/itechcdc/9.4/stpug/srvhead.htm
The purpose of this custom function is to provide a replacement when running
similar code as a web service against
[sasjs/server](https://github.com/sasjs/server). It operates by creating a
text file with the headers. The location of this text file is determined by
a macro variable (`sasjs_stpsrv_header_loc`) which needs to be injected into
each service by the calling process, eg:
%let sasjs_stpsrv_header_loc = C:/temp/some_uuid/stpsrv_header.txt;
Note - the function works by appending headers to the file. If multiple same-
named headers are provided, they will all be appended - the calling process
needs to pick up the last one. This will mean removing the attribute if the
final record has an empty value.
The function takes the following (positional) parameters:
| PARAMETER | DESCRIPTION |
|------------|-------------|
| name $ | name of the header attribute to create|
| value $ | value of the header attribute|
It returns 0 if successful, or -1 if an error occured.
Usage:
%let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/stpsrv_header.txt;
%mcf_stpsrv_header(wrap=YES, insert_cmplib=YES)
data _null_;
rc=stpsrv_header('Content-type','application/text');
rc=stpsrv_header('Content-disposition',"attachment; filename=file.txt");
run;
data _null_;
infile "&sasjs_stpsrv_header_loc";
input;
putlog _infile_;
run;
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4>
@li mcf_init.sas
<h4> Related Programs </h4>
@li mcf_stpsrv_header.test.sas
@li mp_init.sas
**/
%macro mcf_stpsrv_header(wrap=NO
,insert_cmplib=DEPRECATED
,lib=WORK
,cat=SASJS
,pkg=UTILS
)/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(stpsrv_header)=1 %then %return;
%if &wrap=YES %then %do;
proc fcmp outlib=&lib..&cat..&pkg;
%end;
function stpsrv_header(name $, value $);
length loc $128 val $512;
loc=symget('sasjs_stpsrv_header_loc');
val=trim(name)!!': '!!value;
length fref $8;
rc=filename(fref,loc);
if (rc ne 0) then return( -1 );
fid = fopen(fref,'a');
if (fid = 0) then return( -1 );
rc=fput(fid, val);
rc=fwrite(fid);
rc=fclose(fid);
rc=filename(fref);
return(0);
endsub;
%if &wrap=YES %then %do;
quit;
%end;
/* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat));
%end;
%mend mcf_stpsrv_header;

View File

@@ -453,7 +453,8 @@ data _null_;
put ' %else %if %symexist(&metavar) %then %do; '; put ' %else %if %symexist(&metavar) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; '; put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
put ' /* sometimes SAS will add @domain extension - remove for consistency */ '; put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
put ' %else %let user=%scan(&&&metavar,1,@); '; put ' /* but be sure to quote in case of usernames with commas */ ';
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); ';
put ' %end; '; put ' %end; ';
put ' %else %let user=&sysuserid; '; put ' %else %let user=&sysuserid; ';
put ' '; put ' ';

View File

@@ -78,6 +78,7 @@ filename &fname2 clear;
%local isgone; %local isgone;
data _null_; data _null_;
length type uri $256; length type uri $256;
call missing (of _all_);
rc=metadata_resolve("omsobj:SASLibrary?@Id='&liburi'",type,uri); rc=metadata_resolve("omsobj:SASLibrary?@Id='&liburi'",type,uri);
call symputx('isgone',type,'l'); call symputx('isgone',type,'l');
run; run;

View File

@@ -49,20 +49,25 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
@li mf_isblank.sas
@li mf_loc.sas @li mf_loc.sas
@li mm_tree.sas @li mm_tree.sas
@li mf_getuniquefileref.sas
@li mf_isblank.sas
@li mp_abort.sas @li mp_abort.sas
@param metaloc= the metadata folder to export
@param secureref= fileref containing the username / password (should point to @param [in] metaloc= the metadata folder to export
a file in a secure location). Leave blank to substitute $bash type vars. @param [in] secureref= fileref containing the username / password (should
@param outref= fileref to which to write the command point to a file in a secure location). Leave blank to substitute $bash vars.
@param cmdoutloc= the directory to which the command will write the SPK @param [in] excludevars= (0) A space seperated list of macro variable names,
(default=WORK) each of which contains a value that should be used to filter the output
@param cmdoutname= the name of the spk / log files to create (will be objects.
identical just with .spk or .log extension) @param [out] outref= fileref to which to write the command
@param [out] cmdoutloc= (%sysfunc(pathname(work))) The directory to which the
command will write the SPK
@param [out] cmdoutname= (mmxport) The name of the spk / log files to create
(will be identical just with .spk or .log extension)
@version 9.4 @version 9.4
@author Allan Bowe @author Allan Bowe
@@ -71,6 +76,7 @@
%macro mm_spkexport(metaloc= %macro mm_spkexport(metaloc=
,secureref= ,secureref=
,excludevars=0
,outref= ,outref=
,cmdoutloc=%sysfunc(pathname(work)) ,cmdoutloc=%sysfunc(pathname(work))
,cmdoutname=mmxport ,cmdoutname=mmxport
@@ -82,7 +88,7 @@
%end; %end;
/* set creds */ /* set creds */
%local mmxuser mmxpath; %local mmxuser mmxpath i var;
%let mmxuser=$1; %let mmxuser=$1;
%let mmxpass=$2; %let mmxpass=$2;
%if %mf_isblank(&secureref)=0 %then %do; %if %mf_isblank(&secureref)=0 %then %do;
@@ -90,35 +96,43 @@
%end; %end;
/* setup metadata connection options */ /* setup metadata connection options */
%local host port platform_object_path connx_string; %local host port platform_object_path ds;
%let host=%sysfunc(getoption(metaserver)); %let host=%sysfunc(getoption(metaserver));
%let port=%sysfunc(getoption(metaport)); %let port=%sysfunc(getoption(metaport));
%let platform_object_path=%mf_loc(POF); %let platform_object_path=%mf_loc(POF);
%let ds=%mf_getuniquename(prefix=spkexportable);
%let connx_string=%str(-host &host -port &port -user &mmxuser %trim( %mm_tree(root=%str(&metaloc) ,types=EXPORTABLE ,outds=&ds)
)-password &mmxpass);
%mm_tree(root=%str(&metaloc) ,types=EXPORTABLE ,outds=exportable)
%if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref(); %if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref();
data _null_; data _null_;
set exportable end=last; set &ds end=last;
file &outref lrecl=32767; file &outref lrecl=32767;
length str $32767; length str $32767;
if _n_=1 then do; if _n_=1 then do;
put "cd ""&platform_object_path"" \"; put "cd ""&platform_object_path"" \";
put "; ./ExportPackage &connx_string -disableX11 \"; put "; ./ExportPackage -host &host -port &port -user &mmxuser \";
put " -package ""&cmdoutloc/&cmdoutname..spk"" \"; put " -disableX11 -password &mmxpass \"
put " -package ""&cmdoutloc/&cmdoutname..spk"" \";
end; end;
/* exclude particular patterns from the exported SPK */
%if "&excludevars" ne "0" %then %do;
/* ignore top level folder else all subcontent will be exported regardless */
if _n_>1;
%do i=1 %to %sysfunc(countw(&excludevars));
%let var=%scan(&excludevars,&i);
if index(path,symget("&var")) ne 0;
%end;
%end;
str=' -objects '!!cats('"',path,'/',name,"(",publictype,')" \'); str=' -objects '!!cats('"',path,'/',name,"(",publictype,')" \');
put str; put str;
if last then put " -log ""&cmdoutloc/&cmdoutname..log"" 2>&1 "; if last then put " -log ""&cmdoutloc/&cmdoutname..log"" 2>&1 ";
run; run;
%mp_abort(iftrue= (&syscc ne 0) %mp_abort(iftrue= (&syscc ne 0)
,mac=&sysmacroname ,mac=mm_spkexport
,msg=%str(syscc=&syscc) ,msg=%str(syscc=&syscc)
) )
%mend mm_spkexport; %mend mm_spkexport;

View File

@@ -95,6 +95,19 @@
"tests/sas9only", "tests/sas9only",
"tests/viyaonly" "tests/viyaonly"
] ]
},
{
"name": "viya4",
"serverUrl": "https://azureuse011059.my-trials.sas.com",
"serverType": "SASVIYA",
"appLoc": "/Public/temp/macrocore",
"macroFolders": [
"tests/viyaonly"
],
"deployConfig": {
"deployServicePack": true
},
"contextName": "SAS Job Execution compute context"
} }
] ]
} }

32
server/ms_getfile.sas Normal file
View File

@@ -0,0 +1,32 @@
/**
@file
@brief Gets a file from SASjs Drive
@details Fetches a file on SASjs Drive and stores it in the output fileref.
Example:
%ms_getfile(/some/stored/file.ext, outref=myfile)
@param [in] driveloc The full path to the file in SASjs Drive
@param [out] outref= (msgetfil) The fileref to contain the file.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
**/
%macro ms_getfile(driveloc
,outref=msgetfil
,mdebug=0
);
filename &outref temp;
proc http method='GET' out=&outref
url="&_sasjs_apiserverurl/SASjsApi/drive/file?filePath=&driveloc";
%if &mdebug=1 %then %do;
debug level=2;
%end;
run;
%mend ms_getfile;

View File

@@ -1,39 +0,0 @@
/**
@file
@brief Testing mcf_stpsrv_header macro
<h4> SAS Macros </h4>
@li mcf_stpsrv_header.sas
@li mp_assert.sas
**/
%let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/stpsrv_header.txt;
%mcf_stpsrv_header(wrap=YES, insert_cmplib=YES)
data _null_;
rc=stpsrv_header('Content-type','application/text');
rc=stpsrv_header('Content-disposition',"attachment; filename=file.txt");
run;
%let test1=FAIL;
%let test2=FAIL;
data _null_;
infile "&sasjs_stpsrv_header_loc";
input;
if _n_=1 and _infile_='Content-type: application/text'
then call symputx('test1','PASS');
else if _n_=2 & _infile_='Content-disposition: attachment; filename=file.txt'
then call symputx('test2','PASS');
run;
%mp_assert(
iftrue=(%str(&test1)=%str(PASS)),
desc=Check first header line
)
%mp_assert(
iftrue=(%str(&test2)=%str(PASS)),
desc=Check second header line
)

View File

@@ -8,6 +8,13 @@
**/ **/
%macro gsubtest();
%if "%substr(&sysver,1,4)"="V.04" %then %do;
%put %str(ERR)OR: Viya 4 does not support the IO library in lua;
%return;
%end;
/** /**
* test 1 - simple replace * test 1 - simple replace
*/ */
@@ -63,4 +70,8 @@ run;
iftrue=("&strcheck2b"="&str2"), iftrue=("&strcheck2b"="&str2"),
desc=Check that multi line replacement was successful (line3), desc=Check that multi line replacement was successful (line3),
outds=work.test_results outds=work.test_results
) )
%mend gsubtest;
%gsubtest()

View File

@@ -3,6 +3,7 @@
@brief Testing mp_loadformat.sas macro @brief Testing mp_loadformat.sas macro
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mddl_dc_difftable.sas
@li mp_loadformat.sas @li mp_loadformat.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas @li mp_assertscope.sas
@@ -12,6 +13,8 @@
/* prep format catalog */ /* prep format catalog */
libname perm (work); libname perm (work);
%mddl_dc_difftable(libds=perm.audit)
data work.loadfmts; data work.loadfmts;
length fmtname $32; length fmtname $32;
eexcl='Y'; eexcl='Y';
@@ -49,7 +52,7 @@ run;
%mp_loadformat(perm.testcat %mp_loadformat(perm.testcat
,work.stagedata ,work.stagedata
,loadtarget=YES ,loadtarget=YES
,auditlibds=0 ,auditlibds=perm.audit
,locklibds=0 ,locklibds=0
,delete_col=deleteme ,delete_col=deleteme
,outds_add=add_test1 ,outds_add=add_test1
@@ -73,4 +76,9 @@ run;
iftrue=(%mf_nobs(mod_test1)=100), iftrue=(%mf_nobs(mod_test1)=100),
desc=Test 1 - mod obs, desc=Test 1 - mod obs,
outds=work.test_results outds=work.test_results
) )
%mp_assert(
iftrue=(%mf_nobs(perm.audit)=7329),
desc=Test 1 - audit table updated,
outds=work.test_results
)

View File

@@ -63,3 +63,33 @@ run;
desc=Checking second replace 3rd row, desc=Checking second replace 3rd row,
outds=work.test_results outds=work.test_results
) )
%let test3="&sasjswork/file3.txt";
%let str=%str(replace.string.with.dots );
%let rep=%str( more.dots);
data _null_;
file &test3;
put 'blahblah';
put "blahblah&str.blah&str. replace &str.X";
put "blahbreplacewith&str.spacesahblah";
run;
%mp_replace(&test3, findvar=str, replacevar=rep)
data _null_;
infile &test3;
input;
if _n_=2 then call symputx('test3resulta',_infile_);
if _n_=3 then call symputx('test3resultb',_infile_);
run;
%mp_assert(
iftrue=("&test3resulta" = "blahblah&rep.blah&rep. replace &rep.X"),
desc=Checking third replace 2nd row (dots),
outds=work.test_results
)
%mp_assert(
iftrue=("&test3resultb" = "blahbreplacewith&rep.spacesahblah"),
desc=Checking third replace 3rd row (dots),
outds=work.test_results
)

View File

@@ -0,0 +1,41 @@
/**
@file
@brief Testing mm_webout macro
<h4> SAS Macros </h4>
@li mm_spkexport.sas
@li mp_assert.sas
@li mp_as
**/
%* create sample text file as input to the macro;
filename tmp temp;
data _null_;
file tmp;
put '%let mmxuser="sasdemo";';
put '%let mmxpass="Mars321";';
run;
filename myref "%sysfunc(pathname(work))/mmxexport.sh"
permission='A::u::rwx,A::g::r-x,A::o::---';
%mp_assertscope(SNAPSHOT)
%mm_spkexport(metaloc=%str(/Shared Data)
,outref=myref
,secureref=tmp
,cmdoutloc=%str(/tmp)
)
%mp_assertscope(COMPARE)
data _null_;
infile tmp;
input;
putlog _infile_;
call symputx('nobs',_n_);
run;
%mp_assert(
iftrue=(&nobs>2),
desc=Check if content was created
)

View File

@@ -0,0 +1,45 @@
/**
@file
@brief Testing ms_getfile.sas macro
<h4> SAS Macros </h4>
@li ms_createfile.sas
@li ms_getfile.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* first make a remote file */
filename stpcode temp;
%let fname=%mf_getuniquename();
data _null_;
file stpcode;
put "data &fname;run;";
run;
%ms_createfile(/sasjs/tests/&fname..sas
,inref=stpcode
,mdebug=1
)
%mp_assertscope(SNAPSHOT)
%ms_getfile(/sasjs/tests/&fname..sas,outref=testref)
%mp_assertscope(COMPARE)
%let test1=0;
data _null_;
infile testref;
input;
call symputx('test1',_infile_);
run;
%mp_assert(
iftrue=("&test1"="data &fname;run;"),
desc=Checking file was created with the same content,
outds=work.test_results
)

View File

@@ -0,0 +1,52 @@
/**
@file
@brief Testing mv_deleteviyafolder macro function
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_existfolder.sas
@li mp_assert.sas
@li mp_assertscope.sas
@li mv_createfolder.sas
@li mv_deleteviyafolder.sas
**/
options mprint sgen;
%let folder=%mf_uid();
%let tgtfolder=&mcTestAppLoc/temp/&folder;
/* create a folder */
%mv_createfolder(path=&tgtfolder)
%mp_assert(
iftrue=(%mfv_existfolder(&tgtfolder)=1),
desc=Check if created folder exists
)
%mp_assertscope(SNAPSHOT)
%mv_deleteviyafolder(path=&tgtfolder)
/* ignore proc json vars */
%mp_assertscope(COMPARE
,ignorelist=MCLIB0_JADP1LEN MCLIB0_JADP2LEN MCLIB0_JADVLEN MCLIB2_JADP1LEN
MCLIB2_JADVLEN
)
%mp_assert(
iftrue=(%mfv_existfolder(&tgtfolder)=0),
desc=Check if deleted folder is gone
)
/* delete folder with content */
%mv_createfolder(path=&tgtfolder/content/and/stuff)
%mp_assert(
iftrue=(%mfv_existfolder(&tgtfolder/content/and/stuff)=1),
desc=Check if folder with content exists
)
%mv_deleteviyafolder(path=&tgtfolder)
%mp_assert(
iftrue=(%mfv_existfolder(&tgtfolder)=0),
desc=Check if deleted folder with subfolders is gone
)

View File

@@ -4,6 +4,7 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas
@li mv_createjob.sas @li mv_createjob.sas
@li mv_getjobcode.sas @li mv_getjobcode.sas
@@ -27,11 +28,17 @@ run;
) )
/* now get the code back */ /* now get the code back */
%mp_assertscope(SNAPSHOT)
%mv_getjobcode( %mv_getjobcode(
path=&mcTestAppLoc/services/temp, path=&mcTestAppLoc/services/temp,
name=some_job, name=some_job,
outref=mycode outref=mycode
) )
/* exclude automatic proc json macro variables from scope check */
%mp_assertscope(COMPARE,
ignorelist=MCLIB2_JADP1LEN MCLIB2_JADP2LEN MCLIB2_JADPNUM MCLIB2_JADVLEN
MCLIB2_JADP3LEN
)
%let diditexist=NO; %let diditexist=NO;
data work.test1; data work.test1;
@@ -46,4 +53,4 @@ run;
%mp_assert( %mp_assert(
iftrue=(&diditexist=NO), iftrue=(&diditexist=NO),
desc=Check if the code that was sent was successfully retrieved desc=Check if the code that was sent was successfully retrieved
) )

View File

@@ -4,6 +4,7 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas
@li mv_createjob.sas @li mv_createjob.sas
@li mv_jobexecute.sas @li mv_jobexecute.sas
@li mv_jobwaitfor.sas @li mv_jobwaitfor.sas
@@ -49,8 +50,12 @@ data _null_;
run; run;
%* Finally, fetch the log; %* Finally, fetch the log;
%mv_getjoblog(uri=%str(&uri),outref=mylog) %mp_assertscope(SNAPSHOT)
%mv_getjoblog(uri=%str(&uri),outref=mylog,mdebug=1)
/* ignore auto proc json vars */
%mp_assertscope(COMPARE
,ignorelist=MCLIB2_JADP2LEN MCLIB2_JADPNUM MCLIB2_JADVLEN
)
data _null_; data _null_;
infile mylog end=eof; infile mylog end=eof;
@@ -67,4 +72,4 @@ run;
%mp_assert( %mp_assert(
iftrue=(%str(&found)=1), iftrue=(%str(&found)=1),
desc=Check if the log was still fetched even though endsas was submitted desc=Check if the log was still fetched even though endsas was submitted
) )

View File

@@ -655,7 +655,8 @@ data _null_;
put ' %else %if %symexist(&metavar) %then %do; '; put ' %else %if %symexist(&metavar) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; '; put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
put ' /* sometimes SAS will add @domain extension - remove for consistency */ '; put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
put ' %else %let user=%scan(&&&metavar,1,@); '; put ' /* but be sure to quote in case of usernames with commas */ ';
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); ';
put ' %end; '; put ' %end; ';
put ' %else %let user=&sysuserid; '; put ' %else %let user=&sysuserid; ';
put ' '; put ' ';

View File

@@ -8,10 +8,16 @@
%mv_deleteviyafolder(path=/Public/test) %mv_deleteviyafolder(path=/Public/test)
@param path= The full path of the folder to be deleted @param [in] path= The full path of the folder to be deleted
@param access_token_var= The global macro variable to contain the access token @param [in] access_token_var= (ACCESS_TOKEN) The global macro variable to
@param grant_type= valid values are "password" or "authorization_code" (unquoted). contain the access token
The default is authorization_code. @param [in] grant_type= (sas_services) Valid values are:
@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] mdebug= (0) Set to 1 to enable DEBUG messages
@version VIYA V.03.04 @version VIYA V.03.04
@@ -29,6 +35,7 @@
%macro mv_deleteviyafolder(path= %macro mv_deleteviyafolder(path=
,access_token_var=ACCESS_TOKEN ,access_token_var=ACCESS_TOKEN
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0
); );
%local oauth_bearer; %local oauth_bearer;
%if &grant_type=detect %then %do; %if &grant_type=detect %then %do;
@@ -105,14 +112,17 @@ run;
%let libref1a=%mf_getuniquelibref(); %let libref1a=%mf_getuniquelibref();
libname &libref1a JSON fileref=&fname1a; libname &libref1a JSON fileref=&fname1a;
data _null_; %if %mf_existds(&libref1a..items_links) %then %do;
set &libref1a..items_links; data _null_;
if href=:'/folders/folders' then return; set &libref1a..items_links;
if rel='deleteResource' then if href=:'/folders/folders' then return;
call execute('proc http method="DELETE" url='!!quote("&base_uri"!!trim(href)) if rel='deleteResource' then
!!'; headers "Authorization"="Bearer &&&access_token_var" ' call execute('proc http method="DELETE" url='
!!' "Accept"="*/*";run; /**/'); !!quote("&base_uri"!!trim(href))
run; !!'; headers "Authorization"="Bearer &&&access_token_var" '
!!' "Accept"="*/*";run; /**/');
run;
%end;
%put &sysmacroname: perform the delete operation ; %put &sysmacroname: perform the delete operation ;
%local fname2; %local fname2;
@@ -133,9 +143,11 @@ run;
%end; %end;
%else %put &sysmacroname: &path successfully deleted; %else %put &sysmacroname: &path successfully deleted;
/* clear refs */ %if &mdebug=0 %then %do;
filename &fname1 clear; /* clear refs */
filename &fname2 clear; filename &fname1 clear;
libname &libref1 clear; filename &fname2 clear;
libname &libref1 clear;
%end;
%mend mv_deleteviyafolder; %mend mv_deleteviyafolder;

View File

@@ -32,7 +32,7 @@
,grant_type=sas_services ,grant_type=sas_services
,outds=work.viyagroups ,outds=work.viyagroups
); );
%local oauth_bearer; %local oauth_bearer base_uri fname1 libref1;
%if &grant_type=detect %then %do; %if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code; %if %symexist(&access_token_var) %then %let grant_type=authorization_code;
%else %let grant_type=sas_services; %else %let grant_type=sas_services;
@@ -50,11 +50,10 @@
) )
options noquotelenmax; options noquotelenmax;
%local base_uri; /* location of rest apis */ /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI); %let base_uri=%mf_getplatform(VIYARESTAPI);
/* fetching folder details for provided path */ /* fetching folder details for provided path */
%local fname1;
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
%let libref1=%mf_getuniquelibref(); %let libref1=%mf_getuniquelibref();
@@ -78,9 +77,8 @@ data &outds;
run; run;
/* clear refs */ /* clear refs */
filename &fname1 clear; filename &fname1 clear;
libname &libref1 clear; libname &libref1 clear;
%mend mv_getgroups; %mend mv_getgroups;

View File

@@ -33,7 +33,6 @@
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mv_getfoldermembers.sas @li mv_getfoldermembers.sas
@li ml_json.sas
**/ **/
@@ -44,9 +43,9 @@
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0 ,mdebug=0
); );
%local dbg; %local dbg bufsize varcnt fname1 fname2 errmsg;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname entry vars:; %put &sysmacroname local entry vars:;
%put _local_; %put _local_;
%end; %end;
%else %let dbg=*; %else %let dbg=*;
@@ -104,7 +103,6 @@ run;
) )
/* prepare request*/ /* prepare request*/
%local fname1;
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&joburi"; url="&base_uri&joburi";
@@ -114,37 +112,95 @@ proc http method='GET' out=&fname1 &oauth_bearer
%end; %end;
; ;
run; 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;
%local fname2 fname3 fpath1 fpath2 fpath3;
%let fname2=%mf_getuniquefileref();
%let fname3=%mf_getuniquefileref();
%let fpath1=%sysfunc(pathname(&fname1));
%let fpath2=%sysfunc(pathname(&fname2));
%let fpath3=%sysfunc(pathname(&fname3));
/* compile the lua JSON module */ %if &mdebug=1 %then %do;
%ml_json() data _null_;
/* read using LUA - this allows the code to be of any length */ infile &fname1;
input;
putlog _infile_;
run;
%end;
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
,mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%let fname2=%mf_getuniquefileref();
filename &fname2 temp ;
/* cannot use lua IO package as not available in Viya 4 */
/* so use data step to read the JSON until the string `"code":"` is found */
data _null_; data _null_;
file "&fpath3..lua"; file &fname2 recfm=n;
put ' infile &fname1 lrecl=1 recfm=n;
infile = io.open (sas.symget("fpath1"), "r") input sourcechar $char1. @@;
outfile = io.open (sas.symget("fpath2"), "w") format sourcechar hex2.;
io.input(infile) retain startwrite 0;
local resp=json.decode(io.read()) if startwrite=0 and sourcechar='"' then do;
local job=resp["code"] reentry:
outfile:write(job) input sourcechar $ 1. @@;
io.close(infile) if sourcechar='c' then do;
io.close(outfile) reentry2:
'; input sourcechar $ 1. @@;
if sourcechar='o' then do;
input sourcechar $ 1. @@;
if sourcechar='d' then do;
input sourcechar $ 1. @@;
if sourcechar='e' then do;
input sourcechar $ 1. @@;
if sourcechar='"' then do;
input sourcechar $ 1. @@;
if sourcechar=':' then do;
input sourcechar $ 1. @@;
if sourcechar='"' then do;
putlog 'code found';
startwrite=1;
input sourcechar $ 1. @@;
end;
end;
else if sourcechar='c' then goto reentry2;
end;
end;
else if sourcechar='"' then goto reentry;
end;
else if sourcechar='"' then goto reentry;
end;
else if sourcechar='"' then goto reentry;
end;
else if sourcechar='"' then goto reentry;
end;
/* once the `"code":"` string is found, write until unescaped `"` is found */
if startwrite=1 then do;
if sourcechar='\' then do;
input sourcechar $ 1. @@;
if sourcechar in ('"','\') then put sourcechar char1.;
else if sourcechar='n' then put '0A'x;
else if sourcechar='r' then put '0D'x;
else if sourcechar='t' then put '09'x;
else if sourcechar='u' then do;
length uni $4;
input uni $ 4. @@;
sourcechar=unicode('\u'!!uni);
put sourcechar char1.;
end;
else do;
call symputx('errmsg',"Uncaught escape char: "!!sourcechar,'l');
call symputx('syscc',99);
stop;
end;
end;
else if sourcechar='"' then stop;
else put sourcechar char1.;
end;
run; run;
%inc "&fpath3..lua";
%mp_abort(iftrue=("&syscc"="99")
,mac=mv_getjobcode
,msg=%str(&errmsg)
)
/* export to desired destination */ /* export to desired destination */
%if "&outref"="0" %then %do; %if "&outref"="0" %then %do;
data _null_; data _null_;
@@ -169,7 +225,6 @@ run;
/* clear refs */ /* clear refs */
filename &fname1 clear; filename &fname1 clear;
filename &fname2 clear; filename &fname2 clear;
filename &fname3 clear;
%end; %end;
%mend mv_getjobcode; %mend mv_getjobcode;

View File

@@ -86,7 +86,8 @@
@li mp_abort.sas @li mp_abort.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_existfileref.sas @li mf_existfileref.sas
@li ml_json.sas @li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
**/ **/
@@ -95,7 +96,7 @@
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0 ,mdebug=0
); );
%local dbg; %local dbg libref1 libref2 loglocation fname1 fname2;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname entry vars:; %put &sysmacroname entry vars:;
%put _local_; %put _local_;
@@ -154,8 +155,8 @@ options noquotelenmax;
%let base_uri=%mf_getplatform(VIYARESTAPI); %let base_uri=%mf_getplatform(VIYARESTAPI);
/* prepare request*/ /* prepare request*/
%local fname1;
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
%let fname2=%mf_getuniquefileref();
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&uri"; url="&base_uri&uri";
headers headers
@@ -175,37 +176,19 @@ run;
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE) ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
) )
%end; %end;
%local fname2 fname3 fpath1 fpath2 fpath3;
%let fname2=%mf_getuniquefileref();
%let fname3=%mf_getuniquefileref();
%let fpath1=%sysfunc(pathname(&fname1));
%let fpath2=%sysfunc(pathname(&fname2));
%let fpath3=%sysfunc(pathname(&fname3));
/* compile the lua JSON module */ %let libref1=%mf_getuniquelibref();
%ml_json() libname &libref1 JSON fileref=&fname1;
/* read using LUA - this allows the code to be of any length */
data _null_; data _null_;
file "&fpath3..lua"; set &libref1..root;
put ' call symputx('loglocation',loglocation,'l');
infile = io.open (sas.symget("fpath1"), "r")
outfile = io.open (sas.symget("fpath2"), "w")
io.input(infile)
local resp=json.decode(io.read())
local logloc=resp["logLocation"]
outfile:write(logloc)
io.close(infile)
io.close(outfile)
';
run; run;
%inc "&fpath3..lua";
/* get log path*/ /* validate log path*/
%let errflg=1; %let errflg=1;
%let errmsg=No entry in &fname2 fileref; %let errmsg=No loglocation entry in &fname1 fileref;
data _null_; data _null_;
infile &fname2; uri=symget('loglocation');
input;
uri=cats(_infile_);
if length(uri)<12 then do; if length(uri)<12 then do;
call symputx('errflg',1); call symputx('errflg',1);
call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l'); call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
@@ -232,7 +215,7 @@ run;
/* we have a log uri - now fetch the log */ /* we have a log uri - now fetch the log */
%&dbg.put &sysmacroname: querying &base_uri&logloc/content; %&dbg.put &sysmacroname: querying &base_uri&logloc/content;
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname2 &oauth_bearer
url="&base_uri&logloc/content?limit=10000"; url="&base_uri&logloc/content?limit=10000";
headers headers
%if &grant_type=authorization_code %then %do; %if &grant_type=authorization_code %then %do;
@@ -243,14 +226,14 @@ run;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname: fetching log content from &base_uri&logloc/content; %put &sysmacroname: fetching log content from &base_uri&logloc/content;
data _null_;infile &fname1;input;putlog _infile_;run; data _null_;infile &fname2;input;putlog _infile_;run;
%end; %end;
%if &SYS_PROCHTTP_STATUS_CODE=400 %then %do; %if &SYS_PROCHTTP_STATUS_CODE=400 %then %do;
/* fetch log from parent session */ /* fetch log from parent session */
%let logloc=%substr(&logloc,1,%index(&logloc,%str(/jobs/))-1); %let logloc=%substr(&logloc,1,%index(&logloc,%str(/jobs/))-1);
%&dbg.put &sysmacroname: Now querying &base_uri&logloc/log/content; %&dbg.put &sysmacroname: Now querying &base_uri&logloc/log/content;
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname2 &oauth_bearer
url="&base_uri&logloc/log/content?limit=10000"; url="&base_uri&logloc/log/content?limit=10000";
headers headers
%if &grant_type=authorization_code %then %do; %if &grant_type=authorization_code %then %do;
@@ -260,47 +243,32 @@ run;
run; run;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname: fetching log content from &base_uri&logloc/log/content; %put &sysmacroname: fetching log content from &base_uri&logloc/log/content;
data _null_;infile &fname1;input;putlog _infile_;run; data _null_;infile &fname2;input;putlog _infile_;run;
%end; %end;
%end; %end;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201
%then %do; %then %do;
%if &mdebug ne 1 %then %do; /* have already output above */ %if &mdebug ne 1 %then %do; /* have already output above */
data _null_;infile &fname1;input;putlog _infile_;run; data _null_;infile &fname2;input;putlog _infile_;run;
%end; %end;
%mp_abort(mac=&sysmacroname %mp_abort(mac=&sysmacroname
,msg=%str(logfetch: &SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE) ,msg=%str(logfetch: &SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
) )
%end; %end;
data _null_;
file "&fpath3..lua";
put '
infile = io.open (sas.symget("fpath1"), "r")
outfile = io.open (sas.symget("fpath2"), "w")
io.input(infile)
local resp=json.decode(io.read())
for i, v in pairs(resp["items"]) do
outfile:write(v.line,"\n")
end
io.close(infile)
io.close(outfile)
';
run;
%inc "&fpath3..lua";
/* write log out to the specified fileref */ %let libref2=%mf_getuniquelibref();
libname &libref2 JSON fileref=&fname2;
data _null_; data _null_;
infile &fname2 end=last;
file &outref mod; file &outref mod;
if _n_=1 then do; if _n_=1 then do;
put "/** SASJS Viya Job Log Extract start: &uri **/"; put "/** SASJS Viya Job Log Extract start: &uri **/";
end; end;
input; set &libref2..items end=last;
put _infile_;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
putlog _infile_; putlog line;
%end; %end;
put line;
if last then do; if last then do;
put "/** SASJS Viya Job Log Extract end: &uri **/"; put "/** SASJS Viya Job Log Extract end: &uri **/";
end; end;
@@ -309,7 +277,8 @@ run;
%if &mdebug=0 %then %do; %if &mdebug=0 %then %do;
filename &fname1 clear; filename &fname1 clear;
filename &fname2 clear; filename &fname2 clear;
filename &fname3 clear; libname &libref1 clear;
libname &libref2 clear;
%end; %end;
%else %do; %else %do;
%put &sysmacroname exit vars:; %put &sysmacroname exit vars:;