Go to main content

Remote Administration Daemon Client User's Guide

Exit Print View

Updated: July 2019
 
 

RAD Python Client

    The public interfaces are exported in the following three modules:

  • rad.auth – Useful functions or classes for performing authentication

  • rad.client – The client implementation of the RAD protocol and associated useful functionality

  • rad.connect – Useful functions or classes for connecting to a RAD instance


Note -  Most of the examples are based on the zonemgr interface. To understand the examples for this module better, see Appendix A, zonemgr ADR Interface Description Language Example, in Remote Administration Daemon Module Developer’s Guide.

Alternatively, you can import the module and examine the module help.

Example 30  Accessing Help for a Binding Module
user@host1:/var/tmp# python3.5
Python 3.5.6 (default, May 31 2019, 03:27:25) [C] on sunos5
Type "help", "copyright", "credits" or "license" for more information.
>>> import rad.bindings.com.oracle.solaris.rad.zonemgr_1 as zonemgr
>>> help(zonemgr)

Connecting to RAD in Python

The RAD instances can communicate through the RADConnection class. There are various mechanism to get different types of connections to RAD. Each mechanism returns a RADConnection instance, which provides a standard interface to interact with RAD.

The preferred method for managing a connection is to use the with keyword. The connection uses the system resources and this ensures that the resource is closed correctly when the object goes out of scope. If the system resources are not used, the system resources can be reclaimed explicitly with the close() method.


Note -  If you print the RADConnection object, it displays the state of the connection and lets you know if the connection is closed.

Connecting to a Local RAD Instance in Python

You can connect to a local instance using the radcon.connect_unix() function. An implicit authentication is performed against your user ID and most RAD tasks you request with this connection are performed with the privileges available to your user account.

Example 31  Python Language – Creating a RAD Local Connection
>>> import rad.connect as radcon

>>> with radcon.connect_unix() as rc:

Connecting to a RAD Remote Instance and Authenticating in Python

When connecting to a remote instance, no implicit authentication is performed. The connection is not established until you authenticate. The rad.auth module provides a utility class (RadAuth), which may be used to perform a PAM login. If you provide a username and password, authentication is non-interactive. If you do not provide username and password, you will receive a console prompt for the missing information.

Example 32  Python Language – Creating a RAD Remote Connection Over TLS
>>> import rad.connect as radcon
>>> import rad.auth as rada

>>> rc=radcon.connect_tls("host1")
>>> # Illustrate examining RadConnection state.
>>> print rc
<open RadConnection >
>>> auth = rada.RadAuth(rc)
>>> auth.authenticate("jdoe", "xxxpasswordxxx")
>>> <now authenticated and can use this connection>
>>> rc.close()
>>> print rc
<closed RadConnection >
>>> 

RAD is deployed as two cooperating processes. A proxy process is responsible for authentication and establishing communications. A slave process is created by the proxy and handles module processing. A slave is created for each client connection.

Connecting to a RAD Instance by Using a URI in Python

You can use a URI to connect to a local or remote RAD instance. You can use the class RadURI() to connect to a RAD instance. The methods or functions are not required in Python because you can read the attributes of the RAD instances that you create instead of using defined methods. For more information, see Connecting in Python to a RAD Instance by Using a URI.

The following constructor is supported.

def __init__(self, src, schemes = RAD_SCHEMES):
src

String, which is the URI of a RAD instance

schemes

List of strings that specify the schemes to be recognized

The following method is supported:

def connect(self, cred = None):
cred

Credentials that are required for authentication

You can use PAMCredentials class to create PAM credentials for PAM authentication or you can use def get_pam_cred(passw) function, which returns a PAMCredentials object for use in the RadURI.connect() method.

RAD Namespace in Python

Most RAD objects that are represented in the ADR document as <interfaces>. You can find RAD objects by searching the RAD namespace. To access a RAD object, you need a proxy, which is used to search the RAD namespace. An interface proxy class enables you to use a proxy to search the RAD namespace. The interface proxy is defined in the binding module of each interface.

The proxy provides the base name and version details for interface instances and is structured as follows:

<domain name>:type=<interface name>[,optional additional key value pairs]

The <domain name> and the <interface name> are automatically derived from the ADR IDL definition and are stored in the module binding.

Certain interfaces return or accept object references directly to or from clients. These objects might not be named. Objects that are not named are anonymous. Anonymous objects cannot be looked up in the RAD namespace, but the interface provides access methods that make it simple to interact with them.

Creating a Name for a RAD Object in Python

The RAD object names are structured, consisting of a domain and one or more key-value pairs.

For example, you can create a name for a zonemgr zone instance as follows:

>>> ADRName("com.oracle.solaris.rad.zonemgr", { "type": "Zone",
               "name" : "radtest-zone", "id" : "1" })

