Tutorial for Adding User Tasks

This section covers:

Introduction

Templates can be extended by adding user tasks. User tasks can then be delegated to other staff to perform set actions and can also be used by senior staff to perform tasks more efficiently.

User tasks can be constructed in a number of forms and for different purposes:

  • Action Tasks: Performing day to day admin tasks and known fault workarounds.
  • Data Collection: Answer simple questions or retrieve data files.

Then when it comes to inputs, tasks can be either:

  • One Click: Tasks which don't require the user to input any information to run the task.
  • User Inputs: Tasks which require one or more inputs that ** be filled in, before the task can run.

Before working through this tutorial you should read Working with Templates.

Let's start with a simple One Click Action Task.

One Click Action Task

This example will send a command to a device to flush it's ARP cache. This is what happens when you flush the ARP cache directly:

1
2
router> arp --flushcache
router>

The command we need is arp --flushcache and the device responds with the standard shell prompt, so we will fail the task if any other text is present in the response.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="arp_flush" display_name="ARP Flush" type="status">
         <commands>
            <command>arp --flushcache
               <success type='ci_match' value='' />
               <failed type='default' />
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

Explanation:

  • The template starts with an XML declaration.
  • <devicetemplate> allows the split file to extend the standard template.
  • <tasks> is a group container for the single <task> tag.
  • <task> defines the internal and display names of the task, as well as the task type.
  • <commands> which is a group container for the single <command> tag.
  • <command> has no attributes in this example, but it does have some element text, which is the actual command to run on the device.
  • <success> states that if the response is blank, the command was a success.
  • <failed> states that in any other case, the command failed.
  • All corresponding tags are closed.

Once you have uploaded a template with a new task, migrate a device to the new template, and you will be able to add the task to any profiles the device belongs to, in the Web Management Interface.

Tasks are added like this:

Manager task window

Once added to a profile, it will appear in the PxM Client under the device, like this:

pxmc arp task

One Click Action Task with a Text Response

This example handles cases where we are looking for a specific success or failure message back from the device, rather than a blank response.

When you flush the ARP cache on a Windows server, the server responds with Ok:

1
2
3
4
C:\Windows\system32>netsh interface ip delete arpcache
Ok.

C:\Windows\system32>

The success and failed elements should be adjusted to succeed on Ok and fail on anything else.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="arp_flush" display_name="Arp Flush" type="status">
         <commands>
            <command>netsh interface ip delete arpcache
               <success type="ci_in" value="Ok."/>
               <failed type="default"/>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

Explanation:

  • The success tag uses type='ci_in', which searches for the value Ok in the response. We are using a search rather than a match to avoid invisible new line characters.
  • The failed tag will catch any other response and fail the task.

Multiple Commands

Tasks can also contain multiple commands to be run in sequence. Each command run will have its own SUCCESS and FAILED response lines and each command ** succeed before the next is then processed. If you want to stop and then start the print spooler service on a Windows server, then we would use the following two commands, like this::

1
2
3
4
5
6
7
8
C:\Windows\system32>net stop spooler
The Print Spooler service is stopping.
The Print Spooler service was stopped successfully.

C:\Windows\system32>net start spooler
The Print Spooler service is starting.
The Print Spooler service was started successfully.
C:\Windows\system32>

The task would need two commands, one for the stop command and the other for the start command.

We need to add success and failed elements to confirm the following responses. We can use unambiguous subsets of the full messages for simplicity:

  • stopped successfully when stopping the service.
  • started successfully when starting the service.
  • Fail on anything else.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 <?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="restart_print_spooler" display_name="Restart Print Spooler" type="status">
         <commands>
            <command>net stop spooler
               <success type="ci_in" value="stopped successfully"/>
               <failed type="default"/>
            </command>
            <command>net start spooler
               <success type="ci_in" value="started successfully"/>
               <failed type="default"/>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

Multiple Success Response Tags

Using the previous example, consider:

  • What if you try to stop the spooler service and it's already stopped?
  • What if you try to start the spooler service and it's already running?

If the print spooler service is already stopped when we run net stop, this is the response::

1
2
3
4
5
6
C:\Windows\system32>net stop spooler
The Print Spooler service is not started.

