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
"""