mirror of
				https://github.com/CumulusNetworks/ifupdown2.git
				synced 2024-05-06 15:54:50 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			244 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python3
 | |
| #
 | |
| # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
 | |
| # Authors:
 | |
| #           Roopa Prabhu, roopa@cumulusnetworks.com
 | |
| #           Julien Fortin, julien@cumulusnetworks.com
 | |
| #
 | |
| 
 | |
| import sys
 | |
| import argparse
 | |
| import argcomplete
 | |
| 
 | |
| try:
 | |
|     from ifupdown2.ifupdown.utils import utils
 | |
|     from ifupdown2.ifupdown.exceptions import ArgvParseError, ArgvParseHelp
 | |
| except:
 | |
|     from ifupdown.utils import utils
 | |
|     from ifupdown.exceptions import ArgvParseError, ArgvParseHelp
 | |
| 
 | |
| 
 | |
| class VersionAction(argparse.Action):
 | |
|     def __call__(self, parser, namespace, values, option_string=None):
 | |
| 
 | |
|         try:
 | |
|             dpkg = utils.exec_commandl([utils.dpkg_cmd, '-l', 'ifupdown2'])
 | |
| 
 | |
|             if not dpkg:
 | |
|                 raise Exception('dpkg -l ifupdown2 returns without output')
 | |
| 
 | |
|             dpkg = dpkg.split('\n')
 | |
| 
 | |
|             if not dpkg:
 | |
|                 raise Exception('dpkg -l ifupdown2 returns without output')
 | |
| 
 | |
|             for line in dpkg:
 | |
|                 if 'ifupdown2' in line:
 | |
|                     info = line.split()
 | |
| 
 | |
|                     sys.stdout.write('ifupdown2:%s\n' % (info[2]))
 | |
|                     sys.exit(0)
 | |
| 
 | |
|             raise Exception('ifupdown2 package not found using dpkg -l')
 | |
| 
 | |
|         except Exception as e:
 | |
|             sys.stderr.write('error: cannot get current version using dpkg: %s\n' % str(e))
 | |
|             sys.exit(1)
 | |
| 
 | |
| 
 | |
| class Parse:
 | |
|     valid_ops = {
 | |
|         'ifup': 'up',
 | |
|         'ifdown': 'down',
 | |
|         'ifreload': 'reload',
 | |
|         'ifquery': 'query'
 | |
|     }
 | |
| 
 | |
|     def __init__(self, argv):
 | |
|         self.executable_name = argv[0]
 | |
|         self.op = self.get_op()
 | |
|         self.argv = argv[1:]
 | |
| 
 | |
|         if self.op == 'query':
 | |
|             descr = 'query interfaces (all or interface list)'
 | |
|         elif self.op == 'reload':
 | |
|             descr = 'reload interface configuration.'
 | |
|         else:
 | |
|             descr = 'interface management'
 | |
|         argparser = argparse.ArgumentParser(description=descr)
 | |
|         if self.op == 'reload':
 | |
|             self.update_ifreload_argparser(argparser)
 | |
|         else:
 | |
|             self.update_argparser(argparser)
 | |
|             if self.op == 'up':
 | |
|                 self.update_ifup_argparser(argparser)
 | |
|             elif self.op == 'down':
 | |
|                 self.update_ifdown_argparser(argparser)
 | |
|             elif self.op == 'query':
 | |
|                 self.update_ifquery_argparser(argparser)
 | |
|         self.update_common_argparser(argparser)
 | |
|         argcomplete.autocomplete(argparser)
 | |
| 
 | |
|         try:
 | |
|             self.args = argparser.parse_args(self.argv)
 | |
|         except SystemExit as e:
 | |
|             # on "--help" parse_args will raise SystemExit.
 | |
|             # We need to catch this behavior and raise a custom
 | |
|             # exception to return 0 properly
 | |
|             #raise ArgvParseHelp()
 | |
|             for help_str in ('-h', '--help'):
 | |
|                 if help_str in argv:
 | |
|                     raise ArgvParseHelp()
 | |
|             raise
 | |
| 
 | |
|     def validate(self):
 | |
|         if self.op == 'query' and (self.args.syntaxhelp or self.args.list):
 | |
|             return True
 | |
| 
 | |
|         if self.op == 'reload':
 | |
|             if not self.args.all and not self.args.currentlyup and not self.args.CLASS:
 | |
|                 raise ArgvParseError("'-a' or '-c' or '-allow' option is required")
 | |
|         elif not self.args.iflist and not self.args.all and not self.args.CLASS:
 | |
|             raise ArgvParseError("'-a' option or interface list are required")
 | |
| 
 | |
|         if self.args.iflist and self.args.all:
 | |
|             raise ArgvParseError("'-a' option and interface list are mutually exclusive")
 | |
| 
 | |
|         if self.op != 'reload' and self.args.CLASS and self.args.all:
 | |
|             raise ArgvParseError("'--allow' option is mutually exclusive with '-a'")
 | |
|         return True
 | |
| 
 | |
|     def get_op(self):
 | |
|         try:
 | |
|             for key, value in self.valid_ops.items():
 | |
|                 if self.executable_name.endswith(key):
 | |
|                     return value
 | |
|             raise ArgvParseError("Unexpected executable. Should be '%s'" % "' or '".join(list(self.valid_ops.keys())))
 | |
|         except:
 | |
|             raise ArgvParseError("Unexpected executable. Should be '%s'" % "' or '".join(list(self.valid_ops.keys())))
 | |
