diff --git a/ceilometer/compute/nova_notifier.py b/ceilometer/compute/nova_notifier.py deleted file mode 100644 index 5bdd3800..00000000 --- a/ceilometer/compute/nova_notifier.py +++ /dev/null @@ -1,183 +0,0 @@ -# -# Copyright 2013 New Dream Network, LLC (DreamHost) -# -# Author: Doug Hellmann -# -# 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 sys - -from nova.compute import flavors -from nova import conductor -from nova import notifications -from nova.openstack.common import log as logging -from nova.openstack.common.notifier import api as notifier_api -from nova import utils -import six -from stevedore import extension - -# HACK(dhellmann): Insert the nova version of openstack.common into -# sys.modules as though it was the copy from ceilometer, so that when -# we use modules from ceilometer below they do not re-define options. -# use the real ceilometer base package -import ceilometer # noqa -from ceilometer.compute.virt import inspector -from ceilometer.i18n import _ - -for name in ['openstack', 'openstack.common', 'openstack.common.log']: - sys.modules['ceilometer.' + name] = sys.modules['nova.' + name] - -# This module runs inside the nova compute -# agent, which only configures the "nova" logger. -# We use a fake logger name in that namespace -# so that messages from this module appear -# in the log file. -LOG = logging.getLogger('nova.ceilometer.notifier') - -_gatherer = None -conductor_api = conductor.API() - - -class DeletedInstanceStatsGatherer(object): - - def __init__(self, extensions): - self.mgr = extensions - self.inspector = inspector.get_hypervisor_inspector() - - def __call__(self, instance): - cache = {} - samples = self.mgr.map_method('get_samples', - self, - cache, - instance) - # samples is a list of lists, so flatten it before returning - # the results - results = [] - for slist in samples: - results.extend(slist) - return results - - -def initialize_gatherer(gatherer=None): - """Set the callable used to gather stats for the instance. - - gatherer should be a callable accepting one argument (the instance - ref), or None to have a default gatherer used - """ - global _gatherer - if gatherer is not None: - LOG.debug(_('using provided stats gatherer %r'), gatherer) - _gatherer = gatherer - if _gatherer is None: - LOG.debug(_('making a new stats gatherer')) - mgr = extension.ExtensionManager( - namespace='ceilometer.poll.compute', - invoke_on_load=True, - ) - _gatherer = DeletedInstanceStatsGatherer(mgr) - return _gatherer - - -class Instance(object): - """Model class for instances - - The pollsters all expect an instance that looks like what the - novaclient gives them, but the conductor API gives us a - dictionary. This class makes an object from the dictionary so we - can pass it to the pollsters. - """ - def __init__(self, context, info): - for k, v in six.iteritems(info): - if k == 'name': - setattr(self, 'OS-EXT-SRV-ATTR:instance_name', v) - elif k == 'metadata': - setattr(self, k, utils.metadata_to_dict(v)) - else: - setattr(self, k, v) - - instance_type = flavors.extract_flavor(info) - self.flavor_name = instance_type.get('name', 'UNKNOWN') - self.instance_flavor_id = instance_type.get('flavorid', '') - LOG.debug(_('INFO %r'), info) - - @property - def tenant_id(self): - return self.project_id - - @property - def flavor(self): - return { - 'id': self.instance_type_id, - 'flavor_id': self.instance_flavor_id, - 'name': self.flavor_name, - 'vcpus': self.vcpus, - 'ram': self.memory_mb, - 'disk': self.root_gb + self.ephemeral_gb, - 'ephemeral': self.ephemeral_gb - } - - @property - def hostId(self): - return self.host - - @property - def image(self): - return {'id': self.image_ref} - - @property - def name(self): - return self.display_name - - -def notify(context, message): - if message['event_type'] != 'compute.instance.delete.start': - LOG.debug(_('ignoring %s'), message['event_type']) - return - LOG.info(_('processing %s'), message['event_type']) - gatherer = initialize_gatherer() - - instance_id = message['payload']['instance_id'] - LOG.debug(_('polling final stats for %r'), instance_id) - - # Ask for the instance details - instance_ref = conductor_api.instance_get_by_uuid( - context, - instance_id, - ) - - # Get the default notification payload - payload = notifications.info_from_instance( - context, instance_ref, None, None) - - # Extend the payload with samples from our plugins. We only need - # to send some of the data from the sample objects, since a lot - # of the fields are the same. - instance = Instance(context, instance_ref) - samples = gatherer(instance) - payload['samples'] = [{'name': s.name, - 'type': s.type, - 'unit': s.unit, - 'volume': s.volume} - for s in samples] - - publisher_id = notifier_api.publisher_id('compute', None) - - # We could simply modify the incoming message payload, but we - # can't be sure that this notifier will be called before the RPC - # notifier. Modifying the content may also break the message - # signature. So, we start a new message publishing. We will be - # called again recursively as a result, but we ignore the event we - # generate so it doesn't matter. - notifier_api.notify(context, publisher_id, - 'compute.instance.delete.samples', - notifier_api.INFO, payload) diff --git a/doc/source/conf.py b/doc/source/conf.py index eb0eebaf..1c62f294 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -51,8 +51,7 @@ def write_autodoc_index(): RSTDIR = os.path.abspath(os.path.join(BASE_DIR, "sourcecode")) SRCS = {'ceilometer': ROOT} - EXCLUDED_MODULES = ('ceilometer.compute.nova_notifier', - 'ceilometer.openstack.common.log_handler', + EXCLUDED_MODULES = ('ceilometer.openstack.common.log_handler', 'ceilometer.tests') CURRENT_SOURCES = {} diff --git a/doc/source/install/manual.rst b/doc/source/install/manual.rst index 810ff27d..f0c665d7 100755 --- a/doc/source/install/manual.rst +++ b/doc/source/install/manual.rst @@ -331,7 +331,6 @@ Installing the Compute Agent instance_usage_audit_period=hour notify_on_state_change=vm_and_task_state notification_driver=nova.openstack.common.notifier.rpc_notifier - notification_driver=ceilometer.compute.nova_notifier 2. Clone the ceilometer git repository to the server:: diff --git a/nova_tests/.testr.conf b/nova_tests/.testr.conf deleted file mode 100644 index d3284395..00000000 --- a/nova_tests/.testr.conf +++ /dev/null @@ -1,4 +0,0 @@ -[DEFAULT] -test_command=${PYTHON:-python} -m subunit.run discover -t ./nova_tests ./nova_tests $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/nova_tests/__init__.py b/nova_tests/__init__.py deleted file mode 100644 index 1db4852e..00000000 --- a/nova_tests/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright 2013 Intel Corp. -# -# Author: Lianhao Lu -# -# 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 gettext - -gettext.install('nova', unicode=True) diff --git a/nova_tests/test_notifier.py b/nova_tests/test_notifier.py deleted file mode 100644 index bb0af0b9..00000000 --- a/nova_tests/test_notifier.py +++ /dev/null @@ -1,307 +0,0 @@ -# -# Copyright 2012 New Dream Network, LLC (DreamHost) -# -# Author: Julien Danjou -# Doug Hellmann -# -# 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.nova_notifier -""" - -import contextlib -import datetime - -import mock -from oslo_utils import importutils -from oslotest import base -from oslotest import moxstubout - -from stevedore import extension - -## NOTE(dhellmann): These imports are not in the generally approved -## alphabetical order, but they are in the order that actually -## works. Please don't change them. -from nova.tests import fake_network -from nova.compute import vm_states -try: - from nova.compute import flavors -except ImportError: - from nova.compute import instance_types as flavors - -from nova.objects import instance as nova_instance -from nova import config -from nova import context -from nova import db -from nova.openstack.common import log as logging - -# This option is used in the nova_notifier module, so make -# sure it is defined. -config.cfg.CONF.import_opt('compute_manager', 'nova.service') - -# HACK(dhellmann): Import this before any other ceilometer code -# because the notifier module messes with the import path to force -# nova's version of oslo to be used instead of ceilometer's. -from ceilometer.compute import nova_notifier - -from ceilometer import sample -from ceilometer.compute.pollsters import util - -LOG = logging.getLogger(__name__) -nova_CONF = config.cfg.CONF - - -class TestNovaNotifier(base.BaseTestCase): - - class Pollster(object): - instances = [] - test_data_1 = sample.Sample( - name='test1', - type=sample.TYPE_CUMULATIVE, - unit='units-go-here', - volume=1, - user_id='test', - project_id='test', - resource_id='test_run_tasks', - timestamp=datetime.datetime.utcnow().isoformat(), - resource_metadata={'name': 'Pollster', - }, - ) - - def get_samples(self, manager, cache, instance): - self.instances.append((manager, instance)) - test_data_2 = util.make_sample_from_instance( - instance, - name='test2', - type=sample.TYPE_CUMULATIVE, - unit='units-go-here', - volume=1, - ) - return [self.test_data_1, test_data_2] - - @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) - def setUp(self): - super(TestNovaNotifier, self).setUp() - nova_CONF.compute_driver = 'nova.virt.fake.FakeDriver' - nova_CONF.notification_driver = [ - nova_notifier.__name__, - 'nova.openstack.common.notifier.rpc_notifier', - ] - nova_CONF.rpc_backend = 'nova.openstack.common.rpc.impl_fake' - nova_CONF.vnc_enabled = False - nova_CONF.spice.enabled = False - self.compute = importutils.import_object(nova_CONF.compute_manager) - self.context = context.get_admin_context() - self.stubs = self.useFixture(moxstubout.MoxStubout()).stubs - fake_network.set_stub_network_methods(self.stubs) - - self.instance_data = {"display_name": "instance-1", - "id": 1, - "image_ref": "FAKE", - "user_id": "FAKE", - "project_id": "FAKE", - "display_name": "FAKE NAME", - "hostname": "abcdef", - "reservation_id": "FAKE RID", - "instance_type_id": 1, - "architecture": "x86", - "memory_mb": "1024", - "root_gb": "20", - "ephemeral_gb": "0", - "vcpus": 1, - 'node': "fakenode", - "host": "fakehost", - "availability_zone": - "1e3ce043029547f1a61c1996d1a531a4", - "created_at": '2012-05-08 20:23:41', - "launched_at": '2012-05-08 20:25:45', - "terminated_at": '2012-05-09 20:23:41', - "os_type": "linux", - "kernel_id": "kernelid", - "ramdisk_id": "ramdiskid", - "vm_state": vm_states.ACTIVE, - "task_state": None, - "access_ip_v4": "192.168.5.4", - "access_ip_v6": "2001:DB8::0", - "metadata": {}, - "uuid": "144e08f4-00cb-11e2-888e-5453ed1bbb5f", - "system_metadata": {}, - "user_data": None, - "cleaned": 0, - "deleted": None, - "vm_mode": None, - "deleted_at": None, - "disable_terminate": False, - "root_device_name": None, - "default_swap_device": None, - "launched_on": None, - "display_description": None, - "key_data": None, - "key_name": None, - "config_drive": None, - "power_state": None, - "default_ephemeral_device": None, - "progress": 0, - "scheduled_at": None, - "updated_at": None, - "shutdown_terminate": False, - "cell_name": 'cell', - "locked": False, - "locked_by": None, - "launch_index": 0, - "auto_disk_config": False, - "ephemeral_key_uuid": None - } - - self.instance = nova_instance.Instance() - self.instance = nova_instance.Instance._from_db_object( - context, self.instance, self.instance_data, - expected_attrs=['metadata', 'system_metadata']) - - self.stubs.Set(db, 'instance_info_cache_delete', self.do_nothing) - self.stubs.Set(db, 'instance_destroy', self.do_nothing) - self.stubs.Set(db, 'instance_system_metadata_get', - self.fake_db_instance_system_metadata_get) - self.stubs.Set(db, 'block_device_mapping_get_all_by_instance', - lambda context, instance: {}) - self.stubs.Set(db, 'instance_update_and_get_original', - lambda *args, **kwargs: (self.instance, self.instance)) - self.stubs.Set(flavors, 'extract_flavor', self.fake_extract_flavor) - - # Set up to capture the notification messages generated by the - # plugin and to invoke our notifier plugin. - self.notifications = [] - - ext_mgr = extension.ExtensionManager.make_test_instance( - extensions=[ - extension.Extension('test', - None, - None, - self.Pollster(), - ), - ], - ) - self.ext_mgr = ext_mgr - self.gatherer = nova_notifier.DeletedInstanceStatsGatherer(ext_mgr) - # Initialize the global _gatherer in nova_notifier to use the - # gatherer in this test instead of the gatherer in nova_notifier. - nova_notifier.initialize_gatherer(self.gatherer) - - # Terminate the instance to trigger the notification. - with contextlib.nested( - # Under Grizzly, Nova has moved to no-db access on the - # compute node. The compute manager uses RPC to talk to - # the conductor. We need to disable communication between - # the nova manager and the remote system since we can't - # expect the message bus to be available, or the remote - # controller to be there if the message bus is online. - mock.patch.object(self.compute, 'conductor_api'), - # The code that looks up the instance uses a global - # reference to the API, so we also have to patch that to - # return our fake data. - mock.patch.object(nova_notifier.conductor_api, - 'instance_get_by_uuid', - self.fake_instance_ref_get), - mock.patch('nova.openstack.common.notifier.rpc_notifier.notify', - self.notify) - ): - with mock.patch.object(self.compute.conductor_api, - 'instance_destroy', - return_value=self.instance): - self.compute.terminate_instance(self.context, - instance=self.instance, - bdms=[], - reservations=[]) - - def tearDown(self): - self.Pollster.instances = [] - super(TestNovaNotifier, self).tearDown() - nova_notifier._gatherer = None - - # The instance returned by conductor API is a dictionary actually, - # and it will be transformed to an nova_notifier.Instance object - # that looks like what the novaclient gives them. - def fake_instance_ref_get(self, context, id_): - return self.instance_data - - @staticmethod - def fake_extract_flavor(instance_ref): - return {'ephemeral_gb': 0, - 'flavorid': '1', - 'id': 2, - 'memory_mb': 512, - 'name': 'm1.tiny', - 'root_gb': 1, - 'rxtx_factor': 1.0, - 'swap': 0, - 'vcpu_weight': None, - 'vcpus': 1} - - @staticmethod - def do_nothing(*args, **kwargs): - pass - - @staticmethod - def fake_db_instance_system_metadata_get(context, uuid): - return dict(meta_a=123, meta_b="foobar") - - def notify(self, context, message): - self.notifications.append(message) - - def test_pollster_called(self): - self.assertEqual(len(self.Pollster.instances), 1) - - def test_correct_instance(self): - for i, (gatherer, inst) in enumerate(self.Pollster.instances): - self.assertEqual((i, inst.uuid), (i, self.instance.uuid)) - - def test_correct_gatherer(self): - for i, (gatherer, inst) in enumerate(self.Pollster.instances): - self.assertEqual((i, gatherer), (i, self.gatherer)) - - def test_instance_flavor(self): - inst = nova_notifier.Instance(context, self.instance) - self.assertEqual(inst.flavor['name'], 'm1.tiny') - self.assertEqual(inst.flavor['flavor_id'], '1') - - def test_samples(self): - # Ensure that the outgoing notification looks like what we expect - for message in self.notifications: - event = message['event_type'] - if event != 'compute.instance.delete.samples': - continue - payload = message['payload'] - samples = payload['samples'] - - # Because the playload's samples doesn't include instance - # metadata, we can't check the metadata field directly. - # But if we make a mistake in the instance attributes, such - # as missing instance.name or instance.flavor['name'], it - # will raise AttributeError, which results the number of - # the samples doesn't equal to 2. - self.assertEqual(len(samples), 2) - s1 = payload['samples'][0] - self.assertEqual(s1, {'name': 'test1', - 'type': sample.TYPE_CUMULATIVE, - 'unit': 'units-go-here', - 'volume': 1, - }) - s2 = payload['samples'][1] - self.assertEqual(s2, {'name': 'test2', - 'type': sample.TYPE_CUMULATIVE, - 'unit': 'units-go-here', - 'volume': 1, - }) - - break - else: - assert False, 'Did not find expected event' diff --git a/tools/enable_notifications.sh b/tools/enable_notifications.sh index c9564ab6..f4916823 100755 --- a/tools/enable_notifications.sh +++ b/tools/enable_notifications.sh @@ -35,19 +35,6 @@ then echo "notification_driver=neutron.openstack.common.notifier.rabbit_notifier" >> $NEUTRON_CONF fi -# For nova we set both the rabbit notifier and the special ceilometer -# notifier that forces one more poll to happen before an instance is -# removed. -NOVA_CONF=/etc/nova/nova.conf -if ! grep -q "notification_driver=ceilometer.compute.nova_notifier" $NOVA_CONF -then - echo "notification_driver=ceilometer.compute.nova_notifier" >> $NOVA_CONF -fi -if ! grep -q "notification_driver=nova.openstack.common.notifier.rabbit_notifier" $NOVA_CONF -then - echo "notification_driver=nova.openstack.common.notifier.rabbit_notifier" >> $NOVA_CONF -fi - # SPECIAL CASE # Glance does not use the openstack common notifier library, # so we have to set a different option.