#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2014             mk@mathias-kettner.de |
# +------------------------------------------------------------------+
#
# This file is part of Check_MK.
# The official homepage is at http://mathias-kettner.de/check_mk.
#
# check_mk is free software;  you can redistribute it and/or modify it
# under the  terms of the  GNU General Public License  as published by
# the Free Software Foundation in version 2.  check_mk is  distributed
# in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with-
# out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A
# PARTICULAR PURPOSE. See the  GNU General Public License for more de-
# tails. You should have  received  a copy of the  GNU  General Public
# License along with GNU Make; see the file  COPYING.  If  not,  write
# to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor,
# Boston, MA 02110-1301 USA.

# This agent version uses predefined soap inquiries which are sent
# to an esx host system. # Unlike the classic agent the reported data
# isn't processed through the pysphere module.
# Instead a simple string process approach is used which drastically
# reduces the CPU load for this agent

import httplib, pprint, sys, os, getopt, socket, time, datetime, re
from xml.dom import minidom

# Great article how to get additional information
# http://www.veeam.com/kb1007

telegram_list = {
       "systeminfo":
         '<ns1:RetrieveServiceContent xsi:type="ns1:RetrieveServiceContentRequestType">'\
         '<ns1:_this type="ServiceInstance">ServiceInstance</ns1:_this></ns1:RetrieveServiceContent>',

       "login":
         '<ns1:Login xsi:type="ns1:LoginRequestType"><ns1:_this type="SessionManager">%(sessionManager)s</ns1:_this>'\
         '<ns1:userName>%(username)s</ns1:userName><ns1:password>%(password)s</ns1:password></ns1:Login>',

       "hostsystems":
         '<ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType">'\
         '<ns1:_this type="PropertyCollector">%(propertyCollector)s</ns1:_this><ns1:specSet>'\
         '<ns1:propSet><ns1:type>HostSystem</ns1:type><ns1:pathSet>name</ns1:pathSet></ns1:propSet>'\
         '<ns1:objectSet><ns1:obj type="Folder">%(rootFolder)s</ns1:obj><ns1:skip>false</ns1:skip>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>visitFolders</ns1:name>'\
           '<ns1:type>Folder</ns1:type><ns1:path>childEntity</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToHf</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToVmf</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>crToH</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>crToRp</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToDs</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>hToVm</ns1:name></ns1:selectSet>'\
         '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToVmf</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>vmFolder</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToDs</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>datastore</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToHf</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>hostFolder</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>crToH</ns1:name><ns1:type>ComputeResource</ns1:type>'\
         '<ns1:path>host</ns1:path><ns1:skip>false</ns1:skip></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>crToRp</ns1:name><ns1:type>ComputeResource</ns1:type>'\
         '<ns1:path>resourcePool</ns1:path><ns1:skip>false</ns1:skip>'\
         '<ns1:selectSet><ns1:name>rpToRp</ns1:name></ns1:selectSet>'\
         '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>rpToRp</ns1:name><ns1:type>ResourcePool</ns1:type>'\
           '<ns1:path>resourcePool</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>rpToRp</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>hToVm</ns1:name><ns1:type>HostSystem</ns1:type>'\
           '<ns1:path>vm</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>rpToVm</ns1:name><ns1:type>ResourcePool</ns1:type>'\
         '<ns1:path>vm</ns1:path><ns1:skip>false</ns1:skip></ns1:selectSet>'\
         '</ns1:objectSet></ns1:specSet><ns1:options></ns1:options></ns1:RetrievePropertiesEx>',

     "datastores":
         '<ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType">'\
         '<ns1:_this type="PropertyCollector">%(propertyCollector)s</ns1:_this><ns1:specSet>'\
         '<ns1:propSet><ns1:type>Datastore</ns1:type><ns1:pathSet>name</ns1:pathSet>'\
         '<ns1:pathSet>summary.freeSpace</ns1:pathSet>'\
         '<ns1:pathSet>summary.capacity</ns1:pathSet>'\
         '<ns1:pathSet>summary.uncommitted</ns1:pathSet>'\
         '<ns1:pathSet>summary.url</ns1:pathSet>'\
         '<ns1:pathSet>summary.accessible</ns1:pathSet>'\
         '<ns1:pathSet>summary.type</ns1:pathSet>'\
         '<ns1:pathSet>summary.maintenanceMode</ns1:pathSet></ns1:propSet>'\
         '<ns1:objectSet><ns1:obj type="Folder">%(rootFolder)s</ns1:obj><ns1:skip>false</ns1:skip>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>visitFolders</ns1:name>'\
           '<ns1:type>Folder</ns1:type><ns1:path>childEntity</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToHf</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToVmf</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>crToH</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>crToRp</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToDs</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>hToVm</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToVmf</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>vmFolder</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToDs</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>datastore</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToHf</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>hostFolder</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>crToH</ns1:name><ns1:type>ComputeResource</ns1:type>'\
         '<ns1:path>host</ns1:path><ns1:skip>false</ns1:skip></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>crToRp</ns1:name><ns1:type>ComputeResource</ns1:type>'\
           '<ns1:path>resourcePool</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>rpToRp</ns1:name></ns1:selectSet>'\
         '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>rpToRp</ns1:name><ns1:type>ResourcePool</ns1:type>'\
           '<ns1:path>resourcePool</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>rpToRp</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>hToVm</ns1:name><ns1:type>HostSystem</ns1:type>'\
           '<ns1:path>vm</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>rpToVm</ns1:name><ns1:type>ResourcePool</ns1:type>'\
         '<ns1:path>vm</ns1:path><ns1:skip>false</ns1:skip></ns1:selectSet>'\
         '</ns1:objectSet></ns1:specSet><ns1:options></ns1:options></ns1:RetrievePropertiesEx>',

     "licensesused": """
        <ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType">
          <ns1:_this type="PropertyCollector">%(propertyCollector)s</ns1:_this>
          <ns1:specSet>
            <ns1:propSet>
              <ns1:type>LicenseManager</ns1:type>
              <all>0</all>
              <ns1:pathSet>licenses</ns1:pathSet>
            </ns1:propSet>
            <ns1:objectSet>
              <ns1:obj type="LicenseManager">%(licenseManager)s</ns1:obj>
            </ns1:objectSet>
          </ns1:specSet>
          <ns1:options/>
        </ns1:RetrievePropertiesEx>
    """,

     "perfcountersummary":
         '<ns1:QueryPerfProviderSummary xsi:type="ns1:QueryPerfProviderSummaryRequestType">'\
         '<ns1:_this type="PerformanceManager">%(perfManager)</ns1:_this>'\
         '<ns1:entity type="HostSystem">%(esxhost)s</ns1:entity></ns1:QueryPerfProviderSummary>',

     "perfcountersyntax":
         '<ns1:QueryPerfCounter xsi:type="ns1:QueryPerfCounterRequestType">'\
         '<ns1:_this type="PerformanceManager">%(perfManager)s</ns1:_this>%(counters)s</ns1:QueryPerfCounter>',

     "perfcounteravail":
         '<ns1:QueryAvailablePerfMetric xsi:type="ns1:QueryAvailablePerfMetricRequestType">'\
         '<ns1:_this type="PerformanceManager">%(perfManager)s</ns1:_this>'\
         '<ns1:entity type="HostSystem">%(esxhost)s</ns1:entity>'\
         '<ns1:intervalId>20</ns1:intervalId></ns1:QueryAvailablePerfMetric>',

     "perfcounterdata":
         '<ns1:QueryPerf xsi:type="ns1:QueryPerfRequestType"><ns1:_this type="PerformanceManager">%(perfManager)s</ns1:_this>'\
         '<ns1:querySpec><ns1:entity type="HostSystem">%(esxhost)s</ns1:entity><ns1:maxSample>%(samples)s</ns1:maxSample>%(counters)s'\
         '<ns1:intervalId>20</ns1:intervalId></ns1:querySpec></ns1:QueryPerf>',

     "networksystem":
         '<ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType">'\
         '<ns1:_this type="PropertyCollector">%(propertyCollector)s</ns1:_this><ns1:specSet>'\
         '<ns1:propSet><ns1:type>HostNetworkSystem</ns1:type><all>0</all>'\
         '<ns1:pathSet>networkInfo</ns1:pathSet></ns1:propSet>'\
         '<ns1:objectSet><ns1:obj type="HostNetworkSystem">networkSystem</ns1:obj>'\
         '</ns1:objectSet></ns1:specSet><ns1:options></ns1:options></ns1:RetrievePropertiesEx>',

     "esxhostdetails":
         '<ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType">'
         '<ns1:_this type="PropertyCollector">%(propertyCollector)s</ns1:_this><ns1:specSet><ns1:propSet>'\
         '<ns1:type>HostSystem</ns1:type>'\
         '<ns1:pathSet>summary.quickStats.overallMemoryUsage</ns1:pathSet>'\
         '<ns1:pathSet>hardware.cpuPkg</ns1:pathSet>'\
#         '<ns1:pathSet>hardware.pciDevice</ns1:pathSet>'\
         '<ns1:pathSet>runtime.powerState</ns1:pathSet>'\
         '<ns1:pathSet>summary.quickStats.overallCpuUsage</ns1:pathSet>'\
         '<ns1:pathSet>hardware.biosInfo.biosVersion</ns1:pathSet>'\
         '<ns1:pathSet>hardware.biosInfo.releaseDate</ns1:pathSet>'\
         '<ns1:pathSet>hardware.cpuInfo.hz</ns1:pathSet>'\
         '<ns1:pathSet>hardware.cpuInfo.numCpuThreads</ns1:pathSet>'\
         '<ns1:pathSet>hardware.cpuInfo.numCpuPackages</ns1:pathSet>'\
         '<ns1:pathSet>hardware.cpuInfo.numCpuCores</ns1:pathSet>'\
         '<ns1:pathSet>config.multipathState.path</ns1:pathSet>'\
         '<ns1:pathSet>hardware.systemInfo.model</ns1:pathSet>'\
         '<ns1:pathSet>hardware.systemInfo.uuid</ns1:pathSet>'\
         '<ns1:pathSet>hardware.systemInfo.otherIdentifyingInfo</ns1:pathSet>'\
         '<ns1:pathSet>hardware.systemInfo.vendor</ns1:pathSet>'\
         '<ns1:pathSet>name</ns1:pathSet>'\
         '<ns1:pathSet>overallStatus</ns1:pathSet>'\
         '<ns1:pathSet>runtime.healthSystemRuntime.systemHealthInfo.numericSensorInfo</ns1:pathSet>'\
         '<ns1:pathSet>runtime.healthSystemRuntime.hardwareStatusInfo.storageStatusInfo</ns1:pathSet>'\
         '<ns1:pathSet>runtime.healthSystemRuntime.hardwareStatusInfo.cpuStatusInfo</ns1:pathSet>'\
         '<ns1:pathSet>runtime.healthSystemRuntime.hardwareStatusInfo.memoryStatusInfo</ns1:pathSet>'\
         '<ns1:pathSet>runtime.inMaintenanceMode</ns1:pathSet>'\
         '<ns1:pathSet>hardware.memorySize</ns1:pathSet></ns1:propSet>'\
         '<ns1:objectSet><ns1:obj type="Folder">%(rootFolder)s</ns1:obj><ns1:skip>false</ns1:skip>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>visitFolders</ns1:name>'\
           '<ns1:type>Folder</ns1:type><ns1:path>childEntity</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToHf</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToVmf</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>crToH</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>crToRp</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToDs</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>hToVm</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToVmf</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>vmFolder</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToDs</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>datastore</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToHf</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>hostFolder</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>crToH</ns1:name><ns1:type>ComputeResource</ns1:type>'\
           '<ns1:path>host</ns1:path><ns1:skip>false</ns1:skip></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>crToRp</ns1:name><ns1:type>ComputeResource</ns1:type>'\
           '<ns1:path>resourcePool</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>rpToRp</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>rpToRp</ns1:name><ns1:type>ResourcePool</ns1:type>'\
           '<ns1:path>resourcePool</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>rpToRp</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>hToVm</ns1:name><ns1:type>HostSystem</ns1:type>'\
           '<ns1:path>vm</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>rpToVm</ns1:name><ns1:type>ResourcePool</ns1:type>'\
           '<ns1:path>vm</ns1:path><ns1:skip>false</ns1:skip></ns1:selectSet>'\
         '</ns1:objectSet></ns1:specSet><ns1:options></ns1:options></ns1:RetrievePropertiesEx>',

     "vmdetails":
         '<ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType">'\
         '<ns1:_this type="PropertyCollector">%(propertyCollector)s</ns1:_this><ns1:specSet><ns1:propSet>'\
         '<ns1:type>VirtualMachine</ns1:type>'\
           '<ns1:pathSet>summary.quickStats.consumedOverheadMemory</ns1:pathSet>'\
           '<ns1:pathSet>config.hardware.numCPU</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.overallCpuDemand</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.distributedCpuEntitlement</ns1:pathSet>'\
           '<ns1:pathSet>runtime.host</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.distributedMemoryEntitlement</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.uptimeSeconds</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.sharedMemory</ns1:pathSet>'\
           '<ns1:pathSet>config.hardware.memoryMB</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.privateMemory</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.balloonedMemory</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.staticMemoryEntitlement</ns1:pathSet>'\
           '<ns1:pathSet>runtime.powerState</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.overallCpuUsage</ns1:pathSet>'\
           '<ns1:pathSet>config.hardware.numCoresPerSocket</ns1:pathSet>'\
           '<ns1:pathSet>config.hardware.device</ns1:pathSet>'\
           '<ns1:pathSet>config.template</ns1:pathSet>'\
           '<ns1:pathSet>guest.toolsVersion</ns1:pathSet>'\
           '<ns1:pathSet>guestHeartbeatStatus</ns1:pathSet>'\
           '<ns1:pathSet>name</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.compressedMemory</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.swappedMemory</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.guestMemoryUsage</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.staticCpuEntitlement</ns1:pathSet>'\
           '<ns1:pathSet>summary.quickStats.hostMemoryUsage</ns1:pathSet>'\
           '<ns1:pathSet>snapshot.rootSnapshotList</ns1:pathSet>'\
           '<ns1:pathSet>config.datastoreUrl</ns1:pathSet>'\
           '<ns1:pathSet>guest.toolsVersionStatus</ns1:pathSet></ns1:propSet>'\
         '<ns1:objectSet><ns1:obj type="Folder">%(rootFolder)s</ns1:obj><ns1:skip>false</ns1:skip>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>visitFolders</ns1:name>'\
           '<ns1:type>Folder</ns1:type><ns1:path>childEntity</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToHf</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToVmf</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>crToH</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>crToRp</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>dcToDs</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>hToVm</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToVmf</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>vmFolder</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToDs</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>datastore</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>dcToHf</ns1:name><ns1:type>Datacenter</ns1:type>'\
           '<ns1:path>hostFolder</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>crToH</ns1:name><ns1:type>ComputeResource</ns1:type>'\
         '<ns1:path>host</ns1:path><ns1:skip>false</ns1:skip></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>crToRp</ns1:name><ns1:type>ComputeResource</ns1:type>'\
           '<ns1:path>resourcePool</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>rpToRp</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>rpToRp</ns1:name><ns1:type>ResourcePool</ns1:type>'\
           '<ns1:path>resourcePool</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>rpToRp</ns1:name></ns1:selectSet>'\
           '<ns1:selectSet><ns1:name>rpToVm</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec">'\
           '<ns1:name>hToVm</ns1:name><ns1:type>HostSystem</ns1:type>'\
           '<ns1:path>vm</ns1:path><ns1:skip>false</ns1:skip>'\
           '<ns1:selectSet><ns1:name>visitFolders</ns1:name></ns1:selectSet></ns1:selectSet>'\
         '<ns1:selectSet xsi:type="ns1:TraversalSpec"><ns1:name>rpToVm</ns1:name><ns1:type>ResourcePool</ns1:type>'\
         '<ns1:path>vm</ns1:path><ns1:skip>false</ns1:skip></ns1:selectSet>'\
         '</ns1:objectSet></ns1:specSet><ns1:options></ns1:options></ns1:RetrievePropertiesEx>',

     "logout":
         '<ns1:Logout xsi:type="ns1:LogoutRequestType">'\
         '<ns1:_this type="SessionManager">%(sessionManager)s</ns1:_this></ns1:Logout>',

     "continuetoken":
         '<ns1:ContinueRetrievePropertiesEx xsi:type="ns1:ContinueRetrievePropertiesExRequestType">'\
         '<ns1:_this type="PropertyCollector">%(propertyCollector)s</ns1:_this><ns1:token>%(token)s</ns1:token></ns1:ContinueRetrievePropertiesEx>',

     "datacenters": """
  <ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType">
    <ns1:_this type="PropertyCollector">%(propertyCollector)s</ns1:_this>
    <ns1:specSet>
      <ns1:propSet>
        <ns1:type>Datacenter</ns1:type>
        <ns1:pathSet>name</ns1:pathSet>
      </ns1:propSet>
      <ns1:objectSet>
        <ns1:obj type="Folder">%(rootFolder)s</ns1:obj>
        <ns1:skip>false</ns1:skip>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>visitFolders</ns1:name>
          <ns1:type>Folder</ns1:type>
          <ns1:path>childEntity</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>dcToHf</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>dcToVmf</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>crToH</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>crToRp</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>dcToDs</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>hToVm</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>rpToVm</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>dcToVmf</ns1:name>
          <ns1:type>Datacenter</ns1:type>
          <ns1:path>vmFolder</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>dcToDs</ns1:name>
          <ns1:type>Datacenter</ns1:type>
          <ns1:path>datastore</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>dcToHf</ns1:name>
          <ns1:type>Datacenter</ns1:type>
          <ns1:path>hostFolder</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>crToH</ns1:name>
          <ns1:type>ComputeResource</ns1:type>
          <ns1:path>host</ns1:path>
          <ns1:skip>false</ns1:skip>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>crToRp</ns1:name>
          <ns1:type>ComputeResource</ns1:type>
          <ns1:path>resourcePool</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>rpToRp</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>rpToVm</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>rpToRp</ns1:name>
          <ns1:type>ResourcePool</ns1:type>
          <ns1:path>resourcePool</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>rpToRp</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>rpToVm</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>hToVm</ns1:name>
          <ns1:type>HostSystem</ns1:type>
          <ns1:path>vm</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>rpToVm</ns1:name>
          <ns1:type>ResourcePool</ns1:type>
          <ns1:path>vm</ns1:path>
          <ns1:skip>false</ns1:skip>
        </ns1:selectSet>
      </ns1:objectSet>
    </ns1:specSet>
    <ns1:options/>
  </ns1:RetrievePropertiesEx>""",

     "clustersofdatacenter": """
  <ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType">
    <ns1:_this type="PropertyCollector">propertyCollector</ns1:_this>
    <ns1:specSet>
      <ns1:propSet>
        <ns1:type>ClusterComputeResource</ns1:type>
        <ns1:pathSet>name</ns1:pathSet>
      </ns1:propSet>
      <ns1:objectSet>
        <ns1:obj type="Datacenter">%(datacenter)s</ns1:obj>
        <ns1:skip>false</ns1:skip>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>visitFolders</ns1:name>
          <ns1:type>Folder</ns1:type>
          <ns1:path>childEntity</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>dcToHf</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>dcToVmf</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>crToH</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>crToRp</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>dcToDs</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>hToVm</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>rpToVm</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>dcToVmf</ns1:name>
          <ns1:type>Datacenter</ns1:type>
          <ns1:path>vmFolder</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>dcToDs</ns1:name>
          <ns1:type>Datacenter</ns1:type>
          <ns1:path>datastore</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>dcToHf</ns1:name>
          <ns1:type>Datacenter</ns1:type>
          <ns1:path>hostFolder</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>crToH</ns1:name>
          <ns1:type>ComputeResource</ns1:type>
          <ns1:path>host</ns1:path>
          <ns1:skip>false</ns1:skip>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>crToRp</ns1:name>
          <ns1:type>ComputeResource</ns1:type>
          <ns1:path>resourcePool</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>rpToRp</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>rpToVm</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>rpToRp</ns1:name>
          <ns1:type>ResourcePool</ns1:type>
          <ns1:path>resourcePool</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>rpToRp</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>rpToVm</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>hToVm</ns1:name>
          <ns1:type>HostSystem</ns1:type>
          <ns1:path>vm</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>rpToVm</ns1:name>
          <ns1:type>ResourcePool</ns1:type>
          <ns1:path>vm</ns1:path>
          <ns1:skip>false</ns1:skip>
        </ns1:selectSet>
      </ns1:objectSet>
    </ns1:specSet>
    <ns1:options/>
  </ns1:RetrievePropertiesEx>""",

     "esxhostsofcluster":
  """<ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType">
    <ns1:_this type="PropertyCollector">propertyCollector</ns1:_this>
    <ns1:specSet>
      <ns1:propSet>
        <ns1:type>HostSystem</ns1:type>
        <ns1:pathSet>name</ns1:pathSet>
      </ns1:propSet>
      <ns1:objectSet>
        <ns1:obj type="ClusterComputeResource">%(clustername)s</ns1:obj>
        <ns1:skip>false</ns1:skip>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>visitFolders</ns1:name>
          <ns1:type>Folder</ns1:type>
          <ns1:path>childEntity</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>dcToHf</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>dcToVmf</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>crToH</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>crToRp</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>dcToDs</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>hToVm</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>rpToVm</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>dcToVmf</ns1:name>
          <ns1:type>Datacenter</ns1:type>
          <ns1:path>vmFolder</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>dcToDs</ns1:name>
          <ns1:type>Datacenter</ns1:type>
          <ns1:path>datastore</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>dcToHf</ns1:name>
          <ns1:type>Datacenter</ns1:type>
          <ns1:path>hostFolder</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>crToH</ns1:name>
          <ns1:type>ComputeResource</ns1:type>
          <ns1:path>host</ns1:path>
          <ns1:skip>false</ns1:skip>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>crToRp</ns1:name>
          <ns1:type>ComputeResource</ns1:type>
          <ns1:path>resourcePool</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>rpToRp</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>rpToVm</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>rpToRp</ns1:name>
          <ns1:type>ResourcePool</ns1:type>
          <ns1:path>resourcePool</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>rpToRp</ns1:name>
          </ns1:selectSet>
          <ns1:selectSet>
            <ns1:name>rpToVm</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>hToVm</ns1:name>
          <ns1:type>HostSystem</ns1:type>
          <ns1:path>vm</ns1:path>
          <ns1:skip>false</ns1:skip>
          <ns1:selectSet>
            <ns1:name>visitFolders</ns1:name>
          </ns1:selectSet>
        </ns1:selectSet>
        <ns1:selectSet xsi:type="ns1:TraversalSpec">
          <ns1:name>rpToVm</ns1:name>
          <ns1:type>ResourcePool</ns1:type>
          <ns1:path>vm</ns1:path>
          <ns1:skip>false</ns1:skip>
        </ns1:selectSet>
      </ns1:objectSet>
    </ns1:specSet>
    <ns1:options/>
  </ns1:RetrievePropertiesEx>"""
}

