An API is defined by a module developer and contains a variety of components designed to accomplish a task. These components are:
Enums
Values
Structs
Fields
Interfaces
Properties
Methods
Events
These components are all defined in ADR Interface Description Language document. The radadrgen utility is used to process the document to generate language specific components which facilitate client/server interactions within RAD. More details in the role of ADR and rad can be found in Abstract Data Representation. Brief descriptions of each component follows.
Enumerations are primarily used to offer a restricted range of choices for a property, an interface method parameter, result, or error.
To access an enumerated type, simply import the binding and interact with the enumeration.
Example 3-39 Using Enumerations>>> import rad.bindings.com.oracle.solaris.rad.zonemgr as zonemgr >>> print zonemgr.ErrorCode.NONE NONE >>> print zonemgr.ErrorCode.COMMAND_ERROR COMMAND_ERROR >>>
Structs are used to define new types and are composed from existing built-in types and other user defined types. In essence, they are simple forms of interfaces: no methods or events and they are not present in the RAD namespace.
The zonemgr module defines a Property struct which represents an individual Zone configuration property. The structure has the following members name, type, value, listValue, and complexValue. Like enumerations, structures can be interacted with directly once the binding is imported.
Example 3-40 Using Structs>>> import rad.bindings.com.oracle.solaris.rad.zonemgr as zonemgr >>> prop = zonemgr.Property("autoboot", "false") >>> print prop Property(name = 'autoboot', value = 'false', type = None, listvalue = None, complexvalue = None) >>> prop.name = "my name" >>> prop.value = "a value" >>> print prop.name my name >>> print prop.value a value >>>
Interfaces (also known as objects) are the entities which populate the RAD namespace. They must have a "name". An interface is composed of Events, Properties and Methods.
See the Rad Namespace section.
Once we have an object reference we can use this to interact with RAD in a very straightforward fashion. All attributes and methods defined in the IDL are accessible directly as attributes of the python objects which are returned by get_object().
Here is an example which gets a reference to a zone and then boots the zone.
Example 3-41 Working with Object References>>> import rad.bindings.com.oracle.solaris.rad.zonemgr as zonemgr >>> import rad.client as radc >>> import rad.connect as radcon >>> with radcon.connect_unix() as rc: ... patt = radc.ADRGlobPattern({"name" : "test-0"}) ... zone = rc.get_object(zonemgr.Zone(), patt) ... print zone.name ... zone.boot(None) >>>
In the above example we have connected to our RAD instance, created a search for a specific object, retrieved a reference to the object and accessed a remote property on it. This does not include error handling yet.
Here is another example for accessing a remote property.
Example 3-42 Accessing a Remote Property>>> import rad.bindings.com.oracle.solaris.rad.zonemgr as zonemgr >>> import rad.client as radc >>> import rad.connect as radcon >>> with radcon.connect_unix() as rc: ... name = rc.list_objects(zonemgr.Zone(), radc.ADRGlobPattern({"name" : "test-0"})) ... zone = rc.get_object(name[0]) ... for prop in zone.getResourceProperties(zonemgr.Resource("global")): ... if prop.name == "brand": ... print "Zone: %s, brand: %s" % (zone.name, prop.value) ... break ... Zone: test-0, brand: solaris >>>
In this example, we accessed the list of Zone global resource properties and search the list of properties for a property with the name property of "brand". When we find it we print the value of the "brand" property and then terminate the loop.
In this next example we are going to look at events. The ZoneManager instance defines a "stateChange" event which clients can subscribe to for information about changes in the runtime state of a zone.
Example 3-43 Subscribing and Handling Eventsimport rad.connect as radcon import rad.bindings.com.oracle.solaris.rad.zonemgr as zonemgr import signal def handler(event, payload, user): print "event: %s" % str(event) print "payload: %s" % str(payload) print "zone: %s" % str(payload.zone) print "old: %s" % str(payload.oldstate) print "new: %s" % str(payload.newstate) with radcon.connect_unix() as rc: zm = rc.get_object(zonemgr.ZoneManager()) rc.subscribe(zm, "stateChange", handler, zm) signal.pause()
This is a simple example. We subscribe to the single event and pass in a handler and a reference to our ZoneManager object. The handler will be invoked asynchronously by the framework with the various event details and the supplied user data. The user data is an optional argument at subscription and if not provided, the handler will receive None as the user parameter.
Finally, a quick look at error handling when manipulating remote references. Python provides a rich exception handling mechanism and RAD errors are propagated using this mechanism. There are a variety of errors which can be delivered by RAD, but the main one which requires handling is rad.client.ObjectError. The following snippet, shows how it can be used:
Example 3-44 Handling RAD Errorsimport rad.client as radc import rad.conect as radcon import rad.bindings.com.oracle.solaris.rad.zonemgr as zonemgr import logging import sys logging.basicConfig(filename='/tmp/example.log', level=logging.DEBUG) with radcon.connect_unix() as rc: patt = radc.ADRGlobPattern({"name" : "test-0"}) test0 = rc.get_object(zonemgr.Zone(), patt) print test0.name try: test0.boot(None) except radc.ObjectError as ex: error = ex.get_payload() if not error: sys.exit(1) if error.stdout is not None: logging.info(error.stdout) if error.stderr is not None: logging.info(error.stderr) sys.exit(1)