-#!/usr/bin/python
+#!/usr/bin/env python3
# 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:
# limitations under the License.
"""VPP Configuration Main Entry"""
+from __future__ import absolute_import, division, print_function
import re
import os
import sys
import logging
+import argparse
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'
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
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
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
- answer = autoconfig_yn(
- "\nAre you sure you want to apply these changes [Y/n]? ",
- 'y')
- if answer == 'n':
- return -1
+ 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':
+ return -1
# Copy and sysctl
autoconfig_cp(node, rootdir + VPP_HUGE_PAGE_FILE, VPP_REAL_HUGE_PAGE_FILE)
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
-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
+ 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':
+ return -1
# 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
-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:"
+
+ 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
-
- # 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')
+ 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')
+ if answer == 'y':
+ return
+
+ 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", end=' ')
+ 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.
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()
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)
- 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():
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."
- 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()
return
# Modify the devices
- acfg.modify_devices()
+ if ask_questions:
+ acfg.modify_devices()
+ else:
+ acfg.update_interfaces_config()
+
+ # If there are no interfaces, just return
+ for i in nodes.items():
+ node = i[1]
+ if not acfg.has_interfaces(node):
+ print("\nThere are no VPP interfaces configured, please configure at least 1.")
+ return
# 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()
acfg.apply_grub_cmdline()
# Huge Pages
- acfg.modify_huge_pages()
+ if ask_questions:
+ acfg.modify_huge_pages()
acfg.apply_huge_pages()
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]? "
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':
+ question = "Do you want to install the release version [Y/n]? "
+ answer = autoconfig_yn(question, 'y')
+ if answer == 'y':
+ branch = 'release'
+ else:
+ branch = 'master'
logger.setLevel(logging.INFO)
- vutil.install_vpp(node)
+ vutil.install_vpp(node, branch)
# Set the logging level back
logger.setLevel(logging.ERROR)
acfg.patch_qemu(node)
+def autoconfig_ipv4_setup():
+ """
+ Setup IPv4 interfaces
+
+ """
+
+ acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE)
+ acfg.ipv4_interface_setup()
+
+
+def autoconfig_create_iperf_vm():
+ """
+ Setup IPv4 interfaces
+
+ """
+
+ acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE)
+ acfg.destroy_iperf_vm('iperf-server')
+ acfg.create_and_bridge_iperf_virtual_interface()
+ acfg.create_iperf_vm('iperf-server')
+
+
def autoconfig_not_implemented():
"""
This feature is not implemented
"""
- print "\nThis Feature is not implemented yet...."
+ 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\
+2) Create an iperf VM and Connect to VPP an interface\n\
+9 or q) Back to main menu.'
+
+ print ("{}".format(basic_menu_text))
+
+ input_valid = False
+ answer = ''
+ while not input_valid:
+ answer = 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 == '2':
+ autoconfig_create_iperf_vm()
+ elif answer == '9' or answer == 'q':
+ return
+ else:
+ autoconfig_not_implemented()
def autoconfig_main_menu():
main_menu_text = '\nWhat would you like to do?\n\n\
1) Show basic system information\n\
-2) Dry Run (Will save the configuration files in {}/vpp/vpp-config/dryrun for inspection)\n\
- and user input in {}/vpp/vpp-config/configs/auto-config.yaml\n\
+2) Dry Run (Saves the configuration files in {}/vpp/vpp-config/dryrun.\n\
3) Full configuration (WARNING: This will change the system configuration)\n\
4) List/Install/Uninstall VPP.\n\
-9 or q) Quit'.format(rootdir, rootdir)
+q) Quit'.format(rootdir, rootdir)
# 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-79]', answer):
+ if re.findall(r'[Qq1-4]', answer):
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 4 or q.")
- if answer == '9':
- answer = 'q'
return answer
"""
+ # Setup
+ autoconfig_setup()
+
answer = ''
while answer != 'q':
answer = autoconfig_main_menu()
autoconfig_apply()
elif answer == '4':
autoconfig_install()
- elif answer == '9' or answer == 'q':
+ elif answer == 'q':
return
else:
autoconfig_not_implemented()
-def autoconfig_setup():
+def autoconfig_setup(ask_questions=True):
"""
The auto configuration setup function.
global rootdir
- logging.basicConfig(level=logging.ERROR)
-
distro = VPPUtil.get_linux_distro()
if distro[0] == 'Ubuntu':
rootdir = '/usr/local'
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():
(os.path.isfile(VPP_REAL_GRUB_FILE) is True):
autoconfig_cp(node, VPP_REAL_GRUB_FILE, '{}'.format(rootdir + VPP_GRUB_FILE))
+ # Be sure the uio_pci_generic driver is installed
+ cmd = 'modprobe uio_pci_generic'
+ (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
+ if ret != 0:
+ logging.warning('{} failed on node {} {}'. format(cmd, node['host'], stderr))
+
-if __name__ == '__main__':
+# noinspection PyUnresolvedReferences
+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 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 len(sys.argv) == 1:
+ autoconfig_main()
+ return
+ elif len(sys.argv) == 2 and ((sys.argv[1] == '-d') or (
+ sys.argv[1] == '--debug')):
+ 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 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)')
+
+ args = main_parser.parse_args()
+
+ return execute_with_args(args)
+
+
+if __name__ == '__main__':
+ config_main()