def put_in_envelope(payload):
    return '<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" '\
           'xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" '\
           'xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" '\
           'xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'\
           '<SOAP-ENV:Header></SOAP-ENV:Header><SOAP-ENV:Body xmlns:ns1="urn:vim25">' + payload + '</SOAP-ENV:Body></SOAP-ENV:Envelope>'

def convert_hostname(h):
    if opt_spaces == "cut":
        return h.split()[0]
    else:
        return h.replace(" ", "_")

def get_counters(esx_version_num):
    needed_ids = [
        # sys.uptime
        262144,
        # mem.*
        # 65635, 65537, 65577, 65625, 65545, 65611, 65573, 65615, 65582,
        # 65549, 65630, 65622, 65618, 65621, 65561, 65623, 65632, 65557,
        # 65628, 65633, 65541, 65643, 65586, 65553, 65569, 65589, 65639,
        # 65620, 65599, 65580, 65619, 65603,
        #  'disk.deviceLatency': 131091,
        #  'disk.deviceReadLatency': 131083,
        #  'disk.deviceWriteLatency': 131087,
        #  'disk.kernelLatency': 131092,
        #  'disk.kernelReadLatency': 131084,
        #  'disk.kernelWriteLatency': 131088,
        #  'disk.maxQueueDepth': 131096,
        #  'disk.maxTotalLatency': 131095,
        #  'disk.numberRead': 131076,
        #  'disk.numberReadAveraged': 131097,
        #  'disk.numberWrite': 131077,
        #  'disk.numberWriteAveraged': 131098,
        #  'disk.queueLatency': 131094,
        #  'disk.queueReadLatency': 131086,
        #  'disk.queueWriteLatency': 131090,
        #  'disk.read': 131078,
        #  'disk.totalLatency': 131093,
        #  'disk.totalReadLatency': 131085,
        #  'disk.totalWriteLatency': 131089,
        #  'disk.usage': 131073,
        # datastore counters
#  'datastore.datastoreIops': 655367,
#  'datastore.datastoreMaxQueueDepth': 655376,
#  'datastore.datastoreNormalReadLatency': 655372,
#  'datastore.datastoreNormalWriteLatency': 655373,
#  'datastore.datastoreReadBytes': 655368,
#  'datastore.datastoreReadIops': 655370,
#  'datastore.datastoreReadLoadMetric': 655377,
#  'datastore.datastoreReadOIO': 655374,
#  'datastore.datastoreWriteBytes': 655369,
#  'datastore.datastoreWriteIops': 655371,
#  'datastore.datastoreWriteLoadMetric': 655378,
#  'datastore.datastoreWriteOIO': 655375,
#  'datastore.maxTotalLatency': 655379,
#  'datastore.numberReadAveraged': 655360,
#  'datastore.numberWriteAveraged': 655361,
#  'datastore.read': 655362,
#  'datastore.sizeNormalizedDatastoreLatency': 655366,
#  'datastore.totalReadLatency': 655364,
#  'datastore.totalWriteLatency': 655365,
#  'datastore.write': 655363,
        655362,655363,655370,655371,655366,

        # disk.read/write/deviceLatency/numberRead/numberWrite
        131078, 131079, 131091, 131076, 131077,
    ]


    #needed_ids = [
    #    # sys.resourceMem*
    #    262151, 262155, 262169, 262152, 262154, 262153, 262157, 262156, 262168,
    #]

    # Seems as this is not available in ESX 5.0 but we saw it on 5.1
    if esx_version_num > 5.0:
        # sys.resourceMemConsumed
        needed_ids += [
            262171,
        ]

    if esx_version_num > 4.1:
        needed_ids += [
            # net.*
            196616, 196621, 196617, 196625, 196619, 196623, 196609, 196614,
            196620, 196624, 196615, 196622, 196618, 196612, 196613, 196626,
        ]

    return needed_ids

