The self-destruct block ends with a single-statement %else in open code:
%if &keepme ne 1 %then %do;
%mv_deletejes(path=&root/admin, name=makedata);
%end;
%else %put NOTE: &_program retained, as KEEPME was requested;
Outside a macro SAS pairs %else only with a %do branch, so this stops with
'ERROR: Expected %DO not found' and 'ERROR: Skipping to next %END statement'
after the deployment has completed. On Viya the job then reports state error
with jobConditionCode 1012, so a successful deployment looks like a failure
exactly when someone is watching a first install.
Both branches now use %do/%end, which is the pattern the repo uses elsewhere
for this reason - see db/migrations/20261003_row_and_cell_limits.sas.
The same block is fixed in the server variant. The two delete calls also gain
their terminating semicolons: the macro call worked without them, but their
absence is what made the block look responsible for the error.
Behaviour is unchanged: the program still deletes itself unless KEEPME was
requested.
228 lines
6.5 KiB
SAS
228 lines
6.5 KiB
SAS
/**
|
|
@file
|
|
@brief service for creating the configuration tables
|
|
@details
|
|
STP for creating the configuration tables.
|
|
It also adds the STAGING directory as subdirectory to the BASE
|
|
library location.
|
|
|
|
@warning This STP self destructs! It will delete itself (and the
|
|
configurator) after a successful run, to avoid being executed twice and
|
|
overwriting actual data. Pass a KEEPME column in the input data to keep
|
|
them - test harnesses reseed before every run and cannot redeploy first.
|
|
|
|
@sasjslint {"noBannedStrings": false}
|
|
|
|
<h4> SAS Macros </h4>
|
|
@li mf_getapploc.sas
|
|
@li mf_mkdir.sas
|
|
@li mp_abort.sas
|
|
@li mpe_makedata.sas
|
|
@li mpe_makedatamodel.sas
|
|
@li ms_createfile.sas
|
|
@li ms_deletefile.sas
|
|
|
|
@version 9.2
|
|
@author 4GL Apps Ltd
|
|
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
|
|
and may not be re-distributed or re-sold without the express permission of
|
|
4GL Apps Ltd.
|
|
|
|
**/
|
|
|
|
%global path ADMIN OUTFMT;
|
|
|
|
/* response format - HTML (default) or JSON */
|
|
%let OUTFMT=HTML;
|
|
|
|
%webout(FETCH)
|
|
|
|
/* enable vars to be passed as url params */
|
|
%let exist=%sysfunc(exist(work.fromjs));
|
|
%let inds=%sysfunc(ifc(&exist=1,fromjs,_null_));
|
|
data _null_;
|
|
set &inds;
|
|
call symputx('path',dcpath);
|
|
call symputx('ADMIN',ADMIN);
|
|
run;
|
|
|
|
/* check if a JSON response was requested (OUTFMT column in fromjs) */
|
|
%if &exist=1 %then %do;
|
|
data _null_;
|
|
dsid=open('work.fromjs');
|
|
if varnum(dsid,'OUTFMT')>0 then do;
|
|
set work.fromjs;
|
|
call symputx('OUTFMT',upcase(outfmt));
|
|
end;
|
|
rc=close(dsid);
|
|
stop;
|
|
run;
|
|
%end;
|
|
|
|
/* optional KEEPME column - keep this program and the configurator on the drive
|
|
* after a successful run. A normal install self-destructs so the seeding
|
|
* cannot be run twice over live data; a test harness reseeds before every run
|
|
* and wants them to stay put. */
|
|
%let keepme=0;
|
|
%if &exist=1 %then %do;
|
|
data _null_;
|
|
dsid=open('work.fromjs');
|
|
/* every row, not just the first: KEEPME may be set on any of them */
|
|
if varnum(dsid,'KEEPME')>0 then do until(eof);
|
|
set work.fromjs end=eof;
|
|
if upcase(cats(keepme)) in ('1','Y','YES','TRUE') then call symputx('keepme',1);
|
|
end;
|
|
rc=close(dsid);
|
|
stop;
|
|
run;
|
|
%end;
|
|
|
|
%mp_abort(iftrue= (&syscc ne 0)
|
|
,mac=&_program
|
|
,msg=%str(Issue on makedata entry)
|
|
)
|
|
|
|
%let root=%mf_getapploc();
|
|
%let dc_libref=%upcase(DC%substr(%sysevalf(%sysfunc(datetime())/60),3,6));
|
|
%let dcpath=%trim(&path)/&dc_libref;
|
|
%put _all_;
|
|
|
|
%mf_mkdir(&dcpath)
|
|
|
|
libname &dc_libref "&dcpath";
|
|
%mp_abort(iftrue= (&syscc ne 0)
|
|
,mac=&_program..sas
|
|
,msg=%str(Libref (&dc_libref) could not be assigned to (&dcpath) )
|
|
)
|
|
|
|
/* check we have physical permissions to the DCLIB folder */
|
|
data _null_;
|
|
putlog "testing write to: &dcpath/permTest.txt";
|
|
putlog "sysuserid=&sysuserid";
|
|
data _null_;
|
|
file "&dcpath/permTest.txt";
|
|
run;
|
|
%mp_abort(iftrue= (&syscc ne 0)
|
|
,mac=&_program
|
|
,msg=%str(User &sysuserid does not have WRITE permissions on physical
|
|
directory: &dcpath )
|
|
)
|
|
|
|
filename delfile "&dcpath/permTest.txt";
|
|
data _null_;
|
|
rc=fdelete('delfile');
|
|
run;
|
|
%mp_abort(iftrue= (&syscc ne 0)
|
|
,mac=&_program..sas
|
|
,msg=%str(User &sysuserid could create (but not delete) &dcpath/permTest.txt )
|
|
)
|
|
|
|
|
|
/* SASAdministrators */
|
|
%let admin=%sysfunc(coalescec(&admin,SASAdministrators));
|
|
%mpe_makedatamodel(lib=&dc_libref)
|
|
%mpe_makedata(lib=&DC_LIBREF,mpeadmins=&admin,path=%str(&dcpath))
|
|
|
|
|
|
%mp_abort(iftrue= (&syscc ne 0)
|
|
,mac=&_program..sas
|
|
,msg=%str(Problem creating tables in &DC_LIBREF library)
|
|
)
|
|
|
|
/* finally, update the app component. The user will need WM perms for this. */
|
|
filename stngs temp;
|
|
data _null_;
|
|
file stngs ;
|
|
put ' ';
|
|
put '%global dc_repo_users dc_macros dc_libref dc_staging_area dc_admin_group mpelib dc_dttmtfmt;';
|
|
put ' ';
|
|
put '%let dc_libref=' "&dc_libref;";
|
|
put ' ';
|
|
put '/* This metadata group has unrestricted access to Data Controller */';
|
|
put '%let dc_admin_group=' "&admin;";
|
|
put ' ';
|
|
put "libname &dc_libref '&dcpath' ;";
|
|
put ' ';
|
|
put '/* This physical location is used for staging data and audit history */';
|
|
put '%let dc_staging_area=' "&dcpath/dc_staging;";
|
|
put ' ';
|
|
put 'data _null_;';
|
|
put ' set &DC_LIBREF..mpe_config(where=(';
|
|
put ' var_scope="DC" ';
|
|
put ' and &dc_dttmtfmt. lt tx_to';
|
|
put ' and var_active=1';
|
|
put " ));";
|
|
put " call symputx(var_name,var_value,'G');";
|
|
put ' putlog var_name "=" var_value;';
|
|
put "run;";
|
|
put ' ';
|
|
put '/* to override any DC macros with client versions, place them below */';
|
|
put 'options insert=(sasautos=("&dc_macros"));';
|
|
put '%let mpelib=&DC_LIBREF;';
|
|
run;
|
|
|
|
|
|
|
|
%mp_abort(iftrue= (&syscc ne 0)
|
|
,mac=&_program
|
|
,msg=%str(syscc=syscc=&syscc when preparing data_controller_settings)
|
|
)
|
|
|
|
%ms_deletefile(&root/services/public/settings.sas)
|
|
%ms_createfile(&root/services/public/settings.sas, inref=stngs)
|
|
|
|
|
|
%mp_abort(iftrue= (&syscc ne 0)
|
|
,mac=&_program..sas
|
|
,msg=%str(Problem updating &root/services/public/settings)
|
|
)
|
|
|
|
|
|
%if &OUTFMT=JSON %then %do;
|
|
data work.makedata_response;
|
|
length STATUS $10 MESSAGE $256 DCPATH $256 LIBREF $8 ADMIN $64;
|
|
STATUS='SUCCESS';
|
|
MESSAGE="Data Controller Config created by &sysuserid";
|
|
DCPATH="&dcpath";
|
|
LIBREF="&DC_LIBREF";
|
|
ADMIN="&admin";
|
|
run;
|
|
%webout(OPEN)
|
|
%webout(OBJ, makedata_response)
|
|
%webout(CLOSE)
|
|
%end;
|
|
%else %do;
|
|
data _null_;
|
|
file _webout;
|
|
put '<h3>Data Controller Config</h3>';
|
|
put '<p>The following items have been successfully configured:</p>';
|
|
put "<ul><li>Library Location (&dcpath)</li>";
|
|
put "<li>Table Creation (&DC_LIBREF library) using the <b>&sysuserid</b> identity</li>";
|
|
put "<li>Logs Location (%trim(&dcpath)/logs)</li>";
|
|
put "<li>Data Controller Admin Group (&admin)</li>";
|
|
put "</ul>";
|
|
put 'Future configuration changes can be made <a href="';
|
|
put "/#/SASjsDrive?filePath=&root/services/public/settings";
|
|
put '">here</a></p>';
|
|
put "<p> Next Steps: </p>";
|
|
put "<ol><li>Populate<a target='_blank' href='";
|
|
put "/SASjsApi/stp/execute?_program=&root/services/admin/refreshcatalog'>";
|
|
put "Data Catalog</a></li>";
|
|
put "<li><a target='_blank' href='/AppStream/DataController'>Launch!</a>";
|
|
put "</li></ol>";
|
|
run;
|
|
%end;
|
|
|
|
/* We ran successfully, now remove configurator and makedata STPs, unless the
|
|
* caller asked to keep them (KEEPME in the input data). Keeping them is for
|
|
* test harnesses, which reseed before every run and cannot redeploy first. */
|
|
%if &keepme ne 1 %then %do;
|
|
%ms_deletefile(&root/services/admin/configurator.sas);
|
|
%ms_deletefile(&_program..sas);
|
|
%end;
|
|
%else %do;
|
|
%put NOTE: &_program retained, as KEEPME was requested;
|
|
%end;
|
|
|
|
|