Unify Counter generation from notifications

This will make sure we don't lose any metadata information from
notifications into the Counter/samples we publish.

This is part of fixing bug #1187833 and bug #1187843

Change-Id: I315581907be1dcec33f43a5d5fd7b7876a7889f6
Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2013-06-14 13:51:39 +02:00
parent bd594cbde1
commit 00531f9de0
14 changed files with 381 additions and 609 deletions

View File

@ -1,93 +0,0 @@
# -*- encoding: utf-8 -*-
#
# Copyright © 2012 New Dream Network, LLC (DreamHost)
#
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
#
# 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.
"""Common code for working with instances
"""
from oslo.config import cfg
OPTS = [
cfg.ListOpt('reserved_metadata_namespace',
default=['metering.'],
help='list of metadata prefixes resevred for metering use',
),
cfg.IntOpt('reserved_metadata_length',
default=256,
help='limit on length of reserved metadata values'),
]
cfg.CONF.register_opts(OPTS)
INSTANCE_PROPERTIES = [
# Identity properties
'reservation_id',
# Type properties
'architecture',
# Location properties
'kernel_id',
'os_type',
'ramdisk_id',
# Capacity properties
'ephemeral_gb',
'root_gb']
def add_reserved_user_metadata(instance, metadata):
limit = cfg.CONF.reserved_metadata_length
user_metadata = {}
for prefix in cfg.CONF.reserved_metadata_namespace:
md = dict(
(k[len(prefix):].replace('.', '_'),
v[:limit] if isinstance(v, basestring) else v)
for k, v in instance.metadata.items()
if (k.startswith(prefix) and
k[len(prefix):].replace('.', '_') not in metadata)
)
user_metadata.update(md)
if user_metadata:
metadata['user_metadata'] = user_metadata
return metadata
def get_metadata_from_object(instance):
"""Return a metadata dictionary for the instance.
"""
metadata = {
'availability_zone': getattr(instance,
'OS-EXT-AZ:availability_zone', u''),
'display_name': instance.name,
'name': getattr(instance, 'OS-EXT-SRV-ATTR:instance_name', u''),
'instance_type': (instance.flavor['id'] if instance.flavor else None),
'disk_gb': (instance.flavor['disk'] if instance.flavor else None),
'memory_mb': (instance.flavor['ram'] if instance.flavor else None),
'vcpus': (instance.flavor['vcpus'] if instance.flavor else None),
'host': instance.hostId,
# Image properties
'image_ref': (instance.image['id'] if instance.image else None),
}
# Images that come through the conductor API in the nova notifier
# plugin will not have links.
if instance.image and instance.image.get('links'):
metadata['image_ref_url'] = instance.image['links'][0]['href']
else:
metadata['image_ref_url'] = None
for name in INSTANCE_PROPERTIES:
metadata[name] = getattr(instance, name, u'')
return add_reserved_user_metadata(instance, metadata)

View File

