Table of Contents Previous Next
Logo
IceGrid : 39.14 Administrative Sessions
Copyright © 2003-2009 ZeroC, Inc.

39.14 Administrative Sessions

To access IceGrid’s administrative facilities from a program, you must first establish an administrative session. Once done, a wide range of services are at your disposal, including the manipulation of IceGrid registries, nodes, and servers; deployment of new components such as well-known objects; and dynamic monitoring of IceGrid events.
Note that an administrative session can be established with either the master or a slave registry replica, but a session with a slave replica is restricted to read-only operations; see Section 39.12 for more information.

39.14.1 Creating an Administrative Session

The Registry interface provides two operations for creating an administrative session:
module IceGrid {
    exception PermissionDeniedException {
        string reason;
    };

    interface Registry {
        AdminSession* createAdminSession(string userId,
                                         string password)
            throws PermissionDeniedException;

        AdminSession* createAdminSessionFromSecureConnection()
            throws PermissionDeniedException;

        idempotent int getSessionTimeout();

        // ...
    };
};
The createAdminSession operation expects a username and password and returns a session proxy if the client is allowed to create a session. By default, IceGrid does not allow the creation of administrative sessions. You must define the property IceGrid.Registry.AdminPermissionsVerifier with the proxy of a permissions verifier object to enable session creation with createAdminSession. The verifier object must implement the interface Glacier2::PermissionsVerifier (see Section 43.5.1).
The createAdminSessionFromSecureConnection operation does not require a username and password because it uses the credentials supplied by an SSL connection to authenticate the client (see Chapter 42). As with createAdminSession, you must configure the proxy of a permissions verifier object before clients can use createAdminSessionFromSecureConnection to create a session. In this case, the IceGrid.Registry.AdminSSLPermissionsVerifier property specifies the proxy of a verifier object that implements the interface Glacier2::SSLPermissionsVerifier (see Section 43.5.1).
As an example, the following code demonstrates how to obtain a proxy for the registry and invoke createAdminSession:
Ice::ObjectPrx base =
    communicator>stringToProxy("IceGrid/Registry");
IceGrid::RegistryPrx registry =
    IceGrid::RegistryPrx::checkedCast(base); 
string username = ...; 
string password = ...; 
IceGrid::AdminSessionPrx session; 
try { 
    session = registry>createAdminSession(username, password); 
} catch (const IceGrid::PermissionDeniedException & ex) { 
    cout << "permission denied:\n" << ex.reason << endl; 
}
The AdminSession interface provides operations for accessing log files (see Section 39.14.2) and establishing observers (see Section 39.14.3). Furthermore, two additional operations are worthy of your attention:
module IceGrid {
    interface AdminSession extends Glacier2::Session {
        idempotent void keepAlive();
        idempotent Admin* getAdmin();
        // ...
    };
};
If your program uses an administrative session indefinitely, you must prevent the session from expiring by invoking keepAlive periodically. You can determine the timeout period by calling getSessionTimeout on the Registry interface (see Section 39.11.1). Typically a program uses a dedicated thread for this purpose.
The getAdmin operation returns a proxy for the IceGrid::Admin interface, which provides complete access to the registry’s settings. For this reason, you must use extreme caution when enabling administrative sessions.

39.14.2 Log Files

IceGrid’s AdminSession interface provides operations for remotely accessing the log files of a registry, node, or server:
module IceGrid {
interface AdminSession extends Glacier2::Session {
    // ...

    FileIterator* openServerLog(string id, string path, int count)
        throws FileNotAvailableException, ServerNotExistException,
               NodeUnreachableException, DeploymentException;
    FileIterator* openServerStdErr(string id, int count)
        throws FileNotAvailableException, ServerNotExistException,
               NodeUnreachableException, DeploymentException;
    FileIterator* openServerStdOut(string id, int count)
        throws FileNotAvailableException, ServerNotExistException,
               NodeUnreachableException, DeploymentException;

    FileIterator* openNodeStdErr(string name, int count)
        throws FileNotAvailableException, NodeNotExistException,
               NodeUnreachableException;
    FileIterator* openNodeStdOut(string name, int count)
        throws FileNotAvailableException, NodeNotExistException,
               NodeUnreachableException;

