Broadcom Software Academy Blog

Unlocking the Power of UIMAPI: Automating Probe Configuration

Written by Steve D'Arcy | Nov 4, 2024 7:07:23 PM
Key Takeaways
  • Use UIMAPI to perform virtually any action in your DX UIM environment programmatically.
  • Get instructions and examples on using a Java program to interact with the API.
  • See how to use the UIMAPI RESTful interface to view and update the net_connect probe and create a new profile.

The UIMAPI is a RESTful API. With UIMAPI you can programmatically perform almost any action in your DX UIM environment. Using the Swagger front-end as a guide, you can manually execute REST endpoints. However, many customers would rather use a program to automate these actions.

This blog focuses on automating probe configuration. We outline how to use a Java program to interact with the API, offering examples. However, you can employ any programming language that offers support for a RESTful interface. Essentially, a RESTful endpoint is a URL that supports several actions: GET, POST, PUT, and DELETE. For UIMAPI, you will also need credentials. You can perform most GET actions using a web browser and navigating to the URL. As shown in the image below, the Swagger documentation for UIMAPI describes each type of endpoint.

This blog covers the viewing and updating of the net_connect probe as well as creating a new profile, all via the UIMAPI RESTful interface. See my prior post to learn more about using UIMAPI to streamline maintenance modes.

This blog is focused on using the raw configuration file rather than the Monitoring Configuration Service (MCS). If you are interested in using the UIMAPI to manage MCS profiles, look out for my future blogs.

Note: All probe configuration actions are directed at the device and probe, wherever it is running. In this example, the net_connect probe is running on the primary hub.

All examples use the base URL to my localhost/UIMAPI endpoints, but they will also work with a remote hostname/IP address as well:

All examples are using JSON but the UIMAPI also supports XML.

Authenticating the UIMAPI

All UIMAPI endpoints must have authentication, which features a DX UIM user with Web Service ACL permissions, Base64 encoded as a single string {user}:{password}. You can do this once at the start of your program and the encoded string can be sent to every endpoint call. The bytesEncoded string is passed to each endpoint call made.

Here’s an example of Java code:

// Encode the credentials – define user & pwd variables with your credentials
bytesEncoded = Base64.getEncoder().encodeToString((user+":"+pwd).getBytes());

Using HTTP and HTTPS protocols

If using the HTTPS protocol, a certificate may be required. The DX UIM documentation details the process of adding a certificate to a keystore. To establish a secure connection, every endpoint call in these examples requires the keystore and the keystore password.

If you are using the HTTP protocol, set the keystore and keystore password values to null.

Getting a single configuration key value

To get a single configuration key value, use the /probes/config end point:

{base_url}/probes/config

The payload defines the value you want to GET. This requires the address of the probe and the configuration key. The domain, hub, robot, and probe point to where the net_connect probe is running and the key value is the key you want to GET.

The payload is:

{
   "domain":"Validation",
   "hub":"Office",
   "robot":"primary",
   "probe":"net_connect",
   "key":"/profiles/centos1/active"
}

Using the URL (updated with your environment) plus the payload, GET the configuration key value (payload) along with the encoded credentials (bytesEncoded).

Here’s the Java code example:

// Get a config key value from a profile
payload = "{\"domain\":\"Validation\",\"hub\":\"Office\",\"key\":\"/profiles/centos1/active\",\"probe\":\"net_connect\",\"robot\":\"primary\"}";
responseBody = RestCalls.runRestPost(baseUrl, "/probes/config/", payload, bytesEncoded, keystore, keypwd);

System.out.println("Active: " + responseBody);

This will output the value of the /profiles/centos1/active key:

Active: "yes"

You can view the Active value in Admin Console or Infrastructure Manager: 

Getting the entire configuration file

To GET the entire configuration file, the probes GET endpoint requires environment values in the URL string itself:

{base_url}/probes/{domin}/{hub}/{robot}/{probe}/config

These values point to the primary hub where the net_connect probe is running. In this example, the URL will be:

{base_url}/probes/Validation/Office/primary/net_connect/config

Using the URL (updated with your environment), GET the configuration file using the encoded credentials (bytesEncoded). No payload is required.

This is the Java code example:

//Get the entire config file
responseBody = RestCalls.runRestGet(baseUrl, "/probes/Validation/Office/primary/net_connect/config", "", bytesEncoded, keystore, keypwd);

System.out.println(responseBody);

This will output a JSON array of key/value pairs in your net_connect configuration file: 

{
  "probeConfigKey" : [ {
    "key" : "/profiles/centos1/ping",
    "value" : "yes"  }, {
  }, {
    "key" : "/profiles/centos1/timeout",
    "value" : "2"
  }, {

  }, {
    "key" : "/messages/ping threshold failed/token",
    "value" : "threshold_fail"
  } ]
}

Note: This output is truncated. The actual output was 765 lines, but this portion gives you an idea what to expect.

You can view the values in Admin Console or Infrastructure Manager:

Updating a profile

