1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-05 08:30:06 +00:00

Compare commits

..

36 Commits

Author SHA1 Message Date
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
Allan Bowe
cba3f5972b Merge pull request #183 from sasjs/feature/mf_getuniquelibref_safe_default
fix: Closes #182 - update to mf_getuniquelibref.sas
2022-03-04 12:20:54 +02:00
Allan Bowe
ed48c49964 fix: adding tests for mf_getuniquelibref and mentioning deprecated param in README. Also regenerating all.sas 2022-03-04 08:37:29 +00:00
trmoody
203ff3f80d chore: amended comment 2022-03-04 01:26:58 +00:00
trmoody
cfe90a8d0d chore: update to mf_getuniquelibref.sas 2022-03-04 00:38:07 +00:00
Allan Bowe
0749ea0819 Merge pull request #179 from sasjs/173-disable-dependence-on-io-(gsub)-package
New `mp_replace()` macro to find & replace in text files
2022-03-03 15:19:04 +02:00
munja
e09a39e748 fix: tests 2022-03-03 13:18:11 +00:00
Allan Bowe
20dcefaefd Merge pull request #180 from sasjs/all-contributors/add-yabwon
docs: add yabwon as a contributor for code
2022-03-03 15:17:16 +02:00
allcontributors[bot]
4c8347516a docs: update .all-contributorsrc [skip ci] 2022-03-03 13:16:32 +00:00
allcontributors[bot]
e497d226a0 docs: update README.md [skip ci] 2022-03-03 13:16:31 +00:00
munja
ccf8f1acc0 fix: adding test and updating documentation 2022-03-03 12:46:00 +00:00
munja
fe9a2ed979 feat: mp_replace macro, credit Bartosz 2022-03-03 10:30:07 +00:00
munja
078815e83e chore: stub 2022-03-02 21:33:41 +00:00
Allan Bowe
bb80c7af5a chore: adding funding.yml 2022-03-01 19:24:27 +00:00
Allan Bowe
842662aae1 Merge pull request #172 from sasjs/serverupdates
fix: updating mp_streamfile for sasjs/server compatibility
2022-02-28 23:21:48 +02:00
munja
876fac2332 feat: several macros for working with the sasjs/server apis 2022-02-28 21:17:38 +00:00
Allan Bowe
427deca350 Merge pull request #178 from sasjs/allanbowe/enable-consul-token-as-177
feat: adding consul_token option as parameter in mv_registerclient.
2022-02-24 23:20:03 +02:00
Allan Bowe
07bde4b25c feat: adding consul_token option as parameter in mv_registerclient. Closes #177 2022-02-24 21:16:23 +00:00
munja
badf5b5761 fix: updating mp_streamfile for sasjs/server compatibility 2022-02-18 22:22:52 +00:00
38 changed files with 1639 additions and 637 deletions

View File