def usage():
    sys.stderr.write("""Check_MK vSphere Agent

USAGE: agent_vsphere [OPTIONS] HOST
       agent_vsphere -h

ARGUMENTS:
  HOST                          Host name or IP address of VMWare HostSystem

OPTIONS:
  -h, --help                    Show this help message and exit
  -u USER, --user USER          Username for vSphere login
  -s SECRET, --secret SECRET    Secret/Password for vSphere login
  -D, --direct                  Assume a directly queried host system (no vCenter). In
                                This we expect data about only one HostSystem to be
                                found and do not create piggy host data for that host.
  -P                            Skip placeholder virtualmachines. These backup vms are created
                                by the Site Recovery Manager (SRM) and are identified by not
                                having any assigned virtual disks.
  -p, --port port               Alternative port number (default is 443 for the https connection)
  --no-cert-check               Disables the checking of the servers ssl certificate
  --pysphere                    Fallback to old pysphere based special agent. It supports
                                ESX 4.1 but is very slow.
  -H, --hostname                Specify a hostname. This is neccessary if this is
                                different from HOST. It is being used when outputting
                                the hosts power state.
  -a, --agent                   Also retrieve data from the normal Check_MK Agent.
                                This makes sense if you query a vCenter that is
                                Installed on a Windows host that you also want to
                                Monitor with Check_MK.
  -t, --timeout SECS            Set the network timeout to vSphere to SECS seconds.
                                This is also used when connecting the agent (option -a).
                                Default is 60 seconds. Note: the timeout is not only
                                applied to the connection, but also to each individual
                                subquery.
  --debug                       Debug mode: let Python exceptions come through

  --tracefile FILENAME          Log all outgoing and incoming data into the given tracefile
  -i MODULES, --modules MODULES Modules to query. This is a comma separated list of
                                hostsystem, virtualmachine and storage. Default is to
                                query all modules.

  -c, --dump-counters           Simply dumping out all available counters and their values.
                                This mode is meant for debugging and diagnostic purposes.

  -S, --spaces HOW              How to handle spaces in hostnames. "cut": cut everyting
                                after the first space, "underscore": replace with
                                underscores. Default is "underscore".

  --vm_pwr_display WHERE        Specifies where the virtual machines power state should be shown
                                Default (no option) is on the queried vCenter or ESX-Host
                                Possible WHERE options: * esxhost : show on ESX host
                                                        * vm      : show on virtual machine
  --host_pwr_display WHERE      Specifies where the ESX hosts power state should be shown
                                Default (no option) is on the queried vCenter or ESX-Host
                                Possible WHERE options: * esxhost : show on ESX host
                                                        * vm      : show on virtual machine

""")

