Mark combination alarm as None resource
Combination alarm has been removed from Aodh since Pike. We inherit combination alarm from none resource in this patch. Will schedule to remove the resource in future cycle. Closes-Bug: #1668342 Change-Id: I573f4bde9b4b7b12879c39111cf87c751f71ad7e
This commit is contained in:
parent
8ddd903b03
commit
14903dc1cd
@ -18,6 +18,7 @@ from heat.common.i18n import _
|
|||||||
from heat.engine import constraints
|
from heat.engine import constraints
|
||||||
from heat.engine import properties
|
from heat.engine import properties
|
||||||
from heat.engine.resources import alarm_base
|
from heat.engine.resources import alarm_base
|
||||||
|
from heat.engine.resources.openstack.heat import none_resource
|
||||||
from heat.engine import support
|
from heat.engine import support
|
||||||
from heat.engine import watchrule
|
from heat.engine import watchrule
|
||||||
|
|
||||||
@ -224,27 +225,23 @@ class AodhAlarm(alarm_base.BaseAlarm):
|
|||||||
self.client().alarm.get(self.resource_id)
|
self.client().alarm.get(self.resource_id)
|
||||||
|
|
||||||
|
|
||||||
class CombinationAlarm(alarm_base.BaseAlarm):
|
class CombinationAlarm(none_resource.NoneResource):
|
||||||
"""A resource that implements combination of Aodh alarms.
|
"""A resource that implements combination of Aodh alarms.
|
||||||
|
|
||||||
Allows to use alarm as a combination of other alarms with some operator:
|
This resource is now deleted from Aodh, so will directly inherit from
|
||||||
activate this alarm if any alarm in combination has been activated or
|
NoneResource (placeholder resource). For old resources (which not a
|
||||||
if all alarms in combination have been activated.
|
placeholder resource), still can be deleted through client. Any newly
|
||||||
|
created resources will be considered as placeholder resources like none
|
||||||
|
resource. We will schedule to delete it from heat resources list.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
alarm_type = 'combination'
|
default_client_name = 'aodh'
|
||||||
|
entity = 'alarm'
|
||||||
# aodhclient doesn't support to manage combination-alarm,
|
|
||||||
# so we use ceilometerclient to manage this resource as before,
|
|
||||||
# after two release cycles, to hidden this resource.
|
|
||||||
default_client_name = 'ceilometer'
|
|
||||||
|
|
||||||
entity = 'alarms'
|
|
||||||
|
|
||||||
support_status = support.SupportStatus(
|
support_status = support.SupportStatus(
|
||||||
status=support.HIDDEN,
|
status=support.HIDDEN,
|
||||||
message=_('OS::Aodh::CombinationAlarm is deprecated, '
|
message=_('OS::Aodh::CombinationAlarm is deprecated and has been '
|
||||||
'use OS::Aodh::CompositeAlarm instead.'),
|
'removed from Aodh, use OS::Aodh::CompositeAlarm instead.'),
|
||||||
version='9.0.0',
|
version='9.0.0',
|
||||||
previous_status=support.SupportStatus(
|
previous_status=support.SupportStatus(
|
||||||
status=support.DEPRECATED,
|
status=support.DEPRECATED,
|
||||||
@ -253,56 +250,6 @@ class CombinationAlarm(alarm_base.BaseAlarm):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
PROPERTIES = (
|
|
||||||
ALARM_IDS, OPERATOR,
|
|
||||||
) = (
|
|
||||||
'alarm_ids', 'operator',
|
|
||||||
)
|
|
||||||
|
|
||||||
properties_schema = {
|
|
||||||
ALARM_IDS: properties.Schema(
|
|
||||||
properties.Schema.LIST,
|
|
||||||
_('List of alarm identifiers to combine.'),
|
|
||||||
required=True,
|
|
||||||
constraints=[constraints.Length(min=1)],
|
|
||||||
update_allowed=True),
|
|
||||||
OPERATOR: properties.Schema(
|
|
||||||
properties.Schema.STRING,
|
|
||||||
_('Operator used to combine the alarms.'),
|
|
||||||
constraints=[constraints.AllowedValues(['and', 'or'])],
|
|
||||||
update_allowed=True)
|
|
||||||
}
|
|
||||||
properties_schema.update(alarm_base.common_properties_schema)
|
|
||||||
|
|
||||||
def handle_create(self):
|
|
||||||
props = self.actions_to_urls(self.properties)
|
|
||||||
props['name'] = self.physical_resource_name()
|
|
||||||
props['type'] = self.alarm_type
|
|
||||||
alarm = self.client().alarms.create(
|
|
||||||
**self._reformat_properties(props))
|
|
||||||
self.resource_id_set(alarm.alarm_id)
|
|
||||||
|
|
||||||
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
|
||||||
if prop_diff:
|
|
||||||
kwargs = {'alarm_id': self.resource_id}
|
|
||||||
new_props = json_snippet.properties(self.properties_schema,
|
|
||||||
self.context)
|
|
||||||
kwargs.update(self._reformat_properties(
|
|
||||||
self.actions_to_urls(new_props)))
|
|
||||||
alarms_client = self.client().alarms
|
|
||||||
alarms_client.update(**kwargs)
|
|
||||||
|
|
||||||
def handle_suspend(self):
|
|
||||||
self.client().alarms.update(
|
|
||||||
alarm_id=self.resource_id, enabled=False)
|
|
||||||
|
|
||||||
def handle_resume(self):
|
|
||||||
self.client().alarms.update(
|
|
||||||
alarm_id=self.resource_id, enabled=True)
|
|
||||||
|
|
||||||
def handle_check(self):
|
|
||||||
self.client().alarms.get(self.resource_id)
|
|
||||||
|
|
||||||
|
|
||||||
class EventAlarm(alarm_base.BaseAlarm):
|
class EventAlarm(alarm_base.BaseAlarm):
|
||||||
"""A resource that implements event alarms.
|
"""A resource that implements event alarms.
|
||||||
|
@ -15,13 +15,11 @@ import copy
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
import mox
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
from heat.common import template_format
|
from heat.common import template_format
|
||||||
from heat.engine.clients.os import aodh
|
from heat.engine.clients.os import aodh
|
||||||
from heat.engine.clients.os import ceilometer
|
|
||||||
from heat.engine import resource
|
from heat.engine import resource
|
||||||
from heat.engine.resources.openstack.aodh import alarm
|
from heat.engine.resources.openstack.aodh import alarm
|
||||||
from heat.engine import rsrc_defn
|
from heat.engine import rsrc_defn
|
||||||
@ -121,24 +119,6 @@ not_string_alarm_template = '''
|
|||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
combination_alarm_template = '''
|
|
||||||
{
|
|
||||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
|
||||||
"Description" : "Combination Alarm Test",
|
|
||||||
"Resources" : {
|
|
||||||
"CombinAlarm": {
|
|
||||||
"Type": "OS::Aodh::CombinationAlarm",
|
|
||||||
"Properties": {
|
|
||||||
"description": "Do stuff in combination",
|
|
||||||
"alarm_ids": ["alarm1", "alarm2"],
|
|
||||||
"operator": "and",
|
|
||||||
"alarm_actions": [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
|
|
||||||
event_alarm_template = '''
|
event_alarm_template = '''
|
||||||
{
|
{
|
||||||
"heat_template_version" : "newton",
|
"heat_template_version" : "newton",
|
||||||
@ -164,13 +144,6 @@ event_alarm_template = '''
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
class FakeCombinationAlarm(object):
|
|
||||||
alarm_id = 'foo'
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.to_dict = lambda: {'attr': 'val'}
|
|
||||||
|
|
||||||
|
|
||||||
FakeAodhAlarm = {'other_attrs': 'val',
|
FakeAodhAlarm = {'other_attrs': 'val',
|
||||||
'alarm_id': 'foo'}
|
'alarm_id': 'foo'}
|
||||||
|
|
||||||
@ -698,148 +671,6 @@ class AodhAlarmTest(common.HeatTestCase):
|
|||||||
self.assertEqual(expected, alarm.actions_to_urls(props))
|
self.assertEqual(expected, alarm.actions_to_urls(props))
|
||||||
|
|
||||||
|
|
||||||
class CombinationAlarmTest(common.HeatTestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(CombinationAlarmTest, self).setUp()
|
|
||||||
self.fc = mock.Mock()
|
|
||||||
self.m.StubOutWithMock(ceilometer.CeilometerClientPlugin, '_create')
|
|
||||||
|
|
||||||
def create_alarm(self):
|
|
||||||
ceilometer.CeilometerClientPlugin._create().AndReturn(
|
|
||||||
self.fc)
|
|
||||||
self.m.StubOutWithMock(self.fc.alarms, 'create')
|
|
||||||
self.fc.alarms.create(
|
|
||||||
alarm_actions=[],
|
|
||||||
description=u'Do stuff in combination',
|
|
||||||
enabled=True,
|
|
||||||
insufficient_data_actions=[],
|
|
||||||
ok_actions=[],
|
|
||||||
name=mox.IgnoreArg(), type='combination',
|
|
||||||
repeat_actions=True,
|
|
||||||
combination_rule={'alarm_ids': [u'alarm1', u'alarm2'],
|
|
||||||
'operator': u'and'},
|
|
||||||
time_constraints=[],
|
|
||||||
severity='low'
|
|
||||||
).AndReturn(FakeCombinationAlarm())
|
|
||||||
self.tmpl = template_format.parse(combination_alarm_template)
|
|
||||||
self.stack = utils.parse_stack(self.tmpl)
|
|
||||||
resource_defns = self.stack.t.resource_definitions(self.stack)
|
|
||||||
return alarm.CombinationAlarm(
|
|
||||||
'CombinAlarm', resource_defns['CombinAlarm'], self.stack)
|
|
||||||
|
|
||||||
def test_create(self):
|
|
||||||
rsrc = self.create_alarm()
|
|
||||||
|
|
||||||
self.m.ReplayAll()
|
|
||||||
scheduler.TaskRunner(rsrc.create)()
|
|
||||||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
|
||||||
self.assertEqual('foo', rsrc.resource_id)
|
|
||||||
self.m.VerifyAll()
|
|
||||||
|
|
||||||
def test_invalid_alarm_list(self):
|
|
||||||
snippet = template_format.parse(combination_alarm_template)
|
|
||||||
snippet['Resources']['CombinAlarm']['Properties']['alarm_ids'] = []
|
|
||||||
stack = utils.parse_stack(snippet)
|
|
||||||
resource_defns = stack.t.resource_definitions(stack)
|
|
||||||
rsrc = alarm.CombinationAlarm(
|
|
||||||
'CombinAlarm', resource_defns['CombinAlarm'], stack)
|
|
||||||
error = self.assertRaises(exception.StackValidationFailed,
|
|
||||||
rsrc.validate)
|
|
||||||
self.assertEqual(
|
|
||||||
"Property error: Resources.CombinAlarm.Properties.alarm_ids: "
|
|
||||||
"length (0) is out of range (min: 1, max: None)",
|
|
||||||
six.text_type(error))
|
|
||||||
|
|
||||||
def test_update(self):
|
|
||||||
rsrc = self.create_alarm()
|
|
||||||
self.m.StubOutWithMock(self.fc.alarms, 'update')
|
|
||||||
self.fc.alarms.update(
|
|
||||||
alarm_id='foo',
|
|
||||||
alarm_actions=[],
|
|
||||||
description=u'Do stuff in combination',
|
|
||||||
enabled=True,
|
|
||||||
insufficient_data_actions=[],
|
|
||||||
ok_actions=[],
|
|
||||||
repeat_actions=True,
|
|
||||||
combination_rule={'alarm_ids': [u'alarm1', u'alarm3'],
|
|
||||||
'operator': u'and'},
|
|
||||||
time_constraints=[],
|
|
||||||
severity='low'
|
|
||||||
)
|
|
||||||
|
|
||||||
self.m.ReplayAll()
|
|
||||||
scheduler.TaskRunner(rsrc.create)()
|
|
||||||
|
|
||||||
props = self.tmpl['Resources']['CombinAlarm']['Properties'].copy()
|
|
||||||
props['alarm_ids'] = ['alarm1', 'alarm3']
|
|
||||||
update_template = rsrc.t.freeze(properties=props)
|
|
||||||
scheduler.TaskRunner(rsrc.update, update_template)()
|
|
||||||
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
|
|
||||||
|
|
||||||
self.m.VerifyAll()
|
|
||||||
|
|
||||||
def test_suspend(self):
|
|
||||||
rsrc = self.create_alarm()
|
|
||||||
self.m.StubOutWithMock(self.fc.alarms, 'update')
|
|
||||||
self.fc.alarms.update(alarm_id='foo', enabled=False)
|
|
||||||
|
|
||||||
self.m.ReplayAll()
|
|
||||||
scheduler.TaskRunner(rsrc.create)()
|
|
||||||
|
|
||||||
scheduler.TaskRunner(rsrc.suspend)()
|
|
||||||
self.assertEqual((rsrc.SUSPEND, rsrc.COMPLETE), rsrc.state)
|
|
||||||
|
|
||||||
self.m.VerifyAll()
|
|
||||||
|
|
||||||
def test_resume(self):
|
|
||||||
rsrc = self.create_alarm()
|
|
||||||
self.m.StubOutWithMock(self.fc.alarms, 'update')
|
|
||||||
self.fc.alarms.update(alarm_id='foo', enabled=True)
|
|
||||||
|
|
||||||
self.m.ReplayAll()
|
|
||||||
scheduler.TaskRunner(rsrc.create)()
|
|
||||||
rsrc.state_set(rsrc.SUSPEND, rsrc.COMPLETE)
|
|
||||||
|
|
||||||
scheduler.TaskRunner(rsrc.resume)()
|
|
||||||
self.assertEqual((rsrc.RESUME, rsrc.COMPLETE), rsrc.state)
|
|
||||||
|
|
||||||
self.m.VerifyAll()
|
|
||||||
|
|
||||||
def _prepare_resource(self, for_check=True):
|
|
||||||
snippet = template_format.parse(combination_alarm_template)
|
|
||||||
self.stack = utils.parse_stack(snippet)
|
|
||||||
res = self.stack['CombinAlarm']
|
|
||||||
if for_check:
|
|
||||||
res.state_set(res.CREATE, res.COMPLETE)
|
|
||||||
res.client = mock.Mock()
|
|
||||||
mock_alarm = mock.Mock(enabled=True, state='ok')
|
|
||||||
res.client().alarms.get.return_value = mock_alarm
|
|
||||||
return res
|
|
||||||
|
|
||||||
def test_check(self):
|
|
||||||
res = self._prepare_resource()
|
|
||||||
scheduler.TaskRunner(res.check)()
|
|
||||||
self.assertEqual((res.CHECK, res.COMPLETE), res.state)
|
|
||||||
|
|
||||||
def test_check_failure(self):
|
|
||||||
res = self._prepare_resource()
|
|
||||||
res.client().alarms.get.side_effect = Exception('Boom')
|
|
||||||
|
|
||||||
self.assertRaises(exception.ResourceFailure,
|
|
||||||
scheduler.TaskRunner(res.check))
|
|
||||||
self.assertEqual((res.CHECK, res.FAILED), res.state)
|
|
||||||
self.assertIn('Boom', res.status_reason)
|
|
||||||
|
|
||||||
def test_show_resource(self):
|
|
||||||
res = self._prepare_resource(for_check=False)
|
|
||||||
res.client().alarms.create.return_value = mock.MagicMock(
|
|
||||||
alarm_id='2')
|
|
||||||
res.client().alarms.get.return_value = FakeCombinationAlarm()
|
|
||||||
scheduler.TaskRunner(res.create)()
|
|
||||||
self.assertEqual({'attr': 'val'}, res.FnGetAtt('show'))
|
|
||||||
|
|
||||||
|
|
||||||
class EventAlarmTest(common.HeatTestCase):
|
class EventAlarmTest(common.HeatTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(EventAlarmTest, self).setUp()
|
super(EventAlarmTest, self).setUp()
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
critical:
|
||||||
|
- Since Aodh drop support for combination alarm, therefore
|
||||||
|
OS::Aodh::CombinationAlarm is now mark as hidden resource with
|
||||||
|
directly inheriting from None resource which will make the
|
||||||
|
resource do nothing when handling any actions (other than delete).
|
||||||
|
And please don't use it. Old resource which created with that
|
||||||
|
resource type still able to delete. It's recommand to switch
|
||||||
|
that resource type ASAP, since we will remove that resource
|
||||||
|
soon.
|
Loading…
Reference in New Issue
Block a user