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
This commit is contained in:
kairat_kushaev 2015-01-27 21:48:46 +03:00
parent 2c35c47dce
commit c1b63d1eef
4 changed files with 130 additions and 323 deletions

View File

@ -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()

View File

@ -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 "

View File

@ -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 = <None>

View File

@ -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"]))