enable cachetools for gnocchi alarms

- set ttl to an hour since capabilities rarely change (if ever?)
- set cachetools to 1.1.6 since it has some ttl expiration
  improvements and it's a year old so why not.
- i give up trying to disable cache

Change-Id: I1b83ffd32cfd631fc340b068e71f61789388ee73
This commit is contained in:
gord chung 2017-01-12 19:44:42 +00:00
parent 87ec850a29
commit bebe5204fc
4 changed files with 56 additions and 30 deletions

View File

@ -13,6 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import threading
import cachetools
from gnocchiclient import client
from gnocchiclient import exceptions
from oslo_serialization import jsonutils
@ -47,6 +50,9 @@ class AlarmGnocchiThresholdRule(base.AlarmRule):
granularity = wsme.wsattr(wtypes.IntegerType(minimum=1), default=60)
"The time range in seconds over which query"
cache = cachetools.TTLCache(maxsize=1, ttl=3600)
lock = threading.RLock()
@classmethod
def validate_alarm(cls, alarm):
alarm_rule = getattr(alarm, "%s_rule" % alarm.type)
@ -56,10 +62,8 @@ class AlarmGnocchiThresholdRule(base.AlarmRule):
'aggregation_method should be in %s not %s' % (
cls._get_aggregation_methods(), aggregation_method))
# NOTE(sileht): once cachetools is in the requirements
# enable it
# @cachetools.ttl_cache(maxsize=1, ttl=600)
@staticmethod
@cachetools.cached(cache, lock=lock)
def _get_aggregation_methods():
conf = pecan.request.cfg
gnocchi_client = client.Client(

View File

@ -17,7 +17,6 @@
import datetime
import os
from gnocchiclient import exceptions
import mock
import oslo_messaging.conffixture
from oslo_serialization import jsonutils
@ -2920,6 +2919,43 @@ class TestAlarmsRuleGnocchi(TestAlarmsBase):
for r in data
if 'gnocchi_resources_threshold_rule' in r))
def test_post_gnocchi_metrics_alarm_cached(self):
# NOTE(gordc): cache is a decorator and therefore, gets mocked across
# entire scenario. ideally we should test both scenario but tough.
# assume cache will return aggregation_method == ['count'] always.
json = {
'enabled': False,
'name': 'name_post',
'state': 'ok',
'type': 'gnocchi_aggregation_by_metrics_threshold',
'severity': 'critical',
'ok_actions': ['http://something/ok'],
'alarm_actions': ['http://something/alarm'],
'insufficient_data_actions': ['http://something/no'],
'repeat_actions': True,
'gnocchi_aggregation_by_metrics_threshold_rule': {
'metrics': ['b3d9d8ab-05e8-439f-89ad-5e978dd2a5eb',
'009d4faf-c275-46f0-8f2d-670b15bac2b0'],
'comparison_operator': 'le',
'aggregation_method': 'count',
'threshold': 50,
'evaluation_periods': 3,
'granularity': 180,
}
}
with mock.patch('aodh.api.controllers.v2.alarm_rules.'
'gnocchi.client') as clientlib:
c = clientlib.Client.return_value
c.capabilities.list.return_value = {
'aggregation_methods': ['count']}
self.post_json('/alarms', params=json, headers=self.auth_headers)
with mock.patch('aodh.api.controllers.v2.alarm_rules.'
'gnocchi.client') as clientlib:
self.post_json('/alarms', params=json, headers=self.auth_headers)
self.assertFalse(clientlib.called)
def test_post_gnocchi_resources_alarm(self):
json = {
'enabled': False,
@ -2943,38 +2979,15 @@ class TestAlarmsRuleGnocchi(TestAlarmsBase):
}
}
with mock.patch('aodh.api.controllers.v2.alarm_rules.'
'gnocchi.client') as clientlib:
c = clientlib.Client.return_value
c.capabilities.list.side_effect = Exception("boom!")
resp = self.post_json('/alarms', params=json,
headers=self.auth_headers,
expect_errors=True)
self.assertEqual(503, resp.status_code, resp.body)
with mock.patch('aodh.api.controllers.v2.alarm_rules.'
'gnocchi.client') as clientlib:
c = clientlib.Client.return_value
c.capabilities.list.side_effect = (
exceptions.ClientException(500, "my_custom_error"))
resp = self.post_json('/alarms', params=json,
headers=self.auth_headers,
expect_errors=True)
self.assertEqual(500, resp.status_code, resp.body)
self.assertIn('my_custom_error',
resp.json['error_message']['faultstring'])
with mock.patch('aodh.api.controllers.v2.alarm_rules.'
'gnocchi.client') as clientlib:
c = clientlib.Client.return_value
c.capabilities.list.return_value = {
'aggregation_methods': ['count']}
self.post_json('/alarms', params=json, headers=self.auth_headers)
expected = [mock.call.capabilities.list(),
mock.call.resource.get(
"instance",
"209ef69c-c10c-4efb-90ff-46f4b2d90d2e")]
self.assertEqual(expected, c.mock_calls)
expected = mock.call.resource.get(
"instance", "209ef69c-c10c-4efb-90ff-46f4b2d90d2e")
self.assertIn(expected, c.mock_calls)
alarms = list(self.alarm_conn.get_alarms(enabled=False))
self.assertEqual(1, len(alarms))

View File

@ -0,0 +1,8 @@
---
other:
- |
Gnocchi aggregation capabilities are now cached to minimise redundant calls
to Gnocchi when validating aggregation methods. The cache is stored
in-memory for an hour. If additional aggregations are added to Gnocchi,
they will not be proprogated to Aodh's API service for at most an hour or
unless the service is restarted.

View File

@ -31,4 +31,5 @@ stevedore>=1.5.0 # Apache-2.0
tooz>=1.28.0 # Apache-2.0
WebOb>=1.2.3
WSME>=0.8
cachetools>=1.1.6
cotyledon