Allow the user to select master or release during the install
[vpp.git] / extras / vpp_config / vpplib / VPPUtil.py
1 # 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"""
15 import logging
16 import re
17 import subprocess
18 import platform
19 import requests
20
21 from collections import Counter
22
23
24 class 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
112     def _install_vpp_ubuntu(self, node, branch, ubuntu_version='xenial'):
113         """
114         Install the VPP packages
115
116         :param node: Node dictionary with cpuinfo.
117         :param branch: VPP branch
118         :param ubuntu_version: Ubuntu Version
119         :type node: dict
120         :type branch: string
121         :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
130         reps = 'deb [trusted=yes] https://packagecloud.io/fdio/'
131         reps += '{}/ubuntu {} main ./\n'.format(branch, ubuntu_version)
132
133         with open(sfile, 'w') as sfd:
134             sfd.write(reps)
135             sfd.close()
136
137         # Add the key
138         key = requests.get('https://packagecloud.io/fdio/{}/gpgkey'.format(branch))
139         cmd = 'echo "{}" | apt-key add -'.format(key.content)
140         (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')
159         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
165     def _install_vpp_centos(self, node, branch):
166         """
167         Install the VPP packages
168
169         :param node: Node dictionary with cpuinfo.
170         :param branch: The branch name  release or master
171         :type node: dict
172         :type branch: string
173         """
174
175         # 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
192         # 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
207         # Get the file contents
208         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)
211         reps += 'repo_gpgcheck=1\n'
212         reps += 'gpgcheck=0\n'
213         reps += 'enabled=1\n'
214         reps += 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey\n'.format(branch)
215         reps += 'sslverify=1\n'
216         reps += 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt\n'
217         reps += 'metadata_expire=300\n'
218         reps += '\n'
219         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)
222         reps += 'repo_gpgcheck=1\n'
223         reps += 'gpgcheck=0\n'
224         reps += 'enabled=1\n'
225         reps += 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey\n'.format(branch)
226         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'
236         (ret, stdout, stderr) = self.exec_command(cmd)
237         if ret != 0:
238             logging.debug('{} failed on node {} {}'.format(
239                 cmd,
240                 node['host'],
241                 stderr))
242
243         cmd = "yum -q makecache -y --disablerepo='*' --enablerepo='fdio_{}'".format(branch)
244         (ret, stdout, stderr) = self.exec_command(cmd)
245         if ret != 0:
246             logging.debug('{} failed on node {} {}'.format(
247                 cmd,
248                 node['host'],
249                 stderr))
250
251         # Install the packages
252         self._install_vpp_pkg_centos(node, 'vpp-selinux-policy')
253         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')
256         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')
260         self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
261
262     def install_vpp(self, node, branch):
263         """
264         Install the VPP packages
265
266         :param node: Node dictionary with cpuinfo.
267         :param branch: The branch name
268         :type node: dict
269         :type branch: string
270
271         """
272         distro = self.get_linux_distro()
273         logging.info("  {}".format(distro[0]))
274         if distro[0] == 'Ubuntu':
275             logging.info("Install Ubuntu")
276             self._install_vpp_ubuntu(node, branch, ubuntu_version=distro[2])
277         elif distro[0] == 'CentOS Linux':
278             logging.info("Install CentOS")
279             self._install_vpp_centos(node, branch)
280         else:
281             logging.info("Install CentOS (default)")
282             self._install_vpp_centos(node, branch)
283         return
284
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")
327                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dbg')
328                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dev')
329                 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')
333                 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")
355                 self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
356                 self._uninstall_vpp_pkg_centos(node, 'vpp-devel')
357                 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')
361                 self._uninstall_vpp_pkg_centos(node, 'vpp')
362                 self._uninstall_vpp_pkg_centos(node, 'vpp-lib')
363                 self._uninstall_vpp_pkg_centos(node, 'vpp-selinux-policy')
364             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         """
378
379         # First stop VPP
380         self.stop(node)
381
382         distro = self.get_linux_distro()
383         if distro[0] == 'Ubuntu':
384             logging.info("Uninstall Ubuntu")
385             self._uninstall_vpp_ubuntu(node)
386         elif distro[0] == 'CentOS Linux':
387             logging.info("Uninstall CentOS")
388             self._uninstall_vpp_centos(node)
389         else:
390             logging.info("Uninstall CentOS (Default)")
391             self._uninstall_vpp_centos(node)
392             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
422     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
439     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
459         name = ''
460         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
479     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
486         :returns: Dictionary containing VPP hardware information
487         :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
527             rfall = re.findall(r'numa \d+', line)
528             if rfall:
529                 spl = rfall[0].split()
530                 interfaces[name]['numa'] = rfall[0].split()[1]
531
532             # Queues and Descriptors
533             rfall = re.findall(r'rx\: queues \d+', line)
534             if rfall:
535                 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]
546
547         return interfaces
548
549     def _get_installed_vpp_pkgs_ubuntu(self, distro):
550         """
551         Get the VPP hardware information and return it in a
552         dictionary
553
554         :param distro: The linux distro
555         :type distro: dict
556         :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':
617             pkgs = self._get_installed_vpp_pkgs_ubuntu(distro)
618         elif distro[0] == 'CentOS Linux':
619             pkgs = self._get_installed_vpp_pkgs_centos()
620         else:
621             pkgs = self._get_installed_vpp_pkgs_centos()
622             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
659     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
676     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:
705             logging.debug('{} failed on node {} {} {}'.format(cmd, node['host'], stdout, stderr))
706
707     # noinspection RegExpRedundantEscape
708     @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 \
758                         distro[:7] == 'Red Hat':
759             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
791
792     @staticmethod
793     def show_bridge(node):
794         """
795         Shows the current bridge configuration
796
797         :param node: VPP node.
798         :type node: dict
799         :returns: A list of interfaces
800         """
801
802         ifaces = []
803         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
814                 return ifaces
815             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))
829
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):
834                 ifcidx = {'name': iface[0], 'index': line.split()[1]}
835                 ifaces.append(ifcidx)
836
837         print stdout
838         return ifaces