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 35.12 for more information.
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 39.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 38). 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 39.5.1).
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 35.14.2) and establishing observers (see
Section 35.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 35.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.
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 35.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.
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 35.14.1).
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.
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 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 33.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.
Finally, remember to invoke keepAlive periodically to prevent the session from expiring (see
Section 35.14.1).