Table of Contents Previous Next
Logo
The Ice Run Time in Detail : 32.19 Administrative Facility
Copyright © 2003-2009 ZeroC, Inc.

32.19 Administrative Facility

Ice applications often require remote administration, such as when an IceGrid node needs to gracefully deactivate a running server. The Ice run time provides an extensible, centralized facility for exporting administrative functionality. This facility consists of an object adapter named Ice.Admin, an Ice object activated on this adapter, and configuration properties that enable the facility and specify its features.

32.19.1 The admin Object

The Ice.Admin adapter hosts a single object whose identity name is admin. Although this identity name cannot be changed, you can define the identity category using the configuration property Ice.Admin.InstanceName (see Appendix C). If you enable the Ice.Admin adapter without defining this property, the category uses a UUID by default and therefore the object’s identity changes with each instance of the process.
In this book, we refer to the administrative object as the admin object.

Facets

As explained in Chapter 34, an Ice object is actually a collection of sub-objects known as facets whose types are not necessarily related. Although facets are typically used for extending and versioning types, they also allow a group of interfaces with a common purpose to be consolidated into a single Ice object with an established interface for navigation. These qualities make facets an excellent match for the requirements of the administrative facility.
Each facet of the admin object represents a distinct administrative capability. The object does not have a default facet (that is, a facet with an empty name). However, the Ice run time implements two built-in facets that it adds to the admin object:
• Process, described in Section 32.19.4
• Properties, described in Section 32.19.5
An application can control which facets are installed with a configuration property (see Section 32.19.6). An application can also install its own facets if necessary (see Section 32.19.7). Administrative facets are not required to inherit from a common Slice interface.

32.19.2 Enabling the Object Adapter

The administrative facility is disabled by default. To enable it, you must specify endpoints for the administrative object adapter using the property Ice.Admin.Endpoints. In addition, you must do one of the following:
• Define the Ice.Admin.InstanceName property.
• Define the Ice.Admin.ServerId and Ice.Default.Locator properties. If you do not supply a value for Ice.Admin.InstanceName, Ice uses a UUID by default.
The Ice.Admin.ServerId and Ice.Default.Locator properties are typically used in conjunction with an activation service such as IceGrid, as discussed in Section 39.21.
The endpoints for the Ice.Admin adapter must be chosen with caution. Section 32.19.8 addresses the security considerations of using the administrative facility.
It may be necessary to postpone the creation of the administrative object adapter until all facets are installed or other initialization activities have taken place. In this situation, you can define the following configuration property:
Ice.Admin.DelayCreation=1
When this property is set to a non-zero value, the administrative facility is disabled until the application invokes the getAdmin operation on the communicator (see Section 32.19.3).

32.19.3 Using the admin Object

A program can obtain a proxy for its admin object by calling the getAdmin operation on a communicator:
module Ice {
local interface Communicator {
    // ...
    Object* getAdmin();
};
};
This operation returns a null proxy if the administrative facility is disabled. The proxy returned by getAdmin cannot be used for invoking operations because it refers to the default facet and, as we mentioned previously, the admin object does not support a default facet. A program must first obtain a new version of the proxy that is configured with the name of a particular administrative facet before invoking operations on it. Although it cannot be used for invocations, the original proxy is still useful because it contains the endpoints of the Ice.Admin object adapter and therefore the program may elect to export that proxy to a remote client.

Remote Administration

To administer a program remotely, somehow you must obtain a proxy for the program’s admin object. There are several ways for the administrative client to accomplish this:
• Construct the proxy itself, assuming that it knows the admin object’s identity, facets, and endpoints. The format of the stringified proxy is as follows:
instance-name/admin -f admin-facet:admin-endpoints
The identity category, represented here by instance-name, is the value of the Ice.Admin.InstanceName property or a UUID if that property is not defined. (Clearly, the use of a UUID makes the proxy much more difficult for a client to construct on its own.) The name of the administrative facet is supplied as the value of the -f option, and the endpoints of the Ice.Admin adapter appear last in the proxy. See Appendix D for more information on stringified proxies.
• Invoke an application-specific interface for retrieving the admin object’s proxy.
• Use the getServerAdmin operation on the IceGrid::Admin interface, if the remote program was activated by IceGrid (see Section 39.21.3).
Having obtained the proxy, the administrative client must select a facet before invoking any operations. For example, the code below shows how to obtain the configuration properties of the remote program:
// C++
Ice::ObjectPrx adminObj = ...;
Ice::PropertiesAdminPrx propAdmin =
    Ice::PropertiesAdminPrx::checkedCast(adminObj,
                                         "Properties");
