[Top]
[Prev]
[Next]
[Bottom]
This chapter shows an example of quick agent development using
an existing application. The example introduces a simple intermediate programming
layer between a generic agent services interface and the application. Thus,
converting the application to an agent becomes an almost mechanical process.
The examples assume that Site/SunNet/Domain Manager has
been installed on a system being used to develop agents. All files cited
are presumed to be in the sample agent directory:
(
Chapter 13, "Testing and Integration
," has details on how to compile your agent and install it into the network.)
The example uses the following staged approach:
- 1.
Write and test a standalone application that gets
the information desired.
- 2.
Organize the information into groups of attributes
and write the agent schema file.
- 3.
Rewrite and test the application with
a reporting interface not including agent services.
- 4.
Build an agent by including agent
services and testing with snm_cmd.
- 5.
Test the agent with the Site/SunNet/Domain
Manager Console, snm.
In this chapter, you will write an agent
by modifying an existing sample agent. The output shown herein is based on
the sample agent. Yours will be different, specific to your application.
Also, note this chapter does not discuss agent initialization, startup, or
shutdown.
Start with a standalone application. The
example application reports system information, for example, machine type,
and the date.
The following listing shows the source
code for the kernel memory buffer application.
/* application.c */
#include <sys/systeminfo.h>
#include <time.h>
extern void send_error();
static char *day_of_week[7] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
static char *month_of_year[12] = {
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December" };
#ifndef AGENT
/*
|
struct tm *time_info;
time_t time_val;
char *group;
if (argc != 2) {
printf("usage: na.sample group\n");
exit(0);
}
group = argv[1];
if (strcmp(group, "sysinfo") == 0) {
sysinfo(SI_SYSNAME, sysname, SYSNAME_LEN);
sysinfo(SI_RELEASE, release, RELEASE_LEN);
sysinfo(SI_MACHINE, machine, MACHINE_LEN);
sysinfo(SI_HW_SERIAL, serialnumber, SERIALNUMBER_LEN);
/* print sysinfo results */
(void) printf("sysname = %s\n", sysname);
(void) printf("release = %s\n", release);
(void) printf("machine = %s\n", machine);
(void) printf("serialnumber = %s\n", serialnumber);
}
if (strcmp(group, "date") == 0) {
time_val = time((time_t *)NULL);
time_info = localtime(&time_val);
/* convert values */
weekday = day_of_week[time_info->tm_wday];
month = month_of_-year[time_info->tm_mon];
day = time_info->tm_mday;
year = time_info->tm_year + 1900;
/* print out date report */
(void) printf("weekday = %s\n", weekday );
(void) printf("month = %s\n", month);
(void) printf("day = %d\n", day);
(void) printf("year = %d\n", year);
}
|
Use the Makefile in the sample agent
directory to build the application. Run the application to get a feel for
the information it collects. (Note the values reported in these examples will
probably differ from those on your system.) Enter the command:
where <sample-agent-path
> is /opt/SUNWconn/snm/src/sample for a Solaris 2.x installation
or /usr/snm/src/sample for the Solaris 1.x version.
Now enter:
This command creates an executable application
in the file Application/na.sample. Run the application:
The information provided falls into two
groups: a summary of memory buffer statistics and a detailed report of statistics.
From this are defined the two groups sysinfo and date.
Within these groups attributes are defined,
one for each piece of information reported. Note data types of the data and
assign types from
Table 11-1 on page 11-3
. Name each data field (using no more than 64 characters) and write a short
description of each field (using no more than 1024 characters). Note any error
messages in the standalone application code.
The following is the agent schema file,
sample.schema, written for this example.
After defining the schema, you should
write a function to validate group names. The validation routine will be
used by the request verification routine, verify_request(), in
the file, request.c . In the example, the group names are placed
into the groupnames array in the file schema.c as
shown below. (The #ifdef 'ed code in the file is used during the
testing described in
Section 14.4, "Rewrite
with the Reporting Interface," on page 14-11
.)
The reporting interface is a simplified
programming interface to agent services. The idea is to isolate the application
and agent services so the application can be transformed into an agent independent
of the way those services are used. In this way, you are "bringing agent
services to the application" rather than vice versa.
The reporting interface consists of
the files: start.c, request.c, and interface.c
. These files are in the sample agent directory. Each file is responsible
for a specific function as follows:
start.c
- contains the agent main routine and
executes agent initialization and startup.
request.c
- contains routines that execute request
verification and dispatching. The dispatch function contains the reporting
algorithm used by the agent. In the example, the agent attributes are assumed
to be instantaneously sampled and reported periodically, on the interval specified
in the request.
interface.c
- contains a wrapper to the agent
service routines that build message lists for event reports, data reports,
and error reports. The wrapper reduces these calls to routines that sample
attributes by data type. Calls to the wrapper routines can be embedded in
the application at the point where attributes are sampled. This file also
contains #ifdef'ed code for testing with the sample interface but
without agent services.
These files contain the interfaces
to agent services. The last file is the intermediate layer that ties the agent
service interface to the application. In this section, you will add the intermediate
layer to the application. In the next section, you will add the agent services
interface.
The intermediate layer consists
of the following wrapper routines in interface.c:
send_error()
- sends back errors detected by
the standalone application code. The arguments consist of a system error code,
an optional agent error code for agent defined errors and an optional message
string which describes the specific error.
get_option_string()
- retrieves the options string
passed in the agent request. The options string is set in the Options field
of the Console's data report and event report windows.
fe()
- is a set of routines for building
data buffers by data type. These routines call build_report()
which builds the data or event report.
/* interface.c */
#include <netmgt/netmgt.h>
#ifndef NOAGENTSERVICES
/* ---------------------------------------------------------------------
* send_error - send an error report
* no return value
* ---------------------------------------------------------------------
*/
void
send_error(service_error,
agent_error, message)
Netmgt_stat service_error; /*
service error code */
u_int agent_error; /*
agent error code defined in agent schema */
char *message; /*
error message string */
{
Netmgt_error error; /*
error report buffer */
error.service_error
= service_error;
error.agent_error
= agent_error;
error.message =
message;
if (!netmgt_send_error(&error))
NETMGT_DBG("na.sample:
can't send error report: %s\n",
netmgt_sperror());
return;
}
#else
void
send_error(system_error, agent_error, message)
Netmgt_stat system_error; /*
system error code */
u_int agent_error; /*
agent error code */
char *message; /*
error message */
{
printf("system_error
= %d, agent_error = %d, message = \"%s\"\n",
system_error, agent_error,
message);
return;
}
#endif
|
To rewrite the application,
first include <netmgt/netmgt.h> . Next, rewrite the main
routine to be callable from the dispatch_request() routine with
the parameters system, group, and key.
The three parameters are character strings indicating the system for which
information is desired, the group name of the attribute group desired, and
the key selector to be used if the group name specifies a table. For tables,
the attribute netmgt_table_key should also be returned. This is
useful for setting attribute values with the Console's Set tool or for graphing
attributes from the Results Browser tool.
Error messages should be
converted to calls to send_error() with the agent error code for
the appropriate message as defined by the agent schema.
Reporting is carried out
by group name. Calls to the build_<data_type>() routines
should be bracketed by an if statement that checks for the appropriate
group name.
When a report is built,
the returned (boolean) value of the call should be checked. The rewritten
application should return the boolean value FALSE if any of the
build_<data_type>() calls
failed. Otherwise it should return TRUE.
Reporting is done by using
the appropriate build_<data_type>() routine for the type
of information to be collected. This involves replacing printf()
calls with build_<data_type>() calls. The reporting routines
transcribe the information into an event or data report according to the algorithm
in the file request.c.
The rewritten application
is shown below. Note the modified code sections are indicated using
#ifdefAGENT statements. The application can be re-compiled
with the -DAGENT compiler switch set to build an agent. It can
be compiled without it to obtain the original application.
/* application.c */
#include <sys/systeminfo.h>
#include <time.h>
extern void send_error();
static char *day_of_week[7] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
static char *month_of_year[12] = {
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
#ifndef AGENT
/* -----------------------------------------------------------------------
* main (standalone application)
* -----------------------------------------------------------------------
*/
|
#ifndef AGENT
char *group;
if (argc != 2) {
printf("usage: na.sample2 group\n");
exit(0);
}
group = argv[1];
#endif
}
if (strcmp(group, "sysinfo") == 0) {
sysinfo(SI_SYSNAME, sysname, SYSNAME_LEN);
sysinfo(SI_RELEASE, release, RELEASE_LEN);
sysinfo(SI_MACHINE, machine, MACHINE_LEN);
sysinfo(SI_HW_SERIAL, serialnumber, SERIALNUMBER_LEN);
#ifndef AGENT
/* print sysinfo results */
(void) printf("sysname = %s\n", sysname);
(void) printf("release = %s\n", release);
(void) printf("machine = %s\n", machine);
(void) printf("serialnumber = %s\n", serialnumber);
#else
/* build sysinfo report */
if (!build_string("sysname", sysname) ||
!build_string("release", release) ||
!build_string("machine", machine) ||
!build_string("serialnumber", serialnumber)) {
/*
* fatal error - send an error report to the rendezvous and return
*/
send_error(NETMGT_FATAL, (u_int) 1, (char *) NULL);
return FALSE;
}
#endif
}
if (strcmp(group, "date") == 0) {
time_val = time((time_t *)NULL);
time_info = localtime(&time_val);
|
/* convert values */
weekday = day_of_week[time_info->tm_wday];
month = month_of_year[time_info->tm_mon];
day = time_info->tm_mday;
year = time_info->tm_year + 1900;
#ifndef AGENT
/* print out date report */
(void) printf("weekday = %s\n", weekday );
(void) printf("month = %s\n", month);
(void) printf("day = %d\n", day);
(void) printf("year = %d\n", year);
#else
/* build date report */
if (!build_string("weekday", weekday) ||
!build_string("month", month) ||
!build_short("day", day) ||
!build_short("year", year)) {
/*
* fatal error - send an error report to the rendezvous and return
*/
send_error(NETMGT_FATAL, (u_int) 1, (char *) NULL);
return FALSE;
}
#endif
}
#ifndef AGENT
exit(0);
#else
/* indicate success */
return TRUE;
#endif
|
14.4.2 Build with Report Interface
Having made these changes
to the application, build a test version that omits agent services using
the following commands:
where <sample-agent-path
> is /opt/SUNWconn/snm/src/sample if this is a Solaris 2.x
installation or /usr/snm/src/sample if you have installed the Solaris
1.1 version of this product.
Then enter the following
command:
This command creates a
test application executable in the file Test/na.sample.
14.4.3 Test with Report Interface
Run the test application and
verify the group names and that all appropriate attributes are sampled. It
is an error to return an attribute not specified for a group as defined by
the agent schema.
The problem is that only
root can access kernel memory structures. Become root and try again:
Build the agent with the agent
services library. In the sample code directory enter the command:
This command creates an
executable agent in the file Agent/na.sample. Testing the agent
with snm_cmd. snm_cmd is described in greater detail
in
Section 13.2,
"Test the Agent," on page 13-7
. Ensure the logger is running. If it isn't running, start it with the following
command,
where <agents-path
> is /opt/SUNWconn/snm/agents if this is a Solaris 2.x installation
or /usr/snm/agents if this is the SunOS 4.x version.
Ensure the sample agent
service is registered. (See
Section 13.1.10,
"Register the Agent RPC Program Number," on page 13-6
.) The mechanism for starting the agent must be determined. The agent can
be started either automatically by inetd or manually from the command
line. Manually starting an agent has the advantage that messages from the
agent will be reported and any command line debug switches can be used. These
are unavailable when using inetd. When using inetd
to start the agent, verify that an entry for the sample agent exists in
/etc/inetd.conf, and it refers
to the proper file to execute.
Assuming that a Solaris
2.4 version of Site/SunNet/Domain Manager is installed in /opt/SUNWconn/snm
, here is what the sample agent entry should look like.
Assuming the Solaris 1.1.1
version of this product installed in /usr/snm, here is what the
sample agent entry should look like.
If the inetd.conf
file must be modified, remember to send a SIGHUP signal to the
inetd process so that the change
will be noted.
Once the mechanism for starting
the agent has been established, it can be tested with snm_cmd .
Test the agent by making data requests for all groups. The following is an
example with the Solaris 2.4 version of this product:
The next example illustrates
this use of snm_cmd in a Solaris 1.1 environment:
Test the agent with snm
. Ensure the new agent schema file is specified either by being moved into
a directory listed by the schemas keyword in snm.conf or by being
included on the snm command line.
The system where the test
will be made should have its management database (MDB) record cluster modified
to include a reference to the sample agent. For more information on the MDB
and how to specify element representations, see the Administration Guide.
The agent will be tested on the same system on which it was built. Following
is an example record cluster for the test system used in this example:
- 1.
Run snm
and bring up the Data Log window.
- 2.
Bring up
the glyph menu of the test system and do a Quick Dump of all the groups under
the sample agent.
- 3.
Try to
send some event reports.
- This agent application
collects static data so it is easy to set an event on any particular value.
Agents with rapidly changing data can often be induced to send a report by
setting an attribute threshold to a value the attribute does not normally
have.
By using and
modifying the existing na.sample agent code, you streamline the
agent writing process. At this point, na.sample is your new agent.
To complete the process, rename the agent as appropriate and follow the process
described in
Section 13.1.9, "Assign an Agent Name," on page 13-6
.
[Top]
[Prev]
[Next]
[Bottom]
Copyright 1996 Sun Microsystems,
Inc., 2550 Garcia Ave., Mtn. View, CA 94043-1100 USA. All Rights Reserved