@@ -117,6 +117,15 @@
"contributions": [ "contributions": [
"bug" "bug"
] ]
},
{
"login": "yabwon",
"name": "Bart Jablonski",
"avatar_url": "https://avatars.githubusercontent.com/u/9314894?v=4",
"profile": "https://github.com/yabwon",
"contributions": [
"code"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [sasjs]

View File

@@ -47,7 +47,7 @@ Documentation: https://core.sasjs.io
This library will not be used for storing data entries (such as formats or datalines). Where this becomes necessary in the future, a new repo will be created, in order to keep the NPM bundle size down (for the benefit of those looking to embed purely macros in their applications). This library will not be used for storing data entries (such as formats or datalines). Where this becomes necessary in the future, a new repo will be created, in order to keep the NPM bundle size down (for the benefit of those looking to embed purely macros in their applications).
#### FCMP library (All Platforms) ### FCMP library (All Platforms)
- Function and macro names are identical, except for special cases - Function and macro names are identical, except for special cases
- Prefixes: _mcf_ - Prefixes: _mcf_
@@ -204,6 +204,7 @@ When contributing to this library, it is therefore important to ensure that all
We are currently on major release v4. Breaking changes should be marked with the [deprecated](https://www.doxygen.nl/manual/commands.html#cmddeprecated) doxygen tag. The following changes are planned when the next major/breaking release (v5) becomes necessary: We are currently on major release v4. Breaking changes should be marked with the [deprecated](https://www.doxygen.nl/manual/commands.html#cmddeprecated) doxygen tag. The following changes are planned when the next major/breaking release (v5) becomes necessary:
* mf_getuniquelibref.sas to have the deprecated maxtried parameter removed (no longer needed)
* mp_testservice.sas to be renamed as mp_execute.sas (as it doesn't actually test anything) * mp_testservice.sas to be renamed as mp_execute.sas (as it doesn't actually test anything)
* `insert_cmplib` option of mcf_xxx macros will be deprecated (the option is now checked automatically with value inserted only if needed) * `insert_cmplib` option of mcf_xxx macros will be deprecated (the option is now checked automatically with value inserted only if needed)
* mcf_xxx macros to have `wrap=` option defaulted to YES for convenience. Set this option explicitly to avoid issues. * mcf_xxx macros to have `wrap=` option defaulted to YES for convenience. Set this option explicitly to avoid issues.
@@ -217,10 +218,9 @@ If you find this library useful, please leave a [star](https://github.com/sasjs/
![](https://starchart.cc/sasjs/core.svg) ![](https://starchart.cc/sasjs/core.svg)
## Contributors ✨ ## Contributors ✨
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --> <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-10-orange.svg?style=flat-square)](#contributors-) [![All Contributors](https://img.shields.io/badge/all_contributors-11-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END --> <!-- ALL-CONTRIBUTORS-BADGE:END -->
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
@@ -241,6 +241,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center"><a href="https://github.com/kkchandok"><img src="https://avatars.githubusercontent.com/u/46090627?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kkchandok</b></sub></a><br /><a href="#ideas-kkchandok" title="Ideas, Planning, & Feedback">🤔</a></td> <td align="center"><a href="https://github.com/kkchandok"><img src="https://avatars.githubusercontent.com/u/46090627?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kkchandok</b></sub></a><br /><a href="#ideas-kkchandok" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/VladislavParhomchik"><img src="https://avatars.githubusercontent.com/u/83717836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vladislav Parhomchik</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=VladislavParhomchik" title="Tests">⚠️</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3AVladislavParhomchik" title="Reviewed Pull Requests">👀</a></td> <td align="center"><a href="https://github.com/VladislavParhomchik"><img src="https://avatars.githubusercontent.com/u/83717836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vladislav Parhomchik</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=VladislavParhomchik" title="Tests">⚠️</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3AVladislavParhomchik" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/vznesh"><img src="https://avatars.githubusercontent.com/u/28916792?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vignesh T.</b></sub></a><br /><a href="https://github.com/sasjs/core/issues?q=author%3Avznesh" title="Bug reports">🐛</a></td> <td align="center"><a href="https://github.com/vznesh"><img src="https://avatars.githubusercontent.com/u/28916792?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vignesh T.</b></sub></a><br /><a href="https://github.com/sasjs/core/issues?q=author%3Avznesh" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/yabwon"><img src="https://avatars.githubusercontent.com/u/9314894?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bart Jablonski</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=yabwon" title="Code">💻</a></td>
</tr> </tr>
</table> </table>

909
all.sas

File diff suppressed because it is too large Load Diff

View File

@@ -14,27 +14,44 @@
> mclib3 > mclib3
@param prefix= first part of libref. Remember that librefs can only be 8 characters, A blank value is returned if no usable libname is determined.
so a 7 letter prefix would mean that maxtries should be 10.
@param maxtries= the last part of the libref. Provide an integer value. @param [in] prefix= (mclib) first part of the returned libref. As librefs can
be as long as 8 characters, a maximum length of 7 characters is premitted
for this prefix.
@param [in] maxtries= Deprecated parameter. Remains here to ensure a
non-breaking change. Will be removed in v5.
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
**/ **/
%macro mf_getuniquelibref(prefix=mclib,maxtries=1000); %macro mf_getuniquelibref(prefix=mclib,maxtries=1000);
%local x libref; %local x;
%let x=0;
%do x=0 %to &maxtries; %if ( %length(&prefix) gt 7 ) %then %do;
%if %sysfunc(libref(&prefix&x)) ne 0 %then %do; %put %str(ERR)OR: The prefix parameter cannot exceed 7 characters.;
%let libref=&prefix&x; 0
%let rc=%sysfunc(libname(&libref,%sysfunc(pathname(work))));
%if &rc %then %put %sysfunc(sysmsg());
&prefix&x
%*put &sysmacroname: Libref &libref assigned as WORK and returned;
%return; %return;
%end; %end;
%else %if (%sysfunc(NVALID(&prefix,v7))=0) %then %do;
%put %str(ERR)OR: Invalid prefix (&prefix);
0
%return;
%end; %end;
%put unable to find available libref in range &prefix.0-&maxtries;
/* Set maxtries equal to '10 to the power of [# unused characters] - 1' */
%let maxtries=%eval(10**(8-%length(&prefix))-1);
%do x = 0 %to &maxtries;
%if %sysfunc(libref(&prefix&x)) ne 0 %then %do;
&prefix&x
%return;
%end;
%let x = %eval(&x + 1);
%end;
%put %str(ERR)OR: No usable libref in range &prefix.0-&maxtries;
%put %str(ERR)OR- Try reducing the prefix or deleting some libraries!;
0
%mend mf_getuniquelibref; %mend mf_getuniquelibref;

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

@@ -74,7 +74,8 @@
outds=work.test_results outds=work.test_results
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local ds test_result test_comments del add mod ilist; %local ds test_result test_comments del add mod ilist;
%let ilist=%upcase(&sasjs_prefix._FUNCTIONS &ignorelist); %let ilist=%upcase(&sasjs_prefix._FUNCTIONS SYS_PROCHTTP_STATUS_CODE
SYS_PROCHTTP_STATUS_CODE SYS_PROCHTTP_STATUS_PHRASE &ignorelist);
/** /**
* this sets up the global vars, it will also enter STRICT mode. If this * this sets up the global vars, it will also enter STRICT mode. If this
@@ -89,7 +90,7 @@
create table &scopeds as create table &scopeds as
select name,offset,value select name,offset,value
from dictionary.macros from dictionary.macros
where scope="&scope" and name not in (%mf_getquotedstr(&ilist)) where scope="&scope" and upcase(name) not in (%mf_getquotedstr(&ilist))
order by name,offset; order by name,offset;
%end; %end;
%else %if &action=COMPARE %then %do; %else %if &action=COMPARE %then %do;
@@ -103,7 +104,9 @@
%let ds=&syslast; %let ds=&syslast;
proc compare base=&scopeds compare=&ds; proc compare
base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist))))
compare=&ds;
run; run;
%if &sysinfo=0 %then %do; %if &sysinfo=0 %then %do;
@@ -141,4 +144,4 @@
drop table &ds; drop table &ds;
%end; %end;
%mend mp_assertscope; %mend mp_assertscope;

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

@@ -1,7 +1,8 @@
/** /**
@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
(not just SAS datasets).
Only useful if every update uses the macro! Used heavily within Only useful if every update uses the macro! Used heavily within
[Data Controller for SAS](https://datacontroller.io). [Data Controller for SAS](https://datacontroller.io).
@@ -15,7 +16,7 @@
length is 200 characters. length is 200 characters.
@param [out] ctl_ds= (0) The control table which controls the actual locking. @param [out] ctl_ds= (0) The control table which controls the actual locking.
Should already be assigned and available. The definition is available by Should already be assigned and available. The definition is available by
running mp_coretable.sas as follows: `%mp_coretable(LOCKTABLE)`. running the mddl_dc_locktable.sas macro.
@param [in] loops= (25) Number of times to check for a lock. @param [in] loops= (25) Number of times to check for a lock.
@param [in] loop_secs= (1) Seconds to wait between each lock attempt @param [in] loop_secs= (1) Seconds to wait between each lock attempt

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;

149
base/mp_replace.sas Normal file
View File

@@ -0,0 +1,149 @@
/**
@file
@brief Performs a text substitution on a file
@details Performs a find and replace on a file, either in place or to a new
file. Can be used on files where lines are longer than 32767.
Works by reading in the file byte by byte, then marking the beginning and end
of each matched string, before finally doing the replace.
Full credit for this highly efficient and syntactically satisfying SAS logic
goes to [Bartosz Jabłoński](https://www.linkedin.com/in/yabwon), founder of
the [SAS Packages](https://github.com/yabwon/SAS_PACKAGES) framework.
Usage:
%let file="%sysfunc(pathname(work))/file.txt";
%let str=replace/me;
%let rep=with/this;
data _null_;
file &file;
put 'blahblah';
put "blahblah&str.blah";
put 'blahblahblah';
run;
%mp_replace(&file, findvar=str, replacevar=rep)
data _null_;
infile &file;
input;
list;
run;
Note - if you are running a version of SAS that will allow the io package in
LUA, you can also use this macro: mp_gsubfile.sas
@param infile The QUOTED path to the file on which to perform the substitution
@param findvar= Macro variable NAME containing the string to search for
@param replacevar= Macro variable NAME containing the replacement string
@param outfile= (0) Optional QUOTED path to an the adjusted output file (to
avoid overwriting the first file).
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
<h4> Related Macros </h4>
@li mp_gsubfile.test.sas
@version 9.4
@author Bartosz Jabłoński
@author Allan Bowe
**/
%macro mp_replace(infile,
findvar=,
replacevar=,
outfile=0
)/*/STORE SOURCE*/;
%local inref dttm ds1;
%let inref=%mf_getuniquefileref();
%let outref=%mf_getuniquefileref();
%if &outfile=0 %then %let outfile=&infile;
%let ds1=%mf_getuniquename(prefix=allchars);
%let ds2=%mf_getuniquename(prefix=startmark);
/* START */
%let dttm=%sysfunc(datetime());
filename &inref &infile lrecl=1 recfm=n;
data &ds1;
infile &inref;
input sourcechar $char1. @@;
format sourcechar hex2.;
run;
data &ds2;
/* set find string to length in bytes to cover trailing spaces */
length string $ %length(%superq(&findvar));
string =symget("&findvar");
drop string;
firstchar=char(string,1);
findlen=lengthm(string); /* <- for trailing bytes */
do _N_=1 to nobs;
set &ds1 nobs=nobs point=_N_;
if sourcechar=firstchar then do;
pos=1;
s=0;
do point=_N_ to min(_N_ + findlen -1,nobs);
set &ds1 point=point;
if sourcechar=char(string, pos) then s + 1;
else goto _leave_;
pos+1;
end;
_leave_:
if s=findlen then do;
START =_N_;
_N_ =_N_+ s - 1;
STOP =_N_;
output;
end;
end;
end;
stop;
keep START STOP;
run;
data &ds1;
declare hash HS(dataset:"&ds2(keep=start)");
HS.defineKey("start");
HS.defineDone();
declare hash HE(dataset:"&ds2(keep=stop)");
HE.defineKey("stop");
HE.defineDone();
do until(eof);
set &ds1 end=eof curobs =n;
start = ^HS.check(key:n);
stop = ^HE.check(key:n);
length strt $ 1;
strt =put(start,best. -L);
retain out 1;
if out then output;
if start then out=0;
if stop then out=1;
end;
stop;
keep sourcechar strt;
run;
filename &outref &outfile recfm=n;
data _null_;
length replace $ %length(%superq(&replacevar));
replace=symget("&replacevar");
file &outref;
do until(eof);
set &ds1 end=eof;
if strt ="1" then put replace char.;
else put sourcechar char1.;
end;
stop;
run;
/* END */
%put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) seconds to run;
%mend mp_replace;

View File

@@ -12,7 +12,7 @@
%mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt) %mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt)
@param [in] contenttype= (TEXTS) Either TEXT, ZIP, CSV, EXCEL @param [in] contenttype= (TEXT) Either TEXT, ZIP, CSV, EXCEL
@param [in] inloc= /path/to/file.ext to be sent @param [in] inloc= /path/to/file.ext to be sent
@param [in] inref= fileref of file to be sent (if provided, overrides `inloc`) @param [in] inref= fileref of file to be sent (if provided, overrides `inloc`)
@param [in] iftrue= (1=1) Provide a condition under which to execute. @param [in] iftrue= (1=1) Provide a condition under which to execute.

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

@@ -40,6 +40,12 @@
/* now try and assign it */ /* now try and assign it */
if libname("&libref",,'meta',cats('liburi="',liburi,'";')) ne 0 then do; if libname("&libref",,'meta',cats('liburi="',liburi,'";')) ne 0 then do;
putlog "&libref could not be assigned"; putlog "&libref could not be assigned";
putlog liburi=;
/**
* Fetch the system message for display in the abort modal. This is
* not always helpful though. One example, previously received:
* NOTE: Libref XX refers to the same library metadata as libref XX.
*/
call symputx('msg',sysmsg(),'l'); call symputx('msg',sysmsg(),'l');
if "&mabort"='HARD' then call symputx('mp_abort',1,'l'); if "&mabort"='HARD' then call symputx('mp_abort',1,'l');
end; end;
@@ -61,7 +67,7 @@
%if &mp_abort=1 %then %do; %if &mp_abort=1 %then %do;
%mp_abort(iftrue= (&mp_abort=1) %mp_abort(iftrue= (&mp_abort=1)
,mac=&sysmacroname ,mac=mm_assignlib.sas
,msg=&msg ,msg=&msg
) )
%return; %return;

View File

@@ -73,21 +73,41 @@
"name": "server", "name": "server",
"serverUrl": "https://sas.analytium.co.uk:5000", "serverUrl": "https://sas.analytium.co.uk:5000",
"serverType": "SASJS", "serverType": "SASJS",
"appLoc": "/Shared Data/temp/macrocore", "httpsAgentOptions": {
"allowInsecureRequests": false
},
"appLoc": "/sasjs/core",
"macroFolders": [ "macroFolders": [
"tests/serveronly" "tests/serveronly"
], ],
"programFolders": [],
"binaryFolders": [],
"deployConfig": { "deployConfig": {
"deployServicePack": true "deployServicePack": true,
"deployScripts": []
} }
}, },
{ {
"name": "docsonly", "name": "docsonly",
"serverType": "SAS9", "serverType": "SAS9",
"appLoc": "dummy",
"macroFolders": [ "macroFolders": [
"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"
} }
] ]
} }

