This post describes a way how to get detailed information about all workflows. For this an action is used that collects all information and saves it in XML format.
Get Detailed Information about all Workflows
First we take a look what information are provided and where it can be found in the UI of VCF Automation and in the XML. Here a look at the different tabs of a Workflow and the corresponding XML sections.
General Tab and XML Mapping
In the General tab we can find information about the name and the unique ID. Also we have a description and a version here. In XML we have the folder too.
<workflow folder="Library/vRealize Automation 8.x and Cloud Services/Sample Rest Operations" name="Put operation">
<id>4fbef6d4-bf4f-4907-8e33-b446d5084aaf</id>
<description>Generic rest client support for HTTP PUT operation.</description>
<version>0.0.0</version>
|
Variables Tab and XML Mapping
In the Variables tab we can find the attributes of the workflow, its names, types, descriptions and value.
<variables>
<variable>
<name>statusCodeAttribute</name>
<type>number</type>
<description></description>
</variable>
<variable>
<name>errorCode</name>
<type>string</type>
<description></description>
</variable>
</variables>
|
Inputs/Outputs Tab and XML Mapping
In the Inputs/Outputs tab we can find the parameters of the workflow, its names, types and descriptions.
<inputs>
<input>
<name>pathUri</name>
<type>string</type>
<description>Request path uri</description>
</input>
...
</inputs>
<outputs>
<output>
<name>headers</name>
<type>Array/string</type>
<description>Response headers</description>
</output>
...
</outputs>
|
Schema Tab and XML Mapping
In the Schema tab we can find workflow elements, which represents the procedure flow, with the details of each element.
<numberOfItems>4</numberOfItems>
<firstItem>Rest client - PUT operation</firstItem>
<schema>
<item>
<name>Rest client - PUT operation</name>
<description>Simple task with custom script capability.</description>
<type>Task</type>
<nextItem>Check status code</nextItem>
<isActionCall>false</isActionCall>
<isStartWorkflowCall>false</isStartWorkflowCall>
<linkedWorkflow></linkedWorkflow>
<usedActions>
</usedActions>
<script>
...
</script>
</item>
<item>
<name>End</name>
<description></description>
<type>End</type>
</item>
<item>
<name>Check status code</name>
<description>Custom decision based on a custom script.</description>
<type>CustomCondition</type>
<nextItem>End</nextItem>
<nextItemTrue>End</nextItemTrue>
<nextItemFalse>End</nextItemFalse>
<script>
if ( statusCodeAttribute >= 400 ) {
throw "HTTPError: status code: " + statusCodeAttribute;
} else {
return true;
}
</script>
</item>
<item>
<name>End</name>
<description></description>
<type>End</type>
</item>
</schema>
</workflow>
|
Action
To get all these information an action which detects all workflows is used, then the detailed information are collected in a loop, with the help of the Workflow object and its methods, and some variants of it. This information are stored in the XML structure presented above.
/**
* This action creates an XML file with all details of all existing
* workflows and its script code.
*
* @name getWorkflows
* @param {string} in_folderFilter - Search for substring in folder, optional
* @param {string} in_nameFilter - Search for substring in name, optional
* @author Stefan Schnell
* @version 1.3.3
*
* Checked with release 8.14.1
*/
var _getWorkflowsNS = {
/**
* _escapeXML
*
* Escapes characters in a string, which could be misinterpreted as
* markup in XML.
*
* @name escapeXML
* @param {string} strXML - XML which characters to convert
* @returns {string} Converted XML
*/
_escapeXML : function(strXML) {
if (strXML) {
return strXML.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
/*
.replace(/ä/g, "ae;")
.replace(/Ä/g, "Ae;")
.replace(/ö/g, "oe;")
.replace(/Ö/g, "Oe;")
.replace(/ü/g, "ue;")
.replace(/Ü/g, "Ue;")
.replace(/ß/g, "ss;");
*/
}
},
// Main --------------------------------------------------------------
Main : function() {
try {
var output = ("<?xml version=\"1.0\"?>");
output += ("<workflows>");
// Workflows
var workflows =
System.getModule("com.vmware.library.workflow").getAllWorkflows();
/* getAllWorkflows
var workflows = new Array();
var categories = Server.getAllworkflowCategories();
for (i in categories) {
getworkflowsOfCategory(categories[i]);
}
return workflows;
function getworkflowsOfCategory(cat) {
workflows = workflows.concat(cat.workflows);
var cats = cat.subCategories;
if (cats != null) {
for (index in cats) {
if (cats[index] != null)
getworkflowsOfCategory(cats[index]);
}
}
}
*/
// Search for substring in folder
if (in_folderFilter) {
// Reverse search in workflows array to ...
for (var i = workflows.length - 1; i >= 0; i--) {
if (
workflows[i].workflowCategory.path.indexOf(in_folderFilter) === -1
) {
// delete element if in_folderFilter not found in folder name
workflows.splice(i, 1);
}
}
}
// Search for substring in workflow name
if (in_nameFilter) {
// Reverse search in workflows array to ...
for (var i = workflows.length - 1; i >= 0; i--) {
if (workflows[i].name.indexOf(in_nameFilter) === -1) {
// delete element if in_nameFilter not found in workflow name
workflows.splice(i, 1);
}
}
}
workflows.forEach( function(workflow) {
// Workflow Summary
output += "<workflow folder=\"" + workflow.workflowCategory.path +
"\" name=\"" + _getWorkflowsNS._escapeXML(workflow.name) + "\">";
output += "<id>" + workflow.id + "</id>";
if (workflow.description) {
var workflowDescription =
workflow.description.replace(/[\r\n]/gm, '');
output += "<description>" +
_getWorkflowsNS._escapeXML(workflowDescription) +
"</description>";
} else {
output += "<description/>";
}
output += "<version>" + workflow.version + "</version>";
// Variables
var attributes = workflow.attributes;
output += "<variables>";
attributes.forEach( function(attribute) {
output += "<variable>";
output += "<name>" +
_getWorkflowsNS._escapeXML(attribute.name) + "</name>";
output += "<type>" + attribute.type + "</type>";
if (attribute.description) {
output += "<description>" +
_getWorkflowsNS._escapeXML(attribute.description) +
"</description>";
} else {
output += "<description/>";
}
if (attribute.hasOwnProperty("value")) {
if (attribute.value) {
output += "<value>" + attribute.value + "</value>";
} else {
output += "<value/>";
}
}
output += "</variable>";
});
output += "</variables>";
// Inputs
var inParameters = workflow.inParameters;
output += "<inputs>";
inParameters.forEach( function(parameter) {
output += "<input>";
output += "<name>" +
_getWorkflowsNS._escapeXML(parameter.name) + "</name>";
output += "<type>" + parameter.type + "</type>";
if (parameter.description) {
output += "<description>" +
_getWorkflowsNS._escapeXML(parameter.description) +
"</description>";
} else {
output += "<description/>";
}
output += "</input>";
});
output += "</inputs>";
// Outputs
var outParameters = workflow.outParameters;
output += "<outputs>";
outParameters.forEach( function(parameter) {
output += "<output>";
output += "<name>" +
_getWorkflowsNS._escapeXML(parameter.name) + "</name>";
output += "<type>" + parameter.type + "</type>";
if (parameter.description) {
output += "<description>" +
_getWorkflowsNS._escapeXML(parameter.description) +
"</description>";
} else {
output += "<description/>";
}
output += "</output>";
});
output += "</outputs>";
// Schema
output += "<numberOfItems>" + workflow.numberOfItem +
"</numberOfItems>";
output += "<firstItem>" +
_getWorkflowsNS._escapeXML(workflow.firstItem.name) +
"</firstItem>";
var items = workflow.items;
output += "<schema>";
items.forEach( function(item) {
output += "<item>";
output +="<name>" +
_getWorkflowsNS._escapeXML(item.name) + "</name>";
if (item.description) {
output += "<description>" +
_getWorkflowsNS._escapeXML(item.description) +
"</description>";
} else {
output += "<description/>";
}
var nextItem;
if (item.nextItem) {
nextItem = "<nextItem>" +
_getWorkflowsNS._escapeXML(item.nextItem.name) + "</nextItem>";
} else {
nextItem = "<nextItem/>";
}
// Elements
switch(item.constructor.name) {
// WorkflowCustomConditionItem - CustomCondition
case "WorkflowCustomConditionItem" :
output += "<type>CustomCondition</type>";
output += nextItem;
output += "<nextItemTrue>" +
_getWorkflowsNS._escapeXML(item.nextItemTrue.name) +
"</nextItemTrue>";
output += "<nextItemFalse>" +
_getWorkflowsNS._escapeXML(item.nextItemFalse.name) +
"</nextItemFalse>";
output += "<script>";
output += _getWorkflowsNS._escapeXML(item.script);
output += "</script>";
break;
// WorkflowDecisionActivityItem - DecisionActivity
// (Undocumented)
case "WorkflowDecisionActivityItem" :
output += "<type>DecisionActivity</type>";
output += nextItem;
output += "<nextItemTrue>" +
_getWorkflowsNS._escapeXML(item.nextItemTrue.name) +
"</nextItemTrue>";
output += "<nextItemFalse>" +
_getWorkflowsNS._escapeXML(item.nextItemFalse.name) +
"</nextItemFalse>";
output += "<script>" +
_getWorkflowsNS._escapeXML(item.script) + "</script>";
if (item.referencedWorkflow) {
if (item.referencedWorkflow.name) {
output += "<referencedWorkflow>" +
_getWorkflowsNS._escapeXML(item.referencedWorkflow.name) +
"</referencedWorkflow>";
}
}
if (item.referencedAction) {
if (item.referencedAction.name) {
output += "<referencedAction>" +
_getWorkflowsNS._escapeXML(item.referencedAction.name) +
"</referencedAction>";
}
}
break;
// WorkflowForeachItem -Foreach (Undocumented)
case "WorkflowForeachItem" :
output += "<type>Foreach</type>";
output += nextItem;
output += "<loopInnerCatchBlock>" +
_getWorkflowsNS._escapeXML(item.loopInnerCatchBlock) +
"</loopInnerCatchBlock>";
if (item.iterationElement === null) {
output += "<iterationElement/>";
} else {
output += "<iterationElement>" +
_getWorkflowsNS._escapeXML(item.iterationElement.name) +
"</iterationElement>";
}
break;
// WorkflowGenericConditionItem - GenericCondition
case "WorkflowGenericConditionItem" :
output += "<type>GenericCondition</type>";
output += nextItem;
output += "<nextItemTrue>" +
_getWorkflowsNS._escapeXML(item.nextItemTrue.name) +
"</nextItemTrue>";
output += "<nextItemFalse>" +
_getWorkflowsNS._escapeXML(item.nextItemFalse.name) +
"</nextItemFalse>";
output += "<script>";
output += _getWorkflowsNS._escapeXML(item.script);
output += "</script>";
break;
// WorkflowInputItem - Input
case "WorkflowInputItem" :
output += "<type>Input</type>";
output += nextItem;
break;
// WorkflowItem
case "WorkflowItem" :
output += "<type/>";
output += nextItem;
break;
// WorkflowItemEnd
case "WorkflowItemEnd" :
output += "<type>End</type>";
break;
// WorkflowItemWaitingEvent - WaitingEvent
case "WorkflowItemWaitingEvent" :
output += "<type>WaitingEvent</type>";
output += nextItem;
break;
// WorkflowItemWaitingTimer - WaitingTimer
case "WorkflowItemWaitingTimer" :
output += "<type>WaitingTimer</type>";
output += nextItem;
break;
// WorkflowLinkItem - Link
case "WorkflowLinkItem" :
output += "<type>Link</type>";
output += nextItem;
if (item.linkedWorkflow !== null) {
output += "<linkedWorkflow>" +
_getWorkflowsNS._escapeXML(item.linkedWorkflow.name) +
"</linkedWorkflow>";
}
break;
// WorkflowMultipleCallItem - MultipleCall
case "WorkflowMultipleCallItem" :
output += "<type>MultipleCall</type>";
output += nextItem;
output += "<linkedWorkflows>";
item.linkedWorkflows.forEach( function(linkedWorkflow) {
output += "<linkedWorkflow>" +
_getWorkflowsNS._escapeXML(linkedWorkflow.name) +
"</linkedWorkflow>";
});
output += "</linkedWorkflows>";
break;
// WorkflowSwitchItem - Switch (Undocumented)
case "WorkflowSwitchItem" :
output += "<type>Switch</type>";
output += nextItem;
output += "<outItems>";
item.outItems.forEach( function(outItem) {
output += "<outItem>";
output += "<name>" +
_getWorkflowsNS._escapeXML(outItem.name) + "</name>";
output += "</outItem>";
});
output += "</outItems>";
output += "<conditions>";
item.conditions.forEach( function(condition) {
output += ("<condition>" + condition + "</condition>");
});
output += ("</conditions>");
break;
// WorkflowTaskItem - Task
case "WorkflowTaskItem" :
output += "<type>Task</type>";
output += nextItem;
output += "<isActionCall>" + item.isActionCall +
"</isActionCall>";
output += "<isStartWorkflowCall>" +
item.isStartWorkflowCall + "</isStartWorkflowCall>";
if (item.linkedWorkflow) {
output += "<linkedWorkflow>" +
_getWorkflowsNS._escapeXML(item.linkedWorkflow.name) +
"</linkedWorkflow>";
} else {
output += "<linkedWorkflow/>";
}
output += "<usedActions>";
item.usedActions.forEach( function(usedAction) {
output += "<usedAction>" +
_getWorkflowsNS._escapeXML(usedAction.name) +
"</usedAction>";
});
output += "</usedActions>";
output += "<script>";
output += _getWorkflowsNS._escapeXML(item.script);
output += "</script>";
break;
}
output += "</item>";
});
output += "</schema>";
output += "</workflow>";
});
output += "</workflows>";
} catch(e) {
System.log(e);
System.log(e.stack);
} finally {
System.log(output);
}
}
}
// Main
_getWorkflowsNS.Main();
|
The code is really easy to understand. First, a file is created in which the XML data is stored. Then all workflows are detected and possible selections, by folder or workflow names, are made over the inputs. Now, workflow by workflow, the details are detected, with certain characters having to be converted to conform to XML conventions. If this action is now executed, we get an XML file with the desired information.
Conclusion
The generated XML information can be used for analysis purposes. All information are available in a very handy and compact well structured form.