More help is available by typing NET HELPMSG 3521.

C:\Windows\system32>

As the first command is to stop the spooler service, if it is already stopped we can consider that a success using the line below.

1
<success type="ci_in" value="is not started"/>

Our success and failed elements will fail the task if the service has not been stopped by this point. We can safely assume it is ready to be started again, and the rest of the task can remain the same.

The final task, with the appended success element above, would look like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="restart_print_spooler" display_name="Restart Print Spooler" type="status">
         <commands>
            <command>net stop spooler
               <success type="ci_in" value="stopped successfully"/>
               <success type="ci_in" value="is not started"/>
               <failed type="default"/>
            </command>
            <command>net start spooler
               <success type="ci_in" value="started successfully"/>
               <failed type="default"/>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

Inputs to Tasks

You can feed data into tasks via several methods. These include:

Substitutions

Before showing examples of passing input data into tasks, it is important to explain substitutions. Substitutions allow you to use input data in task commands. Substitutions are used consistently across all input methods. The format is always:

1
%(my_value)s
  • Substitutions are always named after the input element attribute name.

  • Sub tasks can use the inputs supplied to the parent task. This is explained in the Calling Subtasks section.

  • You will see substitutions used in the below examples of data input methods.

Configuration String

A fixed configuration string is like defining a constant in a programming language. You can define the constant in the template and then use it's value in a task. The value is set within the Web Management Interface. The constant is available for every device using the template, and it's value can be set per device in the Web Management Interface, saving you changing the template each time.

Here we want to write a task to restart a tomcat application, but the name of the application is different on different servers. However, the general command syntax to restart any tomcat application is always the same.

Let's say the tomcat restart requires the following command::

1
tomcat --app=application_name --restart

The name of the web application to be restarted is replaced into application_name. A successful run of the command returns just the prompt, so we can use the success and failed elements from the first example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="restart_tomcat_webapp" display_name="Restart Tomcat Application" type="status">
         <commands>
            <command>tomcat --app=application_name --restart
               <success type='ci_match' value='' />
               <failed type='default' />
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

This gives us the start of our task, but we want to define different tomcat web application names on different servers. To do this, we need to create a task parameter that can be configured with the name of the tomcat service we want to restart on each server.

We do this by defining a <parameter> tag. More details on using a <parameter> tag for tasks input here: Tag: <tag-parameter-task-input>.

1
2
3
<parameters>
   <parameter fieldname="tomcat_webapp"  display_name="Tomcat Web Application Name"  fieldtype="string"  ondevice="no" />
</parameters>

The parameter fieldtype used in this case is string. The input element links to the parameter with the attribute device_parameter, and it's name is tomcat_webapp. The substitution %(tomcat_webapp)s is being used in the task command.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <parameters>
      <parameter fieldname="tomcat_webapp"
         display_name="Tomcat Web Application Name" fieldtype="string" ondevice="no" />
   </parameters>

   <tasks>
      <task name="restart_tomcat_webapp" display_name="Restart Tomcat Application" type="status">
         <input name="tomcat_webapp"  device_parameter="tomcat_webapp type="configuration" />
         <commands>
            <command>tomcat --app=%(tomcat_webapp)s --restart</command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

With this type of input, before the task can be run the value of the parameter must be set in the Web Management Interface.

You do this on the Tasks tab of the device that uses this template, as follows:

  1. In the left-hand TASKS panel, you can see the Restart Tomcat Application task has one input linked to it called Tomcat Web Application Name.

  2. On the right-hand TASK PARAMETERS panel, the Tomcat Web Application Name is listed, with an input box, click the Edit pencil icon next to a TASK PARAMETER.

  3. Here you can enter the name of the Tomcat Application that you want to restart on this specific server.

Using task parameters allows you to create one task, but configure different application names to be restarted on different servers, rather than hard code a task per application.

Device task parameters

Hiding Configuration Strings from the Task Window

By default configuration strings are shown as a read only line when the task is executed by the user, like this:

Task read only input visible

This line can be hidden from the task window using the hide attribute in the <input> tag, as follows:

