Name
sn_pipeline.PipelineRunnerUtils
Description
Some helper scripts for Pipeline Runner API
Script
var PipelineRunnerUtils = {
/**
* Checks to see if user is authorized to run a pipeline of a particular type by checking user has atleast 1 role/permission set defined in the pipeline type
* Throws an error if user fails access check
* @param {String} pipelineType - name column in sn_pipeline_pipeline_type table that defines which pipelineType to check access for
* @param {Object} requestData - the request body. Used to extract app_sys_id when checking permissions
* @param {GlideRecord} grControllerEnv - controller environment record.
* @returns {Boolean}
*/
checkUserAccess: function(pipelineType, requestData, grControllerEnv) {
var currentUser = gs.getUser();
if (currentUser.hasRole("admin")) {
return true; // You don't mess with the admin
}
var accessDetails = this.getPipelineTypeAccessDetails(pipelineType, grControllerEnv);
var roles = accessDetails.roles;
var permissionSets = accessDetails.permissionSets;
var checkRoles = roles && roles.length;
var checkPermissions = permissionSets && permissionSets.length;
if (!(checkRoles || checkPermissions)) { // neither restrictions are placed, no need to go further
return true;
}
if (checkRoles) {
for (i = 0; i < roles.length; i++) {
if (currentUser.hasRole(roles[i])) {
return true; // user has one of the roles
}
}
}
if (checkPermissions) {
var scope = (requestData.payload || {}).app_sys_id;
if (!scope) { // scope is required to check permission sets.
throw new sn_ws_err.ServiceError()
.setStatus(400)
.setMessage(gs.getMessageLang("Invalid payload", "en"))
.setDetail(gs.getMessage("app_sys_id is required in payload for pipelineType {0}", pipelineType));
}
var scopePermSetRoleAssignmentGR = new GlideRecord('sys_scope_permission_set_role_assignment');
scopePermSetRoleAssignmentGR.addQuery("permission_set", "IN", permissionSets.join());
var userHasRoleJoinQueryCondition = scopePermSetRoleAssignmentGR.addJoinQuery('sys_user_has_role', "role", "role");
userHasRoleJoinQueryCondition.addCondition("user", currentUser.getID());
scopePermSetRoleAssignmentGR.addQuery("scope", scope);
scopePermSetRoleAssignmentGR.query();
if (scopePermSetRoleAssignmentGR.hasNext()) { // user has one of the permission sets in the given scope
return true;
}
}
throw new sn_ws_err.ServiceError()
.setStatus(403)
.setMessage(gs.getMessageLang("User Not Authorized", "en"))
.setDetail(gs.getMessage("User failed access check for pipelineType {0}", pipelineType));
},
/**
* Gets the roles and permissionSets set up for a pipelineType
* @param {String} pipelineType - name column in sn_pipeline_pipeline_type table that defines which pipelineType to check access for
* @param {GlideRecord} grControllerEnv - controller environment record. If passed, queries the controller environment to get pipeline type record
* @returns {Object} { roles: [Array], permissionSets: [Array]}
*/
getPipelineTypeAccessDetails: function(pipelineType, grControllerEnv) {
var pipelineUtils = new PipelineUtils();
var pipelineTypeObject = {};
if (!grControllerEnv) {
pipelineTypeObject = pipelineUtils.getPipelineTypeByName(pipelineType);
return {
roles: pipelineTypeObject[PipelineConstants.formFields.ROLES_REQUIRED_IN_SOURCE_ENVIRONMENT],
permissionSets: pipelineTypeObject[PipelineConstants.formFields.PERMISSION_SETS_REQUIRED_IN_SOURCE_ENVIRONMENT]
};
}
var inputs = {};
inputs[PipelineConstants.flow.runner.input.URL] = grControllerEnv.getValue('instance_url');
inputs[PipelineConstants.flow.runner.input.CREDENTIAL] = grControllerEnv.instance_credential.getRefRecord();
inputs[PipelineConstants.flow.runner.input.PIPELINE_TYPE_NAME] = pipelineType;
var status = 500;
var getPipelineTypeResponse = {};
try {
var getPipelineTypeOutputs = pipelineUtils.getPipelineActionResponse(
PipelineConstants.flow.pipelineType.actions.GET_PIPELINE_TYPE_ACTION,
inputs
);
status = getPipelineTypeOutputs["status_code"];
getPipelineTypeResponse = getPipelineTypeOutputs.response_body ? JSON.parse(getPipelineTypeOutputs.response_body) : {};
} catch (e) {
gs.debug("Get Pipeline Type action failed with error: " + JSON.stringify(e));
throw new sn_ws_err.ServiceError()
.setStatus(500)
.setMessage(gs.getMessageLang("Error getting pipeline type details", "en"))
.setDetail(gs.getMessage("Error when getting pipeline type details from controller instance"));
}
if (status === 200) {
pipelineTypeObject = getPipelineTypeResponse.result || {};
return {
roles: pipelineTypeObject[PipelineConstants.formFields.ROLES_REQUIRED_IN_SOURCE_ENVIRONMENT],
permissionSets: pipelineTypeObject[PipelineConstants.formFields.PERMISSION_SETS_REQUIRED_IN_SOURCE_ENVIRONMENT]
};
} else {
var parsedError = getPipelineTypeResponse.error || {};
throw new sn_ws_err.ServiceError()
.setStatus(status)
.setMessage(parsedError.message)
.setDetail(gs.getMessage("Error when getting pipeline type details from controller instance: {0}", parsedError.detail));
}
},
/**
* Redirects request to controller environment
* @param {GlideRecord} grControllerEnv - controller environment record to which the request is redirected
* @param {String} pipelineType - name column in sn_pipeline_pipeline_type table for the API to hit
* @param {Object} requestData - the request body to send
* @returns {Object} { status: {String}, result: {Object} }
*/
redirectToController: function(grControllerEnv, pipelineType, requestData) {
requestData.source_instance_id = gs.getProperty("instance_id"); // redirecting so source instance id will be current instance
var authKey = (new RequestAuthService()).createKey(JSON.stringify({
pipelineType: pipelineType,
requestData: requestData,
user: gs.getUserID(),
currentTime: (new GlideDateTime()).toString()
}));
var inputs = {};
inputs[PipelineConstants.flow.runner.input.URL] = grControllerEnv.getValue('instance_url');
inputs[PipelineConstants.flow.runner.input.CREDENTIAL] = grControllerEnv.instance_credential.getRefRecord();
inputs[PipelineConstants.flow.runner.input.PIPELINE_TYPE_NAME] = pipelineType;
inputs[PipelineConstants.flow.runner.input.REQUEST_BODY] = JSON.stringify(requestData);
inputs[PipelineConstants.flow.runner.input.REQUEST_AUTH_TOKEN] = authKey;
var status = 500;
var pipelineRunnerResponse = {};
try {
var pipelineRunnerOutputs = (new PipelineUtils()).getPipelineActionResponse(
PipelineConstants.flow.runner.actions.RUNNER_ACTION,
inputs
);
status = pipelineRunnerOutputs["status_code"];
pipelineRunnerResponse = pipelineRunnerOutputs.response_body ? JSON.parse(pipelineRunnerOutputs.response_body) : {};
} catch (e) {
gs.debug("Pipeline Runner redirect failed with error: " + JSON.stringify(e));
throw new sn_ws_err.ServiceError()
.setStatus(500)
.setMessage(gs.getMessageLang("Error starting the pipeline", "en"))
.setDetail(gs.getMessage("Error from redirecting request to controller instance"));
}
if (status === 201) {
var parsedResult = pipelineRunnerResponse.result || {};
parsedResult["redirected"] = true;
return {
status: 201,
result: parsedResult
};
} else {
var parsedError = pipelineRunnerResponse.error || {};
throw new sn_ws_err.ServiceError()
.setStatus(status)
.setMessage(parsedError.message)
.setDetail(gs.getMessage("Redirected response from controller instance: {0}", parsedError.detail));
}
},
/**
* Queries sn_pipeline_pipeline table and throws an error if not found
* @param {String} instanceId - instance_id column of the originating environment
* @param {String} pipelineType - name column of the sn_pipeline_pipeline_type record
* @returns {GlideRecord}
*/
findPipelineForInstanceOfType: function(instanceId, pipelineType) {
var grPipeline = (new PipelineUtils()).getPipelineforInstanceIdOfType(instanceId, pipelineType);
if (!grPipeline) {
throw new sn_ws_err.ServiceError()
.setStatus(404)
.setMessage(gs.getMessageLang("Requested pipeline does not exist for given instance id.", "en"))
.setDetail(gs.getMessage("Could not find pipeline of type {0} for instance id {1}", [pipelineType, instanceId]));
}
return grPipeline;
},
/**
* Initializes the sn_pipeline_pipeline_instance record
* @param {String} pipelineTypeSysId - sys_id of a sn_pipeline_pipeline_type record
* @param {String} sourceInstanceId - instance_id column of the originating environment
* @param {Object} payload - payload sent to start the pipeline
* @returns {GlideRecord}
*/
initializePipelineInstanceRecord: function(pipelineTypeSysId, sourceInstanceId, payload) {
var grPipelineInstance = new GlideRecord(PipelineConstants.table.PIPELINE_INSTANCE_TABLE);
grPipelineInstance.newRecord();
grPipelineInstance.setValue("pipeline_type", pipelineTypeSysId);
grPipelineInstance.setValue("source_instance_id", sourceInstanceId);
grPipelineInstance.setValue("pipeline_payload", JSON.stringify(payload));
return grPipelineInstance;
},
/**
* Runs the validate payload script in sn_pipeline_pipeline_type record and saves results in a sn_pipeline_pipeline_instance record
* @param {GlideRecord} grPipelineInstance - sn_pipeline_pipeline_instance record to save the result to
* @param {Object} payload - payload to validate
* @param {GlideRecord} grPipelineType - sn_pipeline_pipeline_type record whose script to execute
* @returns {GlideRecord} sn_pipeline_pipeline_instance with results saved
*/
validatePayloadAndSaveResult: function(grPipelineInstance, payload, grPipelineType) {
var payloadValidationResult = this.getPipelineTypePayloadValidationResult(grPipelineType, payload);
grPipelineInstance.setValue("payload_validation_details", JSON.stringify(payloadValidationResult));
if (payloadValidationResult && !payloadValidationResult.is_valid) {
grPipelineInstance.setValue("payload_valid", false);
grPipelineInstance.insert();
throw new sn_ws_err.ServiceError()
.setStatus(400)
.setMessage(gs.getMessageLang("Invalid payload.", "en"))
.setDetail(payloadValidationResult.error_message);
}
grPipelineInstance.setValue("payload_valid", true);
return grPipelineInstance;
},
/**
* Returns the results from the validate payload script in sn_pipeline_pipeline_type record
* @param {GlideRecord} grPipelineType - sn_pipeline_pipeline_type record whose script to execute
* @param {Object} payload - payload to validate
* @returns {Object}
*/
getPipelineTypePayloadValidationResult: function(grPipelineType, payload) {
var evaluator = new GlideScopedEvaluator();
evaluator.putVariable("payload", payload);
return evaluator.evaluateScript(grPipelineType, 'payload_validation_script');
},
/**
* Runs the pipeline runner subflow async and returns the context id
* @param {GlideRecord} grPipeline
* @param {Object} payload
* @param {GlideRecord} subflow
* @returns {String}
*/
startPipelineRunnerSubflow: function(grPipeline, payload, subflow, pipelineInstance) {
var runnerInputs = {};
runnerInputs[PipelineConstants.flow.runner.input.PIPELINE] = grPipeline;
runnerInputs[PipelineConstants.flow.runner.input.PAYLOAD] = payload;
runnerInputs[PipelineConstants.flow.runner.input.PIPELINE_TYPE_SUBFLOW] = subflow;
runnerInputs[PipelineConstants.flow.runner.input.PIPELINE_INSTANCE] = pipelineInstance;
var subflowResult = sn_fd.FlowAPI.getRunner()
.subflow(PipelineConstants.flow.runner.subflows.RUNNER_SUBFLOW)
.inBackground()
.withInputs(runnerInputs)
.run();
return subflowResult.getContextId();
}
};
Sys ID
64b1dfcec7d23010408bc8d6f2c2603f