blob: 336097d6e0a5f56ca848070449e937c3b69ad7e0 [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
14"""VPP util library"""
15import logging
16import re
17import subprocess
18import platform
jdenisco24010fb2018-11-13 12:40:12 -050019import requests
John DeNisco68b0ee32017-09-27 16:35:23 -040020
21from collections import Counter
22
23# VPP_VERSION = '1707'
John DeNiscoa7da67f2018-01-26 14:55:33 -050024# VPP_VERSION = '1710'
jdenisco24010fb2018-11-13 12:40:12 -050025VPP_VERSION = '1810'
John DeNisco68b0ee32017-09-27 16:35:23 -040026
27
28class VPPUtil(object):
29 """General class for any VPP related methods/functions."""
30
31 @staticmethod
32 def exec_command(cmd, timeout=None):
33 """Execute a command on the local node.
34
35 :param cmd: Command to run locally.
36 :param timeout: Timeout value
37 :type cmd: str
38 :type timeout: int
39 :return return_code, stdout, stderr
40 :rtype: tuple(int, str, str)
41 """
42
43 logging.info(" Local Command: {}".format(cmd))
44 out = ''
45 err = ''
46 prc = subprocess.Popen(cmd, shell=True, bufsize=1,
47 stdin=subprocess.PIPE,
48 stdout=subprocess.PIPE,
49 stderr=subprocess.PIPE)
50
51 with prc.stdout:
52 for line in iter(prc.stdout.readline, b''):
53 logging.info(" {}".format(line.strip('\n')))
54 out += line
55
56 with prc.stderr:
57 for line in iter(prc.stderr.readline, b''):
58 logging.warn(" {}".format(line.strip('\n')))
59 err += line
60
61 ret = prc.wait()
62
63 return ret, out, err
64
65 def _autoconfig_backup_file(self, filename):
66 """
67 Create a backup file.
68
69 :param filename: The file to backup
70 :type filename: str
71 """
72
73 # Does a copy of the file exist, if not create one
74 ofile = filename + '.orig'
75 (ret, stdout, stderr) = self.exec_command('ls {}'.format(ofile))
76 if ret != 0:
77 logging.debug(stderr)
78 if stdout.strip('\n') != ofile:
79 cmd = 'sudo cp {} {}'.format(filename, ofile)
80 (ret, stdout, stderr) = self.exec_command(cmd)
81 if ret != 0:
82 logging.debug(stderr)
83
84 def _install_vpp_pkg_ubuntu(self, node, pkg):
85 """
86 Install the VPP packages
87
88 :param node: Node dictionary
89 :param pkg: The vpp packages
90 :type node: dict
91 :type pkg: string
92 """
93
94 cmd = 'apt-get -y install {}'.format(pkg)
95 (ret, stdout, stderr) = self.exec_command(cmd)
96 if ret != 0:
97 raise RuntimeError('{} failed on node {} {} {}'.format(
98 cmd, node['host'], stdout, stderr))
99
100 def _install_vpp_pkg_centos(self, node, pkg):
101 """
102 Install the VPP packages
103
104 :param node: Node dictionary
105 :param pkg: The vpp packages
106 :type node: dict
107 :type pkg: string
108 """
109
110 cmd = 'yum -y install {}'.format(pkg)
111 (ret, stdout, stderr) = self.exec_command(cmd)
112 if ret != 0:
113 raise RuntimeError('{} failed on node {} {} {}'.format(
114 cmd, node['host'], stdout, stderr))
115
116 def _install_vpp_ubuntu(self, node, fdio_release=VPP_VERSION,
117 ubuntu_version='xenial'):
118 """
119 Install the VPP packages
120
121 :param node: Node dictionary with cpuinfo.
122 :param fdio_release: VPP release number
123 :param ubuntu_version: Ubuntu Version
124 :type node: dict
125 :type fdio_release: string
126 :type ubuntu_version: string
127 """
128
129 # Modify the sources list
130 sfile = '/etc/apt/sources.list.d/99fd.io.list'
131
132 # Backup the sources list
133 self._autoconfig_backup_file(sfile)
134
jdenisco24010fb2018-11-13 12:40:12 -0500135 reps = 'deb [trusted=yes] https://packagecloud.io/fdio/'
John DeNiscoc6b2a202017-11-01 12:37:47 -0400136 # When using a stable branch
jdenisco24010fb2018-11-13 12:40:12 -0500137 # reps += '{}/ubuntu {} main ./\n'.format(fdio_release, ubuntu_version)
John DeNiscoa7da67f2018-01-26 14:55:33 -0500138 # When using release
jdenisco24010fb2018-11-13 12:40:12 -0500139 reps += 'release/ubuntu {} main ./\n'.format(ubuntu_version)
John DeNisco4dc83972018-03-30 10:50:19 -0400140 # When using master
jdenisco24010fb2018-11-13 12:40:12 -0500141 # reps += 'master/ubuntu {} main/ ./\n'.format(ubuntu_version)
John DeNisco68b0ee32017-09-27 16:35:23 -0400142
jdenisco24010fb2018-11-13 12:40:12 -0500143 with open(sfile, 'w') as sfd:
144 sfd.write(reps)
145 sfd.close()
146
147 # Add the key
148 key = requests.get('https://packagecloud.io/fdio/{}/gpgkey'.format('release'))
149 # cmd = 'curl -L https://packagecloud.io/fdio/{}/gpgkey | apt-key add -'.format(fdio_release)
150 # cmd = 'curl -L https://packagecloud.io/fdio/{}/gpgkey | apt-key add -'.format('mastert')
151 cmd = 'echo "{}" | apt-key add -'.format(key.content)
John DeNisco68b0ee32017-09-27 16:35:23 -0400152 (ret, stdout, stderr) = self.exec_command(cmd)
153 if ret != 0:
154 raise RuntimeError('{} failed on node {} {}'.format(
155 cmd,
156 node['host'],
157 stderr))
158
159 # Install the package
160 cmd = 'apt-get -y update'
161 (ret, stdout, stderr) = self.exec_command(cmd)
162 if ret != 0:
163 raise RuntimeError('{} apt-get update failed on node {} {}'.format(
164 cmd,
165 node['host'],
166 stderr))
167
168 self._install_vpp_pkg_ubuntu(node, 'vpp-lib')
169 self._install_vpp_pkg_ubuntu(node, 'vpp')
170 self._install_vpp_pkg_ubuntu(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400171 self._install_vpp_pkg_ubuntu(node, 'vpp-api-python')
172 self._install_vpp_pkg_ubuntu(node, 'vpp-api-java')
173 self._install_vpp_pkg_ubuntu(node, 'vpp-api-lua')
174 self._install_vpp_pkg_ubuntu(node, 'vpp-dev')
175 self._install_vpp_pkg_ubuntu(node, 'vpp-dbg')
176
177 def _install_vpp_centos(self, node, fdio_release=VPP_VERSION,
178 centos_version='centos7'):
179 """
180 Install the VPP packages
181
182 :param node: Node dictionary with cpuinfo.
183 :param fdio_release: VPP release number
184 :param centos_version: Ubuntu Version
185 :type node: dict
186 :type fdio_release: string
187 :type centos_version: string
188 """
189
jdenisco24010fb2018-11-13 12:40:12 -0500190 # Be sure the correct system packages are installed
191 cmd = 'yum -y update'
192 (ret, stdout, stderr) = self.exec_command(cmd)
193 if ret != 0:
194 logging.debug('{} failed on node {} {}'.format(
195 cmd,
196 node['host'],
197 stderr))
198
199 cmd = 'yum -y install pygpgme yum-utils'
200 (ret, stdout, stderr) = self.exec_command(cmd)
201 if ret != 0:
202 logging.debug('{} failed on node {} {}'.format(
203 cmd,
204 node['host'],
205 stderr))
206
John DeNisco68b0ee32017-09-27 16:35:23 -0400207 # Modify the sources list
208 sfile = '/etc/yum.repos.d/fdio-release.repo'
209
210 # Backup the sources list
211 self._autoconfig_backup_file(sfile)
212
213 # Remove the current file
214 cmd = 'rm {}'.format(sfile)
215 (ret, stdout, stderr) = self.exec_command(cmd)
216 if ret != 0:
217 logging.debug('{} failed on node {} {}'.format(
218 cmd,
219 node['host'],
220 stderr))
221
jdenisco24010fb2018-11-13 12:40:12 -0500222 # Set the branch
223 bname = 'release'
224 # bname = '1810'
225 # bname = 'master'
John DeNisco68b0ee32017-09-27 16:35:23 -0400226
jdenisco24010fb2018-11-13 12:40:12 -0500227 # Get the file contents
228 reps = '[fdio_{}]\n'.format(bname)
229 reps += 'name=fdio_{}\n'.format(bname)
230 reps += 'baseurl=https://packagecloud.io/fdio/{}/el/7/$basearch\n'.format(bname)
231 reps += 'repo_gpgcheck=1\n'
232 reps += 'gpgcheck=0\n'
233 reps += 'enabled=1\n'
234 reps += 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey\n'.format(bname)
235 reps += 'sslverify=1\n'
236 reps += 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt\n'
237 reps += 'metadata_expire=300\n'
238 reps += '\n'
239 reps += '[fdio_{}-source]\n'.format(bname)
240 reps += 'name=fdio_release-{}\n'.format(bname)
241 reps += 'baseurl=https://packagecloud.io/fdio/{}/el/7/SRPMS\n'.format(bname)
242 reps += 'repo_gpgcheck=1\n'
243 reps += 'gpgcheck=0\n'
244 reps += 'enabled=1\n'
245 reps += 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey\n'.format(bname)
246 reps += 'sslverify =1\n'
247 reps += 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt\n'
248 reps += 'metadata_expire=300\n'
249
250 with open(sfile, 'w') as sfd:
251 sfd.write(reps)
252 sfd.close()
253
254 # Update the fdio repo
255 cmd = 'yum clean all'
John DeNisco68b0ee32017-09-27 16:35:23 -0400256 (ret, stdout, stderr) = self.exec_command(cmd)
257 if ret != 0:
jdenisco24010fb2018-11-13 12:40:12 -0500258 logging.debug('{} failed on node {} {}'.format(
259 cmd,
260 node['host'],
261 stderr))
262
263 cmd = "yum -q makecache -y --disablerepo='*' --enablerepo='fdio_{}'".format(bname)
264 (ret, stdout, stderr) = self.exec_command(cmd)
265 if ret != 0:
266 logging.debug('{} failed on node {} {}'.format(
John DeNisco68b0ee32017-09-27 16:35:23 -0400267 cmd,
268 node['host'],
269 stderr))
270
271 # Install the packages
jdenisco24010fb2018-11-13 12:40:12 -0500272 self._install_vpp_pkg_centos(node, 'vpp-selinux-policy')
John DeNisco68b0ee32017-09-27 16:35:23 -0400273 self._install_vpp_pkg_centos(node, 'vpp-lib')
274 self._install_vpp_pkg_centos(node, 'vpp')
275 self._install_vpp_pkg_centos(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400276 self._install_vpp_pkg_centos(node, 'vpp-api-python')
277 self._install_vpp_pkg_centos(node, 'vpp-api-java')
278 self._install_vpp_pkg_centos(node, 'vpp-api-lua')
279 self._install_vpp_pkg_centos(node, 'vpp-devel')
jdeniscob9875092018-11-06 16:10:04 -0500280 self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
John DeNisco68b0ee32017-09-27 16:35:23 -0400281
282 def install_vpp(self, node):
283 """
284 Install the VPP packages
285
286 :param node: Node dictionary with cpuinfo.
287 :type node: dict
288 """
289 distro = self.get_linux_distro()
John DeNisco4dc83972018-03-30 10:50:19 -0400290 logging.info(" {}".format(distro[0]))
John DeNisco68b0ee32017-09-27 16:35:23 -0400291 if distro[0] == 'Ubuntu':
John DeNisco4dc83972018-03-30 10:50:19 -0400292 logging.info("Install Ubuntu")
John DeNisco68b0ee32017-09-27 16:35:23 -0400293 self._install_vpp_ubuntu(node)
294 elif distro[0] == 'CentOS Linux':
295 logging.info("Install CentOS")
296 self._install_vpp_centos(node)
297 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400298 logging.info("Install CentOS (default)")
299 self._install_vpp_centos(node)
300 return
John DeNisco68b0ee32017-09-27 16:35:23 -0400301
302 def _uninstall_vpp_pkg_ubuntu(self, node, pkg):
303 """
304 Uninstall the VPP packages
305
306 :param node: Node dictionary
307 :param pkg: The vpp packages
308 :type node: dict
309 :type pkg: string
310 """
311 cmd = 'dpkg --purge {}'.format(pkg)
312 (ret, stdout, stderr) = self.exec_command(cmd)
313 if ret != 0:
314 raise RuntimeError('{} failed on node {} {} {}'.format(
315 cmd, node['host'], stdout, stderr))
316
317 def _uninstall_vpp_pkg_centos(self, node, pkg):
318 """
319 Uninstall the VPP packages
320
321 :param node: Node dictionary
322 :param pkg: The vpp packages
323 :type node: dict
324 :type pkg: string
325 """
326 cmd = 'yum -y remove {}'.format(pkg)
327 (ret, stdout, stderr) = self.exec_command(cmd)
328 if ret != 0:
329 raise RuntimeError('{} failed on node {} {} {}'.format(
330 cmd, node['host'], stdout, stderr))
331
332 def _uninstall_vpp_ubuntu(self, node):
333 """
334 Uninstall the VPP packages
335
336 :param node: Node dictionary with cpuinfo.
337 :type node: dict
338 """
339 pkgs = self.get_installed_vpp_pkgs()
340
341 if len(pkgs) > 0:
342 if 'version' in pkgs[0]:
343 logging.info("Uninstall Ubuntu Packages")
jdenisco24010fb2018-11-13 12:40:12 -0500344 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dbg')
345 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dev')
John DeNisco68b0ee32017-09-27 16:35:23 -0400346 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-python')
347 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-java')
348 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-lua')
349 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400350 self._uninstall_vpp_pkg_ubuntu(node, 'vpp')
351 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-lib')
352 else:
353 logging.info("Uninstall locally installed Ubuntu Packages")
354 for pkg in pkgs:
355 self._uninstall_vpp_pkg_ubuntu(node, pkg['name'])
356 else:
357 logging.error("There are no Ubuntu packages installed")
358
359 def _uninstall_vpp_centos(self, node):
360 """
361 Uninstall the VPP packages
362
363 :param node: Node dictionary with cpuinfo.
364 :type node: dict
365 """
366
367 pkgs = self.get_installed_vpp_pkgs()
368
369 if len(pkgs) > 0:
370 if 'version' in pkgs[0]:
371 logging.info("Uninstall CentOS Packages")
jdenisco24010fb2018-11-13 12:40:12 -0500372 self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
373 self._uninstall_vpp_pkg_centos(node, 'vpp-devel')
John DeNisco68b0ee32017-09-27 16:35:23 -0400374 self._uninstall_vpp_pkg_centos(node, 'vpp-api-python')
375 self._uninstall_vpp_pkg_centos(node, 'vpp-api-java')
376 self._uninstall_vpp_pkg_centos(node, 'vpp-api-lua')
377 self._uninstall_vpp_pkg_centos(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400378 self._uninstall_vpp_pkg_centos(node, 'vpp')
379 self._uninstall_vpp_pkg_centos(node, 'vpp-lib')
jdenisco24010fb2018-11-13 12:40:12 -0500380 self._uninstall_vpp_pkg_centos(node, 'vpp-selinux-policy')
John DeNisco68b0ee32017-09-27 16:35:23 -0400381 else:
382 logging.info("Uninstall locally installed CentOS Packages")
383 for pkg in pkgs:
384 self._uninstall_vpp_pkg_centos(node, pkg['name'])
385 else:
386 logging.error("There are no CentOS packages installed")
387
388 def uninstall_vpp(self, node):
389 """
390 Uninstall the VPP packages
391
392 :param node: Node dictionary with cpuinfo.
393 :type node: dict
394 """
John DeNiscoc6b2a202017-11-01 12:37:47 -0400395
396 # First stop VPP
397 self.stop(node)
398
John DeNisco68b0ee32017-09-27 16:35:23 -0400399 distro = self.get_linux_distro()
400 if distro[0] == 'Ubuntu':
John DeNisco4dc83972018-03-30 10:50:19 -0400401 logging.info("Uninstall Ubuntu")
John DeNisco68b0ee32017-09-27 16:35:23 -0400402 self._uninstall_vpp_ubuntu(node)
403 elif distro[0] == 'CentOS Linux':
404 logging.info("Uninstall CentOS")
405 self._uninstall_vpp_centos(node)
406 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400407 logging.info("Uninstall CentOS (Default)")
408 self._uninstall_vpp_centos(node)
John DeNisco68b0ee32017-09-27 16:35:23 -0400409 return
410
411 def show_vpp_settings(self, *additional_cmds):
412 """
413 Print default VPP settings. In case others are needed, can be
414 accepted as next parameters (each setting one parameter), preferably
415 in form of a string.
416
417 :param additional_cmds: Additional commands that the vpp should print
418 settings for.
419 :type additional_cmds: tuple
420 """
421 def_setting_tb_displayed = {
422 'IPv6 FIB': 'ip6 fib',
423 'IPv4 FIB': 'ip fib',
424 'Interface IP': 'int addr',
425 'Interfaces': 'int',
426 'ARP': 'ip arp',
427 'Errors': 'err'
428 }
429
430 if additional_cmds:
431 for cmd in additional_cmds:
432 def_setting_tb_displayed['Custom Setting: {}'.format(cmd)] \
433 = cmd
434
435 for _, value in def_setting_tb_displayed.items():
436 self.exec_command('vppctl sh {}'.format(value))
437
438 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400439 def get_vms(node):
440 """
441 Get a list of VMs that are connected to VPP interfaces
442
443 :param node: VPP node.
444 :type node: dict
445 :returns: Dictionary containing a list of VMs and the interfaces that are connected to VPP
446 :rtype: dictionary
447 """
448
449 vmdict = {}
450
451 print "Need to implement get vms"
452
453 return vmdict
454
455 @staticmethod
John DeNiscoa3db0782017-10-17 11:07:22 -0400456 def get_int_ip(node):
457 """
458 Get the VPP interfaces and IP addresses
459
460 :param node: VPP node.
461 :type node: dict
462 :returns: Dictionary containing VPP interfaces and IP addresses
463 :rtype: dictionary
464 """
465 interfaces = {}
466 cmd = 'vppctl show int addr'
467 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
468 if ret != 0:
469 return interfaces
470
471 lines = stdout.split('\n')
472 if len(lines[0]) is not 0:
473 if lines[0].split(' ')[0] == 'FileNotFoundError':
474 return interfaces
475
John DeNiscoc6b2a202017-11-01 12:37:47 -0400476 name = ''
John DeNiscoa3db0782017-10-17 11:07:22 -0400477 for line in lines:
478 if len(line) is 0:
479 continue
480
481 # If the first character is not whitespace
482 # create a new interface
483 if len(re.findall(r'\s', line[0])) is 0:
484 spl = line.split()
485 name = spl[0]
486 if name == 'local0':
487 continue
488 interfaces[name] = {}
489 interfaces[name]['state'] = spl[1].lstrip('(').rstrip('):\r')
490 else:
491 interfaces[name]['address'] = line.lstrip(' ').rstrip('\r')
492
493 return interfaces
494
495 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400496 def get_hardware(node):
497 """
498 Get the VPP hardware information and return it in a
499 dictionary
500
501 :param node: VPP node.
502 :type node: dict
John DeNiscoa3db0782017-10-17 11:07:22 -0400503 :returns: Dictionary containing VPP hardware information
John DeNisco68b0ee32017-09-27 16:35:23 -0400504 :rtype: dictionary
505 """
506
507 interfaces = {}
508 cmd = 'vppctl show hard'
509 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
510 if ret != 0:
511 return interfaces
512
513 lines = stdout.split('\n')
514 if len(lines[0]) is not 0:
515 if lines[0].split(' ')[0] == 'FileNotFoundError':
516 return interfaces
517
518 for line in lines:
519 if len(line) is 0:
520 continue
521
522 # If the first character is not whitespace
523 # create a new interface
524 if len(re.findall(r'\s', line[0])) is 0:
525 spl = line.split()
526 name = spl[0]
527 interfaces[name] = {}
528 interfaces[name]['index'] = spl[1]
529 interfaces[name]['state'] = spl[2]
530
531 # Ethernet address
532 rfall = re.findall(r'Ethernet address', line)
533 if rfall:
534 spl = line.split()
535 interfaces[name]['mac'] = spl[2]
536
537 # Carrier
538 rfall = re.findall(r'carrier', line)
539 if rfall:
540 spl = line.split('carrier ')
541 interfaces[name]['carrier'] = spl[1]
542
543 # Socket
544 rfall = re.findall(r'cpu socket', line)
545 if rfall:
546 spl = line.split('cpu socket ')
547 interfaces[name]['cpu socket'] = spl[1]
548
549 # Queues and Descriptors
550 rfall = re.findall(r'rx queues', line)
551 if rfall:
552 spl = line.split(',')
553 interfaces[name]['rx queues'] = spl[0].lstrip(' ').split(' ')[2]
554 interfaces[name]['rx descs'] = spl[1].split(' ')[3]
555 interfaces[name]['tx queues'] = spl[2].split(' ')[3]
556 interfaces[name]['tx descs'] = spl[3].split(' ')[3]
557
558 return interfaces
559
560 def _get_installed_vpp_pkgs_ubuntu(self):
561 """
562 Get the VPP hardware information and return it in a
563 dictionary
564
565 :returns: List of the packages installed
566 :rtype: list
567 """
568
569 pkgs = []
570 cmd = 'dpkg -l | grep vpp'
571 (ret, stdout, stderr) = self.exec_command(cmd)
572 if ret != 0:
573 return pkgs
574
575 lines = stdout.split('\n')
576 for line in lines:
577 items = line.split()
578 if len(items) < 2:
579 continue
580 pkg = {'name': items[1], 'version': items[2]}
581 pkgs.append(pkg)
582
583 return pkgs
584
585 def _get_installed_vpp_pkgs_centos(self):
586 """
587 Get the VPP hardware information and return it in a
588 dictionary
589
590 :returns: List of the packages installed
591 :rtype: list
592 """
593
594 pkgs = []
595 cmd = 'rpm -qa | grep vpp'
596 (ret, stdout, stderr) = self.exec_command(cmd)
597 if ret != 0:
598 return pkgs
599
600 lines = stdout.split('\n')
601 for line in lines:
602 if len(line) == 0:
603 continue
604
605 items = line.split()
606 if len(items) < 2:
607 pkg = {'name': items[0]}
608 else:
609 pkg = {'name': items[1], 'version': items[2]}
610
611 pkgs.append(pkg)
612
613 return pkgs
614
615 def get_installed_vpp_pkgs(self):
616 """
617 Get the VPP hardware information and return it in a
618 dictionary
619
620 :returns: List of the packages installed
621 :rtype: list
622 """
623
624 distro = self.get_linux_distro()
625 if distro[0] == 'Ubuntu':
626 pkgs = self._get_installed_vpp_pkgs_ubuntu()
627 elif distro[0] == 'CentOS Linux':
628 pkgs = self._get_installed_vpp_pkgs_centos()
629 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400630 pkgs = self._get_installed_vpp_pkgs_centos()
John DeNisco68b0ee32017-09-27 16:35:23 -0400631 return []
632
633 return pkgs
634
635 @staticmethod
636 def get_interfaces_numa_node(node, *iface_keys):
637 """Get numa node on which are located most of the interfaces.
638
639 Return numa node with highest count of interfaces provided as arguments.
640 Return 0 if the interface does not have numa_node information available.
641 If all interfaces have unknown location (-1), then return 0.
642 If most of interfaces have unknown location (-1), but there are
643 some interfaces with known location, then return the second most
644 location of the provided interfaces.
645
646 :param node: Node from DICT__nodes.
647 :param iface_keys: Interface keys for lookup.
648 :type node: dict
649 :type iface_keys: strings
650 """
651 numa_list = []
652 for if_key in iface_keys:
653 try:
654 numa_list.append(node['interfaces'][if_key].get('numa_node'))
655 except KeyError:
656 pass
657
658 numa_cnt_mc = Counter(numa_list).most_common()
659 numa_cnt_mc_len = len(numa_cnt_mc)
660 if numa_cnt_mc_len > 0 and numa_cnt_mc[0][0] != -1:
661 return numa_cnt_mc[0][0]
662 elif numa_cnt_mc_len > 1 and numa_cnt_mc[0][0] == -1:
663 return numa_cnt_mc[1][0]
664
665 return 0
666
667 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400668 def restart(node):
669 """
670
671 Starts vpp for a given node
672
673 :param node: VPP node.
674 :type node: dict
675 """
676
677 cmd = 'service vpp restart'
678 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
679 if ret != 0:
680 raise RuntimeError('{} failed on node {} {} {}'.
681 format(cmd, node['host'],
682 stdout, stderr))
683
684 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400685 def start(node):
686 """
687
688 Starts vpp for a given node
689
690 :param node: VPP node.
691 :type node: dict
692 """
693
694 cmd = 'service vpp start'
695 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
696 if ret != 0:
697 raise RuntimeError('{} failed on node {} {} {}'.
698 format(cmd, node['host'],
699 stdout, stderr))
700
701 @staticmethod
702 def stop(node):
703 """
704
705 Stops vpp for a given node
706
707 :param node: VPP node.
708 :type node: dict
709 """
710
711 cmd = 'service vpp stop'
712 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
713 if ret != 0:
jdenisco24010fb2018-11-13 12:40:12 -0500714 logging.debug('{} failed on node {} {} {}'.
John DeNisco68b0ee32017-09-27 16:35:23 -0400715 format(cmd, node['host'],
716 stdout, stderr))
717
John DeNiscoa7da67f2018-01-26 14:55:33 -0500718 # noinspection RegExpRedundantEscape
John DeNisco68b0ee32017-09-27 16:35:23 -0400719 @staticmethod
720 def status(node):
721 """
722
723 Gets VPP status
724
725 :param: node
726 :type node: dict
727 :returns: status, errors
728 :rtype: tuple(str, list)
729 """
730 errors = []
731 vutil = VPPUtil()
732 pkgs = vutil.get_installed_vpp_pkgs()
733 if len(pkgs) == 0:
734 return "Not Installed", errors
735
736 cmd = 'service vpp status'
737 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
738
739 # Get the active status
740 state = re.findall(r'Active:[\w (\)]+', stdout)[0].split(' ')
741 if len(state) > 2:
742 statestr = "{} {}".format(state[1], state[2])
743 else:
744 statestr = "Invalid"
745
746 # For now we won't look for DPDK errors
747 # lines = stdout.split('\n')
748 # for line in lines:
749 # if 'EAL' in line or \
750 # 'FAILURE' in line or \
751 # 'failed' in line or \
752 # 'Failed' in line:
753 # errors.append(line.lstrip(' '))
754
755 return statestr, errors
756
757 @staticmethod
758 def get_linux_distro():
759 """
760 Get the linux distribution and check if it is supported
761
762 :returns: linux distro, None if the distro is not supported
763 :rtype: list
764 """
765
766 distro = platform.linux_distribution()
767 if distro[0] == 'Ubuntu' or \
768 distro[0] == 'CentOS Linux' or \
John DeNisco4dc83972018-03-30 10:50:19 -0400769 distro[:7] == 'Red Hat':
John DeNisco68b0ee32017-09-27 16:35:23 -0400770 return distro
771 else:
772 raise RuntimeError('Linux Distribution {} is not supported'.format(distro[0]))
773
774 @staticmethod
775 def version():
776 """
777
778 Gets VPP Version information
779
780 :returns: version
781 :rtype: dict
782 """
783
784 version = {}
785 cmd = 'vppctl show version verbose'
786 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
787 if ret != 0:
788 return version
789
790 lines = stdout.split('\n')
791 if len(lines[0]) is not 0:
792 if lines[0].split(' ')[0] == 'FileNotFoundError':
793 return version
794
795 for line in lines:
796 if len(line) is 0:
797 continue
798 dct = line.split(':')
799 version[dct[0]] = dct[1].lstrip(' ')
800
801 return version
John DeNiscoc6b2a202017-11-01 12:37:47 -0400802
803 @staticmethod
804 def show_bridge(node):
805 """
806 Shows the current bridge configuration
807
808 :param node: VPP node.
809 :type node: dict
John DeNisco9fa5cf42018-02-06 15:23:05 -0500810 :returns: A list of interfaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400811 """
812
John DeNisco9fa5cf42018-02-06 15:23:05 -0500813 ifaces = []
John DeNiscoc6b2a202017-11-01 12:37:47 -0400814 cmd = 'vppctl show bridge'
815 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
816 if ret != 0:
817 raise RuntimeError('{} failed on node {} {} {}'.
818 format(cmd, node['host'],
819 stdout, stderr))
820 lines = stdout.split('\r\n')
821 bridges = []
822 for line in lines:
823 if line == 'no bridge-domains in use':
824 print line
John DeNisco9fa5cf42018-02-06 15:23:05 -0500825 return ifaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400826 if len(line) == 0:
827 continue
828
829 lspl = line.lstrip(' ').split()
830 if lspl[0] != 'BD-ID':
831 bridges.append(lspl[0])
832
833 for bridge in bridges:
834 cmd = 'vppctl show bridge {} detail'.format(bridge)
835 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
836 if ret != 0:
837 raise RuntimeError('{} failed on node {} {} {}'.
838 format(cmd, node['host'],
839 stdout, stderr))
John DeNisco9fa5cf42018-02-06 15:23:05 -0500840
841 lines = stdout.split('\r\n')
842 for line in lines:
843 iface = re.findall(r'[a-zA-z]+\d+/\d+/\d+', line)
844 if len(iface):
845 ifcidx ={'name': iface[0], 'index': line.split()[1] }
846 ifaces.append(ifcidx)
847
848 print stdout
John DeNisco4dc83972018-03-30 10:50:19 -0400849 return ifaces