Merge "Use context name instead of key_uuid"
[yardstick.git] / yardstick / tests / unit / benchmark / contexts / test_heat.py
1 #!/usr/bin/env python
2
3 ##############################################################################
4 # Copyright (c) 2015 Ericsson AB and others.
5 #
6 # All rights reserved. This program and the accompanying materials
7 # are made available under the terms of the Apache License, Version 2.0
8 # which accompanies this distribution, and is available at
9 # http://www.apache.org/licenses/LICENSE-2.0
10 ##############################################################################
11
12 from collections import OrderedDict
13 from itertools import count
14 import logging
15
16 import mock
17 import unittest
18
19 from yardstick.benchmark.contexts import base
20 from yardstick.benchmark.contexts import heat
21 from yardstick.benchmark.contexts import model
22 from yardstick.common import exceptions as y_exc
23 from yardstick.orchestrator import heat as orch_heat
24 from yardstick import ssh
25
26
27 LOG = logging.getLogger(__name__)
28
29
30 class HeatContextTestCase(unittest.TestCase):
31
32     def __init__(self, *args, **kwargs):
33         super(HeatContextTestCase, self).__init__(*args, **kwargs)
34         self.name_iter = ('vnf{:03}'.format(x) for x in count(0, step=3))
35
36     def setUp(self):
37         self.test_context = heat.HeatContext()
38         self.addCleanup(self._remove_contexts)
39         self.mock_context = mock.Mock(spec=heat.HeatContext())
40
41     def _remove_contexts(self):
42         if self.test_context in self.test_context.list:
43             self.test_context._delete_context()
44
45     def test___init__(self):
46         self.assertIsNone(self.test_context._name)
47         self.assertIsNone(self.test_context._task_id)
48         self.assertFalse(self.test_context._flags.no_setup)
49         self.assertFalse(self.test_context._flags.no_teardown)
50         self.assertIsNone(self.test_context.stack)
51         self.assertEqual(self.test_context.networks, OrderedDict())
52         self.assertEqual(self.test_context.servers, [])
53         self.assertEqual(self.test_context.placement_groups, [])
54         self.assertEqual(self.test_context.server_groups, [])
55         self.assertIsNone(self.test_context.keypair_name)
56         self.assertIsNone(self.test_context.secgroup_name)
57         self.assertEqual(self.test_context._server_map, {})
58         self.assertIsNone(self.test_context._image)
59         self.assertIsNone(self.test_context._flavor)
60         self.assertIsNone(self.test_context._user)
61         self.assertIsNone(self.test_context.template_file)
62         self.assertIsNone(self.test_context.heat_parameters)
63         self.assertIsNone(self.test_context.key_filename)
64
65     @mock.patch.object(ssh.SSH, 'gen_keys')
66     @mock.patch('yardstick.benchmark.contexts.heat.PlacementGroup')
67     @mock.patch('yardstick.benchmark.contexts.heat.ServerGroup')
68     @mock.patch('yardstick.benchmark.contexts.heat.Network')
69     @mock.patch('yardstick.benchmark.contexts.heat.Server')
70     def test_init(self, mock_server, mock_network, mock_sg, mock_pg, mock_ssh_gen_keys):
71
72         pgs = {'pgrp1': {'policy': 'availability'}}
73         sgs = {'servergroup1': {'policy': 'affinity'}}
74         networks = {'bar': {'cidr': '10.0.1.0/24'}}
75         servers = {'baz': {'floating_ip': True, 'placement': 'pgrp1'}}
76         attrs = {'name': 'foo',
77                  'task_id': '1234567890',
78                  'placement_groups': pgs,
79                  'server_groups': sgs,
80                  'networks': networks,
81                  'servers': servers}
82
83         self.test_context.init(attrs)
84
85         self.assertFalse(self.test_context._flags.no_setup)
86         self.assertFalse(self.test_context._flags.no_teardown)
87         self.assertEqual(self.test_context._name, "foo")
88         self.assertEqual(self.test_context._task_id, '1234567890')
89         self.assertEqual(self.test_context.name, "foo-12345678")
90         self.assertEqual(self.test_context.keypair_name, "foo-12345678-key")
91         self.assertEqual(self.test_context.secgroup_name, "foo-12345678-secgroup")
92
93         mock_pg.assert_called_with('pgrp1', self.test_context,
94                                    pgs['pgrp1']['policy'])
95         mock_sg.assert_called_with('servergroup1', self.test_context,
96                                    sgs['servergroup1']['policy'])
97         self.assertEqual(len(self.test_context.placement_groups), 1)
98         self.assertEqual(len(self.test_context.server_groups), 1)
99
100         mock_network.assert_called_with(
101             'bar', self.test_context, networks['bar'])
102         self.assertEqual(len(self.test_context.networks), 1)
103
104         mock_server.assert_called_with('baz', self.test_context,
105                                        servers['baz'])
106         self.assertEqual(len(self.test_context.servers), 1)
107
108         mock_ssh_gen_keys.assert_called()
109
110     def test_init_no_name_or_task_id(self):
111         attrs = {}
112         self.assertRaises(KeyError, self.test_context.init, attrs)
113
114     def test_name(self):
115         self.test_context._name = 'foo'
116         self.test_context._task_id = '1234567890'
117         self.test_context._name_task_id = '{}-{}'.format(
118             self.test_context._name, self.test_context._task_id[:8])
119         self.assertEqual(self.test_context.name, 'foo-12345678')
120         self.assertEqual(self.test_context.assigned_name, 'foo')
121
122     def test_name_flags(self):
123         self.test_context._flags = base.Flags(**{"no_setup": True, "no_teardown": True})
124         self.test_context._name = 'foo'
125         self.test_context._task_id = '1234567890'
126
127         self.assertEqual(self.test_context.name, 'foo')
128         self.assertEqual(self.test_context.assigned_name, 'foo')
129
130     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
131     def test__add_resources_to_template_no_servers(self, mock_template):
132         self.test_context._name = 'ctx'
133         self.test_context._task_id = '1234567890'
134         self.test_context._name_task_id = '{}-{}'.format(
135             self.test_context._name, self.test_context._task_id[:8])
136         self.test_context.keypair_name = "ctx-key"
137         self.test_context.secgroup_name = "ctx-secgroup"
138         self.test_context.key_uuid = "2f2e4997-0a8e-4eb7-9fa4-f3f8fbbc393b"
139         netattrs = {'cidr': '10.0.0.0/24', 'provider': None,
140                     'external_network': 'ext_net'}
141
142         self.test_context.networks = OrderedDict(
143             {"mynet": model.Network("mynet", self.test_context,
144                                            netattrs)})
145
146         self.test_context._add_resources_to_template(mock_template)
147         mock_template.add_keypair.assert_called_with(
148             "ctx-key",
149             "ctx-12345678")
150         mock_template.add_security_group.assert_called_with("ctx-secgroup")
151         mock_template.add_network.assert_called_with(
152             "ctx-12345678-mynet", 'physnet1', None, None, None, None)
153         mock_template.add_router.assert_called_with(
154             "ctx-12345678-mynet-router",
155             netattrs["external_network"],
156             "ctx-12345678-mynet-subnet")
157         mock_template.add_router_interface.assert_called_with(
158             "ctx-12345678-mynet-router-if0",
159             "ctx-12345678-mynet-router",
160             "ctx-12345678-mynet-subnet")
161
162     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
163     def test_attrs_get(self, *args):
164         image, flavor, user = expected_tuple = 'foo1', 'foo2', 'foo3'
165         self.assertNotEqual(self.test_context.image, image)
166         self.assertNotEqual(self.test_context.flavor, flavor)
167         self.assertNotEqual(self.test_context.user, user)
168         self.test_context._image = image
169         self.test_context._flavor = flavor
170         self.test_context._user = user
171         attr_tuple = self.test_context.image, self.test_context.flavor, self.test_context.user
172         self.assertEqual(attr_tuple, expected_tuple)
173
174     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
175     def test_attrs_set_negative(self, *args):
176         with self.assertRaises(AttributeError):
177             self.test_context.image = 'foo'
178
179         with self.assertRaises(AttributeError):
180             self.test_context.flavor = 'foo'
181
182         with self.assertRaises(AttributeError):
183             self.test_context.user = 'foo'
184
185     def test__create_new_stack(self):
186         template = mock.Mock()
187         self.test_context._create_new_stack(template)
188         template.create.assert_called_once()
189
190     def test__create_new_stack_stack_create_failed(self):
191         template = mock.Mock()
192         template.create.side_effect = y_exc.HeatTemplateError
193
194         self.assertRaises(y_exc.HeatTemplateError,
195                           self.test_context._create_new_stack,
196                           template)
197
198     def test__create_new_stack_keyboard_interrupt(self):
199         template = mock.Mock()
200         template.create.side_effect = KeyboardInterrupt
201         self.assertRaises(y_exc.StackCreationInterrupt,
202                           self.test_context._create_new_stack,
203                           template)
204
205     @mock.patch.object(orch_heat.HeatTemplate, 'add_keypair')
206     @mock.patch.object(heat.HeatContext, '_create_new_stack')
207     def test_deploy_stack_creation_failed(self, mock_create, *args):
208         self.test_context._name = 'foo'
209         self.test_context._task_id = '1234567890'
210         self.test_context._name_task_id = 'foo-12345678'
211         mock_create.side_effect = y_exc.HeatTemplateError
212         self.assertRaises(y_exc.HeatTemplateError,
213                           self.test_context.deploy)
214
215     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
216     def test_deploy(self, mock_template):
217         self.test_context._name = 'foo'
218         self.test_context._task_id = '1234567890'
219         self.test_context._name_task_id = '{}-{}'.format(
220             self.test_context._name, self.test_context._task_id[:8])
221         self.test_context.template_file = '/bar/baz/some-heat-file'
222         self.test_context.heat_parameters = {'image': 'cirros'}
223         self.test_context.get_neutron_info = mock.MagicMock()
224         self.test_context.deploy()
225
226         mock_template.assert_called_with('foo-12345678',
227                                          '/bar/baz/some-heat-file',
228                                          {'image': 'cirros'})
229         self.assertIsNotNone(self.test_context.stack)
230
231     def test_add_server_port(self):
232         network1 = mock.MagicMock()
233         network2 = mock.MagicMock()
234         self.test_context._name = 'foo'
235         self.test_context._task_id = '1234567890'
236         self.test_context._name_task_id = '{}-{}'.format(
237             self.test_context._name, self.test_context._task_id[:8])
238         self.test_context.stack = mock.MagicMock()
239         self.test_context.networks = {
240             'a': network1,
241             'c': network2,
242         }
243         self.test_context.stack.outputs = {
244             u'b': u'10.20.30.45',
245             u'b-subnet_id': 1,
246             u'foo-12345678-a-subnet-cidr': u'10.20.0.0/15',
247             u'foo-12345678-a-subnet-gateway_ip': u'10.20.30.1',
248             u'b-mac_address': u'00:01',
249             u'b-device_id': u'dev21',
250             u'b-network_id': u'net789',
251             u'd': u'40.30.20.15',
252             u'd-subnet_id': 2,
253             u'foo-12345678-c-subnet-cidr': u'40.30.0.0/18',
254             u'foo-12345678-c-subnet-gateway_ip': u'40.30.20.254',
255             u'd-mac_address': u'00:10',
256             u'd-device_id': u'dev43',
257             u'd-network_id': u'net987',
258             u'e': u'40.30.20.15',
259             u'e-subnet_id': 2,
260             u'e-mac_address': u'00:10',
261             u'e-device_id': u'dev43',
262             u'e-network_id': u'net987',
263         }
264         server = mock.MagicMock()
265         server.ports = OrderedDict([
266             ('a', [{'stack_name': 'b', 'port': 'port_a'}]),
267             ('c', [{'stack_name': 'd', 'port': 'port_c'},
268                    {'stack_name': 'e', 'port': 'port_f'}]),
269         ])
270
271         expected = {
272             "private_ip": '10.20.30.45',
273             "subnet_id": 1,
274             "subnet_cidr": '10.20.0.0/15',
275             "network": '10.20.0.0',
276             "netmask": '255.254.0.0',
277             "name": "port_a",
278             "gateway_ip": '10.20.30.1',
279             "mac_address": '00:01',
280             "device_id": 'dev21',
281             "network_id": 'net789',
282             "network_name": 'a',
283             "local_mac": '00:01',
284             "local_ip": '10.20.30.45',
285         }
286         self.test_context.add_server_port(server)
287         self.assertEqual(server.private_ip, '10.20.30.45')
288         self.assertEqual(len(server.interfaces), 3)
289         self.assertDictEqual(server.interfaces['port_a'], expected)
290
291     @mock.patch('yardstick.benchmark.contexts.heat.os')
292     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
293     def test_undeploy(self, mock_template, *args):
294         self.test_context.stack = mock_template
295         self.test_context._name = 'foo'
296         self.test_context._task_id = '1234567890'
297         self.test_context._name_task_id = '{}-{}'.format(
298             self.test_context._name, self.test_context._task_id[:8])
299         # mock_os.path.exists.return_value = True
300         self.test_context.key_filename = 'foo/bar/foobar'
301         self.test_context.undeploy()
302         self.assertTrue(mock_template.delete.called)
303
304     @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
305     @mock.patch('yardstick.benchmark.contexts.heat.os')
306     def test_undeploy_key_filename(self, mock_os, mock_template):
307         self.test_context.stack = mock_template
308         self.test_context._name = 'foo'
309         self.test_context._task_id = '1234567890'
310         self.test_context._name_task_id = '{}-{}'.format(
311             self.test_context._name, self.test_context._task_id)
312         mock_os.path.exists.return_value = True
313         self.test_context.key_filename = 'foo/bar/foobar'
314         self.assertIsNone(self.test_context.undeploy())
315
316     @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
317     def test__get_server_found_dict(self, *args):
318         """
319         Use HeatContext._get_server to get a server that matches
320         based on a dictionary input.
321         """
322         foo2_server = mock.Mock()
323         foo2_server.key_filename = None
324         foo2_server.private_ip = '10.0.0.2'
325         foo2_server.public_ip = '127.0.0.2'
326         foo2_server.context.user = 'oof'
327
328         baz3_server = mock.Mock()
329         baz3_server.key_filename = None
330         baz3_server.private_ip = '10.0.0.3'
331         baz3_server.public_ip = '127.0.0.3'
332         baz3_server.context.user = 'zab'
333
334         self.test_context._name = 'bar'
335         self.test_context._task_id = '1234567890'
336         self.test_context._name_task_id = '{}-{}'.format(
337             self.test_context._name, self.test_context._task_id[:8])
338         self.test_context._user = 'bot'
339         self.test_context.stack = mock.Mock()
340         self.test_context.stack.outputs = {
341             'private_ip': '10.0.0.1',
342             'public_ip': '127.0.0.1',
343         }
344         self.test_context._server_map = {
345             'baz3': baz3_server,
346             'foo2': foo2_server,
347         }
348
349         attr_name = {
350             'name': 'foo.bar-12345678',
351             'private_ip_attr': 'private_ip',
352             'public_ip_attr': 'public_ip',
353         }
354         self.test_context.key_uuid = 'foo-42'
355         result = self.test_context._get_server(attr_name)
356         self.assertEqual(result['user'], 'bot')
357         self.assertEqual(result['ip'], '127.0.0.1')
358         self.assertEqual(result['private_ip'], '10.0.0.1')
359
360     @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
361     def test__get_server_found_dict_no_attrs(self, *args):
362         """
363         Use HeatContext._get_server to get a server that matches
364         based on a dictionary input.
365         """
366         foo2_server = mock.Mock()
367         foo2_server.private_ip = '10.0.0.2'
368         foo2_server.public_ip = '127.0.0.2'
369         foo2_server.context.user = 'oof'
370
371         baz3_server = mock.Mock()
372         baz3_server.private_ip = '10.0.0.3'
373         baz3_server.public_ip = '127.0.0.3'
374         baz3_server.context.user = 'zab'
375
376         self.test_context._name = 'bar'
377         self.test_context._task_id = '1234567890'
378         self.test_context._name_task_id = '{}-{}'.format(
379             self.test_context._name, self.test_context._task_id[:8])
380         self.test_context._user = 'bot'
381         self.test_context.stack = mock.Mock()
382         self.test_context.stack.outputs = {
383             'private_ip': '10.0.0.1',
384             'public_ip': '127.0.0.1',
385         }
386         self.test_context._server_map = {
387             'baz3': baz3_server,
388             'foo2': foo2_server,
389         }
390
391         attr_name = {
392             'name': 'foo.bar-12345678',
393         }
394
395         self.test_context.key_uuid = 'foo-42'
396         result = self.test_context._get_server(attr_name)
397         self.assertEqual(result['user'], 'bot')
398         # no private ip attr mapping in the map results in None value in the result
399         self.assertIsNone(result['private_ip'])
400         # no public ip attr mapping in the map results in no value in the result
401         self.assertNotIn('ip', result)
402
403     @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
404     def test__get_server_found_not_dict(self, *args):
405         """
406         Use HeatContext._get_server to get a server that matches
407         based on a non-dictionary input
408         """
409         foo2_server = mock.Mock()
410         foo2_server.private_ip = '10.0.0.2'
411         foo2_server.public_ip = '127.0.0.2'
412         foo2_server.context.user = 'oof'
413
414         baz3_server = mock.Mock()
415         baz3_server.private_ip = '10.0.0.3'
416         baz3_server.public_ip = None
417         baz3_server.context.user = 'zab'
418
419         self.test_context._name = 'bar1'
420         self.test_context._task_id = '1234567890'
421         self.test_context._name_task_id = 'bar1-12345678'
422         self.test_context.stack = mock.Mock()
423         self.test_context.stack.outputs = {
424             'private_ip': '10.0.0.1',
425             'public_ip': '127.0.0.1',
426         }
427         self.test_context.generate_routing_table = mock.MagicMock(return_value=[])
428
429         self.test_context._server_map = {
430             'baz3': baz3_server,
431             'foo2': foo2_server,
432         }
433
434         attr_name = 'baz3'
435         result = self.test_context._get_server(attr_name)
436         self.assertEqual(result['user'], 'zab')
437         self.assertEqual(result['private_ip'], '10.0.0.3')
438         # no public_ip on the server results in no value in the result
439         self.assertNotIn('public_ip', result)
440
441     @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
442     def test__get_server_none_found_not_dict(self, *args):
443         """
444         Use HeatContext._get_server to not get a server due to
445         None value associated with the match to a non-dictionary
446         input
447         """
448         foo2_server = mock.Mock()
449         foo2_server.private_ip = '10.0.0.2'
450         foo2_server.public_ip = '127.0.0.2'
451         foo2_server.context.user = 'oof'
452
453         baz3_server = mock.Mock()
454         baz3_server.private_ip = '10.0.0.3'
455         baz3_server.public_ip = None
456         baz3_server.context.user = 'zab'
457
458         self.test_context._name = 'bar1'
459         self.test_context.stack = mock.Mock()
460         self.test_context.stack.outputs = {
461             'private_ip': '10.0.0.1',
462             'public_ip': '127.0.0.1',
463         }
464         self.test_context._server_map = {
465             'baz3': baz3_server,
466             'foo2': foo2_server,
467             'wow4': None,
468         }
469
470         self.test_context.key_uuid = 'foo-42'
471         attr_name = 'wow4'
472         result = self.test_context._get_server(attr_name)
473         self.assertIsNone(result)
474
475     @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
476     def test__get_server_not_found_dict(self, *args):
477         """
478         Use HeatContext._get_server to not get a server for lack
479         of a match to a dictionary input
480         """
481         foo2_server = mock.Mock()
482         foo2_server.private_ip = '10.0.0.2'
483         foo2_server.public_ip = '127.0.0.2'
484         foo2_server.context.user = 'oof'
485
486         baz3_server = mock.Mock()
487         baz3_server.private_ip = '10.0.0.3'
488         baz3_server.public_ip = None
489         baz3_server.context.user = 'zab'
490
491         self.test_context._name = 'bar1'
492         self.test_context._task_id = '1235467890'
493         self.test_context._name_task_id = '{}-{}'.format(
494             self.test_context._name, self.test_context._task_id[:8])
495         self.test_context.stack = mock.Mock()
496         self.test_context.stack.outputs = {
497             'private_ip': '10.0.0.1',
498             'public_ip': '127.0.0.1',
499         }
500         self.test_context._server_map = {
501             'baz3': baz3_server,
502             'foo2': foo2_server,
503         }
504
505         self.test_context.key_uuid = 'foo-42'
506         attr_name = {
507             'name': 'foo.wow4',
508             'private_ip_attr': 'private_ip',
509             'public_ip_attr': 'public_ip',
510         }
511         result = self.test_context._get_server(attr_name)
512         self.assertIsNone(result)
513
514     @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources")
515     def test__get_server_not_found_not_dict(self, *args):
516         """
517         Use HeatContext._get_server to not get a server for lack
518         of a match to a non-dictionary input
519         """
520         foo2_server = mock.Mock()
521         foo2_server.private_ip = '10.0.0.2'
522         foo2_server.public_ip = '127.0.0.2'
523         foo2_server.context.user = 'oof'
524
525         baz3_server = mock.Mock()
526         baz3_server.private_ip = '10.0.0.3'
527         baz3_server.public_ip = None
528         baz3_server.context.user = 'zab'
529
530         self.mock_context._name = 'bar1'
531         self.test_context.stack = mock.Mock()
532         self.mock_context.stack.outputs = {
533             'private_ip': '10.0.0.1',
534             'public_ip': '127.0.0.1',
535         }
536         self.mock_context._server_map = {
537             'baz3': baz3_server,
538             'foo2': foo2_server,
539         }
540
541         self.test_context.key_uuid = 'foo-42'
542         attr_name = 'foo.wow4'
543         result = self.test_context._get_server(attr_name)
544         self.assertIsNone(result)
545
546     # TODO: Split this into more granular tests
547     def test__get_network(self):
548         network1 = mock.MagicMock()
549         network1.name = 'net_1'
550         network1.vld_id = 'vld111'
551         network1.segmentation_id = 'seg54'
552         network1.network_type = 'type_a'
553         network1.physical_network = 'phys'
554
555         network2 = mock.MagicMock()
556         network2.name = 'net_2'
557         network2.segmentation_id = 'seg45'
558         network2.network_type = 'type_b'
559         network2.physical_network = 'virt'
560
561         self.test_context.networks = {
562             'a': network1,
563             'b': network2,
564         }
565
566         attr_name = None
567         self.assertIsNone(self.test_context._get_network(attr_name))
568
569         attr_name = {}
570         self.assertIsNone(self.test_context._get_network(attr_name))
571
572         attr_name = {'network_type': 'nosuch'}
573         self.assertIsNone(self.test_context._get_network(attr_name))
574
575         attr_name = 'vld777'
576         self.assertIsNone(self.test_context._get_network(attr_name))
577
578         attr_name = {'segmentation_id': 'seg45'}
579         expected = {
580             "name": 'net_2',
581             "segmentation_id": 'seg45',
582             "network_type": 'type_b',
583             "physical_network": 'virt',
584         }
585         result = self.test_context._get_network(attr_name)
586         self.assertDictEqual(result, expected)
587
588         attr_name = 'a'
589         expected = {
590             "name": 'net_1',
591             "segmentation_id": 'seg54',
592             "network_type": 'type_a',
593             "physical_network": 'phys',
594         }
595         result = self.test_context._get_network(attr_name)
596         self.assertDictEqual(result, expected)