self.run_rule(context, wr, now)
def run_rule(self, context, wr, now=timeutils.utcnow()):
- action_map = {'ALARM': 'AlarmActions',
- 'NORMAL': 'OKActions',
- 'NODATA': 'InsufficientDataActions'}
-
watcher = watchrule.WatchRule(wr.rule, wr.watch_data,
wr.last_evaluated, now)
new_state = watcher.get_alarm_state()
if new_state != wr.state:
- logger.warn('WATCH: stack:%s, watch_name:%s %s',
- wr.stack_name, wr.name, new_state)
-
- if not action_map[new_state] in wr.rule:
- logger.info('no action for new state %s',
- new_state)
+ if self.rule_action(wr, new_state):
wr.state = new_state
- wr.save()
- else:
- s = db_api.stack_get_by_name(None, wr.stack_name)
- if s and s.status in ('CREATE_COMPLETE',
- 'UPDATE_COMPLETE'):
- user_creds = db_api.user_creds_get(s.user_creds_id)
- ctxt = ctxtlib.RequestContext.from_dict(dict(user_creds))
- stack = parser.Stack.load(ctxt, s.id)
- for a in wr.rule[action_map[new_state]]:
- greenpool.spawn_n(stack[a].alarm)
- wr.state = new_state
- wr.save()
wr.last_evaluated = now
+ wr.save()
+
+ def rule_action(self, wr, new_state):
+ # TODO : push watch-rule processing into engine.watchrule
+ logger.warn('WATCH: stack:%s, watch_name:%s %s',
+ wr.stack_name, wr.name, new_state)
+
+ actioned = False
+ if not watchrule.WatchRule.ACTION_MAP[new_state] in wr.rule:
+ logger.info('no action for new state %s',
+ new_state)
+ actioned = True
+ else:
+ s = db_api.stack_get_by_name(None, wr.stack_name)
+ if s and s.status in (parser.Stack.CREATE_COMPLETE,
+ parser.Stack.UPDATE_COMPLETE):
+ user_creds = db_api.user_creds_get(s.user_creds_id)
+ ctxt = ctxtlib.RequestContext.from_dict(dict(user_creds))
+ stack = parser.Stack.load(ctxt, s.id)
+ for a in wr.rule[watchrule.WatchRule.ACTION_MAP[new_state]]:
+ greenpool.spawn_n(stack[a].alarm)
+ actioned = True
+ else:
+ logger.warning("Could not process watch state %s for stack" %
+ new_state)
+ return actioned
def create_watch_data(self, context, watch_name, stats_data):
'''
result = [api.format_watch_data(w) for w in wds]
return result
+
+ def set_watch_state(self, context, watch_name, state):
+ '''
+ Temporarily set the state of a given watch
+ arg1 -> RPC context.
+ arg2 -> Name of the watch
+ arg3 -> State (must be one defined in WatchRule class
+ '''
+
+ if state not in watchrule.WatchRule.WATCH_STATES:
+ raise AttributeError('Unknown watch state %s' % state)
+
+ if watch_name:
+ try:
+ wr = db_api.watch_rule_get(context, watch_name)
+ except Exception as ex:
+ logger.warn('show_watch (%s) db error %s' %
+ (watch_name, str(ex)))
+
+ if not wr:
+ raise AttributeError('Unknown watch name %s' % watch_name)
+
+ else:
+ raise AttributeError('Must pass watch_name')
+
+ if state != wr.state:
+ if self.rule_action(wr, state):
+ logger.debug("Overriding state %s for watch %s with %s" %
+ (wr.state, watch_name, state))
+ else:
+ logger.warning("Unable to override state %s for watch %s" %
+ (wr.state, watch_name))
+
+ # Return the watch with the state overriden to indicate success
+ # We do not update the timestamps as we are not modifying the DB
+ result = api.format_watch(wr)
+ result[api.WATCH_STATE_VALUE] = state
+ return result
return self.call(ctxt, self.make_msg('show_watch_metric',
namespace=namespace, metric_name=metric_name),
topic=_engine_topic(self.topic, ctxt, None))
+
+ def set_watch_state(self, ctxt, watch_name, state):
+ '''
+ Temporarily set the state of a given watch
+ arg1 -> RPC context.
+ arg2 -> Name of the watch
+ arg3 -> State (must be one defined in WatchRule class)
+ '''
+ return self.call(ctxt, self.make_msg('set_watch_state',
+ watch_name=watch_name, state=state),
+ topic=_engine_topic(self.topic, ctxt, None))
class WatchRule(object):
- ALARM = 'ALARM'
- NORMAL = 'NORMAL'
- NODATA = 'NODATA'
+ WATCH_STATES = (ALARM, NORMAL, NODATA
+ ) = ('ALARM', 'NORMAL', 'NODATA')
+
+ ACTION_MAP = {ALARM: 'AlarmActions',
+ NORMAL: 'OKActions',
+ NODATA: 'InsufficientDataActions'}
def __init__(self, rule, dataset, last_evaluated, now):
self.rule = rule
from heat.engine import parser
from heat.engine import manager
from heat.engine import auth
+from heat.engine import watchrule
tests_dir = os.path.dirname(os.path.realpath(__file__))
for key in engine_api.WATCH_DATA_KEYS:
self.assertTrue(key in result[0])
+ def test_set_watch_state(self):
+ # Insert dummy watch rule into the DB
+ values = {'stack_name': u'wordpress_ha', 'state': 'NORMAL',
+ 'name': u'OverrideAlarm',
+ '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'}}
+ db_ret = db_api.watch_rule_create(self.ctx, values)
+ self.assertNotEqual(db_ret, None)
+
+ for state in watchrule.WatchRule.WATCH_STATES:
+ result = self.man.set_watch_state(self.ctx,
+ watch_name="OverrideAlarm",
+ state=state)
+ self.assertNotEqual(result, None)
+ self.assertEqual(result[engine_api.WATCH_STATE_VALUE], state)
+
+ # Cleanup, delete the dummy rule
+ db_api.watch_rule_delete(self.ctx, "OverrideAlarm")
+
+ def test_set_watch_state_badstate(self):
+ # Insert dummy watch rule into the DB
+ values = {'stack_name': u'wordpress_ha', 'state': 'NORMAL',
+ 'name': u'OverrideAlarm2',
+ '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'}}
+ db_ret = db_api.watch_rule_create(self.ctx, values)
+ self.assertNotEqual(db_ret, None)
+
+ for state in ["HGJHGJHG", "1234", "!\*(&%"]:
+ self.assertRaises(AttributeError,
+ self.man.set_watch_state,
+ self.ctx, watch_name="OverrideAlarm2",
+ state=state)
+
+ # Cleanup, delete the dummy rule
+ db_api.watch_rule_delete(self.ctx, "OverrideAlarm2")
+
+ def test_set_watch_state_noexist(self):
+ # watch_name="nonexistent" should raise an AttributeError
+ state = watchrule.WatchRule.ALARM # State valid
+ self.assertRaises(AttributeError,
+ self.man.set_watch_state,
+ self.ctx, watch_name="nonexistent", state=state)
+
# allows testing of the test directly
if __name__ == '__main__':
def test_show_watch_metric(self):
self._test_engine_api('show_watch_metric', 'call',
namespace=None, metric_name=None)
+
+ def test_set_watch_state(self):
+ self._test_engine_api('set_watch_state', 'call',
+ watch_name='watch1', state="xyz")