1 ##############################################################################
2 # Copyright (c) 2016 Dan Radez (dradez@redhat.com) (Red Hat)
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 ##############################################################################
13 from mock import patch
14 from mock import MagicMock
15 from mock import mock_open
16 from io import StringIO
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
30 from nose.tools import (
31 assert_regexp_matches,
39 class TestOvercloudDeploy(unittest.TestCase):
42 """This method is run once for each class before any tests are run"""
45 def teardown_class(cls):
46 """This method is run once for each class _after_ all tests are run"""
49 """This method is run once before _each_ test method is executed"""
52 """This method is run once after _each_ test method is executed"""
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])
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), [])
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])
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()
88 inv.get_node_counts.return_value = (3, 2)
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)
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,
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']}
111 inv.get_node_counts.return_value = (3, 2)
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)
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()}
130 inv.get_node_counts.return_value = (0, 0)
132 assert_raises(ApexDeployException, create_deploy_cmd,
133 ds, ns, inv, '/tmp', virt)
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()
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,
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()
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,
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()
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()
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,
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()
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')
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)
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',
247 {'nic_mapping': {'controller':
248 {'members': ['tenant_nic']},
250 {'members': ['tenant_nic']}}},
252 [{'nic_mapping': {'controller':
253 {'members': ['ext_nic']},
255 {'members': ['ext_nic']}}}]}}
259 saved_stdout = sys.stdout
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)
271 sys.stdout = saved_stdout
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,
281 'performance': {'Compute': {},
283 ns = {'domain_name': 'test.domain',
286 {'nic_mapping': {'controller':
287 {'members': ['tenant_nic']},
289 {'members': ['tenant_nic']}}},
291 [{'nic_mapping': {'controller':
292 {'members': ['ext_nic']},
294 {'members': ['ext_nic']}}}]}}
298 saved_stdout = sys.stdout
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\'',
306 assert_in('NeutronVPPAgentPhysnets', output)
309 sys.stdout = saved_stdout
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',
321 ns = {'domain_name': 'test.domain',
324 {'nic_mapping': {'controller':
325 {'members': ['tenant_nic']},
327 {'members': ['tenant_nic']}}},
329 [{'nic_mapping': {'controller':
330 {'members': ['ext_nic']},
332 {'members': ['ext_nic']}}}]}}
334 inv.get_node_counts.return_value = (3, 2)
337 saved_stdout = sys.stdout
341 prep_env(ds, ns, inv, 'opnfv-env.yml', '/net-env.yml', '/tmp')
342 output = out.getvalue().strip()
343 assert_in('NeutronDhcpAgentsPerNetwork: 2', output)
346 sys.stdout = saved_stdout
348 def test_generate_ceph_key(self):
349 assert_equal(len(generate_ceph_key()), 40)
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,
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')
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')
373 def test_external_network_cmds(self):
376 ns_dict = {'networks':
377 {'external': [{'floating_ip_range': (0, 1),
379 {'compute': {'vlan': 'native'}},
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)
391 def test_external_network_cmds_no_ext(self):
397 {'introspection_range': (0, 1),
399 {'compute': {'vlan': '123'}},
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)
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)
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')