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:
- Add Output Only fields to the "UE Task" Universal Template.
- Modify extension.py to populate Output Only fields.
- 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:
- task_action
- step_1
- 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:
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 2 | We 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 7 | We added an import for the ui module to access the update_output_fields() method |
Line 70 | We initialize variable sleep_value. This variable will be used to control the sleep delays. |
Line 73 | We create a new dictionary to hold output fields to be sent back to the Controller. |
Lines 74 to 76 | We format a task_action string using the primary_choice_field and secondary_choice_field values passed down from the Controller. |
Line 77 | We 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 78 | This 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 94 | This 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
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
Now, both the local and Controller's version of the Universal Template are the same.