blob: a1c64a3e15dee590bcb9117150ba27958a734959 [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
John DeNisco68b0ee32017-09-27 16:35:23 -040023
24class VPPUtil(object):
25 """General class for any VPP related methods/functions."""
26
27 @staticmethod
28 def exec_command(cmd, timeout=None):
29 """Execute a command on the local node.
30
31 :param cmd: Command to run locally.
32 :param timeout: Timeout value
33 :type cmd: str
34 :type timeout: int
35 :return return_code, stdout, stderr
36 :rtype: tuple(int, str, str)
37 """
38
39 logging.info(" Local Command: {}".format(cmd))
40 out = ''
41 err = ''
42 prc = subprocess.Popen(cmd, shell=True, bufsize=1,
43 stdin=subprocess.PIPE,
44 stdout=subprocess.PIPE,
45 stderr=subprocess.PIPE)
46
47 with prc.stdout:
48 for line in iter(prc.stdout.readline, b''):
49 logging.info(" {}".format(line.strip('\n')))
50 out += line
51
52 with prc.stderr:
53 for line in iter(prc.stderr.readline, b''):
54 logging.warn(" {}".format(line.strip('\n')))
55 err += line
56
57 ret = prc.wait()
58
59 return ret, out, err
60
61 def _autoconfig_backup_file(self, filename):
62 """
63 Create a backup file.
64
65 :param filename: The file to backup
66 :type filename: str
67 """
68
69 # Does a copy of the file exist, if not create one
70 ofile = filename + '.orig'
71 (ret, stdout, stderr) = self.exec_command('ls {}'.format(ofile))
72 if ret != 0:
73 logging.debug(stderr)
74 if stdout.strip('\n') != ofile:
75 cmd = 'sudo cp {} {}'.format(filename, ofile)
76 (ret, stdout, stderr) = self.exec_command(cmd)
77 if ret != 0:
78 logging.debug(stderr)
79
80 def _install_vpp_pkg_ubuntu(self, node, pkg):
81 """
82 Install the VPP packages
83
84 :param node: Node dictionary
85 :param pkg: The vpp packages
86 :type node: dict
87 :type pkg: string
88 """
89
90 cmd = 'apt-get -y install {}'.format(pkg)
91 (ret, stdout, stderr) = self.exec_command(cmd)
92 if ret != 0:
93 raise RuntimeError('{} failed on node {} {} {}'.format(
94 cmd, node['host'], stdout, stderr))
95
96 def _install_vpp_pkg_centos(self, node, pkg):
97 """
98 Install the VPP packages
99
100 :param node: Node dictionary
101 :param pkg: The vpp packages
102 :type node: dict
103 :type pkg: string
104 """
105
106 cmd = 'yum -y install {}'.format(pkg)
107 (ret, stdout, stderr) = self.exec_command(cmd)
108 if ret != 0:
109 raise RuntimeError('{} failed on node {} {} {}'.format(
110 cmd, node['host'], stdout, stderr))
111
jdeniscob0b9dad2018-12-18 15:29:45 -0500112 def _install_vpp_ubuntu(self, node, branch, ubuntu_version='xenial'):
John DeNisco68b0ee32017-09-27 16:35:23 -0400113 """
114 Install the VPP packages
115
116 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500117 :param branch: VPP branch
John DeNisco68b0ee32017-09-27 16:35:23 -0400118 :param ubuntu_version: Ubuntu Version
119 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500120 :type branch: string
John DeNisco68b0ee32017-09-27 16:35:23 -0400121 :type ubuntu_version: string
122 """
123
124 # Modify the sources list
125 sfile = '/etc/apt/sources.list.d/99fd.io.list'
126
127 # Backup the sources list
128 self._autoconfig_backup_file(sfile)
129
jdenisco24010fb2018-11-13 12:40:12 -0500130 reps = 'deb [trusted=yes] https://packagecloud.io/fdio/'
jdeniscob0b9dad2018-12-18 15:29:45 -0500131 reps += '{}/ubuntu {} main ./\n'.format(branch, ubuntu_version)
John DeNisco68b0ee32017-09-27 16:35:23 -0400132
jdenisco24010fb2018-11-13 12:40:12 -0500133 with open(sfile, 'w') as sfd:
134 sfd.write(reps)
135 sfd.close()
136
137 # Add the key
jdeniscob0b9dad2018-12-18 15:29:45 -0500138 key = requests.get('https://packagecloud.io/fdio/{}/gpgkey'.format(branch))
jdenisco24010fb2018-11-13 12:40:12 -0500139 cmd = 'echo "{}" | apt-key add -'.format(key.content)
John DeNisco68b0ee32017-09-27 16:35:23 -0400140 (ret, stdout, stderr) = self.exec_command(cmd)
141 if ret != 0:
142 raise RuntimeError('{} failed on node {} {}'.format(
143 cmd,
144 node['host'],
145 stderr))
146
147 # Install the package
148 cmd = 'apt-get -y update'
149 (ret, stdout, stderr) = self.exec_command(cmd)
150 if ret != 0:
151 raise RuntimeError('{} apt-get update failed on node {} {}'.format(
152 cmd,
153 node['host'],
154 stderr))
155
156 self._install_vpp_pkg_ubuntu(node, 'vpp-lib')
157 self._install_vpp_pkg_ubuntu(node, 'vpp')
158 self._install_vpp_pkg_ubuntu(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400159 self._install_vpp_pkg_ubuntu(node, 'vpp-api-python')
160 self._install_vpp_pkg_ubuntu(node, 'vpp-api-java')
161 self._install_vpp_pkg_ubuntu(node, 'vpp-api-lua')
162 self._install_vpp_pkg_ubuntu(node, 'vpp-dev')
163 self._install_vpp_pkg_ubuntu(node, 'vpp-dbg')
164
jdeniscob0b9dad2018-12-18 15:29:45 -0500165 def _install_vpp_centos(self, node, branch):
John DeNisco68b0ee32017-09-27 16:35:23 -0400166 """
167 Install the VPP packages
168
169 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500170 :param branch: The branch name release or master
John DeNisco68b0ee32017-09-27 16:35:23 -0400171 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500172 :type branch: string
John DeNisco68b0ee32017-09-27 16:35:23 -0400173 """
174
jdenisco24010fb2018-11-13 12:40:12 -0500175 # Be sure the correct system packages are installed
176 cmd = 'yum -y update'
177 (ret, stdout, stderr) = self.exec_command(cmd)
178 if ret != 0:
179 logging.debug('{} failed on node {} {}'.format(
180 cmd,
181 node['host'],
182 stderr))
183
184 cmd = 'yum -y install pygpgme yum-utils'
185 (ret, stdout, stderr) = self.exec_command(cmd)
186 if ret != 0:
187 logging.debug('{} failed on node {} {}'.format(
188 cmd,
189 node['host'],
190 stderr))
191
John DeNisco68b0ee32017-09-27 16:35:23 -0400192 # Modify the sources list
193 sfile = '/etc/yum.repos.d/fdio-release.repo'
194
195 # Backup the sources list
196 self._autoconfig_backup_file(sfile)
197
198 # Remove the current file
199 cmd = 'rm {}'.format(sfile)
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
jdenisco24010fb2018-11-13 12:40:12 -0500207 # Get the file contents
jdeniscob0b9dad2018-12-18 15:29:45 -0500208 reps = '[fdio_{}]\n'.format(branch)
209 reps += 'name=fdio_{}\n'.format(branch)
210 reps += 'baseurl=https://packagecloud.io/fdio/{}/el/7/$basearch\n'.format(branch)
jdenisco24010fb2018-11-13 12:40:12 -0500211 reps += 'repo_gpgcheck=1\n'
212 reps += 'gpgcheck=0\n'
213 reps += 'enabled=1\n'
jdeniscob0b9dad2018-12-18 15:29:45 -0500214 reps += 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey\n'.format(branch)
jdenisco24010fb2018-11-13 12:40:12 -0500215 reps += 'sslverify=1\n'
216 reps += 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt\n'
217 reps += 'metadata_expire=300\n'
218 reps += '\n'
jdeniscob0b9dad2018-12-18 15:29:45 -0500219 reps += '[fdio_{}-source]\n'.format(branch)
220 reps += 'name=fdio_{}-source\n'.format(branch)
221 reps += 'baseurl=https://packagecloud.io/fdio/{}/el/7/SRPMS\n'.format(branch)
jdenisco24010fb2018-11-13 12:40:12 -0500222 reps += 'repo_gpgcheck=1\n'
223 reps += 'gpgcheck=0\n'
224 reps += 'enabled=1\n'
jdeniscob0b9dad2018-12-18 15:29:45 -0500225 reps += 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey\n'.format(branch)
jdenisco24010fb2018-11-13 12:40:12 -0500226 reps += 'sslverify =1\n'
227 reps += 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt\n'
228 reps += 'metadata_expire=300\n'
229
230 with open(sfile, 'w') as sfd:
231 sfd.write(reps)
232 sfd.close()
233
234 # Update the fdio repo
235 cmd = 'yum clean all'
John DeNisco68b0ee32017-09-27 16:35:23 -0400236 (ret, stdout, stderr) = self.exec_command(cmd)
237 if ret != 0:
jdenisco24010fb2018-11-13 12:40:12 -0500238 logging.debug('{} failed on node {} {}'.format(
239 cmd,
240 node['host'],
241 stderr))
242
jdeniscob0b9dad2018-12-18 15:29:45 -0500243 cmd = "yum -q makecache -y --disablerepo='*' --enablerepo='fdio_{}'".format(branch)
jdenisco24010fb2018-11-13 12:40:12 -0500244 (ret, stdout, stderr) = self.exec_command(cmd)
245 if ret != 0:
246 logging.debug('{} failed on node {} {}'.format(
John DeNisco68b0ee32017-09-27 16:35:23 -0400247 cmd,
248 node['host'],
249 stderr))
250
251 # Install the packages
jdenisco24010fb2018-11-13 12:40:12 -0500252 self._install_vpp_pkg_centos(node, 'vpp-selinux-policy')
John DeNisco68b0ee32017-09-27 16:35:23 -0400253 self._install_vpp_pkg_centos(node, 'vpp-lib')
254 self._install_vpp_pkg_centos(node, 'vpp')
255 self._install_vpp_pkg_centos(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400256 self._install_vpp_pkg_centos(node, 'vpp-api-python')
257 self._install_vpp_pkg_centos(node, 'vpp-api-java')
258 self._install_vpp_pkg_centos(node, 'vpp-api-lua')
259 self._install_vpp_pkg_centos(node, 'vpp-devel')
jdeniscob9875092018-11-06 16:10:04 -0500260 self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
John DeNisco68b0ee32017-09-27 16:35:23 -0400261
jdeniscob0b9dad2018-12-18 15:29:45 -0500262 def install_vpp(self, node, branch):
John DeNisco68b0ee32017-09-27 16:35:23 -0400263 """
264 Install the VPP packages
265
266 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500267 :param branch: The branch name
John DeNisco68b0ee32017-09-27 16:35:23 -0400268 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500269 :type branch: string
270
John DeNisco68b0ee32017-09-27 16:35:23 -0400271 """
272 distro = self.get_linux_distro()
John DeNisco4dc83972018-03-30 10:50:19 -0400273 logging.info(" {}".format(distro[0]))
John DeNisco68b0ee32017-09-27 16:35:23 -0400274 if distro[0] == 'Ubuntu':
John DeNisco4dc83972018-03-30 10:50:19 -0400275 logging.info("Install Ubuntu")
jdeniscob0b9dad2018-12-18 15:29:45 -0500276 self._install_vpp_ubuntu(node, branch, ubuntu_version=distro[2])
John DeNisco68b0ee32017-09-27 16:35:23 -0400277 elif distro[0] == 'CentOS Linux':
278 logging.info("Install CentOS")
jdeniscob0b9dad2018-12-18 15:29:45 -0500279 self._install_vpp_centos(node, branch)
John DeNisco68b0ee32017-09-27 16:35:23 -0400280 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400281 logging.info("Install CentOS (default)")
jdeniscob0b9dad2018-12-18 15:29:45 -0500282 self._install_vpp_centos(node, branch)
John DeNisco4dc83972018-03-30 10:50:19 -0400283 return
John DeNisco68b0ee32017-09-27 16:35:23 -0400284
285 def _uninstall_vpp_pkg_ubuntu(self, node, pkg):
286 """
287 Uninstall the VPP packages
288
289 :param node: Node dictionary
290 :param pkg: The vpp packages
291 :type node: dict
292 :type pkg: string
293 """
294 cmd = 'dpkg --purge {}'.format(pkg)
295 (ret, stdout, stderr) = self.exec_command(cmd)
296 if ret != 0:
297 raise RuntimeError('{} failed on node {} {} {}'.format(
298 cmd, node['host'], stdout, stderr))
299
300 def _uninstall_vpp_pkg_centos(self, node, pkg):
301 """
302 Uninstall the VPP packages
303
304 :param node: Node dictionary
305 :param pkg: The vpp packages
306 :type node: dict
307 :type pkg: string
308 """
309 cmd = 'yum -y remove {}'.format(pkg)
310 (ret, stdout, stderr) = self.exec_command(cmd)
311 if ret != 0:
312 raise RuntimeError('{} failed on node {} {} {}'.format(
313 cmd, node['host'], stdout, stderr))
314
315 def _uninstall_vpp_ubuntu(self, node):
316 """
317 Uninstall the VPP packages
318
319 :param node: Node dictionary with cpuinfo.
320 :type node: dict
321 """
322 pkgs = self.get_installed_vpp_pkgs()
323
324 if len(pkgs) > 0:
325 if 'version' in pkgs[0]:
326 logging.info("Uninstall Ubuntu Packages")
jdenisco24010fb2018-11-13 12:40:12 -0500327 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dbg')
328 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dev')
John DeNisco68b0ee32017-09-27 16:35:23 -0400329 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-python')
330 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-java')
331 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-lua')
332 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400333 self._uninstall_vpp_pkg_ubuntu(node, 'vpp')
334 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-lib')
335 else:
336 logging.info("Uninstall locally installed Ubuntu Packages")
337 for pkg in pkgs:
338 self._uninstall_vpp_pkg_ubuntu(node, pkg['name'])
339 else:
340 logging.error("There are no Ubuntu packages installed")
341
342 def _uninstall_vpp_centos(self, node):
343 """
344 Uninstall the VPP packages
345
346 :param node: Node dictionary with cpuinfo.
347 :type node: dict
348 """
349
350 pkgs = self.get_installed_vpp_pkgs()
351
352 if len(pkgs) > 0:
353 if 'version' in pkgs[0]:
354 logging.info("Uninstall CentOS Packages")
jdenisco24010fb2018-11-13 12:40:12 -0500355 self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
356 self._uninstall_vpp_pkg_centos(node, 'vpp-devel')
John DeNisco68b0ee32017-09-27 16:35:23 -0400357 self._uninstall_vpp_pkg_centos(node, 'vpp-api-python')
358 self._uninstall_vpp_pkg_centos(node, 'vpp-api-java')
359 self._uninstall_vpp_pkg_centos(node, 'vpp-api-lua')
360 self._uninstall_vpp_pkg_centos(node, 'vpp-plugins')
John DeNisco68b0ee32017-09-27 16:35:23 -0400361 self._uninstall_vpp_pkg_centos(node, 'vpp')
362 self._uninstall_vpp_pkg_centos(node, 'vpp-lib')
jdenisco24010fb2018-11-13 12:40:12 -0500363 self._uninstall_vpp_pkg_centos(node, 'vpp-selinux-policy')
John DeNisco68b0ee32017-09-27 16:35:23 -0400364 else:
365 logging.info("Uninstall locally installed CentOS Packages")
366 for pkg in pkgs:
367 self._uninstall_vpp_pkg_centos(node, pkg['name'])
368 else:
369 logging.error("There are no CentOS packages installed")
370
371 def uninstall_vpp(self, node):
372 """
373 Uninstall the VPP packages
374
375 :param node: Node dictionary with cpuinfo.
376 :type node: dict
377 """
John DeNiscoc6b2a202017-11-01 12:37:47 -0400378
379 # First stop VPP
380 self.stop(node)
381
John DeNisco68b0ee32017-09-27 16:35:23 -0400382 distro = self.get_linux_distro()
383 if distro[0] == 'Ubuntu':
John DeNisco4dc83972018-03-30 10:50:19 -0400384 logging.info("Uninstall Ubuntu")
John DeNisco68b0ee32017-09-27 16:35:23 -0400385 self._uninstall_vpp_ubuntu(node)
386 elif distro[0] == 'CentOS Linux':
387 logging.info("Uninstall CentOS")
388 self._uninstall_vpp_centos(node)
389 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400390 logging.info("Uninstall CentOS (Default)")
391 self._uninstall_vpp_centos(node)
John DeNisco68b0ee32017-09-27 16:35:23 -0400392 return
393
394 def show_vpp_settings(self, *additional_cmds):
395 """
396 Print default VPP settings. In case others are needed, can be
397 accepted as next parameters (each setting one parameter), preferably
398 in form of a string.
399
400 :param additional_cmds: Additional commands that the vpp should print
401 settings for.
402 :type additional_cmds: tuple
403 """
404 def_setting_tb_displayed = {
405 'IPv6 FIB': 'ip6 fib',
406 'IPv4 FIB': 'ip fib',
407 'Interface IP': 'int addr',
408 'Interfaces': 'int',
409 'ARP': 'ip arp',
410 'Errors': 'err'
411 }
412
413 if additional_cmds:
414 for cmd in additional_cmds:
415 def_setting_tb_displayed['Custom Setting: {}'.format(cmd)] \
416 = cmd
417
418 for _, value in def_setting_tb_displayed.items():
419 self.exec_command('vppctl sh {}'.format(value))
420
421 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400422 def get_vms(node):
423 """
424 Get a list of VMs that are connected to VPP interfaces
425
426 :param node: VPP node.
427 :type node: dict
428 :returns: Dictionary containing a list of VMs and the interfaces that are connected to VPP
429 :rtype: dictionary
430 """
431
432 vmdict = {}
433
434 print "Need to implement get vms"
435
436 return vmdict
437
438 @staticmethod
John DeNiscoa3db0782017-10-17 11:07:22 -0400439 def get_int_ip(node):
440 """
441 Get the VPP interfaces and IP addresses
442
443 :param node: VPP node.
444 :type node: dict
445 :returns: Dictionary containing VPP interfaces and IP addresses
446 :rtype: dictionary
447 """
448 interfaces = {}
449 cmd = 'vppctl show int addr'
450 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
451 if ret != 0:
452 return interfaces
453
454 lines = stdout.split('\n')
455 if len(lines[0]) is not 0:
456 if lines[0].split(' ')[0] == 'FileNotFoundError':
457 return interfaces
458
John DeNiscoc6b2a202017-11-01 12:37:47 -0400459 name = ''
John DeNiscoa3db0782017-10-17 11:07:22 -0400460 for line in lines:
461 if len(line) is 0:
462 continue
463
464 # If the first character is not whitespace
465 # create a new interface
466 if len(re.findall(r'\s', line[0])) is 0:
467 spl = line.split()
468 name = spl[0]
469 if name == 'local0':
470 continue
471 interfaces[name] = {}
472 interfaces[name]['state'] = spl[1].lstrip('(').rstrip('):\r')
473 else:
474 interfaces[name]['address'] = line.lstrip(' ').rstrip('\r')
475
476 return interfaces
477
478 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400479 def get_hardware(node):
480 """
481 Get the VPP hardware information and return it in a
482 dictionary
483
484 :param node: VPP node.
485 :type node: dict
John DeNiscoa3db0782017-10-17 11:07:22 -0400486 :returns: Dictionary containing VPP hardware information
John DeNisco68b0ee32017-09-27 16:35:23 -0400487 :rtype: dictionary
488 """
489
490 interfaces = {}
491 cmd = 'vppctl show hard'
492 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
493 if ret != 0:
494 return interfaces
495
496 lines = stdout.split('\n')
497 if len(lines[0]) is not 0:
498 if lines[0].split(' ')[0] == 'FileNotFoundError':
499 return interfaces
500
501 for line in lines:
502 if len(line) is 0:
503 continue
504
505 # If the first character is not whitespace
506 # create a new interface
507 if len(re.findall(r'\s', line[0])) is 0:
508 spl = line.split()
509 name = spl[0]
510 interfaces[name] = {}
511 interfaces[name]['index'] = spl[1]
512 interfaces[name]['state'] = spl[2]
513
514 # Ethernet address
515 rfall = re.findall(r'Ethernet address', line)
516 if rfall:
517 spl = line.split()
518 interfaces[name]['mac'] = spl[2]
519
520 # Carrier
521 rfall = re.findall(r'carrier', line)
522 if rfall:
523 spl = line.split('carrier ')
524 interfaces[name]['carrier'] = spl[1]
525
526 # Socket
jdenisco7c37a672018-11-20 11:25:17 -0500527 rfall = re.findall(r'numa \d+', line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400528 if rfall:
jdenisco7c37a672018-11-20 11:25:17 -0500529 spl = rfall[0].split()
530 interfaces[name]['numa'] = rfall[0].split()[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400531
532 # Queues and Descriptors
jdenisco7c37a672018-11-20 11:25:17 -0500533 rfall = re.findall(r'rx\: queues \d+', line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400534 if rfall:
jdenisco7c37a672018-11-20 11:25:17 -0500535 interfaces[name]['rx queues'] = rfall[0].split()[2]
536 rdesc = re.findall(r'desc \d+', line)
537 if rdesc:
538 interfaces[name]['rx descs'] = rdesc[0].split()[1]
539
540 rfall = re.findall(r'tx\: queues \d+', line)
541 if rfall:
542 interfaces[name]['tx queues'] = rfall[0].split()[2]
543 rdesc = re.findall(r'desc \d+', line)
544 if rdesc:
545 interfaces[name]['tx descs'] = rdesc[0].split()[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400546
547 return interfaces
548
jdeniscob0b9dad2018-12-18 15:29:45 -0500549 def _get_installed_vpp_pkgs_ubuntu(self, distro):
John DeNisco68b0ee32017-09-27 16:35:23 -0400550 """
551 Get the VPP hardware information and return it in a
552 dictionary
553
jdeniscob0b9dad2018-12-18 15:29:45 -0500554 :param distro: The linux distro
555 :type distro: dict
John DeNisco68b0ee32017-09-27 16:35:23 -0400556 :returns: List of the packages installed
557 :rtype: list
558 """
559
560 pkgs = []
561 cmd = 'dpkg -l | grep vpp'
562 (ret, stdout, stderr) = self.exec_command(cmd)
563 if ret != 0:
564 return pkgs
565
566 lines = stdout.split('\n')
567 for line in lines:
568 items = line.split()
569 if len(items) < 2:
570 continue
571 pkg = {'name': items[1], 'version': items[2]}
572 pkgs.append(pkg)
573
574 return pkgs
575
576 def _get_installed_vpp_pkgs_centos(self):
577 """
578 Get the VPP hardware information and return it in a
579 dictionary
580
581 :returns: List of the packages installed
582 :rtype: list
583 """
584
585 pkgs = []
586 cmd = 'rpm -qa | grep vpp'
587 (ret, stdout, stderr) = self.exec_command(cmd)
588 if ret != 0:
589 return pkgs
590
591 lines = stdout.split('\n')
592 for line in lines:
593 if len(line) == 0:
594 continue
595
596 items = line.split()
597 if len(items) < 2:
598 pkg = {'name': items[0]}
599 else:
600 pkg = {'name': items[1], 'version': items[2]}
601
602 pkgs.append(pkg)
603
604 return pkgs
605
606 def get_installed_vpp_pkgs(self):
607 """
608 Get the VPP hardware information and return it in a
609 dictionary
610
611 :returns: List of the packages installed
612 :rtype: list
613 """
614
615 distro = self.get_linux_distro()
616 if distro[0] == 'Ubuntu':
jdeniscob0b9dad2018-12-18 15:29:45 -0500617 pkgs = self._get_installed_vpp_pkgs_ubuntu(distro)
John DeNisco68b0ee32017-09-27 16:35:23 -0400618 elif distro[0] == 'CentOS Linux':
619 pkgs = self._get_installed_vpp_pkgs_centos()
620 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400621 pkgs = self._get_installed_vpp_pkgs_centos()
John DeNisco68b0ee32017-09-27 16:35:23 -0400622 return []
623
624 return pkgs
625
626 @staticmethod
627 def get_interfaces_numa_node(node, *iface_keys):
628 """Get numa node on which are located most of the interfaces.
629
630 Return numa node with highest count of interfaces provided as arguments.
631 Return 0 if the interface does not have numa_node information available.
632 If all interfaces have unknown location (-1), then return 0.
633 If most of interfaces have unknown location (-1), but there are
634 some interfaces with known location, then return the second most
635 location of the provided interfaces.
636
637 :param node: Node from DICT__nodes.
638 :param iface_keys: Interface keys for lookup.
639 :type node: dict
640 :type iface_keys: strings
641 """
642 numa_list = []
643 for if_key in iface_keys:
644 try:
645 numa_list.append(node['interfaces'][if_key].get('numa_node'))
646 except KeyError:
647 pass
648
649 numa_cnt_mc = Counter(numa_list).most_common()
650 numa_cnt_mc_len = len(numa_cnt_mc)
651 if numa_cnt_mc_len > 0 and numa_cnt_mc[0][0] != -1:
652 return numa_cnt_mc[0][0]
653 elif numa_cnt_mc_len > 1 and numa_cnt_mc[0][0] == -1:
654 return numa_cnt_mc[1][0]
655
656 return 0
657
658 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400659 def restart(node):
660 """
661
662 Starts vpp for a given node
663
664 :param node: VPP node.
665 :type node: dict
666 """
667
668 cmd = 'service vpp restart'
669 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
670 if ret != 0:
671 raise RuntimeError('{} failed on node {} {} {}'.
672 format(cmd, node['host'],
673 stdout, stderr))
674
675 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400676 def start(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 start'
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
693 def stop(node):
694 """
695
696 Stops vpp for a given node
697
698 :param node: VPP node.
699 :type node: dict
700 """
701
702 cmd = 'service vpp stop'
703 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
704 if ret != 0:
jdeniscob0b9dad2018-12-18 15:29:45 -0500705 logging.debug('{} failed on node {} {} {}'.format(cmd, node['host'], stdout, stderr))
John DeNisco68b0ee32017-09-27 16:35:23 -0400706
John DeNiscoa7da67f2018-01-26 14:55:33 -0500707 # noinspection RegExpRedundantEscape
John DeNisco68b0ee32017-09-27 16:35:23 -0400708 @staticmethod
709 def status(node):
710 """
711
712 Gets VPP status
713
714 :param: node
715 :type node: dict
716 :returns: status, errors
717 :rtype: tuple(str, list)
718 """
719 errors = []
720 vutil = VPPUtil()
721 pkgs = vutil.get_installed_vpp_pkgs()
722 if len(pkgs) == 0:
723 return "Not Installed", errors
724
725 cmd = 'service vpp status'
726 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
727
728 # Get the active status
729 state = re.findall(r'Active:[\w (\)]+', stdout)[0].split(' ')
730 if len(state) > 2:
731 statestr = "{} {}".format(state[1], state[2])
732 else:
733 statestr = "Invalid"
734
735 # For now we won't look for DPDK errors
736 # lines = stdout.split('\n')
737 # for line in lines:
738 # if 'EAL' in line or \
739 # 'FAILURE' in line or \
740 # 'failed' in line or \
741 # 'Failed' in line:
742 # errors.append(line.lstrip(' '))
743
744 return statestr, errors
745
746 @staticmethod
747 def get_linux_distro():
748 """
749 Get the linux distribution and check if it is supported
750
751 :returns: linux distro, None if the distro is not supported
752 :rtype: list
753 """
754
755 distro = platform.linux_distribution()
756 if distro[0] == 'Ubuntu' or \
757 distro[0] == 'CentOS Linux' or \
John DeNisco4dc83972018-03-30 10:50:19 -0400758 distro[:7] == 'Red Hat':
John DeNisco68b0ee32017-09-27 16:35:23 -0400759 return distro
760 else:
761 raise RuntimeError('Linux Distribution {} is not supported'.format(distro[0]))
762
763 @staticmethod
764 def version():
765 """
766
767 Gets VPP Version information
768
769 :returns: version
770 :rtype: dict
771 """
772
773 version = {}
774 cmd = 'vppctl show version verbose'
775 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
776 if ret != 0:
777 return version
778
779 lines = stdout.split('\n')
780 if len(lines[0]) is not 0:
781 if lines[0].split(' ')[0] == 'FileNotFoundError':
782 return version
783
784 for line in lines:
785 if len(line) is 0:
786 continue
787 dct = line.split(':')
788 version[dct[0]] = dct[1].lstrip(' ')
789
790 return version
John DeNiscoc6b2a202017-11-01 12:37:47 -0400791
792 @staticmethod
793 def show_bridge(node):
794 """
795 Shows the current bridge configuration
796
797 :param node: VPP node.
798 :type node: dict
John DeNisco9fa5cf42018-02-06 15:23:05 -0500799 :returns: A list of interfaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400800 """
801
John DeNisco9fa5cf42018-02-06 15:23:05 -0500802 ifaces = []
John DeNiscoc6b2a202017-11-01 12:37:47 -0400803 cmd = 'vppctl show bridge'
804 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
805 if ret != 0:
806 raise RuntimeError('{} failed on node {} {} {}'.
807 format(cmd, node['host'],
808 stdout, stderr))
809 lines = stdout.split('\r\n')
810 bridges = []
811 for line in lines:
812 if line == 'no bridge-domains in use':
813 print line
John DeNisco9fa5cf42018-02-06 15:23:05 -0500814 return ifaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400815 if len(line) == 0:
816 continue
817
818 lspl = line.lstrip(' ').split()
819 if lspl[0] != 'BD-ID':
820 bridges.append(lspl[0])
821
822 for bridge in bridges:
823 cmd = 'vppctl show bridge {} detail'.format(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))
John DeNisco9fa5cf42018-02-06 15:23:05 -0500829
830 lines = stdout.split('\r\n')
831 for line in lines:
832 iface = re.findall(r'[a-zA-z]+\d+/\d+/\d+', line)
833 if len(iface):
jdeniscob0b9dad2018-12-18 15:29:45 -0500834 ifcidx = {'name': iface[0], 'index': line.split()[1]}
John DeNisco9fa5cf42018-02-06 15:23:05 -0500835 ifaces.append(ifcidx)
836
837 print stdout
John DeNisco4dc83972018-03-30 10:50:19 -0400838 return ifaces