~ubuntu-branches/ubuntu/trusty/heat/trusty-security

« back to all changes in this revision

Viewing changes to heat/tests/test_cloud_loadbalancer.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Yolanda Robla, Chuck Short
  • Date: 2013-07-22 16:22:29 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20130722162229-zzvfu40id94ii0hc
Tags: 2013.2~b2-0ubuntu1
[ Yolanda Robla ]
* debian/tests: added autopkg tests

[ Chuck Short ]
* New upstream release
* debian/control:
  - Add python-pbr to build-depends.
  - Add python-d2to to build-depends.
  - Dropped python-argparse.
  - Add python-six to build-depends.
  - Dropped python-sendfile.
  - Dropped python-nose.
  - Added testrepository.
  - Added python-testtools.
* debian/rules: Run testrepository instead of nosetets.
* debian/patches/removes-lxml-version-limitation-from-pip-requires.patch: Dropped
  no longer needed.
* debian/patches/fix-package-version-detection-when-building-doc.patch: Dropped
  no longer needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#    vim: tabstop=4 shiftwidth=4 softtabstop=4
 
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
 
 
16
import uuid
 
17
import json
 
18
import copy
 
19
import random
 
20
import string
 
21
 
 
22
from heat.common import template_format
 
23
from heat.engine import scheduler
 
24
from heat.engine import resource
 
25
from heat.engine.resources.rackspace import cloud_loadbalancer as lb
 
26
from heat.tests.common import HeatTestCase
 
27
from heat.tests.utils import setup_dummy_db
 
28
from heat.tests.utils import parse_stack
 
29
 
 
30
# The following fakes are for pyrax
 
31
 
 
32
 
 
33
class FakeClient(object):
 
34
    user_agent = "Fake"
 
35
    USER_AGENT = "Fake"
 
36
 
 
37
 
 
38
class FakeManager(object):
 
39
    api = FakeClient()
 
40
 
 
41
    def list(self):
 
42
        pass
 
43
 
 
44
    def get(self, item):
 
45
        pass
 
46
 
 
47
    def delete(self, item):
 
48
        pass
 
49
 
 
50
    def create(self, *args, **kwargs):
 
51
        pass
 
52
 
 
53
    def find(self, *args, **kwargs):
 
54
        pass
 
55
 
 
56
    def action(self, item, action_type, body={}):
 
57
        pass
 
58
 
 
59
 
 
60
class FakeLoadBalancerManager(object):
 
61
    def __init__(self, api=None, *args, **kwargs):
 
62
        pass
 
63
 
 
64
    def set_content_caching(self, *args, **kwargs):
 
65
        pass
 
66
 
 
67
 
 
68
class FakeNode(object):
 
69
    def __init__(self, address="0.0.0.0", port=80, condition=None, weight=None,
 
70
                 status=None, parent=None, type=None, id=None):
 
71
        self.address = address
 
72
        self.port = port
 
73
        self.condition = condition
 
74
        self.weight = weight
 
75
        self.status = status
 
76
        self.parent = parent
 
77
        self.type = type
 
78
        self.id = id
 
79
 
 
80
    def __eq__(self, other):
 
81
        return self.__dict__ == other.__dict__
 
82
 
 
83
    def __ne__(self, other):
 
84
        return not self.__eq__(other)
 
85
 
 
86
 
 
87
class FakeVirtualIP(object):
 
88
    def __init__(self, address=None, port=None, condition=None,
 
89
                 ipVersion=None, type=None):
 
90
        self.address = address
 
91
        self.port = port
 
92
        self.condition = condition
 
93
        self.ipVersion = ipVersion
 
94
        self.type = type
 
95
 
 
96
    def __eq__(self, other):
 
97
        return self.__dict__ == other.__dict__
 
98
 
 
99
    def __ne__(self, other):
 
100
        return not self.__eq__(other)
 
101
 
 
102
 
 
103
class FakeLoadBalancerClient(object):
 
