]> git.proxmox.com Git - mirror_ifupdown2.git/blame - sbin/ifupdown
First cut ifupdown2 module for vrrpd
[mirror_ifupdown2.git] / sbin / ifupdown
CommitLineData
a6f80f0e 1#!/usr/bin/python
904908bc
RP
2#
3# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6# ifupdown --
7# tool to configure network interfaces
8#
a6f80f0e 9import sys
10import os
e6c9d007 11import argcomplete
a6f80f0e 12import argparse
14dc390d 13import ConfigParser
14import StringIO
a6f80f0e 15import logging
261379f0 16import logging.handlers
61636dcc 17import resource
d40e96ee 18from ifupdown.ifupdownmain import *
19from ifupdown.utils import *
a6f80f0e 20
21lockfile="/run/network/.lock"
14dc390d 22configfile="/etc/network/ifupdown2/ifupdown2.conf"
23configmap_g=None
a6f80f0e 24logger = None
3dcc1d0e 25interfacesfileiobuf=None
03d5166b 26ENVPATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
a6f80f0e 27
f802fe3c 28def run_up(args):
a6f80f0e 29 logger.debug('args = %s' %str(args))
30
31 try:
739f665b 32 iflist = args.iflist
33 if len(args.iflist) == 0:
34 iflist = None
a6f80f0e 35 logger.debug('creating ifupdown object ..')
f802fe3c 36 cachearg=(False if (iflist or args.nocache or
d08d5f54 37 args.perfmode or args.noact)
38 else True)
14dc390d 39 ifupdown_handle = ifupdownMain(config=configmap_g,
40 force=args.force,
f802fe3c 41 withdepends=args.withdepends,
42 perfmode=args.perfmode,
f802fe3c 43 dryrun=args.noact,
20dd6242 44 cache=cachearg,
45 addons_enable=not args.noaddons,
14dc390d 46 statemanager_enable=not args.noaddons,
3dcc1d0e 47 interfacesfile=args.interfacesfile,
48 interfacesfileiobuf=interfacesfileiobuf,
49 interfacesfileformat=args.interfacesfileformat)
20dd6242 50 if args.noaddons:
51 ifupdown_handle.up(['up'], args.all, args.CLASS, iflist,
52 excludepats=args.excludepats,
9dce3561 53 printdependency=args.printdependency,
54 syntaxcheck=args.syntaxcheck)
20dd6242 55 else:
56 ifupdown_handle.up(['pre-up', 'up', 'post-up'],
d08d5f54 57 args.all, args.CLASS, iflist,
739f665b 58 excludepats=args.excludepats,
9dce3561 59 printdependency=args.printdependency,
60 syntaxcheck=args.syntaxcheck)
f802fe3c 61 except:
62 raise
739f665b 63
f802fe3c 64def run_down(args):
65 logger.debug('args = %s' %str(args))
66
67 try:
68 iflist = args.iflist
f802fe3c 69 logger.debug('creating ifupdown object ..')
14dc390d 70 ifupdown_handle = ifupdownMain(config=configmap_g, force=args.force,
f802fe3c 71 withdepends=args.withdepends,
72 perfmode=args.perfmode,
f802fe3c 73 dryrun=args.noact,
20dd6242 74 addons_enable=not args.noaddons,
14dc390d 75 statemanager_enable=not args.noaddons,
3dcc1d0e 76 interfacesfile=args.interfacesfile,
77 interfacesfileiobuf=interfacesfileiobuf,
78 interfacesfileformat=args.interfacesfileformat)
f802fe3c 79
80 ifupdown_handle.down(['pre-down', 'down', 'post-down'],
81 args.all, args.CLASS, iflist,
82 excludepats=args.excludepats,
5c721925 83 printdependency=args.printdependency,
84 usecurrentconfig=args.usecurrentconfig)
f802fe3c 85 except:
86 raise
87
88def run_query(args):
89 logger.debug('args = %s' %str(args))
90
91 try:
92 iflist = args.iflist
f802fe3c 93 if args.checkcurr:
94 qop='query-checkcurr'
95 elif args.running:
f802fe3c 96 qop='query-running'
97 elif args.raw:
98 qop='query-raw'
99 elif args.syntaxhelp:
100 qop = 'query-syntax'
101 elif args.printdependency:
102 qop = 'query-dependency'
5c721925 103 elif args.printsavedstate:
104 qop = 'query-savedstate'
f802fe3c 105 else:
106 qop='query'
83c1f241 107 cachearg=(False if (iflist or args.nocache or
108 args.perfmode or args.syntaxhelp or
109 (qop != 'query-checkcurr' and
110 qop != 'query-running')) else True)
c798b0f4 111 if not iflist and qop == 'query-running':
112 iflist = [i for i in os.listdir('/sys/class/net/')
113 if os.path.isdir('/sys/class/net/%s' %i)]
83c1f241 114 logger.debug('creating ifupdown object ..')
14dc390d 115 ifupdown_handle = ifupdownMain(config=configmap_g,
116 withdepends=args.withdepends,
83c1f241 117 perfmode=args.perfmode,
14dc390d 118 cache=cachearg,
3dcc1d0e 119 interfacesfile=args.interfacesfile,
120 interfacesfileiobuf=interfacesfileiobuf,
121 interfacesfileformat=args.interfacesfileformat)
83c1f241 122
f802fe3c 123 ifupdown_handle.query([qop], args.all, args.CLASS, iflist,
124 excludepats=args.excludepats,
125 printdependency=args.printdependency,
126 format=args.format)
127 except:
128 raise
129
f802fe3c 130def run_reload(args):
131 logger.debug('args = %s' %str(args))
132
133 try:
134 logger.debug('creating ifupdown object ..')
14dc390d 135 ifupdown_handle = ifupdownMain(config=configmap_g,
136 withdepends=args.withdepends,
137 perfmode=args.perfmode)
20dd6242 138 ifupdown_handle.reload(['pre-up', 'up', 'post-up'],
139 ['pre-down', 'down', 'post-down'],
140 args.all, None, None,
14dc390d 141 excludepats=args.excludepats,
142 usecurrentconfig=args.usecurrentconfig)
a6f80f0e 143 except:
144 raise
145
a6f80f0e 146def init(args):
147 global logger
3dcc1d0e 148 global interfacesfileiobuf
a6f80f0e 149
150 log_level = logging.WARNING
fe0a57d3 151 if args.verbose:
a6f80f0e 152 log_level = logging.INFO
fe0a57d3 153 if args.debug:
a6f80f0e 154 log_level = logging.DEBUG
155
156 try:
261379f0
RP
157 if hasattr(args, 'syslog') and args.syslog:
158 root_logger = logging.getLogger()
159 syslog_handler = logging.handlers.SysLogHandler(address='/dev/log',
160 facility=logging.handlers.SysLogHandler.LOG_DAEMON)
161 logging.addLevelName(logging.ERROR, 'error')
162 logging.addLevelName(logging.WARNING, 'warning')
163 logging.addLevelName(logging.DEBUG, 'debug')
164 logging.addLevelName(logging.INFO, 'info')
165 root_logger.setLevel(log_level)
166 syslog_handler.setFormatter(logging.Formatter(
167 '%(name)s: %(levelname)s: %(message)s'))
168 root_logger.addHandler(syslog_handler)
169 logger = logging.getLogger('ifupdown')
170 else:
171 logging.basicConfig(level=log_level,
172 format='%(levelname)s: %(message)s')
173 logging.addLevelName(logging.ERROR, 'error')
174 logging.addLevelName(logging.WARNING, 'warning')
175 logging.addLevelName(logging.DEBUG, 'debug')
176 logging.addLevelName(logging.INFO, 'info')
177 logger = logging.getLogger('ifupdown')
a6f80f0e 178 except:
179 raise
180
3dcc1d0e 181 # If interfaces file is stdin, read
182 if hasattr(args, 'interfacesfile') and args.interfacesfile == '-':
183 interfacesfileiobuf = sys.stdin.read()
a6f80f0e 184
185def deinit():
eab25b7c 186 {}
a6f80f0e 187
188def update_argparser(argparser):
cca03c30 189 """ base parser, common to all commands """
37c0543d 190
191 argparser.add_argument('-a', '--all', action='store_true', required=False,
cca03c30 192 help='process all interfaces marked \"auto\"')
a6f80f0e 193 argparser.add_argument('iflist', metavar='IFACE',
f802fe3c 194 nargs='*', help='interface list separated by spaces. ' +
195 'IFACE list is mutually exclusive with -a option.')
a6f80f0e 196 argparser.add_argument('-v', '--verbose', dest='verbose',
197 action='store_true', help='verbose')
198 argparser.add_argument('-d', '--debug', dest='debug',
199 action='store_true',
200 help='output debug info')
201 argparser.add_argument('-q', '--quiet', dest='quiet',
202 action='store_true',
203 help=argparse.SUPPRESS)
eab25b7c 204 argparser.add_argument('--allow', dest='CLASS',
205 help='ignore non-\"allow-CLASS\" interfaces')
14dc390d 206 argparser.add_argument('-w', '--with-depends', dest='withdepends',
f802fe3c 207 action='store_true', help='run with all dependent interfaces.'+
208 ' This option is redundant when \'-a\' is specified. With ' +
209 '\'-a\' interfaces are always executed in dependency order')
3e8ee54f 210 argparser.add_argument('--perfmode', dest='perfmode',
eab25b7c 211 action='store_true', help=argparse.SUPPRESS)
14dc390d 212 #argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
213 # default=-1, choices=range(1,12), help=argparse.SUPPRESS)
739f665b 214 argparser.add_argument('--nocache', dest='nocache', action='store_true',
215 help=argparse.SUPPRESS)
3e8ee54f 216 argparser.add_argument('-X', '--exclude', dest='excludepats',
37c0543d 217 action='append',
218 help='Exclude interfaces from the list of interfaces' +
f802fe3c 219 ' to operate on. Can be specified multiple times.')
14dc390d 220 argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
221 default='/etc/network/interfaces',
222 help='use interfaces file instead of default ' +
223 '/etc/network/interfaces')
3dcc1d0e 224 argparser.add_argument('-t', '--interfaces-format',
225 dest='interfacesfileformat',
226 default='native',
227 choices=['native', 'json'],
228 help='interfaces file format')
a6f80f0e 229
230def update_ifupdown_argparser(argparser):
cca03c30 231 """ common arg parser for ifup and ifdown """
a6f80f0e 232 argparser.add_argument('-f', '--force', dest='force',
233 action='store_true',
234 help='force run all operations')
261379f0
RP
235 argparser.add_argument('-l', '--syslog', dest='syslog',
236 action='store_true',
237 help=argparse.SUPPRESS)
5c721925 238 group = argparser.add_mutually_exclusive_group(required=False)
239 group.add_argument('-n', '--no-act', dest='noact',
3e8ee54f 240 action='store_true', help='print out what would happen,' +
241 'but don\'t do it')
14dc390d 242 group.add_argument('-p', '--print-dependency',
cca03c30 243 dest='printdependency', choices=['list', 'dot'],
244 help='print iface dependency')
d40e96ee 245 group.add_argument('--no-scripts', '--admin-state',
20dd6242 246 dest='noaddons', action='store_true',
14dc390d 247 help='dont run any addon modules/scripts. Only bring the ' +
248 'interface administratively up/down')
a6f80f0e 249
250def update_ifup_argparser(argparser):
9dce3561 251 argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck',
252 action='store_true',
253 help='Only run the interfaces file parser')
a6f80f0e 254 update_ifupdown_argparser(argparser)
255
256def update_ifdown_argparser(argparser):
257 update_ifupdown_argparser(argparser)
522bf8e6 258 argparser.add_argument('-u', '--use-current-config',
5c721925 259 dest='usecurrentconfig', action='store_true',
14dc390d 260 help='By default ifdown looks at the saved state for ' +
261 'interfaces to bring down. This option allows ifdown to ' +
262 'look at the current interfaces file. Useful when your ' +
263 'state file is corrupted or you want down to use the latest '
264 'from the interfaces file')
a6f80f0e 265
266def update_ifquery_argparser(argparser):
cca03c30 267 """ arg parser for ifquery options """
268
37c0543d 269 # -l is same as '-a', only here for backward compatibility
3e8ee54f 270 argparser.add_argument('-l', '--list', action='store_true', dest='all',
cca03c30 271 help=argparse.SUPPRESS)
a6f80f0e 272 group = argparser.add_mutually_exclusive_group(required=False)
360d5f8e 273 group.add_argument('-r', '--running', dest='running',
eab25b7c 274 action='store_true',
275 help='query running state of an interface')
360d5f8e 276 group.add_argument('-c', '--check', dest='checkcurr',
739f665b 277 action='store_true',
360d5f8e 278 help='check interface file contents against ' +
279 'running state of an interface')
51a80991 280 group.add_argument('-x', '--raw', action='store_true', dest='raw',
d08d5f54 281 help='print raw config file entries')
5c721925 282 group.add_argument('--print-savedstate', action='store_true',
283 dest='printsavedstate',
284 help=argparse.SUPPRESS)
522bf8e6 285 argparser.add_argument('-o', '--format', dest='format', default='native',
14dc390d 286 choices=['native', 'json'],
287 help='interface display format')
288 argparser.add_argument('-p', '--print-dependency',
d08d5f54 289 dest='printdependency', choices=['list', 'dot'],
290 help='print interface dependency')
14dc390d 291 argparser.add_argument('-s', '--syntax-help', action='store_true',
d08d5f54 292 dest='syntaxhelp',
293 help='print supported interface config syntax')
37c0543d 294
739f665b 295def update_ifreload_argparser(argparser):
f802fe3c 296 """ parser for ifreload """
297 argparser.add_argument('-a', '--all', action='store_true', required=True,
298 help='process all interfaces marked \"auto\"')
299 argparser.add_argument('iflist', metavar='IFACE',
300 nargs='*', help=argparse.SUPPRESS)
301 argparser.add_argument('-n', '--no-act', dest='noact',
302 action='store_true', help=argparse.SUPPRESS)
303 argparser.add_argument('-v', '--verbose', dest='verbose',
304 action='store_true', help='verbose')
305 argparser.add_argument('-d', '--debug', dest='debug',
37c0543d 306 action='store_true',
f802fe3c 307 help='output debug info')
14dc390d 308 argparser.add_argument('-w', '--with-depends', dest='withdepends',
f802fe3c 309 action='store_true', help=argparse.SUPPRESS)
310 argparser.add_argument('--perfmode', dest='perfmode',
311 action='store_true', help=argparse.SUPPRESS)
312 argparser.add_argument('--nocache', dest='nocache', action='store_true',
313 help=argparse.SUPPRESS)
314 argparser.add_argument('-X', '--exclude', dest='excludepats',
315 action='append',
316 help=argparse.SUPPRESS)
14dc390d 317 #argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
318 # default=-1, choices=range(1,12), help=argparse.SUPPRESS)
3dcc1d0e 319 #argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
320 # default='/etc/network/interfaces',
321 # help='use interfaces file instead of default ' +
322 # '/etc/network/interfaces')
522bf8e6 323 argparser.add_argument('-u', '--use-current-config',
14dc390d 324 dest='usecurrentconfig', action='store_true',
325 help='By default ifreload looks at saved state for ' +
326 'interfaces to bring down. With this option ifreload will'
327 ' only look at the current interfaces file. Useful when your ' +
328 'state file is corrupted or you want down to use the latest '
329 'from the interfaces file')
261379f0
RP
330 argparser.add_argument('-l', '--syslog', dest='syslog',
331 action='store_true',
332 help=argparse.SUPPRESS)
37c0543d 333
a6f80f0e 334def parse_args(argsv, op):
cca03c30 335 if op == 'query':
37c0543d 336 descr = 'query interfaces (all or interface list)'
91067b3d 337 elif op == 'reload':
338 descr = 'reload interface configuration.'
cca03c30 339 else:
340 descr = 'interface management'
a6f80f0e 341 argparser = argparse.ArgumentParser(description=descr)
f802fe3c 342 if op == 'reload':
739f665b 343 update_ifreload_argparser(argparser)
f802fe3c 344 else:
345 update_argparser(argparser)
346 if op == 'up':
347 update_ifup_argparser(argparser)
348 elif op == 'down':
349 update_ifdown_argparser(argparser)
350 elif op == 'query':
351 update_ifquery_argparser(argparser)
352 elif op == 'reload':
353 update_ifreload_argparser(argparser)
e6c9d007 354 argcomplete.autocomplete(argparser)
a6f80f0e 355 return argparser.parse_args(argsv)
356
f802fe3c 357handlers = {'up' : run_up,
358 'down' : run_down,
359 'query' : run_query,
360 'reload' : run_reload }
361
9dce3561 362def validate_args(op, args):
3dcc1d0e 363 #if op == 'up' and args.syntaxcheck:
364 # if args.iflist or args.all:
365 # print 'ignoring interface options ..'
366 # return True
9dce3561 367 if op == 'query' and args.syntaxhelp:
368 return True
fffdae9c
RP
369 if op == 'reload':
370 if not args.all:
371 print '\'-a\' option is required'
372 return False
373 elif (not args.iflist and
374 not args.all and not args.CLASS):
9dce3561 375 print '\'-a\' option or interface list are required'
376 return False
377 if args.iflist and args.all:
378 print '\'-a\' option and interface list are mutually exclusive'
379 return False
fffdae9c 380 if op != 'reload' and args.CLASS and (args.all or args.iflist):
5ee3e1a8
RP
381 print ('\'--allow\' option is mutually exclusive ' +
382 'with interface list and \'-a\'')
383 return False
9dce3561 384 return True
385
14dc390d 386def read_config():
387 global configmap_g
388
389 config = open(configfile, 'r').read()
390 configStr = '[ifupdown2]\n' + config
391 configFP = StringIO.StringIO(configStr)
392 parser = ConfigParser.RawConfigParser()
393 parser.readfp(configFP)
394 configmap_g = dict(parser.items('ifupdown2'))
395
8e113d63
RP
396 # Preprocess config map
397 configval = configmap_g.get('multiple_vlan_aware_bridge_support', '0')
398 if configval == '0':
399 # if multiple bridges not allowed, set the bridge-vlan-aware
400 # attribute in the 'no_repeats' config, so that the ifupdownmain
401 # module can catch it appropriately
402 configmap_g['no_repeats'] = {'bridge-vlan-aware' : 'yes'}
403
a6f80f0e 404def main(argv):
405 """ main function """
f802fe3c 406 args = None
a6f80f0e 407 try:
408 op = None
fe0a57d3 409 if argv[0].endswith('ifup'):
a6f80f0e 410 op = 'up'
fe0a57d3 411 elif argv[0].endswith('ifdown'):
a6f80f0e 412 op = 'down'
fe0a57d3 413 elif argv[0].endswith('ifquery'):
a6f80f0e 414 op = 'query'
fe0a57d3 415 elif argv[0].endswith('ifreload'):
739f665b 416 op = 'reload'
a6f80f0e 417 else:
418 print ('Unexpected executable.' +
419 ' Should be \'ifup\' or \'ifdown\' or \'ifquery\'')
420 exit(1)
a6f80f0e 421 # Command line arg parser
422 args = parse_args(argv[1:], op)
9dce3561 423 if not validate_args(op, args):
a6f80f0e 424 exit(1)
522bf8e6
RP
425
426 if not sys.argv[0].endswith('ifquery') and not os.geteuid() == 0:
427 print 'error: must be root to run this command'
428 exit(1)
429
430 if not sys.argv[0].endswith('ifquery') and not utils.lockFile(lockfile):
431 print 'Another instance of this program is already running.'
432 exit(0)
433
14dc390d 434 read_config()
a6f80f0e 435 init(args)
f802fe3c 436 handlers.get(op)(args)
a6f80f0e 437 except Exception, e:
fe0a57d3 438 if not str(e):
eab25b7c 439 exit(1)
f802fe3c 440 if args and args.debug:
a6f80f0e 441 raise
442 else:
f802fe3c 443 if logger:
444 logger.error(str(e))
445 else:
446 print str(e)
86fc62e2 447 #if args and not args.debug:
448 # print '\nrerun the command with \'-d\' for a detailed errormsg'
eab25b7c 449 exit(1)
a6f80f0e 450 finally:
451 deinit()
452
a6f80f0e 453if __name__ == "__main__":
454
03d5166b 455 # required during boot
456 os.putenv('PATH', ENVPATH)
61636dcc 457 resource.setrlimit(resource.RLIMIT_CORE, (0,0))
a6f80f0e 458 main(sys.argv)