vpp_config: Rework for Python2/3 compatibility.

On ubuntu:
   $cd <basedir>/extras/vpp_config
   $./scripts/clean.sh
   $./scripts/cp-data.sh
   $sudo apt-get install python3-pip python3-setuptools
   $python3 -m pip install .
   $vpp-config

Changes:
   * Convert to print() function.
   * raw_input changes.
   * floor division changes.
   * replace vpp-config.py with a setuptools 'vpp-config' entry_point.
   * replace netaddr with ipaddress from the standard library and backport.
   * .decode() subprocess.Popen's stdout because in python3 they are bytes.

Change-Id: Id98894ee54e0c31a0ba0304134b159caef415705
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
diff --git a/extras/vpp_config/vpp_config.py b/extras/vpp_config/vpp_config.py
index 145bf4e..1f79201 100755
--- a/extras/vpp_config/vpp_config.py
+++ b/extras/vpp_config/vpp_config.py
@@ -1,6 +1,7 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 # Copyright (c) 2016 Cisco and/or its affiliates.
+# Copyright (c) 2018 Vinci Consulting Corp.  All rights reserved.
 # 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:
@@ -14,6 +15,7 @@
 # limitations under the License.
 
 """VPP Configuration Main Entry"""
+from __future__ import absolute_import, division, print_function
 
 import re
 import os
@@ -24,6 +26,12 @@
 from vpplib.AutoConfig import AutoConfig
 from vpplib.VPPUtil import VPPUtil
 
+#  Python2/3 compatible
+try:
+    input = raw_input  # noqa
+except NameError:
+    pass
+
 VPP_DRYRUNDIR = '/vpp/vpp-config/dryrun'
 VPP_AUTO_CONFIGURATION_FILE = '/vpp/vpp-config/configs/auto-config.yaml'
 VPP_HUGE_PAGE_FILE = '/vpp/vpp-config/dryrun/sysctl.d/80-vpp.conf'
@@ -51,14 +59,14 @@
     default = default.lower()
     answer = ''
     while not input_valid:
-        answer = raw_input(question)
+        answer = input(question)
         if len(answer) == 0:
             answer = default
         if re.findall(r'[YyNn]', answer):
             input_valid = True
             answer = answer[0].lower()
         else:
-            print "Please answer Y, N or Return."
+            print ("Please answer Y, N or Return.")
 
     return answer
 
@@ -153,9 +161,9 @@
 
     diffs = autoconfig_diff(node, VPP_REAL_HUGE_PAGE_FILE, rootdir + VPP_HUGE_PAGE_FILE)
     if diffs != '':
-        print "These are the changes we will apply to"
-        print "the huge page file ({}).\n".format(VPP_REAL_HUGE_PAGE_FILE)
-        print diffs
+        print ("These are the changes we will apply to")
+        print ("the huge page file ({}).\n".format(VPP_REAL_HUGE_PAGE_FILE))
+        print (diffs)
         if ask_questions:
             answer = autoconfig_yn("\nAre you sure you want to apply these changes [Y/n]? ", 'y')
             if answer == 'n':
@@ -169,7 +177,7 @@
             raise RuntimeError('{} failed on node {} {} {}'.
                                format(cmd, node['host'], stdout, stderr))
     else:
-        print '\nThere are no changes to the huge page configuration.'
+        print ('\nThere are no changes to the huge page configuration.')
 
     return 0
 
@@ -189,9 +197,9 @@
 
     diffs = autoconfig_diff(node, VPP_REAL_STARTUP_FILE, rootdir + VPP_STARTUP_FILE)
     if diffs != '':
-        print "These are the changes we will apply to"
-        print "the VPP startup file ({}).\n".format(VPP_REAL_STARTUP_FILE)
-        print diffs
+        print ("These are the changes we will apply to")
+        print ("the VPP startup file ({}).\n".format(VPP_REAL_STARTUP_FILE))
+        print (diffs)
         if ask_questions:
             answer = autoconfig_yn("\nAre you sure you want to apply these changes [Y/n]? ", 'y')
             if answer == 'n':
@@ -200,7 +208,7 @@
         # Copy the VPP startup
         autoconfig_cp(node, rootdir + VPP_STARTUP_FILE, VPP_REAL_STARTUP_FILE)
     else:
-        print '\nThere are no changes to VPP startup.'
+        print ('\nThere are no changes to VPP startup.')
 
     return 0
 
