Site/SunNet/Domain Manager Application and Agent Development Guide (FrameMaker version)
この本のみを検索
PDF 文書ファイルをダウンロードする

Using the Database API Functions

8

This chapter describes the Site/SunNet/Domain Manager database API functions. The API functions allow you to do the following tasks:
  • Open the database.
  • Lock and unlock the database.
  • Retrieve information about elements (components, buses, views, and connections) from the database.
  • Add a new element instance to the database.
  • Delete an element instance from the database.
  • Modify element instances in the database.
  • Loading an ASCII file into the Console.
  • Saving element instances or saving the Console's runtime database into an ASCII file.
Example code segments are provided for each task. Refer to the man page for each function for a full description of syntax and returned values.
Before proceeding with this chapter, you should make sure that you have a thorough understanding of the Site/SunNet/Domain Manager database structures.

8.1 Building Your Program

The API functions are used in conjunction with a header file supplied with the product software. The header file netmgt_db.h defines the data structures for a cluster record buffer that is used with database operations. The cluster record
buffer is used to hold a copy of a cluster record retrieved from the database or to hold a new cluster record while it is being created. When you add a new cluster record or modify an existing cluster record, the information in the cluster record buffer is written into the database. The header file also defines errors that can be returned by API functions.

8.2 Static and Dynamic Linking

You can link your application with libnetmgt_db and libnetmgt either statically or dynamically. Dynamically is preferrable and recommended for the following reasons:
  • Dynamically linked programs save disk space and main memory because they share library code at runtime.
  • Shared library code can be enhanced without having to relink the applications that use it.
  • Dynamically linked applications provide better compatibility. In order to ensure that your applications are compatible with future releases of this product, dynamic linking must be used.

8.2.1 Dynamic Linking

Dynamic linking, as shown in the samples below, is the preferrable and recommended linking method. When you dynamically link your program, you can include the following libnetmgt libraries:
  • If you have installed the Solaris 1.1.1 version of this product:
· /usr/snm/lib/libnetmgt_db.so
· /usr/snm/lib/libnetmgt.so

  • If you have installed the Solaris 2.4 version of this product:
· /opt/SUNWconn/snm/lib/libnetmgt_db.so
· /opt/SUNWconn/snm/lib/libnetmgt.so


Note - If you link with the libnetmgt_db.so library, the libnetmgt.so library must also be used, with libnetmgt_db.so being listed before libnetmgt.so in the command line. The libnetmgt.so library may be used without the libnetmgt_db.so library.

8.2.1.1 Dynamic Linking for the Solaris 2.4 Environment

To link with the libraries provided with the Solaris 2.4 version of this product, you must link with the network services library (libnsl) and the internationalization library (libintl). To dynamically link your application, follow this format:

  host% cc myprog.c -o myprog -R /opt/SUNWconn/snm/lib -L /opt/SUNWconn/snm/lib -lnetmgt_db  
  -lnetmgt -lnsl -lintl  

Since the Solaris 2.x version of this product does not make links in /usr/lib, all Site/SunNet/Domain Manager applications should link with the -R option, as shown above. This avoids forcing the user to set the LD_LIBRARY_PATH variable at runtime.

8.2.1.2 Dynamic Linking for the Solaris 1.1.1 Environment

To dynamically link your application with the libraries provided with the Solaris 1.1.1 version of this product, follow this format:

  host% cc myprog.c -o myprog -L /usr/snm/lib -lnetmgt_db -lnetmgt -lnsl  

8.2.2 Static Linking

When you statically link your program, you can include the following libnetmgt libraries:
  • If you have installed the Solaris 1.1.1 version of this product:
· /usr/snm/lib/libnetmgt_db.a
· /usr/snm/lib/libnetmgt.a

  • If you have installed the Solaris 2.4 version of this product:
· /opt/SUNWconn/snm/lib/libnetmgt_db.a
· /opt/SUNWconn/snm/lib/libnetmgt.a


Note - If you link with the libnetmgt_db.a library, the libnetmgt.a library must also be used, with libnetmgt_db.a being listed before libnetmgt.a in the command line. The libnetmgt.a library may be used without the libnetmgt_db.a library.

8.2.2.1 Static Linking for the Solaris 2.4 Environment

