├── .gitignore
├── LICENSE
├── README.md
├── py-vminfo-web.py
├── py-vminfo.py
├── python-vmstats-web2.png
├── viconfig.template
├── vm-win-stats-py3.png
└── vminfo-launch.html
/.gitignore:
--------------------------------------------------------------------------------
1 | viconfig.py
2 | python-vmstats-web2.png
3 | vm-win-stats-py3.png
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 lgeeklee
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | python-vmstats
2 | ==============
3 |
4 | Python script using pyVmomi to get VM statistics
5 |
6 | Command line version:
7 |
8 |
9 |
10 | The script requires the following parameters:
11 |
12 | -s HOST, --host HOST : Remote host to connect to.
13 |
14 | -u USER, --user USER : User name to use when connecting to host.
15 |
16 | -p PASSWORD, --password PASSWORD : Password to use when connecting to host.
17 |
18 | -m VM, --vm VM : Virtual Machine to report.
19 |
20 | -i INT, --interval INT : Interval to average the vSphere stats over in minutes
21 |
22 | -c, --cert_check_skip : Skip ssl certificate check
23 |
24 | The -p/--password is now optional and if not provided on the command line will prompt instead.
25 |
26 |
27 | The web version:
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/py-vminfo-web.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 |
4 |
5 | """
6 | Python program that generates various statistics for one or more virtual machines
7 |
8 | A list of virtual machines can be provided as a comma separated list.
9 | """
10 |
11 | from __future__ import print_function
12 | from pyVim.connect import SmartConnect, Disconnect
13 | from pyVmomi import vmodl, vim
14 | from datetime import timedelta, datetime
15 |
16 | import atexit
17 | import getpass
18 | import cgi
19 | import viconfig
20 | import ssl
21 |
22 | form = cgi.FieldStorage()
23 | print("Content-Type: text/html;charset=utf-8\n\n")
24 |
25 |
26 | def BuildQuery(content, vchtime, counterId, instance, vm, interval):
27 | perfManager = content.perfManager
28 | metricId = vim.PerformanceManager.MetricId(counterId=counterId, instance=instance)
29 | startTime = vchtime - timedelta(minutes=(interval + 1))
30 | endTime = vchtime - timedelta(minutes=1)
31 | query = vim.PerformanceManager.QuerySpec(intervalId=20, entity=vm, metricId=[metricId], startTime=startTime,
32 | endTime=endTime)
33 | perfResults = perfManager.QueryPerf(querySpec=[query])
34 | if perfResults:
35 | return perfResults
36 | else:
37 | print('ERROR: Performance results empty. TIP: Check time drift on source and vCenter server')
38 | print('Troubleshooting info:')
39 | print('vCenter/host date and time: {}'.format(vchtime))
40 | print('Start perf counter time : {}'.format(startTime))
41 | print('End perf counter time : {}'.format(endTime))
42 | print(query)
43 | exit()
44 |
45 |
46 | def html_table(vm_property, vm_value):
47 | print('
')
48 | print('' + vm_property + ' | ')
49 | print('' + str(vm_value) + ' | ')
50 | print('
')
51 |
52 |
53 |
54 | def PrintVmInfo(vm, content, vchtime, interval, perf_dict):
55 | statInt = interval * 3 # There are 3 20s samples in each minute
56 | summary = vm.summary
57 | disk_list = []
58 | network_list = []
59 |
60 | # Convert limit and reservation values from -1 to None
61 | if vm.resourceConfig.cpuAllocation.limit == -1:
62 | vmcpulimit = "None"
63 | else:
64 | vmcpulimit = "{} Mhz".format(vm.resourceConfig.cpuAllocation.limit)
65 | if vm.resourceConfig.memoryAllocation.limit == -1:
66 | vmmemlimit = "None"
67 | else:
68 | vmmemlimit = "{} MB".format(vm.resourceConfig.memoryAllocation.limit)
69 |
70 | if vm.resourceConfig.cpuAllocation.reservation == 0:
71 | vmcpures = "None"
72 | else:
73 | vmcpures = "{} Mhz".format(vm.resourceConfig.cpuAllocation.reservation)
74 | if vm.resourceConfig.memoryAllocation.reservation == 0:
75 | vmmemres = "None"
76 | else:
77 | vmmemres = "{} MB".format(vm.resourceConfig.memoryAllocation.reservation)
78 |
79 | vm_hardware = vm.config.hardware
80 | for each_vm_hardware in vm_hardware.device:
81 | if (each_vm_hardware.key >= 2000) and (each_vm_hardware.key < 3000):
82 | disk_list.append('{} | {:.1f}GB | Thin: {} | {}'.format(each_vm_hardware.deviceInfo.label,
83 | each_vm_hardware.capacityInKB/1024/1024,
84 | each_vm_hardware.backing.thinProvisioned,
85 | each_vm_hardware.backing.fileName))
86 | elif (each_vm_hardware.key >= 4000) and (each_vm_hardware.key < 5000):
87 | network_list.append('{} | {} | {}'.format(each_vm_hardware.deviceInfo.label,
88 | each_vm_hardware.deviceInfo.summary,
89 | each_vm_hardware.macAddress))
90 |
91 | disk_output = '
'.join(disk_list)
92 | network_output = '
'.join(network_list)
93 |
94 | #CPU Ready Average
95 | statCpuReady = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'cpu.ready.summation')), "", vm, interval)
96 | cpuReady = (float(sum(statCpuReady[0].value[0].value)) / statInt)
97 | #CPU Usage Average % - NOTE: values are type LONG so needs divided by 100 for percentage
98 | statCpuUsage = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'cpu.usage.average')), "", vm, interval)
99 | cpuUsage = ((float(sum(statCpuUsage[0].value[0].value)) / statInt) / 100)
100 | #Memory Active Average MB
101 | statMemoryActive = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'mem.active.average')), "", vm, interval)
102 | memoryActive = (float(sum(statMemoryActive[0].value[0].value) / 1024) / statInt)
103 | #Memory Shared
104 | statMemoryShared = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'mem.shared.average')), "", vm, interval)
105 | memoryShared = (float(sum(statMemoryShared[0].value[0].value) / 1024) / statInt)
106 | #Memory Balloon
107 | statMemoryBalloon = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'mem.vmmemctl.average')), "", vm, interval)
108 | memoryBalloon = (float(sum(statMemoryBalloon[0].value[0].value) / 1024) / statInt)
109 | #Memory Swapped
110 | statMemorySwapped = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'mem.swapped.average')), "", vm, interval)
111 | memorySwapped = (float(sum(statMemorySwapped[0].value[0].value) / 1024) / statInt)
112 | #Datastore Average IO
113 | statDatastoreIoRead = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'datastore.numberReadAveraged.average')),
114 | "*", vm, interval)
115 | DatastoreIoRead = (float(sum(statDatastoreIoRead[0].value[0].value)) / statInt)
116 | statDatastoreIoWrite = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'datastore.numberWriteAveraged.average')),
117 | "*", vm, interval)
118 | DatastoreIoWrite = (float(sum(statDatastoreIoWrite[0].value[0].value)) / statInt)
119 | #Datastore Average Latency
120 | statDatastoreLatRead = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'datastore.totalReadLatency.average')),
121 | "*", vm, interval)
122 | DatastoreLatRead = (float(sum(statDatastoreLatRead[0].value[0].value)) / statInt)
123 | statDatastoreLatWrite = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'datastore.totalWriteLatency.average')),
124 | "*", vm, interval)
125 | DatastoreLatWrite = (float(sum(statDatastoreLatWrite[0].value[0].value)) / statInt)
126 |
127 | #Network usage (Tx/Rx)
128 | statNetworkTx = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'net.transmitted.average')), "", vm, interval)
129 | networkTx = (float(sum(statNetworkTx[0].value[0].value) * 8 / 1024) / statInt)
130 | statNetworkRx = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'net.received.average')), "", vm, interval)
131 | networkRx = (float(sum(statNetworkRx[0].value[0].value) * 8 / 1024) / statInt)
132 |
133 |
134 | print('''\
135 |
162 | ''')
163 |
164 | print('')
165 |
166 | print('NOTE: Any VM statistics are averages of the last {} minutes
'.format(statInt / 3))
167 | print('
Core Information
')
168 | html_table('Virtual Machine Name', ' {} '.format(summary.config.name))
169 | html_table('Description', summary.config.annotation)
170 | html_table('Guest', summary.config.guestFullName)
171 | if vm.rootSnapshot:
172 | html_table('Snapshot Status', 'Snapshot(s) found')
173 | else:
174 | html_table('Snapshot Status', 'No Snapshots')
175 | html_table('VM .vmx Path', summary.config.vmPathName)
176 | html_table('Virtual Disks', disk_output)
177 | html_table('Virtual NIC(s)', network_output)
178 | print('
')
179 | print('vCPU and Memory Information
')
180 | print('')
181 | html_table('[VM] Limits', 'CPU: {}, Memory: {}'.format(vmcpulimit, vmmemlimit))
182 | html_table('[VM] Reservations', 'CPU: {}, Memory: {}'.format(vmcpures, vmmemres))
183 | html_table('[VM] Number of vCPUs', summary.config.numCpu)
184 | html_table('[VM] CPU Ready', 'Average {:.1f} %, Maximum {:.1f} %'.format((cpuReady / 20000 * 100),
185 | ((float(max(statCpuReady[0].value[0]
186 | .value)) / 20000 * 100))))
187 | html_table('[VM] CPU (%)', '{:.0f} %'.format(cpuUsage))
188 | html_table('[VM] Memory', '{} MB ({:.1f} GB)'.format(summary.config.memorySizeMB,
189 | (float(summary.config.memorySizeMB) / 1024)))
190 | html_table('[VM] Memory Shared', '{:.0f} %, {:.0f} MB'.format(((memoryShared / summary.config.memorySizeMB) * 100),
191 | memoryShared))
192 | html_table('[VM] Memory Balloon', '{:.0f} %, {:.0f} MB'.format(((memoryBalloon / summary.config.memorySizeMB)
193 | * 100), memoryBalloon))
194 | html_table('[VM] Memory Swapped', '{:.0f} %, {:.0f} MB'.format(((memorySwapped / summary.config.memorySizeMB)
195 | * 100), memorySwapped))
196 | html_table('[VM] Memory Active', '{:.0f} %, {:.0f} MB'.format(((memoryActive / summary.config.memorySizeMB) * 100),
197 | memoryActive))
198 | print('
')
199 | print('Datastore and Network Information
')
200 | print('')
201 | html_table('[VM] Datastore Average IO', 'Read: {:.0f} IOPS, Write: {:.0f} IOPS'.format(DatastoreIoRead,
202 | DatastoreIoWrite))
203 | html_table('[VM] Datastore Average Latency', 'Read: {:.0f} ms, Write: {:.0f} ms'.format(DatastoreLatRead,
204 | DatastoreLatWrite))
205 | html_table('[VM] Overall Network Usage', 'Transmitted {:.3f} Mbps, Received {:.3f} Mbps'.format(networkTx, networkRx))
206 | print('
')
207 | print('Parent Host Information
')
208 | print('')
209 | html_table('[Host] Name', summary.runtime.host.name)
210 | html_table('[Host] CPU Detail', 'Processor Sockets: {}, Cores per Socket {}'.format(
211 | summary.runtime.host.summary.hardware.numCpuPkgs,
212 | (summary.runtime.host.summary.hardware.numCpuCores / summary.runtime.host.summary.hardware.numCpuPkgs)))
213 | html_table('[Host] CPU Type', summary.runtime.host.summary.hardware.cpuModel)
214 | html_table('[Host] CPU Usage', 'Used: {} Mhz, Total: {} Mhz'.format(
215 | summary.runtime.host.summary.quickStats.overallCpuUsage,
216 | (summary.runtime.host.summary.hardware.cpuMhz * summary.runtime.host.summary.hardware.numCpuCores)))
217 | html_table('[Host] Memory Usage ', 'Used: {:.0f} GB, Total: {:.0f} GB\n'.format(
218 | (float(summary.runtime.host.summary.quickStats.overallMemoryUsage) / 1024),
219 | (float(summary.runtime.host.summary.hardware.memorySize) / 1024 / 1024 / 1024)))
220 |
221 | print('
')
222 |
223 |
224 | def StatCheck(perf_dict, counter_name):
225 | counter_key = perf_dict[counter_name]
226 | return counter_key
227 |
228 |
229 | def GetProperties(content, viewType, props, specType):
230 | # Build a view and get basic properties for all Virtual Machines
231 | objView = content.viewManager.CreateContainerView(content.rootFolder, viewType, True)
232 | tSpec = vim.PropertyCollector.TraversalSpec(name='tSpecName', path='view', skip=False, type=vim.view.ContainerView)
233 | pSpec = vim.PropertyCollector.PropertySpec(all=False, pathSet=props, type=specType)
234 | oSpec = vim.PropertyCollector.ObjectSpec(obj=objView, selectSet=[tSpec], skip=False)
235 | pfSpec = vim.PropertyCollector.FilterSpec(objectSet=[oSpec], propSet=[pSpec], reportMissingObjectsInResults=False)
236 | retOptions = vim.PropertyCollector.RetrieveOptions()
237 | totalProps = []
238 | retProps = content.propertyCollector.RetrievePropertiesEx(specSet=[pfSpec], options=retOptions)
239 | totalProps += retProps.objects
240 | while retProps.token:
241 | retProps = content.propertyCollector.ContinueRetrievePropertiesEx(token=retProps.token)
242 | totalProps += retProps.objects
243 | objView.Destroy()
244 | # Turn the output in retProps into a usable dictionary of values
245 | gpOutput = []
246 | for eachProp in totalProps:
247 | propDic = {}
248 | for prop in eachProp.propSet:
249 | propDic[prop.name] = prop.val
250 | propDic['moref'] = eachProp.obj
251 | gpOutput.append(propDic)
252 | return gpOutput
253 |
254 |
255 | def main():
256 | args = viconfig.GetArgs()
257 | try:
258 | vmnames = form['vmname'].value
259 | si = None
260 | if args['password']:
261 | password = args['password']
262 | else:
263 | password = getpass.getpass(prompt="Enter password for host {} and user {}: ".format(args['host'], args['user']))
264 | try:
265 | context = ssl._create_unverified_context()
266 | si = SmartConnect(host=args['host'],
267 | user=args['user'],
268 | pwd=password,
269 | port=int(args['port']),
270 | sslContext=context)
271 | except IOError as e:
272 | pass
273 | if not si:
274 | print('Could not connect to the specified host using specified username and password')
275 | return -1
276 |
277 | atexit.register(Disconnect, si)
278 | content = si.RetrieveContent()
279 | # Get vCenter date and time for use as baseline when querying for counters
280 | vchtime = si.CurrentTime()
281 |
282 | # Get all the performance counters
283 | perf_dict = {}
284 | perfList = content.perfManager.perfCounter
285 | for counter in perfList:
286 | counter_full = "{}.{}.{}".format(counter.groupInfo.key, counter.nameInfo.key, counter.rollupType)
287 | perf_dict[counter_full] = counter.key
288 |
289 | retProps = GetProperties(content, [vim.VirtualMachine], ['name', 'runtime.powerState'], vim.VirtualMachine)
290 |
291 | #Find VM supplied as arg and use Managed Object Reference (moref) for the PrintVmInfo
292 | for vm in retProps:
293 | if (vm['name'] in vmnames) and (vm['runtime.powerState'] == "poweredOn"):
294 | PrintVmInfo(vm['moref'], content, vchtime, int(form['vminterval'].value), perf_dict)
295 | elif vm['name'] in vmnames:
296 | print('ERROR: Problem connecting to Virtual Machine. {} is likely powered off or suspended'.format(vm['name']))
297 |
298 | except vmodl.MethodFault as e:
299 | print('Caught vmodl fault : ' + e.msg)
300 | return -1
301 | except Exception as e:
302 | print('Caught exception : ' + str(e))
303 | return -1
304 |
305 | return 0
306 |
307 | # Start program
308 | if __name__ == "__main__":
309 | main()
310 |
--------------------------------------------------------------------------------
/py-vminfo.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """
4 | Python program that generates various statistics for one or more virtual machines
5 |
6 | A list of virtual machines can be provided as a comma separated list.
7 | """
8 |
9 | from __future__ import print_function
10 | from pyVim.connect import SmartConnect, Disconnect
11 | from pyVmomi import vmodl, vim
12 | from datetime import timedelta, datetime
13 |
14 | import argparse
15 | import atexit
16 | import getpass
17 |
18 | import ssl
19 |
20 | def GetArgs():
21 | """
22 | Supports the command-line arguments listed below.
23 | """
24 | parser = argparse.ArgumentParser(description='Process args for retrieving all the Virtual Machines')
25 | parser.add_argument('-s', '--host', required=True, action='store', help='Remote host to connect to')
26 | parser.add_argument('-o', '--port', type=int, default=443, action='store', help='Port to connect on')
27 | parser.add_argument('-u', '--user', required=True, action='store', help='User name to use when connecting to host')
28 | parser.add_argument('-p', '--password', required=False, action='store',
29 | help='Password to use when connecting to host')
30 | parser.add_argument('-m', '--vm', required=True, action='store', help='On eor more Virtual Machines to report on')
31 | parser.add_argument('-c', '--cert_check_skip', required=False, action='store_true', help='skip ssl certificate check')
32 | parser.add_argument('-i', '--interval', type=int, default=15, action='store',
33 | help='Interval to average the vSphere stats over')
34 | args = parser.parse_args()
35 | return args
36 |
37 |
38 | def BuildQuery(content, vchtime, counterId, instance, vm, interval):
39 | perfManager = content.perfManager
40 | metricId = vim.PerformanceManager.MetricId(counterId=counterId, instance=instance)
41 | startTime = vchtime - timedelta(minutes=(interval + 1))
42 | endTime = vchtime - timedelta(minutes=1)
43 | query = vim.PerformanceManager.QuerySpec(intervalId=20, entity=vm, metricId=[metricId], startTime=startTime,
44 | endTime=endTime)
45 | perfResults = perfManager.QueryPerf(querySpec=[query])
46 | if perfResults:
47 | return perfResults
48 | else:
49 | print('ERROR: Performance results empty. TIP: Check time drift on source and vCenter server')
50 | print('Troubleshooting info:')
51 | print('vCenter/host date and time: {}'.format(vchtime))
52 | print('Start perf counter time : {}'.format(startTime))
53 | print('End perf counter time : {}'.format(endTime))
54 | print(query)
55 | exit()
56 |
57 |
58 |
59 | def PrintVmInfo(vm, content, vchtime, interval, perf_dict, ):
60 | statInt = interval * 3 # There are 3 20s samples in each minute
61 | summary = vm.summary
62 | disk_list = []
63 | network_list = []
64 |
65 | # Convert limit and reservation values from -1 to None
66 | if vm.resourceConfig.cpuAllocation.limit == -1:
67 | vmcpulimit = "None"
68 | else:
69 | vmcpulimit = "{} Mhz".format(vm.resourceConfig.cpuAllocation.limit)
70 | if vm.resourceConfig.memoryAllocation.limit == -1:
71 | vmmemlimit = "None"
72 | else:
73 | vmmemlimit = "{} MB".format(vm.resourceConfig.memoryAllocation.limit)
74 |
75 | if vm.resourceConfig.cpuAllocation.reservation == 0:
76 | vmcpures = "None"
77 | else:
78 | vmcpures = "{} Mhz".format(vm.resourceConfig.cpuAllocation.reservation)
79 | if vm.resourceConfig.memoryAllocation.reservation == 0:
80 | vmmemres = "None"
81 | else:
82 | vmmemres = "{} MB".format(vm.resourceConfig.memoryAllocation.reservation)
83 |
84 | vm_hardware = vm.config.hardware
85 | for each_vm_hardware in vm_hardware.device:
86 | if (each_vm_hardware.key >= 2000) and (each_vm_hardware.key < 3000):
87 | disk_list.append('{} | {:.1f}GB | Thin: {} | {}'.format(each_vm_hardware.deviceInfo.label,
88 | each_vm_hardware.capacityInKB/1024/1024,
89 | each_vm_hardware.backing.thinProvisioned,
90 | each_vm_hardware.backing.fileName))
91 | elif (each_vm_hardware.key >= 4000) and (each_vm_hardware.key < 5000):
92 | network_list.append('{} | {} | {}'.format(each_vm_hardware.deviceInfo.label,
93 | each_vm_hardware.deviceInfo.summary,
94 | each_vm_hardware.macAddress))
95 |
96 | #CPU Ready Average
97 | statCpuReady = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'cpu.ready.summation')), "", vm, interval)
98 | cpuReady = (float(sum(statCpuReady[0].value[0].value)) / statInt)
99 | #CPU Usage Average % - NOTE: values are type LONG so needs divided by 100 for percentage
100 | statCpuUsage = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'cpu.usage.average')), "", vm, interval)
101 | cpuUsage = ((float(sum(statCpuUsage[0].value[0].value)) / statInt) / 100)
102 | #Memory Active Average MB
103 | statMemoryActive = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'mem.active.average')), "", vm, interval)
104 | memoryActive = (float(sum(statMemoryActive[0].value[0].value) / 1024) / statInt)
105 | #Memory Shared
106 | statMemoryShared = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'mem.shared.average')), "", vm, interval)
107 | memoryShared = (float(sum(statMemoryShared[0].value[0].value) / 1024) / statInt)
108 | #Memory Balloon
109 | statMemoryBalloon = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'mem.vmmemctl.average')), "", vm, interval)
110 | memoryBalloon = (float(sum(statMemoryBalloon[0].value[0].value) / 1024) / statInt)
111 | #Memory Swapped
112 | statMemorySwapped = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'mem.swapped.average')), "", vm, interval)
113 | memorySwapped = (float(sum(statMemorySwapped[0].value[0].value) / 1024) / statInt)
114 | #Datastore Average IO
115 | statDatastoreIoRead = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'datastore.numberReadAveraged.average')),
116 | "*", vm, interval)
117 | DatastoreIoRead = (float(sum(statDatastoreIoRead[0].value[0].value)) / statInt)
118 | statDatastoreIoWrite = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'datastore.numberWriteAveraged.average')),
119 | "*", vm, interval)
120 | DatastoreIoWrite = (float(sum(statDatastoreIoWrite[0].value[0].value)) / statInt)
121 | #Datastore Average Latency
122 | statDatastoreLatRead = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'datastore.totalReadLatency.average')),
123 | "*", vm, interval)
124 | DatastoreLatRead = (float(sum(statDatastoreLatRead[0].value[0].value)) / statInt)
125 | statDatastoreLatWrite = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'datastore.totalWriteLatency.average')),
126 | "*", vm, interval)
127 | DatastoreLatWrite = (float(sum(statDatastoreLatWrite[0].value[0].value)) / statInt)
128 |
129 | #Network usage (Tx/Rx)
130 | statNetworkTx = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'net.transmitted.average')), "", vm, interval)
131 | networkTx = (float(sum(statNetworkTx[0].value[0].value) * 8 / 1024) / statInt)
132 | statNetworkRx = BuildQuery(content, vchtime, (StatCheck(perf_dict, 'net.received.average')), "", vm, interval)
133 | networkRx = (float(sum(statNetworkRx[0].value[0].value) * 8 / 1024) / statInt)
134 |
135 | print('\nNOTE: Any VM statistics are averages of the last {} minutes\n'.format(statInt / 3))
136 | print('Server Name :', summary.config.name)
137 | print('Description :', summary.config.annotation)
138 | print('Guest :', summary.config.guestFullName)
139 | if vm.rootSnapshot:
140 | print('Snapshot Status : Snapshots present')
141 | else:
142 | print('Snapshot Status : No Snapshots')
143 | print('VM .vmx Path :', summary.config.vmPathName)
144 | try:
145 | print('Virtual Disks :', disk_list[0])
146 | if len(disk_list) > 1:
147 | disk_list.pop(0)
148 | for each_disk in disk_list:
149 | print(' ', each_disk)
150 | except IndexError:
151 | pass
152 | print('Virtual NIC(s) :', network_list[0])
153 | if len(network_list) > 1:
154 | network_list.pop(0)
155 | for each_vnic in network_list:
156 | print(' ', each_vnic)
157 | print('[VM] Limits : CPU: {}, Memory: {}'.format(vmcpulimit, vmmemlimit))
158 | print('[VM] Reservations : CPU: {}, Memory: {}'.format(vmcpures, vmmemres))
159 | print('[VM] Number of vCPUs :', summary.config.numCpu)
160 | print('[VM] CPU Ready : Average {:.1f} %, Maximum {:.1f} %'.format((cpuReady / 20000 * 100),
161 | ((float(max(
162 | statCpuReady[0].value[
163 | 0].value)) / 20000 * 100))))
164 | print('[VM] CPU (%) : {:.0f} %'.format(cpuUsage))
165 | print('[VM] Memory : {} MB ({:.1f} GB)'.format(summary.config.memorySizeMB, (float(summary.config.memorySizeMB) / 1024)))
166 | print('[VM] Memory Shared : {:.0f} %, {:.0f} MB'.format(
167 | ((memoryShared / summary.config.memorySizeMB) * 100), memoryShared))
168 | print('[VM] Memory Balloon : {:.0f} %, {:.0f} MB'.format(
169 | ((memoryBalloon / summary.config.memorySizeMB) * 100), memoryBalloon))
170 | print('[VM] Memory Swapped : {:.0f} %, {:.0f} MB'.format(
171 | ((memorySwapped / summary.config.memorySizeMB) * 100), memorySwapped))
172 | print('[VM] Memory Active : {:.0f} %, {:.0f} MB'.format(
173 | ((memoryActive / summary.config.memorySizeMB) * 100), memoryActive))
174 | print('[VM] Datastore Average IO : Read: {:.0f} IOPS, Write: {:.0f} IOPS'.format(DatastoreIoRead,
175 | DatastoreIoWrite))
176 | print('[VM] Datastore Average Latency : Read: {:.0f} ms, Write: {:.0f} ms'.format(DatastoreLatRead,
177 | DatastoreLatWrite))
178 | print('[VM] Overall Network Usage : Transmitted {:.3f} Mbps, Received {:.3f} Mbps'.format(networkTx, networkRx))
179 | print('[Host] Name : {}'.format(summary.runtime.host.name))
180 | print('[Host] CPU Detail : Processor Sockets: {}, Cores per Socket {}'.format(
181 | summary.runtime.host.summary.hardware.numCpuPkgs,
182 | (summary.runtime.host.summary.hardware.numCpuCores / summary.runtime.host.summary.hardware.numCpuPkgs)))
183 | print('[Host] CPU Type : {}'.format(summary.runtime.host.summary.hardware.cpuModel))
184 | print('[Host] CPU Usage : Used: {} Mhz, Total: {} Mhz'.format(
185 | summary.runtime.host.summary.quickStats.overallCpuUsage,
186 | (summary.runtime.host.summary.hardware.cpuMhz * summary.runtime.host.summary.hardware.numCpuCores)))
187 | print('[Host] Memory Usage : Used: {:.0f} GB, Total: {:.0f} GB\n'.format(
188 | (float(summary.runtime.host.summary.quickStats.overallMemoryUsage) / 1024),
189 | (float(summary.runtime.host.summary.hardware.memorySize) / 1024 / 1024 / 1024)))
190 |
191 |
192 | def StatCheck(perf_dict, counter_name):
193 | counter_key = perf_dict[counter_name]
194 | return counter_key
195 |
196 |
197 | def GetProperties(content, viewType, props, specType):
198 | # Build a view and get basic properties for all Virtual Machines
199 | objView = content.viewManager.CreateContainerView(content.rootFolder, viewType, True)
200 | tSpec = vim.PropertyCollector.TraversalSpec(name='tSpecName', path='view', skip=False, type=vim.view.ContainerView)
201 | pSpec = vim.PropertyCollector.PropertySpec(all=False, pathSet=props, type=specType)
202 | oSpec = vim.PropertyCollector.ObjectSpec(obj=objView, selectSet=[tSpec], skip=False)
203 | pfSpec = vim.PropertyCollector.FilterSpec(objectSet=[oSpec], propSet=[pSpec], reportMissingObjectsInResults=False)
204 | retOptions = vim.PropertyCollector.RetrieveOptions()
205 | totalProps = []
206 | retProps = content.propertyCollector.RetrievePropertiesEx(specSet=[pfSpec], options=retOptions)
207 | totalProps += retProps.objects
208 | while retProps.token:
209 | retProps = content.propertyCollector.ContinueRetrievePropertiesEx(token=retProps.token)
210 | totalProps += retProps.objects
211 | objView.Destroy()
212 | # Turn the output in retProps into a usable dictionary of values
213 | gpOutput = []
214 | for eachProp in totalProps:
215 | propDic = {}
216 | for prop in eachProp.propSet:
217 | propDic[prop.name] = prop.val
218 | propDic['moref'] = eachProp.obj
219 | gpOutput.append(propDic)
220 | return gpOutput
221 |
222 |
223 | def main():
224 | args = GetArgs()
225 | try:
226 | vmnames = args.vm
227 | si = None
228 | if args.password:
229 | password = args.password
230 | else:
231 | password = getpass.getpass(prompt="Enter password for host {} and user {}: ".format(args.host, args.user))
232 | try:
233 | if args.cert_check_skip:
234 | context = ssl._create_unverified_context()
235 | si = SmartConnect(host=args.host,
236 | user=args.user,
237 | pwd=password,
238 | port=int(args.port),
239 | sslContext=context)
240 | else:
241 | si = SmartConnect(host=args.host,
242 | user=args.user,
243 | pwd=password,
244 | port=int(args.port))
245 | except IOError as e:
246 | pass
247 | if not si:
248 | print('Could not connect to the specified host using specified username and password')
249 | return -1
250 |
251 | atexit.register(Disconnect, si)
252 | content = si.RetrieveContent()
253 | # Get vCenter date and time for use as baseline when querying for counters
254 | vchtime = si.CurrentTime()
255 |
256 | # Get all the performance counters
257 | perf_dict = {}
258 | perfList = content.perfManager.perfCounter
259 | for counter in perfList:
260 | counter_full = "{}.{}.{}".format(counter.groupInfo.key, counter.nameInfo.key, counter.rollupType)
261 | perf_dict[counter_full] = counter.key
262 |
263 | retProps = GetProperties(content, [vim.VirtualMachine], ['name', 'runtime.powerState'], vim.VirtualMachine)
264 |
265 | #Find VM supplied as arg and use Managed Object Reference (moref) for the PrintVmInfo
266 | for vm in retProps:
267 | if (vm['name'] in vmnames) and (vm['runtime.powerState'] == "poweredOn"):
268 | PrintVmInfo(vm['moref'], content, vchtime, args.interval, perf_dict)
269 | elif vm['name'] in vmnames:
270 | print('ERROR: Problem connecting to Virtual Machine. {} is likely powered off or suspended'.format(vm['name']))
271 |
272 | except vmodl.MethodFault as e:
273 | print('Caught vmodl fault : ' + e.msg)
274 | return -1
275 | except Exception as e:
276 | print('Caught exception : ' + str(e))
277 | return -1
278 |
279 | return 0
280 |
281 | # Start program
282 | if __name__ == "__main__":
283 | main()
284 |
--------------------------------------------------------------------------------
/python-vmstats-web2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lgeeklee/python-vmstats/fc5ab24fe0585bede1febfaf4c94d750078a5763/python-vmstats-web2.png
--------------------------------------------------------------------------------
/viconfig.template:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 |
4 |
5 | def GetArgs():
6 | """
7 | Supports the command-line arguments listed below.
8 | """
9 |
10 | args = dict(host='',
11 | port=443,
12 | user='',
13 | password='',)
14 |
15 | return args
16 |
17 |
18 | def main():
19 | pass
20 |
21 |
22 | if __name__ == "__main__":
23 | main()
--------------------------------------------------------------------------------
/vm-win-stats-py3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lgeeklee/python-vmstats/fc5ab24fe0585bede1febfaf4c94d750078a5763/vm-win-stats-py3.png
--------------------------------------------------------------------------------
/vminfo-launch.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 | py-vminfo
9 |
10 |
11 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------