PapiExecutor always verifies
[csit.git] / resources / libraries / python / VPPUtil.py
1 # Copyright (c) 2019 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 """VPP util library."""
15
16 import binascii
17
18 from robot.api import logger
19
20 from resources.libraries.python.Constants import Constants
21 from resources.libraries.python.DUTSetup import DUTSetup
22 from resources.libraries.python.L2Util import L2Util
23 from resources.libraries.python.PapiExecutor import PapiExecutor
24 from resources.libraries.python.ssh import exec_cmd_no_error
25 from resources.libraries.python.topology import NodeType
26
27
28 class VPPUtil(object):
29     """General class for any VPP related methods/functions."""
30
31     @staticmethod
32     def show_vpp_settings(node, *additional_cmds):
33         """Print default VPP settings. In case others are needed, can be
34         accepted as next parameters (each setting one parameter), preferably
35         in form of a string.
36
37         :param node: VPP node.
38         :param additional_cmds: Additional commands that the vpp should print
39             settings for.
40         :type node: dict
41         :type additional_cmds: tuple
42         """
43         def_setting_tb_displayed = {
44             'IPv6 FIB': 'ip6 fib',
45             'IPv4 FIB': 'ip fib',
46             'Interface IP': 'int addr',
47             'Interfaces': 'int',
48             'ARP': 'ip arp',
49             'Errors': 'err'
50         }
51
52         if additional_cmds:
53             for cmd in additional_cmds:
54                 def_setting_tb_displayed['Custom Setting: {}'.format(cmd)] = cmd
55
56         for _, cmd in def_setting_tb_displayed.items():
57             command = 'vppctl sh {cmd}'.format(cmd=cmd)
58             exec_cmd_no_error(node, command, timeout=30, sudo=True)
59
60     @staticmethod
61     def restart_vpp_service(node):
62         """Restart VPP service on the specified topology node.
63
64         :param node: Topology node.
65         :type node: dict
66         """
67         DUTSetup.restart_service(node, Constants.VPP_UNIT)
68
69     @staticmethod
70     def restart_vpp_service_on_all_duts(nodes):
71         """Restart VPP service on all DUT nodes.
72
73         :param nodes: Topology nodes.
74         :type nodes: dict
75         """
76         for node in nodes.values():
77             if node['type'] == NodeType.DUT:
78                 VPPUtil.restart_vpp_service(node)
79
80     @staticmethod
81     def stop_vpp_service(node):
82         """Stop VPP service on the specified topology node.
83
84         :param node: Topology node.
85         :type node: dict
86         """
87         DUTSetup.stop_service(node, Constants.VPP_UNIT)
88
89     @staticmethod
90     def stop_vpp_service_on_all_duts(nodes):
91         """Stop VPP service on all DUT nodes.
92
93         :param nodes: Topology nodes.
94         :type nodes: dict
95         """
96         for node in nodes.values():
97             if node['type'] == NodeType.DUT:
98                 VPPUtil.stop_vpp_service(node)
99
100     @staticmethod
101     def verify_vpp_installed(node):
102         """Verify that VPP is installed on the specified topology node.
103
104         :param node: Topology node.
105         :type node: dict
106         """
107         cmd = 'command -v vpp'
108         exec_cmd_no_error(
109             node, cmd, message='VPP is not installed!')
110
111     @staticmethod
112     def verify_vpp_started(node):
113         """Verify that VPP is started on the specified topology node.
114
115         :param node: Topology node.
116         :type node: dict
117         """
118         cmd = ('vppctl show pci 2>&1 | '
119                'fgrep -v "Connection refused" | '
120                'fgrep -v "No such file or directory"')
121         exec_cmd_no_error(
122             node, cmd, sudo=True, message='VPP failed to start!', retries=120)
123
124     @staticmethod
125     def verify_vpp(node):
126         """Verify that VPP is installed and started on the specified topology
127         node.
128
129         :param node: Topology node.
130         :type node: dict
131         :raises RuntimeError: If VPP service fails to start.
132         """
133         VPPUtil.verify_vpp_installed(node)
134         try:
135             # Verify responsivness of vppctl.
136             VPPUtil.verify_vpp_started(node)
137             # Verify responsivness of PAPI.
138             VPPUtil.show_log(node)
139         finally:
140             DUTSetup.get_service_logs(node, Constants.VPP_UNIT)
141
142     @staticmethod
143     def verify_vpp_on_all_duts(nodes):
144         """Verify that VPP is installed and started on all DUT nodes.
145
146         :param nodes: Nodes in the topology.
147         :type nodes: dict
148         """
149         for node in nodes.values():
150             if node['type'] == NodeType.DUT:
151                 VPPUtil.verify_vpp(node)
152
153     @staticmethod
154     def vpp_show_version(node, verbose=True):
155         """Run "show_version" PAPI command.
156
157         :param node: Node to run command on.
158         :param verbose: Show version, compile date and compile location if True
159             otherwise show only version.
160         :type node: dict
161         :type verbose: bool
162         :returns: VPP version.
163         :rtype: str
164         """
165         with PapiExecutor(node) as papi_exec:
166             reply = papi_exec.add('show_version').get_reply()
167         return_version = reply['version'].rstrip('\0x00')
168         version = 'VPP version:      {ver}\n'.format(ver=return_version)
169         if verbose:
170             version += ('Compile date:     {date}\n'
171                         'Compile location: {cl}\n'.
172                         format(date=reply['build_date'].rstrip('\0x00'),
173                                cl=reply['build_directory'].rstrip('\0x00')))
174         logger.info(version)
175         return return_version
176
177     @staticmethod
178     def show_vpp_version_on_all_duts(nodes):
179         """Show VPP version verbose on all DUTs.
180
181         :param nodes: Nodes in the topology.
182         :type nodes: dict
183         """
184         for node in nodes.values():
185             if node['type'] == NodeType.DUT:
186                 VPPUtil.vpp_show_version(node)
187
188     @staticmethod
189     def vpp_show_interfaces(node):
190         """Run "show interface" CLI command.
191
192         :param node: Node to run command on.
193         :type node: dict
194         """
195
196         cmd = 'sw_interface_dump'
197         args = dict(name_filter_valid=0, name_filter='')
198         err_msg = 'Failed to get interface dump on host {host}'.format(
199             host=node['host'])
200         with PapiExecutor(node) as papi_exec:
201             details = papi_exec.add(cmd, **args).get_details(err_msg)
202
203         for if_dump in details:
204             if_dump['interface_name'] = if_dump['interface_name'].rstrip('\x00')
205             if_dump['tag'] = if_dump['tag'].rstrip('\x00')
206             if_dump['l2_address'] = L2Util.bin_to_mac(if_dump['l2_address'])
207         # TODO: return only base data
208         logger.trace('Interface data of host {host}:\n{details}'.format(
209             host=node['host'], details=details))
210
211     @staticmethod
212     def vpp_enable_traces_on_dut(node, fail_on_error=False):
213         """Enable vpp packet traces on the DUT node.
214
215         :param node: DUT node to set up.
216         :param fail_on_error: If True, keyword fails if an error occurs,
217             otherwise passes.
218         :type node: dict
219         :type fail_on_error: bool
220         """
221         cmds = [
222             "trace add dpdk-input 50",
223             "trace add vhost-user-input 50",
224             "trace add memif-input 50"
225         ]
226
227         for cmd in cmds:
228             try:
229                 PapiExecutor.run_cli_cmd(node, cmd)
230             except AssertionError:
231                 if fail_on_error:
232                     raise
233
234     @staticmethod
235     def vpp_enable_traces_on_all_duts(nodes, fail_on_error=False):
236         """Enable vpp packet traces on all DUTs in the given topology.
237
238         :param nodes: Nodes in the topology.
239         :param fail_on_error: If True, keyword fails if an error occurs,
240             otherwise passes.
241         :type nodes: dict
242         :type fail_on_error: bool
243         """
244         for node in nodes.values():
245             if node['type'] == NodeType.DUT:
246                 VPPUtil.vpp_enable_traces_on_dut(node, fail_on_error)
247
248     @staticmethod
249     def vpp_enable_elog_traces_on_dut(node):
250         """Enable API/CLI/Barrier traces on the DUT node.
251
252         :param node: DUT node to set up.
253         :type node: dict
254         """
255         PapiExecutor.run_cli_cmd(node, "elog trace api cli barrier")
256
257     @staticmethod
258     def vpp_enable_elog_traces_on_all_duts(nodes):
259         """Enable API/CLI/Barrier traces on all DUTs in the given topology.
260
261         :param nodes: Nodes in the topology.
262         :type nodes: dict
263         """
264         for node in nodes.values():
265             if node['type'] == NodeType.DUT:
266                 VPPUtil.vpp_enable_elog_traces_on_dut(node)
267
268     @staticmethod
269     def show_event_logger_on_dut(node):
270         """Show event logger on the DUT node.
271
272         :param node: DUT node to show traces on.
273         :type node: dict
274         """
275         PapiExecutor.run_cli_cmd(node, "show event-logger")
276
277     @staticmethod
278     def show_event_logger_on_all_duts(nodes):
279         """Show event logger on all DUTs in the given topology.
280
281         :param nodes: Nodes in the topology.
282         :type nodes: dict
283         """
284         for node in nodes.values():
285             if node['type'] == NodeType.DUT:
286                 VPPUtil.show_event_logger_on_dut(node)
287
288     @staticmethod
289     def show_log(node):
290         """Show log on the specified topology node.
291
292         :param node: Topology node.
293         :type node: dict
294         :returns: VPP log data.
295         :rtype: list
296         """
297         return PapiExecutor.run_cli_cmd(node, "show log")
298
299     @staticmethod
300     def vpp_show_threads(node):
301         """Show VPP threads on node.
302
303         :param node: Node to run command on.
304         :type node: dict
305         :returns: VPP thread data.
306         :rtype: list
307         """
308         with PapiExecutor(node) as papi_exec:
309             reply = papi_exec.add('show_threads').get_reply()
310
311         threads_data = list()
312         for thread in reply["thread_data"]:
313             thread_data = list()
314             for item in thread:
315                 if isinstance(item, unicode):
316                     item = item.rstrip('\x00')
317                 thread_data.append(item)
318             threads_data.append(thread_data)
319
320         logger.info("show threads:\n{threads}".format(threads=threads_data))
321
322         return threads_data