~midonet-drivers/python-networking-midonet/liberty

« back to all changes in this revision

Viewing changes to midonet/neutron/tests/unit/test_extension_lbaas.py

  • Committer: Jaume Devesa
  • Date: 2015-08-25 12:33:00 UTC
  • Revision ID: devvesa@gmail.com-20150825123300-x39xyxc5wjsrm7me
Removing tarball data

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2015 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
 
 
16
 
import contextlib
17
 
from webob import exc
18
 
 
19
 
from midonet.neutron.tests.unit import test_midonet_plugin_v2 as test_mn
20
 
 
21
 
from neutron.plugins.common import constants
22
 
from neutron.tests.unit.api import test_extensions as test_ex
23
 
from neutron.tests.unit.extensions import test_l3
24
 
from neutron_lbaas.extensions import loadbalancer
25
 
from neutron_lbaas.tests.unit.db.loadbalancer import test_db_loadbalancer
26
 
from oslo_config import cfg
27
 
from oslo_utils import uuidutils
28
 
 
29
 
MN_DRIVER_KLASS = ('midonet.neutron.services.loadbalancer.driver.'
30
 
                   'MidonetLoadbalancerDriver')
31
 
 
32
 
 
33
 
class LoadbalancerTestExtensionManager(test_l3.L3TestExtensionManager):
34
 
 
35
 
    def get_resources(self):
36
 
        res = super(LoadbalancerTestExtensionManager, self).get_resources()
37
 
        return res + loadbalancer.Loadbalancer.get_resources()
38
 
 
39
 
    def get_actions(self):
40
 
        return []
41
 
 
42
 
    def get_request_extensions(self):
43
 
        return []
44
 
 
45
 
 
46
 
class LoadbalancerTestCase(test_db_loadbalancer.LoadBalancerTestMixin,
47
 
                           test_l3.L3NatTestCaseMixin,
48
 
                           test_mn.MidonetPluginV2TestCase):
49
 
 
50
 
    def setUp(self):
51
 
        service_plugins = {
52
 
            'lb_plugin_name': test_db_loadbalancer.DB_LB_PLUGIN_KLASS}
53
 
        lbaas_provider = (constants.LOADBALANCER + ':lbaas:' +
54
 
                          MN_DRIVER_KLASS + ':default')
55
 
        ext_mgr = LoadbalancerTestExtensionManager()
56
 
        cfg.CONF.set_override('service_provider',
57
 
                              [lbaas_provider],
58
 
                              'service_providers')
59
 
 
60
 
        super(LoadbalancerTestCase, self).setUp(
61
 
            service_plugins=service_plugins, ext_mgr=ext_mgr)
62
 
        self.ext_api = test_ex.setup_extensions_middleware(ext_mgr)
63
 
 
64
 
        # Subnet and router must always exist and associated
65
 
        network = self._make_network(self.fmt, 'net1', True)
66
 
        self._subnet = self._make_subnet(self.fmt, network, "10.0.0.1",
67
 
                                   '10.0.0.0/24')
68
 
        self._subnet_id = self._subnet['subnet']['id']
69
 
        router = self._make_router(self.fmt, self._tenant_id, 'router1', True)
70
 
        self._router_id = router['router']['id']
71
 
        self._router_interface_action('add', self._router_id, self._subnet_id,
72
 
                                      None)
73
 
 
74
 
        # Also prepare external network and subnet which are needed for VIP
75
 
        ext_network = self._make_network(self.fmt, 'ext_net1', True)
76
 
        self._set_net_external(ext_network['network']['id'])
77
 
        self._ext_subnet = self._make_subnet(self.fmt, ext_network,
78
 
                                             "200.0.0.1", '200.0.0.0/24')
79
 
 
80
 
        # Router must have gateway set for VIP - Pool association
81
 
        self._add_external_gateway_to_router(self._router_id,
82
 
                                             ext_network['network']['id'])
