VMware Cloud Community
StefanSchnell
Enthusiast
Enthusiast

Tip: How to get Detailed Information About all Workflows

In this post I describe a way how to get detailed information about all workflows in vRealize Automation. For this I use an action, like in my post how to get detailed information about actions, that collects all information and saves it in XML format. The approaches between the actions and workflows are very similar, only the objects and their attributes differ. First we take a look at what information are provided and where it can be found in the UI of the vRA 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 - General TabWorkflow - General Tab 

 

<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.

Workflow - Variables TabWorkflow - Variables Tab

 

  <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.

Workflow - Inputs/Outputs TabWorkflow - Inputs/Outputs Tab

 

  <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.

Workflow - Schema TabWorkflow - Schema Tab    Workflow - Schema Item DetailWorkflow - Schema Item Detail

 

  <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 &gt;= 400 ) {
	throw &quot;HTTPError: status code: &quot; + 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.

 

/* Begin----------------------------------------------------------------
 *
 * This action creates an XML file with all details of all existing
 * workflows and its script code.
 *
 *  getWorkflows
 *  {string} in_folderFilter - Search for substring in folder, optional
 *  {string} in_nameFilter - Search for substring in name, optional
 *  Stefan Schnell
 *  1.2.0
 *
 */

var _getWorkflowsNS = {

  /* escapeXML----------------------------------------------------------
   *
   * Escapes characters in a string, which could be misinterpreted as
   * markup in XML.
   *
   *  escapeXML
   *  {string} strXML - XML which characters to convert
   * @returns {string} Converted XML
   *
   */
  escapeXML : function(strXML) {
    if (strXML) {
      return strXML.replace(/&/g, "&amp;")
                   .replace(/</g, "&lt;")
                   .replace(/>/g, "&gt;")
                   .replace(/"/g, "&quot;")
                   .replace(/'/g, "&apos;");
    }
  },

  // Main---------------------------------------------------------------
  Main : function() {

    var fileName = "/var/run/vco/workflows.xml";

    try {

      var file = new File(fileName);
      if (file.exists) {
        file.deleteFile();
      }

      var fileWriter = new FileWriter(fileName);
      fileWriter.open();

      fileWriter.writeLine("<?xml version=\"1.0\"?>");
      fileWriter.writeLine("<workflows>");

      // Workflows------------------------------------------------------
      var workflows = System.getModule("com.vmware.library.workflow").getAllWorkflows();

      // 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---------------------------------------------
        fileWriter.writeLine("  <workflow folder=\"" + workflow.workflowCategory.path +
          "\" name=\"" + _getWorkflowsNS.escapeXML(workflow.name) + "\">");
        fileWriter.writeLine("    <id>" + workflow.id + "</id>");

        if (workflow.description) {
          var workflowDescription = workflow.description.replace(/[\r\n]/gm, '');
          fileWriter.writeLine("    <description>" +
            _getWorkflowsNS.escapeXML(workflowDescription) + "</description>");
        } else {
          fileWriter.writeLine("    <description></description>");
        }
        fileWriter.writeLine("    <version>" + workflow.version + "</version>");

        // Variables----------------------------------------------------
        var attributes = workflow.attributes;
        fileWriter.writeLine("    <variables>");
        attributes.forEach( function(attribute) {
          fileWriter.writeLine("      <variable>");
          fileWriter.writeLine("        <name>" +
            _getWorkflowsNS.escapeXML(attribute.name) + "</name>");
          fileWriter.writeLine("        <type>" + attribute.type + "</type>");
          if (attribute.description) {
            fileWriter.writeLine("        <description>" +
              _getWorkflowsNS.escapeXML(attribute.description) + "</description>");
          } else {
            fileWriter.writeLine("        <description></description>");
          }
          if (attribute.hasOwnProperty("value")) {
            if (attribute.value) {
              fileWriter.writeLine("        <value>" + attribute.value + "</value>");
            } else {
              fileWriter.writeLine("        <value></value>");
            }
          }
          fileWriter.writeLine("      </variable>");
        });
        fileWriter.writeLine("    </variables>");

        // Inputs-------------------------------------------------------
        var inParameters = workflow.inParameters;
        fileWriter.writeLine("    <inputs>");
        inParameters.forEach( function(parameter) {
          fileWriter.writeLine("      <input>");
          fileWriter.writeLine("        <name>" +
            _getWorkflowsNS.escapeXML(parameter.name) + "</name>");
          fileWriter.writeLine("        <type>" + parameter.type + "</type>");
          if (parameter.description) {
            fileWriter.writeLine("        <description>" +
              _getWorkflowsNS.escapeXML(parameter.description) + "</description>");
          } else {
            fileWriter.writeLine("        <description></description>");
          }
          fileWriter.writeLine("      </input>");
        });
        fileWriter.writeLine("    </inputs>");

        // Outputs------------------------------------------------------
        var outParameters = workflow.outParameters;
        fileWriter.writeLine("    <outputs>");
        outParameters.forEach( function(parameter) {
          fileWriter.writeLine("      <output>");
          fileWriter.writeLine("        <name>" +
            _getWorkflowsNS.escapeXML(parameter.name) + "</name>");
          fileWriter.writeLine("        <type>" + parameter.type + "</type>");
          if (parameter.description) {
            fileWriter.writeLine("        <description>" +
              _getWorkflowsNS.escapeXML(parameter.description) + "</description>");
          } else {
            fileWriter.writeLine("        <description></description>");
          }
          fileWriter.writeLine("      </output>");
        });
        fileWriter.writeLine("    </outputs>");

        // Schema-------------------------------------------------------
        fileWriter.writeLine("    <numberOfItems>" + workflow.numberOfItem +
          "</numberOfItems>");
        fileWriter.writeLine("    <firstItem>" +
          _getWorkflowsNS.escapeXML(workflow.firstItem.name) + "</firstItem>");
        var items = workflow.items;
        fileWriter.writeLine("    <schema>");
        items.forEach( function(item) {
          fileWriter.writeLine("      <item>");
          fileWriter.writeLine("        <name>" +
            _getWorkflowsNS.escapeXML(item.name) + "</name>");
          if (item.description) {
            fileWriter.writeLine("        <description>" +
              _getWorkflowsNS.escapeXML(item.description) + "</description>");
          } else {
            fileWriter.writeLine("        <description></description>");
          }

        var nextItem;
        if (item.nextItem) {
          nextItem = "        <nextItem>" +
            _getWorkflowsNS.escapeXML(item.nextItem.name) + "</nextItem>";
        } else {
          nextItem = "        <nextItem></nextItem>";
        }

          // Elements---------------------------------------------------
          switch(item.constructor.name) {

            case "WorkflowCustomConditionItem" :
              fileWriter.writeLine("        <type>CustomCondition</type>");
              fileWriter.writeLine(nextItem);
              fileWriter.writeLine("        <nextItemTrue>" +
                _getWorkflowsNS.escapeXML(item.nextItemTrue.name) +
                "</nextItemTrue>");
              fileWriter.writeLine("        <nextItemFalse>" +
                _getWorkflowsNS.escapeXML(item.nextItemFalse.name) +
                "</nextItemFalse>");
              fileWriter.writeLine("        <script>");
              fileWriter.writeLine(_getWorkflowsNS.escapeXML(item.script));
              fileWriter.writeLine("        </script>");
              break;

            case "WorkflowGenericConditionItem" :
              fileWriter.writeLine("        <type>GenericCondition</type>");
              fileWriter.writeLine(nextItem);
              fileWriter.writeLine("        <nextItemTrue>" +
                _getWorkflowsNS.escapeXML(item.nextItemTrue.name) +
                "</nextItemTrue>");
              fileWriter.writeLine("        <nextItemFalse>" +
                _getWorkflowsNS.escapeXML(item.nextItemFalse.name) +
                "</nextItemFalse>");
              fileWriter.writeLine("        <script>");
              fileWriter.writeLine(_getWorkflowsNS.escapeXML(item.script));
              fileWriter.writeLine("        </script>");
              break;

            case "WorkflowInputItem" :
              fileWriter.writeLine("        <type>Input</type>");
              fileWriter.writeLine(nextItem);
              break;

            case "WorkflowItem" :
              fileWriter.writeLine("        <type></type>");
              fileWriter.writeLine(nextItem);
              break;

            case "WorkflowItemEnd" :
              fileWriter.writeLine("        <type>End</type>");
              break;

            case "WorkflowItemWaitingEvent" :
              fileWriter.writeLine("        <type>WaitingEvent</type>");
              fileWriter.writeLine(nextItem);
              break;

            case "WorkflowItemWaitingTimer" :
              fileWriter.writeLine("        <type>WaitingTimer</type>");
              fileWriter.writeLine(nextItem);
              break;

            case "WorkflowLinkItem" :
              fileWriter.writeLine("        <type>Link</type>");
              fileWriter.writeLine(nextItem);
              fileWriter.writeLine("        <linkedWorkflow>" +
                _getWorkflowsNS.escapeXML(item.linkedWorkflow.name) +
                "</linkedWorkflow>");
              break;

            case "WorkflowMultipleCallItem" :
              fileWriter.writeLine("        <type>MultipleCall</type>");
              fileWriter.writeLine(nextItem);
              fileWriter.writeLine("        <linkedWorkflows>");
              item.linkedWorkflows.forEach( function(linkedWorkflow) {
                fileWriter.writeLine("          <linkedWorkflow>" +
                  _getWorkflowsNS.escapeXML(linkedWorkflow.name) +
                  "</linkedWorkflow>");
              });
              fileWriter.writeLine("        </linkedWorkflows>");
              break;

            case "WorkflowTaskItem" :
              fileWriter.writeLine("        <type>Task</type>");
              fileWriter.writeLine(nextItem);
              fileWriter.writeLine("        <isActionCall>" + item.isActionCall +
                "</isActionCall>");
              fileWriter.writeLine("        <isStartWorkflowCall>" +
                item.isStartWorkflowCall + "</isStartWorkflowCall>");
              if (item.linkedWorkflow) {
                fileWriter.writeLine("        <linkedWorkflow>" +
                  _getWorkflowsNS.escapeXML(item.linkedWorkflow.name) +
                  "</linkedWorkflow>");
              } else {
                fileWriter.writeLine("        <linkedWorkflow></linkedWorkflow>");
              }
              fileWriter.writeLine("        <usedActions>");
              item.usedActions.forEach( function(usedAction) {
                fileWriter.writeLine("          <usedAction>" +
                  _getWorkflowsNS.escapeXML(usedAction.name) +
                  "</usedAction>");
              });
              fileWriter.writeLine("        </usedActions>");
              fileWriter.writeLine("        <script>");
              fileWriter.writeLine(_getWorkflowsNS.escapeXML(item.script));
              fileWriter.writeLine("        </script>");
              break;

          }

          fileWriter.writeLine("      </item>");
        });
        fileWriter.writeLine("    </schema>");

        fileWriter.writeLine("  </workflow>");

      });

      fileWriter.writeLine("</workflows>");

    } catch(e) {
      System.log(e);
      System.log(e.stack);
    } finally {
      fileWriter.close();
    }

  }

}

// Main-----------------------------------------------------------------
_getWorkflowsNS.Main();

// End------------------------------------------------------------------

 

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. Here we have the same advantages as I already explained at the post about the Actions. All information are available in a very handy and compact well structured form.


More interesting information at blog.stschnell.de

0 Kudos
0 Replies