Merge "Bug Fix: Start openvswitch service in Centos distro"
[yardstick.git] / yardstick / tests / unit / benchmark / contexts / standalone / test_ovs_dpdk.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 io
16 import os
17
18 import mock
19 import six
20 import unittest
21
22 from yardstick.benchmark.contexts.standalone import model
23 from yardstick.benchmark.contexts.standalone import ovs_dpdk
24 from yardstick.common import exceptions
25 from yardstick.network_services import utils
26
27
28 class OvsDpdkContextTestCase(unittest.TestCase):
29
30     NODES_SAMPLE = "nodes_sample.yaml"
31     NODES_ovs_dpdk_SAMPLE = "nodes_ovs_dpdk_sample.yaml"
32     NODES_DUPLICATE_SAMPLE = "nodes_duplicate_sample.yaml"
33
34     NETWORKS = {
35         'private_0': {
36             'phy_port': "0000:05:00.0",
37             'vpci': "0000:00:07.0",
38             'cidr': '152.16.100.10/24',
39             'interface': 'if0',
40             'mac': "00:00:00:00:00:01",
41             'vf_pci': {'vf_pci': 0},
42             'gateway_ip': '152.16.100.20'},
43         'public_0': {
44             'phy_port': "0000:05:00.1",
45             'vpci': "0000:00:08.0",
46             'cidr': '152.16.40.10/24',
47             'interface': 'if0',
48             'vf_pci': {'vf_pci': 0},
49             'mac': "00:00:00:00:00:01",
50             'gateway_ip': '152.16.100.20'},
51     }
52
53     def setUp(self):
54         self.attrs = {
55             'name': 'foo',
56             'task_id': '1234567890',
57             'file': self._get_file_abspath(self.NODES_ovs_dpdk_SAMPLE)
58         }
59         self.ovs_dpdk = ovs_dpdk.OvsDpdkContext()
60         self.addCleanup(self._remove_contexts)
61
62     def _remove_contexts(self):
63         if self.ovs_dpdk in self.ovs_dpdk.list:
64             self.ovs_dpdk._delete_context()
65
66     @mock.patch('yardstick.benchmark.contexts.standalone.model.Server')
67     @mock.patch('yardstick.benchmark.contexts.standalone.model.StandaloneContextHelper')
68     def test___init__(self, mock_helper, mock_server):
69         self.ovs_dpdk.helper = mock_helper
70         self.ovs_dpdk.vnf_node = mock_server
71         self.assertIsNone(self.ovs_dpdk.file_path)
72         self.assertTrue(self.ovs_dpdk.first_run)
73
74     def test_init(self):
75         ATTRS = {
76             'name': 'StandaloneOvsDpdk',
77             'task_id': '1234567890',
78             'file': 'pod',
79             'flavor': {},
80             'servers': {},
81             'networks': {},
82         }
83
84         self.ovs_dpdk.helper.parse_pod_file = mock.Mock(
85             return_value=[{}, {}, {}])
86         self.assertIsNone(self.ovs_dpdk.init(ATTRS))
87
88     def test_setup_ovs(self):
89         fake_path = '/fake_path'
90         fake_dpdk_nic_bind = 'dpdk_tool.py'
91         self.ovs_dpdk.ovs_properties = {'vpath': fake_path}
92         self.ovs_dpdk.dpdk_devbind = fake_dpdk_nic_bind
93         self.ovs_dpdk.networks = self.NETWORKS
94         self.ovs_dpdk.connection = mock.Mock()
95         self.ovs_dpdk.connection.execute = mock.Mock(return_value=(0, 0, 0))
96         create_from = fake_path + '/etc/openvswitch/conf.db'
97         create_to = fake_path + '/share/openvswitch/vswitch.ovsschema'
98         cmd_list = [
99             'killall -r "ovs.*" -q | true',
100             'mkdir -p {0}/etc/openvswitch'.format(fake_path),
101             'mkdir -p {0}/var/run/openvswitch'.format(fake_path),
102             'rm {0}/etc/openvswitch/conf.db | true'.format(fake_path),
103             'ovsdb-tool create {0} {1}'.format(create_from, create_to),
104             'modprobe vfio-pci',
105             'chmod a+x /dev/vfio',
106             'chmod 0666 /dev/vfio/*',
107             '{0} --force -b vfio-pci {1}'.format(fake_dpdk_nic_bind,
108                 self.ovs_dpdk.networks['private_0']['phy_port']),
109             '{0} --force -b vfio-pci {1}'.format(fake_dpdk_nic_bind,
110                 self.ovs_dpdk.networks['public_0']['phy_port'])
111         ]
112         calls = [mock.call(cmd, timeout=self.ovs_dpdk.CMD_TIMEOUT)
113                  for cmd in cmd_list]
114
115         self.ovs_dpdk.setup_ovs()
116         self.ovs_dpdk.connection.execute.assert_has_calls(calls,
117                                                           any_order=True)
118
119     def test_setup_ovs_exception(self):
120         self.ovs_dpdk.networks = self.NETWORKS
121         self.ovs_dpdk.connection = mock.Mock()
122         self.ovs_dpdk.connection.execute = mock.Mock(return_value=(1, 0, 0))
123
124         with self.assertRaises(exceptions.OVSSetupError):
125             self.ovs_dpdk.setup_ovs()
126
127     def test_start_ovs_serverswitch(self):
128         with mock.patch("yardstick.ssh.SSH") as ssh:
129             ssh_mock = mock.Mock(autospec=ssh.SSH)
130             ssh_mock.execute = \
131                 mock.Mock(return_value=(0, "a", ""))
132             ssh.return_value = ssh_mock
133             self.ovs_dpdk.connection = ssh_mock
134             self.ovs_dpdk.networks = self.NETWORKS
135             self.ovs_dpdk.ovs_properties = {}
136             self.ovs_dpdk.wait_for_vswitchd = 0
137             self.assertIsNone(self.ovs_dpdk.start_ovs_serverswitch())
138
139     def test_setup_ovs_bridge_add_flows(self):
140         with mock.patch("yardstick.ssh.SSH") as ssh:
141             ssh_mock = mock.Mock(autospec=ssh.SSH)
142             ssh_mock.execute = \
143                 mock.Mock(return_value=(0, "a", ""))
144             ssh.return_value = ssh_mock
145             self.ovs_dpdk.connection = ssh_mock
146             self.ovs_dpdk.networks = self.NETWORKS
147             self.ovs_dpdk.ovs_properties = {
148                 'version': {'ovs': '2.7.0'}
149             }
150             self.ovs_dpdk.wait_for_vswitchd = 0
151             self.assertIsNone(self.ovs_dpdk.setup_ovs_bridge_add_flows())
152
153     @mock.patch("yardstick.ssh.SSH")
154     def test_cleanup_ovs_dpdk_env(self, mock_ssh):
155        mock_ssh.execute.return_value = 0, "a", ""
156        self.ovs_dpdk.connection = mock_ssh
157        self.ovs_dpdk.networks = self.NETWORKS
158        self.ovs_dpdk.ovs_properties = {
159            'version': {'ovs': '2.7.0'}
160        }
161        self.ovs_dpdk.wait_for_vswitchd = 0
162        self.assertIsNone(self.ovs_dpdk.cleanup_ovs_dpdk_env())
163
164     @mock.patch.object(ovs_dpdk.OvsDpdkContext, '_check_hugepages')
165     @mock.patch.object(utils, 'get_nsb_option')
166     @mock.patch.object(model.OvsDeploy, 'ovs_deploy')
167     def test_check_ovs_dpdk_env(self, mock_ovs_deploy, mock_get_nsb_option,
168                                 mock_check_hugepages):
169         self.ovs_dpdk.connection = mock.Mock()
170         self.ovs_dpdk.connection.execute = mock.Mock(
171             return_value=(1, 0, 0))
172         self.ovs_dpdk.networks = self.NETWORKS
173         self.ovs_dpdk.ovs_properties = {
174             'version': {'ovs': '2.7.0', 'dpdk': '16.11.1'}
175         }
176         self.ovs_dpdk.wait_for_vswitchd = 0
177         self.ovs_dpdk.cleanup_ovs_dpdk_env = mock.Mock()
178         mock_get_nsb_option.return_value = 'fake_path'
179
180         self.ovs_dpdk.check_ovs_dpdk_env()
181         mock_ovs_deploy.assert_called_once()
182         mock_check_hugepages.assert_called_once()
183         mock_get_nsb_option.assert_called_once_with('bin_path')
184
185     @mock.patch.object(ovs_dpdk.OvsDpdkContext, '_check_hugepages')
186     def test_check_ovs_dpdk_env_wrong_version(self, mock_check_hugepages):
187         self.ovs_dpdk.connection = mock.Mock()
188         self.ovs_dpdk.connection.execute = mock.Mock(
189             return_value=(1, 0, 0))
190         self.ovs_dpdk.networks = self.NETWORKS
191         self.ovs_dpdk.ovs_properties = {
192             'version': {'ovs': '0.0.1', 'dpdk': '9.8.7'}
193         }
194         self.ovs_dpdk.wait_for_vswitchd = 0
195         self.ovs_dpdk.cleanup_ovs_dpdk_env = mock.Mock()
196
197         with self.assertRaises(exceptions.OVSUnsupportedVersion):
198             self.ovs_dpdk.check_ovs_dpdk_env()
199         mock_check_hugepages.assert_called_once()
200
201     @mock.patch('yardstick.ssh.SSH')
202     def test_deploy(self, *args):
203         self.ovs_dpdk.vm_deploy = False
204         self.assertIsNone(self.ovs_dpdk.deploy())
205
206         self.ovs_dpdk.vm_deploy = True
207         self.ovs_dpdk.host_mgmt = {}
208         self.ovs_dpdk.install_req_libs = mock.Mock()
209         self.ovs_dpdk.helper.get_nic_details = mock.Mock(return_value={})
210         self.ovs_dpdk.check_ovs_dpdk_env = mock.Mock(return_value={})
211         self.ovs_dpdk.setup_ovs = mock.Mock(return_value={})
212         self.ovs_dpdk.start_ovs_serverswitch = mock.Mock(return_value={})
213         self.ovs_dpdk.setup_ovs_bridge_add_flows = mock.Mock(return_value={})
214         self.ovs_dpdk.setup_ovs_dpdk_context = mock.Mock(return_value={})
215         self.ovs_dpdk.wait_for_vnfs_to_start = mock.Mock(return_value={})
216         # TODO(elfoley): This test should check states/sideeffects instead of
217         # output.
218         self.assertIsNone(self.ovs_dpdk.deploy())
219
220     @mock.patch.object(model.Libvirt, 'check_if_vm_exists_and_delete')
221     def test_undeploy(self, mock_libvirt):
222         self.ovs_dpdk.vm_deploy = True
223         self.ovs_dpdk.connection = mock.Mock()
224         self.ovs_dpdk.vm_names = ['vm_0', 'vm_1']
225         self.ovs_dpdk.drivers = ['vm_0', 'vm_1']
226         self.ovs_dpdk.cleanup_ovs_dpdk_env = mock.Mock()
227         self.ovs_dpdk.networks = self.NETWORKS
228         self.ovs_dpdk.undeploy()
229         mock_libvirt.assert_has_calls([
230             mock.call(self.ovs_dpdk.vm_names[0], self.ovs_dpdk.connection),
231             mock.call(self.ovs_dpdk.vm_names[1], self.ovs_dpdk.connection)
232         ])
233
234     def _get_file_abspath(self, filename):
235         curr_path = os.path.dirname(os.path.abspath(__file__))
236         file_path = os.path.join(curr_path, filename)
237         return file_path
238
239     def test__get_server_with_dic_attr_name(self):
240
241         self.ovs_dpdk.init(self.attrs)
242
243         attr_name = {'name': 'foo.bar'}
244         result = self.ovs_dpdk._get_server(attr_name)
245
246         self.assertEqual(result, None)
247
248     def test__get_server_not_found(self):
249
250         self.ovs_dpdk.helper.parse_pod_file = mock.Mock(
251             return_value=[{}, {}, {}])
252         self.ovs_dpdk.init(self.attrs)
253
254         attr_name = 'bar.foo'
255         result = self.ovs_dpdk._get_server(attr_name)
256
257         self.assertEqual(result, None)
258
259     def test__get_server_mismatch(self):
260
261         self.ovs_dpdk.init(self.attrs)
262
263         attr_name = 'bar.foo1'
264         result = self.ovs_dpdk._get_server(attr_name)
265
266         self.assertEqual(result, None)
267
268     def test__get_server_duplicate(self):
269
270         self.attrs['file'] = self._get_file_abspath(self.NODES_DUPLICATE_SAMPLE)
271
272         self.ovs_dpdk.init(self.attrs)
273
274         attr_name = 'node1.foo-12345678'
275         with self.assertRaises(ValueError):
276             self.ovs_dpdk._get_server(attr_name)
277
278     def test__get_server_found(self):
279
280         self.ovs_dpdk.init(self.attrs)
281
282         attr_name = 'node1.foo-12345678'
283         result = self.ovs_dpdk._get_server(attr_name)
284
285         self.assertEqual(result['ip'], '10.229.47.137')
286         self.assertEqual(result['name'], 'node1.foo-12345678')
287         self.assertEqual(result['user'], 'root')
288         self.assertEqual(result['key_filename'], '/root/.yardstick_key')
289
290     # TODO(elfoley): Split this test for networks that exist and networks that
291     #                don't
292     def test__get_network(self):
293         network1 = {
294             'name': 'net_1',
295             'vld_id': 'vld111',
296             'segmentation_id': 'seg54',
297             'network_type': 'type_a',
298             'physical_network': 'phys',
299         }
300         network2 = {
301             'name': 'net_2',
302             'vld_id': 'vld999',
303         }
304         self.ovs_dpdk.networks = {
305             'a': network1,
306             'b': network2,
307         }
308
309         # Tests for networks that do not exist
310         attr_name = {}
311         self.assertIsNone(self.ovs_dpdk._get_network(attr_name))
312
313         attr_name = {'vld_id': 'vld777'}
314         self.assertIsNone(self.ovs_dpdk._get_network(attr_name))
315
316         self.assertIsNone(self.ovs_dpdk._get_network(None))
317
318         # TODO(elfoley): Split this test
319         attr_name = 'vld777'
320         self.assertIsNone(self.ovs_dpdk._get_network(attr_name))
321
322         # Tests for networks that exist
323         attr_name = {'vld_id': 'vld999'}
324         expected = {
325             "name": 'net_2',
326             "vld_id": 'vld999',
327             "segmentation_id": None,
328             "network_type": None,
329             "physical_network": None,
330         }
331         result = self.ovs_dpdk._get_network(attr_name)
332         self.assertDictEqual(result, expected)
333
334         attr_name = 'a'
335         expected = network1
336         result = self.ovs_dpdk._get_network(attr_name)
337         self.assertDictEqual(result, expected)
338
339     def test_configure_nics_for_ovs_dpdk(self):
340         with mock.patch("yardstick.ssh.SSH") as ssh:
341             ssh_mock = mock.Mock(autospec=ssh.SSH)
342             ssh_mock.execute = \
343                 mock.Mock(return_value=(0, "a", ""))
344             ssh.return_value = ssh_mock
345         self.ovs_dpdk.vm_deploy = True
346         self.ovs_dpdk.connection = ssh_mock
347         self.ovs_dpdk.vm_names = ['vm_0', 'vm_1']
348         self.ovs_dpdk.drivers = []
349         self.ovs_dpdk.networks = self.NETWORKS
350         self.ovs_dpdk.helper.get_mac_address = mock.Mock(return_value="")
351         self.ovs_dpdk.get_vf_datas = mock.Mock(return_value="")
352         self.assertIsNone(self.ovs_dpdk.configure_nics_for_ovs_dpdk())
353
354     @mock.patch.object(model.Libvirt, 'add_ovs_interface')
355     def test__enable_interfaces(self, mock_add_ovs_interface):
356         self.ovs_dpdk.vm_deploy = True
357         self.ovs_dpdk.connection = mock.Mock()
358         self.ovs_dpdk.vm_names = ['vm_0', 'vm_1']
359         self.ovs_dpdk.drivers = []
360         self.ovs_dpdk.networks = self.NETWORKS
361         self.ovs_dpdk.ovs_properties = {'vpath': 'fake_path'}
362         self.ovs_dpdk.get_vf_datas = mock.Mock(return_value="")
363         self.ovs_dpdk._enable_interfaces(0, ["private_0"], 'test')
364         mock_add_ovs_interface.assert_called_once_with(
365             'fake_path', 0, self.NETWORKS['private_0']['vpci'],
366             self.NETWORKS['private_0']['mac'], 'test')
367
368     @mock.patch.object(model.Libvirt, 'write_file')
369     @mock.patch.object(model.Libvirt, 'build_vm_xml')
370     @mock.patch.object(model.Libvirt, 'check_if_vm_exists_and_delete')
371     @mock.patch.object(model.Libvirt, 'virsh_create_vm')
372     def test_setup_ovs_dpdk_context(self, mock_create_vm, mock_check_if_exists,
373                                     mock_build_xml, mock_write_file):
374         self.ovs_dpdk.vm_deploy = True
375         self.ovs_dpdk.connection = mock.Mock()
376         self.ovs_dpdk.vm_names = ['vm_0', 'vm_1']
377         self.ovs_dpdk.drivers = []
378         self.ovs_dpdk.servers = {
379             'vnf_0': {
380                 'network_ports': {
381                     'mgmt': {'cidr': '152.16.100.10/24'},
382                     'xe0': ['private_0'],
383                     'xe1': ['public_0']
384                 }
385             }
386         }
387         self.ovs_dpdk.networks = self.NETWORKS
388         self.ovs_dpdk.host_mgmt = {}
389         self.ovs_dpdk.flavor = {}
390         self.ovs_dpdk.configure_nics_for_ovs_dpdk = mock.Mock(return_value="")
391         xml_str = mock.Mock()
392         mock_build_xml.return_value = (xml_str, '00:00:00:00:00:01')
393         self.ovs_dpdk._enable_interfaces = mock.Mock(return_value=xml_str)
394         vnf_instance = mock.Mock()
395         self.ovs_dpdk.vnf_node.generate_vnf_instance = mock.Mock(
396             return_value=vnf_instance)
397
398         self.assertEqual([vnf_instance],
399                          self.ovs_dpdk.setup_ovs_dpdk_context())
400         mock_create_vm.assert_called_once_with(
401             self.ovs_dpdk.connection, '/tmp/vm_ovs_0.xml')
402         mock_check_if_exists.assert_called_once_with(
403             'vm_0', self.ovs_dpdk.connection)
404         mock_build_xml.assert_called_once_with(
405             self.ovs_dpdk.connection, self.ovs_dpdk.vm_flavor, 'vm_0', 0)
406         mock_write_file.assert_called_once_with('/tmp/vm_ovs_0.xml', xml_str)
407
408     @mock.patch.object(io, 'BytesIO')
409     def test__check_hugepages(self, mock_bytesio):
410         data = six.BytesIO('HugePages_Total:      20\n'
411                            'HugePages_Free:       20\n'
412                            'HugePages_Rsvd:        0\n'
413                            'HugePages_Surp:        0\n'
414                            'Hugepagesize:    1048576 kB'.encode())
415         mock_bytesio.return_value = data
416         self.ovs_dpdk.connection = mock.Mock()
417         self.ovs_dpdk._check_hugepages()
418
419     @mock.patch.object(io, 'BytesIO')
420     def test__check_hugepages_no_info(self, mock_bytesio):
421         data = six.BytesIO(''.encode())
422         mock_bytesio.return_value = data
423         self.ovs_dpdk.connection = mock.Mock()
424         with self.assertRaises(exceptions.OVSHugepagesInfoError):
425             self.ovs_dpdk._check_hugepages()
426
427     @mock.patch.object(io, 'BytesIO')
428     def test__check_hugepages_no_total_hp(self, mock_bytesio):
429         data = six.BytesIO('HugePages_Total:       0\n'
430                            'HugePages_Free:        0\n'
431                            'HugePages_Rsvd:        0\n'
432                            'HugePages_Surp:        0\n'
433                            'Hugepagesize:    1048576 kB'.encode())
434         mock_bytesio.return_value = data
435         self.ovs_dpdk.connection = mock.Mock()
436         with self.assertRaises(exceptions.OVSHugepagesNotConfigured):
437             self.ovs_dpdk._check_hugepages()
438
439     @mock.patch.object(io, 'BytesIO')
440     def test__check_hugepages_no_free_hp(self, mock_bytesio):
441         data = six.BytesIO('HugePages_Total:      20\n'
442                            'HugePages_Free:        0\n'
443                            'HugePages_Rsvd:        0\n'
444                            'HugePages_Surp:        0\n'
445                            'Hugepagesize:    1048576 kB'.encode())
446         mock_bytesio.return_value = data
447         self.ovs_dpdk.connection = mock.Mock()
448         with self.assertRaises(exceptions.OVSHugepagesZeroFree) as exc:
449             self.ovs_dpdk._check_hugepages()
450         self.assertEqual('There are no HugePages free in this system. Total '
451                          'HugePages configured: 20', exc.exception.msg)