ServiceNow Error when copying flow
Label cache error: Table not found: x_cls_clear_skye_i_identity_settings: Label cache error: Table not found: x_cls_clear_skye_i_identity_settingswhen copying the promote profile subflowreproduceable on 5.2 and 3
KB1575415 - How To Remove Unnecessary Label Cache Entries of a Flow/Subflow/Action
11:43
Apparently, running the background script detailed in the SN KB should resolve the issue
once happy, modify the fix script below to set debugmode to false
---
Fix script:
// README
// This script updates and removes unnecessary label cache entries of a flow/subflow (defintion and master snapshot).
//
// IMPORTANT NOTES:
// This script only deletes the unnecessary label cache in the server. UI can hold a copy of a label cache.
// Therefore refresh the browser that has the action opened once this script is executed for the action.
// If this script is executed and the action is saved using UI, the previous label cache (before the delete)
// will be saved since the label cache from the UI will be sent to the server and saved.
// Script Parameters
// If true then do not actually modify the flow/subflow's label cache (debug mode). If false then update the flow/subflow's label cache (real mode).
var debugMode = true;
// If empty, then execute for all flow/subflow definition and master snapshot files. Otherwise, only run for the flow/subflow/action with name = targetName.
var targetName = "";
// If true then it logs more debug messages.
var skipDetails = false;
// Code
var missCount = 0;
var hitCount = 0;
var numberOfRecordsModified = 0;
var numberOfFlowsModified = 0;
var flowsModified = {};
function cleanFlowLabelCache(flow, debug, flowVersion) {
var flowModified = false;
printWithName(flow.name, "Attempting to clean the label cache for flow/subflow \'" + flow.name + "\' with sys id \'" + flow.sys_id + "\' which is on the table " + flow.sys_class_name);
if (isEmpty(flow.label_cache) || flow.label_cache == "[]") {
printWithName(flow.name, "Has an empty label cache");
} else {
var pills = getPills(flow.sys_id, flowVersion);
// removes control characters in unicode (ex: \n), which the inclusion will cause a thrown exception in JSON.parse()
flow.label_cache = flow.label_cache.toString().replace(/[\u0000-\u001F\u007F-\u009F]/g, "");
var label_cache = {};
try {
label_cache = JSON.parse(flow.label_cache);
} catch(e) {
gs.print("Exception thrown. Message: " + e.message + " Stack trace: " + e.stack);
}
printWithName(flow.name, "Original label cache before the removal:\n" + flow.name + ": " + flow.label_cache);
var newLabelCache = [];
for (var labelKey in label_cache) {
if (pills[label_cache[labelKey].name] || pills['{{' + label_cache[labelKey].name + '}}'] ) {
if (skipDetails == false)
printWithName(flow.name, "We have a match " + label_cache[labelKey].name);
newLabelCache.push(label_cache[labelKey]);
hitCount++;
} else {
if (skipDetails == false)
printWithName(flow.name, "We have a miss " + label_cache[labelKey].name);
missCount++;
flowModified = true;
}
}
flow.label_cache = JSON.stringify(newLabelCache);
printWithName(flow.name, "New label cache after the removal:\n" + flow.name + ": " + flow.label_cache);
if (debug == false)
flow.update();
}
return flowModified;
}
function isEmpty(obj) {
return !obj || (Object.keys(obj).length === 0 && obj.constructor === Object)
}
function getPills(flowId, flowVersion) {
var pills = {};
var instances = new GlideRecord("sys_hub_flow_component");
instances.addQuery("flow", flowId);
instances.query();
while(instances.next()) {
if (flowVersion == "2") {
findPillsInInstanceCompressedString(instances, pills);
} else {
findPillsInMapping(instances.sys_id, pills);
findPillsInVariableValue(instances.sys_id, pills);
}
}
findPillsInMapping(flowId, pills);
findPillsInVariableValue(flowId, pills);
if (flowVersion == "2") {
findPillsInTriggerInstanceV2(flowId, pills);
} else {
findPillsInTriggerInstance(flowId, pills);
}
return pills;
}
function getUncompressedValue(compressedValues) {
if (skipDetails == false)
gs.print("compressedValues: " + compressedValues);
var values = "";
if (compressedValues)
values = new GlideCompressionUtil().expandToString(new GlideStringUtil().base64DecodeAsBytes(compressedValues));
if (skipDetails == false)
gs.print(values);
return values;
}
function findPillsInInstanceCompressedString(instances, pills) {
var tableName = null;
if (instances.sys_class_name == "sys_hub_action_instance_v2") {
tableName = "sys_hub_action_instance_v2";
} else if (instances.sys_class_name == "sys_hub_sub_flow_instance_v2") {
tableName = "sys_hub_sub_flow_instance_v2";
} else if (instances.sys_class_name == "sys_hub_flow_logic_instance_v2") {
tableName = "sys_hub_flow_logic_instance_v2";
}
if (tableName) {
var instanceGr = new GlideRecord(tableName);
if (instanceGr.get(instances.sys_id)) {
var compressedValues = null;
if (tableName == "sys_hub_sub_flow_instance_v2")
compressedValues = instanceGr.subflow_inputs + '';
else if (tableName == "sys_hub_action_instance_v2" || tableName == "sys_hub_flow_logic_instance_v2") {
compressedValues = instanceGr.values + '';
}
if (compressedValues) {
var values = getUncompressedValue(compressedValues);
findPillsInValue(values, pills);
}
}
}
}
function findPillsInTriggerInstanceV2(flowId, pills) {
var triggerInstance = new GlideRecord("sys_hub_trigger_instance_v2");
triggerInstance.addQuery("flow", flowId);
triggerInstance.query();
// should be at max one result in triggerInstance
while(triggerInstance.next()) {
var compressedValues = triggerInstance.trigger_inputs + '';
var values = getUncompressedValue(compressedValues);
findPillsInValue(values, pills);
}
}
function findPillsInTriggerInstance(flowId, pills) {
var triggerInstance = new GlideRecord("sys_hub_trigger_instance");
triggerInstance.addQuery("flow", flowId);
triggerInstance.query();
// should be at max one result in triggerInstance
while(triggerInstance.next()) {
var triggerInstanceId = triggerInstance.sys_id;
var sysVariableValue = new GlideRecord("sys_variable_value");
sysVariableValue.addQuery("document_key", triggerInstanceId);
sysVariableValue.query();
while(sysVariableValue.next()) {
var value = sysVariableValue.value;
findPillsInValue(value, pills);
}
}
}
function findPillsInMapping(id, pills) {
var elementMapping = new GlideRecord("sys_element_mapping");
elementMapping.addQuery("id", id);
elementMapping.query();
while(elementMapping.next()) {
var value = elementMapping.value;
findPillsInValue(value, pills);
}
}
function findPillsInVariableValue(id, pills) {
var variableValue = new GlideRecord("sys_variable_value");
variableValue.addQuery("document_key", id);
variableValue.query();
while(variableValue.next()) {
var value = variableValue.value;
findPillsInValue(value, pills);
}
};
function findPillsInTransform (value, pills) {
// removes "{{fd_transform:" prefix and "}}" postfix
if (value && value.length > 16) {
var uuid = value.substring(15, value.length - 2);
var pillCompound = new GlideRecord("sys_hub_pill_compound");
pillCompound.addQuery("ui_id", uuid);
pillCompound.query();
while (pillCompound.next()) {
var prescription = pillCompound.prescription;
if (skipDetails == false)
gs.print("Prescription value: " + prescription);
findPillsInValue(prescription, pills);
}
}
};
function findPillsInValue (value, pills) {
var result;
var PILL_REGEX = /{{(?!{)([^}]*)}}/g;
while(result = PILL_REGEX.exec(value)) {
if (result[0] && result[0].startsWith("{{fd_transform:") && result[0].length > 16) {
findPillsInTransform(result[0], pills);
} else {
pills[result[0]] = true;
}
if (skipDetails == false)
gs.print("Pill value: " + result[0]);
}
};
function findPillsInErrorHandling(id, pills) {
var errorHandlingMetadata = new GlideRecord("sys_hub_action_status_metadata");
if (!errorHandlingMetadata.get("action_type_id", id))
return;
var statusCondition = new GlideRecord("sys_hub_status_condition");
statusCondition.addQuery("action_status_metadata_id", errorHandlingMetadata.sys_id);
statusCondition.query();
while (statusCondition.next()) {
findPillsInValue(statusCondition.status, pills);
findPillsInValue(statusCondition.condition, pills);
}
}
function printWithName(name, text) {
gs.print(name + ": " + text);
}
var modified;
gs.print("Debug mode: " + debugMode);
if (debugMode == false)
gs.print("This is an actual execution that updates the label cache");
else
gs.print("This is a test run that does not actually update the label cache");
var flows = new GlideRecord("sys_hub_flow_snapshot");
flows.addQuery("master", true);
if (targetName)
flows.addQuery("name", targetName);
flows.query();
while (flows.next()) {
var version = flows.getValue("version");
var flowVersion = "1";
if (version == "2") {
flowVersion = "2";
}
modified = cleanFlowLabelCache(flows, debugMode, flowVersion);
if (modified) {
numberOfRecordsModified++;
if (!flowsModified[flows.name]) {
flowsModified[flows.name] = true;
numberOfFlowsModified++;
}
}
}
flows = new GlideRecord("sys_hub_flow");
if (targetName)
flows.addQuery("name", targetName);
flows.query();
while (flows.next()) {
var version = flows.getValue("version");
var flowVersion = "1";
if (version == "2") {
flowVersion = "2";
}
modified = cleanFlowLabelCache(flows, debugMode, flowVersion);
if (modified) {
numberOfRecordsModified++;
if (!flowsModified[flows.name]) {
flowsModified[flows.name] = true;
numberOfFlowsModified++;
}
}
}
gs.print("Total number of label cache entries removed: " + missCount);
gs.print("Total number of label cache entries kept (not removed): " + hitCount);
gs.print("Total number of flow/subflow definition and master snapshot records modified: " + numberOfRecordsModified);
gs.print("Total number of unique flow flow/subflow modified: " + numberOfFlowsModified);
Comments
Post a Comment