blob: 1092b9491110bbd8a2e1ec0040cc4f87af43ef2c [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
Elena Ezhovaa5105e62013-11-26 20:46:52 +040020from tempest.common.utils import data_utils
21from tempest import config
22from tempest import exceptions
23from tempest.scenario import manager
24from tempest import test
25
26config = config.CONF
27
28
29class TestLoadBalancerBasic(manager.NetworkScenarioTest):
30
31 """
32 This test checks basic load balancing.
33
34 The following is the scenario outline:
35 1. Create an instance
36 2. SSH to the instance and start two servers
37 3. Create a load balancer with two members and with ROUND_ROBIN algorithm
38 associate the VIP with a floating ip
39 4. Send 10 requests to the floating ip and check that they are shared
40 between the two servers and that both of them get equal portions
41 of the requests
42 """
43
44 @classmethod
45 def check_preconditions(cls):
46 super(TestLoadBalancerBasic, cls).check_preconditions()
47 cfg = config.network
48 if not test.is_extension_enabled('lbaas', 'network'):
49 msg = 'LBaaS Extension is not enabled'
50 cls.enabled = False
51 raise cls.skipException(msg)
52 if not (cfg.tenant_networks_reachable or cfg.public_network_id):
53 msg = ('Either tenant_networks_reachable must be "true", or '
54 'public_network_id must be defined.')
55 cls.enabled = False
56 raise cls.skipException(msg)
57
58 @classmethod
59 def setUpClass(cls):
60 super(TestLoadBalancerBasic, cls).setUpClass()
61 cls.check_preconditions()
62 cls.security_groups = {}
Elena Ezhovaa5105e62013-11-26 20:46:52 +040063 cls.servers_keypairs = {}
Elena Ezhovaa5105e62013-11-26 20:46:52 +040064 cls.members = []
Elena Ezhovaa5105e62013-11-26 20:46:52 +040065 cls.floating_ips = {}
Elena Ezhova91531102014-02-07 17:25:58 +040066 cls.server_ip = None
67 cls.vip_ip = None
Elena Ezhovaa5105e62013-11-26 20:46:52 +040068 cls.port1 = 80
69 cls.port2 = 88
70
71 def _create_security_groups(self):
72 self.security_groups[self.tenant_id] =\
73 self._create_security_group_neutron(tenant_id=self.tenant_id)
Eugene Nikanorov55d13142014-03-24 15:39:21 +040074 self._create_security_group_rules_for_port(self.port1)
75 self._create_security_group_rules_for_port(self.port2)
76
77 def _create_security_group_rules_for_port(self, port):
78 rule = {
79 'direction': 'ingress',
80 'protocol': 'tcp',
81 'port_range_min': port,
82 'port_range_max': port,
83 }
84 self._create_security_group_rule(
85 client=self.network_client,
86 secgroup=self.security_groups[self.tenant_id],
87 tenant_id=self.tenant_id,
88 **rule)
Elena Ezhovaa5105e62013-11-26 20:46:52 +040089
90 def _create_server(self):
91 tenant_id = self.tenant_id
92 name = data_utils.rand_name("smoke_server-")
93 keypair = self.create_keypair(name='keypair-%s' % name)
94 security_groups = [self.security_groups[tenant_id].name]
Elena Ezhova91531102014-02-07 17:25:58 +040095 net = self._list_networks(tenant_id=self.tenant_id)[0]
Yair Fried2d2f3fe2014-02-24 16:19:20 +020096 create_kwargs = {
97 'nics': [
Elena Ezhova91531102014-02-07 17:25:58 +040098 {'net-id': net['id']},
Yair Fried2d2f3fe2014-02-24 16:19:20 +020099 ],
100 'key_name': keypair.name,
101 'security_groups': security_groups,
102 }
103 server = self.create_server(name=name,
104 create_kwargs=create_kwargs)
105 self.servers_keypairs[server] = keypair
Elena Ezhova91531102014-02-07 17:25:58 +0400106 if (config.network.public_network_id and not
107 config.network.tenant_networks_reachable):
108 public_network_id = config.network.public_network_id
109 floating_ip = self._create_floating_ip(
110 server, public_network_id)
111 self.floating_ips[floating_ip] = server
112 self.server_ip = floating_ip.floating_ip_address
113 else:
114 self.server_ip = server.networks[net['name']][0]
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400115 self.assertTrue(self.servers_keypairs)
Elena Ezhova91531102014-02-07 17:25:58 +0400116 return server
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400117
Elena Ezhova91531102014-02-07 17:25:58 +0400118 def _start_servers(self, server):
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400119 """
120 1. SSH to the instance
Elena Ezhova91531102014-02-07 17:25:58 +0400121 2. Start two http backends listening on ports 80 and 88 respectively
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400122 """
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400123
Elena Ezhova91531102014-02-07 17:25:58 +0400124 private_key = self.servers_keypairs[server].private_key
125 ssh_client = self.get_remote_client(
126 server_or_ip=self.server_ip,
127 private_key=private_key).ssh_client
128 start_server = "while true; do echo -e 'HTTP/1.0 200 OK\r\n\r\n" \
129 "%(server)s' | sudo nc -l -p %(port)s ; done &"
130 cmd = start_server % {'server': 'server1',
131 'port': self.port1}
132 ssh_client.exec_command(cmd)
133 cmd = start_server % {'server': 'server2',
134 'port': self.port2}
135 ssh_client.exec_command(cmd)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400136
137 def _check_connection(self, check_ip):
138 def try_connect(ip):
139 try:
140 urllib.urlopen("http://{0}/".format(ip))
141 return True
142 except IOError:
143 return False
144 timeout = config.compute.ping_timeout
145 timer = 0
146 while not try_connect(check_ip):
147 time.sleep(1)
148 timer += 1
149 if timer >= timeout:
150 message = "Timed out trying to connect to %s" % check_ip
151 raise exceptions.TimeoutException(message)
152
153 def _create_pool(self):
154 """Create a pool with ROUND_ROBIN algorithm."""
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200155 # get tenant subnet and verify there's only one
156 subnet = self._list_subnets(tenant_id=self.tenant_id)[0]
157 self.subnet = net_common.DeletableSubnet(client=self.network_client,
Elena Ezhova91531102014-02-07 17:25:58 +0400158 **subnet)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200159 self.pool = super(TestLoadBalancerBasic, self)._create_pool(
160 'ROUND_ROBIN',
161 'HTTP',
162 self.subnet.id)
163 self.assertTrue(self.pool)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400164
Elena Ezhova91531102014-02-07 17:25:58 +0400165 def _create_members(self, server_ids):
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400166 """
167 Create two members.
168
169 In case there is only one server, create both members with the same ip
170 but with different ports to listen on.
171 """
172 servers = self.compute_client.servers.list()
173 for server in servers:
174 if server.id in server_ids:
Elena Ezhova91531102014-02-07 17:25:58 +0400175 ip = self.server_ip
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200176 pool_id = self.pool.id
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400177 if len(set(server_ids)) == 1 or len(servers) == 1:
178 member1 = self._create_member(ip, self.port1, pool_id)
179 member2 = self._create_member(ip, self.port2, pool_id)
180 self.members.extend([member1, member2])
181 else:
182 member = self._create_member(ip, self.port1, pool_id)
183 self.members.append(member)
184 self.assertTrue(self.members)
185
186 def _assign_floating_ip_to_vip(self, vip):
187 public_network_id = config.network.public_network_id
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200188 port_id = vip.port_id
Yair Frieda2e3b2c2014-02-17 10:56:10 +0200189 floating_ip = self._create_floating_ip(vip, public_network_id,
190 port_id=port_id)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200191 self.floating_ips.setdefault(vip.id, [])
192 self.floating_ips[vip.id].append(floating_ip)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400193
194 def _create_load_balancer(self):
195 self._create_pool()
Elena Ezhova91531102014-02-07 17:25:58 +0400196 self._create_members([self.servers_keypairs.keys()[0].id])
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200197 subnet_id = self.subnet.id
198 pool_id = self.pool.id
199 self.vip = super(TestLoadBalancerBasic, self)._create_vip('HTTP', 80,
200 subnet_id,
201 pool_id)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400202 self._status_timeout(NeutronRetriever(self.network_client,
203 self.network_client.vip_path,
204 net_common.DeletableVip),
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200205 self.vip.id,
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400206 expected_status='ACTIVE')
Elena Ezhova91531102014-02-07 17:25:58 +0400207 if (config.network.public_network_id and not
208 config.network.tenant_networks_reachable):
209 self._assign_floating_ip_to_vip(self.vip)
210 self.vip_ip = self.floating_ips[
211 self.vip.id][0]['floating_ip_address']
212 else:
213 self.vip_ip = self.vip.address
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400214
215 def _check_load_balancing(self):
216 """
217 1. Send 10 requests on the floating ip associated with the VIP
218 2. Check that the requests are shared between
219 the two servers and that both of them get equal portions
220 of the requests
221 """
222
Elena Ezhova91531102014-02-07 17:25:58 +0400223 self._check_connection(self.vip_ip)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400224 resp = []
225 for count in range(10):
226 resp.append(
227 urllib.urlopen(
Elena Ezhova91531102014-02-07 17:25:58 +0400228 "http://{0}/".format(self.vip_ip)).read())
Matt Riedemann30670e02014-02-08 12:06:56 -0800229 self.assertEqual(set(["server1\n", "server2\n"]), set(resp))
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400230 self.assertEqual(5, resp.count("server1\n"))
231 self.assertEqual(5, resp.count("server2\n"))
232
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400233 @test.attr(type='smoke')
234 @test.services('compute', 'network')
235 def test_load_balancer_basic(self):
236 self._create_security_groups()
Elena Ezhova91531102014-02-07 17:25:58 +0400237 server = self._create_server()
238 self._start_servers(server)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400239 self._create_load_balancer()
240 self._check_load_balancing()
241
242
243class NeutronRetriever(object):
244 def __init__(self, network_client, path, resource):
245 self.network_client = network_client
246 self.path = path
247 self.resource = resource
248
249 def get(self, thing_id):
250 obj = self.network_client.get(self.path % thing_id)
251 return self.resource(client=self.network_client, **obj.values()[0])