mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
warn on template rendering errors and continue + --syntax-check option to ifup +
minor parser cleanups Ticket: CM-2488 Reviewed By: Testing Done: Tested ifupdown sanity and also the interfaces file in CM-2488
This commit is contained in:
@ -570,7 +570,7 @@ class ifupdownMain(ifupdownBase):
|
||||
self.logger.warning('error saving state (%s)' %str(e))
|
||||
|
||||
def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
|
||||
excludepats=None, printdependency=None):
|
||||
excludepats=None, printdependency=None, syntaxcheck=False):
|
||||
""" up an interface """
|
||||
|
||||
if auto:
|
||||
@ -582,6 +582,10 @@ class ifupdownMain(ifupdownBase):
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
# If only syntax check was requested, return here
|
||||
if syntaxcheck:
|
||||
return
|
||||
|
||||
if ifacenames:
|
||||
# If iface list is given by the caller, always check if iface
|
||||
# is present
|
||||
|
@ -27,7 +27,20 @@ class networkInterfaces():
|
||||
self.callbacks = {'iface_found' : None,
|
||||
'validate' : None}
|
||||
self.allow_classes = {}
|
||||
self._filestack = [self.ifaces_file]
|
||||
|
||||
@property
|
||||
def _currentfile(self):
|
||||
try:
|
||||
return self._filestack[-1]
|
||||
except:
|
||||
return self.ifaces_file
|
||||
|
||||
def _parse_error(self, filename, lineno, msg):
|
||||
if lineno == -1:
|
||||
self.logger.error('%s: %s' %(filename, msg))
|
||||
else:
|
||||
self.logger.error('%s: line%d: %s' %(filename, lineno, msg))
|
||||
|
||||
def subscribe(self, callback_name, callback_func):
|
||||
if callback_name not in self.callbacks.keys():
|
||||
@ -69,13 +82,17 @@ class networkInterfaces():
|
||||
for f in glob.glob(sourced_file):
|
||||
self.read_file(f)
|
||||
else:
|
||||
self.logger.warn('unable to read source line at %d', lineno)
|
||||
|
||||
self._parse_error(self._currentfile, lineno,
|
||||
'unable to read source line')
|
||||
return 0
|
||||
|
||||
def process_auto(self, lines, cur_idx, lineno):
|
||||
for a in lines[cur_idx].split()[1:]:
|
||||
self.auto_ifaces.append(a)
|
||||
auto_ifaces = lines[cur_idx].split()[1:]
|
||||
if not auto_ifaces:
|
||||
self._parse_error(self._currentfile, lineno + 1,
|
||||
'invalid auto line \'%s\''%lines[cur_idx])
|
||||
return 0
|
||||
[self.auto_ifaces.append(a) for a in auto_ifaces]
|
||||
return 0
|
||||
|
||||
def _add_to_iface_config(self, iface_config, attrname, attrval):
|
||||
@ -117,34 +134,28 @@ class networkInterfaces():
|
||||
iface_config = collections.OrderedDict()
|
||||
for line_idx in range(cur_idx + 1, len(lines)):
|
||||
l = lines[line_idx].strip('\n\t ')
|
||||
|
||||
if self.ignore_line(l) == 1:
|
||||
continue
|
||||
|
||||
if self.is_keyword(l.split()[0]) == True:
|
||||
if self._is_keyword(l.split()[0]):
|
||||
line_idx -= 1
|
||||
break
|
||||
|
||||
ifaceobj.raw_config.append(l)
|
||||
|
||||
# preprocess vars (XXX: only preprocesses $IFACE for now)
|
||||
l = re.sub(r'\$IFACE', ifacename, l)
|
||||
|
||||
attrs = l.split(' ', 1)
|
||||
if len(attrs) < 2:
|
||||
self.logger.warn('%s: invalid syntax at line %d'
|
||||
%(ifacename, line_idx + 1))
|
||||
self._parse_error(self._currentfile, line_idx,
|
||||
'invalid syntax \'%s\'' %ifacename)
|
||||
continue
|
||||
attrname = attrs[0]
|
||||
attrval = attrs[1].strip(' ')
|
||||
try:
|
||||
if not self.callbacks.get('validate')(attrname, attrval):
|
||||
self.logger.warn('unsupported keyword (%s) at line %d'
|
||||
%(l, line_idx + 1))
|
||||
self._parse_error(self._currentfile, line_idx + 1,
|
||||
'unsupported keyword (%s)' %l)
|
||||
except:
|
||||
pass
|
||||
self._add_to_iface_config(iface_config, attrname, attrval)
|
||||
|
||||
lines_consumed = line_idx - cur_idx
|
||||
|
||||
# Create iface object
|
||||
@ -168,7 +179,6 @@ class networkInterfaces():
|
||||
|
||||
# Call iface found callback
|
||||
self.callbacks.get('iface_found')(ifaceobj)
|
||||
|
||||
return lines_consumed # Return next index
|
||||
|
||||
|
||||
@ -177,18 +187,15 @@ class networkInterfaces():
|
||||
'auto' : process_auto,
|
||||
'iface' : process_iface}
|
||||
|
||||
def is_keyword(self, str):
|
||||
|
||||
def _is_keyword(self, str):
|
||||
# The additional split here is for allow- keyword
|
||||
tmp_str = str.split('-')[0]
|
||||
if tmp_str in self.network_elems.keys():
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
def get_keyword_func(self, str):
|
||||
def _get_keyword_func(self, str):
|
||||
tmp_str = str.split('-')[0]
|
||||
|
||||
return self.network_elems.get(tmp_str)
|
||||
|
||||
def get_allow_classes_for_iface(self, ifacename):
|
||||
@ -196,37 +203,27 @@ class networkInterfaces():
|
||||
for class_name, ifacenames in self.allow_classes.items():
|
||||
if ifacename in ifacenames:
|
||||
classes.append(class_name)
|
||||
|
||||
return classes
|
||||
|
||||
def process_filedata(self, filedata):
|
||||
lineno = 0
|
||||
line_idx = 0
|
||||
lines_consumed = 0
|
||||
|
||||
raw_config = filedata.split('\n')
|
||||
lines = [l.strip(' \n') for l in raw_config]
|
||||
|
||||
while (line_idx < len(lines)):
|
||||
lineno = lineno + 1
|
||||
|
||||
if self.ignore_line(lines[line_idx]):
|
||||
line_idx += 1
|
||||
continue
|
||||
|
||||
words = lines[line_idx].split()
|
||||
|
||||
# Check if first element is a supported keyword
|
||||
if self.is_keyword(words[0]):
|
||||
keyword_func = self.get_keyword_func(words[0])
|
||||
lines_consumed = keyword_func(self, lines, line_idx, lineno)
|
||||
if self._is_keyword(words[0]):
|
||||
keyword_func = self._get_keyword_func(words[0])
|
||||
lines_consumed = keyword_func(self, lines, line_idx, line_idx)
|
||||
line_idx += lines_consumed
|
||||
else:
|
||||
self.logger.warning('could not process line %s' %l + ' at' +
|
||||
' lineno %d' %lineno)
|
||||
|
||||
self._parse_error(self._currentfile, line_idx + 1,
|
||||
'error processing line \'%s\'' %lines[line_idx])
|
||||
line_idx += 1
|
||||
|
||||
return 0
|
||||
|
||||
def run_template_engine(self, textdata):
|
||||
@ -236,7 +233,6 @@ class networkInterfaces():
|
||||
self.logger.warning('template engine mako not found. ' +
|
||||
'skip template parsing ..');
|
||||
return textdata
|
||||
|
||||
t = Template(text=textdata, output_encoding='utf-8')
|
||||
return t.render()
|
||||
|
||||
@ -244,18 +240,30 @@ class networkInterfaces():
|
||||
ifaces_file = filename
|
||||
if not ifaces_file:
|
||||
ifaces_file=self.ifaces_file
|
||||
|
||||
self.logger.debug('reading interfaces file %s' %ifaces_file)
|
||||
self._filestack.append(ifaces_file)
|
||||
self.logger.info('reading interfaces file %s' %ifaces_file)
|
||||
f = open(ifaces_file)
|
||||
filedata = f.read()
|
||||
f.close()
|
||||
|
||||
# process line continuations
|
||||
filedata = ' '.join(d.strip() for d in filedata.split('\\'))
|
||||
|
||||
# run through template engine
|
||||
filedata = self.run_template_engine(filedata)
|
||||
try:
|
||||
self.logger.info('template processing on interfaces file %s ...'
|
||||
%ifaces_file)
|
||||
rendered_filedata = self.run_template_engine(filedata)
|
||||
except Exception, e:
|
||||
self._parse_error(self._currentfile, -1,
|
||||
'failed to render template (%s).' %str(e) +
|
||||
'Continue without template rendering ...')
|
||||
rendered_filedata = None
|
||||
pass
|
||||
self.logger.info('parsing interfaces file %s ...' %ifaces_file)
|
||||
if rendered_filedata:
|
||||
self.process_filedata(rendered_filedata)
|
||||
else:
|
||||
self.process_filedata(filedata)
|
||||
self._filestack.pop()
|
||||
|
||||
def load(self, filename=None):
|
||||
return self.read_file(filename)
|
||||
|
@ -228,8 +228,7 @@ class ifaceScheduler():
|
||||
if (ifupdownobj.ignore_error(str(e))):
|
||||
pass
|
||||
else:
|
||||
raise Exception('error running iface %s (%s)'
|
||||
%(ifacename, str(e)))
|
||||
raise Exception('%s : (%s)' %(ifacename, str(e)))
|
||||
|
||||
@classmethod
|
||||
def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None,
|
||||
@ -282,8 +281,7 @@ class ifaceScheduler():
|
||||
if (ifupdownobj.ignore_error(str(e))):
|
||||
pass
|
||||
else:
|
||||
raise Exception('error running iface %s (%s)'
|
||||
%(ifacename, str(e)))
|
||||
raise Exception('%s : (%s)' %(ifacename, str(e)))
|
||||
|
||||
@classmethod
|
||||
def sched_ifaces(cls, ifupdownobj, ifacenames, ops,
|
||||
|
@ -35,12 +35,14 @@ def run_up(args):
|
||||
if args.noaddons:
|
||||
ifupdown_handle.up(['up'], args.all, args.CLASS, iflist,
|
||||
excludepats=args.excludepats,
|
||||
printdependency=args.printdependency)
|
||||
printdependency=args.printdependency,
|
||||
syntaxcheck=args.syntaxcheck)
|
||||
else:
|
||||
ifupdown_handle.up(['pre-up', 'up', 'post-up'],
|
||||
args.all, args.CLASS, iflist,
|
||||
excludepats=args.excludepats,
|
||||
printdependency=args.printdependency)
|
||||
printdependency=args.printdependency,
|
||||
syntaxcheck=args.syntaxcheck)
|
||||
except:
|
||||
raise
|
||||
|
||||
@ -198,6 +200,9 @@ def update_ifupdown_argparser(argparser):
|
||||
'up/down')
|
||||
|
||||
def update_ifup_argparser(argparser):
|
||||
argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck',
|
||||
action='store_true',
|
||||
help='Only run the interfaces file parser')
|
||||
update_ifupdown_argparser(argparser)
|
||||
|
||||
def update_ifdown_argparser(argparser):
|
||||
@ -294,6 +299,21 @@ handlers = {'up' : run_up,
|
||||
'query' : run_query,
|
||||
'reload' : run_reload }
|
||||
|
||||
def validate_args(op, args):
|
||||
if op == 'up' and args.syntaxcheck:
|
||||
if args.iflist or args.all:
|
||||
print 'ignoring interface options ..'
|
||||
return True
|
||||
if op == 'query' and args.syntaxhelp:
|
||||
return True
|
||||
if not args.iflist and not args.all:
|
||||
print '\'-a\' option or interface list are required'
|
||||
return False
|
||||
if args.iflist and args.all:
|
||||
print '\'-a\' option and interface list are mutually exclusive'
|
||||
return False
|
||||
return True
|
||||
|
||||
def main(argv):
|
||||
""" main function """
|
||||
args = None
|
||||
@ -313,13 +333,7 @@ def main(argv):
|
||||
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'
|
||||
if not validate_args(op, args):
|
||||
exit(1)
|
||||
init(args)
|
||||
handlers.get(op)(args)
|
||||
|
Reference in New Issue
Block a user