X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=extras%2Fvpp_config%2Fvpp_config.py;h=e863cde854e70f9a6d452ed7b2ad087666bc21d1;hb=b2f09146c957f87edd431e75a24f8a456d539a02;hp=2e644185236d3c6bb9e8880fa65ba830e9e72579;hpb=68b0ee3a38e3a86f0389d8cc695915df190c3dfb;p=vpp.git diff --git a/extras/vpp_config/vpp_config.py b/extras/vpp_config/vpp_config.py index 2e644185236..e863cde854e 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 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: @@ -14,15 +15,23 @@ # 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' @@ -50,14 +59,14 @@ def autoconfig_yn(question, default): 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 @@ -138,11 +147,13 @@ def autoconfig_show_system(): 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 @@ -150,14 +161,13 @@ def autoconfig_hugepage_apply(node): 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) @@ -167,104 +177,103 @@ def autoconfig_hugepage_apply(node): 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. @@ -272,20 +281,24 @@ def autoconfig_apply(): 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(): @@ -295,42 +308,40 @@ def autoconfig_apply(): 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() @@ -349,16 +360,27 @@ def autoconfig_dryrun(): 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() @@ -367,7 +389,8 @@ def autoconfig_dryrun(): acfg.apply_grub_cmdline() # Huge Pages - acfg.modify_huge_pages() + if ask_questions: + acfg.modify_huge_pages() acfg.apply_huge_pages() @@ -391,15 +414,15 @@ def autoconfig_install(): 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]? " @@ -408,13 +431,19 @@ def autoconfig_install(): 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) @@ -440,13 +469,91 @@ def autoconfig_patch_qemu(): 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(): @@ -457,32 +564,29 @@ 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 @@ -492,6 +596,9 @@ def autoconfig_main(): """ + # Setup + autoconfig_setup() + answer = '' while answer != 'q': answer = autoconfig_main_menu() @@ -503,13 +610,13 @@ def autoconfig_main(): 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. @@ -519,8 +626,6 @@ def autoconfig_setup(): global rootdir - logging.basicConfig(level=logging.ERROR) - distro = VPPUtil.get_linux_distro() if distro[0] == 'Ubuntu': rootdir = '/usr/local' @@ -535,15 +640,20 @@ def autoconfig_setup(): 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(): @@ -559,15 +669,88 @@ def autoconfig_setup(): (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()