| 
 | |
|     def get_args(self):
 | |
|         return self.args
 | |
| 
 | |
|     def update_argparser(self, 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', action='append', help='ignore non-"allow-CLASS" interfaces')
 | |
|         argparser.add_argument('-w', '--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('--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.')
 | |
|         argparser.add_argument('-i', '--interfaces', dest='interfacesfile', default=None,
 | |
|                                help='Specify interfaces file instead of file defined in ifupdown2.conf file')
 | |
|         argparser.add_argument('-t', '--interfaces-format', dest='interfacesfileformat', default='native',
 | |
|                                choices=['native', 'json'], help='interfaces file format')
 | |
|         argparser.add_argument('-T', '--type', dest='type', default=None, choices=['iface', 'vlan'],
 | |
|                                help='type of interface entry (iface or vlan). '
 | |
|                                     'This option can be used in case of ambiguity between '
 | |
|                                     'a vlan interface and an iface interface of the same name')
 | |
| 
 | |
|     def update_ifupdown_argparser(self, argparser):
 | |
|         """ common arg parser for ifup and ifdown """
 | |
|         argparser.add_argument('-f', '--force', dest='force', action='store_true', help='force run all operations')
 | |
|         argparser.add_argument('-l', '--syslog', dest='syslog', action='store_true')
 | |
|         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('-p', '--print-dependency', dest='printdependency',
 | |
|                            choices=['list', 'dot'], help='print iface dependency')
 | |
|         group.add_argument('--no-scripts', '--admin-state', dest='noaddons', action='store_true',
 | |
|                            help='dont run any addon modules/scripts. Only bring the interface administratively up/down')
 | |
| 
 | |
|     def update_ifup_argparser(self, argparser):
 | |
|         argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck',
 | |
|                                action='store_true', help='Only run the interfaces file parser')
 | |
|         argparser.add_argument('-k', '--skip-upperifaces', dest='skipupperifaces', action='store_true',
 | |
|                                help='ifup by default tries to add newly created interfaces into its upper/parent '
 | |
|                                     'interfaces. Eg. if a bridge port is created as a result of ifup on the port, '
 | |
|                                     'ifup automatically adds the port to the bridge. This option can be used to '
 | |
|                                     'disable this default behaviour')
 | |
|         self.update_ifupdown_argparser(argparser)
 | |
| 
 | |
|     def update_ifdown_argparser(self, argparser):
 | |
|         self.update_ifupdown_argparser(argparser)
 | |
|         argparser.add_argument('-u', '--use-current-config',
 | |
|                                dest='usecurrentconfig', action='store_true',
 | |
|                                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(self, 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='list',
 | |
|                                help='list all matching known interfaces')
 | |
|         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('-x', '--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('-o', '--format', dest='format', default='native',
 | |
|                                choices=['native', 'json'], help='interface display format')
 | |
|         argparser.add_argument('-p', '--print-dependency', dest='printdependency',
 | |
|                                choices=['list', 'dot'], help='print interface dependency')
 | |
|         argparser.add_argument('-s', '--syntax-help', action='store_true', dest='syntaxhelp',
 | |
|                                help='print supported interface config syntax')
 | |
|         argparser.add_argument('--with-defaults', action='store_true', dest='withdefaults',
 | |
|                                help='check policy default file contents, for unconfigured attributes, '
 | |
|                                     'against running state of an interface')
 | |
| 
 | |
|     def update_ifreload_argparser(self, argparser):
 | |
|         """ parser for ifreload """
 | |
|         group = argparser.add_mutually_exclusive_group(required=True)
 | |
|         group.add_argument('-a', '--all', action='store_true', help='process all interfaces marked "auto"')
 | |
|         group.add_argument('-c', '--currently-up', dest='currentlyup', action='store_true',
 | |
|                            help='Reload the configuration for all interfaces which are '
 | |
|                                 'currently up regardless of whether an interface has '
 | |
|                                 '"auto <interface>" configuration within the /etc/network/interfaces file.')
 | |
|         group.add_argument('--allow', dest='CLASS', action='append', help='ignore non-"allow-CLASS" interfaces')
 | |
|         argparser.add_argument('iflist', metavar='IFACE', nargs='*', help=argparse.SUPPRESS)
 | |
|         argparser.add_argument('-n', '--no-act', dest='noact', action='store_true',
 | |
|                                help='print out what would happen, but don\'t do it')
 | |
|         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('-w', '--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('-i', '--interfaces', dest='interfacesfile',
 | |
|         #            default='/etc/network/interfaces',
 | |
|         #            help='use interfaces file instead of default ' +
 | |
|         #            '/etc/network/interfaces')
 | |
|         argparser.add_argument('-u', '--use-current-config', dest='usecurrentconfig', action='store_true',
 | |
|                                help='By default ifreload looks at saved state for interfaces to bring down. '
 | |
|                                     'With this option ifreload will only 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')
 | |
|         argparser.add_argument('-l', '--syslog', dest='syslog', action='store_true')
 | |
|         argparser.add_argument('-f', '--force', dest='force', action='store_true', help='force run all operations')
 | |
|         argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck', action='store_true',
 | |
|                                help='Only run the interfaces file parser')
 | |
| 
 | |
|     def update_common_argparser(self, argparser):
 | |
|         ''' general parsing rules '''
 | |
| 
 | |
|         argparser.add_argument('-V', '--version', action=VersionAction, nargs=0)
 |