104
    def __init__(self, *args, **kwargs):
 
105
        self.Node = FakeNode
 
106
        self.VirtualIP = FakeVirtualIP
 
107
        pass
 
108
 
 
109
    def get(*args, **kwargs):
 
110
        pass
 
111
 
 
112
    def create(*args, **kwargs):
 
113
        pass
 
114
 
 
115
 
 
116
class FakeLoadBalancer(object):
 
117
    def __init__(self, name=None, info=None, *args, **kwargs):
 
118
        name = name or uuid.uuid4()
 
119
        info = info or {"fake": "fake"}
 
120
        self.id = uuid.uuid4()
 
121
        self.manager = FakeLoadBalancerManager()
 
122
        self.Node = FakeNode
 
123
        self.VirtualIP = FakeVirtualIP
 
124
        self.nodes = []
 
125
 
 
126
    def get(*args, **kwargs):
 
127
        pass
 
128
 
 
129
    def add_nodes(*args, **kwargs):
 
130
        pass
 
131
 
 
132
    def add_ssl_termination(*args, **kwargs):
 
133
        pass
 
134
 
 
135
    def set_error_page(*args, **kwargs):
 
136
        pass
 
137
 
 
138
    def add_access_list(*args, **kwargs):
 
139
        pass
 
140
 
 
141
 
 
142
class LoadBalancerWithFakeClient(lb.CloudLoadBalancer):
 
143
    def cloud_lb(self):
 
144
        return FakeLoadBalancerClient()
 
145
 
 
146
 
 
147
def override_resource():
 
148
    return {
 
149
        'Rackspace::Cloud::LoadBalancer': LoadBalancerWithFakeClient
 
150
    }
 
151
 
 
152
 
 
153
class LoadBalancerTest(HeatTestCase):
 
154
 
 
155
    def setUp(self):
 
156
        super(LoadBalancerTest, self).setUp()
 
157
 
 
158
        self.lb_template = {
 
159
            "AWSTemplateFormatVersion": "2010-09-09",
 
160
            "Description": "fawef",
 
161
            "Resources": {
 
162
                self._get_lb_resource_name(): {
 
163
                    "Type": "Rackspace::Cloud::LoadBalancer",
 
164
                    "Properties": {
 
165
                        "name": "test-clb",
 
166
                        "nodes": [{"address": "166.78.103.141", "port": 80,
 
167
                                   "condition": "ENABLED"}],
 
168
                        "protocol": "HTTP",
 
169
                        "port": 80,
 
170
                        "virtualIps": [
 
171
                            {"type": "PUBLIC", "ipVersion": "IPV6"}],
 
172
                        "algorithm": 'LEAST_CONNECTIONS',
 
173
                        "connectionThrottle": {'maxConnectionRate': 1000},
 
174
                        'timeout': 110,
 
175
                        'contentCaching': 'DISABLED'
 
176
                    }
 
177
                }
 
178
            }
 
179
        }
 
180
 
 
181
        self.lb_name = 'test-clb'
 
182
        self.expected_body = {
 
183
            "nodes": [FakeNode(address=u"166.78.103.141", port=80,
 
184
                               condition=u"ENABLED")],
 
185
            "protocol": u'HTTP',
 
186
            "port": 80,
 
187
            "virtual_ips": [FakeVirtualIP(type=u"PUBLIC", ipVersion=u"IPV6")],
 
188
            "halfClosed": None,
 
189
            "algorithm": u'LEAST_CONNECTIONS',
 
190
            "connectionThrottle": {'maxConnectionRate': 1000,
 
191
                                   'maxConnections': None,
 
192
                                   'rateInterval': None,
 
193
                                   'minConnections': None},
 
194
            "connectionLogging": None,
 
195
            "halfClosed": None,
 
196
            "healthMonitor": None,
 
197
            "metadata": None,
 
198
            "sessionPersistence": None,
 
199
            "timeout": 110
 
200
        }
 
201
 
 
202
        lb.resource_mapping = override_resource
 
