1
0
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:
roopa
2014-03-28 06:03:14 -07:00
parent 08179c9d2e
commit 9dce35612d
4 changed files with 81 additions and 57 deletions

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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)