1
2
3
<task name="restart_tomcat_webapp" display_name="Restart Tomcat Application" type="status">
   <input name="tomcat_webapp" device_parameter="tomcat_webapp" type="configuration" hide="true"/>
   ...

When the task is run through the *** the string will be hidden, and if no other inputs are present, the task window will ask for confirmation before running:

Task confirmation

Free Text Input

A free text input allows the user to type data to be used in the task. This could be a simple string, an integer, an email address, IP address, web url, etc.

Unlike a fixed configuration string, free text input does not need a parameter defining before the task, only an input element inside the task with a type of string.

Taking the Tomcat example, we could ask for the application name rather than using a fixed value. The template to do this would be:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="restart_tomcat_webapp" display_name="Restart Tomcat Application" type="status">
         <input name="tomcat_webapp" display_name="Tomcat Web Application Name" type="string"/>
         <commands>
            <command>tomcat --app=%(tomcat_webapp)s --restart</command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

When the task is run through the ***, the user will be prompted to enter the data in the form:

Task input free text

Select or Dropdown Input

Another way of passing data into a task is via a dropdown list. This works similarly to the configuration string, but rather than entering just one value into the Web Management Interface, you set up a list of values. Like the configuration text input, you need to define a parameter to use within the task. This parameter has a fieldtype of list.

Note

For clarity in the task, it is common to put _list at the end of a list type parameter fieldname.

As with the configuration string method, the list parameter is then referenced in the task by using an input element of type select.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <parameters>
      <parameter fieldname="tomcat_webapp_list"
         display_name="Tomcat Web Application List"
         fieldtype="list"
         ordering="1"
         ondevice="no" />
   </parameters>

   <tasks>
      <task name="restart_tomcat_webapp" display_name="Restart Tomcat Application" type="status">
         <input name="tomcat_webapp"
            display_name="Tomcat Application:"
            device_parameter="tomcat_webapp_list"
            type="select" />
         <commands>
            <command>tomcat --app=%(tomcat_webapp)s --restart</command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

The Tomcat Web Application list parameter will now appear in the right-hand TASK PARAMETERS panel, on the device's Tasks tab page.

Device task parameters select list

Click Edit pencil icon to open the List editor window.

Edit value

You now have a few options to build/edit the list, you can:

  • Add a single entry
  • Generate a sequence of entries
  • Import (or paste) CSV

Single Entry

To add a single entry you can right-click in the big white open space of the list window and select Add entry or you can click the menu item New and then select Add entry. This will open up a new line in the List editor and put it into edit mode:

Task input list edit

Here you can add a new entry, the fields are explained below:

Attribute Contents
Name The display name of the option in the dropdown selection when a user runs the task.This can contain spaces and capitalisation.
Value The value that gets passed to the task to be used in the substitution. The case of this value and any whitespace will be persisted, consider this when you write the task and quote the substitution if necessary.

Having both these columns allows you to pass potentially non-readable or technical data into a task, but give it a sensible business display name to present to the user.

For our Tomcat Web Application list example we might use names that relate to the application as it's known within the business. If someone on the helpdesk is running the task it is clear to them which to choose, even if the name of the actual tomcat service running on the server is slightly different.

Task input list populated

Once the data has been entered click the Save changes button and the list will be saved. The list can be edited at any time by clicking Edit pencil icon next to the TASK PARAMETER entry on the Tasks tab of the device. Any individual lines can be deleted from the list by clicking the Delete icon on the row you wish to delete.

The options are displayed to the user in the same order they appear in the List editor. You can re-order the options by dragging and dropping them in the List editor.

Device task parameters select list populated

Generate Sequence

To create a sequence of values that have the same format but different numeric values contained in them, you can use the sequence generator.

A good use case for the sequence generator is writing tasks to run against switches. To generate a drop down list of all 24 ports to use in tasks, you can right-click in the main panel of the List editor and select Sequence Generator.

Task input list generate sequence

Here you can generate new entries, the fields are explained below:

Attribute Contents
Start The number the loop starts at and includes.
End The number the loop ends at and includes.
Increment The size of the increment each time through the loop.
Name Template The name field generated for each entry in the sequence, with #{i} substituted for the current counter.
Value Template The value field generated for each entry in the sequence, with #{i} substituted for the current counter.

