Files
dc/sas/sasjs/targets/viya/services_viya/admin/makedata.sas
T
dc c0ea810766
Build / Build-and-ng-test (pull_request) Successful in 4m54s
Lighthouse Checks / lighthouse (pull_request) Successful in 20m1s
Build / Build-and-test-development (pull_request) Successful in 32m10s
fix(makedata): pair the %else of the keepme block so it parses in open code
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.
2026-10-28 16:38:21 +00:00

306 lines
7.8 KiB
SAS

/**
@file
@brief self destructing setup service
@details Will create the database and perform config activities
<h4> SAS Macros </h4>
@li mf_getapploc.sas
@li mf_getuniquefileref.sas
@li mf_mkdir.sas
@li mf_trimstr.sas
@li mp_abort.sas
@li mpe_makedata.sas
@li mpe_makedatamodel.sas
@li mpe_makesampledata.sas
@li mv_createfile.sas
@li mv_deletejes.sas
@version 3.5
@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 dcpath ADMIN _contextname ;
%webout(FETCH)
/* enable vars to be passed as url params */
%let exist=%sysfunc(exist(work.fromjs));
%let inds=%sysfunc(ifc(&exist=1,fromjs,_null_));
/* optional KEEPME column - keep this program on the content server after a
* successful run. A normal install self-destructs so the seeding cannot be
* run twice over live data; a test harness reseeds once and then re-runs
* individual tests, so it wants the program 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;
data _null_;
set &inds;
call symputx('dcpath',dcpath);
call symputx('ADMIN',ADMIN);
call symputx('_contextname',_contextname);
run;
options noquotelenmax;
%let dclib=%upcase(VIYA%substr(%sysevalf(%sysfunc(datetime())/60),3,4));
%let dclibname=Data Controller (&dclib);
%let DC_LIBREF=&dclib;
%let work=%sysfunc(pathname(work));
%let dcpath=%mf_trimstr(&dcpath,/)/&dclib;
%put &=sysuserid;
%put &=dcpath;
%put &=admin;
%mf_mkdir(&dcpath)
%mp_abort(iftrue= (&syscc ne 0)
,mac=&_program
,msg=%str(Unable to create &dcpath using &sysuserid)
)
%mf_mkdir(&dcpath/secret)
%mf_mkdir(&dcpath/dc_staging)
/* check we have physical permissions to the DCLIB folder */
data _null_;
putlog "dcpath=&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 to: &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 )
)
libname &dclib "&dcpath";
%global admin;
%let admin=%sysfunc(coalescec(&admin,All Users));
%mpe_makedatamodel(lib=&dclib)
%mpe_makedata(lib=&dclib,mpeadmins=&admin,path=%str(&dcpath))
%mp_abort(iftrue=(&syscc ne 0)
,mac=&sysmacroname
,msg=%str(Err during &dclib build)
)
/* sample data library */
%mf_mkdir(&dcpath/dc_demo)
libname dcdemo "&dcpath/dc_demo";
%mpe_makesampledata(outlib=DCDEMO)
%mp_abort(iftrue=(&syscc ne 0)
,mac=&sysmacroname
,msg=%str(Err during demo data build)
)
/* the DC precode is stored in the root of the project */
%let root=%mf_getapploc(&_program)/services;
%put &=root;
filename jobout filesrvc folderpath="&root";
data _null_;
file jobout('settings.sas');
put '/* these values are ignored if DC_LIBREF was declared in autoexec */';
put ' ';
put '%global DC_LIBREF dc_admin_group dc_staging_area ;';
put '/* This library (libref) contains the control datasets for DC */';
put '/* If a different libref must be used, configure it below */';
put '%let DC_LIBREF=' "&dclib;";
put ' ';
put "libname &dclib '&dcpath' ;";
put ' ';
put '/* This group has unrestricted access to Data Controller */';
put '%let dc_admin_group=' "&admin;";
put ' ';
put '/* This physical location is used for staging data and audit history */';
put '%let dc_staging_area=' "&dcpath/dc_staging;";
put ' ';
put 'cas dcsession sessopts=(caslib=casuser);';
put 'caslib _all_ assign;';
put ' ';
if &syssite in (70221618,70253615) then do;
put "libname dcdemo '&dcpath/dc_demo';";
end;
run;
/* create demo data
cas dcsession;
caslib _all_ assign;
caslib casmusic path='/opt/sas/viya/cascache/tracks' libref=casmusic GLOBAL;
proc casutil;
LOAD DATA=dcdemo.cars
CASOUT="cars"
OUTCASLIB="casmusic" PROMOTE ;
run;
*/
/*
cas mysess;
caslib _all_ assign;
data casmusic.artists(promote=yes);
length name varchar(30);
do tracks=1 to 100;
name='Phil Collins'!!cats(tracks);
output;
end;
run;
*/
/*
%let url=http://millionsongdataset.com/sites/default/files/AdditionalFiles%trim(
)/unique_tracks.txt;
filename test url "&url" lrecl=3000 ;
proc sql;
drop table casmusic.tunes;
data tracks;
infile test dlmstr='<SEP>' dsd end=lastobs;
input track_id:$32. song_id:$32. artist_nm:$128. title:$256.;
output;
if lastobs then do;
track_id='dummyrecords';
title='none';
artist_nm='none';
do x=1 to 4000000;
drop x;
song_id=cats(x);
output;
end;
stop;
end;
run;
proc casutil;
LOAD DATA=tracks
CASOUT="tunes"
OUTCASLIB="casmusic" PROMOTE ;
run;
/*
data append;
if 0 then set &dclib..MPE_TABLES;
libref="CASMUSIC";
dsn='TUNES';
num_of_approvals_required=1;
loadtype='UPDATE';
buskey='TRACK_ID SONG_ID';
tx_from=0;
tx_to='31DEC9999:23:59:59'dt;
output;
dsn='ARTISTS';
buskey='NAME';
output;
run;
proc append base=&dclib..MPE_tABLES data=append;
run;
*/
%mp_abort(iftrue=(&syscc ne 0)
,mac=&sysmacroname
,msg=%str(Err during settings job creation)
)
/* Update the compute context in the streamed frontend (DC.html) so that
Data Controller runs under the same context that was selected when this
service was invoked. The file must be re-created using %mv_createfile
(the same macro used to stream the frontend at deploy time) rather than
updated in place with a filesrvc fileref - only the Files service POST
assigns the correct mime type (text/html / file_html), without which the
frontend will not stream. This service is always invoked from a URL so
the _contextname parameter is always present. */
%global _contextname;
%let dchtml_in=%mf_getuniquefileref();
%let dchtml_out=%mf_getuniquefileref();
/* Escape regex metacharacters (\ and $) in the context name so they are
treated as literals when embedded in the prxchange replacement string.
In a Perl regex replacement, \ introduces a backreference and $ introduces
variable interpolation; prefixing each with \ quotes them as literals. */
data _null_;
length _ctxname $256 _ctxesc $512;
_ctxname=symget('_contextname');
_ctxesc=tranwrd(tranwrd(_ctxname,'\','\\'),'$','\$');
call symputx('_contextname_escaped',_ctxesc);
run;
/* read the existing frontend */
filename &dchtml_in filesrvc folderpath="&root" filename="DC.html"
lrecl=32767;
%mp_abort(iftrue= (&syscc ne 0)
,mac=&sysmacroname
,msg=%str(Unable to open DC.html in &root)
)
/* write the updated html to a temporary file */
data _null_;
file &dchtml_out lrecl=32767;
infile &dchtml_in lrecl=32767 truncover;
input;
length line $32767;
line=prxchange(cats('s|contextname="[^"]*"|contextname="'
,symget('_contextname_escaped')
,'"|'
),-1,_infile_);
put line;
run;
filename &dchtml_in clear;
%mp_abort(iftrue= (&syscc ne 0)
,mac=&sysmacroname
,msg=%str(Unable to update compute context in DC.html)
)
/* re-create DC.html via the Files service to retain the html mime type */
%mv_createfile(path=&root, name=DC.html, inref=&dchtml_out)
filename &dchtml_out clear;
%webout(OPEN)
data result;
dclib="&dclib";
admingroup="&admin";
dcpath="&dcpath";
run;
%webout(OBJ,result)
%webout(CLOSE)
/* keep the program when KEEPME was requested, so a reseed does not need a
* redeploy first */
%if &keepme ne 1 %then %do;
%mv_deletejes(path=&root/admin, name=makedata);
%end;
%else %do;
%put NOTE: &_program retained, as KEEPME was requested;
%end;