Remote Administration Daemon Developer Guide

Exit Print View

Updated: July 2014
 
 

Interface Components

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 an 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

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

Using Enumeration Types

Enumerated types are defined in the binding header with the type prepended with the module name. Values are prepended to follow (as closely as possible) the C coding standard naming conventions.

Example 3-9  zonemgr ErrorCode Enumeration
typedef enum zonemgr_ErrorCode {
     ZEC_NONE =0,
     ZEC_FRAMEWORK_ERROR = 1,
     ZEC_SNAPSHOT_ERROR = 2,
     ZEC_COMMAND_ERROR = 3,
     ZEC_RESOURCE_ALREADY_EXISTS = 4,
     ZEC_RESOURCE_NOT_FOUND = 5,
     ZEC_RESOURCE_TOO_MANY = 6,
     ZEC_RESOURCE_UNKNOWN = 7,
     ZEC_ALREADY_EDITING = 8,
     ZEC_PROPERTY_UNKNOWN = 9,
     ZEC_NOT_EDITING = 10,
     ZEC_SYSTEM_ERROR = 11,
     ZEC_INVALID_ARGUMENT = 12,
     ZEC_INVALID_ZONE_STATE = 13,
}zonemgr_ErrorCode_t;

Structs

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.

Using Struct Types

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 are defined in the binding header and follow similar naming conventions.

To free a structure, free functions (<module>_<structure>_free()) are provided by the binding to ensure proper cleanup of any memory held by nested data.

Example 3-10  The zonemgr Property Struct Definition and its Free Function
typedef enum zonemgr_PropertyValueType {
     ZPVT_PROP_SIMPLE = 0,
     ZPVT_PROP_LIST = 1,
     ZPVT_PROP_COMPLEX = 2,
} zonemgr_PropertyValueType_t;

typedef struct zonemgr_Property {
 char * zp_name;
 char * zp_value;
 zonemgr_PropertyValueType_t zp_type;
 char * * zp_listvalue;
 int zp_listvalue_count;
 char * * zp_complexvalue;
 int zp_complexvalue_count;
} zonemgr_Property_t;

void zonemgr_Property_free(zonemgr_Property_t *);

Interfaces/Objects

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 an Object Reference

See the Rad Namespace section.

Working with Object References

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 by invoking calling functions in the generated client binding.

Here is an example which gets a reference to a zone and then boots the zone.

Example 3-11   Working with Object References
#include <rad/radclient.h>
#include <rad/radclient_basetypes.h>
#include <rad/client/1/zonemgr.h>

rc_err_t status;
rc_instance_t *zone_inst;
zonemgr_Result_t *result;
zonemgr_Result_t *error;

rc_conn_t *conn = rc_connect_unix(NULL, B_TRUE, NULL);
if (conn != NULL) {
     status = zonemgr_Zone__rad_lookup(conn, B_TRUE, &zone_inst, 1, "name", "test-0");
     if (status == RCE_OK) {
          status = zonemgr_Zone_boot(zone_inst, NULL, 0, &result, &error);
          rc_instance_rele(zone_inst);
      }
}
Accessing a Remote Property

Here is an example for accessing a remote property.

Example 3-12   Accessing a Remote Property
#include <rad/radclient.h>
#include <rad/radclient_basetypes.h>
#include <rad/client/1/zonemgr.h>

rc_err_t status;
rc_instance_t *zone_inst;
char *name;
zonemgr_Property_t *result;
zonemgr_Result_t *error;
int result_count;

rc_conn_t *conn = rc_connect_unix(NULL, B_TRUE, NULL);
if (conn != NULL) {
         status = zonemgr_Zone__rad_lookup(conn, B_TRUE, &zone_inst, 1, "name", "test-0");
         if (status == RCE_OK) {
            zonemgr_Resource_t global = { .zr_type = "global"};
            status = zonemgr_Zone_getResourceProperties(zone_inst, &global, NULL, 0, &result, &result_count, &error); 
            if (status == RCE_OK) {
                    for (int i = 0; i < result_count; i++){
                            if (result[i].zp_value != NULL && result[i].zp_value[0] != '\0')
                                    printf("%s=%s\n", result[i].zp_name, result[i].zp_value);
                    }
                    zonemgr_Property_array_free(result, result_count);
            }
            rc_instance_rele(zone_inst);
         }
}

In this example, we accessed the list of Zone global resource properties and printed out the name and value of every Property that has a value.

RAD Event Handling

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-13   Subscribing and Handling Events
#include <unistd.h>
#include <time.h>
#include <rad/radclient.h>
#include <rad/radclient_basetypes.h>
#include <rad/client/1/zonemgr.h>

void stateChange_handler(rc_instance_t *inst, zonemgr_StateChange_t *payload, struct timespec timestamp, void *arg)
{       
    printf("event: zone state change\n");
    printf("payload:\n zone: %s\n old state: %s\n new state: %s\n",
    payload->zsc_zone, payload->zsc_oldstate, payload->zsc_newstate);
       
    zonemgr_StateChange_free(payload);
}

rc_err_t status;
rc_instance_t *zm_inst;
int result_count;

rc_conn_t *conn = rc_connect_unix(NULL, B_TRUE, NULL);
if (conn != NULL) {
        status = zonemgr_ZoneManager__rad_lookup(conn, B_TRUE, &zm_inst, 0);
        if (status == RCE_OK) {
            status = zonemgr_ZoneManager_subscribe_stateChange(zm_inst, stateChange_handler, NULL);
            if (status == RCE_OK)
                printf("Successfully subscribed to statechange event!\n");
            rc_instance_rele(zm_inst);
        }
 }
 for (;;)
 sleep(1);

This is a simple example. We subscribe to the single event and pass in a handler and a handle for 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 in this case being NULL).

RAD Error Handling

Finally, a quick look at error handling when manipulating remote references. The list of possible errors is defined by the enum rc_err_t(). There are a variety of errors which can be delivered by RAD, but the one which potentially requires additional handling is the rc_err_t() value RCE_SERVER_OBJECT. The following snippet, shows how it can be used:

Example 3-14  Handling RAD Errors
#include <rad/radclient.h>
#include <rad/radclient_basetypes.h>
#include <rad/client/1/zonemgr.h>

rc_err_t status;
rc_instance_t *zone_inst;
zonemgr_Result_t *result;
zonemgr_Result_t *error;

rc_conn_t *conn = rc_connect_unix(NULL, B_TRUE, NULL);
if (conn != NULL) {
      status = zonemgr_Zone__rad_lookup(conn, B_TRUE, &zone_inst, 1, "name", "test-0");
     if (status == RCE_OK) {
             status = zonemgr_Zone_boot(zone_inst, NULL, 0, &result, &error);
            if (status == RCE_SERVER_OBJECT) {
                 printf("Error Code %d\n", error->zr_code);
                    if (error->zr_stdout != NULL)
                         printf("stdout: %s\n", error->zr_stdout);
                     if (error->zr_stderr != NULL)
                         printf("stderr: %s\n", error->zr_stderr);
                      zonemgr_Result_free(error);
                }
                rc_instance_rele(zone_inst);
        }
}

Note -  With an rc_err_t value of RCE_SERVER_OBJECT you may get a payload. This is only present if your interface method or property has defined an "error" element, in which case the payload is the content of that error. If there is no "error" element for the interface method (or property), then there is no payload and there will be no error reference argument for the method or property get/set functions.