aboutsummaryrefslogtreecommitdiffstats
path: root/extras/vpp_config/vpplib/VPPUtil.py
blob: d6354858828bf7e2c54495b98ea975cf1be926cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
AC_INIT([vpp], [17.04], [vpp-dev@fd.io])
LT_INIT
AC_CONFIG_AUX_DIR([.])
AM_INIT_AUTOMAKE([subdir-objects])
AM_SILENT_RULES([yes])
AC_CONFIG_FILES([Makefile plugins/Makefile vpp-api/python/Makefile vpp-api/java/Makefile])
AC_CONFIG_MACRO_DIR([m4])

AC_PROG_CC
AM_PROG_AS
AM_PROG_LIBTOOL
AC_PROG_YACC

AM_CONDITIONAL([CROSSCOMPILE], [test "$cross_compiling" == "yes"])

###############################################################################
# Macros
###############################################################################

AC_DEFUN([ENABLE_ARG],
[
  AC_ARG_ENABLE($1,
    AC_HELP_STRING(patsubst([--enable-$1],[_],[-]), $2),
    [enable_$1=yes n_enable_$1=1],
    [enable_$1=no n_enable_$1=0])
  AM_CONDITIONAL(m4_toupper(ENABLE_$1), test "$enable_$1" = "yes")
  m4_append([list_of_enabled], [$1], [, ])
])

AC_DEFUN([DISABLE_ARG],
[
  AC_ARG_ENABLE($1,
    AC_HELP_STRING(patsubst([--disable-$1],[_],[-]), $2),
    [enable_$1=no n_enable_$1=0],
    [enable_$1=yes n_enable_$1=1])
  AM_CONDITIONAL(m4_toupper(ENABLE_$1), test "$enable_$1" = "yes")
  m4_append([list_of_enabled], [$1], [, ])
])

AC_DEFUN([WITH_ARG],
[
  AC_ARG_WITH($1,
    AC_HELP_STRING(patsubst([--with-$1],[_],[-]), $2),
    [with_$1=yes n_with_$1=1],
    [with_$1=no n_with_$1=0])
  AM_CONDITIONAL(m4_toupper(WITH_$1), test "$with_$1" = "yes")
  m4_append([list_of_with], [$1], [, ])
])

AC_DEFUN([WITHOUT_ARG],
[
  AC_ARG_WITH($1,
    AC_HELP_STRING(patsubst([--without-$1],[_],[-]), $2),
    [with_$1=no n_with_$1=0],
    [with_$1=yes n_with_$1=1])
  AM_CONDITIONAL(m4_toupper(WITH_$1), test "$with_$1" = "yes")
  m4_append([list_of_with], [$1], [, ])
])

AC_DEFUN([PLUGIN_ENABLED],
[
   AC_ARG_ENABLE($1_plugin,
     AC_HELP_STRING([--disable-$1-plugin], [Do not build $1 plugin]),
       [enable_$1_plugin=no],
       [enable_$1_plugin=yes ])
  AM_CONDITIONAL(m4_toupper(ENABLE_$1_PLUGIN), test "$enable_$1_plugin" = "yes")
  m4_append([list_of_plugins], [$1], [, ])
])

AC_DEFUN([PLUGIN_DISABLED],
[
   AC_ARG_ENABLE($1_plugin,
     AC_HELP_STRING([--enable-$1-plugin], [Build $1 plugin]),
       [enable_$1_plugin=yes ],
       [enable_$1_plugin=no])
  AM_CONDITIONAL(m4_toupper((ENABLE_$1_PLUGIN), test "$enable_$1_plugin" = "yes")
  m4_append([list_of_plugins], [$1], [, ])
])

AC_DEFUN([PRINT_VAL], [ AC_MSG_RESULT(AC_HELP_STRING($1,$2)) ])

###############################################################################
# configure arguments
###############################################################################

# --enable-X
ENABLE_ARG(tests,	[Enable unit tests])
ENABLE_ARG(dpdk_shared,	[Enable unit tests])
ENABLE_ARG(perftool,	[Enable perftool])
ENABLE_ARG(g2,		[Enable g2])

# --disable-X
DISABLE_ARG(vlib,	[Disable vlib and dependant libs and binaries])
DISABLE_ARG(svm,	[Disable svm and dependant libs and binaries])
DISABLE_ARG(papi,	[Disable Python API bindings])
DISABLE_ARG(japi,	[Disable Java API bindings])

# --with-X
WITH_ARG(dpdk,		[Use use DPDK])
WITH_ARG(dpdk_crypto,	[Use DPDK cryptodev])
WITH_ARG(dpdk_mlx5_pmd,	[Use DPDK with mlx5 PMD])

# --without-X
WITHOUT_ARG(libssl,	[Disable libssl])
WITHOUT_ARG(apicli,	[Disable binary api CLI])

AC_ARG_WITH(unix,
            AC_HELP_STRING([--with-unix],[Compile unix version of clib]),
	    [],
	    [case $host_os in
	      darwin* | linux*) with_unix=yes;;
	      *) with_unix=no;;
	      esac])

