From c1b63d1eef3c4ea8d8d390d2fe2aa719cbd1bffb Mon Sep 17 00:00:00 2001 From: kairat_kushaev Date: Tue, 27 Jan 2015 21:48:46 +0300 Subject: [PATCH] Test auto-scaling for neutron Test does the following: 1. Creates an instances with LoadBalancer 2. Increased desired capacity 3. Check that LB resources has been increased Test replaces test_neutron_autoscaling unittest. Part of blueprint decouple-nested. Change-Id: I3b4924bfe3e427ffc77b23e0a3b6b08accfa39eb --- heat/tests/test_neutron_autoscaling.py | 323 ------------------ heat_integrationtests/common/config.py | 3 + .../heat_integrationtests.conf.sample | 3 + .../scenario/test_neutron_autoscaling.py | 124 +++++++ 4 files changed, 130 insertions(+), 323 deletions(-) delete mode 100644 heat/tests/test_neutron_autoscaling.py create mode 100644 heat_integrationtests/scenario/test_neutron_autoscaling.py diff --git a/heat/tests/test_neutron_autoscaling.py b/heat/tests/test_neutron_autoscaling.py deleted file mode 100644 index 11040d7a37..0000000000 --- a/heat/tests/test_neutron_autoscaling.py +++ /dev/null @@ -1,323 +0,0 @@ -# -# 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 copy -import uuid - -import mox -from neutronclient.v2_0 import client as neutronclient -from oslo.config import cfg - -from heat.common import template_format -from heat.db import api as db_api -from heat.engine.clients.os import nova -from heat.engine import environment -from heat.engine import parser -from heat.engine.resources import instance -from heat.engine import template -from heat.tests import common -from heat.tests import utils -from heat.tests.v1_1 import fakes as fakes_v1_1 - - -as_template = ''' -{ - "AWSTemplateFormatVersion" : "2010-09-09", - "Description" : "AutoScaling Test", - "Parameters" : { - "ImageId": {"Type": "String"}, - "KeyName": {"Type": "String"}, - "SubnetId": {"Type": "String"} - }, - "Resources" : { - "SvrGrp" : { - "Type" : "AWS::AutoScaling::AutoScalingGroup", - "Properties" : { - "AvailabilityZones" : ["nova"], - "LaunchConfigurationName" : { "Ref" : "LaunchConfig" }, - "MinSize" : "1", - "MaxSize" : "5", - "DesiredCapacity": "1", - "VPCZoneIdentifier": [ { "Ref": "SubnetId" } ], - "LoadBalancerNames" : [ { "Ref" : "ElasticLoadBalancer" } ] - } - }, - "myMonitor": { - "Type": "OS::Neutron::HealthMonitor", - "Properties": { - "type": "HTTP", - "delay": 3, - "max_retries": 5, - "timeout": 10 - } - }, - "myPool": { - "Type": "OS::Neutron::Pool", - "Properties": { - "description": "Test Pool", - "lb_method": "ROUND_ROBIN", - "monitors": [ { "Ref": "myMonitor" } ], - "name": "Test_Pool", - "protocol": "HTTP", - "subnet_id": { "Ref": "SubnetId" }, - "vip": { - "description": "Test VIP", - "connection_limit": 1000, - "address": "10.0.3.121", - "protocol_port": 80, - "name": "test_vip" - } - } - }, - "ElasticLoadBalancer" : { - 'Type': 'OS::Neutron::LoadBalancer', - 'Properties': { - 'protocol_port': 8080, - 'pool_id': { "Ref": "myPool" } - } - }, - "LaunchConfig" : { - "Type" : "AWS::AutoScaling::LaunchConfiguration", - "Properties": { - "ImageId" : {"Ref": "ImageId"}, - "InstanceType" : "bar", - } - } - } -} -''' - - -class AutoScalingTest(common.HeatTestCase): - params = {'KeyName': 'test', 'ImageId': 'foo'} - - def setUp(self): - super(AutoScalingTest, self).setUp() - - self.ctx = utils.dummy_context() - self.fc = fakes_v1_1.FakeClient() - - cfg.CONF.set_default('heat_waitcondition_server_url', - 'http://server.test:8000/v1/waitcondition') - - self.stub_keystoneclient() - - self.m.StubOutWithMock(neutronclient.Client, - 'create_health_monitor') - self.m.StubOutWithMock(neutronclient.Client, - 'associate_health_monitor') - self.m.StubOutWithMock(neutronclient.Client, 'create_pool') - self.m.StubOutWithMock(neutronclient.Client, 'create_vip') - self.m.StubOutWithMock(neutronclient.Client, 'show_pool') - self.m.StubOutWithMock(neutronclient.Client, 'show_vip') - self.m.StubOutWithMock(neutronclient.Client, 'create_member') - self.m.StubOutWithMock(neutronclient.Client, 'list_members') - - self.m.StubOutWithMock(nova.NovaClientPlugin, 'server_to_ipaddress') - self.m.StubOutWithMock(parser.Stack, 'validate') - - self.m.StubOutWithMock(instance.Instance, 'handle_create') - self.m.StubOutWithMock(instance.Instance, 'check_create_complete') - - def test_lb(self): - - tmpl = template_format.parse(as_template) - - network_body = { - "network": { - "id": str(uuid.uuid4()), - "name": "testnet", - "admin_state_up": True - } - } - subnet_body = { - "subnet": { - "name": "testsubnet", - "id": str(uuid.uuid4()), - "network_id": network_body['network']['id'], - "ip_version": 4, - "cidr": "10.0.3.0/24", - "allocation_pools": [ - { - "start": "10.0.3.20", - "end": "10.0.3.150" - } - ], - "gateway_ip": "10.0.3.1" - } - } - - self.params["SubnetId"] = subnet_body['subnet']['id'] - mon_block = { - 'health_monitor': tmpl['Resources']['myMonitor']['Properties'] - } - mon_block['health_monitor']['admin_state_up'] = True - mon_ret_block = copy.deepcopy(mon_block) - mon_ret_block['health_monitor']['id'] = str(uuid.uuid4()) - mon_ret_block['health_monitor']['status'] = 'ACTIVE' - - pool_block = {'pool': {}} - tmp_pool_block = tmpl['Resources']['myPool']['Properties'] - for val in ['lb_method', 'protocol', 'name', 'description']: - pool_block['pool'][val] = tmp_pool_block[val] - pool_block['pool']['admin_state_up'] = True - pool_block['pool']['subnet_id'] = self.params['SubnetId'] - pool_block['pool']['admin_state_up'] = True - pool_ret_block = copy.deepcopy(pool_block) - pool_ret_block['pool']['id'] = str(uuid.uuid4()) - pool_ret_block['pool']['status'] = 'ACTIVE' - - tmp_vip_block = tmp_pool_block.pop('vip') - vip_block = { - 'vip': { - 'protocol': pool_block['pool']['protocol'], - 'description': tmp_vip_block['description'], - 'admin_state_up': True, - 'subnet_id': self.params['SubnetId'], - 'connection_limit': tmp_vip_block['connection_limit'], - 'pool_id': pool_ret_block['pool']['id'], - 'address': tmp_vip_block['address'], - 'protocol_port': tmp_vip_block['protocol_port'], - 'name': tmp_vip_block['name'] - } - } - vip_ret_block = copy.deepcopy(vip_block) - vip_ret_block['vip']['id'] = str(uuid.uuid4()) - vip_ret_block['vip']['status'] = 'ACTIVE' - - membera_block = { - 'member': { - 'protocol_port': 8080, - 'pool_id': pool_ret_block['pool']['id'], - 'address': '1.2.3.4' - } - } - membera_ret_block = copy.deepcopy(membera_block) - membera_ret_block['member']['id'] = str(uuid.uuid4()) - - memberb_block = { - 'member': { - 'protocol_port': 8080, - 'pool_id': pool_ret_block['pool']['id'], - 'address': '1.2.3.5' - } - } - memberb_ret_block = copy.deepcopy(memberb_block) - memberb_ret_block['member']['id'] = str(uuid.uuid4()) - - memberc_block = { - 'member': { - 'protocol_port': 8080, - 'pool_id': pool_ret_block['pool']['id'], - 'address': '1.2.3.6' - } - } - memberc_ret_block = copy.deepcopy(memberc_block) - memberc_ret_block['member']['id'] = str(uuid.uuid4()) - - neutronclient.Client.create_health_monitor( - mon_block).AndReturn(mon_ret_block) - - neutronclient.Client.create_pool( - pool_block).AndReturn(pool_ret_block) - - neutronclient.Client.associate_health_monitor( - pool_ret_block['pool']['id'], - {'health_monitor': { - 'id': mon_ret_block['health_monitor']['id'] - }}).AndReturn(None) - - neutronclient.Client.create_vip( - vip_block).AndReturn(vip_ret_block) - - neutronclient.Client.show_pool( - pool_ret_block['pool']['id']).AndReturn(pool_ret_block) - - neutronclient.Client.show_vip( - vip_ret_block['vip']['id']).AndReturn(vip_ret_block) - - parser.Stack.validate() - instid = str(uuid.uuid4()) - instance.Instance.handle_create().AndReturn(instid) - instance.Instance.check_create_complete( - mox.IgnoreArg()).AndReturn(False) - instance.Instance.check_create_complete( - mox.IgnoreArg()).AndReturn(True) - self.stub_ImageConstraint_validate() - self.stub_FlavorConstraint_validate() - nova.NovaClientPlugin.server_to_ipaddress( - mox.IgnoreArg()).AndReturn('1.2.3.4') - - neutronclient.Client.create_member( - membera_block).AndReturn(membera_ret_block) - - # Start of update - parser.Stack.validate() - instid = str(uuid.uuid4()) - instance.Instance.handle_create().AndReturn(instid) - instance.Instance.check_create_complete( - mox.IgnoreArg()).AndReturn(False) - instance.Instance.check_create_complete( - mox.IgnoreArg()).AndReturn(True) - - instid = str(uuid.uuid4()) - instance.Instance.handle_create().AndReturn(instid) - instance.Instance.check_create_complete( - mox.IgnoreArg()).AndReturn(False) - instance.Instance.check_create_complete( - mox.IgnoreArg()).AndReturn(True) - - nova.NovaClientPlugin.server_to_ipaddress( - mox.IgnoreArg()).AndReturn('1.2.3.5') - - neutronclient.Client.create_member( - memberb_block).AndReturn(memberb_ret_block) - - nova.NovaClientPlugin.server_to_ipaddress( - mox.IgnoreArg()).AndReturn('1.2.3.6') - - neutronclient.Client.create_member( - memberc_block).AndReturn(memberc_ret_block) - - self.m.ReplayAll() - - # Start of stack create - env = {'parameters': self.params} - tmpl = template_format.parse(as_template) - - stack = parser.Stack(self.ctx, 'update_test_stack', - template.Template(tmpl), - environment.Environment(env)) - - stack.store() - stack.create() - self.assertEqual((parser.Stack.CREATE, parser.Stack.COMPLETE), - stack.state) - - # Start of stack update - stack2 = parser.Stack.load(self.ctx, stack_id=stack.id) - - tmpl2 = copy.deepcopy(tmpl) - tmpl2['Resources']['SvrGrp']['Properties']['DesiredCapacity'] = '3' - - update_stack = parser.Stack(self.ctx, 'update_test_stack', - template.Template(tmpl2), - environment.Environment(env)) - stack2.update(update_stack) - self.assertEqual((parser.Stack.UPDATE, parser.Stack.COMPLETE), - stack2.state) - - members = db_api.resource_data_get_all(stack['ElasticLoadBalancer']) - self.assertEqual(3, len(members.keys())) - - self.m.VerifyAll() diff --git a/heat_integrationtests/common/config.py b/heat_integrationtests/common/config.py index 562b80becc..31a996b424 100644 --- a/heat_integrationtests/common/config.py +++ b/heat_integrationtests/common/config.py @@ -68,6 +68,9 @@ IntegrationTestGroup = [ cfg.StrOpt('fixed_network_name', default='private', help="Visible fixed network name "), + cfg.StrOpt('fixed_subnet_name', + default='private-subnet', + help="Visible fixed sub-network name "), cfg.IntOpt('ssh_timeout', default=300, help="Timeout in seconds to wait for authentication to " diff --git a/heat_integrationtests/heat_integrationtests.conf.sample b/heat_integrationtests/heat_integrationtests.conf.sample index 05232b7d28..2dbdaf6a87 100644 --- a/heat_integrationtests/heat_integrationtests.conf.sample +++ b/heat_integrationtests/heat_integrationtests.conf.sample @@ -23,6 +23,9 @@ # Visible fixed network name (string value) #fixed_network_name = private +# Visible fixed sub-network name (string value) +#fixed_subnet_name = private-subnet + # Name of image to use for tests which boot servers. (string value) #image_ref = diff --git a/heat_integrationtests/scenario/test_neutron_autoscaling.py b/heat_integrationtests/scenario/test_neutron_autoscaling.py new file mode 100644 index 0000000000..8f769efe3e --- /dev/null +++ b/heat_integrationtests/scenario/test_neutron_autoscaling.py @@ -0,0 +1,124 @@ +# 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 heat_integrationtests.common import test + +test_template = ''' +heat_template_version: 2014-10-16 + +description: Auto-scaling Test + +parameters: + image_id: + type: string + label: Image ID + description: Image ID from configurations + capacity: + type: string + label: Capacity + description: Auto-scaling group desired capacity + fixed_subnet_name: + type: string + label: fixed subnetwork ID + description: subnetwork ID used for autoscaling + instance_type: + type: string + label: instance_type + description: type of instance to launch + +resources: + test_pool: + type: OS::Neutron::Pool + properties: + description: Test Pool + lb_method: ROUND_ROBIN + name: test_pool + protocol: HTTP + subnet: { get_param: fixed_subnet_name } + vip: { + "description": "Test VIP", + "protocol_port": 80, + "name": "test_vip" + } + load_balancer: + type: OS::Neutron::LoadBalancer + properties: + protocol_port: 80 + pool_id: { get_resource: test_pool } + launch_config: + type: AWS::AutoScaling::LaunchConfiguration + properties: + ImageId: { get_param: image_id } + InstanceType: { get_param: instance_type } + server_group: + type: AWS::AutoScaling::AutoScalingGroup + properties: + AvailabilityZones : ["nova"] + LaunchConfigurationName : { get_resource : launch_config } + MinSize : 1 + MaxSize : 5 + DesiredCapacity: { get_param: capacity } + LoadBalancerNames : [ { get_resource : load_balancer } ] +''' + + +class NeutronAutoscalingTest(test.HeatIntegrationTest): + """" + The class is responsible for testing of neutron resources autoscaling. + """ + + def setUp(self): + super(NeutronAutoscalingTest, self).setUp() + self.client = self.orchestration_client + if not self.conf.minimal_image_ref: + raise self.skipException("No minimal image configured to test") + if not self.conf.instance_type: + raise self.skipException("No flavor configured to test") + if not self.conf.fixed_subnet_name: + raise self.skipException("No sub-network configured to test") + + def test_neutron_autoscaling(self): + """ + Check autoscaling of load balancer members in heat. + + The alternative scenario is the following: + 1. Initialize environment variables. + 2. Create a stack with a load balancer. + 3. Check that the load balancer created + one load balancer member for stack. + 4. Update stack definition: increase desired capacity of stack. + 5. Check that number of members in load balancer was increased. + """ + + # Init env variables + env = {'parameters': {"image_id": self.conf.minimal_image_ref, + "capacity": "1", + "instance_type": self.conf.instance_type, + "fixed_subnet_name": + self.conf.fixed_subnet_name, + }} + + # Create stack + stack_id = self.stack_create(template=test_template, + environment=env) + + members = self.network_client.list_members() + self.assertEqual(1, len(members["members"])) + + # Increase desired capacity and update the stack + env["parameters"]["capacity"] = "2" + self.update_stack(stack_id, + template=test_template, + environment=env) + + upd_members = self.network_client.list_members() + self.assertEqual(2, len(upd_members["members"])) \ No newline at end of file