[openstack-ceilometer] Handle poorly formed individual sensor readings

Eoghan Glynn eglynn at fedoraproject.org
Thu Oct 23 14:10:05 UTC 2014


commit a22d8847402f9e53a473f7ac0e8c1c74aa4c58d7
Author: Eoghan Glynn <eglynn at redhat.com>
Date:   Thu Oct 23 13:56:52 2014 +0000

    Handle poorly formed individual sensor readings
    
    Change-Id: I0d25d294ef7c972ce2d82cd8c4b8023bfe297613

 ...-poorly-formed-individual-sensor-readings.patch |  160 ++++++++++++++++++++
 openstack-ceilometer.spec                          |    9 +-
 2 files changed, 168 insertions(+), 1 deletions(-)
---
diff --git a/0001-Handle-poorly-formed-individual-sensor-readings.patch b/0001-Handle-poorly-formed-individual-sensor-readings.patch
new file mode 100644
index 0000000..c9dadc9
--- /dev/null
+++ b/0001-Handle-poorly-formed-individual-sensor-readings.patch
@@ -0,0 +1,160 @@
+From 5b826ea1dc33b58009b16e3663298589d6978f81 Mon Sep 17 00:00:00 2001
+From: Chris Dent <chdent at redhat.com>
+Date: Wed, 15 Oct 2014 17:18:17 +0100
+Subject: [PATCH] Handle poorly formed individual sensor readings
+
+ipmitool returns a series of multiple readings per run. Some of
+these readings may be of a form that parser code cannot handle. The
+desired behavior in this case is for the single reading to be
+dropped and for parsing to continue. This change ensures that
+behavior by continuing through the loop instead of allowing
+exceptions to cause the loop to exit.
+
+Tests have been added which verify the correct behavior.
+
+Note that though there was an opportunity to log each skipped
+reading this would lead to a very large number of log messages as
+many or even most samples from ipmitool are not parsed.
+
+Change-Id: I6a3193d5a6e12c69ca5c548e5fb58d8bc9646348
+Closes-Bug: #1381600
+(cherry picked from commit 8323cfe92af2ad27f6611be0a6887cac12b2c630)
+(cherry picked from commit b1fca33e5f4c5443389d131a212a058d2306ac23)
+---
+ ceilometer/ipmi/pollsters/sensor.py            | 11 +++--
+ ceilometer/tests/ipmi/pollsters/base.py        | 10 +++--
+ ceilometer/tests/ipmi/pollsters/test_sensor.py | 58 ++++++++++++++++++++++++++
+ 3 files changed, 72 insertions(+), 7 deletions(-)
+
+diff --git a/ceilometer/ipmi/pollsters/sensor.py b/ceilometer/ipmi/pollsters/sensor.py
+index a23e088..a1a4e54 100644
+--- a/ceilometer/ipmi/pollsters/sensor.py
++++ b/ceilometer/ipmi/pollsters/sensor.py
+@@ -54,19 +54,24 @@ class SensorPollster(plugin.PollsterBase):
+         sensor_type_data = self._get_sensor_types(stats, self.METRIC)
+ 
+         for sensor_data in sensor_type_data:
++            # Continue if sensor_data is not parseable.
+             try:
+                 sensor_reading = sensor_data['Sensor Reading']
++                sensor_id = sensor_data['Sensor ID']
+             except KeyError:
+-                raise InvalidSensorData("missing 'Sensor Reading'")
++                continue
+ 
+             if not parser.validate_reading(sensor_reading):
+                 continue
+ 
+-            volume, unit = parser.parse_reading(sensor_reading)
++            try:
++                volume, unit = parser.parse_reading(sensor_reading)
++            except parser.InvalidSensorData:
++                continue
+ 
+             resource_id = '%(host)s-%(sensor-id)s' % {
+                 'host': CONF.host,
+-                'sensor-id': parser.transform_id(sensor_data['Sensor ID'])
++                'sensor-id': parser.transform_id(sensor_id)
+             }
+ 
+             metadata = {
+diff --git a/ceilometer/tests/ipmi/pollsters/base.py b/ceilometer/tests/ipmi/pollsters/base.py
+index 575c54d..5b72edf 100644
+--- a/ceilometer/tests/ipmi/pollsters/base.py
++++ b/ceilometer/tests/ipmi/pollsters/base.py
+@@ -57,13 +57,15 @@ class TestPollsterBase(base.BaseTestCase):
+ 
+         self.pollster = self.make_pollster()
+ 
+-    def _verify_metering(self, length, expected_vol, node):
++    def _verify_metering(self, length, expected_vol=None, node=None):
+         cache = {}
+         resources = {}
+ 
+         samples = list(self.pollster.get_samples(self.mgr, cache, resources))
+         self.assertEqual(length, len(samples))
+ 
+-        self.assertTrue(any(s.volume == expected_vol for s in samples))
+-        self.assertTrue(any(s.resource_metadata['node'] == node
+-                            for s in samples))
++        if expected_vol:
++            self.assertTrue(any(s.volume == expected_vol for s in samples))
++        if node:
++            self.assertTrue(any(s.resource_metadata['node'] == node
++                                for s in samples))
+diff --git a/ceilometer/tests/ipmi/pollsters/test_sensor.py b/ceilometer/tests/ipmi/pollsters/test_sensor.py
+index ad83391..3b4ab31 100644
+--- a/ceilometer/tests/ipmi/pollsters/test_sensor.py
++++ b/ceilometer/tests/ipmi/pollsters/test_sensor.py
+@@ -41,6 +41,10 @@ VOLTAGE_SENSOR_DATA = {
+     'Voltage': ipmi_test_data.VOLTAGE_DATA
+ }
+ 
++MISSING_SENSOR_DATA = ipmi_test_data.MISSING_SENSOR['payload']['payload']
++MALFORMED_SENSOR_DATA = ipmi_test_data.BAD_SENSOR['payload']['payload']
++MISSING_ID_SENSOR_DATA = ipmi_test_data.NO_SENSOR_ID['payload']['payload']
++
+ 
+ class TestTemperatureSensorPollster(base.TestPollsterBase):
+ 
+@@ -61,6 +65,60 @@ class TestTemperatureSensorPollster(base.TestPollsterBase):
+         self._verify_metering(10, float(32), CONF.host)
+ 
+ 
++class TestMissingSensorData(base.TestPollsterBase):
++
++    def fake_sensor_data(self, sensor_type):
++        return MISSING_SENSOR_DATA
++
++    def fake_data(self):
++        # No use for Sensor test
++        return None
++
++    def make_pollster(self):
++        return sensor.TemperatureSensorPollster()
++
++    @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock())
++    def test_get_samples(self):
++        self._test_get_samples()
++        self._verify_metering(0)
++
++
++class TestMalformedSensorData(base.TestPollsterBase):
++
++    def fake_sensor_data(self, sensor_type):
++        return MALFORMED_SENSOR_DATA
++
++    def fake_data(self):
++        # No use for Sensor test
++        return None
++
++    def make_pollster(self):
++        return sensor.TemperatureSensorPollster()
++
++    @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock())
++    def test_get_samples(self):
++        self._test_get_samples()
++        self._verify_metering(0)
++
++
++class TestMissingSensorId(base.TestPollsterBase):
++
++    def fake_sensor_data(self, sensor_type):
++        return MISSING_ID_SENSOR_DATA
++
++    def fake_data(self):
++        # No use for Sensor test
++        return None
++
++    def make_pollster(self):
++        return sensor.TemperatureSensorPollster()
++
++    @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock())
++    def test_get_samples(self):
++        self._test_get_samples()
++        self._verify_metering(0)
++
++
+ class TestFanSensorPollster(base.TestPollsterBase):
+ 
+     def fake_sensor_data(self, sensor_type):
diff --git a/openstack-ceilometer.spec b/openstack-ceilometer.spec
index c60f935..d232765 100644
--- a/openstack-ceilometer.spec
+++ b/openstack-ceilometer.spec
@@ -4,7 +4,7 @@
 
 Name:             openstack-ceilometer
 Version:          2014.2