203
        setup_dummy_db()
 
204
        resource._register_class("Rackspace::Cloud::LoadBalancer",
 
205
                                 LoadBalancerWithFakeClient)
 
206
 
 
207
    def _get_lb_resource_name(self):
 
208
        return "lb-" + str(uuid.uuid4())
 
209
 
 
210
    def __getattribute__(self, name):
 
211
        if name == 'expected_body' or name == 'lb_template':
 
212
            return copy.deepcopy(super(LoadBalancerTest, self)
 
213
                                 .__getattribute__(name))
 
214
        return super(LoadBalancerTest, self).__getattribute__(name)
 
215
 
 
216
    def _mock_create(self, t, stack, resource_name, lb_name, lb_body):
 
217
        rsrc = LoadBalancerWithFakeClient(resource_name,
 
218
                                          t['Resources'][resource_name],
 
219
                                          stack)
 
220
        self.m.StubOutWithMock(rsrc.clb, 'create')
 
221
        fake_loadbalancer = FakeLoadBalancer(name=lb_name)
 
222
        rsrc.clb.create(lb_name, **lb_body).AndReturn(fake_loadbalancer)
 
223
        return (rsrc, fake_loadbalancer)
 
224
 
 
225
    def _get_first_resource_name(self, templ):
 
226
        return next(k for k in templ['Resources'])
 
227
 
 
228
    def _random_name(self):
 
229
        return ''.join(random.choice(string.ascii_uppercase)
 
230
                       for x in range(10))
 
231
 
 
232
    def _mock_loadbalancer(self, lb_template, expected_name, expected_body):
 
233
        t = template_format.parse(json.dumps(lb_template))
 
234
        s = parse_stack(t, stack_name=self._random_name())
 
235
 
 
236
        rsrc, fake_loadbalancer = self._mock_create(t, s,
 
237
                                                    self.
 
238
                                                    _get_first_resource_name(
 
239
                                                        lb_template),
 
240
                                                    expected_name,
 
241
                                                    expected_body)
 
242
        self.m.StubOutWithMock(fake_loadbalancer, 'get')
 
243
        fake_loadbalancer.get().MultipleTimes().AndReturn(None)
 
244
 
 
245
        fake_loadbalancer.status = 'ACTIVE'
 
246
 
 
247
        return (rsrc, fake_loadbalancer)
 
248
 
 
249
    def _set_template(self, templ, **kwargs):
 
250
        for k, v in kwargs.iteritems():
 
251
            templ['Resources'][self._get_first_resource_name(templ)][
 
252
                'Properties'][k] = v
 
253
        return templ
 
254
 
 
255
    def _set_expected(self, expected, **kwargs):
 
256
        for k, v in kwargs.iteritems():
 
257
            expected[k] = v
 
258
        return expected
 
259
 
 
260
    def test_alter_properties(self):
 
261
        #test alter properties functions
 
262
        template = self._set_template(self.lb_template,
 
263
                                      sessionPersistence='HTTP_COOKIE',
 
264
                                      connectionLogging=True,
 
265
                                      metadata={'yolo': 'heeyyy_gurl'})
 
266
 
 
267
        expected = self._set_expected(self.expected_body,
 
268
                                      sessionPersistence=
 
269
                                      {'persistenceType': 'HTTP_COOKIE'},
 
270
                                      connectionLogging={'enabled': True},
 
271
                                      metadata=[
 
272
                                          {'key': 'yolo',
 
273
                                           'value': 'heeyyy_gurl'}])
 
274
 
 
275
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
276
                                                          self.lb_name,
 
277
                                                          expected)
 
278
 
 
279
        self.m.ReplayAll()
 
280
        scheduler.TaskRunner(rsrc.create)()
 
281
        self.m.VerifyAll()
 
282
 
 
283
    def test_validate_half_closed(self):
 
284
        #test failure (invalid protocol)
 
285
        template = self._set_template(self.lb_template, halfClosed=True)
 
