Add name support for show, update and delete

Since the alarm name is limited to be unique for
each project, add support for users to show, update
and delete alarms using alarm name will be much more
user friendly than using alarm_id.

Partial-Bug: #1556809

Change-Id: I2d9316a24372f28b65c15a02aaefda8c0a1f748b
This commit is contained in:
Kevin_Zheng
2016-03-14 19:17:57 +08:00
parent f4d92717a5
commit 8218e5d53d
3 changed files with 162 additions and 22 deletions

View File

@@ -47,6 +47,10 @@ class MutipleMeaningException(object):
"""An mixin for exception that can be enhanced by reading the details"""
class CommandError(Exception):
pass
class BadRequest(ClientException):
"""HTTP 400 - Bad request: you sent some malformed data."""
http_status = 400
@@ -110,6 +114,10 @@ class RateLimit(RetryAfterException):
message = "Rate limit"
class NoUniqueMatch(Exception):
pass
class NotImplemented(ClientException):
"""HTTP 501 - Not Implemented:

View File

@@ -73,6 +73,21 @@ class AodhClientTest(base.ClientTestBase):
self.assertEqual('ev_alarm1', alarm_show['name'])
self.assertEqual('dummy', alarm_show['event_type'])
# GET BY NAME
result = self.aodh(
'alarm', params="show --alarm-name ev_alarm1")
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('ev_alarm1', alarm_show['name'])
self.assertEqual('dummy', alarm_show['event_type'])
# GET BY NAME AND ID ERROR
self.assertRaises(exceptions.CommandFailed,
self.aodh, u'alarm',
params=(u"show %s --alarm-name ev_alarm1" %
ALARM_ID))
# LIST
result = self.aodh('alarm', params="list")
self.assertIn(ALARM_ID,
@@ -117,12 +132,12 @@ class AodhClientTest(base.ClientTestBase):
# CREATE
result = self.aodh(u'alarm',
params=(u"create --type threshold --name alarm1 "
params=(u"create --type threshold --name alarm_th "
"-m meter_name --threshold 5 "
"--project-id %s" % PROJECT_ID))
alarm = self.details_multiple(result)[0]
ALARM_ID = alarm['alarm_id']
self.assertEqual('alarm1', alarm['name'])
self.assertEqual('alarm_th', alarm['name'])
self.assertEqual('meter_name', alarm['meter_name'])
self.assertEqual('5.0', alarm['threshold'])
@@ -144,17 +159,18 @@ class AodhClientTest(base.ClientTestBase):
# CREATE FAIL
result = self.aodh(u'alarm',
params=(u"create --type threshold --name alarm1 "
params=(u"create --type threshold --name alarm_th "
"-m meter_name --threshold 5 "
"--project-id %s" % PROJECT_ID),
fail_ok=True, merge_stderr=True)
self.assertFirstLineStartsWith(
result.split('\n'), "Alarm with name='alarm1' exists (HTTP 409)")
result.split('\n'),
"Alarm with name='alarm_th' exists (HTTP 409)")
# CREATE FAIL MISSING PARAM
self.assertRaises(exceptions.CommandFailed,
self.aodh, u'alarm',
params=(u"create --type threshold --name alarm1 "
params=(u"create --type threshold --name alarm_th "
"--project-id %s" % PROJECT_ID))
# UPDATE
@@ -172,10 +188,26 @@ class AodhClientTest(base.ClientTestBase):
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('alarm1', alarm_show['name'])
self.assertEqual('alarm_th', alarm_show['name'])
self.assertEqual('meter_name', alarm_show['meter_name'])
self.assertEqual('10.0', alarm_show['threshold'])
# GET BY NAME
result = self.aodh(
'alarm', params="show --alarm-name alarm_th")
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('alarm_th', alarm_show['name'])
self.assertEqual('meter_name', alarm_show['meter_name'])
self.assertEqual('10.0', alarm_show['threshold'])
# GET BY NAME AND ID ERROR
self.assertRaises(exceptions.CommandFailed,
self.aodh, u'alarm',
params=(u"show %s --alarm-name alarm_th" %
ALARM_ID))
# LIST
result = self.aodh('alarm', params="list")
self.assertIn(ALARM_ID,
@@ -185,14 +217,14 @@ class AodhClientTest(base.ClientTestBase):
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('alarm1', alarm_list['name'])
self.assertEqual('alarm_th', alarm_list['name'])
# LIST WITH QUERY
result = self.aodh('alarm',
params=("list --query project_id=%s" % PROJECT_ID))
alarm_list = self.parser.listing(result)[0]
self.assertEqual(ALARM_ID, alarm_list["alarm_id"])
self.assertEqual('alarm1', alarm_list['name'])
self.assertEqual('alarm_th', alarm_list['name'])
# DELETE
result = self.aodh('alarm', params="delete %s" % ALARM_ID)
@@ -272,6 +304,20 @@ class AodhClientTest(base.ClientTestBase):
self.assertEqual(project_id, alarm_show["project_id"])
self.assertEqual('calarm1', alarm_show['name'])
# GET BY NAME
result = self.aodh(
'alarm', params="show --alarm-name calarm1")
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'])
# GET BY NAME AND ID ERROR
self.assertRaises(exceptions.CommandFailed,
self.aodh, u'alarm',
params=(u"show %s --alarm-name calarm1" %
alarm_id))
# LIST
result = self.aodh('alarm', params="list")
self.assertIn(alarm_id,
@@ -323,7 +369,7 @@ class AodhClientGnocchiRulesTest(base.ClientTestBase):
result = self.aodh(u'alarm',
params=(u"create "
"--type gnocchi_resources_threshold "
"--name alarm1 --metric cpu_util "
"--name alarm_gn1 --metric cpu_util "
"--threshold 80 "
"--resource-id %s --resource-type instance "
"--aggregation-method last "
@@ -331,7 +377,7 @@ class AodhClientGnocchiRulesTest(base.ClientTestBase):
% (RESOURCE_ID, PROJECT_ID)))
alarm = self.details_multiple(result)[0]
ALARM_ID = alarm['alarm_id']
self.assertEqual('alarm1', alarm['name'])
self.assertEqual('alarm_gn1', alarm['name'])
self.assertEqual('cpu_util', alarm['metric'])
self.assertEqual('80.0', alarm['threshold'])
self.assertEqual('last', alarm['aggregation_method'])
@@ -343,7 +389,7 @@ class AodhClientGnocchiRulesTest(base.ClientTestBase):
result = self.aodh(u'alarm',
params=(u"create "
"--type gnocchi_resources_threshold "
"--name alarm1 --metric cpu_util "
"--name alarm_gn1 --metric cpu_util "
"--threshold 80 "
"--resource-id %s --resource-type instance "
"--aggregation-method last "
@@ -351,7 +397,8 @@ class AodhClientGnocchiRulesTest(base.ClientTestBase):
% (RESOURCE_ID, PROJECT_ID)),
fail_ok=True, merge_stderr=True)
self.assertFirstLineStartsWith(
result.split('\n'), "Alarm with name='alarm1' exists (HTTP 409)")
result.split('\n'),
"Alarm with name='alarm_gn1' exists (HTTP 409)")
# CREATE FAIL MISSING PARAM
self.assertRaises(exceptions.CommandFailed,
@@ -379,13 +426,31 @@ class AodhClientGnocchiRulesTest(base.ClientTestBase):
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('alarm1', alarm_show['name'])
self.assertEqual('alarm_gn1', alarm_show['name'])
self.assertEqual('cpu_util', alarm_show['metric'])
self.assertEqual('90.0', alarm_show['threshold'])
self.assertEqual('critical', alarm_show['severity'])
self.assertEqual('last', alarm_show['aggregation_method'])
self.assertEqual('instance', alarm_show['resource_type'])
# GET BY NAME
result = self.aodh(
'alarm', params="show --alarm-name alarm_gn1")
self.assertEqual(ALARM_ID, alarm_show["alarm_id"])
self.assertEqual(PROJECT_ID, alarm_show["project_id"])
self.assertEqual('alarm_gn1', alarm_show['name'])
self.assertEqual('cpu_util', alarm_show['metric'])
self.assertEqual('90.0', alarm_show['threshold'])
self.assertEqual('critical', alarm_show['severity'])
self.assertEqual('last', alarm_show['aggregation_method'])
self.assertEqual('instance', alarm_show['resource_type'])
# GET BY NAME AND ID ERROR
self.assertRaises(exceptions.CommandFailed,
self.aodh, u'alarm',
params=(u"show %s --alarm-name alarm_gn1" %
ALARM_ID))
# LIST
result = self.aodh('alarm', params="list")
self.assertIn(ALARM_ID,
@@ -395,14 +460,14 @@ class AodhClientGnocchiRulesTest(base.ClientTestBase):
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('alarm1', alarm_list['name'])
self.assertEqual('alarm_gn1', alarm_list['name'])
# LIST WITH QUERY
result = self.aodh('alarm',
params=("list --query project_id=%s" % PROJECT_ID))
alarm_list = self.parser.listing(result)[0]
self.assertEqual(ALARM_ID, alarm_list["alarm_id"])
self.assertEqual('alarm1', alarm_list['name'])
self.assertEqual('alarm_gn1', alarm_list['name'])
# DELETE
result = self.aodh('alarm', params="delete %s" % ALARM_ID)

View File

@@ -19,6 +19,8 @@ from cliff import show
from oslo_serialization import jsonutils
from oslo_utils import strutils
from aodhclient import exceptions
from aodhclient.i18n import _
from aodhclient import utils
ALARM_TYPES = ['threshold', 'event', 'composite',
@@ -65,16 +67,56 @@ def _format_alarm(alarm):
return alarm
def _find_alarm_by_name(client, name, return_id=False):
# then try to get entity as name
query = jsonutils.dumps({"=": {"name": name}})
alarms = client.list(query)
if len(alarms) > 1:
msg = (_("Multiple alarms matches found for '%s', "
"use an ID to be more specific.") % name)
raise exceptions.NoUniqueMatch(msg)
elif not alarms:
msg = (_("Alarm %s not found") % name)
raise exceptions.NotFound(404, msg)
else:
if return_id:
return alarms[0]['alarm_id']
return alarms[0]
def _check_name_and_id(parsed_args, action):
if parsed_args.id and parsed_args.alarm_name:
raise exceptions.CommandError(
"You should provide only one of "
"alarm ID and alarm name(--alarm-name) "
"to %s an alarm." % action)
if not parsed_args.id and not parsed_args.alarm_name:
msg = (_("You need to specify one of "
"alarm ID and alarm name(--alarm-name) "
"to %s an alarm.") % action)
raise exceptions.CommandError(msg)
class CliAlarmShow(show.ShowOne):
"""Show an alarm"""
def get_parser(self, prog_name):
parser = super(CliAlarmShow, self).get_parser(prog_name)
parser.add_argument("alarm_id", help="ID of an alarm")
parser.add_argument("id", nargs='?',
metavar='<ALARM ID>',
help="ID of an alarm")
parser.add_argument("--alarm-name", dest='alarm_name',
metavar='<ALARM NAME>',
help="name of an alarm")
return parser
def take_action(self, parsed_args):
alarm = self.app.client.alarm.get(alarm_id=parsed_args.alarm_id)
_check_name_and_id(parsed_args, 'query')
if parsed_args.id:
alarm = self.app.client.alarm.get(alarm_id=parsed_args.id)
else:
alarm = _find_alarm_by_name(self.app.client.alarm,
parsed_args.alarm_name)
return self.dict2columns(_format_alarm(alarm))
@@ -323,13 +365,26 @@ class CliAlarmUpdate(CliAlarmCreate):
def get_parser(self, prog_name):
parser = super(CliAlarmUpdate, self).get_parser(prog_name)
parser.add_argument("alarm_id", help="ID of the alarm")
parser.add_argument("id", nargs='?',
metavar='<ALARM ID>',
help="ID of an alarm")
parser.add_argument("--alarm-name", dest='alarm_name',
metavar='<ALARM NAME>',
help="name of an alarm")
return parser
def take_action(self, parsed_args):
_check_name_and_id(parsed_args, 'update')
attributes = self._alarm_from_args(parsed_args)
updated_alarm = self.app.client.alarm.update(
alarm_id=parsed_args.alarm_id, alarm_update=attributes)
if parsed_args.id:
updated_alarm = self.app.client.alarm.update(
alarm_id=parsed_args.id, alarm_update=attributes)
else:
alarm_id = _find_alarm_by_name(self.app.client.alarm,
parsed_args.alarm_name,
return_id=True)
updated_alarm = self.app.client.alarm.update(
alarm_id=alarm_id, alarm_update=attributes)
return self.dict2columns(_format_alarm(updated_alarm))
@@ -338,8 +393,20 @@ class CliAlarmDelete(command.Command):
def get_parser(self, prog_name):
parser = super(CliAlarmDelete, self).get_parser(prog_name)
parser.add_argument("alarm_id", help="ID of the alarm")
parser.add_argument("id", nargs='?',
metavar='<ALARM ID>',
help="ID of an alarm")
parser.add_argument("--alarm-name", dest='alarm_name',
metavar='<ALARM NAME>',
help="name of an alarm")
return parser
def take_action(self, parsed_args):
self.app.client.alarm.delete(parsed_args.alarm_id)
_check_name_and_id(parsed_args, 'delete')
if parsed_args.id:
self.app.client.alarm.delete(parsed_args.id)
else:
alarm_id = _find_alarm_by_name(self.app.client.alarm,
parsed_args.alarm_name,
return_id=True)
self.app.client.alarm.delete(alarm_id)