Quantcast
Channel: Symantec Connect - Endpoint Management - Articles
Viewing all articles
Browse latest Browse all 706

Patch Trending - Linking Gauge Controls to Create a Dashboard with Aggregate Compliance

$
0
0

Introduction

In a previous article [1] we learnt how to create a gauge-control to quickly review the patch compliance level for a server. How can we extend this view to multiple servers for example in hierarchy?

This article will detail how to achieve this, and an upcoming article will also detail how to create a Global Patch Trending page on a parent server (without using hierarchy or replication).

Here is the output we will achieve from this article:

gauge_sample_ii.png

Pre-requisite: you must have the Patch Trending toolkit running on your Client Facing SMP's before you can create a global gauge control.

Top

Design

In order to keep the task as simple as possible we will not replicate any data from the Client Facing SMP's (CF-SMP). Rather we will load the compliance data javascript files in turn and build up a gauge control, including a global compliance gauge based aggregate data.

In this manner you can add the page to a Console web-part and replicate it to all child servers (via standalone of hierarchy replication) and it will work in all cases.

In addition to a single gauge control (displaying the 4 entries) we will add a one line summary of the global situation, with the count of applicable, installed and vulnerable updates.

Top

Implementation

So, let's get started. In this document we will use 3 CF-SMP named SMP-NALA, SMP-EMEA, SMP-APAC and a reporting server named SMP-Global.

We use a single gauge control so the html code in itself is super simple:

<html>
  <head>
    <title>Global compliance gauge view</title>
  </head>
  <body style="width: 1000px; font-family:arial; margin-left: auto; margin-right: auto">
  <div id='text_div'></div>
    <div id='chart_div'></div>
  </body>
</html>

Then we need to code in the Javascript to gather the data from the various servers, but before we do that let's make sure the results will be satisfactory. To this avail we will hard code the gauge data inside the javascript (data is random and shown in bold italic):

<html>
  <head>
    <title>Global compliance gauge view</title>
    <script type='text/javascript' src='https://www.google.com/jsapi'></script>
    <script type='text/javascript'>
 
    google.load('visualization', '1', {packages:['gauge']});
    google.setOnLoadCallback(drawchart);
    
    function logevent(msg) {
      var d = document.getElementById("text_div");
      d.innerHTML = "<h3>" + msg  + "</h3>";
    }
 
    
    function drawchart() {
    
      var smp_nala_compl = 94.3;
      var smp_emea_compl = 93.4;
      var smp_apac_compl = 96.5;
 
      var inst = 1832682;
      var appl = 1933472;
      var vuln = appl - inst;
      
      logevent("Global Patch Compliance summary: Applicable = " + appl + ", Installed = " + inst + ", Vulnerable = " + vuln + ".");
      
      var global_compl = (inst/appl) * 100;
    
      var data = google.visualization.arrayToDataTable([
        ['Label', 'Value'],
        ['nala', smp_nala_compl],
        ['emea', smp_emea_compl],
        ['apac', smp_apac_compl],
        ['Global', Math.round(global_compl * 100) / 100]
      ]);
      
      var options = {
        width: 1000, height: 200,
        greenFrom:90, greenTo: 100,
        redFrom: 00, redTo: 75,
        yellowFrom:75, yellowTo: 90,
        minorTicks: 5
      };
 
      var chart = new google.visualization.Gauge(document.getElementById('chart_div'));
      chart.draw(data, options);
      
    }
 
    </script>
  </head>
  <body style="width: 1000px; font-family:arial; margin-left: auto; margin-right: auto">
  <div id='text_div'></div>
    <div id='chart_div'></div>
  </body>
</html>

