Add a non interactive mode
Change-Id: I2ebcb1acb43b4316e3dd48e83909d710dbef4e2f
Signed-off-by: John DeNisco <jdenisco@cisco.com>
diff --git a/extras/vpp_config/data/auto-config.yaml b/extras/vpp_config/data/auto-config.yaml
index 4a74de2..83e3aab 100644
--- a/extras/vpp_config/data/auto-config.yaml
+++ b/extras/vpp_config/data/auto-config.yaml
@@ -1,23 +1,14 @@
-metadata:
- system_config_file: /vpp/vpp-config/configs/system-config.yaml
- version: 0.1
+metadata: {system_config_file: /vpp/vpp-config/configs/system-config.yaml, version: 0.1}
nodes:
DUT1:
- cpu:
- grub_config_file: /vpp/vpp-config/dryrun/default/grub
- reserve_vpp_main_core: true
- total_other_cpus: 0
- total_vpp_cpus: 2
+ cpu: {grub_config_file: /vpp/vpp-config/dryrun/default/grub, reserve_vpp_main_core: false,
+ total_other_cpus: 0, total_vpp_cpus: 0}
host: localhost
- hugepages:
- hugepage_config_file: /vpp/vpp-config/dryrun/sysctl.d/80-vpp.conf
- total: '1024'
- interfaces:
- tcp:
- active_open_sessions: 0
- passive_open_sessions: 0
+ hugepages: {hugepage_config_file: /vpp/vpp-config/dryrun/sysctl.d/80-vpp.conf,
+ total: '1024'}
+ interfaces: {}
+ tcp: {active_open_sessions: 0, passive_open_sessions: 0}
type: DUT
vpp:
startup_config_file: /vpp/vpp-config/dryrun/vpp/startup.conf
- unix:
- interactive: false
+ unix: {interactive: false}
diff --git a/extras/vpp_config/scripts/vpp-config b/extras/vpp_config/scripts/vpp-config
index 8f5314b..7cb27fc 100755
--- a/extras/vpp_config/scripts/vpp-config
+++ b/extras/vpp_config/scripts/vpp-config
@@ -17,14 +17,6 @@
import os
import sys
-import vpp_config as vppcfg
+import vpp_config as vpp
-# Check for root
-if not os.geteuid() == 0:
- sys.exit('\nPlease run the VPP Configuration Utility as root.')
-
-# Setup
-vppcfg.autoconfig_setup()
-
-# Main menu
-vppcfg.autoconfig_main()
+vpp.config_main()
diff --git a/extras/vpp_config/setup.py b/extras/vpp_config/setup.py
index 32c376d..892a60d 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.5",
+ version="17.10.6",
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 da455c1..69e7de7 100755
--- a/extras/vpp_config/vpp_config.py
+++ b/extras/vpp_config/vpp_config.py
@@ -19,6 +19,7 @@
import os
import sys
import logging
+import argparse
from vpplib.AutoConfig import AutoConfig
from vpplib.VPPUtil import VPPUtil
@@ -138,11 +139,13 @@
acfg.sys_info()
-def autoconfig_hugepage_apply(node):
+def autoconfig_hugepage_apply(node, ask_questions=True):
"""
Apply the huge page configuration.
:param node: The node structure
:type node: dict
+ :param ask_questions: When True ask the user questions
+ :type ask_questions: bool
:returns: -1 if the caller should return, 0 if not
:rtype: int
@@ -153,11 +156,10 @@
print "These are the changes we will apply to"
print "the huge page file ({}).\n".format(VPP_REAL_HUGE_PAGE_FILE)
print diffs
- answer = autoconfig_yn(
- "\nAre you sure you want to apply these changes [Y/n]? ",
- 'y')
- if answer == 'n':
- return -1
+ if ask_questions:
+ answer = autoconfig_yn("\nAre you sure you want to apply these changes [Y/n]? ", 'y')
+ if answer == 'n':
+ return -1
# Copy and sysctl
autoconfig_cp(node, rootdir + VPP_HUGE_PAGE_FILE, VPP_REAL_HUGE_PAGE_FILE)
@@ -172,33 +174,28 @@
return 0
-def autoconfig_vpp_apply(node):
+def autoconfig_vpp_apply(node, ask_questions=True):
"""
Apply the vpp configuration.
:param node: The node structure
:type node: dict
+ :param ask_questions: When True ask the user questions
+ :type ask_questions: bool
:returns: -1 if the caller should return, 0 if not
:rtype: int
"""
- cmd = "service vpp stop"
- (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
- if ret != 0:
- raise RuntimeError('{} failed on node {} {} {}'.
- format(cmd, node['host'], stdout, stderr))
-
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
- answer = autoconfig_yn(
- "\nAre you sure you want to apply these changes [Y/n]? ",
- 'y')
- if answer == 'n':
- return -1
+ if ask_questions:
+ answer = autoconfig_yn("\nAre you sure you want to apply these changes [Y/n]? ", 'y')
+ if answer == 'n':
+ return -1
# Copy the VPP startup
autoconfig_cp(node, rootdir + VPP_STARTUP_FILE, VPP_REAL_STARTUP_FILE)
@@ -208,63 +205,67 @@
return 0
-def autoconfig_grub_apply(node):
+def autoconfig_grub_apply(node, ask_questions=True):
"""
Apply the grub configuration.
:param node: The node structure
:type node: dict
+ :param ask_questions: When True ask the user questions
+ :type ask_questions: bool
:returns: -1 if the caller should return, 0 if not
:rtype: int
"""
+
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
- question = "\nDo you want to keep the current boot cmdline [Y/n]? "
- answer = autoconfig_yn(question, 'y')
- if answer == 'n':
- node['grub']['keep_cmdline'] = False
+ if ask_questions:
+ question = "\nDo you want to keep the current boot cmdline [Y/n]? "
+ answer = autoconfig_yn(question, 'y')
+ if answer == 'y':
+ return
- # 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
- answer = autoconfig_yn(
- "\nAre you sure you want to apply these changes [y/N]? ",
- 'n')
+ node['grub']['keep_cmdline'] = False
+
+ # 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
+ if ask_questions:
+ answer = autoconfig_yn("\nAre you sure you want to apply these changes [y/N]? ", 'n')
if answer == 'n':
return -1
- # Copy and update grub
- autoconfig_cp(node, rootdir + VPP_GRUB_FILE, VPP_REAL_GRUB_FILE)
- distro = VPPUtil.get_linux_distro()
- if distro[0] == 'Ubuntu':
- cmd = "update-grub"
- else:
- cmd = "grub2-mkconfig -o /boot/grub2/grub.cfg"
- (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
- if ret != 0:
- 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."
- return -1
+ # Copy and update grub
+ autoconfig_cp(node, rootdir + VPP_GRUB_FILE, VPP_REAL_GRUB_FILE)
+ distro = VPPUtil.get_linux_distro()
+ if distro[0] == 'Ubuntu':
+ cmd = "update-grub"
else:
- print '\nThere are no changes to the GRUB config.'
+ cmd = "grub2-mkconfig -o /boot/grub2/grub.cfg"
+
+ (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
+ if ret != 0:
+ 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."
+ return -1
+ else:
+ print '\nThere are no changes to the GRUB config.'
return 0
-def autoconfig_apply():
+def autoconfig_apply(ask_questions=True):
"""
Apply the configuration.
@@ -272,6 +273,9 @@
Copy the files from the dryrun directory to the actual file.
Peform the system function
+ :param ask_questions: When true ask the user questions
+ :type ask_questions: bool
+
"""
vutil = VPPUtil()
@@ -282,10 +286,11 @@
acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE)
- 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
+ if ask_questions:
+ 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
nodes = acfg.get_nodes()
for i in nodes.items():
@@ -295,42 +300,45 @@
if not acfg.min_system_resources(node):
return
+ # Stop VPP
+ VPPUtil.stop(node)
+
# Huge Pages
- ret = autoconfig_hugepage_apply(node)
+ ret = autoconfig_hugepage_apply(node, ask_questions)
if ret != 0:
return
# VPP
- ret = autoconfig_vpp_apply(node)
+ ret = autoconfig_vpp_apply(node, ask_questions)
if ret != 0:
return
# Grub
- ret = autoconfig_grub_apply(node)
+ ret = autoconfig_grub_apply(node, ask_questions)
if ret != 0:
+ # We can still start VPP, even if we haven't configured grub
+ VPPUtil.start(node)
return
# Everything is configured start vpp
- 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))
+ VPPUtil.start(node)
-
-def autoconfig_dryrun():
+def autoconfig_dryrun(ask_questions=True):
"""
Execute the dryrun function.
+ :param ask_questions: When true ask the user for paraameters
+ :type ask_questions: bool
+
"""
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, please install VPP."
return
- acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE)
+ acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE, clean=True)
# Stop VPP on each node
nodes = acfg.get_nodes()
@@ -349,16 +357,20 @@
return
# Modify the devices
- acfg.modify_devices()
+ if ask_questions:
+ acfg.modify_devices()
+ else:
+ acfg.update_interfaces_config()
# Modify CPU
- acfg.modify_cpu()
+ acfg.modify_cpu(ask_questions)
# Calculate the cpu parameters
acfg.calculate_cpu_parameters()
# Acquire TCP stack parameters
- acfg.acquire_tcp_params()
+ if ask_questions:
+ acfg.acquire_tcp_params()
# Apply the startup
acfg.apply_vpp_startup()
@@ -367,7 +379,8 @@
acfg.apply_grub_cmdline()
# Huge Pages
- acfg.modify_huge_pages()
+ if ask_questions:
+ acfg.modify_huge_pages()
acfg.apply_huge_pages()
@@ -475,14 +488,15 @@
"""
-# basic_menu_text = '\nWhat would you like to do?\n\n\
-# 1) List/Create Simple IPv4 Setup\n\
-# 2) List/Create Create VM and Connect to VPP interfaces\n\
-# 9 or q) Back to main 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.'
+
+ # 1) List/Create Simple IPv4 Setup\n\
+ # 2) List/Create Create VM and Connect to VPP interfaces\n\
+ # 9 or q) Back to main menu.'
+
+
print "{}".format(basic_menu_text)
input_valid = False
@@ -521,7 +535,7 @@
if answer == '1':
autoconfig_ipv4_setup()
# elif answer == '2':
- # autoconfig_create_vm()
+ # autoconfig_create_vm()
elif answer == '9' or answer == 'q':
return
else:
@@ -572,6 +586,9 @@
"""
+ # Setup
+ autoconfig_setup()
+
answer = ''
while answer != 'q':
answer = autoconfig_main_menu()
@@ -591,7 +608,7 @@
autoconfig_not_implemented()
-def autoconfig_setup():
+def autoconfig_setup(ask_questions=True):
"""
The auto configuration setup function.
@@ -617,15 +634,16 @@
raise RuntimeError('The Auto configuration file does not exist {}'.
format(filename))
- print "\nWelcome to the VPP system configuration utility"
+ if ask_questions:
+ 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():
@@ -642,14 +660,62 @@
autoconfig_cp(node, VPP_REAL_GRUB_FILE, '{}'.format(rootdir + VPP_GRUB_FILE))
-if __name__ == '__main__':
+def execute_with_args(args):
+ """
+ Execute the configuration utility with agruments.
+
+ :param args: The Command line arguments
+ :type args: tuple
+ """
+
+ # Setup
+ autoconfig_setup(ask_questions=False)
+
+ # Execute the command
+ if args.show:
+ autoconfig_show_system()
+ elif args.dry_run:
+ autoconfig_dryrun(ask_questions=False)
+ elif args.apply:
+ autoconfig_apply(ask_questions=False)
+ else:
+ autoconfig_not_implemented()
+
+
+def config_main():
+ """
+ The vpp configuration utility main entry point.
+
+ """
# Check for root
if not os.geteuid() == 0:
sys.exit('\nPlease run the VPP Configuration Utility as root.')
- # Setup
- autoconfig_setup()
+ # If no arguments were entered, ask the user questions to get the main parameters
+ if len(sys.argv) == 1:
+ # Main menu
+ autoconfig_main()
+ return
- # Main menu
- autoconfig_main()
+ # 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'
+
+ 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()
+
+ return execute_with_args(args)
+
+
+if __name__ == '__main__':
+
+ config_main()
diff --git a/extras/vpp_config/vpplib/AutoConfig.py b/extras/vpp_config/vpplib/AutoConfig.py
index 7b7d7a7..b995f41 100644
--- a/extras/vpp_config/vpplib/AutoConfig.py
+++ b/extras/vpp_config/vpplib/AutoConfig.py
@@ -37,14 +37,16 @@
class AutoConfig(object):
"""Auto Configuration Tools"""
- def __init__(self, rootdir, filename):
+ def __init__(self, rootdir, filename, clean=False):
"""
The Auto Configure class.
:param rootdir: The root directory for all the auto configuration files
:param filename: The autoconfiguration file
+ :param clean: When set initialize the nodes from the auto-config file
:type rootdir: str
:type filename: str
+ :type clean: bool
"""
self._autoconfig_filename = rootdir + filename
self._rootdir = rootdir
@@ -52,6 +54,7 @@
self._nodes = {}
self._vpp_devices_node = {}
self._hugepage_config = ""
+ self._clean = clean
self._loadconfig()
def get_nodes(self):
@@ -84,6 +87,7 @@
if ret != 0:
logging.debug(stderr)
+ # noinspection PyBroadException
@staticmethod
def _ask_user_ipv4():
"""
@@ -189,7 +193,7 @@
raise RuntimeError("Couldn't read the Auto config file {}.".format(self._autoconfig_filename, exc))
systemfile = self._rootdir + self._metadata['system_config_file']
- if os.path.isfile(systemfile):
+ if self._clean is False and os.path.isfile(systemfile):
with open(systemfile, 'r') as sysstream:
try:
systopo = yaml.load(sysstream)
@@ -221,7 +225,7 @@
# Write the system config file
filename = self._rootdir + self._metadata['system_config_file']
with open(filename, 'w') as yamlfile:
- yaml.dump(ydata, yamlfile, default_flow_style=False)
+ yaml.dump(ydata, yamlfile)
def _update_auto_config(self):
"""
@@ -252,8 +256,8 @@
interface = item[1]
node['interfaces'][port] = {}
- node['interfaces'][port]['pci_address'] = \
- interface['pci_address']
+ addr = '{}'.format(interface['pci_address'])
+ node['interfaces'][port]['pci_address'] = addr
if 'mac_address' in interface:
node['interfaces'][port]['mac_address'] = \
interface['mac_address']
@@ -281,7 +285,7 @@
# Write the auto config config file
with open(self._autoconfig_filename, 'w') as yamlfile:
- yaml.dump(ydata, yamlfile, default_flow_style=False)
+ yaml.dump(ydata, yamlfile)
def apply_huge_pages(self):
"""
@@ -327,7 +331,10 @@
# Get main core
cpu = '\n'
- vpp_main_core = node['cpu']['vpp_main_core']
+ if 'vpp_main_core' in node['cpu']:
+ vpp_main_core = node['cpu']['vpp_main_core']
+ else:
+ vpp_main_core = 0
if vpp_main_core is not 0:
cpu += ' main-core {}\n'.format(vpp_main_core)
@@ -696,7 +703,10 @@
# Get the isolated CPUs
other_workers = node['cpu']['other_workers']
vpp_workers = node['cpu']['vpp_workers']
- vpp_main_core = node['cpu']['vpp_main_core']
+ if 'vpp_main_core' in node['cpu']:
+ vpp_main_core = node['cpu']['vpp_main_core']
+ else:
+ vpp_main_core = 0
all_workers = []
if other_workers is not None:
all_workers = [other_workers]
@@ -943,10 +953,12 @@
node['cpu']['reserve_vpp_main_core'] = reserve_vpp_main_core
node['cpu']['vpp_main_core'] = 0
- def modify_cpu(self):
+ def modify_cpu(self, ask_questions=True):
"""
Modify the cpu configuration, asking for the user for the values.
+ :param ask_questions: When true ask the user for config parameters
+
"""
# Get the CPU layout
@@ -990,11 +1002,13 @@
node['cpu']['cpus_per_node'] = cpus_per_node
# Ask the user some questions
- self._modify_cpu_questions(node, total_cpus, numa_nodes)
+ if ask_questions:
+ self._modify_cpu_questions(node, total_cpus, numa_nodes)
# Populate the interfaces with the numa node
- ikeys = node['interfaces'].keys()
- VPPUtil.get_interfaces_numa_node(node, *tuple(ikeys))
+ if 'interfaces' in node:
+ ikeys = node['interfaces'].keys()
+ VPPUtil.get_interfaces_numa_node(node, *tuple(ikeys))
# We don't want to write the cpuinfo
node['cpuinfo'] = ""
@@ -1060,6 +1074,33 @@
dpdk_devices[dvid] = device
del other_devices[dvid]
+ def update_interfaces_config(self):
+ """
+ Modify the interfaces directly from the config file.
+
+ """
+
+ for i in self._nodes.items():
+ node = i[1]
+ devices = node['devices']
+ all_devices = devices['other_devices']
+ all_devices.update(devices['dpdk_devices'])
+ all_devices.update(devices['kernel_devices'])
+
+ current_ifcs = {}
+ interfaces = {}
+ if 'interfaces' in node:
+ current_ifcs = node['interfaces']
+ if current_ifcs:
+ for ifc in current_ifcs.values():
+ dvid = ifc['pci_address']
+ if dvid in all_devices:
+ VppPCIUtil.vpp_create_interface(interfaces, dvid,
+ all_devices[dvid])
+ node['interfaces'] = interfaces
+
+ self.updateconfig()
+
def modify_devices(self):
"""
Modify the devices configuration, asking for the user for the values.