When you create a name, you can handle key-value pairs. This removes any issues in processing names where values contain special characters (for example, commas (,), and equal signs (=).

The RADConnection class provides methods for listing objects by name and for obtaining a remote object reference.

RAD Singletons in Python

A module developer creates a singleton to represent an interface. This interface can be accessed easily. For example, the zonemgr module defines a singleton interface, ZoneInfo. It contains information about the zone that contains the RAD instance with which you are communicating.

Example 33  Python Language – Obtaining a Reference to a RAD Singleton
>>> import rad.bindings.com.oracle.solaris.rad.zonemgr as zonemgr
>>> import rad.connect as radcon
>>> with radcon.connect_unix() as rc:
...     zi = rc.get_object(zonemgr.ZoneInfo())
...     print zi.name
...
global
>>>

In this example, you have imported the RAD bindings and the rad.connect module, and connected to the local RAD instance. After connecting to the local RAD instance, obtain a remote object reference directly by using a proxy instance. After you have the remote reference, you can access properties and methods directly as you would with any Python object.

Listing RAD Instances of an Interface in Python

An interface can contain multiple RAD instances. For example, the zonemgr module defines a Zone interface and there is an instance for each zone on the system. The RADConnection class provides the list_objects() method to list the interface instances as shown in the following example.

Example 34  Python Language – Listing RAD Interface Instances
>>> import rad.bindings.com.oracle.solaris.rad.zonemgr as zonemgr
>>> import rad.connect as radcon
>>> with radcon.connect_unix() as rc:
... zonelist = rc.list_objects(zonemgr.Zone())
... print zonelist
... 
[Name: com.oracle.solaris.rad.zonemgr:type=Zone,name=test-0,id=-1 Version: (1.0), Name: 
com.oracle.solaris.rad.zonemgr:type=Zone,name=test-1,id=-1 Version: (1.0), Name: 
com.oracle.solaris.rad.zonemgr:type=Zone,name=NOT-TEST,id=-1 Version: (1.0)]
>>>

Obtaining a RAD Remote Object Reference From a Name in Python

Names (ADRName is the class name) are returned by the RADConnection list_objects method. Once you have a name, you can obtain a remote object reference easily.

Example 35  Python Language – Obtaining a RAD Remote Object Reference
>>> import rad.bindings.com.oracle.solaris.rad.zonemgr as zonemgr
>>> import rad.connect as radcon
>>> with radcon.connect_unix() as rc:
... zonelist = rc.list_objects(zonemgr.Zone())
... zone = rc.get_object(zonelist[0])
... print zone.name
... 
test-0
>>>

You can get values of individual components of an ADRName object by using the dot notation nameObj.key or by using the getattr(nameObj, key)() function call.

zonelist[0].name

Sophisticated RAD Searches in Python

You can search for a zone by its name or ID or a set of zones by pattern matching. You can extend the basic definition of a name provided by a proxy. For example, if zones are uniquely identified by the key name, then you can find a zone with the name test-0 as shown in the following example. The example uses glob patterns to find a zone.

Example 36  Python Language – Using Glob Patterns
>>> 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:
... zonelist = rc.list_objects(zonemgr.Zone(), radc.ADRGlobPattern({"name" : "test-0"}))
... print zonelist
... 
[Name: com.oracle.solaris.rad.zonemgr:type=Zone,name=test-0,id=-1 Version: (1.0)]
>>> 

In this example, the ADRGlobPattern class (imported from the rad.client module) is used to refine the search. The list_objects() method from the RADConnection class is used, but the search is refined by extending the name definition. The ADRGlobPattern class takes a key:value dictionary and extends the name used for the search.

Glob Pattern Searching in RAD in Python

You can use a glob pattern to find zones with wildcard pattern matching. Keys and values in the pattern may contain an asterisk (*), which is interpreted as wildcard pattern matching. The following example shows how to find all zones with a name which begins with test.

Example 37  Python Language – Using Glob Patterns With Wildcards in RAD
>>> 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:
... zonelist = rc.list_objects(zonemgr.Zone(), radc.ADRGlobPattern({"name" : "test*"})) 
...  print zonelist
... 
[Name: com.oracle.solaris.rad.zonemgr:type=Zone,name=test-0,id=-1 Version: (1.0), Name:
com.oracle.solaris.rad.zonemgr:type=Zone,name=test-1,id=-1 Version: (1.0)]
>>> 
Regex Pattern Searching in RAD in Python

You can also use ERE search capabilities of RAD. The following example shows how to find only zones with name test-0 or test-1.

Example 38  Python Language – Using Regex Patterns in RAD
>>> 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:
... zonelist = rc.list_objects(zonemgr.Zone(), radc.ADRRegexPattern({"name" : "test-0|test-1"}))
...  print zonelist... 
[Name: com.oracle.solaris.rad.zonemgr:type=Zone,name=test-0,id=-1 Version: (1.0), Name:
com.oracle.solaris.rad.zonemgr:type=Zone,name=test-1,id=-1 Version: (1.0)]
>>> 

The key and the value must be valid EREs as determined by the instance of RAD to which you are connected. The expression is compiled and executed on the server.

RAD Interface Components in Python

    An API is defined by a module developer. It contains one or more of the following components, each of which performs a task:

  • Enumerations

    • Values

  • Structures

    • Fields

  • Dictionary

  • Interfaces

    • Properties

    • Methods

    • Events

These components are defined in an ADR IDL document. The radadrgen utility is used to process the document to generate language specific components which facilitate client-server interactions within RAD. For more information about the role of ADR and RAD, see Chapter 2, Abstract Data Representation for RAD in Remote Administration Daemon Module Developer’s Guide. Brief descriptions of each component follows.

RAD Enumerations in Python

Enumerations are primarily used to offer a restricted range of choices for a property, an interface method parameter, result, or error.

Using RAD Enumeration Types in Python

To access an enumerated type, import the binding and interact with the enumeration.

Example 39  Python Language – Using RAD Enumerations
>>> import rad.bindings.com.oracle.solaris.rad.zonemgr as zonemgr
>>> print zonemgr.ErrorCode.NONE
NONE
>>> print zonemgr.ErrorCode.COMMAND_ERROR
COMMAND_ERROR
>>>

RAD Structure Types in Python

Structures, or "structs", are used to define new types and are composed from existing built-in types and other user defined types. Structs are simple form of interfaces with no methods or events. They are not included in the RAD namespace.

Using RAD Structs in Python

The zonemgr module defines a Property struct which represents an individual zone configuration property. The structure has the following members: name, type, value, value, listValue, and complexValue. Like enumerations, structures can be interacted with directly once the binding is imported.

Example 40  Python Language – Using RAD 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
>>> 

Dictionary Support in Python for RAD

You can use the built-in dictionary type in Python. For example, the following Python code sets the sample dictionary property as defined in Defining a Dictionary for RAD in Remote Administration Daemon Module Developer’s Guide:

object.DictProp = {1: 'value1', 2: 'value2'}

RAD Interfaces in Python

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.

Obtaining a RAD Object Reference in Python

See the RAD Namespace in Python section.

Working With RAD Object References in Python

Once you have an object reference, you can use this object reference to interact with RAD directly. All attributes and methods defined in the IDL are accessible directly as Python object attributes that are returned by the get_object() function.

The following example gets a reference to a zone and then boots the zone.

Example 41  Python Language – Working With RAD 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 this example, you have connected to the RAD instance, created a search for a specific object, retrieved a reference to the object, and accessed a remote property on it. No error handling occurred.

Accessing a RAD Remote Property in Python

The following example shows how to access a remote property.

Example 42  Python Language – Accessing a Remote RAD 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, you have accessed the list of global resource properties of the Zone and searched the list of properties for the brand property. When you find it, print the value of the brand property and then terminate the loop.

RAD Event Handling in Python

This example shows how to subscribe to and handle 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 43  Python Language – Subscribing to and Handling RAD Events
import 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()

In this example, you have subscribed to a single event by passing a handler and a reference to the ZoneManager object. The handler is invoked asynchronously by the framework with various event details and user data. The user data is an optional argument at subscription. If the user data is not provided, the handler receives None as the user parameter.

Python Error Handling in RAD

Python provides a exception handling mechanism and propagates RAD errors by using this mechanism. RAD delivers a variety of error codes that you can handle with rad.client.ObjectError. The following example shows how to handle RAD errors.

Example 44  Python Language – Handling RAD Errors
import 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)