short_options = 'hi:u:s:Dat:H:Pp:S:'
long_options  = [
    'help', 'user=', 'secret=', 'direct', 'agent', 'debug', 'modules=', 'timeout=', 'no-cert-check',
    'hostname=', 'tracefile=', "pysphere", "port=", "spaces=", "host_pwr_display=", "vm_pwr_display="
]

opt_debug               = False
opt_direct              = False
opt_agent               = False
opt_timeout             = 60
opt_port                = 443
opt_hostname            = None
opt_skip_placeholder_vm = False
opt_pysphere            = False
opt_tracefile           = None
opt_host_pwr_display    = None
opt_vm_pwr_display      = None
opt_spaces              = "underscore"
opt_no_cert             = False

error = None
error_exit = 1

host_address  = None
user          = None
secret        = None
tracefile     = None
query_objects = [ 'hostsystem', 'virtualmachine', 'datastore', 'counters', 'licenses' ]

try:
    opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
except getopt.GetoptError, err:
    sys.stderr.write("%s\n" % err)
    sys.exit(1)

for o,a in opts:
    if o in [ '--debug' ]:
        opt_debug = True
    elif o in [ '--tracefile' ]:
        opt_tracefile = a
    elif o in [ '-D', '--direct' ]:
        opt_direct = True
    elif o in [ '-a', '--agent' ]:
        opt_agent = True
    elif o == '-P':
        opt_skip_placeholder_vm = True
    elif o in [ '-p', '--port' ]:
        opt_port = a
    elif o in [ '--no-cert-check' ]:
        opt_no_cert = True
    elif o == '--pysphere':
        opt_pysphere = True
    elif o in [ '-u', '--user' ]:
        user = a
    elif o in [ '-s', '--secret' ]:
        secret = a
    elif o in [ '-i', '--modules' ]:
        query_objects = a.split(',')
    elif o in [ '-t', '--timeout' ]:
        opt_timeout = int(a)
    elif o in [ '-H', '--hostname' ]:
        opt_hostname = a
    elif o in [ '--vm_pwr_display' ]:
        opt_vm_pwr_display = a
    elif o in [ '--host_pwr_display' ]:
        opt_host_pwr_display = a
    elif o in [ '-S', '--spaces']:
        if a not in [ "cut", "underscore" ]:
            usage()
            sys.exit(1)
        opt_spaces = a
    elif o in [ '-h', '--help' ]:
        usage()
        sys.exit(0)


