Table Of Contents

Previous topic

2.3. GUI Plugins

Next topic

2.5. Services

This Page

2.4. Add an Agent

Simple

  • Inherit agent.Agent
  • Define the class VARIABLES
  • Call Agent.__init__ in subclass init
  • Define handleX where X is the commands that are received

Each node runs a single daemon process for receiving and processing events from the messaging system. An agent is a python module that is loaded by the daemon process. To add your own agent type, you need to create a python class that extends Agent or a subclass and place the file in a modules directory of a SEER package directory.

2.4.1. Defining Agent Variables

You must defined some class variables in your agent that are used to determine message types, variables to accept, control panel look, etc. Any class level docstrings will also be collected for display in the GUI.

DEPENDS
Generic Add-on variable to specify module dependencies such as [‘ApacheService’]. This will cause the ApacheService module to be loaded at startup as well.
SOFTWARE
Generic Add-on variable to specify binary software dependencies as ash [‘apache22’]. This will force the loading of the apach22 software bundle onto the node.
AGENTGROUP
String that specifies the group in GUI control panel to place the agent list. If you used “Traffic Generation”, the agent would show up under the Traffic Generation group in the GUI.
AGENTTYPE
String that specifies the agent type to address when commands are being sent. For example ‘HTTP’.
NICENAME
A human readable name to place in the Control Panel list such as Web.
COMMANDS
A string list of the commands that this agent responds to such as [‘START’, ‘STOP’]. This list only controls the buttons that appear in the GUI control panel. An agent is still free to respond to other commands.
VARIABLES
A list of Variable objects describing the settable variables for this agent. Each Variable object contains its type, its name, a default value, a label for GUI panel and help text for the GUI panel. Instances of the agent can access the variable as a class member using its name. (i.e. self.servers)

When extending the basic agent class, you need to call the Agent __init__ method, and then implement the methods to respond to commands from a GUI or script. The Agent class will process incoming variable sets and call handleX where X is an event type. The Agent class provides TGStart and TGStop for basic usage of a traffic generation tool. Just assign these methods tohandleSTART and handleSTOP.

2.4.2. Variable Classes

Variables types are defined in messages_pb2.py. The current list is:

  • NODE, NODELIST - Stored as a NodeList object
  • INTF, INTFLIST - Stored as an IPList object
  • CIDR, CIDRLIST - Stored as a list of CIDR objects
  • PROTOCOL - Stored as ???
  • DIST, STRING - Stored as strings
  • DOUBLE - Stored as a python float
  • INT - Stored as a python int

The NodeList and IPList types provide a wrapper around list with some additional behaviour. NodeList is is a basic list of strings with an additional method myNodeMemberOf that returns true if the current node is a member of the list. IPList is a basic list of strings with an additional method matchMyIPs that returns the set of strings that match an IP address on the local machine.

2.4.3. Agent instance variables

The agent variables for each instance are available as a regular class variable. For example: self.servers will refer to the servers variable. They are initialized with your default value up creation of each new group (object). When setting variables from a command, they also come with a node name so each variables is actually stored as a default dictionary. When you refer to a variable, if your node name appears as a key into the dictionary, that value is loaded. Otherwise, the ‘*’ value is loaded. If you want to see what another node has for its value, you can call getNodeVar to get the entry for another node name. Accessing the variable directly is the same as calling getNodeVar(myname)

Other instance variables that are preset are: self.pids array of PID values self.runningserver used by TGStart/TGStop code to note if a server was started self.group the group name for this instance self.log link to a Logger object for this instance Here is the Web agent class as an example:

class HTTPAgent(agent.Agent):
    """
            The HTTP generator controls a set of wget clients that make HTTP requests
            to a set of servers running apache
    """

    DEPENDS = ['ApacheService']
    SOFTWARE = []

    AGENTGROUP = 'Traffic Generation'
    AGENTTYPE = 'HTTP'
    NICENAME = 'Web'
    COMMANDS = ['START','STOP']
    VARIABLES = [
            Variable(NODELIST, 'clients', [], 'Clients', 'Select the nodes that will become HTTP agents'),
            Variable(NODELIST, 'servers', [], 'Servers', 'Select the nodes that will become HTTP servers'),
            Variable(DIST, 'think', 1, 'Thinking Time', 'Function to determine time between requests'),
            Variable(DIST, 'sizes', 1, 'File Sizes', 'Function to determine the size of the page requested')
            ]

    def __init__(self): agent.Agent.__init__(self)

    handleSTART = TGGStart
    handleSTOP = TGStop
    def serverExec(self): services.ApacheService.start()
    def serverStop(self): services.ApacheService.stop()

    def clientExec(self, src, dst, size):
            cmd = "wget -nv -t 1 -O /dev/null "
            if (src is not None):
                    cmd += "--bind-address %s " % (src)
            cmd += "http://%s/getsize.py?length=%d " % (dst, size)
            subpid = spawn(cmd, None)

    def handleBLAH(self):
            """ This method would be called when the command BLAH is received
            for self.group.  It will print out the current set of variables
            """
            print self.clients, self.servers, self.think, self.sizes

2.4.4. Using TGStart and TGStop

In the example we make use of TGStart and TGStop from the base class. These functions require that the variables (clients, services, think, sizes) are avaiable and so we define them in VARIABLES. TGStart() and TGStop() also require you to override some base methods. In this case: serverExec(), serverStop() and clientExec().

  • serverExec() is called when a START event is received and the local node is a member of servers
  • serverStop() called when a STOP event is received and the local node started a server
  • clientInit() is called initially upon a START event inside the new client process group
  • clientExec() is called when the next think time has expired

Note that when using TGStart(), a new process group is created for you if the local node is a member of clients and calls to clientExec() are made from this new process so that killing off an agent client tree is just killing the process group.

If you want to change the inner workings you can also override clientOneLoop() to override the loop behavior or launchTrafficController() to control all of the start behavior. However, if you are thinking of overriding launchTrafficController() it may be better to just write your own handleSTART() routine.

2.4.5. Other Examples

The best place to find examples is in the repository modules directory http://seer.isi.deterlab.net/trac/browser/code/trunk/modules.