Note -  With ObjectError exceptions, you might get a payload. This payload is present only if your interface method or property has defined an error element, where the payload is the content of that error. If no error element for the interface method (or property) is declared, then no payload exists and error will have a value of None.

Connecting in Python to a RAD Instance by Using a URI

You can use the standard URI format to connect to a RAD instance. The URI format is as follows:

scheme://user?@host:port?auth=value
scheme

(Mandatory) The supported schemes are unix, rad, rads, and ssh.

user

(Optional) The user who is connecting to the remote RAD instance. If you do not specify the user, the current user is assumed.

host

(Mandatory) The system that contains the remote RAD instance.

port

(Optional) The port number. The default port is 12302 (RAD IANA port).

auth

(Optional) The authentication method that is used to connect to the remote RAD instance. The supported values are pam and gss. If you do not specify the authentication, then pam is assumed. If you are using SSH as the transport protocol, you must not specify the authentication mechanism.

Example 45  Python Language – Connecting to a RAD Instance by Using a URI

The following example shows how to open a TCP connection as jdoe to the host abc at port 10000 with default authentication.

rads://jdoe@abc.example.com:10000

The following example shows how to open a TLS connection as hg to the host abc at the default RAD port with gss authentication.

radg://hg@abc.example.com?auth=gss

The following example shows how to open an SSH connection as the current user to the host abc at the default SSH port.

ssh://abc.example.com

The following example shows how to open a connection to a local RAD instance.

unix:///path