Set lock_path correctly.
[openstack-build/neutron-build.git] / neutron / tests / unit / agent / linux / test_keepalived.py
1 # Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
13 # under the License.
14
15 import testtools
16
17 from neutron.agent.linux import keepalived
18 from neutron.common import constants as n_consts
19 from neutron.tests import base
20
21 # Keepalived user guide:
22 # http://www.keepalived.org/pdf/UserGuide.pdf
23
24
25 class KeepalivedGetFreeRangeTestCase(base.BaseTestCase):
26     def test_get_free_range(self):
27         free_range = keepalived.get_free_range(
28             parent_range='169.254.0.0/16',
29             excluded_ranges=['169.254.0.0/24',
30                              '169.254.1.0/24',
31                              '169.254.2.0/24'],
32             size=24)
33         self.assertEqual('169.254.3.0/24', free_range)
34
35     def test_get_free_range_without_excluded(self):
36         free_range = keepalived.get_free_range(
37             parent_range='169.254.0.0/16',
38             excluded_ranges=[],
39             size=20)
40         self.assertEqual('169.254.0.0/20', free_range)
41
42     def test_get_free_range_excluded_out_of_parent(self):
43         free_range = keepalived.get_free_range(
44             parent_range='169.254.0.0/16',
45             excluded_ranges=['255.255.255.0/24'],
46             size=24)
47         self.assertEqual('169.254.0.0/24', free_range)
48
49     def test_get_free_range_not_found(self):
50         tiny_parent_range = '192.168.1.0/24'
51         huge_size = 8
52         with testtools.ExpectedException(ValueError):
53             keepalived.get_free_range(
54                 parent_range=tiny_parent_range,
55                 excluded_ranges=[],
56                 size=huge_size)
57
58
59 class KeepalivedConfBaseMixin(object):
60
61     def _get_config(self):
62         config = keepalived.KeepalivedConf()
63
64         instance1 = keepalived.KeepalivedInstance('MASTER', 'eth0', 1,
65                                                   ['169.254.192.0/18'],
66                                                   advert_int=5)
67         instance1.set_authentication('AH', 'pass123')
68         instance1.track_interfaces.append("eth0")
69
70         vip_address1 = keepalived.KeepalivedVipAddress('192.168.1.0/24',
71                                                        'eth1')
72
73         vip_address2 = keepalived.KeepalivedVipAddress('192.168.2.0/24',
74                                                        'eth2')
75
76         vip_address3 = keepalived.KeepalivedVipAddress('192.168.3.0/24',
77                                                        'eth2')
78
79         vip_address_ex = keepalived.KeepalivedVipAddress('192.168.55.0/24',
80                                                          'eth10')
81
82         instance1.vips.append(vip_address1)
83         instance1.vips.append(vip_address2)
84         instance1.vips.append(vip_address3)
85         instance1.vips.append(vip_address_ex)
86
87         virtual_route = keepalived.KeepalivedVirtualRoute(n_consts.IPv4_ANY,
88                                                           "192.168.1.1",
89                                                           "eth1")
90         instance1.virtual_routes.gateway_routes = [virtual_route]
91
92         instance2 = keepalived.KeepalivedInstance('MASTER', 'eth4', 2,
93                                                   ['169.254.192.0/18'],
94                                                   mcast_src_ip='224.0.0.1')
95         instance2.track_interfaces.append("eth4")
96
97         vip_address1 = keepalived.KeepalivedVipAddress('192.168.3.0/24',
98                                                        'eth6')
99
100         instance2.vips.append(vip_address1)
101         instance2.vips.append(vip_address2)
102         instance2.vips.append(vip_address_ex)
103
104         config.add_instance(instance1)
105         config.add_instance(instance2)
106
107         return config
108
109
110 class KeepalivedConfTestCase(base.BaseTestCase,
111                              KeepalivedConfBaseMixin):
112
113     expected = """vrrp_instance VR_1 {
114     state MASTER
115     interface eth0
116     virtual_router_id 1
117     priority 50
118     garp_master_repeat 5
119     garp_master_refresh 10
120     advert_int 5
121     authentication {
122         auth_type AH
123         auth_pass pass123
124     }
125     track_interface {
126         eth0
127     }
128     virtual_ipaddress {
129         169.254.0.1/24 dev eth0
130     }
131     virtual_ipaddress_excluded {
132         192.168.1.0/24 dev eth1
133         192.168.2.0/24 dev eth2
134         192.168.3.0/24 dev eth2
135         192.168.55.0/24 dev eth10
136     }
137     virtual_routes {
138         0.0.0.0/0 via 192.168.1.1 dev eth1
139     }
140 }
141 vrrp_instance VR_2 {
142     state MASTER
143     interface eth4
144     virtual_router_id 2
145     priority 50
146     garp_master_repeat 5
147     garp_master_refresh 10
148     mcast_src_ip 224.0.0.1
149     track_interface {
150         eth4
151     }
152     virtual_ipaddress {
153         169.254.0.2/24 dev eth4
154     }
155     virtual_ipaddress_excluded {
156         192.168.2.0/24 dev eth2
157         192.168.3.0/24 dev eth6
158         192.168.55.0/24 dev eth10
159     }
160 }"""
161
162     def test_config_generation(self):
163         config = self._get_config()
164         self.assertEqual(self.expected, config.get_config_str())
165
166     def test_config_with_reset(self):
167         config = self._get_config()
168         self.assertEqual(self.expected, config.get_config_str())
169
170         config.reset()
171         self.assertEqual('', config.get_config_str())
172
173     def test_get_existing_vip_ip_addresses_returns_list(self):
174         config = self._get_config()
175         instance = config.get_instance(1)
176         current_vips = sorted(instance.get_existing_vip_ip_addresses('eth2'))
177         self.assertEqual(['192.168.2.0/24', '192.168.3.0/24'], current_vips)
178
179
180 class KeepalivedStateExceptionTestCase(base.BaseTestCase):
181     def test_state_exception(self):
182         invalid_vrrp_state = 'a seal walks'
183         self.assertRaises(keepalived.InvalidInstanceStateException,
184                           keepalived.KeepalivedInstance,
185                           invalid_vrrp_state, 'eth0', 33,
186                           ['169.254.192.0/18'])
187
188         invalid_auth_type = 'into a club'
189         instance = keepalived.KeepalivedInstance('MASTER', 'eth0', 1,
190                                                  ['169.254.192.0/18'])
191         self.assertRaises(keepalived.InvalidAuthenticationTypeException,
192                           instance.set_authentication,
193                           invalid_auth_type, 'some_password')
194
195
196 class KeepalivedInstanceRoutesTestCase(base.BaseTestCase):
197     @classmethod
198     def _get_instance_routes(cls):
199         routes = keepalived.KeepalivedInstanceRoutes()
200         default_gw_eth0 = keepalived.KeepalivedVirtualRoute(
201             '0.0.0.0/0', '1.0.0.254', 'eth0')
202         default_gw_eth1 = keepalived.KeepalivedVirtualRoute(
203             '::/0', 'fe80::3e97:eff:fe26:3bfa/64', 'eth1')
204         routes.gateway_routes = [default_gw_eth0, default_gw_eth1]
205         extra_routes = [
206             keepalived.KeepalivedVirtualRoute('10.0.0.0/8', '1.0.0.1'),
207             keepalived.KeepalivedVirtualRoute('20.0.0.0/8', '2.0.0.2')]
208         routes.extra_routes = extra_routes
209         extra_subnets = [
210             keepalived.KeepalivedVirtualRoute(
211                 '30.0.0.0/8', None, 'eth0', scope='link')]
212         routes.extra_subnets = extra_subnets
213         return routes
214
215     def test_routes(self):
216         routes = self._get_instance_routes()
217         self.assertEqual(len(routes.routes), 5)
218
219     def test_remove_routes_on_interface(self):
220         routes = self._get_instance_routes()
221         routes.remove_routes_on_interface('eth0')
222         self.assertEqual(len(routes.routes), 3)
223         routes.remove_routes_on_interface('eth1')
224         self.assertEqual(len(routes.routes), 2)
225
226     def test_build_config(self):
227         expected = """    virtual_routes {
228         0.0.0.0/0 via 1.0.0.254 dev eth0
229         ::/0 via fe80::3e97:eff:fe26:3bfa/64 dev eth1
230         10.0.0.0/8 via 1.0.0.1
231         20.0.0.0/8 via 2.0.0.2
232         30.0.0.0/8 dev eth0 scope link
233     }"""
234         routes = self._get_instance_routes()
235         self.assertEqual(expected, '\n'.join(routes.build_config()))
236
237
238 class KeepalivedInstanceTestCase(base.BaseTestCase,
239                                  KeepalivedConfBaseMixin):
240     def test_get_primary_vip(self):
241         instance = keepalived.KeepalivedInstance('MASTER', 'ha0', 42,
242                                                  ['169.254.192.0/18'])
243         self.assertEqual('169.254.0.42/24', instance.get_primary_vip())
244
245     def test_remove_addresses_by_interface(self):
246         config = self._get_config()
247         instance = config.get_instance(1)
248         instance.remove_vips_vroutes_by_interface('eth2')
249         instance.remove_vips_vroutes_by_interface('eth10')
250
251         expected = """vrrp_instance VR_1 {
252     state MASTER
253     interface eth0
254     virtual_router_id 1
255     priority 50
256     garp_master_repeat 5
257     garp_master_refresh 10
258     advert_int 5
259     authentication {
260         auth_type AH
261         auth_pass pass123
262     }
263     track_interface {
264         eth0
265     }
266     virtual_ipaddress {
267         169.254.0.1/24 dev eth0
268     }
269     virtual_ipaddress_excluded {
270         192.168.1.0/24 dev eth1
271     }
272     virtual_routes {
273         0.0.0.0/0 via 192.168.1.1 dev eth1
274     }
275 }
276 vrrp_instance VR_2 {
277     state MASTER
278     interface eth4
279     virtual_router_id 2
280     priority 50
281     garp_master_repeat 5
282     garp_master_refresh 10
283     mcast_src_ip 224.0.0.1
284     track_interface {
285         eth4
286     }
287     virtual_ipaddress {
288         169.254.0.2/24 dev eth4
289     }
290     virtual_ipaddress_excluded {
291         192.168.2.0/24 dev eth2
292         192.168.3.0/24 dev eth6
293         192.168.55.0/24 dev eth10
294     }
295 }"""
296
297         self.assertEqual(expected, config.get_config_str())
298
299     def test_build_config_no_vips(self):
300         expected = """vrrp_instance VR_1 {
301     state MASTER
302     interface eth0
303     virtual_router_id 1
304     priority 50
305     garp_master_repeat 5
306     garp_master_refresh 10
307     virtual_ipaddress {
308         169.254.0.1/24 dev eth0
309     }
310 }"""
311         instance = keepalived.KeepalivedInstance(
312             'MASTER', 'eth0', 1, ['169.254.192.0/18'])
313         self.assertEqual(expected, '\n'.join(instance.build_config()))
314
315
316 class KeepalivedVipAddressTestCase(base.BaseTestCase):
317     def test_vip_with_scope(self):
318         vip = keepalived.KeepalivedVipAddress('fe80::3e97:eff:fe26:3bfa/64',
319                                               'eth1',
320                                               'link')
321         self.assertEqual('fe80::3e97:eff:fe26:3bfa/64 dev eth1 scope link',
322                          vip.build_config())
323
324     def test_add_vip_idempotent(self):
325         instance = keepalived.KeepalivedInstance('MASTER', 'eth0', 1,
326                                                  ['169.254.192.0/18'])
327         instance.add_vip('192.168.222.1/32', 'eth11', None)
328         instance.add_vip('192.168.222.1/32', 'eth12', 'link')
329         self.assertEqual(1, len(instance.vips))
330
331
332 class KeepalivedVirtualRouteTestCase(base.BaseTestCase):
333     def test_virtual_route_with_dev(self):
334         route = keepalived.KeepalivedVirtualRoute(n_consts.IPv4_ANY, '1.2.3.4',
335                                                   'eth0')
336         self.assertEqual('0.0.0.0/0 via 1.2.3.4 dev eth0',
337                          route.build_config())
338
339     def test_virtual_route_without_dev(self):
340         route = keepalived.KeepalivedVirtualRoute('50.0.0.0/8', '1.2.3.4')
341         self.assertEqual('50.0.0.0/8 via 1.2.3.4', route.build_config())