# License for the specific language governing permissions and limitations
# under the License.
+from heat.common import exception
from heat.engine import resource
+from heat.engine import watchrule
class CeilometerAlarm(resource.Resource):
alarm = self.ceilometer().alarms.create(**props)
self.resource_id_set(alarm.alarm_id)
+ # the watchrule below is for backwards compatibility.
+ # 1) so we don't create watch tasks unneccessarly
+ # 2) to support CW stats post, we will redirect the request
+ # to ceilometer.
+ wr = watchrule.WatchRule(context=self.context,
+ watch_name=self.physical_resource_name(),
+ rule=self.parsed_template('Properties'),
+ stack_id=self.stack.id)
+ wr.state = wr.CEILOMETER_CONTROLLED
+ wr.store()
+
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
if prop_diff:
kwargs = {'alarm_id': self.resource_id}
enabled=True)
def handle_delete(self):
+ try:
+ wr = watchrule.WatchRule.load(
+ self.context, watch_name=self.physical_resource_name())
+ wr.destroy()
+ except exception.WatchRuleNotFound:
+ pass
+
if self.resource_id is not None:
self.ceilometer().alarms.delete(self.resource_id)
wrs = db_api.watch_rule_get_all_by_stack(cnxt,
stack_id)
- # reset the last_evaluated so we don't fire off alarms when
- # the engine has not been running.
now = timeutils.utcnow()
+ start_watch_thread = False
for wr in wrs:
+ # reset the last_evaluated so we don't fire off alarms when
+ # the engine has not been running.
db_api.watch_rule_update(cnxt, wr.id, {'last_evaluated': now})
- if len(wrs) > 0:
+ if wr.state != rpc_api.WATCH_STATE_CEILOMETER_CONTROLLED:
+ start_watch_thread = True
+
+ if start_watch_thread:
self._timer_in_thread(stack_id, self._periodic_watcher_task,
sid=stack_id)
arg3 -> State (must be one defined in WatchRule class
'''
wr = watchrule.WatchRule.load(cnxt, watch_name)
+ if wr.state == rpc_api.WATCH_STATE_CEILOMETER_CONTROLLED:
+ return
actions = wr.set_watch_state(state)
for action in actions:
self._start_in_thread(wr.stack_id, action)
ALARM,
NORMAL,
NODATA,
- SUSPENDED
+ SUSPENDED,
+ CEILOMETER_CONTROLLED,
) = (
rpc_api.WATCH_STATE_ALARM,
rpc_api.WATCH_STATE_OK,
rpc_api.WATCH_STATE_NODATA,
- rpc_api.WATCH_STATE_SUSPENDED
+ rpc_api.WATCH_STATE_SUSPENDED,
+ rpc_api.WATCH_STATE_CEILOMETER_CONTROLLED,
)
ACTION_MAP = {ALARM: 'AlarmActions',
NORMAL: 'OKActions',
self.state = state
self.rule = rule
self.stack_id = stack_id
- self.timeperiod = datetime.timedelta(seconds=int(rule['Period']))
+ period = 0
+ if 'Period' in rule:
+ period = int(rule['Period'])
+ elif 'period' in rule:
+ period = int(rule['period'])
+ self.timeperiod = datetime.timedelta(seconds=period)
self.id = wid
self.watch_data = watch_data
self.last_evaluated = last_evaluated
new_state)
return actions
+ def _to_ceilometer(self, data):
+ from heat.engine import clients
+ clients = clients.Clients(self.context)
+ sample = {}
+ sample['counter_type'] = 'gauge'
+
+ for k, d in iter(data.items()):
+ if k == 'Namespace':
+ continue
+ sample['counter_name'] = k
+ sample['counter_volume'] = d['Value']
+ sample['counter_unit'] = d['Unit']
+ dims = d.get('Dimensions', {})
+ if isinstance(dims, list):
+ dims = dims[0]
+ sample['resource_metadata'] = dims
+ sample['resource_id'] = dims.get('InstanceId')
+ logger.debug('new sample:%s data:%s' % (k, sample))
+ clients.ceilometer().samples.create(**sample)
+
def create_watch_data(self, data):
+ if self.state == self.CEILOMETER_CONTROLLED:
+ # this is a short term measure for those that have cfn-push-stats
+ # within their templates, but want to use Ceilometer alarms.
+
+ self._to_ceilometer(data)
+ return
+
if self.state == self.SUSPENDED:
logger.debug('Ignoring metric data for %s, SUSPENDED state'
% self.name)
if wr.state == WatchRule.SUSPENDED:
return False
- if wr.rule['MetricName'] not in stats_data:
+ if wr.state == WatchRule.CEILOMETER_CONTROLLED:
+ metric = wr.rule['counter_name']
+ rule_dims = {}
+ for k, v in iter(wr.rule.get('matching_metadata', {}).items()):
+ name = k.split('.')[-1]
+ rule_dims[name] = v
+ else:
+ metric = wr.rule['MetricName']
+ rule_dims = dict((d['Name'], d['Value'])
+ for d in wr.rule.get('Dimensions', []))
+
+ if metric not in stats_data:
return False
- rule_dims = dict((d['Name'], d['Value'])
- for d in wr.rule.get('Dimensions', []))
-
for k, v in iter(stats_data.items()):
if k == 'Namespace':
continue
- if k == wr.rule['MetricName']:
+ if k == metric:
data_dims = v.get('Dimensions', {})
if isinstance(data_dims, list):
data_dims = data_dims[0]