Abort scenario execution on SLA failure
* Change the api of the SLA classes: - add_iteration() - processes a single iteration result from the queue - result() - return the SLAResult based on the data processed so far. It now also returns a successful result in case there was no iterations data. * Add a new SLAChecker class: - add_iteration() - processes a single iteration result with different SLAs - results() - return cumulative SLA results for all SLAs * Change the benchmark engine so that it supports scenario runner aborts on SLA failure * Support the "abort on SLA failure" feature in the CLI: rally task start ... --abort-on-sla-failure * Modify the SLA detailed messages (cleaner text and less decimal places) * Update unit and functional tests correspondingly. Also remove the usage of the deprecated "max_failure_percent" SLA from the functional tests. Change-Id: I91894a81649815428fd1ac7afcfce9cf47160fc9
This commit is contained in:
parent
66d4f89f56
commit
e188a81a5f
@ -13,6 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import unittest
|
import unittest
|
||||||
@ -243,6 +244,210 @@ class TaskTestCase(unittest.TestCase):
|
|||||||
r"(?P<task_id>[0-9a-f\-]{36}): started", output)
|
r"(?P<task_id>[0-9a-f\-]{36}): started", output)
|
||||||
self.assertIsNotNone(result)
|
self.assertIsNotNone(result)
|
||||||
|
|
||||||
|
def _test_start_abort_on_sla_failure_success(self, cfg, times):
|
||||||
|
rally = utils.Rally()
|
||||||
|
with mock.patch.dict("os.environ", utils.TEST_ENV):
|
||||||
|
deployment_id = envutils.get_global("RALLY_DEPLOYMENT")
|
||||||
|
config = utils.TaskConfig(cfg)
|
||||||
|
rally(("task start --task %(task_file)s "
|
||||||
|
"--deployment %(deployment_id)s --abort-on-sla-failure") %
|
||||||
|
{"task_file": config.filename,
|
||||||
|
"deployment_id": deployment_id})
|
||||||
|
results = json.loads(rally("task results"))
|
||||||
|
iterations_completed = len(results[0]["result"])
|
||||||
|
self.assertEqual(times, iterations_completed)
|
||||||
|
|
||||||
|
def test_start_abort_on_sla_failure_success_constant(self):
|
||||||
|
times = 100
|
||||||
|
cfg = {
|
||||||
|
"Dummy.dummy": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"sleep": 0.1
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": times,
|
||||||
|
"concurrency": 5
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"failure_rate": {"max": 0.0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self._test_start_abort_on_sla_failure_success(cfg, times)
|
||||||
|
|
||||||
|
def test_start_abort_on_sla_failure_success_serial(self):
|
||||||
|
times = 100
|
||||||
|
cfg = {
|
||||||
|
"Dummy.dummy": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"sleep": 0.1
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "serial",
|
||||||
|
"times": times
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"failure_rate": {"max": 0.0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self._test_start_abort_on_sla_failure_success(cfg, times)
|
||||||
|
|
||||||
|
def test_start_abort_on_sla_failure_success_rps(self):
|
||||||
|
times = 100
|
||||||
|
cfg = {
|
||||||
|
"Dummy.dummy": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"sleep": 0.1
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "rps",
|
||||||
|
"times": times,
|
||||||
|
"rps": 20
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"failure_rate": {"max": 0.0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self._test_start_abort_on_sla_failure_success(cfg, times)
|
||||||
|
|
||||||
|
def _test_start_abort_on_sla_failure(self, cfg, times):
|
||||||
|
rally = utils.Rally()
|
||||||
|
with mock.patch.dict("os.environ", utils.TEST_ENV):
|
||||||
|
deployment_id = envutils.get_global("RALLY_DEPLOYMENT")
|
||||||
|
config = utils.TaskConfig(cfg)
|
||||||
|
rally(("task start --task %(task_file)s "
|
||||||
|
"--deployment %(deployment_id)s --abort-on-sla-failure") %
|
||||||
|
{"task_file": config.filename,
|
||||||
|
"deployment_id": deployment_id})
|
||||||
|
results = json.loads(rally("task results"))
|
||||||
|
iterations_completed = len(results[0]["result"])
|
||||||
|
# NOTE(msdubov): Change '<=' to '<' as soon as we fix the runners.
|
||||||
|
self.assertTrue(iterations_completed <= times)
|
||||||
|
|
||||||
|
def test_start_abort_on_sla_failure_max_seconds_constant(self):
|
||||||
|
times = 100
|
||||||
|
cfg = {
|
||||||
|
"Dummy.dummy": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"sleep": 0.1
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": times,
|
||||||
|
"concurrency": 5
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"max_seconds_per_iteration": 0.01
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self._test_start_abort_on_sla_failure(cfg, times)
|
||||||
|
|
||||||
|
def test_start_abort_on_sla_failure_max_seconds_serial(self):
|
||||||
|
times = 100
|
||||||
|
cfg = {
|
||||||
|
"Dummy.dummy": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"sleep": 0.1
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "serial",
|
||||||
|
"times": times
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"max_seconds_per_iteration": 0.01
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self._test_start_abort_on_sla_failure(cfg, times)
|
||||||
|
|
||||||
|
def test_start_abort_on_sla_failure_max_seconds_rps(self):
|
||||||
|
times = 100
|
||||||
|
cfg = {
|
||||||
|
"Dummy.dummy": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"sleep": 0.1
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "rps",
|
||||||
|
"times": times,
|
||||||
|
"rps": 20
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"max_seconds_per_iteration": 0.01
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self._test_start_abort_on_sla_failure(cfg, times)
|
||||||
|
|
||||||
|
def test_start_abort_on_sla_failure_max_failure_rate_constant(self):
|
||||||
|
times = 100
|
||||||
|
cfg = {
|
||||||
|
"Dummy.dummy_exception": [
|
||||||
|
{
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": times,
|
||||||
|
"concurrency": 5
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"failure_rate": {"max": 0.0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self._test_start_abort_on_sla_failure(cfg, times)
|
||||||
|
|
||||||
|
def test_start_abort_on_sla_failure_max_failure_rate_serial(self):
|
||||||
|
times = 100
|
||||||
|
cfg = {
|
||||||
|
"Dummy.dummy_exception": [
|
||||||
|
{
|
||||||
|
"runner": {
|
||||||
|
"type": "serial",
|
||||||
|
"times": times
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"failure_rate": {"max": 0.0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self._test_start_abort_on_sla_failure(cfg, times)
|
||||||
|
|
||||||
|
def test_start_abort_on_sla_failure_max_failure_rate_rps(self):
|
||||||
|
times = 100
|
||||||
|
cfg = {
|
||||||
|
"Dummy.dummy_exception": [
|
||||||
|
{
|
||||||
|
"runner": {
|
||||||
|
"type": "rps",
|
||||||
|
"times": times,
|
||||||
|
"rps": 20
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"failure_rate": {"max": 0.0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self._test_start_abort_on_sla_failure(cfg, times)
|
||||||
|
|
||||||
# NOTE(oanufriev): Not implemented
|
# NOTE(oanufriev): Not implemented
|
||||||
def test_abort(self):
|
def test_abort(self):
|
||||||
pass
|
pass
|
||||||
@ -251,7 +456,7 @@ class TaskTestCase(unittest.TestCase):
|
|||||||
class SLATestCase(unittest.TestCase):
|
class SLATestCase(unittest.TestCase):
|
||||||
|
|
||||||
def _get_sample_task_config(self, max_seconds_per_iteration=4,
|
def _get_sample_task_config(self, max_seconds_per_iteration=4,
|
||||||
max_failure_percent=0):
|
failure_rate_max=0):
|
||||||
return {
|
return {
|
||||||
"KeystoneBasic.create_and_list_users": [
|
"KeystoneBasic.create_and_list_users": [
|
||||||
{
|
{
|
||||||
@ -265,7 +470,7 @@ class SLATestCase(unittest.TestCase):
|
|||||||
},
|
},
|
||||||
"sla": {
|
"sla": {
|
||||||
"max_seconds_per_iteration": max_seconds_per_iteration,
|
"max_seconds_per_iteration": max_seconds_per_iteration,
|
||||||
"max_failure_percent": max_failure_percent,
|
"failure_rate": {"max": failure_rate_max}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -289,9 +494,9 @@ class SLATestCase(unittest.TestCase):
|
|||||||
"detail": mock.ANY,
|
"detail": mock.ANY,
|
||||||
"pos": 0, "status": "PASS"},
|
"pos": 0, "status": "PASS"},
|
||||||
{"benchmark": "KeystoneBasic.create_and_list_users",
|
{"benchmark": "KeystoneBasic.create_and_list_users",
|
||||||
"criterion": "max_failure_percent",
|
"criterion": "failure_rate",
|
||||||
"detail": mock.ANY,
|
"detail": mock.ANY,
|
||||||
"pos": 0, "status": "PASS"},
|
"pos": 0, "status": "PASS"}
|
||||||
]
|
]
|
||||||
data = rally("task sla_check --json", getjson=True)
|
data = rally("task sla_check --json", getjson=True)
|
||||||
self.assertEqual(expected, data)
|
self.assertEqual(expected, data)
|
||||||
|
Loading…
Reference in New Issue
Block a user