#!/usr/bin/python

import gc
import sys
import atexit
import time
import timeit

import pyVmomi
import pyVim

from pyVim.connect import Connect, Disconnect
from pyVmomi.VmomiSupport import newestVersions
from optparse import OptionParser

def GetOptions():
    """
    Supports the command-line arguments listed below
    """
    parser = OptionParser()
    parser.add_option("-H", "--host",
                      default="sof-40609-srv",
                      help="Remote host to connect to.")
    parser.add_option("-u", "--user",
                      default="root",
                      help="User name to use when connecting to hostd.")
    parser.add_option("-p", "--password",
                      default="",
                      help="Password to use when connecting to hostd.")
    (options, _) = parser.parse_args()
    return options


class Attribute:
   def __init__(self, name, type, wildcard):
      self.name = name
      self.type = type
      self.wildcard = wildcard

   def __str__(self):
       return "%s:%s" % (self.name, self.type)

   def __repr__(self):
       return self.__str__()

class Counter:
   def __init__(self, id, name, attributes, type, unit, description):
      self.id = id
      self.name = name
      self.attributes = attributes
      self.type = type
      self.unit = unit
      self.description = description

   def __str__(self):
      attributes = ''
      for attr in self.attributes:
         if attributes != '':
            attributes += ', '
         attributes += str(attr)
      return "%d: %s(%s) [%s, %s]: %s" % (self.id, self.name, attributes, self.type, self.unit, self.description)

   def __repr__(self):
       return self.__str__()

class Stat:
   def __init__(self, cntr, attributesValues):
      self.cntr = cntr
      self.attributesValues = attributesValues

   def __str__(self):
      attributesValues = ''
      for i in range(0, len(self.attributesValues)):
         if attributesValues != '':
            attributesValues += ', '
         attributesValues += self.cntr.attributes[i].name + "='" + self.attributesValues[i] + "'"
      return "%s(%s)" % (self.cntr.name, attributesValues)

   def __repr__(self):
       return self.__str__()

counters = {}

def executeQuery(query, timer):
   gcold = gc.isenabled()
   gc.disable()
   try:
      beginTime = timer()
      result = query.Execute();
      endTime = timer()
      elapsedTime = endTime - beginTime
      print "Elapsed %f" % (elapsedTime)
      return result;
   finally:
      if gcold:
         gc.enable()

def main():
   # Process command line
   options = GetOptions()

   si = Connect(host = options.host,
                user = options.user,
                namespace = newestVersions.GetNamespace('vim'),
                pwd = options.password)
   atexit.register(Disconnect, si)

   timer = time.time

   hsi = si.RetrieveInternalContent()
   sr = hsi.GetStatsRegistry()[0]

   #
   # Just for the test - show raw stats, also
   #
   rawStat = sr.QueryRawStatsInt()
   print "Raw counters (%d):" % (len(rawStat))
   for stat in rawStat:
      attributes = []
      for attr in stat.statDef.attribute:
         attributes.append(Attribute(attr.name.key, attr.type.key, attr.wildcardAllowed))
      cntr = Counter(stat.id,
                     stat.statDef.name.key,
                     attributes,
                     stat.statDef.type.key,
                     stat.statDef.unit.label,
                     stat.statDef.name.summary)
      print "\t%s" % (str(cntr))

   #
   # Going to request all possible counters
   #
   rawSpec = pyVmomi.Vim.Stats.Query.Spec()
   querySpec = pyVmomi.Vim.Stats.Query.Spec()

   #
   # Just for the test - show raw stats, also
   #
   supportedStat = sr.supportedStat
   print "Supported counters (%d):" % (len(supportedStat))
   for stat in supportedStat:
      statLabel = stat.key
      statId = stat.id
      attributes = []
      attributesValues = []

      request = True
      for attr in stat.statDef.attribute:
         attributes.append(Attribute(attr.name.key, attr.type.key, attr.wildcardAllowed))
         if attr.wildcardAllowed:
            attributesValues.append("*")
         else:
            request = False

      cntr = Counter(statId,
                     stat.statDef.name.key,
                     attributes,
                     stat.statDef.type.key,
                     stat.statDef.unit.label,
                     stat.statDef.name.summary)
      counters[statId] = cntr
      print "\t%s" % (str(cntr))

      if request:
         instance = pyVmomi.Vim.Stats.StatInstance()
         instance.label = statLabel
         instance.id = statId
         if len(attributesValues) > 0:
            instance.attribute = attributesValues
         querySpec.instance.append(instance)
      else:
         print "\tSkipping to request stat %s. At least one attribute is not supporting wild-card." % (str(cntr))

   for stat in rawStat:
      statLabel = stat.key
      statId = stat.id
      attributes = []
      attributesValues = []

      request = True
      for attr in stat.statDef.attribute:
         attributes.append(Attribute(attr.name.key, attr.type.key, attr.wildcardAllowed))
         if attr.wildcardAllowed:
            attributesValues.append("*")
         else:
            request = False

      if request:
         instance = pyVmomi.Vim.Stats.StatInstance()
         instance.label = statLabel
         instance.id = statId
         if len(attributesValues) > 0:
            instance.attribute = attributesValues
         rawSpec.instance.append(instance)
      else:
         print "\tSkipping to request stat %s. At least one attribute is not supporting wild-card." % (str(cntr))

   if len(rawSpec.instance) > 0:
      print "Executing: "
      for inst in rawSpec.instance:
         cntr = counters[inst.id]
         stat = Stat(cntr, inst.attribute)
         print "\t%s" % (str(stat))

      result = sr.QueryStatValuesInt(rawSpec)
      print "Result (%d):" % (len(result))
      for value in result:
         cntr = counters[value.id]
         stat = Stat(cntr, value.attribute)

         if (value.value != -9223372036854775808):
            if cntr.unit != '%':
               print "\t%s = %d %s" % (str(stat), value.value, cntr.unit)
            else:
               print "\t%s = %.2f %%" % (str(stat), float(value.value) / 100)
         else:
            print "\t%s = N/A" % (str(stat))

   if len(querySpec.instance) > 0:
      #
      # This call is creating a managed object in the HostD
      #
      query = sr.CreateQuery(querySpec)

      print "Executing: "
      for inst in querySpec.instance:
         cntr = counters[inst.id]
         stat = Stat(cntr, inst.attribute)
         print "\t%s" % (str(stat))

      print "First pass ............."
      result = executeQuery(query, timer)
      firstSampleTS = result.timestamp

      print "............. sleeping ............."
      time.sleep(1)

      #
      # We need to do second pass and take the result from it,
      # because many statistics are delta or rate and they need at least two
      # samples in order to produce valid value.
      #
      print "............. second pass ............."
      result = executeQuery(query, timer)

      print "Result sampled between %s and %s (%d):" % (firstSampleTS, result.timestamp, len(result.statValue))
      for value in result.statValue:
         cntr = counters[value.id]
         stat = Stat(cntr, value.attribute)

         if (value.value != -9223372036854775808):
            if cntr.unit != '%':
               print "\t%s = %d %s" % (str(stat), value.value, cntr.unit)
            else:
               print "\t%s = %.2f %%" % (str(stat), float(value.value) / 100)
         else:
            print "\t%s = N/A" % (str(stat))

      print "Queries available on the server:"
      queries = sr.RetrieveQueriesInt()
      print queries

      #
      # Queries should be deleted automatically when the sessions expires.
      # However, here we are testing hostd.stats.Query.destroy() method.
      #
      print "Deleting queries..."
      for q in queries:
         q.Destroy()
   else:
      print "No counters to request!"

# Start program
if __name__ == "__main__":
   main()
