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 ##############################################################################
14 from mock import patch
15 from mock import MagicMock
16 from mock import mock_open
17 from io import StringIO
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
32 from nose.tools import (
33 assert_regexp_matches,
41 class TestOvercloudDeploy(unittest.TestCase):
44 """This method is run once for each class before any tests are run"""
47 def teardown_class(cls):
48 """This method is run once for each class _after_ all tests are run"""
51 """This method is run once before _each_ test method is executed"""
54 """This method is run once after _each_ test method is executed"""
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])
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), [])
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])
75 def test_build_sdn_env_list_with_default(self):
76 ds = {'sdn_controller': 'opendaylight',
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)
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()
98 inv.get_node_counts.return_value = (3, 2)
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)
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,
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']}
121 inv.get_node_counts.return_value = (3, 2)
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)
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()}
140 inv.get_node_counts.return_value = (0, 0)
142 assert_raises(ApexDeployException, create_deploy_cmd,
143 ds, ns, inv, '/tmp', virt)
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())
158 prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
159 mock_virt_utils.virt_customize.assert_called()
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,
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())
174 prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
175 mock_virt_utils.virt_customize.assert_called()
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,
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()
194 prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
195 mock_virt_utils.virt_customize.assert_called()
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())
211 prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
212 mock_virt_utils.virt_customize.assert_called()
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,
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())
227 prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
228 mock_virt_utils.virt_customize.assert_called()
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')
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)
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',
262 {'nic_mapping': {'controller':
263 {'members': ['tenant_nic']},
265 {'members': ['tenant_nic']}}},
267 [{'nic_mapping': {'controller':
268 {'members': ['ext_nic']},
270 {'members': ['ext_nic']}}}]}}
274 saved_stdout = sys.stdout
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)
286 sys.stdout = saved_stdout
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,
296 'performance': {'Compute': {},
298 ns = {'domain_name': 'test.domain',
301 {'nic_mapping': {'controller':
302 {'members': ['tenant_nic']},
304 {'members': ['tenant_nic']}}},
306 [{'nic_mapping': {'controller':
307 {'members': ['ext_nic']},
309 {'members': ['ext_nic']}}}]}}
313 saved_stdout = sys.stdout
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\'',
321 assert_in('NeutronVPPAgentPhysnets', output)
324 sys.stdout = saved_stdout
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',
336 ns = {'domain_name': 'test.domain',
339 {'nic_mapping': {'controller':
340 {'members': ['tenant_nic']},
342 {'members': ['tenant_nic']}}},
344 [{'nic_mapping': {'controller':
345 {'members': ['ext_nic']},
347 {'members': ['ext_nic']}}}]}}
349 inv.get_node_counts.return_value = (3, 2)
352 saved_stdout = sys.stdout
356 prep_env(ds, ns, inv, 'opnfv-env.yml', '/net-env.yml', '/tmp')
357 output = out.getvalue().strip()
358 assert_in('NeutronDhcpAgentsPerNetwork: 2', output)
361 sys.stdout = saved_stdout
363 def test_generate_ceph_key(self):
364 assert_equal(len(generate_ceph_key()), 40)
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,
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')
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')
388 def test_external_network_cmds(self):
391 ns_dict = {'networks':
392 {'external': [{'floating_ip_range': (0, 1),
394 {'compute': {'vlan': 'native'}},
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)
406 def test_external_network_cmds_no_ext(self):
412 {'introspection_range': (0, 1),
414 {'compute': {'vlan': '123'}},
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)
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)
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')