AM_CONDITIONAL(WITH_UNIX, test "$with_unix" = "yes")

AC_ARG_WITH(pre-data,
            AC_HELP_STRING([--with-pre-data],[Set buffer rewrite space]),
	    [case $with_pre_data in
	       128) ;;
	       256) ;;
               *) with_pre_data="pre-data-not-set" ;;
	     esac], [with_pre_data=128])

###############################################################################
# Substitutions and defines
###############################################################################

AC_SUBST(PRE_DATA_SIZE,		[$with_pre_data])
AC_SUBST(APICLI,		[-DVPP_API_TEST_BUILTIN=${n_with_apicli}])

AC_DEFINE_UNQUOTED(DPDK, 		[${n_with_dpdk}])
AC_DEFINE_UNQUOTED(DPDK_SHARED_LIB,	[${n_enable_dpdk_shared}])
AC_DEFINE_UNQUOTED(DPDK_CRYPTO,		[${n_with_dpdk_crypto}])
AC_DEFINE_UNQUOTED(WITH_LIBSSL,		[${n_with_libssl}])


# Silence following noise:
# ar: `u' modifier ignored since `D' is the default (see `U')
AR_FLAGS=cr
AC_SUBST(AR_FLAGS)

###############################################################################
# Plugins
###############################################################################

# Please keep alphabetical order
PLUGIN_ENABLED(acl)
PLUGIN_ENABLED(flowperpkt)
PLUGIN_ENABLED(ila)
PLUGIN_ENABLED(ioam)
PLUGIN_ENABLED(lb)
PLUGIN_ENABLED(sixrd)
PLUGIN_ENABLED(snat)

###############################################################################
# Dependency checks
###############################################################################

AM_COND_IF([ENABLE_DPDK_SHARED],
[
  AC_CHECK_HEADERS([rte_config.h],
    [],
    [AC_MSG_ERROR([DPDK header files not found])],)
  AC_CHECK_LIB( [dpdk], [rte_eal_init],
    [],
    [AC_MSG_ERROR([DPDK shared library not found])],)
])

AM_COND_IF([ENABLE_G2],
[
  PKG_CHECK_MODULES(g2, gtk+-2.0)
])

# If cross-compiling, we need external vppapigen and we cannot continue without it
# For native builds, we just set dependency on vpppaigen binary in top_builddir
AM_COND_IF([CROSSCOMPILE],
[
  AC_PATH_PROG([VPPAPIGEN], [vppapigen], [no])
  if test "$VPPAPIGEN" = "no"; then
    AC_MSG_ERROR([Externaly built vppapigen is needed when cross-compiling...])
  fi
],[
  VPPAPIGEN=\$\(top_builddir\)/vppapigen
])
AC_SUBST([VPPAPIGEN])


###############################################################################
# JAVA
###############################################################################

AM_COND_IF([ENABLE_JAPI],
[
  AX_VPP_FIND_JDK8
  AC_SUBST(JAVA_HOME)
  AC_SUBST(JAVAC)
  AC_SUBST(JAVAH)
  AC_SUBST(JAR)
])

###############################################################################
# Output
###############################################################################

AC_OUTPUT

AC_MSG_RESULT([==============================================================================])
PRINT_VAL([version], $PACKAGE $VERSION)
PRINT_VAL([prefix], ${prefix})
PRINT_VAL([libdir], ${libdir})
PRINT_VAL([includedir], ${includedir})
PRINT_VAL([CFLAGS], ${CFLAGS})
PRINT_VAL([CPPFLAGS], ${CPPFLAGS})
PRINT_VAL([LDFLAGS], ${LDFLAGS})
AM_COND_IF([ENABLE_JAPI],
[
  PRINT_VAL([JAVA_VERSION], ${JAVA_VERSION})
  PRINT_VAL([JAVA_HOME], ${JAVA_HOME})
])