Generated sequence example:

Column Value
Start 1
End 5
Increment 1
Name Template Port #{i}
Value Template eth#{i}

Generates:

Generated Sequence: Name Generated Sequence: Value
Port 1 eth1
Port 2 eth2
Port 3 eth3
Port 4 eth4
Port 5 eth5

Import (or paste) CSV

You can also create a list of options in a spreadsheet or text editor. By selecting New -> Import CSV menu option in the List Editor popup window, you can paste CSV text from the clipboard or import a CSV file.

ask input list csv import

The format is:

1
name,value

Select Dropdown within the PxM Client

Now we've created our Tomcat Web Application List, assigned it to our template and set our list option choices, the task is ready to be run. When the user runs the task from the *** they will see the following:

PxMC task tomcat

PxMC task tomcat dropdown

The user can make a selection from the list of options in the task and make their selection based on the names. The values are hidden and are only passed to the task when it is run.

For example, if the user were to pick the first option Payment Broker then the corresponding value would be broker_app_14*.

So after the substitution, the final command which will be run against the device will be::

1
tomcat --app=broker_app_14 --restart

Note

For values with spaces in, you may need to place quotes around the string in the task.

Checkbox

Another simple input to a task is a checkbox (or tickbox). This is setup like the free text input, i.e. you don't need a parameter defined, just an <input> tag inside the task. To add a checkbox, add an <input> tag inside the task like this:

1
2
<task ...>
   <input name="flush_arp_flag" display_name="Flush ARP Cache at end of task?" type="boolean"/>

Now we use the Boolean value, in this example the name flush_arp_flag to decide if we want to do something or not in the task commands. To do this we use a <conditions> tag.

Conditions are used inside the <command> tag to specify if that particular command is to be executed. The command will only be run if the condition test returns true. So here we have a checkbox to say we want to flush the arp cache (a task we looked at earlier) at the end of the main task, but only if the checkbox is ticked, i.e. set to True.

To do this we would use:

1
2
3
4
5
<command format="textual_dataset">arp -flush
   <conditions>
      <testEq name="flush_arp_flag" value="True"/>
   </conditions>
</command>

The <conditions> tag is a container to hold multiple tests. In order for the conditions to be met, ALL tests needs to return true.

In this example we only need one condition test to act on the checkbox input.

Other conditions test tags exist as child tags under the conditions tag. More info here: Tag: <tag-conditions>.

The <testEq> tag is a test that is looking for one value to equal another.

A checkbox (Boolean) returns a value of True if checked, therefore we have a <testEq> tag inside the conditions tag that is checking to see if the value of flush_arp_flag is equal to True. If it is then the outer <command> tag that the condition tag is inside of will then be executed. If not matched, the command will be skipped. When a checkbox is not checked we just want to do nothing so no other conditions or actions are required.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="restart_tomcat_webapp" type="status">
         <input name="flush_arp_flag" display_name="Flush ARP Cache at end of task?" type="boolean"/>
         <commands>
            <command>tomcat --app=tomcat_webapp_1 --restart</command>
            <command>arp -flush
               <conditions>
                  <testEq name="flush_arp_flag" value="True"/>
               </conditions>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplates>

Note

The example task above has one fixed Tomcat Web Application name, just for simplicity.

When this task is then run through the PxM Client, the user experience looks like:

Task checkbox

The user running the task then simply has to tick the checkbox for the condition commands in the task to be run. You can have multiple commands that use the same conditions value to test, for example, multiple commands that are run if just one checkbox is ticked, and you can have multiple checkboxes in a task, as long as they have different names.

File Upload

Files can also be uploaded to a Windows device as part of a task. This is done by adding an input tag that has the type file, like this:

1
2
<task ...>
   <input name="upload_file" display_name="File to upload to server" type="file"/>

Then in the task itself you can tell the PxM Platform where to copy the file too:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task display_name="Upload File Test" name="upload_file_test" type="status">
         <input display_name="File to upload" name="upload_filename" type="file"/>
         <commands>
            <command type="call" taskname="verify_and_create_share"/>
            <command command="smb.put"
               destination="//%(share_root)s%(device_name)s/%(upload_filename.filename)s"
               source="%(upload_filename)s"
               type="local_shell" >
               <success type="ci_match" value=""/>
               <success type="ci_in" value="putting"/>
               <failed type="default"/>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplates>