To link with the libraries provided with the Solaris 2.4 version of this product, you must link with the network services library (libnsl) and the internationalization library (libintl). To statically link your application, follow this format:

  host% cc myprog.c -o myprog -L /opt/SUNWconn/snm/lib -Bstatic -lnetmgt_db -lnetmgt -lnsl  
  -lintl -Bdynamic -ldl  

If you use the static method, you must specifically link in libdl.

8.2.2.2 Static Linking in a Solaris 1.1.1 Environment

To statically link your application with the libraries provided for the Solaris 1.1 version of this product, follow this format:

  host% cc myprog.c -o myprog -L /usr/snm/lib -Bstatic -lnetmgt_db -lnetmgt -lnsl  
  -lintl -Bdynamic -ldl  

If you use the static method, you must specifically link in libdl.

8.3 Error Handling

Most functions return True (1) or False (0) values upon completion. If a value of False is returned, an error has occurred. If any error occurs during the execution of a function, the external variable snm_error is set to the error number that indicates the cause of the error. Errors are defined in the header file netmgt_db.h. See the snm_error(3N) man page for error codes and explanations.

8.4 Opening the Database

The snmdb_open function is used to open the database. The database must be located in the directory specified by the database keyword in the snm.conf file. (The snm.conf file is located in /etc for the Solaris 1.1.1 version of this product, and in /etc/opt/SUNWconn/snm for the Solaris 2.4 version.) If there is no directory specified by the database keyword, then the database is located in the following directory:
  • /var/adm/snm for the Solaris 1.1.1 version of this product
  • /var/opt/SUNWconn/snm for the Solaris 2.4 version of this product
The database that is opened is the file db.<name>, where <name> is the name specified by the environment variable SNM_NAME, or the login user name is SNM_NAME is not specified. You should call snmdb_open() before you perform any database operations.
The following is an example of how to call snmdb_open().

  if (!snmdb_open())        exit(1);  

8.5 Locking and Unlocking the Database

The database should be locked while you are writing information to the database. Locking the database is not necessary while you are reading information from the database or while you are performing operations on the cluster record buffer. Locking the database prevents other applications, such as the Console, from making changes to the database. If your program does not lock the database, you should make sure that there are no other active applications that can make changes to the database.

Note - While the database is locked, Console users cannot perform any operations (such as sending and viewing requests) from the Console. Therefore, you should minimize the time that the database is locked. snmdb_lock allows you the option of displaying a clock on the Console while the database is locked.

The snmdb_lock() and snmdb_unlock() functions lock and unlock the database. Call snmdb_lock() to lock the database before you make changes to the database. After the database updates are done, you should call snmdb_unlock() to release the lock.

Note - The lock and unlock functions cause low-priority trap reports to be generated when elements are added, changed, or deleted in the database. These trap reports are sent to the event dispatcher, which then forwards the reports to registered management applications. See Section 2.4, "Trap Reports," on page 2-4, for more information.

The following is an example of how to call snmdb_lock() and snmdb_unlock().

  if (snmdb_lock(TRUE, TRUE)) {  
      ......  
      /* update the database record(s) */  
      ......  
      if (!snmdb_unlock())  
        printf("Error: unable to unlock the database.\n");  
  }  
  else  
      printf("Error: unable to lock the database. error = %d\n",  
              snm_error);  

8.6 Retrieving Element Information from the Database

The functions used to retrieve database information fall into two sets:
  • Functions that retrieve information for one element.
  • Functions that retrieve the names of one or more elements of a given type in one or more views.
Each of these sets of functions is described in the following sections.

Note - The examples shown in the following sections are program fragments only. A complete program example is included in the product structure in the file view_db.c in the API_examples directory.

8.6.1 Retrieving Information for a Single Element

To retrieve information about a single element from the database, you must first read the element cluster record into the cluster record buffer by calling snmdb_read. You can then retrieve any of the records contained in an element's cluster record. See the Administration Guide for information on cluster records. For agent and membership (view) records, you can either retrieve an enumerated list of the agent or view records or you can retrieve a specific agent or view record for the element.

Note - A call to snmdb_read initializes the cluster record buffer; therefore, you do not need to clear the buffer before reading subsequent cluster records into the internal buffer.

To retrieve a piece of element information for a single element, do the following:
  1. Call snmdb_read(). Before you try to get any element information, you must call snmdb_read() to load the element record into the cluster record buffer.

  2. Call one or more of the following functions:

