Use the new alarm format
The change sync the client API with the new alarm type and keep compatibility with the previous format of the alarm. It allows to create the new type of alarm: combination alarm. Implements blueprint alarming-logical-combination Change-Id: Ie62265023cadc20cf36a0d0b3775f4d984e324cf
This commit is contained in:
committed by
Mehdi Abaakouk
parent
052f210f56
commit
3499631b1a
@@ -140,6 +140,17 @@ def args_array_to_dict(kwargs, key_to_convert):
|
||||
return kwargs
|
||||
|
||||
|
||||
def key_with_slash_to_nested_dict(kwargs):
|
||||
nested_kwargs = {}
|
||||
for k in kwargs.keys():
|
||||
keys = k.split('/', 1)
|
||||
if len(keys) == 2:
|
||||
nested_kwargs.setdefault(keys[0], {})[keys[1]] = kwargs[k]
|
||||
del kwargs[k]
|
||||
kwargs.update(nested_kwargs)
|
||||
return kwargs
|
||||
|
||||
|
||||
def exit(msg=''):
|
||||
if msg:
|
||||
print >> sys.stderr, msg
|
||||
|
||||
@@ -57,3 +57,20 @@ class UtilsTest(test_utils.BaseTestCase):
|
||||
'matching_metadata': {'metadata.key': 'metadata_value'},
|
||||
'other': 'value'
|
||||
})
|
||||
|
||||
def test_key_with_slash_to_nested_dict(self):
|
||||
my_args = {
|
||||
'combination_rule/alarm_ids': ['id1', 'id2'],
|
||||
'combination_rule/operator': 'and',
|
||||
'threshold_rule/threshold': 400,
|
||||
'threshold_rule/statictic': 'avg',
|
||||
'threshold_rule/comparison_operator': 'or',
|
||||
}
|
||||
nested_dict = utils.key_with_slash_to_nested_dict(my_args)
|
||||
self.assertEqual(nested_dict, {
|
||||
'combination_rule': {'alarm_ids': ['id1', 'id2'],
|
||||
'operator': 'and'},
|
||||
'threshold_rule': {'threshold': 400,
|
||||
'statictic': 'avg',
|
||||
'comparison_operator': 'or'},
|
||||
})
|
||||
|
||||
@@ -22,37 +22,91 @@ import testtools
|
||||
from ceilometerclient.tests import utils
|
||||
import ceilometerclient.v2.alarms
|
||||
|
||||
|
||||
AN_ALARM = {u'alarm_actions': [u'http://site:8000/alarm'],
|
||||
u'ok_actions': [u'http://site:8000/ok'],
|
||||
u'description': u'An alarm',
|
||||
u'matching_metadata': {u'key_name': u'key_value'},
|
||||
u'evaluation_periods': 2,
|
||||
u'type': u'threshold',
|
||||
u'threshold_rule': {
|
||||
u'meter_name': u'storage.objects',
|
||||
u'query': [{u'field': u'key_name',
|
||||
u'op': u'eq',
|
||||
u'value': u'key_value'}],
|
||||
u'evaluation_periods': 2,
|
||||
u'period': 240.0,
|
||||
u'statistic': u'avg',
|
||||
u'threshold': 200.0,
|
||||
u'comparison_operator': 'gt',
|
||||
},
|
||||
u'timestamp': u'2013-05-09T13:41:23.085000',
|
||||
u'enabled': True,
|
||||
u'meter_name': u'storage.objects',
|
||||
u'period': 240.0,
|
||||
u'alarm_id': u'alarm-id',
|
||||
u'state': u'ok',
|
||||
u'insufficient_data_actions': [u'http://site:8000/nodata'],
|
||||
u'statistic': u'avg',
|
||||
u'threshold': 200.0,
|
||||
u'user_id': u'user-id',
|
||||
u'project_id': u'project-id',
|
||||
u'state_timestamp': u'2013-05-09T13:41:23.085000',
|
||||
u'comparison_operator': 'gt',
|
||||
u'repeat_actions': False,
|
||||
u'name': 'SwiftObjectAlarm'}
|
||||
CREATE_ALARM = copy.deepcopy(AN_ALARM)
|
||||
del CREATE_ALARM['timestamp']
|
||||
del CREATE_ALARM['state_timestamp']
|
||||
del CREATE_ALARM['alarm_id']
|
||||
DELTA_ALARM = {u'alarm_actions': ['url1', 'url2'],
|
||||
u'comparison_operator': u'lt',
|
||||
u'meter_name': u'foobar',
|
||||
u'threshold': 42.1}
|
||||
DELTA_ALARM = {u'alarm_actions': ['url1', 'url2']}
|
||||
DELTA_ALARM_RULE = {u'comparison_operator': u'lt',
|
||||
u'threshold': 42.1,
|
||||
u'meter_name': u'foobar',
|
||||
u'query': [{u'field': u'key_name',
|
||||
u'op': u'eq',
|
||||
u'value': u'key_value'}]}
|
||||
UPDATED_ALARM = copy.deepcopy(AN_ALARM)
|
||||
UPDATED_ALARM.update(DELTA_ALARM)
|
||||
UPDATED_ALARM['threshold_rule'].update(DELTA_ALARM_RULE)
|
||||
UPDATE_ALARM = copy.deepcopy(UPDATED_ALARM)
|
||||
del UPDATE_ALARM['user_id']
|
||||
del UPDATE_ALARM['project_id']
|
||||
del UPDATE_ALARM['name']
|
||||
del UPDATE_ALARM['alarm_id']
|
||||
del UPDATE_ALARM['timestamp']
|
||||
del UPDATE_ALARM['state_timestamp']
|
||||
|
||||
AN_LEGACY_ALARM = {u'alarm_actions': [u'http://site:8000/alarm'],
|
||||
u'ok_actions': [u'http://site:8000/ok'],
|
||||
u'description': u'An alarm',
|
||||
u'matching_metadata': {u'key_name': u'key_value'},
|
||||
u'evaluation_periods': 2,
|
||||
u'timestamp': u'2013-05-09T13:41:23.085000',
|
||||
u'enabled': True,
|
||||
u'meter_name': u'storage.objects',
|
||||
u'period': 240.0,
|
||||
u'alarm_id': u'alarm-id',
|
||||
u'state': u'ok',
|
||||
u'insufficient_data_actions': [u'http://site:8000/nodata'],
|
||||
u'statistic': u'avg',
|
||||
u'threshold': 200.0,
|
||||
u'user_id': u'user-id',
|
||||
u'project_id': u'project-id',
|
||||
u'state_timestamp': u'2013-05-09T13:41:23.085000',
|
||||
u'comparison_operator': 'gt',
|
||||
u'repeat_actions': False,
|
||||
u'name': 'SwiftObjectAlarm'}
|
||||
CREATE_LEGACY_ALARM = copy.deepcopy(AN_LEGACY_ALARM)
|
||||
del CREATE_LEGACY_ALARM['timestamp']
|
||||
del CREATE_LEGACY_ALARM['state_timestamp']
|
||||
del CREATE_LEGACY_ALARM['alarm_id']
|
||||
DELTA_LEGACY_ALARM = {u'alarm_actions': ['url1', 'url2'],
|
||||
u'comparison_operator': u'lt',
|
||||
u'meter_name': u'foobar',
|
||||
u'threshold': 42.1}
|
||||
UPDATED_LEGACY_ALARM = copy.deepcopy(AN_LEGACY_ALARM)
|
||||
UPDATED_LEGACY_ALARM.update(DELTA_LEGACY_ALARM)
|
||||
UPDATE_LEGACY_ALARM = copy.deepcopy(UPDATED_LEGACY_ALARM)
|
||||
del UPDATE_LEGACY_ALARM['user_id']
|
||||
del UPDATE_LEGACY_ALARM['project_id']
|
||||
del UPDATE_LEGACY_ALARM['name']
|
||||
del UPDATE_LEGACY_ALARM['alarm_id']
|
||||
del UPDATE_LEGACY_ALARM['timestamp']
|
||||
del UPDATE_LEGACY_ALARM['state_timestamp']
|
||||
|
||||
|
||||
fixtures = {
|
||||
'/v2/alarms':
|
||||
@@ -77,6 +131,18 @@ fixtures = {
|
||||
UPDATED_ALARM,
|
||||
),
|
||||
},
|
||||
'/v2/alarms/alarm-id/state':
|
||||
{
|
||||
'PUT': (
|
||||
{},
|
||||
'alarm'
|
||||
),
|
||||
'GET': (
|
||||
{},
|
||||
'alarm'
|
||||
),
|
||||
|
||||
},
|
||||
'/v2/alarms?q.op=&q.op=&q.value=project-id&q.value=SwiftObjectAlarm'
|
||||
'&q.field=project_id&q.field=name':
|
||||
{
|
||||
@@ -136,6 +202,7 @@ class AlarmManagerTest(testtools.TestCase):
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertTrue(alarm)
|
||||
self.assertEqual(alarm.alarm_id, 'alarm-id')
|
||||
self.assertEqual(alarm.rule, alarm.threshold_rule)
|
||||
|
||||
def test_create(self):
|
||||
alarm = self.mgr.create(**CREATE_ALARM)
|
||||
@@ -145,10 +212,61 @@ class AlarmManagerTest(testtools.TestCase):
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertTrue(alarm)
|
||||
|
||||
def test_create_legacy(self):
|
||||
def test_update(self):
|
||||
alarm = self.mgr.update(alarm_id='alarm-id', **UPDATE_ALARM)
|
||||
expect = [
|
||||
('PUT', '/v2/alarms/alarm-id', {}, UPDATE_ALARM),
|
||||
]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertTrue(alarm)
|
||||
self.assertEqual(alarm.alarm_id, 'alarm-id')
|
||||
for (key, value) in UPDATED_ALARM.iteritems():
|
||||
self.assertEqual(getattr(alarm, key), value)
|
||||
|
||||
def test_set_state(self):
|
||||
state = self.mgr.set_state(alarm_id='alarm-id', state='alarm')
|
||||
expect = [
|
||||
('PUT', '/v2/alarms/alarm-id/state', {}, 'alarm'),
|
||||
]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertEqual(state, 'alarm')
|
||||
|
||||
def test_get_state(self):
|
||||
state = self.mgr.get_state(alarm_id='alarm-id')
|
||||
expect = [
|
||||
('GET', '/v2/alarms/alarm-id/state', {}, None),
|
||||
]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertEqual(state, 'alarm')
|
||||
|
||||
def test_delete(self):
|
||||
deleted = self.mgr.delete(alarm_id='victim-id')
|
||||
expect = [
|
||||
('DELETE', '/v2/alarms/victim-id', {}, None),
|
||||
]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertTrue(deleted is None)
|
||||
|
||||
|
||||
class AlarmLegacyManagerTest(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(AlarmLegacyManagerTest, self).setUp()
|
||||
self.api = utils.FakeAPI(fixtures)
|
||||
self.mgr = ceilometerclient.v2.alarms.AlarmManager(self.api)
|
||||
|
||||
def test_create(self):
|
||||
alarm = self.mgr.create(**CREATE_LEGACY_ALARM)
|
||||
expect = [
|
||||
('POST', '/v2/alarms', {}, CREATE_ALARM),
|
||||
]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertTrue(alarm)
|
||||
|
||||
def test_create_counter_name(self):
|
||||
create = {}
|
||||
create.update(CREATE_ALARM)
|
||||
create['counter_name'] = CREATE_ALARM['meter_name']
|
||||
create.update(CREATE_LEGACY_ALARM)
|
||||
create['counter_name'] = CREATE_LEGACY_ALARM['meter_name']
|
||||
del create['meter_name']
|
||||
alarm = self.mgr.create(**create)
|
||||
expect = [
|
||||
@@ -158,35 +276,27 @@ class AlarmManagerTest(testtools.TestCase):
|
||||
self.assertTrue(alarm)
|
||||
|
||||
def test_update(self):
|
||||
alarm = self.mgr.update(alarm_id='alarm-id', **DELTA_ALARM)
|
||||
alarm = self.mgr.update(alarm_id='alarm-id', **UPDATE_LEGACY_ALARM)
|
||||
expect = [
|
||||
('PUT', '/v2/alarms/alarm-id', {}, DELTA_ALARM),
|
||||
('PUT', '/v2/alarms/alarm-id', {}, UPDATE_ALARM),
|
||||
]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertTrue(alarm)
|
||||
self.assertEqual(alarm.alarm_id, 'alarm-id')
|
||||
for (key, value) in DELTA_ALARM.iteritems():
|
||||
for (key, value) in UPDATED_ALARM.iteritems():
|
||||
self.assertEqual(getattr(alarm, key), value)
|
||||
|
||||
def test_update_legacy(self):
|
||||
delta = {}
|
||||
delta.update(DELTA_ALARM)
|
||||
delta['counter_name'] = DELTA_ALARM['meter_name']
|
||||
del delta['meter_name']
|
||||
alarm = self.mgr.update(alarm_id='alarm-id', **delta)
|
||||
def test_update_counter_name(self):
|
||||
updated = {}
|
||||
updated.update(UPDATE_LEGACY_ALARM)
|
||||
updated['counter_name'] = UPDATED_LEGACY_ALARM['meter_name']
|
||||
del updated['meter_name']
|
||||
alarm = self.mgr.update(alarm_id='alarm-id', **updated)
|
||||
expect = [
|
||||
('PUT', '/v2/alarms/alarm-id', {}, DELTA_ALARM),
|
||||
('PUT', '/v2/alarms/alarm-id', {}, UPDATE_ALARM),
|
||||
]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertTrue(alarm)
|
||||
self.assertEqual(alarm.alarm_id, 'alarm-id')
|
||||
for (key, value) in DELTA_ALARM.iteritems():
|
||||
for (key, value) in UPDATED_ALARM.iteritems():
|
||||
self.assertEqual(getattr(alarm, key), value)
|
||||
|
||||
def test_delete(self):
|
||||
deleted = self.mgr.delete(alarm_id='victim-id')
|
||||
expect = [
|
||||
('DELETE', '/v2/alarms/victim-id', {}, None),
|
||||
]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertTrue(deleted is None)
|
||||
|
||||
@@ -23,28 +23,32 @@ from ceilometerclient.v2 import options
|
||||
|
||||
|
||||
UPDATABLE_ATTRIBUTES = [
|
||||
'name',
|
||||
'description',
|
||||
'period',
|
||||
'evaluation_periods',
|
||||
'type',
|
||||
'state',
|
||||
'enabled',
|
||||
'meter_name',
|
||||
'statistic',
|
||||
'comparison_operator',
|
||||
'threshold',
|
||||
'alarm_actions',
|
||||
'ok_actions',
|
||||
'insufficient_data_actions',
|
||||
'repeat_actions',
|
||||
'matching_metadata',
|
||||
'threshold_rule',
|
||||
'combination_rule',
|
||||
]
|
||||
CREATION_ATTRIBUTES = UPDATABLE_ATTRIBUTES + ['name', 'project_id', 'user_id']
|
||||
CREATION_ATTRIBUTES = UPDATABLE_ATTRIBUTES + ['project_id', 'user_id']
|
||||
|
||||
|
||||
class Alarm(base.Resource):
|
||||
def __repr__(self):
|
||||
return "<Alarm %s>" % self._info
|
||||
|
||||
def __getattr__(self, k):
|
||||
# Alias to have the Alarm client object
|
||||
# that look like the Alarm storage object
|
||||
if k == 'rule':
|
||||
k = '%s_rule' % self.type
|
||||
return super(Alarm, self).__getattr__(k)
|
||||
|
||||
|
||||
class AlarmManager(base.Manager):
|
||||
resource_class = Alarm
|
||||
@@ -62,6 +66,11 @@ class AlarmManager(base.Manager):
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _compat_legacy_alarm_kwargs(cls, kwargs):
|
||||
cls._compat_counter_rename_kwargs(kwargs)
|
||||
cls._compat_alarm_before_rule_type_kwargs(kwargs)
|
||||
|
||||
@staticmethod
|
||||
def _compat_counter_rename_kwargs(kwargs):
|
||||
# NOTE(jd) Compatibility with Havana-2 API
|
||||
@@ -70,17 +79,53 @@ class AlarmManager(base.Manager):
|
||||
DeprecationWarning)
|
||||
kwargs['meter_name'] = kwargs['counter_name']
|
||||
|
||||
@staticmethod
|
||||
def _compat_alarm_before_rule_type_kwargs(kwargs):
|
||||
# NOTE(sileht) Compatibility with Havana-3 API
|
||||
if kwargs.get('type'):
|
||||
return
|
||||
warnings.warn("alarm without type set is deprecated",
|
||||
DeprecationWarning)
|
||||
|
||||
kwargs['type'] = 'threshold'
|
||||
kwargs['threshold_rule'] = {}
|
||||
for field in ['period', 'evaluation_periods', 'threshold',
|
||||
'statistic', 'comparison_operator', 'meter_name']:
|
||||
if field in kwargs:
|
||||
kwargs['threshold_rule'][field] = kwargs[field]
|
||||
del kwargs[field]
|
||||
|
||||
query = []
|
||||
if 'matching_metadata' in kwargs:
|
||||
for key in kwargs['matching_metadata']:
|
||||
query.append({'field': key,
|
||||
'op': 'eq',
|
||||
'value': kwargs['matching_metadata'][key]})
|
||||
del kwargs['matching_metadata']
|
||||
kwargs['threshold_rule']['query'] = query
|
||||
|
||||
def create(self, **kwargs):
|
||||
self._compat_counter_rename_kwargs(kwargs)
|
||||
self._compat_legacy_alarm_kwargs(kwargs)
|
||||
new = dict((key, value) for (key, value) in kwargs.items()
|
||||
if key in CREATION_ATTRIBUTES)
|
||||
return self._create(self._path(), new)
|
||||
|
||||
def update(self, alarm_id, **kwargs):
|
||||
self._compat_counter_rename_kwargs(kwargs)
|
||||
self._compat_legacy_alarm_kwargs(kwargs)
|
||||
updated = dict((key, value) for (key, value) in kwargs.items()
|
||||
if key in UPDATABLE_ATTRIBUTES)
|
||||
return self._update(self._path(alarm_id), updated)
|
||||
|
||||
def delete(self, alarm_id):
|
||||
return self._delete(self._path(alarm_id))
|
||||
|
||||
def set_state(self, alarm_id, state):
|
||||
resp, body = self.api.json_request('PUT',
|
||||
"%s/state" % self._path(alarm_id),
|
||||
body=state)
|
||||
return body
|
||||
|
||||
def get_state(self, alarm_id):
|
||||
resp, body = self.api.json_request('GET',
|
||||
"%s/state" % self._path(alarm_id))
|
||||
return body
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import functools
|
||||
import json
|
||||
|
||||
from ceilometerclient.common import utils
|
||||
@@ -25,6 +26,7 @@ from ceilometerclient.v2 import options
|
||||
|
||||
ALARM_STATES = ['ok', 'alarm', 'insufficient_data']
|
||||
ALARM_OPERATORS = ['lt', 'le', 'eq', 'ne', 'ge', 'gt']
|
||||
ALARM_COMBINATION_OPERATORS = ['and', 'or']
|
||||
STATISTICS = ['max', 'min', 'avg', 'sum', 'count']
|
||||
|
||||
|
||||
@@ -133,23 +135,19 @@ def do_alarm_list(cc, args={}):
|
||||
alarms = cc.alarms.list(q=options.cli_to_array(args.query))
|
||||
# omit action initially to keep output width sane
|
||||
# (can switch over to vertical formatting when available from CLIFF)
|
||||
field_labels = ['Name', 'Description', 'Metric', 'Period', 'Count',
|
||||
'Threshold', 'Comparison', 'State', 'Enabled', 'Alarm ID',
|
||||
'User ID', 'Project ID']
|
||||
fields = ['name', 'description', 'meter_name', 'period',
|
||||
'evaluation_periods', 'threshold', 'comparison_operator',
|
||||
'state', 'enabled', 'alarm_id', 'user_id', 'project_id']
|
||||
field_labels = ['Name', 'Description', 'State', 'Enabled', 'Continuous',
|
||||
'Alarm ID', 'User ID', 'Project ID']
|
||||
fields = ['name', 'description', 'state', 'enabled', 'repeat_actions',
|
||||
'alarm_id', 'user_id', 'project_id']
|
||||
utils.print_list(alarms, fields, field_labels,
|
||||
sortby=0)
|
||||
|
||||
|
||||
def _display_alarm(alarm):
|
||||
fields = ['name', 'description', 'meter_name', 'period',
|
||||
'evaluation_periods', 'statistic', 'threshold',
|
||||
'comparison_operator', 'state', 'enabled', 'alarm_id', 'user_id',
|
||||
'project_id', 'alarm_actions', 'ok_actions',
|
||||
'insufficient_data_actions', 'repeat_actions',
|
||||
'matching_metadata']
|
||||
fields = ['name', 'description', 'type', 'rule',
|
||||
'state', 'enabled', 'alarm_id', 'user_id', 'project_id',
|
||||
'alarm_actions', 'ok_actions', 'insufficient_data_actions',
|
||||
'repeat_actions']
|
||||
data = dict([(f, getattr(alarm, f, '')) for f in fields])
|
||||
utils.print_dict(data, wrap=72)
|
||||
|
||||
@@ -168,96 +166,136 @@ def do_alarm_show(cc, args={}):
|
||||
_display_alarm(alarm)
|
||||
|
||||
|
||||
@utils.arg('--name', metavar='<NAME>',
|
||||
help='Name of the alarm (must be unique per tenant)')
|
||||
@utils.arg('--project-id', metavar='<PROJECT_ID>',
|
||||
help='Tenant to associate with alarm '
|
||||
'(only settable by admin users)')
|
||||
@utils.arg('--user-id', metavar='<USER_ID>',
|
||||
help='User to associate with alarm '
|
||||
'(only settable by admin users)')
|
||||
@utils.arg('--description', metavar='<DESCRIPTION>',
|
||||
help='Free text description of the alarm')
|
||||
def common_alarm_arguments(func):
|
||||
@utils.arg('--name', metavar='<NAME>', required=True,
|
||||
help='Name of the alarm (must be unique per tenant)')
|
||||
@utils.arg('--project-id', metavar='<PROJECT_ID>',
|
||||
help='Tenant to associate with alarm '
|
||||
'(only settable by admin users)')
|
||||
@utils.arg('--user-id', metavar='<USER_ID>',
|
||||
help='User to associate with alarm '
|
||||
'(only settable by admin users)')
|
||||
@utils.arg('--description', metavar='<DESCRIPTION>',
|
||||
help='Free text description of the alarm')
|
||||
@utils.arg('--state', metavar='<STATE>',
|
||||
help='State of the alarm, one of: ' + str(ALARM_STATES))
|
||||
@utils.arg('--enabled', type=utils.string_to_bool, metavar='{True|False}',
|
||||
help='True if alarm evaluation/actioning is enabled')
|
||||
@utils.arg('--alarm-action', dest='alarm_actions',
|
||||
metavar='<Webhook URL>', action='append', default=None,
|
||||
help=('URL to invoke when state transitions to alarm. '
|
||||
'May be used multiple times.'))
|
||||
@utils.arg('--ok-action', dest='ok_actions',
|
||||
metavar='<Webhook URL>', action='append', default=None,
|
||||
help=('URL to invoke when state transitions to OK. '
|
||||
'May be used multiple times.'))
|
||||
@utils.arg('--insufficient-data-action', dest='insufficient_data_actions',
|
||||
metavar='<Webhook URL>', action='append', default=None,
|
||||
help=('URL to invoke when state transitions to unkown. '
|
||||
'May be used multiple times.'))
|
||||
@utils.arg('--repeat-actions', dest='repeat_actions',
|
||||
metavar='{True|False}', type=utils.string_to_bool,
|
||||
default=False,
|
||||
help=('True if actions should be repeatedly notified '
|
||||
'while alarm remains in target state'))
|
||||
@functools.wraps(func)
|
||||
def _wrapper(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
return _wrapper
|
||||
|
||||
|
||||
@common_alarm_arguments
|
||||
@utils.arg('--period', type=int, metavar='<PERIOD>',
|
||||
help='Length of each period (seconds) to evaluate over')
|
||||
@utils.arg('--evaluation-periods', type=int, metavar='<COUNT>',
|
||||
help='Number of periods to evaluate over')
|
||||
@utils.arg('--state', metavar='<STATE>',
|
||||
help='State of the alarm, one of: ' + str(ALARM_STATES))
|
||||
@utils.arg('--enabled', type=utils.string_to_bool, metavar='{True|False}',
|
||||
help='True if alarm evaluation/actioning is enabled')
|
||||
@utils.arg('--meter-name', metavar='<METRIC>',
|
||||
@utils.arg('--meter-name', metavar='<METRIC>', required=True,
|
||||
help='Metric to evaluate against')
|
||||
@utils.arg('--statistic', metavar='<STATISTIC>',
|
||||
help='Statistic to evaluate, one of: ' + str(STATISTICS))
|
||||
@utils.arg('--comparison-operator', metavar='<OPERATOR>',
|
||||
help='Operator to compare with, one of: ' + str(ALARM_OPERATORS))
|
||||
@utils.arg('--threshold', type=float, metavar='<THRESHOLD>',
|
||||
@utils.arg('--threshold', type=float, metavar='<THRESHOLD>', required=True,
|
||||
help='Threshold to evaluate against')
|
||||
@utils.arg('--alarm-action', dest='alarm_actions',
|
||||
metavar='<Webhook URL>', action='append', default=None,
|
||||
help=('URL to invoke when state transitions to alarm. '
|
||||
'May be used multiple times.'))
|
||||
@utils.arg('--ok-action', dest='ok_actions',
|
||||
metavar='<Webhook URL>', action='append', default=None,
|
||||
help=('URL to invoke when state transitions to OK. '
|
||||
'May be used multiple times.'))
|
||||
@utils.arg('--insufficient-data-action', dest='insufficient_data_actions',
|
||||
metavar='<Webhook URL>', action='append', default=None,
|
||||
help=('URL to invoke when state transitions to unkown. '
|
||||
'May be used multiple times.'))
|
||||
@utils.arg('--repeat-actions', dest='repeat_actions', metavar='{True|False}',
|
||||
type=utils.string_to_bool, default=False,
|
||||
help=('True if actions should be repeatedly notified '
|
||||
'while alarm remains in target state'))
|
||||
@utils.arg('--matching-metadata', dest='matching_metadata',
|
||||
metavar='<Matching Metadata>', action='append', default=None,
|
||||
help=('A meter should match this resource metadata (key=value) '
|
||||
'additionally to the meter_name'))
|
||||
def do_alarm_create(cc, args={}):
|
||||
'''Create a new alarm.'''
|
||||
'''Create a new alarm (Deprecated).'''
|
||||
fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
|
||||
fields = utils.args_array_to_dict(fields, "matching_metadata")
|
||||
alarm = cc.alarms.create(**fields)
|
||||
_display_alarm(alarm)
|
||||
|
||||
|
||||
@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
|
||||
@common_alarm_arguments
|
||||
@utils.arg('--meter-name', metavar='<METRIC>', required=True,
|
||||
dest='threshold_rule/meter_name',
|
||||
help='Metric to evaluate against')
|
||||
@utils.arg('--period', type=int, metavar='<PERIOD>',
|
||||
dest='threshold_rule/period',
|
||||
help='Length of each period (seconds) to evaluate over')
|
||||
@utils.arg('--evaluation-periods', type=int, metavar='<COUNT>',
|
||||
dest='threshold_rule/evaluation_periods',
|
||||
help='Number of periods to evaluate over')
|
||||
@utils.arg('--statistic', metavar='<STATISTIC>',
|
||||
dest='threshold_rule/statistic',
|
||||
help='Statistic to evaluate, one of: ' + str(STATISTICS))
|
||||
@utils.arg('--comparison-operator', metavar='<OPERATOR>',
|
||||
dest='threshold_rule/comparison_operator',
|
||||
help='Operator to compare with, one of: ' + str(ALARM_OPERATORS))
|
||||
@utils.arg('--threshold', type=float, metavar='<THRESHOLD>', required=True,
|
||||
dest='threshold_rule/threshold',
|
||||
help='Threshold to evaluate against')
|
||||
@utils.arg('-q', '--query', metavar='<QUERY>',
|
||||
dest='threshold_rule/query',
|
||||
help='The query to find the data for computing statistics '
|
||||
'(key[op]value; list.)')
|
||||
def do_alarm_threshold_create(cc, args={}):
|
||||
'''Create a new alarm based on computed statistics.'''
|
||||
fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
|
||||
fields = utils.key_with_slash_to_nested_dict(fields)
|
||||
fields['type'] = 'threshold'
|
||||
if 'query' in fields['threshold_rule']:
|
||||
fields['threshold_rule']['query'] = options.cli_to_array(
|
||||
fields['threshold_rule']['query'])
|
||||
alarm = cc.alarms.create(**fields)
|
||||
_display_alarm(alarm)
|
||||
|
||||
|
||||
@common_alarm_arguments
|
||||
@utils.arg('--alarm_ids', action='append', metavar='<ALARM IDS>',
|
||||
required=True, dest='combination_rule/alarm_ids',
|
||||
help='List of alarm id')
|
||||
@utils.arg('--operator', metavar='<OPERATOR>',
|
||||
dest='combination_rule/operator',
|
||||
help='Operator to compare with, one of: ' + str(
|
||||
ALARM_COMBINATION_OPERATORS))
|
||||
def do_alarm_combination_create(cc, args={}):
|
||||
'''Create a new alarm based on state of other alarms.'''
|
||||
fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
|
||||
fields = utils.key_with_slash_to_nested_dict(fields)
|
||||
fields['type'] = 'combination'
|
||||
alarm = cc.alarms.create(**fields)
|
||||
_display_alarm(alarm)
|
||||
|
||||
|
||||
@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>', required=True,
|
||||
help='ID of the alarm to update.')
|
||||
@utils.arg('--description', metavar='<DESCRIPTION>',
|
||||
help='Free text description of the alarm')
|
||||
@common_alarm_arguments
|
||||
@utils.arg('--period', type=int, metavar='<PERIOD>',
|
||||
help='Length of each period (seconds) to evaluate over')
|
||||
@utils.arg('--evaluation-periods', type=int, metavar='<COUNT>',
|
||||
help='Number of periods to evaluate over')
|
||||
@utils.arg('--state', metavar='<STATE>',
|
||||
help='State of the alarm, one of: ' + str(ALARM_STATES))
|
||||
@utils.arg('--enabled', type=utils.string_to_bool, metavar='{True|False}',
|
||||
help='True if alarm evaluation/actioning is enabled')
|
||||
@utils.arg('--meter-name', metavar='<METRIC>',
|
||||
@utils.arg('--meter-name', metavar='<METRIC>', required=True,
|
||||
help='Metric to evaluate against')
|
||||
@utils.arg('--statistic', metavar='<STATISTIC>',
|
||||
help='Statistic to evaluate, one of: ' + str(STATISTICS))
|
||||
@utils.arg('--comparison-operator', metavar='<OPERATOR>',
|
||||
help='Operator to compare with, one of: ' + str(ALARM_OPERATORS))
|
||||
@utils.arg('--threshold', type=float, metavar='<THRESHOLD>',
|
||||
@utils.arg('--threshold', type=float, metavar='<THRESHOLD>', required=True,
|
||||
help='Threshold to evaluate against')
|
||||
@utils.arg('--alarm-action', dest='alarm_actions',
|
||||
metavar='<Webhook URL>', action='append', default=None,
|
||||
help=('URL to invoke when state transitions to alarm. '
|
||||
'May be used multiple times.'))
|
||||
@utils.arg('--ok-action', dest='ok_actions',
|
||||
metavar='<Webhook URL>', action='append', default=None,
|
||||
help=('URL to invoke when state transitions to OK. '
|
||||
'May be used multiple times.'))
|
||||
@utils.arg('--insufficient-data-action', dest='insufficient_data_actions',
|
||||
metavar='<Webhook URL>', action='append', default=None,
|
||||
help=('URL to invoke when state transitions to unkown. '
|
||||
'May be used multiple times.'))
|
||||
@utils.arg('--repeat-actions', dest='repeat_actions',
|
||||
metavar='{True|False}', type=utils.string_to_bool,
|
||||
help=('True if actions should be repeatedly notified '
|
||||
'while alarm remains in target state'))
|
||||
@utils.arg('--matching-metadata', dest='matching_metadata',
|
||||
metavar='<Matching Metadata>', action='append', default=None,
|
||||
help=('A meter should match this resource metadata (key=value) '
|
||||
@@ -267,12 +305,79 @@ def do_alarm_update(cc, args={}):
|
||||
fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
|
||||
fields = utils.args_array_to_dict(fields, "matching_metadata")
|
||||
fields.pop('alarm_id')
|
||||
alarm = cc.alarms.update(args.alarm_id, **fields)
|
||||
try:
|
||||
alarm = cc.alarms.update(args.alarm_id, **fields)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
|
||||
_display_alarm(alarm)
|
||||
|
||||
|
||||
@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
|
||||
help='ID of the alarm to show.')
|
||||
@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>', required=True,
|
||||
help='ID of the alarm to update.')
|
||||
@common_alarm_arguments
|
||||
@utils.arg('--meter-name', metavar='<METRIC>',
|
||||
dest='threshold_rule/meter_name', required=True,
|
||||
help='Metric to evaluate against')
|
||||
@utils.arg('--period', type=int, metavar='<PERIOD>',
|
||||
dest='threshold_rule/period',
|
||||
help='Length of each period (seconds) to evaluate over')
|
||||
@utils.arg('--evaluation-periods', type=int, metavar='<COUNT>',
|
||||
dest='threshold_rule/evaluation_periods',
|
||||
help='Number of periods to evaluate over')
|
||||
@utils.arg('--statistic', metavar='<STATISTIC>',
|
||||
dest='threshold_rule/statistic',
|
||||
help='Statistic to evaluate, one of: ' + str(STATISTICS))
|
||||
@utils.arg('--comparison-operator', metavar='<OPERATOR>',
|
||||
dest='threshold_rule/comparison_operator',
|
||||
help='Operator to compare with, one of: ' + str(ALARM_OPERATORS))
|
||||
@utils.arg('--threshold', type=float, metavar='<THRESHOLD>', required=True,
|
||||
dest='threshold_rule/threshold',
|
||||
help='Threshold to evaluate against')
|
||||
@utils.arg('-q', '--query', metavar='<QUERY>',
|
||||
dest='threshold_rule/query',
|
||||
help='The query to find the data for computing statistics '
|
||||
'(key[op]value; list.)')
|
||||
def do_alarm_threshold_update(cc, args={}):
|
||||
'''Update an existing alarm based on computed statistics.'''
|
||||
fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
|
||||
fields = utils.key_with_slash_to_nested_dict(fields)
|
||||
fields.pop('alarm_id')
|
||||
fields['type'] = 'threshold'
|
||||
if 'query' in fields['threshold_rule']:
|
||||
fields['threshold_rule']['query'] = options.cli_to_array(
|
||||
fields['threshold_rule']['query'])
|
||||
try:
|
||||
alarm = cc.alarms.update(args.alarm_id, **fields)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
|
||||
_display_alarm(alarm)
|
||||
|
||||
|
||||
@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>', required=True,
|
||||
help='ID of the alarm to update.')
|
||||
@common_alarm_arguments
|
||||
@utils.arg('--alarm_ids', action='append', metavar='<ALARM IDS>',
|
||||
dest='combination_rule/alarm_ids', required=True,
|
||||
help='List of alarm id')
|
||||
@utils.arg('---operator', metavar='<OPERATOR>',
|
||||
dest='combination_rule/operator',
|
||||
help='Operator to compare with, one of: ' + str(
|
||||
ALARM_COMBINATION_OPERATORS))
|
||||
def do_alarm_combination_update(cc, args={}):
|
||||
'''Update an existing alarm based on state of other alarms.'''
|
||||
fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
|
||||
fields = utils.key_with_slash_to_nested_dict(fields)
|
||||
fields.pop('alarm_id')
|
||||
fields['type'] = 'combination'
|
||||
try:
|
||||
alarm = cc.alarms.update(args.alarm_id, **fields)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
|
||||
_display_alarm(alarm)
|
||||
|
||||
|
||||
@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>', required=True,
|
||||
help='ID of the alarm to delete.')
|
||||
def do_alarm_delete(cc, args={}):
|
||||
'''Delete an alarm.'''
|
||||
if args.alarm_id is None:
|
||||
@@ -283,6 +388,32 @@ def do_alarm_delete(cc, args={}):
|
||||
raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
|
||||
|
||||
|
||||
@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>', required=True,
|
||||
help='ID of the alarm state to set.')
|
||||
@utils.arg('--state', metavar='<STATE>', required=True,
|
||||
help='State of the alarm, one of: ' + str(ALARM_STATES))
|
||||
def do_alarm_set_state(cc, args={}):
|
||||
'''Set the state of an alarm.'''
|
||||
try:
|
||||
cc.alarms.set_state(args.alarm_id, args.state)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
|
||||
state = cc.alarms.get_state(args.alarm_id)
|
||||
utils.print_dict({'state': state}, wrap=72)
|
||||
|
||||
|
||||
@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>', required=True,
|
||||
help='ID of the alarm state to show.')
|
||||
def do_alarm_get_state(cc, args={}):
|
||||
'''Get the state of an alarm.'''
|
||||
try:
|
||||
cc.alarms.set_state(args.alarm_id, args.state)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
|
||||
state = cc.alarms.get_state(args.alarm_id)
|
||||
utils.print_dict({'state': state}, wrap=72)
|
||||
|
||||
|
||||
@utils.arg('-q', '--query', metavar='<QUERY>',
|
||||
help='key[op]value; list.')
|
||||
def do_resource_list(cc, args={}):
|
||||
|
||||
Reference in New Issue
Block a user