blob: 62f433b2d6acfc4b04aa9dc236432d837cb25e23 [file] [log] [blame]
YAMAMOTO Takashi5214b272018-01-16 13:58:41 +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
17
18from tempest.common import utils
19from tempest.common import waiters
20from tempest.lib.common import ssh
21from tempest.lib.common.utils import data_utils
22from tempest.lib import decorators
23
24from neutron_tempest_plugin import config
25from neutron_tempest_plugin.scenario import base
26from neutron_tempest_plugin.scenario import constants
27
28try:
29 # TODO(yamamoto): Remove this hack after bgp tests are rehomed
30 from neutron_dynamic_routing.tests.tempest import bgp_client
31except ImportError:
32 bgp_client = None
33
34
35CONF = config.CONF
36
37
38class BgpClientMixin(object):
39 @classmethod
40 def resource_setup(cls):
41 super(BgpClientMixin, cls).resource_setup()
42 if bgp_client is None:
43 msg = "No BGP service client is available"
44 raise cls.skipException(msg)
45 manager = cls.os_admin
46 cls.bgp_client = bgp_client.BgpSpeakerClientJSON(
47 manager.auth_provider,
48 CONF.network.catalog_type,
49 CONF.network.region or CONF.identity.region,
50 endpoint_type=CONF.network.endpoint_type,
51 build_interval=CONF.network.build_interval,
52 build_timeout=CONF.network.build_timeout,
53 **manager.default_params)
54
55 def create_bgp_speaker(self, **kwargs):
56 bgp_speaker = self.bgp_client.create_bgp_speaker(post_data={
57 'bgp_speaker': kwargs,
58 })['bgp_speaker']
59 self.addCleanup(self.bgp_client.delete_bgp_speaker, bgp_speaker['id'])
60 return bgp_speaker
61
62 def create_bgp_peer(self, **kwargs):
63 bgp_peer = self.bgp_client.create_bgp_peer(post_data={
64 'bgp_peer': kwargs,
65 })['bgp_peer']
66 self.addCleanup(self.bgp_client.delete_bgp_peer, bgp_peer['id'])
67 return bgp_peer
68
69 def add_bgp_peer_with_id(self, bgp_speaker_id, bgp_peer_id):
70 self.bgp_client.add_bgp_peer_with_id(bgp_speaker_id, bgp_peer_id)
71
72
73class Bgp(BgpClientMixin, base.BaseTempestTestCase):
74 """Test the following topology
75
76 +-------------------+
77 | public |
78 | network |
79 | |
80 +-+---------------+-+
81 | |
82 | |
83 +-------+-+ +-+-------+
84 | LEFT | | RIGHT |
85 | router | <--BGP--> | router |
86 | | | |
87 +----+----+ +----+----+
88 | |
89 +----+----+ +----+----+
90 | LEFT | | RIGHT |
91 | network | | network |
92 | | | |
93 +---------+ +---------+
94 """
95
96 credentials = ['primary', 'admin']
97
98 @classmethod
99 @utils.requires_ext(extension="bgp-speaker-router-insertion",
100 service="network")
101 def resource_setup(cls):
102 super(Bgp, cls).resource_setup()
103
104 # common
105 cls.keypair = cls.create_keypair()
106 cls.secgroup = cls.os_primary.network_client.create_security_group(
107 name=data_utils.rand_name('secgroup-'))['security_group']
108 cls.security_groups.append(cls.secgroup)
109 cls.create_loginable_secgroup_rule(secgroup_id=cls.secgroup['id'])
110 cls.create_pingable_secgroup_rule(secgroup_id=cls.secgroup['id'])
111
112 # LEFT
113 cls.router = cls.create_router(
114 data_utils.rand_name('left-router'),
115 admin_state_up=True,
116 external_network_id=CONF.network.public_network_id)
117 cls.network = cls.create_network(network_name='left-network')
118 cls.subnet = cls.create_subnet(cls.network,
119 name='left-subnet')
120 cls.create_router_interface(cls.router['id'], cls.subnet['id'])
121
122 # RIGHT
123 cls._right_network, cls._right_subnet, cls._right_router = \
124 cls._create_right_network()
125
126 @classmethod
127 def _create_right_network(cls):
128 # NOTE(yamamoto): Disable SNAT to workaround a bug
129 # https://midonet.atlassian.net/browse/MNA-1114
130 router = cls.create_admin_router(
131 data_utils.rand_name('right-router'),
132 admin_state_up=True,
133 external_network_id=CONF.network.public_network_id,
134 enable_snat=False,
135 project_id=cls.os_primary.network_client.tenant_id)
136 network = cls.create_network(network_name='right-network')
137 subnet = cls.create_subnet(
138 network,
139 cidr=netaddr.IPNetwork('10.10.0.0/24'),
140 name='right-subnet')
141 cls.create_router_interface(router['id'], subnet['id'])
142 return network, subnet, router
143
144 def _create_server(self, create_floating_ip=True, network=None):
145 if network is None:
146 network = self.network
147 port = self.create_port(network, security_groups=[self.secgroup['id']])
148 if create_floating_ip:
149 fip = self.create_and_associate_floatingip(port['id'])
150 else:
151 fip = None
152 server = self.create_server(
153 flavor_ref=CONF.compute.flavor_ref,
154 image_ref=CONF.compute.image_ref,
155 key_name=self.keypair['name'],
156 networks=[{'port': port['id']}])['server']
157 waiters.wait_for_server_status(self.os_primary.servers_client,
158 server['id'],
159 constants.SERVER_STATUS_ACTIVE)
160 return {'port': port, 'fip': fip, 'server': server}
161
162 def _find_ipv4_subnet(self, network_id):
163 subnets = self.os_admin.network_client.list_subnets(
164 network_id=network_id)['subnets']
165 for subnet in subnets:
166 if subnet['ip_version'] == 4:
167 return subnet['id']
168 msg = "No suitable subnets on public network"
169 raise self.skipException(msg)
170
171 def _get_external_ip(self, router, subnet_id):
172 for ip in router['external_gateway_info']['external_fixed_ips']:
173 if ip['subnet_id'] == subnet_id:
174 return ip['ip_address']
175 return None
176
177 def _setup_bgp(self):
178 network_id = CONF.network.public_network_id
179 subnet_id = self._find_ipv4_subnet(network_id)
180 sites = [
181 dict(name="left", network=self.network, subnet=self.subnet,
182 router=self.router, local_as=64512),
183 dict(name="right", network=self._right_network,
184 subnet=self._right_subnet, router=self._right_router,
185 local_as=64513),
186 ]
187 psk = data_utils.rand_name('mysecret')
188 for i in range(0, 2):
189 site = sites[i]
190 router = site['router']
191 site['bgp_speaker'] = self.create_bgp_speaker(
192 name=data_utils.rand_name('%s-bgp-speaker' % site['name']),
193 local_as=site['local_as'],
194 ip_version=4,
195 logical_router=router['id'])
196 site['external_v4_ip'] = self._get_external_ip(router, subnet_id)
197 for i in range(0, 2):
198 site = sites[i]
199 bgp_speaker_id = site['bgp_speaker']['id']
200 peer = sites[1 - i]
201 peer_ip = peer['external_v4_ip']
202 peer_as = peer['local_as']
203 bgp_peer = self.create_bgp_peer(
204 name=data_utils.rand_name('%s-bgp-peer' % site['name']),
205 peer_ip=peer_ip,
206 remote_as=peer_as,
207 auth_type='md5',
208 password=psk)
209 self.add_bgp_peer_with_id(bgp_speaker_id, bgp_peer['id'])
210
211 @decorators.idempotent_id('c1208ce2-c55f-4424-9035-25de83161d6f')
212 def test_bgp(self):
213 # RIGHT
214 right_server = self._create_server(
215 network=self._right_network,
216 create_floating_ip=False)
217
218 # LEFT
219 left_server = self._create_server()
220 ssh_client = ssh.Client(left_server['fip']['floating_ip_address'],
221 CONF.validation.image_ssh_user,
222 pkey=self.keypair['private_key'])
223
224 # check LEFT -> RIGHT connectivity via BGP advertised routes
225 self.check_remote_connectivity(
226 ssh_client,
227 right_server['port']['fixed_ips'][0]['ip_address'],
228 should_succeed=False)
229 self._setup_bgp()
230 self.check_remote_connectivity(
231 ssh_client,
232 right_server['port']['fixed_ips'][0]['ip_address'])