4834ba68283c456219d1f0a827f0d9d85cc62444
[csit.git] / resources / libraries / python / DUTSetup.py
1 # Copyright (c) 2016 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """DUT setup library."""
15
16 from robot.api import logger
17
18 from resources.libraries.python.topology import NodeType
19 from resources.libraries.python.topology import Topology
20 from resources.libraries.python.ssh import SSH
21 from resources.libraries.python.constants import Constants
22 from resources.libraries.python.VatExecutor import VatExecutor
23
24
25 class DUTSetup(object):
26     """Contains methods for setting up DUTs."""
27     @staticmethod
28     def start_vpp_service_on_all_duts(nodes):
29         """Start up the VPP service on all nodes."""
30         ssh = SSH()
31         for node in nodes.values():
32             if node['type'] == NodeType.DUT:
33                 ssh.connect(node)
34                 (ret_code, stdout, stderr) = \
35                     ssh.exec_command_sudo('service vpp restart', timeout=120)
36                 if int(ret_code) != 0:
37                     logger.debug('stdout: {0}'.format(stdout))
38                     logger.debug('stderr: {0}'.format(stderr))
39                     raise Exception('DUT {0} failed to start VPP service'.
40                                     format(node['host']))
41
42     @staticmethod
43     def vpp_show_version_verbose(node):
44         """Run "show version verbose" CLI command.
45
46         :param node: Node to run command on.
47         :type node: dict
48         """
49         vat = VatExecutor()
50         vat.execute_script("show_version_verbose.vat", node, json_out=False)
51
52     @staticmethod
53     def vpp_api_trace_save(node):
54         """Run "api trace save" CLI command.
55
56         :param node: Node to run command on.
57         :type node: dict
58         """
59         vat = VatExecutor()
60         vat.execute_script("api_trace_save.vat", node, json_out=False)
61
62     @staticmethod
63     def vpp_api_trace_dump(node):
64         """Run "api trace custom-dump" CLI command.
65
66         :param node: Node to run command on.
67         :type node: dict
68         """
69         vat = VatExecutor()
70         vat.execute_script("api_trace_dump.vat", node, json_out=False)
71
72     @staticmethod
73     def setup_all_duts(nodes):
74         """Prepare all DUTs in given topology for test execution."""
75         for node in nodes.values():
76             if node['type'] == NodeType.DUT:
77                 DUTSetup.setup_dut(node)
78
79     @staticmethod
80     def setup_dut(node):
81         """Run script over SSH to setup the DUT node.
82
83         :param node: DUT node to set up.
84         :type node: dict
85
86         :raises Exception: If the DUT setup fails.
87         """
88         ssh = SSH()
89         ssh.connect(node)
90
91         (ret_code, stdout, stderr) = \
92             ssh.exec_command('sudo -Sn bash {0}/{1}/dut_setup.sh'.
93                              format(Constants.REMOTE_FW_DIR,
94                                     Constants.RESOURCES_LIB_SH), timeout=120)
95         logger.trace(stdout)
96         logger.trace(stderr)
97         if int(ret_code) != 0:
98             logger.debug('DUT {0} setup script failed: "{1}"'.
99                          format(node['host'], stdout + stderr))
100             raise Exception('DUT test setup script failed at node {}'.
101                             format(node['host']))
102
103     @staticmethod
104     def get_vpp_pid(node):
105         """Get PID of running VPP process.
106
107         :param node: DUT node.
108         :type node: dict
109         :return: PID
110         :rtype: int
111         :raises RuntimeError if it is not possible to get the PID.
112         """
113
114         ssh = SSH()
115         ssh.connect(node)
116         ret_code, stdout, stderr = ssh.exec_command('pidof vpp')
117
118         logger.trace(stdout)
119         logger.trace(stderr)
120
121         if int(ret_code) != 0:
122             logger.debug('Not possible to get PID of VPP process on node: '
123                          '{0}\n {1}'.format(node['host'], stdout + stderr))
124             raise RuntimeError('Not possible to get PID of VPP process on node:'
125                                ' {}'.format(node['host']))
126
127         if len(stdout.splitlines()) == 1:
128             return int(stdout)
129         elif len(stdout.splitlines()) == 0:
130             logger.debug("No VPP PID found on node {0}".
131                          format(node['host']))
132             return None
133         else:
134             logger.debug("More then one VPP PID found on node {0}".
135                          format(node['host']))
136             ret_list = ()
137             for line in stdout.splitlines():
138                 ret_list.append(int(line))
139             return ret_list
140
141     @staticmethod
142     def get_vpp_pids(nodes):
143         """Get PID of running VPP process on all DUTs.
144
145         :param nodes: DUT nodes.
146         :type nodes: dict
147         :return: PIDs
148         :rtype: dict
149         """
150
151         pids = dict()
152         for node in nodes.values():
153             if node['type'] == NodeType.DUT:
154                 pids[node['host']] = DUTSetup.get_vpp_pid(node)
155         return pids
156
157     @staticmethod
158     def vpp_show_crypto_device_mapping(node):
159         """Run "show crypto device mapping" CLI command.
160
161         :param node: Node to run command on.
162         :type node: dict
163         """
164         vat = VatExecutor()
165         vat.execute_script("show_crypto_device_mapping.vat", node,
166                            json_out=False)
167
168     @staticmethod
169     def crypto_device_verify(node, force_init=False, numvfs=32):
170         """Verify if Crypto QAT device virtual functions are initialized on all
171         DUTs. If parameter force initialization is set to True, then try to
172         initialize or disable QAT.
173
174         :param node: DUT node.
175         :param force_init: If True then try to initialize to specific value.
176         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
177         :type node: dict
178         :type force_init: bool
179         :type numvfs: int
180         :returns: nothing
181         :raises RuntimeError: If QAT is not initialized or failed to initialize.
182         """
183
184         ssh = SSH()
185         ssh.connect(node)
186
187         cryptodev = Topology.get_cryptodev(node)
188         cmd = 'cat /sys/bus/pci/devices/{}/sriov_numvfs'.format(
189             cryptodev.replace(':', r'\:'))
190
191         # Try to read number of VFs from PCI address of QAT device
192         for _ in range(3):
193             ret_code, stdout, _ = ssh.exec_command(cmd)
194             if int(ret_code) == 0:
195                 try:
196                     sriov_numvfs = int(stdout)
197                 except ValueError:
198                     logger.trace('Reading sriov_numvfs info failed on: {}'\
199                         .format(node['host']))
200                 else:
201                     if sriov_numvfs != numvfs:
202                         if force_init:
203                             # QAT is not initialized and we want to initialize
204                             # with numvfs
205                             DUTSetup.crypto_device_init(node, numvfs)
206                         else:
207                             raise RuntimeError('QAT device {} is not '\
208                                 'initialized to {} on host: {}'.format(\
209                                 cryptodev, numvfs, node['host']))
210                     break
211
212     @staticmethod
213     def crypto_device_init(node, numvfs):
214         """Init Crypto QAT device virtual functions on DUT.
215
216         :param node: DUT node.
217         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
218         :type node: dict
219         :type numvfs: int
220         :returns: nothing
221         :raises RuntimeError: If QAT failed to initialize.
222         """
223
224         ssh = SSH()
225         ssh.connect(node)
226
227         cryptodev = Topology.get_cryptodev(node)
228
229         # QAT device must be bind to kernel driver before initialization
230         DUTSetup.pci_driver_unbind(node, cryptodev)
231         DUTSetup.pci_driver_bind(node, cryptodev, "dh895xcc")
232
233         # Initialize QAT VFs
234         ret_code, _, _ = ssh.exec_command(
235             "sudo sh -c 'echo {} | tee /sys/bus/pci/devices/{}/sriov_numvfs'"
236             .format(numvfs, cryptodev.replace(':', r'\:')))
237
238         if int(ret_code) != 0:
239             raise RuntimeError('Failed to initialize {} VFs on QAT device on '
240                                'host: {}'.format(numvfs, node['host']))
241
242     @staticmethod
243     def pci_driver_unbind(node, pci_addr):
244         """Unbind PCI device from current driver on node.
245
246         :param node: DUT node.
247         :param pci_addr: PCI device address.
248         :type node: dict
249         :type pci_addr: str
250         :returns: nothing
251         :raises RuntimeError: If PCI device unbind failed.
252         """
253
254         ssh = SSH()
255         ssh.connect(node)
256
257         ret_code, _, _ = ssh.exec_command(
258             "sudo sh -c 'echo {} | tee /sys/bus/pci/devices/{}/driver/unbind'"
259             .format(pci_addr, pci_addr.replace(':', r'\:')))
260
261         if int(ret_code) != 0:
262             raise RuntimeError('Failed to unbind PCI device from driver on '
263                                'host: {}'.format(node['host']))
264
265     @staticmethod
266     def pci_driver_bind(node, pci_addr, driver):
267         """Bind PCI device to driver on node.
268
269         :param node: DUT node.
270         :param pci_addr: PCI device address.
271         :param driver: Driver to bind.
272         :type node: dict
273         :type pci_addr: str
274         :type driver: str
275         :returns: nothing
276         :raises RuntimeError: If PCI device bind failed.
277         """
278
279         ssh = SSH()
280         ssh.connect(node)
281
282         ret_code, _, _ = ssh.exec_command(
283             "sudo sh -c 'echo {} | tee /sys/bus/pci/drivers/{}/bind'"
284             .format(pci_addr, driver))
285
286         if int(ret_code) != 0:
287             raise RuntimeError('Failed to bind PCI device to {} driver on '
288                                'host: {}'.format(driver, node['host']))
289
290     @staticmethod
291     def kernel_module_verify(node, module, force_load=False):
292         """Verify if kernel module is loaded on all DUTs. If parameter force
293         load is set to True, then try to load the modules.
294
295         :param node: DUT node.
296         :param module: Module to verify.
297         :param force_load: If True then try to load module.
298         :type node: dict
299         :type module: str
300         :type force_init: bool
301         :returns: nothing
302         :raises RuntimeError: If module is not loaded or failed to load.
303         """
304
305         ssh = SSH()
306         ssh.connect(node)
307
308         cmd = 'grep -w {} /proc/modules'.format(module)
309         ret_code, _, _ = ssh.exec_command(cmd)
310
311         if int(ret_code) != 0:
312             if force_load:
313                 # Module is not loaded and we want to load it
314                 DUTSetup.kernel_module_load(node, module)
315             else:
316                 raise RuntimeError('Kernel module {} is not loaded on host: '\
317                     '{}'.format(module, node['host']))
318
319     @staticmethod
320     def kernel_module_load(node, module):
321         """Load kernel module on node.
322
323         :param node: DUT node.
324         :param module: Module to load.
325         :type node: dict
326         :type module: str
327         :returns: nothing
328         :raises RuntimeError: If loading failed.
329         """
330
331         ssh = SSH()
332         ssh.connect(node)
333
334         ret_code, _, _ = ssh.exec_command_sudo("modprobe {}".format(module))
335
336         if int(ret_code) != 0:
337             raise RuntimeError('Failed to load {} kernel module on host: '\
338                 '{}'.format(module, node['host']))