-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSAS Content - Obtain Folder URI.step
1 lines (1 loc) · 21 KB
/
SAS Content - Obtain Folder URI.step
1
{"creationTimeStamp":"2023-12-04T00:09:29.947Z","modifiedTimeStamp":"2023-12-18T17:49:01.924Z","createdBy":"viya_admin","modifiedBy":"viya_admin","name":"SAS Content - Obtain Folder URI.step","displayName":"SAS Content - Obtain Folder URI.step","localDisplayName":"SAS Content - Obtain Folder URI.step","properties":{},"links":[{"method":"GET","rel":"self","href":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","uri":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","type":"application/vnd.sas.data.flow.step"},{"method":"GET","rel":"alternate","href":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","uri":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","type":"application/vnd.sas.data.flow.step.summary"},{"method":"GET","rel":"up","href":"/dataFlows/steps","uri":"/dataFlows/steps","type":"application/vnd.sas.collection","itemType":"application/vnd.sas.data.flow.step.summary"},{"method":"PUT","rel":"update","href":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","uri":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","type":"application/vnd.sas.data.flow.step","responseType":"application/vnd.sas.data.flow.step"},{"method":"DELETE","rel":"delete","href":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","uri":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef"},{"method":"GET","rel":"transferExport","href":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","uri":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","responseType":"application/vnd.sas.transfer.object"},{"method":"PUT","rel":"transferImportUpdate","href":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","uri":"/dataFlows/steps/4ccb7cb3-5135-4062-91d3-3f0c0e03b9ef","type":"application/vnd.sas.transfer.object","responseType":"application/vnd.sas.summary"}],"metadataVersion":0.0,"version":2,"type":"code","flowMetadata":{"inputPorts":[],"outputPorts":[]},"ui":"{\n\t\"showPageContentOnly\": true,\n\t\"pages\": [\n\t\t{\n\t\t\t\"id\": \"parameters\",\n\t\t\t\"type\": \"page\",\n\t\t\t\"label\": \"Parameters\",\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"sasContentFolder\",\n\t\t\t\t\t\"type\": \"path\",\n\t\t\t\t\t\"label\": \"Select SAS Content folder:\",\n\t\t\t\t\t\"pathtype\": \"folder\",\n\t\t\t\t\t\"placeholder\": \"/Example/Public/Some_Folder\",\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"outputMacroInfo\",\n\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\"text\": \"The following are the two global macro variables created within this step:\\n\\n1. targetFolderURI: macro variable containing URI of the folder provided\\n\\n2. contentFolderExists: indicator whether the specified folder exists or not. Valid values are 1 if it exists, 0 if it doesn't exist, and 99 as a special value to indicate the need for further debugging.\",\n\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"id\": \"about\",\n\t\t\t\"type\": \"page\",\n\t\t\t\"label\": \"About\",\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"about_description\",\n\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\"text\": \"This is a utility custom step which obtains the URI of a selected SAS Content folder and saves it in a global macro variable if the folder exists. It also populates another global macro variable with a flag of 1 or 0 to indicate if the folder exists or not, which may be used in downstream code.\\n\\nSome SAS programs require operations to be performed on folders located inside the SAS Infrastructure Data Server (also known as SAS Content), and such operations typically require the folder URI. \",\n\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"about_parameters\",\n\t\t\t\t\t\"type\": \"section\",\n\t\t\t\t\t\"label\": \"Parameters\",\n\t\t\t\t\t\"open\": 0,\n\t\t\t\t\t\"visible\": \"\",\n\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"parameters_text\",\n\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\"text\": \"This custom step wraps proc http calls to a SAS Viya endpoint in order to check for a folder. While it's likely that your environment's administrator has already ensured for the same, please verify that north-south communication among pods is enabled / whitelisted in your environment. A quick check for this would be to run a simple proc http call (e.g. a get request) to your SAS Viya endpoint and note if you are able to get a response code of 200 (OK).\",\n\t\t\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"parameters_input\",\n\t\t\t\t\t\t\t\"type\": \"section\",\n\t\t\t\t\t\t\t\"label\": \"Input Parameters\",\n\t\t\t\t\t\t\t\"open\": 1,\n\t\t\t\t\t\t\t\"visible\": \"\",\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"id\": \"input_parameters_text\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"text\": \"- SAS Content Folder (folder selector, required): provide the full path of a SAS Content folder you wish to obtain the URI for.\",\n\t\t\t\t\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"parameters_output_specs\",\n\t\t\t\t\t\t\t\"type\": \"section\",\n\t\t\t\t\t\t\t\"label\": \"Output Specifications\",\n\t\t\t\t\t\t\t\"open\": 1,\n\t\t\t\t\t\t\t\"visible\": \"\",\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"id\": \"output_parameters_text\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"text\": \"The simple output provided by this initial version of this custom step are in the form of 2 global macro variables.\\n\\n1. targetFolderURI: this contains the URI of the folder in case it exists, and a direction to the HTTP status code error variable in case of other reasons. Other reasons could include the specified folder not existing on the target environment, or an inability to make an HTTP request (as mentioned above).\\n\\n2. contentFolderExists: this is populated with the following values. \\n i. In case the folder exists, this is populated with a value of 1. \\n ii. In case the folder does not exist, the value is set to 0.\\n iii. In case the request was unsuccessful (resulting in a status code other than 200 or 404), then the value is set to 99.\\n\\nThe value of SYS_PROCHTTP_STATUS_CODE, a system variable, is also surfaced within the log for better debugging.\",\n\t\t\t\t\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"about_runtimecontrol\",\n\t\t\t\t\t\"type\": \"section\",\n\t\t\t\t\t\"label\": \"Run-time Control\",\n\t\t\t\t\t\"open\": 0,\n\t\t\t\t\t\"visible\": \"\",\n\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"runtimecontrol_text\",\n\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\"text\": \"Edit / keep this section only if you want to have a run-time control\\n\\nNote: Run-time control is optional. You may choose whether to execute the main code of this step or not, based on upstream conditions set by earlier SAS programs. This includes nodes run prior to this custom step earlier in a SAS Studio Flow, or a previous program in the same session.\\n\\nRefer this blog (https://communities.sas.com/t5/SAS-Communities-Library/Switch-on-switch-off-run-time-control-of-SAS-Studio-Custom-Steps/ta-p/885526) for more details on the concept.\\n\\nThe following macro variable,\\n\\n_ofu_run_trigger\\n\\nwill initialize with a value of 1 by default, indicating an \\\"enabled\\\" status and allowing the custom step to run.\\n\\nIf you wish to control execution of this custom step, include code in an upstream SAS program to set this variable to 0. This \\\"disables\\\" execution of the custom step.\\n\\nTo \\\"disable\\\" this step, run the following code upstream:\\n\\n%global _ofu_run_trigger;\\n%let _ofu_run_trigger =0;\\n\\nTo \\\"enable\\\" this step again, run the following (it's assumed that this has already been set as a global variable):\\n\\n%let _ofu_run_trigger =1;\\n\\nIMPORTANT: Be aware that disabling this step means that none of its main execution code will run, and any downstream code which was dependent on this code may fail. Change this setting only if it aligns with the objective of your SAS Studio program.\",\n\t\t\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"about_documentation\",\n\t\t\t\t\t\"type\": \"section\",\n\t\t\t\t\t\"label\": \"Documentation\",\n\t\t\t\t\t\"open\": 0,\n\t\t\t\t\t\"visible\": \"\",\n\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"documentation_text\",\n\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\"text\": \"1. Note this section within the documentation on the filesrvc filename reference method. Note that the filesrvc filename reference results in an automatically generated macro variable containing the URI, which is in fact used within this custom step. However, the direct use of the filesrvc reference on a non-existent folder results in an error, which is handled by this custom step: https://go.documentation.sas.com/doc/en/pgmsascdc/default/lestmtsglobal/p0qapul7pyz9hmn0zfoefj0c278a.htm#p0nscb67k9xhr5n1fqx4pvnoed4f\\n\\n2. This specific operation was inspired by similar code provided by David Weik for the purpose of transferring custom steps. His full code is located here: https://github.com/Criptic/sas_snippets/blob/master/Upload-and-Register-all-Custom-Steps.sas\\n\",\n\t\t\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"version_text\",\n\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\"text\": \"Version: 1.0 (03DEC2023)\",\n\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"contact_text\",\n\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\"text\": \"Created/contact: \\n\\n- Sundaresh Sankaran ([email protected])\\n\",\n\t\t\t\t\t\"visible\": \"\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"syntaxversion\": \"1.3.0\"\n}","templates":{"SAS":"/* templated code goes here*/;\n\n/*-----------------------------------------------------------------------------------------*\n START MACRO DEFINITIONS.\n*------------------------------------------------------------------------------------------*/\n\n/* -----------------------------------------------------------------------------------------* \n Error flag for capture during code execution.\n*------------------------------------------------------------------------------------------ */\n\n%global _ofu_error_flag;\n%let _ofu_error_flag=0;\n\n/* -----------------------------------------------------------------------------------------* \n Global macro variable for the trigger to run this custom step. A value of 1 \n (the default) enables this custom step to run. A value of 0 (provided by upstream code)\n sets this to disabled.\n*------------------------------------------------------------------------------------------ */\n\n%global _ofu_run_trigger;\n\n%if %sysevalf(%superq(_ofu_run_trigger)=, boolean) %then %do;\n\n\t%put NOTE: Trigger macro variable _ofu_run_trigger does not exist. Creating it now.;\n %let _ofu_run_trigger=1;\n\n%end;\n\n/* -----------------------------------------------------------------------------------------* \n Macro to identify whether a given folder location provided from a \n SAS Studio Custom Step folder selector happens to be a SAS Content folder\n or a folder on the filesystem (SAS Server).\n\n Inputs:\n 1. pathReference: A path reference provided by the file or folder selector control in \n a SAS Studio Custom step.\n\n Outputs:\n 1. _path_identifier: Set inside macro, a global variable indicating the prefix of the \n path provided.\n\n*------------------------------------------------------------------------------------------ */\n%macro _identify_content_or_server(pathReference);\n %global _path_identifier;\n data _null_;\n call symput(\"_path_identifier\", scan(\"&pathReference.\",1,\":\",\"MO\"));\n run;\n%mend _identify_content_or_server;\n\n\n/* -----------------------------------------------------------------------------------------* \n Macro to extract the path provided from a SAS Studio Custom Step file or folder selector.\n\n Inputs:\n 1. pathReference: A path reference provided by the file or folder selector control in \n a SAS Studio Custom step.\n\n Outputs:\n 1. _sas_folder_path: Set inside macro, a global variable containing the path.\n\n*------------------------------------------------------------------------------------------ */\n%macro _extract_sas_folder_path(pathReference);\n %global _sas_folder_path;\n data _null_;\n call symput(\"_sas_folder_path\", scan(\"&pathReference.\",2,\":\",\"MO\"));\n run;\n%mend _extract_sas_folder_path;\n\n\n\n/*-----------------------------------------------------------------------------------------*\n Macro to obtain the URI of a desired SAS Content folder if it exists.\n This macro will check a given path in SAS Content and set a macro variable to folder URI \n if it exists, or a direction to the error code if not.\n \n Inputs:\n 1. targetFolderContent: the full path of the folder to check for\n \n Outputs:\n 1. targetFolderURI (global variable): set inside macro to the URI of the folder\n 2. contentFolderExists (global variable): set to 0 if the folder does not exist, 1 if\n it does, and 99 in case of other conditions (such as HTTP request failure). \n Note this is a side objective / additional objective of the current macro.\n\n Also available standalone at: \n https://github.com/SundareshSankaran/sas_utility_programs/blob/main/code/Get%20SAS%20Content%20Folder%20URI/macro_get_sas_content_folder_uri.sas\n*------------------------------------------------------------------------------------------*/\n\n%macro _get_sas_content_folder_uri(targetFolderContent);\n\n %global targetFolderURI;\n %global contentFolderExists;\n\n /*-----------------------------------------------------------------------------------------*\n Create a JSON payload containing the folder to check for.\n *------------------------------------------------------------------------------------------*/\n %local targetPathJSON;\n\n data _null_;\n call symput(\"targetPathJSON\",'{\"items\": ['||'\"'||transtrn(strip(transtrn(&targetFolderContent.,\"/\",\" \")),\" \",'\",\"')||'\"'||'], \"contentType\": \"folder\"}');\n run;\n\n filename pathData temp;\n filename outResp temp;\n\n data _null_;\n length inputData $32767.;\n inputData = symget(\"targetPathJSON\");\n file pathData;\n\t put inputData;\n run;\n\n /*-----------------------------------------------------------------------------------------*\n Call the /folders/paths endpoint to obtain the URI of the desired folder.\n *------------------------------------------------------------------------------------------*/\n %local viyaHost;\n %let viyaHost=%sysfunc(getoption(SERVICESBASEURL));\n\n %put NOTE: The Viya host resolves to &viyaHost.;\n\n proc http\n\t method='POST'\n\t url=\"&viyaHost./folders/paths\"\n\t in=pathData \n\toauth_bearer=sas_services\n\t/* out=outResp; */\n ;\n\theaders 'Content-Type'='application/vnd.sas.content.folder.path+json';\n quit;\n \n /*-----------------------------------------------------------------------------------------*\n In the event of a successful request, extract the URI\n *------------------------------------------------------------------------------------------*/\n\n %if \"&SYS_PROCHTTP_STATUS_CODE.\"=\"200\" %then %do;\n filename TEMPFNM filesrvc folderpath=&targetFolderContent.;\n\n /*-----------------------------------------------------------------------------------------*\n The Filename Filesrvc leads to an automatic macro variable which holds the URI. This \n will be assigned to the global variable.\n *------------------------------------------------------------------------------------------*/\n data _null_;\n\t call symput(\"targetFolderURI\", \"&_FILESRVC_TEMPFNM_URI.\");\n call symputx(\"contentFolderExists\", 1);\n run;\n\n filename TEMPFNM clear;\n %symdel _FILESRVC_TEMPFNM_URI;\n\n %end;\n %else %do;\n data _null_;\n call symput(\"targetFolderURI\", \"Refer SYS_PROCHTTP_STATUS_CODE macro variable.\");\n run;\n /*-----------------------------------------------------------------------------------------*\n Note that this macro also doubles up as a check for a desired folder inside \n SAS Content. While it's desirable to have separate code/macros for every single desired \n operation, we are adding this additional output because it does not require significant \n computation (beyond the code below).\n *------------------------------------------------------------------------------------------*/\n %if \"&SYS_PROCHTTP_STATUS_CODE.\"=\"404\" %then %do;\n %put NOTE: Folder is not found. ;\n data _null_;\n call symputx(\"contentFolderExists\",0);\n run;\n %end;\n %else %do;\n %put ERROR: The HTTP request returned &SYS_PROCHTTP_STATUS_CODE. ;\n data _null_;\n call symputx(\"contentFolderExists\",99);\n run;\n %end;\n %end;\n\n%mend _get_sas_content_folder_uri;\n\n/*-----------------------------------------------------------------------------------------*\n EXECUTION CODE MACRO \n*------------------------------------------------------------------------------------------*/\n\n%macro _ofu_main_execution_code;\n\n %local sasFolderPath;\n\n /*-----------------------------------------------------------------------------------------*\n Reset values of existing global variables (targetFolderURI and contentFolderExists) to \n zero, in case this custom step or macro had been used before. Users may like to \n save the values of these global variables prior to running this step.\n *------------------------------------------------------------------------------------------*/\n\n %if %symexist(targetFolderURI) %then %do;\n %let targetFolderURI=;\n %end;\n\n %if %symexist(contentFolderExists) %then %do;\n %let contentFolderExists=;\n %end;\n\n /*-----------------------------------------------------------------------------------------*\n Check if the folder path provided is in fact a SAS Content related path.\n *------------------------------------------------------------------------------------------*/\n\n %_identify_content_or_server(&sasContentFolder.);\n\n %if \"&_path_identifier.\"=\"sascontent\" %then %do;\n %put NOTE: The path provided is prefixed with &_path_identifier. ;\n %end;\n %else %do;\n %let _ofu_error_flag=1;\n %put ERROR: Path provided does not seem to be a SAS Content folder. Check your path. ;\n %end;\n\n %if &_ofu_error_flag. = 0 %then %do;\n\n /*-----------------------------------------------------------------------------------------*\n Extract the folder path from the path reference provided.\n *------------------------------------------------------------------------------------------*/\n\n %_extract_sas_folder_path(&sasContentFolder.);\n %let sasFolderPath=&_sas_folder_path.;\n %symdel _sas_folder_path;\n\n %_get_sas_content_folder_uri(\"&sasFolderPath.\");\n\n %if &_ofu_error_flag. = 0 %then %do;\n %put NOTE: This step has executed.;\n %put NOTE: Folder URI for &sasFolderPath., saved in global macro variable targetFolderURI is: &targetFolderURI.;\n %put NOTE: The indicator of whether the folder exists, global macro variable contentFolderExists is: &contentFolderExists.;\n %end;\n \n %end;\n\n%mend _ofu_main_execution_code;\n\n/*-----------------------------------------------------------------------------------------*\n END MACRO DEFINITIONS.\n*------------------------------------------------------------------------------------------*/\n\n/*-----------------------------------------------------------------------------------------*\n EXECUTION CODE\n The execution code is controlled by the trigger variable defined in this custom step. This\n trigger variable is in an \"enabled\" (value of 1) state by default, but in some cases, as \n dictated by logic, could be set to a \"disabled\" (value of 0) state.\n*------------------------------------------------------------------------------------------*/\n\n%if &_ofu_run_trigger. = 1 %then %do;\n\n %_ofu_main_execution_code;\n\n%end;\n%if &_ofu_run_trigger. = 0 %then %do;\n\n %put NOTE: This step has been disabled. Nothing to do.;\n\n%end;\n\n\n/*-----------------------------------------------------------------------------------------*\n Clean up existing macro variables and macro definitions.\n*------------------------------------------------------------------------------------------*/\n%if %symexist(_ofu_error_flag) %then %do;\n %symdel _ofu_error_flag;\n%end;\n%if %symexist(sasFolderPath) %then %do;\n %symdel sasFolderPath;\n%end;\n%if %symexist(_ofu_run_trigger) %then %do;\n %symdel _ofu_run_trigger;\n%end;\n\n%sysmacdelete _identify_content_or_server;\n%sysmacdelete _extract_sas_folder_path;\n%sysmacdelete _get_sas_content_folder_uri;\n%sysmacdelete _ofu_main_execution_code;"}}