Add support for 'last' function

Added documentation for last function
Added python parsing for last function
Added tempest tests for last_value function

Change-Id: I4c35321e23e13596a2ef02e7e57306d5685c81ec
Depends-On: Ib5123ed035018757a50d9ebeb7335fbca48054f2
Implements: Blueprint last-value
This commit is contained in:
Ryan Brandt 2016-07-20 11:39:58 -06:00 committed by Tomasz Trębski
parent 968f41fa86
commit 8b6e235a40
3 changed files with 180 additions and 4 deletions

View File

@ -656,11 +656,11 @@ The list of available statistical functions include the following.
```
<function>
::= 'min' | 'max' | 'sum' | 'count' | 'avg'
::= 'min' | 'max' | 'sum' | 'count' | 'avg' | 'last'
```
where 'avg' is the arithmetic average. Note, threshold values are always in the same units as the metric that they are being compared to.
where 'avg' is the arithmetic average and last is the single most recent value of the metric. When using the last function, the values for 'period' and 'periods' will be ignored. Note, threshold values are always in the same units as the metric that they are being compared to.
#### Simple Example
@ -686,6 +686,7 @@ Functions work on all metric measurements during the period time frame.
* sum (returns the sum of all the values)
* count (returns the number of metric observations)
* avg (returns the average of all the values)
* last (returns the single most recent value, ignores values for 'period' and 'periods')
The metric is a complex identifier that says the name and optional dimensions.

View File

@ -1,6 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2014 Hewlett-Packard
# (C) Copyright 2016 Hewlett Packard Enterprise LP
#
# 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
@ -212,7 +213,8 @@ min = pyparsing.CaselessLiteral("min")
avg = pyparsing.CaselessLiteral("avg")
count = pyparsing.CaselessLiteral("count")
sum = pyparsing.CaselessLiteral("sum")
func = (max | min | avg | count | sum)("func")
last = pyparsing.CaselessLiteral("last")
func = (max | min | avg | count | sum | last)("func")
less_than_op = (
(pyparsing.CaselessLiteral("<") | pyparsing.CaselessLiteral("lt")))
@ -311,7 +313,9 @@ def main():
"count(log.error{test=1}, deterministic) > 1.0",
"count(log.error{test=1}, deterministic, 120) > 1.0"
"count(log.error{test=1}, deterministic, 120) > 1.0",
"last(test_metric{hold=here}) < 13"
]
for expr in expr_list:

View File

@ -0,0 +1,171 @@
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
#
# 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 time
import base
from monasca_tempest_tests.tests.api import helpers
from tempest.common.utils import data_utils
from tempest import test
WAIT_SECS = 10
class TestAlarmTransitions(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestAlarmTransitions, cls).resource_setup()
@classmethod
def resource_cleanup(cls):
super(TestAlarmTransitions, cls).resource_cleanup()
def _wait_for_alarm_creation(self, definition_id):
for x in xrange(WAIT_SECS):
time.sleep(1)
resp, resp_body = self.monasca_client.list_alarms(
query_params="?alarm_definition_id=" + definition_id)
self.assertEqual(200, resp.status)
if len(resp_body['elements']) != 0:
break
self.assertEqual(1, len(resp_body['elements']))
alarm_id = resp_body['elements'][0]['id']
initial_state = resp_body['elements'][0]['state']
return alarm_id, initial_state
def _wait_for_alarm_transition(self, alarm_id, expected_state):
for x in xrange(WAIT_SECS):
time.sleep(1)
resp, resp_body = self.monasca_client.get_alarm(alarm_id)
self.assertEqual(200, resp.status)
if resp_body['state'] == expected_state:
break
self.assertEqual(expected_state, resp_body['state'])
def _send_measurement(self, metric_def, value):
metric = helpers.create_metric(name=metric_def['name'],
dimensions=metric_def['dimensions'],
value=value)
resp, resp_body = self.monasca_client.create_metrics([metric])
self.assertEqual(204, resp.status)
@test.attr(type="gate")
def test_alarm_max_function(self):
metric_def = {'name': data_utils.rand_name("max_test"),
'dimensions': {
'dim_to_match': data_utils.rand_name("max_match")
}}
expression = "max(" + metric_def['name'] + ") > 14"
definition = helpers.create_alarm_definition(name="Test Max Function",
description="",
expression=expression,
match_by=["dim_to_match"])
resp, resp_body = self.monasca_client.create_alarm_definitions(definition)
self.assertEqual(201, resp.status)
definition_id = resp_body['id']
time.sleep(1)
self._send_measurement(metric_def, 1)
alarm_id, initial_state = self._wait_for_alarm_creation(definition_id)
self.assertEqual("UNDETERMINED", initial_state)
self._send_measurement(metric_def, 20)
self._wait_for_alarm_transition(alarm_id, "ALARM")
@test.attr(type="gate")
def test_alarm_max_with_deterministic(self):
metric_def = {'name': data_utils.rand_name("max_deterministic_test"),
'dimensions': {
'dim_to_match': data_utils.rand_name("max_match")
}}
expression = "max(" + metric_def['name'] + ",deterministic) > 14"
definition = helpers.create_alarm_definition(name="Test Max Deterministic Function",
description="",
expression=expression,
match_by=["dim_to_match"])
resp, resp_body = self.monasca_client.create_alarm_definitions(definition)
self.assertEqual(201, resp.status)
definition_id = resp_body['id']
time.sleep(1)
self._send_measurement(metric_def, 1)
alarm_id, initial_state = self._wait_for_alarm_creation(definition_id)
self.assertEqual("OK", initial_state)
self._send_measurement(metric_def, 20)
self._wait_for_alarm_transition(alarm_id, "ALARM")
@test.attr(type="gate")
def test_alarm_last_function(self):
metric_def = {'name': data_utils.rand_name("last_test"),
'dimensions': {
'dim_to_match': data_utils.rand_name("last_match")
}}
expression = "last(" + metric_def['name'] + ") > 14"
definition = helpers.create_alarm_definition(name="Test Last Function",
description="",
expression=expression,
match_by=["dim_to_match"])
resp, resp_body = self.monasca_client.create_alarm_definitions(definition)
self.assertEqual(201, resp.status)
definition_id = resp_body['id']
time.sleep(1)
self._send_measurement(metric_def, 1)
alarm_id, initial_state = self._wait_for_alarm_creation(definition_id)
self.assertEqual("OK", initial_state)
self._send_measurement(metric_def, 20)
self._wait_for_alarm_transition(alarm_id, "ALARM")
self._send_measurement(metric_def, 3)
self._wait_for_alarm_transition(alarm_id, "OK")
@test.attr(type="gate")
def test_alarm_last_with_deterministic(self):
metric_def = {'name': data_utils.rand_name("last_deterministic_test"),
'dimensions': {
'dim_to_match': data_utils.rand_name("last_match")
}}
expression = "last(" + metric_def['name'] + ",deterministic) > 14"
definition = helpers.create_alarm_definition(name="Test Last Deterministic Function",
description="",
expression=expression,
match_by=["dim_to_match"])
resp, resp_body = self.monasca_client.create_alarm_definitions(definition)
self.assertEqual(201, resp.status)
definition_id = resp_body['id']
time.sleep(1)
self._send_measurement(metric_def, 1)
alarm_id, initial_state = self._wait_for_alarm_creation(definition_id)
self.assertEqual("OK", initial_state)
self._send_measurement(metric_def, 20)
self._wait_for_alarm_transition(alarm_id, "ALARM")
self._send_measurement(metric_def, 3)
self._wait_for_alarm_transition(alarm_id, "OK")