In this example, we are going to update a configuration key value. The process is the same regardless of the key, so the key we are going to update is a profile active key, which was used in the above example. We’re changing its value from yes (active) to no (inactive). This will disable the profile.

Updating a single configuration key value uses the POST endpoint and requires environment values in the URL string:

{base_url}/probes/{domin}/{hub}/{robot}/{probe}/config

These values point to where the net_connect probe is running. In this example, use

{base_url}/probes/Validation/Office/primary/net_connect/config

The payload is:

{
   "encrypt":"false",
   "key":"/profiles/centos1/active",
   "value":"no"
}

Using the URL (updated with your environment) plus the payload, POST the configuration key value (payload) along with the encoded credentials (bytesEncoded).

Here’s the Java code example:

// Update a config key - this can also add a key if not there 
payload = "{\"encrypt\":\"false\",\"key\":\"/profiles/centos1/active\",\"value\":\"no\"}";
responseBody = RestCalls.runRestPost(baseUrl, "/probes/Validation/Office/primary/net_connect/config", payload, bytesEncoded, keystore, keypwd);
 
// Get a config key value from a profile
payload = "{\"domain\":\"Validation\",\"hub\":\"Office\",\"key\":\"/profiles/centos1/active\",\"probe\":\"net_connect\",\"robot\":\"primary\"}";
responseBody = RestCalls.runRestPost(baseUrl, "/probes/config/", payload, bytesEncoded, keystore, keypwd);


System.out.println("Profile: centos1 - Active: " + responseBody);

This will output the value of the /profiles/centos1/active key:

Active: "no"

You can view the Active value in Admin Console or Infrastructure Manager: 

Creating a new profile

In this example, we create an entirely new profile using a REST call. The profile added will be named centos4 and have a one-minute interval while monitoring the UIM Robot Service.

Adding a new profile is done using the PUT endpoint, which requires environment values in the URL string:

{base_url}/probes/{domin}/{hub}/{robot}/{probe}/config

These values point to the primary hub where the net_connect probe is running. In this example, the URL will be:

{base_url}/probes/Validation/Office/primary/net_connect/config

The payload is:

payload = "["
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/active\",\"value\":\"no\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/QoS\",\"value\":\"yes\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/ping\",\"value\":\"yes\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/interval\",\"value\":\"1min\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/hostname\",\"value\":\"centos4\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/ip\",\"value\":\"172.16.217.140\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/timeout\",\"value\":\"2\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/failures\",\"value\":\"1\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/retries\",\"value\":\"3\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/dynamic_ip_monitoring\",\"value\":\"no\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/msg_ok\",\"value\":\"MsgConnectOk\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/msg_fail\",\"value\":\"MsgConnectFail\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/qos_source\",\"value\":\"0\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/source\",\"value\":\"0\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/target\",\"value\":\"2\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/icmp_size\",\"value\":\"0\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/flags\",\"value\":\"0\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/IPLongValue\",\"value\":\"184341980\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/alarm\",\"value\":\"0\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/threshold_ok\",\"value\":\"ping threshold OK\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/threshold_fail\",\"value\":\"ping threshold failed\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/icmp_threshold\",\"value\":\"100\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/alarm_on_packet_loss\",\"value\":\"no\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/packets_to_send\",\"value\":\"0\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/max_packets_lost\",\"value\":\"0\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/qos_on_packets_lost\",\"value\":\"no\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/delay_between_packet_to_send\",\"value\":\"0\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/max_jitter\",\"value\":\"2000\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/alarm_on_jitter\",\"value\":\"0\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/active\",\"value\":\"yes\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/alarm\",\"value\":\"yes\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/QoS\",\"value\":\"yes\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/wait_to_send_command\",\"value\":\"no\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/timeout\",\"value\":\"10\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/retries\",\"value\":\"3\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/delay_between_retries\",\"value\":\"0\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/challengeresponsetimeout\",\"value\":\"1000\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/sendcommand\",\"value\":\"no\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/responsemustcontain\",\"value\":\"no\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/sendcommand2\",\"value\":\"no\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/response2mustcontain\",\"value\":\"no\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/sendcommand3\",\"value\":\"no\"},"
   + "{\"encrypt\":\"false\",\"key\":\"/profiles/centos4/services/NimBUS_Robot/response3mustcontain\",\"value\":\"no\"}"
+ "]";

Note: The payload is an array in which each key is represented as a separate JSON object. Each object is followed by a comma, except for the last one. The entire JSON array must be enclosed in square brackets [ ], even if it contains only one object.

This is the Java code example:

// Create a new profile 
int rc = RestCalls.runRestPut(baseUrl, "/probes/Validation/Office/primary/net_connect/config", payload, bytesEncoded, keystore, keypwd);        
System.out.println("Return Code: " + rc);

This will output the following Return Code:

Return Code: 204

You can view the new centos4 profile in Admin Console or Infrastructure Manager: 

Appendix A

Here are all the REST methods used in the examples. These methods are in a class named RestCalls.

runRestPost method