AC_MSG_RESULT([])
AC_MSG_RESULT([with:])
m4_foreach([x], m4_dquote(list_of_with), [
  AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${with_], x, [}])))
])

AC_MSG_RESULT([])
AC_MSG_RESULT([enabled:])
m4_foreach([x], m4_dquote(list_of_enabled), [
  AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${enable_], x, [}])))
])

AC_MSG_RESULT([])
AC_MSG_RESULT([plugins:])
m4_foreach([x], m4_dquote(list_of_plugins), [
  AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${enable_], x, [_plugin}])))
])
AC_MSG_RESULT([==============================================================================])
f='#n728'>728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
# Copyright (c) 2016 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import print_function

"""VPP util library"""
import logging
import re
import subprocess
import platform
import requests

from collections import Counter

ubuntu_pkgs = {'release': ['vpp', 'vpp-plugins', 'vpp-api-java', 'vpp-api-lua', 'vpp-api-python',
                           'vpp-dbg', 'vpp-dev'],
               'master': ['vpp', 'vpp-plugin-core', 'vpp-ext-deps', 'vpp-api-python',
                          'vpp-dbg', 'vpp-dev', 'vpp-plugin-dpdk']}

centos_pkgs = {'release': ['vpp', 'vpp-plugins', 'vpp-api-java', 'vpp-api-lua',
                           'vpp-api-python', 'vpp-debuginfo', 'vpp-devel', 'libvpp0'],
               'master': ['vpp', 'vpp-plugins', 'vpp-ext-deps', 'vpp-api-java', 'vpp-api-lua',
                          'vpp-api-python', 'vpp-debuginfo', 'vpp-devel', 'libvpp0']}


