Skip to content

Howto: Using ISE API in Python scripts

tfb-bull edited this page Aug 27, 2012 · 1 revision

Using ISE API in Python scripts

The sequencer also provides a XML based API to execute actions and is usable in external Python scripts.

Importing ISE API module

In order to use the ISE API, you'll have to import the following module:

from sequencer.ise import api

Building XML data

The ISE API takes XML data as input. You may use an already written XML file (as long as it complies with the XSD schema) or dynamically build an XML tree by using the sequencer model module.

To dynamically create XML data within your scripts, import the following classes:

from sequencer.ise.parser import ISE, PAR, SEQ, ACTION

These classes are helpers based on lxml.

  • ISE is used to create instructions elements, this is the root element of a sequencer XML file
  • PAR is used to create par elements, these elements are used to define actions, sequence of actions or other parallel action groups which are to be executed in parallel
  • SEQ is used to create seq elements, a sequence defines an ordered sequence of actions (or other sequences or even parallel action groups)
  • ACTION is used to create action elements, an action is defined by a set of attributes (id, remote, desc, etc.)

Refer to ise.xsd for further details on the schema.

Create a simple test case

We're going to demonstrate how to create a basic test case using previously explained XML wrappers.

First, let's create the root element of our XML document:

ise = ISE()

Create a sequence:

seq = SEQ(desc="My sequence of actions")

Add actions to the sequence:

seq.append(ACTION('/bin/ping -c 1 localhost',
                  id="ping_once",
                  component_set="localhost",
                  remote="false",
                  force="allowed"))
seq.append(ACTION('/bin/uname -a',
                  id="uname_all",
                  component_set="localhost",
                  remote="false",
                  force="allowed"))

Add the sequence to the root:

ise.append(seq)

Transform the XML tree into a string

xml = lxml.etree.tostring(ise, pretty_print=True)

Execute the instructions sequence

with io.StringIO(unicode(xml)) as reader:
    execution = api.execute(reader)

Results and errors management

A simple way to manage execution results is to go through the executed_actions dictionary:

for action in execution.executed_actions.itervalues():
    print action.rc
    print action.stdout
    print action.stderr

A more complex test case: actions in parallel

We've demonstrated how to execute a sequence of actions locally. One of the most interesting feature of the sequencer is to be able to execute sequence of actions in parallel on remote hosts. The following example illustrates how to do this with a very simple test case. If you wish to test this example, you should update your ~/.ssh/config file to contain something like this:

Host test1
    HostName localhost
Host test2
    HostName localhost

As before, we create the root element:

ise = ISE()

Now, we create a parallel element:

par = PAR(desc="My parallel group of action sequences")

Create and add a first sequence of actions:

seq1 = SEQ(desc="First sequence on host test1")
seq1.append(ACTION('/bin/uname -a',
                  id="uname_all_on_test1",
                  component_set="test1",
                  remote="true",
                  force="allowed"))
seq1.append(ACTION('/bin/date -R',
                  id="date_rfc2822_on_test1",
                  component_set="test1",
                  remote="true",
                  force="allowed"))

Add the sequence to the parallel element:

par.append(seq1)

Create a second sequence of actions to be executed on a different host:

seq2 = SEQ(desc="Second sequence on host test2")
seq2.append(ACTION('/bin/uname -a',
                  id="uname_all_on_test2",
                  component_set="test2",
                  remote="true",
                  force="allowed"))
seq2.append(ACTION('/bin/date -R',
                  id="date_rfc2822_on_test2",
                  component_set="test2",
                  remote="true",
                  force="allowed"))

Add the sequence to the parallel element:

par.append(seq2)

Finally, add the parallel element to the document root:

ise.append(par)

Process data, execute and manage results

xml = lxml.etree.tostring(ise, pretty_print=True)
with io.StringIO(unicode(xml)) as reader:
    execution = api.execute(reader)
for action in execution.executed_actions.itervalues():
    print action.rc
    print action.stdout
    print action.stderr

Conclusion

Through these simple examples, we've demonstrated how to use the sequencer's ISE API within Python scripts. This feature is extremely powerful and can be extended to many usage (I use it to configure basic services on many remote hosts for example). Play around with it, have a look to the test cases (tests/testapi.py) and if you feel like it give some feedback about your own experience.

Going further

We haven't demonstrated every possibilities (execution flow control, error management, debugging, scaling, etc.) offered by the ISE API, I encourage you to have a look to the API code (which is well documented), the documentation (and the XSD schema !) and most importantly: experiment.

Feedback

If you have comments (mistakes, improvements, etc.) about this howto, you may contact me directly on github.

Clone this wiki locally