VMware vSphere support: Memory Usage
1) Added vSphere Hypervisor inspector. 2) Implemented memory usage pollster to generate memory usage samples for vSphere VMs. Change-Id: I2aab2fdbc9d0ff4ccf8553bac19c44e463e6595a Implements: blueprint vmware-vcenter-server
This commit is contained in:
parent
63f6cd4f9b
commit
82999b3886
52
ceilometer/compute/pollsters/memory.py
Normal file
52
ceilometer/compute/pollsters/memory.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Copyright (c) 2014 VMware, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from ceilometer.compute import plugin
|
||||||
|
from ceilometer.compute.pollsters import util
|
||||||
|
from ceilometer.compute.virt import inspector as virt_inspector
|
||||||
|
from ceilometer.openstack.common.gettextutils import _ # noqa
|
||||||
|
from ceilometer.openstack.common import log
|
||||||
|
from ceilometer import sample
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryUsagePollster(plugin.ComputePollster):
|
||||||
|
|
||||||
|
def get_samples(self, manager, cache, resources):
|
||||||
|
for instance in resources:
|
||||||
|
LOG.debug(_('Checking memory usage for instance %s'), instance.id)
|
||||||
|
try:
|
||||||
|
memory_info = manager.inspector.inspect_memory_usage(instance)
|
||||||
|
LOG.debug(_("MEMORY USAGE: %(instance)s %(usage)f"),
|
||||||
|
({'instance': instance.__dict__,
|
||||||
|
'usage': memory_info.usage}))
|
||||||
|
yield util.make_sample_from_instance(
|
||||||
|
instance,
|
||||||
|
name='memory.usage',
|
||||||
|
type=sample.TYPE_GAUGE,
|
||||||
|
unit='MB',
|
||||||
|
volume=memory_info.usage,
|
||||||
|
)
|
||||||
|
except virt_inspector.InstanceNotFoundException as err:
|
||||||
|
# Instance was deleted while getting samples. Ignore it.
|
||||||
|
LOG.debug(_('Exception while getting samples %s'), err)
|
||||||
|
except NotImplementedError:
|
||||||
|
# Selected inspector does not implement this pollster.
|
||||||
|
LOG.debug(_('Obtaining Memory Usage is not implemented for %s'
|
||||||
|
), manager.inspector.__class__.__name__)
|
||||||
|
except Exception as err:
|
||||||
|
LOG.error(_('Could not get Memory Usage for %(id)s: %(e)s'), (
|
||||||
|
{'id': instance.id, 'e': err}))
|
@ -53,6 +53,12 @@ Instance = collections.namedtuple('Instance', ['name', 'UUID'])
|
|||||||
#
|
#
|
||||||
CPUStats = collections.namedtuple('CPUStats', ['number', 'time'])
|
CPUStats = collections.namedtuple('CPUStats', ['number', 'time'])
|
||||||
|
|
||||||
|
# Named tuple representing Memory usage statistics.
|
||||||
|
#
|
||||||
|
# usage: Amount of memory used
|
||||||
|
#
|
||||||
|
MemoryUsageStats = collections.namedtuple('MemoryUsageStats', ['usage'])
|
||||||
|
|
||||||
|
|
||||||
# Named tuple representing vNICs.
|
# Named tuple representing vNICs.
|
||||||
#
|
#
|
||||||
@ -143,6 +149,14 @@ class Inspector(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def inspect_memory_usage(self, instance):
|
||||||
|
"""Inspect the memory usage statistics for an instance.
|
||||||
|
|
||||||
|
:param instance: the target instance
|
||||||
|
:return: the amount of memory used
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
def get_hypervisor_inspector():
|
def get_hypervisor_inspector():
|
||||||
try:
|
try:
|
||||||
|
97
ceilometer/compute/virt/vmware/inspector.py
Normal file
97
ceilometer/compute/virt/vmware/inspector.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# Copyright (c) 2014 VMware, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""Implementation of Inspector abstraction for VMware vSphere"""
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
from oslo.vmware import api
|
||||||
|
from oslo.vmware import vim
|
||||||
|
|
||||||
|
from ceilometer.compute.virt import inspector as virt_inspector
|
||||||
|
from ceilometer.compute.virt.vmware import vsphere_operations
|
||||||
|
from ceilometer.openstack.common import units
|
||||||
|
|
||||||
|
|
||||||
|
opt_group = cfg.OptGroup(name='vmware',
|
||||||
|
title='Options for VMware')
|
||||||
|
|
||||||
|
OPTS = [
|
||||||
|
cfg.StrOpt('host_ip',
|
||||||
|
default='',
|
||||||
|
help='IP address of the VMware Vsphere host'),
|
||||||
|
cfg.StrOpt('host_username',
|
||||||
|
default='',
|
||||||
|
help='Username of VMware Vsphere'),
|
||||||
|
cfg.StrOpt('host_password',
|
||||||
|
default='',
|
||||||
|
help='Password of VMware Vsphere'),
|
||||||
|
cfg.IntOpt('api_retry_count',
|
||||||
|
default=10,
|
||||||
|
help='Number of times a VMware Vsphere API must be retried'),
|
||||||
|
cfg.FloatOpt('task_poll_interval',
|
||||||
|
default=0.5,
|
||||||
|
help='Sleep time in seconds for polling an ongoing async '
|
||||||
|
'task'),
|
||||||
|
]
|
||||||
|
|
||||||
|
cfg.CONF.register_group(opt_group)
|
||||||
|
cfg.CONF.register_opts(OPTS, group=opt_group)
|
||||||
|
|
||||||
|
VC_AVERAGE_MEMORY_CONSUMED_CNTR = 'mem:consumed:average'
|
||||||
|
|
||||||
|
|
||||||
|
def get_api_session():
|
||||||
|
hostIp = cfg.CONF.vmware.host_ip
|
||||||
|
wsdl_loc = vim.Vim._get_wsdl_loc("https", hostIp)
|
||||||
|
api_session = api.VMwareAPISession(
|
||||||
|
hostIp,
|
||||||
|
cfg.CONF.vmware.host_username,
|
||||||
|
cfg.CONF.vmware.host_password,
|
||||||
|
cfg.CONF.vmware.api_retry_count,
|
||||||
|
cfg.CONF.vmware.task_poll_interval,
|
||||||
|
wsdl_loc=wsdl_loc)
|
||||||
|
return api_session
|
||||||
|
|
||||||
|
|
||||||
|
class VsphereInspector(virt_inspector.Inspector):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(VsphereInspector, self).__init__()
|
||||||
|
self._ops = vsphere_operations.VsphereOperations(
|
||||||
|
get_api_session(), 1000)
|
||||||
|
|
||||||
|
def inspect_instances(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def inspect_cpus(self, instance_name):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def inspect_vnics(self, instance_name):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def inspect_disks(self, instance_name):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def inspect_memory_usage(self, instance):
|
||||||
|
vm_moid = self._ops.get_vm_moid(instance.id)
|
||||||
|
if vm_moid is None:
|
||||||
|
raise virt_inspector.InstanceNotFoundException(
|
||||||
|
_('VM %s not found in VMware Vsphere') % instance.id)
|
||||||
|
mem_counter_id = self._ops.get_perf_counter_id(
|
||||||
|
VC_AVERAGE_MEMORY_CONSUMED_CNTR)
|
||||||
|
memory = self._ops.query_vm_aggregate_stats(vm_moid, mem_counter_id)
|
||||||
|
#Stat provided from VMware Vsphere is in Bytes, converting it to MB.
|
||||||
|
memory = memory / (units.Mi)
|
||||||
|
return virt_inspector.MemoryUsageStats(usage=memory)
|
55
ceilometer/tests/compute/pollsters/test_memory.py
Normal file
55
ceilometer/tests/compute/pollsters/test_memory.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Copyright (c) 2014 VMware, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
import six
|
||||||
|
|
||||||
|
from ceilometer.compute import manager
|
||||||
|
from ceilometer.compute.pollsters import memory
|
||||||
|
from ceilometer.compute.virt import inspector as virt_inspector
|
||||||
|
from ceilometer.tests.compute.pollsters import base
|
||||||
|
|
||||||
|
|
||||||
|
class TestMemoryPollster(base.TestPollsterBase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestMemoryPollster, self).setUp()
|
||||||
|
|
||||||
|
@mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock())
|
||||||
|
def test_get_samples(self):
|
||||||
|
next_value = iter((
|
||||||
|
virt_inspector.MemoryUsageStats(usage=1.0),
|
||||||
|
virt_inspector.MemoryUsageStats(usage=2.0),
|
||||||
|
))
|
||||||
|
|
||||||
|
def inspect_memory_usage(name):
|
||||||
|
return six.next(next_value)
|
||||||
|
|
||||||
|
self.inspector.inspect_memory_usage = \
|
||||||
|
mock.Mock(side_effect=inspect_memory_usage)
|
||||||
|
|
||||||
|
mgr = manager.AgentManager()
|
||||||
|
pollster = memory.MemoryUsagePollster()
|
||||||
|
|
||||||
|
def _verify_memory_metering(expected_memory_mb):
|
||||||
|
cache = {}
|
||||||
|
samples = list(pollster.get_samples(mgr, cache, [self.instance]))
|
||||||
|
self.assertEqual(1, len(samples))
|
||||||
|
self.assertEqual(set(['memory.usage']),
|
||||||
|
set([s.name for s in samples]))
|
||||||
|
self.assertEqual(expected_memory_mb, samples[0].volume)
|
||||||
|
|
||||||
|
_verify_memory_metering(1.0)
|
||||||
|
_verify_memory_metering(2.0)
|
61
ceilometer/tests/compute/virt/vmware/test_inspector.py
Normal file
61
ceilometer/tests/compute/virt/vmware/test_inspector.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# Copyright (c) 2014 VMware, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
"""
|
||||||
|
Tests for VMware Vsphere inspector.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from oslo.vmware import api
|
||||||
|
|
||||||
|
from ceilometer.compute.virt import inspector as virt_inspector
|
||||||
|
from ceilometer.compute.virt.vmware import inspector as vsphere_inspector
|
||||||
|
from ceilometer.openstack.common import test
|
||||||
|
|
||||||
|
|
||||||
|
class TestVsphereInspection(test.BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
api_session = api.VMwareAPISession("test_server", "test_user",
|
||||||
|
"test_password", 0, None,
|
||||||
|
create_session=False)
|
||||||
|
api_session._vim = mock.MagicMock()
|
||||||
|
vsphere_inspector.get_api_session = mock.Mock(
|
||||||
|
return_value=api_session)
|
||||||
|
self._inspector = vsphere_inspector.VsphereInspector()
|
||||||
|
self._inspector._ops = mock.MagicMock()
|
||||||
|
|
||||||
|
super(TestVsphereInspection, self).setUp()
|
||||||
|
|
||||||
|
def test_inspect_memory_usage(self):
|
||||||
|
fake_instance_moid = 'fake_instance_moid'
|
||||||
|
fake_instance_id = 'fake_instance_id'
|
||||||
|
fake_perf_counter_id = 'fake_perf_counter_id'
|
||||||
|
fake_memory_value = 1048576.0
|
||||||
|
fake_stat = virt_inspector.MemoryUsageStats(usage=1.0)
|
||||||
|
|
||||||
|
def construct_mock_instance_object(fake_instance_id):
|
||||||
|
instance_object = mock.MagicMock()
|
||||||
|
instance_object.id = fake_instance_id
|
||||||
|
return instance_object
|
||||||
|
|
||||||
|
fake_instance = construct_mock_instance_object(fake_instance_id)
|
||||||
|
self._inspector._ops.get_vm_moid.return_value = fake_instance_moid
|
||||||
|
self._inspector._ops.get_perf_counter_id.return_value = \
|
||||||
|
fake_perf_counter_id
|
||||||
|
self._inspector._ops.query_vm_aggregate_stats.return_value = \
|
||||||
|
fake_memory_value
|
||||||
|
memory_stat = self._inspector.inspect_memory_usage(fake_instance)
|
||||||
|
self.assertEqual(fake_stat, memory_stat)
|
@ -70,7 +70,8 @@ Name Type Unit Resource Origin No
|
|||||||
============================= ========== ========= ======== ============ ==================================================================
|
============================= ========== ========= ======== ============ ==================================================================
|
||||||
instance Gauge instance inst ID both Existence of instance
|
instance Gauge instance inst ID both Existence of instance
|
||||||
instance:<type> Gauge instance inst ID both Existence of instance <type> (openstack types)
|
instance:<type> Gauge instance inst ID both Existence of instance <type> (openstack types)
|
||||||
memory Gauge MB inst ID notification Volume of RAM in MB
|
memory Gauge MB inst ID notification Volume of RAM allocated in MB
|
||||||
|
memory.usage Gauge MB inst ID pollster Volume of RAM used in MB
|
||||||
cpu Cumulative ns inst ID pollster CPU time used
|
cpu Cumulative ns inst ID pollster CPU time used
|
||||||
cpu_util Gauge % inst ID pollster Average CPU utilisation
|
cpu_util Gauge % inst ID pollster Average CPU utilisation
|
||||||
vcpus Gauge vcpu inst ID notification Number of VCPUs
|
vcpus Gauge vcpu inst ID notification Number of VCPUs
|
||||||
|
@ -982,3 +982,27 @@
|
|||||||
#key_file=<None>
|
#key_file=<None>
|
||||||
|
|
||||||
|
|
||||||
|
[vmware]
|
||||||
|
|
||||||
|
#
|
||||||
|
# Options defined in ceilometer.compute.virt.vmware.inspector
|
||||||
|
#
|
||||||
|
|
||||||
|
# IP address of the VMware Vsphere host (string value)
|
||||||
|
#host_ip=
|
||||||
|
|
||||||
|
# Username of VMware Vsphere (string value)
|
||||||
|
#host_username=
|
||||||
|
|
||||||
|
# Password of VMware Vsphere (string value)
|
||||||
|
#host_password=
|
||||||
|
|
||||||
|
# Number of times a VMware Vsphere API must be retried
|
||||||
|
# (integer value)
|
||||||
|
#api_retry_count=10
|
||||||
|
|
||||||
|
# Sleep time in seconds for polling an ongoing async task
|
||||||
|
# (floating point value)
|
||||||
|
#task_poll_interval=0.5
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ ceilometer.poll.compute =
|
|||||||
network.outgoing.packets = ceilometer.compute.pollsters.net:OutgoingPacketsPollster
|
network.outgoing.packets = ceilometer.compute.pollsters.net:OutgoingPacketsPollster
|
||||||
instance = ceilometer.compute.pollsters.instance:InstancePollster
|
instance = ceilometer.compute.pollsters.instance:InstancePollster
|
||||||
instance_flavor = ceilometer.compute.pollsters.instance:InstanceFlavorPollster
|
instance_flavor = ceilometer.compute.pollsters.instance:InstanceFlavorPollster
|
||||||
|
memory.usage = ceilometer.compute.pollsters.memory:MemoryUsagePollster
|
||||||
|
|
||||||
ceilometer.poll.central =
|
ceilometer.poll.central =
|
||||||
ip.floating = ceilometer.network.floatingip:FloatingIPPollster
|
ip.floating = ceilometer.network.floatingip:FloatingIPPollster
|
||||||
@ -139,6 +140,7 @@ ceilometer.storage =
|
|||||||
ceilometer.compute.virt =
|
ceilometer.compute.virt =
|
||||||
libvirt = ceilometer.compute.virt.libvirt.inspector:LibvirtInspector
|
libvirt = ceilometer.compute.virt.libvirt.inspector:LibvirtInspector
|
||||||
hyperv = ceilometer.compute.virt.hyperv.inspector:HyperVInspector
|
hyperv = ceilometer.compute.virt.hyperv.inspector:HyperVInspector
|
||||||
|
vsphere = ceilometer.compute.virt.vmware.inspector:VsphereInspector
|
||||||
|
|
||||||
ceilometer.hardware.inspectors =
|
ceilometer.hardware.inspectors =
|
||||||
snmp = ceilometer.hardware.inspector.snmp:SNMPInspector
|
snmp = ceilometer.hardware.inspector.snmp:SNMPInspector
|
||||||
|
Loading…
x
Reference in New Issue
Block a user