83
 
 
84
 
        # Override the default subnet ID used in the upstream load balancer
85
 
        # tests so that the midonet-specific tests use the specific subnet
86
 
        # created in the setup
87
 
        test_db_loadbalancer._subnet_id = self._subnet_id
88
 
 
89
 
    def tearDown(self):
90
 
        super(LoadbalancerTestCase, self).tearDown()
91
 
 
92
 
    @contextlib.contextmanager
93
 
    def subnet_with_router(self, cidr='10.0.1.0/24'):
94
 
        with self.subnet(cidr=cidr) as sub:
95
 
            subnet = sub['subnet']
96
 
            self._router_interface_action('add', self._router_id,
97
 
                                          subnet['id'], None)
98
 
            yield sub
99
 
 
100
 
    @contextlib.contextmanager
101
 
    def pool_with_hm_associated(self, subnet_id=None, do_delete=True):
102
 
        with self.health_monitor(do_delete=do_delete) as hm:
103
 
            with self.pool(subnet_id=subnet_id, do_delete=do_delete) as pool:
104
 
                # Associate the health_monitor to the pool
105
 
                assoc = {"health_monitor": {
106
 
                         "id": hm['health_monitor']['id'],
107
 
                         'tenant_id': self._tenant_id}}
108
 
                req = self.new_create_request("pools",
109
 
                                              assoc,
110
 
                                              fmt=self.fmt,
111
 
                                              id=pool['pool']['id'],
112
 
                                              subresource="health_monitors")
113
 
                res = req.get_response(self.ext_api)
114
 
                self.assertEqual(res.status_int, exc.HTTPCreated.code)
115
 
 
116
 
                # Due to the policy check, the returned response gets the
117
 
                # associated health monitor IDs stripped and an empty list is
118
 
                # returned.  So verify the association by doing a separate
119
 
                # 'get'.
120
 
                req = self.new_show_request('pools',
121
 
                                            pool['pool']['id'],
122
 
                                            fmt=self.fmt)
123
 
                p = self.deserialize(self.fmt, req.get_response(self.ext_api))
124
 
 
125
 
                yield p, hm
126
 
 
127
 
    def _test_create_vip(self, name="VIP", pool_id=None, protocol='HTTP',
128
 
                         port_number=80, admin_state_up=True,
129
 
                         subnet_id=None,
130
 
                         expected_res_status=exc.HTTPCreated.code):
131
 
        if subnet_id is None:
132
 
            subnet_id = self._ext_subnet['subnet']['id']
133
 
        self._create_vip(self.fmt, name, pool_id, protocol, port_number,
134
 
                         admin_state_up, subnet_id=subnet_id,
135
 
                         expected_res_status=expected_res_status)
136
 
 
137
 
    def _test_vip_status(self, vip_id, status):
138
 
        req = self.new_show_request('vips', vip_id)
139
 
        resp = req.get_response(self.ext_api)
140
 
        self.assertEqual(exc.HTTPOk.code, resp.status_int)
141
 
        vip = self.deserialize(self.fmt, resp)
142
 
        self.assertEqual(status, vip['vip']['status'])
143
 
 
144
 
    def _test_create_pool(self, name="pool", lb_method='ROUND_ROBIN',
145
 
                          protocol='TCP', admin_state_up=True,
146
 
                          subnet_id=test_db_loadbalancer._subnet_id,
147
 
                          expected_res_status=exc.HTTPOk.code):
148
 
        self._create_pool(self.fmt, name, lb_method, protocol, admin_state_up,
149
 
                          subnet_id=subnet_id,
150
 
                          expected_res_status=expected_res_status)
151
 
 
152
 
    def test_create_pool(self):
153
 
        name = "pool1"