class VPPUtil(object):
    """General class for any VPP related methods/functions."""

    @staticmethod
    def exec_command(cmd, timeout=None):
        """Execute a command on the local node.

        :param cmd: Command to run locally.
        :param timeout: Timeout value
        :type cmd: str
        :type timeout: int
        :return return_code, stdout, stderr
        :rtype: tuple(int, str, str)
        """

        logging.info(" Local Command: {}".format(cmd))
        out = ''
        err = ''
        prc = subprocess.Popen(cmd, shell=True, bufsize=1,
                               stdin=subprocess.PIPE,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)

        with prc.stdout:
            lines = prc.stdout.readlines()
            for line in lines:
                if type(line) != str:
                    line = line.decode()
                logging.info("  {}".format(line.strip('\n')))
                out += line

        with prc.stderr:
            lines = prc.stderr.readlines()
            for line in lines:
                if type(line) != str:
                    line = line.decode()
                logging.warning("  {}".format(line.strip('\n')))
                err += line

        ret = prc.wait()

        return ret, out, err

    def _autoconfig_backup_file(self, filename):
        """
        Create a backup file.

        :param filename: The file to backup
        :type filename: str
        """

        # Does a copy of the file exist, if not create one
        ofile = filename + '.orig'
        (ret, stdout, stderr) = self.exec_command('ls {}'.format(ofile))
        if ret != 0:
            logging.debug(stderr)
            if stdout.strip('\n') != ofile:
                cmd = 'sudo cp {} {}'.format(filename, ofile)
                (ret, stdout, stderr) = self.exec_command(cmd)
                if ret != 0:
                    logging.debug(stderr)

    def _install_vpp_ubuntu(self, node, branch, ubuntu_version='xenial'):
        """
        Install the VPP packages

        :param node: Node dictionary with cpuinfo.
        :param branch: VPP branch
        :param ubuntu_version: Ubuntu Version
        :type node: dict
        :type branch: string
        :type ubuntu_version: string
        """

        # Modify the sources list
        sfile = '/etc/apt/sources.list.d/99fd.io.list'

        # Backup the sources list
        self._autoconfig_backup_file(sfile)

        reps = 'deb [trusted=yes] https://packagecloud.io/fdio/'
        reps += '{}/ubuntu {} main\n'.format(branch, ubuntu_version)

        with open(sfile, 'w') as sfd:
            sfd.write(reps)
            sfd.close()

        # Add the key

        key = requests.get(
            'https://packagecloud.io/fdio/{}/gpgkey'.format(branch))
        cmd = 'echo "{}" | apt-key add -'.format(key.content.decode(key.encoding))
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            raise RuntimeError('{} failed on node {} {}'.format(
                cmd,
                node['host'],
                stderr))

        # Install the package
        cmd = 'apt-get -y update'
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            raise RuntimeError('{} apt-get update failed on node {} {}'.format(
                cmd,
                node['host'],
                stderr))

        # Get the package list
        pkgstr = ''
        for ps in ubuntu_pkgs[branch]:
            pkgstr += ps + ' '

        cmd = 'apt-get -y install {}'.format(pkgstr)
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            raise RuntimeError('{} failed on node {} {} {}'.format(
                cmd, node['host'], stdout, stderr))

    def _install_vpp_centos(self, node, branch):
        """
        Install the VPP packages

        :param node: Node dictionary with cpuinfo.
        :param branch: The branch name  release or master
        :type node: dict
        :type branch: string
        """

        # Be sure the correct system packages are installed
        cmd = 'yum -y update'
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            logging.debug('{} failed on node {} {}'.format(
                cmd,
                node['host'],
                stderr))

        cmd = 'yum -y install pygpgme yum-utils'
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            logging.debug('{} failed on node {} {}'.format(
                cmd,
                node['host'],
                stderr))

        # Modify the sources list
        sfile = '/etc/yum.repos.d/fdio-release.repo'

        # Backup the sources list
        self._autoconfig_backup_file(sfile)

        # Remove the current file
        cmd = 'rm {}'.format(sfile)
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            logging.debug('{} failed on node {} {}'.format(
                cmd,
                node['host'],
                stderr))

        # Get the file contents

        reps = '\n'.join([
            '[fdio_{}]'.format(branch),
            'name=fdio_{}'.format(branch),
            'baseurl=https://packagecloud.io/fdio/{}/el/7/$basearch'.format(
                branch),
            'repo_gpgcheck=1',
            'gpgcheck=0',
            'enabled=1',
            'gpgkey=https://packagecloud.io/fdio/{}/gpgkey'.format(branch),
            'sslverify=1',
            'sslcacert=/etc/pki/tls/certs/ca-bundle.crt',
            'metadata_expire=300\n',
            '[fdio_{}-source]'.format(branch),
            'name=fdio_release-{}'.format(branch),
            'baseurl=https://packagecloud.io/fdio/{}/el/7/SRPMS'.format(
                branch),
            'repo_gpgcheck=1',
            'gpgcheck=0',
            'enabled=1',
            'gpgkey=https://packagecloud.io/fdio/{}/gpgkey'.format(branch),
            'sslverify =1',
            'sslcacert=/etc/pki/tls/certs/ca-bundle.crt',
            'metadata_expire=300\n'
        ])
        with open(sfile, 'w') as sfd:
            sfd.write(reps)
            sfd.close()

        # Update the fdio repo
        cmd = 'yum clean all'
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            logging.debug('{} failed on node {} {}'.format(
                cmd,
                node['host'],
                stderr))

        cmd = "yum -q makecache -y --disablerepo='*' " \
              "--enablerepo='fdio_{}'".format(branch)
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            logging.debug('{} failed on node {} {}'.format(
                cmd,
                node['host'],
                stderr))

        # Get the package list
        pkgstr = ''
        for ps in centos_pkgs[branch]:
            pkgstr += ps + ' '

        cmd = 'yum -y install {}'.format(pkgstr)
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            raise RuntimeError('{} failed on node {} {} {}'.format(
                cmd, node['host'], stdout, stderr))

    def install_vpp(self, node, branch):
        """
        Install the VPP packages

        :param node: Node dictionary with cpuinfo.
        :param branch: The branch name
        :type node: dict
        :type branch: string

        """
        distro = self.get_linux_distro()
        logging.info("  {}".format(distro[0]))
        if distro[0] == 'Ubuntu':
            logging.info("Install Ubuntu")
            self._install_vpp_ubuntu(node, branch, ubuntu_version=distro[2])
        elif distro[0] == 'CentOS Linux':
            logging.info("Install CentOS")
            self._install_vpp_centos(node, branch)
        else:
            logging.info("Install CentOS (default)")
            self._install_vpp_centos(node, branch)
        return

    def _uninstall_vpp_ubuntu(self, node):
        """
        Uninstall the VPP packages

        :param node: Node dictionary with cpuinfo.
        :type node: dict
        """

        # get the package list
        pkgstr = ''
        pkgs = self.get_installed_vpp_pkgs()
        for pkg in pkgs:
            pkgname = pkg['name']
            pkgstr += pkgname + ' '

        cmd = 'dpkg --purge {}'.format(pkgstr)
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            raise RuntimeError('{} failed on node {} {} {}'.format(
                cmd, node['host'], stdout, stderr))

    def _uninstall_vpp_centos(self, node):
        """
        Uninstall the VPP packages

        :param node: Node dictionary with cpuinfo.
        :type node: dict
        """

        pkgstr = ''
        pkgs = self.get_installed_vpp_pkgs()
        for pkg in pkgs:
            pkgname = pkg['name']
            pkgstr += pkgname + ' '

        logging.info("Uninstalling {}".format(pkgstr))
        cmd = 'yum -y remove {}'.format(pkgstr)
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            raise RuntimeError('{} failed on node {} {} {}'.format(
                cmd, node['host'], stdout, stderr))

    def uninstall_vpp(self, node):
        """
        Uninstall the VPP packages

        :param node: Node dictionary with cpuinfo.
        :type node: dict
        """

        # First stop VPP
        self.stop(node)
        distro = self.get_linux_distro()
        if distro[0] == 'Ubuntu':
            logging.info("Uninstall Ubuntu")
            self._uninstall_vpp_ubuntu(node)
        elif distro[0] == 'CentOS Linux':
            logging.info("Uninstall CentOS")
            self._uninstall_vpp_centos(node)
        else:
            logging.info("Uninstall CentOS (Default)")
            self._uninstall_vpp_centos(node)
            return

    def show_vpp_settings(self, *additional_cmds):
        """
        Print default VPP settings. In case others are needed, can be
        accepted as next parameters (each setting one parameter), preferably
        in form of a string.

        :param additional_cmds: Additional commands that the vpp should print
        settings for.
        :type additional_cmds: tuple
        """
        def_setting_tb_displayed = {
            'IPv6 FIB': 'ip6 fib',
            'IPv4 FIB': 'ip fib',
            'Interface IP': 'int addr',
            'Interfaces': 'int',
            'ARP': 'ip arp',
            'Errors': 'err'
        }

        if additional_cmds:
            for cmd in additional_cmds:
                def_setting_tb_displayed['Custom Setting: {}'.format(cmd)] \
                    = cmd

                for _, value in def_setting_tb_displayed.items():
                    self.exec_command('vppctl sh {}'.format(value))

    @staticmethod
    def get_vms(node):
        """
        Get a list of VMs that are connected to VPP interfaces

        :param node: VPP node.
        :type node: dict
        :returns: Dictionary containing a list of VMs and the interfaces
                  that are connected to VPP
        :rtype: dictionary
        """

        vmdict = {}

        print("Need to implement get vms")

        return vmdict

    @staticmethod
    def get_int_ip(node):
        """
        Get the VPP interfaces and IP addresses

        :param node: VPP node.
        :type node: dict
        :returns: Dictionary containing VPP interfaces and IP addresses
        :rtype: dictionary
        """
        interfaces = {}
        cmd = 'vppctl show int addr'
        (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
        if ret != 0:
            return interfaces

        lines = stdout.split('\n')
        if len(lines[0]) is not 0:
            if lines[0].split(' ')[0] == 'FileNotFoundError':
                return interfaces

        name = ''
        for line in lines:
            if len(line) is 0:
                continue

            # If the first character is not whitespace
            # create a new interface
            if len(re.findall(r'\s', line[0])) is 0:
                spl = line.split()
                name = spl[0]
                if name == 'local0':
                    continue
                interfaces[name] = {}
                interfaces[name]['state'] = spl[1].lstrip('(').rstrip('):\r')
            else:
                interfaces[name]['address'] = line.lstrip(' ').rstrip('\r')

        return interfaces

    @staticmethod
    def get_hardware(node):
        """
        Get the VPP hardware information and return it in a
        dictionary

        :param node: VPP node.
        :type node: dict
        :returns: Dictionary containing VPP hardware information
        :rtype: dictionary
        """

        interfaces = {}
        cmd = 'vppctl show hard'
        (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
        if ret != 0:
            return interfaces

        lines = stdout.split('\n')
        if len(lines[0]) is not 0:
            if lines[0].split(' ')[0] == 'FileNotFoundError':
                return interfaces

        for line in lines:
            if len(line) is 0:
                continue

            # If the first character is not whitespace
            # create a new interface
            if len(re.findall(r'\s', line[0])) is 0:
                spl = line.split()
                name = spl[0]
                interfaces[name] = {}
                interfaces[name]['index'] = spl[1]
                interfaces[name]['state'] = spl[2]

            # Ethernet address
            rfall = re.findall(r'Ethernet address', line)
            if rfall:
                spl = line.split()
                interfaces[name]['mac'] = spl[2]

            # Carrier
            rfall = re.findall(r'carrier', line)
            if rfall:
                spl = line.split('carrier ')
                interfaces[name]['carrier'] = spl[1]

            # Socket
            spl = ''
            rfall = re.findall(r'numa \d+', line)
            if rfall:
                spl = rfall[0].split()
                interfaces[name]['numa'] = rfall[0].split()[1]

            # Queues and Descriptors
            rfall = re.findall(r'rx\: queues \d+', line)
            if rfall:
                interfaces[name]['rx queues'] = rfall[0].split()[2]
                rdesc = re.findall(r'desc \d+', line)
                if rdesc:
                    interfaces[name]['rx descs'] = rdesc[0].split()[1]

            rfall = re.findall(r'tx\: queues \d+', line)
            if rfall:
                interfaces[name]['tx queues'] = rfall[0].split()[2]
                rdesc = re.findall(r'desc \d+', line)
                if rdesc:
                    interfaces[name]['tx descs'] = rdesc[0].split()[1]

        return interfaces

    def _get_installed_vpp_pkgs_ubuntu(self):
        """
        Get the VPP hardware information and return it in a
        dictionary

        :returns: List of the packages installed
        :rtype: list
        """

        pkgs = []
        cmd = 'dpkg -l | grep vpp'
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            return pkgs

        lines = stdout.split('\n')
        for line in lines:
            items = line.split()
            if len(items) < 2:
                continue
            pkg = {'name': items[1], 'version': items[2]}
            pkgs.append(pkg)

        return pkgs

    def _get_installed_vpp_pkgs_centos(self):
        """
        Get the VPP hardware information and return it in a
        dictionary

        :returns: List of the packages installed
        :rtype: list
        """

        pkgs = []
        cmd = 'rpm -qa | grep vpp'
        (ret, stdout, stderr) = self.exec_command(cmd)
        if ret != 0:
            return pkgs

        lines = stdout.split('\n')
        for line in lines:
            if len(line) == 0:
                continue

            items = line.split()
            if len(items) < 2:
                pkg = {'name': items[0]}
            else:
                pkg = {'name': items[1], 'version': items[2]}

            pkgs.append(pkg)

        return pkgs

    def get_installed_vpp_pkgs(self):
        """
        Get the VPP hardware information and return it in a
        dictionary

        :returns: List of the packages installed
        :rtype: list
        """

        distro = self.get_linux_distro()
        if distro[0] == 'Ubuntu':
            pkgs = self._get_installed_vpp_pkgs_ubuntu()
        elif distro[0] == 'CentOS Linux':
            pkgs = self._get_installed_vpp_pkgs_centos()
        else:
            pkgs = self._get_installed_vpp_pkgs_centos()
            return []

        return pkgs

    @staticmethod
    def get_interfaces_numa_node(node, *iface_keys):
        """Get numa node on which are located most of the interfaces.

        Return numa node with highest count of interfaces provided as
        arguments.
        Return 0 if the interface does not have numa_node information
        available.
        If all interfaces have unknown location (-1), then return 0.
        If most of interfaces have unknown location (-1), but there are
        some interfaces with known location, then return the second most
        location of the provided interfaces.

        :param node: Node from DICT__nodes.
        :param iface_keys: Interface keys for lookup.
        :type node: dict
        :type iface_keys: strings
        """
        numa_list = []
        for if_key in iface_keys:
            try:
                numa_list.append(node['interfaces'][if_key].get('numa_node'))
            except KeyError:
                pass

        numa_cnt_mc = Counter(numa_list).most_common()
        numa_cnt_mc_len = len(numa_cnt_mc)
        if numa_cnt_mc_len > 0 and numa_cnt_mc[0][0] != -1:
            return numa_cnt_mc[0][0]
        elif numa_cnt_mc_len > 1 and numa_cnt_mc[0][0] == -1:
            return numa_cnt_mc[1][0]

        return 0

    @staticmethod
    def restart(node):
        """

        Starts vpp for a given node

        :param node: VPP node.
        :type node: dict
        """

        cmd = 'service vpp restart'
        (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
        if ret != 0:
            raise RuntimeError('{} failed on node {} {} {}'.
                               format(cmd, node['host'],
                                      stdout, stderr))

    @staticmethod
    def start(node):
        """

        Starts vpp for a given node

        :param node: VPP node.
        :type node: dict
        """

        cmd = 'service vpp start'
        (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
        if ret != 0:
            raise RuntimeError('{} failed on node {} {} {}'.
                               format(cmd, node['host'],
                                      stdout, stderr))

    @staticmethod
    def stop(node):
        """

        Stops vpp for a given node

        :param node: VPP node.
        :type node: dict
        """

        cmd = 'service vpp stop'
        (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
        if ret != 0:
            logging.debug('{} failed on node {} {} {}'.
                          format(cmd, node['host'],
                                 stdout, stderr))

    # noinspection RegExpRedundantEscape
    @staticmethod
    def status(node):
        """

        Gets VPP status

        :param: node
        :type node: dict
        :returns: status, errors
        :rtype: tuple(str, list)
        """
        errors = []
        vutil = VPPUtil()
        pkgs = vutil.get_installed_vpp_pkgs()
        if len(pkgs) == 0:
            return "Not Installed", errors

        cmd = 'service vpp status'
        (ret, stdout, stderr) = VPPUtil.exec_command(cmd)

        # Get the active status
        state = re.findall(r'Active:[\w (\)]+', stdout)[0].split(' ')
        if len(state) > 2:
            statestr = "{} {}".format(state[1], state[2])
        else:
            statestr = "Invalid"

        # For now we won't look for DPDK errors
        # lines = stdout.split('\n')
        # for line in lines:
        #    if 'EAL' in line or \
        #                     'FAILURE' in line or \
        #                     'failed' in line or \
        #                     'Failed' in line:
        #         errors.append(line.lstrip(' '))

        return statestr, errors

    @staticmethod
    def get_linux_distro():
        """
        Get the linux distribution and check if it is supported

        :returns: linux distro, None if the distro is not supported
        :rtype: list
        """

        distro = platform.linux_distribution()
        if distro[0] == 'Ubuntu' or \
                distro[0] == 'CentOS Linux' or \
                distro[:7] == 'Red Hat':
            return distro
        else:
            raise RuntimeError(
                'Linux Distribution {} is not supported'.format(distro[0]))

    @staticmethod
    def version():
        """

        Gets VPP Version information

        :returns: version
        :rtype: dict
        """

        version = {}
        cmd = 'vppctl show version verbose'
        (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
        if ret != 0:
            return version

        lines = stdout.split('\n')
        if len(lines[0]) is not 0:
            if lines[0].split(' ')[0] == 'FileNotFoundError':
                return version

        for line in lines:
            if len(line) is 0:
                continue
            dct = line.split(':')
            version[dct[0]] = dct[1].lstrip(' ')

        return version

    @staticmethod
    def show_bridge(node):
        """
        Shows the current bridge configuration

        :param node: VPP node.
        :type node: dict
        :returns: A list of interfaces
        """

        ifaces = []
        cmd = 'vppctl show bridge'
        (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
        if ret != 0:
            raise RuntimeError('{} failed on node {} {} {}'.
                               format(cmd, node['host'],
                                      stdout, stderr))
        lines = stdout.split('\r\n')
        bridges = []
        for line in lines:
            if line == 'no bridge-domains in use':
                print(line)
                return ifaces
            if len(line) == 0:
                continue

            lspl = line.lstrip(' ').split()
            if lspl[0] != 'BD-ID':
                bridges.append(lspl[0])

        for bridge in bridges:
            cmd = 'vppctl show bridge {} detail'.format(bridge)
            (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
            if ret != 0:
                raise RuntimeError('{} failed on node {} {} {}'.
                                   format(cmd, node['host'],
                                          stdout, stderr))

        lines = stdout.split('\r\n')
        for line in lines:
            iface = re.findall(r'[a-zA-z]+\d+/\d+/\d+', line)
            if len(iface):
                ifcidx = {'name': iface[0], 'index': line.split()[1]}
                ifaces.append(ifcidx)

        print(stdout)
        return ifaces