# If the --pysphere option is set we use the legacy pysphere agent, though 50 times slower...
if opt_pysphere:
    path_vsphere_pysphere = os.path.dirname(os.path.abspath(__file__))
    cmd = [ "%s/agent_vsphere.pysphere" % path_vsphere_pysphere ]
    import subprocess
    p = subprocess.Popen(cmd + sys.argv[1:], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    out, err = p.communicate()
    if out:
        sys.stdout.write(out)
    if err:
        sys.stderr.write(err)
    sys.exit(p.returncode)

if len(args) == 1:
    host_address = args[0]
elif not args:
    sys.stderr.write("ERROR: No host given.\n")
    sys.exit(1)
else:
    sys.stderr.write("ERROR: Please specify exactly one host.\n")
    sys.exit(1)


vsphere_output = []
def output(line):
    vsphere_output.append(line)

socket.setdefaulttimeout(opt_timeout)
def get_agent_info_tcp(hostname):
    response = ""
    try:
        # TODO: gethostbyname() automatically detects IP addresses and does
        # *not* contact any nameserver in that case. So the following two
        # lines of code should not be neccessary:
        if hostname[0] in "123456789":
            ipaddress = hostname
        else:
            ipaddress = socket.gethostbyname(hostname)
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            s.settimeout(opt_timeout)
        except:
            pass # some old Python versions lack settimeout(). Better ignore than fail
        s.connect((ipaddress, 6556))
        try:
            s.setblocking(1)
        except:
            pass
        response = ""
        while True:
            out = s.recv(4096, socket.MSG_WAITALL)
            if out and len(out) > 0:
                response += out
            else:
                break
        s.close()
        return response
    except Exception, e:
        if opt_debug:
            raise
    return response


# Globals of ESX System. These settings are available after the first "systeminfo" query
systemfields = [
 ("apiVersion", float),
 ("name", None),
 ("rootFolder", None),
 ("perfManager", None),
 ("sessionManager", None),
 ("licenseManager", None),
 ("propertyCollector", None),
 ("version", None),
 ("build", None),
 ("vendor", None),
 ("osType", None),
]

systeminfo = {}

if opt_tracefile:
    tracefile_dir = os.path.dirname(opt_tracefile) or "."
    if os.path.exists(tracefile_dir):
        tracefile = file(opt_tracefile, "w")
    elif opt_debug:
        sys.stderr.write("Path for tracefile %s does not exist" % opt_tracefile)
        sys.stderr.flush()

def get_pattern(pattern, line):
    if not line:
        return []
    p = re.compile(pattern)
    return p.findall(line)

if tracefile:
    tracefile.write("Tracefile %s Host address: %s\n" %
                    (datetime.datetime.now().strftime("%Y-%m-%d %H:%M"), host_address))


host_cookie_path        = None
last_cookie_access_time = None
server_cookie           = None
server_handle           = None

class MKQueryServerException(Exception):
    pass

# Cookie storage is only available in OMD setups
if "OMD_SITE" in os.environ:
    cookie_path = os.path.expanduser("~/tmp/check_mk/agents/agent_vsphere")

    if not os.path.exists(cookie_path):
        os.makedirs(cookie_path)

    host_cookie_path = "%s/cookie.%s" % (cookie_path, host_address)

def delete_server_cookie():
    if host_cookie_path and os.path.exists(host_cookie_path):
        os.unlink(host_cookie_path)

def query_server(payload, payload_params = {}):
    # Finalize payload
    payload_params.update(systeminfo)
    soapdata = put_in_envelope(payload)
    soapdata = soapdata % payload_params

    def init_headers(soapdata):
        server_handle.putrequest("POST", "/sdk")
        server_handle.putheader("Content-Length", "%d" % len(soapdata))
        server_handle.putheader("Content-Type", 'text/xml; charset="utf-8"')
        server_handle.putheader("SOAPAction", "urn:vim25/5.0")
        server_handle.putheader("User-Agent", "VMware VI Client/5.0.0") # TODO: set client version?
        if server_cookie:
            server_handle.putheader("Cookie", server_cookie)
        server_handle.endheaders()
    init_headers(soapdata)

    response_data = []

    time_sent = time.time()
    server_handle.send(soapdata)

    def check_not_authenticated(text):
        if "NotAuthenticatedFault" in text:
            raise MKQueryServerException("No longer authenticated")

    response  = server_handle.getresponse()
    response_data.append(response.read())

    check_not_authenticated(response_data[0][:512])

    while True:
        # Look for a <token>0</token> field.
        # If it exists not all data was transmitted and we need to start a
        # ContinueRetrievePropertiesExResponse query...
        token = re.findall("<token>(.*)</token>", response_data[-1][:512])
        if token:
            payload_params.update({"token": token[0]})
            soapdata = put_in_envelope(telegram_list["continuetoken"]) % payload_params
            init_headers(soapdata)
            server_handle.send(soapdata)
            response  = server_handle.getresponse()
            response_data.append(response.read())
            check_not_authenticated(response_data[-1][:512])
        else:
            break


    time_response = time.time()

    if tracefile:
        tracefile.write("####   Sent  ####\n%s" % soapdata)
        timing_info = "Response took: %f" % (time_response - time_sent)
        tracefile.write("\n#### Received #### %s\n%s\n" % (timing_info, "".join(response_data)))

    return response.status, response.reason, response.msg, "".join(response_data)

def encode_url(text):
    for char, replacement in [ ( "&",  "&amp;"),
                               ( ">",  "&gt;" ),
                               ( "<",  "&lt;"),
                               ( "'",  "&apos;"),
                               ( "\"", "&quot;") ]:
        text = text.replace(char, replacement)
    return text


def connect_to_server():
    # Initialize server connection
    try:
        global server_handle
        netloc = host_address + ":" + str(opt_port)

        if opt_no_cert:
            try:
                import ssl
                server_handle = httplib.HTTPSConnection(netloc, context = ssl._create_unverified_context())
            except:
                server_handle = httplib.HTTPSConnection(netloc)
        else:
            server_handle = httplib.HTTPSConnection(netloc)

        if opt_debug:
            sys.stderr.write("Connecting to %s..." % netloc)
            sys.stderr.flush()

        server_handle.connect()
    except Exception, e:
        if opt_debug:
            raise
        global error
        error = "Cannot connect to vSphere Server. Please check the IP and SSL certificate (if applicable) "\
                "and try again. This error is not related to the login credentials. Error message: %r" % e

def retrieve_systeminfo():
    global systeminfo
    # Retrieve basic data, which requires no login
    payload = telegram_list["systeminfo"]
    reply_code, reply_msg, reply_headers, reply_data = query_server(payload)
    for entry, function in systemfields:
         element = get_pattern("<%(entry)s.*>(.*)</%(entry)s>" % { "entry": entry }, reply_data)
         if element:
             systeminfo[entry] = function and function(element[0]) or element[0]

def login():
    global server_cookie

    if host_cookie_path and os.path.exists(host_cookie_path):
        last_update = int(os.stat(host_cookie_path).st_mtime)
        server_cookie = file(host_cookie_path, "r").read()
    else:
        payload = telegram_list["login"]
        reply_code, repy_msg, reply_headers, reply_data = \
                    query_server(payload, payload_params = {"username": encode_url(user),
                                                            "password": encode_url(secret)})
        if "InvalidLogin" in reply_data:
            global error
            error = "Cannot login to vSphere Server. Login response is not 'OK'. Please check the credentials"
        else:
            server_cookie = reply_headers.get("Set-Cookie")
            if host_cookie_path and server_cookie:
                cookie_file = file(host_cookie_path, "w")
                os.chmod(host_cookie_path, 0600)
                cookie_file.write(server_cookie)



#   .--Main----------------------------------------------------------------.
#   |                        __  __       _                                |
#   |                       |  \/  | __ _(_)_ __                           |
#   |                       | |\/| |/ _` | | '_ \                          |
#   |                       | |  | | (_| | | | | |                         |
#   |                       |_|  |_|\__,_|_|_| |_|                         |
#   |                                                                      |
#   +----------------------------------------------------------------------+

connect_to_server()
retrieve_systeminfo()

if not systeminfo:
    sys.stderr.write("Unable to get data from Web API"+ "\n")
    sys.exit(1)

# The cookie access time is required to determine the agents check interval
# This is required later on by the performancecounters. Depending on the
# interval we need more or less real-time samples
if host_cookie_path and os.path.exists(host_cookie_path):
    last_cookie_access_time = os.stat(host_cookie_path).st_mtime
    os.utime(host_cookie_path, None) # Touch the cookie file, whenever it is accessed

login()

if not error:
    # If the data aquisition fails, e.g. invalid cookie we try another run
    run_count = 0
    while run_count < 2:
        run_count += 1

        # Note: If the cookie fails inbetween these calls, we also start a second run
        try:
            ##########################
            # Check MK header and Agent Version
            output("<<<check_mk>>>")
            output("Version: %.1f" % systeminfo["apiVersion"])
            output("AgentOS: %s" %   systeminfo["name"])

            output("<<<esx_systeminfo>>>")
            for entry in systeminfo.items():
                output("%s %s" % entry)


            #############################
            # Determine available host systems
            #############################
            hostsystems = {}

            reply_code, reply_msg, reply_headers, hostsystems_response = query_server(telegram_list["hostsystems"])
            elements = get_pattern('<obj type="HostSystem">(.*?)</obj>.*?<val xsi:type="xsd:string">(.*?)</val>', hostsystems_response)

            # On some ESX systems the cookie login does not work as expected, when the agent_vsphere
            # is called only once or twice a day. The cookie is somehow outdated, but there is no authentification
            # failed message. Instead, the query simply returns an empty data set..
            # We try to detect this here (there is always a hostsystem) and raise a MKQueryServerException
            # which forces a new login
            if not elements:
                raise MKQueryServerException("Login cookie is no longer valid")

            for hostsystem, name in elements:
                hostsystems[hostsystem] = name

            ###########################
            # Licenses
            ###########################
            if "licenses" in query_objects:
                reply_code, reply_msg, reply_headers, licenses_response = query_server(telegram_list["licensesused"])

                output("<<<esx_vsphere_licenses:sep(9)>>>")
                root_node     = minidom.parseString(licenses_response)
                licenses_node = root_node.getElementsByTagName("LicenseManagerLicenseInfo")
                for license_node in licenses_node:
                    total = license_node.getElementsByTagName("total")[0].firstChild.data
                    if total == "0":
                        continue
                    name  = license_node.getElementsByTagName("name")[0].firstChild.data
                    used  = license_node.getElementsByTagName("used")[0].firstChild.data
                    output("%s\t%s %s" % (name, used, total))


            ###########################
            # Datastores
            ###########################
            datastores = {} # We need the datastore info later on in the virtualmachines and counter sections
            reply_code, reply_msg, reply_headers, datastores_response = query_server(telegram_list["datastores"])
            elements = get_pattern('<objects><obj type="Datastore">(.*?)</obj>(.*?)</objects>', datastores_response)
            for datastore, content in elements:
                entries = get_pattern('<name>(.*?)</name><val xsi:type.*?>(.*?)</val>', content)
                datastores[datastore] = {}
                for name, value in entries:
                    datastores[datastore][name] = value

            if "datastore" in query_objects:
                output("<<<esx_vsphere_datastores:sep(9)>>>")
                for key in sorted(datastores.keys()):
                    data = datastores[key]
                    output("[%s]" % data.get("name"))
                    for ds_key in sorted(data.keys()):
                        if ds_key == "name":
                            continue
                        output("%s\t%s" % (ds_key.split(".")[1], data[ds_key]))

            ###########################
            # Counters
            ###########################
            if "counters" in query_objects:
                # Get additional interface counter info, this only works when querying ESX hosts
                # TODO: get this info from the vcenter
                net_extra_info = []
                if opt_direct:
                    reply_code, reply_msg, reply_headers, networksystem_response = query_server(telegram_list["networksystem"])
                    nic_objects = get_pattern('<pnic><key>(.*?)</pnic>', networksystem_response)
                    for nic in nic_objects:
                        nic_if = get_pattern('(.*?)</key><device>(.*?)</device>(.*)<mac>(.*?)</mac>', nic)
                        try:
                            bandwidth_block = nic_if[0][2]
                            bandwidth = get_pattern('</driver><linkSpeed><speedMb>(.*?)</speedMb>', bandwidth_block)
                            net_extra_info.append("net.macaddress|%s|%s|mac" % (nic_if[0][1], nic_if[0][3]))
                            if bandwidth:
                                net_extra_info.append("net.bandwidth|%s|%s|bytes" % (nic_if[0][1], int(bandwidth[0]) * 1000000))
                                net_extra_info.append("net.state|%s|1|state" % nic_if[0][1])
                            else:
                                net_extra_info.append("net.state|%s|2|state" % nic_if[0][1])
                        except Exception, e:
                            continue

                # Get counter syntax
                counter_syntax_payload = telegram_list["perfcountersyntax"]
                needed_ids             = get_counters(systeminfo["apiVersion"])
                counter_data = []
                for entry in needed_ids:
                    counter_data.append("<ns1:counterId>%s</ns1:counterId>" % entry)

                reply_code, reply_msg, reply_headers, counters_syntax_response = \
                    query_server(counter_syntax_payload, payload_params = { "counters": "".join(counter_data)})

                counters_syntax = {}
                elements = get_pattern('<returnval><key>(.*?)</key>.*?<key>(.*?)</key>.*?'\
                                       '<key>(.*?)</key>.*?<key>(.*?)</key>.*?', counters_syntax_response)

                for key, nameInfo, groupInfo, unitInfo in elements:
                    counters_syntax[key] = { "name": nameInfo, "group": groupInfo, "unit": unitInfo }


                # Determine the needed number of real-time samples
                # One real-time sample is 20 seconds -> With a check interval of 1 minute we need the last 3 samples
                # Longer check intervals require even more samples... n-minutes * 3
                # We set the max_samples hard cap to 180 (1 hour)
                # An ESX system does not offer more than one hour of real time samples, anyway.
                max_samples = 3
                if last_cookie_access_time:
                    timedelta = time.time() - last_cookie_access_time
                    max_samples = min(180, max(1, int(timedelta) / 20))

                hostnames = hostsystems.keys()
                counter_data_payload = telegram_list["perfcounterdata"]
                for idx, host in enumerate(hostnames):
                    if not opt_direct:
                        output("<<<<%s>>>>" % convert_hostname(hostsystems[host]))

                    ### TODO: check if this host supports perfdata
                    ### TODO: try to get esx hosts perfdata from vCenter
                    counter_avail = telegram_list["perfcounteravail"]
                    reply_code, reply_msg, reply_headers, counter_avail_response = query_server(counter_avail, payload_params = { "esxhost": host })

                    counters_avail  = {}
                    p = re.compile("<counterId>([0-9]*)</counterId><instance>([^<]*)")
                    elements = get_pattern("<counterId>([0-9]*)</counterId><instance>([^<]*)", counter_avail_response)
                    for counter, instance in elements:
                        counters_avail.setdefault(counter, []).append(instance)

                    counter_data = []
                    for entry in needed_ids:
                        for instance in counters_avail.get(entry, []):
                            counter_data.append("<ns1:metricId><ns1:counterId>%d</ns1:counterId><ns1:instance>%s</ns1:instance></ns1:metricId>" % (entry, instance))
                    counters_value = {}
                    reply_code, reply_msg, reply_headers, counter_data_response = \
                        query_server(counter_data_payload, payload_params = { "esxhost": host, "counters": "".join(counter_data), "samples": max_samples })
                    # Python regex only supports up to 100 match groups in a regex..
                    # We are only extracting the whole value line and split it later on
                    # This is a perfect candidate for "Catastrophic Backtracking" :)
                    # Someday we should replace all of these get_pattern calls with
                    # one of these new and fancy xml parsers I've heard from
                    elements = get_pattern("<id><counterId>(.*?)</counterId><instance>(.*?)</instance></id>(%s)" % ("<value>.*?</value>" * max_samples), counter_data_response)
                    for entry in elements:
                        counter, instance, valuestring = entry
                        values = get_pattern("<value>(.*?)</value>", valuestring)
                        if counter in counters_syntax:
                            counters_value["%s.%s" % (counter, instance)] = { "id": counter, "instance": instance, "value": "#".join(values)}

                    output("<<<esx_vsphere_counters:sep(124)>>>")
                    counters_output = {}
                    for key in sorted(counters_value.keys()):
                        value = counters_value[key]
                        desc  = counters_syntax[value["id"]]
                        counters_output[ (desc["group"], desc["name"], value["instance"]) ] = ( value["value"], desc["unit"] )

                    # Add datastore name to counters
                    for key, values in datastores.items():
                        counters_output[ ("datastore", "name", key) ] = (values.get("name"), "string")

                    for key in sorted(counters_output.keys()):
                        value = counters_output[key]
                        output("%s.%s|%s|%s|%s" % (key + value))

                    for line in net_extra_info:
                        output(line)

                if not opt_direct:
                    output('<<<<>>>>')

            ###########################
            # Hostsystem
            ###########################
            if "hostsystem" in query_objects:
                hostsystems_properties = {}
                hostsystems_sensors    = {}


                # Propsets
                reply_code, reply_msg, reply_headers, esxhostdetails_response = query_server(telegram_list["esxhostdetails"])
                hostsystems_objects = get_pattern('<objects>(.*?)</objects>', esxhostdetails_response)

                for entry in hostsystems_objects:
                    hostname = get_pattern('<obj type="HostSystem">(.*)</obj>', entry[:512])[0]
                    hostsystems_properties[hostname] = {}
                    hostsystems_sensors[hostname]    = {}

                    current_propname = ""

                    def eval_sensor_info(sensor_propset):
                        sensor_pattern = ""
                        for key in [ "name", "label", "summary", "key", "currentReading",
                                     "unitModifier", "baseUnits", "sensorType" ]:
                            sensor_pattern += "<%(name)s>(.*?)</%(name)s>.*?" % { "name": key}

                        sensor_data = get_pattern(sensor_pattern, sensor_propset)
                        for name, label, summary, key, currentReading, unitModifier, baseUnits, sensorType in sensor_data:
                            hostsystems_sensors[hostname][name] = { "name": name, "label": label, "summary": summary, "key": key,
                                                                    "currentReading": currentReading, "unitModifier": unitModifier,
                                                                    "baseUnits": baseUnits, "sensorType": sensorType }

                    def eval_hardwarestatus_info(sensor_propset):
                        sensor_pattern = ""
                        for key in [ "name", "label", "summary", "key" ]:
                            sensor_pattern += "<%(name)s>(.*?)</%(name)s>.*?" % { "name": key}

                        sensor_data = get_pattern(sensor_pattern, sensor_propset)
                        for name, label, summary, key in sensor_data:
                            hostsystems_sensors[hostname][name] = { "name": name, "label": label, "summary": summary, "key": key }

                    def eval_multipath_state(multipath_propset):
                        multipaths = get_pattern("<name>(.*?)</name><pathState>(.*?)</pathState>", value)
                        for mp_name, mp_state in multipaths:
                            hostsystems_properties[hostname].setdefault(current_propname, []).append("%s %s" % (mp_name, mp_state))

                    def eval_propset_block(elements, id_key, propset):
                        pattern = ""
                        for key in elements:
                            pattern += "<%(name)s>(.*?)</%(name)s>.*?" % { "name": key}

                        data = get_pattern(pattern, propset)
                        for match_groups in data:
                            entries = dict(zip(elements, match_groups))
                            for key, value in entries.items():
                                hostsystems_properties[hostname].setdefault("%s.%s.%s" % \
                                    (current_propname, key, entries[id_key]), []).append(value)

                    def eval_cpu_pkg(cpu_pkg_propset):
                        eval_propset_block( [ "index", "vendor", "hz", "busHz", "description" ], "index", cpu_pkg_propset)

                    def eval_pci_device(pci_propset):
                        eval_propset_block( [ "id", "vendorName", "deviceName" ], "id", pci_propset)

                    def eval_systeminfo_other(otherinfo_propset):
                        data       = get_pattern("<identifierValue>(.*?)</identifierValue>.*?<key>(.*?)</key>", otherinfo_propset)
                        keys_index = {}

                        for value, key in data:
                            idx = 0
                            if key in keys_index:
                                keys_index[key] = keys_index[key] + 1
                                idx = keys_index[key]
                            hostsystems_properties[hostname]["hardware.systemInfo.otherIdentifyingInfo.%s.%d" % (key, idx)] = [ value ]
                            keys_index[key] = idx

                    eval_functions = {
                        "config.multipathState.path"                                      : eval_multipath_state,
                        "runtime.healthSystemRuntime.systemHealthInfo.numericSensorInfo"  : eval_sensor_info,
                        "runtime.healthSystemRuntime.hardwareStatusInfo.storageStatusInfo": eval_hardwarestatus_info,
                        "runtime.healthSystemRuntime.hardwareStatusInfo.cpuStatusInfo"    : eval_hardwarestatus_info,
                        "runtime.healthSystemRuntime.hardwareStatusInfo.memoryStatusInfo" : eval_hardwarestatus_info,
                        "hardware.cpuPkg"                                                 : eval_cpu_pkg,
                        "hardware.pciDevice"                                              : eval_pci_device,
                        "hardware.systemInfo.otherIdentifyingInfo"                        : eval_systeminfo_other,
                    }

                    elements = get_pattern('<propSet><name>(.*?)</name><val.*?>(.*?)</val></propSet>', entry)
                    for current_propname, value in elements:
                        if eval_functions.get(current_propname):
                            eval_functions[current_propname](value)
                        else:
                            hostsystems_properties[hostname].setdefault(current_propname, []).append(value)

                # TODO: improve error handling: check if multiple results and opt_direct
                for hostname, properties in hostsystems_properties.items():
                    if not opt_direct:
                        output("<<<<%s>>>>" % convert_hostname(properties["name"][0]))

                    output("<<<esx_vsphere_hostsystem>>>")
                    for key in sorted(properties.keys()):
                        output("%s %s" % (key, " ".join(properties[key])))

                    output("<<<esx_vsphere_sensors:sep(59)>>>")
                    for key in sorted(hostsystems_sensors[hostname].keys()):
                        data = hostsystems_sensors[hostname][key]
                        if data["key"] in ["green", "unknown", "Green"]:
                            continue
                        output('%s;%s;%s;%s;%s;%s;%s;%s;%s' % (
                                        data["name"].replace(";", "_"),
                                        data.get("baseUnits", ""),
                                        data.get("currentReading", ""),
                                        data.get("sensorType", ""),
                                        data.get("unitModifier", ""),
                                        data.get("rateUnits", ""),
                                        data["key"],
                                        data["label"],
                                        data["summary"].replace(";", "_")))


            ###########################
            # Virtual machines
            ###########################
            vm_esx_host = {}
            if "virtualmachine" in query_objects:
                vms = {}

                def is_placeholder_vm(devices):
                    elements = get_pattern("<VirtualDevice xsi:type=\"([^\"]+)", devices)
                    if "VirtualDisk" not in elements:
                        return True
                    return False

                # <objects><propSet><name>...</name><val ..>...</val></propSet></objects>
                reply_code, reply_msg, reply_headers, vmdetails_response = query_server(telegram_list["vmdetails"])

                elements = get_pattern("<objects>(.*?)</objects>", vmdetails_response)
                for entry in elements:
                    vm_data = dict(get_pattern("<name>(.*?)</name><val.*?>(.*?)</val>", entry))
                    if opt_skip_placeholder_vm and is_placeholder_vm(vm_data.get("config.hardware.device")):
                        continue
                    else:
                        # we don't need this in the agent output
                        if vm_data.get("config.hardware.device"):
                            del vm_data["config.hardware.device"]
                    if "runtime.host" in vm_data:
                        vm_data["runtime.host"] = hostsystems.get(vm_data["runtime.host"], vm_data["runtime.host"])

                    vm_esx_host.setdefault(vm_data["runtime.host"], []).append(vm_data["name"])

                    def eval_snapshot_list(info):
                        response = []
                        snapshot_info = get_pattern("<name>(.*?)</name>.*?<id>(.*?)</id><createTime>(.*?)</createTime><state>(.*?)</state>", info)
                        for entry in snapshot_info:
                            try:
                                # 2013-11-06T15:39:39.347543Z
                                creation_time = int(time.mktime(time.strptime(entry[2][:19], "%Y-%m-%dT%H:%M:%S")))
                            except:
                                creation_time = 0
                            response.append("%s %s %s %s" % (entry[1], creation_time, entry[3], entry[0].replace("|", " ")))
                        return "|".join(response)


                    def eval_datastores(info):
                        datastore_urls = get_pattern("<name>(.*?)</name><url>(.*?)</url>", info)
                        response = []
                        for name, url in datastore_urls:
                            for datastore in datastores.values():
                                if name == datastore["name"]:
                                    vm_datastore = []
                                    for key, value in datastore.items():
                                        if key != "name":
                                            key = key.split(".")[1]
                                        vm_datastore.append("%s %s" % (key, value))
                                    response.append("|".join(vm_datastore))
                                    break
                            else:
                                # No matching datastore was found. At least add the name
                                response.append("name %s" % name)
                        return "\t".join(response)

                    transform_functions = {
                        "snapshot.rootSnapshotList" : eval_snapshot_list,
                        "config.datastoreUrl"       : eval_datastores,
                    }
                    for key, transform in transform_functions.items():
                        if key in vm_data:
                            vm_data[key] = transform(vm_data[key])

                    vms[vm_data.get("name")] = vm_data


                for key in sorted(vms.keys()):
                    data = vms[key]
                    if data.get("name"):
                        output("<<<<%s>>>>" % convert_hostname(data.get("name")))
                        output("<<<esx_vsphere_vm>>>")
                        entries = list(data.items())
                        entries.sort()
                        for entry in entries:
                            output("%s %s" % entry)



            output("<<<<>>>>")



            if not opt_direct:
                reply_code, reply_msg, reply_headers, response = query_server(telegram_list["datacenters"])
                datacenters = get_pattern('<objects><obj type="Datacenter">(.*?)</obj>', response)
                for datacenter in datacenters:
                    reply_code, reply_msg, reply_headers, response = query_server(telegram_list["clustersofdatacenter"],
                                                                                  payload_params = {"datacenter": datacenter} )
                    clusters = get_pattern('<objects><obj type="ClusterComputeResource">(.*?)</obj>.*?string">(.*?)</val></propSet></objects>', response)

                    output("<<<esx_vsphere_clusters:sep(9)>>>")
                    for cluster in clusters:
                        reply_code, reply_msg, reply_headers, response = query_server(telegram_list["esxhostsofcluster"],
                                                                                      payload_params = {"clustername": cluster[0]} )
                        cluster_vms = []
                        hosts = get_pattern('<objects><obj type="HostSystem">.*?string">(.*?)</val></propSet></objects>', response)
                        for host in hosts:
                            cluster_vms.extend(vm_esx_host.get(host, []))
                        output("%s\thostsystems\t%s\t%s" % (datacenter, cluster[1], "\t".join(hosts)))
                        output("%s\tvms\t%s\t%s" % (datacenter, cluster[1], "\t".join(map(convert_hostname, cluster_vms))))

            output("<<<esx_vsphere_objects:sep(9)>>>")

            # the piggybacked data is printed later on, because it looks quite messy...
            vm_piggy_data   = {}
            host_piggy_data = {}

            if "hostsystem" in query_objects:
                if opt_host_pwr_display != "vm": # handled later on..
                    if opt_direct and opt_hostname:
                        for hostname, data in hostsystems_properties.items():
                            output("hostsystem\t%s\t\t%s" % (opt_hostname, hostsystems_properties[hostname]["runtime.powerState"][0]))
                    else:
                        for hostname, data in hostsystems_properties.items():
                            converted_hostname = convert_hostname(hostsystems_properties[hostname]["name"][0])
                            host_info = "hostsystem\t%s\t\t%s" % (converted_hostname, hostsystems_properties[hostname]["runtime.powerState"][0])
                            if opt_host_pwr_display == "esxhost" and not opt_direct:
                                host_piggy_data.setdefault(converted_hostname, []).append(host_info)
                            else:
                                output(host_info)

            if "virtualmachine" in query_objects:
                for key in vms.keys():
                    data = vms[key]
                    running_on = hostsystems.get(data.get("runtime.host"), data.get("runtime.host"))
                    vm_info = "virtualmachine\t%s\t%s\t%s" % (convert_hostname(data.get("name")), running_on, data.get("runtime.powerState"))

                    if opt_vm_pwr_display == "vm":
                        vm_name = convert_hostname(data.get("name"))
                        vm_piggy_data.setdefault(vm_name, []).append(vm_info)
                    elif opt_vm_pwr_display == "esxhost" and not opt_direct:
                        host_piggy_data.setdefault(running_on, []).append(vm_info)
                    else:
                        output(vm_info)

            if "virtualmachine" in query_objects and "hostsystem" in query_objects and opt_host_pwr_display == "vm":
                def find_host(hostname):
                    for key, value in hostsystems_properties.items():
                        if value.get("name")[0] == hostname:
                            return key

                for key in vms.keys():
                    data = vms[key]
                    running_on = hostsystems.get(data.get("runtime.host"), data.get("runtime.host"))
                    vm_host = find_host(running_on)
                    if not vm_host:
                        continue

                    vm_info = "hostsystem\t%s\t\t%s" % (running_on, hostsystems_properties[vm_host]["runtime.powerState"][0])
                    vm_name = convert_hostname(data.get("name"))
                    vm_piggy_data.setdefault(vm_name, []).append(vm_info)

            for entries in [ host_piggy_data, vm_piggy_data ]:
                for key, values in entries.items():
                    output("<<<<%s>>>>" % key)
                    output("<<<esx_vsphere_objects:sep(9)>>>")
                    output("\n".join(values))
            output("<<<<>>>>")

            # We only logout in non OMD-setups
            if not host_cookie_path:
                query_server(telegram_list["logout"])

            break
        except MKQueryServerException, e:
            # There was a problem during the query.
            # It is possible that the server cookie got invalid.
            # We are delete the cookie and start a second run
            vsphere_output = []    # Reset current output
            delete_server_cookie()
            login()
            continue # do a second run
        except Exception, e:
            if opt_debug:
                raise
            error = "Error while processing received data"


def make_utf8(line):
    if type(line) == unicode:
        return line.encode("utf-8")
    else:
        return line

print "\n".join(map(make_utf8, vsphere_output))

if opt_agent:
    sys.stdout.write(get_agent_info_tcp(host_address))
    sys.stdout.flush()
    error_exit = 0

if tracefile:
    tracefile.close()

if error:
    sys.stderr.write(error + "\n")
    sys.exit(error_exit)