@ -22,10 +22,8 @@
from oslo.config import cfg
from ceilometer.compute import instance
from ceilometer import counter
from ceilometer import plugin
from ceilometer import utils
OPTS = [
@ -39,7 +37,6 @@ cfg.CONF.register_opts(OPTS)
class ComputeNotificationBase(plugin.NotificationBase):
@staticmethod
def get_exchange_topics(conf):
"""Return a sequence of ExchangeTopics defining the exchange and
@ -54,50 +51,27 @@ class ComputeNotificationBase(plugin.NotificationBase):
class InstanceScheduled(ComputeNotificationBase):
metadata_keys = ['request_spec']
@staticmethod
def get_event_types():
return ['scheduler.run_instance.scheduled']
def notification_to_metadata(self, event):
metadata = super(InstanceScheduled,
self).notification_to_metadata(event)
metadata['weighted_host'] = event['payload']['weighted_host']['host']
metadata['weight'] = event['payload']['weighted_host']['weight']
return metadata
def process_notification(self, message):
return [
counter.Counter(
name='instance.scheduled',
type=counter.TYPE_DELTA,
volume=1,
unit='instance',
user_id=None,
project_id=
message['payload']['request_spec']
['instance_properties']['project_id'],
resource_id=message['payload']['instance_id'],
timestamp=message['timestamp'],
resource_metadata=dict(
utils.recursive_keypairs(message['payload'])),
)
]
yield counter.Counter.from_notification(
name='instance.scheduled',
type=counter.TYPE_DELTA,
volume=1,
unit='instance',
user_id=None,
project_id=
message['payload']['request_spec']
['instance_properties']['project_id'],
resource_id=message['payload']['instance_id'],
message=message)
class ComputeInstanceNotificationBase(ComputeNotificationBase):
"""Convert compute.instance.* notifications into Counters
"""
metadata_keys = instance.INSTANCE_PROPERTIES
def notification_to_metadata(self, event):
metadata = super(ComputeInstanceNotificationBase,
self).notification_to_metadata(event)
metadata['instance_type'] = event['payload']['instance_type_id']
return metadata
@staticmethod
def get_event_types():
return ['compute.instance.create.end',
@ -108,112 +82,83 @@ class ComputeInstanceNotificationBase(ComputeNotificationBase):
class Instance(ComputeInstanceNotificationBase):
def process_notification(self, message):
return [
counter.Counter(name='instance',
type=counter.TYPE_GAUGE,
unit='instance',
volume=1,
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
timestamp=message['timestamp'],
resource_metadata=self.notification_to_metadata(
message),
),
]
yield counter.Counter.from_notification(
name='instance',
type=counter.TYPE_GAUGE,
unit='instance',
volume=1,
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
message=message)
class Memory(ComputeInstanceNotificationBase):
def process_notification(self, message):
return [
counter.Counter(name='memory',
type=counter.TYPE_GAUGE,
unit='MB',
volume=message['payload']['memory_mb'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
timestamp=message['timestamp'],
resource_metadata=self.notification_to_metadata(
message)),
]
yield counter.Counter.from_notification(
name='memory',
type=counter.TYPE_GAUGE,
unit='MB',
volume=message['payload']['memory_mb'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
message=message)
class VCpus(ComputeInstanceNotificationBase):
def process_notification(self, message):
return [
counter.Counter(name='vcpus',
type=counter.TYPE_GAUGE,
unit='vcpu',
volume=message['payload']['vcpus'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
timestamp=message['timestamp'],
resource_metadata=self.notification_to_metadata(
message)),
]
yield counter.Counter.from_notification(
name='vcpus',
type=counter.TYPE_GAUGE,
unit='vcpu',
volume=message['payload']['vcpus'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
message=message)
class RootDiskSize(ComputeInstanceNotificationBase):
def process_notification(self, message):
return [
counter.Counter(name='disk.root.size',
type=counter.TYPE_GAUGE,
unit='GB',
volume=message['payload']['root_gb'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
timestamp=message['timestamp'],
resource_metadata=self.notification_to_metadata(
message)),
]
yield counter.Counter.from_notification(
name='disk.root.size',
type=counter.TYPE_GAUGE,
unit='GB',
volume=message['payload']['root_gb'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
message=message)
class EphemeralDiskSize(ComputeInstanceNotificationBase):
def process_notification(self, message):
return [
counter.Counter(name='disk.ephemeral.size',
type=counter.TYPE_GAUGE,
unit='GB',
volume=message['payload']['ephemeral_gb'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
timestamp=message['timestamp'],
resource_metadata=self.notification_to_metadata(
message)),
]
yield counter.Counter.from_notification(
name='disk.ephemeral.size',
type=counter.TYPE_GAUGE,
unit='GB',
volume=message['payload']['ephemeral_gb'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
message=message)
class InstanceFlavor(ComputeInstanceNotificationBase):
def process_notification(self, message):
counters = []
instance_type = message.get('payload', {}).get('instance_type')
if instance_type:
counters.append(
counter.Counter(
name='instance:%s' % instance_type,
type=counter.TYPE_GAUGE,
unit='instance',
volume=1,
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
timestamp=message['timestamp'],
resource_metadata=self.notification_to_metadata(
message),
)
)
return counters
yield counter.Counter.from_notification(
name='instance:%s' % instance_type,
type=counter.TYPE_GAUGE,
unit='instance',
volume=1,
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
message=message)
class InstanceDelete(ComputeInstanceNotificationBase):
@ -226,17 +171,13 @@ class InstanceDelete(ComputeInstanceNotificationBase):
return ['compute.instance.delete.samples']
def process_notification(self, message):
return [
counter.Counter(name=sample['name'],
type=sample['type'],
unit=sample['unit'],
volume=sample['volume'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
timestamp=message['timestamp'],
resource_metadata=self.notification_to_metadata(
message),
)
for sample in message['payload'].get('samples', [])
]
for sample in message['payload'].get('samples', []):
yield counter.Counter.from_notification(
name=sample['name'],
type=sample['type'],
unit=sample['unit'],
volume=sample['volume'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['instance_id'],
message=message)

View File

@ -21,7 +21,8 @@
import copy
import datetime
from ceilometer.compute import instance as compute_instance
from oslo.config import cfg
from ceilometer.compute import plugin
from ceilometer import counter
from ceilometer.openstack.common import log
@ -30,6 +31,78 @@ from ceilometer.openstack.common import timeutils
LOG = log.getLogger(__name__)
INSTANCE_PROPERTIES = [
# Identity properties
'reservation_id',
# Type properties
'architecture',
'OS-EXT-AZ:availability_zone',
'kernel_id',
'os_type',
'ramdisk_id',
# Capacity properties
'disk_gb',
'ephemeral_gb',
'memory_mb',
'root_gb',
'vcpus']
OPTS = [
cfg.ListOpt('reserved_metadata_namespace',
default=['metering.'],
help='list of metadata prefixes reserved for metering use'),
cfg.IntOpt('reserved_metadata_length',
default=256,
help='limit on length of reserved metadata values'),
]
cfg.CONF.register_opts(OPTS)
def _add_reserved_user_metadata(instance, metadata):
limit = cfg.CONF.reserved_metadata_length
user_metadata = {}
for prefix in cfg.CONF.reserved_metadata_namespace:
md = dict(
(k[len(prefix):].replace('.', '_'),
v[:limit] if isinstance(v, basestring) else v)
for k, v in instance.metadata.items()
if (k.startswith(prefix) and
k[len(prefix):].replace('.', '_') not in metadata)
)
user_metadata.update(md)
if user_metadata:
metadata['user_metadata'] = user_metadata
return metadata
def _get_metadata_from_object(instance):
"""Return a metadata dictionary for the instance.
"""
metadata = {
'display_name': instance.name,
'name': getattr(instance, 'OS-EXT-SRV-ATTR:instance_name', u''),
'instance_type': (instance.flavor['id'] if instance.flavor else None),
'host': instance.hostId,
'flavor': instance.flavor,
# Image properties
'image': instance.image,
'image_ref': (instance.image['id'] if instance.image else None),
}
# Images that come through the conductor API in the nova notifier
# plugin will not have links.
if instance.image and instance.image.get('links'):
metadata['image_ref_url'] = instance.image['links'][0]['href']
else:
metadata['image_ref_url'] = None
for name in INSTANCE_PROPERTIES:
metadata[name] = getattr(instance, name, u'')
return _add_reserved_user_metadata(instance, metadata)
def _instance_name(instance):
"""Shortcut to get instance name."""
return getattr(instance, 'OS-EXT-SRV-ATTR:instance_name', None)
@ -45,7 +118,7 @@ def make_counter_from_instance(instance, name, type, unit, volume):
project_id=instance.tenant_id,
resource_id=instance.id,
timestamp=timeutils.isotime(),
resource_metadata=compute_instance.get_metadata_from_object(instance),
resource_metadata=_get_metadata_from_object(instance),
)

View File

@ -23,6 +23,7 @@ in by the plugins that create them.
"""
import collections
import copy
from oslo.config import cfg
@ -67,3 +68,23 @@ Counter = collections.namedtuple('Counter',
TYPE_GAUGE = 'gauge'
TYPE_DELTA = 'delta'
TYPE_CUMULATIVE = 'cumulative'
def from_notification(cls, name, type, volume, unit,
user_id, project_id, resource_id,
message):
metadata = copy.copy(message['payload'])
metadata['event_type'] = message['event_type']
metadata['host'] = message['publisher_id']
return cls(name=name,
type=type,
volume=volume,
unit=unit,
user_id=user_id,
project_id=project_id,
resource_id=resource_id,
timestamp=message['timestamp'],
resource_metadata=metadata)
Counter.from_notification = classmethod(from_notification)

View File

@ -51,25 +51,6 @@ class ImageBase(plugin.NotificationBase):
class ImageCRUDBase(ImageBase):
metadata_keys = [
'name',
'size',
'status',
'disk_format',
'container_format',
'location',
'deleted',
'created_at',
'updated_at',
'properties',
'protected',
'checksum',
'is_public',
'deleted_at',
'min_ram',
]
@staticmethod
def get_event_types():
return [
@ -80,67 +61,46 @@ class ImageCRUDBase(ImageBase):
class ImageCRUD(ImageCRUDBase):
def process_notification(self, message):
metadata = self.notification_to_metadata(message)
return [
counter.Counter(
name=message['event_type'],
type=counter.TYPE_DELTA,
unit='image',
volume=1,
resource_id=message['payload']['id'],
user_id=None,
project_id=message['payload']['owner'],
timestamp=message['timestamp'],
resource_metadata=metadata,
),
]
yield counter.Counter.from_notification(
name=message['event_type'],
type=counter.TYPE_DELTA,
unit='image',
volume=1,
resource_id=message['payload']['id'],
user_id=None,
project_id=message['payload']['owner'],
message=message)
class Image(ImageCRUDBase):
def process_notification(self, message):
metadata = self.notification_to_metadata(message)
return [
counter.Counter(
name='image',
type=counter.TYPE_GAUGE,
unit='image',
volume=1,
resource_id=message['payload']['id'],
user_id=None,
project_id=message['payload']['owner'],
timestamp=message['timestamp'],
resource_metadata=metadata,
),
]
yield counter.Counter.from_notification(
name='image',
type=counter.TYPE_GAUGE,
unit='image',
volume=1,
resource_id=message['payload']['id'],
user_id=None,
project_id=message['payload']['owner'],
message=message)
class ImageSize(ImageCRUDBase):
def process_notification(self, message):
metadata = self.notification_to_metadata(message)
return [
counter.Counter(
name='image.size',
type=counter.TYPE_GAUGE,
unit='B',
volume=message['payload']['size'],
resource_id=message['payload']['id'],
user_id=None,
project_id=message['payload']['owner'],
timestamp=message['timestamp'],
resource_metadata=metadata,
),
]
yield counter.Counter.from_notification(
name='image.size',
type=counter.TYPE_GAUGE,
unit='B',
volume=message['payload']['size'],
resource_id=message['payload']['id'],
user_id=None,
project_id=message['payload']['owner'],
message=message)
class ImageDownload(ImageBase):
"""Emit image_download counter when an image is downloaded."""
metadata_keys = ['destination_ip', 'owner_id']
@staticmethod
def get_event_types():
return [
@ -148,28 +108,19 @@ class ImageDownload(ImageBase):
]
def process_notification(self, message):
metadata = self.notification_to_metadata(message)
return [
counter.Counter(
name='image.download',
type=counter.TYPE_DELTA,
unit='B',
volume=message['payload']['bytes_sent'],
resource_id=message['payload']['image_id'],
user_id=message['payload']['receiver_user_id'],
project_id=message['payload']['receiver_tenant_id'],
timestamp=message['timestamp'],
resource_metadata=metadata,
),
]
yield counter.Counter.from_notification(
name='image.download',
type=counter.TYPE_DELTA,
unit='B',
volume=message['payload']['bytes_sent'],
resource_id=message['payload']['image_id'],
user_id=message['payload']['receiver_user_id'],
project_id=message['payload']['receiver_tenant_id'],
message=message)
class ImageServe(ImageBase):
"""Emit image_serve counter when an image is served out."""
metadata_keys = ['destination_ip', 'receiver_user_id',
'receiver_tenant_id']
@staticmethod
def get_event_types():
return [
@ -177,17 +128,12 @@ class ImageServe(ImageBase):
]
def process_notification(self, message):
metadata = self.notification_to_metadata(message)
return [
counter.Counter(
name='image.serve',
type=counter.TYPE_DELTA,
unit='B',
volume=message['payload']['bytes_sent'],
resource_id=message['payload']['image_id'],
user_id=None,
project_id=message['payload']['owner_id'],
timestamp=message['timestamp'],
resource_metadata=metadata,
),
]
yield counter.Counter.from_notification(
name='image.serve',
type=counter.TYPE_DELTA,
unit='B',
volume=message['payload']['bytes_sent'],
resource_id=message['payload']['image_id'],
user_id=None,
project_id=message['payload']['owner_id'],
message=message)

View File

@ -72,34 +72,31 @@ class NetworkNotificationBase(plugin.NotificationBase):
def process_notification(self, message):
LOG.info('network notification %r', message)
message['payload'] = message['payload'][self.resource_name]
metadata = self.notification_to_metadata(message)
counter_name = getattr(self, 'counter_name', self.resource_name)
unit_value = getattr(self, 'unit', self.resource_name)
yield counter.Counter(name=counter_name,
type=counter.TYPE_GAUGE,
unit=unit_value,
volume=1,
user_id=message['_context_user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['id'],
timestamp=message['timestamp'],
resource_metadata=metadata,
)
yield counter.Counter.from_notification(
name=counter_name,
type=counter.TYPE_GAUGE,
unit=unit_value,
volume=1,
user_id=message['_context_user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['id'],
message=message)
event_type_split = message['event_type'].split('.')
if len(event_type_split) > 2:
yield counter.Counter(name=counter_name
+ "." + event_type_split[1],
type=counter.TYPE_DELTA,
unit=unit_value,
volume=1,
user_id=message['_context_user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['id'],
timestamp=message['timestamp'],
resource_metadata=metadata,
)
yield counter.Counter.from_notification(
name=counter_name
+ "." + event_type_split[1],
type=counter.TYPE_DELTA,
unit=unit_value,
volume=1,
user_id=message['_context_user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['id'],
message=message)
class Network(NetworkNotificationBase):
@ -107,16 +104,6 @@ class Network(NetworkNotificationBase):
metering framework.
"""
metadata_keys = [
"status",
"subnets",
"name",
"router:external",
"admin_state_up",
"shared",
]
resource_name = 'network'
@ -125,19 +112,6 @@ class Subnet(NetworkNotificationBase):
metering framework.
"""
metadata_keys = [
"name",
"enable_dhcp",
"network_id",
"dns_nameservers",
"allocation_pools",
"host_routes",
"ip_version",
"gateway_ip",
"cidr",
]
resource_name = 'subnet'
@ -146,18 +120,6 @@ class Port(NetworkNotificationBase):
metering framework.
"""
metadata_keys = [
"status",
"name",
"admin_state_up",
"network_id",
"device_owner",
"mac_address",
"fixed_ips",
"device_id",
]
resource_name = 'port'
@ -166,14 +128,6 @@ class Router(NetworkNotificationBase):
metering framework.
"""
metadata_keys = [
"status",
"external_gateway_info",
"admin_state_up",
"name",
]
resource_name = 'router'
@ -182,15 +136,6 @@ class FloatingIP(NetworkNotificationBase):
metering framework.
"""
metadata_keys = [
"router_id",
"floating_network_id",
"fixed_ip_address",
"floating_ip_address",
"port_id",
]
resource_name = 'floatingip'
counter_name = 'ip.floating'
unit = 'ip'

View File

@ -69,14 +69,6 @@ class NotificationBase(PluginBase):
:param message: Message to process.
"""
def notification_to_metadata(self, event):
"""Transform a payload dict to a metadata dict."""
metadata = dict([(k, event['payload'].get(k))
for k in self.metadata_keys])
metadata['event_type'] = event['event_type']
metadata['host'] = event['publisher_id']
return metadata
class PollsterBase(PluginBase):
"""Base class for plugins that support the polling API."""

View File

@ -36,15 +36,7 @@ cfg.CONF.register_opts(OPTS)
class _Base(plugin.NotificationBase):
"""Convert volume notifications into Counters
"""
metadata_keys = [
"status",
"display_name",
"volume_type",
"size",
]
"""Convert volume notifications into Counters."""
@staticmethod
def get_exchange_topics(conf):
@ -66,36 +58,26 @@ class _Base(plugin.NotificationBase):
class Volume(_Base):
def process_notification(self, message):
return [
counter.Counter(name='volume',
type=counter.TYPE_GAUGE,
unit='volume',
volume=1,
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['volume_id'],
timestamp=message['timestamp'],
resource_metadata=self.notification_to_metadata(
message),
),
]
yield counter.Counter.from_notification(
name='volume',
type=counter.TYPE_GAUGE,
unit='volume',
volume=1,
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['volume_id'],
message=message)
class VolumeSize(_Base):
def process_notification(self, message):
return [
counter.Counter(name='volume.size',
type=counter.TYPE_GAUGE,
unit='GB',
volume=message['payload']['size'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['volume_id'],
timestamp=message['timestamp'],
resource_metadata=self.notification_to_metadata(
message),
),
]
yield counter.Counter.from_notification(
name='volume.size',
type=counter.TYPE_GAUGE,
unit='GB',
volume=message['payload']['size'],
user_id=message['payload']['user_id'],
project_id=message['payload']['tenant_id'],
resource_id=message['payload']['volume_id'],
message=message)

View File

@ -28,18 +28,6 @@
#enable_v1_api=true
#
# Options defined in ceilometer.compute.instance
#
# list of metadata prefixes resevred for metering use (list
# value)
#reserved_metadata_namespace=metering.
# limit on length of reserved metadata values (integer value)
#reserved_metadata_length=256
#
# Options defined in ceilometer.compute.notifications
#
@ -48,6 +36,18 @@
#nova_control_exchange=nova
#
# Options defined in ceilometer.compute.pollsters
#
# list of metadata prefixes reserved for metering use (list
# value)
#reserved_metadata_namespace=metering.
# limit on length of reserved metadata values (integer value)
#reserved_metadata_length=256
#
# Options defined in ceilometer.compute.virt.inspector
#

View File

@ -1,112 +0,0 @@
# -*- encoding: utf-8 -*-
#
# Copyright © 2012 New Dream Network, LLC (DreamHost)
#
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
#
# 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 ceilometer.compute.instance
"""
import mock
from ceilometer.compute import instance
from ceilometer.compute import manager
from ceilometer.tests import base
class FauxInstance(object):
def __init__(self, **kwds):
for name, value in kwds.items():
setattr(self, name, value)
def __getitem__(self, key):
return getattr(self, key)
def get(self, key, default):
try:
return getattr(self, key)
except AttributeError:
return default
class TestLocationMetadata(base.TestCase):
@mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock())
def setUp(self):
self.manager = manager.AgentManager()
super(TestLocationMetadata, self).setUp()
# Mimics an instance returned from nova api call
self.INSTANCE_PROPERTIES = {'name': 'display name',
'OS-EXT-SRV-ATTR:instance_name':
'instance-000001',
'availability_zone': None,
'OS-EXT-AZ:availability_zone':
'foo-zone',
'reservation_id': 'reservation id',
'architecture': 'x86_64',
'kernel_id': 'kernel id',
'os_type': 'linux',
'ramdisk_id': 'ramdisk id',
'ephemeral_gb': 7,
'root_gb': 3,
'image': {'id': 1,
'links': [{"rel": "bookmark",
'href': 2}]},
'hostId': '1234-5678',
'flavor': {'id': 1,
'disk': 0,
'ram': 512,
'vcpus': 2},
'metadata': {'metering.autoscale.group':
'X' * 512,
'metering.ephemeral_gb': 42}}
self.instance = FauxInstance(**self.INSTANCE_PROPERTIES)
def test_metadata(self):
md = instance.get_metadata_from_object(self.instance)
iprops = self.INSTANCE_PROPERTIES
self.assertEqual(md['availability_zone'],
iprops['OS-EXT-AZ:availability_zone'])
self.assertEqual(md['name'], iprops['OS-EXT-SRV-ATTR:instance_name'])
self.assertEqual(md['disk_gb'], iprops['flavor']['disk'])
self.assertEqual(md['display_name'], iprops['name'])
self.assertEqual(md['instance_type'], iprops['flavor']['id'])
self.assertEqual(md['image_ref'], iprops['image']['id'])
self.assertEqual(md['image_ref_url'],
iprops['image']['links'][0]['href'])
self.assertEqual(md['memory_mb'], iprops['flavor']['ram'])
self.assertEqual(md['vcpus'], iprops['flavor']['vcpus'])
self.assertEqual(md['host'], iprops['hostId'])
self.assertEqual(md['reservation_id'], iprops['reservation_id'])
self.assertEqual(md['kernel_id'], iprops['kernel_id'])
self.assertEqual(md['ramdisk_id'], iprops['ramdisk_id'])
self.assertEqual(md['architecture'], iprops['architecture'])
self.assertEqual(md['os_type'], iprops['os_type'])
self.assertEqual(md['ephemeral_gb'], iprops['ephemeral_gb'])
self.assertEqual(md['root_gb'], iprops['root_gb'])
user_metadata = md['user_metadata']
expected = iprops['metadata']['metering.autoscale.group'][:256]
self.assertEqual(user_metadata['autoscale_group'], expected)
self.assertEqual(len(user_metadata), 1)
def test_metadata_empty_image(self):
self.INSTANCE_PROPERTIES['image'] = ''
self.instance = FauxInstance(**self.INSTANCE_PROPERTIES)
md = instance.get_metadata_from_object(self.instance)
self.assertEqual(md['image_ref'], None)
self.assertEqual(md['image_ref_url'], None)

View File

@ -401,9 +401,9 @@ INSTANCE_SCHEDULED = {
class TestNotifications(base.TestCase):
def test_process_notification(self):
info = notifications.Instance().process_notification(
info = list(notifications.Instance().process_notification(
INSTANCE_CREATE_END
)[0]
))[0]
for name, actual, expected in [
('counter_name', info.name, 'instance'),
('counter_type', info.type, counter.TYPE_GAUGE),
@ -412,7 +412,8 @@ class TestNotifications(base.TestCase):
INSTANCE_CREATE_END['timestamp']),
('resource_id', info.resource_id,
INSTANCE_CREATE_END['payload']['instance_id']),
('instance_type', info.resource_metadata['instance_type'],
('instance_type_id',
info.resource_metadata['instance_type_id'],
INSTANCE_CREATE_END['payload']['instance_type_id']),
('host', info.resource_metadata['host'],
INSTANCE_CREATE_END['publisher_id']),
@ -425,42 +426,42 @@ class TestNotifications(base.TestCase):
def test_instance_create_instance(self):
ic = notifications.Instance()
counters = ic.process_notification(INSTANCE_CREATE_END)
counters = list(ic.process_notification(INSTANCE_CREATE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume, 1)
def test_instance_create_flavor(self):
ic = notifications.InstanceFlavor()
counters = ic.process_notification(INSTANCE_CREATE_END)
counters = list(ic.process_notification(INSTANCE_CREATE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume, 1)
def test_instance_create_memory(self):
ic = notifications.Memory()
counters = ic.process_notification(INSTANCE_CREATE_END)
counters = list(ic.process_notification(INSTANCE_CREATE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume, INSTANCE_CREATE_END['payload']['memory_mb'])
def test_instance_create_vcpus(self):
ic = notifications.VCpus()
counters = ic.process_notification(INSTANCE_CREATE_END)
counters = list(ic.process_notification(INSTANCE_CREATE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume, INSTANCE_CREATE_END['payload']['vcpus'])
def test_instance_create_root_disk_size(self):
ic = notifications.RootDiskSize()
counters = ic.process_notification(INSTANCE_CREATE_END)
counters = list(ic.process_notification(INSTANCE_CREATE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume, INSTANCE_CREATE_END['payload']['root_gb'])
def test_instance_create_ephemeral_disk_size(self):
ic = notifications.EphemeralDiskSize()
counters = ic.process_notification(INSTANCE_CREATE_END)
counters = list(ic.process_notification(INSTANCE_CREATE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume,
@ -468,34 +469,34 @@ class TestNotifications(base.TestCase):
def test_instance_exists_instance(self):
ic = notifications.Instance()
counters = ic.process_notification(INSTANCE_EXISTS)
counters = list(ic.process_notification(INSTANCE_EXISTS))
self.assertEqual(len(counters), 1)
def test_instance_exists_flavor(self):
ic = notifications.Instance()
counters = ic.process_notification(INSTANCE_EXISTS)
counters = list(ic.process_notification(INSTANCE_EXISTS))
self.assertEqual(len(counters), 1)
def test_instance_delete_instance(self):
ic = notifications.Instance()
counters = ic.process_notification(INSTANCE_DELETE_START)
counters = list(ic.process_notification(INSTANCE_DELETE_START))
self.assertEqual(len(counters), 1)
def test_instance_delete_flavor(self):
ic = notifications.Instance()
counters = ic.process_notification(INSTANCE_DELETE_START)
counters = list(ic.process_notification(INSTANCE_DELETE_START))
self.assertEqual(len(counters), 1)
def test_instance_finish_resize_instance(self):
ic = notifications.Instance()
counters = ic.process_notification(INSTANCE_FINISH_RESIZE_END)
counters = list(ic.process_notification(INSTANCE_FINISH_RESIZE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume, 1)
def test_instance_finish_resize_flavor(self):
ic = notifications.InstanceFlavor()
counters = ic.process_notification(INSTANCE_FINISH_RESIZE_END)
counters = list(ic.process_notification(INSTANCE_FINISH_RESIZE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume, 1)
@ -503,7 +504,7 @@ class TestNotifications(base.TestCase):
def test_instance_finish_resize_memory(self):
ic = notifications.Memory()
counters = ic.process_notification(INSTANCE_FINISH_RESIZE_END)
counters = list(ic.process_notification(INSTANCE_FINISH_RESIZE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume,
@ -511,7 +512,7 @@ class TestNotifications(base.TestCase):
def test_instance_finish_resize_vcpus(self):
ic = notifications.VCpus()
counters = ic.process_notification(INSTANCE_FINISH_RESIZE_END)
counters = list(ic.process_notification(INSTANCE_FINISH_RESIZE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume,
@ -519,14 +520,14 @@ class TestNotifications(base.TestCase):
def test_instance_resize_finish_instance(self):
ic = notifications.Instance()
counters = ic.process_notification(INSTANCE_FINISH_RESIZE_END)
counters = list(ic.process_notification(INSTANCE_FINISH_RESIZE_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume, 1)
def test_instance_resize_finish_flavor(self):
ic = notifications.InstanceFlavor()
counters = ic.process_notification(INSTANCE_RESIZE_REVERT_END)
counters = list(ic.process_notification(INSTANCE_RESIZE_REVERT_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume, 1)
@ -534,7 +535,7 @@ class TestNotifications(base.TestCase):
def test_instance_resize_finish_memory(self):
ic = notifications.Memory()
counters = ic.process_notification(INSTANCE_RESIZE_REVERT_END)
counters = list(ic.process_notification(INSTANCE_RESIZE_REVERT_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume,
@ -542,7 +543,7 @@ class TestNotifications(base.TestCase):
def test_instance_resize_finish_vcpus(self):
ic = notifications.VCpus()
counters = ic.process_notification(INSTANCE_RESIZE_REVERT_END)
counters = list(ic.process_notification(INSTANCE_RESIZE_REVERT_END))
self.assertEqual(len(counters), 1)
c = counters[0]
self.assertEqual(c.volume,
@ -550,7 +551,7 @@ class TestNotifications(base.TestCase):
def test_instance_delete_samples(self):
ic = notifications.InstanceDelete()
counters = ic.process_notification(INSTANCE_DELETE_SAMPLES)
counters = list(ic.process_notification(INSTANCE_DELETE_SAMPLES))
self.assertEqual(len(counters), 2)
names = [c.name for c in counters]
self.assertEqual(names, ['sample-name1', 'sample-name2'])
@ -561,7 +562,7 @@ class TestNotifications(base.TestCase):
self.assertIn(INSTANCE_SCHEDULED['event_type'],
ic.get_event_types())
counters = ic.process_notification(INSTANCE_SCHEDULED)
counters = list(ic.process_notification(INSTANCE_SCHEDULED))
self.assertEqual(len(counters), 1)
names = [c.name for c in counters]
self.assertEqual(names, ['instance.scheduled'])

View File

@ -29,6 +29,82 @@ from ceilometer.compute.virt import inspector as virt_inspector
from ceilometer.tests import base as test_base
class FauxInstance(object):
def __init__(self, **kwds):
for name, value in kwds.items():
setattr(self, name, value)
def __getitem__(self, key):
return getattr(self, key)
def get(self, key, default):
try:
return getattr(self, key)
except AttributeError:
return default
class TestLocationMetadata(test_base.TestCase):
@mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock())
def setUp(self):
self.manager = manager.AgentManager()
super(TestLocationMetadata, self).setUp()
# Mimics an instance returned from nova api call
self.INSTANCE_PROPERTIES = {'name': 'display name',
'OS-EXT-SRV-ATTR:instance_name':
'instance-000001',
'OS-EXT-AZ:availability_zone':
'foo-zone',
'reservation_id': 'reservation id',
'architecture': 'x86_64',
'kernel_id': 'kernel id',
'os_type': 'linux',
'ramdisk_id': 'ramdisk id',
'ephemeral_gb': 7,
'root_gb': 3,
'image': {'id': 1,
'links': [{"rel": "bookmark",
'href': 2}]},
'hostId': '1234-5678',
'flavor': {'id': 1,
'disk': 0,
'ram': 512,
'vcpus': 2},
'metadata': {'metering.autoscale.group':
'X' * 512,
'metering.ephemeral_gb': 42}}
self.instance = FauxInstance(**self.INSTANCE_PROPERTIES)
def test_metadata(self):
md = pollsters._get_metadata_from_object(self.instance)
for prop, value in self.INSTANCE_PROPERTIES.iteritems():
if prop not in ("metadata"):
# Special cases
if prop == 'name':
prop = 'display_name'
elif prop == 'hostId':
prop = "host"
elif prop == 'OS-EXT-SRV-ATTR:instance_name':
prop = 'name'
self.assertEqual(md[prop], value)
user_metadata = md['user_metadata']
expected = self.INSTANCE_PROPERTIES[
'metadata']['metering.autoscale.group'][:256]
self.assertEqual(user_metadata['autoscale_group'], expected)
self.assertEqual(len(user_metadata), 1)
def test_metadata_empty_image(self):
self.INSTANCE_PROPERTIES['image'] = ''
self.instance = FauxInstance(**self.INSTANCE_PROPERTIES)
md = pollsters._get_metadata_from_object(self.instance)
self.assertEqual(md['image_ref'], None)
self.assertEqual(md['image_ref_url'], None)
class TestPollsterBase(test_base.TestCase):
def setUp(self):

View File

@ -102,7 +102,7 @@ class TestNotification(base.TestCase):
def test_image_download(self):
handler = notifications.ImageDownload()
counters = handler.process_notification(NOTIFICATION_SEND)
counters = list(handler.process_notification(NOTIFICATION_SEND))
self.assertEqual(len(counters), 1)
download = counters[0]
self._verify_common_counter(download, 'image.download', 42)
@ -112,7 +112,7 @@ class TestNotification(base.TestCase):
def test_image_serve(self):
handler = notifications.ImageServe()
counters = handler.process_notification(NOTIFICATION_SEND)
counters = list(handler.process_notification(NOTIFICATION_SEND))
self.assertEqual(len(counters), 1)
serve = counters[0]
self._verify_common_counter(serve, 'image.serve', 42)
@ -125,7 +125,7 @@ class TestNotification(base.TestCase):
def test_image_crud_on_update(self):
handler = notifications.ImageCRUD()
counters = handler.process_notification(NOTIFICATION_UPDATE)
counters = list(handler.process_notification(NOTIFICATION_UPDATE))
self.assertEqual(len(counters), 1)
update = counters[0]
self._verify_common_counter(update, 'image.update', 1)
@ -133,7 +133,7 @@ class TestNotification(base.TestCase):
def test_image_on_update(self):
handler = notifications.Image()
counters = handler.process_notification(NOTIFICATION_UPDATE)
counters = list(handler.process_notification(NOTIFICATION_UPDATE))
self.assertEqual(len(counters), 1)
update = counters[0]
self._verify_common_counter(update, 'image', 1)
@ -141,7 +141,7 @@ class TestNotification(base.TestCase):
def test_image_size_on_update(self):
handler = notifications.ImageSize()
counters = handler.process_notification(NOTIFICATION_UPDATE)
counters = list(handler.process_notification(NOTIFICATION_UPDATE))
self.assertEqual(len(counters), 1)
update = counters[0]
self._verify_common_counter(update, 'image.size',
@ -150,7 +150,7 @@ class TestNotification(base.TestCase):
def test_image_crud_on_upload(self):
handler = notifications.ImageCRUD()
counters = handler.process_notification(NOTIFICATION_UPLOAD)
counters = list(handler.process_notification(NOTIFICATION_UPLOAD))
self.assertEqual(len(counters), 1)
upload = counters[0]
self._verify_common_counter(upload, 'image.upload', 1)
@ -158,7 +158,7 @@ class TestNotification(base.TestCase):
def test_image_on_upload(self):
handler = notifications.Image()
counters = handler.process_notification(NOTIFICATION_UPLOAD)
counters = list(handler.process_notification(NOTIFICATION_UPLOAD))
self.assertEqual(len(counters), 1)
upload = counters[0]
self._verify_common_counter(upload, 'image', 1)
@ -166,7 +166,7 @@ class TestNotification(base.TestCase):
def test_image_size_on_upload(self):
handler = notifications.ImageSize()
counters = handler.process_notification(NOTIFICATION_UPLOAD)
counters = list(handler.process_notification(NOTIFICATION_UPLOAD))
self.assertEqual(len(counters), 1)
upload = counters[0]
self._verify_common_counter(upload, 'image.size',
@ -175,7 +175,7 @@ class TestNotification(base.TestCase):
def test_image_crud_on_delete(self):
handler = notifications.ImageCRUD()
counters = handler.process_notification(NOTIFICATION_DELETE)
counters = list(handler.process_notification(NOTIFICATION_DELETE))
self.assertEqual(len(counters), 1)
delete = counters[0]
self._verify_common_counter(delete, 'image.delete', 1)
@ -183,7 +183,7 @@ class TestNotification(base.TestCase):
def test_image_on_delete(self):
handler = notifications.Image()
counters = handler.process_notification(NOTIFICATION_DELETE)
counters = list(handler.process_notification(NOTIFICATION_DELETE))
self.assertEqual(len(counters), 1)
delete = counters[0]
self._verify_common_counter(delete, 'image', 1)
@ -191,7 +191,7 @@ class TestNotification(base.TestCase):
def test_image_size_on_delete(self):
handler = notifications.ImageSize()
counters = handler.process_notification(NOTIFICATION_DELETE)
counters = list(handler.process_notification(NOTIFICATION_DELETE))
self.assertEqual(len(counters), 1)
delete = counters[0]
self._verify_common_counter(delete, 'image.size',

View File

@ -72,7 +72,7 @@ class TestNotifications(base.TestCase):
def test_volume_exists(self):
v = notifications.Volume()
counters = v.process_notification(NOTIFICATION_VOLUME_EXISTS)
counters = list(v.process_notification(NOTIFICATION_VOLUME_EXISTS))
self.assertEqual(len(counters), 1)
c = counters[0]
self._verify_common_counter(c, 'volume', NOTIFICATION_VOLUME_EXISTS)
@ -80,7 +80,7 @@ class TestNotifications(base.TestCase):
def test_volume_size_exists(self):
v = notifications.VolumeSize()
counters = v.process_notification(NOTIFICATION_VOLUME_EXISTS)
counters = list(v.process_notification(NOTIFICATION_VOLUME_EXISTS))
self.assertEqual(len(counters), 1)
c = counters[0]
self._verify_common_counter(c, 'volume.size',
@ -90,7 +90,7 @@ class TestNotifications(base.TestCase):
def test_volume_delete(self):
v = notifications.Volume()
counters = v.process_notification(NOTIFICATION_VOLUME_DELETE)
counters = list(v.process_notification(NOTIFICATION_VOLUME_DELETE))
self.assertEqual(len(counters), 1)
c = counters[0]
self._verify_common_counter(c, 'volume', NOTIFICATION_VOLUME_DELETE)
@ -98,7 +98,7 @@ class TestNotifications(base.TestCase):
def test_volume_size_delete(self):
v = notifications.VolumeSize()
counters = v.process_notification(NOTIFICATION_VOLUME_DELETE)
counters = list(v.process_notification(NOTIFICATION_VOLUME_DELETE))
self.assertEqual(len(counters), 1)
c = counters[0]
self._verify_common_counter(c, 'volume.size',