Skip Headers
Oracle® Communications IP Service Activator Configuration Development Kit Guide
Release 7.2

E47724-01
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

5 Sharing Data Between Scripts

This chapter, aimed at experienced Python programmers, explains how to exchange data between scripts using the shared data area.

About Sharing Data Between Scripts

It is possible to share data between Configuration Development Kit (CDK) scripts. This feature has a range of applications, including the ability to store and re-use data or functions that are commonly used by scripts and to exercise greater control over the order of script execution.

The device driver allocates an area of memory for each device that it manages. This is referred to as the shared data area or shared area. Shared data may be stored for the lifetime of the device, that is, until the device is unmanaged or the device driver restarted, or for a single transaction. Information that is currently held in the shared data area may be accessed by any CDK scripts that are applied to that device.

By default, data is stored in the shared area as a simple Python dictionary but it is also possible to structure the shared information using classes. If you wish to use a class-based structure, you must create a Python module that defines the structure and pass it to the device driver using a command-line option.

The class-based solution provides a more manageable approach to using the shared data area. It allows some initial setup to be performed by the Python module so that the shared data area contains useful data when the first CDK script is run against a device. This contrasts with the dictionary-based structure, where the dictionary is empty when the first CDK script runs and any data, classes or functions must be added by the CDK scripts themselves.

This chapter describes how to store information in the shared data area using classes or a dictionary, provides an example approach to script organization to make use of the shared area and outlines some potential applications.

Using Classes

Storing data in the shared data area using a class-based data structure provides a maintainable use of the area.

The structure of the classes that will be stored in the shared data area must be defined as a Python module. A module is a file containing code which defines a group of Python functions or other objects.

The module is run when the device driver is started with the following command-line parameter:

-SharedDataModule module

where module is the name of the Python module that defines the structure of information held in the shared data area.

For example:

\Program\cisco_device_driver.exe|"-SharedDataModule CreateSharedArea …

The Python module must be installed on every machine that is hosting a device driver used to configure scripts.

Note:

When specifying the name of the Python module, you do not need to include the script's.py extension.

If you are running the device driver on Solaris, the location of the Python module must be set in the PYTHONPATH environment variable.

If you are running the device driver on Windows, the driver looks for the module in c:\Program Files\Oracle Communications\IP Service Activator\Program by default. The PYTHONPATH variable may be set to an alternative location.

The module defines the basic structure of the object class stored in the shared data area and the methods available to instances of the class.

The module is a user-defined script and is likely to vary across installations according to the needs of the operation. At minimum, it should provide methods for inserting new objects in and removing objects from the shared area. A sample module is provided in "Sample Scripts for Using the Shared Data Area".

Note:

The name of the function that the device driver calls to create the class-based structure is hard-coded within the driver. User-defined modules must contain a CreateSharedObject function. For example:
def CreateSharedObject():
return SharedInfo()

If there is no CreateSharedObject function, the driver reverts to a dictionary.

Figure 5-1 illustrates the class-based shared data area.

Figure 5-1 The Class-based Shared Data Area

Description of Figure 5-1 follows
Description of "Figure 5-1 The Class-based Shared Data Area"

Using a Python Dictionary

If the -SharedDataModule command-line parameter is not passed to the relevant device driver, the driver creates an empty dictionary in the shared data area on startup.

A Python dictionary is an associative array, implemented using hash tables, which provides access to values by integers, strings or other Python objects referred to as keys. A key indicates where in the dictionary a given value may be found. Because the key into a dictionary may be something other than a number, dictionary objects do not have any implicit ordering relative to each other. However, an explicit ordering may be defined using another data structure, such as a list. The objects stored in a dictionary may be of any type.

Once created, new positions may be created in a dictionary as values are written to them, without the need to create the position beforehand. Values stored in a dictionary may be accessed and used by scripts running on the same host machine.

Figure 5-2 illustrates the dictionary-based shared data area.

Figure 5-2 The Dictionary-based Shared Data Area

Surrounding text describes Figure 5-2 .

Storing and Retrieving Data

The device driver creates two stores of shared data for a device: one that persists for the lifetime of the device, and one that persists for the lifetime of a transaction.

The following method retrieves the data that has been stored in the shared data area during the current transaction only:

_device.getThisCommitSharedData()

The following method retrieves data that is stored in the shared data area for the lifetime of the device:

_device.getLifetimeSharedData()

Once a script has a reference to the shared data it can read and write data to the area.

The technique for storing information in the shared area depends on whether data is stored as a class or dictionary.

