ceilometer: new Gnocchi Alarm resources
Ceilometer offers two new kind of alarms. This change adds the associated resources to Heat. Implements blueprint ceilometer-gnocchi-alarm Change-Id: I0d3dfcbda7d09361bb90fd16122b903bf4c03fbe
This commit is contained in:
parent
70747cdc1a
commit
f9fa8da05c
18
contrib/heat_gnocchi/README.md
Normal file
18
contrib/heat_gnocchi/README.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Gnocchi plugin for OpenStack Heat
|
||||||
|
=================================
|
||||||
|
|
||||||
|
This plugin adds Ceilometer Gnocchi Alarm resources in a Heat template.
|
||||||
|
|
||||||
|
|
||||||
|
### 1. Install the Gnocchi plugin in Heat
|
||||||
|
|
||||||
|
NOTE: These instructions assume the value of heat.conf plugin_dirs includes the
|
||||||
|
default directory /usr/lib/heat.
|
||||||
|
|
||||||
|
To install the plugin, from this directory run:
|
||||||
|
sudo python ./setup.py install
|
||||||
|
|
||||||
|
### 2. Restart heat
|
||||||
|
|
||||||
|
Only the process "heat-engine" needs to be restarted to load the newly installed
|
||||||
|
plugin.
|
0
contrib/heat_gnocchi/heat_gnocchi/__init__.py
Normal file
0
contrib/heat_gnocchi/heat_gnocchi/__init__.py
Normal file
132
contrib/heat_gnocchi/heat_gnocchi/resources/gnocchi_alarm.py
Normal file
132
contrib/heat_gnocchi/heat_gnocchi/resources/gnocchi_alarm.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from heat.common.i18n import _
|
||||||
|
from heat.engine import constraints
|
||||||
|
from heat.engine import properties
|
||||||
|
from heat.engine.resources.ceilometer import alarm
|
||||||
|
from heat.engine import support
|
||||||
|
|
||||||
|
|
||||||
|
COMMON_GNOCCHI_PROPERTIES = (
|
||||||
|
COMPARISON_OPERATOR, EVALUATION_PERIODS, GRANULARITY,
|
||||||
|
AGGREGATION_METHOD, THRESHOLD,
|
||||||
|
) = (
|
||||||
|
'comparison_operator', 'evaluation_periods', 'granularity',
|
||||||
|
'aggregation_method', 'threshold',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
common_gnocchi_properties_schema = {
|
||||||
|
COMPARISON_OPERATOR: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
_('Operator used to compare specified statistic with threshold.'),
|
||||||
|
constraints=[
|
||||||
|
constraints.AllowedValues(['ge', 'gt', 'eq', 'ne', 'lt',
|
||||||
|
'le']),
|
||||||
|
],
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
|
EVALUATION_PERIODS: properties.Schema(
|
||||||
|
properties.Schema.INTEGER,
|
||||||
|
_('Number of periods to evaluate over.'),
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
|
AGGREGATION_METHOD: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
_('The aggregation method to compare to the threshold'),
|
||||||
|
constraints=[
|
||||||
|
constraints.AllowedValues(['mean', 'sum', 'last', 'max', 'min',
|
||||||
|
'std', 'median', 'first', 'count']),
|
||||||
|
],
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
|
GRANULARITY: properties.Schema(
|
||||||
|
properties.Schema.INTEGER,
|
||||||
|
_('The time range in seconds.'),
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
|
THRESHOLD: properties.Schema(
|
||||||
|
properties.Schema.NUMBER,
|
||||||
|
_('Threshold to evaluate against.'),
|
||||||
|
required=True,
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CeilometerGnocchiResourcesAlarm(alarm.BaseCeilometerAlarm):
|
||||||
|
|
||||||
|
support_status = support.SupportStatus(version='2015.1')
|
||||||
|
|
||||||
|
PROPERTIES = (
|
||||||
|
METRIC, RESOURCE_CONSTRAINT, RESOURCE_TYPE
|
||||||
|
) = (
|
||||||
|
'metric', 'resource_constraint', 'resource_type'
|
||||||
|
)
|
||||||
|
PROPERTIES += COMMON_GNOCCHI_PROPERTIES
|
||||||
|
|
||||||
|
properties_schema = {
|
||||||
|
METRIC: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
_('Metric name watched by the alarm.'),
|
||||||
|
required=True,
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
|
RESOURCE_CONSTRAINT: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
_('Id of a resource or expression to select multiple resources'),
|
||||||
|
required=True,
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
|
RESOURCE_TYPE: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
_('Resource type'),
|
||||||
|
required=True,
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
|
}
|
||||||
|
properties_schema.update(common_gnocchi_properties_schema)
|
||||||
|
properties_schema.update(alarm.common_properties_schema)
|
||||||
|
|
||||||
|
ceilometer_alarm_type = 'gnocchi_resources_threshold'
|
||||||
|
|
||||||
|
|
||||||
|
class CeilometerGnocchiMetricsAlarm(CeilometerGnocchiResourcesAlarm):
|
||||||
|
|
||||||
|
support_status = support.SupportStatus(version='2015.1')
|
||||||
|
|
||||||
|
PROPERTIES = (METRICS,) = ('metrics',)
|
||||||
|
PROPERTIES += COMMON_GNOCCHI_PROPERTIES
|
||||||
|
|
||||||
|
properties_schema = {
|
||||||
|
METRICS: properties.Schema(
|
||||||
|
properties.Schema.LIST,
|
||||||
|
_('A list of metric ids.'),
|
||||||
|
required=True,
|
||||||
|
update_allowed=True,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
properties_schema.update(common_gnocchi_properties_schema)
|
||||||
|
properties_schema.update(alarm.common_properties_schema)
|
||||||
|
|
||||||
|
ceilometer_alarm_type = 'gnocchi_metrics_threshold'
|
||||||
|
|
||||||
|
|
||||||
|
def resource_mapping():
|
||||||
|
return {
|
||||||
|
'OS::Ceilometer::GnocchiResourcesAlarm':
|
||||||
|
CeilometerGnocchiResourcesAlarm,
|
||||||
|
'OS::Ceilometer::GnocchiMetricslarm': CeilometerGnocchiMetricsAlarm,
|
||||||
|
}
|
0
contrib/heat_gnocchi/heat_gnocchi/tests/__init__.py
Normal file
0
contrib/heat_gnocchi/heat_gnocchi/tests/__init__.py
Normal file
366
contrib/heat_gnocchi/heat_gnocchi/tests/test_gnocchi_alarm.py
Normal file
366
contrib/heat_gnocchi/heat_gnocchi/tests/test_gnocchi_alarm.py
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
#
|
||||||
|
# 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 copy
|
||||||
|
|
||||||
|
from ceilometerclient import exc as ceilometerclient_exc
|
||||||
|
import mock
|
||||||
|
import mox
|
||||||
|
|
||||||
|
from heat.common import exception
|
||||||
|
from heat.common import template_format
|
||||||
|
from heat.engine.clients.os import ceilometer
|
||||||
|
from heat.engine import resource
|
||||||
|
from heat.engine import scheduler
|
||||||
|
from heat.tests import common
|
||||||
|
from heat.tests import utils
|
||||||
|
|
||||||
|
from ..resources import gnocchi_alarm # noqa
|
||||||
|
|
||||||
|
gnocchi_resources_alarm_template = '''
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: Gnocchi Resources Alarm Test
|
||||||
|
resources:
|
||||||
|
GnoResAlarm:
|
||||||
|
type: OS::Ceilometer::GnocchiResourcesAlarm
|
||||||
|
properties:
|
||||||
|
description: Do stuff with gnocchi
|
||||||
|
metric: cpu_util
|
||||||
|
aggregation_method: mean
|
||||||
|
granularity: 60
|
||||||
|
evaluation_periods: 1
|
||||||
|
threshold: 50
|
||||||
|
alarm_actions: []
|
||||||
|
resource_type: instance
|
||||||
|
resource_constraint: server_group=mystack
|
||||||
|
comparison_operator: gt
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
gnocchi_metrics_alarm_template = '''
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
description: Gnocchi Metrics Alarm Test
|
||||||
|
resources:
|
||||||
|
GnoMetricsAlarm:
|
||||||
|
type: OS::Ceilometer::GnocchiMetricsAlarm
|
||||||
|
properties:
|
||||||
|
description: Do stuff with gnocchi metrics
|
||||||
|
metrics: ["911fce07-e0d7-4210-8c8c-4a9d811fcabc",
|
||||||
|
"2543d435-fe93-4443-9351-fb0156930f94"]
|
||||||
|
aggregation_method: mean
|
||||||
|
granularity: 60
|
||||||
|
evaluation_periods: 1
|
||||||
|
threshold: 50
|
||||||
|
alarm_actions: []
|
||||||
|
comparison_operator: gt
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class FakeCeilometerAlarm(object):
|
||||||
|
alarm_id = 'foo'
|
||||||
|
|
||||||
|
|
||||||
|
class FakeCeilometerAlarms(object):
|
||||||
|
def create(self, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def update(self, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def delete(self, alarm_id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FakeCeilometerClient(object):
|
||||||
|
alarms = FakeCeilometerAlarms()
|
||||||
|
|
||||||
|
|
||||||
|
class GnocchiResourcesAlarmTest(common.HeatTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(GnocchiResourcesAlarmTest, self).setUp()
|
||||||
|
self.fc = FakeCeilometerClient()
|
||||||
|
resource._register_class("OS::Ceilometer::GnocchiResourcesAlarm",
|
||||||
|
gnocchi_alarm.CeilometerGnocchiResourcesAlarm)
|
||||||
|
self.m.StubOutWithMock(ceilometer.CeilometerClientPlugin, '_create')
|
||||||
|
|
||||||
|
def create_alarm(self):
|
||||||
|
ceilometer.CeilometerClientPlugin._create().AndReturn(
|
||||||
|
self.fc)
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'create')
|
||||||
|
self.fc.alarms.create(
|
||||||
|
alarm_actions=[],
|
||||||
|
description=u'Do stuff with gnocchi',
|
||||||
|
enabled=True,
|
||||||
|
insufficient_data_actions=None,
|
||||||
|
ok_actions=None,
|
||||||
|
name=mox.IgnoreArg(), type='gnocchi_resources_threshold',
|
||||||
|
repeat_actions=True,
|
||||||
|
gnocchi_resources_threshold_rule={
|
||||||
|
"metric": "cpu_util",
|
||||||
|
"aggregation_method": "mean",
|
||||||
|
"granularity": 60,
|
||||||
|
"evaluation_periods": 1,
|
||||||
|
"threshold": 50,
|
||||||
|
"resource_type": "instance",
|
||||||
|
"resource_constraint": "server_group=mystack",
|
||||||
|
"comparison_operator": "gt",
|
||||||
|
}
|
||||||
|
).AndReturn(FakeCeilometerAlarm())
|
||||||
|
snippet = template_format.parse(gnocchi_resources_alarm_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
resource_defns = stack.t.resource_definitions(stack)
|
||||||
|
return gnocchi_alarm.CeilometerGnocchiResourcesAlarm(
|
||||||
|
'GnoResAlarm', resource_defns['GnoResAlarm'], stack)
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
self.assertEqual('foo', rsrc.resource_id)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'update')
|
||||||
|
self.fc.alarms.update(
|
||||||
|
alarm_id='foo',
|
||||||
|
gnocchi_resources_threshold_rule={
|
||||||
|
'resource_constraint': 'd3d6c642-921e-4fc2-9c5f-15d9a5afb598'})
|
||||||
|
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
|
||||||
|
update_template = copy.deepcopy(rsrc.t)
|
||||||
|
update_template['Properties']['resource_constraint'] = (
|
||||||
|
'd3d6c642-921e-4fc2-9c5f-15d9a5afb598')
|
||||||
|
scheduler.TaskRunner(rsrc.update, update_template)()
|
||||||
|
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_suspend(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'update')
|
||||||
|
self.fc.alarms.update(alarm_id='foo', enabled=False)
|
||||||
|
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
|
||||||
|
scheduler.TaskRunner(rsrc.suspend)()
|
||||||
|
self.assertEqual((rsrc.SUSPEND, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_resume(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'update')
|
||||||
|
self.fc.alarms.update(alarm_id='foo', enabled=True)
|
||||||
|
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
rsrc.state_set(rsrc.SUSPEND, rsrc.COMPLETE)
|
||||||
|
|
||||||
|
scheduler.TaskRunner(rsrc.resume)()
|
||||||
|
self.assertEqual((rsrc.RESUME, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'delete')
|
||||||
|
self.fc.alarms.delete('foo')
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
scheduler.TaskRunner(rsrc.delete)()
|
||||||
|
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_delete_not_found(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'delete')
|
||||||
|
self.fc.alarms.delete('foo').AndRaise(
|
||||||
|
ceilometerclient_exc.HTTPNotFound())
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
scheduler.TaskRunner(rsrc.delete)()
|
||||||
|
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def _prepare_check_resource(self):
|
||||||
|
snippet = template_format.parse(gnocchi_resources_alarm_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
res = stack['GnoResAlarm']
|
||||||
|
res.ceilometer = mock.Mock()
|
||||||
|
mock_alarm = mock.Mock(enabled=True, state='ok')
|
||||||
|
res.ceilometer().alarms.get.return_value = mock_alarm
|
||||||
|
return res
|
||||||
|
|
||||||
|
def test_check(self):
|
||||||
|
res = self._prepare_check_resource()
|
||||||
|
scheduler.TaskRunner(res.check)()
|
||||||
|
self.assertEqual((res.CHECK, res.COMPLETE), res.state)
|
||||||
|
|
||||||
|
def test_check_failure(self):
|
||||||
|
res = self._prepare_check_resource()
|
||||||
|
res.ceilometer().alarms.get.side_effect = Exception('Boom')
|
||||||
|
|
||||||
|
self.assertRaises(exception.ResourceFailure,
|
||||||
|
scheduler.TaskRunner(res.check))
|
||||||
|
self.assertEqual((res.CHECK, res.FAILED), res.state)
|
||||||
|
self.assertIn('Boom', res.status_reason)
|
||||||
|
|
||||||
|
|
||||||
|
class GnocchiMetricsAlarmTest(common.HeatTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(GnocchiMetricsAlarmTest, self).setUp()
|
||||||
|
self.fc = FakeCeilometerClient()
|
||||||
|
resource._register_class("OS::Ceilometer::GnocchiMetricsAlarm",
|
||||||
|
gnocchi_alarm.CeilometerGnocchiMetricsAlarm)
|
||||||
|
self.m.StubOutWithMock(ceilometer.CeilometerClientPlugin, '_create')
|
||||||
|
|
||||||
|
def create_alarm(self):
|
||||||
|
ceilometer.CeilometerClientPlugin._create().AndReturn(
|
||||||
|
self.fc)
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'create')
|
||||||
|
self.fc.alarms.create(
|
||||||
|
alarm_actions=[],
|
||||||
|
description=u'Do stuff with gnocchi metrics',
|
||||||
|
enabled=True,
|
||||||
|
insufficient_data_actions=None,
|
||||||
|
ok_actions=None,
|
||||||
|
name=mox.IgnoreArg(), type='gnocchi_metrics_threshold',
|
||||||
|
repeat_actions=True,
|
||||||
|
gnocchi_metrics_threshold_rule={
|
||||||
|
"aggregation_method": "mean",
|
||||||
|
"granularity": 60,
|
||||||
|
"evaluation_periods": 1,
|
||||||
|
"threshold": 50,
|
||||||
|
"comparison_operator": "gt",
|
||||||
|
"metrics": ["911fce07-e0d7-4210-8c8c-4a9d811fcabc",
|
||||||
|
"2543d435-fe93-4443-9351-fb0156930f94"],
|
||||||
|
}
|
||||||
|
).AndReturn(FakeCeilometerAlarm())
|
||||||
|
snippet = template_format.parse(gnocchi_metrics_alarm_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
resource_defns = stack.t.resource_definitions(stack)
|
||||||
|
return gnocchi_alarm.CeilometerGnocchiMetricsAlarm(
|
||||||
|
'GnoMetricsAlarm', resource_defns['GnoMetricsAlarm'], stack)
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
self.assertEqual('foo', rsrc.resource_id)
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'update')
|
||||||
|
self.fc.alarms.update(
|
||||||
|
alarm_id='foo',
|
||||||
|
gnocchi_metrics_threshold_rule={
|
||||||
|
'metrics': ['d3d6c642-921e-4fc2-9c5f-15d9a5afb598',
|
||||||
|
'bc60f822-18a0-4a0c-94e7-94c554b00901']})
|
||||||
|
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
|
||||||
|
update_template = copy.deepcopy(rsrc.t)
|
||||||
|
update_template['Properties']['metrics'] = [
|
||||||
|
'd3d6c642-921e-4fc2-9c5f-15d9a5afb598',
|
||||||
|
'bc60f822-18a0-4a0c-94e7-94c554b00901']
|
||||||
|
scheduler.TaskRunner(rsrc.update, update_template)()
|
||||||
|
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_suspend(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'update')
|
||||||
|
self.fc.alarms.update(alarm_id='foo', enabled=False)
|
||||||
|
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
|
||||||
|
scheduler.TaskRunner(rsrc.suspend)()
|
||||||
|
self.assertEqual((rsrc.SUSPEND, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_resume(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'update')
|
||||||
|
self.fc.alarms.update(alarm_id='foo', enabled=True)
|
||||||
|
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
rsrc.state_set(rsrc.SUSPEND, rsrc.COMPLETE)
|
||||||
|
|
||||||
|
scheduler.TaskRunner(rsrc.resume)()
|
||||||
|
self.assertEqual((rsrc.RESUME, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'delete')
|
||||||
|
self.fc.alarms.delete('foo')
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
scheduler.TaskRunner(rsrc.delete)()
|
||||||
|
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def test_delete_not_found(self):
|
||||||
|
rsrc = self.create_alarm()
|
||||||
|
self.m.StubOutWithMock(self.fc.alarms, 'delete')
|
||||||
|
self.fc.alarms.delete('foo').AndRaise(
|
||||||
|
ceilometerclient_exc.HTTPNotFound())
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
scheduler.TaskRunner(rsrc.delete)()
|
||||||
|
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
def _prepare_check_resource(self):
|
||||||
|
snippet = template_format.parse(gnocchi_metrics_alarm_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
res = stack['GnoMetricsAlarm']
|
||||||
|
res.ceilometer = mock.Mock()
|
||||||
|
mock_alarm = mock.Mock(enabled=True, state='ok')
|
||||||
|
res.ceilometer().alarms.get.return_value = mock_alarm
|
||||||
|
return res
|
||||||
|
|
||||||
|
def test_check(self):
|
||||||
|
res = self._prepare_check_resource()
|
||||||
|
scheduler.TaskRunner(res.check)()
|
||||||
|
self.assertEqual((res.CHECK, res.COMPLETE), res.state)
|
||||||
|
|
||||||
|
def test_check_failure(self):
|
||||||
|
res = self._prepare_check_resource()
|
||||||
|
res.ceilometer().alarms.get.side_effect = Exception('Boom')
|
||||||
|
|
||||||
|
self.assertRaises(exception.ResourceFailure,
|
||||||
|
scheduler.TaskRunner(res.check))
|
||||||
|
self.assertEqual((res.CHECK, res.FAILED), res.state)
|
||||||
|
self.assertIn('Boom', res.status_reason)
|
29
contrib/heat_gnocchi/setup.cfg
Normal file
29
contrib/heat_gnocchi/setup.cfg
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
[metadata]
|
||||||
|
name = heat-contrib-gnocchi
|
||||||
|
summary = Heat resources for working gnocchi queues
|
||||||
|
description-file =
|
||||||
|
README.md
|
||||||
|
author = OpenStack
|
||||||
|
author-email = openstack-dev@lists.openstack.org
|
||||||
|
home-page = http://www.openstack.org/
|
||||||
|
classifier =
|
||||||
|
Environment :: OpenStack
|
||||||
|
Intended Audience :: Information Technology
|
||||||
|
Intended Audience :: System Administrators
|
||||||
|
License :: OSI Approved :: Apache Software License
|
||||||
|
Operating System :: POSIX :: Linux
|
||||||
|
Programming Language :: Python
|
||||||
|
Programming Language :: Python :: 2
|
||||||
|
Programming Language :: Python :: 2.7
|
||||||
|
Programming Language :: Python :: 2.6
|
||||||
|
|
||||||
|
[files]
|
||||||
|
packages =
|
||||||
|
heat_gnocchi
|
||||||
|
# Copy to /usr/lib/heat for plugin loading
|
||||||
|
data_files =
|
||||||
|
lib/heat/gnocchi = heat_gnocchi/resources/*
|
||||||
|
|
||||||
|
[global]
|
||||||
|
setup-hooks =
|
||||||
|
pbr.hooks.setup_hook
|
30
contrib/heat_gnocchi/setup.py
Normal file
30
contrib/heat_gnocchi/setup.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
# In python < 2.7.4, a lazy loading of package `pbr` will break
|
||||||
|
# setuptools if some other modules registered functions in `atexit`.
|
||||||
|
# solution from: http://bugs.python.org/issue15881#msg170215
|
||||||
|
try:
|
||||||
|
import multiprocessing # noqa
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
setuptools.setup(
|
||||||
|
setup_requires=['pbr'],
|
||||||
|
pbr=True)
|
@ -313,51 +313,26 @@ class CeilometerAlarm(resource.Resource):
|
|||||||
self.ceilometer().alarms.get(self.resource_id)
|
self.ceilometer().alarms.get(self.resource_id)
|
||||||
|
|
||||||
|
|
||||||
class CombinationAlarm(resource.Resource):
|
class BaseCeilometerAlarm(resource.Resource):
|
||||||
|
|
||||||
support_status = support.SupportStatus(version='2014.1')
|
|
||||||
|
|
||||||
PROPERTIES = (
|
|
||||||
ALARM_IDS, OPERATOR,
|
|
||||||
) = (
|
|
||||||
'alarm_ids', 'operator',
|
|
||||||
)
|
|
||||||
|
|
||||||
properties_schema = {
|
|
||||||
ALARM_IDS: properties.Schema(
|
|
||||||
properties.Schema.LIST,
|
|
||||||
_('List of alarm identifiers to combine.'),
|
|
||||||
required=True,
|
|
||||||
constraints=[constraints.Length(min=1)],
|
|
||||||
update_allowed=True),
|
|
||||||
OPERATOR: properties.Schema(
|
|
||||||
properties.Schema.STRING,
|
|
||||||
_('Operator used to combine the alarms.'),
|
|
||||||
constraints=[constraints.AllowedValues(['and', 'or'])],
|
|
||||||
update_allowed=True)
|
|
||||||
}
|
|
||||||
properties_schema.update(common_properties_schema)
|
|
||||||
|
|
||||||
default_client_name = 'ceilometer'
|
default_client_name = 'ceilometer'
|
||||||
|
|
||||||
def handle_create(self):
|
def handle_create(self):
|
||||||
properties = actions_to_urls(self.stack,
|
properties = actions_to_urls(self.stack,
|
||||||
self.properties)
|
self.properties)
|
||||||
properties['name'] = self.physical_resource_name()
|
properties['name'] = self.physical_resource_name()
|
||||||
properties['type'] = 'combination'
|
properties['type'] = self.ceilometer_alarm_type
|
||||||
|
|
||||||
alarm = self.ceilometer().alarms.create(
|
alarm = self.ceilometer().alarms.create(
|
||||||
**self._reformat_properties(properties))
|
**self._reformat_properties(properties))
|
||||||
self.resource_id_set(alarm.alarm_id)
|
self.resource_id_set(alarm.alarm_id)
|
||||||
|
|
||||||
def _reformat_properties(self, properties):
|
def _reformat_properties(self, properties):
|
||||||
combination_rule = {}
|
rule = {}
|
||||||
for name in [self.ALARM_IDS, self.OPERATOR]:
|
for name in self.PROPERTIES:
|
||||||
value = properties.pop(name, None)
|
value = properties.pop(name, None)
|
||||||
if value:
|
if value:
|
||||||
combination_rule[name] = value
|
rule[name] = value
|
||||||
if combination_rule:
|
if rule:
|
||||||
properties['combination_rule'] = combination_rule
|
properties['%s_rule' % self.ceilometer_alarm_type] = rule
|
||||||
return properties
|
return properties
|
||||||
|
|
||||||
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
||||||
@ -386,6 +361,34 @@ class CombinationAlarm(resource.Resource):
|
|||||||
self.ceilometer().alarms.get(self.resource_id)
|
self.ceilometer().alarms.get(self.resource_id)
|
||||||
|
|
||||||
|
|
||||||
|
class CombinationAlarm(BaseCeilometerAlarm):
|
||||||
|
|
||||||
|
support_status = support.SupportStatus(version='2014.1')
|
||||||
|
|
||||||
|
PROPERTIES = (
|
||||||
|
ALARM_IDS, OPERATOR,
|
||||||
|
) = (
|
||||||
|
'alarm_ids', 'operator',
|
||||||
|
)
|
||||||
|
|
||||||
|
properties_schema = {
|
||||||
|
ALARM_IDS: properties.Schema(
|
||||||
|
properties.Schema.LIST,
|
||||||
|
_('List of alarm identifiers to combine.'),
|
||||||
|
required=True,
|
||||||
|
constraints=[constraints.Length(min=1)],
|
||||||
|
update_allowed=True),
|
||||||
|
OPERATOR: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
_('Operator used to combine the alarms.'),
|
||||||
|
constraints=[constraints.AllowedValues(['and', 'or'])],
|
||||||
|
update_allowed=True)
|
||||||
|
}
|
||||||
|
properties_schema.update(common_properties_schema)
|
||||||
|
|
||||||
|
ceilometer_alarm_type = 'combination'
|
||||||
|
|
||||||
|
|
||||||
def resource_mapping():
|
def resource_mapping():
|
||||||
return {
|
return {
|
||||||
'OS::Ceilometer::Alarm': CeilometerAlarm,
|
'OS::Ceilometer::Alarm': CeilometerAlarm,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user