89
server/ms_createfile.sas Normal file
View File

@@ -0,0 +1,89 @@
/**
@file
@brief Creates a file on SASjs Drive
@details Creates a file on SASjs Drive. To use the file as a Stored Program,
it must have a ".sas" extension.
Example:
filename stpcode temp;
data _null_;
file stpcode;
put '%put hello world;';
run;
%ms_createfile(/some/stored/program.sas, inref=stpcode)
@param [in] driveloc The full path to the file in SASjs Drive
@param [in] inref= (0) The fileref containing the file to create.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
@li mp_abort.sas
**/
%macro ms_createfile(driveloc
,inref=0
,mdebug=0
);
%local fname0 fname1 boundary fname statcd msg;
%let fname0=%mf_getuniquefileref();
%let fname1=%mf_getuniquefileref();
%let boundary=%mf_getuniquename();
data _null_;
file &fname0 termstr=crlf;
infile &inref end=eof;
if _n_ = 1 then do;
put "--&boundary.";
put 'Content-Disposition: form-data; name="filePath"';
put ;
put "&driveloc";
put "--&boundary";
put 'Content-Disposition: form-data; name="file"; filename="ignore.sas"';
put "Content-Type: text/plain";
put ;
end;
input;
put _infile_; /* add the actual file to be sent */
if eof then do;
put ;
put "--&boundary--";
end;
run;
%if &mdebug=1 %then %do;
data _null_;
infile &fname0;
input;
put _infile_;
run;
%end;
proc http method='POST' in=&fname0 out=&fname1
url="&_sasjs_apiserverurl/SASjsApi/drive/file";
headers "Content-Type"="multipart/form-data; boundary=&boundary";
%if &mdebug=1 %then %do;
debug level=1;
%end;
run;
%let statcd=0;
data _null_;
infile &fname1;
input;
putlog _infile_;
if _infile_='{"status":"success"}' then call symputx('statcd',1,'l');
else call symputx('msg',_infile_,'l');
run;
%mp_abort(
iftrue=(&statcd=0)
,mac=ms_createfile.sas
,msg=%superq(msg)
)
%mend ms_createfile;

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;

