Improve "Libvirt.virsh_create_vm" function
[yardstick.git] / yardstick / tests / unit / benchmark / contexts / standalone / test_model.py
1 # Copyright (c) 2016-2017 Intel Corporation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import copy
16 import os
17 import mock
18 import unittest
19 import uuid
20
21 from xml.etree import ElementTree
22
23 from yardstick import ssh
24 from yardstick.benchmark.contexts.standalone import model
25 from yardstick.common import exceptions
26 from yardstick import constants
27 from yardstick.network_services import utils
28
29
30 XML_SAMPLE = """<?xml version="1.0"?>
31 <domain type="kvm">
32     <devices>
33     </devices>
34 </domain>
35 """
36
37 XML_SAMPLE_INTERFACE = """<?xml version="1.0"?>
38 <domain type="kvm">
39     <devices>
40         <interface>
41         </interface>
42     </devices>
43 </domain>
44 """
45
46
47 class ModelLibvirtTestCase(unittest.TestCase):
48
49     def setUp(self):
50         self.pci_address_str = '0001:04:03.2'
51         self.pci_address = utils.PciAddress(self.pci_address_str)
52         self.mac = '00:00:00:00:00:01'
53         self._mock_ssh = mock.Mock()
54         self.mock_ssh = self._mock_ssh.start()
55         self.addCleanup(self._cleanup)
56
57     def _cleanup(self):
58         self._mock_ssh.stop()
59
60     # TODO: Remove mocking of yardstick.ssh.SSH (here and elsewhere)
61     # In this case, we are mocking a param to be passed into other methods
62     # It can be a generic Mock() with return values set for the right methods
63     def test_check_if_vm_exists_and_delete(self):
64         with mock.patch("yardstick.ssh.SSH") as ssh:
65             ssh_mock = mock.Mock(autospec=ssh.SSH)
66             ssh_mock.execute = mock.Mock(return_value=(0, "a", ""))
67             ssh.return_value = ssh_mock
68         # NOTE(ralonsoh): this test doesn't cover function execution.
69         model.Libvirt.check_if_vm_exists_and_delete("vm_0", ssh_mock)
70
71     def test_virsh_create_vm(self):
72         self.mock_ssh.execute = mock.Mock(return_value=(0, 0, 0))
73         model.Libvirt.virsh_create_vm(self.mock_ssh, 'vm_0')
74         self.mock_ssh.execute.assert_called_once_with('virsh create vm_0')
75
76     def test_virsh_create_vm_error(self):
77         self.mock_ssh.execute = mock.Mock(return_value=(1, 0, 'error_create'))
78         with self.assertRaises(exceptions.LibvirtCreateError) as exc:
79             model.Libvirt.virsh_create_vm(self.mock_ssh, 'vm_0')
80         self.assertEqual('Error creating the virtual machine. Error: '
81                          'error_create.', str(exc.exception))
82         self.mock_ssh.execute.assert_called_once_with('virsh create vm_0')
83
84     def test_virsh_destroy_vm(self):
85         with mock.patch("yardstick.ssh.SSH") as ssh:
86             ssh_mock = mock.Mock(autospec=ssh.SSH)
87             ssh_mock.execute = mock.Mock(return_value=(0, "a", ""))
88             ssh.return_value = ssh_mock
89         # NOTE(ralonsoh): this test doesn't cover function execution.
90         model.Libvirt.virsh_destroy_vm("vm_0", ssh_mock)
91
92     def test_add_interface_address(self):
93         xml = ElementTree.ElementTree(
94             element=ElementTree.fromstring(XML_SAMPLE_INTERFACE))
95         interface = xml.find('devices').find('interface')
96         result = model.Libvirt._add_interface_address(interface, self.pci_address)
97         self.assertEqual('pci', result.get('type'))
98         self.assertEqual('0x{}'.format(self.pci_address.domain),
99                          result.get('domain'))
100         self.assertEqual('0x{}'.format(self.pci_address.bus),
101                          result.get('bus'))
102         self.assertEqual('0x{}'.format(self.pci_address.slot),
103                          result.get('slot'))
104         self.assertEqual('0x{}'.format(self.pci_address.function),
105                          result.get('function'))
106
107     def test_add_ovs_interfaces(self):
108         xml_input = copy.deepcopy(XML_SAMPLE)
109         xml_output = model.Libvirt.add_ovs_interface(
110             '/usr/local', 0, self.pci_address_str, self.mac, xml_input)
111
112         root = ElementTree.fromstring(xml_output)
113         et_out = ElementTree.ElementTree(element=root)
114         interface = et_out.find('devices').find('interface')
115         self.assertEqual('vhostuser', interface.get('type'))
116         mac = interface.find('mac')
117         self.assertEqual(self.mac, mac.get('address'))
118         source = interface.find('source')
119         self.assertEqual('unix', source.get('type'))
120         self.assertEqual('/usr/local/var/run/openvswitch/dpdkvhostuser0',
121                          source.get('path'))
122         self.assertEqual('client', source.get('mode'))
123         _model = interface.find('model')
124         self.assertEqual('virtio', _model.get('type'))
125         driver = interface.find('driver')
126         self.assertEqual('4', driver.get('queues'))
127         host = driver.find('host')
128         self.assertEqual('off', host.get('mrg_rxbuf'))
129         self.assertIsNotNone(interface.find('address'))
130
131     def test_add_sriov_interfaces(self):
132         xml_input = copy.deepcopy(XML_SAMPLE)
133         vm_pci = '0001:05:04.2'
134         xml_output = model.Libvirt.add_sriov_interfaces(
135             vm_pci, self.pci_address_str, self.mac, xml_input)
136         root = ElementTree.fromstring(xml_output)
137         et_out = ElementTree.ElementTree(element=root)
138         interface = et_out.find('devices').find('interface')
139         self.assertEqual('yes', interface.get('managed'))
140         self.assertEqual('hostdev', interface.get('type'))
141         mac = interface.find('mac')
142         self.assertEqual(self.mac, mac.get('address'))
143         source = interface.find('source')
144         source_address = source.find('address')
145         self.assertIsNotNone(source.find('address'))
146
147         self.assertEqual('pci', source_address.get('type'))
148         self.assertEqual('0x' + self.pci_address_str.split(':')[0],
149                          source_address.get('domain'))
150         self.assertEqual('0x' + self.pci_address_str.split(':')[1],
151                          source_address.get('bus'))
152         self.assertEqual('0x' + self.pci_address_str.split(':')[2].split('.')[0],
153                          source_address.get('slot'))
154         self.assertEqual('0x' + self.pci_address_str.split(':')[2].split('.')[1],
155                          source_address.get('function'))
156
157         interface_address = interface.find('address')
158         self.assertEqual('pci', interface_address.get('type'))
159         self.assertEqual('0x' + vm_pci.split(':')[0],
160                          interface_address.get('domain'))
161         self.assertEqual('0x' + vm_pci.split(':')[1],
162                          interface_address.get('bus'))
163         self.assertEqual('0x' + vm_pci.split(':')[2].split('.')[0],
164                          interface_address.get('slot'))
165         self.assertEqual('0x' + vm_pci.split(':')[2].split('.')[1],
166                          interface_address.get('function'))
167
168     def test_create_snapshot_qemu(self):
169         result = "/var/lib/libvirt/images/0.qcow2"
170         with mock.patch("yardstick.ssh.SSH") as ssh:
171             ssh_mock = mock.Mock(autospec=ssh.SSH)
172             ssh_mock.execute = \
173                 mock.Mock(return_value=(0, "a", ""))
174             ssh.return_value = ssh_mock
175         image = model.Libvirt.create_snapshot_qemu(ssh_mock, "0", "ubuntu.img")
176         self.assertEqual(image, result)
177
178     @mock.patch.object(model.Libvirt, 'pin_vcpu_for_perf', return_value='4,5')
179     @mock.patch.object(model.Libvirt, 'create_snapshot_qemu',
180                        return_value='qemu_image')
181     def test_build_vm_xml(self, mock_create_snapshot_qemu,
182                           mock_pin_vcpu_for_perf):
183         extra_specs = {'hw:cpu_cores': '4',
184                        'hw:cpu_sockets': '3',
185                        'hw:cpu_threads': '2',
186                        'cputune': 'cool'}
187         flavor = {'ram': '1024',
188                   'extra_specs': extra_specs,
189                   'hw_socket': '1',
190                   'images': 'images'}
191         mac = model.StandaloneContextHelper.get_mac_address(0x00)
192         _uuid = uuid.uuid4()
193         connection = mock.Mock()
194         with mock.patch.object(model.StandaloneContextHelper,
195                                'get_mac_address', return_value=mac) as \
196                 mock_get_mac_address, \
197                 mock.patch.object(uuid, 'uuid4', return_value=_uuid):
198             xml_out, mac = model.Libvirt.build_vm_xml(
199                 connection, flavor, 'vm_name', 100)
200
201         xml_ref = model.VM_TEMPLATE.format(vm_name='vm_name',
202             random_uuid=_uuid, mac_addr=mac, memory='1024', vcpu='8', cpu='4',
203             numa_cpus='0-7', socket='3', threads='2',
204             vm_image='qemu_image', cpuset='4,5', cputune='cool')
205         self.assertEqual(xml_ref, xml_out)
206         mock_get_mac_address.assert_called_once_with(0x00)
207         mock_create_snapshot_qemu.assert_called_once_with(
208             connection, 100, 'images')
209         mock_pin_vcpu_for_perf.assert_called_once_with(connection, '1')
210
211     # TODO: Edit this test to test state instead of output
212     # update_interrupts_hugepages_perf does not return anything
213     def test_update_interrupts_hugepages_perf(self):
214         with mock.patch("yardstick.ssh.SSH") as ssh:
215             ssh_mock = mock.Mock(autospec=ssh.SSH)
216             ssh_mock.execute = \
217                 mock.Mock(return_value=(0, "a", ""))
218             ssh.return_value = ssh_mock
219         # NOTE(ralonsoh): 'update_interrupts_hugepages_perf' always return
220         # None, this check is trivial.
221         #status = Libvirt.update_interrupts_hugepages_perf(ssh_mock)
222         #self.assertIsNone(status)
223         model.Libvirt.update_interrupts_hugepages_perf(ssh_mock)
224
225     @mock.patch.object(model, 'CpuSysCores')
226     @mock.patch.object(model.Libvirt, 'update_interrupts_hugepages_perf')
227     def test_pin_vcpu_for_perf(self, *args):
228         # NOTE(ralonsoh): test mocked methods/variables.
229         with mock.patch("yardstick.ssh.SSH") as ssh:
230             ssh_mock = mock.Mock(autospec=ssh.SSH)
231             ssh_mock.execute = \
232                 mock.Mock(return_value=(0, "a", ""))
233             ssh.return_value = ssh_mock
234         status = model.Libvirt.pin_vcpu_for_perf(ssh_mock, 4)
235         self.assertIsNotNone(status)
236
237 class StandaloneContextHelperTestCase(unittest.TestCase):
238
239     NODE_SAMPLE = "nodes_sample.yaml"
240     NODE_SRIOV_SAMPLE = "nodes_sriov_sample.yaml"
241
242     NETWORKS = {
243         'mgmt': {'cidr': '152.16.100.10/24'},
244         'private_0': {
245             'phy_port': "0000:05:00.0",
246             'vpci': "0000:00:07.0",
247             'cidr': '152.16.100.10/24',
248             'gateway_ip': '152.16.100.20'},
249         'public_0': {
250             'phy_port': "0000:05:00.1",
251             'vpci': "0000:00:08.0",
252             'cidr': '152.16.40.10/24',
253             'gateway_ip': '152.16.100.20'}
254     }
255
256     def setUp(self):
257         self.helper = model.StandaloneContextHelper()
258
259     def test___init__(self):
260         self.assertIsNone(self.helper.file_path)
261
262     def test_install_req_libs(self):
263         with mock.patch("yardstick.ssh.SSH") as ssh:
264             ssh_mock = mock.Mock(autospec=ssh.SSH)
265             ssh_mock.execute = \
266                 mock.Mock(return_value=(1, "a", ""))
267             ssh.return_value = ssh_mock
268         # NOTE(ralonsoh): this test doesn't cover function execution. This test
269         # should also check mocked function calls.
270         model.StandaloneContextHelper.install_req_libs(ssh_mock)
271
272     def test_get_kernel_module(self):
273         with mock.patch("yardstick.ssh.SSH") as ssh:
274             ssh_mock = mock.Mock(autospec=ssh.SSH)
275             ssh_mock.execute = \
276                 mock.Mock(return_value=(1, "i40e", ""))
277             ssh.return_value = ssh_mock
278         # NOTE(ralonsoh): this test doesn't cover function execution. This test
279         # should also check mocked function calls.
280         model.StandaloneContextHelper.get_kernel_module(
281             ssh_mock, "05:00.0", None)
282
283     @mock.patch.object(model.StandaloneContextHelper, 'get_kernel_module')
284     def test_get_nic_details(self, mock_get_kernel_module):
285         with mock.patch("yardstick.ssh.SSH") as ssh:
286             ssh_mock = mock.Mock(autospec=ssh.SSH)
287             ssh_mock.execute = mock.Mock(return_value=(1, "i40e ixgbe", ""))
288             ssh.return_value = ssh_mock
289         mock_get_kernel_module.return_value = "i40e"
290         # NOTE(ralonsoh): this test doesn't cover function execution. This test
291         # should also check mocked function calls.
292         model.StandaloneContextHelper.get_nic_details(
293             ssh_mock, self.NETWORKS, 'dpdk-devbind.py')
294
295     def test_get_virtual_devices(self):
296         pattern = "PCI_SLOT_NAME=0000:05:00.0"
297         with mock.patch("yardstick.ssh.SSH") as ssh:
298             ssh_mock = mock.Mock(autospec=ssh.SSH)
299             ssh_mock.execute = \
300                 mock.Mock(return_value=(1, pattern, ""))
301             ssh.return_value = ssh_mock
302         # NOTE(ralonsoh): this test doesn't cover function execution. This test
303         # should also check mocked function calls.
304         model.StandaloneContextHelper.get_virtual_devices(
305             ssh_mock, '0000:00:05.0')
306
307     def _get_file_abspath(self, filename):
308         curr_path = os.path.dirname(os.path.abspath(__file__))
309         file_path = os.path.join(curr_path, filename)
310         return file_path
311
312     def test_read_config_file(self):
313         self.helper.file_path = self._get_file_abspath(self.NODE_SAMPLE)
314         status = self.helper.read_config_file()
315         self.assertIsNotNone(status)
316
317     def test_parse_pod_file(self):
318         self.helper.file_path = self._get_file_abspath("dummy")
319         self.assertRaises(IOError, self.helper.parse_pod_file,
320                           self.helper.file_path)
321
322         self.helper.file_path = self._get_file_abspath(self.NODE_SAMPLE)
323         self.assertRaises(TypeError, self.helper.parse_pod_file,
324                           self.helper.file_path)
325
326         self.helper.file_path = self._get_file_abspath(self.NODE_SRIOV_SAMPLE)
327         self.assertIsNotNone(self.helper.parse_pod_file(self.helper.file_path))
328
329     def test_get_mac_address(self):
330         status = model.StandaloneContextHelper.get_mac_address()
331         self.assertIsNotNone(status)
332
333     @mock.patch('yardstick.ssh.SSH')
334     def test_get_mgmt_ip(self, *args):
335         # NOTE(ralonsoh): test mocked methods/variables.
336         with mock.patch("yardstick.ssh.SSH") as ssh:
337             ssh_mock = mock.Mock(autospec=ssh.SSH)
338             ssh_mock.execute = mock.Mock(
339                 return_value=(1, "1.2.3.4 00:00:00:00:00:01", ""))
340             ssh.return_value = ssh_mock
341         # NOTE(ralonsoh): this test doesn't cover function execution. This test
342         # should also check mocked function calls.
343         status = model.StandaloneContextHelper.get_mgmt_ip(
344             ssh_mock, "00:00:00:00:00:01", "1.1.1.1/24", {})
345         self.assertIsNotNone(status)
346
347     @mock.patch('yardstick.ssh.SSH')
348     def test_get_mgmt_ip_no(self, *args):
349         # NOTE(ralonsoh): test mocked methods/variables.
350         with mock.patch("yardstick.ssh.SSH") as ssh:
351             ssh_mock = mock.Mock(autospec=ssh.SSH)
352             ssh_mock.execute = \
353                 mock.Mock(return_value=(1, "", ""))
354             ssh.return_value = ssh_mock
355         # NOTE(ralonsoh): this test doesn't cover function execution. This test
356         # should also check mocked function calls.
357         model.WAIT_FOR_BOOT = 0
358         status = model.StandaloneContextHelper.get_mgmt_ip(
359             ssh_mock, "99", "1.1.1.1/24", {})
360         self.assertIsNone(status)
361
362
363 class ServerTestCase(unittest.TestCase):
364
365     NETWORKS = {
366         'mgmt': {'cidr': '152.16.100.10/24'},
367         'private_0': {
368             'phy_port': "0000:05:00.0",
369             'vpci': "0000:00:07.0",
370             'driver': 'i40e',
371             'mac': '',
372             'cidr': '152.16.100.10/24',
373             'gateway_ip': '152.16.100.20'},
374         'public_0': {
375             'phy_port': "0000:05:00.1",
376             'vpci': "0000:00:08.0",
377             'driver': 'i40e',
378             'mac': '',
379             'cidr': '152.16.40.10/24',
380             'gateway_ip': '152.16.100.20'}
381     }
382
383     def setUp(self):
384         self.server = model.Server()
385
386     def test___init__(self):
387         self.assertIsNotNone(self.server)
388
389     def test_build_vnf_interfaces(self):
390         vnf = {
391             "network_ports": {
392                 'mgmt': {'cidr': '152.16.100.10/24'},
393                 'xe0': ['private_0'],
394                 'xe1': ['public_0'],
395             }
396         }
397         status = model.Server.build_vnf_interfaces(vnf, self.NETWORKS)
398         self.assertIsNotNone(status)
399
400     def test_generate_vnf_instance(self):
401         vnf = {
402             "network_ports": {
403                 'mgmt': {'cidr': '152.16.100.10/24'},
404                 'xe0': ['private_0'],
405                 'xe1': ['public_0'],
406             }
407         }
408         status = self.server.generate_vnf_instance(
409             {}, self.NETWORKS, '1.1.1.1/24', 'vm_0', vnf, '00:00:00:00:00:01')
410         self.assertIsNotNone(status)
411
412
413 class OvsDeployTestCase(unittest.TestCase):
414
415     OVS_DETAILS = {'version': {'ovs': 'ovs_version', 'dpdk': 'dpdk_version'}}
416
417     def setUp(self):
418         self._mock_ssh = mock.patch.object(ssh, 'SSH')
419         self.mock_ssh = self._mock_ssh .start()
420         self.ovs_deploy = model.OvsDeploy(self.mock_ssh,
421                                           '/tmp/dpdk-devbind.py',
422                                           self.OVS_DETAILS)
423         self._mock_path_isfile = mock.patch.object(os.path, 'isfile')
424         self._mock_path_join = mock.patch.object(os.path, 'join')
425         self.mock_path_isfile = self._mock_path_isfile.start()
426         self.mock_path_join = self._mock_path_join.start()
427
428         self.addCleanup(self._stop_mock)
429
430     def _stop_mock(self):
431         self._mock_ssh.stop()
432         self._mock_path_isfile.stop()
433         self._mock_path_join.stop()
434
435     @mock.patch.object(model.StandaloneContextHelper, 'install_req_libs')
436     def test_prerequisite(self, mock_install_req_libs):
437         pkgs = ["git", "build-essential", "pkg-config", "automake",
438                 "autotools-dev", "libltdl-dev", "cmake", "libnuma-dev",
439                 "libpcap-dev"]
440         self.ovs_deploy.prerequisite()
441         mock_install_req_libs.assert_called_once_with(
442             self.ovs_deploy.connection, pkgs)
443
444     def test_ovs_deploy_no_file(self):
445         self.mock_path_isfile.return_value = False
446         mock_file = mock.Mock()
447         self.mock_path_join.return_value = mock_file
448
449         self.ovs_deploy.ovs_deploy()
450         self.mock_path_isfile.assert_called_once_with(mock_file)
451         self.mock_path_join.assert_called_once_with(
452             constants.YARDSTICK_ROOT_PATH,
453             'yardstick/resources/scripts/install/',
454             self.ovs_deploy.OVS_DEPLOY_SCRIPT)
455
456     @mock.patch.object(os.environ, 'get', return_value='test_proxy')
457     def test_ovs_deploy(self, mock_env_get):
458         self.mock_path_isfile.return_value = True
459         mock_deploy_file = mock.Mock()
460         mock_remove_ovs_deploy = mock.Mock()
461         self.mock_path_join.side_effect = [mock_deploy_file,
462                                            mock_remove_ovs_deploy]
463         dpdk_version = self.OVS_DETAILS['version']['dpdk']
464         ovs_version = self.OVS_DETAILS['version']['ovs']
465
466         with mock.patch.object(self.ovs_deploy.connection, 'put') as \
467                 mock_put, \
468                 mock.patch.object(self.ovs_deploy.connection, 'execute') as \
469                 mock_execute, \
470                 mock.patch.object(self.ovs_deploy, 'prerequisite'):
471             mock_execute.return_value = (0, 0, 0)
472             self.ovs_deploy.ovs_deploy()
473
474             self.mock_path_isfile.assert_called_once_with(mock_deploy_file)
475             self.mock_path_join.assert_has_calls([
476                 mock.call(constants.YARDSTICK_ROOT_PATH,
477                           'yardstick/resources/scripts/install/',
478                           self.ovs_deploy.OVS_DEPLOY_SCRIPT),
479                 mock.call(self.ovs_deploy.bin_path,
480                           self.ovs_deploy.OVS_DEPLOY_SCRIPT)
481             ])
482             mock_put.assert_called_once_with(mock_deploy_file,
483                                              mock_remove_ovs_deploy)
484             cmd = ("sudo -E %(remote_ovs_deploy)s --ovs='%(ovs_version)s' "
485                    "--dpdk='%(dpdk_version)s' -p='%(proxy)s'" %
486                    {'remote_ovs_deploy': mock_remove_ovs_deploy,
487                     'ovs_version': ovs_version,
488                     'dpdk_version': dpdk_version,
489                     'proxy': 'test_proxy'})
490             mock_execute.assert_called_once_with(cmd)
491             mock_env_get.assert_called_once_with('http_proxy', '')