@@ -218,12 +226,12 @@
 
     """
 
-    print "\nThe configured grub cmdline looks like this:"
+    print ("\nThe configured grub cmdline looks like this:")
     configured_cmdline = node['grub']['default_cmdline']
     current_cmdline = node['grub']['current_cmdline']
-    print configured_cmdline
-    print "\nThe current boot cmdline looks like this:"
-    print current_cmdline
+    print (configured_cmdline)
+    print ("\nThe current boot cmdline looks like this:")
+    print (current_cmdline)
     if ask_questions:
         question = "\nDo you want to keep the current boot cmdline [Y/n]? "
         answer = autoconfig_yn(question, 'y')
@@ -235,9 +243,9 @@
     # Diff the file
     diffs = autoconfig_diff(node, VPP_REAL_GRUB_FILE, rootdir + VPP_GRUB_FILE)
     if diffs != '':
-        print "These are the changes we will apply to"
-        print "the GRUB file ({}).\n".format(VPP_REAL_GRUB_FILE)
-        print diffs
+        print ("These are the changes we will apply to")
+        print ("the GRUB file ({}).\n".format(VPP_REAL_GRUB_FILE))
+        print (diffs)
         if ask_questions:
             answer = autoconfig_yn("\nAre you sure you want to apply these changes [y/N]? ", 'n')
             if answer == 'n':
@@ -256,11 +264,11 @@
             raise RuntimeError('{} failed on node {} {} {}'.
                                format(cmd, node['host'], stdout, stderr))
 
-        print "There have been changes to the GRUB config a",
-        print "reboot will be required."
+        print ("There have been changes to the GRUB config a", end=' ')
+        print ("reboot will be required.")
         return -1
     else:
-        print '\nThere are no changes to the GRUB config.'
+        print ('\nThere are no changes to the GRUB config.')
 
     return 0
 
@@ -281,13 +289,13 @@
     vutil = VPPUtil()
     pkgs = vutil.get_installed_vpp_pkgs()
     if len(pkgs) == 0:
-        print "\nVPP is not installed, Install VPP with option 4."
+        print ("\nVPP is not installed, Install VPP with option 4.")
         return
 
     acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE)
 
     if ask_questions:
-        print "\nWe are now going to configure your system(s).\n"
+        print ("\nWe are now going to configure your system(s).\n")
         answer = autoconfig_yn("Are you sure you want to do this [Y/n]? ", 'y')
         if answer == 'n':
             return
@@ -336,7 +344,7 @@
     vutil = VPPUtil()
     pkgs = vutil.get_installed_vpp_pkgs()
     if len(pkgs) == 0:
-        print "\nVPP is not installed, please install VPP."
+        print ("\nVPP is not installed, please install VPP.")
         return
 
     acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE, clean=True)
@@ -405,15 +413,15 @@
         pkgs = vutil.get_installed_vpp_pkgs()
 
         if len(pkgs) > 0:
-            print "\nThese packages are installed on node {}" \
-                .format(node['host'])
-            print "{:25} {}".format("Name", "Version")
+            print ("\nThese packages are installed on node {}"
+                   .format(node['host']))
+            print ("{:25} {}".format("Name", "Version"))
             for pkg in pkgs:
-                if 'version' in pkg:
-                    print "{:25} {}".format(
-                        pkg['name'], pkg['version'])
-                else:
-                    print "{}".format(pkg['name'])
+                try:
+                    print ("{:25} {}".format(
+                        pkg['name'], pkg['version']))
+                except KeyError:
+                    print ("{}".format(pkg['name']))
 
             question = "\nDo you want to uninstall these "
             question += "packages [y/N]? "
@@ -422,8 +430,8 @@
                 logger.setLevel(logging.INFO)
                 vutil.uninstall_vpp(node)
         else:
-            print "\nThere are no VPP packages on node {}." \
-                .format(node['host'])
+            print ("\nThere are no VPP packages on node {}."
+                   .format(node['host']))
             question = "Do you want to install VPP [Y/n]? "
             answer = autoconfig_yn(question, 'y')
             if answer == 'y':
@@ -488,7 +496,7 @@
 
     """
 
-    print "\nThis Feature is not implemented yet...."
+    print ("\nThis Feature is not implemented yet....")
 
 
 def autoconfig_basic_test_menu():
@@ -502,20 +510,20 @@
 2) Create an iperf VM and Connect to VPP an interface\n\
 9 or q) Back to main menu.'
 
-    print "{}".format(basic_menu_text)
+    print ("{}".format(basic_menu_text))
 
     input_valid = False
     answer = ''
     while not input_valid:
-        answer = raw_input("\nCommand: ")
+        answer = input("\nCommand: ")
         if len(answer) > 1:
-            print "Please enter only 1 character."
+            print ("Please enter only 1 character.")
             continue
         if re.findall(r'[Qq1-29]', answer):
             input_valid = True
             answer = answer[0].lower()
         else:
-            print "Please enter a character between 1 and 2 or 9."
+            print ("Please enter a character between 1 and 2 or 9.")
 
         if answer == '9':
             answer = 'q'
@@ -531,7 +539,7 @@
     vutil = VPPUtil()
     pkgs = vutil.get_installed_vpp_pkgs()
     if len(pkgs) == 0:
-        print "\nVPP is not installed, install VPP with option 4."
+        print ("\nVPP is not installed, install VPP with option 4.")
         return
 
     answer = ''