77
server/ms_runstp.sas Normal file
View File

@@ -0,0 +1,77 @@
/**
@file
@brief Executes a SASjs Server Stored Program
@details Runs a Stored Program (using POST method) and extracts the webout and
log from the response JSON.
Example:
%ms_runstp(/some/stored/program
,debug=131
,outref=weboot
)
@param [in] pgm The full path to the Stored Program in SASjs Drive (_program
parameter)
@param [in] debug= (131) The value to supply to the _debug URL parameter
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@param [out] outref= (outweb) The output fileref to contain the response JSON
(will be created using temp engine)
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mp_abort.sas
**/
%macro ms_runstp(pgm
,debug=131
,outref=outweb
,mdebug=0
);
%local dbg fname1;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%let fname1=%mf_getuniquefileref();
%mp_abort(iftrue=("&pgm"="")
,mac=&sysmacroname
,msg=%str(Program not provided)
)
data _null_;
file &fname1;
infile "&_sasjs_tokenfile";
input;
put 'Authorization: Bearer' _infile_;
run;
filename &outref temp;
/* prepare request*/
proc http method='POST' headerin=&fname1 out=&outref
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
run;
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
or &mdebug=1 %then %do;
data _null_;infile &outref;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)
)
%if &mdebug=1 %then %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%else %do;
/* clear refs */
filename &fname1 clear;
%end;
%mend ms_runstp;

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