public static String runRestPost(String baseUri, String path, String payload, String credentials, String keystore, String keypwd) throws ClientProtocolException, IOException {
 String responseBody = null;
 
 CloseableHttpClient client = setupHttpClient(baseUri, keystore, keypwd);
 
 logger.log(NimLog.DEBUG, "URL: "+ baseUri+path);
     
 HttpPost request = new HttpPost(baseUri+path);
 request.addHeader(HttpHeaders.AUTHORIZATION,"Basic " + credentials);
 request.setHeader(HttpHeaders.ACCEPT, "application/json");
 request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
 request.setEntity(new StringEntity(payload, StandardCharsets.UTF_8));
          
 HttpResponse response = client.execute(request);
 int rc = response.getStatusLine().getStatusCode();
     
 //System.out.println("RC: " + rc + " : response: " +response);
     
 if (response.getEntity() != null) {
    responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
 }
     
 if (rc >= 200 && rc < 300) {
    // do some error checking here
    return responseBody;
 } else {
    logger.log(NimLog.ERROR, "Got response code "+rc+" from method: "+response.getStatusLine().getReasonPhrase());
 }
 return null;     
}

runRestGet method

public static String runRestGet(String baseUri, String path, String payload, String credentials, String keystore, String keypwd) throws ClientProtocolException, IOException {
String responseBody = null;
    CloseableHttpClient client = setupHttpClient(baseUri, keystore, keypwd);
                
    HttpGet request = new HttpGet(baseUri+path+payload);
    request.addHeader(HttpHeaders.AUTHORIZATION,"Basic " + credentials);
    request.setHeader(HttpHeaders.ACCEPT, "application/json");
    request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
        
    HttpResponse response = client.execute(request);
    int rc = response.getStatusLine().getStatusCode();
        
    responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
//System.out.println("Response body: " + responseBody);
        
    if (rc >= 200 && rc < 300) {
       return responseBody;
    } else {
       logger.log(NimLog.ERROR, "Got response code "+rc+" from method: "+response.getStatusLine().getReasonPhrase());
    }
    return responseBody;
}

runRestPut method

public static int runRestPut(String baseUri, String path, String payload, String credentials, String keystore, String keypwd) throws ClientProtocolException, IOException 

   CloseableHttpClient client = setupHttpClient(baseUri, keystore, keypwd);
 
   logger.log(NimLog.DEBUG, "URL: "+ baseUri+path);
     
   HttpPut request = new HttpPut(baseUri+path);
   request.addHeader(HttpHeaders.AUTHORIZATION,"Basic " + credentials);
   request.setHeader(HttpHeaders.ACCEPT, "application/json");
   request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
   request.setEntity(new StringEntity(payload, StandardCharsets.UTF_8));
          
   HttpResponse response = client.execute(request);
   int rc = response.getStatusLine().getStatusCode();
     
   if (rc >= 200 && rc < 300) {
      // do some error checking here
      return rc;
   } else {
      logger.log(NimLog.ERROR, "Got response code "+rc+" from method: "+response.getStatusLine().getReasonPhrase());
   }
   return rc;
}

setupHttpClient method

private static CloseableHttpClient setupHttpClient(String baseUri, String keyfile,    String keypwd)  {
   CloseableHttpClient httpclient = null;
   try {
 if (baseUri.startsWith("https")) {
    logger.log(NimLog.DEBUG, "setupHttpClient: Setting up https client");
    //Creating SSLContextBuilder object
    SSLContextBuilder SSLBuilder = SSLContexts.custom();
   
    // Loading the Keystore file
    File file = new File(keyfile);
    // Update the password for your key file 
    SSLBuilder = SSLBuilder.loadTrustMaterial(file,"#####".toCharArray());
 
    // Building the SSLContext
    SSLContext sslcontext = SSLBuilder.build();
  
    // Creating SSLConnectionSocketFactory object
    SSLConnectionSocketFactory sslConSocFactory = new SSLConnectionSocketFactory(sslcontext, new NoopHostnameVerifier());
  
    // Creating HttpClientBuilder
    HttpClientBuilder clientbuilder = HttpClients.custom();
 
    // Setting the SSLConnectionSocketFactory
    clientbuilder = clientbuilder.setSSLSocketFactory(sslConSocFactory);
 
    // Building the CloseableHttpClient
    httpclient = clientbuilder.build();
    return httpclient;
} else {
    logger.log(NimLog.DEBUG, "setupHttpClient: Setting up http client");
    httpclient = HttpClients.custom()
         .setConnectionTimeToLive(20, TimeUnit.SECONDS)
         .setMaxConnTotal(400).setMaxConnPerRoute(400)
         .setDefaultRequestConfig(RequestConfig.custom()
      .setSocketTimeout(120000).setConnectTimeout(5000).build())
       .setRetryHandler(new DefaultHttpRequestRetryHandler(5, true))
       .build();
    return httpclient;
}
   } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException e) {
 logger.log(NimLog.ERROR, "setupHttpClient: Exception trying to create the http client: " + e.getLocalizedMessage());
        logger.logStackTrace(NimLog.ERROR, e);
   }
   return httpclient;
}