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