154
 
        keys = [('name', name),
155
 
                ('subnet_id', test_db_loadbalancer._subnet_id),
156
 
                ('tenant_id', self._tenant_id),
157
 
                ('protocol', 'HTTP'),
158
 
                ('lb_method', 'ROUND_ROBIN'),
159
 
                ('admin_state_up', True),
160
 
                ('status', 'ACTIVE')]
161
 
        with self.pool(name=name) as pool:
162
 
            for k, v in keys:
163
 
                self.assertEqual(pool['pool'][k], v)
164
 
 
165
 
    def test_create_pool_with_bad_subnet(self):
166
 
        # Subnet does not exist so it should throw an error
167
 
        self._create_pool(self.fmt, 'pool1', 'ROUND_ROBIN', 'TCP', True,
168
 
                          expected_res_status=exc.HTTPNotFound.code,
169
 
                          subnet_id=uuidutils.generate_uuid())
170
 
 
171
 
    def test_create_pool_with_external_subnet(self):
172
 
        # Subnet is on an external network, which results in an error
173
 
        self._test_create_pool(subnet_id=self._ext_subnet['subnet']['id'],
174
 
                               expected_res_status=exc.HTTPBadRequest.code)
175
 
 
176
 
    def test_create_pool_with_no_router(self):
177
 
        # Subnet with no router association should throw an exception
178
 
        with self.subnet() as sub:
179
 
            self._test_create_pool(subnet_id=sub['subnet']['id'],
180
 
                                   expected_res_status=exc.HTTPBadRequest.code)
181
 
 
182
 
    def test_delete_pool(self):
183
 
        with self.pool(do_delete=False) as pool:
184
 
            req = self.new_delete_request('pools', pool['pool']['id'])
185
 
            res = req.get_response(self.ext_api)
186
 
            self.assertEqual(res.status_int, exc.HTTPNoContent.code)
187
 
 
188
 
    def test_show_pool(self):
189
 
        name = "pool1"
190
 
        keys = [('name', name),
191
 
                ('subnet_id', test_db_loadbalancer._subnet_id),
192
 
                ('tenant_id', self._tenant_id),
193
 
                ('protocol', 'HTTP'),
194
 
                ('lb_method', 'ROUND_ROBIN'),
195
 
                ('admin_state_up', True),
196
 
                ('status', 'ACTIVE')]
197
 
        with self.pool(name=name) as pool:
198
 
            req = self.new_show_request('pools',
199
 
                                        pool['pool']['id'],
200
 
                                        fmt=self.fmt)
201
 
            res = self.deserialize(self.fmt, req.get_response(self.ext_api))
202
 
            for k, v in keys:
203
 
                self.assertEqual(res['pool'][k], v)
204
 
 
205
 
    def test_update_pool(self):
206
 
        keys = [('name', 'new_name'),
207
 
                ('admin_state_up', False)]
208
 
        with self.pool() as pool:
209
 
            req = self.new_update_request('pools',
210
 
                                          {'pool': {
211
 
                                              'name': 'new_name',
212
 
                                              'admin_state_up': False}},
213
 
                                          pool['pool']['id'])
214
 
            res = self.deserialize(self.fmt, req.get_response(self.ext_api))
215
 
            for k, v in keys:
216
 
                self.assertEqual(res['pool'][k], v)
217
 
 
218
 
    def test_create_vip(self):
219
 
        keys = [('name', 'vip1'),
220
 
                ('subnet_id', self._ext_subnet['subnet']['id']),
221
 
                ('tenant_id', self._tenant_id),
222
 
                ('protocol', 'HTTP'),
223
 
                ('protocol_port', 80),
224
 
                ('admin_state_up', True)]
225
 
        with self.pool() as pool:
226
 
            with self.vip(pool=pool, subnet=self._ext_subnet) as vip:
227
 
                for k, v in keys:
228
 
                    self.assertEqual(vip['vip'][k], v)
229
 
 
230
 
    def test_create_vip_with_bad_subnet(self):
231
 
        # Subnet does not exist so it should throw an error