-Release:          1%{?dist}
+Release:          2%{?dist}
 Summary:          OpenStack measurement collection service
 
 Group:            Applications/System
@@ -16,6 +16,8 @@ Source2:          %{pypi_name}.logrotate
 Source3:          %{pypi_name}.conf.sample
 Source4:          ceilometer-rootwrap-sudoers
 
+Patch0001: 0001-Handle-poorly-formed-individual-sensor-readings.patch
+
 %if 0%{?rhel} && 0%{?rhel} <= 6
 Source10:         %{name}-api.init
 Source100:        %{name}-api.upstart
@@ -286,6 +288,8 @@ This package contains documentation files for ceilometer.
 %prep
 %setup -q -n ceilometer-%{version}
 
+%patch0001 -p1
+
 find . \( -name .gitignore -o -name .placeholder \) -delete
 
 find ceilometer -name \*.py -exec sed -i '/\/usr\/bin\/env python/{d;q}' {} +
@@ -757,6 +761,9 @@ fi
 
 
 %changelog
+* Thu Oct 23 2014 Eoghan Glynn <eglynn at redhat.com> 2014.2-2
+- Handle poorly formed individual sensor readings
+
 * Mon Oct 20 2014 Eoghan Glynn <eglynn at redhat.com> 2014.2-1
 - Update to upstream 2014.2 (Juno release)
 


More information about the scm-commits mailing list