Note

This task calls a subtask which is detailed below.

Calling Subtasks

It is possible to call a task from inside another, much like creating a function, to prevent repetition across multiple tasks. This is useful when you want to arrive at at a known state before making a change, i.e. clearing the config on a switch port before changing it's VLAN settings.

Below is a subtask that resets a switch port:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<task name="subtask_reset_port" type="status">

   <commands>
      <command>interface %(port)s</command>
      <command>shutdown</command>
      <command>no switchport mode access</command>
      <command>no switchport mode trunk</command>
      <command>no switchport trunk native vlan</command>
      <command>no switchport voice vlan</command>
      <command>exit</command>
   </commands>

</task>

Note

  • The task should be written as any other, but the 'display_name' attribute should not be used. If a task has a display_name, it is shown in the profile task picker on the Web Management Interface and can be run from the *. As this task will only be used by other tasks it does not need one.
  • The task uses a substitution of %(port)s but there are no inputs defined in the task. In this case the input value has been supplied to the subtask by the task that called it.

This subtask can now be called from any other task as many times as you like, by doing the following:

1
<command type="call" taskname="subtask_reset_port"/>

Note

In the template the subtask ** be defined before any tasks that call it. If it is defined afterwards, the template will upload but the tasks that call it will not be available.

The subtask will have it's own success and failure elements defined. If any steps of the subtask fail, the whole chain of tasks will fail.

The split template file to clear a port's config using a subtask, then reconfigure it might look like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <parameters>
      <parameter fieldname="port_list" display_name="Port List" fieldtype="list" ondevice="no"/>
   </parameters>

   <tasks>
      <task name="subtask_reset_port" type="status">
         <commands>
            <command>interface %(port)s</command>
            <command>shutdown</command>
            <command>no switchport mode access</command>
            <command>no switchport mode trunk</command>
            <command>no switchport trunk native vlan</command>
            <command>no switchport voice vlan</command>
            <command>exit</command>
         </commands>
      </task>

      <task name="set_port_printer" display_name="Set to Printer Port" type="status">
         <input name="port"
            display_name="Please select port:"
            device_parameter="switch_port_list"
            type="select" />
         <input name="printer_vlan"
            device_parameter="printer_vlan"
            type="configuration" />
         <commands>
            <command type="call" taskname="subtask_reset_port"/>
            <command>interface %(port)s</command>
            <command>switchport mode access</command>
            <command>switchport access vlan %(printer_vlan)s</command>
            <command>no shutdown</command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

Breakdown of the task Set to Printer Port, which would be run by the user from the *:

  • The first input is a port list. It's associated parameter is at the top. The values available will have been configured in the Web Management Interface.
  • The second is a configuration input, in this case the printers VLAN. This would be a fixed integer defined in the Web Management Interface.
  • Subtask subtask_reset_port is called as the first command. The 'port' input required by the subtask has been supplied to the calling task, so it will be passed through.
  • The task then puts the port into the printer VLAN and re-enables the port (no shutdown in Cisco speak). The subtask_reset_port task contained a shutdown so at some point the port needs to be re-enabled. This is a very important step when changing switch port VLAN assignment, as the shutdown and re-enabling of the port will force any client to perform a new DHCP request, as it's network connection will have dropped and reconnected.
  • You can call any task as a subtask, providing any required inputs are configured in the task that calls it. You could for example run a backup as a subtask before making a change to a device.

Conditional Subtasks

You can also combine subtasks and conditions. You could decide to only call a subtask if a checkbox on the * task window has been checked, for example. You can use conditions on any command.

Consider this snippet of template:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="subtask_flush_arp" type="status">
         <commands>
            <command>arp --flushcache</command>
         </commands>
      </task>

      <task name="restart_broker_webapp" type="status">
         <input name="flush_arp_flag" display_name="Flush ARP Cache at end of task?" type="boolean"/>
         <commands>
            <command>tomcat --app=broker_app_11 --restart</command>
            <command type="call" taskname="subtask_flush_arp">
               <conditions>
                  <testEq name="flush_arp_flag" value="True"/>
               </conditions>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

