#!/usr/bin/python
# encoding: utf-8
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2010             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-
# ails.  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

# Usage:
# Replace the classic agent_vsphere with this file

# Note: This agent is still in development

import httplib, pprint, sys, os, getopt, socket, time, datetime, re

#execfile("soap_commands.py", globals(), globals())

soapdata_list = [
            (["required"],      "1_serviceinfo", '<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"><ns1:RetrieveServiceContent xsi:type="ns1:RetrieveServiceContentRequestType"><ns1:_this type="ServiceInstance">ServiceInstance</ns1:_this></ns1:RetrieveServiceContent></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
            (["required"],      "2_login", '<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"><ns1:Login xsi:type="ns1:LoginRequestType"><ns1:_this type="SessionManager">ha-sessionmgr</ns1:_this><ns1:userName>###user###</ns1:userName><ns1:password>###secret###</ns1:password></ns1:Login></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
            (["required"],      "3_hostsystem_name", '<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"><ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType"><ns1:_this type="PropertyCollector">ha-property-collector</ns1:_this><ns1:specSet><ns1:propSet><ns1:type>HostSystem</ns1:type><ns1:pathSet>name</ns1:pathSet></ns1:propSet><ns1:objectSet><ns1:obj type="Folder">ha-folder-root</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></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
            (["datastore"],     "4_datastores", '<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"><ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType"><ns1:_this type="PropertyCollector">ha-property-collector</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">ha-folder-root</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></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
#            ([],                "5_retrieve_ex_3", '<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"><ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType"><ns1:_this type="PropertyCollector">ha-property-collector</ns1:_this><ns1:specSet><ns1:propSet><ns1:type>PerformanceManager</ns1:type><ns1:all>true</ns1:all></ns1:propSet><ns1:objectSet><ns1:obj type="PerformanceManager">ha-perfmgr</ns1:obj><ns1:skip>false</ns1:skip></ns1:objectSet></ns1:specSet><ns1:options></ns1:options></ns1:RetrievePropertiesEx></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
#            ([],                "6_query_perf_provider_summary", '<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"><ns1:QueryPerfProviderSummary xsi:type="ns1:QueryPerfProviderSummaryRequestType"><ns1:_this type="PerformanceManager">ha-perfmgr</ns1:_this><ns1:entity type="HostSystem">ha-host</ns1:entity></ns1:QueryPerfProviderSummary></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
            (["counters"],      "7_query_avail_perf_metric", '<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"><ns1:QueryAvailablePerfMetric xsi:type="ns1:QueryAvailablePerfMetricRequestType"><ns1:_this type="PerformanceManager">ha-perfmgr</ns1:_this><ns1:entity type="HostSystem">ha-host</ns1:entity><ns1:intervalId>20</ns1:intervalId></ns1:QueryAvailablePerfMetric></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
            (["counters"],      "8_perf_counter_syntax", '<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"><ns1:QueryPerfCounter xsi:type="ns1:QueryPerfCounterRequestType"><ns1:_this type="PerformanceManager">ha-perfmgr</ns1:_this>###counters###</ns1:QueryPerfCounter></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
            (["counters"],      "9_perf_counter_data", '<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"><ns1:QueryPerf xsi:type="ns1:QueryPerfRequestType"><ns1:_this type="PerformanceManager">ha-perfmgr</ns1:_this><ns1:querySpec><ns1:entity type="HostSystem">ha-host</ns1:entity><ns1:maxSample>1</ns1:maxSample>###counters###<ns1:intervalId>20</ns1:intervalId></ns1:querySpec></ns1:QueryPerf></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
            (["hostsystem"],    "10_hostsystem", '<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"><ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType"><ns1:_this type="PropertyCollector">ha-property-collector</ns1:_this><ns1:specSet><ns1:propSet><ns1:type>HostSystem</ns1:type><ns1:pathSet>summary.quickStats.overallMemoryUsage</ns1:pathSet><ns1:pathSet>hardware.cpuInfo.numCpuThreads</ns1:pathSet><ns1:pathSet>runtime.powerState</ns1:pathSet><ns1:pathSet>summary.quickStats.overallCpuUsage</ns1:pathSet><ns1:pathSet>hardware.cpuInfo.hz</ns1:pathSet><ns1:pathSet>hardware.cpuInfo.numCpuPackages</ns1:pathSet><ns1:pathSet>config.multipathState.path</ns1:pathSet><ns1:pathSet>hardware.cpuInfo.numCpuCores</ns1:pathSet><ns1:pathSet>name</ns1:pathSet><ns1:pathSet>overallStatus</ns1:pathSet><ns1:pathSet>runtime.healthSystemRuntime.systemHealthInfo.numericSensorInfo</ns1:pathSet><ns1:pathSet>runtime.inMaintenanceMode</ns1:pathSet><ns1:pathSet>hardware.memorySize</ns1:pathSet></ns1:propSet><ns1:objectSet><ns1:obj type="Folder">ha-folder-root</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></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
            (["virtualmachine"],"11_virtualmachine", '<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"><ns1:RetrievePropertiesEx xsi:type="ns1:RetrievePropertiesExRequestType"><ns1:_this type="PropertyCollector">ha-property-collector</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>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>guest.toolsVersionStatus</ns1:pathSet></ns1:propSet><ns1:objectSet><ns1:obj type="Folder">ha-folder-root</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></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
            (["required"],      "12_logout", '<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"><ns1:Logout xsi:type="ns1:LogoutRequestType"><ns1:_this type="SessionManager">ha-sessionmgr</ns1:_this></ns1:Logout></SOAP-ENV:Body></SOAP-ENV:Envelope>'),
           ]


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

# List of predefined SOAP requests
# ( [{used_by_object}], {internal_id}, {SOAP telegram} )

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,

        # 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.
  --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".

""")

short_options = 'hi:u:s:Dat:H:cpS:'
long_options  = [
    'help', 'user=', 'secret=', 'direct', 'agent', 'debug', 'modules=', 'timeout=', 'hostname=',
    'dump-counters', 'tracefile=', "pysphere", "spaces=",
]

opt_debug               = False
opt_direct              = False
opt_agent               = False
opt_dump_counters       = False
opt_timeout             = 60
opt_hostname            = None
opt_skip_placeholder_vm = False
opt_pysphere            = False
opt_tracefile           = None
opt_spaces              = "underscore"

error = None
error_exit = 1

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

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 == '--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(',') + [ "required" ]
    elif o in [ '-t', '--timeout' ]:
        opt_timeout = int(a)
    elif o in [ '-H', '--hostname' ]:
        opt_hostname = a
    elif o in [ '-c', '--dump-counters' ]:
        opt_dump_counters = True
    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)

# vCenter only supports the classical slow vSphere agent (based on pysphere)
# Also we do not support ESX 4.1 (yet).
if not opt_direct or 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)


socket.setdefaulttimeout(opt_timeout)

def get_agent_info_tcp(hostname):
    output = ""
    try:
        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
        output = ""
        while True:
            out = s.recv(4096, socket.MSG_WAITALL)
            if out and len(out) > 0:
                output += out
            else:
                break
        s.close()
        return output
    except Exception, e:
        if opt_debug:
            raise
    return output


results = {}

esx_version_num = None
esx_name        = ""

if opt_tracefile:
    if os.path.exists(os.path.dirname(opt_tracefile)):
        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))

try:
    my_cookie   = None
    netloc      = host_address
    request_uri = "/sdk"
    transport   = httplib.HTTPSConnection
    transdict   = {'timeout': opt_timeout}
    handle      = transport(netloc, None, **transdict)
    handle.connect()

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

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

        handle.send(soapdata)

        time_sent     = time.time()
        response = handle.getresponse()
        time_response = time.time()

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

        return response.status, response.reason, response.msg, body

    def get_counter_instances():
        p = re.compile("<counterId>([0-9]*)</counterId><instance>([^<]*)")
        m = p.findall( results["7_query_avail_perf_metric"] )

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

        return counters_avail

    for (objects, name, soapdata) in soapdata_list:
        # Only sent queries we actually need
        for entry in objects:
            if entry in query_objects:
                break
        else:
            continue

        # Prepare request data
        if name == "2_login":
            def encode_url(text):
                for char, replacement in [ ( "&",  "&amp;"),
                                           ( ">",  "&gt;" ),
                                           ( "<",  "&lt;"),
                                           ( "'",  "&apos;"),
                                           ( "\"", "&quot;") ]:
                    text = text.replace(char, replacement)
                return text 
            soapdata = soapdata.replace("###user###", encode_url(user)).replace("###secret###", encode_url(secret))
        elif name == "8_perf_counter_syntax":
            needed_ids = get_counters(esx_version_num)
            counter_data = []
            for entry in needed_ids:
                counter_data.append("<ns1:counterId>%s</ns1:counterId>" % entry)
            soapdata = soapdata.replace("###counters###", "".join(counter_data))
        elif name == "9_perf_counter_data":
            needed_ids     = get_counters(esx_version_num)
            counters_avail = get_counter_instances()
            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))
            soapdata = soapdata.replace("###counters###", "".join(counter_data))

        # Query data 
        if tracefile:
            tracefile.write("\n\nStart query: %s\n" % name)
        reply_code, reply_msg, reply_headers, reply_data = query_server(soapdata)
        results[name] = reply_data

        # Postprocess response data
        if name == "1_serviceinfo":
            elements = get_pattern("<name>(.*)</name>.*<apiVersion>([0-9\.]*)</apiVersion>", results["1_serviceinfo"])
            esx_name        = elements[0][0]
            esx_version_num = float(elements[0][1])
        elif name == "2_login":
            my_cookie =  reply_headers.get("Set-Cookie")
            if reply_msg != "OK":
                raise Exception("Login response is not 'OK'. Please check the credentials")

except Exception, e:
    if opt_debug:
        raise
    error = "Cannot connect to vSphere Server. Maybe you provided wrong " \
            "credentials. Please check your connection settings and try " \
            "again."

if not error:
    try:

        ##########################
        # Check MK header and Agent Version
        print   "<<<check_mk>>>"
        print "Version: %.1f" %  esx_version_num
        print "AgentOs: %s" %  esx_name

        #############################
        # Hostsystem instance to name
        #############################
        hostsystem_name = {}
        elements = get_pattern('<obj type="HostSystem">(.*?)</obj>.*?<val xsi:type="xsd:string">(.*?)</val>',
                               results["3_hostsystem_name"])
        for hostsystem, name in elements:
            hostsystem_name[hostsystem] = name

        ###########################
        # Datastores
        ###########################
        if "datastore" in query_objects:
            datastores = {}
            elements = get_pattern('<objects><obj type="Datastore">(.*?)</obj>(.*?)</objects>', results["4_datastores"])
            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


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

        ###########################
        # Counters
        ###########################
        if "counters" in query_objects:
            ### Syntax
            counters_syntax = {}
            elements = get_pattern('<returnval><key>(.*?)</key>.*?<key>(.*?)</key>.*?'\
                                   '<key>(.*?)</key>.*?<key>(.*?)</key>.*?', results["8_perf_counter_syntax"])

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


            ### Data
            counters_value = {}

            elements = get_pattern("<id><counterId>(.*?)</counterId><instance>(.*?)</instance></id><value>(.*?)</value>", results["9_perf_counter_data"])

            for counter, instance, value in elements:
                if counter in counters_syntax:
                    counters_value["%s.%s" % (counter, instance)] = { "id": counter, "instance": instance, "value": value }

            print "<<<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"] )

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

        ###########################
        # Hostsystem
        ###########################
        if "hostsystem" in query_objects:
            hostsystem_propsets = {}
            hostsystem_sensors  = {}

            # Propsets
            elements = get_pattern('<propSet><name>(.*?)</name><val.*?>(.*?)</val></propSet>', results["10_hostsystem"])
            sensor_propset = None
            for name, value in elements:
                if name == "runtime.healthSystemRuntime.systemHealthInfo.numericSensorInfo":
                    sensor_propset = value
                elif name == "config.multipathState.path":
                    multipaths = get_pattern("<name>(.*?)</name><pathState>(.*?)</pathState>", value)
                    for mp_name, mp_state in multipaths:
                        hostsystem_propsets.setdefault(name, []).append("%s %s" % (mp_name, mp_state))
                else:
                    hostsystem_propsets.setdefault(name, []).append(value)

            # Sensor info
            entry_pattern = ""
            for key in [ "name", "label", "summary", "key", "currentReading",
                         "unitModifier", "baseUnits", "sensorType" ]:
                entry_pattern += "<%(name)s>(.*?)</%(name)s>.*?" % { "name": key}

            # TODO: rate unit?
            sensor_data = get_pattern(entry_pattern, sensor_propset)
            for name, label, summary, key, currentReading, unitModifier, baseUnits, sensorType in sensor_data:
                hostsystem_sensors[name] = { "name": name, "label": label, "summary": summary, "key": key,
                                             "currentReading": currentReading, "unitModifier": unitModifier,
                                             "baseUnits": baseUnits, "sensorType": sensorType }


            print "<<<esx_vsphere_hostsystem>>>"
            for key in sorted(hostsystem_propsets.keys()):
                if key == "runtime.healthSystemRuntime.systemHealthInfo.numericSensorInfo":
                    continue
                value = hostsystem_propsets[key]
                print "%s %s" % (key, " ".join(value))

            print "<<<esx_vsphere_sensors:sep(59)>>>"
            for key in sorted(hostsystem_sensors.keys()):
                data = hostsystem_sensors[key]
                if data["key"] in ["green", "unknown"]:
                    continue
                line = '%s;%s;%s;%s;%s;' % (data["name"], data["baseUnits"], data["currentReading"],
                                            data["sensorType"], data["unitModifier"])
                if "rateUnits" in data:
                    line += data["rateUnits"]
                line += ";%s;%s;%s" % ( data["key"], data["label"], data["summary"] )
                print line


        ###########################
        # Virtual machines
        ###########################
        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>
            elements = get_pattern("<objects>(.*?)</objects>", results["11_virtualmachine"])
            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
                    del vm_data["config.hardware.device"]
                vms[vm_data.get("name")] = vm_data

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


        print "<<<<>>>>"
        print "<<<esx_vsphere_objects:sep(9)>>>"
        if "hostsystem" in query_objects:
            if opt_direct and opt_hostname:
                hostname = opt_hostname
            else:
                # Note: Won't work with vCenter queries..
                hostname = hostsystem_propsets["name"][0]
            print "hostsystem\t%s\t\t%s" % ( hostname, "".join(hostsystem_propsets["runtime.powerState"]) )


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

    except Exception, e:
        if opt_debug:
            raise
        error = "Error while processing received data"

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)