286
        expected = self._set_expected(self.expected_body, halfClosed=True)
 
287
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
288
                                                          self.lb_name,
 
289
                                                          expected)
 
290
        self.assertEquals(rsrc.validate(), {
 
291
            'Error':
 
292
            'The halfClosed property is only available for the '
 
293
            'TCP or TCP_CLIENT_FIRST protocols'})
 
294
 
 
295
        #test TCP protocol
 
296
        template = self._set_template(template, protocol='TCP')
 
297
        expected = self._set_expected(expected, protocol='TCP')
 
298
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
299
                                                          self.lb_name,
 
300
                                                          expected)
 
301
        self.assertEquals(rsrc.validate(), None)
 
302
 
 
303
        #test TCP_CLIENT_FIRST protocol
 
304
        template = self._set_template(template,
 
305
                                      protocol='TCP_CLIENT_FIRST')
 
306
        expected = self._set_expected(expected,
 
307
                                      protocol='TCP_CLIENT_FIRST')
 
308
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
309
                                                          self.lb_name,
 
310
                                                          expected)
 
311
        self.assertEquals(rsrc.validate(), None)
 
312
 
 
313
    def test_validate_health_monitor(self):
 
314
        #test connect success
 
315
        health_monitor = {
 
316
            'type': 'CONNECT',
 
317
            'attemptsBeforeDeactivation': 1,
 
318
            'delay': 1,
 
319
            'timeout': 1
 
320
        }
 
321
        template = self._set_template(self.lb_template,
 
322
                                      healthMonitor=health_monitor)
 
323
        expected = self._set_expected(self.expected_body,
 
324
                                      healthMonitor=health_monitor)
 
325
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
326
                                                          self.lb_name,
 
327
                                                          expected)
 
328
 
 
329
        self.assertEquals(rsrc.validate(), None)
 
330
 
 
331
        #test connect failure
 
332
        #bodyRegex is only valid for type 'HTTP(S)'
 
333
        health_monitor['bodyRegex'] = 'dfawefawe'
 
334
        template = self._set_template(template,
 
335
                                      healthMonitor=health_monitor)
 
336
        expected = self._set_expected(expected,
 
337
                                      healthMonitor=health_monitor)
 
338
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
339
                                                          self.lb_name,
 
340
                                                          expected)
 
341
        self.assertEquals(rsrc.validate(),
 
342
                          {'Error': 'Unknown Property bodyRegex'})
 
343
 
 
344
        #test http fields
 
345
        health_monitor['type'] = 'HTTP'
 
346
        health_monitor['bodyRegex'] = 'bodyRegex'
 
347
        health_monitor['statusRegex'] = 'statusRegex'
 
348
        health_monitor['hostHeader'] = 'hostHeader'
 
349
        health_monitor['path'] = 'path'
 
350
 
 
351
        template = self._set_template(template,
 
352
                                      healthMonitor=health_monitor)
 
353
        expected = self._set_expected(expected,
 
354
                                      healthMonitor=health_monitor)
 
355
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
356
                                                          self.lb_name,
 
357
                                                          expected)
 
358
        self.assertEquals(rsrc.validate(), None)
 
359
 
 
360
    def test_validate_ssl_termination(self):
 
361
        ssl_termination = {
 
362
            'enabled': True,
 
363
            'privatekey': 'ewfawe',
 
364
            'certificate': 'dfaewfwef',
 
365
            'intermediateCertificate': 'fwaefawe',
 
366
            'secureTrafficOnly': True
 
367
        }
 
368
 
 
369
        #test ssl termination enabled without required fields failure
 
370
        template = self._set_template(self.lb_template,
 
371
                                      sslTermination=ssl_termination)
 
372
        expected = self._set_expected(self.expected_body,
 
373
                                      sslTermination=ssl_termination)
 
374
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
375
                                                          self.lb_name,
 
376
                                                          expected)
 