Breakdown:

  • A subtask has been created to flush the ARP cache.
  • In the restart_broker_webapp task underneath, there is an input called flush_arp_flag. This is type="boolean" which will be presented to the user as a checkbox.
  • The first command restarts the web app.
  • The second command will test the value of the checkbox, and if it is checked, it will run the subtask to flush the ARP cache.

Note

When testing the value of a checkbox, the test is case sensitive and the values MUST be written either True or False.

Updating Device Configuration Comments

A nice detail you can add to tasks, if the device supports it, is providing a description when making a change. You can use task inputs to add meaningful data to these descriptions e.g. a change management system ticket number.

We could extend the set_printer_port task to include this ticket number input:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<task name="set_port_printer" type="status">

   <input name="port"
      display_name="Please select port:"
      device_parameter="switch_port_list"
      type="select" />
   <input name="printer_vlan"
      device_parameter="printer_vlan"
      type="configuration" />
   <input name="ticket_ref"
      display_name="Change Ticket Number:"
      type="string" />
   <commands>
      <command type="call" taskname="subtask_reset_port"/>
      <command>interface %(port)s</command>
      <command>switchport mode access</command>
      <command>switchport access vlan %(printer_vlan)s</command>
      <command>description PRINTER PORT - Ref: %(ticket_ref)s -
         changed by "%(username)s" via Osirium at %(O_TASK_UTC_STARTTIME)s
      </command>
      <command>no shutdown</command>
   </commands>

</task>

Breakdown of the appended elements:

  • Another free text input parameter called ticket_ref has been added.
  • An extra <command> has been added to set the description of the port, including the ticket_ref input and 2 other global substitutions.

For a full list of global substitutions please see Global Substitutions

Messages

It is possible to have the PxM Platform display a message back to the user running the task. This message can be a fixed string or it can contain substitutions. Going back to our example of the Windows Arp Flush, if we want to display a simple message just to say the Arp Flush ran successfully then we could.

Likewise, we can also add a message when a task fails, like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="arp_flush" display_name="Arp Flush" type="status">
         <commands>
            <command>netsh interface ip delete arpcache
               <success type="ci_in" value="Ok" message="The Arp Flush ran successfully."/>
               <failed type="default" message="The Arp Flush fail to run."/>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

You ** define new response tags (<success> and <failed>) if you want to add messages. By default the task will display a message containing the last line response from the device the task was run on.

The message then looks like this:

Task message

Substitutions in Messages

Substitutions can also be used in messages as in the example below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="set_to_auto" display_name="Set Port to Auto Speed and Duplex" type="status">
         <input name="port" display_name="Port" type="string"/>
         <commands>
            <command>set interface %(port)s speed auto duplex auto
               <success type="ci_match" value="" message="Port %(port)s set to Auto Speed and Duplex."/>
               <failed type="default" message="Failed to set speed and duplex on port %(port)s."/>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

They can be used to confirm the selection back to the user like this:

Task message with input

Data Collection Tasks

Now we look at how we can capture data and relay it back to the user running the task.

Full Response Capture

We've seen how a message can be used to reflect input back to the user, now we will show how you can read something from a device and feed this information back to the user.

This is achieved by using an update env command.

Let's start with a simple example, querying a Cisco switch for it's configured domain name:

1
2
3
cisco-2960-001#show ip domain-name
osirium.net
cisco-2960-001#

Here we want to capture the entire line of the response.

Note

Currently the PxM Platform can only capture the first line or part Regular Expressions of the first line of the response. This will be enhanced in a future version.

To capture this we need to use the update_env command:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task name="show_domain_name" display_name="Show Domain Name" type="status" access="shell">
         <commands>
            <command format="update_env" attribute="domain_name">show ip domain-name
               <success type='default' />
            </command>
            <command newline="lf">
               <success type="default" message="The configured domain name is: %(domain_name)s"/>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

