From 3bef76d030a14937eaf933ec807f4c4fca481a28 Mon Sep 17 00:00:00 2001 From: vgusev Date: Mon, 9 Feb 2015 14:19:21 +0300 Subject: [PATCH] [Ceilometer] Add CeilometerAlarms.create_alarm_and_get_history scenario Added new scenario for testing Ceilometer alarms Change-Id: If7a47a52244cf187218d90f8c6cd151d458bfe78 --- rally-jobs/rally.yaml | 23 +++++++++++ .../benchmark/scenarios/ceilometer/alarms.py | 30 +++++++++++++++ .../scenarios/ceilometer/resources.py | 2 +- rally/benchmark/scenarios/ceilometer/utils.py | 38 ++++++++++++++++++- rally/benchmark/utils.py | 4 ++ .../create-alarm-and-get-history.json | 27 +++++++++++++ .../create-alarm-and-get-history.yaml | 20 ++++++++++ .../scenarios/ceilometer/test_alarms.py | 15 ++++++++ .../scenarios/ceilometer/test_resources.py | 2 +- .../scenarios/ceilometer/test_utils.py | 38 ++++++++++++++++++- tests/unit/benchmark/test_utils.py | 9 +++++ tests/unit/fakes.py | 14 +++++++ 12 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 samples/tasks/scenarios/ceilometer/create-alarm-and-get-history.json create mode 100644 samples/tasks/scenarios/ceilometer/create-alarm-and-get-history.yaml diff --git a/rally-jobs/rally.yaml b/rally-jobs/rally.yaml index 65ca66ee6f..93fa92cf69 100755 --- a/rally-jobs/rally.yaml +++ b/rally-jobs/rally.yaml @@ -176,6 +176,29 @@ failure_rate: max: 0 + CeilometerAlarms.create_alarm_and_get_history: + - + args: + meter_name: "ram_util" + threshold: 10.0 + type: "threshold" + state: "ok" + statistic: "avg" + alarm_actions: ["http://localhost:8776/alarm"] + ok_actions: ["http://localhost:8776/ok"] + insufficient_data_actions: ["http://localhost:8776/notok"] + runner: + type: "constant" + times: 10 + concurrency: 5 + context: + users: + tenants: 2 + users_per_tenant: 2 + sla: + failure_rate: + max: 0 + CeilometerAlarms.list_alarms: - runner: diff --git a/rally/benchmark/scenarios/ceilometer/alarms.py b/rally/benchmark/scenarios/ceilometer/alarms.py index 4febd7d04a..7d53f8f434 100644 --- a/rally/benchmark/scenarios/ceilometer/alarms.py +++ b/rally/benchmark/scenarios/ceilometer/alarms.py @@ -106,3 +106,33 @@ class CeilometerAlarms(ceilometerutils.CeilometerScenario): """ alarm = self._create_alarm(meter_name, threshold, kwargs) self._delete_alarm(alarm.alarm_id) + + @validation.required_services(consts.Service.CEILOMETER) + @validation.required_openstack(users=True) + @base.scenario(context={"cleanup": ["ceilometer"]}) + def create_alarm_and_get_history(self, meter_name, threshold, state, + timeout=60, **kwargs): + """Create an alarm, get and set the state and get the alarm history. + + This scenario makes following queries: + GET /v2/alarms/{alarm_id}/history + GET /v2/alarms/{alarm_id}/state + PUT /v2/alarms/{alarm_id}/state + Initially alarm is created and then get the state of the created alarm + using its alarm_id. Then get the history of the alarm. And finally the + state of the alarm is updated using given state. meter_name and + threshold are required parameters for alarm creation. kwargs stores + other optional parameters like 'ok_actions', 'project_id' etc that may + be passed while alarm creation. + + :param meter_name: specifies meter name of the alarm + :param threshold: specifies alarm threshold + :param state: an alarm state to be set + :param timeout: The number of seconds for which to attempt a + successful check of the alarm state + :param kwargs: specifies optional arguments for alarm creation. + """ + alarm = self._create_alarm(meter_name, threshold, kwargs) + self._get_alarm_state(alarm.alarm_id) + self._get_alarm_history(alarm.alarm_id) + self._set_alarm_state(alarm, state, timeout) diff --git a/rally/benchmark/scenarios/ceilometer/resources.py b/rally/benchmark/scenarios/ceilometer/resources.py index 00370e20a8..e737cc2381 100644 --- a/rally/benchmark/scenarios/ceilometer/resources.py +++ b/rally/benchmark/scenarios/ceilometer/resources.py @@ -29,4 +29,4 @@ class CeilometerResource(ceilometerutils.CeilometerScenario): This scenario fetches list of all resources using GET /v2/resources. """ - self._list_resources() + self._list_resources() \ No newline at end of file diff --git a/rally/benchmark/scenarios/ceilometer/utils.py b/rally/benchmark/scenarios/ceilometer/utils.py index 6bba6c641a..ade09d399c 100644 --- a/rally/benchmark/scenarios/ceilometer/utils.py +++ b/rally/benchmark/scenarios/ceilometer/utils.py @@ -13,6 +13,7 @@ # under the License. from rally.benchmark.scenarios import base +from rally.benchmark import utils as bench_utils class CeilometerScenario(base.Scenario): @@ -81,6 +82,41 @@ class CeilometerScenario(base.Scenario): """ self.clients("ceilometer").alarms.update(alarm_id, **alarm_dict_delta) + @base.atomic_action_timer("ceilometer.get_alarm_history") + def _get_alarm_history(self, alarm_id): + """Assemble the alarm history requested. + + :param alarm_id: specifies id of the alarm + :returns: list of alarm changes + """ + return self.clients("ceilometer").alarms.get_history(alarm_id) + + @base.atomic_action_timer("ceilometer.get_alarm_state") + def _get_alarm_state(self, alarm_id): + """Get the state of the alarm. + + :param alarm_id: specifies id of the alarm + :returns: state of the alarm + """ + return self.clients("ceilometer").alarms.get_state(alarm_id) + + @base.atomic_action_timer("ceilometer.set_alarm_state") + def _set_alarm_state(self, alarm, state, timeout): + """Set the state of the alarm. + + :param alarm: alarm instance + :param state: an alarm state to be set + :param timeout: The number of seconds for which to attempt a + successful check of the alarm state. + :returns: alarm in the set state + """ + self.clients("ceilometer").alarms.set_state(alarm.alarm_id, state) + return bench_utils.wait_for(alarm, + is_ready=bench_utils.resource_is(state), + update_resource=bench_utils + .get_from_manager(), + timeout=timeout, check_interval=1) + @base.atomic_action_timer("ceilometer.get_meters") def _list_meters(self): """Get list of user's meters.""" @@ -178,4 +214,4 @@ class CeilometerScenario(base.Scenario): :returns: queried samples """ return self.clients("ceilometer").query_samples.query( - filter, orderby, limit) + filter, orderby, limit) \ No newline at end of file diff --git a/rally/benchmark/utils.py b/rally/benchmark/utils.py index a048ed2264..862973095f 100644 --- a/rally/benchmark/utils.py +++ b/rally/benchmark/utils.py @@ -32,6 +32,10 @@ def get_status(resource): if ((hasattr(resource, "stack_status") and isinstance(resource.stack_status, six.string_types))): return resource.stack_status.upper() + # workaround for ceilometer alarms - using state instead of status + if ((hasattr(resource, "state") and + isinstance(resource.state, six.string_types))): + return resource.state.upper() return getattr(resource, "status", "NONE").upper() diff --git a/samples/tasks/scenarios/ceilometer/create-alarm-and-get-history.json b/samples/tasks/scenarios/ceilometer/create-alarm-and-get-history.json new file mode 100644 index 0000000000..8432feb366 --- /dev/null +++ b/samples/tasks/scenarios/ceilometer/create-alarm-and-get-history.json @@ -0,0 +1,27 @@ +{ + "CeilometerAlarms.create_alarm_and_get_history": [ + { + "args": { + "meter_name": "ram_util", + "threshold": 10.0, + "type": "threshold", + "state": "ok", + "statistic": "avg", + "alarm_actions": ["http://localhost:8776/alarm"], + "ok_actions": ["http://localhost:8776/ok"], + "insufficient_data_actions": ["http://localhost:8776/notok"] + }, + "runner": { + "type": "constant", + "times": 10, + "concurrency": 5 + }, + "context": { + "users": { + "tenants": 2, + "users_per_tenant": 2 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/ceilometer/create-alarm-and-get-history.yaml b/samples/tasks/scenarios/ceilometer/create-alarm-and-get-history.yaml new file mode 100644 index 0000000000..dff289ea70 --- /dev/null +++ b/samples/tasks/scenarios/ceilometer/create-alarm-and-get-history.yaml @@ -0,0 +1,20 @@ +--- + CeilometerAlarms.create_alarm_and_get_history: + - + args: + meter_name: "ram_util" + threshold: 10.0 + type: "threshold" + state: "ok" + statistic: "avg" + alarm_actions: ["http://localhost:8776/alarm"] + ok_actions: ["http://localhost:8776/ok"] + insufficient_data_actions: ["http://localhost:8776/notok"] + runner: + type: "constant" + times: 10 + concurrency: 5 + context: + users: + tenants: 2 + users_per_tenant: 2 diff --git a/tests/unit/benchmark/scenarios/ceilometer/test_alarms.py b/tests/unit/benchmark/scenarios/ceilometer/test_alarms.py index 6bb702e549..05e1c3e076 100644 --- a/tests/unit/benchmark/scenarios/ceilometer/test_alarms.py +++ b/tests/unit/benchmark/scenarios/ceilometer/test_alarms.py @@ -80,3 +80,18 @@ class CeilometerAlarmsTestCase(test.TestCase): "fake_threshold", {"fakearg": "f"}) scenario._delete_alarm.assert_called_once_with(fake_alarm.alarm_id) + + def test_create_and_get_alarm_history(self): + alarm = mock.Mock(alarm_id="foo_id") + scenario = alarms.CeilometerAlarms() + scenario._create_alarm = mock.MagicMock(return_value=alarm) + scenario._get_alarm_state = mock.MagicMock() + scenario._get_alarm_history = mock.MagicMock() + scenario._set_alarm_state = mock.MagicMock() + scenario.create_alarm_and_get_history( + "meter_name", "threshold", "state", 60, fakearg="f") + scenario._create_alarm.assert_called_once_with( + "meter_name", "threshold", {"fakearg": "f"}) + scenario._get_alarm_state.assert_called_once_with("foo_id") + scenario._get_alarm_history.assert_called_once_with("foo_id") + scenario._set_alarm_state.assert_called_once_with(alarm, "state", 60) diff --git a/tests/unit/benchmark/scenarios/ceilometer/test_resources.py b/tests/unit/benchmark/scenarios/ceilometer/test_resources.py index cb269ad4ed..63c169139b 100644 --- a/tests/unit/benchmark/scenarios/ceilometer/test_resources.py +++ b/tests/unit/benchmark/scenarios/ceilometer/test_resources.py @@ -24,4 +24,4 @@ class CeilometerResourcesTestCase(test.TestCase): scenario._list_resources = mock.MagicMock() scenario.list_resources() - scenario._list_resources.assert_called_once_with() + scenario._list_resources.assert_called_once_with() \ No newline at end of file diff --git a/tests/unit/benchmark/scenarios/ceilometer/test_utils.py b/tests/unit/benchmark/scenarios/ceilometer/test_utils.py index 0922d07b9a..065a90b074 100644 --- a/tests/unit/benchmark/scenarios/ceilometer/test_utils.py +++ b/tests/unit/benchmark/scenarios/ceilometer/test_utils.py @@ -13,12 +13,14 @@ # under the License. import mock +from oslotest import mockpatch from rally.benchmark.scenarios.ceilometer import utils from tests.unit import fakes from tests.unit import test -UTILS = "rally.benchmark.scenarios.ceilometer.utils" +BM_UTILS = "rally.benchmark.utils" +CEILOMETER_UTILS = "rally.benchmark.scenarios.ceilometer.utils" class CeilometerScenarioTestCase(test.TestCase): @@ -27,6 +29,14 @@ class CeilometerScenarioTestCase(test.TestCase): self.scenario = utils.CeilometerScenario() self.scenario.clients = mock.MagicMock( return_value=fakes.FakeCeilometerClient()) + self.res_is = mockpatch.Patch(BM_UTILS + ".resource_is") + self.get_fm = mockpatch.Patch(BM_UTILS + ".get_from_manager") + self.wait_for = mockpatch.Patch(CEILOMETER_UTILS + + ".bench_utils.wait_for") + self.useFixture(self.wait_for) + self.useFixture(self.res_is) + self.useFixture(self.get_fm) + self.gfm = self.get_fm.mock def test__list_alarms(self): alarm1_id = "fake_alarm1_id" @@ -71,6 +81,32 @@ class CeilometerScenarioTestCase(test.TestCase): self.scenario._update_alarm(fake_alarm.alarm_id, fake_alarm_dict_diff) self.assertEqual(fake_alarm.description, "Changed Test Description") + def test__get_alarm_history(self): + fake_history = self.scenario._get_alarm_history("fake-alarm") + self.assertEqual(fake_history, ["fake-alarm-history"]) + + def test__get_alarm_state(self): + fake_alarm_dict = {"alarm_id": "alarm-id", "state": "alarm-state"} + fake_alarm = self.scenario._create_alarm("fake-meter-name", 100, + fake_alarm_dict) + fake_state = self.scenario._get_alarm_state(fake_alarm.alarm_id) + self.assertEqual(fake_state, "alarm-state") + + @mock.patch(CEILOMETER_UTILS + ".CeilometerScenario.clients") + def test__set_alarm_state(self, mock_clients): + alarm = mock.Mock() + mock_clients("ceilometer").alarms.create.return_value = alarm + return_alarm = self.scenario._set_alarm_state(alarm, "ok", 100) + self.wait_for.mock.assert_called_once_with( + alarm, + is_ready=self.res_is.mock(), + update_resource=self.gfm(), + timeout=100, check_interval=1) + self.res_is.mock.assert_has_calls([mock.call("ok")]) + self.assertEqual(self.wait_for.mock(), return_alarm) + self._test_atomic_action_timer(self.scenario.atomic_actions(), + "ceilometer.set_alarm_state") + def test__list_meters(self): """Test _list_meters.""" fake_meters = self.scenario._list_meters() diff --git a/tests/unit/benchmark/test_utils.py b/tests/unit/benchmark/test_utils.py index 60f523da18..7d05f0f4ac 100644 --- a/tests/unit/benchmark/test_utils.py +++ b/tests/unit/benchmark/test_utils.py @@ -102,6 +102,15 @@ class BenchmarkUtilsTestCase(test.TestCase): self.assertRaises(exceptions.GetResourceNotFound, get_from_manager, resource) + def test_get_from_manager_in_deleted_state_for_ceilometer_resource(self): + get_from_manager = utils.get_from_manager() + manager = fakes.FakeManager() + resource = fakes.FakeResource(manager=manager) + resource.state = "DELETED" + manager._cache(resource) + self.assertRaises(exceptions.GetResourceNotFound, + get_from_manager, resource) + def test_get_from_manager_not_found(self): get_from_manager = utils.get_from_manager() manager = mock.MagicMock() diff --git a/tests/unit/fakes.py b/tests/unit/fakes.py index a2a12a0ec4..0bea395ffe 100644 --- a/tests/unit/fakes.py +++ b/tests/unit/fakes.py @@ -207,6 +207,7 @@ class FakeAlarm(FakeResource): super(FakeAlarm, self).__init__(manager) self.meter_name = kwargs.get("meter_name") self.threshold = kwargs.get("threshold") + self.state = kwargs.get("state", "fake-alarm-state") self.alarm_id = kwargs.get("alarm_id", "fake-alarm-id") self.optional_args = kwargs.get("optional_args", {}) @@ -716,6 +717,19 @@ class FakeAlarmManager(FakeManager): del self.cache[alarm.id] self.resources_order.remove(alarm.id) + def get_state(self, alarm_id): + alarm = self.find(alarm_id=alarm_id) + if alarm is not None: + return getattr(alarm, "state", "fake-alarm-state") + + def get_history(self, alarm_id): + return ["fake-alarm-history"] + + def set_state(self, alarm_id, state): + alarm = self.find(alarm_id=alarm_id) + if alarm is not None: + return setattr(alarm, "state", state) + class FakeSampleManager(FakeManager):