VIRL VPP PID fix
[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
117         for i in range(3):
118             logger.trace('Try {}: Get VPP PID'.format(i))
119             ret_code, stdout, stderr = ssh.exec_command('pidof vpp')
120
121             if int(ret_code) != 0:
122                 raise RuntimeError('Not possible to get PID of VPP process '
123                                    'on node: {0}\n {1}'.
124                                    format(node['host'], stdout + stderr))
125
126             if len(stdout.splitlines()) == 1:
127                 return int(stdout)
128             elif len(stdout.splitlines()) == 0:
129                 logger.debug("No VPP PID found on node {0}".
130                              format(node['host']))
131                 continue
132             else:
133                 logger.debug("More then one VPP PID found on node {0}".
134                              format(node['host']))
135                 ret_list = ()
136                 for line in stdout.splitlines():
137                     ret_list.append(int(line))
138                 return ret_list
139
140         return None
141
142     @staticmethod
143     def get_vpp_pids(nodes):
144         """Get PID of running VPP process on all DUTs.
145
146         :param nodes: DUT nodes.
147         :type nodes: dict
148         :return: PIDs
149         :rtype: dict
150         """
151
152         pids = dict()
153         for node in nodes.values():
154             if node['type'] == NodeType.DUT:
155                 pids[node['host']] = DUTSetup.get_vpp_pid(node)
156         return pids
157
158     @staticmethod
159     def vpp_show_crypto_device_mapping(node):
160         """Run "show crypto device mapping" CLI command.
161
162         :param node: Node to run command on.
163         :type node: dict
164         """
165         vat = VatExecutor()
166         vat.execute_script("show_crypto_device_mapping.vat", node,
167                            json_out=False)
168
169     @staticmethod
170     def crypto_device_verify(node, force_init=False, numvfs=32):
171         """Verify if Crypto QAT device virtual functions are initialized on all
172         DUTs. If parameter force initialization is set to True, then try to
173         initialize or disable QAT.
174
175         :param node: DUT node.
176         :param force_init: If True then try to initialize to specific value.
177         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
178         :type node: dict
179         :type force_init: bool
180         :type numvfs: int
181         :returns: nothing
182         :raises RuntimeError: If QAT is not initialized or failed to initialize.
183         """
184
185         ssh = SSH()
186         ssh.connect(node)
187
188         cryptodev = Topology.get_cryptodev(node)
189         cmd = 'cat /sys/bus/pci/devices/{}/sriov_numvfs'.format(
190             cryptodev.replace(':', r'\:'))
191
192         # Try to read number of VFs from PCI address of QAT device
193         for _ in range(3):
194             ret_code, stdout, _ = ssh.exec_command(cmd)
195             if int(ret_code) == 0:
196                 try:
197                     sriov_numvfs = int(stdout)
198                 except ValueError:
199                     logger.trace('Reading sriov_numvfs info failed on: {}'\
200                         .format(node['host']))
201                 else:
202                     if sriov_numvfs != numvfs:
203                         if force_init:
204                             # QAT is not initialized and we want to initialize
205                             # with numvfs
206                             DUTSetup.crypto_device_init(node, numvfs)
207                         else:
208                             raise RuntimeError('QAT device {} is not '\
209                                 'initialized to {} on host: {}'.format(\
210                                 cryptodev, numvfs, node['host']))
211                     break
212
213     @staticmethod
214     def crypto_device_init(node, numvfs):
215         """Init Crypto QAT device virtual functions on DUT.
216
217         :param node: DUT node.
218         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
219         :type node: dict
220         :type numvfs: int
221         :returns: nothing
222         :raises RuntimeError: If QAT failed to initialize.
223         """
224
225         ssh = SSH()
226         ssh.connect(node)
227
228         cryptodev = Topology.get_cryptodev(node)
229
230         # QAT device must be bind to kernel driver before initialization
231         DUTSetup.pci_driver_unbind(node, cryptodev)
232         DUTSetup.pci_driver_bind(node, cryptodev, "dh895xcc")
233
234         # Initialize QAT VFs
235         ret_code, _, _ = ssh.exec_command(
236             "sudo sh -c 'echo {} | tee /sys/bus/pci/devices/{}/sriov_numvfs'"
237             .format(numvfs, cryptodev.replace(':', r'\:')))
238
239         if int(ret_code) != 0:
240             raise RuntimeError('Failed to initialize {} VFs on QAT device on '
241                                'host: {}'.format(numvfs, node['host']))
242
243     @staticmethod
244     def pci_driver_unbind(node, pci_addr):
245         """Unbind PCI device from current driver on node.
246
247         :param node: DUT node.
248         :param pci_addr: PCI device address.
249         :type node: dict
250         :type pci_addr: str
251         :returns: nothing
252         :raises RuntimeError: If PCI device unbind failed.
253         """
254
255         ssh = SSH()
256         ssh.connect(node)
257
258         ret_code, _, _ = ssh.exec_command(
259             "sudo sh -c 'echo {} | tee /sys/bus/pci/devices/{}/driver/unbind'"
260             .format(pci_addr, pci_addr.replace(':', r'\:')))
261
262         if int(ret_code) != 0:
263             raise RuntimeError('Failed to unbind PCI device from driver on '
264                                'host: {}'.format(node['host']))
265
266     @staticmethod
267     def pci_driver_bind(node, pci_addr, driver):
268         """Bind PCI device to driver on node.
269
270         :param node: DUT node.
271         :param pci_addr: PCI device address.
272         :param driver: Driver to bind.
273         :type node: dict
274         :type pci_addr: str
275         :type driver: str
276         :returns: nothing
277         :raises RuntimeError: If PCI device bind failed.
278         """
279
280         ssh = SSH()
281         ssh.connect(node)
282
283         ret_code, _, _ = ssh.exec_command(
284             "sudo sh -c 'echo {} | tee /sys/bus/pci/drivers/{}/bind'"
285             .format(pci_addr, driver))
286
287         if int(ret_code) != 0:
288             raise RuntimeError('Failed to bind PCI device to {} driver on '
289                                'host: {}'.format(driver, node['host']))
290
291     @staticmethod
292     def kernel_module_verify(node, module, force_load=False):
293         """Verify if kernel module is loaded on all DUTs. If parameter force
294         load is set to True, then try to load the modules.
295
296         :param node: DUT node.
297         :param module: Module to verify.
298         :param force_load: If True then try to load module.
299         :type node: dict
300         :type module: str
301         :type force_init: bool
302         :returns: nothing
303         :raises RuntimeError: If module is not loaded or failed to load.
304         """
305
306         ssh = SSH()
307         ssh.connect(node)
308
309         cmd = 'grep -w {} /proc/modules'.format(module)
310         ret_code, _, _ = ssh.exec_command(cmd)
311
312         if int(ret_code) != 0:
313             if force_load:
314                 # Module is not loaded and we want to load it
315                 DUTSetup.kernel_module_load(node, module)
316             else:
317                 raise RuntimeError('Kernel module {} is not loaded on host: '\
318                     '{}'.format(module, node['host']))
319
320     @staticmethod
321     def kernel_module_load(node, module):
322         """Load kernel module on node.
323
324         :param node: DUT node.
325         :param module: Module to load.
326         :type node: dict
327         :type module: str
328         :returns: nothing
329         :raises RuntimeError: If loading failed.
330         """
331
332         ssh = SSH()
333         ssh.connect(node)
334
335         ret_code, _, _ = ssh.exec_command_sudo("modprobe {}".format(module))
336
337         if int(ret_code) != 0:
338             raise RuntimeError('Failed to load {} kernel module on host: '\
339                 '{}'.format(module, node['host']))