If shared data is stored as a class object, it is possible to call the methods defined for the class. These methods are defined in the Python module named in the -SharedDataModule parameter on the device driver's command line.

For example, assuming the existence of an insertBehavior() method for the shared data class:

_device.getThisCommitSharedData().insertBehavior(BehaviorX())

inserts an object of type BehaviorX in the shared data area.

If data is stored in a dictionary, it is possible to access data via its key. For example:

Address=_device.getThisCommitSharedData()["IPAddress"]

An Example of Using the Shared Data Area

The CDK offers a very flexible solution to sharing data between scripts, enabling storage of data per device for the lifetime of the device, or for the lifetime of a transaction, with no restriction on the type of data to be stored or the structure used to organize it. Any use of the shared data area can therefore be geared towards the particular needs of the operation.

The example in this section illustrates the type of processing that may be performed using the shared data area and uses a dictionary-based approach to storing data. This means that all classes and methods are defined within the scripts themselves. If a class-based approach were used, these would be defined in a Python module passed to the device driver on the command line. This would simplify the data, behavior and controller scripts applied to devices. A sample Python module definition is provided in "Sample Scripts for Using the Shared Data Area".

Types of Script

In order to support re-use of script functionality and reduce redundancy, the example described in this section divides scripts into three basic types, according to the type of function they perform:

  • Data scripts define configuration data that is specific to a particular policy target, such as an interface.

  • Behavior scripts define generic functions that can be run against multiple policy objects, for example, defining policy or class maps, or performing a generic operation such as parsing or ordering data. When run, a behavior script creates a behavior object in the shared data area.

  • The controller script manages the execution of the behavior and data script objects (created by behavior and data scripts), for example, by prioritizing the order in which behavior and data objects are processed.

Note:

The division of scripts into behavior, data and controller scripts is designed to take full advantage of the features offered by the shared data area. The scheme presented in this example is a sample categorization and acts as an illustration only. You may choose to categorize scripts according to any other logical scheme.

The division of scripts into behavior, data and controller types optimizes re-use of the functionality defined by a script. For example, a behavior script can be applied to any number of devices to define generic aspects of policy map configuration and inherited to the relevant interfaces. A number of separate data scripts define the interface-specific information and are applied to each relevant interface. This is illustrated in Figure 5-3.

Figure 5-3 Division of Scripts into Types

Diagram illustrating the division of scripts into types

About the Example

The example shows how to apply configuration changes to a device, making a simple change to the interface IP address and description. Although the changes it makes are simple, it illustrates some basic principles and tasks that you may wish to use in your own scripts. These include:

  • Parsing the device's running configuration and storing it in the shared data area.

    The example demonstrates how to retrieve device configuration only once and store it in the shared data area. The stored configuration is referenced by other scripts that are set to run against the device. This minimizes communication with the device and cuts down network traffic.

  • Comparing potential new device configuration to that which is already installed

    This ensures that there is no unnecessary transmission of data to the device if, for example, the relevant command has already been configured.

  • Queuing the commands to be sent to the device.

    As scripts are run against the device, the configuration they create is stored in the shared data area. When all the configuration to be sent has been accumulated, it is sent in a single communication session with the device.

  • Prioritizing the order in which script functionality is executed.

    Each behavior script assigns a priority to the behavior object it creates. The controller script sorts behavior objects and executes them in their priority order.

The following scripts feature in the example:

  • Data scripts that define interface-specific configuration:

    • setIpAddress.py defines the IP address of an interface

    • setDescription.py defines the description of an interface

  • A behavior script, processInterfaces.py, which creates a behavior object in the shared data area, indicating the priority in which the behavior must be run.

  • The example illustrates a single behavior script, but there may be a number of behavior scripts set to run against a device. The processing performed by a behavior script may be dependent on some processing that has already been performed by another behavior script. For example, the class map name created by a behavior script may act as input to a subsequent behavior script that generates the policy map.

  • A controller script, BehaviorAndCommandController.py, which sorts the stored behavior objects and calls an Execute method that is defined for every behavior.

Most of the processing that is carried out on existing and new configuration is performed by methods defined within the behavior script. However, these are not actually run until the controller script calls the behavior's Execute method.

The Oracle Communications IP Service Activator client provides a basic method for specifying the order in which scripts are applied to an object, enabling you to specify whether a script is run before or after the standard configuration changes made by the device driver. Figure 5-4 shows the Schedule page in the Driver Script dialog box where you can specify when the script is run.