@@ -563,20 +571,20 @@
     # 5) Dry Run from {}/vpp/vpp-config/auto-config.yaml (will not ask questions).\n\
     # 6) Install QEMU patch (Needed when running openstack).\n\
 
-    print "{}".format(main_menu_text)
+    print ("{}".format(main_menu_text))
 
     input_valid = False
     answer = ''
     while not input_valid:
-        answer = raw_input("\nCommand: ")
+        answer = input("\nCommand: ")
         if len(answer) > 1:
-            print "Please enter only 1 character."
+            print ("Please enter only 1 character.")
             continue
         if re.findall(r'[Qq1-4]', answer):
             input_valid = True
             answer = answer[0].lower()
         else:
-            print "Please enter a character between 1 and 4 or q."
+            print ("Please enter a character between 1 and 4 or q.")
 
     return answer
 
@@ -632,15 +640,19 @@
                            format(filename))
 
     if ask_questions:
-        print "\nWelcome to the VPP system configuration utility"
+        print ("\nWelcome to the VPP system configuration utility")
 
-        print "\nThese are the files we will modify:"
-        print "    /etc/vpp/startup.conf"
-        print "    /etc/sysctl.d/80-vpp.conf"
-        print "    /etc/default/grub"
+        print ("\nThese are the files we will modify:")
+        print ("    /etc/vpp/startup.conf")
+        print ("    /etc/sysctl.d/80-vpp.conf")
+        print ("    /etc/default/grub")
 
-        print "\nBefore we change them, we'll create working copies in {}".format(rootdir + VPP_DRYRUNDIR)
-        print "Please inspect them carefully before applying the actual configuration (option 3)!"
+        print (
+            "\nBefore we change them, we'll create working copies in "
+            "{}".format(rootdir + VPP_DRYRUNDIR))
+        print (
+            "Please inspect them carefully before applying the actual "
+            "configuration (option 3)!")
 
     nodes = acfg.get_nodes()
     for i in nodes.items():
@@ -696,31 +708,43 @@
     if not os.geteuid() == 0:
         sys.exit('\nPlease run the VPP Configuration Utility as root.')
 
-    if len(sys.argv) > 1 and ((sys.argv[1] == '-d') or (sys.argv[1] == '--debug')):
+    if len(sys.argv) > 1 and ((sys.argv[1] == '-d') or (
+            sys.argv[1] == '--debug')):
         logging.basicConfig(level=logging.DEBUG)
     else:
         logging.basicConfig(level=logging.ERROR)
 
-    # If no arguments were entered, ask the user questions to get the main parameters
+    # If no arguments were entered, ask the user questions to
+    # get the main parameters
     if len(sys.argv) == 1:
         autoconfig_main()
         return
-    elif len(sys.argv) == 2 and (sys.argv[1] == '-d' or sys.argv[1] == '--debug'):
+    elif len(sys.argv) == 2 and ((sys.argv[1] == '-d') or (
+            sys.argv[1] == '--debug')):
         autoconfig_main()
         return
 
-    # There were arguments specified, so execute the utility using command line arguments
-    description = 'The VPP configuration utility allows the user to configure VPP in a simple and safe manner. \
-The utility takes input from the user or the speficfied .yaml file. The user should then examine these files \
-to be sure they are correct and then actually apply the configuration. When run without arguments the utility run \
-in an interactive mode'
+    # There were arguments specified, so execute the utility using
+    # command line arguments
+    description = 'The VPP configuration utility allows the user to '
+    'configure VPP in a simple and safe manner. The utility takes input '
+    'from the user or the specified .yaml file. The user should then '
+    'examine these files to be sure they are correct and then actually '
+    'apply the configuration. When run without arguments the utility run '
+    'in an interactive mode'
 
-    main_parser = argparse.ArgumentParser(prog='arg-test', description=description,
-                                          epilog='See "%(prog)s help COMMAND" for help on a specific command.')
-    main_parser.add_argument('--apply', '-a', action='store_true', help='Apply the cofiguration.')
-    main_parser.add_argument('--dry-run', '-dr', action='store_true', help='Create the dryrun configuration files.')
-    main_parser.add_argument('--show', '-s', action='store_true', help='Shows basic system information')
-    main_parser.add_argument('--debug', '-d', action='count', help='Print debug output (multiple levels)')
+    main_parser = argparse.ArgumentParser(
+        prog='arg-test',
+        description=description,
+        epilog='See "%(prog)s help COMMAND" for help on a specific command.')
+    main_parser.add_argument('--apply', '-a', action='store_true',
+                             help='Apply the cofiguration.')
+    main_parser.add_argument('--dry-run', '-dr', action='store_true',
+                             help='Create the dryrun configuration files.')
+    main_parser.add_argument('--show', '-s', action='store_true',
+                             help='Shows basic system information')
+    main_parser.add_argument('--debug', '-d', action='count',
+                             help='Print debug output (multiple levels)')
 
     args = main_parser.parse_args()