JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Remote Administration Daemon Developer Guide     Oracle Solaris 11.1 Information Library
search filter icon
search icon

Document Information

Preface

1.  Introduction

2.  Concepts

3.  Abstract Data Representation

4.  libadr

5.  Client Libraries

6.  Module Development

7.  rad Best Practices

When To Use rad?

How To Use rad?

API Guidelines

Target Audience

Legacy Constraints

Conservative Design

Component Guidelines

API Guidelines

Method Guidelines

Property Guideline

Event Guidelines

Module Location: Deciding between Proxy or Slave

Synchronous and Asynchronous Invocation

Duplication

Client Library Support

Naming Guidelines

Object Names

Case

Language-Specific Considerations

API Design Examples

User Management Example

A.  rad Binary Protocol

How To Use rad?

This section contains specific guidance on how to use rad.

API Guidelines

Designing a rad API requires judgement and the application of domain knowledge.

Target Audience

The users of the API fall into two broad categories:

Unfortunately, accommodating the desires of consumers in these two categories within one interface is difficult. The first group desire task-based APIs which match directly onto well-understood and defined administrative activities. The second group desire detailed, operation-based interfaces which may be aggregated to better support unusual or niche administrative activities.

For any given subsystem, you can view existing command-line utilities (CLIs) and libraries (APIs) as expressions of the rad APIs which are required. The CLIs represent the task-based administrative interfaces and the APIs represent the operation-based developer interfaces.

The goal in using rad is to provide interfaces that address the lowest-level objectives of the target audience. If targeting administrators (task-based), this effort could translate to matching existing CLIs. If targeting developers, this effort could mean significantly less aggregation of the lower-level APIs.

Legacy Constraints

Many subsystems present incomplete interfaces to the world. Some CLIs contain processing capabilities that are not accessible from an existing API. This situation is another motivation for providing task-based administrative interfaces before introducing more detailed interfaces.

Such constraints must be considered in the rad API design. Consider migrating functionality from the CLI into the API to facilitate the creation of the new interface. Also consider presenting an interface which wraps the CLI and takes advantage of the existing functionality. Do not simply duplicate the functionality in the new rad interface, which would introduce redundancy and significantly increase maintenance complexity. One particular area where rad interface developers need to be careful is to avoid duplication around parameter checking and transformation. This duplication is likely to be a sign that existing CLI functionality should be migrated to an API.

rad modules must be written in C. Some subsystems, for instance, those written in other languages, have no mechanism for a C module to access API functionality. In these cases, rad module creators must access whatever functionality is available in the CLI or make a potentially significant engineering effort to access the existing functionality, for example, rewriting existing code in C, embedding a language interpreter in their C module, and the like.

Conservative Design

Designing a rad interface is very similar to designing a library interface. The same general principles of design apply: be conservative, start small, consider evolutionary paths and carefully consider commitment levels.

Once an interface is established, the use of versioning and considered, incremental improvements will expand the functionality.

Component Guidelines

This section presents specific design advice on the most significant components of a rad module. Naming is addressed separately in Naming Guidelines

API Guidelines

APIs are the primary deliverable of a rad module. They are a grouping of interfaces, events, methods and properties which enable a user to interact with a subsystem.

When exposing the elements of a subsystem consider carefully how existing functions can be grouped together to form an interface. Imperative languages, such as C, tend to pass structures as the first argument to functions, which provides a clear indicator as to how best to group functions into APIs.

Method Guidelines

Methods provide mechanisms for examining and modifying administrative state.

Consider grouping together existing native APIs into aggregated rad functions which enable higher order operations to be exposed.

Follow established good practice for RPC style development. rad is primarily for remote administration, and avoiding excessive network load is good practice.

Property Guideline

Make sure to define an <error> element with properties which can be modified.

Event Guidelines

The module is responsible for providing a sequence number. Monotonically increasing sequence numbers are recommended for use, since these will be of most potential use to any clients.

Consider providing mechanisms for allowing a client to throttle event generation.

Carefully design event payloads to minimize network load.

Don't try to replicate the functionality of network monitoring protocols such as SNMP.

Module Location: Deciding between Proxy or Slave

Judicious use of the is_proxy variable enables you to control where a module is loaded for execution: in the rad proxy or in a slave process.

A module should, by default, be loaded into a slave process unless the following conditions apply:

