blob: 365c4c95f79f1b06f8de2ffcf4e7ed3305d95868 [file] [log] [blame]
John DeNisco68b0ee32017-09-27 16:35:23 -04001# 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
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -080014from __future__ import print_function
15
John DeNisco68b0ee32017-09-27 16:35:23 -040016"""VPP util library"""
17import logging
18import re
19import subprocess
20import platform
jdenisco24010fb2018-11-13 12:40:12 -050021import requests
John DeNisco68b0ee32017-09-27 16:35:23 -040022
23from collections import Counter
24
John DeNisco68b0ee32017-09-27 16:35:23 -040025
26class VPPUtil(object):
27 """General class for any VPP related methods/functions."""
28
29 @staticmethod
30 def exec_command(cmd, timeout=None):
31 """Execute a command on the local node.
32
33 :param cmd: Command to run locally.
34 :param timeout: Timeout value
35 :type cmd: str
36 :type timeout: int
37 :return return_code, stdout, stderr
38 :rtype: tuple(int, str, str)
39 """
40
41 logging.info(" Local Command: {}".format(cmd))
42 out = ''
43 err = ''
44 prc = subprocess.Popen(cmd, shell=True, bufsize=1,
45 stdin=subprocess.PIPE,
46 stdout=subprocess.PIPE,
47 stderr=subprocess.PIPE)
48
49 with prc.stdout:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -080050 lines = prc.stdout.readlines()
51 for line in lines:
52 if type(line) != str:
53 line = line.decode()
John DeNisco68b0ee32017-09-27 16:35:23 -040054 logging.info(" {}".format(line.strip('\n')))
55 out += line
56
57 with prc.stderr:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -080058 lines = prc.stderr.readlines()
59 for line in lines:
60 if type(line) != str:
61 line = line.decode()
John DeNisco68b0ee32017-09-27 16:35:23 -040062 logging.warn(" {}".format(line.strip('\n')))
63 err += line
64
65 ret = prc.wait()
66
67 return ret, out, err
68
69 def _autoconfig_backup_file(self, filename):
70 """
71 Create a backup file.
72
73 :param filename: The file to backup
74 :type filename: str
75 """
76
77 # Does a copy of the file exist, if not create one
78 ofile = filename + '.orig'
79 (ret, stdout, stderr) = self.exec_command('ls {}'.format(ofile))
80 if ret != 0:
81 logging.debug(stderr)
82 if stdout.strip('\n') != ofile:
83 cmd = 'sudo cp {} {}'.format(filename, ofile)
84 (ret, stdout, stderr) = self.exec_command(cmd)
85 if ret != 0:
86 logging.debug(stderr)
87
88 def _install_vpp_pkg_ubuntu(self, node, pkg):
89 """
90 Install the VPP packages
91
92 :param node: Node dictionary
93 :param pkg: The vpp packages
94 :type node: dict
95 :type pkg: string
96 """
97
98 cmd = 'apt-get -y install {}'.format(pkg)
99 (ret, stdout, stderr) = self.exec_command(cmd)
100 if ret != 0:
101 raise RuntimeError('{} failed on node {} {} {}'.format(
102 cmd, node['host'], stdout, stderr))
103
104 def _install_vpp_pkg_centos(self, node, pkg):
105 """
106 Install the VPP packages
107
108 :param node: Node dictionary
109 :param pkg: The vpp packages
110 :type node: dict
111 :type pkg: string
112 """
113
114 cmd = 'yum -y install {}'.format(pkg)
115 (ret, stdout, stderr) = self.exec_command(cmd)
116 if ret != 0:
117 raise RuntimeError('{} failed on node {} {} {}'.format(
118 cmd, node['host'], stdout, stderr))
119
jdeniscob0b9dad2018-12-18 15:29:45 -0500120 def _install_vpp_ubuntu(self, node, branch, ubuntu_version='xenial'):
John DeNisco68b0ee32017-09-27 16:35:23 -0400121 """
122 Install the VPP packages
123
124 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500125 :param branch: VPP branch
John DeNisco68b0ee32017-09-27 16:35:23 -0400126 :param ubuntu_version: Ubuntu Version
127 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500128 :type branch: string
John DeNisco68b0ee32017-09-27 16:35:23 -0400129 :type ubuntu_version: string
130 """
131
132 # Modify the sources list
133 sfile = '/etc/apt/sources.list.d/99fd.io.list'
134
135 # Backup the sources list
136 self._autoconfig_backup_file(sfile)
137
jdenisco24010fb2018-11-13 12:40:12 -0500138 reps = 'deb [trusted=yes] https://packagecloud.io/fdio/'
jdeniscob0b9dad2018-12-18 15:29:45 -0500139 reps += '{}/ubuntu {} main ./\n'.format(branch, ubuntu_version)
John DeNisco68b0ee32017-09-27 16:35:23 -0400140
jdenisco24010fb2018-11-13 12:40:12 -0500141 with open(sfile, 'w') as sfd:
142 sfd.write(reps)
143 sfd.close()
144
145 # Add the key
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800146
147 key = requests.get(
148 'https://packagecloud.io/fdio/{}/gpgkey'.format(branch))
149 cmd = 'echo "{}" | apt-key add -'.format(key.content.decode(key.encoding))
John DeNisco68b0ee32017-09-27 16:35:23 -0400150 (ret, stdout, stderr) = self.exec_command(cmd)
151 if ret != 0:
152 raise RuntimeError('{} failed on node {} {}'.format(
153 cmd,
154 node['host'],
155 stderr))
156
157 # Install the package
158 cmd = 'apt-get -y update'
159 (ret, stdout, stderr) = self.exec_command(cmd)
160 if ret != 0:
161 raise RuntimeError('{} apt-get update failed on node {} {}'.format(
162 cmd,
163 node['host'],
164 stderr))
165
166 self._install_vpp_pkg_ubuntu(node, 'vpp-lib')
167 self._install_vpp_pkg_ubuntu(node, 'vpp')
168 self._install_vpp_pkg_ubuntu(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400169 self._install_vpp_pkg_ubuntu(node, 'vpp-api-python')
170 self._install_vpp_pkg_ubuntu(node, 'vpp-api-java')
171 self._install_vpp_pkg_ubuntu(node, 'vpp-api-lua')
172 self._install_vpp_pkg_ubuntu(node, 'vpp-dev')
173 self._install_vpp_pkg_ubuntu(node, 'vpp-dbg')
174
jdeniscob0b9dad2018-12-18 15:29:45 -0500175 def _install_vpp_centos(self, node, branch):
John DeNisco68b0ee32017-09-27 16:35:23 -0400176 """
177 Install the VPP packages
178
179 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500180 :param branch: The branch name release or master
John DeNisco68b0ee32017-09-27 16:35:23 -0400181 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500182 :type branch: string
John DeNisco68b0ee32017-09-27 16:35:23 -0400183 """
184
jdenisco24010fb2018-11-13 12:40:12 -0500185 # Be sure the correct system packages are installed
186 cmd = 'yum -y update'
187 (ret, stdout, stderr) = self.exec_command(cmd)
188 if ret != 0:
189 logging.debug('{} failed on node {} {}'.format(
190 cmd,
191 node['host'],
192 stderr))
193
194 cmd = 'yum -y install pygpgme yum-utils'
195 (ret, stdout, stderr) = self.exec_command(cmd)
196 if ret != 0:
197 logging.debug('{} failed on node {} {}'.format(
198 cmd,
199 node['host'],
200 stderr))
201
John DeNisco68b0ee32017-09-27 16:35:23 -0400202 # Modify the sources list
203 sfile = '/etc/yum.repos.d/fdio-release.repo'
204
205 # Backup the sources list
206 self._autoconfig_backup_file(sfile)
207
208 # Remove the current file
209 cmd = 'rm {}'.format(sfile)
210 (ret, stdout, stderr) = self.exec_command(cmd)
211 if ret != 0:
212 logging.debug('{} failed on node {} {}'.format(
213 cmd,
214 node['host'],
215 stderr))
216
jdenisco24010fb2018-11-13 12:40:12 -0500217 # Get the file contents
jdenisco24010fb2018-11-13 12:40:12 -0500218
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800219 reps = '\n'.join([
220 '[fdio_{}]'.format(branch),
221 'name=fdio_{}'.format(branch),
222 'baseurl=https://packagecloud.io/fdio/{}/el/7/$basearch'.format(
223 branch),
224 'repo_gpgcheck=1',
225 'gpgcheck=0',
226 'enabled=1',
227 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey'.format(branch),
228 'sslverify=1',
229 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt',
230 'metadata_expire=300\n',
231 '[fdio_{}-source]'.format(branch),
232 'name=fdio_release-{}'.format(branch),
233 'baseurl=https://packagecloud.io/fdio/{}/el/7/SRPMS'.format(
234 branch),
235 'repo_gpgcheck=1',
236 'gpgcheck=0',
237 'enabled=1',
238 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey'.format(branch),
239 'sslverify =1',
240 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt',
241 'metadata_expire=300\n'
242 ])
jdenisco24010fb2018-11-13 12:40:12 -0500243 with open(sfile, 'w') as sfd:
244 sfd.write(reps)
245 sfd.close()
246
247 # Update the fdio repo
248 cmd = 'yum clean all'
John DeNisco68b0ee32017-09-27 16:35:23 -0400249 (ret, stdout, stderr) = self.exec_command(cmd)
250 if ret != 0:
jdenisco24010fb2018-11-13 12:40:12 -0500251 logging.debug('{} failed on node {} {}'.format(
252 cmd,
253 node['host'],
254 stderr))
255
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800256 cmd = "yum -q makecache -y --disablerepo='*' " \
257 "--enablerepo='fdio_{}'".format(branch)
jdenisco24010fb2018-11-13 12:40:12 -0500258 (ret, stdout, stderr) = self.exec_command(cmd)
259 if ret != 0:
260 logging.debug('{} failed on node {} {}'.format(
John DeNisco68b0ee32017-09-27 16:35:23 -0400261 cmd,
262 node['host'],
263 stderr))
264
265 # Install the packages
jdenisco24010fb2018-11-13 12:40:12 -0500266 self._install_vpp_pkg_centos(node, 'vpp-selinux-policy')
John DeNisco68b0ee32017-09-27 16:35:23 -0400267 self._install_vpp_pkg_centos(node, 'vpp-lib')
268 self._install_vpp_pkg_centos(node, 'vpp')
269 self._install_vpp_pkg_centos(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400270 self._install_vpp_pkg_centos(node, 'vpp-api-python')
271 self._install_vpp_pkg_centos(node, 'vpp-api-java')
272 self._install_vpp_pkg_centos(node, 'vpp-api-lua')
273 self._install_vpp_pkg_centos(node, 'vpp-devel')
jdeniscob9875092018-11-06 16:10:04 -0500274 self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
John DeNisco68b0ee32017-09-27 16:35:23 -0400275
jdeniscob0b9dad2018-12-18 15:29:45 -0500276 def install_vpp(self, node, branch):
John DeNisco68b0ee32017-09-27 16:35:23 -0400277 """
278 Install the VPP packages
279
280 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500281 :param branch: The branch name
John DeNisco68b0ee32017-09-27 16:35:23 -0400282 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500283 :type branch: string
284
John DeNisco68b0ee32017-09-27 16:35:23 -0400285 """
286 distro = self.get_linux_distro()
John DeNisco4dc83972018-03-30 10:50:19 -0400287 logging.info(" {}".format(distro[0]))
John DeNisco68b0ee32017-09-27 16:35:23 -0400288 if distro[0] == 'Ubuntu':
John DeNisco4dc83972018-03-30 10:50:19 -0400289 logging.info("Install Ubuntu")
jdeniscob0b9dad2018-12-18 15:29:45 -0500290 self._install_vpp_ubuntu(node, branch, ubuntu_version=distro[2])
John DeNisco68b0ee32017-09-27 16:35:23 -0400291 elif distro[0] == 'CentOS Linux':
292 logging.info("Install CentOS")
jdeniscob0b9dad2018-12-18 15:29:45 -0500293 self._install_vpp_centos(node, branch)
John DeNisco68b0ee32017-09-27 16:35:23 -0400294 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400295 logging.info("Install CentOS (default)")
jdeniscob0b9dad2018-12-18 15:29:45 -0500296 self._install_vpp_centos(node, branch)
John DeNisco4dc83972018-03-30 10:50:19 -0400297 return
John DeNisco68b0ee32017-09-27 16:35:23 -0400298
299 def _uninstall_vpp_pkg_ubuntu(self, node, pkg):
300 """
301 Uninstall the VPP packages
302
303 :param node: Node dictionary
304 :param pkg: The vpp packages
305 :type node: dict
306 :type pkg: string
307 """
308 cmd = 'dpkg --purge {}'.format(pkg)
309 (ret, stdout, stderr) = self.exec_command(cmd)
310 if ret != 0:
311 raise RuntimeError('{} failed on node {} {} {}'.format(
312 cmd, node['host'], stdout, stderr))
313
314 def _uninstall_vpp_pkg_centos(self, node, pkg):
315 """
316 Uninstall the VPP packages
317
318 :param node: Node dictionary
319 :param pkg: The vpp packages
320 :type node: dict
321 :type pkg: string
322 """
323 cmd = 'yum -y remove {}'.format(pkg)
324 (ret, stdout, stderr) = self.exec_command(cmd)
325 if ret != 0:
326 raise RuntimeError('{} failed on node {} {} {}'.format(
327 cmd, node['host'], stdout, stderr))
328
329 def _uninstall_vpp_ubuntu(self, node):
330 """
331 Uninstall the VPP packages
332
333 :param node: Node dictionary with cpuinfo.
334 :type node: dict
335 """
336 pkgs = self.get_installed_vpp_pkgs()
337
338 if len(pkgs) > 0:
339 if 'version' in pkgs[0]:
340 logging.info("Uninstall Ubuntu Packages")
jdenisco24010fb2018-11-13 12:40:12 -0500341 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dbg')
342 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dev')
John DeNisco68b0ee32017-09-27 16:35:23 -0400343 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-python')
344 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-java')
345 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-lua')
346 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400347 self._uninstall_vpp_pkg_ubuntu(node, 'vpp')
348 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-lib')
349 else:
350 logging.info("Uninstall locally installed Ubuntu Packages")
351 for pkg in pkgs:
352 self._uninstall_vpp_pkg_ubuntu(node, pkg['name'])
353 else:
354 logging.error("There are no Ubuntu packages installed")
355
356 def _uninstall_vpp_centos(self, node):
357 """
358 Uninstall the VPP packages
359
360 :param node: Node dictionary with cpuinfo.
361 :type node: dict
362 """
363
364 pkgs = self.get_installed_vpp_pkgs()
365
366 if len(pkgs) > 0:
367 if 'version' in pkgs[0]:
368 logging.info("Uninstall CentOS Packages")
jdenisco24010fb2018-11-13 12:40:12 -0500369 self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
370 self._uninstall_vpp_pkg_centos(node, 'vpp-devel')
John DeNisco68b0ee32017-09-27 16:35:23 -0400371 self._uninstall_vpp_pkg_centos(node, 'vpp-api-python')
372 self._uninstall_vpp_pkg_centos(node, 'vpp-api-java')
373 self._uninstall_vpp_pkg_centos(node, 'vpp-api-lua')
374 self._uninstall_vpp_pkg_centos(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400375 self._uninstall_vpp_pkg_centos(node, 'vpp')
376 self._uninstall_vpp_pkg_centos(node, 'vpp-lib')
jdenisco24010fb2018-11-13 12:40:12 -0500377 self._uninstall_vpp_pkg_centos(node, 'vpp-selinux-policy')
John DeNisco68b0ee32017-09-27 16:35:23 -0400378 else:
379 logging.info("Uninstall locally installed CentOS Packages")
380 for pkg in pkgs:
381 self._uninstall_vpp_pkg_centos(node, pkg['name'])
382 else:
383 logging.error("There are no CentOS packages installed")
384
385 def uninstall_vpp(self, node):
386 """
387 Uninstall the VPP packages
388
389 :param node: Node dictionary with cpuinfo.
390 :type node: dict
391 """
John DeNiscoc6b2a202017-11-01 12:37:47 -0400392
393 # First stop VPP
394 self.stop(node)
395
John DeNisco68b0ee32017-09-27 16:35:23 -0400396 distro = self.get_linux_distro()
397 if distro[0] == 'Ubuntu':
John DeNisco4dc83972018-03-30 10:50:19 -0400398 logging.info("Uninstall Ubuntu")
John DeNisco68b0ee32017-09-27 16:35:23 -0400399 self._uninstall_vpp_ubuntu(node)
400 elif distro[0] == 'CentOS Linux':
401 logging.info("Uninstall CentOS")
402 self._uninstall_vpp_centos(node)
403 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400404 logging.info("Uninstall CentOS (Default)")
405 self._uninstall_vpp_centos(node)
John DeNisco68b0ee32017-09-27 16:35:23 -0400406 return
407
408 def show_vpp_settings(self, *additional_cmds):
409 """
410 Print default VPP settings. In case others are needed, can be
411 accepted as next parameters (each setting one parameter), preferably
412 in form of a string.
413
414 :param additional_cmds: Additional commands that the vpp should print
415 settings for.
416 :type additional_cmds: tuple
417 """
418 def_setting_tb_displayed = {
419 'IPv6 FIB': 'ip6 fib',
420 'IPv4 FIB': 'ip fib',
421 'Interface IP': 'int addr',
422 'Interfaces': 'int',
423 'ARP': 'ip arp',
424 'Errors': 'err'
425 }
426
427 if additional_cmds:
428 for cmd in additional_cmds:
429 def_setting_tb_displayed['Custom Setting: {}'.format(cmd)] \
430 = cmd
431
432 for _, value in def_setting_tb_displayed.items():
433 self.exec_command('vppctl sh {}'.format(value))
434
435 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400436 def get_vms(node):
437 """
438 Get a list of VMs that are connected to VPP interfaces
439
440 :param node: VPP node.
441 :type node: dict
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800442 :returns: Dictionary containing a list of VMs and the interfaces
443 that are connected to VPP
John DeNiscoc6b2a202017-11-01 12:37:47 -0400444 :rtype: dictionary
445 """
446
447 vmdict = {}
448
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800449 print ("Need to implement get vms")
450
John DeNiscoc6b2a202017-11-01 12:37:47 -0400451 return vmdict
452
453 @staticmethod
John DeNiscoa3db0782017-10-17 11:07:22 -0400454 def get_int_ip(node):
455 """
456 Get the VPP interfaces and IP addresses
457
458 :param node: VPP node.
459 :type node: dict
460 :returns: Dictionary containing VPP interfaces and IP addresses
461 :rtype: dictionary
462 """
463 interfaces = {}
464 cmd = 'vppctl show int addr'
465 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
466 if ret != 0:
467 return interfaces
468
469 lines = stdout.split('\n')
470 if len(lines[0]) is not 0:
471 if lines[0].split(' ')[0] == 'FileNotFoundError':
472 return interfaces
473
John DeNiscoc6b2a202017-11-01 12:37:47 -0400474 name = ''
John DeNiscoa3db0782017-10-17 11:07:22 -0400475 for line in lines:
476 if len(line) is 0:
477 continue
478
479 # If the first character is not whitespace
480 # create a new interface
481 if len(re.findall(r'\s', line[0])) is 0:
482 spl = line.split()
483 name = spl[0]
484 if name == 'local0':
485 continue
486 interfaces[name] = {}
487 interfaces[name]['state'] = spl[1].lstrip('(').rstrip('):\r')
488 else:
489 interfaces[name]['address'] = line.lstrip(' ').rstrip('\r')
490
491 return interfaces
492
493 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400494 def get_hardware(node):
495 """
496 Get the VPP hardware information and return it in a
497 dictionary
498
499 :param node: VPP node.
500 :type node: dict
John DeNiscoa3db0782017-10-17 11:07:22 -0400501 :returns: Dictionary containing VPP hardware information
John DeNisco68b0ee32017-09-27 16:35:23 -0400502 :rtype: dictionary
503 """
504
505 interfaces = {}
506 cmd = 'vppctl show hard'
507 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
508 if ret != 0:
509 return interfaces
510
511 lines = stdout.split('\n')
512 if len(lines[0]) is not 0:
513 if lines[0].split(' ')[0] == 'FileNotFoundError':
514 return interfaces
515
516 for line in lines:
517 if len(line) is 0:
518 continue
519
520 # If the first character is not whitespace
521 # create a new interface
522 if len(re.findall(r'\s', line[0])) is 0:
523 spl = line.split()
524 name = spl[0]
525 interfaces[name] = {}
526 interfaces[name]['index'] = spl[1]
527 interfaces[name]['state'] = spl[2]
528
529 # Ethernet address
530 rfall = re.findall(r'Ethernet address', line)
531 if rfall:
532 spl = line.split()
533 interfaces[name]['mac'] = spl[2]
534
535 # Carrier
536 rfall = re.findall(r'carrier', line)
537 if rfall:
538 spl = line.split('carrier ')
539 interfaces[name]['carrier'] = spl[1]
540
541 # Socket
jdenisco7c37a672018-11-20 11:25:17 -0500542 rfall = re.findall(r'numa \d+', line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400543 if rfall:
jdenisco7c37a672018-11-20 11:25:17 -0500544 spl = rfall[0].split()
545 interfaces[name]['numa'] = rfall[0].split()[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400546
547 # Queues and Descriptors
jdenisco7c37a672018-11-20 11:25:17 -0500548 rfall = re.findall(r'rx\: queues \d+', line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400549 if rfall:
jdenisco7c37a672018-11-20 11:25:17 -0500550 interfaces[name]['rx queues'] = rfall[0].split()[2]
551 rdesc = re.findall(r'desc \d+', line)
552 if rdesc:
553 interfaces[name]['rx descs'] = rdesc[0].split()[1]
554
555 rfall = re.findall(r'tx\: queues \d+', line)
556 if rfall:
557 interfaces[name]['tx queues'] = rfall[0].split()[2]
558 rdesc = re.findall(r'desc \d+', line)
559 if rdesc:
560 interfaces[name]['tx descs'] = rdesc[0].split()[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400561
562 return interfaces
563
jdeniscob0b9dad2018-12-18 15:29:45 -0500564 def _get_installed_vpp_pkgs_ubuntu(self, distro):
John DeNisco68b0ee32017-09-27 16:35:23 -0400565 """
566 Get the VPP hardware information and return it in a
567 dictionary
568
jdeniscob0b9dad2018-12-18 15:29:45 -0500569 :param distro: The linux distro
570 :type distro: dict
John DeNisco68b0ee32017-09-27 16:35:23 -0400571 :returns: List of the packages installed
572 :rtype: list
573 """
574
575 pkgs = []
576 cmd = 'dpkg -l | grep vpp'
577 (ret, stdout, stderr) = self.exec_command(cmd)
578 if ret != 0:
579 return pkgs
580
581 lines = stdout.split('\n')
582 for line in lines:
583 items = line.split()
584 if len(items) < 2:
585 continue
586 pkg = {'name': items[1], 'version': items[2]}
587 pkgs.append(pkg)
588
589 return pkgs
590
591 def _get_installed_vpp_pkgs_centos(self):
592 """
593 Get the VPP hardware information and return it in a
594 dictionary
595
596 :returns: List of the packages installed
597 :rtype: list
598 """
599
600 pkgs = []
601 cmd = 'rpm -qa | grep vpp'
602 (ret, stdout, stderr) = self.exec_command(cmd)
603 if ret != 0:
604 return pkgs
605
606 lines = stdout.split('\n')
607 for line in lines:
608 if len(line) == 0:
609 continue
610
611 items = line.split()
612 if len(items) < 2:
613 pkg = {'name': items[0]}
614 else:
615 pkg = {'name': items[1], 'version': items[2]}
616
617 pkgs.append(pkg)
618
619 return pkgs
620
621 def get_installed_vpp_pkgs(self):
622 """
623 Get the VPP hardware information and return it in a
624 dictionary
625
626 :returns: List of the packages installed
627 :rtype: list
628 """
629
630 distro = self.get_linux_distro()
631 if distro[0] == 'Ubuntu':
jdeniscob0b9dad2018-12-18 15:29:45 -0500632 pkgs = self._get_installed_vpp_pkgs_ubuntu(distro)
John DeNisco68b0ee32017-09-27 16:35:23 -0400633 elif distro[0] == 'CentOS Linux':
634 pkgs = self._get_installed_vpp_pkgs_centos()
635 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400636 pkgs = self._get_installed_vpp_pkgs_centos()
John DeNisco68b0ee32017-09-27 16:35:23 -0400637 return []
638
639 return pkgs
640
641 @staticmethod
642 def get_interfaces_numa_node(node, *iface_keys):
643 """Get numa node on which are located most of the interfaces.
644
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800645 Return numa node with highest count of interfaces provided as
646 arguments.
647 Return 0 if the interface does not have numa_node information
648 available.
John DeNisco68b0ee32017-09-27 16:35:23 -0400649 If all interfaces have unknown location (-1), then return 0.
650 If most of interfaces have unknown location (-1), but there are
651 some interfaces with known location, then return the second most
652 location of the provided interfaces.
653
654 :param node: Node from DICT__nodes.
655 :param iface_keys: Interface keys for lookup.
656 :type node: dict
657 :type iface_keys: strings
658 """
659 numa_list = []
660 for if_key in iface_keys:
661 try:
662 numa_list.append(node['interfaces'][if_key].get('numa_node'))
663 except KeyError:
664 pass
665
666 numa_cnt_mc = Counter(numa_list).most_common()
667 numa_cnt_mc_len = len(numa_cnt_mc)
668 if numa_cnt_mc_len > 0 and numa_cnt_mc[0][0] != -1:
669 return numa_cnt_mc[0][0]
670 elif numa_cnt_mc_len > 1 and numa_cnt_mc[0][0] == -1:
671 return numa_cnt_mc[1][0]
672
673 return 0
674
675 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400676 def restart(node):
677 """
678
679 Starts vpp for a given node
680
681 :param node: VPP node.
682 :type node: dict
683 """
684
685 cmd = 'service vpp restart'
686 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
687 if ret != 0:
688 raise RuntimeError('{} failed on node {} {} {}'.
689 format(cmd, node['host'],
690 stdout, stderr))
691
692 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400693 def start(node):
694 """
695
696 Starts vpp for a given node
697
698 :param node: VPP node.
699 :type node: dict
700 """
701
702 cmd = 'service vpp start'
703 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
704 if ret != 0:
705 raise RuntimeError('{} failed on node {} {} {}'.
706 format(cmd, node['host'],
707 stdout, stderr))
708
709 @staticmethod
710 def stop(node):
711 """
712
713 Stops vpp for a given node
714
715 :param node: VPP node.
716 :type node: dict
717 """
718
719 cmd = 'service vpp stop'
720 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
721 if ret != 0:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800722 logging.debug('{} failed on node {} {} {}'.
723 format(cmd, node['host'],
724 stdout, stderr))
John DeNisco68b0ee32017-09-27 16:35:23 -0400725
John DeNiscoa7da67f2018-01-26 14:55:33 -0500726 # noinspection RegExpRedundantEscape
John DeNisco68b0ee32017-09-27 16:35:23 -0400727 @staticmethod
728 def status(node):
729 """
730
731 Gets VPP status
732
733 :param: node
734 :type node: dict
735 :returns: status, errors
736 :rtype: tuple(str, list)
737 """
738 errors = []
739 vutil = VPPUtil()
740 pkgs = vutil.get_installed_vpp_pkgs()
741 if len(pkgs) == 0:
742 return "Not Installed", errors
743
744 cmd = 'service vpp status'
745 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
746
747 # Get the active status
748 state = re.findall(r'Active:[\w (\)]+', stdout)[0].split(' ')
749 if len(state) > 2:
750 statestr = "{} {}".format(state[1], state[2])
751 else:
752 statestr = "Invalid"
753
754 # For now we won't look for DPDK errors
755 # lines = stdout.split('\n')
756 # for line in lines:
757 # if 'EAL' in line or \
758 # 'FAILURE' in line or \
759 # 'failed' in line or \
760 # 'Failed' in line:
761 # errors.append(line.lstrip(' '))
762
763 return statestr, errors
764
765 @staticmethod
766 def get_linux_distro():
767 """
768 Get the linux distribution and check if it is supported
769
770 :returns: linux distro, None if the distro is not supported
771 :rtype: list
772 """
773
774 distro = platform.linux_distribution()
775 if distro[0] == 'Ubuntu' or \
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800776 distro[0] == 'CentOS Linux' or \
777 distro[:7] == 'Red Hat':
John DeNisco68b0ee32017-09-27 16:35:23 -0400778 return distro
779 else:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800780 raise RuntimeError(
781 'Linux Distribution {} is not supported'.format(distro[0]))
John DeNisco68b0ee32017-09-27 16:35:23 -0400782
783 @staticmethod
784 def version():
785 """
786
787 Gets VPP Version information
788
789 :returns: version
790 :rtype: dict
791 """
792
793 version = {}
794 cmd = 'vppctl show version verbose'
795 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
796 if ret != 0:
797 return version
798
799 lines = stdout.split('\n')
800 if len(lines[0]) is not 0:
801 if lines[0].split(' ')[0] == 'FileNotFoundError':
802 return version
803
804 for line in lines:
805 if len(line) is 0:
806 continue
807 dct = line.split(':')
808 version[dct[0]] = dct[1].lstrip(' ')
809
810 return version
John DeNiscoc6b2a202017-11-01 12:37:47 -0400811
812 @staticmethod
813 def show_bridge(node):
814 """
815 Shows the current bridge configuration
816
817 :param node: VPP node.
818 :type node: dict
John DeNisco9fa5cf42018-02-06 15:23:05 -0500819 :returns: A list of interfaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400820 """
821
John DeNisco9fa5cf42018-02-06 15:23:05 -0500822 ifaces = []
John DeNiscoc6b2a202017-11-01 12:37:47 -0400823 cmd = 'vppctl show bridge'
824 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
825 if ret != 0:
826 raise RuntimeError('{} failed on node {} {} {}'.
827 format(cmd, node['host'],
828 stdout, stderr))
829 lines = stdout.split('\r\n')
830 bridges = []
831 for line in lines:
832 if line == 'no bridge-domains in use':
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800833 print (line)
John DeNisco9fa5cf42018-02-06 15:23:05 -0500834 return ifaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400835 if len(line) == 0:
836 continue
837
838 lspl = line.lstrip(' ').split()
839 if lspl[0] != 'BD-ID':
840 bridges.append(lspl[0])
841
842 for bridge in bridges:
843 cmd = 'vppctl show bridge {} detail'.format(bridge)
844 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
845 if ret != 0:
846 raise RuntimeError('{} failed on node {} {} {}'.
847 format(cmd, node['host'],
848 stdout, stderr))
John DeNisco9fa5cf42018-02-06 15:23:05 -0500849
850 lines = stdout.split('\r\n')
851 for line in lines:
852 iface = re.findall(r'[a-zA-z]+\d+/\d+/\d+', line)
853 if len(iface):
jdeniscob0b9dad2018-12-18 15:29:45 -0500854 ifcidx = {'name': iface[0], 'index': line.split()[1]}
John DeNisco9fa5cf42018-02-06 15:23:05 -0500855 ifaces.append(ifcidx)
856
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800857 print (stdout)
John DeNisco4dc83972018-03-30 10:50:19 -0400858 return ifaces