blob: 8f37d74dc512a512596107ed021df83e7568c590 [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
Elena Ezhova6e73f462014-04-18 17:38:13 +040016
Elena Ezhova6e73f462014-04-18 17:38:13 +040017import tempfile
Elena Ezhovaa5105e62013-11-26 20:46:52 +040018import time
Elena Ezhova6e73f462014-04-18 17:38:13 +040019import urllib2
Elena Ezhovaa5105e62013-11-26 20:46:52 +040020
Elena Ezhova6e73f462014-04-18 17:38:13 +040021from tempest.common import commands
Elena Ezhovaa5105e62013-11-26 20:46:52 +040022from tempest import config
23from tempest import exceptions
24from tempest.scenario import manager
Yair Fried8186f812014-09-28 09:39:39 +030025from tempest.services.network import resources as net_resources
Elena Ezhovaa5105e62013-11-26 20:46:52 +040026from tempest import test
27
28config = config.CONF
29
30
Andrea Frittoli4971fc82014-09-25 10:22:20 +010031class TestLoadBalancerBasic(manager.NetworkScenarioTest):
Elena Ezhovaa5105e62013-11-26 20:46:52 +040032
33 """
34 This test checks basic load balancing.
35
36 The following is the scenario outline:
37 1. Create an instance
38 2. SSH to the instance and start two servers
39 3. Create a load balancer with two members and with ROUND_ROBIN algorithm
40 associate the VIP with a floating ip
armando-migliaccio29bd43b2014-09-10 11:43:15 -070041 4. Send NUM requests to the floating ip and check that they are shared
42 between the two servers.
Elena Ezhovaa5105e62013-11-26 20:46:52 +040043 """
44
45 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000046 def skip_checks(cls):
47 super(TestLoadBalancerBasic, cls).skip_checks()
Elena Ezhovaa5105e62013-11-26 20:46:52 +040048 cfg = config.network
49 if not test.is_extension_enabled('lbaas', 'network'):
50 msg = 'LBaaS Extension is not enabled'
Elena Ezhovaa5105e62013-11-26 20:46:52 +040051 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.')
Elena Ezhovaa5105e62013-11-26 20:46:52 +040055 raise cls.skipException(msg)
56
57 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +010058 def resource_setup(cls):
59 super(TestLoadBalancerBasic, cls).resource_setup()
Elena Ezhovaa5105e62013-11-26 20:46:52 +040060 cls.servers_keypairs = {}
Elena Ezhovaa5105e62013-11-26 20:46:52 +040061 cls.members = []
Elena Ezhovaa5105e62013-11-26 20:46:52 +040062 cls.floating_ips = {}
Elena Ezhova4a27b462014-04-09 15:25:46 +040063 cls.server_ips = {}
Elena Ezhovaa5105e62013-11-26 20:46:52 +040064 cls.port1 = 80
65 cls.port2 = 88
armando-migliaccio29bd43b2014-09-10 11:43:15 -070066 cls.num = 50
Elena Ezhovaa5105e62013-11-26 20:46:52 +040067
Elena Ezhova4a27b462014-04-09 15:25:46 +040068 def setUp(self):
69 super(TestLoadBalancerBasic, self).setUp()
70 self.server_ips = {}
Darragh O'Reilly7c8176e2014-04-26 16:03:23 +000071 self.server_fixed_ips = {}
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -050072 self._create_security_group_for_test()
Adam Gandelmanbbf5c472014-08-12 16:46:12 -070073 self._set_net_and_subnet()
74
75 def _set_net_and_subnet(self):
76 """
77 Query and set appropriate network and subnet attributes to be used
78 for the test. Existing tenant networks are used if they are found.
79 The configured private network and associated subnet is used as a
80 fallback in absence of tenant networking.
81 """
82 try:
83 tenant_net = self._list_networks(tenant_id=self.tenant_id)[0]
84 except IndexError:
85 tenant_net = None
86
87 if tenant_net:
88 tenant_subnet = self._list_subnets(tenant_id=self.tenant_id)[0]
Yair Fried8186f812014-09-28 09:39:39 +030089 self.subnet = net_resources.DeletableSubnet(
Adam Gandelmanbbf5c472014-08-12 16:46:12 -070090 client=self.network_client,
91 **tenant_subnet)
92 self.network = tenant_net
93 else:
94 self.network = self._get_network_by_name(
95 config.compute.fixed_network_name)
96 # TODO(adam_g): We are assuming that the first subnet associated
97 # with the fixed network is the one we want. In the future, we
98 # should instead pull a subnet id from config, which is set by
99 # devstack/admin/etc.
100 subnet = self._list_subnets(network_id=self.network['id'])[0]
Yair Fried8186f812014-09-28 09:39:39 +0300101 self.subnet = net_resources.AttributeDict(subnet)
Elena Ezhova4a27b462014-04-09 15:25:46 +0400102
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500103 def _create_security_group_for_test(self):
104 self.security_group = self._create_security_group(
Elena Ezhova4a27b462014-04-09 15:25:46 +0400105 tenant_id=self.tenant_id)
Eugene Nikanorov55d13142014-03-24 15:39:21 +0400106 self._create_security_group_rules_for_port(self.port1)
107 self._create_security_group_rules_for_port(self.port2)
108
109 def _create_security_group_rules_for_port(self, port):
110 rule = {
111 'direction': 'ingress',
112 'protocol': 'tcp',
113 'port_range_min': port,
114 'port_range_max': port,
115 }
116 self._create_security_group_rule(
Elena Ezhova4a27b462014-04-09 15:25:46 +0400117 secgroup=self.security_group,
Eugene Nikanorov55d13142014-03-24 15:39:21 +0400118 tenant_id=self.tenant_id,
119 **rule)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400120
Elena Ezhova4a27b462014-04-09 15:25:46 +0400121 def _create_server(self, name):
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500122 keypair = self.create_keypair()
Ken'ichi Ohmichi1b3461e2014-12-02 03:41:07 +0000123 security_groups = [{'name': self.security_group['name']}]
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200124 create_kwargs = {
Sergey Shnaidmancb85dcd2014-11-26 20:01:11 +0300125 'networks': [
126 {'uuid': self.network['id']},
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200127 ],
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500128 'key_name': keypair['name'],
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200129 'security_groups': security_groups,
130 }
Adam Gandelmanbbf5c472014-08-12 16:46:12 -0700131 net_name = self.network['name']
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500132 server = self.create_server(name=name, create_kwargs=create_kwargs)
133 self.servers_keypairs[server['id']] = keypair
Elena Ezhova91531102014-02-07 17:25:58 +0400134 if (config.network.public_network_id and not
135 config.network.tenant_networks_reachable):
136 public_network_id = config.network.public_network_id
Yair Friedae0e73d2014-11-24 11:56:26 +0200137 floating_ip = self.create_floating_ip(
Elena Ezhova91531102014-02-07 17:25:58 +0400138 server, public_network_id)
139 self.floating_ips[floating_ip] = server
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500140 self.server_ips[server['id']] = floating_ip.floating_ip_address
Elena Ezhova91531102014-02-07 17:25:58 +0400141 else:
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500142 self.server_ips[server['id']] =\
143 server['addresses'][net_name][0]['addr']
144 self.server_fixed_ips[server['id']] =\
145 server['addresses'][net_name][0]['addr']
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400146 self.assertTrue(self.servers_keypairs)
Elena Ezhova91531102014-02-07 17:25:58 +0400147 return server
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400148
Elena Ezhova4a27b462014-04-09 15:25:46 +0400149 def _create_servers(self):
150 for count in range(2):
151 self._create_server(name=("server%s" % (count + 1)))
152 self.assertEqual(len(self.servers_keypairs), 2)
153
154 def _start_servers(self):
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400155 """
Elena Ezhova4a27b462014-04-09 15:25:46 +0400156 Start two backends
157
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400158 1. SSH to the instance
Elena Ezhova91531102014-02-07 17:25:58 +0400159 2. Start two http backends listening on ports 80 and 88 respectively
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400160 """
Elena Ezhova4a27b462014-04-09 15:25:46 +0400161 for server_id, ip in self.server_ips.iteritems():
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500162 private_key = self.servers_keypairs[server_id]['private_key']
David Kranz0fb14292015-02-11 15:55:20 -0500163 server_name = self.servers_client.get_server(server_id)['name']
Elena Ezhova6e73f462014-04-18 17:38:13 +0400164 username = config.scenario.ssh_user
Elena Ezhova4a27b462014-04-09 15:25:46 +0400165 ssh_client = self.get_remote_client(
166 server_or_ip=ip,
167 private_key=private_key)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400168
Robert Mizielskie1d88992014-07-15 15:28:09 +0200169 # Write a backend's response into a file
Sergey Shnaidmancb85dcd2014-11-26 20:01:11 +0300170 resp = ('echo -ne "HTTP/1.1 200 OK\r\nContent-Length: 7\r\n'
171 'Connection: close\r\nContent-Type: text/html; '
172 'charset=UTF-8\r\n\r\n%s"; cat >/dev/null')
Elena Ezhova0c8e3292014-06-05 12:15:39 +0400173
Elena Ezhova6e73f462014-04-18 17:38:13 +0400174 with tempfile.NamedTemporaryFile() as script:
175 script.write(resp % server_name)
176 script.flush()
177 with tempfile.NamedTemporaryFile() as key:
178 key.write(private_key)
179 key.flush()
180 commands.copy_file_to_host(script.name,
Elena Ezhova0c8e3292014-06-05 12:15:39 +0400181 "/tmp/script1",
Elena Ezhova6e73f462014-04-18 17:38:13 +0400182 ip,
183 username, key.name)
Elena Ezhova0c8e3292014-06-05 12:15:39 +0400184
Elena Ezhova6e73f462014-04-18 17:38:13 +0400185 # Start netcat
Sergey Shnaidmancb85dcd2014-11-26 20:01:11 +0300186 start_server = ('while true; do '
Attila Fazekas63838592015-01-09 09:34:40 +0100187 'sudo nc -ll -p %(port)s -e sh /tmp/%(script)s; '
Itzik Brown5eb05552015-04-01 11:46:44 +0300188 'done > /dev/null &')
Elena Ezhova6e73f462014-04-18 17:38:13 +0400189 cmd = start_server % {'port': self.port1,
190 'script': 'script1'}
Elena Ezhova4a27b462014-04-09 15:25:46 +0400191 ssh_client.exec_command(cmd)
Elena Ezhova0c8e3292014-06-05 12:15:39 +0400192
Elena Ezhova4a27b462014-04-09 15:25:46 +0400193 if len(self.server_ips) == 1:
Elena Ezhova6e73f462014-04-18 17:38:13 +0400194 with tempfile.NamedTemporaryFile() as script:
195 script.write(resp % 'server2')
196 script.flush()
197 with tempfile.NamedTemporaryFile() as key:
198 key.write(private_key)
199 key.flush()
200 commands.copy_file_to_host(script.name,
Elena Ezhova0c8e3292014-06-05 12:15:39 +0400201 "/tmp/script2", ip,
Elena Ezhova6e73f462014-04-18 17:38:13 +0400202 username, key.name)
203 cmd = start_server % {'port': self.port2,
204 'script': 'script2'}
Elena Ezhova4a27b462014-04-09 15:25:46 +0400205 ssh_client.exec_command(cmd)
Elena Ezhova4a27b462014-04-09 15:25:46 +0400206
207 def _check_connection(self, check_ip, port=80):
208 def try_connect(ip, port):
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400209 try:
Elena Ezhova6e73f462014-04-18 17:38:13 +0400210 resp = urllib2.urlopen("http://{0}:{1}/".format(ip, port))
Elena Ezhova4a27b462014-04-09 15:25:46 +0400211 if resp.getcode() == 200:
212 return True
213 return False
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400214 except IOError:
215 return False
Sergey Shnaidmancb85dcd2014-11-26 20:01:11 +0300216 except urllib2.HTTPError:
217 return False
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400218 timeout = config.compute.ping_timeout
Elena Ezhova4a27b462014-04-09 15:25:46 +0400219 start = time.time()
220 while not try_connect(check_ip, port):
221 if (time.time() - start) > timeout:
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400222 message = "Timed out trying to connect to %s" % check_ip
223 raise exceptions.TimeoutException(message)
224
225 def _create_pool(self):
226 """Create a pool with ROUND_ROBIN algorithm."""
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200227 self.pool = super(TestLoadBalancerBasic, self)._create_pool(
Elena Ezhova4a27b462014-04-09 15:25:46 +0400228 lb_method='ROUND_ROBIN',
229 protocol='HTTP',
230 subnet_id=self.subnet.id)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200231 self.assertTrue(self.pool)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400232
Elena Ezhova4a27b462014-04-09 15:25:46 +0400233 def _create_members(self):
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400234 """
235 Create two members.
236
237 In case there is only one server, create both members with the same ip
238 but with different ports to listen on.
239 """
Elena Ezhova4a27b462014-04-09 15:25:46 +0400240
Darragh O'Reilly7c8176e2014-04-26 16:03:23 +0000241 for server_id, ip in self.server_fixed_ips.iteritems():
242 if len(self.server_fixed_ips) == 1:
Elena Ezhova4a27b462014-04-09 15:25:46 +0400243 member1 = self._create_member(address=ip,
244 protocol_port=self.port1,
245 pool_id=self.pool.id)
Elena Ezhova4a27b462014-04-09 15:25:46 +0400246 member2 = self._create_member(address=ip,
247 protocol_port=self.port2,
248 pool_id=self.pool.id)
Elena Ezhova4a27b462014-04-09 15:25:46 +0400249 self.members.extend([member1, member2])
250 else:
251 member = self._create_member(address=ip,
252 protocol_port=self.port1,
253 pool_id=self.pool.id)
Elena Ezhova4a27b462014-04-09 15:25:46 +0400254 self.members.append(member)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400255 self.assertTrue(self.members)
256
257 def _assign_floating_ip_to_vip(self, vip):
258 public_network_id = config.network.public_network_id
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200259 port_id = vip.port_id
Yair Friedae0e73d2014-11-24 11:56:26 +0200260 floating_ip = self.create_floating_ip(vip, public_network_id,
261 port_id=port_id)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200262 self.floating_ips.setdefault(vip.id, [])
263 self.floating_ips[vip.id].append(floating_ip)
Swaminathan Vasudevan27d75f42015-03-02 11:41:43 -0800264 # Check for floating ip status before you check load-balancer
265 self.check_floating_ip_status(floating_ip, "ACTIVE")
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400266
267 def _create_load_balancer(self):
268 self._create_pool()
Elena Ezhova4a27b462014-04-09 15:25:46 +0400269 self._create_members()
270 self.vip = self._create_vip(protocol='HTTP',
271 protocol_port=80,
272 subnet_id=self.subnet.id,
273 pool_id=self.pool.id)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500274 self.vip.wait_for_status('ACTIVE')
Elena Ezhova91531102014-02-07 17:25:58 +0400275 if (config.network.public_network_id and not
276 config.network.tenant_networks_reachable):
277 self._assign_floating_ip_to_vip(self.vip)
278 self.vip_ip = self.floating_ips[
279 self.vip.id][0]['floating_ip_address']
280 else:
281 self.vip_ip = self.vip.address
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400282
Darragh O'Reilly44fc88a2014-04-26 15:42:47 +0000283 # Currently the ovs-agent is not enforcing security groups on the
284 # vip port - see https://bugs.launchpad.net/neutron/+bug/1163569
285 # However the linuxbridge-agent does, and it is necessary to add a
286 # security group with a rule that allows tcp port 80 to the vip port.
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500287 self.network_client.update_port(
288 self.vip.port_id, security_groups=[self.security_group.id])
Darragh O'Reilly44fc88a2014-04-26 15:42:47 +0000289
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400290 def _check_load_balancing(self):
291 """
armando-migliaccio29bd43b2014-09-10 11:43:15 -0700292 1. Send NUM requests on the floating ip associated with the VIP
293 2. Check that the requests are shared between the two servers
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400294 """
295
Elena Ezhova91531102014-02-07 17:25:58 +0400296 self._check_connection(self.vip_ip)
armando-migliaccio29bd43b2014-09-10 11:43:15 -0700297 self._send_requests(self.vip_ip, ["server1", "server2"])
Elena Ezhova4a27b462014-04-09 15:25:46 +0400298
armando-migliaccio29bd43b2014-09-10 11:43:15 -0700299 def _send_requests(self, vip_ip, servers):
300 counters = dict.fromkeys(servers, 0)
301 for i in range(self.num):
Sergey Shnaidmancb85dcd2014-11-26 20:01:11 +0300302 try:
303 server = urllib2.urlopen("http://{0}/".format(vip_ip)).read()
304 counters[server] += 1
305 # HTTP exception means fail of server, so don't increase counter
306 # of success and continue connection tries
307 except urllib2.HTTPError:
308 continue
armando-migliaccio29bd43b2014-09-10 11:43:15 -0700309 # Assert that each member of the pool gets balanced at least once
310 for member, counter in counters.iteritems():
311 self.assertGreater(counter, 0, 'Member %s never balanced' % member)
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400312
Chris Hoge7579c1a2015-02-26 14:12:15 -0800313 @test.idempotent_id('c0c6f1ca-603b-4509-9c0f-2c63f0d838ee')
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400314 @test.services('compute', 'network')
315 def test_load_balancer_basic(self):
Elena Ezhova4a27b462014-04-09 15:25:46 +0400316 self._create_server('server1')
317 self._start_servers()
Elena Ezhovaa5105e62013-11-26 20:46:52 +0400318 self._create_load_balancer()
319 self._check_load_balancing()