Synchronous and Asynchronous Invocation

All method invocations in rad are synchronous. Asynchronous behavior can be obtained by adopting a design pattern that relies on the use of events to provide notifications. Refer to Synchronization for more details.

Duplication

Do not duplicate code from existing CLIs. Instead, consider moving common code into a lower library layer that can be shared by rad and the CLI.

Client Library Support

rad modules are designed to have a language agnostic interface. However, you might want to provide additional language support through the delivery of a language-specific extension. This type of deliverables should be restricted in use. The main reason for their existence is to help improve the fit of an interface into a language idiom.

Naming Guidelines

When naming an API, interface, or object, module developers have broad leeway to choose names that make sense for their modules. However, some conventions can help avoid pitfalls that might arise when retrieving objects from the rad server.

Object Names

The domain portion of rad object names follows a reverse-dotted naming convention that prevents collisions in rad's flat object namespace. This convention typically resembles a Java package naming scheme:

com.oracle.solaris.rad.zfs
com.oracle.solaris.rad.zonesmgt
com.oracle.solaris.rad.usermgt
org.opensolaris.os.rad.ips
...

To distinguish a rad API from a native API designed and implemented for a specific language, include a "rad." component in the API name.

With the goal of storing objects with names consumers would expect, APIs, and the domains of the objects defined within them, should share the same name. This practice makes the mapping between the two easily identifiable by both the module consumer and module developer.

With the same goal of simplicity, identifying an interface object is made easier by adhering to a "type=interface" convention within the object name.

Applying both conventions, a typical API will look like the following example.

<api 
  xmlns="http://xmlns.oracle.com/radadr"
  name="com.oracle.solaris.rad.zfs">

  <interface name="ZPool">
    <summary>
      zpool administration
    </summary>
    ...

Within the module, the API appears as follows:

int
_rad_init(void *handle)
{
    ...
    adr_name_t *name =
        adr_name_fromstr("com.oracle.solaris.rad.zfs:type=ZPool");
    (void) cont_insert_singleton(rad_container, name, &interface_ZPool_svr);

On the consumer side (Python), the API appears as follows:

import rad.client
import rad.util

# Create a connection
radconn = rad.util.connect_unix()

# Retrieve a ZPool object
zpool_name = rad.client.Name("com.oracle.solaris.rad.zfs",
    [("type", "ZPool")])
zpool = radconn.get_object(zpool_name)

Using this naming convention also precludes the need to specify a pragma to identify a package when generating Java interfaces because radadrgen(1) uses the API name as the Java package name by default.

Case

In an effort to normalize the appearance of like items across development boundaries, and to minimize the awkwardness in generated language-specific interfaces, several case strategies have been informally adopted.

Module
The base of the API/domain name. For a module describing an interface domain.prefix.base.xml, module spec files should be named base.xml, and the resulting shared library mod_base.so.

Examples:

  • /usr/lib/rad/apis/zfs.xml

  • /usr/lib/rad/module/mod_zfs.so

API
Reverse-dotted domain, all lowercase.

Examples:

  • com.oracle.solaris.rad.zfs

  • com.oracle.solaris.rad.zonemgt

Interface, struct, union, enum
Non-qualified, camel case, starting with uppercase.

Examples:

  • Time

  • NameService

  • LDAPConfig

  • ErrorCode

Enum value and fallback
Non-qualified, uppercase, underscores.

Examples:

  • CHAR

  • INVALID_TOKEN

  • REQUIRE_ALL

Interface property and method, struct field, event
Non-qualified, camel case, starting with lowercase.

Examples:

  • count

  • addHostName

  • deleteUser

Language-Specific Considerations

Though ADR is language-neutral, certain environments might have conventions that place additional constraints on interface design.

Currently known language-specific constraints:

A JMX MXBean Proxy has a single namespace for both methods defined by the interface, and derived methods used for accessing attributes defined by the interface. If a method defined by the interface has a name and signature that is consistent with the JavaBeans-style naming of a derived attribute-access method, then the Proxy will assume calls to it are attempts to access a foo attribute on the JMX object and will fail. For example:

public void setFoo(String s);
public int getFoo();
public boolean isFoo();

This constraint is not a limitation of Java or of JMX but of the Proxy implementation. The designer could choose not use the Proxy, or to use a Proxy implementation that does not have this limitation.