1
# Copyright (c) 2014 VMware, Inc.
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
# not use this file except in compliance with the License. You may obtain
6
# a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# License for the specific language governing permissions and limitations
16
from oslo.vmware import vim_util
19
PERF_MANAGER_TYPE = "PerformanceManager"
20
PERF_COUNTER_PROPERTY = "perfCounter"
21
VM_INSTANCE_ID_PROPERTY = 'config.extraConfig["nvp.vm-uuid"].value'
23
# ESXi Servers sample performance data every 20 seconds. 20-second interval
24
# data is called instance data or real-time data. To retrieve instance data,
25
# we need to specify a value of 20 seconds for the "PerfQuerySpec.intervalId"
26
# property. In that case the "QueryPerf" method operates as a raw data feed
27
# that bypasses the vCenter database and instead retrieves performance data
29
# The following value is time interval for real-time performance stats
30
# in seconds and it is not configurable.
31
VC_REAL_TIME_SAMPLING_INTERVAL = 20
34
class VsphereOperations(object):
35
"""Class to invoke vSphere APIs calls required by various
36
pollsters, collecting data from VMware infrastructure.
38
def __init__(self, api_session, max_objects):
39
self._api_session = api_session
40
self._max_objects = max_objects
41
# Mapping between "VM's Nova instance Id" -> "VM's MOID"
42
# In case a VM is deployed by Nova, then its name is instance ID.
43
# So this map essentially has VM names as keys.
44
self._vm_moid_lookup_map = {}
46
# Mapping from full name -> ID, for VC Performance counters
47
self._perf_counter_id_lookup_map = None
49
def _init_vm_moid_lookup_map(self):
50
session = self._api_session
51
result = session.invoke_api(vim_util, "get_objects", session.vim,
52
"VirtualMachine", self._max_objects,
53
[VM_INSTANCE_ID_PROPERTY],
56
for vm_object in result.objects:
57
vm_moid = vm_object.obj.value
58
vm_instance_id = vm_object.propSet[0].val
60
self._vm_moid_lookup_map[vm_instance_id] = vm_moid
62
result = session.invoke_api(vim_util, "continue_retrieval",
65
def get_vm_moid(self, vm_instance_id):
66
"""Method returns VC MOID of the VM by its NOVA instance ID.
68
if vm_instance_id not in self._vm_moid_lookup_map:
69
self._init_vm_moid_lookup_map()
71
return self._vm_moid_lookup_map.get(vm_instance_id, None)
73
def _init_perf_counter_id_lookup_map(self):
75
# Query details of all the performance counters from VC
76
session = self._api_session
77
client_factory = session.vim.client.factory
78
perf_manager = session.vim.service_content.perfManager
80
prop_spec = vim_util.build_property_spec(
81
client_factory, PERF_MANAGER_TYPE, [PERF_COUNTER_PROPERTY])
83
obj_spec = vim_util.build_object_spec(
84
client_factory, perf_manager, None)
86
filter_spec = vim_util.build_property_filter_spec(
87
client_factory, [prop_spec], [obj_spec])
89
options = client_factory.create('ns0:RetrieveOptions')
90
options.maxObjects = 1
92
prop_collector = session.vim.service_content.propertyCollector
93
result = session.invoke_api(session.vim, "RetrievePropertiesEx",
94
prop_collector, specSet=[filter_spec],
97
perf_counter_infos = result.objects[0].propSet[0].val.PerfCounterInfo
99
# Extract the counter Id for each counter and populate the map
100
self._perf_counter_id_lookup_map = {}
101
for perf_counter_info in perf_counter_infos:
103
counter_group = perf_counter_info.groupInfo.key
104
counter_name = perf_counter_info.nameInfo.key
105
counter_rollup_type = perf_counter_info.rollupType
106
counter_id = perf_counter_info.key
108
counter_full_name = (counter_group + ":" + counter_name + ":" +
110
self._perf_counter_id_lookup_map[counter_full_name] = counter_id
112
def get_perf_counter_id(self, counter_full_name):
113
"""Method returns the ID of VC performance counter by its full name.
115
A VC performance counter is uniquely identified by the
116
tuple {'Group Name', 'Counter Name', 'Rollup Type'}.
117
It will have an id - counter ID (changes from one VC to another),
118
which is required to query performance stats from that VC.
119
This method returns the ID for a counter,
120
assuming 'CounterFullName' => 'Group Name:CounterName:RollupType'.
122
if not self._perf_counter_id_lookup_map:
123
self._init_perf_counter_id_lookup_map()
124
return self._perf_counter_id_lookup_map[counter_full_name]
126
# TODO(akhils@vmware.com) Move this method to common library
127
# when it gets checked-in
128
def query_vm_property(self, vm_moid, property_name):
129
"""Method returns the value of specified property for a VM.
131
:param vm_moid: moid of the VM whose property is to be queried
132
:param property_name: path of the property
134
vm_mobj = vim_util.get_moref(vm_moid, "VirtualMachine")
135
session = self._api_session
136
return session.invoke_api(vim_util, "get_object_property",
137
session.vim, vm_mobj, property_name)
139
def query_vm_aggregate_stats(self, vm_moid, counter_id):
140
"""Method queries the aggregated real-time stat value for a VM.
142
This method should be used for aggregate counters.
144
:param vm_moid: moid of the VM
145
:param counter_id: id of the perf counter in VC
146
:return: the aggregated stats value for the counter
148
# For aggregate counters, device_name should be ""
149
stats = self._query_vm_perf_stats(vm_moid, counter_id, "")
151
# Performance manager provides the aggregated stats value
152
# with device name -> None
153
return stats.get(None, 0)
155
def query_vm_device_stats(self, vm_moid, counter_id):
156
"""Method queries the real-time stat values for a VM, for all devices.
158
This method should be used for device(non-aggregate) counters.
160
:param vm_moid: moid of the VM
161
:param counter_id: id of the perf counter in VC
162
:return: a map containing the stat values keyed by the device ID/name
164
# For device counters, device_name should be "*" to get stat values
166
stats = self._query_vm_perf_stats(vm_moid, counter_id, "*")
168
# For some device counters, in addition to the per device value
169
# the Performance manager also returns the aggregated value.
170
# Just to be consistent, deleting the aggregated value if present.
171
stats.pop(None, None)
174
def _query_vm_perf_stats(self, vm_moid, counter_id, device_name):
175
"""Method queries the real-time stat values for a VM.
177
:param vm_moid: moid of the VM for which stats are needed
178
:param counter_id: id of the perf counter in VC
179
:param device_name: name of the device for which stats are to be
180
queried. For aggregate counters pass empty string ("").
181
For device counters pass "*", if stats are required over all
183
:return: a map containing the stat values keyed by the device ID/name
186
session = self._api_session
187
client_factory = session.vim.client.factory
189
# Construct the QuerySpec
190
metric_id = client_factory.create('ns0:PerfMetricId')
191
metric_id.counterId = counter_id
192
metric_id.instance = device_name
194
query_spec = client_factory.create('ns0:PerfQuerySpec')
195
query_spec.entity = vim_util.get_moref(vm_moid, "VirtualMachine")
196
query_spec.metricId = [metric_id]
197
query_spec.intervalId = VC_REAL_TIME_SAMPLING_INTERVAL
198
# The following setting ensures that we need only one latest sample
199
query_spec.maxSample = 1
201
perf_manager = session.vim.service_content.perfManager
202
perf_stats = session.invoke_api(session.vim, 'QueryPerf', perf_manager,
203
querySpec=[query_spec])
207
entity_metric = perf_stats[0]
208
sample_infos = entity_metric.sampleInfo
209
samples_count = len(sample_infos)
211
if samples_count > 0:
212
for metric_series in entity_metric.value:
213
stat_value = metric_series.value[samples_count - 1]
214
device_id = metric_series.id.instance
215
stat_values[device_id] = stat_value