engine_api.WATCH_THRESHOLD: 'Threshold',
engine_api.WATCH_UNIT: 'Unit'}
- # AWS doesn't return StackName in the main MetricAlarm
- # structure, so we add StackName as a dimension to all responses
- a[engine_api.WATCH_DIMENSIONS].append({'StackName':
- a[engine_api.WATCH_STACK_NAME]})
+ # AWS doesn't return StackId in the main MetricAlarm
+ # structure, so we add StackId as a dimension to all responses
+ a[engine_api.WATCH_DIMENSIONS].append({'StackId':
+ a[engine_api.WATCH_STACK_ID]})
# Reformat dimensions list into AWS API format
a[engine_api.WATCH_DIMENSIONS] = self._reformat_dimensions(
--- /dev/null
+from sqlalchemy import *
+from migrate import *
+
+
+def upgrade(migrate_engine):
+ meta = MetaData(bind=migrate_engine)
+
+ stack = Table('stack', meta, autoload=True)
+ watch_rule = Table('watch_rule', meta, autoload=True)
+
+ Column('stack_id', String(length=36), ForeignKey("stack.id"),
+ nullable=False).create(watch_rule)
+
+ watch_rule.c.stack_name.drop()
+
+
+def downgrade(migrate_engine):
+ meta = MetaData(bind=migrate_engine)
+
+ watch_rule = Table('watch_rule', meta, autoload=True)
+
+ watch_rule.c.stack_id.drop()
+ Column('stack_name', String(length=255), convert_unicode=False,
+ assert_unicode=None, unicode_error=None,
+ _warn_on_bytestring=False).create(watch_rule)
name = Column('name', String, nullable=False)
rule = Column('rule', Json)
state = Column('state', String)
- stack_name = Column('stack_name', String)
last_evaluated = Column(DateTime, default=timeutils.utcnow)
+ stack_id = Column(String, ForeignKey('stack.id'),
+ nullable=False)
+ stack = relationship(Stack, backref=backref('watch_rule'))
+
class WatchData(BASE, HeatBase):
"""Represents a watch_data created by the heat engine."""
WATCH_INSUFFICIENT_ACTIONS, WATCH_METRIC_NAME, WATCH_NAMESPACE,
WATCH_OK_ACTIONS, WATCH_PERIOD, WATCH_STATE_REASON,
WATCH_STATE_REASON_DATA, WATCH_STATE_UPDATED_TIME, WATCH_STATE_VALUE,
- WATCH_STATISTIC, WATCH_THRESHOLD, WATCH_UNIT, WATCH_STACK_NAME
+ WATCH_STATISTIC, WATCH_THRESHOLD, WATCH_UNIT, WATCH_STACK_ID
) = (
'actions_enabled', 'actions', 'topic',
'updated_time', 'description', 'name',
'insufficient_actions', 'metric_name', 'namespace',
'ok_actions', 'period', 'state_reason',
'state_reason_data', 'state_updated_time', 'state_value',
- 'statistic', 'threshold', 'unit', 'stack_name')
+ 'statistic', 'threshold', 'unit', 'stack_id')
# Alternate representation of a watch rule to align with DB format
WATCH_STATISTIC: watch.rule.get(RULE_STATISTIC),
WATCH_THRESHOLD: watch.rule.get(RULE_THRESHOLD),
WATCH_UNIT: watch.rule.get(RULE_UNIT),
- WATCH_STACK_NAME: watch.stack_name
+ WATCH_STACK_ID: watch.stack_id
}
return result
def handle_create(self):
wr = watchrule.WatchRule(context=self.context, watch_name=self.name,
rule=self.parsed_template('Properties'),
- stack_name=self.stack.name)
+ stack_id=self.stack.id)
wr.store()
def handle_update(self):
created_at = timestamp.Timestamp(db_api.watch_rule_get, 'created_at')
updated_at = timestamp.Timestamp(db_api.watch_rule_get, 'updated_at')
- def __init__(self, context, watch_name, rule, stack_name, state=NORMAL,
- wid=None, watch_data=[], last_evaluated=timeutils.utcnow()):
+ def __init__(self, context, watch_name, rule, stack_id=None,
+ state=NORMAL, wid=None, watch_data=[],
+ last_evaluated=timeutils.utcnow()):
self.context = context
self.now = timeutils.utcnow()
self.name = watch_name
self.state = state
self.rule = rule
- self.stack_name = stack_name
+ self.stack_id = stack_id
self.timeperiod = datetime.timedelta(seconds=int(rule['Period']))
self.id = wid
self.watch_data = watch_data
return cls(context=context,
watch_name=dbwr.name,
rule=dbwr.rule,
- stack_name=dbwr.stack_name,
+ stack_id=dbwr.stack_id,
state=dbwr.state,
wid=dbwr.id,
watch_data=dbwr.watch_data,
'name': self.name,
'rule': self.rule,
'state': self.state,
- 'stack_name': self.stack_name
+ 'stack_id': self.stack_id
}
if not self.id:
def rule_action(self, new_state):
logger.warn('WATCH: stack:%s, watch_name:%s %s',
- self.stack_name, self.name, new_state)
+ self.stack_id, self.name, new_state)
actioned = False
if not self.ACTION_MAP[new_state] in self.rule:
# scoping, this is the simplest possible solution to the
# HA/Autoscaling regression described in bug/1078779
# Further work in-progress here (shardy) as this
- # breaks when stack_name is not unique accross tenants
+ # breaks when stack_id is not unique accross tenants
sl = [x for x in
db_api.stack_get_all(self.context)
- if x.name == self.stack_name]
+ if x.id == self.stack_id]
s = None
if len(sl) == 1:
s = sl[0]
elif len(sl) > 1:
- logger.error("stack %s name not unique, " % self.stack_name
+ logger.error("stack %s not unique, " % self.stack_id
+ "cannot action watch rule")
else:
- logger.error("stack %s name could not be found, " %
- self.stack_name + "cannot action watch rule")
+ logger.error("stack %s could not be found, " %
+ self.stack_id + "cannot action watch rule")
if s and s.status in (parser.Stack.CREATE_COMPLETE,
parser.Stack.UPDATE_COMPLETE):
# The tests
def test_reformat_dimensions(self):
- dims = [{'StackName': u'wordpress_ha5',
- 'Foo': 'bar'}]
+ dims = [{'StackId': u'21617058-781e-4262-97ab-5f9df371ee52',
+ 'Foo': 'bar'}]
response = self.controller._reformat_dimensions(dims)
- expected = [{'Name': 'StackName', 'Value': u'wordpress_ha5'},
+ expected = [{'Name': 'StackId',
+ 'Value': u'21617058-781e-4262-97ab-5f9df371ee52'},
{'Name': 'Foo', 'Value': 'bar'}]
self.assert_(response == expected)
# Stub out the RPC call to the engine with a pre-canned response
engine_resp = [{u'state_updated_time': u'2012-08-30T14:13:21Z',
- u'stack_name': u'wordpress_ha5',
+ u'stack_id': u'21617058-781e-4262-97ab-5f9df371ee52',
u'period': u'300',
u'actions': [u'WebServerRestartPolicy'],
u'topic': None,
'MetricName': u'ServiceFailure',
'ActionsEnabled': None,
'Dimensions': [
- {'Name': 'StackName',
- 'Value': u'wordpress_ha5'}]}]}}}
+ {'Name': 'StackId',
+ 'Value': u'21617058-781e-4262-97ab-5f9df371ee52'}
+ ]}]}}}
self.assert_(response == expected)
def test_show_watch(self):
# Insert two dummy watch rules into the DB
- values = {'stack_name': u'wordpress_ha', 'state': 'NORMAL',
+ values = {'stack_id': self.stack.id,
+ 'state': 'NORMAL',
'name': u'HttpFailureAlarm',
'rule': {
u'EvaluationPeriods': u'1',
for key in engine_api.WATCH_KEYS:
self.assertTrue(key in result[0])
+ # Cleanup, delete the dummy rules
+ db_api.watch_rule_delete(self.ctx, "HttpFailureAlarm")
+ db_api.watch_rule_delete(self.ctx, "AnotherWatch")
+
def test_show_watch_metric(self):
- # Get one of the watch rules created in test_show_watch
+ # Insert dummy watch rule into the DB
+ values = {'stack_id': self.stack.id,
+ 'state': 'NORMAL',
+ 'name': u'HttpFailureAlarm',
+ '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)
+
# And add a metric datapoint
watch = db_api.watch_rule_get_by_name(self.ctx, "HttpFailureAlarm")
self.assertNotEqual(watch, None)
metric_name=None)
self.assertEqual(2, len(result))
+ # Cleanup, delete the dummy rule
+ db_api.watch_rule_delete(self.ctx, "HttpFailureAlarm")
+
# Check the response has all keys defined in the engine API
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',
+ values = {'stack_id': self.stack.id,
+ 'state': 'NORMAL',
'name': u'OverrideAlarm',
'rule': {
u'EvaluationPeriods': u'1',
db_ret = db_api.watch_rule_create(self.ctx, values)
self.assertNotEqual(db_ret, None)
+ class DummyAction:
+ alarm = "dummyfoo"
+
+ self.m.StubOutWithMock(parser.Stack, '__getitem__')
+ parser.Stack.__getitem__(
+ 'WebServerRestartPolicy').AndReturn(DummyAction())
+
+ self.m.StubOutWithMock(watchrule.greenpool, 'spawn_n')
+ watchrule.greenpool.spawn_n("dummyfoo").AndReturn(None)
+ self.m.ReplayAll()
+
for state in watchrule.WatchRule.WATCH_STATES:
+
result = self.man.set_watch_state(self.ctx,
watch_name="OverrideAlarm",
state=state)
def test_set_watch_state_badstate(self):
# Insert dummy watch rule into the DB
- values = {'stack_name': u'wordpress_ha', 'state': 'NORMAL',
+ values = {'stack_id': self.stack.id,
+ 'state': 'NORMAL',
'name': u'OverrideAlarm2',
'rule': {
u'EvaluationPeriods': u'1',
from nose.plugins.attrib import attr
from heat.common import exception
+from heat.common import context
+from heat.common import config
from heat.engine import parser
from heat.engine.resources import instance
from heat.engine.resources import loadbalancer as lb
from heat.tests.v1_1 import fakes
+def create_context(mocks, user='lb_test_user',
+ tenant='test_admin', ctx=None):
+ ctx = ctx or context.get_admin_context()
+ mocks.StubOutWithMock(ctx, 'username')
+ mocks.StubOutWithMock(ctx, 'tenant_id')
+ ctx.username = user
+ ctx.tenant_id = tenant
+ return ctx
+
+
@attr(tag=['unit', 'resource'])
@attr(speed='fast')
class LoadBalancerTest(unittest.TestCase):
def setUp(self):
self.m = mox.Mox()
self.fc = fakes.FakeClient()
- self.m.StubOutWithMock(parser.Stack, 'store')
self.m.StubOutWithMock(lb.LoadBalancer, 'nova')
self.m.StubOutWithMock(instance.Instance, 'nova')
self.m.StubOutWithMock(self.fc.servers, 'create')
self.m.StubOutWithMock(Metadata, '__set__')
+ config.register_engine_opts()
def tearDown(self):
self.m.UnsetStubs()
return t
def parse_stack(self, t):
- class DummyContext():
- tenant = 'test_tenant'
- tenant_id = '1234abcd'
- username = 'test_username'
- password = 'password'
- auth_url = 'http://localhost:5000/v2.0'
template = parser.Template(t)
params = parser.Parameters('test_stack', template, {'KeyName': 'test'})
- stack = parser.Stack(DummyContext(), 'test_stack', template,
- params, stack_id=-1)
+ stack = parser.Stack(create_context(self.m), 'test_stack', template,
+ params, stack_id=None)
+ stack.store()
return stack
def test_loadbalancer(self):
lb.LoadBalancer.nova().AndReturn(self.fc)
- parser.Stack.store(mox.IgnoreArg()).AndReturn('5678')
+# parser.Stack.store(mox.IgnoreArg()).AndReturn('5678')
instance.Instance.nova().MultipleTimes().AndReturn(self.fc)
self.fc.servers.create(flavor=2, image=745, key_name='test',
meta=None, name=u'test_stack.LoadBalancer.LB_instance',
@attr(speed='fast')
class WatchRuleTest(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ # Create a dummy stack in the DB as WatchRule instances
+ # must be associated with a stack
+ ctx = context.get_admin_context()
+ tmpl = db_api.raw_template_create(ctx, {'foo': 'bar'})
+ dummy_stack = {'id': '6754d843-bed2-40dc-a325-84882bb90a98',
+ 'name': 'dummystack',
+ 'raw_template_id': tmpl.id,
+ 'user_creds_id': 1,
+ 'username': 'dummyuser',
+ 'owner_id': None,
+ 'status': 'CREATE_COMPLETE',
+ 'status_reason': 'foo status',
+ 'parameters': {'foo': 'bar'},
+ 'timeout': 60,
+ 'tenant': 123456}
+ db_ret = db_api.stack_create(ctx, dummy_stack)
+ cls.stack_id = db_ret.id
+
def setUp(self):
self.username = 'watchrule_test_user'
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
new_state = watcher.get_alarm_state()
logger.info(new_state)
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
new_state = watcher.get_alarm_state()
logger.info(new_state)
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
watcher.now = now
new_state = watcher.get_alarm_state()
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
watcher.now = now
new_state = watcher.get_alarm_state()
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
watcher.now = now
new_state = watcher.get_alarm_state()
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
watcher.now = now
new_state = watcher.get_alarm_state()
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
watcher.now = now
new_state = watcher.get_alarm_state()
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
watcher.now = now
new_state = watcher.get_alarm_state()
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
watcher.now = now
new_state = watcher.get_alarm_state()
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
watcher.now = now
new_state = watcher.get_alarm_state()
watcher = watchrule.WatchRule(context=self.ctx,
watch_name="testwatch",
rule=rule,
- stack_name="teststack",
watch_data=data,
+ stack_id=self.stack_id,
last_evaluated=last)
watcher.now = now
new_state = watcher.get_alarm_state()
def test_load(self):
# Insert two dummy watch rules into the DB
- values = {'stack_name': u'wordpress_ha', 'state': 'NORMAL',
+ values = {'stack_id': self.stack_id,
+ 'state': 'NORMAL',
'name': u'HttpFailureAlarm',
'rule': {
u'EvaluationPeriods': u'1',
self.assertEqual(wr.name, wn)
self.assertEqual(wr.state, values['state'])
self.assertEqual(wr.rule, values['rule'])
- self.assertEqual(wr.stack_name, values['stack_name'])
self.assertEqual(wr.timeperiod, datetime.timedelta(
seconds=int(values['rule']['Period'])))
def test_store(self):
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'}
+ 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'}
wr = watchrule.WatchRule(context=self.ctx, watch_name='storetest',
- rule=rule, stack_name='teststack')
+ stack_id=self.stack_id, rule=rule)
wr.store()
dbwr = db_api.watch_rule_get_by_name(self.ctx, 'storetest')
self.assertNotEqual(dbwr, None)
self.assertEqual(dbwr.name, 'storetest')
self.assertEqual(dbwr.state, watchrule.WatchRule.NORMAL)
- self.assertEqual(dbwr.stack_name, 'teststack')
self.assertEqual(dbwr.rule, rule)
# Cleanup