Initial commit for phase 2, Add some simple validation.

Change-Id: I5b1d5600cdef4b05cc7c2f1cddb60aed2cc49ac2
Signed-off-by: John DeNisco <jdenisco@cisco.com>
diff --git a/extras/vpp_config/setup.py b/extras/vpp_config/setup.py
index 3444e68..8d2a396 100644
--- a/extras/vpp_config/setup.py
+++ b/extras/vpp_config/setup.py
@@ -1,7 +1,7 @@
 from setuptools import setup
 
 setup(name="vpp_config",
-      version="17.10.1",
+      version="17.10.3",
       author="John DeNisco",
       author_email="jdenisco@cisco.com",
       description="VPP Configuration Utility",
diff --git a/extras/vpp_config/vpp_config.py b/extras/vpp_config/vpp_config.py
index 2e64418..b8b49a0 100755
--- a/extras/vpp_config/vpp_config.py
+++ b/extras/vpp_config/vpp_config.py
@@ -440,6 +440,16 @@
         acfg.patch_qemu(node)
 
 
+def autoconfig_ipv4_setup():
+    """
+    Setup IPv4 interfaces
+
+    """
+
+    acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE)
+    acfg.ipv4_interface_setup()
+
+
 def autoconfig_not_implemented():
     """
     This feature is not implemented
@@ -449,6 +459,59 @@
     print "\nThis Feature is not implemented yet...."
 
 
+def autoconfig_basic_test_menu():
+    """
+    The auto configuration basic test menu
+
+    """
+
+    basic_menu_text = '\nWhat would you like to do?\n\n\
+1) List/Create Simple IPv4 Setup\n\
+9 or q) Back to main menu.'
+
+    print "{}".format(basic_menu_text)
+
+    input_valid = False
+    answer = ''
+    while not input_valid:
+        answer = raw_input("\nCommand: ")
+        if len(answer) > 1:
+            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."
+
+        if answer == '9':
+            answer = 'q'
+
+    return answer
+
+
+def autoconfig_basic_test():
+    """
+    The auto configuration basic test menu
+
+    """
+    vutil = VPPUtil()
+    pkgs = vutil.get_installed_vpp_pkgs()
+    if len(pkgs) == 0:
+        print "\nVPP is not installed, install VPP with option 4."
+        return
+
+    answer = ''
+    while answer != 'q':
+        answer = autoconfig_basic_test_menu()
+        if answer == '1':
+            autoconfig_ipv4_setup()
+        elif answer == '9' or answer == 'q':
+            return
+        else:
+            autoconfig_not_implemented()
+
+
 def autoconfig_main_menu():
     """
     The auto configuration main menu
@@ -461,6 +524,7 @@
        and user input in {}/vpp/vpp-config/configs/auto-config.yaml\n\
 3) Full configuration (WARNING: This will change the system configuration)\n\
 4) List/Install/Uninstall VPP.\n\
+5) Execute some basic tests.\n\
 9 or q) Quit'.format(rootdir, rootdir)
 
     # 5) Dry Run from {}/vpp/vpp-config/auto-config.yaml (will not ask questions).\n\
@@ -479,7 +543,7 @@
             input_valid = True
             answer = answer[0].lower()
         else:
-            print "Please enter a character between 1 and 7 or 9."
+            print "Please enter a character between 1 and 5 or 9."
 
     if answer == '9':
         answer = 'q'
@@ -503,6 +567,8 @@
             autoconfig_apply()
         elif answer == '4':
             autoconfig_install()
+        elif answer == '5':
+            autoconfig_basic_test()
         elif answer == '9' or answer == 'q':
             return
         else:
diff --git a/extras/vpp_config/vpplib/AutoConfig.py b/extras/vpp_config/vpplib/AutoConfig.py
index 49c7d54..ab943e0 100644
--- a/extras/vpp_config/vpplib/AutoConfig.py
+++ b/extras/vpp_config/vpplib/AutoConfig.py
@@ -17,6 +17,7 @@
 import os
 import re
 import yaml
+import ipaddress
 
 from vpplib.VPPUtil import VPPUtil
 from vpplib.VppPCIUtil import VppPCIUtil
@@ -84,6 +85,36 @@
                     logging.debug(stderr)
 
     @staticmethod