This generates the following result, which is exactly what we are after (it's the same image as shown in the introduction in case you wondered ;):

gauge_sample_ii.png

Now, we can dig in the technical part: in order to gather each server compliance and calculate the global compliance we must load global_1.js file from each server in turn, as these files all define the same variables (so we cannot add them simply as remote javascript).

We could use xmlhttp to do this and evaluate the response as javascript, however I have decided to let the browser download the javascript by using a small function to add the script source dynamically.

The loading implementation is done with the following threading model in mind:

Multi-server_Gauge-chart.png

The cascading execution is required because we want to make sure the data is loaded before we attempt to use it. So we insert the js file into the document, and then wait for a timeout to expire. Once the timeout expired (and the data loaded) we can copy the data (to store it as it will be over-written when loading the next global_1.js file) for later use. Here is the javascript skeleton of this waterfall:

loadjs(server_1_js_uri);
window.setTimeout(server_2_onTimeout, 500);

function server_2_onTimeout () {
    loadjs(server_2_js_uri);
    window.setTimeout(server_2_onTimeout, 500);
}

function server_3_onTimeout () {
    loadjs(server_3_js_uri);
    window.setTimeout(server_3_onTimeout, 500);
}

// if you need ore than 3 servers, you can carry on...

function server_n_onTimeout () {
    loadjs(server_n_js_uri);
    drawchart();
}

Now this is the simplified outline. In practice I had to resort to something a little more complex, because of browser specific issues.

Instead of calling directly the loadjs function I added a callback function on the remote server that contains a single function call. In this manner we avoid thread synchronization issues or calling functions before data is available etc.

Here is the final code, with the variables you should change highlighted:

<html>
  <head>
    <title>Global compliance gauge view</title>
    <script type='text/javascript' src='https://www.google.com/jsapi'></script>
  </head>
  <body style="width: 1000px; font-family:arial; margin-left: auto; margin-right: auto">
  <div id='text_div'></div>
    <div id='chart_div'></div>
  </body>
  <script type="text/javascript">
    google.load('visualization', '1', {packages:['gauge']});
    
    function logevent(msg) {
      var d = document.getElementById("text_div");
      d.innerHTML = "<h3>" + msg  + "</h3>";
    }

    function drawchart() {
    
      var nala_compl = global_local[0][1] / global_local[0][2] * 100;
      var emea_compl = global_local[1][1] / global_local[1][2] * 100;
      var apac_compl = global_local[2][1] / global_local[2][2] * 100;

      var inst = global_local[0][1] + global_local[1][1] + global_local[2][1];
      var appl = global_local[0][2] + global_local[1][2] + global_local[2][2];
      var vuln = inst - appl;
      
      logevent("Global Patch Compliance summary: Applicable = " + appl + ", Installed = " + inst + " Vulnerable = " + vuln + ".");
      var global_compl = (global_local[0][1] + global_local[1][1] + global_local[2][1]) / (global_local[0][2] + global_local[1][2] + global_local[2][2]) * 100;

      var data = google.visualization.arrayToDataTable([
        ['Label', 'Value'],
        ['nala', Math.round(nala_compl * 100) / 100],
        ['emea', Math.round(emea_compl * 100) / 100],
        ['apac', Math.round(apac_compl * 100) / 100],
        ['Global', Math.round(global_compl * 100) / 100]
      ]);

      var options = {
        width: 1000, height: 200, minorTicks: 5,
        greenFrom:  90, greenTo: 100,
        redFrom:    00, redTo:    75,
        yellowFrom: 75, yellowTo: 90
      };

      var chart = new google.visualization.Gauge(document.getElementById('chart_div'));
      chart.draw(data, options);
    }

    function loadjs(filename){
      var fileref = document.createElement('script');
      fileref.setAttribute("type","text/javascript");
      fileref.setAttribute("src", filename);	      

      if (typeof fileref!="undefined")
        document.getElementsByTagName("head")[0].appendChild(fileref);
    }

    var nala;
    var emea;
    var apac;

    var global_local = new Array();
    function nala_onloaded () {
      nala = global_1;
      global_local[0] = nala[nala.length -1];
      logevent("emea global compliance data is being loaded into the page...");
      loadjs("http://emea.domain.com/altiris/ns/patchtrending/javascript/global_1.js");
      window.setTimeout(emea_onTimeout, 500);
    }

    function emea_onloaded () {
      emea = global_1;
      global_local[1] = emea[emea.length -1];
      logevent("apac global compliance data is being loaded into the page...");
      loadjs("http://apac.domain.com/altiris/ns/patchtrending/javascript/global_1.js");
      window.setTimeout(apac_onTimeout, 500);
    }

    function apac_onloaded () {
      apac = global_1;
      global_local[2] = apac[apac.length -1];
      drawchart();
    }

    function nala_onTimeout () {
      loadjs("http://nala.domain.com/altiris/ns/patchtrending/javascript/callback.js");
    }

    function emea_onTimeout () {
      loadjs("http://emea.domain.com/altiris/ns/patchtrending/javascript/callback.js");    
    }

    function apac_onTimeout () {
      loadjs("http://apac.domain.com/altiris/ns/patchtrending/javascript/callback.js");
    }

    logevent("nala global compliance data is being loaded into the page...");
    loadjs("http://nala.domain.com/altiris/ns/patchtrending/javascript/global_1.js");
    window.setTimeout(nala_onTimeout, 500);
</script>
</html> 

And here is the callback.js file content for each server:

nala_onloaded() // callback.js content on nala server

emea_onloaded() // callback.js content on emea server

apac_onloaded() // callback.js content on apac server

Top

Conclusion

you should be able to link your client facing server data now in order to build-up a global compliance chart. You could also integrate this chart in the SMP console using techniques already described in [1].

Top

References

[1Patch Trending: Creating a Gauge Chart to Show Global Compliance on the Console

Top


Viewing all articles
Browse latest Browse all 706

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>