mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
Ticket: CM-1438 Reviewed By: review pending Testing Done: Tested ifup/ifdown Before this patch, `ifup --with-depends <iface>` only brought up lowerdevices. Because those were enough for iface to function. And if ifaces above it (upperdevices) needed fixing, user could just execute `ifup --with-depends <ifaceupper>`. But in a recent, bond under a bridge bug in 2.0, got me thinking that its probably better to up the upperdevices which might be impacted as well. and this patch does just that. The patch includes changes to make ifupdown generate dependency information for all interfaces even if the user requested to operate on a single interface. This is to get a full view of the interfaces file. This might add some overhead. Should not change anything during boot. Still looking at ways to optimize.
359 lines
14 KiB
Python
Executable File
359 lines
14 KiB
Python
Executable File
#!/usr/bin/python
|
|
# PYTHON_ARGCOMPLETE_OK
|
|
|
|
import sys
|
|
import os
|
|
import argcomplete
|
|
import argparse
|
|
from ifupdown.ifupdownmain import *
|
|
|
|
import logging
|
|
|
|
lockfile="/run/network/.lock"
|
|
logger = None
|
|
|
|
def run_up(args):
|
|
logger.debug('args = %s' %str(args))
|
|
|
|
try:
|
|
iflist = args.iflist
|
|
if len(args.iflist) == 0:
|
|
iflist = None
|
|
logger.debug('creating ifupdown object ..')
|
|
cachearg=(False if (iflist or args.nocache or
|
|
args.perfmode or args.noact)
|
|
else True)
|
|
ifupdown_handle = ifupdownMain(force=args.force,
|
|
withdepends=args.withdepends,
|
|
perfmode=args.perfmode,
|
|
njobs=args.jobs,
|
|
dryrun=args.noact,
|
|
cache=cachearg,
|
|
addons_enable=not args.noaddons,
|
|
statemanager_enable=not args.noaddons)
|
|
|
|
if args.noaddons:
|
|
ifupdown_handle.up(['up'], args.all, args.CLASS, iflist,
|
|
excludepats=args.excludepats,
|
|
printdependency=args.printdependency)
|
|
else:
|
|
ifupdown_handle.up(['pre-up', 'up', 'post-up'],
|
|
args.all, args.CLASS, iflist,
|
|
excludepats=args.excludepats,
|
|
printdependency=args.printdependency)
|
|
except:
|
|
raise
|
|
|
|
def run_down(args):
|
|
logger.debug('args = %s' %str(args))
|
|
|
|
try:
|
|
iflist = args.iflist
|
|
logger.debug('creating ifupdown object ..')
|
|
cachearg=(False if (iflist or args.nocache or
|
|
args.perfmode or args.noact)
|
|
else True)
|
|
ifupdown_handle = ifupdownMain(force=args.force,
|
|
withdepends=args.withdepends,
|
|
perfmode=args.perfmode,
|
|
njobs=args.jobs,
|
|
dryrun=args.noact,
|
|
cache=cachearg,
|
|
addons_enable=not args.noaddons,
|
|
statemanager_enable=not args.noaddons)
|
|
|
|
ifupdown_handle.down(['pre-down', 'down', 'post-down'],
|
|
args.all, args.CLASS, iflist,
|
|
excludepats=args.excludepats,
|
|
printdependency=args.printdependency,
|
|
usecurrentconfig=args.usecurrentconfig)
|
|
except:
|
|
raise
|
|
|
|
def run_query(args):
|
|
logger.debug('args = %s' %str(args))
|
|
|
|
try:
|
|
iflist = args.iflist
|
|
if args.checkcurr:
|
|
qop='query-checkcurr'
|
|
elif args.running:
|
|
qop='query-running'
|
|
elif args.raw:
|
|
qop='query-raw'
|
|
elif args.syntaxhelp:
|
|
qop = 'query-syntax'
|
|
elif args.printdependency:
|
|
qop = 'query-dependency'
|
|
elif args.printsavedstate:
|
|
qop = 'query-savedstate'
|
|
else:
|
|
qop='query'
|
|
cachearg=(False if (iflist or args.nocache or
|
|
args.perfmode or args.syntaxhelp or
|
|
(qop != 'query-checkcurr' and
|
|
qop != 'query-running')) else True)
|
|
if not iflist and qop == 'query-running':
|
|
iflist = [i for i in os.listdir('/sys/class/net/')
|
|
if os.path.isdir('/sys/class/net/%s' %i)]
|
|
logger.debug('creating ifupdown object ..')
|
|
ifupdown_handle = ifupdownMain(withdepends=args.withdepends,
|
|
perfmode=args.perfmode,
|
|
njobs=args.jobs,
|
|
cache=cachearg)
|
|
|
|
ifupdown_handle.query([qop], args.all, args.CLASS, iflist,
|
|
excludepats=args.excludepats,
|
|
printdependency=args.printdependency,
|
|
format=args.format)
|
|
except:
|
|
raise
|
|
|
|
def run_reload(args):
|
|
logger.debug('args = %s' %str(args))
|
|
|
|
try:
|
|
logger.debug('creating ifupdown object ..')
|
|
cachearg=(False if (args.nocache or
|
|
args.perfmode or args.noact) else True)
|
|
ifupdown_handle = ifupdownMain(withdepends=args.withdepends,
|
|
perfmode=args.perfmode,
|
|
njobs=args.jobs,
|
|
cache=cachearg)
|
|
ifupdown_handle.reload(['pre-up', 'up', 'post-up'],
|
|
['pre-down', 'down', 'post-down'],
|
|
args.all, None, None,
|
|
excludepats=args.excludepats,
|
|
downchangediface=args.downchangediface)
|
|
except:
|
|
raise
|
|
|
|
def init(args):
|
|
global logger
|
|
|
|
log_level = logging.WARNING
|
|
if args.verbose:
|
|
log_level = logging.INFO
|
|
if args.debug:
|
|
log_level = logging.DEBUG
|
|
|
|
try:
|
|
logging.basicConfig(level=log_level,
|
|
format='%(levelname)s: %(message)s')
|
|
logger = logging.getLogger('ifupdown')
|
|
except:
|
|
raise
|
|
|
|
|
|
def deinit():
|
|
{}
|
|
|
|
def update_argparser(argparser):
|
|
""" base parser, common to all commands """
|
|
|
|
argparser.add_argument('-a', '--all', action='store_true', required=False,
|
|
help='process all interfaces marked \"auto\"')
|
|
argparser.add_argument('iflist', metavar='IFACE',
|
|
nargs='*', help='interface list separated by spaces. ' +
|
|
'IFACE list is mutually exclusive with -a option.')
|
|
argparser.add_argument('-v', '--verbose', dest='verbose',
|
|
action='store_true', help='verbose')
|
|
argparser.add_argument('-d', '--debug', dest='debug',
|
|
action='store_true',
|
|
help='output debug info')
|
|
argparser.add_argument('-q', '--quiet', dest='quiet',
|
|
action='store_true',
|
|
help=argparse.SUPPRESS)
|
|
argparser.add_argument('--allow', dest='CLASS',
|
|
help='ignore non-\"allow-CLASS\" interfaces')
|
|
argparser.add_argument('--with-depends', dest='withdepends',
|
|
action='store_true', help='run with all dependent interfaces.'+
|
|
' This option is redundant when \'-a\' is specified. With ' +
|
|
'\'-a\' interfaces are always executed in dependency order')
|
|
argparser.add_argument('--perfmode', dest='perfmode',
|
|
action='store_true', help=argparse.SUPPRESS)
|
|
argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
|
|
default=-1, choices=range(1,12), help=argparse.SUPPRESS)
|
|
argparser.add_argument('--nocache', dest='nocache', action='store_true',
|
|
help=argparse.SUPPRESS)
|
|
argparser.add_argument('-X', '--exclude', dest='excludepats',
|
|
action='append',
|
|
help='Exclude interfaces from the list of interfaces' +
|
|
' to operate on. Can be specified multiple times.')
|
|
|
|
def update_ifupdown_argparser(argparser):
|
|
""" common arg parser for ifup and ifdown """
|
|
argparser.add_argument('-f', '--force', dest='force',
|
|
action='store_true',
|
|
help='force run all operations')
|
|
group = argparser.add_mutually_exclusive_group(required=False)
|
|
group.add_argument('-n', '--no-act', dest='noact',
|
|
action='store_true', help='print out what would happen,' +
|
|
'but don\'t do it')
|
|
group.add_argument('--print-dependency',
|
|
dest='printdependency', choices=['list', 'dot'],
|
|
help='print iface dependency')
|
|
group.add_argument('--no-scripts', '--no-addons',
|
|
dest='noaddons', action='store_true',
|
|
help='dont run any addon modules or scripts. Runs only link ' +
|
|
'up/down')
|
|
|
|
def update_ifup_argparser(argparser):
|
|
update_ifupdown_argparser(argparser)
|
|
|
|
def update_ifdown_argparser(argparser):
|
|
update_ifupdown_argparser(argparser)
|
|
argparser.add_argument('--use-current-config',
|
|
dest='usecurrentconfig', action='store_true',
|
|
help=argparse.SUPPRESS)
|
|
#help='By default ifdown looks at the saved state for ' +
|
|
#'interfaces to bring down. This option allows ifdown to ' +
|
|
#'look at the current interfaces file. Useful when your ' +
|
|
#'state file is corrupted or you want down to use the latest '
|
|
#'from the interfaces file')
|
|
|
|
def update_ifquery_argparser(argparser):
|
|
""" arg parser for ifquery options """
|
|
|
|
# -l is same as '-a', only here for backward compatibility
|
|
argparser.add_argument('-l', '--list', action='store_true', dest='all',
|
|
help=argparse.SUPPRESS)
|
|
group = argparser.add_mutually_exclusive_group(required=False)
|
|
group.add_argument('-r', '--running', dest='running',
|
|
action='store_true',
|
|
help='query running state of an interface')
|
|
group.add_argument('-c', '--check', dest='checkcurr',
|
|
action='store_true',
|
|
help='check interface file contents against ' +
|
|
'running state of an interface')
|
|
group.add_argument('--raw', action='store_true', dest='raw',
|
|
help='print raw config file entries')
|
|
group.add_argument('--print-savedstate', action='store_true',
|
|
dest='printsavedstate',
|
|
help=argparse.SUPPRESS)
|
|
argparser.add_argument('--format', dest='format', default='native',
|
|
choices=['native', 'json'], help=argparse.SUPPRESS)
|
|
argparser.add_argument('--print-dependency',
|
|
dest='printdependency', choices=['list', 'dot'],
|
|
help='print interface dependency')
|
|
argparser.add_argument('--syntax-help', action='store_true',
|
|
dest='syntaxhelp',
|
|
help='print supported interface config syntax')
|
|
|
|
def update_ifreload_argparser(argparser):
|
|
""" parser for ifreload """
|
|
argparser.add_argument('-a', '--all', action='store_true', required=True,
|
|
help='process all interfaces marked \"auto\"')
|
|
argparser.add_argument('iflist', metavar='IFACE',
|
|
nargs='*', help=argparse.SUPPRESS)
|
|
argparser.add_argument('-n', '--no-act', dest='noact',
|
|
action='store_true', help=argparse.SUPPRESS)
|
|
argparser.add_argument('-v', '--verbose', dest='verbose',
|
|
action='store_true', help='verbose')
|
|
argparser.add_argument('-d', '--debug', dest='debug',
|
|
action='store_true',
|
|
help='output debug info')
|
|
argparser.add_argument('--with-depends', dest='withdepends',
|
|
action='store_true', help=argparse.SUPPRESS)
|
|
argparser.add_argument('--perfmode', dest='perfmode',
|
|
action='store_true', help=argparse.SUPPRESS)
|
|
argparser.add_argument('--nocache', dest='nocache', action='store_true',
|
|
help=argparse.SUPPRESS)
|
|
argparser.add_argument('-X', '--exclude', dest='excludepats',
|
|
action='append',
|
|
help=argparse.SUPPRESS)
|
|
argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
|
|
default=-1, choices=range(1,12), help=argparse.SUPPRESS)
|
|
argparser.add_argument('--down-changediface', dest='downchangediface',
|
|
action='store_true', help='down interfaces whose ' +
|
|
'config have changed before bringing them up. By' +
|
|
' default all interfaces are brought up')
|
|
|
|
def parse_args(argsv, op):
|
|
if op == 'query':
|
|
descr = 'query interfaces (all or interface list)'
|
|
else:
|
|
descr = 'interface management'
|
|
argparser = argparse.ArgumentParser(description=descr)
|
|
if op == 'reload':
|
|
update_ifreload_argparser(argparser)
|
|
else:
|
|
update_argparser(argparser)
|
|
if op == 'up':
|
|
update_ifup_argparser(argparser)
|
|
elif op == 'down':
|
|
update_ifdown_argparser(argparser)
|
|
elif op == 'query':
|
|
update_ifquery_argparser(argparser)
|
|
elif op == 'reload':
|
|
update_ifreload_argparser(argparser)
|
|
|
|
argcomplete.autocomplete(argparser)
|
|
|
|
return argparser.parse_args(argsv)
|
|
|
|
handlers = {'up' : run_up,
|
|
'down' : run_down,
|
|
'query' : run_query,
|
|
'reload' : run_reload }
|
|
|
|
def main(argv):
|
|
""" main function """
|
|
args = None
|
|
try:
|
|
op = None
|
|
if argv[0].endswith('ifup'):
|
|
op = 'up'
|
|
elif argv[0].endswith('ifdown'):
|
|
op = 'down'
|
|
elif argv[0].endswith('ifquery'):
|
|
op = 'query'
|
|
elif argv[0].endswith('ifreload'):
|
|
op = 'reload'
|
|
else:
|
|
print ('Unexpected executable.' +
|
|
' Should be \'ifup\' or \'ifdown\' or \'ifquery\'')
|
|
exit(1)
|
|
# Command line arg parser
|
|
args = parse_args(argv[1:], op)
|
|
if not args.iflist and not args.all:
|
|
if op != 'query' or not args.syntaxhelp:
|
|
print '\'-a\' option or interface list are required'
|
|
exit(1)
|
|
|
|
if args.iflist and args.all:
|
|
print '\'-a\' option and interface list are mutually exclusive'
|
|
exit(1)
|
|
init(args)
|
|
handlers.get(op)(args)
|
|
except Exception, e:
|
|
if not str(e):
|
|
exit(1)
|
|
if args and args.debug:
|
|
raise
|
|
else:
|
|
if logger:
|
|
logger.error(str(e))
|
|
else:
|
|
print str(e)
|
|
if args and not args.debug:
|
|
print '\nRerun the command with \'-d\' for a detailed errormsg'
|
|
exit(1)
|
|
finally:
|
|
deinit()
|
|
|
|
if __name__ == "__main__":
|
|
|
|
if not os.geteuid() == 0:
|
|
print 'Error: Must be root to run this command'
|
|
exit(1)
|
|
|
|
"""
|
|
XXX: Cannot use this. A spawned dhclient process can hold the lock
|
|
if not utilities.lockFile(lockfile):
|
|
print 'Another instance of this program is already running.'
|
|
exit(0)
|
|
"""
|
|
|
|
main(sys.argv)
|