336097d6e0a5f56ca848070449e937c3b69ad7e0
[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 # VPP_VERSION = '1707'
24 # VPP_VERSION = '1710'
25 VPP_VERSION = '1810'
26
27
28 class 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
135         reps = 'deb [trusted=yes] https://packagecloud.io/fdio/'
136         # When using a stable branch
137         # reps += '{}/ubuntu {} main ./\n'.format(fdio_release, ubuntu_version)
138         # When using release
139         reps += 'release/ubuntu {} main ./\n'.format(ubuntu_version)
140         # When using master
141         # reps += 'master/ubuntu {} main/ ./\n'.format(ubuntu_version)
142
143         with open(sfile, 'w') as sfd:
144             sfd.write(reps)
145             sfd.close()
146
147         # Add the key
148         key = requests.get('https://packagecloud.io/fdio/{}/gpgkey'.format('release'))
149         # cmd = 'curl -L https://packagecloud.io/fdio/{}/gpgkey | apt-key add -'.format(fdio_release)
150         # cmd = 'curl -L https://packagecloud.io/fdio/{}/gpgkey | apt-key add -'.format('mastert')
151         cmd = 'echo "{}" | apt-key add -'.format(key.content)
152         (ret, stdout, stderr) = self.exec_command(cmd)
153         if ret != 0:
154             raise RuntimeError('{} failed on node {} {}'.format(
155                 cmd,
156                 node['host'],
157                 stderr))
158
159         # Install the package
160         cmd = 'apt-get -y update'
161         (ret, stdout, stderr) = self.exec_command(cmd)
162         if ret != 0:
163             raise RuntimeError('{} apt-get update failed on node {} {}'.format(
164                 cmd,
165                 node['host'],
166                 stderr))
167
168         self._install_vpp_pkg_ubuntu(node, 'vpp-lib')
169         self._install_vpp_pkg_ubuntu(node, 'vpp')
170         self._install_vpp_pkg_ubuntu(node, 'vpp-plugins')
171         self._install_vpp_pkg_ubuntu(node, 'vpp-api-python')
172         self._install_vpp_pkg_ubuntu(node, 'vpp-api-java')
173         self._install_vpp_pkg_ubuntu(node, 'vpp-api-lua')
174         self._install_vpp_pkg_ubuntu(node, 'vpp-dev')
175         self._install_vpp_pkg_ubuntu(node, 'vpp-dbg')
176
177     def _install_vpp_centos(self, node, fdio_release=VPP_VERSION,
178                             centos_version='centos7'):
179         """
180         Install the VPP packages
181
182         :param node: Node dictionary with cpuinfo.
183         :param fdio_release: VPP release number
184         :param centos_version: Ubuntu Version
185         :type node: dict
186         :type fdio_release: string
187         :type centos_version: string
188         """
189
190         # Be sure the correct system packages are installed
191         cmd = 'yum -y update'
192         (ret, stdout, stderr) = self.exec_command(cmd)
193         if ret != 0:
194             logging.debug('{} failed on node {} {}'.format(
195                 cmd,
196                 node['host'],
197                 stderr))
198
199         cmd = 'yum -y install pygpgme yum-utils'
200         (ret, stdout, stderr) = self.exec_command(cmd)
201         if ret != 0:
202             logging.debug('{} failed on node {} {}'.format(
203                 cmd,
204                 node['host'],
205                 stderr))
206
207         # Modify the sources list
208         sfile = '/etc/yum.repos.d/fdio-release.repo'
209
210         # Backup the sources list
211         self._autoconfig_backup_file(sfile)
212
213         # Remove the current file
214         cmd = 'rm {}'.format(sfile)
215         (ret, stdout, stderr) = self.exec_command(cmd)
216         if ret != 0:
217             logging.debug('{} failed on node {} {}'.format(
218                 cmd,
219                 node['host'],
220                 stderr))
221
222         # Set the branch
223         bname = 'release'
224         # bname = '1810'
225         # bname = 'master'
226
227         # Get the file contents
228         reps = '[fdio_{}]\n'.format(bname)
229         reps += 'name=fdio_{}\n'.format(bname)
230         reps += 'baseurl=https://packagecloud.io/fdio/{}/el/7/$basearch\n'.format(bname)
231         reps += 'repo_gpgcheck=1\n'
232         reps += 'gpgcheck=0\n'
233         reps += 'enabled=1\n'
234         reps += 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey\n'.format(bname)
235         reps += 'sslverify=1\n'
236         reps += 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt\n'
237         reps += 'metadata_expire=300\n'
238         reps += '\n'
239         reps += '[fdio_{}-source]\n'.format(bname)
240         reps += 'name=fdio_release-{}\n'.format(bname)
241         reps += 'baseurl=https://packagecloud.io/fdio/{}/el/7/SRPMS\n'.format(bname)
242         reps += 'repo_gpgcheck=1\n'
243         reps += 'gpgcheck=0\n'
244         reps += 'enabled=1\n'
245         reps += 'gpgkey=https://packagecloud.io/fdio/{}/gpgkey\n'.format(bname)
246         reps += 'sslverify =1\n'
247         reps += 'sslcacert=/etc/pki/tls/certs/ca-bundle.crt\n'
248         reps += 'metadata_expire=300\n'
249
250         with open(sfile, 'w') as sfd:
251             sfd.write(reps)
252             sfd.close()
253
254         # Update the fdio repo
255         cmd = 'yum clean all'
256         (ret, stdout, stderr) = self.exec_command(cmd)
257         if ret != 0:
258             logging.debug('{} failed on node {} {}'.format(
259                 cmd,
260                 node['host'],
261                 stderr))
262
263         cmd = "yum -q makecache -y --disablerepo='*' --enablerepo='fdio_{}'".format(bname)
264         (ret, stdout, stderr) = self.exec_command(cmd)
265         if ret != 0:
266             logging.debug('{} failed on node {} {}'.format(
267                 cmd,
268                 node['host'],
269                 stderr))
270
271         # Install the packages
272         self._install_vpp_pkg_centos(node, 'vpp-selinux-policy')
273         self._install_vpp_pkg_centos(node, 'vpp-lib')
274         self._install_vpp_pkg_centos(node, 'vpp')
275         self._install_vpp_pkg_centos(node, 'vpp-plugins')
276         self._install_vpp_pkg_centos(node, 'vpp-api-python')
277         self._install_vpp_pkg_centos(node, 'vpp-api-java')
278         self._install_vpp_pkg_centos(node, 'vpp-api-lua')
279         self._install_vpp_pkg_centos(node, 'vpp-devel')
280         self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
281
282     def install_vpp(self, node):
283         """
284         Install the VPP packages
285
286         :param node: Node dictionary with cpuinfo.
287         :type node: dict
288         """
289         distro = self.get_linux_distro()
290         logging.info("  {}".format(distro[0]))
291         if distro[0] == 'Ubuntu':
292             logging.info("Install Ubuntu")
293             self._install_vpp_ubuntu(node)
294         elif distro[0] == 'CentOS Linux':
295             logging.info("Install CentOS")
296             self._install_vpp_centos(node)
297         else:
298             logging.info("Install CentOS (default)")
299             self._install_vpp_centos(node)
300         return
301
302     def _uninstall_vpp_pkg_ubuntu(self, node, pkg):
303         """
304         Uninstall the VPP packages
305
306         :param node: Node dictionary
307         :param pkg: The vpp packages
308         :type node: dict
309         :type pkg: string
310         """
311         cmd = 'dpkg --purge {}'.format(pkg)
312         (ret, stdout, stderr) = self.exec_command(cmd)
313         if ret != 0:
314             raise RuntimeError('{} failed on node {} {} {}'.format(
315                 cmd, node['host'], stdout, stderr))
316
317     def _uninstall_vpp_pkg_centos(self, node, pkg):
318         """
319         Uninstall the VPP packages
320
321         :param node: Node dictionary
322         :param pkg: The vpp packages
323         :type node: dict
324         :type pkg: string
325         """
326         cmd = 'yum -y remove {}'.format(pkg)
327         (ret, stdout, stderr) = self.exec_command(cmd)
328         if ret != 0:
329             raise RuntimeError('{} failed on node {} {} {}'.format(
330                 cmd, node['host'], stdout, stderr))
331
332     def _uninstall_vpp_ubuntu(self, node):
333         """
334         Uninstall the VPP packages
335
336         :param node: Node dictionary with cpuinfo.
337         :type node: dict
338         """
339         pkgs = self.get_installed_vpp_pkgs()
340
341         if len(pkgs) > 0:
342             if 'version' in pkgs[0]:
343                 logging.info("Uninstall Ubuntu Packages")
344                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dbg')
345                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dev')
346                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-python')
347                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-java')
348                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-lua')
349                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-plugins')
350                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp')
351                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-lib')
352             else:
353                 logging.info("Uninstall locally installed Ubuntu Packages")
354                 for pkg in pkgs:
355                     self._uninstall_vpp_pkg_ubuntu(node, pkg['name'])
356         else:
357             logging.error("There are no Ubuntu packages installed")
358
359     def _uninstall_vpp_centos(self, node):
360         """
361         Uninstall the VPP packages
362
363         :param node: Node dictionary with cpuinfo.
364         :type node: dict
365             """
366
367         pkgs = self.get_installed_vpp_pkgs()
368
369         if len(pkgs) > 0:
370             if 'version' in pkgs[0]:
371                 logging.info("Uninstall CentOS Packages")
372                 self._install_vpp_pkg_centos(node, 'vpp-debuginfo')
373                 self._uninstall_vpp_pkg_centos(node, 'vpp-devel')
374                 self._uninstall_vpp_pkg_centos(node, 'vpp-api-python')
375                 self._uninstall_vpp_pkg_centos(node, 'vpp-api-java')
376                 self._uninstall_vpp_pkg_centos(node, 'vpp-api-lua')
377                 self._uninstall_vpp_pkg_centos(node, 'vpp-plugins')
378                 self._uninstall_vpp_pkg_centos(node, 'vpp')
379                 self._uninstall_vpp_pkg_centos(node, 'vpp-lib')
380                 self._uninstall_vpp_pkg_centos(node, 'vpp-selinux-policy')
381             else:
382                 logging.info("Uninstall locally installed CentOS Packages")
383                 for pkg in pkgs:
384                     self._uninstall_vpp_pkg_centos(node, pkg['name'])
385         else:
386             logging.error("There are no CentOS packages installed")
387
388     def uninstall_vpp(self, node):
389         """
390         Uninstall the VPP packages
391
392         :param node: Node dictionary with cpuinfo.
393         :type node: dict
394         """
395
396         # First stop VPP
397         self.stop(node)
398
399         distro = self.get_linux_distro()
400         if distro[0] == 'Ubuntu':
401             logging.info("Uninstall Ubuntu")
402             self._uninstall_vpp_ubuntu(node)
403         elif distro[0] == 'CentOS Linux':
404             logging.info("Uninstall CentOS")
405             self._uninstall_vpp_centos(node)
406         else:
407             logging.info("Uninstall CentOS (Default)")
408             self._uninstall_vpp_centos(node)
409             return
410
411     def show_vpp_settings(self, *additional_cmds):
412         """
413         Print default VPP settings. In case others are needed, can be
414         accepted as next parameters (each setting one parameter), preferably
415         in form of a string.
416
417         :param additional_cmds: Additional commands that the vpp should print
418         settings for.
419         :type additional_cmds: tuple
420         """
421         def_setting_tb_displayed = {
422             'IPv6 FIB': 'ip6 fib',
423             'IPv4 FIB': 'ip fib',
424             'Interface IP': 'int addr',
425             'Interfaces': 'int',
426             'ARP': 'ip arp',
427             'Errors': 'err'
428         }
429
430         if additional_cmds:
431             for cmd in additional_cmds:
432                 def_setting_tb_displayed['Custom Setting: {}'.format(cmd)] \
433                     = cmd
434
435                 for _, value in def_setting_tb_displayed.items():
436                     self.exec_command('vppctl sh {}'.format(value))
437
438     @staticmethod
439     def get_vms(node):
440         """
441         Get a list of VMs that are connected to VPP interfaces
442
443         :param node: VPP node.
444         :type node: dict
445         :returns: Dictionary containing a list of VMs and the interfaces that are connected to VPP
446         :rtype: dictionary
447         """
448
449         vmdict = {}
450
451         print "Need to implement get vms"
452         
453         return vmdict
454
455     @staticmethod
456     def get_int_ip(node):
457         """
458         Get the VPP interfaces and IP addresses
459
460         :param node: VPP node.
461         :type node: dict
462         :returns: Dictionary containing VPP interfaces and IP addresses
463         :rtype: dictionary
464         """
465         interfaces = {}
466         cmd = 'vppctl show int addr'
467         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
468         if ret != 0:
469             return interfaces
470
471         lines = stdout.split('\n')
472         if len(lines[0]) is not 0:
473             if lines[0].split(' ')[0] == 'FileNotFoundError':
474                 return interfaces
475
476         name = ''
477         for line in lines:
478             if len(line) is 0:
479                 continue
480
481             # If the first character is not whitespace
482             # create a new interface
483             if len(re.findall(r'\s', line[0])) is 0:
484                 spl = line.split()
485                 name = spl[0]
486                 if name == 'local0':
487                     continue
488                 interfaces[name] = {}
489                 interfaces[name]['state'] = spl[1].lstrip('(').rstrip('):\r')
490             else:
491                 interfaces[name]['address'] = line.lstrip(' ').rstrip('\r')
492
493         return interfaces
494
495     @staticmethod
496     def get_hardware(node):
497         """
498         Get the VPP hardware information and return it in a
499         dictionary
500
501         :param node: VPP node.
502         :type node: dict
503         :returns: Dictionary containing VPP hardware information
504         :rtype: dictionary
505         """
506
507         interfaces = {}
508         cmd = 'vppctl show hard'
509         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
510         if ret != 0:
511             return interfaces
512
513         lines = stdout.split('\n')
514         if len(lines[0]) is not 0:
515             if lines[0].split(' ')[0] == 'FileNotFoundError':
516                 return interfaces
517
518         for line in lines:
519             if len(line) is 0:
520                 continue
521
522             # If the first character is not whitespace
523             # create a new interface
524             if len(re.findall(r'\s', line[0])) is 0:
525                 spl = line.split()
526                 name = spl[0]
527                 interfaces[name] = {}
528                 interfaces[name]['index'] = spl[1]
529                 interfaces[name]['state'] = spl[2]
530
531             # Ethernet address
532             rfall = re.findall(r'Ethernet address', line)
533             if rfall:
534                 spl = line.split()
535                 interfaces[name]['mac'] = spl[2]
536
537             # Carrier
538             rfall = re.findall(r'carrier', line)
539             if rfall:
540                 spl = line.split('carrier ')
541                 interfaces[name]['carrier'] = spl[1]
542
543             # Socket
544             rfall = re.findall(r'cpu socket', line)
545             if rfall:
546                 spl = line.split('cpu socket ')
547                 interfaces[name]['cpu socket'] = spl[1]
548
549             # Queues and Descriptors
550             rfall = re.findall(r'rx queues', line)
551             if rfall:
552                 spl = line.split(',')
553                 interfaces[name]['rx queues'] = spl[0].lstrip(' ').split(' ')[2]
554                 interfaces[name]['rx descs'] = spl[1].split(' ')[3]
555                 interfaces[name]['tx queues'] = spl[2].split(' ')[3]
556                 interfaces[name]['tx descs'] = spl[3].split(' ')[3]
557
558         return interfaces
559
560     def _get_installed_vpp_pkgs_ubuntu(self):
561         """
562         Get the VPP hardware information and return it in a
563         dictionary
564
565         :returns: List of the packages installed
566         :rtype: list
567         """
568
569         pkgs = []
570         cmd = 'dpkg -l | grep vpp'
571         (ret, stdout, stderr) = self.exec_command(cmd)
572         if ret != 0:
573             return pkgs
574
575         lines = stdout.split('\n')
576         for line in lines:
577             items = line.split()
578             if len(items) < 2:
579                 continue
580             pkg = {'name': items[1], 'version': items[2]}
581             pkgs.append(pkg)
582
583         return pkgs
584
585     def _get_installed_vpp_pkgs_centos(self):
586         """
587         Get the VPP hardware information and return it in a
588         dictionary
589
590         :returns: List of the packages installed
591         :rtype: list
592         """
593
594         pkgs = []
595         cmd = 'rpm -qa | grep vpp'
596         (ret, stdout, stderr) = self.exec_command(cmd)
597         if ret != 0:
598             return pkgs
599
600         lines = stdout.split('\n')
601         for line in lines:
602             if len(line) == 0:
603                 continue
604
605             items = line.split()
606             if len(items) < 2:
607                 pkg = {'name': items[0]}
608             else:
609                 pkg = {'name': items[1], 'version': items[2]}
610
611             pkgs.append(pkg)
612
613         return pkgs
614
615     def get_installed_vpp_pkgs(self):
616         """
617         Get the VPP hardware information and return it in a
618         dictionary
619
620         :returns: List of the packages installed
621         :rtype: list
622         """
623
624         distro = self.get_linux_distro()
625         if distro[0] == 'Ubuntu':
626             pkgs = self._get_installed_vpp_pkgs_ubuntu()
627         elif distro[0] == 'CentOS Linux':
628             pkgs = self._get_installed_vpp_pkgs_centos()
629         else:
630             pkgs = self._get_installed_vpp_pkgs_centos()
631             return []
632
633         return pkgs
634
635     @staticmethod
636     def get_interfaces_numa_node(node, *iface_keys):
637         """Get numa node on which are located most of the interfaces.
638
639         Return numa node with highest count of interfaces provided as arguments.
640         Return 0 if the interface does not have numa_node information available.
641         If all interfaces have unknown location (-1), then return 0.
642         If most of interfaces have unknown location (-1), but there are
643         some interfaces with known location, then return the second most
644         location of the provided interfaces.
645
646         :param node: Node from DICT__nodes.
647         :param iface_keys: Interface keys for lookup.
648         :type node: dict
649         :type iface_keys: strings
650         """
651         numa_list = []
652         for if_key in iface_keys:
653             try:
654                 numa_list.append(node['interfaces'][if_key].get('numa_node'))
655             except KeyError:
656                 pass
657
658         numa_cnt_mc = Counter(numa_list).most_common()
659         numa_cnt_mc_len = len(numa_cnt_mc)
660         if numa_cnt_mc_len > 0 and numa_cnt_mc[0][0] != -1:
661             return numa_cnt_mc[0][0]
662         elif numa_cnt_mc_len > 1 and numa_cnt_mc[0][0] == -1:
663             return numa_cnt_mc[1][0]
664
665         return 0
666
667     @staticmethod
668     def restart(node):
669         """
670
671         Starts vpp for a given node
672
673         :param node: VPP node.
674         :type node: dict
675         """
676
677         cmd = 'service vpp restart'
678         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
679         if ret != 0:
680             raise RuntimeError('{} failed on node {} {} {}'.
681                                format(cmd, node['host'],
682                                       stdout, stderr))
683
684     @staticmethod
685     def start(node):
686         """
687
688         Starts vpp for a given node
689
690         :param node: VPP node.
691         :type node: dict
692         """
693
694         cmd = 'service vpp start'
695         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
696         if ret != 0:
697             raise RuntimeError('{} failed on node {} {} {}'.
698                                format(cmd, node['host'],
699                                       stdout, stderr))
700
701     @staticmethod
702     def stop(node):
703         """
704
705         Stops vpp for a given node
706
707         :param node: VPP node.
708         :type node: dict
709         """
710
711         cmd = 'service vpp stop'
712         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
713         if ret != 0:
714             logging.debug('{} failed on node {} {} {}'.
715                                format(cmd, node['host'],
716                                       stdout, stderr))
717
718     # noinspection RegExpRedundantEscape
719     @staticmethod
720     def status(node):
721         """
722
723         Gets VPP status
724
725         :param: node
726         :type node: dict
727         :returns: status, errors
728         :rtype: tuple(str, list)
729         """
730         errors = []
731         vutil = VPPUtil()
732         pkgs = vutil.get_installed_vpp_pkgs()
733         if len(pkgs) == 0:
734             return "Not Installed", errors
735
736         cmd = 'service vpp status'
737         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
738
739         # Get the active status
740         state = re.findall(r'Active:[\w (\)]+', stdout)[0].split(' ')
741         if len(state) > 2:
742             statestr = "{} {}".format(state[1], state[2])
743         else:
744             statestr = "Invalid"
745
746         # For now we won't look for DPDK errors
747         # lines = stdout.split('\n')
748         # for line in lines:
749         #    if 'EAL' in line or \
750         #                     'FAILURE' in line or \
751         #                     'failed' in line or \
752         #                     'Failed' in line:
753         #         errors.append(line.lstrip(' '))
754
755         return statestr, errors
756
757     @staticmethod
758     def get_linux_distro():
759         """
760         Get the linux distribution and check if it is supported
761
762         :returns: linux distro, None if the distro is not supported
763         :rtype: list
764         """
765
766         distro = platform.linux_distribution()
767         if distro[0] == 'Ubuntu' or \
768                         distro[0] == 'CentOS Linux' or \
769                         distro[:7] == 'Red Hat':
770             return distro
771         else:
772             raise RuntimeError('Linux Distribution {} is not supported'.format(distro[0]))
773
774     @staticmethod
775     def version():
776         """
777
778         Gets VPP Version information
779
780         :returns: version
781         :rtype: dict
782         """
783
784         version = {}
785         cmd = 'vppctl show version verbose'
786         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
787         if ret != 0:
788             return version
789
790         lines = stdout.split('\n')
791         if len(lines[0]) is not 0:
792             if lines[0].split(' ')[0] == 'FileNotFoundError':
793                 return version
794
795         for line in lines:
796             if len(line) is 0:
797                 continue
798             dct = line.split(':')
799             version[dct[0]] = dct[1].lstrip(' ')
800
801         return version
802
803     @staticmethod
804     def show_bridge(node):
805         """
806         Shows the current bridge configuration
807
808         :param node: VPP node.
809         :type node: dict
810         :returns: A list of interfaces
811         """
812
813         ifaces = []
814         cmd = 'vppctl show bridge'
815         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
816         if ret != 0:
817             raise RuntimeError('{} failed on node {} {} {}'.
818                                format(cmd, node['host'],
819                                       stdout, stderr))
820         lines = stdout.split('\r\n')
821         bridges = []
822         for line in lines:
823             if line == 'no bridge-domains in use':
824                 print line
825                 return ifaces
826             if len(line) == 0:
827                 continue
828
829             lspl = line.lstrip(' ').split()
830             if lspl[0] != 'BD-ID':
831                 bridges.append(lspl[0])
832
833         for bridge in bridges:
834             cmd = 'vppctl show bridge {} detail'.format(bridge)
835             (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
836             if ret != 0:
837                 raise RuntimeError('{} failed on node {} {} {}'.
838                                    format(cmd, node['host'],
839                                           stdout, stderr))
840
841         lines = stdout.split('\r\n')
842         for line in lines:
843             iface = re.findall(r'[a-zA-z]+\d+/\d+/\d+', line)
844             if len(iface):
845                 ifcidx ={'name': iface[0], 'index': line.split()[1] }
846                 ifaces.append(ifcidx)
847
848         print stdout
849         return ifaces