Dynamic Update and Output Only Fields

Introduction

On this page, we will enhance the ue-task Extension to support Output Only fields.  These are fields that are designed to be updated by an Extension instance running on an agent system.  They can be used for any purpose but, a typical use case is to reflect state changes that occur in the Extension instance.  That is what we will simulate here.

This page will cover the following:

  1. Add Output Only fields to the "UE Task" Universal Template.
  2. Modify extension.py to populate Output Only fields.
  3. Execute ue-task-test task and review the Output Only field updates

Step 1 - Output Only fields to the "UE Task" Universal Template

Go back to the "UE Task" Universal Template form.  

On the Fields tab of the Universal Template, create three Output Only fields of type Text:

  1. task_action
  2. step_1
  3. step_2

Click the "Save & New" option in the dropdown next to the "Save" icon and create the step_1 and step_2 fields. (For a better layout, don't check the "Start Row" and "End Row" boxes for step_1 and step_2 fields).

At this point, the Template’s Field tab should be populated as follows:

The task_action field will be used to reflect the task action taken by the ue-task-test task.

Fields step_1 and step_2 will be used to reflect the progression of work in the task instance as it works its way through them.

Step 2 - Add support for updating Output Only fields in extension.py

Open file ~/dev/extensions/sample-task/src/extension.py in your editor of choice.

Enhance the extension_start method with the following code:

primary_choice_field Dynamic Choice Command
from __future__ import (print_function)
import time
from universal_extension import UniversalExtension
from universal_extension import ExtensionResult
from universal_extension import logger
from universal_extension.deco import dynamic_choice_command
from universal_extension import ui


class Extension(UniversalExtension):
    """Required class that serves as the entry point for the extension
    """

    def __init__(self):
        """Initializes an instance of the 'Extension' class
        """
        # Call the base class initializer
        super(Extension, self).__init__()

    @dynamic_choice_command("primary_choice_field")
    def primary_choice_command(self, fields):
        """Dynamic choice command implementation for
        primary_choice_field.

        Parameters
        ----------
        fields : dict
            populated with the values of the dependent fields
        """
        return ExtensionResult(
            rc=0,
            message="Values for choice field: 'primary_choice_field'",
            values=["Start", "Pause", "Stop", "Build", "Destroy"]
        )

    @dynamic_choice_command("secondary_choice_field")
    def secondary_choice_command(self, fields):
        """Dynamic choice command implementation for
        secondary_choice_field.

        Parameters
        ----------
        fields : dict
            populated with the values of the dependent fields
        """
        return ExtensionResult(
            rc=0,
            message="Values for choice field: 'secondary_choice_field'",
            values=["System", "Command", "Application", "Transfer", "Evidence"]
        )

    def extension_start(self, fields):
        """Required method that serves as the starting point for work performed
        for a task instance.

        Parameters
        ----------
        fields : dict
            populated with field values from the associated task instance
            launched in the Controller

        Returns
        -------
        ExtensionResult
            once the work is done, an instance of ExtensionResult must be
            returned. See the documentation for a full list of parameters that
            can be passed to the ExtensionResult class constructor
        """

        sleep_value = 5

        # Update the 'task_action' Output Only field on the task instance form
        out_fields = {}
        task_action = "{0} {1}".format(
            fields['primary_choice_field'][0],
            fields['secondary_choice_field'][0])
        out_fields["task_action"] = task_action
        ui.update_output_fields(out_fields)

        # Sleep
        time.sleep(sleep_value)

        # Update the 'step_1' Output Only field on the task instance form
        out_fields = {}
        out_fields["step_1"] = "Step 1 - Success"
        ui.update_output_fields(out_fields)

        # Sleep
        time.sleep(sleep_value)

        # Update the 'step_2' Output Only field on the task instance form
        out_fields = {}
        out_fields["step_2"] = "Step 2 - Success"
        ui.update_output_fields(out_fields)

        # Get the value of the 'action' field
        action = fields.get('action', [""])[0]

        if action.lower() == 'print':
            # Print to standard output...
            print("Hello STDOUT!")
        else:
            # Log to standard error...
            logger.info('Hello STDERR!')

        # Return the result with a payload containing a Hello message...
        return ExtensionResult(
            unv_output='Hello Extension!'
        )

Line 2We added an import for the time module to gain access to the sleep function which we will use to force controlled delays between Output Only field updates.
Line 7We added an import for the ui module to access the update_output_fields() method
Line 70We initialize variable sleep_value.  This variable will be used to control the sleep delays.
Line 73We create a new dictionary to hold output fields to be sent back to the Controller.
Lines 74 to 76We format a task_action string using the primary_choice_field and secondary_choice_field values passed down from the Controller.
Line 77We assign the formatted task_action string value to the out_fields dictionary using key "task_action" to associate it with the "task_action" Output Only field in associated task instance in the Controller.
Line 78This calls the update_output_fields() method from the ui module.  This will send a message to the Controller and update the value of the specified fields in the associated task instance (in this case just "task_action").
Lines 80 to 94This follows the same basic basic procedure to update Output Only fields step_1 and step_2.  A sleep delay is introduced between each output field update.

Step 3 - Build and Upload the Extension Zip Archive Using the UIP VS Code Extension

From the VS Code command palette, execute the UIP: Push command as shown below:

Recall that the UIP: Push command builds and uploads the Extension zip archive


 Click here to expand uip-cli details...

Step 3 Supplemental - Build and Upload the Extension Zip Archive Using the CLI

Save all changes to extension.py.

From the command line, cd to the ./sample-1 directory and execute the push command as shown below:

Recall that the push command builds and uploads the Extension zip archive

Step 4 - Launch task and observe the output only fields 

From the VS Code command palette, execute the UIP: Task Launch No Wait command as shown below: 

In the Controller, open the "UE Task Tasks" tab and select the ue-task-test task (or whatever name you gave it).

Switch to the Instances tab for the task and you should see the recently launched tasks with a status of Running or Success (depending on timing).  If the task shows a status of Running, click refresh every few seconds until it goes to Success.

Once the task goes to Success, double click on it to open the task instance form.

Scroll down to the "sample-1 Details" section and review the Output Only fields:

The “Task Action” field along with the “Step 1” and “Step 2” fields have been updated by the Extension instance running on the agent.

This was accomplished by the calls to ui.update_output_fields(out_fields) in the extension_start method in extension.py.

Step 5 - Update the Local template.json

In step 1, we modified the Universal Template by adding new Output Only Fields. Recall that inside ~/dev/extensions/sample-task/src/templates, there is a template.json file. This file should correspond to the Universal Template in the Controller. 

Right now, they are not both the same. The Controller's version of template.json has the Dynamic Choice Fields changes. To grab those changes, use the pull command as shown below:

UIP VS Code Extension

 Click here to expand uip-cli details...

Step Supplemental - CLI


Now, both the local and Controller's version of the Universal Template are the same.

< Previous     Next >