From 5fa6559b0b6c175b9f655c2cb89cdf61b4823eef Mon Sep 17 00:00:00 2001 From: Angus Salkeld Date: Wed, 13 May 2015 14:24:04 +1000 Subject: [PATCH] Add basic Ceilometer alarm test This sends a manual ceilometer sample to trigger the alarm, then confirms that the autoscale policy/group reacts correctly. Note: this doesn't used ScenarioBaseTest as it skips the test unnecessarily on unused images and networks. Change-Id: I5c842779d90497ba88df66bbfd8f447679645192 Depends-On: Ib3795bcca9d5ec3d68c6443a9854dbc56118ca40 --- heat_integrationtests/common/clients.py | 27 +++++++++ heat_integrationtests/common/test.py | 1 + heat_integrationtests/pre_test_hook.sh | 2 + heat_integrationtests/requirements.txt | 1 + .../templates/test_ceilometer_alarm.yaml | 33 +++++++++++ .../scenario/test_ceilometer_alarm.py | 57 +++++++++++++++++++ 6 files changed, 121 insertions(+) create mode 100644 heat_integrationtests/scenario/templates/test_ceilometer_alarm.yaml create mode 100644 heat_integrationtests/scenario/test_ceilometer_alarm.py diff --git a/heat_integrationtests/common/clients.py b/heat_integrationtests/common/clients.py index 1ba3a212ad..6042456fe4 100644 --- a/heat_integrationtests/common/clients.py +++ b/heat_integrationtests/common/clients.py @@ -12,6 +12,7 @@ import os +import ceilometerclient.client import cinderclient.client import heatclient.client import keystoneclient.exceptions @@ -30,6 +31,7 @@ class ClientManager(object): CINDERCLIENT_VERSION = '1' HEATCLIENT_VERSION = '1' NOVACLIENT_VERSION = '2' + CEILOMETER_VERSION = '2' def __init__(self, conf): self.conf = conf @@ -39,6 +41,7 @@ class ClientManager(object): self.network_client = self._get_network_client() self.volume_client = self._get_volume_client() self.object_client = self._get_object_client() + self.metering_client = self._get_metering_client() def _get_orchestration_client(self): region = self.conf.region @@ -136,3 +139,27 @@ class ClientManager(object): 'insecure': dscv, } return swiftclient.client.Connection(**args) + + def _get_metering_client(self): + dscv = self.conf.disable_ssl_certificate_validation + + keystone = self._get_identity_client() + endpoint = keystone.service_catalog.url_for( + attr='region', + filter_value=self.conf.region, + service_type='metering', + endpoint_type='publicURL') + + args = { + 'username': self.conf.username, + 'password': self.conf.password, + 'tenant_name': self.conf.tenant_name, + 'auth_url': self.conf.auth_url, + 'insecure': dscv, + 'region_name': self.conf.region, + 'endpoint_type': 'publicURL', + 'service_type': 'metering', + } + + return ceilometerclient.client.Client(self.CEILOMETER_VERSION, + endpoint, **args) diff --git a/heat_integrationtests/common/test.py b/heat_integrationtests/common/test.py index 7c8300d60a..4168fb4aff 100644 --- a/heat_integrationtests/common/test.py +++ b/heat_integrationtests/common/test.py @@ -87,6 +87,7 @@ class HeatIntegrationTest(testscenarios.WithScenarios, self.network_client = self.manager.network_client self.volume_client = self.manager.volume_client self.object_client = self.manager.object_client + self.metering_client = self.manager.metering_client self.useFixture(fixtures.FakeLogger(format=_LOG_FORMAT)) self.updated_time = {} diff --git a/heat_integrationtests/pre_test_hook.sh b/heat_integrationtests/pre_test_hook.sh index 3a9b6fb48b..09a2168eef 100755 --- a/heat_integrationtests/pre_test_hook.sh +++ b/heat_integrationtests/pre_test_hook.sh @@ -16,6 +16,8 @@ localrc_path=$BASE/new/devstack/localrc localconf=$BASE/new/devstack/local.conf + +echo "CEILOMETER_PIPELINE_INTERVAL=60" >> $localrc_path echo "HEAT_ENABLE_ADOPT_ABANDON=True" >> $localrc_path echo -e '[[post-config|$HEAT_CONF]]\n[DEFAULT]\n' >> $localconf echo -e 'notification_driver=messagingv2\n' >> $localconf diff --git a/heat_integrationtests/requirements.txt b/heat_integrationtests/requirements.txt index 2f08f9a190..5d2aefbd5a 100644 --- a/heat_integrationtests/requirements.txt +++ b/heat_integrationtests/requirements.txt @@ -4,6 +4,7 @@ oslo.messaging>=1.8.0,<1.9.0 # Apache-2.0 oslo.config>=1.9.3,<1.10.0 # Apache-2.0 oslo.utils>=1.4.0,<1.5.0 # Apache-2.0 paramiko>=1.13.0 +python-ceilometerclient>=1.0.13 python-cinderclient>=1.1.0 python-keystoneclient>=1.1.0 python-heatclient>=0.3.0 diff --git a/heat_integrationtests/scenario/templates/test_ceilometer_alarm.yaml b/heat_integrationtests/scenario/templates/test_ceilometer_alarm.yaml new file mode 100644 index 0000000000..01bc790b74 --- /dev/null +++ b/heat_integrationtests/scenario/templates/test_ceilometer_alarm.yaml @@ -0,0 +1,33 @@ +heat_template_version: 2013-05-23 +resources: + asg: + type: OS::Heat::AutoScalingGroup + properties: + max_size: 5 + min_size: 1 + resource: + type: OS::Heat::RandomString + scaleup_policy: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: {get_resource: asg} + cooldown: 0 + scaling_adjustment: 1 + alarm: + type: OS::Ceilometer::Alarm + properties: + description: Scale-up if the average CPU > 50% for 1 minute + meter_name: test_meter + statistic: count + comparison_operator: ge + threshold: 1 + period: 60 + evaluation_periods: 1 + alarm_actions: + - {get_attr: [scaleup_policy, alarm_url]} + matching_metadata: + metadata.metering.stack_id: {get_param: "OS::stack_id"} +outputs: + asg_size: + value: {get_attr: [asg, current_size]} diff --git a/heat_integrationtests/scenario/test_ceilometer_alarm.py b/heat_integrationtests/scenario/test_ceilometer_alarm.py new file mode 100644 index 0000000000..d8f21fd620 --- /dev/null +++ b/heat_integrationtests/scenario/test_ceilometer_alarm.py @@ -0,0 +1,57 @@ +# 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 oslo_log import log as logging + +from heat_integrationtests.common import test + +LOG = logging.getLogger(__name__) + + +class CeilometerAlarmTest(test.HeatIntegrationTest): + """Class is responsible for testing of ceilometer usage.""" + def setUp(self): + super(CeilometerAlarmTest, self).setUp() + self.client = self.orchestration_client + self.template = self._load_template(__file__, + 'test_ceilometer_alarm.yaml', + 'templates') + + def check_instance_count(self, stack_identifier, expected): + stack = self.client.stacks.get(stack_identifier) + actual = self._stack_output(stack, 'asg_size') + if actual != expected: + LOG.warn('check_instance_count exp:%d, act:%s' % (expected, + actual)) + return actual == expected + + def test_alarm(self): + """Confirm we can create an alarm and trigger it.""" + + # 1. create the stack + stack_identifier = self.stack_create(template=self.template) + + # 2. send ceilometer a metric (should cause the alarm to fire) + sample = {} + sample['counter_type'] = 'gauge' + sample['counter_name'] = 'test_meter' + sample['counter_volume'] = 1 + sample['counter_unit'] = 'count' + sample['resource_metadata'] = {'metering.stack_id': + stack_identifier.split('/')[-1]} + sample['resource_id'] = 'shouldnt_matter' + self.metering_client.samples.create(**sample) + + # 3. confirm we get a scaleup. + # Note: there is little point waiting more than 60s+time to scale up. + self.assertTrue(test.call_until_true( + 120, 2, self.check_instance_count, stack_identifier, 2))