@@ -0,0 +1,54 @@
/**
@file
@brief Testing mf_getuniquelibref macro
@details To test performance you can also use the following macro:
<h4> SAS Macros </h4>
@li mf_getuniquelibref.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* check valid libs */
%mp_assertscope(SNAPSHOT)
%let libshort=%mf_getuniquelibref(prefix=lib);
%mp_assertscope(COMPARE,ignorelist=LIBSHORT)
libname &libshort (work);
%mp_assert(
iftrue=(&syscc=0),
desc=Checking for valid libref &libshort,
outds=work.test_results
)
%let lib7=%mf_getuniquelibref(prefix=libref7);
libname &lib7 (work);
%mp_assert(
iftrue=(&syscc=0),
desc=Checking for valid libref &lib7,
outds=work.test_results
)
/* check for invalid libs */
%let lib8=%mf_getuniquelibref(prefix=lib8char);
%mp_assert(
iftrue=(&lib8=0),
desc=Invalid prefix (8 chars),
outds=work.test_results
)
%let liblong=%mf_getuniquelibref(prefix=invalidlib);
%mp_assert(
iftrue=(&liblong=0),
desc=Checking for invalid libref (long),
outds=work.test_results
)
%let badlib=%mf_getuniquelibref(prefix=8adlib);
%mp_assert(
iftrue=(&badlib=0),
desc=Checking for invalid libref (8adlib),
outds=work.test_results
)