Ice::PropertyDict props = propAdmin>getPropertiesForPrefix("");
Here we used an overloaded version of checkedCast to supply the facet name of interest (Properties). We could have selected the facet using the proxy method ice_facet instead, as shown below:
// C++
Ice::ObjectPrx adminObj = ...;
Ice::PropertiesAdminPrx propAdmin =
    Ice::PropertiesAdminPrx::checkedCast(
        adminObj>ice_facet("Properties"));
Ice::PropertyDict props = propAdmin>getPropertiesForPrefix("");
This code is functionally equivalent to the first example.
A remote client must also know (or be able to determine) which facets are available in the target server. Typically this information is statically configured in the client, since the client must also know the interface types of any facets that it uses. If an invocation on a facet raises FacetNotExistException, the client may have used an incorrect facet name, or the server may have disabled the facet in question.

32.19.4 The Process Facet

An activation service, such as an IceGrid node (see Chapter 39), needs a reliable way to gracefully deactivate a server. One approach is to use a platform-specific mechanism, such as POSIX signals. This works well on POSIX platforms when the server is prepared to intercept signals and react appropriately (see Section 31.12). On Windows platforms, it works less reliably for C++ servers, and not at all for Java servers. For these reasons, the Process facet provides an alternative that is both portable and reliable.
Section 32.19.8 discusses the security risks associated with enabling the Process facet.

Interface

The Slice interface Ice::Process allows an activation service to request a graceful shutdown of the program:
module Ice {
interface Process {
    ["ami"] void shutdown();
    void writeMessage(string message, int fd);
};
};
When shutdown is invoked, the object implementing this interface is expected to initiate the termination of its process. The activation service may expect the program to terminate within a certain period of time, after which it may terminate the program abruptly.
The writeMessage operation allows remote clients to print a message to the program’s standard output (fd == 1) or standard error (fd == 2) channels.

Application Requirements

The default implementation of the Process facet requires cooperation from an application in order to successfully terminate a process. Specifically, the facet invokes shutdown on its communicator and assumes that the application uses this event as a signal to commence its termination procedure. For example, an application typically uses a thread (often the main thread) to call the communicator operation waitForShutdown, which blocks the calling thread until the communicator is shut down or destroyed. After waitForShutdown returns, the calling thread can initiate a graceful shutdown of its process.
Refer to Section 32.2 for more information on the communicator operations shutdown and waitForShutdown.

Replacing the Process Facet

You can replace the default Process facet if your application requires a different scheme for gracefully shutting itself down. To define your own facet, create a servant that implements the Ice::Process interface. As an example, the servant definition shown below duplicates the functionality of the default Process facet:
class ProcessI : public Ice::Process {
public:
    ProcessI(const Ice::CommunicatorPtr& communicator) :
        _communicator(communicator)
    {}

    void shutdown(const Ice::Current&)
    {
        _communicator>shutdown();
    }

    void writeMessage(const string& msg, Ice::Int fd,
                      const Ice::Current&)
    {
        if(fd == 1) cout << msg << endl;
        else if(fd == 2) cerr << msg << endl;
    }

private:
    const Ice::CommunicatorPtr _communicator;
};
As you can see, the default implementation of shutdown simply shuts down the communicator, which initiates an orderly termination of the Ice run time’s server-side components and prevents object adapters from dispatching any new requests. You can add your own application-specific behavior to the shutdown method to ensure that your program terminates in a timely manner.
Note: As explained in Section 32.2, a servant must not invoke destroy on its communicator while executing a dispatched operation.
To avoid the risk of a race condition, the recommended strategy for replacing the Process facet is to delay creation of the administrative facets so that your application has a chance to replace the facet:
Ice.Admin.DelayCreation=1
With this property defined, the application can safely remove the default Process facet and install its own:
// C++
Ice::CommunicatorPtr communicator = ...
communicator->removeAdminFacet("Process");
Ice::ProcessPtr myProcessFacet = new MyProcessFacet(...);
communicator->addAdminFacet(myProcessFacet, "Process");
The final step is to activate the administrative facility by calling getAdmin on the communicator:
communicator->getAdmin();

Integration with an Activation Service

If the Ice.Admin.ServerId and Ice.Default.Locator properties are defined, the Ice run time performs the following steps after creating the Ice.Admin adapter:
• Obtains proxies for the Process facet and the default locator
• Invokes getRegistry on the proxy to obtain a proxy for the locator registry
• Invokes setServerProcessProxy on the locator registry and supplies the value of Ice.Admin.ServerId along with a proxy for the Process facet
The identifier specified by Ice.Admin.ServerId must uniquely identify the process within the locator registry.
In the case of IceGrid, the node defines the Ice.Admin.ServerId and Ice.Default.Locator properties for each deployed server. The node also supplies a value for Ice.Admin.Endpoints if the property is not defined by the server. See Chapter 39 for more information.

