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:
ricolin 2017-03-08 16:26:20 +08:00
parent 8ddd903b03
commit 14903dc1cd
3 changed files with 21 additions and 233 deletions

View File

@ -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.

View File

@ -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()

View File

@ -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.