blob: 90e416d9d06be28ec449b2ca8eaea9c7882c348c [file] [log] [blame]
YAMAMOTO Takashi25935722017-01-23 15:34:11 +09001# Copyright (c) 2017 Midokura SARL
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 netaddr
LIU Yulong5ba88ef2017-12-22 10:50:15 +080017from neutron_lib import constants as lib_constants
18from neutron_lib.services.qos import constants as qos_consts
Chandan Kumarc125fd12017-11-15 19:41:01 +053019from tempest.common import utils
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090020from tempest.common import waiters
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090021from tempest.lib.common.utils import data_utils
Sławek Kapłońskic0caa2e2017-02-25 10:11:32 +000022from tempest.lib import decorators
Ihar Hrachyshkace9c4862018-01-18 18:26:14 +000023import testscenarios
YAMAMOTO Takashi60faf4f2017-01-25 08:03:07 +090024from testscenarios.scenarios import multiply_scenarios
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090025
LIU Yulong5ba88ef2017-12-22 10:50:15 +080026from neutron_tempest_plugin.api import base as base_api
Chandan Kumar667d3d32017-09-22 12:24:06 +053027from neutron_tempest_plugin.common import ssh
Brian Haleyba800452017-12-14 10:30:48 -050028from neutron_tempest_plugin.common import utils as common_utils
Chandan Kumar667d3d32017-09-22 12:24:06 +053029from neutron_tempest_plugin import config
30from neutron_tempest_plugin.scenario import base
31from neutron_tempest_plugin.scenario import constants
LIU Yulong5ba88ef2017-12-22 10:50:15 +080032from neutron_tempest_plugin.scenario import test_qos
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090033
34
35CONF = config.CONF
36
37
38load_tests = testscenarios.load_tests_apply_scenarios
39
40
41class FloatingIpTestCasesMixin(object):
42 credentials = ['primary', 'admin']
43
44 @classmethod
Chandan Kumarc125fd12017-11-15 19:41:01 +053045 @utils.requires_ext(extension="router", service="network")
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090046 def resource_setup(cls):
47 super(FloatingIpTestCasesMixin, cls).resource_setup()
48 cls.network = cls.create_network()
49 cls.subnet = cls.create_subnet(cls.network)
50 cls.router = cls.create_router_by_client()
51 cls.create_router_interface(cls.router['id'], cls.subnet['id'])
52 cls.keypair = cls.create_keypair()
53
rajat294495c042017-06-28 15:37:16 +053054 cls.secgroup = cls.os_primary.network_client.create_security_group(
Chandan Kumarc125fd12017-11-15 19:41:01 +053055 name=data_utils.rand_name('secgroup'))['security_group']
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090056 cls.security_groups.append(cls.secgroup)
57 cls.create_loginable_secgroup_rule(secgroup_id=cls.secgroup['id'])
58 cls.create_pingable_secgroup_rule(secgroup_id=cls.secgroup['id'])
59
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090060 if cls.same_network:
61 cls._dest_network = cls.network
62 else:
63 cls._dest_network = cls._create_dest_network()
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090064
65 @classmethod
Itzik Browna31510f2018-01-19 11:09:48 +020066 def _get_external_gateway(cls):
67 if CONF.network.public_network_id:
68 subnets = cls.os_admin.network_client.list_subnets(
69 network_id=CONF.network.public_network_id)
70
71 for subnet in subnets['subnets']:
72 if (subnet['gateway_ip']
73 and subnet['ip_version'] == lib_constants.IP_VERSION_4):
74 return subnet['gateway_ip']
75
76 @classmethod
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090077 def _create_dest_network(cls):
78 network = cls.create_network()
79 subnet = cls.create_subnet(network,
80 cidr=netaddr.IPNetwork('10.10.0.0/24'))
81 cls.create_router_interface(cls.router['id'], subnet['id'])
82 return network
83
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000084 def _create_server(self, create_floating_ip=True, network=None):
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090085 if network is None:
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000086 network = self.network
87 port = self.create_port(network, security_groups=[self.secgroup['id']])
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090088 if create_floating_ip:
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000089 fip = self.create_and_associate_floatingip(port['id'])
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090090 else:
91 fip = None
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000092 server = self.create_server(
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090093 flavor_ref=CONF.compute.flavor_ref,
94 image_ref=CONF.compute.image_ref,
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000095 key_name=self.keypair['name'],
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090096 networks=[{'port': port['id']}])['server']
rajat294495c042017-06-28 15:37:16 +053097 waiters.wait_for_server_status(self.os_primary.servers_client,
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090098 server['id'],
99 constants.SERVER_STATUS_ACTIVE)
100 return {'port': port, 'fip': fip, 'server': server}
101
102 def _test_east_west(self):
YAMAMOTO Takashi60faf4f2017-01-25 08:03:07 +0900103 # The proxy VM is used to control the source VM when it doesn't
104 # have a floating-ip.
105 if self.src_has_fip:
106 proxy = None
107 proxy_client = None
108 else:
109 proxy = self._create_server()
110 proxy_client = ssh.Client(proxy['fip']['floating_ip_address'],
111 CONF.validation.image_ssh_user,
112 pkey=self.keypair['private_key'])
113
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900114 # Source VM
YAMAMOTO Takashi60faf4f2017-01-25 08:03:07 +0900115 if self.src_has_fip:
116 src_server = self._create_server()
117 src_server_ip = src_server['fip']['floating_ip_address']
118 else:
119 src_server = self._create_server(create_floating_ip=False)
120 src_server_ip = src_server['port']['fixed_ips'][0]['ip_address']
121 ssh_client = ssh.Client(src_server_ip,
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900122 CONF.validation.image_ssh_user,
YAMAMOTO Takashi60faf4f2017-01-25 08:03:07 +0900123 pkey=self.keypair['private_key'],
124 proxy_client=proxy_client)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900125
126 # Destination VM
127 if self.dest_has_fip:
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000128 dest_server = self._create_server(network=self._dest_network)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900129 else:
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000130 dest_server = self._create_server(create_floating_ip=False,
131 network=self._dest_network)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900132
133 # Check connectivity
134 self.check_remote_connectivity(ssh_client,
135 dest_server['port']['fixed_ips'][0]['ip_address'])
136 if self.dest_has_fip:
137 self.check_remote_connectivity(ssh_client,
138 dest_server['fip']['floating_ip_address'])
139
140
141class FloatingIpSameNetwork(FloatingIpTestCasesMixin,
142 base.BaseTempestTestCase):
YAMAMOTO Takashi60faf4f2017-01-25 08:03:07 +0900143 scenarios = multiply_scenarios([
144 ('SRC with FIP', dict(src_has_fip=True)),
145 ('SRC without FIP', dict(src_has_fip=False)),
146 ], [
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900147 ('DEST with FIP', dict(dest_has_fip=True)),
148 ('DEST without FIP', dict(dest_has_fip=False)),
YAMAMOTO Takashi60faf4f2017-01-25 08:03:07 +0900149 ])
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900150
151 same_network = True
152
Brian Haleyba800452017-12-14 10:30:48 -0500153 @common_utils.unstable_test("bug 1717302")
Sławek Kapłońskic0caa2e2017-02-25 10:11:32 +0000154 @decorators.idempotent_id('05c4e3b3-7319-4052-90ad-e8916436c23b')
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900155 def test_east_west(self):
156 self._test_east_west()
157
158
159class FloatingIpSeparateNetwork(FloatingIpTestCasesMixin,
160 base.BaseTempestTestCase):
YAMAMOTO Takashi60faf4f2017-01-25 08:03:07 +0900161 scenarios = multiply_scenarios([
162 ('SRC with FIP', dict(src_has_fip=True)),
163 ('SRC without FIP', dict(src_has_fip=False)),
164 ], [
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900165 ('DEST with FIP', dict(dest_has_fip=True)),
166 ('DEST without FIP', dict(dest_has_fip=False)),
YAMAMOTO Takashi60faf4f2017-01-25 08:03:07 +0900167 ])
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900168
169 same_network = False
170
Brian Haleyba800452017-12-14 10:30:48 -0500171 @common_utils.unstable_test("bug 1717302")
Sławek Kapłońskic0caa2e2017-02-25 10:11:32 +0000172 @decorators.idempotent_id('f18f0090-3289-4783-b956-a0f8ac511e8b')
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900173 def test_east_west(self):
174 self._test_east_west()
Itzik Browna31510f2018-01-19 11:09:48 +0200175
176
177class DefaultSnatToExternal(FloatingIpTestCasesMixin,
178 base.BaseTempestTestCase):
179 same_network = True
180
181 @decorators.idempotent_id('3d73ea1a-27c6-45a9-b0f8-04a283d9d764')
182 def test_snat_external_ip(self):
183 """Check connectivity to an external IP"""
184 gateway_external_ip = self._get_external_gateway()
185
186 if not gateway_external_ip:
187 raise self.skipTest("IPv4 gateway is not configured for public "
188 "network or public_network_id is not "
189 "configured")
190 proxy = self._create_server()
191 proxy_client = ssh.Client(proxy['fip']['floating_ip_address'],
192 CONF.validation.image_ssh_user,
193 pkey=self.keypair['private_key'])
194 src_server = self._create_server(create_floating_ip=False)
195 src_server_ip = src_server['port']['fixed_ips'][0]['ip_address']
196 ssh_client = ssh.Client(src_server_ip,
197 CONF.validation.image_ssh_user,
198 pkey=self.keypair['private_key'],
199 proxy_client=proxy_client)
200 self.check_remote_connectivity(ssh_client,
201 gateway_external_ip)
LIU Yulong5ba88ef2017-12-22 10:50:15 +0800202
203
204class FloatingIPQosTest(FloatingIpTestCasesMixin,
205 test_qos.QoSTest):
206
207 same_network = True
208
209 @classmethod
210 @utils.requires_ext(extension="router", service="network")
211 @utils.requires_ext(extension="qos", service="network")
212 @base_api.require_qos_rule_type(qos_consts.RULE_TYPE_BANDWIDTH_LIMIT)
213 def resource_setup(cls):
214 super(FloatingIPQosTest, cls).resource_setup()
215
216 @decorators.idempotent_id('5eb48aea-eaba-4c20-8a6f-7740070a0aa3')
217 def test_qos(self):
218 """Test floating IP is binding to a QoS policy with
219
220 ingress and egress bandwidth limit rules. And it applied correctly
221 by sending a file from the instance to the test node.
222 Then calculating the bandwidth every ~1 sec by the number of bits
223 received / elapsed time.
224 """
225
226 self._test_basic_resources()
227 policy_id = self._create_qos_policy()
228 ssh_client = self._create_ssh_client()
229 self.os_admin.network_client.create_bandwidth_limit_rule(
230 policy_id, max_kbps=constants.LIMIT_KILO_BITS_PER_SECOND,
231 max_burst_kbps=constants.LIMIT_KILO_BYTES,
232 direction=lib_constants.INGRESS_DIRECTION)
233 self.os_admin.network_client.create_bandwidth_limit_rule(
234 policy_id, max_kbps=constants.LIMIT_KILO_BITS_PER_SECOND,
235 max_burst_kbps=constants.LIMIT_KILO_BYTES,
236 direction=lib_constants.EGRESS_DIRECTION)
237
238 rules = self.os_admin.network_client.list_bandwidth_limit_rules(
239 policy_id)
240 self.assertEqual(2, len(rules['bandwidth_limit_rules']))
241
242 fip = self.os_admin.network_client.get_floatingip(
243 self.fip['id'])['floatingip']
244 self.assertEqual(self.port['id'], fip['port_id'])
245
246 self.os_admin.network_client.update_floatingip(
247 self.fip['id'],
248 qos_policy_id=policy_id)
249
250 fip = self.os_admin.network_client.get_floatingip(
251 self.fip['id'])['floatingip']
252 self.assertEqual(policy_id, fip['qos_policy_id'])
253
254 self._create_file_for_bw_tests(ssh_client)
255 common_utils.wait_until_true(lambda: self._check_bw(
256 ssh_client,
257 self.fip['floating_ip_address'],
258 port=self.NC_PORT),
259 timeout=120,
260 sleep=1)