9bc91e512aea2154b6bc7778fcf44f3eec52f014
[apex.git] / apex / tests / test_apex_undercloud.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 ipaddress
11 import libvirt
12 import os
13 import subprocess
14 import unittest
15
16 from mock import patch
17 from mock import MagicMock
18
19 from apex.common import constants
20 from apex.undercloud.undercloud import Undercloud
21 from apex.undercloud.undercloud import ApexUndercloudException
22
23 from nose.tools import (
24     assert_regexp_matches,
25     assert_raises,
26     assert_true,
27     assert_false,
28     assert_equal)
29
30
31 class TestUndercloud(unittest.TestCase):
32     @classmethod
33     def setup_class(cls):
34         """This method is run once for each class before any tests are run"""
35
36     @classmethod
37     def teardown_class(cls):
38         """This method is run once for each class _after_ all tests are run"""
39
40     def setup(self):
41         """This method is run once before _each_ test method is executed"""
42
43     def teardown(self):
44         """This method is run once after _each_ test method is executed"""
45
46     @patch.object(Undercloud, '_get_vm', return_value=None)
47     @patch.object(Undercloud, 'create')
48     def test_init(self, mock_get_vm, mock_create):
49         Undercloud('img_path', 'tplt_path')
50         mock_create.assert_called()
51
52     @patch.object(Undercloud, '_get_vm', return_value=object())
53     @patch.object(Undercloud, 'create')
54     def test_init_uc_exists(self, mock_get_vm, mock_create):
55         assert_raises(ApexUndercloudException,
56                       Undercloud, 'img_path', 'tplt_path')
57
58     @patch('apex.undercloud.undercloud.libvirt.open')
59     @patch.object(Undercloud, 'create')
60     def test_get_vm_exists(self, mock_create, mock_libvirt):
61         assert_raises(ApexUndercloudException,
62                       Undercloud, 'img_path', 'tplt_path')
63
64     @patch('apex.undercloud.undercloud.libvirt.open')
65     @patch.object(Undercloud, 'create')
66     def test_get_vm_not_exists(self, mock_create, mock_libvirt):
67         conn = mock_libvirt.return_value
68         conn.lookupByName.side_effect = libvirt.libvirtError('defmsg')
69         Undercloud('img_path', 'tplt_path')
70
71     @patch('apex.undercloud.undercloud.vm_lib')
72     @patch.object(Undercloud, 'inject_auth', return_value=None)
73     @patch.object(Undercloud, 'setup_volumes', return_value=None)
74     @patch.object(Undercloud, '_get_vm', return_value=None)
75     def test_create(self, mock_get_vm, mock_setup_vols,
76                     mock_inject_auth, mock_vm_lib):
77         Undercloud('img_path', 'tplt_path', external_network=True)
78         mock_inject_auth.assert_called()
79         mock_setup_vols.assert_called()
80         mock_inject_auth.assert_called()
81
82     @patch.object(Undercloud, '_get_vm', return_value=None)
83     @patch.object(Undercloud, 'create')
84     def test_set_ip(self, mock_get_vm, mock_create):
85         uc = Undercloud('img_path', 'tplt_path', external_network=True)
86         uc.vm = MagicMock()
87         if_addrs = {'item1': {'addrs': [{'type': libvirt.VIR_IP_ADDR_TYPE_IPV4,
88                                          'addr': 'ipaddress'}]},
89                     'item2': {'addrs': [{'type': libvirt.VIR_IP_ADDR_TYPE_IPV4,
90                                          'addr': 'ipaddress'}]}}
91         uc.vm.interfaceAddresses.return_value = if_addrs
92         assert_true(uc._set_ip())
93
94     @patch('apex.undercloud.undercloud.time.sleep')
95     @patch.object(Undercloud, '_set_ip', return_value=False)
96     @patch.object(Undercloud, '_get_vm', return_value=None)
97     @patch.object(Undercloud, 'create')
98     def test_start(self, mock_create, mock_get_vm,
99                    mock_set_ip, mock_time):
100         uc = Undercloud('img_path', 'tplt_path', external_network=True)
101         uc.vm = MagicMock()
102         uc.vm.isActive.return_value = False
103         mock_set_ip.return_value = True
104         uc.start()
105
106     @patch('apex.undercloud.undercloud.time.sleep')
107     @patch.object(Undercloud, '_set_ip', return_value=False)
108     @patch.object(Undercloud, '_get_vm', return_value=None)
109     @patch.object(Undercloud, 'create')
110     def test_start_no_ip(self, mock_create, mock_get_vm,
111                          mock_set_ip, mock_time):
112         uc = Undercloud('img_path', 'tplt_path', external_network=True)
113         uc.vm = MagicMock()
114         uc.vm.isActive.return_value = True
115         mock_set_ip.return_value = False
116         assert_raises(ApexUndercloudException, uc.start)
117
118     @patch('apex.undercloud.undercloud.utils')
119     @patch.object(Undercloud, 'generate_config', return_value={})
120     @patch.object(Undercloud, '_get_vm', return_value=None)
121     @patch.object(Undercloud, 'create')
122     def test_detect_nat_with_external(self, mock_create, mock_get_vm,
123                                       mock_generate_config, mock_utils):
124         ns = MagicMock()
125         ns.enabled_network_list = ['admin', 'external']
126         ns_dict = {
127             'apex': MagicMock(),
128             'dns-domain': 'dns',
129             'networks': {'admin':
130                          {'cidr': ipaddress.ip_network('192.0.2.0/24'),
131                           'installer_vm': {'ip': '192.0.2.1',
132                                            'vlan': 'native'},
133                           'dhcp_range': ['192.0.2.15', '192.0.2.30'],
134                           'gateway': '192.1.1.1',
135                           },
136                          'external':
137                          [{'enabled': True,
138                            'cidr': ipaddress.ip_network('192.168.0.0/24'),
139                           'installer_vm': {'ip': '192.168.0.1',
140                                            'vlan': 'native'},
141                            'gateway': '192.168.0.1'
142                            }]
143                          }
144         }
145         ns.__getitem__.side_effect = ns_dict.__getitem__
146         ns.__contains__.side_effect = ns_dict.__contains__
147
148         uc = Undercloud('img_path', 'tplt_path', external_network=True)
149         assert_true(uc.detect_nat(ns))
150
151     @patch('apex.undercloud.undercloud.utils')
152     @patch.object(Undercloud, 'generate_config', return_value={})
153     @patch.object(Undercloud, '_get_vm', return_value=None)
154     @patch.object(Undercloud, 'create')
155     def test_detect_nat_no_external(self, mock_create, mock_get_vm,
156                                     mock_generate_config, mock_utils):
157         ns = MagicMock()
158         ns.enabled_network_list = ['admin', 'external']
159         ns_dict = {
160             'apex': MagicMock(),
161             'dns-domain': 'dns',
162             'networks': {'admin':
163                          {'cidr': ipaddress.ip_network('192.0.2.0/24'),
164                           'installer_vm': {'ip': '192.0.2.1',
165                                            'vlan': 'native'},
166                           'dhcp_range': ['192.0.2.15', '192.0.2.30'],
167                           'gateway': '192.0.2.1',
168                           },
169                          'external':
170                          [{'enabled': False,
171                            'cidr': ipaddress.ip_network('192.168.0.0/24'),
172                           'installer_vm': {'ip': '192.168.0.1',
173                                            'vlan': 'native'},
174                            'gateway': '192.168.1.1'
175                            }]
176                          }
177         }
178         ns.__getitem__.side_effect = ns_dict.__getitem__
179         ns.__contains__.side_effect = ns_dict.__contains__
180
181         uc = Undercloud('img_path', 'tplt_path', external_network=False)
182         assert_true(uc.detect_nat(ns))
183
184     @patch('apex.undercloud.undercloud.utils')
185     @patch.object(Undercloud, 'generate_config', return_value={})
186     @patch.object(Undercloud, '_get_vm', return_value=None)
187     @patch.object(Undercloud, 'create')
188     def test_detect_no_nat_no_external(self, mock_create, mock_get_vm,
189                                        mock_generate_config, mock_utils):
190         ns = MagicMock()
191         ns.enabled_network_list = ['admin', 'external']
192         ns_dict = {
193             'apex': MagicMock(),
194             'dns-domain': 'dns',
195             'networks': {'admin':
196                          {'cidr': ipaddress.ip_network('192.0.2.0/24'),
197                           'installer_vm': {'ip': '192.0.2.1',
198                                            'vlan': 'native'},
199                           'dhcp_range': ['192.0.2.15', '192.0.2.30'],
200                           'gateway': '192.0.2.3',
201                           },
202                          'external':
203                          [{'enabled': False,
204                            'cidr': ipaddress.ip_network('192.168.0.0/24'),
205                           'installer_vm': {'ip': '192.168.0.1',
206                                            'vlan': 'native'},
207                            'gateway': '192.168.1.1'
208                            }]
209                          }
210         }
211         ns.__getitem__.side_effect = ns_dict.__getitem__
212         ns.__contains__.side_effect = ns_dict.__contains__
213
214         uc = Undercloud('img_path', 'tplt_path', external_network=False)
215         assert_false(uc.detect_nat(ns))
216
217     @patch('apex.undercloud.undercloud.utils')
218     @patch.object(Undercloud, 'generate_config', return_value={})
219     @patch.object(Undercloud, '_get_vm', return_value=None)
220     @patch.object(Undercloud, 'create')
221     def test_configure(self, mock_create, mock_get_vm,
222                        mock_generate_config, mock_utils):
223         uc = Undercloud('img_path', 'tplt_path', external_network=True)
224         ns = MagicMock()
225         ds = MagicMock()
226         uc.configure(ns, ds, 'playbook', '/tmp/dir')
227
228     @patch('apex.undercloud.undercloud.utils')
229     @patch.object(Undercloud, 'generate_config', return_value={})
230     @patch.object(Undercloud, '_get_vm', return_value=None)
231     @patch.object(Undercloud, 'create')
232     def test_configure_raises(self, mock_create, mock_get_vm,
233                               mock_generate_config, mock_utils):
234         uc = Undercloud('img_path', 'tplt_path', external_network=True)
235         ns = MagicMock()
236         ds = MagicMock()
237         subps_err = subprocess.CalledProcessError(1, 'cmd')
238         mock_utils.run_ansible.side_effect = subps_err
239         assert_raises(ApexUndercloudException,
240                       uc.configure, ns, ds, 'playbook', '/tmp/dir')
241
242     @patch('apex.undercloud.undercloud.os.remove')
243     @patch('apex.undercloud.undercloud.os.path')
244     @patch('apex.undercloud.undercloud.shutil')
245     @patch.object(Undercloud, '_get_vm', return_value=None)
246     @patch.object(Undercloud, 'create')
247     def test_setup_vols(self, mock_get_vm, mock_create,
248                         mock_shutil, mock_os_path, mock_os_remove):
249         uc = Undercloud('img_path', 'tplt_path', external_network=True)
250         mock_os_path.isfile.return_value = True
251         mock_os_path.exists.return_value = True
252         uc.setup_volumes()
253         for img_file in ('overcloud-full.vmlinuz', 'overcloud-full.initrd',
254                          'undercloud.qcow2'):
255             src_img = os.path.join(uc.image_path, img_file)
256             dest_img = os.path.join(constants.LIBVIRT_VOLUME_PATH, img_file)
257             mock_shutil.copyfile.assert_called_with(src_img, dest_img)
258
259     @patch('apex.undercloud.undercloud.os.path')
260     @patch.object(Undercloud, '_get_vm', return_value=None)
261     @patch.object(Undercloud, 'create')
262     def test_setup_vols_raises(self, mock_get_vm, mock_create, mock_os_path):
263         uc = Undercloud('img_path', 'tplt_path', external_network=True)
264         mock_os_path.isfile.return_value = False
265         assert_raises(ApexUndercloudException, uc.setup_volumes)
266
267     @patch('apex.undercloud.undercloud.virt_utils')
268     @patch.object(Undercloud, '_get_vm', return_value=None)
269     @patch.object(Undercloud, 'create')
270     def test_inject_auth(self, mock_get_vm, mock_create, mock_vutils):
271         uc = Undercloud('img_path', 'tplt_path', external_network=True)
272         uc.root_pw = 'test'
273         uc.inject_auth()
274         test_ops = [{'--root-password': 'password:test'},
275                     {'--run-command': 'mkdir -p /root/.ssh'},
276                     {'--upload':
277                      '/root/.ssh/id_rsa.pub:/root/.ssh/authorized_keys'},
278                     {'--run-command': 'chmod 600 /root/.ssh/authorized_keys'},
279                     {'--run-command': 'restorecon /root/.ssh/authorized_keys'},
280                     {'--run-command':
281                      'cp /root/.ssh/authorized_keys /home/stack/.ssh/'},
282                     {'--run-command':
283                      'chown stack:stack /home/stack/.ssh/authorized_keys'},
284                     {'--run-command':
285                      'chmod 600 /home/stack/.ssh/authorized_keys'}]
286         mock_vutils.virt_customize.assert_called_with(test_ops, uc.volume)
287
288     @patch.object(Undercloud, '_get_vm', return_value=None)
289     @patch.object(Undercloud, 'create')
290     def test_generate_config(self, mock_get_vm, mock_create):
291         ns = MagicMock()
292         ns.enabled_network_list = ['admin', 'external']
293         ns_dict = {
294             'apex': MagicMock(),
295             'dns-domain': 'dns',
296             'networks': {'admin':
297                          {'cidr': ipaddress.ip_network('192.0.2.0/24'),
298                           'installer_vm': {'ip': '192.0.2.1',
299                                            'vlan': 'native'},
300                           'dhcp_range': ['192.0.2.15', '192.0.2.30']
301                           },
302                          'external':
303                          [{'enabled': True,
304                            'cidr': ipaddress.ip_network('192.168.0.0/24'),
305                           'installer_vm': {'ip': '192.168.0.1',
306                                            'vlan': 'native'}
307                            }]
308                          }
309         }
310         ns.__getitem__.side_effect = ns_dict.__getitem__
311         ns.__contains__.side_effect = ns_dict.__contains__
312         ds = {'global_params': {}}
313
314         Undercloud('img_path', 'tplt_path').generate_config(ns, ds)
315
316     @patch.object(Undercloud, '_get_vm', return_value=None)
317     @patch.object(Undercloud, 'create')
318     @patch('apex.undercloud.undercloud.virt_utils')
319     def test_update_delorean(self, mock_vutils, mock_uc_create, mock_get_vm):
320         uc = Undercloud('img_path', 'tmplt_path', external_network=True)
321         uc._update_delorean_repo()
322         download_cmd = (
323             "curl -L -f -o "
324             "/etc/yum.repos.d/deloran.repo "
325             "https://trunk.rdoproject.org/centos7-{}"
326             "/current-tripleo/delorean.repo".format(
327                 constants.DEFAULT_OS_VERSION))
328         test_ops = [{'--run-command': download_cmd}]
329         mock_vutils.virt_customize.assert_called_with(test_ops, uc.volume)