    FileIterator* openRegistryStdErr(string name, int count)
        throws FileNotAvailableException,
               RegistryNotExistException,
               RegistryUnreachableException;
    FileIterator * openRegistryStdOut(string name, int count)
        throws FileNotAvailableException,
               RegistryNotExistException,
               RegistryUnreachableException;
};
};
In order to access the text of a program’s standard output or standard error log, you must configure it using the Ice.StdOut and Ice.StdErr properties, respectively (see Section C.11). For registries and nodes, you must define these properties explicitly, but for servers the node defines these properties automatically if the property IceGrid.Node.Output is defined (see Section C.15).
In the case of openServerLog, the value of the path argument must resolve to the same file as one of the server’s log descriptors (see Section 39.16.12). This security measure prevents a client from opening an arbitrary file on the server’s host.
All of the operations accept a count argument and return a proxy to a FileIterator object. The count argument determines where to start reading the log file: if the value is negative, the iterator is positioned at the beginning of the file, otherwise the iterator is positioned to return the last count lines of text.
The FileIterator interface is quite simple:
module IceGrid {
interface FileIterator {
    bool read(int size, out Ice::StringSeq lines)
        throws FileNotAvailableException;
    void destroy();
};
};
A client may invoke the read operation as many times as necessary. The size argument specifies the maximum number of bytes that read can return; the client must not use a size that would cause the reply to exceed the client’s configured maximum message size (see the property Ice.MessageSizeMax in Section C.11).
If this is the client’s first call to read, the lines argument holds whatever text was available from the iterator’s initial position, and the iterator is repositioned in preparation for the next call to read. The operation returns false to indicate that more text is available and true if all available text has been read.
Line termination characters are removed from the contents of lines. When displaying the text, you must be aware that the first and last elements of the sequence can be partial lines. For example, the last line of the sequence might be incomplete if the limit specified by size is reached. The next call to read returns the remainder of that line as the first element in the sequence.
As an example, the C++ code below displays the contents of a log file and waits for new text to become available:
IceGrid::FileIteratorPrx iter = ...;
while(true) {
    Ice::StringSeq lines;
    bool end = iter>read(10000, lines);
    if (!lines.empty()) {
        // The first line might be a continuation from
        // the previous call to read.
        cout << lines[0];
        for (Ice::StringSeq::const_iterator p =
             ++lines.begin(); p != lines.end(); ++p)
            cout << endl << *p << flush;
    }
    if (end)
        sleep(1);
}
Notice that the loop includes a delay in case read returns true, which prevents the client from entering a busy loop when no data is currently available.
The client should call destroy when the iterator object is no longer required. At the time the client’s session terminates, IceGrid reclaims any iterators that were not explicitly destroyed.
If the client waits indefinitely for new data, it must invoke keepAlive on the administrative session to prevent it from expiring (see Section 39.14.1).

39.14.3 Dynamic Monitoring

IceGrid allows an application to monitor relevant state changes by registering callback objects. (The IceGrid GUI tool uses these callback interfaces for its implementation.) The callback interfaces are useful to, for example, automatically generate an email notification when a node goes down or some other state change of interest occurs.

The Observer Interfaces

IceGrid offers a callback interface for each major component of the IceGrid architecture:
module IceGrid {
interface NodeObserver {
    void nodeInit(NodeDynamicInfoSeq nodes);
    void nodeUp(NodeDynamicInfo node);
    void nodeDown(string name);
    void updateServer(string node, ServerDynamicInfo updatedInfo);
    void updateAdapter(string node,
                       AdapterDynamicInfo updatedInfo);
};

interface ApplicationObserver {
    void applicationInit(int serial,
                         ApplicationInfoSeq applications);
    void applicationAdded(int serial, ApplicationInfo desc);
    void applicationRemoved(int serial, string name);
    void applicationUpdated(int serial,
                            ApplicationUpdateInfo desc);
};

interface AdapterObserver {
    void adapterInit(AdapterInfoSeq adpts);
    void adapterAdded(AdapterInfo info);
    void adapterUpdated(AdapterInfo info);
    void adapterRemoved(string id);
};

interface ObjectObserver {
    void objectInit(ObjectInfoSeq objects);
    void objectAdded(ObjectInfo info);
    void objectUpdated(ObjectInfo info);
    void objectRemoved(Ice::Identity id);
};

interface RegistryObserver {
    void registryInit(RegistryInfoSeq registries);
    void registryUp(RegistryInfo node);
    void registryDown(string name);
};
};
The next section describes how to install an observer.

Registering Observers

The AdminSession interface provides two operations for registering your observers:
module IceGrid {
    interface AdminSession extends Glacier2::Session {
        idempotent void keepAlive();

        idempotent void setObservers(
                RegistryObserver* registryObs,
                NodeObserver* nodeObs,
                ApplicationObserver* appObs,
                AdapterObserver* adptObs,
                ObjectObserver* objObs)
            throws ObserverAlreadyRegisteredException;

        idempotent void setObserversByIdentity(
                Ice::Identity registryObs,
                Ice::Identity nodeObs,
                Ice::Identity appObs,
                Ice::Identity adptObs,
                Ice::Identity objObs)
            throws ObserverAlreadyRegisteredException;

        // ...
    };
};
You should invoke setObservers and supply proxies when it is possible for the registry to establish a separate connection to the client to deliver its callbacks. If network restrictions such as firewalls prevent such a connection, you should use the setObserversByIdentity operation, which creates a bidirectional connection instead (see Section 37.7).
You can pass a null proxy for any parameter to setObservers, or an empty identity for any parameter to setObserversByIdentity, if you want to use only some of the observers. In addition, passing a null proxy or an empty identity for an observer cancels a previous registration of that observer. The operations raise ObserverAlreadyRegisteredException if you pass a proxy or identity that was registered in a previous call.
Once the observers are registered, operations corresponding to state changes will be invoked on the observers. (See the online Slice API Reference for details on the data passed to the observers. You can also look at the source code for the IceGrid GUI implementation in the Ice for Java distribution to see how observers are used by the GUI.)
Finally, remember to invoke keepAlive periodically to prevent the session from expiring (see Section 39.14.1).
Table of Contents Previous Next
Logo