blob: f4ca958d4a70de2580ad4a7fdf01f04ec20bf39f [file] [log] [blame]
Elena Ezhovaa5105e62013-11-26 20:46:52 +04001# Copyright 2014 Mirantis.inc
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import time
17import urllib
18
19from tempest.api.network import common as net_common
20from tempest.common import ssh
21from tempest.common.utils import data_utils
22from tempest import config
23from tempest import exceptions
24from tempest.scenario import manager
25from tempest import test
26
27config = config.CONF
28
29
30class TestLoadBalancerBasic(manager.NetworkScenarioTest):
31
32 """
33 This test checks basic load balancing.
34
35 The following is the scenario outline:
36 1. Create an instance
37 2. SSH to the instance and start two servers
38 3. Create a load balancer with two members and with ROUND_ROBIN algorithm
39 associate the VIP with a floating ip
40 4. Send 10 requests to the floating ip and check that they are shared
41 between the two servers and that both of them get equal portions
42 of the requests
43 """
44
45 @classmethod
46 def check_preconditions(cls):
47 super(TestLoadBalancerBasic, cls).check_preconditions()
48 cfg = config.network
49 if not test.is_extension_enabled('lbaas', 'network'):
50 msg = 'LBaaS Extension is not enabled'
51 cls.enabled = False
52 raise cls.skipException(msg)
53 if not (cfg.tenant_networks_reachable or cfg.public_network_id):
54 msg = ('Either tenant_networks_reachable must be "true", or '
55 'public_network_id must be defined.')
56 cls.enabled = False
57 raise cls.skipException(msg)
58
59 @classmethod
60 def setUpClass(cls):
61 super(TestLoadBalancerBasic, cls).setUpClass()
62 cls.check_preconditions()
63 cls.security_groups = {}
64 cls.networks = []
65 cls.subnets = []
66 cls.servers_keypairs = {}
67 cls.pools = []
68 cls.members = []
69 cls.vips = []
70 cls.floating_ips = {}
71 cls.port1 = 80
72 cls.port2 = 88
73
74 def _create_security_groups(self):
75 self.security_groups[self.tenant_id] =\
76 self._create_security_group_neutron(tenant_id=self.tenant_id)
77
78 def _create_server(self):
79 tenant_id = self.tenant_id
80 name = data_utils.rand_name("smoke_server-")
81 keypair = self.create_keypair(name='keypair-%s' % name)
82 security_groups = [self.security_groups[tenant_id].name]
83 nets = self.network_client.list_networks()
84 for net in nets['networks']:
85 if net['tenant_id'] == self.tenant_id:
86 self.networks.append(net)
87 create_kwargs = {
88 'nics': [
89 {'net-id': net['id']},
90 ],
91 'key_name': keypair.name,
92 'security_groups': security_groups,
93 }
94 server = self.create_server(name=name,
95 create_kwargs=create_kwargs)
96 self.servers_keypairs[server] = keypair
97 break
98 self.assertTrue(self.servers_keypairs)
99
100 def _start_servers(self):
101 """
102 1. SSH to the instance
103 2. Start two servers listening on ports 80 and 88 respectively
104 """
105 for server in self.servers_keypairs.keys():
106 ssh_login = config.compute.image_ssh_user
107 private_key = self.servers_keypairs[server].private_key
108 network_name = self.networks[0]['name']
109
110 ip_address = server.networks[network_name][0]
111 ssh_client = ssh.Client(ip_address, ssh_login,
112 pkey=private_key,
113 timeout=100)
114 start_server = "while true; do echo -e 'HTTP/1.0 200 OK\r\n\r\n" \
115 "%(server)s' | sudo nc -l -p %(port)s ; done &"
116 cmd = start_server % {'server': 'server1',
117 'port': self.port1}
118 ssh_client.exec_command(cmd)
119 cmd = start_server % {'server': 'server2',
120 'port': self.port2}
121 ssh_client.exec_command(cmd)
122
123 def _check_connection(self, check_ip):
124 def try_connect(ip):
125 try:
126 urllib.urlopen("http://{0}/".format(ip))
127 return True
128 except IOError:
129 return False
130 timeout = config.compute.ping_timeout
131 timer = 0
132 while not try_connect(check_ip):
133 time.sleep(1)
134 timer += 1
135 if timer >= timeout:
136 message = "Timed out trying to connect to %s" % check_ip
137 raise exceptions.TimeoutException(message)
138
139 def _create_pool(self):
140 """Create a pool with ROUND_ROBIN algorithm."""
141 subnets = self.network_client.list_subnets()
142 for subnet in subnets['subnets']:
143 if subnet['tenant_id'] == self.tenant_id:
144 self.subnets.append(subnet)
145 pool = super(TestLoadBalancerBasic, self)._create_pool(
146 'ROUND_ROBIN',
147 'HTTP',
148 subnet['id'])
149 self.pools.append(pool)
150 break
151 self.assertTrue(self.pools)
152
153 def _create_members(self, network_name, server_ids):
154 """
155 Create two members.
156
157 In case there is only one server, create both members with the same ip
158 but with different ports to listen on.
159 """
160 servers = self.compute_client.servers.list()
161 for server in servers:
162 if server.id in server_ids:
163 ip = server.networks[network_name][0]
164 pool_id = self.pools[0]['id']
165 if len(set(server_ids)) == 1 or len(servers) == 1:
166 member1 = self._create_member(ip, self.port1, pool_id)
167 member2 = self._create_member(ip, self.port2, pool_id)
168 self.members.extend([member1, member2])
169 else:
170 member = self._create_member(ip, self.port1, pool_id)
171 self.members.append(member)
172 self.assertTrue(self.members)
173
174 def _assign_floating_ip_to_vip(self, vip):
175 public_network_id = config.network.public_network_id
176 port_id = vip['port_id']
177 floating_ip = self._create_floating_ip(vip,
178 public_network_id,
179 port_filters=port_id)
180 self.floating_ips.setdefault(vip['id'], [])
181 self.floating_ips[vip['id']].append(floating_ip)
182
183 def _create_load_balancer(self):
184 self._create_pool()
185 self._create_members(self.networks[0]['name'],
186 [self.servers_keypairs.keys()[0].id])
187 subnet_id = self.subnets[0]['id']
188 pool_id = self.pools[0]['id']
189 vip = super(TestLoadBalancerBasic, self)._create_vip('HTTP', 80,
190 subnet_id,
191 pool_id)
192 self.vips.append(vip)
193 self._status_timeout(NeutronRetriever(self.network_client,
194 self.network_client.vip_path,
195 net_common.DeletableVip),
196 self.vips[0]['id'],
197 expected_status='ACTIVE')
198 self._assign_floating_ip_to_vip(self.vips[0])
199
200 def _check_load_balancing(self):
201 """
202 1. Send 10 requests on the floating ip associated with the VIP
203 2. Check that the requests are shared between
204 the two servers and that both of them get equal portions
205 of the requests
206 """
207
208 vip = self.vips[0]
209 floating_ip_vip = self.floating_ips[
210 vip['id']][0]['floating_ip_address']
211 self._check_connection(floating_ip_vip)
212 resp = []
213 for count in range(10):
214 resp.append(
215 urllib.urlopen(
216 "http://{0}/".format(floating_ip_vip)).read())
217 self.assertEqual({"server1\n", "server2\n"}, set(resp))
218 self.assertEqual(5, resp.count("server1\n"))
219 self.assertEqual(5, resp.count("server2\n"))
220
221 @test.attr(type='smoke')
222 @test.services('compute', 'network')
223 def test_load_balancer_basic(self):
224 self._create_security_groups()
225 self._create_server()
226 self._start_servers()
227 self._create_load_balancer()
228 self._check_load_balancing()
229
230
231class NeutronRetriever(object):
232 def __init__(self, network_client, path, resource):
233 self.network_client = network_client
234 self.path = path
235 self.resource = resource
236
237 def get(self, thing_id):
238 obj = self.network_client.get(self.path % thing_id)
239 return self.resource(client=self.network_client, **obj.values()[0])