<template name="Device availability" category="qos">
  <description>Report data on availability of switches and routers</description>
  <section name="% Availability of switches and routers">
    <description>% availability of switches and routers based on continuity of receiving data from a switch and sysUpTime</description>
    <usage>Select the Interval over which availability is to be calculated and the Path (ie >>Zone>Group>Agent hierarchy) containing devices for which the availability report is required</usage>
    <input label="Interval" name="interval" type="string" value = "lastHour">
        <option value="lastHour" />
        <option value="today" />
        <option value="thisWeek" />
        <option value="last7Days" />
        <option value="thisMonth" />
        <option value="last30Days" />
    </input>
    <input label="Path" name="path" type="path" value="" required="false" />
    <input label="Include 100%" name="includeall" type="string" value="yes">
      <option value="yes" />
      <option value="no" />
    </input>
    <input label="Include sysDescr" name="includeSysDescr" type="string" value="no">
      <option value="yes" />
      <option value="no" />
    </input>
    <script><![CDATA[

var view = "historycounters";

// get the interval size with a dummy query
var dummy = Query.topN(view, "", "agent = null", interval, null, null).run();

// and use it to calculate the time window and uptime threshold
var start_ms = dummy.start.getTime();
var end_ms = dummy.end.getTime();
var now = new Date();
now.setSeconds(0);
var now_ms = now.getTime();
if(end_ms > now_ms) end_ms = now_ms;
var intervalMins = Math.round((end_ms - start_ms) / 60000);
var centiSecsSinceStart = Math.round((now_ms - start_ms) / 10);

var net = new Network();
if(typeof(path) != 'undefined') net.path = path;

var agents = net.agents();
var checkAgents = new Array();
var uptime = new Array();

// for computing mean
var mean_total = 0;
var mean_n = 0;

// see who has been up the whole time, and count them as 100%
// collect the others in a list for further processing
for each (var agentIP in agents) {
  net.path = agentIP;
  var sysUp = net.sysUpTime();
  if (sysUp >= centiSecsSinceStart) {
   if("yes" == includeall) uptime[agentIP] = 100.0;
   mean_total += 100.0;
   mean_n++;
  }
  else checkAgents.push(agentIP);
}

if(checkAgents.length > 0) {
  var where = "agent=" + checkAgents.join();
  var select = "agent,count(intervalstart)";
  var sort = "count(intervalstart)";
  var n = null;
  var result = Query.topN(view, select, where, interval, sort, n).run();
  for (var r=0; r < result.nrows; r++) {
    var agentIP = result.cell(r, 0);
    if(agentIP != null) {
      var minuteCount = result.cell(r, 1);
      var percentUp = minuteCount * 100.0 / intervalMins;
      // if percentUp == 100.0, then perhaps we should treat that the
      // same as if sysUpTime dated back to before the start - but what
      // if a switch is rebooting in less than a minute?  Better to show
      // an extra column "last boot" so that this can be detected. See below.
      uptime[agentIP] = percentUp;
      mean_total += percentUp;
      mean_n++;
    }
  }
}

var availData = Table.create(["agent", "name", "Zone", "Group", "availability (%)", "uptime (min)", "last boot"], ["agent", "string", "string", "string", "double", "integer", "time"]);

var sysDescrCol = new Array();

for (var agentIP in uptime) {
  net.path = agentIP;
  uptimePercent = uptime[agentIP];
  var sysUp = net.sysUpTime();
  lastBoot_ms = now_ms - (sysUp * 10);
  lastBoot = new Date(lastBoot_ms);
  availData.addRow([net.path, net.sysName(), net.zone(), net.group(), uptimePercent, (sysUp / 6000), lastBoot]);
  if("yes" == includeSysDescr) sysDescrCol.push(net.sysDescr());
}

if("yes" == includeSysDescr) availData.addColumn("sysDescr", "string", sysDescrCol);

var report = Report.current();
var date = new Date(report.getTime());
report.heading(interval + " availability report run at " + date);
// report.paragraph("" + dummy.start + " - " + dummy.end);

if(availData.nrows == 0) {
  report.paragraph("Average availability = 100%");
}
else {
  // should really be sorting by both availability and uptime
  availData.sort(4, 0);
  var mean = (mean_total / mean_n).toFixed(2);
  report.paragraph("Average availability = " + mean + "%  (n=" + mean_n + ")");
}

report.table(availData);

    ]]></script>
  </section>
</template>