Figure 5-4 The Schedule Page

Description of Figure 5-4 follows
Description of "Figure 5-4 The Schedule Page"

By specifying that data and behavior scripts run before standard configuration changes and the controller script runs after the changes, it is guaranteed that any data that the controller script needs to process will exist in the shared data area.

All of the scripts operate on the shared data area that is dedicated to data held for the current transaction only:

  • The data scripts write information to the shared area, checking for the existence of stored potential configuration for the device, and adding their output to the storage area. Figure 5-5 illustrates the data script in operation.

    Figure 5-5 Data Scripts Writing Configuration Data to the Shared Data Area

    Diagram illustrating the operation of data scripts
  • The behavior script writes a behavior object to the area and stores information about the order in which it should be executed in relation to other behaviors (there may be multiple behavior scripts run against a device in a single transaction). Figure 5-6 illustrates the behavior script in operation.

    Figure 5-6 Behavior Script Writing a Behavior Object to the Shared Data Area

    Diagram illustrating the operation of behavior scripts
  • The controller script processes any behavior objects written to the shared data area in their priority order, calling an Execute method defined for each behavior object. This performs the body of the processing, retrieving and parsing configuration from the device (if it has not already been retrieved), comparing the existing configuration with the stored configuration created by the data scripts, and sending any configuration that needs to be sent to the device in a single communication session. Figure 5-7 illustrates the controller script in operation.

    Figure 5-7 Controller Script Processing Behavior Objects

    Diagram illustrating the operation of the controller script.

The following sections provide a listing of each script. The scripts update the getThisCommitSharedData area or read data from the area, storing data in a number of dictionaries. These are:

  • Interfaces: created or updated by the data scripts with the IP address and description with which to configure an interface on a device, and by the behavior script to retrieve new commands for the device

  • Config: used by the behavior script to store existing device configuration

  • Commands: used by the behavior script to store the commands to be transmitted to the device, and by the controller script to retrieve commands for transmission to the device

  • Behavior: used by the behavior script to store information about the priority in which it must be run in relation to other behavior scripts, and by the controller script to call each behavior's Execute method in the correct order.