View File

@@ -3,6 +3,7 @@
@brief Testing mp_cntlout.sas macro @brief Testing mp_cntlout.sas macro
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_nobs.sas
@li mp_cntlout.sas @li mp_cntlout.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas @li mp_assertscope.sas

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

@@ -0,0 +1,95 @@
/**
@file
@brief Testing mp_replace.sas macro
<h4> SAS Macros </h4>
@li mp_replace.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
%let test1="&sasjswork/file.txt";
%let str=replace/me;
%let rep=with/this;
data _null_;
file &test1;
put 'blahblah';
put "blahblah&str.blah";
put 'blahblahblah';
run;
%mp_assertscope(SNAPSHOT)
%mp_replace(&test1, findvar=str, replacevar=rep)
%mp_assertscope(COMPARE)
data _null_;
infile &test1;
input;
if _n_=2 then call symputx('test1result',_infile_);
run;
%mp_assert(
iftrue=("&test1result" = "blahblah&rep.blah"),
desc=Checking first replace,
outds=work.test_results
)
%let test2="&sasjswork/file2.txt";
%let str=%str(replacewith trailing spaces );
%let rep=%str( with more spaces );
data _null_;
file &test2;
put 'blahblah';
put "blahblah&str.blah&str. replace &str.X";
put "blahbreplacewith&str.spacesahblah";
run;
%mp_replace(&test2, findvar=str, replacevar=rep)
data _null_;
infile &test2;
input;
if _n_=2 then call symputx('test2resulta',_infile_);
if _n_=3 then call symputx('test2resultb',_infile_);
run;
%mp_assert(
iftrue=("&test2resulta" = "blahblah&rep.blah&rep. replace &rep.X"),
desc=Checking second replace 2nd row,
outds=work.test_results
)
%mp_assert(
iftrue=("&test2resultb" = "blahbreplacewith&rep.spacesahblah"),
desc=Checking second replace 3rd row,
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

@@ -5,12 +5,16 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mfs_httpheader.sas @li mfs_httpheader.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas
**/ **/
%let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/header.txt; %let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/header.txt;
%mp_assertscope(SNAPSHOT)
%mfs_httpheader(Content-type,application/csv) %mfs_httpheader(Content-type,application/csv)
%mp_assertscope(COMPARE)
data _null_; data _null_;
infile "&sasjs_stpsrv_header_loc"; infile "&sasjs_stpsrv_header_loc";
input; input;

View File