+    def _ask_user_ipv4():
+        """
+        Asks the user for a number within a range.
+        default is returned if return is entered.
+
+        :returns: IP address and prefix len
+        :rtype: tuple
+        """
+
+        while True:
+            answer = raw_input("Please enter the IPv4 Address [n.n.n.n]: ")
+            try:
+                ipaddr = ipaddress.ip_address(u'{}'.format(answer))
+            except:
+                print "Please enter a valid IPv4 address."
+                continue
+
+            answer = raw_input("Please enter the netmask [n.n.n.n]: ")
+            try:
+                netmask = ipaddress.ip_address(u'{}'.format(answer))
+                pl = ipaddress.ip_network(u'0.0.0.0/{}'.format(netmask))
+                plen = pl.exploded.split('/')[1]
+                break
+            except:
+                print "Please enter a valid IPv4 address and netmask."
+                continue
+
+        return ipaddr, plen
+
+    @staticmethod
     def _ask_user_range(question, first, last, default):
         """
         Asks the user for a number within a range.
@@ -1150,7 +1181,7 @@
             print "\nThere currently a total of {} huge pages.". \
                 format(total)
             question = \
-                "How many huge pages do you want [{} - {}][{}]? ".\
+                "How many huge pages do you want [{} - {}][{}]? ". \
                 format(MIN_TOTAL_HUGE_PAGES, maxpages, MIN_TOTAL_HUGE_PAGES)
             answer = self._ask_user_range(question, 1024, maxpages, 1024)
             node['hugepages']['total'] = str(answer)
@@ -1363,10 +1394,10 @@
 
         # System Memory
         if 'free' in node['hugepages'] and \
-           'memfree' in node['hugepages'] and \
-           'size' in node['hugepages']:
-            free =  node['hugepages']['free']
-            memfree =  float(node['hugepages']['memfree'].split(' ')[0])
+                'memfree' in node['hugepages'] and \
+                'size' in node['hugepages']:
+            free = node['hugepages']['free']
+            memfree = float(node['hugepages']['memfree'].split(' ')[0])
             hugesize = float(node['hugepages']['size'].split(' ')[0])
 
             memhugepages = MIN_TOTAL_HUGE_PAGES * hugesize
@@ -1425,3 +1456,94 @@
             self.min_system_resources(node)
 
             print "\n=============================="
+
+    def _ipv4_interface_setup_questions(self, node):
+        """
+        Ask the user some questions and get a list of interfaces
+        and IPv4 addresses associated with those interfaces
+
+        :param node: Node dictionary.
+        :type node: dict
+        :returns: A list or interfaces with ip addresses
+        :rtype: dict
+        """
+
+        vpputl = VPPUtil()
+        interfaces = vpputl.get_hardware(node)
+        if interfaces == {}:
+            return
+
+        interfaces_with_ip = []
+        for intf in sorted(interfaces.items()):
+            name = intf[0]
+            if name == 'local0':
+                continue
+
+            question = "Would you like an address to interface {} [Y/n]? ".format(name)
+            answer = self._ask_user_yn(question, 'y')
+            if answer == 'y':
+                address = {}
+                addr, plen = self._ask_user_ipv4()
+                address['name'] = name
+                address['addr'] = addr
+                address['plen'] = plen
+                interfaces_with_ip.append(address)
+
+        return interfaces_with_ip
+
+    def ipv4_interface_setup(self):
+        """
+        After asking the user some questions, get a list of interfaces
+        and IPv4 addresses associated with those interfaces
+
+        """
+
+        for i in self._nodes.items():
+            node = i[1]
+
+            # Show the current interfaces with IP addresses
+            current_ints = VPPUtil.get_int_ip(node)
+            if current_ints is not {}:
+                print ("\nThese are the current interfaces with IP addresses:")
+                for items in sorted(current_ints.items()):
+                    name = items[0]
+                    value = items[1]
+                    if 'address' not in value:
+                        address = 'Not Set'
+                    else:
+                        address = value['address']
+                    print ("{:30} {:20} {:10}".format(name, address, value['state']))
+                question = "\nWould you like to keep this configuration [Y/n]? "
+                answer = self._ask_user_yn(question, 'y')
+                if answer == 'y':
+                    continue
+            else:
+                print ("\nThere are currently no interfaces with IP addresses.")
+
+            # Create a script that add the ip addresses to the interfaces
+            # and brings the interfaces up
+            ints_with_addrs = self._ipv4_interface_setup_questions(node)
+            content = ''
+            for ints in ints_with_addrs:
+                name = ints['name']
+                addr = ints['addr']
+                plen = ints['plen']
+                setipstr = 'set int ip address {} {}/{}\n'.format(name, addr, plen)
+                setintupstr = 'set int state {} up\n'.format(name)
+                content += setipstr + setintupstr
+
+            # Write the content to the script
+            rootdir = node['rootdir']
+            filename = rootdir + '/vpp/vpp-config/scripts/set_int_ipv4_and_up'
+            with open(filename, 'w+') as sfile:
+                sfile.write(content)
+
+            # Execute the script
+            cmd = 'vppctl exec {}'.format(filename)
+            (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
+            if ret != 0:
+                logging.debug(stderr)
+
+            print("\nA script as been created at {}".format(filename))
+            print("This script can be run using the following:")
+            print("vppctl exec {}\n".format(filename))
\ No newline at end of file
diff --git a/extras/vpp_config/vpplib/VPPUtil.py b/extras/vpp_config/vpplib/VPPUtil.py
index 350b775..f042e80 100644
--- a/extras/vpp_config/vpplib/VPPUtil.py
+++ b/extras/vpp_config/vpplib/VPPUtil.py
@@ -373,6 +373,45 @@
                     self.exec_command('vppctl sh {}'.format(value))
 
     @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
+
+        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
@@ -380,7 +419,7 @@
 
         :param node: VPP node.
         :type node: dict
-        :returns: Dictionary containing improtant VPP information
+        :returns: Dictionary containing VPP hardware information
         :rtype: dictionary
         """