blob: 89e2d74fc5da9b31a4d011d53458172537a8203b [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
jdenisco7c37a672018-11-20 11:25:17 -0500141 # reps += 'master/ubuntu {} main ./\n'.format(ubuntu_version)
142 # When using 1807
143 # reps += '1807/ubuntu {} main ./\n'.format(ubuntu_version)
John DeNisco68b0ee32017-09-27 16:35:23 -0400144
jdenisco24010fb2018-11-13 12:40:12 -0500145 with open(sfile, 'w') as sfd:
146 sfd.write(reps)
147 sfd.close()
148
149 # Add the key
150 key = requests.get('https://packagecloud.io/fdio/{}/gpgkey'.format('release'))
jdenisco7c37a672018-11-20 11:25:17 -0500151 # key = requests.get('https://packagecloud.io/fdio/{}/gpgkey'.format('master'))
152 # key = requests.get('https://packagecloud.io/fdio/{}/gpgkey'.format('1807'))
jdenisco24010fb2018-11-13 12:40:12 -0500153 cmd = 'echo "{}" | apt-key add -'.format(key.content)
John DeNisco68b0ee32017-09-27 16:35:23 -0400154 (ret, stdout, stderr) = self.exec_command(cmd)
155 if ret != 0:
156 raise RuntimeError('{} failed on node {} {}'.format(
157 cmd,
158 node['host'],
159 stderr))
160
161 # Install the package
162 cmd = 'apt-get -y update'
163 (ret, stdout, stderr) = self.exec_command(cmd)
164 if ret != 0:
165 raise RuntimeError('{} apt-get update failed on node {} {}'.format(
166 cmd,
167 node['host'],
168 stderr))
169
170 self._install_vpp_pkg_ubuntu(node, 'vpp-lib')
171 self._install_vpp_pkg_ubuntu(node, 'vpp')
172 self._install_vpp_pkg_ubuntu(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400173 self._install_vpp_pkg_ubuntu(node, 'vpp-api-python')
174 self._install_vpp_pkg_ubuntu(node, 'vpp-api-java')
175 self._install_vpp_pkg_ubuntu(node, 'vpp-api-lua')
176 self._install_vpp_pkg_ubuntu(node, 'vpp-dev')
177 self._install_vpp_pkg_ubuntu(node, 'vpp-dbg')
178
179 def _install_vpp_centos(self, node, fdio_release=VPP_VERSION,
180 centos_version='centos7'):
181 """
182 Install the VPP packages
183
184 :param node: Node dictionary with cpuinfo.
185 :param fdio_release: VPP release number
186 :param centos_version: Ubuntu Version
187 :type node: dict
188 :type fdio_release: string
189 :type centos_version: string
190 """
191
jdenisco24010fb2018-11-13 12:40:12 -0500192 # Be sure the correct system packages are installed
193 cmd = 'yum -y update'
194 (ret, stdout, stderr) = self.exec_command(cmd)
195 if ret != 0:
196 logging.debug('{} failed on node {} {}'.format(
197 cmd,
198 node['host'],
199 stderr))
200
201 cmd = 'yum -y install pygpgme yum-utils'
202 (ret, stdout, stderr) = self.exec_command(cmd)
203 if ret != 0:
204 logging.debug('{} failed on node {} {}'.format(
205 cmd,
206 node['host'],
207 stderr))
208
John DeNisco68b0ee32017-09-27 16:35:23 -0400209 # Modify the sources list
210 sfile = '/etc/yum.repos.d/fdio-release.repo'
211
212 # Backup the sources list
213 self._autoconfig_backup_file(sfile)
214
215 # Remove the current file
216 cmd = 'rm {}'.format(sfile)
217 (ret, stdout, stderr) = self.exec_command(cmd)
218 if ret != 0:
219 logging.debug('{} failed on node {} {}'.format(
220 cmd,
221 node['host'],
222 stderr))
223
jdenisco24010fb2018-11-13 12:40:12 -0500224 # Set the branch
225 bname = 'release'
226 # bname = '1810'
227 # bname = 'master'
John DeNisco68b0ee32017-09-27 16:35:23 -0400228
jdenisco24010fb2018-11-13 12:40:12 -0500229 # Get the file contents
230 reps = '[fdio_{}]\n'.format(bname)
231 reps += 'name=fdio_{}\n'.format(bname)
232 reps += 'baseurl=https://packagecloud.io/fdio/{}/el/7/$basearch\n'.format(bname)
233 reps += 'repo_gpgcheck=1\n'
234 reps += 'gpgcheck=0\n'
235 reps += 'enabled=1\n'
236 reps += 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey\n'.format(bname)
237 reps += 'sslverify=1\n'
238 reps += 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt\n'
239 reps += 'metadata_expire=300\n'
240 reps += '\n'
241 reps += '[fdio_{}-source]\n'.format(bname)
242 reps += 'name=fdio_release-{}\n'.format(bname)
243 reps += 'baseurl=https://packagecloud.io/fdio/{}/el/7/SRPMS\n'.format(bname)
244 reps += 'repo_gpgcheck=1\n'
245 reps += 'gpgcheck=0\n'
246 reps += 'enabled=1\n'
247 reps += 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey\n'.format(bname)
248 reps += 'sslverify =1\n'
249 reps += 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt\n'
250 reps += 'metadata_expire=300\n'
251
252 with open(sfile, 'w') as sfd:
253 sfd.write(reps)
254 sfd.close()
255
256 # Update the fdio repo
257 cmd = 'yum clean all'
John DeNisco68b0ee32017-09-27 16:35:23 -0400258 (ret, stdout, stderr) = self.exec_command(cmd)
259 if ret != 0:
jdenisco24010fb2018-11-13 12:40:12 -0500260 logging.debug('{} failed on node {} {}'.format(
261 cmd,
262 node['host'],
263 stderr))
264
265 cmd = "yum -q makecache -y --disablerepo='*' --enablerepo='fdio_{}'".format(bname)
266 (ret, stdout, stderr) = self.exec_command(cmd)
267 if ret != 0:
268 logging.debug('{} failed on node {} {}'.format(
John DeNisco68b0ee32017-09-27 16:35:23 -0400269 cmd,
270 node['host'],
271 stderr))
272
273 # Install the packages
jdenisco24010fb2018-11-13 12:40:12 -0500274 self._install_vpp_pkg_centos(node, 'vpp-selinux-policy')
John DeNisco68b0ee32017-09-27 16:35:23 -0400275 self._install_vpp_pkg_centos(node, 'vpp-lib')
276 self._install_vpp_pkg_centos(node, 'vpp')
277 self._install_vpp_pkg_centos(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400278 self._install_vpp_pkg_centos(node, 'vpp-api-python')
279 self._install_vpp_pkg_centos(node, 'vpp-api-java')
280 self._install_vpp_pkg_centos(node, 'vpp-api-lua')
281 self._install_vpp_pkg_centos(node, 'vpp-devel')
jdeniscob9875092018-11-06 16:10:04 -0500282 self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
John DeNisco68b0ee32017-09-27 16:35:23 -0400283
284 def install_vpp(self, node):
285 """
286 Install the VPP packages
287
288 :param node: Node dictionary with cpuinfo.
289 :type node: dict
290 """
291 distro = self.get_linux_distro()
John DeNisco4dc83972018-03-30 10:50:19 -0400292 logging.info(" {}".format(distro[0]))
John DeNisco68b0ee32017-09-27 16:35:23 -0400293 if distro[0] == 'Ubuntu':
John DeNisco4dc83972018-03-30 10:50:19 -0400294 logging.info("Install Ubuntu")
John DeNisco68b0ee32017-09-27 16:35:23 -0400295 self._install_vpp_ubuntu(node)
296 elif distro[0] == 'CentOS Linux':
297 logging.info("Install CentOS")
298 self._install_vpp_centos(node)
299 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400300 logging.info("Install CentOS (default)")
301 self._install_vpp_centos(node)
302 return
John DeNisco68b0ee32017-09-27 16:35:23 -0400303
304 def _uninstall_vpp_pkg_ubuntu(self, node, pkg):
305 """
306 Uninstall the VPP packages
307
308 :param node: Node dictionary
309 :param pkg: The vpp packages
310 :type node: dict
311 :type pkg: string
312 """
313 cmd = 'dpkg --purge {}'.format(pkg)
314 (ret, stdout, stderr) = self.exec_command(cmd)
315 if ret != 0:
316 raise RuntimeError('{} failed on node {} {} {}'.format(
317 cmd, node['host'], stdout, stderr))
318
319 def _uninstall_vpp_pkg_centos(self, node, pkg):
320 """
321 Uninstall the VPP packages
322
323 :param node: Node dictionary
324 :param pkg: The vpp packages
325 :type node: dict
326 :type pkg: string
327 """
328 cmd = 'yum -y remove {}'.format(pkg)
329 (ret, stdout, stderr) = self.exec_command(cmd)
330 if ret != 0:
331 raise RuntimeError('{} failed on node {} {} {}'.format(
332 cmd, node['host'], stdout, stderr))
333
334 def _uninstall_vpp_ubuntu(self, node):
335 """
336 Uninstall the VPP packages
337
338 :param node: Node dictionary with cpuinfo.
339 :type node: dict
340 """
341 pkgs = self.get_installed_vpp_pkgs()
342
343 if len(pkgs) > 0:
344 if 'version' in pkgs[0]:
345 logging.info("Uninstall Ubuntu Packages")
jdenisco24010fb2018-11-13 12:40:12 -0500346 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dbg')
347 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dev')
John DeNisco68b0ee32017-09-27 16:35:23 -0400348 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-python')
349 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-java')
350 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-lua')
351 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400352 self._uninstall_vpp_pkg_ubuntu(node, 'vpp')
353 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-lib')
354 else:
355 logging.info("Uninstall locally installed Ubuntu Packages")
356 for pkg in pkgs:
357 self._uninstall_vpp_pkg_ubuntu(node, pkg['name'])
358 else:
359 logging.error("There are no Ubuntu packages installed")
360
361 def _uninstall_vpp_centos(self, node):
362 """
363 Uninstall the VPP packages
364
365 :param node: Node dictionary with cpuinfo.
366 :type node: dict
367 """
368
369 pkgs = self.get_installed_vpp_pkgs()
370
371 if len(pkgs) > 0:
372 if 'version' in pkgs[0]:
373 logging.info("Uninstall CentOS Packages")
jdenisco24010fb2018-11-13 12:40:12 -0500374 self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
375 self._uninstall_vpp_pkg_centos(node, 'vpp-devel')
John DeNisco68b0ee32017-09-27 16:35:23 -0400376 self._uninstall_vpp_pkg_centos(node, 'vpp-api-python')
377 self._uninstall_vpp_pkg_centos(node, 'vpp-api-java')
378 self._uninstall_vpp_pkg_centos(node, 'vpp-api-lua')
379 self._uninstall_vpp_pkg_centos(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400380 self._uninstall_vpp_pkg_centos(node, 'vpp')
381 self._uninstall_vpp_pkg_centos(node, 'vpp-lib')
jdenisco24010fb2018-11-13 12:40:12 -0500382 self._uninstall_vpp_pkg_centos(node, 'vpp-selinux-policy')
John DeNisco68b0ee32017-09-27 16:35:23 -0400383 else:
384 logging.info("Uninstall locally installed CentOS Packages")
385 for pkg in pkgs:
386 self._uninstall_vpp_pkg_centos(node, pkg['name'])
387 else:
388 logging.error("There are no CentOS packages installed")
389
390 def uninstall_vpp(self, node):
391 """
392 Uninstall the VPP packages
393
394 :param node: Node dictionary with cpuinfo.
395 :type node: dict
396 """
John DeNiscoc6b2a202017-11-01 12:37:47 -0400397
398 # First stop VPP
399 self.stop(node)
400
John DeNisco68b0ee32017-09-27 16:35:23 -0400401 distro = self.get_linux_distro()
402 if distro[0] == 'Ubuntu':
John DeNisco4dc83972018-03-30 10:50:19 -0400403 logging.info("Uninstall Ubuntu")
John DeNisco68b0ee32017-09-27 16:35:23 -0400404 self._uninstall_vpp_ubuntu(node)
405 elif distro[0] == 'CentOS Linux':
406 logging.info("Uninstall CentOS")
407 self._uninstall_vpp_centos(node)
408 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400409 logging.info("Uninstall CentOS (Default)")
410 self._uninstall_vpp_centos(node)
John DeNisco68b0ee32017-09-27 16:35:23 -0400411 return
412
413 def show_vpp_settings(self, *additional_cmds):
414 """
415 Print default VPP settings. In case others are needed, can be
416 accepted as next parameters (each setting one parameter), preferably
417 in form of a string.
418
419 :param additional_cmds: Additional commands that the vpp should print
420 settings for.
421 :type additional_cmds: tuple
422 """
423 def_setting_tb_displayed = {
424 'IPv6 FIB': 'ip6 fib',
425 'IPv4 FIB': 'ip fib',
426 'Interface IP': 'int addr',
427 'Interfaces': 'int',
428 'ARP': 'ip arp',
429 'Errors': 'err'
430 }
431
432 if additional_cmds:
433 for cmd in additional_cmds:
434 def_setting_tb_displayed['Custom Setting: {}'.format(cmd)] \
435 = cmd
436
437 for _, value in def_setting_tb_displayed.items():
438 self.exec_command('vppctl sh {}'.format(value))
439
440 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400441 def get_vms(node):
442 """
443 Get a list of VMs that are connected to VPP interfaces
444
445 :param node: VPP node.
446 :type node: dict
447 :returns: Dictionary containing a list of VMs and the interfaces that are connected to VPP
448 :rtype: dictionary
449 """
450
451 vmdict = {}
452
453 print "Need to implement get vms"
454
455 return vmdict
456
457 @staticmethod
John DeNiscoa3db0782017-10-17 11:07:22 -0400458 def get_int_ip(node):
459 """
460 Get the VPP interfaces and IP addresses
461
462 :param node: VPP node.
463 :type node: dict
464 :returns: Dictionary containing VPP interfaces and IP addresses
465 :rtype: dictionary
466 """
467 interfaces = {}
468 cmd = 'vppctl show int addr'
469 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
470 if ret != 0:
471 return interfaces
472
473 lines = stdout.split('\n')
474 if len(lines[0]) is not 0:
475 if lines[0].split(' ')[0] == 'FileNotFoundError':
476 return interfaces
477
John DeNiscoc6b2a202017-11-01 12:37:47 -0400478 name = ''
John DeNiscoa3db0782017-10-17 11:07:22 -0400479 for line in lines:
480 if len(line) is 0:
481 continue
482
483 # If the first character is not whitespace
484 # create a new interface
485 if len(re.findall(r'\s', line[0])) is 0:
486 spl = line.split()
487 name = spl[0]
488 if name == 'local0':
489 continue
490 interfaces[name] = {}
491 interfaces[name]['state'] = spl[1].lstrip('(').rstrip('):\r')
492 else:
493 interfaces[name]['address'] = line.lstrip(' ').rstrip('\r')
494
495 return interfaces
496
497 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400498 def get_hardware(node):
499 """
500 Get the VPP hardware information and return it in a
501 dictionary
502
503 :param node: VPP node.
504 :type node: dict
John DeNiscoa3db0782017-10-17 11:07:22 -0400505 :returns: Dictionary containing VPP hardware information
John DeNisco68b0ee32017-09-27 16:35:23 -0400506 :rtype: dictionary
507 """
508
509 interfaces = {}
510 cmd = 'vppctl show hard'
511 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
512 if ret != 0:
513 return interfaces
514
515 lines = stdout.split('\n')
516 if len(lines[0]) is not 0:
517 if lines[0].split(' ')[0] == 'FileNotFoundError':
518 return interfaces
519
520 for line in lines:
521 if len(line) is 0:
522 continue
523
524 # If the first character is not whitespace
525 # create a new interface
526 if len(re.findall(r'\s', line[0])) is 0:
527 spl = line.split()
528 name = spl[0]
529 interfaces[name] = {}
530 interfaces[name]['index'] = spl[1]
531 interfaces[name]['state'] = spl[2]
532
533 # Ethernet address
534 rfall = re.findall(r'Ethernet address', line)
535 if rfall:
536 spl = line.split()
537 interfaces[name]['mac'] = spl[2]
538
539 # Carrier
540 rfall = re.findall(r'carrier', line)
541 if rfall:
542 spl = line.split('carrier ')
543 interfaces[name]['carrier'] = spl[1]
544
545 # Socket
jdenisco7c37a672018-11-20 11:25:17 -0500546 rfall = re.findall(r'numa \d+', line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400547 if rfall:
jdenisco7c37a672018-11-20 11:25:17 -0500548 spl = rfall[0].split()
549 interfaces[name]['numa'] = rfall[0].split()[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400550
551 # Queues and Descriptors
jdenisco7c37a672018-11-20 11:25:17 -0500552 rfall = re.findall(r'rx\: queues \d+', line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400553 if rfall:
jdenisco7c37a672018-11-20 11:25:17 -0500554 interfaces[name]['rx queues'] = rfall[0].split()[2]
555 rdesc = re.findall(r'desc \d+', line)
556 if rdesc:
557 interfaces[name]['rx descs'] = rdesc[0].split()[1]
558
559 rfall = re.findall(r'tx\: queues \d+', line)
560 if rfall:
561 interfaces[name]['tx queues'] = rfall[0].split()[2]
562 rdesc = re.findall(r'desc \d+', line)
563 if rdesc:
564 interfaces[name]['tx descs'] = rdesc[0].split()[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400565
566 return interfaces
567
568 def _get_installed_vpp_pkgs_ubuntu(self):
569 """
570 Get the VPP hardware information and return it in a
571 dictionary
572
573 :returns: List of the packages installed
574 :rtype: list
575 """
576
577 pkgs = []
578 cmd = 'dpkg -l | grep vpp'
579 (ret, stdout, stderr) = self.exec_command(cmd)
580 if ret != 0:
581 return pkgs
582
583 lines = stdout.split('\n')
584 for line in lines:
585 items = line.split()
586 if len(items) < 2:
587 continue
588 pkg = {'name': items[1], 'version': items[2]}
589 pkgs.append(pkg)
590
591 return pkgs
592
593 def _get_installed_vpp_pkgs_centos(self):
594 """
595 Get the VPP hardware information and return it in a
596 dictionary
597
598 :returns: List of the packages installed
599 :rtype: list
600 """
601
602 pkgs = []
603 cmd = 'rpm -qa | grep vpp'
604 (ret, stdout, stderr) = self.exec_command(cmd)
605 if ret != 0:
606 return pkgs
607
608 lines = stdout.split('\n')
609 for line in lines:
610 if len(line) == 0:
611 continue
612
613 items = line.split()
614 if len(items) < 2:
615 pkg = {'name': items[0]}
616 else:
617 pkg = {'name': items[1], 'version': items[2]}
618
619 pkgs.append(pkg)
620
621 return pkgs
622
623 def get_installed_vpp_pkgs(self):
624 """
625 Get the VPP hardware information and return it in a
626 dictionary
627
628 :returns: List of the packages installed
629 :rtype: list
630 """
631
632 distro = self.get_linux_distro()
633 if distro[0] == 'Ubuntu':
634 pkgs = self._get_installed_vpp_pkgs_ubuntu()
635 elif distro[0] == 'CentOS Linux':
636 pkgs = self._get_installed_vpp_pkgs_centos()
637 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400638 pkgs = self._get_installed_vpp_pkgs_centos()
John DeNisco68b0ee32017-09-27 16:35:23 -0400639 return []
640
641 return pkgs
642
643 @staticmethod
644 def get_interfaces_numa_node(node, *iface_keys):
645 """Get numa node on which are located most of the interfaces.
646
647 Return numa node with highest count of interfaces provided as arguments.
648 Return 0 if the interface does not have numa_node information available.
649 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:
jdenisco24010fb2018-11-13 12:40:12 -0500722 logging.debug('{} failed on node {} {} {}'.
John DeNisco68b0ee32017-09-27 16:35:23 -0400723 format(cmd, node['host'],
724 stdout, stderr))
725
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 \
776 distro[0] == 'CentOS Linux' or \
John DeNisco4dc83972018-03-30 10:50:19 -0400777 distro[:7] == 'Red Hat':
John DeNisco68b0ee32017-09-27 16:35:23 -0400778 return distro
779 else:
780 raise RuntimeError('Linux Distribution {} is not supported'.format(distro[0]))
781
782 @staticmethod
783 def version():
784 """
785
786 Gets VPP Version information
787
788 :returns: version
789 :rtype: dict
790 """
791
792 version = {}
793 cmd = 'vppctl show version verbose'
794 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
795 if ret != 0:
796 return version
797
798 lines = stdout.split('\n')
799 if len(lines[0]) is not 0:
800 if lines[0].split(' ')[0] == 'FileNotFoundError':
801 return version
802
803 for line in lines:
804 if len(line) is 0:
805 continue
806 dct = line.split(':')
807 version[dct[0]] = dct[1].lstrip(' ')
808
809 return version
John DeNiscoc6b2a202017-11-01 12:37:47 -0400810
811 @staticmethod
812 def show_bridge(node):
813 """
814 Shows the current bridge configuration
815
816 :param node: VPP node.
817 :type node: dict
John DeNisco9fa5cf42018-02-06 15:23:05 -0500818 :returns: A list of interfaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400819 """
820
John DeNisco9fa5cf42018-02-06 15:23:05 -0500821 ifaces = []
John DeNiscoc6b2a202017-11-01 12:37:47 -0400822 cmd = 'vppctl show bridge'
823 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
824 if ret != 0:
825 raise RuntimeError('{} failed on node {} {} {}'.
826 format(cmd, node['host'],
827 stdout, stderr))
828 lines = stdout.split('\r\n')
829 bridges = []
830 for line in lines:
831 if line == 'no bridge-domains in use':
832 print line
John DeNisco9fa5cf42018-02-06 15:23:05 -0500833 return ifaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400834 if len(line) == 0:
835 continue
836
837 lspl = line.lstrip(' ').split()
838 if lspl[0] != 'BD-ID':
839 bridges.append(lspl[0])
840
841 for bridge in bridges:
842 cmd = 'vppctl show bridge {} detail'.format(bridge)
843 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
844 if ret != 0:
845 raise RuntimeError('{} failed on node {} {} {}'.
846 format(cmd, node['host'],
847 stdout, stderr))
John DeNisco9fa5cf42018-02-06 15:23:05 -0500848
849 lines = stdout.split('\r\n')
850 for line in lines:
851 iface = re.findall(r'[a-zA-z]+\d+/\d+/\d+', line)
852 if len(iface):
853 ifcidx ={'name': iface[0], 'index': line.split()[1] }
854 ifaces.append(ifcidx)
855
856 print stdout
John DeNisco4dc83972018-03-30 10:50:19 -0400857 return ifaces