0ae9ba1fa9
Change-Id: Ic7d4d152c529b29fa1e07cf865181f623d6744b8 Implements: blueprint mox-to-mock-conversion
979 lines
39 KiB
Python
979 lines
39 KiB
Python
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
|
|
import datetime
|
|
|
|
import mock
|
|
from oslo_utils import timeutils
|
|
|
|
from heat.common import exception
|
|
from heat.engine import stack
|
|
from heat.engine import template
|
|
from heat.engine import watchrule
|
|
from heat.objects import watch_rule
|
|
from heat.tests import common
|
|
from heat.tests import utils
|
|
|
|
|
|
class WatchData(object):
|
|
def __init__(self, data, created_at):
|
|
self.created_at = created_at
|
|
self.data = {'test_metric': {'Value': data,
|
|
'Unit': 'Count'}}
|
|
|
|
|
|
class DummyAction(object):
|
|
signal = "DummyAction"
|
|
|
|
|
|
class WatchRuleTest(common.HeatTestCase):
|
|
stack_id = None
|
|
|
|
def setUp(self):
|
|
super(WatchRuleTest, self).setUp()
|
|
|
|
self.username = 'watchrule_test_user'
|
|
self.ctx = utils.dummy_context()
|
|
self.ctx.auth_token = 'abcd1234'
|
|
|
|
self._setup_database()
|
|
|
|
def _setup_database(self):
|
|
if self.stack_id is not None:
|
|
return
|
|
# Create a dummy stack in the DB as WatchRule instances
|
|
# must be associated with a stack
|
|
empty_tmpl = {'HeatTemplateFormatVersion': '2012-12-12'}
|
|
tmpl = template.Template(empty_tmpl)
|
|
stack_name = 'dummystack'
|
|
dummy_stack = stack.Stack(self.ctx, stack_name, tmpl)
|
|
dummy_stack.state_set(dummy_stack.CREATE, dummy_stack.COMPLETE,
|
|
'Testing')
|
|
dummy_stack.store()
|
|
|
|
self.stack_id = dummy_stack.id
|
|
|
|
def _setup_action_mocks(self, mock_get_resource, now,
|
|
action_expected=True):
|
|
"""Setup stubs for the action tests."""
|
|
timeutils.set_time_override(now)
|
|
self.addCleanup(timeutils.clear_time_override)
|
|
|
|
if action_expected:
|
|
dummy_action = DummyAction()
|
|
mock_get_resource.return_value = dummy_action
|
|
|
|
def test_minimum(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'Period': '300',
|
|
'Statistic': 'Minimum',
|
|
'ComparisonOperator': 'LessThanOrEqualToThreshold',
|
|
'Threshold': '50'}
|
|
|
|
now = timeutils.utcnow()
|
|
last = now - datetime.timedelta(seconds=320)
|
|
data = [WatchData(77, now - datetime.timedelta(seconds=100))]
|
|
|
|
# Test 1 - Values greater than 0 are normal
|
|
data.append(WatchData(53, now - datetime.timedelta(seconds=150)))
|
|
wr = watchrule.WatchRule(self.ctx,
|
|
'testwatch',
|
|
rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('NORMAL', new_state)
|
|
|
|
# Test 2
|
|
data.append(WatchData(25, now - datetime.timedelta(seconds=250)))
|
|
wr = watchrule.WatchRule(self.ctx,
|
|
'testwatch',
|
|
rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('ALARM', new_state)
|
|
|
|
def test_maximum(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
last = now - datetime.timedelta(seconds=320)
|
|
data = [WatchData(7, now - datetime.timedelta(seconds=100))]
|
|
|
|
# Test 1 - values less than 30 are normal
|
|
data.append(WatchData(23, now - datetime.timedelta(seconds=150)))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.now = now
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('NORMAL', new_state)
|
|
|
|
# Test 2
|
|
data.append(WatchData(35, now - datetime.timedelta(seconds=150)))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.now = now
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('ALARM', new_state)
|
|
|
|
def test_samplecount(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'Period': '300',
|
|
'Statistic': 'SampleCount',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '3'}
|
|
|
|
now = timeutils.utcnow()
|
|
last = now - datetime.timedelta(seconds=320)
|
|
data = [WatchData(1, now - datetime.timedelta(seconds=100))]
|
|
|
|
# Test 1 - 2 samples is normal
|
|
data.append(WatchData(1, now - datetime.timedelta(seconds=150)))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.now = now
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('NORMAL', new_state)
|
|
|
|
# Test 2 - 3 samples is an alarm
|
|
data.append(WatchData(1, now - datetime.timedelta(seconds=200)))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.now = now
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('ALARM', new_state)
|
|
|
|
# Test 3 - 3 samples (one old) is normal
|
|
data.pop(0)
|
|
data.append(WatchData(1, now - datetime.timedelta(seconds=400)))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.now = now
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('NORMAL', new_state)
|
|
|
|
def test_sum(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'Period': '300',
|
|
'Statistic': 'Sum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '100'}
|
|
|
|
now = timeutils.utcnow()
|
|
last = now - datetime.timedelta(seconds=320)
|
|
data = [WatchData(17, now - datetime.timedelta(seconds=100))]
|
|
|
|
# Test 1 - values less than 40 are normal
|
|
data.append(WatchData(23, now - datetime.timedelta(seconds=150)))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.now = now
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('NORMAL', new_state)
|
|
|
|
# Test 2 - sum greater than 100 is an alarm
|
|
data.append(WatchData(85, now - datetime.timedelta(seconds=150)))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.now = now
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('ALARM', new_state)
|
|
|
|
def test_average(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'Period': '300',
|
|
'Statistic': 'Average',
|
|
'ComparisonOperator': 'GreaterThanThreshold',
|
|
'Threshold': '100'}
|
|
|
|
now = timeutils.utcnow()
|
|
last = now - datetime.timedelta(seconds=320)
|
|
data = [WatchData(117, now - datetime.timedelta(seconds=100))]
|
|
|
|
# Test 1
|
|
data.append(WatchData(23, now - datetime.timedelta(seconds=150)))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.now = now
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('NORMAL', new_state)
|
|
|
|
# Test 2
|
|
data.append(WatchData(195, now - datetime.timedelta(seconds=250)))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=data,
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.now = now
|
|
new_state = wr.get_alarm_state()
|
|
self.assertEqual('ALARM', new_state)
|
|
|
|
def test_load(self):
|
|
# Setup
|
|
# Insert two dummy watch rules into the DB
|
|
rule = {u'EvaluationPeriods': u'1',
|
|
u'AlarmActions': [u'WebServerRestartPolicy'],
|
|
u'AlarmDescription': u'Restart the WikiDatabase',
|
|
u'Namespace': u'system/linux',
|
|
u'Period': u'300',
|
|
u'ComparisonOperator': u'GreaterThanThreshold',
|
|
u'Statistic': u'SampleCount',
|
|
u'Threshold': u'2',
|
|
u'MetricName': u'ServiceFailure'}
|
|
rules = []
|
|
rules.append(watchrule.WatchRule(context=self.ctx,
|
|
watch_name='HttpFailureAlarm',
|
|
rule=rule,
|
|
watch_data=[],
|
|
stack_id=self.stack_id,
|
|
state='NORMAL'))
|
|
rules[0].store()
|
|
|
|
rules.append(watchrule.WatchRule(context=self.ctx,
|
|
watch_name='AnotherWatch',
|
|
rule=rule,
|
|
watch_data=[],
|
|
stack_id=self.stack_id,
|
|
state='NORMAL'))
|
|
rules[1].store()
|
|
|
|
# Test
|
|
for wn in ('HttpFailureAlarm', 'AnotherWatch'):
|
|
wr = watchrule.WatchRule.load(self.ctx, wn)
|
|
self.assertIsInstance(wr, watchrule.WatchRule)
|
|
self.assertEqual(wn, wr.name)
|
|
self.assertEqual('NORMAL', wr.state)
|
|
self.assertEqual(rule, wr.rule)
|
|
self.assertEqual(datetime.timedelta(seconds=int(rule['Period'])),
|
|
wr.timeperiod)
|
|
|
|
def test_store(self):
|
|
# Setup
|
|
rule = {u'EvaluationPeriods': u'1',
|
|
u'AlarmActions': [u'WebServerRestartPolicy'],
|
|
u'AlarmDescription': u'Restart the WikiDatabase',
|
|
u'Namespace': u'system/linux',
|
|
u'Period': u'300',
|
|
u'ComparisonOperator': u'GreaterThanThreshold',
|
|
u'Statistic': u'SampleCount',
|
|
u'Threshold': u'2',
|
|
u'MetricName': u'ServiceFailure'}
|
|
|
|
# Test
|
|
wr = watchrule.WatchRule(context=self.ctx, watch_name='storetest',
|
|
stack_id=self.stack_id, rule=rule)
|
|
wr.store()
|
|
|
|
# Verify
|
|
dbwr = watch_rule.WatchRule.get_by_name(self.ctx, 'storetest')
|
|
self.assertIsNotNone(dbwr)
|
|
self.assertEqual('storetest', dbwr.name)
|
|
self.assertEqual(watchrule.WatchRule.NODATA, dbwr.state)
|
|
self.assertEqual(rule, dbwr.rule)
|
|
|
|
def test_evaluate(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
timeutils.set_time_override(now)
|
|
self.addCleanup(timeutils.clear_time_override)
|
|
|
|
# Test 1 - It's not time to evaluate, so should stay NODATA
|
|
last = now - datetime.timedelta(seconds=299)
|
|
data = WatchData(25, now - datetime.timedelta(seconds=150))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[data],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
actions = wr.evaluate()
|
|
self.assertEqual('NODATA', wr.state)
|
|
self.assertEqual([], actions)
|
|
|
|
# Test 2 - now - last == Period, so should set NORMAL
|
|
last = now - datetime.timedelta(seconds=300)
|
|
data = WatchData(25, now - datetime.timedelta(seconds=150))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[data],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
actions = wr.evaluate()
|
|
self.assertEqual('NORMAL', wr.state)
|
|
self.assertEqual(now, wr.last_evaluated)
|
|
self.assertEqual([], actions)
|
|
|
|
# Test 3 - Now data breaches Threshold, so should set ALARM
|
|
last = now - datetime.timedelta(seconds=300)
|
|
data = WatchData(35, now - datetime.timedelta(seconds=150))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[data],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
actions = wr.evaluate()
|
|
self.assertEqual('ALARM', wr.state)
|
|
self.assertEqual(now, wr.last_evaluated)
|
|
self.assertEqual([], actions)
|
|
|
|
def test_evaluate_suspend(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
timeutils.set_time_override(now)
|
|
self.addCleanup(timeutils.clear_time_override)
|
|
|
|
last = now - datetime.timedelta(seconds=300)
|
|
data = WatchData(35, now - datetime.timedelta(seconds=150))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[data],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.state_set(wr.SUSPENDED)
|
|
|
|
# Test
|
|
actions = wr.evaluate()
|
|
self.assertEqual(wr.SUSPENDED, wr.state)
|
|
self.assertEqual([], actions)
|
|
|
|
def test_evaluate_ceilometer_controlled(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
timeutils.set_time_override(now)
|
|
self.addCleanup(timeutils.clear_time_override)
|
|
|
|
last = now - datetime.timedelta(seconds=300)
|
|
data = WatchData(35, now - datetime.timedelta(seconds=150))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[data],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
wr.state_set(wr.CEILOMETER_CONTROLLED)
|
|
|
|
# Test
|
|
actions = wr.evaluate()
|
|
self.assertEqual(wr.CEILOMETER_CONTROLLED, wr.state)
|
|
self.assertEqual([], actions)
|
|
|
|
@mock.patch('heat.engine.stack.Stack.resource_by_refid')
|
|
def test_rule_actions_alarm_normal(self, mock_get_resource):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'AlarmActions': ['DummyAction'],
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
self._setup_action_mocks(mock_get_resource, now,
|
|
action_expected=False)
|
|
|
|
# Set data so rule evaluates to NORMAL state
|
|
last = now - datetime.timedelta(seconds=300)
|
|
data = WatchData(25, now - datetime.timedelta(seconds=150))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[data],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
# Test
|
|
actions = wr.evaluate()
|
|
self.assertEqual('NORMAL', wr.state)
|
|
self.assertEqual([], actions)
|
|
self.assertEqual(0, mock_get_resource.call_count)
|
|
|
|
@mock.patch('heat.engine.stack.Stack.resource_by_refid')
|
|
def test_rule_actions_alarm_alarm(self, mock_get_resource):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'AlarmActions': ['DummyAction'],
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
self._setup_action_mocks(mock_get_resource, now)
|
|
|
|
# Set data so rule evaluates to ALARM state
|
|
last = now - datetime.timedelta(seconds=300)
|
|
data = WatchData(35, now - datetime.timedelta(seconds=150))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[data],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
# Test
|
|
actions = wr.evaluate()
|
|
self.assertEqual('ALARM', wr.state)
|
|
self.assertEqual(['DummyAction'], actions)
|
|
|
|
# re-set last_evaluated so the rule will be evaluated again.
|
|
last = now - datetime.timedelta(seconds=300)
|
|
wr.last_evaluated = last
|
|
actions = wr.evaluate()
|
|
self.assertEqual('ALARM', wr.state)
|
|
self.assertEqual(['DummyAction'], actions)
|
|
self.assertTrue(mock_get_resource.call_count > 0)
|
|
|
|
@mock.patch('heat.engine.stack.Stack.resource_by_refid')
|
|
def test_rule_actions_alarm_two_actions(self, mock_get_resource):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'AlarmActions': ['DummyAction', 'AnotherDummyAction'],
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
self._setup_action_mocks(mock_get_resource, now)
|
|
|
|
# Set data so rule evaluates to ALARM state
|
|
last = now - datetime.timedelta(seconds=300)
|
|
data = WatchData(35, now - datetime.timedelta(seconds=150))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[data],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
# Test
|
|
actions = wr.evaluate()
|
|
self.assertEqual('ALARM', wr.state)
|
|
self.assertEqual(['DummyAction', 'DummyAction'], actions)
|
|
self.assertTrue(mock_get_resource.call_count > 0)
|
|
|
|
@mock.patch('heat.engine.stack.Stack.resource_by_refid')
|
|
def test_rule_actions_ok_alarm(self, mock_get_resource):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'OKActions': ['DummyAction'],
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
self._setup_action_mocks(mock_get_resource, now, action_expected=False)
|
|
|
|
# On creation the rule evaluates to NODATA state
|
|
last = now - datetime.timedelta(seconds=300)
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
# Test
|
|
actions = wr.evaluate()
|
|
self.assertEqual('NODATA', wr.state)
|
|
self.assertEqual([], actions)
|
|
|
|
# Move time forward and add data below threshold so we transition from
|
|
# ALARM -> NORMAL, so evaluate() should output a 'DummyAction'
|
|
now = now + datetime.timedelta(seconds=300)
|
|
self._setup_action_mocks(mock_get_resource, now)
|
|
|
|
data = WatchData(25, now - datetime.timedelta(seconds=150))
|
|
wr.watch_data = [data]
|
|
|
|
actions = wr.evaluate()
|
|
self.assertEqual('NORMAL', wr.state)
|
|
self.assertEqual(['DummyAction'], actions)
|
|
self.assertTrue(mock_get_resource.call_count > 0)
|
|
|
|
@mock.patch('heat.engine.stack.Stack.resource_by_refid')
|
|
def test_rule_actions_nodata(self, mock_get_resource):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'InsufficientDataActions': ['DummyAction'],
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
self._setup_action_mocks(mock_get_resource, now, action_expected=False)
|
|
|
|
# Set data so rule evaluates to ALARM state
|
|
last = now - datetime.timedelta(seconds=300)
|
|
data = WatchData(35, now - datetime.timedelta(seconds=150))
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[data],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
# Test
|
|
actions = wr.evaluate()
|
|
self.assertEqual('ALARM', wr.state)
|
|
self.assertEqual([], actions)
|
|
|
|
# Move time forward and don't add data so we transition from
|
|
# ALARM -> NODATA, so evaluate() should output a 'DummyAction'
|
|
now = now + datetime.timedelta(seconds=300)
|
|
self._setup_action_mocks(mock_get_resource, now)
|
|
|
|
actions = wr.evaluate()
|
|
self.assertEqual('NODATA', wr.state)
|
|
self.assertEqual(['DummyAction'], actions)
|
|
self.assertTrue(mock_get_resource.call_count > 0)
|
|
|
|
@mock.patch('ceilometerclient.client.AuthPlugin.redirect_to_aodh_endpoint')
|
|
@mock.patch('heat.engine.stack.Stack.resource_by_refid')
|
|
def test_to_ceilometer(self, mock_get_resource, mock_redirect):
|
|
# Setup
|
|
rule = {u'EvaluationPeriods': u'1',
|
|
u'AlarmDescription': u'test alarm',
|
|
u'Period': u'300',
|
|
u'ComparisonOperator': u'GreaterThanThreshold',
|
|
u'Statistic': u'SampleCount',
|
|
u'Threshold': u'2',
|
|
u'MetricName': u'CreateDataMetric'}
|
|
testdata = {u'CreateDataMetric': {"Unit": "Counter", "Value": "1"}}
|
|
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name='create_data_test',
|
|
stack_id=self.stack_id,
|
|
rule=rule)
|
|
wr.store()
|
|
|
|
mock_ceilometer_client = mock.MagicMock()
|
|
|
|
self.ctx._clients = mock.MagicMock()
|
|
self.ctx._clients.client.return_value = mock_ceilometer_client
|
|
|
|
# Test
|
|
wr._to_ceilometer(testdata)
|
|
|
|
# Verify
|
|
self.assertEqual(1, mock_ceilometer_client.samples.create.call_count)
|
|
create_kw_args = mock_ceilometer_client.samples.create.call_args[1]
|
|
expected = {
|
|
'counter_type': 'gauge',
|
|
'counter_name': 'CreateDataMetric',
|
|
'counter_volume': '1',
|
|
'counter_unit': 'Counter',
|
|
'resource_metadata': {},
|
|
'resource_id': None,
|
|
}
|
|
self.assertEqual(expected, create_kw_args)
|
|
|
|
def test_create_watch_data(self):
|
|
# Setup
|
|
rule = {u'EvaluationPeriods': u'1',
|
|
u'AlarmDescription': u'test alarm',
|
|
u'Period': u'300',
|
|
u'ComparisonOperator': u'GreaterThanThreshold',
|
|
u'Statistic': u'SampleCount',
|
|
u'Threshold': u'2',
|
|
u'MetricName': u'CreateDataMetric'}
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name='create_data_test',
|
|
stack_id=self.stack_id,
|
|
rule=rule)
|
|
|
|
wr.store()
|
|
|
|
# Test
|
|
data = {u'CreateDataMetric': {"Unit": "Counter",
|
|
"Value": "1",
|
|
"Dimensions": []}}
|
|
wr.create_watch_data(data)
|
|
|
|
# Verify
|
|
obj_wr = watch_rule.WatchRule.get_by_name(self.ctx, 'create_data_test')
|
|
obj_wds = [wd for wd in obj_wr.watch_data]
|
|
self.assertEqual(data, obj_wds[0].data)
|
|
|
|
# Note, would be good to write another datapoint and check it
|
|
# but sqlite seems to not interpret the backreference correctly
|
|
# so dbwr.watch_data is always a list containing only the latest
|
|
# datapoint. In non-test use on mysql this is not the case, we
|
|
# correctly get a list of all datapoints where watch_rule_id ==
|
|
# watch_rule.id, so leave it as a single-datapoint test for now.
|
|
|
|
def test_create_watch_data_suspended(self):
|
|
# Setup
|
|
rule = {u'EvaluationPeriods': u'1',
|
|
u'AlarmDescription': u'test alarm',
|
|
u'Period': u'300',
|
|
u'ComparisonOperator': u'GreaterThanThreshold',
|
|
u'Statistic': u'SampleCount',
|
|
u'Threshold': u'2',
|
|
u'MetricName': u'CreateDataMetric'}
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name='create_data_test',
|
|
stack_id=self.stack_id,
|
|
rule=rule,
|
|
state=watchrule.WatchRule.SUSPENDED)
|
|
|
|
wr.store()
|
|
|
|
# Test
|
|
data = {u'CreateDataMetric': {"Unit": "Counter",
|
|
"Value": "1",
|
|
"Dimensions": []}}
|
|
wr.create_watch_data(data)
|
|
|
|
# Verify
|
|
obj_wr = watch_rule.WatchRule.get_by_name(self.ctx, 'create_data_test')
|
|
obj_wds = [wd for wd in obj_wr.watch_data]
|
|
self.assertEqual([], obj_wds)
|
|
|
|
def test_create_watch_data_match(self):
|
|
# Setup
|
|
rule = {u'EvaluationPeriods': u'1',
|
|
u'AlarmDescription': u'test alarm',
|
|
u'Period': u'300',
|
|
u'ComparisonOperator': u'GreaterThanThreshold',
|
|
u'Statistic': u'SampleCount',
|
|
u'Threshold': u'2',
|
|
u'Dimensions': [{u'Name': 'AutoScalingGroupName',
|
|
u'Value': 'group_x'}],
|
|
u'MetricName': u'CreateDataMetric'}
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name='create_data_test',
|
|
stack_id=self.stack_id,
|
|
rule=rule)
|
|
wr.store()
|
|
|
|
# Test
|
|
data = {u'CreateDataMetric': {"Unit": "Counter",
|
|
"Value": "1",
|
|
"Dimensions": [{u'AutoScalingGroupName':
|
|
u'group_x'}]}}
|
|
self.assertTrue(watchrule.rule_can_use_sample(wr, data))
|
|
|
|
def test_create_watch_data_match_2(self):
|
|
# Setup
|
|
rule = {u'EvaluationPeriods': u'1',
|
|
u'AlarmDescription': u'test alarm',
|
|
u'Period': u'300',
|
|
u'ComparisonOperator': u'GreaterThanThreshold',
|
|
u'Statistic': u'SampleCount',
|
|
u'Threshold': u'2',
|
|
u'Dimensions': [{u'Name': 'AutoScalingGroupName',
|
|
u'Value': 'group_x'}],
|
|
u'MetricName': u'CreateDataMetric'}
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name='create_data_test',
|
|
stack_id=self.stack_id,
|
|
rule=rule)
|
|
wr.store()
|
|
|
|
# Test
|
|
data = {u'not_interesting': {"Unit": "Counter",
|
|
"Value": "1",
|
|
"Dimensions": [
|
|
{u'AutoScalingGroupName':
|
|
u'group_x'}]},
|
|
u'CreateDataMetric': {"Unit": "Counter",
|
|
"Value": "1",
|
|
"Dimensions": [
|
|
{u'AutoScalingGroupName':
|
|
u'group_x'}]}}
|
|
self.assertTrue(watchrule.rule_can_use_sample(wr, data))
|
|
|
|
def test_create_watch_data_match_3(self):
|
|
# Setup
|
|
rule = {u'EvaluationPeriods': u'1',
|
|
u'AlarmDescription': u'test alarm',
|
|
u'Period': u'300',
|
|
u'ComparisonOperator': u'GreaterThanThreshold',
|
|
u'Statistic': u'SampleCount',
|
|
u'Threshold': u'2',
|
|
u'Dimensions': [{u'Name': 'AutoScalingGroupName',
|
|
u'Value': 'group_x'}],
|
|
u'MetricName': u'CreateDataMetric'}
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name='create_data_test',
|
|
stack_id=self.stack_id,
|
|
rule=rule)
|
|
wr.store()
|
|
|
|
# Test
|
|
data = {u'CreateDataMetric': {"Unit": "Counter",
|
|
"Value": "1",
|
|
"Dimensions": [
|
|
{u'AutoScalingGroupName':
|
|
u'group_x'}]}}
|
|
self.assertTrue(watchrule.rule_can_use_sample(wr, data))
|
|
|
|
def test_create_watch_data_not_match_metric(self):
|
|
# Setup
|
|
rule = {u'EvaluationPeriods': u'1',
|
|
u'AlarmDescription': u'test alarm',
|
|
u'Period': u'300',
|
|
u'ComparisonOperator': u'GreaterThanThreshold',
|
|
u'Statistic': u'SampleCount',
|
|
u'Threshold': u'2',
|
|
u'Dimensions': [{u'Name': 'AutoScalingGroupName',
|
|
u'Value': 'group_x'}],
|
|
u'MetricName': u'CreateDataMetric'}
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name='create_data_test',
|
|
stack_id=self.stack_id,
|
|
rule=rule)
|
|
wr.store()
|
|
|
|
# Test
|
|
data = {u'not_this': {"Unit": "Counter",
|
|
"Value": "1",
|
|
"Dimensions": [
|
|
{u'AutoScalingGroupName':
|
|
u'group_x'}]},
|
|
u'nor_this': {"Unit": "Counter",
|
|
"Value": "1",
|
|
"Dimensions": [
|
|
{u'AutoScalingGroupName':
|
|
u'group_x'}]}}
|
|
self.assertFalse(watchrule.rule_can_use_sample(wr, data))
|
|
|
|
def test_create_watch_data_not_match_dimensions(self):
|
|
# Setup
|
|
rule = {u'EvaluationPeriods': u'1',
|
|
u'AlarmDescription': u'test alarm',
|
|
u'Period': u'300',
|
|
u'ComparisonOperator': u'GreaterThanThreshold',
|
|
u'Statistic': u'SampleCount',
|
|
u'Threshold': u'2',
|
|
u'Dimensions': [{u'Name': 'AutoScalingGroupName',
|
|
u'Value': 'group_x'}],
|
|
u'MetricName': u'CreateDataMetric'}
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name='create_data_test',
|
|
stack_id=self.stack_id,
|
|
rule=rule)
|
|
wr.store()
|
|
|
|
# Test
|
|
data = {u'CreateDataMetric': {"Unit": "Counter",
|
|
"Value": "1",
|
|
"Dimensions": [
|
|
{u'wrong_key':
|
|
u'group_x'}]}}
|
|
self.assertFalse(watchrule.rule_can_use_sample(wr, data))
|
|
|
|
def test_destroy(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'AlarmActions': ['DummyAction'],
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
last = timeutils.utcnow()
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name='testwatch_destroy',
|
|
rule=rule,
|
|
watch_data=[],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
wr.store()
|
|
|
|
# Sanity Check
|
|
check = watchrule.WatchRule.load(context=self.ctx,
|
|
watch_name='testwatch_destroy')
|
|
self.assertIsInstance(check, watchrule.WatchRule)
|
|
|
|
# Test
|
|
wr.destroy()
|
|
self.assertRaises(exception.WatchRuleNotFound,
|
|
watchrule.WatchRule.load,
|
|
context=self.ctx,
|
|
watch_name='testwatch_destroy')
|
|
|
|
def test_state_set(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'AlarmActions': ['DummyAction'],
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
last = timeutils.utcnow()
|
|
watcher = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch_set_state",
|
|
rule=rule,
|
|
watch_data=[],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
# Test
|
|
watcher.state_set(watcher.SUSPENDED)
|
|
|
|
# Verify
|
|
self.assertEqual(watcher.SUSPENDED, watcher.state)
|
|
check = watchrule.WatchRule.load(context=self.ctx,
|
|
watch_name='testwatch_set_state')
|
|
self.assertEqual(watchrule.WatchRule.SUSPENDED, check.state)
|
|
|
|
@mock.patch('heat.engine.stack.Stack.resource_by_refid')
|
|
def test_set_watch_state(self, mock_get_resource):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'AlarmActions': ['DummyAction'],
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
self._setup_action_mocks(mock_get_resource, now)
|
|
|
|
# Set data so rule evaluates to ALARM state
|
|
last = now - datetime.timedelta(seconds=200)
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
# Test
|
|
actions = wr.set_watch_state(watchrule.WatchRule.NODATA)
|
|
self.assertEqual([], actions)
|
|
|
|
actions = wr.set_watch_state(watchrule.WatchRule.NORMAL)
|
|
self.assertEqual([], actions)
|
|
|
|
actions = wr.set_watch_state(watchrule.WatchRule.ALARM)
|
|
self.assertEqual(['DummyAction'], actions)
|
|
self.assertTrue(mock_get_resource.call_count > 0)
|
|
|
|
def test_set_watch_state_invalid(self):
|
|
# Setup
|
|
rule = {'EvaluationPeriods': '1',
|
|
'MetricName': 'test_metric',
|
|
'AlarmActions': ['DummyAction'],
|
|
'Period': '300',
|
|
'Statistic': 'Maximum',
|
|
'ComparisonOperator': 'GreaterThanOrEqualToThreshold',
|
|
'Threshold': '30'}
|
|
|
|
now = timeutils.utcnow()
|
|
|
|
last = now - datetime.timedelta(seconds=200)
|
|
wr = watchrule.WatchRule(context=self.ctx,
|
|
watch_name="testwatch",
|
|
rule=rule,
|
|
watch_data=[],
|
|
stack_id=self.stack_id,
|
|
last_evaluated=last)
|
|
|
|
# Test
|
|
self.assertRaises(ValueError, wr.set_watch_state, None)
|
|
self.assertRaises(ValueError, wr.set_watch_state, "BADSTATE")
|