Merge "barometer: fix barometer apex build"
[apex.git] / apex / tests / test_apex_overcloud_deploy.py
1 ##############################################################################
2 # Copyright (c) 2016 Dan Radez (dradez@redhat.com) (Red Hat)
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 import os
11 import sys
12 import unittest
13
14 from mock import patch
15 from mock import MagicMock
16 from mock import mock_open
17 from io import StringIO
18
19 from apex.common import constants as con
20 from apex.common.exceptions import ApexDeployException
21 from apex.overcloud.deploy import build_sdn_env_list
22 from apex.overcloud.deploy import create_deploy_cmd
23 from apex.overcloud.deploy import prep_image
24 from apex.overcloud.deploy import make_ssh_key
25 from apex.overcloud.deploy import prep_env
26 from apex.overcloud.deploy import generate_ceph_key
27 from apex.overcloud.deploy import prep_storage_env
28 from apex.overcloud.deploy import external_network_cmds
29 from apex.overcloud.deploy import create_congress_cmds
30 from apex.overcloud.deploy import SDN_FILE_MAP
31
32 from nose.tools import (
33     assert_regexp_matches,
34     assert_raises,
35     assert_in,
36     assert_not_in,
37     assert_greater,
38     assert_equal)
39
40
41 class TestOvercloudDeploy(unittest.TestCase):
42     @classmethod
43     def setup_class(cls):
44         """This method is run once for each class before any tests are run"""
45
46     @classmethod
47     def teardown_class(cls):
48         """This method is run once for each class _after_ all tests are run"""
49
50     def setup(self):
51         """This method is run once before _each_ test method is executed"""
52
53     def teardown(self):
54         """This method is run once after _each_ test method is executed"""
55
56     def test_build_sdn_env_list(self):
57         ds = {'sdn_controller': 'opendaylight'}
58         sdn_map = {'opendaylight': 'test'}
59         res = '/usr/share/openstack-tripleo-heat-templates/environments/test'
60         assert_equal(build_sdn_env_list(ds, sdn_map), [res])
61
62     def test_build_sdn_env_list_dict(self):
63         ds = {'opendaylight': True,
64               'sdn_controller': None}
65         sdn_map = {'opendaylight': {}}
66         assert_equal(build_sdn_env_list(ds, sdn_map), [])
67
68     def test_build_sdn_env_list_tuple(self):
69         ds = {'opendaylight': 'test',
70               'sdn_controller': None}
71         sdn_map = {'opendaylight': ('test', 'test')}
72         res = '/usr/share/openstack-tripleo-heat-templates/environments/test'
73         assert_equal(build_sdn_env_list(ds, sdn_map), [res])
74
75     def test_build_sdn_env_list_with_default(self):
76         ds = {'sdn_controller': 'opendaylight',
77               'vpn': True}
78         prefix = '/usr/share/openstack-tripleo-heat-templates/environments'
79         res = [os.path.join(prefix, 'neutron-opendaylight.yaml'),
80                os.path.join(prefix, 'neutron-bgpvpn-opendaylight.yaml')]
81         assert_equal(build_sdn_env_list(ds, SDN_FILE_MAP), res)
82
83     @patch('apex.overcloud.deploy.prep_storage_env')
84     @patch('apex.overcloud.deploy.build_sdn_env_list')
85     @patch('builtins.open', mock_open())
86     def test_create_deploy_cmd(self, mock_sdn_list, mock_prep_storage):
87         mock_sdn_list.return_value = []
88         ds = {'deploy_options': MagicMock(),
89               'global_params': MagicMock()}
90         ds['global_params'].__getitem__.side_effect = \
91             lambda i: True if i == 'ha_enabled' else MagicMock()
92         ds['deploy_options'].__getitem__.side_effect = \
93             lambda i: True if i == 'congress' else MagicMock()
94         ds['deploy_options'].__contains__.side_effect = \
95             lambda i: True if i == 'congress' else MagicMock()
96         ns = {'ntp': ['ntp']}
97         inv = MagicMock()
98         inv.get_node_counts.return_value = (3, 2)
99         virt = True
100         result_cmd = create_deploy_cmd(ds, ns, inv, '/tmp', virt)
101         assert_in('--ntp-server ntp', result_cmd)
102         assert_in('enable_tacker.yaml', result_cmd)
103         assert_in('enable_congress.yaml', result_cmd)
104         assert_in('enable_barometer.yaml', result_cmd)
105         assert_in('virtual-environment.yaml', result_cmd)
106         assert_in('--control-scale 3', result_cmd)
107         assert_in('--compute-scale 2', result_cmd)
108
109     @patch('apex.overcloud.deploy.prep_storage_env')
110     @patch('apex.overcloud.deploy.build_sdn_env_list')
111     @patch('builtins.open', mock_open())
112     def test_create_deploy_cmd_no_ha_bm(self, mock_sdn_list,
113                                         mock_prep_storage):
114         mock_sdn_list.return_value = []
115         ds = {'deploy_options': MagicMock(),
116               'global_params': MagicMock()}
117         ds['global_params'].__getitem__.side_effect = \
118             lambda i: False if i == 'ha_enabled' else MagicMock()
119         ns = {'ntp': ['ntp']}
120         inv = MagicMock()
121         inv.get_node_counts.return_value = (3, 2)
122         virt = False
123         result_cmd = create_deploy_cmd(ds, ns, inv, '/tmp', virt)
124         assert_in('--ntp-server ntp', result_cmd)
125         assert_in('--control-scale 1', result_cmd)
126         assert_in('--compute-scale 2', result_cmd)
127         assert_in('baremetal-environment.yaml', result_cmd)
128         assert_not_in('enable_tacker.yaml', result_cmd)
129         assert_not_in('enable_congress.yaml', result_cmd)
130         assert_not_in('enable_barometer.yaml', result_cmd)
131
132     @patch('apex.overcloud.deploy.prep_storage_env')
133     @patch('apex.overcloud.deploy.build_sdn_env_list')
134     def test_create_deploy_cmd_raises(self, mock_sdn_list, mock_prep_storage):
135         mock_sdn_list.return_value = []
136         ds = {'deploy_options': MagicMock(),
137               'global_params': MagicMock()}
138         ns = {}
139         inv = MagicMock()
140         inv.get_node_counts.return_value = (0, 0)
141         virt = False
142         assert_raises(ApexDeployException, create_deploy_cmd,
143                       ds, ns, inv, '/tmp', virt)
144
145     @patch('apex.overcloud.deploy.virt_utils')
146     @patch('apex.overcloud.deploy.shutil')
147     @patch('apex.overcloud.deploy.os.path')
148     @patch('builtins.open', mock_open())
149     def test_prep_image(self, mock_os_path, mock_shutil, mock_virt_utils):
150         ds_opts = {'dataplane': 'fdio',
151                    'sdn_controller': 'opendaylight',
152                    'odl_version': 'master'}
153         ds = {'deploy_options': MagicMock(),
154               'global_params': MagicMock()}
155         ds['deploy_options'].__getitem__.side_effect = \
156             lambda i: ds_opts.get(i, MagicMock())
157         ns = MagicMock()
158         prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
159         mock_virt_utils.virt_customize.assert_called()
160
161     @patch('apex.overcloud.deploy.virt_utils')
162     @patch('apex.overcloud.deploy.shutil')
163     @patch('apex.overcloud.deploy.os.path')
164     @patch('builtins.open', mock_open())
165     def test_prep_image_sdn_false(self, mock_os_path, mock_shutil,
166                                   mock_virt_utils):
167         ds_opts = {'dataplane': 'fdio',
168                    'sdn_controller': False}
169         ds = {'deploy_options': MagicMock(),
170               'global_params': MagicMock()}
171         ds['deploy_options'].__getitem__.side_effect = \
172             lambda i: ds_opts.get(i, MagicMock())
173         ns = MagicMock()
174         prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
175         mock_virt_utils.virt_customize.assert_called()
176
177     @patch('apex.overcloud.deploy.virt_utils')
178     @patch('apex.overcloud.deploy.shutil')
179     @patch('apex.overcloud.deploy.os.path')
180     @patch('builtins.open', mock_open())
181     def test_prep_image_sdn_odl(self, mock_os_path, mock_shutil,
182                                 mock_virt_utils):
183         ds_opts = {'dataplane': 'ovs',
184                    'sdn_controller': 'opendaylight',
185                    'odl_version': con.DEFAULT_ODL_VERSION,
186                    'odl_vpp_netvirt': True}
187         ds = {'deploy_options': MagicMock(),
188               'global_params': MagicMock()}
189         ds['deploy_options'].__getitem__.side_effect = \
190             lambda i: ds_opts.get(i, MagicMock())
191         ds['deploy_options'].__contains__.side_effect = \
192             lambda i: True if i in ds_opts else MagicMock()
193         ns = MagicMock()
194         prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
195         mock_virt_utils.virt_customize.assert_called()
196
197     @patch('apex.overcloud.deploy.virt_utils')
198     @patch('apex.overcloud.deploy.shutil')
199     @patch('apex.overcloud.deploy.os.path')
200     @patch('builtins.open', mock_open())
201     def test_prep_image_sdn_odl_not_def(self, mock_os_path,
202                                         mock_shutil, mock_virt_utils):
203         ds_opts = {'dataplane': 'ovs',
204                    'sdn_controller': 'opendaylight',
205                    'odl_version': 'uncommon'}
206         ds = {'deploy_options': MagicMock(),
207               'global_params': MagicMock()}
208         ds['deploy_options'].__getitem__.side_effect = \
209             lambda i: ds_opts.get(i, MagicMock())
210         ns = MagicMock()
211         prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
212         mock_virt_utils.virt_customize.assert_called()
213
214     @patch('apex.overcloud.deploy.virt_utils')
215     @patch('apex.overcloud.deploy.shutil')
216     @patch('apex.overcloud.deploy.os.path')
217     @patch('builtins.open', mock_open())
218     def test_prep_image_sdn_ovn(self, mock_os_path, mock_shutil,
219                                 mock_virt_utils):
220         ds_opts = {'dataplane': 'ovs',
221                    'sdn_controller': 'ovn'}
222         ds = {'deploy_options': MagicMock(),
223               'global_params': MagicMock()}
224         ds['deploy_options'].__getitem__.side_effect = \
225             lambda i: ds_opts.get(i, MagicMock())
226         ns = MagicMock()
227         prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
228         mock_virt_utils.virt_customize.assert_called()
229
230     @patch('apex.overcloud.deploy.os.path.isfile')
231     def test_prep_image_no_image(self, mock_isfile):
232         mock_isfile.return_value = False
233         assert_raises(ApexDeployException, prep_image,
234                       {}, {}, 'undercloud.qcow2', '/tmp')
235
236     def test_make_ssh_key(self):
237         priv, pub = make_ssh_key()
238         assert_in('-----BEGIN PRIVATE KEY-----', priv)
239         assert_in('ssh-rsa', pub)
240
241     @patch('apex.overcloud.deploy.fileinput')
242     @patch('apex.overcloud.deploy.shutil')
243     def test_prep_env(self, mock_shutil, mock_fileinput):
244         mock_fileinput.input.return_value = \
245             ['CloudDomain', 'replace_private_key', 'replace_public_key',
246              'opendaylight::vpp_routing_node', 'ControllerExtraConfig',
247              'NovaComputeExtraConfig', 'ComputeKernelArgs', 'HostCpusList',
248              'ComputeExtraConfigPre', 'resource_registry',
249              'NovaSchedulerDefaultFilters']
250         ds = {'deploy_options':
251               {'sdn_controller': 'opendaylight',
252                'odl_vpp_routing_node': 'test',
253                'dataplane': 'ovs_dpdk',
254                'performance': {'Compute': {'vpp': {'main-core': 'test',
255                                                    'corelist-workers': 'test'},
256                                            'ovs': {'dpdk_cores': 'test'},
257                                            'kernel': {'test': 'test'}},
258                                'Controller': {'vpp': 'test'}}}}
259         ns = {'domain_name': 'test.domain',
260               'networks':
261               {'tenant':
262                {'nic_mapping': {'controller':
263                                 {'members': ['tenant_nic']},
264                                 'compute':
265                                 {'members': ['tenant_nic']}}},
266                'external':
267                [{'nic_mapping': {'controller':
268                                  {'members': ['ext_nic']},
269                                  'compute':
270                                  {'members': ['ext_nic']}}}]}}
271         inv = None
272         try:
273             # Swap stdout
274             saved_stdout = sys.stdout
275             out = StringIO()
276             sys.stdout = out
277             # run test
278             prep_env(ds, ns, inv, 'opnfv-env.yml', '/net-env.yml', '/tmp')
279             output = out.getvalue().strip()
280             assert_in('CloudDomain: test.domain', output)
281             assert_in('ssh-rsa', output)
282             assert_in('ComputeKernelArgs: \'test=test \'', output)
283             assert_in('fdio::vpp_cpu_main_core: \'test\'', output)
284         finally:
285             # put stdout back
286             sys.stdout = saved_stdout
287
288     @patch('apex.overcloud.deploy.fileinput')
289     @patch('apex.overcloud.deploy.shutil')
290     def test_prep_env_round_two(self, mock_shutil, mock_fileinput):
291         mock_fileinput.input.return_value = \
292             ['NeutronVPPAgentPhysnets']
293         ds = {'deploy_options':
294               {'sdn_controller': False,
295                'dataplane': 'fdio',
296                'performance': {'Compute': {},
297                                'Controller': {}}}}
298         ns = {'domain_name': 'test.domain',
299               'networks':
300               {'tenant':
301                {'nic_mapping': {'controller':
302                                 {'members': ['tenant_nic']},
303                                 'compute':
304                                 {'members': ['tenant_nic']}}},
305                'external':
306                [{'nic_mapping': {'controller':
307                                  {'members': ['ext_nic']},
308                                  'compute':
309                                  {'members': ['ext_nic']}}}]}}
310         inv = None
311         try:
312             # Swap stdout
313             saved_stdout = sys.stdout
314             out = StringIO()
315             sys.stdout = out
316             # run test
317             prep_env(ds, ns, inv, 'opnfv-env.yml', '/net-env.yml', '/tmp')
318             output = out.getvalue().strip()
319             assert_in('NeutronVPPAgentPhysnets: \'datacentre:tenant_nic\'',
320                       output)
321             assert_in('NeutronVPPAgentPhysnets', output)
322         finally:
323             # put stdout back
324             sys.stdout = saved_stdout
325
326     @patch('apex.overcloud.deploy.fileinput')
327     @patch('apex.overcloud.deploy.shutil')
328     def test_prep_env_round_three(self, mock_shutil, mock_fileinput):
329         mock_fileinput.input.return_value = \
330             ['OS::TripleO::Services::NeutronDhcpAgent',
331              'NeutronDhcpAgentsPerNetwork', 'ComputeServices']
332         ds = {'deploy_options':
333               {'sdn_controller': 'opendaylight',
334                'dataplane': 'fdio',
335                'dvr': True}}
336         ns = {'domain_name': 'test.domain',
337               'networks':
338               {'tenant':
339                {'nic_mapping': {'controller':
340                                 {'members': ['tenant_nic']},
341                                 'compute':
342                                 {'members': ['tenant_nic']}}},
343                'external':
344                [{'nic_mapping': {'controller':
345                                  {'members': ['ext_nic']},
346                                  'compute':
347                                  {'members': ['ext_nic']}}}]}}
348         inv = MagicMock()
349         inv.get_node_counts.return_value = (3, 2)
350         try:
351             # Swap stdout
352             saved_stdout = sys.stdout
353             out = StringIO()
354             sys.stdout = out
355             # run test
356             prep_env(ds, ns, inv, 'opnfv-env.yml', '/net-env.yml', '/tmp')
357             output = out.getvalue().strip()
358             assert_in('NeutronDhcpAgentsPerNetwork: 2', output)
359         finally:
360             # put stdout back
361             sys.stdout = saved_stdout
362
363     def test_generate_ceph_key(self):
364         assert_equal(len(generate_ceph_key()), 40)
365
366     @patch('apex.overcloud.deploy.generate_ceph_key')
367     @patch('apex.overcloud.deploy.fileinput')
368     @patch('apex.overcloud.deploy.os.path.isfile')
369     @patch('builtins.open', mock_open())
370     def test_prep_storage_env(self, mock_isfile, mock_fileinput,
371                               mock_ceph_key):
372         mock_fileinput.input.return_value = \
373             ['CephClusterFSID', 'CephMonKey', 'CephAdminKey', 'random_key']
374         ds = {'deploy_options': MagicMock()}
375         ds['deploy_options'].__getitem__.side_effect = \
376             lambda i: '/dev/sdx' if i == 'ceph_device' else MagicMock()
377         ds['deploy_options'].__contains__.side_effect = \
378             lambda i: True if i == 'ceph_device' else MagicMock()
379         prep_storage_env(ds, '/tmp')
380
381     @patch('apex.overcloud.deploy.os.path.isfile')
382     @patch('builtins.open', mock_open())
383     def test_prep_storage_env_raises(self, mock_isfile):
384         mock_isfile.return_value = False
385         ds = {'deploy_options': MagicMock()}
386         assert_raises(ApexDeployException, prep_storage_env, ds, '/tmp')
387
388     def test_external_network_cmds(self):
389         cidr = MagicMock()
390         cidr.version = 6
391         ns_dict = {'networks':
392                    {'external': [{'floating_ip_range': (0, 1),
393                                   'nic_mapping':
394                                   {'compute': {'vlan': 'native'}},
395                                   'gateway': 'gw',
396                                   'cidr': cidr}]}}
397         ns = MagicMock()
398         ns.enabled_network_list = ['external']
399         ns.__getitem__.side_effect = lambda i: ns_dict.get(i, MagicMock())
400         cmds = ' '.join(external_network_cmds(ns))
401         assert_in('--external', cmds)
402         assert_in('--allocation-pool start=0,end=1', cmds)
403         assert_in('--gateway gw', cmds)
404         assert_in('--network external', cmds)
405
406     def test_external_network_cmds_no_ext(self):
407         cidr = MagicMock()
408         cidr.version = 6
409         ns_dict = {'apex':
410                    {'networks':
411                     {'admin':
412                      {'introspection_range': (0, 1),
413                       'nic_mapping':
414                       {'compute': {'vlan': '123'}},
415                       'gateway': 'gw',
416                       'cidr': cidr}}}}
417         ns = MagicMock()
418         ns.enabled_network_list = ['admin']
419         ns.__getitem__.side_effect = lambda i: ns_dict.get(i, MagicMock())
420         external_network_cmds(ns)
421         cmds = ' '.join(external_network_cmds(ns))
422         assert_in('--external', cmds)
423         assert_in('--allocation-pool start=0,end=1', cmds)
424         assert_in('--network external', cmds)
425         assert_in('--provider-network-type vlan', cmds)
426
427     @patch('apex.overcloud.deploy.parsers')
428     def test_create_congress_cmds(self, mock_parsers):
429         assert_greater(len(create_congress_cmds('overcloud_file')), 0)
430
431     @patch('apex.overcloud.deploy.parsers.parse_overcloudrc')
432     def test_create_congress_cmds_raises(self, mock_parsers):
433         mock_parsers.return_value.__getitem__.side_effect = KeyError()
434         assert_raises(KeyError, create_congress_cmds, 'overcloud_file')