From 1437e06bf1dce29a9b0414131b03eb506bd9af40 Mon Sep 17 00:00:00 2001 From: Helena McGough Date: Fri, 30 Jun 2017 09:03:40 +0000 Subject: [PATCH] Make alarm severity configurable - Enabled the user to configure the severity of alarms triggered by metrics/meters - Provided/Updated documentation for this changea - Included all of the necessary tests for this change - Included a reno for this change Change-Id: Icefe2edf7695c4a8b3d5838844e2514b9876967f --- collectd_ceilometer/aodh/notifier.py | 13 +- collectd_ceilometer/aodh/sender.py | 33 ++- collectd_ceilometer/common/meters/base.py | 7 +- collectd_ceilometer/common/settings.py | 36 ++++ collectd_ceilometer/tests/aodh/test_plugin.py | 204 ++++++++++++++++-- .../tests/common/test_meters_base.py | 16 ++ devstack/libs/collectd | 18 ++ devstack/settings | 3 + doc/source/devstackGSG.rst | 13 ++ doc/source/usage.rst | 12 ++ etc/collectd.conf.d/collectd-aodh-plugin.conf | 2 + .../notes/severity-conf-8f336e1bfa3ad06b.yaml | 8 + 12 files changed, 332 insertions(+), 33 deletions(-) create mode 100644 releasenotes/notes/severity-conf-8f336e1bfa3ad06b.yaml diff --git a/collectd_ceilometer/aodh/notifier.py b/collectd_ceilometer/aodh/notifier.py index 19ece0a..4713b42 100644 --- a/collectd_ceilometer/aodh/notifier.py +++ b/collectd_ceilometer/aodh/notifier.py @@ -40,17 +40,22 @@ class Notifier(object): # prepare all data related to the sample metername = notification.meter_name(vl) message = notification.message(vl) - severity = notification.severity(vl) + severity = notification.collectd_severity(vl) resource_id = notification.resource_id(vl) timestamp = datetime.datetime.utcfromtimestamp(vl.time).isoformat() + if notification.alarm_severity(metername) in \ + ('critical', 'moderate', 'low'): + alarm_severity = notification.alarm_severity(metername) + else: + alarm_severity = 'moderate' LOGGER.debug( 'Writing: plugin="%s", message="%s", severity="%s", time="%s', vl.plugin, message, severity, timestamp) - self._send_data(metername, severity, resource_id) + self._send_data(metername, severity, resource_id, alarm_severity) - def _send_data(self, metername, severity, resource_id): + def _send_data(self, metername, severity, resource_id, alarm_severity): """Send data to Aodh.""" LOGGER.debug('Sending alarm for %s', metername) - self._sender.send(metername, severity, resource_id) + self._sender.send(metername, severity, resource_id, alarm_severity) diff --git a/collectd_ceilometer/aodh/sender.py b/collectd_ceilometer/aodh/sender.py index d92de7c..04ce0b6 100644 --- a/collectd_ceilometer/aodh/sender.py +++ b/collectd_ceilometer/aodh/sender.py @@ -110,8 +110,17 @@ class Sender(object): return self._auth_token - def send(self, metername, severity, resource_id): - """Send the payload to Aodh.""" + def send(self, metername, severity, resource_id, alarm_severity): + """Send the payload to Aodh. + + severity: is retrieved from the collectd notification itself, it + defines how severely a threshold is broken. Changes everytime + a notification is generated for a specific meter. + alarm_severity: is a variable used to define the severity of the aodh + alarm that will be created. Defined when the alarm is + created and doesn't change, it defines how severe the + situation is if that alarm is triggered. + """ # get the auth_token auth_token = self._authenticate() LOGGER.info('Auth_token: %s', @@ -131,8 +140,8 @@ class Sender(object): alarm_name = self._get_alarm_name(metername, resource_id) # Update or create this alarm - result = self._update_or_create_alarm(alarm_name, auth_token, - severity, metername) + result = self._update_or_create_alarm(alarm_name, auth_token, severity, + metername, alarm_severity) if result is None: return @@ -155,7 +164,8 @@ class Sender(object): if auth_token is not None: result = self._update_or_create_alarm(alarm_name, auth_token, - severity, metername) + severity, metername, + alarm_severity) if result.status_code == HTTP_NOT_FOUND: LOGGER.debug("Received 404 error when submitting %s notification, \ @@ -164,7 +174,8 @@ class Sender(object): # check for and/or get alarm_id result = self._update_or_create_alarm(alarm_name, auth_token, - severity, metername) + severity, metername, + alarm_severity) if result.status_code == HTTP_CREATED: LOGGER.debug('Result: %s', HTTP_CREATED) @@ -181,7 +192,7 @@ class Sender(object): return endpoint def _update_or_create_alarm(self, alarm_name, auth_token, - severity, metername): + severity, metername, alarm_severity): # check for an alarm and update try: alarm_id = self._get_alarm_id(alarm_name) @@ -194,17 +205,19 @@ class Sender(object): endpoint = self._get_endpoint("aodh") LOGGER.warn('No known ID for %s', alarm_name) result, self._alarm_ids[alarm_name] = \ - self._create_alarm(endpoint, severity, metername, alarm_name) + self._create_alarm(endpoint, severity, + metername, alarm_name, alarm_severity) return result - def _create_alarm(self, endpoint, severity, metername, alarm_name): + def _create_alarm(self, endpoint, severity, metername, + alarm_name, alarm_severity): """Create a new alarm with a new alarm_id.""" url = "{}/v2/alarms/".format(endpoint) rule = {'event_type': metername, } payload = json.dumps({'state': self._get_alarm_state(severity), 'name': alarm_name, - 'severity': severity, + 'severity': alarm_severity, 'type': "event", 'event_rule': rule, }) diff --git a/collectd_ceilometer/common/meters/base.py b/collectd_ceilometer/common/meters/base.py index 8a94d01..0d5bc19 100644 --- a/collectd_ceilometer/common/meters/base.py +++ b/collectd_ceilometer/common/meters/base.py @@ -72,10 +72,15 @@ class Meter(object): """Get the notification message.""" return vl.message - def severity(self, vl): + def collectd_severity(self, vl): """Get the notification severity and translate to Aodh severity type.""" collectd_severity = {self._collectd.NOTIF_FAILURE: 'critical', self._collectd.NOTIF_WARNING: 'moderate', self._collectd.NOTIF_OKAY: 'low', }.get(vl.severity) return collectd_severity + + def alarm_severity(self, meter_name): + """Get the user-defined severity for the alarm, or use default.""" + # pylint: disable=no-self-use + return Config.instance().alarm_severity(meter_name) diff --git a/collectd_ceilometer/common/settings.py b/collectd_ceilometer/common/settings.py index 012f518..41440e9 100644 --- a/collectd_ceilometer/common/settings.py +++ b/collectd_ceilometer/common/settings.py @@ -76,6 +76,9 @@ class Config(object): self._user_units = {} self._units = UNITS.copy() + # dictionary for user defined severities + self._alarm_severities = {} + def read(self, cfg): """Read the collectd configuration @@ -106,6 +109,17 @@ class Config(object): return unit return self._units.get(plugin, "None") + def alarm_severity(self, meter): + """Get alarm_severity for a meter.""" + # check for an user-defined alarm severity + try: + # check for an user-defined alarm severity + return self._alarm_severities[meter] + except KeyError as ke: + LOGGER.info(ke) + LOGGER.info('There is no user-defined severity for this alarm') + return 'moderate' + def _read_node(self, node): """Read a configuration node @@ -119,6 +133,11 @@ class Config(object): self._read_units(node.children) return + # if the node is 'ALARM_SEVERITIES' call the alarm severities function + if key == 'ALARM_SEVERITIES': + self._read_alarm_severities(node.children) + return + # if we have a root node read only all its children # as we don't expect any value here if node.children: @@ -172,3 +191,20 @@ class Config(object): LOGGER.error( 'Invalid unit configuration: %s', node.key.upper()) self._units.update(self._user_units) + + def _read_alarm_severities(self, nodes): + """Read in any user-defined severity settings for alarms.""" + for node in nodes: + if node.key.upper() == 'ALARM_SEVERITY': + if len(node.values) == 2: + key, val = node.values + self._alarm_severities[key] = val + else: + LOGGER.error( + 'Invalid alarm severity configuration:\ + severity %s' % ' '.join( + ['"%s"' % i for i in node.values])) + else: + LOGGER.error( + 'Invalid alarm severity configuration: %s', + node.key.upper()) diff --git a/collectd_ceilometer/tests/aodh/test_plugin.py b/collectd_ceilometer/tests/aodh/test_plugin.py index ebfb744..f6f036c 100644 --- a/collectd_ceilometer/tests/aodh/test_plugin.py +++ b/collectd_ceilometer/tests/aodh/test_plugin.py @@ -17,15 +17,18 @@ """Plugin tests.""" +import abc import logging import mock import requests +import six import unittest from collectd_ceilometer.aodh import plugin from collectd_ceilometer.aodh import sender from collectd_ceilometer.common.keystone_light import KeystoneException from collectd_ceilometer.common.meters import base +from collectd_ceilometer.common import settings Logger = logging.getLoggerClass() @@ -79,9 +82,55 @@ def mock_config(**kwargs): **kwargs) +def config_module( + values, severities=None, + module_name="collectd_ceilometer.ceilometer.plugin"): + children = [config_value(key, value) + for key, value in six.iteritems(values)] + if severities: + children.append(config_severities(severities)) + return config_node('MODULE', children=children, value=module_name) + + +def config_severities(severities): + """Create a mocked collectd config node having severities for alarms.""" + children = [config_value('ALARM_SEVERITY', key, value) + for key, value in six.iteritems(severities)] + return config_node('ALARM_SEVERITIES', children) + + +def config_node(key, children, value=None): + """Create a mocked collectd config node having given children and value.""" + return mock.create_autospec( + spec=MockedConfig, spec_set=True, instance=True, + children=tuple(children), key=key, values=(value,)) + + +def config_value(key, *values): + """Create a mocked collectd config node having given multiple values.""" + return mock.create_autospec( + spec=MockedConfig, spec_set=True, instance=True, + children=tuple(), key=key, values=values) + + class MockedConfig(object): """Mocked config class.""" + @abc.abstractproperty + def children(self): + """Mocked children method.""" + pass + + @abc.abstractproperty + def key(self): + """Mocked key method.""" + pass + + @abc.abstractproperty + def values(self): + """Mocked values method.""" + pass + def mock_value( host='localhost', plugin='cpu', plugin_instance='0', @@ -111,6 +160,18 @@ class MockedValue(object): class TestPlugin(unittest.TestCase): """Test the collectd plugin.""" + @property + def default_values(self): + """Default configuration values.""" + return dict( + BATCH_SIZE=1, + OS_AUTH_URL='https://test-auth.url.tld/test', + CEILOMETER_URL_TYPE='internalURL', + CEILOMETER_TIMEOUT=1000, + OS_USERNAME='tester', + OS_PASSWORD='testpasswd', + OS_TENANT_NAME='service') + @mock.patch.object(plugin, 'Plugin', autospec=True) @mock.patch.object(plugin, 'Config', autospec=True) @mock.patch.object(plugin, 'CollectdLogHandler', autospec=True) @@ -159,16 +220,17 @@ class TestPlugin(unittest.TestCase): _get_alarm_name.return_value = 'my-alarm' meter_name = meter.meter_name.return_value - severity = meter.severity.return_value + severity = meter.collectd_severity.return_value resource_id = meter.resource_id.return_value + alarm_severity = meter.alarm_severity.return_value # send the values - instance.send(meter_name, severity, resource_id) + instance.send(meter_name, severity, resource_id, alarm_severity) # check that the function is called _update_or_create_alarm.assert_called_once_with( instance, 'my-alarm', auth_client.auth_token, - severity, meter_name) + severity, meter_name, alarm_severity) # reset function _update_or_create_alarm.reset_mock() @@ -176,12 +238,12 @@ class TestPlugin(unittest.TestCase): # run test again for failed attempt _update_or_create_alarm.return_value = None - instance.send(meter_name, severity, resource_id) + instance.send(meter_name, severity, resource_id, alarm_severity) # and values that have been sent _update_or_create_alarm.assert_called_once_with( instance, 'my-alarm', auth_client.auth_token, - severity, meter_name) + severity, meter_name, alarm_severity) # reset post method _update_or_create_alarm.reset_mock() @@ -211,11 +273,12 @@ class TestPlugin(unittest.TestCase): # init values to send _get_alarm_id.return_value = 'my-alarm-id' metername = meter.meter_name.return_value - severity = meter.severity.return_value + severity = meter.collectd_severity.return_value rid = meter.resource_id.return_value + alarm_severity = meter.alarm_severity.return_value # send the values - instance.send(metername, severity, rid) + instance.send(metername, severity, rid, alarm_severity) # update the alarm put.assert_called_once_with( @@ -254,11 +317,12 @@ class TestPlugin(unittest.TestCase): _get_alarm_id.side_effect = KeyError() _create_alarm.return_value = requests.Response(), 'my-alarm-id' metername = meter.meter_name.return_value - severity = meter.severity.return_value + severity = meter.collectd_severity.return_value rid = meter.resource_id.return_value + alarm_severity = meter.alarm_severity.return_value # send the values again - instance.send(metername, severity, rid) + instance.send(metername, severity, rid, alarm_severity) put.assert_not_called() @@ -295,7 +359,7 @@ class TestPlugin(unittest.TestCase): # no requests method has been called put.assert_not_called() - @mock.patch.object(base.Meter, 'severity', spec=callable) + @mock.patch.object(base.Meter, 'collectd_severity', spec=callable) def test_get_alarm_state_severity_low(self, severity): """Test _get_alarm_state if severity is 'low'. @@ -316,7 +380,7 @@ class TestPlugin(unittest.TestCase): self.assertNotEqual(instance._get_alarm_state('low'), 'insufficient data') - @mock.patch.object(base.Meter, 'severity', spec=callable) + @mock.patch.object(base.Meter, 'collectd_severity', spec=callable) def test_get_alarm_state_severity_moderate(self, severity): """Test _get_alarm_state if severity is 'moderate'. @@ -337,7 +401,7 @@ class TestPlugin(unittest.TestCase): self.assertNotEqual(instance._get_alarm_state('moderate'), 'insufficient data') - @mock.patch.object(base.Meter, 'severity', spec=callable) + @mock.patch.object(base.Meter, 'collectd_severity', spec=callable) def test_get_alarm_state_severity_critical(self, severity): """Test _get_alarm_state if severity is 'critical'. @@ -405,15 +469,16 @@ class TestPlugin(unittest.TestCase): alarm_name = _get_alarm_name.return_value meter_name = meter.meter_name.return_value - severity = meter.severity.return_value + severity = meter.collectd_severity.return_value resource_id = meter.resource_id.return_value + alarm_severity = meter.alarm_severity.return_value # send the data - instance.send(meter_name, severity, resource_id) + instance.send(meter_name, severity, resource_id, alarm_severity) _update_or_create_alarm.assert_called_once_with( instance, alarm_name, client.auth_token, - severity, meter_name) + severity, meter_name, alarm_severity) # de-assert the request _update_or_create_alarm.reset_mock() @@ -432,11 +497,11 @@ class TestPlugin(unittest.TestCase): client.auth_token = 'Test auth token' # send the data - instance.send(meter_name, severity, resource_id) + instance.send(meter_name, severity, resource_id, alarm_severity) _update_or_create_alarm.assert_called_once_with( instance, alarm_name, client.auth_token, - severity, meter_name) + severity, meter_name, alarm_severity) # update/create response is unauthorized -> new token needs # to be acquired @@ -447,7 +512,7 @@ class TestPlugin(unittest.TestCase): client.auth_token = 'New test auth token' # send the data again - instance.send(meter_name, severity, resource_id) + instance.send(meter_name, severity, resource_id, alarm_severity) @mock.patch.object(sender, 'ClientV3', autospec=True) @mock.patch.object(plugin, 'Notifier', autospec=True) @@ -477,3 +542,106 @@ class TestPlugin(unittest.TestCase): instance = plugin.Plugin(collectd=collectd, config=config) instance.shutdown + + @mock.patch.object(settings, 'LOGGER', autospec=True) + def test_user_severities(self, LOGGER): + """Test if a user enters a severity for a specific meter. + + Set-up: Create a node with some user defined severities + Configure the node + Test: Read the configured node and compare the results + of the method to the severities configured in the node + Expected-behaviour: Valid mapping metric names are mapped correctly + to severities, and invalid values return None. + """ + node = config_module( + values=self.default_values, + severities={'age': 'low', + 'star.distance': 'moderate', + 'star.temperature': 'critical'}) + config = settings.Config._decorated() + + config.read(node) + + LOGGER.error.assert_not_called() + self.assertEqual(config.alarm_severity('age'), 'low') + self.assertEqual(config.alarm_severity('star.distance'), 'moderate') + self.assertEqual(config.alarm_severity('star.temperature'), 'critical') + self.assertEqual(config.alarm_severity('monty'), 'moderate') + self.assertEqual(config.alarm_severity('python'), 'moderate') + + @mock.patch.object(settings, 'LOGGER', autospec=True) + def test_user_severities_invalid(self, LOGGER): + """Test invalid user defined severities. + + Set-up: Configure the node with one defined severity + Set a configuration to have 3 entries instead of the 2 + which are expected + Test: Try to read the configuration node with incorrect configurations + Compare the configuration to the response on the method + Expected-behaviour: alarm_severity will return None + Log will be written that severities were + incorrectly configured + """ + node = config_module(values=self.default_values, + severities=dict(age='low')) + # make some alarm severity entry invalid + for child in node.children: + if child.key == 'ALARM_SEVERITIES': + child.children[0].values = (1, 2, 3) + break + config = settings.Config._decorated() + + config.read(node) + + self.assertEqual(config.alarm_severity('age'), 'moderate') + LOGGER.error.assert_called_with( + 'Invalid alarm severity configuration: \ + severity "1" "2" "3"') + + @mock.patch.object(settings, 'LOGGER', autospec=True) + def test_user_severities_invalid_node(self, LOGGER): + """Test invalid node with severities configuration. + + Set-up: Set up a configuration node with a severity defined + Configure the node with an incorrect module title + Test: Read the incorrect configuration node + Expected-behaviour: Error will be recorded in the log + Severity configuration will return None + """ + node = config_module(values=self.default_values, + severities=dict(age='moderate')) + # make some alarm severity entry invalid + for child in node.children: + if child.key == 'ALARM_SEVERITIES': + child.children[0].key = 'NOT_SEVERITIES' + break + config = settings.Config._decorated() + + config.read(node) + + LOGGER.error.assert_called_with( + 'Invalid alarm severity configuration: %s', "NOT_SEVERITIES") + self.assertEqual(config.alarm_severity('age'), 'moderate') + + def test_read_alarm_severities(self): + """Test reading in user defined alarm severities method. + + Set-up: Set up a node configured with a severities dictionary defined + Test: Read the node for the ALARM_SEVERITY configuration + Expected-behaviour: Info log will be recorded + Severities are correctly configured + """ + node = config_module(values=self.default_values, + severities=dict(age='low')) + + for n in node.children: + if n.key.upper() == 'ALARM_SEVERITY': + if len(n.values) == 2: + key, val = n.values + break + config = settings.Config._decorated() + + config._read_node(node) + + self.assertEqual('low', config.alarm_severity('age')) diff --git a/collectd_ceilometer/tests/common/test_meters_base.py b/collectd_ceilometer/tests/common/test_meters_base.py index bb050fa..3bd8d70 100644 --- a/collectd_ceilometer/tests/common/test_meters_base.py +++ b/collectd_ceilometer/tests/common/test_meters_base.py @@ -21,6 +21,7 @@ from __future__ import unicode_literals from collectd_ceilometer.common.meters.base import Meter from collectd_ceilometer.tests.base import TestCase + import mock @@ -96,3 +97,18 @@ class MetersTest(TestCase): self._collectd.get_dataset.assert_called_once() LOGGER.warning.assert_called_once() self.assertEqual("gauge", actual) + + @mock.patch.object(Meter, 'meter_name', autospec=True) + def test_default_alarm_severity(self, metername): + """Test the default severity setting. + + Set-up: set the return value for severity + Call the alarm_severity method and its pre-requistites + Test: Compare the configured severity to the result of alarm_severity() + Expected behaviour: Result will be True + """ + metername.return_value = 'my-meter' + + result = self.meter.alarm_severity('my-meter') + + self.assertEqual(result, 'moderate') diff --git a/devstack/libs/collectd b/devstack/libs/collectd index b995e5c..1242173 100644 --- a/devstack/libs/collectd +++ b/devstack/libs/collectd @@ -162,6 +162,7 @@ function adapt_collectd_conf { sudo sed -i 's|CEILOMETER_TIMEOUT.*$|CEILOMETER_TIMEOUT "'$CEILOMETER_TIMEOUT'"|g' $COLLECTD_CONF_DIR/collectd-aodh-plugin.conf sudo sed -i 's|OS_PASSWORD.*$|OS_PASSWORD "'$SERVICE_PASSWORD'"|g' $COLLECTD_CONF_DIR/collectd-aodh-plugin.conf sudo sed -i 's|OS_TENANT_NAME.*$|OS_TENANT_NAME "'$SERVICE_TENANT_NAME'"|g' $COLLECTD_CONF_DIR/collectd-aodh-plugin.conf + config_custom_severities "aodh" "$COLLECTD_ALARM_SEVERITIES" fi # Configure collectd logfile plugin @@ -196,6 +197,23 @@ function config_custom_units { fi } +# Check for severitys defined by the user +function config_custom_severities { + service_name=$1 + custom_severities=$2 + if [[ $custom_severities != none ]]; then + + OIFS=$IFS + IFS=',' + + for ALARM_SEVERITIES in $custom_severities; + do + sudo sed -i '//a\ ALARM_SEVERITY '"$ALARM_SEVERITIES"'' $COLLECTD_CONF_DIR/collectd-$service_name-plugin.conf + done + IFS=$OIFS + fi +} + # remove plugin conf file function restore_collectd_conf { # Remove all of the .conf files once they are backed up diff --git a/devstack/settings b/devstack/settings index 78e2b5c..179d61e 100644 --- a/devstack/settings +++ b/devstack/settings @@ -44,6 +44,9 @@ fi COLLECTD_CEILOMETER_UNITS=${COLLECTD_CEILOMETER_CUSTOM_UNITS:-none} COLLECTD_GNOCCHI_UNITS=${COLLECTD_GNOCCHI_CUSTOM_UNITS:-none} +# Custom alarm severities feature +COLLECTD_ALARM_SEVERITIES=${COLLECTD_AODH_SEVERITIES:-none} + # User defined requirements COLLECTD_ADDITIONAL_PACKAGES=${COLLECTD_ADDITIONAL_PACKAGES:-''} COLLECTD_REQUIREMENTS='' diff --git a/doc/source/devstackGSG.rst b/doc/source/devstackGSG.rst index c7f41fd..15c47d1 100644 --- a/doc/source/devstackGSG.rst +++ b/doc/source/devstackGSG.rst @@ -170,6 +170,19 @@ To enable aodh with collectd, add the following to your local.conf: COLLECTD_AODH_ENABLED=True +This plugin allows you to specify the severity of the alarms that will be +created for meters. +To enable this add the following line to your local.conf, once you have enabled +the collectd-aodh-plugin: + +:: + + COLLECTD_AODH_SEVERITIES='"" ' + +You can set this severity to be one of three settings "low", "moderate" or +"critical". If you leave this unset for any of the meters that trigger an alarm +severity will default to "moderate". + In addition to this, alarms can be created manually via the Aodh command line based on the metrics generated by the gnocchi plugin and meters from the ceilometer plugin. For more information on this please read diff --git a/doc/source/usage.rst b/doc/source/usage.rst index 44a4704..347316d 100644 --- a/doc/source/usage.rst +++ b/doc/source/usage.rst @@ -35,6 +35,18 @@ To use collectd-ceilometer-plugin in collectd:: local.conf settings ------------------- +COLLECTD_AODH_SEVERITIES +~~~~~~~~~~~~~~~~~~~~~~~ + ("meter" severity) a comma seperated list of pairs, defining meters and the + severity of the alarms they will trigger if their value goes above a + certain threshold. The meter is generally in the form of "plugin.type" + where plugin and plugin type are attributes of the collectd data. There are + three severity options available "low", "moderate" and "critical". + If this configuration option is left unset for any alarm the default + severity is "moderate". + + Example: COLLECTD_AODH_SEVERITIES='"" , "" ' + COLLECTD_BRANCH ~~~~~~~~~~~~~~~ () Indicates which branch of collectd to checkout before diff --git a/etc/collectd.conf.d/collectd-aodh-plugin.conf b/etc/collectd.conf.d/collectd-aodh-plugin.conf index 35e29d9..c679b29 100644 --- a/etc/collectd.conf.d/collectd-aodh-plugin.conf +++ b/etc/collectd.conf.d/collectd-aodh-plugin.conf @@ -27,6 +27,8 @@ OS_PASSWORD "password" OS_TENANT_NAME "service" + + diff --git a/releasenotes/notes/severity-conf-8f336e1bfa3ad06b.yaml b/releasenotes/notes/severity-conf-8f336e1bfa3ad06b.yaml new file mode 100644 index 0000000..25fdeba --- /dev/null +++ b/releasenotes/notes/severity-conf-8f336e1bfa3ad06b.yaml @@ -0,0 +1,8 @@ +--- + - features: + Included a new feature that allows you to specify the severity of any alarm + created on a meter/metric. This can be specified in the local.conf using the + configuration option "COLLECTD_AODH_SEVERITIES" and will be configured on + deployment with devStack. If left unset the alarms severity will default + to "moderate". Included more detailed usage instructions in devStackGSG.rst + for this new feature.