Publishing Events
Introduction
As part of 7.2.0.0, Universal Extensions can now be used to extend the Controller's monitoring capabilities through Universal Events and Universal Monitors/Universal Monitor Triggers.
Specifically, the Universal Extension API has been enhanced to supported publishing events using the publish method from the event module.
Throughout this document, the event publishing functionality will be demonstrated using a contrived file monitor example.
On this page, we will cover the following:
- Set up the new UE Publisher template.
- Add a directory field to the UE Publisher template.
- Enhance the UE Publisher's local event template.
- Modify the ue-publisher Extension.
- Create a task for the UE Publisher template.
- Create a Universal Monitor task and trigger.
- Run the Universal Monitor Trigger.
- Update the local template.json.
Step 1 - Set up the new "UE Publisher" template
Up until now, we have been working with the "UE Task" Universal Template. For this tutorial, we will need to use the "UE Publisher" template that was added to the VS Code Extension and UIP-CLI.
Create a new folder ~/dev/extensions/sample-publisher
where the new template will be stored. Navigate to that directory and run the UIP: Initialize New Project command as shown below:
On the following prompt, select the "sample-publisher" folder:
Then, select the "ue-publisher" starter template:
In the following prompts that are used to configure the template, everything can be kept as is. Note the
"UE Publisher" template has an additional option called "Local Universal Event name" shown below.
Open the ~/dev/extensions/sample-publisher/extension.py
if currently not open. Let's examine the file:
from __future__ import (print_function) from time import sleep from universal_extension import UniversalExtension from universal_extension import ExtensionResult from universal_extension import event 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__() # Flag to control the event loop below self.run = True 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 """ # Get the value of the 'sleep_value' field sleep_value = fields.get('sleep_value', 3) # loop that publishes events continuously as long as self.run is True while self.run: # Publish an event event.publish( 'publisher_event', {} ) # sleep before publishing next event sleep(sleep_value) # Return the result with a payload marking the end of extension_start() return ExtensionResult( unv_output='extension_start() finished' ) def extension_cancel(self): """Optional method that allows the Extension to do any cleanup work before finishing """ # Set self.run to False which will end the event loop above self.run = False
Line 2 | Imports the sleep method from the time module which will be used to add a delay between successive events. |
Line 5 | Imports the event module which contains the publish method used later on. |
Line 19 | A flag called self.run with initial value of True is added to control the event loop. |
Line 40 | Extract the sleep_value field from the task instance passed down by the Controller. |
Line 43 | While loop that runs as long as the self.run field value is True |
Line 45-48 | Used to publish an empty event, as shown by the empty attributes dictionary. |
Line 51 | Used to add a tiny delay before the next event is published |
Line 58-63 | Upon receiving the Cancel command from the Controller, the self.run flag is set to False |
Now, let's push the extension out to the Controller. Since this is the first time, use the UIP: Push All command:
If successful, you should see the "UE Publisher" template in the "Universal Templates" list:
Step 2 - Add a directory field to the "UE Publisher" template
Navigate to the Fields tab of the UE Publisher template, and add a new field as shown below:
This required field will be used to specify the directory to get the file list of.
Save the template.
Step 3 - Enhance the "UE Publisher's" local event template
Navigate to the Event Templates tab of the UE Publisher template:
Double click the publisher_event entry, and modify it as shown below:
A new attribute of type Text called filelist is added which will contain the list of files (formatted as a string) in the directory specified by the directory field added in the last step.
Save the Event Template.
Step 4 - Modify the ue-publisher extension
Now, we need to enhance ~/dev/extensions/sample-publisher/extension.py
to publish the filelist event. Update the file as shown below:
from __future__ import (print_function) from time import sleep import os from universal_extension import UniversalExtension from universal_extension import ExtensionResult from universal_extension import event 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__() # Flag to control the event loop below self.run = True 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 """ # Get the value of the 'sleep_value' field sleep_value = fields.get('sleep_value', 3) # Get the value of the 'directory' field directory = fields.get('directory', '') # Verify the directory exists if not directory: return ExtensionResult( rc=-1, unv_output="specified directory is empty" ) elif not os.path.exists(directory): return ExtensionResult( rc=-1, unv_output="specified directory does not exist" ) prev_filelist = set() # loop that publishes events continuously as long as self.run is True while self.run: curr_filelist = set(os.listdir(directory)) # Subtracting 'prev_filelist' from 'curr_filelist' will ensure the # 'filelist' only contains the newly detected files. filelist = curr_filelist - prev_filelist filelist = ','.join(filelist) prev_filelist = curr_filelist.copy() if filelist: print(filelist) # Publish the event event.publish( 'publisher_event', {"filelist": filelist} ) # sleep before publishing next event sleep(sleep_value) # Return the result with a payload marking the end of extension_start() return ExtensionResult( unv_output='extension_start() finished' ) def extension_cancel(self): """Optional method that allows the Extension to do any cleanup work before finishing """ # Set self.run to False which will end the event loop above self.run = False
Line 3 | Imports the os module used to list files in an directory. |
Line 44 | Extract the directory field from the task instance passed down by the Controller. |
Line 47-56 | Verify the directory exists |
Line 58-80 | Get the current directory listing and remove the files from the previous iteration, only leaving new files discovered in the current iteration. Then, publish the filtered file listing as a comma-separated string to the publisher_event event. |
Save the changes to extension.py
and execute the UIP: Push command as shown below:
Recall that the UIP: Push command builds and uploads the Extension zip archive
Step 5 - Create a task for the "UE Publisher" template
Right-click on the navigation tree pane, and click Refresh as shown below:
Then under the Services menu, click UE Publisher Tasks under the Integrations section:
Create a new task called sample-publisher-task:
- For the directory field, type in a valid path on the system where the selected agent is running
Save the task.
Step 6 - Create a Universal Monitor task and trigger
Now that we have the event publishing logic added, we need to attach the event itself to a Universal Monitor task.
Under the Services menu, click Universal Monitors under the Monitors section as shown below:
Create a new Universal Monitor task as shown below:
- Make sure the Event Type is set to Local since the ue_publisher Event Template is (locally) attached to the UE Publisher Universal Template
- Make sure the Universal Template is set to UE Publisher
- Make sure the Event Template is set to Publisher Event (this is the user-friendly name of ue_publisher Event Template)
- Make sure the Universal Task Publisher is set to sample-publisher-task
- Make sure there is an entry for Filelist as shown above. As you may have guessed, this Universal Monitor task will check if Filelist contains test.txt
Save the task.
We can either run the sample-monitor-task as a standalone task which finishes upon detecting the target file (test.txt), or we can attach the task to a Universal Monitor trigger. To cover the complete functionality, we will attach it to a Universal Monitor Trigger.
Under the Services menu, click Universal Monitor Triggers under the Triggers section. Create a new trigger as shown below:
The trigger above will launch the Sleep 0 task when the sample-monitor-task's specified criteria is matched.
Save the trigger.
Step 7 - Run the Universal Monitor Trigger
We are finally ready to see the event functionality in action. Navigate to the sample-monitor-trigger, right-click on it, and select Enable:
Clicking Enable will launch the sample-monitor-task and sample-publisher-task. To see this, go to the Instances tab of the sample-monitor-trigger. You should see the following:
The sample-publisher-task is sending an event every 5 seconds with the filelisting. Since we haven't created the test.txt file in the specified directory, the Sleep 0 task isn't triggered yet.
In your specified directory, create the test.txt file. After about 5 seconds, click the Refresh icon in the Instances tab of the sample-monitor-trigger, and you should see the following:
If you delete the test.txt file and create it again, the Sleep 0 Timer task should be launched again by the trigger.
Step 8 - Update the local template.json
Throughout the tutorial, we modified the Universal Template several times. Recall that inside ~/dev/extensions/sample-publisher/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. 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.
/wiki/spaces/DEV/pages/1313202 /wiki/spaces/DEV/pages/1313206