377
        self.assertEquals(rsrc.validate(),
 
378
                          {'Error':
 
379
                          'Property error : %s: Property securePort not '
 
380
                          'assigned' % rsrc.name})
 
381
 
 
382
        ssl_termination['securePort'] = 443
 
383
        template = self._set_template(template,
 
384
                                      sslTermination=ssl_termination)
 
385
        expected = self._set_expected(expected,
 
386
                                      sslTermination=ssl_termination)
 
387
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
388
                                                          self.lb_name,
 
389
                                                          expected)
 
390
        self.assertEquals(rsrc.validate(), None)
 
391
 
 
392
    def test_post_creation_access_list(self):
 
393
        access_list = [{"address": '192.168.1.1/0',
 
394
                        'type': 'ALLOW'},
 
395
                       {'address': '172.165.3.43',
 
396
                        'type': 'DENY'}]
 
397
 
 
398
        template = self._set_template(self.lb_template,
 
399
                                      accessList=access_list)
 
400
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
401
                                                          self.lb_name,
 
402
                                                          self.expected_body)
 
403
        self.m.StubOutWithMock(fake_loadbalancer, 'add_access_list')
 
404
        fake_loadbalancer.add_access_list(access_list)
 
405
 
 
406
        self.m.ReplayAll()
 
407
        scheduler.TaskRunner(rsrc.create)()
 
408
        self.m.VerifyAll()
 
409
 
 
410
    def test_post_creation_error_page(self):
 
411
        error_page = "REALLY BIG ERROR"
 
412
 
 
413
        template = self._set_template(self.lb_template,
 
414
                                      errorPage=error_page)
 
415
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
416
                                                          self.lb_name,
 
417
                                                          self.expected_body)
 
418
        self.m.StubOutWithMock(fake_loadbalancer, 'set_error_page')
 
419
        fake_loadbalancer.set_error_page(error_page)
 
420
 
 
421
        self.m.ReplayAll()
 
422
        scheduler.TaskRunner(rsrc.create)()
 
423
        self.m.VerifyAll()
 
424
 
 
425
    def test_post_creation_ssl_termination(self):
 
426
        ssl_termination = {
 
427
            'securePort': 443,
 
428
            'privatekey': 'afwefawe',
 
429
            'certificate': 'fawefwea',
 
430
            'intermediateCertificate': "intermediate_certificate",
 
431
            'enabled': True,
 
432
            'secureTrafficOnly': False
 
433
        }
 
434
 
 
435
        template = self._set_template(self.lb_template,
 
436
                                      sslTermination=ssl_termination)
 
437
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
438
                                                          self.lb_name,
 
439
                                                          self.expected_body)
 
440
        self.m.StubOutWithMock(fake_loadbalancer, 'add_ssl_termination')
 
441
        fake_loadbalancer.add_ssl_termination(
 
442
            ssl_termination['securePort'],
 
443
            ssl_termination['privatekey'],
 
444
            ssl_termination['certificate'],
 
445
            intermediateCertificate=ssl_termination['intermediateCertificate'],
 
446
            enabled=ssl_termination['enabled'],
 
447
            secureTrafficOnly=ssl_termination['secureTrafficOnly'])
 
448
 
 
449
        self.m.ReplayAll()
 
450
        scheduler.TaskRunner(rsrc.create)()
 
451
        self.m.VerifyAll()
 
452
 
 
453
    def test_post_creation_content_caching(self):
 
454
        template = self._set_template(self.lb_template,
 
455
                                      contentCaching='ENABLED')
 
456
        rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
 
457
                                                          self.lb_name,
 
458
                                                          self.expected_body)
 
459
        self.m.ReplayAll()
 
460
        scheduler.TaskRunner(rsrc.create)()
 
461
        self.m.VerifyAll()
 
462
 
 
463
    def test_update_add_node_by_ref(self):
 
464
        added_node = {'nodes': [
 
465
            {"address": "166.78.103.141", "port": 80, "condition": "ENABLED"},
 
466
            {"ref": "TEST_NODE_REF", "port": 80, "condition": "ENABLED"}]}
 