The behavior script also creates additional dictionaries outside the getThisCommitSharedData area. These are used to process existing interface configuration so that it can be compared with potential new commands to be configured for an interface. These dictionaries are:

  • allinterfaces: holds a complete list of the interfaces on the device

  • interfaceconfig: holds the relevant commands (that is, commands that configure the interface's IP address and description) that are already configured on a device for a specific interface

The behavior script also creates a list of the commands that need to be sent to the device in a temporary area before adding this information to the commands dictionary in the getThisCommitSharedData area.

Data Script: setIPAddress.py

The setIPAddress.py script defines an interface-specific IP address and mask and would be applied at interface level through the IP Service Activator client.

The sections that follow provide the setIPAddress.py script listing and an explanation of how the script works.

Listing of setIPAddress.py

1   #Title: InterfaceIpAddressChanges.
    Version = '1.0'
    #IP Service Activator version: 7.0.0
    #Date: 1-Aug-2008   




9   #begin preamble section
    # Copy this line and paste it into the context field, editing the 
    # IP address and mask as required
    ip="0.0.0.0"
    mask="255.255.255.252"

15  #begin behavior section
    script_name = "INTERFACE_IPADDRESS"
    script_driver_type = "cisco"
    script_type = Interface
    script_device_role = Any
    script_interface_role = Any
    script_apply_when = Before
    script_repeat = False
    script_apply_on_restart = True

25  #begin common section
    # First make sure that there is a section representing interfaces
    if not _device.getThisCommitSharedData().has_key("interfaces"):
      _device.getThisCommitSharedData()["interfaces"]={}

30  interfaces = _device.getThisCommitSharedData()["interfaces"]
    if not interfaces.has_key(_interface.getInterfaceName() ):
      interfaces[_interface.getInterfaceName()]={}

34  #begin install section
    # Store the ip address command
36  ipCmd="ip address "+ ip + " " +mask
    interfaces[_interface.getInterfaceName()]["ip address"]=ipCmd

39  #begin remove section
    # Mark the ip address key as empty
    interfaces[_interface.getInterfaceName()]["ip address"]=""

Explanation of setIPAddress.py

The script's processing starts by checking whether there is an interfaces key in the getThisCommitSharedData dictionary (line 27). If no key exists, the script creates one and makes the newly-created key a reference to a new dictionary. On lines 30-32, the script retrieves the content of the interfaces dictionary, and checks whether a key exists with the relevant interface name. If no key exists, the script creates one and makes the newly-created key a reference to a new dictionary. The interface IP address and mask is then stored at the correct point in the interfaces dictionary (lines 34-37).

Data Script: setDescription.py

The setDescription.py script performs processing identical to that performed by setIpAddress.py except that an interface description replaces the IP address.

The section that follows provides the setDescription.py script listing.

Listing of setDescription.py

1   #Title: InterfaceDescriptionChanges
    Version = '1.0'
    #IP Service Activator version: 7.0.0
    #Date: 31-Mar-2008




9   #begin preamble section
    description= "PE interface for customer XXX"

12  #begin behavior section
    script_name = "INTERFACE_DESCRIPTION"
    script_driver_type = "cisco"
    script_type = Interface
    script_device_role = Any
    script_interface_role = Any
    script_apply_when = Before
    script_repeat = False
    script_apply_on_restart = True

22  #begin common section
    # first make sure that there is a section representing interfaces
    if not _device.getThisCommitSharedData().has_key("interfaces"):
      _device.getThisCommitSharedData()["interfaces"]={}

    interfaces=_device.getThisCommitSharedData()["interfaces"]
    if not interfaces.has_key(_interface.getInterfaceName() ):
      interfaces[_interface.getInterfaceName()]={}

31  #begin install section
    # Set the description of the interface data
    descCmd="description "+ description
    interfaces[_interface.getInterfaceName()]["description"]=descCmd

36  #begin remove section
    # Mark the description key as empty
    interfaces[_interface.getInterfaceName()]["description"]=""

Behavior Script: processInterfaces.py

The sections that follow provide the processInterfaces.py script listing and an explanation of how the script works.

Listing of processInterfaces.py

1   #Title: InterfaceDescriptionChanges
    Version = '1.0'
    #IP Service Activator version: 7.0.0
    #Date: 31-Mar-2008   




9   #begin preamble section
    #N/A

12  #begin behavior section
    script_name = "PROCESS_INTERFACES"
    script_driver_type = "cisco"
    script_type = Interface
    script_device_role = Any
    script_interface_role = Any
    script_apply_when = Before
    script_repeat = False
    script_apply_on_restart = True

22  #begin common section
    #Load the string module
24  import string
    class InterfaceProcessor:
26    def __init__( self ):
27      self.types=("description", "ip address" )
28      def getDeviceConfig(self, command ):
          if not _device.getThisCommitSharedData().has_key("config"):
            _device.getThisCommitSharedData()["config"]={}

34        # Log onto the device, send the command and stash the returned 
          # config split into lines.
          if not _device.getThisCommitSharedData()["config"].has_key(command):
            _device.openSession()
            config = _device.deliverCommand(command )
            _device.closeSession()
            _device.getThisCommitSharedData()["config"][command]=string.split(config,"\n")

40        # Return the content of the [config][command] key
          return _device.getThisCommitSharedData()["config"][command]

43        # Get configuration from the device 
        def getInterfaceConfig( self ):
          config=self.getDeviceConfig("show running config")

47        allinterfaces={}
          interfaceconfig=None
49        for ind in range( 0 , len(config) ):
            str=string.lstrip( config[ind] )

            if ( str.startswith ("interface") ):
53            interfaceconfig={}
              allinterfaces[str]=interfaceconfig
            else:
            if( interfaceconfig ):
57            if( str == "!"):
                interfaceconfig=None
              else:
60              for type in self.types:
61                if ( str.startswith( type )  ):
62                  interfaceconfig[type]=str
          # else not in an interface and do need to look at the line.
          return allinterfaces

66      def Execute(self):

68        # Check for the commands dictionary 
          if not _device.getThisCommitSharedData().has_key("commands"):
            _device.getThisCommitSharedData()["commands"]={}
71        # Check that priority 3 commands exist
          if not _device.getThisCommitSharedData()
["commands"].has_key(3):
            _device.getThisCommitSharedData()["commands"][3]=[]

76        # Check whether there is any required interface configuration
          if not _device.getThisCommitSharedData().has_key("interfaces"):
            return

80        # Retrieve the current configuration from the device
          allOldData=self.getInterfaceConfig()

83        # Loop through the interfaces with required data
          for (name, reqData) in _device.getThisCommitSharedData()["interfaces"].items():
            commands=[]

87          # Get the existing interface config or create an empty object
            if( allOldData.has_key(name) ):
              oldData=allOldData[name]
            else:
              oldData={}
92            # Process each type of config the script can handle in turn 
              if reqData.has_key(type):
94              if(  reqData[type] ):
                if( not oldData.has_key(type) or oldData[type] != reqData[type] ):
                  commands.append( reqData[type] )
                else:
                  if( oldData.has_key(type) ):
                    commands.append( "no " + oldData[type ] )

102        # If there are any interface commands, surround them by enter
          # and exit commands and add them to the list of commands to execute
          if( len( commands )):
            _device.getThisCommitSharedData()["commands"][3].append
("interface " + name)
            _device.getThisCommitSharedData()["commands"][3]=\
            _device.getThisCommitSharedData()["commands"][3] + commands 
 
111         _device.getThisCommitSharedData()["commands"][3].
append("exit")

113 #begin install section
    if not _device.getThisCommitSharedData().has_key("behavior"):
      _device.getThisCommitSharedData()["behavior"]={}

    if not _device.getThisCommitSharedData()["behavior"].has_key(100):
      _device.getThisCommitSharedData()["behavior"][100]=[]

    _device.getThisCommitSharedData()["behavior"][100].append(InterfaceProcessor())

#begin remove section

Explanation of processInterfaces.py

The Common section (line 22) defines an InterfaceProcessor class that can perform the following tasks:

  • Parse and store the configuration that is already on the device

  • Check whether there is new configuration to be delivered to the device

  • Compare new configuration with any existing configuration of the same type

  • Store the commands to be delivered

The class can be divided into two parts. The first part defines methods for parsing, comparing and storing the configuration, the second part defines an Execute method that calls these methods. When the script is run, a behavior object is created in the shared data area, by a call to the InterfaceProcessor class. The Execute method is called and the script's processing is performed only when the controller script calls the method.

The imported string module (line 24) provides functionality required by the parsing process.

The __init__ constructor method (line 26) is run automatically when the class name is called to create an instance. The method can be used to perform all the set up required for the class.

Line 27 creates a list of strings, where each string defines the start of a line of configuration that the script is designed to handle. This list of strings is assigned to the class variable types. This variable is used later in the script (line 93), and provides a more maintainable method of managing the data to be handled by the script. If the script needs to be updated to handle additional configuration in future, a new string can simply be added to the variable.

The getDeviceConfig method (line 28) is currently called with the show running config command. The method supports any other configuration command, however, and provides the type of functionality that you may wish to define in a Python module when using a class-based approach to the shared data area. The method checks whether the getThisCommitSharedData dictionary already has a copy of the running configuration (stored in the config dictionary). If not, it logs into the device, retrieves the config, splits it into lines and stores it in the config dictionary.

The getInterfaceConfig method calls getDeviceConfig with the show running config command. It then creates an allinterfaces dictionary (line 47) and an interfaceconfig variable and sets the variable to None. It then cycles through each line of configuration held in the config dictionary and checks for interface configuration (lines 49-50). Where interface configuration is found, the method creates an interfaceconfig dictionary (line 53) and adds a key labelled according to the name of the interface to the allinterfaces dictionary that points to the interfaceconfig dictionary. For each of the strings assigned to the class variable types (i.e. ip address and description), the method checks whether the line of config currently being processed starts with the string (line 61). If so, it creates a key in the interfaceconfig dictionary, taking the current value of type as the key name, and writes the current line of configuration to the key (line 62). When the end of interface configuration is reached (indicated by a ! character) (line 57), the method clears the interfaceconfig variable to mark that the parser is outside of interface configuration. Finally, the method returns the content of the interfaces dictionary (line 64).

The Execute method is called by the controller script when it runs. It checks whether the commands dictionary exists within the getThisCommitSharedData dictionary and, if not, creates one (lines 69-70). It then checks that key 3 exists in the commands dictionary; this is the priority assigned to the commands generated by this particular behavior. There may be keys for commands generated by other behaviors in the commands dictionary. If the key does not exist, the method creates it (lines 72-74).

Before performing any further processing, the method checks whether there is any interface configuration waiting to be sent to the device (lines 77-79). The method checks whether an interfaces dictionary exists in the getThisCommitSharedData dictionary. This is the dictionary created or updated by any data scripts that have run against the device. If the dictionary does not exist, there is nothing to do and the method returns.

The method then retrieves the current configuration from the device by calling the getInterfaceConfig method (line 81). The return of getInterfaceConfig is the interfaces dictionary, so the allOldData variable is a pointer to a dictionary.

The method then loops through the interfaces for which configuration has been stored in the interfaces dictionary (lines 83-86), retrieving its name, value pairs (each pair consists of an interface name and the configuration to be put onto the device). The method processes each pair in turn, creating an area for the current interface's commands.

If the retrieved configuration (held in the interfaces dictionary) has a key whose name matches that currently being processed, the method assigns the content of the key (i.e. the interface name that points to the current interface configuration) to the variable oldData. If not, the method creates an empty dictionary (lines 87-91).

Then each type of configuration the script can handle is processed in turn and the method checks whether there is a command stored for the interface (line 93). If the command to be delivered is not an empty string, and if the command is not already configured on the device (line 94), or is configured and is not the same as the command currently stored for the interface (line 96), the method adds the command to the commands list for the interface (97). If the command to be sent is an empty string (that is, the configured command is no longer required), and the command is already configured on the device, the method adds the ’no' form of the command to the commands list for the interface (line 100).

If there are any commands in the commands list, surround them by enter and exit commands and add them to the getThisCommitSharedData dictionary's commands dictionary at the priority 3 key (lines 102-111). The commands dictionary stores the commands to execute and their order of execution.

The Install section (line 113) is the only section of the script that will be executed when the script is run against the device. It writes a behavior object to the getThisCommitSharedData dictionary by calling the InterfaceProcessor method (line 119). Behavior objects are stored according to their priority within a behavior dictionary.

Controller Script: BehaviorAndCommandController.py

The sections that follow provide the BehaviorAndCommandController.py script listing and an explanation of how the script works.

Listing of BehaviorAndCommandController.py

1  #Title: CommandSender
   Version = '1.0'
   #IP Service Activator version: 7.0.0
   #Date: 1-Mar-2008 



9  #begin preamble section
   #N/A
12 #begin behavior section
   script_name = "Command Sender"
   script_driver_type = "cisco"
   script_type = Device
   script_device_role = Any
   script_interface_role = Any
   script_apply_when = After
   script_repeat = true
   script_apply_on_restart = True

22 #begin common section

   #begin install section
25 if ( _device.getThisCommitSharedData().has_key("behavior") ):
     behaviors = _device.getThisCommitSharedData()["behavior"]
     ordering  = behaviors.keys()
     ordering.sort()
     for order in ordering:
       for behavior in behaviors[ order ] :
31       behavior.Execute()

33 if _device.getThisCommitSharedData().has_key("commands") :
     _device.openSession()
     _device.deliverCommand("configure terminal")

37   commands = _device.getThisCommitSharedData()["commands"]
     ordering = commands.keys()
     ordering.sort()
     for order in ordering:
       for command in commands[ order ] :
         _device.deliverCommand(command)

44   _device.closeSession()      

Explanation of BehaviorAndCommandController.py

The script first checks for the behavior dictionary in the getThisCommitSharedData dictionary (line 25). If the dictionary exists, the script retrieves its keys (each behavior script has written a key to the behavior dictionary to indicate the priority in which it should be executed), sorts the keys/priorities and calls each behavior object's Execute method in turn (lines 26-31).

After processing the behavior object, the script checks whether this has resulted in commands being written to the getThisCommitSharedData dictionary's commands dictionary. The script sorts the stored commands by key, loops through all of the stored commands and sends them to the device (lines 37-42).

Error Reporting in Behavior Scripts

If you follow the guidelines outlined for using the shared data area, a Behavior script's functionality is not executed until it is called by the Controller script. This means that the _result variable that indicates the success or failure of the script that is currently running cannot be used to report on the Behavior script. This is because the script that is currently running when the Behavior script's functionality is executed is the Controller script.

To report on errors that occur when the behavior object is executed, the Behavior script's ID and failure information must be stored within the behavior object created by the script. These details can then be retrieved by the Controller script when it runs.

The Behavior script's class constructor method should define variables to hold the values of the _id and _failure_code variables, as follows:

class InterfaceProcessor
  def __init__ (self):
    self.id=_id
    self.failure=_failure_code

The script's Execute method checks for a failure condition and, if a failure occurred, returns the variable values and a message about the failure, as follows:

  if (failure):
    return (self.id,self.failure,'behavior script InterfaceProcessor failed')

The controller script uses the _result variable's sendScriptObjectFailure method to retrieve the behavior script's failure details, as follows:

result=behavior.Execute()
  if (result):
  (id,failure,message)=result
  _result.sendScriptObjectFailure(id,failure,message)

These details are sent to the policy server and the message displayed in the current faults pane in the user interface.