. snmdb_get_element_type()
. snmdb_get_property()
. snmdb_get_color()
. snmdb_get_agent()
. snmdb_get_view()
. snmdb_enumerate_agents()
. snmdb_enumerate_connections()
. snmdb_enumerate_views()

  1. For enumerated lists (agents, connections, or views), call snmdb_free_list() to free the storage allocated for the enumerated information.

The following examples assume that an element named "andrew" is defined in the database with the following information:

  record component.ss1 (                # sparcstation 1  
     string[32] Name  
     string[40] IP_Address  
     string[40] User  
     string[40] Location  
     string[80] Description  
  )  
  
  cluster(  
     component.ss1 ( andrew 129.144.44.81 "Alice Wang" "Building  
     #14" "SunNet Manager Engineer" )  
     glyphColor ( 255 221 0 )  
     agent ( diskinfo )  
     agent ( etherif )  
     agent ( hostif )  
     agent ( hostmem )  
     agent ( iproutes )  
     proxy ( concord-mib"" )  
     proxy ( hostperf"" )  
     proxy ( ippath"" )  
     membership ( SunNetMgr 170 120 0 )  
     membership ( Home 150 120 0 )  
     connect ( swap )  
     connect ( golden )  
  )  

In the header file netmgt_db.h, the data type of the cluster record buffer is defined as:

  typedef struct {  
            unsigned char data[SNMBUFFERSIZE];  
  } snmdb_buffer;  

The following code segment shows how to retrieve information on the element "andrew:"

  snmdb_buffer buf;           /*cluster record buffer of element */  
  int red, green, blue;       /* color values */  
  int isproxy;       /* indicator - whether agent is proxy */  
  int x, y;                   /* x, y coordinates in a view */  
  char name[128];             /* name buffer */  
  
  /* first, we load the element record into the cluster record  
      buffer for 'andrew' */  
  if (!snmdb_read("andrew", &buf)) { /* read error */  
     printf("snmdb_read() failed, error = %d\n", snm_error);  
     return;  
  }  
  
  /* get the type of the element, in this case, it should  
      return the string "component.ss1" */  
  printf("The type of element 'andrew' is %s\n",  
           (char *)snmdb_get_element_type(&buf));  
  
  /* get the value of property 'User', 'Location', and  
      'Description' */  
  printf("For element 'andrew': 'User' field = %s\n",  
           snmdb_get_property(&buf, "User", 0).db_string);  
  printf("           'Location' field = %s\n",  
           snmdb_get_property(&buf, "Location", 0).db_string);  
  printf("           'Description' field = %s\n",  
           snmdb_get_property(&buf, "Description", 0).db_string);  
  
  /* get the color of it */  
  /* colors are represented in RGB numbers, snmdb_get_color()  
      will return the RGB numbers of the element glyph */  
  /* in this case, red = 255, green = 221, blue = 0 */  
  if (snmdb_get_color(&buf, &red, &green, &blue))  
     printf("Color values are: %d, %d, %d\n", red, green, blue);  
  else  
     printf("There is no color defined for element.\n");  
  
  /* get agent information for agent 'hostperf' */  
  if (snmdb_get_agent(&buf, "hostperf", &isproxy, name)) {  
     if (isproxy)  
       printf("hostperf is proxy, proxy name = %s\n", name);  


     else  
       printf("hostperf is not proxy\n");  
  }  
  else  
     printf("agent 'hostperf' is not running on element.\n");  
  
  /* get the location of element in view 'SunNetMgr' */  
  if (snmdb_get_view(&buf, "SunNetMgr", &x, &y, NULL, NULL)) {  
     printf("Location of 'andrew' in view 'SunNetMgr' is :\n");  
     printf(" x = %d, y = %d\n", x, y);  
  }  
  else  
     printf("Element is not in view 'SunNetMgr', error = %d\n",  
             snm_error);  

The following code segment shows how to get all the agents that apply to the target element, how to get all the element names that the target element is connected to, and how to get all the views in which the target element exists:

  snmdb_buffer buf;                 /* buffer of element */  
  char **names;                     /* pointer to the enumerated list */  
  char **str;                       /* temp. pointer */  
  
  /* first, we load the element record into the cluster record  
      buffer for 'andrew' */  
  if (!snmdb_read("andrew", &buf)) { /* read error */  
     printf("snmdb_read() failed, error = %d\n", snm_error);  
     return;  
  }  
  
  /* get all the agent names that run on (or apply to)  
      'andrew' */  
  if ((names = snmdb_enumerate_agents(&buf)) == NULL) {  
     printf("Error: unable to enumerate agents, error = %d\n",  
             snm_error);  
     return;  
  }  
  /* got the enumerated list successfully, print the list */  
  for (str = names; *str; str++)  


     printf("agent '%s' found\n", *str);  
  /* remember to free the space used */  
  snmdb_free_list(names);  
  
  /* get all the element names that 'andrew' is connected to */  
  if ((names = snmdb_enumerate_connections(&buf)) == NULL) {  
     printf("Error: unable to enumerate connections, error = %d\n",  
            snm_error);  
     return;  
  }  
  /* got the enumerated list successfully, print the list */  
  for (str = names; *str; str++)  
     printf("connected to '%s'\n", *str);  
  /* remember to free the space used */  
  snmdb_free_list(names);  
  
  /* get all the view names that 'andrew' exists in */  
  if ((names = snmdb_enumerate_views(&buf)) == NULL) {  
     printf("Error: unable to enumerate views, error = %d\n",  
             snm_error);  
     return;  
  }/* got the enumerated list successfully, print the list */  
  for (str = names; *str; str++)  
     printf("element exists in view '%s'\n", *str);  
  /* remember to free the space used */  
  snmdb_free_list(names);  

8.6.2 Retrieving Elements of a Given Type

To retrieve the names of elements of a given type in a particular view or in all views, do the following:
  1. Call snmdb_enumerate_elements() to specify which element to enumerate in a particular view or in all views. This function also initializes storage for the list of elements.

  2. Call snmdb_get_next_element() multiple times to retrieve the names of the elements in the list.

  3. Call snmdb_free_enumeration_handle() to free the storage allocated for the enumerated element names.

The following code segment shows how to retrieve all element names in all views:

  snmdb_handle *handle;          /* pointer to the enumerated list */  
  char *str;                     /* temp. pointer */  
  
  if (!(handle = snmdb_enumerate_elements(NULL, NULL))) {  
     printf("No element in any view\n");  
     return;  
  }  
  
  printf("Elements of all types in all views are:\n");  
  while (str = snmdb_get_next_element(handle))  
     printf("element = %s\n", str);  
  printf("end of list\n");  
  
  /* remember to free the space */  
  snmdb_free_enumeration_handle(handle);  

The following code segment shows how to retrieve all element names of a given type in one particular view.

  snmdb_handle *handle;         /* pointer to the enumerated list */  
  char *str;                    /* temp. pointer */  
  
  if (!(handle =  
         snmdb_enumerate_elements("SunNetMgr", "component.ss1"))) {  
     printf("No element of type 'component.ss1' exists in view.\n");  
     return;  
  }  
  
  printf("Elements of type 'component.ss1' in view  
     'SunNetMgr':\n");  
  while (str = snmdb_get_next_element(handle))  
     printf("element = %s\n", str);  
  printf("end of view\n");  
  
  /* remember to free the space */  
  snmdb_free_enumeration_handle(handle);  

8.7 Adding a New Element Instance into the Database

You can add new element instances to the database. To add a new element instance, you first initialize the cluster record buffer, then create one or more records that make up the element cluster record. Then, you write the cluster record from the buffer to the database. Note that in the cluster record you must define at least one view in which the element will reside. Otherwise, an error is returned and the element is not added to the database.

Note - The element <type> for the element you are adding must be defined in a schema file; there is no API for adding a new element <type>.


Note - See the Administration Guide for information on adding a new element types.

To add a new element into the database, do the following:
  1. Call snmdb_init_buffer(). You need to call snmdb_init_buffer() to initialize the cluster record buffer for the new element.

  2. Call one or more of the following functions:

. snmdb_set_property()
. snmdb_set_color()
. snmdb_add_agent()
. snmdb_add_connection()
. snmdb_add_to_view()

  1. Call snmdb_add() to add the new element to the database. You can optionally lock the database by calling snmdb_lock() before calling snmdb_add(). If the element is being added to a view that is currently displayed by the Console, call snmdb_lock() with its first parameter set to TRUE. This causes the Console to update its display when the element is added to the database. (Otherwise, the Console user must leave the view and then return to the view to see the new element.) Remember to unlock the database with snmdb_unlock().

The following code segment shows how to add a new element "andrew". A complete program example is included in the product structure in the file add_db.c in the API_examples directory.

  snmdb_buffer buf;              /* buffer of element */  
  
  /* initialize the cluster record buffer of the element */  
  if (!snmdb_init_buffer("andrew", "component.ss1", &buf)) {  
     printf("snmdb_init_buffer() failed, error = %d\n",  
             snm_error);  
     return;  
  }  
  
  /* set the property */  
  if (!snmdb_set_property(&buf, "User", "test machine") ||  
       !snmdb_set_property(&buf, "Location", "Building 14")) {  
     printf("snmdb_set_property() failed, error = %d\n",  
             snm_error);  
     return;  
  }  
  
  /* set the color of the element */  
  snmdb_set_color(&buf, 100, 220, 0);  
  
  /* add a non-proxy and a proxy agent */  
  if (!snmdb_add_agent(&buf, "hostif", NULL) ||  
        !snmdb_add_agent(&buf, "hostperf", "andrew")) {  
     printf("snmdb_add_agent() failed, error = %d\n",  
             snm_error);  
     return;  
  }  
  
  /* add a connection to another element */  
  /* Note: the element you want to connect to should be a  
             valid element name that exists in the database */  
  if (!snmdb_add_connection(&buf, "swap")) { /* error */  
     printf("snmdb_add_connection() failed, error = %d\n",  
             snm_error);  
     return;  
  }  


  /* add the element 'andrew' into the view 'SunNetMgr' */  
  if (!snmdb_add_to_view(&buf, "SunNetMgr", 10, 50, 0, 0, 0)) {  
     printf("snmdb_add_to_view() failed, error = %d\n",  
             snm_error);  
     return;  
  }  
  /* now we're ready to add the element to the database */  
  snmdb_lock (TRUE, FALSE);  
  if (!snmdb_add(&buf)) { /* error */  
     printf("snmdb_add() failed, error = %d\n", snm_error);  
     snmdb_unlock();  
     return;  
  }  
  /* element added successfully */  
  snmdb_unlock();  

8.8 Deleting an Element Instance from the Database

The function to delete an element instance operates directly on the database; the cluster record buffer is not used. You delete an element using snmdb_delete(). Note that you will not be able to delete an element if its subview is not empty.
If an element is being deleted from a view that is currently displayed by the Console, call snmdb_lock() with its first parameter set to TRUE. This causes the Console to update its display when the element is deleted. (Otherwise, the Console user must leave the view and then return to the view to see the element deleted.) Remember to unlock the database with snmdb_unlock().
The following code segment shows how to delete the element "andrew" from the database. A complete program example is included in the product structure in the file del_db.c in the API_examples directory.

  if (!snmdb_delete("andrew")) { /* unable to delete it */  
     if (snm_error == SNMDB_SUBVIEW_IS_NOT_EMPTY)  
       printf("Error: element's subview is not empty.\n");  
     else  
       printf("Error: unable to delete element, error = %d\n",  
               snm_error);  
  }  
  /* element is deleted successfully */  

8.9 Modifying an Element in the Database

To modify an element instance, the element's cluster record is first read into the cluster record buffer. After modifications are made to the records in the cluster record, the revised cluster record is written from the buffer back to the database.
To modify an element, do the following:
  1. Call snmdb_read(). Before you try to change any element information, you must call snmdb_read() to load the element record into the cluster record buffer.

  2. Call one or more of the following functions:

. snmdb_set_property()
. snmdb_add_agent() or snmdb_delete_agent()
. snmdb_set_color() or snmdb_delete_color()
. snmdb_add_connection() or snmdb_delete_connection()
. snmdb_add_to_view() or snmdb_delete_from_view()

  1. Call snmdb_update() to write the updated element back to the database. You can optionally lock the database by calling snmdb_lock() before calling snmdb_update(). If the element is being modified in a view that is currently displayed by the Console, call snmdb_lock() with its first parameter set to TRUE. This causes the Console to update its display when the element is modified. (Otherwise, the Console user must leave the view and then return to the view to see the element modifications.) Remember to unlock the database with snmdb_unlock().

Note that you can make multiple changes to an element at a time. The changed information is written to the cluster record buffer. snmdb_update() writes the contents of the buffer to the database.
The following code segment shows how to update the element "andrew". A complete program example is included in the product structure in the file mod_db.c in the API_examples directory.

  snmdb_buffer buf;/* cluster record buffer of element */  
  
  /* first, we load the element record into the cluster record  
      buffer for element 'andrew' */  
  if (!snmdb_read("andrew", &buf)) { /* read error */  
     printf("snmdb_read() failed, error = %d\n", snm_error);  
     return;  
  }  
  
  /* modify the property value */  
  if (!snmdb_set_property(&buf, "User", "Admin System")) {  
     printf("snmdb_set_property() failed, error = %d\n",  
             snm_error);  
     return;  
  }  
  
  /* add the element 'andrew' into the view 'SunNetMgr' */  
  if (!snmdb_add_to_view(&buf, "SunNetMgr", 10, 50, 0, 0, 0)) {  
     printf("snmdb_add_to_view() failed, error = %d\n",  
             snm_error);  
     return;  
  }  
  
  /* delete the element 'andrew' from view 'Engineering' */  
  if (!snmdb_delete_from_view(&buf, "Engineering")) {  
     printf("snmdb_delete_from_view() failed, error = %d\n",  
             snm_error);  
     return;  
  }  
  
  /* delete the connection between 'andrew' and 'swap' */  
  if (!snmdb_delete_connection(&buf, "swap")) {  
     printf("snmdb_delete_connection() failed, error = %d\n",  
             snm_error);  
     return;  
  }  


  /* delete the agent record which describes 'hostif' runs  
      on the element */  
  if (!snmdb_delete_agent(&buf, "hostif")) {  
     printf("snmdb_delete_agent() failed, error = %d\n",  
             snm_error);  
     return;  
  }  
  /* delete the color record, use default color */  
  snmdb_delete_color(&buf);  
  
  /* now we write the updated element back to the database */  
  if (!snmdb_update(&buf)) {  
     printf("snmdb_update() failed, error = %d\n", snm_error);  
     return;  
  }  
  /* element is updated successfully */  

8.10Saving Database Records to an ASCII File

You can save an element cluster record that has been read into the cluster record buffer by calling snmdb_save_element(). Note that because this function only operates on a single element at a time and it does not save request instances, it is not equivalent to using the Save option in the Console's File menu. See Section 8.12, "Saving the Runtime Database to an ASCII File," if you want to save the entire database.
You can save all the element instances in a database to an ASCII file by enumerating through all the elements in the database, then reading and saving each element. This is shown in the example below.

  /* Open the output file. */  
  if (!(fptr = fopen(outfile, "w"))) {  
       printf("Cannot open %s for writing.\n", outfile);  
       exit(1);  
  }  
  
  /* Enumerate through all the elements in the database. */  
  if (!(handle = snmdb_enumerate_elements(NULL, NULL))) {  
    printf("No element found in the database.\n");  
    exit(1);  
  }  
  
  /* Loop through the element records and save them into output  
  file. */  
  while (name = snmdb_get_next_element(handle)) {  
    if (!snmdb_read(name, &buf))  
      printf("snmdb_read() failed, skipping element '%s'\n", name);  
    if (!snmdb_save_element(&buf, fptr))  
      printf("snmdb_save_element() failed, snm_error = %d\n",  
  snm_error);  
  }  
  
  /* Free the enumerator handle. */  
  snmdb_free_enumeration_handle(handle);  

8.11 Loading a Database File into the Console

You can load a database file into a Console session by calling snmdb_console_load(). Database load is accomplished through an RPC call to the Console. Note that the Console must be running. See the snmdb_console_load(3N) man page for information about this function.

8.12 Saving the Runtime Database to an ASCII File

You can have the Console save all element and request instances in its runtime database to a specified file in ASCII MDB form by calling snmdb_console_save_components(). Saving the runtime database is
accomplished through an RPC call to the Console. This call has a three parameters: the path name of the file in which the MDB is to be saved, a pointer to an integer for returned RPC error codes, and a pointer to an integer for returned Console errors. Note that the Console must be running. See the snmdb_console_save_component(3N) man page for information about this function.