32.19.5 The Properties Facet

An administrator may find it useful to be able to view the configuration properties of a remote Ice application. For example, the IceGrid administrative tools allow you to query the properties of active servers. The Properties facet supplies this functionality.

Interface

The Ice::PropertiesAdmin interface provides access to the communicator’s configuration properties:
module Ice {
interface PropertiesAdmin {
    ["ami"] string getProperty(string key);
    ["ami"] PropertyDict getPropertiesForPrefix(string prefix);
};
};
The getProperty operation retrieves the value of a single property, and the getPropertiesForPrefix operation returns a dictionary of properties whose keys match the given prefix. These operations have the same semantics as those in the Ice::Properties interface described in Section 30.8.1.

32.19.6 Filtering Facets

The Ice run time enables all of its built-in administrative facets by default, and an application may install its own facets. You can control which facets the Ice run time enables using the Ice.Admin.Facets property. For example, the following property definition enables the Properties facet and leaves the Process facet (and any application-defined facets) disabled:
Ice.Admin.Facets=Properties
To specify more than one facet, separate them with a comma or white space. A facet whose name contains white space must be enclosed in single or double quotes.

32.19.7 Custom Facets

An application can add and remove administrative facets using the Communicator operations shown below:
module Ice {
local interface Communicator {
    // ...
    void addAdminFacet(Object servant, string facet);
    Object removeAdminFacet(string facet);
};
};
The addAdminFacet operation installs a new facet with the given name, or raises AlreadyRegisteredException if a facet already exists with the same name. The removeAdminFacet operation removes (and returns) the facet with the given name, or raises NotRegisteredException if no matching facet is found.
The mechanism for filtering administrative facets described in Section 32.19.6 also applies to application-defined facets. If you call addAdminFacet while a filter is in effect, and the name of your custom facet does not match the filter, the Ice run time will not expose your facet but instead keeps a reference to it so that a subsequent call to removeAdminFacet is possible.

32.19.8 Security Considerations

Exposing administrative functionality naturally makes a program vulnerable, therefore it is important that proper precautions are taken.

Issues

With respect to the default functionality, the Properties facet could expose sensitive configuration information, and the Process facet supports a shutdown operation that opens the door for a denial-of-service attack.
Developers should carefully consider the security implications of any additional administrative facets that an application installs.

Remedies

There are several approaches you can take to mitigate the possibility of abuse:
• Disable the administrative facility
The administrative facility is disabled by default, and remains disabled as long as the prerequisites listed in Section 32.19.2 are not met. Note that IceGrid enables the facility in servers that it activates for the following reasons:
The Process facet allows the IceGrid node to gracefully terminate the process.
The Properties facet enables IceGrid administrative clients to obtain configuration information about activated servers.
You could disable a facet using filtering, but doing so may disrupt IceGrid’s normal operation.
• Select a proper endpoint
A reasonably secure value for the Ice.Admin.Endpoints property is one that uses the local host interface (-h 127.0.0.1), which restricts access to clients that run on the same host. Incidentally, this is the default value that IceGrid defines for its servers, although you can override that if you like. Note that using a local host endpoint does not preclude remote administration for IceGrid servers because IceGrid transparently routes requests on admin objects to the appropriate server via its node (see Section 39.21.3).
If your application must support administration from non-local hosts, we recommend the use of SSL and certificate-based access control (see Chapter 42).
• Filter the facets
After choosing a suitable endpoint, you can minimize risks by filtering the facets to enable only the functionality that is required. For example, if you are not using IceGrid’s server activation feature and do not require the ability to remotely terminate a program, you should disable the Process facet using the mechanism described in Section 32.19.6.
• Consider the object’s identity
The default identity of the admin object has a UUID for its category, which makes it difficult for a hostile client to guess. Depending on your requirements, the use of a UUID may be an advantage or a disadvantage. For example, in a trusted environment, the use of a UUID may create additional work, such as the need to add an interface that an administrative client can use to obtain the identity or proxy of a remote admin object. An obscure identity might be more of a hindrance in this situation, and therefore specifying a static category via the Ice.Admin.InstanceName property is a reasonable alternative. In general, however, we recommend using the default behavior.
Table of Contents Previous Next
Logo