467
        expected_ip = '172.168.1.4'
 
468
        rsrc, fake_loadbalancer = self._mock_loadbalancer(self.lb_template,
 
469
                                                          self.lb_name,
 
470
                                                          self.expected_body)
 
471
        fake_loadbalancer.nodes = self.expected_body['nodes']
 
472
        self.m.ReplayAll()
 
473
        scheduler.TaskRunner(rsrc.create)()
 
474
        self.m.VerifyAll()
 
475
 
 
476
        self.m.StubOutWithMock(rsrc.clb, 'get')
 
477
        rsrc.clb.get(rsrc.resource_id).AndReturn(fake_loadbalancer)
 
478
 
 
479
        self.m.StubOutWithMock(rsrc.stack, 'resource_by_refid')
 
480
 
 
481
        class FakeFn(object):
 
482
            def FnGetAtt(self, attr):
 
483
                return expected_ip
 
484
 
 
485
        rsrc.stack.resource_by_refid('TEST_NODE_REF').AndReturn(FakeFn())
 
486
 
 
487
        self.m.StubOutWithMock(fake_loadbalancer, 'add_nodes')
 
488
        fake_loadbalancer.add_nodes([
 
489
            fake_loadbalancer.Node(address=expected_ip,
 
490
                                   port=80,
 
491
                                   condition='ENABLED')])
 
492
 
 
493
        self.m.ReplayAll()
 
494
        rsrc.handle_update({}, {}, added_node)
 
495
        self.m.VerifyAll()
 
496
 
 
497
    def test_update_add_node_by_address(self):
 
498
        expected_ip = '172.168.1.4'
 
499
        added_node = {'nodes': [
 
500
            {"address": "166.78.103.141", "port": 80, "condition": "ENABLED"},
 
501
            {"address": expected_ip, "port": 80, "condition": "ENABLED"}]}
 
502
        rsrc, fake_loadbalancer = self._mock_loadbalancer(self.lb_template,
 
503
                                                          self.lb_name,
 
504
                                                          self.expected_body)
 
505
        fake_loadbalancer.nodes = self.expected_body['nodes']
 
506
        self.m.ReplayAll()
 
507
        scheduler.TaskRunner(rsrc.create)()
 
508
        self.m.VerifyAll()
 
509
 
 
510
        self.m.StubOutWithMock(rsrc.clb, 'get')
 
511
        rsrc.clb.get(rsrc.resource_id).AndReturn(fake_loadbalancer)
 
512
 
 
513
        self.m.StubOutWithMock(fake_loadbalancer, 'add_nodes')
 
514
        fake_loadbalancer.add_nodes([
 
515
            fake_loadbalancer.Node(address=expected_ip,
 
516
                                   port=80,
 
517
                                   condition='ENABLED')])
 
518
 
 
519
        self.m.ReplayAll()
 
520
        rsrc.handle_update({}, {}, added_node)
 
521
        self.m.VerifyAll()
 
522
 
 
523
    def test_update_delete_node_failed(self):
 
524
        deleted_node = {'nodes': []}
 
525
        rsrc, fake_loadbalancer = self._mock_loadbalancer(self.lb_template,
 
526
                                                          self.lb_name,
 
527
                                                          self.expected_body)
 
528
        fake_loadbalancer.nodes = self.expected_body['nodes']
 
529
        self.m.ReplayAll()
 
530
        scheduler.TaskRunner(rsrc.create)()
 
531
        self.m.VerifyAll()
 
532
 
 
533
        self.m.StubOutWithMock(rsrc.clb, 'get')
 
534
        rsrc.clb.get(rsrc.resource_id).AndReturn(fake_loadbalancer)
 
535
 
 
536
        self.m.ReplayAll()
 
537
        self.assertRaises(ValueError, rsrc.handle_update, {}, {}, deleted_node)
 
538
        self.m.VerifyAll()