232
 
        with self.pool() as pool:
233
 
            self._test_create_vip(pool_id=pool['pool']['id'],
234
 
                                  subnet_id=uuidutils.generate_uuid(),
235
 
                                  expected_res_status=exc.HTTPNotFound.code)
236
 
 
237
 
    def test_create_vip_same_subnet_as_pool_with_hm(self):
238
 
        # VIP and pool subnets cannot be the same if HM is associated
239
 
        with self.pool_with_hm_associated() as (pool, hm):
240
 
            self._test_create_vip(pool_id=pool['pool']['id'],
241
 
                                  subnet_id=pool['pool']['subnet_id'],
242
 
                                  expected_res_status=exc.HTTPBadRequest.code)
243
 
 
244
 
    def test_create_vip_same_subnet_as_pool_with_no_hm(self):
245
 
        # VIP and pool subnets can be the same if HM is not associated
246
 
        with self.pool(do_delete=False) as pool:
247
 
            self._test_create_vip(pool_id=pool['pool']['id'],
248
 
                                  subnet_id=pool['pool']['subnet_id'])
249
 
 
250
 
    def test_create_vip_with_bad_pool(self):
251
 
        # Non-existent pool results in an error
252
 
        self._test_create_vip(pool_id=uuidutils.generate_uuid(),
253
 
                              expected_res_status=exc.HTTPNotFound.code)
254
 
 
255
 
    def test_create_vip_with_ext_subnet_and_pool_with_no_gw(self):
256
 
        # Pool associated with vip must be attached to a router that has gw
257
 
        self._remove_external_gateway_from_router(
258
 
            self._router_id, self._ext_subnet['subnet']['network_id'])
259
 
        with self.pool() as pool:
260
 
            self._test_create_vip(pool_id=pool['pool']['id'],
261
 
                                  subnet_id=self._ext_subnet['subnet']['id'],
262
 
                                  expected_res_status=exc.HTTPBadRequest.code)
263
 
 
264
 
    def test_update_vip(self):
265
 
        keys = [('name', 'new_name'),
266
 
                ('subnet_id', self._ext_subnet['subnet']['id']),
267
 
                ('tenant_id', self._tenant_id),
268
 
                ('protocol', 'HTTP'),
269
 
                ('protocol_port', 80),
270
 
                ('admin_state_up', False)]
271
 
        with self.pool() as pool:
272
 
            with self.vip(pool=pool, subnet=self._ext_subnet) as vip:
273
 
                req = self.new_update_request('vips',
274
 
                                              {'vip': {
275
 
                                                  'name': 'new_name',
276
 
                                                  'admin_state_up': False}},
277
 
                                              vip['vip']['id'])
278
 
                res = self.deserialize(
279
 
                    self.fmt, req.get_response(self.ext_api))
280
 
                for k, v in keys:
281
 
                    self.assertEqual(res['vip'][k], v)
282
 
 
283
 
    def test_update_vip_same_subnet_as_pool_with_hm(self):
284
 
        # Updating the pool Id to a pool with the same subnet as the VIP
285
 
        # when HM is associated with the pool results in a validation error
286
 
        with self.subnet_with_router() as sub:
287
 
            subnet = sub['subnet']
288
 
            with self.pool() as pool1:
289
 
                with self.vip(pool=pool1, subnet=sub) as vip:
290
 
                    with self.pool_with_hm_associated(
291
 
                            do_delete=False,
292
 
                            subnet_id=subnet['id']) as (pool2, hm):
293
 
                        req = self.new_update_request(
294
 
                            'vips', {'vip': {'pool_id': pool2['pool']['id']}},
295
 
                            vip['vip']['id'])
296
 
                        res = req.get_response(self.ext_api)
297
 
                        self.assertEqual(exc.HTTPBadRequest.code,
298
 
                                         res.status_int)
299
 
                        self._test_vip_status(vip['vip']['id'],
300
 
                                              constants.ERROR)
