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