"Fossies" - the Fresh Open Source Software Archive

Member "openstack-heat-13.0.0/heat/tests/openstack/aodh/test_alarm.py" (16 Oct 2019, 31475 Bytes) of package /linux/misc/openstack/openstack-heat-13.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_alarm.py": 12.0.0_vs_13.0.0.

    1 
    2 #
    3 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    4 #    not use this file except in compliance with the License. You may obtain
    5 #    a copy of the License at
    6 #
    7 #         http://www.apache.org/licenses/LICENSE-2.0
    8 #
    9 #    Unless required by applicable law or agreed to in writing, software
   10 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   11 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   12 #    License for the specific language governing permissions and limitations
   13 #    under the License.
   14 
   15 import copy
   16 import json
   17 
   18 import mock
   19 import six
   20 
   21 from heat.common import exception
   22 from heat.common import template_format
   23 from heat.engine.clients.os import aodh
   24 from heat.engine.clients.os import octavia
   25 from heat.engine import resource
   26 from heat.engine.resources.openstack.aodh import alarm
   27 from heat.engine import rsrc_defn
   28 from heat.engine import scheduler
   29 from heat.engine import stack as parser
   30 from heat.engine import template as tmpl
   31 from heat.tests import common
   32 from heat.tests import utils
   33 
   34 
   35 alarm_template = '''
   36 {
   37   "AWSTemplateFormatVersion" : "2010-09-09",
   38   "Description" : "Alarm Test",
   39   "Parameters" : {},
   40   "Resources" : {
   41     "MEMAlarmHigh": {
   42      "Type": "OS::Aodh::Alarm",
   43      "Properties": {
   44         "description": "Scale-up if MEM > 50% for 1 minute",
   45         "meter_name": "MemoryUtilization",
   46         "statistic": "avg",
   47         "period": "60",
   48         "evaluation_periods": "1",
   49         "threshold": "50",
   50         "alarm_actions": [],
   51         "matching_metadata": {},
   52         "comparison_operator": "gt",
   53       }
   54     },
   55     "signal_handler" : {
   56       "Type" : "SignalResourceType"
   57     }
   58   }
   59 }
   60 '''
   61 
   62 alarm_template_with_time_constraints = '''
   63 {
   64   "AWSTemplateFormatVersion" : "2010-09-09",
   65   "Description" : "Alarm Test",
   66   "Parameters" : {},
   67   "Resources" : {
   68     "MEMAlarmHigh": {
   69      "Type": "OS::Aodh::Alarm",
   70      "Properties": {
   71         "description": "Scale-up if MEM > 50% for 1 minute",
   72         "meter_name": "MemoryUtilization",
   73         "statistic": "avg",
   74         "period": "60",
   75         "evaluation_periods": "1",
   76         "threshold": "50",
   77         "alarm_actions": [],
   78         "matching_metadata": {},
   79         "comparison_operator": "gt",
   80         "time_constraints":
   81         [{"name": "tc1",
   82         "start": "0 23 * * *",
   83         "timezone": "Asia/Taipei",
   84         "duration": 10800,
   85         "description": "a description"
   86         }]
   87       }
   88     },
   89     "signal_handler" : {
   90       "Type" : "SignalResourceType"
   91     }
   92   }
   93 }
   94 '''
   95 
   96 not_string_alarm_template = '''
   97 {
   98   "AWSTemplateFormatVersion" : "2010-09-09",
   99   "Description" : "Alarm Test",
  100   "Parameters" : {},
  101   "Resources" : {
  102     "MEMAlarmHigh": {
  103      "Type": "OS::Aodh::Alarm",
  104      "Properties": {
  105         "description": "Scale-up if MEM > 50% for 1 minute",
  106         "meter_name": "MemoryUtilization",
  107         "statistic": "avg",
  108         "period": 60,
  109         "evaluation_periods": 1,
  110         "threshold": 50,
  111         "alarm_actions": [],
  112         "matching_metadata": {},
  113         "comparison_operator": "gt",
  114       }
  115     },
  116     "signal_handler" : {
  117       "Type" : "SignalResourceType"
  118     }
  119   }
  120 }
  121 '''
  122 
  123 event_alarm_template = '''
  124 {
  125   "heat_template_version" : "newton",
  126   "description" : "Event alarm test",
  127   "parameters" : {},
  128   "resources" : {
  129     "test_event_alarm": {
  130      "type": "OS::Aodh::EventAlarm",
  131      "properties": {
  132         "description": "Alarm event when an image is updated",
  133         "event_type": "image.update",
  134         "query": [{
  135           "field": 'traits.resource_id',
  136           "op": "eq",
  137           "value": "9a8fec25-1ba6-4170-aa44-5d72f17c07f6"}]
  138       }
  139     },
  140     "signal_handler" : {
  141       "type" : "SignalResourceType"
  142     }
  143   }
  144 }
  145 '''
  146 
  147 lbmemberhealth_alarm_template = '''
  148 {
  149   "heat_template_version" : "newton",
  150   "description" : "Loadbalancer member health alarm test",
  151   "parameters" : {},
  152   "resources" : {
  153     "test_loadbalancer_member_health_alarm": {
  154         "type": "OS::Aodh::LBMemberHealthAlarm",
  155         "properties": {
  156             "description": "Something something dark side",
  157             "alarm_actions": ["trust+heat://"],
  158             "repeat_actions": false,
  159             "pool": "12345",
  160             "stack": "13579",
  161             "autoscaling_group_id": "02468"
  162         }
  163     },
  164     "signal_handler" : {
  165       "type" : "SignalResourceType"
  166     }
  167   }
  168 }
  169 '''
  170 
  171 FakeAodhAlarm = {'other_attrs': 'val',
  172                  'alarm_id': 'foo'}
  173 
  174 
  175 class AodhAlarmTest(common.HeatTestCase):
  176     def setUp(self):
  177         super(AodhAlarmTest, self).setUp()
  178         self.fa = mock.Mock()
  179 
  180     def create_stack(self, template=None, time_constraints=None):
  181         if template is None:
  182             template = alarm_template
  183         temp = template_format.parse(template)
  184         template = tmpl.Template(temp)
  185         ctx = utils.dummy_context()
  186         ctx.tenant = 'test_tenant'
  187         stack = parser.Stack(ctx, utils.random_name(), template,
  188                              disable_rollback=True)
  189         stack.store()
  190 
  191         self.patchobject(aodh.AodhClientPlugin,
  192                          '_create').return_value = self.fa
  193 
  194         al = copy.deepcopy(temp['Resources']['MEMAlarmHigh']['Properties'])
  195         al['time_constraints'] = time_constraints if time_constraints else []
  196 
  197         self.patchobject(self.fa.alarm, 'create').return_value = FakeAodhAlarm
  198 
  199         return stack
  200 
  201     def test_mem_alarm_high_update_no_replace(self):
  202         """Tests update updatable properties without replacing the Alarm."""
  203 
  204         # short circuit the alarm's references
  205         t = template_format.parse(alarm_template)
  206         properties = t['Resources']['MEMAlarmHigh']['Properties']
  207         properties['alarm_actions'] = ['signal_handler']
  208         properties['matching_metadata'] = {'a': 'v'}
  209         properties['query'] = [dict(field='b', op='eq', value='w')]
  210 
  211         test_stack = self.create_stack(template=json.dumps(t))
  212 
  213         update_mock = self.patchobject(self.fa.alarm, 'update')
  214 
  215         test_stack.create()
  216         rsrc = test_stack['MEMAlarmHigh']
  217 
  218         update_props = copy.deepcopy(rsrc.properties.data)
  219         update_props.update({
  220             'comparison_operator': 'lt',
  221             'description': 'fruity',
  222             'evaluation_periods': '2',
  223             'period': '90',
  224             'enabled': True,
  225             'repeat_actions': True,
  226             'statistic': 'max',
  227             'threshold': '39',
  228             'insufficient_data_actions': [],
  229             'alarm_actions': [],
  230             'ok_actions': ['signal_handler'],
  231             'matching_metadata': {'x': 'y'},
  232             'query': [dict(field='c', op='ne', value='z')]
  233         })
  234 
  235         snippet = rsrc_defn.ResourceDefinition(rsrc.name,
  236                                                rsrc.type(),
  237                                                update_props)
  238 
  239         scheduler.TaskRunner(rsrc.update, snippet)()
  240 
  241         self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
  242         self.assertEqual(1, update_mock.call_count)
  243 
  244     def test_mem_alarm_high_update_replace(self):
  245         """Tests resource replacing when changing non-updatable properties."""
  246 
  247         t = template_format.parse(alarm_template)
  248         properties = t['Resources']['MEMAlarmHigh']['Properties']
  249         properties['alarm_actions'] = ['signal_handler']
  250         properties['matching_metadata'] = {'a': 'v'}
  251 
  252         test_stack = self.create_stack(template=json.dumps(t))
  253 
  254         test_stack.create()
  255         rsrc = test_stack['MEMAlarmHigh']
  256 
  257         properties = copy.copy(rsrc.properties.data)
  258         properties['meter_name'] = 'temp'
  259         snippet = rsrc_defn.ResourceDefinition(rsrc.name,
  260                                                rsrc.type(),
  261                                                properties)
  262 
  263         updater = scheduler.TaskRunner(rsrc.update, snippet)
  264         self.assertRaises(resource.UpdateReplace, updater)
  265 
  266     def test_mem_alarm_suspend_resume(self):
  267         """Tests suspending and resuming of the alarm.
  268 
  269         Make sure that the Alarm resource gets disabled on suspend
  270         and re-enabled on resume.
  271         """
  272         test_stack = self.create_stack()
  273 
  274         update_mock = self.patchobject(self.fa.alarm, 'update')
  275         al_suspend = {'enabled': False}
  276         al_resume = {'enabled': True}
  277 
  278         test_stack.create()
  279         rsrc = test_stack['MEMAlarmHigh']
  280         scheduler.TaskRunner(rsrc.suspend)()
  281         self.assertEqual((rsrc.SUSPEND, rsrc.COMPLETE), rsrc.state)
  282         scheduler.TaskRunner(rsrc.resume)()
  283         self.assertEqual((rsrc.RESUME, rsrc.COMPLETE), rsrc.state)
  284 
  285         update_mock.assert_has_calls((
  286             mock.call('foo', al_suspend),
  287             mock.call('foo', al_resume)))
  288 
  289     def test_mem_alarm_high_correct_int_parameters(self):
  290         test_stack = self.create_stack(not_string_alarm_template)
  291 
  292         test_stack.create()
  293         rsrc = test_stack['MEMAlarmHigh']
  294         self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
  295         self.assertIsNone(rsrc.validate())
  296 
  297         self.assertIsInstance(rsrc.properties['evaluation_periods'], int)
  298         self.assertIsInstance(rsrc.properties['period'], int)
  299         self.assertIsInstance(rsrc.properties['threshold'], int)
  300 
  301     def test_alarm_metadata_prefix(self):
  302         t = template_format.parse(alarm_template)
  303         properties = t['Resources']['MEMAlarmHigh']['Properties']
  304         # Test for bug/1383521, where meter_name is in NOVA_METERS
  305         properties[alarm.AodhAlarm.METER_NAME] = 'memory.usage'
  306         properties['matching_metadata'] = {'metadata.user_metadata.groupname':
  307                                            'foo'}
  308 
  309         test_stack = self.create_stack(template=json.dumps(t))
  310 
  311         rsrc = test_stack['MEMAlarmHigh']
  312         rsrc.properties.data = rsrc.get_alarm_props(properties)
  313         self.assertIsNone(rsrc.properties.data.get('matching_metadata'))
  314         query = rsrc.properties.data['threshold_rule']['query']
  315         expected_query = [{'field': u'metadata.user_metadata.groupname',
  316                            'value': u'foo', 'op': 'eq'}]
  317         self.assertEqual(expected_query, query)
  318 
  319     def test_alarm_metadata_correct_query_key(self):
  320         t = template_format.parse(alarm_template)
  321         properties = t['Resources']['MEMAlarmHigh']['Properties']
  322         # Test that meter_name is not in NOVA_METERS
  323         properties[alarm.AodhAlarm.METER_NAME] = 'memory_util'
  324         properties['matching_metadata'] = {'metadata.user_metadata.groupname':
  325                                            'foo'}
  326         self.stack = self.create_stack(template=json.dumps(t))
  327 
  328         rsrc = self.stack['MEMAlarmHigh']
  329         rsrc.properties.data = rsrc.get_alarm_props(properties)
  330         self.assertIsNone(rsrc.properties.data.get('matching_metadata'))
  331         query = rsrc.properties.data['threshold_rule']['query']
  332         expected_query = [{'field': u'metadata.metering.groupname',
  333                            'value': u'foo', 'op': 'eq'}]
  334         self.assertEqual(expected_query, query)
  335 
  336     def test_mem_alarm_high_correct_matching_metadata(self):
  337         t = template_format.parse(alarm_template)
  338         properties = t['Resources']['MEMAlarmHigh']['Properties']
  339         properties['matching_metadata'] = {'fro': 'bar',
  340                                            'bro': True,
  341                                            'dro': 1234,
  342                                            'pro': '{"Mem": {"Ala": {"Hig"}}}',
  343                                            'tro': [1, 2, 3, 4]}
  344 
  345         test_stack = self.create_stack(template=json.dumps(t))
  346 
  347         test_stack.create()
  348         rsrc = test_stack['MEMAlarmHigh']
  349         self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
  350         rsrc.properties.data = rsrc.get_alarm_props(properties)
  351         self.assertIsNone(rsrc.properties.data.get('matching_metadata'))
  352         for key in rsrc.properties.data['threshold_rule']['query']:
  353             self.assertIsInstance(key['value'], six.text_type)
  354 
  355     def test_no_matching_metadata(self):
  356         """Make sure that we can pass in an empty matching_metadata."""
  357 
  358         t = template_format.parse(alarm_template)
  359         properties = t['Resources']['MEMAlarmHigh']['Properties']
  360         properties['alarm_actions'] = ['signal_handler']
  361         del properties['matching_metadata']
  362 
  363         test_stack = self.create_stack(template=json.dumps(t))
  364 
  365         test_stack.create()
  366         rsrc = test_stack['MEMAlarmHigh']
  367         self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
  368         self.assertIsNone(rsrc.validate())
  369 
  370     def test_mem_alarm_high_not_correct_string_parameters(self):
  371         orig_snippet = template_format.parse(not_string_alarm_template)
  372         for p in ('period', 'evaluation_periods'):
  373             snippet = copy.deepcopy(orig_snippet)
  374             snippet['Resources']['MEMAlarmHigh']['Properties'][p] = '60a'
  375             stack = utils.parse_stack(snippet)
  376 
  377             resource_defns = stack.t.resource_definitions(stack)
  378             rsrc = alarm.AodhAlarm(
  379                 'MEMAlarmHigh', resource_defns['MEMAlarmHigh'], stack)
  380             error = self.assertRaises(exception.StackValidationFailed,
  381                                       rsrc.validate)
  382             self.assertEqual(
  383                 "Property error: Resources.MEMAlarmHigh.Properties.%s: "
  384                 "Value '60a' is not an integer" % p, six.text_type(error))
  385 
  386     def test_mem_alarm_high_not_integer_parameters(self):
  387         orig_snippet = template_format.parse(not_string_alarm_template)
  388         for p in ('period', 'evaluation_periods'):
  389             snippet = copy.deepcopy(orig_snippet)
  390             snippet['Resources']['MEMAlarmHigh']['Properties'][p] = [60]
  391             stack = utils.parse_stack(snippet)
  392 
  393             resource_defns = stack.t.resource_definitions(stack)
  394             rsrc = alarm.AodhAlarm(
  395                 'MEMAlarmHigh', resource_defns['MEMAlarmHigh'], stack)
  396             # python 3.4.3 returns another error message
  397             # so try to handle this by regexp
  398             msg = ("Property error: Resources.MEMAlarmHigh.Properties.%s: "
  399                    r"int\(\) argument must be a string"
  400                    "(, a bytes-like object)?"
  401                    " or a number, not 'list'" % p)
  402             self.assertRaisesRegex(exception.StackValidationFailed,
  403                                    msg, rsrc.validate)
  404 
  405     def test_mem_alarm_high_check_not_required_parameters(self):
  406         snippet = template_format.parse(not_string_alarm_template)
  407         snippet['Resources']['MEMAlarmHigh']['Properties'].pop('meter_name')
  408         stack = utils.parse_stack(snippet)
  409 
  410         resource_defns = stack.t.resource_definitions(stack)
  411         rsrc = alarm.AodhAlarm(
  412             'MEMAlarmHigh', resource_defns['MEMAlarmHigh'], stack)
  413         error = self.assertRaises(exception.StackValidationFailed,
  414                                   rsrc.validate)
  415         self.assertEqual(
  416             "Property error: Resources.MEMAlarmHigh.Properties: "
  417             "Property meter_name not assigned",
  418             six.text_type(error))
  419 
  420         for p in ('period', 'evaluation_periods', 'statistic',
  421                   'comparison_operator'):
  422             snippet = template_format.parse(not_string_alarm_template)
  423             snippet['Resources']['MEMAlarmHigh']['Properties'].pop(p)
  424             stack = utils.parse_stack(snippet)
  425 
  426             resource_defns = stack.t.resource_definitions(stack)
  427             rsrc = alarm.AodhAlarm(
  428                 'MEMAlarmHigh', resource_defns['MEMAlarmHigh'], stack)
  429             self.assertIsNone(rsrc.validate())
  430 
  431     def _prepare_resource(self, for_check=True):
  432         snippet = template_format.parse(not_string_alarm_template)
  433         self.stack = utils.parse_stack(snippet)
  434         res = self.stack['MEMAlarmHigh']
  435         if for_check:
  436             res.state_set(res.CREATE, res.COMPLETE)
  437         res.client = mock.Mock()
  438         mock_alarm = mock.Mock(enabled=True, state='ok')
  439         res.client().alarm.get.return_value = mock_alarm
  440         return res
  441 
  442     def test_check(self):
  443         res = self._prepare_resource()
  444         scheduler.TaskRunner(res.check)()
  445         self.assertEqual((res.CHECK, res.COMPLETE), res.state)
  446 
  447     def test_check_alarm_failure(self):
  448         res = self._prepare_resource()
  449         res.client().alarm.get.side_effect = Exception('Boom')
  450 
  451         self.assertRaises(exception.ResourceFailure,
  452                           scheduler.TaskRunner(res.check))
  453         self.assertEqual((res.CHECK, res.FAILED), res.state)
  454         self.assertIn('Boom', res.status_reason)
  455 
  456     def test_show_resource(self):
  457         res = self._prepare_resource(for_check=False)
  458         res.client().alarm.create.return_value = FakeAodhAlarm
  459         res.client().alarm.get.return_value = FakeAodhAlarm
  460         scheduler.TaskRunner(res.create)()
  461         self.assertEqual(FakeAodhAlarm, res.FnGetAtt('show'))
  462 
  463     def test_alarm_with_wrong_start_time(self):
  464         t = template_format.parse(alarm_template_with_time_constraints)
  465         time_constraints = [{"name": "tc1",
  466                              "start": "0 23 * * *",
  467                              "timezone": "Asia/Taipei",
  468                              "duration": 10800,
  469                              "description": "a description"
  470                              }]
  471         test_stack = self.create_stack(template=json.dumps(t),
  472                                        time_constraints=time_constraints)
  473         test_stack.create()
  474         self.assertEqual((test_stack.CREATE, test_stack.COMPLETE),
  475                          test_stack.state)
  476 
  477         rsrc = test_stack['MEMAlarmHigh']
  478 
  479         properties = copy.copy(rsrc.properties.data)
  480         start_time = '* * * * * 100'
  481         properties.update({
  482             'comparison_operator': 'lt',
  483             'description': 'fruity',
  484             'evaluation_periods': '2',
  485             'period': '90',
  486             'enabled': True,
  487             'repeat_actions': True,
  488             'statistic': 'max',
  489             'threshold': '39',
  490             'insufficient_data_actions': [],
  491             'alarm_actions': [],
  492             'ok_actions': ['signal_handler'],
  493             'matching_metadata': {'x': 'y'},
  494             'query': [dict(field='c', op='ne', value='z')],
  495             'time_constraints': [{"name": "tc1",
  496                                   "start": start_time,
  497                                   "timezone": "Asia/Taipei",
  498                                   "duration": 10800,
  499                                   "description": "a description"
  500                                   }]
  501         })
  502         snippet = rsrc_defn.ResourceDefinition(rsrc.name,
  503                                                rsrc.type(),
  504                                                properties)
  505         error = self.assertRaises(
  506             exception.ResourceFailure,
  507             scheduler.TaskRunner(rsrc.update, snippet)
  508         )
  509         self.assertEqual(
  510             "StackValidationFailed: resources.MEMAlarmHigh: Property error: "
  511             "Properties.time_constraints[0].start: Error "
  512             "validating value '%s': Invalid CRON expression: "
  513             "[%s] is not acceptable, out of range" % (start_time, start_time),
  514             error.message)
  515 
  516     def test_alarm_with_wrong_timezone(self):
  517         t = template_format.parse(alarm_template_with_time_constraints)
  518         time_constraints = [{"name": "tc1",
  519                              "start": "0 23 * * *",
  520                              "timezone": "Asia/Taipei",
  521                              "duration": 10800,
  522                              "description": "a description"
  523                              }]
  524         test_stack = self.create_stack(template=json.dumps(t),
  525                                        time_constraints=time_constraints)
  526         test_stack.create()
  527         self.assertEqual((test_stack.CREATE, test_stack.COMPLETE),
  528                          test_stack.state)
  529 
  530         rsrc = test_stack['MEMAlarmHigh']
  531 
  532         properties = copy.copy(rsrc.properties.data)
  533         timezone = 'wrongtimezone'
  534         properties.update({
  535             'comparison_operator': 'lt',
  536             'description': 'fruity',
  537             'evaluation_periods': '2',
  538             'period': '90',
  539             'enabled': True,
  540             'repeat_actions': True,
  541             'statistic': 'max',
  542             'threshold': '39',
  543             'insufficient_data_actions': [],
  544             'alarm_actions': [],
  545             'ok_actions': ['signal_handler'],
  546             'matching_metadata': {'x': 'y'},
  547             'query': [dict(field='c', op='ne', value='z')],
  548             'time_constraints': [{"name": "tc1",
  549                                   "start": "0 23 * * *",
  550                                   "timezone": timezone,
  551                                   "duration": 10800,
  552                                   "description": "a description"
  553                                   }]
  554         })
  555         snippet = rsrc_defn.ResourceDefinition(rsrc.name,
  556                                                rsrc.type(),
  557                                                properties)
  558         error = self.assertRaises(
  559             exception.ResourceFailure,
  560             scheduler.TaskRunner(rsrc.update, snippet)
  561         )
  562         self.assertEqual(
  563             "StackValidationFailed: resources.MEMAlarmHigh: Property error: "
  564             "Properties.time_constraints[0].timezone: Error "
  565             "validating value '%s': Invalid timezone: '%s'"
  566             % (timezone, timezone),
  567             error.message)
  568 
  569     def test_alarm_live_state(self):
  570         snippet = template_format.parse(alarm_template)
  571         self.stack = utils.parse_stack(snippet)
  572         resource_defns = self.stack.t.resource_definitions(self.stack)
  573         self.rsrc_defn = resource_defns['MEMAlarmHigh']
  574         self.client = mock.Mock()
  575         self.patchobject(alarm.AodhAlarm, 'client',
  576                          return_value=self.client)
  577 
  578         alarm_res = alarm.AodhAlarm('alarm', self.rsrc_defn, self.stack)
  579         alarm_res.create()
  580         value = {
  581             'description': 'Scale-up if MEM > 50% for 1 minute',
  582             'alarm_actions': [],
  583             'time_constraints': [],
  584             'threshold_rule': {
  585                 'meter_name': 'MemoryUtilization',
  586                 'statistic': 'avg',
  587                 'period': '60',
  588                 'evaluation_periods': '1',
  589                 'threshold': '50',
  590                 'matching_metadata': {},
  591                 'comparison_operator': 'gt',
  592                 'query': [{'field': 'c', 'op': 'ne', 'value': 'z'}]
  593             }
  594         }
  595         self.client.alarm.get.return_value = value
  596         expected_data = {
  597             'description': 'Scale-up if MEM > 50% for 1 minute',
  598             'alarm_actions': [],
  599             'statistic': 'avg',
  600             'period': '60',
  601             'evaluation_periods': '1',
  602             'threshold': '50',
  603             'matching_metadata': {},
  604             'comparison_operator': 'gt',
  605             'query': [{'field': 'c', 'op': 'ne', 'value': 'z'}],
  606             'repeat_actions': None,
  607             'ok_actions': None,
  608             'insufficient_data_actions': None,
  609             'severity': None,
  610             'enabled': None
  611         }
  612         reality = alarm_res.get_live_state(alarm_res.properties)
  613         self.assertEqual(expected_data, reality)
  614 
  615     def test_queue_actions(self):
  616         stack = self.create_stack()
  617         alarm = stack['MEMAlarmHigh']
  618 
  619         props = {
  620             'alarm_actions': ['http://example.com/test'],
  621             'alarm_queues': ['alarm_queue'],
  622             'ok_actions': [],
  623             'ok_queues': ['ok_queue_1', 'ok_queue_2'],
  624             'insufficient_data_actions': ['http://example.com/test2',
  625                                           'http://example.com/test3'],
  626             'insufficient_data_queues': ['nodata_queue'],
  627         }
  628 
  629         expected = {
  630             'alarm_actions': ['http://example.com/test',
  631                               'trust+zaqar://?queue_name=alarm_queue'],
  632             'ok_actions': ['trust+zaqar://?queue_name=ok_queue_1',
  633                            'trust+zaqar://?queue_name=ok_queue_2'],
  634             'insufficient_data_actions': [
  635                 'http://example.com/test2',
  636                 'http://example.com/test3',
  637                 'trust+zaqar://?queue_name=nodata_queue'
  638             ],
  639         }
  640 
  641         self.assertEqual(expected, alarm.actions_to_urls(props))
  642 
  643 
  644 class EventAlarmTest(common.HeatTestCase):
  645     def setUp(self):
  646         super(EventAlarmTest, self).setUp()
  647         self.fa = mock.Mock()
  648 
  649     def create_stack(self, template=None):
  650         if template is None:
  651             template = event_alarm_template
  652         temp = template_format.parse(template)
  653         template = tmpl.Template(temp)
  654         ctx = utils.dummy_context()
  655         ctx.tenant = 'test_tenant'
  656         stack = parser.Stack(ctx, utils.random_name(), template,
  657                              disable_rollback=True)
  658         stack.store()
  659 
  660         self.patchobject(aodh.AodhClientPlugin,
  661                          '_create').return_value = self.fa
  662 
  663         self.patchobject(self.fa.alarm, 'create').return_value = FakeAodhAlarm
  664 
  665         return stack
  666 
  667     def test_update(self):
  668         test_stack = self.create_stack()
  669         update_mock = self.patchobject(self.fa.alarm, 'update')
  670         test_stack.create()
  671         rsrc = test_stack['test_event_alarm']
  672 
  673         update_props = copy.deepcopy(rsrc.properties.data)
  674         update_props.update({
  675             'enabled': True,
  676             'insufficient_data_actions': [],
  677             'alarm_actions': [],
  678             'ok_actions': ['signal_handler'],
  679             'query': [dict(
  680                 field='traits.resource_id',
  681                 op='eq',
  682                 value='c7405b0f-139f-4fbd-9348-f32dfc5674ac')]
  683         })
  684 
  685         snippet = rsrc_defn.ResourceDefinition(rsrc.name,
  686                                                rsrc.type(),
  687                                                update_props)
  688 
  689         scheduler.TaskRunner(rsrc.update, snippet)()
  690 
  691         self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
  692         self.assertEqual(1, update_mock.call_count)
  693 
  694     def test_delete(self):
  695         test_stack = self.create_stack()
  696         rsrc = test_stack['test_event_alarm']
  697 
  698         self.patchobject(aodh.AodhClientPlugin, 'client',
  699                          return_value=self.fa)
  700         self.patchobject(self.fa.alarm, 'delete')
  701         rsrc.resource_id = '12345'
  702 
  703         self.assertEqual('12345', rsrc.handle_delete())
  704         self.assertEqual(1, self.fa.alarm.delete.call_count)
  705 
  706     def _prepare_resource(self, for_check=True):
  707         snippet = template_format.parse(event_alarm_template)
  708         self.stack = utils.parse_stack(snippet)
  709         res = self.stack['test_event_alarm']
  710         if for_check:
  711             res.state_set(res.CREATE, res.COMPLETE)
  712         res.client = mock.Mock()
  713         mock_alarm = mock.Mock(enabled=True, state='ok')
  714         res.client().alarm.get.return_value = mock_alarm
  715         return res
  716 
  717     def test_check(self):
  718         res = self._prepare_resource()
  719         scheduler.TaskRunner(res.check)()
  720         self.assertEqual((res.CHECK, res.COMPLETE), res.state)
  721 
  722     def test_check_alarm_failure(self):
  723         res = self._prepare_resource()
  724         res.client().alarm.get.side_effect = Exception('Boom')
  725 
  726         self.assertRaises(exception.ResourceFailure,
  727                           scheduler.TaskRunner(res.check))
  728         self.assertEqual((res.CHECK, res.FAILED), res.state)
  729         self.assertIn('Boom', res.status_reason)
  730 
  731     def test_show_resource(self):
  732         res = self._prepare_resource(for_check=False)
  733         res.client().alarm.create.return_value = FakeAodhAlarm
  734         res.client().alarm.get.return_value = FakeAodhAlarm
  735         scheduler.TaskRunner(res.create)()
  736         self.assertEqual(FakeAodhAlarm, res.FnGetAtt('show'))
  737 
  738 
  739 class LBMemberHealthAlarmTest(common.HeatTestCase):
  740 
  741     def setUp(self):
  742         super(LBMemberHealthAlarmTest, self).setUp()
  743         self.fa = mock.Mock()
  744         self.patchobject(
  745             octavia.OctaviaClientPlugin, 'get_pool').return_value = "9999"
  746 
  747     def create_stack(self, template=None):
  748 
  749         if template is None:
  750             template = lbmemberhealth_alarm_template
  751         temp = template_format.parse(template)
  752         template = tmpl.Template(temp)
  753         ctx = utils.dummy_context()
  754         ctx.tenant = 'test_tenant'
  755         stack = parser.Stack(ctx, utils.random_name(), template,
  756                              disable_rollback=True)
  757         stack.store()
  758 
  759         self.patchobject(aodh.AodhClientPlugin,
  760                          '_create').return_value = self.fa
  761 
  762         self.patchobject(self.fa.alarm, 'create').return_value = FakeAodhAlarm
  763         return stack
  764 
  765     def _prepare_resource(self, for_check=True):
  766 
  767         snippet = template_format.parse(lbmemberhealth_alarm_template)
  768         self.stack = utils.parse_stack(snippet)
  769         res = self.stack['test_loadbalancer_member_health_alarm']
  770         if for_check:
  771             res.state_set(res.CREATE, res.COMPLETE)
  772         res.client = mock.Mock()
  773         mock_alarm = mock.Mock(enabled=True, state='ok')
  774         res.client().alarm.get.return_value = mock_alarm
  775         return res
  776 
  777     def test_delete(self):
  778         test_stack = self.create_stack()
  779         rsrc = test_stack['test_loadbalancer_member_health_alarm']
  780 
  781         self.patchobject(aodh.AodhClientPlugin, 'client',
  782                          return_value=self.fa)
  783         self.patchobject(self.fa.alarm, 'delete')
  784         rsrc.resource_id = '12345'
  785 
  786         self.assertEqual('12345', rsrc.handle_delete())
  787         self.assertEqual(1, self.fa.alarm.delete.call_count)
  788 
  789     def test_check(self):
  790         res = self._prepare_resource()
  791         scheduler.TaskRunner(res.check)()
  792         self.assertEqual((res.CHECK, res.COMPLETE), res.state)
  793 
  794     def test_check_alarm_failure(self):
  795         res = self._prepare_resource()
  796         res.client().alarm.get.side_effect = Exception('Boom')
  797 
  798         self.assertRaises(exception.ResourceFailure,
  799                           scheduler.TaskRunner(res.check))
  800         self.assertEqual((res.CHECK, res.FAILED), res.state)
  801         self.assertIn('Boom', res.status_reason)
  802 
  803     def test_show_resource(self):
  804         res = self._prepare_resource(for_check=False)
  805         res.client().alarm.create.return_value = FakeAodhAlarm
  806         res.client().alarm.get.return_value = FakeAodhAlarm
  807         scheduler.TaskRunner(res.create)()
  808         self.assertEqual(FakeAodhAlarm, res.FnGetAtt('show'))
  809 
  810     def test_update(self):
  811         test_stack = self.create_stack()
  812         update_mock = self.patchobject(self.fa.alarm, 'update')
  813         test_stack.create()
  814         rsrc = test_stack['test_loadbalancer_member_health_alarm']
  815 
  816         update_props = copy.deepcopy(rsrc.properties.data)
  817         update_props.update({
  818             "enabled": True,
  819             "description": "",
  820             "insufficient_data_actions": [],
  821             "alarm_actions": [],
  822             "ok_actions": ["signal_handler"],
  823             "pool": "0000",
  824             "autoscaling_group_id": "2222"
  825         })
  826 
  827         snippet = rsrc_defn.ResourceDefinition(rsrc.name,
  828                                                rsrc.type(),
  829                                                update_props)
  830 
  831         scheduler.TaskRunner(rsrc.update, snippet)()
  832 
  833         self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
  834         self.assertEqual(1, update_mock.call_count)