72602929598a42fed6d5e66b3d9afa3d35abdb71
[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         :returns: 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 = 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         :returns: 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'.\
190             format(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: {}'.
210                                                format(cryptodev, numvfs,
211                                                       node['host']))
212                     break
213
214     @staticmethod
215     def crypto_device_init(node, numvfs):
216         """Init Crypto QAT device virtual functions on DUT.
217
218         :param node: DUT node.
219         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
220         :type node: dict
221         :type numvfs: int
222         :returns: nothing
223         :raises RuntimeError: If QAT failed to initialize.
224         """
225
226         ssh = SSH()
227         ssh.connect(node)
228
229         cryptodev = Topology.get_cryptodev(node)
230
231         # QAT device must be bind to kernel driver before initialization
232         DUTSetup.pci_driver_unbind(node, cryptodev)
233         DUTSetup.pci_driver_bind(node, cryptodev, "dh895xcc")
234
235         # Initialize QAT VFs
236         ret_code, _, _ = ssh.exec_command(
237             "sudo sh -c 'echo {} | tee /sys/bus/pci/devices/{}/sriov_numvfs'"
238             .format(numvfs, cryptodev.replace(':', r'\:')))
239
240         if int(ret_code) != 0:
241             raise RuntimeError('Failed to initialize {} VFs on QAT device on '
242                                'host: {}'.format(numvfs, node['host']))
243
244     @staticmethod
245     def pci_driver_unbind(node, pci_addr):
246         """Unbind PCI device from current driver on node.
247
248         :param node: DUT node.
249         :param pci_addr: PCI device address.
250         :type node: dict
251         :type pci_addr: str
252         :returns: nothing
253         :raises RuntimeError: If PCI device unbind failed.
254         """
255
256         ssh = SSH()
257         ssh.connect(node)
258
259         ret_code, _, _ = ssh.exec_command(
260             "sudo sh -c 'echo {} | tee /sys/bus/pci/devices/{}/driver/unbind'"
261             .format(pci_addr, pci_addr.replace(':', r'\:')))
262
263         if int(ret_code) != 0:
264             raise RuntimeError('Failed to unbind PCI device from driver on '
265                                'host: {}'.format(node['host']))
266
267     @staticmethod
268     def pci_driver_bind(node, pci_addr, driver):
269         """Bind PCI device to driver on node.
270
271         :param node: DUT node.
272         :param pci_addr: PCI device address.
273         :param driver: Driver to bind.
274         :type node: dict
275         :type pci_addr: str
276         :type driver: str
277         :returns: nothing
278         :raises RuntimeError: If PCI device bind failed.
279         """
280
281         ssh = SSH()
282         ssh.connect(node)
283
284         ret_code, _, _ = ssh.exec_command(
285             "sudo sh -c 'echo {} | tee /sys/bus/pci/drivers/{}/bind'"
286             .format(pci_addr, driver))
287
288         if int(ret_code) != 0:
289             raise RuntimeError('Failed to bind PCI device to {} driver on '
290                                'host: {}'.format(driver, node['host']))
291
292     @staticmethod
293     def kernel_module_verify(node, module, force_load=False):
294         """Verify if kernel module is loaded on all DUTs. If parameter force
295         load is set to True, then try to load the modules.
296
297         :param node: DUT node.
298         :param module: Module to verify.
299         :param force_load: If True then try to load module.
300         :type node: dict
301         :type module: str
302         :type force_init: bool
303         :returns: nothing
304         :raises RuntimeError: If module is not loaded or failed to load.
305         """
306
307         ssh = SSH()
308         ssh.connect(node)
309
310         cmd = 'grep -w {} /proc/modules'.format(module)
311         ret_code, _, _ = ssh.exec_command(cmd)
312
313         if int(ret_code) != 0:
314             if force_load:
315                 # Module is not loaded and we want to load it
316                 DUTSetup.kernel_module_load(node, module)
317             else:
318                 raise RuntimeError('Kernel module {} is not loaded on host: {}'.
319                                    format(module, node['host']))
320
321     @staticmethod
322     def kernel_module_load(node, module):
323         """Load kernel module on node.
324
325         :param node: DUT node.
326         :param module: Module to load.
327         :type node: dict
328         :type module: str
329         :returns: nothing
330         :raises RuntimeError: If loading failed.
331         """
332
333         ssh = SSH()
334         ssh.connect(node)
335
336         ret_code, _, _ = ssh.exec_command_sudo("modprobe {}".format(module))
337
338         if int(ret_code) != 0:
339             raise RuntimeError('Failed to load {} kernel module on host: {}'.
340                                format(module, node['host']))