Allow the Ceilometer Alarm to be used with cfn-push-stats
This is for when: - Ceilometer does not support the desired custom metric - Easier migration to Ceilometer Alarms (reuse most of old templates) A watchrule is create within the Ceilometer alarm, but it is marked as belonging to Ceilometer. This is used in the follow situation: - So we can figure out that we don't need to run the watch periodic task - when we receive new sample data we can forward the data to Ceilometer blueprint watch-ceilometer Change-Id: I0d672e69a522a23158805d75378f4bfe631b4bf3
This commit is contained in:
parent
31e53d4fe7
commit
af68b6168c
@ -13,7 +13,9 @@
|
||||
# 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):
|
||||
@ -85,6 +87,17 @@ 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}
|
||||
@ -102,6 +115,13 @@ class CeilometerAlarm(resource.Resource):
|
||||
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)
|
||||
|
||||
|
@ -100,13 +100,17 @@ class EngineService(service.Service):
|
||||
wrs = db_api.watch_rule_get_all_by_stack(cnxt,
|
||||
stack_id)
|
||||
|
||||
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.
|
||||
now = timeutils.utcnow()
|
||||
for wr in wrs:
|
||||
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)
|
||||
|
||||
@ -736,6 +740,8 @@ class EngineService(service.Service):
|
||||
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)
|
||||
|
@ -31,12 +31,14 @@ class WatchRule(object):
|
||||
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',
|
||||
@ -54,7 +56,12 @@ class WatchRule(object):
|
||||
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
|
||||
@ -257,7 +264,34 @@ class WatchRule(object):
|
||||
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)
|
||||
@ -322,16 +356,24 @@ def rule_can_use_sample(wr, stats_data):
|
||||
|
||||
if wr.state == WatchRule.SUSPENDED:
|
||||
return False
|
||||
if wr.rule['MetricName'] not in stats_data:
|
||||
return False
|
||||
|
||||
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
|
||||
|
||||
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]
|
||||
|
@ -118,9 +118,9 @@ WATCH_RULE_KEYS = (
|
||||
|
||||
WATCH_STATES = (
|
||||
WATCH_STATE_OK, WATCH_STATE_ALARM, WATCH_STATE_NODATA,
|
||||
WATCH_STATE_SUSPENDED
|
||||
WATCH_STATE_SUSPENDED, WATCH_STATE_CEILOMETER_CONTROLLED
|
||||
) = (
|
||||
'NORMAL', 'ALARM', 'NODATA', 'SUSPENDED'
|
||||
'NORMAL', 'ALARM', 'NODATA', 'SUSPENDED', 'CEILOMETER_CONTROLLED'
|
||||
)
|
||||
|
||||
WATCH_DATA_KEYS = (
|
||||
|
Loading…
Reference in New Issue
Block a user