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