Add composite rule alarm support in aodhclient

Add support of composite alarm feature in client side.

blueprint composite-threshold-rule-alarm
Change-Id: Ic26c6269ae90ae67a04719999c52e55e8d65f9cc
This commit is contained in:
liusheng
2016-01-26 16:27:04 +08:00
parent 3024acd5c6
commit 8fe5949368
4 changed files with 136 additions and 2 deletions

View File

@@ -219,6 +219,112 @@ class AodhClientTest(base.ClientTestBase):
self.assertNotIn(ALARM_ID,
[r['alarm_id'] for r in self.parser.listing(result)])
def test_composite_scenario(self):
project_id = str(uuid.uuid4())
# CREATE
result = self.aodh(u'alarm',
params=(u"create --type composite --name calarm1 "
" --composite-rule '{\"or\":[{\"threshold\""
": 0.8,\"meter_name\": \"cpu_util\","
"\"type\": \"threshold\"},{\"and\": ["
"{\"threshold\": 200, \"meter_name\": "
"\"disk.iops\", \"type\": \"threshold\"},"
"{\"threshold\": 1000,\"meter_name\":"
"\"network.incoming.packets.rate\","
"\"type\": \"threshold\"}]}]}' "
"--project-id %s" % project_id))
alarm = self.details_multiple(result)[0]
alarm_id = alarm['alarm_id']
self.assertEqual('calarm1', alarm['name'])
self.assertEqual('composite', alarm['type'])
self.assertIn('composite_rule', alarm)
# CREATE FAIL
result = self.aodh(u'alarm',
params=(u"create --type composite --name calarm1 "
" --composite-rule '{\"or\":[{\"threshold\""
": 0.8,\"meter_name\": \"cpu_util\","
"\"type\": \"threshold\"},{\"and\": ["
"{\"threshold\": 200, \"meter_name\": "
"\"disk.iops\", \"type\": \"threshold\"},"
"{\"threshold\": 1000,\"meter_name\":"
"\"network.incoming.packets.rate\","
"\"type\": \"threshold\"}]}]}' "
"--project-id %s" % project_id),
fail_ok=True, merge_stderr=True)
self.assertFirstLineStartsWith(
result.split('\n'), "Alarm with name='calarm1' exists (HTTP 409)")
# CREATE FAIL MISSING PARAM
self.assertRaises(exceptions.CommandFailed,
self.aodh, u'alarm',
params=(u"create --type composite --name calarm1 "
"--project-id %s" % project_id))
# UPDATE
result = self.aodh(
'alarm', params=("update %s --severity critical" % alarm_id))
alarm_updated = self.details_multiple(result)[0]
self.assertEqual(alarm_id, alarm_updated["alarm_id"])
self.assertEqual('critical', alarm_updated['severity'])
# GET
result = self.aodh(
'alarm', params="show %s" % alarm_id)
alarm_show = self.details_multiple(result)[0]
self.assertEqual(alarm_id, alarm_show["alarm_id"])
self.assertEqual(project_id, alarm_show["project_id"])
self.assertEqual('calarm1', alarm_show['name'])
# LIST
result = self.aodh('alarm', params="list --type composite")
self.assertIn(alarm_id,
[r['alarm_id'] for r in self.parser.listing(result)])
output_colums = ['alarm_id', 'type', 'name', 'state', 'severity',
'enabled']
for alarm_list in self.parser.listing(result):
self.assertEqual(sorted(output_colums), sorted(alarm_list.keys()))
if alarm_list["alarm_id"] == alarm_id:
self.assertEqual('calarm1', alarm_list['name'])
# SEARCH ALL
result = self.aodh('alarm', params="search --type composite")
self.assertIn(alarm_id,
[r['alarm_id'] for r in self.parser.listing(result)])
for alarm_list in self.parser.listing(result):
if alarm_list["alarm_id"] == alarm_id:
self.assertEqual('calarm1', alarm_list['name'])
# SEARCH SOME
result = self.aodh('alarm',
params=("search --type composite --query "
"'{\"=\": {\"project_id\": \"%s\"}}'"
% project_id))
alarm_list = self.parser.listing(result)[0]
self.assertEqual(alarm_id, alarm_list["alarm_id"])
self.assertEqual('calarm1', alarm_list['name'])
# DELETE
result = self.aodh('alarm', params="delete %s" % alarm_id)
self.assertEqual("", result)
# GET FAIL
result = self.aodh('alarm', params="show %s" % alarm_id,
fail_ok=True, merge_stderr=True)
expected = "Alarm %s not found (HTTP 404)" % alarm_id
self.assertFirstLineStartsWith(result.split('\n'), expected)
# DELETE FAIL
result = self.aodh('alarm', params="delete %s" % alarm_id,
fail_ok=True, merge_stderr=True)
self.assertFirstLineStartsWith(result.split('\n'), expected)
# LIST DOES NOT HAVE ALARM
result = self.aodh('alarm', params="list --type composite")
self.assertNotIn(alarm_id,
[r['alarm_id'] for r in self.parser.listing(result)])
class AodhClientGnocchiRulesTest(base.ClientTestBase):