301
 
 
302
 
    def test_update_vip_same_subnet_as_pool_with_no_hm(self):
303
 
        # Updating the pool Id to a pool with the same subnet as the VIP
304
 
        # when HM is NOT associated with the pool is accepted
305
 
        with self.subnet_with_router() as sub:
306
 
            subnet = sub['subnet']
307
 
            with self.pool(subnet_id=subnet['id']) as pool1:
308
 
                with self.pool(subnet_id=self._subnet_id) as pool2:
309
 
                    with self.vip(pool=pool1, subnet=self._ext_subnet) as vip:
310
 
                        req = self.new_update_request(
311
 
                            'vips', {'vip': {'pool_id': pool2['pool']['id']}},
312
 
                            vip['vip']['id'])
313
 
                        res = req.get_response(self.ext_api)
314
 
                        self.assertEqual(exc.HTTPOk.code, res.status_int)
315
 
                        self._test_vip_status(vip['vip']['id'],
316
 
                                              constants.ACTIVE)
317
 
 
318
 
    def test_create_pool_health_monitor(self):
319
 
        with self.pool_with_hm_associated() as (p, hm):
320
 
            self.assertEqual(len(p['pool']['health_monitors']), 1)
321
 
            self.assertEqual(p['pool']['health_monitors'][0],
322
 
                             hm['health_monitor']['id'])
323
 
 
324
 
    def test_create_pool_health_monitor_already_associated(self):
325
 
        # Associating two health monitors to a pool throws an error
326
 
        with self.pool_with_hm_associated() as (p, hm):
327
 
            with self.health_monitor() as hm2:
328
 
                # Associate the second hm
329
 
                assoc2 = {"health_monitor": {
330
 
                          "id": hm2['health_monitor']['id'],
331
 
                          'tenant_id': self._tenant_id}}
332
 
                req2 = self.new_create_request(
333
 
                    "pools", assoc2, fmt=self.fmt, id=p['pool']['id'],
334
 
                    subresource="health_monitors")
335
 
                res2 = req2.get_response(self.ext_api)
336
 
                self.assertEqual(res2.status_int, exc.HTTPBadRequest.code)
337
 
 
338
 
    def test_delete_pool_health_monitor(self):
339
 
        with self.pool_with_hm_associated() as (p, hm):
340
 
            req = self.new_delete_request("pools", fmt=self.fmt,
341
 
                                          id=p['pool']['id'],
342
 
                                          sub_id=hm['health_monitor']['id'],
343
 
                                          subresource="health_monitors")
344
 
            res = req.get_response(self.ext_api)
345
 
            self.assertEqual(res.status_int, exc.HTTPNoContent.code)
346
 
 
347
 
            # Verify that it's gone
348
 
            req = self.new_show_request('pools', p['pool']['id'], fmt=self.fmt)
349
 
            res = self.deserialize(self.fmt, req.get_response(self.ext_api))
350
 
            self.assertEqual(len(res['pool']['health_monitors']), 0)
351
 
 
352
 
    def test_create_pool_health_monitor_with_same_vip_subnet(self):
353
 
        # Associating two health monitors to a pool which is associated
354
 
        # with a vip of the same subnet
355
 
        with self.pool(subnet_id=self._subnet_id) as pool:
356
 
            with self.vip(pool=pool, subnet=self._subnet):
357
 
                with self.health_monitor() as hm:
358
 
                    assoc = {"health_monitor": {
359
 
                             "id": hm['health_monitor']['id'],
360
 
                             'tenant_id': self._tenant_id}}
361
 
                    req = self.new_create_request(
362
 
                        "pools", assoc, fmt=self.fmt, id=pool['pool']['id'],
363
 
                        subresource="health_monitors")
364
 
                    res = req.get_response(self.ext_api)
365
 
                    self.assertEqual(res.status_int, exc.HTTPBadRequest.code)