@@ -0,0 +1,30 @@
/**
@file
@brief Testing ms_createfile.sas macro
<h4> SAS Macros </h4>
@li ms_createfile.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
filename stpcode temp;
data _null_;
file stpcode;
put '%put hello world;';
run;
options mprint;
%let fname=%mf_getuniquename();
%mp_assertscope(SNAPSHOT)
%ms_createfile(/sasjs/tests/&fname..sas
,inref=stpcode
,mdebug=1
)
%mp_assertscope(COMPARE)

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,44 @@
/**
@file
@brief Testing ms_runstp.sas macro
<h4> SAS Macros </h4>
@li ms_runstp.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
%mp_assertscope(SNAPSHOT)
%ms_runstp(/Public/app/frs/allan/services/common/appinit
,debug=131
,outref=weboot
)
%mp_assertscope(COMPARE)
libname webeen json (weboot);
data _null_;
infile weboot;
input;
putlog _infile_;
run;
data work.httpheaders;
set webeen.httpheaders;
call symputx('test1',content_type);
run;
data work.log;
set webeen.log;
put (_all_)(=);
if _n_>10 then stop;
run;
%mp_assert(
iftrue=("&test1"="application/json"),
desc=Checking line was created,
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

@@ -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:;

View File

@@ -1,10 +1,10 @@
/** /**
@file mv_registerclient.sas @file mv_registerclient.sas
@brief Register Client and Secret (admin task) @brief Register Client and Secret (admin task)
@details When building apps on SAS Viya, an client id and secret are sometimes @details When building apps on SAS Viya, a client id and secret are usually
required. In order to generate them, filesystem access to the Consul Token required. In order to generate them, the Consul Token is required. To access
is needed (it is not enough to be in the SASAdministrator group in SAS this token, you need to be a system administrator (it is not enough to be in
Environment Manager). the SASAdministrator group in SAS Environment Manager).
If you are registering a lot of clients / secrets, you may find it more If you are registering a lot of clients / secrets, you may find it more
convenient to use the [Viya Token Generator] convenient to use the [Viya Token Generator]
@@ -25,62 +25,69 @@
"https://raw.githubusercontent.com/sasjs/core/main/all.sas"; "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc; %inc mc;
%* generate random client using consul token as input parameter;
%mv_registerclient(consul_token=12x34sa43v2345n234lasd)
%* generate random client details with all scopes;
%mv_registerclient(scopes=openid *)
%* specific client with just openid scope; %* specific client with just openid scope;
%mv_registerclient(client_id=YourClient %mv_registerclient(client_id=YourClient
,client_secret=YourSecret ,client_secret=YourSecret
,scopes=openid ,scopes=openid
) )
%* generate random client details with all scopes;
%mv_registerclient(scopes=openid *)
%* generate random client with 90/180 second access/refresh token expiry; %* generate random client with 90/180 second access/refresh token expiry;
%mv_registerclient(scopes=openid * %mv_registerclient(scopes=openid *
,access_token_validity=90 ,access_token_validity=90
,refresh_token_validity=180 ,refresh_token_validity=180
) )
@param client_id= The client name. Auto generated if blank. @param [in,out] client_id= The client name. Auto generated if blank.
@param client_secret= Client secret. Auto generated if client is blank. @param [in,out] client_secret= Client secret. Auto generated if client is
@param scopes=(openid) List of space-seperated unquoted scopes blank.
@param grant_type=(authorization_code|refresh_token) Valid values are @param [in] consul_token= (0) Provide the actual consul token value here if
"password" or "authorization_code" (unquoted) using Viya 4 or above.
@param outds=(mv_registerclient) The dataset to contain the registered client @param [in] scopes= (openid) List of space-seperated unquoted scopes
id and secret @param [in] grant_type= (authorization_code|refresh_token) Valid values are
@param access_token_validity=(DEFAULT) The duration of validity of the access "password" or "authorization_code" (unquoted). Pipe seperated.
token in seconds. A value of DEFAULT will omit the entry (and use system @param [out] outds=(mv_registerclient) The dataset to contain the registered
default) client id and secret
@param refresh_token_validity=(DEFAULT) The duration of validity of the @param [in] access_token_validity= (DEFAULT) The access token duration in
seconds. A value of DEFAULT will omit the entry (and use system default)
@param [in] refresh_token_validity= (DEFAULT) The duration of validity of the
refresh token in seconds. A value of DEFAULT will omit the entry (and use refresh token in seconds. A value of DEFAULT will omit the entry (and use
system default) system default)
@param name= An optional, human readable name for the client @param [in] client_name= (DEFAULT) An optional, human readable name for the
@param required_user_groups= A list of group names. If a user does not belong client.
to all the required groups, the user will not be authenticated and no tokens @param [in] required_user_groups= A list of group names. If a user does not
are issued to this client for that user. If this field is not specified, belong to all the required groups, the user will not be authenticated and no
authentication and token issuance proceeds normally. tokens are issued to this client for that user. If this field is not
@param autoapprove= During the auth step the user can choose which scope to specified, authentication and token issuance proceeds normally.
apply. Setting this to true will autoapprove all the client scopes. @param [in] autoapprove= During the auth step the user can choose which scope
@param use_session= If true, access tokens issued to this client will be to apply. Setting this to true will autoapprove all the client scopes.
@param [in] use_session= If true, access tokens issued to this client will be
associated with an HTTP session and revoked upon logout or time-out. associated with an HTTP session and revoked upon logout or time-out.
@param outjson= (_null_) A dataset containing the lines of JSON submitted. @param [out] outjson= (_null_) A dataset containing the lines of JSON
Useful for debugging. submitted. Useful for debugging.
@version VIYA V.03.04 @version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core @author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_abort.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas @li mf_getuniquelibref.sas
@li mf_loc.sas @li mf_loc.sas
@li mf_getquotedstr.sas @li mf_getquotedstr.sas
@li mf_getuser.sas @li mf_getuser.sas
@li mp_abort.sas
**/ **/
%macro mv_registerclient(client_id= %macro mv_registerclient(client_id=
,client_secret= ,client_secret=
,consul_token=0
,client_name=DEFAULT ,client_name=DEFAULT
,scopes=openid ,scopes=openid
,grant_type=authorization_code|refresh_token ,grant_type=authorization_code|refresh_token
@@ -92,33 +99,41 @@
,refresh_token_validity=DEFAULT ,refresh_token_validity=DEFAULT
,outjson=_null_ ,outjson=_null_
); );
%local consul_token fname1 fname2 fname3 libref access_token url tokloc; %local fname1 fname2 fname3 libref access_token url tokloc msg;
%if client_name=DEFAULT %then %let client_name= %if client_name=DEFAULT %then %let client_name=
Generated by %mf_getuser() on %sysfunc(datetime(),datetime19.) using SASjs; Generated by %mf_getuser() (&sysuserid) on %sysfunc(datetime(),datetime19.
) using SASjs;
options noquotelenmax; options noquotelenmax;
/* first, get consul token needed to get client id / secret */
%let tokloc=/etc/SASSecurityCertificateFramework/tokens/consul/default;
%let tokloc=%mf_loc(VIYACONFIG)&tokloc/client.token;
%if "&consul_token"="0" %then %do;
/* first, get consul token needed to get client id / secret */
%let tokloc=/etc/SASSecurityCertificateFramework/tokens/consul/default;
%let tokloc=%mf_loc(VIYACONFIG)&tokloc/client.token;
%mp_abort(iftrue=(%sysfunc(fileexist(&tokloc))=0) %if %sysfunc(fileexist(&tokloc))=0 %then %do;
,mac=&sysmacroname %let msg=Unable to access the consul token at &tokloc;
,msg=%str(Unable to access the consul token at &tokloc) %put &sysmacroname: &msg;
) %put Try passing the value in the consul= macro parameter;
%put See docs: https://core.sasjs.io/mv__registerclient_8sas.html;
%mp_abort(mac=mv_registerclient,msg=%str(&msg))
%end;
%let consul_token=0; data _null_;
data _null_; infile "&tokloc";
infile "&tokloc"; input token:$64.;
input token:$64.; call symputx('consul_token',token);
call symputx('consul_token',token); run;
run;
%mp_abort(iftrue=("&consul_token"="0") %if "&consul_token"="0" %then %do;
,mac=&sysmacroname %put &sysmacroname: Unable to source the consul token from &tokloc;
,msg=%str(Unable to source the consul token from &tokloc) %put It seems your account (&sysuserid) does not have admin rights;
) %put Please speak with your platform adminstrator;
%put Docs: https://core.sasjs.io/mv__registerclient_8sas.html;
%abort;
%end;
%end;
%local base_uri; /* location of rest apis */ %local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI); %let base_uri=%mf_getplatform(VIYARESTAPI);
@@ -131,6 +146,9 @@ proc http method='POST' out=&fname1
headers "X-Consul-Token"="&consul_token"; headers "X-Consul-Token"="&consul_token";
run; run;
%put &=SYS_PROCHTTP_STATUS_CODE;
%put &=SYS_PROCHTTP_STATUS_PHRASE;
%let libref=%mf_getuniquelibref(); %let libref=%mf_getuniquelibref();
libname &libref JSON fileref=&fname1; libname &libref JSON fileref=&fname1;