blob: 38c71081ac04cd8b7765242ea287d28e574048b3 [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
jdenisco24010fb2018-11-13 12:40:12 -050020import requests
John DeNisco68b0ee32017-09-27 16:35:23 -040021
22from collections import Counter
23
Paul Vinciguerraef1ae3a2019-04-30 21:15:18 -070024import distro
25
jdeniscoabfd7782019-05-01 15:27:40 -040026ubuntu_pkgs = {'release': ['vpp', 'vpp-plugin-core', 'vpp-plugin-dpdk', 'vpp-api-python', 'python3-vpp-api',
jdenisco2cefb062019-02-19 16:25:05 -050027 'vpp-dbg', 'vpp-dev'],
jdeniscoabfd7782019-05-01 15:27:40 -040028 'master': ['vpp', 'vpp-plugin-core', 'vpp-plugin-dpdk', 'vpp-api-python', 'python3-vpp-api',
29 'vpp-dbg', 'vpp-dev']}
jdenisco2cefb062019-02-19 16:25:05 -050030
jdeniscoabfd7782019-05-01 15:27:40 -040031centos_pkgs = {'release': ['vpp', 'vpp-selinux-policy', 'vpp-plugins', 'vpp-api-lua',
jdenisco2cefb062019-02-19 16:25:05 -050032 'vpp-api-python', 'vpp-debuginfo', 'vpp-devel', 'libvpp0'],
jdeniscoabfd7782019-05-01 15:27:40 -040033 'master': ['vpp', 'vpp-selinux-policy', 'vpp-plugins', 'vpp-api-lua',
jdenisco2cefb062019-02-19 16:25:05 -050034 'vpp-api-python', 'vpp-debuginfo', 'vpp-devel', 'libvpp0']}
35
John DeNisco68b0ee32017-09-27 16:35:23 -040036
37class VPPUtil(object):
38 """General class for any VPP related methods/functions."""
39
40 @staticmethod
41 def exec_command(cmd, timeout=None):
42 """Execute a command on the local node.
43
44 :param cmd: Command to run locally.
45 :param timeout: Timeout value
46 :type cmd: str
47 :type timeout: int
48 :return return_code, stdout, stderr
49 :rtype: tuple(int, str, str)
50 """
51
52 logging.info(" Local Command: {}".format(cmd))
53 out = ''
54 err = ''
55 prc = subprocess.Popen(cmd, shell=True, bufsize=1,
56 stdin=subprocess.PIPE,
57 stdout=subprocess.PIPE,
58 stderr=subprocess.PIPE)
59
60 with prc.stdout:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -080061 lines = prc.stdout.readlines()
62 for line in lines:
63 if type(line) != str:
64 line = line.decode()
John DeNisco68b0ee32017-09-27 16:35:23 -040065 logging.info(" {}".format(line.strip('\n')))
66 out += line
67
68 with prc.stderr:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -080069 lines = prc.stderr.readlines()
70 for line in lines:
71 if type(line) != str:
72 line = line.decode()
jdenisco2cefb062019-02-19 16:25:05 -050073 logging.warning(" {}".format(line.strip('\n')))
John DeNisco68b0ee32017-09-27 16:35:23 -040074 err += line
75
76 ret = prc.wait()
77
78 return ret, out, err
79
80 def _autoconfig_backup_file(self, filename):
81 """
82 Create a backup file.
83
84 :param filename: The file to backup
85 :type filename: str
86 """
87
88 # Does a copy of the file exist, if not create one
89 ofile = filename + '.orig'
90 (ret, stdout, stderr) = self.exec_command('ls {}'.format(ofile))
91 if ret != 0:
92 logging.debug(stderr)
93 if stdout.strip('\n') != ofile:
94 cmd = 'sudo cp {} {}'.format(filename, ofile)
95 (ret, stdout, stderr) = self.exec_command(cmd)
96 if ret != 0:
97 logging.debug(stderr)
98
jdeniscob0b9dad2018-12-18 15:29:45 -050099 def _install_vpp_ubuntu(self, node, branch, ubuntu_version='xenial'):
John DeNisco68b0ee32017-09-27 16:35:23 -0400100 """
101 Install the VPP packages
102
103 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500104 :param branch: VPP branch
John DeNisco68b0ee32017-09-27 16:35:23 -0400105 :param ubuntu_version: Ubuntu Version
106 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500107 :type branch: string
John DeNisco68b0ee32017-09-27 16:35:23 -0400108 :type ubuntu_version: string
109 """
110
111 # Modify the sources list
112 sfile = '/etc/apt/sources.list.d/99fd.io.list'
113
114 # Backup the sources list
115 self._autoconfig_backup_file(sfile)
116
jdenisco24010fb2018-11-13 12:40:12 -0500117 reps = 'deb [trusted=yes] https://packagecloud.io/fdio/'
jdenisco2cefb062019-02-19 16:25:05 -0500118 reps += '{}/ubuntu {} main\n'.format(branch, ubuntu_version)
John DeNisco68b0ee32017-09-27 16:35:23 -0400119
jdenisco24010fb2018-11-13 12:40:12 -0500120 with open(sfile, 'w') as sfd:
121 sfd.write(reps)
122 sfd.close()
123
124 # Add the key
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800125
126 key = requests.get(
127 'https://packagecloud.io/fdio/{}/gpgkey'.format(branch))
128 cmd = 'echo "{}" | apt-key add -'.format(key.content.decode(key.encoding))
John DeNisco68b0ee32017-09-27 16:35:23 -0400129 (ret, stdout, stderr) = self.exec_command(cmd)
130 if ret != 0:
131 raise RuntimeError('{} failed on node {} {}'.format(
132 cmd,
133 node['host'],
134 stderr))
135
136 # Install the package
137 cmd = 'apt-get -y update'
138 (ret, stdout, stderr) = self.exec_command(cmd)
139 if ret != 0:
140 raise RuntimeError('{} apt-get update failed on node {} {}'.format(
141 cmd,
142 node['host'],
143 stderr))
144
jdenisco2cefb062019-02-19 16:25:05 -0500145 # Get the package list
146 pkgstr = ''
147 for ps in ubuntu_pkgs[branch]:
148 pkgstr += ps + ' '
149
150 cmd = 'apt-get -y install {}'.format(pkgstr)
151 (ret, stdout, stderr) = self.exec_command(cmd)
152 if ret != 0:
153 raise RuntimeError('{} failed on node {} {} {}'.format(
154 cmd, node['host'], stdout, stderr))
John DeNisco68b0ee32017-09-27 16:35:23 -0400155
jdeniscob0b9dad2018-12-18 15:29:45 -0500156 def _install_vpp_centos(self, node, branch):
John DeNisco68b0ee32017-09-27 16:35:23 -0400157 """
158 Install the VPP packages
159
160 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500161 :param branch: The branch name release or master
John DeNisco68b0ee32017-09-27 16:35:23 -0400162 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500163 :type branch: string
John DeNisco68b0ee32017-09-27 16:35:23 -0400164 """
165
jdenisco24010fb2018-11-13 12:40:12 -0500166 # Be sure the correct system packages are installed
167 cmd = 'yum -y update'
168 (ret, stdout, stderr) = self.exec_command(cmd)
169 if ret != 0:
170 logging.debug('{} failed on node {} {}'.format(
171 cmd,
172 node['host'],
173 stderr))
174
175 cmd = 'yum -y install pygpgme yum-utils'
176 (ret, stdout, stderr) = self.exec_command(cmd)
177 if ret != 0:
178 logging.debug('{} failed on node {} {}'.format(
179 cmd,
180 node['host'],
181 stderr))
182
John DeNisco68b0ee32017-09-27 16:35:23 -0400183 # Modify the sources list
184 sfile = '/etc/yum.repos.d/fdio-release.repo'
185
186 # Backup the sources list
187 self._autoconfig_backup_file(sfile)
188
189 # Remove the current file
190 cmd = 'rm {}'.format(sfile)
191 (ret, stdout, stderr) = self.exec_command(cmd)
192 if ret != 0:
193 logging.debug('{} failed on node {} {}'.format(
194 cmd,
195 node['host'],
196 stderr))
197
jdenisco24010fb2018-11-13 12:40:12 -0500198 # Get the file contents
jdenisco24010fb2018-11-13 12:40:12 -0500199
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800200 reps = '\n'.join([
201 '[fdio_{}]'.format(branch),
202 'name=fdio_{}'.format(branch),
203 'baseurl=https://packagecloud.io/fdio/{}/el/7/$basearch'.format(
204 branch),
205 'repo_gpgcheck=1',
206 'gpgcheck=0',
207 'enabled=1',
208 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey'.format(branch),
209 'sslverify=1',
210 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt',
211 'metadata_expire=300\n',
212 '[fdio_{}-source]'.format(branch),
213 'name=fdio_release-{}'.format(branch),
214 'baseurl=https://packagecloud.io/fdio/{}/el/7/SRPMS'.format(
215 branch),
216 'repo_gpgcheck=1',
217 'gpgcheck=0',
218 'enabled=1',
219 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey'.format(branch),
220 'sslverify =1',
221 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt',
222 'metadata_expire=300\n'
223 ])
jdenisco24010fb2018-11-13 12:40:12 -0500224 with open(sfile, 'w') as sfd:
225 sfd.write(reps)
226 sfd.close()
227
228 # Update the fdio repo
229 cmd = 'yum clean all'
John DeNisco68b0ee32017-09-27 16:35:23 -0400230 (ret, stdout, stderr) = self.exec_command(cmd)
231 if ret != 0:
jdenisco24010fb2018-11-13 12:40:12 -0500232 logging.debug('{} failed on node {} {}'.format(
233 cmd,
234 node['host'],
235 stderr))
236
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800237 cmd = "yum -q makecache -y --disablerepo='*' " \
238 "--enablerepo='fdio_{}'".format(branch)
jdenisco24010fb2018-11-13 12:40:12 -0500239 (ret, stdout, stderr) = self.exec_command(cmd)
240 if ret != 0:
241 logging.debug('{} failed on node {} {}'.format(
John DeNisco68b0ee32017-09-27 16:35:23 -0400242 cmd,
243 node['host'],
244 stderr))
245
jdenisco2cefb062019-02-19 16:25:05 -0500246 # Get the package list
247 pkgstr = ''
248 for ps in centos_pkgs[branch]:
249 pkgstr += ps + ' '
250
251 cmd = 'yum -y install {}'.format(pkgstr)
252 (ret, stdout, stderr) = self.exec_command(cmd)
253 if ret != 0:
254 raise RuntimeError('{} failed on node {} {} {}'.format(
255 cmd, node['host'], stdout, stderr))
John DeNisco68b0ee32017-09-27 16:35:23 -0400256
jdeniscob0b9dad2018-12-18 15:29:45 -0500257 def install_vpp(self, node, branch):
John DeNisco68b0ee32017-09-27 16:35:23 -0400258 """
259 Install the VPP packages
260
261 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500262 :param branch: The branch name
John DeNisco68b0ee32017-09-27 16:35:23 -0400263 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500264 :type branch: string
265
John DeNisco68b0ee32017-09-27 16:35:23 -0400266 """
267 distro = self.get_linux_distro()
John DeNisco4dc83972018-03-30 10:50:19 -0400268 logging.info(" {}".format(distro[0]))
John DeNisco68b0ee32017-09-27 16:35:23 -0400269 if distro[0] == 'Ubuntu':
John DeNisco4dc83972018-03-30 10:50:19 -0400270 logging.info("Install Ubuntu")
jdeniscob0b9dad2018-12-18 15:29:45 -0500271 self._install_vpp_ubuntu(node, branch, ubuntu_version=distro[2])
John DeNisco68b0ee32017-09-27 16:35:23 -0400272 elif distro[0] == 'CentOS Linux':
273 logging.info("Install CentOS")
jdeniscob0b9dad2018-12-18 15:29:45 -0500274 self._install_vpp_centos(node, branch)
John DeNisco68b0ee32017-09-27 16:35:23 -0400275 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400276 logging.info("Install CentOS (default)")
jdeniscob0b9dad2018-12-18 15:29:45 -0500277 self._install_vpp_centos(node, branch)
John DeNisco4dc83972018-03-30 10:50:19 -0400278 return
John DeNisco68b0ee32017-09-27 16:35:23 -0400279
John DeNisco68b0ee32017-09-27 16:35:23 -0400280 def _uninstall_vpp_ubuntu(self, node):
281 """
282 Uninstall the VPP packages
283
284 :param node: Node dictionary with cpuinfo.
285 :type node: dict
286 """
John DeNisco68b0ee32017-09-27 16:35:23 -0400287
jdenisco2cefb062019-02-19 16:25:05 -0500288 # get the package list
289 pkgstr = ''
290 pkgs = self.get_installed_vpp_pkgs()
291 for pkg in pkgs:
292 pkgname = pkg['name']
293 pkgstr += pkgname + ' '
294
295 cmd = 'dpkg --purge {}'.format(pkgstr)
296 (ret, stdout, stderr) = self.exec_command(cmd)
297 if ret != 0:
298 raise RuntimeError('{} failed on node {} {} {}'.format(
299 cmd, node['host'], stdout, stderr))
John DeNisco68b0ee32017-09-27 16:35:23 -0400300
301 def _uninstall_vpp_centos(self, node):
302 """
303 Uninstall the VPP packages
304
305 :param node: Node dictionary with cpuinfo.
306 :type node: dict
jdenisco2cefb062019-02-19 16:25:05 -0500307 """
John DeNisco68b0ee32017-09-27 16:35:23 -0400308
jdenisco2cefb062019-02-19 16:25:05 -0500309 pkgstr = ''
John DeNisco68b0ee32017-09-27 16:35:23 -0400310 pkgs = self.get_installed_vpp_pkgs()
jdenisco2cefb062019-02-19 16:25:05 -0500311 for pkg in pkgs:
312 pkgname = pkg['name']
313 pkgstr += pkgname + ' '
John DeNisco68b0ee32017-09-27 16:35:23 -0400314
jdenisco2cefb062019-02-19 16:25:05 -0500315 logging.info("Uninstalling {}".format(pkgstr))
316 cmd = 'yum -y remove {}'.format(pkgstr)
317 (ret, stdout, stderr) = self.exec_command(cmd)
318 if ret != 0:
319 raise RuntimeError('{} failed on node {} {} {}'.format(
320 cmd, node['host'], stdout, stderr))
John DeNisco68b0ee32017-09-27 16:35:23 -0400321
322 def uninstall_vpp(self, node):
323 """
324 Uninstall the VPP packages
325
326 :param node: Node dictionary with cpuinfo.
327 :type node: dict
328 """
John DeNiscoc6b2a202017-11-01 12:37:47 -0400329
330 # First stop VPP
331 self.stop(node)
John DeNisco68b0ee32017-09-27 16:35:23 -0400332 distro = self.get_linux_distro()
333 if distro[0] == 'Ubuntu':
John DeNisco4dc83972018-03-30 10:50:19 -0400334 logging.info("Uninstall Ubuntu")
John DeNisco68b0ee32017-09-27 16:35:23 -0400335 self._uninstall_vpp_ubuntu(node)
336 elif distro[0] == 'CentOS Linux':
337 logging.info("Uninstall CentOS")
338 self._uninstall_vpp_centos(node)
339 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400340 logging.info("Uninstall CentOS (Default)")
341 self._uninstall_vpp_centos(node)
John DeNisco68b0ee32017-09-27 16:35:23 -0400342 return
343
344 def show_vpp_settings(self, *additional_cmds):
345 """
346 Print default VPP settings. In case others are needed, can be
347 accepted as next parameters (each setting one parameter), preferably
348 in form of a string.
349
350 :param additional_cmds: Additional commands that the vpp should print
351 settings for.
352 :type additional_cmds: tuple
353 """
354 def_setting_tb_displayed = {
355 'IPv6 FIB': 'ip6 fib',
356 'IPv4 FIB': 'ip fib',
357 'Interface IP': 'int addr',
358 'Interfaces': 'int',
359 'ARP': 'ip arp',
360 'Errors': 'err'
361 }
362
363 if additional_cmds:
364 for cmd in additional_cmds:
365 def_setting_tb_displayed['Custom Setting: {}'.format(cmd)] \
366 = cmd
367
368 for _, value in def_setting_tb_displayed.items():
369 self.exec_command('vppctl sh {}'.format(value))
370
371 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400372 def get_vms(node):
373 """
374 Get a list of VMs that are connected to VPP interfaces
375
376 :param node: VPP node.
377 :type node: dict
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800378 :returns: Dictionary containing a list of VMs and the interfaces
379 that are connected to VPP
John DeNiscoc6b2a202017-11-01 12:37:47 -0400380 :rtype: dictionary
381 """
382
383 vmdict = {}
384
jdenisco2cefb062019-02-19 16:25:05 -0500385 print("Need to implement get vms")
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800386
John DeNiscoc6b2a202017-11-01 12:37:47 -0400387 return vmdict
388
389 @staticmethod
John DeNiscoa3db0782017-10-17 11:07:22 -0400390 def get_int_ip(node):
391 """
392 Get the VPP interfaces and IP addresses
393
394 :param node: VPP node.
395 :type node: dict
396 :returns: Dictionary containing VPP interfaces and IP addresses
397 :rtype: dictionary
398 """
399 interfaces = {}
400 cmd = 'vppctl show int addr'
401 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
402 if ret != 0:
403 return interfaces
404
405 lines = stdout.split('\n')
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700406 if len(lines[0]) != 0:
John DeNiscoa3db0782017-10-17 11:07:22 -0400407 if lines[0].split(' ')[0] == 'FileNotFoundError':
408 return interfaces
409
John DeNiscoc6b2a202017-11-01 12:37:47 -0400410 name = ''
John DeNiscoa3db0782017-10-17 11:07:22 -0400411 for line in lines:
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700412 if len(line) == 0:
John DeNiscoa3db0782017-10-17 11:07:22 -0400413 continue
414
415 # If the first character is not whitespace
416 # create a new interface
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700417 if len(re.findall(r'\s', line[0])) == 0:
John DeNiscoa3db0782017-10-17 11:07:22 -0400418 spl = line.split()
419 name = spl[0]
420 if name == 'local0':
421 continue
422 interfaces[name] = {}
423 interfaces[name]['state'] = spl[1].lstrip('(').rstrip('):\r')
424 else:
425 interfaces[name]['address'] = line.lstrip(' ').rstrip('\r')
426
427 return interfaces
428
429 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400430 def get_hardware(node):
431 """
432 Get the VPP hardware information and return it in a
433 dictionary
434
435 :param node: VPP node.
436 :type node: dict
John DeNiscoa3db0782017-10-17 11:07:22 -0400437 :returns: Dictionary containing VPP hardware information
John DeNisco68b0ee32017-09-27 16:35:23 -0400438 :rtype: dictionary
439 """
440
441 interfaces = {}
442 cmd = 'vppctl show hard'
443 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
444 if ret != 0:
445 return interfaces
446
447 lines = stdout.split('\n')
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700448 if len(lines[0]) != 0:
John DeNisco68b0ee32017-09-27 16:35:23 -0400449 if lines[0].split(' ')[0] == 'FileNotFoundError':
450 return interfaces
451
452 for line in lines:
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700453 if len(line) == 0:
John DeNisco68b0ee32017-09-27 16:35:23 -0400454 continue
455
456 # If the first character is not whitespace
457 # create a new interface
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700458 if len(re.findall(r'\s', line[0])) == 0:
John DeNisco68b0ee32017-09-27 16:35:23 -0400459 spl = line.split()
460 name = spl[0]
461 interfaces[name] = {}
462 interfaces[name]['index'] = spl[1]
463 interfaces[name]['state'] = spl[2]
464
465 # Ethernet address
466 rfall = re.findall(r'Ethernet address', line)
467 if rfall:
468 spl = line.split()
469 interfaces[name]['mac'] = spl[2]
470
471 # Carrier
472 rfall = re.findall(r'carrier', line)
473 if rfall:
474 spl = line.split('carrier ')
475 interfaces[name]['carrier'] = spl[1]
476
477 # Socket
jdenisco2cefb062019-02-19 16:25:05 -0500478 spl = ''
jdenisco7c37a672018-11-20 11:25:17 -0500479 rfall = re.findall(r'numa \d+', line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400480 if rfall:
jdenisco7c37a672018-11-20 11:25:17 -0500481 spl = rfall[0].split()
482 interfaces[name]['numa'] = rfall[0].split()[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400483
484 # Queues and Descriptors
jdenisco7c37a672018-11-20 11:25:17 -0500485 rfall = re.findall(r'rx\: queues \d+', line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400486 if rfall:
jdenisco7c37a672018-11-20 11:25:17 -0500487 interfaces[name]['rx queues'] = rfall[0].split()[2]
488 rdesc = re.findall(r'desc \d+', line)
489 if rdesc:
490 interfaces[name]['rx descs'] = rdesc[0].split()[1]
491
492 rfall = re.findall(r'tx\: queues \d+', line)
493 if rfall:
494 interfaces[name]['tx queues'] = rfall[0].split()[2]
495 rdesc = re.findall(r'desc \d+', line)
496 if rdesc:
497 interfaces[name]['tx descs'] = rdesc[0].split()[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400498
499 return interfaces
500
jdenisco2cefb062019-02-19 16:25:05 -0500501 def _get_installed_vpp_pkgs_ubuntu(self):
John DeNisco68b0ee32017-09-27 16:35:23 -0400502 """
503 Get the VPP hardware information and return it in a
504 dictionary
505
506 :returns: List of the packages installed
507 :rtype: list
508 """
509
510 pkgs = []
511 cmd = 'dpkg -l | grep vpp'
512 (ret, stdout, stderr) = self.exec_command(cmd)
513 if ret != 0:
514 return pkgs
515
516 lines = stdout.split('\n')
517 for line in lines:
518 items = line.split()
519 if len(items) < 2:
520 continue
521 pkg = {'name': items[1], 'version': items[2]}
522 pkgs.append(pkg)
523
524 return pkgs
525
526 def _get_installed_vpp_pkgs_centos(self):
527 """
528 Get the VPP hardware information and return it in a
529 dictionary
530
531 :returns: List of the packages installed
532 :rtype: list
533 """
534
535 pkgs = []
536 cmd = 'rpm -qa | grep vpp'
537 (ret, stdout, stderr) = self.exec_command(cmd)
538 if ret != 0:
539 return pkgs
540
541 lines = stdout.split('\n')
542 for line in lines:
543 if len(line) == 0:
544 continue
545
546 items = line.split()
547 if len(items) < 2:
548 pkg = {'name': items[0]}
549 else:
550 pkg = {'name': items[1], 'version': items[2]}
551
552 pkgs.append(pkg)
553
554 return pkgs
555
556 def get_installed_vpp_pkgs(self):
557 """
558 Get the VPP hardware information and return it in a
559 dictionary
560
561 :returns: List of the packages installed
562 :rtype: list
563 """
564
565 distro = self.get_linux_distro()
566 if distro[0] == 'Ubuntu':
jdenisco2cefb062019-02-19 16:25:05 -0500567 pkgs = self._get_installed_vpp_pkgs_ubuntu()
John DeNisco68b0ee32017-09-27 16:35:23 -0400568 elif distro[0] == 'CentOS Linux':
569 pkgs = self._get_installed_vpp_pkgs_centos()
570 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400571 pkgs = self._get_installed_vpp_pkgs_centos()
John DeNisco68b0ee32017-09-27 16:35:23 -0400572 return []
573
574 return pkgs
575
576 @staticmethod
577 def get_interfaces_numa_node(node, *iface_keys):
578 """Get numa node on which are located most of the interfaces.
579
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800580 Return numa node with highest count of interfaces provided as
581 arguments.
582 Return 0 if the interface does not have numa_node information
583 available.
John DeNisco68b0ee32017-09-27 16:35:23 -0400584 If all interfaces have unknown location (-1), then return 0.
585 If most of interfaces have unknown location (-1), but there are
586 some interfaces with known location, then return the second most
587 location of the provided interfaces.
588
589 :param node: Node from DICT__nodes.
590 :param iface_keys: Interface keys for lookup.
591 :type node: dict
592 :type iface_keys: strings
593 """
594 numa_list = []
595 for if_key in iface_keys:
596 try:
597 numa_list.append(node['interfaces'][if_key].get('numa_node'))
598 except KeyError:
599 pass
600
601 numa_cnt_mc = Counter(numa_list).most_common()
602 numa_cnt_mc_len = len(numa_cnt_mc)
603 if numa_cnt_mc_len > 0 and numa_cnt_mc[0][0] != -1:
604 return numa_cnt_mc[0][0]
605 elif numa_cnt_mc_len > 1 and numa_cnt_mc[0][0] == -1:
606 return numa_cnt_mc[1][0]
607
608 return 0
609
610 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400611 def restart(node):
612 """
613
614 Starts vpp for a given node
615
616 :param node: VPP node.
617 :type node: dict
618 """
619
620 cmd = 'service vpp restart'
621 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
622 if ret != 0:
623 raise RuntimeError('{} failed on node {} {} {}'.
624 format(cmd, node['host'],
625 stdout, stderr))
626
627 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400628 def start(node):
629 """
630
631 Starts vpp for a given node
632
633 :param node: VPP node.
634 :type node: dict
635 """
636
637 cmd = 'service vpp start'
638 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
639 if ret != 0:
640 raise RuntimeError('{} failed on node {} {} {}'.
641 format(cmd, node['host'],
642 stdout, stderr))
643
644 @staticmethod
645 def stop(node):
646 """
647
648 Stops vpp for a given node
649
650 :param node: VPP node.
651 :type node: dict
652 """
653
654 cmd = 'service vpp stop'
655 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
656 if ret != 0:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800657 logging.debug('{} failed on node {} {} {}'.
658 format(cmd, node['host'],
659 stdout, stderr))
John DeNisco68b0ee32017-09-27 16:35:23 -0400660
John DeNiscoa7da67f2018-01-26 14:55:33 -0500661 # noinspection RegExpRedundantEscape
John DeNisco68b0ee32017-09-27 16:35:23 -0400662 @staticmethod
663 def status(node):
664 """
665
666 Gets VPP status
667
668 :param: node
669 :type node: dict
670 :returns: status, errors
671 :rtype: tuple(str, list)
672 """
673 errors = []
674 vutil = VPPUtil()
675 pkgs = vutil.get_installed_vpp_pkgs()
676 if len(pkgs) == 0:
677 return "Not Installed", errors
678
679 cmd = 'service vpp status'
680 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
681
682 # Get the active status
683 state = re.findall(r'Active:[\w (\)]+', stdout)[0].split(' ')
684 if len(state) > 2:
685 statestr = "{} {}".format(state[1], state[2])
686 else:
687 statestr = "Invalid"
688
689 # For now we won't look for DPDK errors
690 # lines = stdout.split('\n')
691 # for line in lines:
692 # if 'EAL' in line or \
693 # 'FAILURE' in line or \
694 # 'failed' in line or \
695 # 'Failed' in line:
696 # errors.append(line.lstrip(' '))
697
698 return statestr, errors
699
700 @staticmethod
701 def get_linux_distro():
702 """
703 Get the linux distribution and check if it is supported
704
705 :returns: linux distro, None if the distro is not supported
706 :rtype: list
707 """
708
Paul Vinciguerraef1ae3a2019-04-30 21:15:18 -0700709 dist = distro.linux_distribution()
710 if dist[0] == 'Ubuntu' or \
711 dist[0] == 'CentOS Linux' or \
712 dist[:7] == 'Red Hat':
713 return dist
John DeNisco68b0ee32017-09-27 16:35:23 -0400714 else:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800715 raise RuntimeError(
Paul Vinciguerraef1ae3a2019-04-30 21:15:18 -0700716 'Linux Distribution {} is not supported'.format(dist[0]))
John DeNisco68b0ee32017-09-27 16:35:23 -0400717
718 @staticmethod
719 def version():
720 """
721
722 Gets VPP Version information
723
724 :returns: version
725 :rtype: dict
726 """
727
728 version = {}
729 cmd = 'vppctl show version verbose'
730 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
731 if ret != 0:
732 return version
733
734 lines = stdout.split('\n')
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700735 if len(lines[0]) != 0:
John DeNisco68b0ee32017-09-27 16:35:23 -0400736 if lines[0].split(' ')[0] == 'FileNotFoundError':
737 return version
738
739 for line in lines:
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700740 if len(line) == 0:
John DeNisco68b0ee32017-09-27 16:35:23 -0400741 continue
742 dct = line.split(':')
743 version[dct[0]] = dct[1].lstrip(' ')
744
745 return version
John DeNiscoc6b2a202017-11-01 12:37:47 -0400746
747 @staticmethod
748 def show_bridge(node):
749 """
750 Shows the current bridge configuration
751
752 :param node: VPP node.
753 :type node: dict
John DeNisco9fa5cf42018-02-06 15:23:05 -0500754 :returns: A list of interfaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400755 """
756
John DeNisco9fa5cf42018-02-06 15:23:05 -0500757 ifaces = []
John DeNiscoc6b2a202017-11-01 12:37:47 -0400758 cmd = 'vppctl show bridge'
759 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
760 if ret != 0:
761 raise RuntimeError('{} failed on node {} {} {}'.
762 format(cmd, node['host'],
763 stdout, stderr))
764 lines = stdout.split('\r\n')
765 bridges = []
766 for line in lines:
767 if line == 'no bridge-domains in use':
jdenisco2cefb062019-02-19 16:25:05 -0500768 print(line)
John DeNisco9fa5cf42018-02-06 15:23:05 -0500769 return ifaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400770 if len(line) == 0:
771 continue
772
773 lspl = line.lstrip(' ').split()
774 if lspl[0] != 'BD-ID':
775 bridges.append(lspl[0])
776
777 for bridge in bridges:
778 cmd = 'vppctl show bridge {} detail'.format(bridge)
779 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
780 if ret != 0:
781 raise RuntimeError('{} failed on node {} {} {}'.
782 format(cmd, node['host'],
783 stdout, stderr))
John DeNisco9fa5cf42018-02-06 15:23:05 -0500784
785 lines = stdout.split('\r\n')
786 for line in lines:
787 iface = re.findall(r'[a-zA-z]+\d+/\d+/\d+', line)
788 if len(iface):
jdeniscob0b9dad2018-12-18 15:29:45 -0500789 ifcidx = {'name': iface[0], 'index': line.split()[1]}
John DeNisco9fa5cf42018-02-06 15:23:05 -0500790 ifaces.append(ifcidx)
791
jdenisco2cefb062019-02-19 16:25:05 -0500792 print(stdout)
John DeNisco4dc83972018-03-30 10:50:19 -0400793 return ifaces