Breakdown:

  • The show ip domain-name command will succeed by default, as we don't know whether a domain will be in the response or not. It will also store the whole response line into a local variable called domain_name.
  • The second command sends a line feed using newline="lf". We are using this command's success element to send a message back to the user containing the domain_name substitution.
  • We have to use this extra blank command, because update_env values only become available after the command in which they are set.

The message displayed would be:

Task update env message

The display message is also shown in the system queue if you expand the row using the left-hand little blue triangle, like this:

Log update env message

Sub-String Capture

To capture an extract of the response rather than the full line, you can use regular expressions. In this case we will use the regex_capture attribute.

The command and response when displaying a port's VLAN configuration on a Cisco:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
cisco-2960-001#show interfaces FastEthernet0/1 switchport
Name: Fa0/1
Switchport: Enabled
Administrative Mode: dynamic auto
Operational Mode: static access
Administrative Trunking Encapsulation: dot1q
Operational Trunking Encapsulation: native
Negotiation of Trunking: On
Access Mode VLAN: 1 (default)
Trunking Native Mode VLAN: 1 (default)
Administrative Native VLAN tagging: enabled
Voice VLAN: none
Administrative private-vlan host-association: none
Administrative private-vlan mapping: none
Administrative private-vlan trunk native VLAN: none
Administrative private-vlan trunk Native VLAN tagging: enabled
Administrative private-vlan trunk encapsulation: dot1q
Administrative private-vlan trunk normal VLANs: none
Administrative private-vlan trunk associations: none
Administrative private-vlan trunk mappings: none
Operational private-vlan: none
Trunking VLANs Enabled: ALL
Pruning VLANs Enabled: 2-1001
Capture Mode Disabled
Capture VLANs Allowed: ALL

Protected: false
Unknown unicast blocked: disabled
Unknown multicast blocked: disabled
Appliance trust: none
cisco-2960-001#

There are quite a few lines returned from the device, but we can use the Cisco include filter to show just the access VLAN we are looking for::

1
2
3
cisco-2960-001#show interfaces FastEthernet0/1 switchport | include Access
Access Mode VLAN: 1 (default)
cisco-2960-001#

The bit we really want to pull out is the VLAN number, but the name default might be useful too.

We can use the regex with a single capturing group below to extract the text after Access Mode VLAN::

1
^Access Mode VLAN: (.*)

A more detailed overview of regular expressions can be found here: Regular Expressions.

Now we can create a task that takes a port number, and displays back which VLAN the port is configured in:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
 <devicetemplate>

   <tasks>
      <task display_name="Show Port VLAN Config" name="show_port_vlan_config" type="status">
         <input name="port" display_name="Port" type="string"/>
         <commands>
            <command format="update_env"
               attribute="vlan"
               regex_capture="^Access Mode VLAN: (.*)">show interfaces %(port)s switchport | include Access
            </command>
            <command newline="lf">
               <success type="default" message="Port: "%(port)s" is in VLAN: "%(vlan)s"."/>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

How this displays to the user:

Task regex capture message

You can use multiple update_env commands in a task, and use all the attribute substitutions in a single message.

To make displaying multiple attributes easier you might want to place them on separate lines.

You can also add line breaks to a message with the HTML break tag <br>. In an XML document the brackets need to be replaced with XML entities:

1
&lt;br&gt;

Here it is being used in a template:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<devicetemplate>

   <tasks>
      <task display_name="Show Port VLAN Config" name="show_port_vlan_config" type="status">
         <input name="port" display_name="Port" type="string"/>
         <commands>
            <command format="update_env" attribute="vlan" regex_capture="^Access Mode VLAN: (.*)">show interfaces %(port)s switchport | include Access
            </command>
            <command newline="lf">
               <success type="default" message="Port: %(port)s&lt;br&gt;VLAN: %(vlan)s"/>
            </command>
         </commands>
      </task>
   </tasks>

</devicetemplate>

How this displays to the user:

Task regex capture message multiple lines

Long Running Commands

By default the PxM Platform will wait up to 15 seconds for a response to a command. If a response is not seen in that time, the PxM Platform will report a WaitForNotSeen error in the task log.

If you need the PxM Platform to wait longer than 15 seconds for a certain command, you can use the response_timeout attribute (in seconds):

1
<command response_timeout="300">a-long-running-command</command>