View File

@@ -189,6 +189,7 @@ class CliAlarmCreateTest(testtools.TestCase):
'query': '{}',
'resource_type': 'generic'
},
'composite_rule': None,
'type': 'threshold'
}
alarm_rep = self.cli_alarm_create._alarm_from_args(test_parsed_args)

View File

@@ -83,6 +83,10 @@ class AlarmManager(base.Manager):
'gnocchi_aggregation_by_resources_threshold_rule'))
alarm_update.pop(
'gnocchi_aggregation_by_resources_threshold_rule')
elif 'composite_rule' in alarm_update:
if alarm_update['composite_rule']:
alarm['composite_rule'] = alarm_update['composite_rule']
alarm_update.pop('composite_rule')
alarm.update(alarm_update)
return self._put(

View File

@@ -13,11 +13,13 @@
from cliff import command
from cliff import lister
from cliff import show
from oslo_serialization import jsonutils
from oslo_utils import strutils
from aodhclient import utils
ALARM_TYPES = ['threshold', 'event', 'gnocchi_resources_threshold',
ALARM_TYPES = ['threshold', 'event', 'composite',
'gnocchi_resources_threshold',
'gnocchi_aggregation_by_metrics_threshold',
'gnocchi_aggregation_by_resources_threshold']
ALARM_STATES = ['ok', 'alarm', 'insufficient data']
@@ -61,6 +63,10 @@ class CliAlarmSearch(CliAlarmList):
def _format_alarm(alarm):
if alarm.get('composite_rule'):
composite_rule = jsonutils.dumps(alarm['composite_rule'], indent=2)
alarm['composite_rule'] = composite_rule
return alarm
for alarm_type in ALARM_TYPES:
if alarm.get('%s_rule' % alarm_type):
alarm.update(alarm.pop('%s_rule' % alarm_type))
@@ -209,7 +215,19 @@ class CliAlarmCreate(show.ShowOne):
gnocchi_aggr_metrics_group.add_argument(
'--metrics', metavar='<METRICS>', action='append',
dest='metrics', help='The list of metric ids.')
composite_group = parser.add_argument_group('composite alarm')
composite_group.add_argument(
'--composite-rule', metavar='<COMPOSITE_RULE>',
dest='composite_rule',
type=jsonutils.loads,
help='Composite threshold rule with JSON format, the form can'
'be a nested dict which combine threshold/gnocchi rules by'
' "and", "or". For example, the form is like: '
'{"or":[RULE1, RULE2, {"and": [RULE3, RULE4]}]}, The'
'RULEx can be basic threshold rules but must include a'
'"type" field, like this: {"threshold": 0.8,'
'"meter_name":"cpu_util","type":"threshold"}'
)
self.parser = parser
return parser
@@ -239,6 +257,10 @@ class CliAlarmCreate(show.ShowOne):
'requires --metric, --threshold, '
'--aggregation-method, --query and '
'--resource_type')
elif (parsed_args.type == 'composite' and
not parsed_args.composite_rule):
self.parser.error('composite alarm requires'
' --composite-rule parameter')
def _alarm_from_args(self, parsed_args):
alarm = utils.dict_from_parsed_args(
@@ -270,6 +292,7 @@ class CliAlarmCreate(show.ShowOne):
'evaluation_periods', 'metric',
'query', 'resource_type']))
alarm['composite_rule'] = parsed_args.composite_rule
if self.create:
alarm['type'] = parsed_args.type
self._validate_args(parsed_args)