| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | #!/usr/bin/python | 
					
						
							| 
									
										
										
										
											2013-11-13 16:07:15 -08:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2014-07-22 11:15:56 -07:00
										 |  |  | # Copyright 2014 Cumulus Networks, Inc. All rights reserved. | 
					
						
							| 
									
										
										
										
											2013-11-13 16:07:15 -08:00
										 |  |  | # Author: Roopa Prabhu, roopa@cumulusnetworks.com | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # networkInterfaces -- | 
					
						
							|  |  |  | #    ifupdown network interfaces file parser | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import collections | 
					
						
							|  |  |  | import logging | 
					
						
							|  |  |  | import glob | 
					
						
							| 
									
										
										
										
											2014-01-16 06:46:17 -08:00
										 |  |  | import re | 
					
						
							| 
									
										
										
										
											2014-04-18 14:09:20 -07:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2014-10-09 12:58:16 -07:00
										 |  |  | import copy | 
					
						
							|  |  |  | from utils import utils | 
					
						
							| 
									
										
										
										
											2013-11-13 16:07:15 -08:00
										 |  |  | from iface import * | 
					
						
							| 
									
										
										
										
											2014-04-18 14:09:20 -07:00
										 |  |  | from template import templateEngine | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-13 06:15:40 -07:00
										 |  |  | whitespaces = '\n\t\r ' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | class networkInterfaces(): | 
					
						
							| 
									
										
										
										
											2014-07-17 11:44:36 -07:00
										 |  |  |     """ debian ifupdown /etc/network/interfaces file parser """ | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     hotplugs = {} | 
					
						
							|  |  |  |     auto_ifaces = [] | 
					
						
							|  |  |  |     callbacks = {} | 
					
						
							| 
									
										
										
										
											2014-10-09 12:58:16 -07:00
										 |  |  |     auto_all = False | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-22 22:25:52 -07:00
										 |  |  |     _addrfams = {'inet' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6'], | 
					
						
							|  |  |  |                  'inet6' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6']} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-18 14:09:20 -07:00
										 |  |  |     def __init__(self, interfacesfile='/etc/network/interfaces', | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |                  interfacesfileiobuf=None, interfacesfileformat='native', | 
					
						
							| 
									
										
										
										
											2016-07-10 20:28:53 -07:00
										 |  |  |                  template_enable='0', template_engine=None, | 
					
						
							|  |  |  |                  template_lookuppath=None): | 
					
						
							| 
									
										
										
										
											2014-07-17 11:44:36 -07:00
										 |  |  |         """This member function initializes the networkinterfaces parser object.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Kwargs: | 
					
						
							| 
									
										
										
										
											2014-07-22 11:15:56 -07:00
										 |  |  |             **interfacesfile** (str):  path to the interfaces file (default is /etc/network/interfaces) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             **interfacesfileiobuf** (object): interfaces file io stream | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             **interfacesfileformat** (str): format of interfaces file (choices are 'native' and 'json'. 'native' being the default) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             **template_engine** (str): template engine name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             **template_lookuppath** (str): template lookup path | 
					
						
							| 
									
										
										
										
											2014-07-17 11:44:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Raises: | 
					
						
							|  |  |  |             AttributeError, KeyError """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         self.logger = logging.getLogger('ifupdown.' + | 
					
						
							|  |  |  |                     self.__class__.__name__) | 
					
						
							| 
									
										
										
										
											2014-02-08 09:05:32 -08:00
										 |  |  |         self.callbacks = {'iface_found' : None, | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |                           'validateifaceattr' : None, | 
					
						
							|  |  |  |                           'validateifaceobj' : None} | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         self.allow_classes = {} | 
					
						
							| 
									
										
										
										
											2014-04-18 14:09:20 -07:00
										 |  |  |         self.interfacesfile = interfacesfile | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |         self.interfacesfileiobuf = interfacesfileiobuf | 
					
						
							|  |  |  |         self.interfacesfileformat = interfacesfileformat | 
					
						
							| 
									
										
										
										
											2014-04-18 14:09:20 -07:00
										 |  |  |         self._filestack = [self.interfacesfile] | 
					
						
							| 
									
										
										
										
											2016-07-14 20:09:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self._template_engine = None | 
					
						
							|  |  |  |         self._template_engine_name = template_engine | 
					
						
							|  |  |  |         self._template_engine_path = template_lookuppath | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-25 16:09:14 -07:00
										 |  |  |         self._currentfile_has_template = False | 
					
						
							| 
									
										
										
										
											2014-06-27 23:44:36 -07:00
										 |  |  |         self._ws_split_regex = re.compile(r'[\s\t]\s*') | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-22 16:26:14 -08:00
										 |  |  |         self.errors = 0 | 
					
						
							|  |  |  |         self.warns = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def _currentfile(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return self._filestack[-1] | 
					
						
							|  |  |  |         except: | 
					
						
							| 
									
										
										
										
											2014-04-18 14:09:20 -07:00
										 |  |  |             return self.interfacesfile | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _parse_error(self, filename, lineno, msg): | 
					
						
							| 
									
										
										
										
											2014-04-25 16:09:14 -07:00
										 |  |  |         if lineno == -1 or self._currentfile_has_template: | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |             self.logger.error('%s: %s' %(filename, msg)) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.logger.error('%s: line%d: %s' %(filename, lineno, msg)) | 
					
						
							| 
									
										
										
										
											2015-11-22 16:26:14 -08:00
										 |  |  |         self.errors += 1 | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 11:07:11 -08:00
										 |  |  |     def _parse_warn(self, filename, lineno, msg): | 
					
						
							|  |  |  |         if lineno == -1 or self._currentfile_has_template: | 
					
						
							|  |  |  |             self.logger.warn('%s: %s' %(filename, msg)) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.logger.warn('%s: line%d: %s' %(filename, lineno, msg)) | 
					
						
							| 
									
										
										
										
											2015-11-22 16:26:14 -08:00
										 |  |  |         self.warns += 1 | 
					
						
							| 
									
										
										
										
											2014-11-21 11:07:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |     def _validate_addr_family(self, ifaceobj, lineno=-1): | 
					
						
							| 
									
										
										
										
											2014-04-22 22:25:52 -07:00
										 |  |  |         if ifaceobj.addr_family: | 
					
						
							|  |  |  |             if not self._addrfams.get(ifaceobj.addr_family): | 
					
						
							|  |  |  |                 self._parse_error(self._currentfile, lineno, | 
					
						
							|  |  |  |                     'iface %s: unsupported address family \'%s\'' | 
					
						
							|  |  |  |                     %(ifaceobj.name, ifaceobj.addr_family)) | 
					
						
							|  |  |  |                 ifaceobj.addr_family = None | 
					
						
							|  |  |  |                 ifaceobj.addr_method = None | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             if ifaceobj.addr_method: | 
					
						
							|  |  |  |                 if (ifaceobj.addr_method not in | 
					
						
							|  |  |  |                         self._addrfams.get(ifaceobj.addr_family)): | 
					
						
							|  |  |  |                     self._parse_error(self._currentfile, lineno, | 
					
						
							|  |  |  |                         'iface %s: unsupported address method \'%s\'' | 
					
						
							|  |  |  |                         %(ifaceobj.name, ifaceobj.addr_method)) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 ifaceobj.addr_method = 'static' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |     def subscribe(self, callback_name, callback_func): | 
					
						
							| 
									
										
										
										
											2014-07-22 11:15:56 -07:00
										 |  |  |         """This member function registers callback functions.
 | 
					
						
							| 
									
										
										
										
											2014-07-17 11:44:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Args: | 
					
						
							| 
									
										
										
										
											2014-07-22 11:15:56 -07:00
										 |  |  |             **callback_name** (str): callback function name (supported names: 'iface_found', 'validateifaceattr', 'validateifaceobj') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             **callback_func** (function pointer): callback function pointer | 
					
						
							| 
									
										
										
										
											2014-07-17 11:44:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Warns on error | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         if callback_name not in self.callbacks.keys(): | 
					
						
							|  |  |  |             print 'warning: invalid callback ' + callback_name | 
					
						
							|  |  |  |             return -1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.callbacks[callback_name] = callback_func | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def ignore_line(self, line): | 
					
						
							| 
									
										
										
										
											2014-06-13 06:15:40 -07:00
										 |  |  |         l = line.strip(whitespaces) | 
					
						
							| 
									
										
										
										
											2014-02-19 21:30:55 -08:00
										 |  |  |         if not l or l[0] == '#': | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |             return 1 | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_allow(self, lines, cur_idx, lineno): | 
					
						
							| 
									
										
										
										
											2013-11-13 16:07:15 -08:00
										 |  |  |         allow_line = lines[cur_idx] | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-27 23:44:36 -07:00
										 |  |  |         words = re.split(self._ws_split_regex, allow_line) | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         if len(words) <= 1: | 
					
						
							| 
									
										
										
										
											2014-02-17 19:01:37 -08:00
										 |  |  |             raise Exception('invalid allow line \'%s\' at line %d' | 
					
						
							|  |  |  |                             %(allow_line, lineno)) | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         allow_class = words[0].split('-')[1] | 
					
						
							|  |  |  |         ifacenames = words[1:] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |         if self.allow_classes.get(allow_class): | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |             for i in ifacenames: | 
					
						
							|  |  |  |                 self.allow_classes[allow_class].append(i) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |                 self.allow_classes[allow_class] = ifacenames | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_source(self, lines, cur_idx, lineno): | 
					
						
							|  |  |  |         # Support regex | 
					
						
							| 
									
										
										
										
											2014-01-30 22:36:41 -08:00
										 |  |  |         self.logger.debug('processing sourced line ..\'%s\'' %lines[cur_idx]) | 
					
						
							| 
									
										
										
										
											2014-06-27 23:44:36 -07:00
										 |  |  |         sourced_file = re.split(self._ws_split_regex, lines[cur_idx], 2)[1] | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |         if sourced_file: | 
					
						
							| 
									
										
										
										
											2014-11-19 17:48:02 -08:00
										 |  |  |             filenames = glob.glob(sourced_file) | 
					
						
							|  |  |  |             if not filenames: | 
					
						
							| 
									
										
										
										
											2016-03-19 19:45:33 -07:00
										 |  |  |                 if '*' not in sourced_file: | 
					
						
							|  |  |  |                     self._parse_warn(self._currentfile, lineno, | 
					
						
							| 
									
										
										
										
											2014-11-19 17:48:02 -08:00
										 |  |  |                             'cannot find source file %s' %sourced_file) | 
					
						
							|  |  |  |                 return 0 | 
					
						
							|  |  |  |             for f in filenames: | 
					
						
							| 
									
										
										
										
											2013-11-10 22:35:40 -08:00
										 |  |  |                 self.read_file(f) | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |             self._parse_error(self._currentfile, lineno, | 
					
						
							|  |  |  |                     'unable to read source line') | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_auto(self, lines, cur_idx, lineno): | 
					
						
							| 
									
										
										
										
											2014-06-27 23:44:36 -07:00
										 |  |  |         auto_ifaces = re.split(self._ws_split_regex, lines[cur_idx])[1:] | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |         if not auto_ifaces: | 
					
						
							| 
									
										
										
										
											2014-04-22 22:25:52 -07:00
										 |  |  |             self._parse_error(self._currentfile, lineno, | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |                     'invalid auto line \'%s\''%lines[cur_idx]) | 
					
						
							|  |  |  |             return 0 | 
					
						
							| 
									
										
										
										
											2014-10-09 12:58:16 -07:00
										 |  |  |         for a in auto_ifaces: | 
					
						
							|  |  |  |             if a == 'all': | 
					
						
							|  |  |  |                 self.auto_all = True | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             r = utils.parse_iface_range(a) | 
					
						
							|  |  |  |             if r: | 
					
						
							|  |  |  |                 for i in range(r[1], r[2]): | 
					
						
							|  |  |  |                    self.auto_ifaces.append('%s-%d' %(r[0], i)) | 
					
						
							|  |  |  |             self.auto_ifaces.append(a) | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-18 14:09:20 -07:00
										 |  |  |     def _add_to_iface_config(self, ifacename, iface_config, attrname, | 
					
						
							|  |  |  |                              attrval, lineno): | 
					
						
							| 
									
										
										
										
											2014-04-07 14:38:06 -07:00
										 |  |  |         newattrname = attrname.replace("_", "-") | 
					
						
							| 
									
										
										
										
											2014-04-08 14:50:15 -07:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2014-10-31 11:28:07 -07:00
										 |  |  |             if not self.callbacks.get('validateifaceattr')(newattrname, | 
					
						
							|  |  |  |                                       attrval): | 
					
						
							| 
									
										
										
										
											2014-04-08 14:50:15 -07:00
										 |  |  |                 self._parse_error(self._currentfile, lineno, | 
					
						
							| 
									
										
										
										
											2014-04-18 14:09:20 -07:00
										 |  |  |                         'iface %s: unsupported keyword (%s)' | 
					
						
							|  |  |  |                         %(ifacename, attrname)) | 
					
						
							| 
									
										
										
										
											2014-04-08 14:50:15 -07:00
										 |  |  |                 return | 
					
						
							|  |  |  |         except: | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2014-04-07 14:38:06 -07:00
										 |  |  |         attrvallist = iface_config.get(newattrname, []) | 
					
						
							|  |  |  |         if newattrname in ['scope', 'netmask', 'broadcast', 'preferred-lifetime']: | 
					
						
							| 
									
										
										
										
											2014-02-17 19:01:37 -08:00
										 |  |  |             # For attributes that are related and that can have multiple | 
					
						
							|  |  |  |             # entries, store them at the same index as their parent attribute. | 
					
						
							|  |  |  |             # The example of such attributes is 'address' and its related | 
					
						
							|  |  |  |             # attributes. since the related attributes can be optional,  | 
					
						
							|  |  |  |             # we add null string '' in places where they are optional. | 
					
						
							|  |  |  |             # XXX: this introduces awareness of attribute names in | 
					
						
							|  |  |  |             # this class which is a violation. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # get the index corresponding to the 'address' | 
					
						
							|  |  |  |             addrlist = iface_config.get('address') | 
					
						
							|  |  |  |             if addrlist: | 
					
						
							|  |  |  |                 # find the index of last address element | 
					
						
							|  |  |  |                 for i in range(0, len(addrlist) - len(attrvallist) -1): | 
					
						
							|  |  |  |                     attrvallist.append('') | 
					
						
							|  |  |  |                 attrvallist.append(attrval) | 
					
						
							| 
									
										
										
										
											2014-04-07 14:38:06 -07:00
										 |  |  |                 iface_config[newattrname] = attrvallist | 
					
						
							| 
									
										
										
										
											2014-02-17 19:01:37 -08:00
										 |  |  |         elif not attrvallist: | 
					
						
							| 
									
										
										
										
											2014-04-07 14:38:06 -07:00
										 |  |  |             iface_config[newattrname] = [attrval] | 
					
						
							| 
									
										
										
										
											2014-02-17 19:01:37 -08:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2014-04-07 14:38:06 -07:00
										 |  |  |             iface_config[newattrname].append(attrval) | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-09 12:58:16 -07:00
										 |  |  |     def parse_iface(self, lines, cur_idx, lineno, ifaceobj): | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         lines_consumed = 0 | 
					
						
							| 
									
										
										
										
											2013-12-20 13:59:37 -08:00
										 |  |  |         line_idx = cur_idx | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-13 06:15:40 -07:00
										 |  |  |         iface_line = lines[cur_idx].strip(whitespaces) | 
					
						
							| 
									
										
										
										
											2014-06-27 23:44:36 -07:00
										 |  |  |         iface_attrs = re.split(self._ws_split_regex, iface_line) | 
					
						
							| 
									
										
										
										
											2014-01-16 06:46:17 -08:00
										 |  |  |         ifacename = iface_attrs[1] | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-08 21:08:43 -07:00
										 |  |  |         if utils.check_ifname_size_invalid(ifacename): | 
					
						
							|  |  |  |             self._parse_warn(self._currentfile, lineno, | 
					
						
							|  |  |  |                              '%s: interface name too long' %ifacename) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-30 21:44:46 -08:00
										 |  |  |         # in cases where mako is unable to render the template | 
					
						
							|  |  |  |         # or incorrectly renders it due to user template | 
					
						
							|  |  |  |         # errors, we maybe left with interface names with | 
					
						
							|  |  |  |         # mako variables in them. There is no easy way to | 
					
						
							|  |  |  |         # recognize and warn about these. In the below check | 
					
						
							|  |  |  |         # we try to warn the user of such cases by looking for | 
					
						
							|  |  |  |         # variable patterns ('$') in interface names. | 
					
						
							|  |  |  |         if '$' in ifacename: | 
					
						
							|  |  |  |            self._parse_warn(self._currentfile, lineno, | 
					
						
							|  |  |  |                     '%s: unexpected characters in interface name' %ifacename) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |         ifaceobj.raw_config.append(iface_line) | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         iface_config = collections.OrderedDict() | 
					
						
							|  |  |  |         for line_idx in range(cur_idx + 1, len(lines)): | 
					
						
							| 
									
										
										
										
											2014-06-13 06:15:40 -07:00
										 |  |  |             l = lines[line_idx].strip(whitespaces) | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |             if self.ignore_line(l) == 1: | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2014-06-27 23:44:36 -07:00
										 |  |  |             attrs = re.split(self._ws_split_regex, l, 1) | 
					
						
							|  |  |  |             if self._is_keyword(attrs[0]): | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |                 line_idx -= 1 | 
					
						
							|  |  |  |                 break | 
					
						
							| 
									
										
										
										
											2014-06-27 23:44:36 -07:00
										 |  |  |             # if not a keyword, every line must have at least a key and value | 
					
						
							| 
									
										
										
										
											2013-11-10 22:35:40 -08:00
										 |  |  |             if len(attrs) < 2: | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |                 self._parse_error(self._currentfile, line_idx, | 
					
						
							| 
									
										
										
										
											2014-04-18 14:09:20 -07:00
										 |  |  |                         'iface %s: invalid syntax \'%s\'' %(ifacename, l)) | 
					
						
							| 
									
										
										
										
											2013-11-10 22:35:40 -08:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2014-06-27 23:44:36 -07:00
										 |  |  |             ifaceobj.raw_config.append(l) | 
					
						
							| 
									
										
										
										
											2014-02-08 09:05:32 -08:00
										 |  |  |             attrname = attrs[0] | 
					
						
							| 
									
										
										
										
											2014-06-27 23:44:36 -07:00
										 |  |  |             # preprocess vars (XXX: only preprocesses $IFACE for now) | 
					
						
							|  |  |  |             attrval = re.sub(r'\$IFACE', ifacename, attrs[1]) | 
					
						
							| 
									
										
										
										
											2014-04-18 14:09:20 -07:00
										 |  |  |             self._add_to_iface_config(ifacename, iface_config, attrname, | 
					
						
							|  |  |  |                                       attrval, line_idx+1) | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         lines_consumed = line_idx - cur_idx | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Create iface object | 
					
						
							| 
									
										
										
										
											2014-01-30 22:36:41 -08:00
										 |  |  |         if ifacename.find(':') != -1: | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |             ifaceobj.name = ifacename.split(':')[0] | 
					
						
							| 
									
										
										
										
											2014-01-30 22:36:41 -08:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |             ifaceobj.name = ifacename | 
					
						
							| 
									
										
										
										
											2014-01-30 22:36:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |         ifaceobj.config = iface_config | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         ifaceobj.generate_env() | 
					
						
							| 
									
										
										
										
											2014-04-22 22:25:52 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |             ifaceobj.addr_family = iface_attrs[2] | 
					
						
							|  |  |  |             ifaceobj.addr_method = iface_attrs[3] | 
					
						
							| 
									
										
										
										
											2014-04-22 22:25:52 -07:00
										 |  |  |         except IndexError: | 
					
						
							|  |  |  |             # ignore | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         self._validate_addr_family(ifaceobj, lineno) | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-09 12:58:16 -07:00
										 |  |  |         if self.auto_all or (ifaceobj.name in self.auto_ifaces): | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |             ifaceobj.auto = True | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |         classes = self.get_allow_classes_for_iface(ifaceobj.name) | 
					
						
							| 
									
										
										
										
											2014-02-19 21:30:55 -08:00
										 |  |  |         if classes: | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |             [ifaceobj.set_class(c) for c in classes] | 
					
						
							| 
									
										
										
										
											2014-10-09 12:58:16 -07:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         return lines_consumed       # Return next index | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-09 12:58:16 -07:00
										 |  |  |     def process_iface(self, lines, cur_idx, lineno): | 
					
						
							|  |  |  |         ifaceobj = iface() | 
					
						
							|  |  |  |         lines_consumed = self.parse_iface(lines, cur_idx, lineno, ifaceobj) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         range_val = utils.parse_iface_range(ifaceobj.name) | 
					
						
							|  |  |  |         if range_val: | 
					
						
							|  |  |  |            for v in range(range_val[1], range_val[2]): | 
					
						
							|  |  |  |                 ifaceobj_new = copy.deepcopy(ifaceobj) | 
					
						
							| 
									
										
										
										
											2014-12-17 12:39:38 -08:00
										 |  |  |                 ifaceobj_new.realname = '%s' %ifaceobj.name | 
					
						
							|  |  |  |                 ifaceobj_new.name = '%s%d' %(range_val[0], v) | 
					
						
							|  |  |  |                 ifaceobj_new.flags = iface.IFACERANGE_ENTRY | 
					
						
							| 
									
										
										
										
											2014-11-11 21:58:12 -08:00
										 |  |  |                 if v == range_val[1]: | 
					
						
							|  |  |  |                     ifaceobj_new.flags |= iface.IFACERANGE_START | 
					
						
							| 
									
										
										
										
											2014-10-09 12:58:16 -07:00
										 |  |  |                 self.callbacks.get('iface_found')(ifaceobj_new) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.callbacks.get('iface_found')(ifaceobj) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return lines_consumed       # Return next index | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-24 10:11:07 -07:00
										 |  |  |     def process_vlan(self, lines, cur_idx, lineno): | 
					
						
							|  |  |  |         ifaceobj = iface() | 
					
						
							|  |  |  |         lines_consumed = self.parse_iface(lines, cur_idx, lineno, ifaceobj) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         range_val = utils.parse_iface_range(ifaceobj.name) | 
					
						
							|  |  |  |         if range_val: | 
					
						
							|  |  |  |            for v in range(range_val[1], range_val[2]): | 
					
						
							|  |  |  |                 ifaceobj_new = copy.deepcopy(ifaceobj) | 
					
						
							| 
									
										
										
										
											2014-12-17 12:39:38 -08:00
										 |  |  |                 ifaceobj_new.realname = '%s' %ifaceobj.name | 
					
						
							|  |  |  |                 ifaceobj_new.name = '%s%d' %(range_val[0], v) | 
					
						
							| 
									
										
										
										
											2014-10-24 10:11:07 -07:00
										 |  |  |                 ifaceobj_new.type = ifaceType.BRIDGE_VLAN | 
					
						
							| 
									
										
										
										
											2014-12-17 12:39:38 -08:00
										 |  |  |                 ifaceobj_new.flags = iface.IFACERANGE_ENTRY | 
					
						
							| 
									
										
										
										
											2014-11-11 21:58:12 -08:00
										 |  |  |                 if v == range_val[1]: | 
					
						
							|  |  |  |                     ifaceobj_new.flags |= iface.IFACERANGE_START | 
					
						
							| 
									
										
										
										
											2014-10-24 10:11:07 -07:00
										 |  |  |                 self.callbacks.get('iface_found')(ifaceobj_new) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             ifaceobj.type = ifaceType.BRIDGE_VLAN | 
					
						
							|  |  |  |             self.callbacks.get('iface_found')(ifaceobj) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return lines_consumed       # Return next index | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |     network_elems = { 'source'      : process_source, | 
					
						
							|  |  |  |                       'allow'      : process_allow, | 
					
						
							|  |  |  |                       'auto'        : process_auto, | 
					
						
							| 
									
										
										
										
											2014-10-24 10:11:07 -07:00
										 |  |  |                       'iface'       : process_iface, | 
					
						
							|  |  |  |                       'vlan'       : process_vlan} | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |     def _is_keyword(self, str): | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         # The additional split here is for allow- keyword | 
					
						
							| 
									
										
										
										
											2016-02-29 23:04:08 -08:00
										 |  |  |         if (str in self.network_elems.keys() or | 
					
						
							|  |  |  |             str.split('-')[0] == 'allow'): | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |             return 1 | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |     def _get_keyword_func(self, str): | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         tmp_str = str.split('-')[0] | 
					
						
							|  |  |  |         return self.network_elems.get(tmp_str) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_allow_classes_for_iface(self, ifacename): | 
					
						
							|  |  |  |         classes = [] | 
					
						
							|  |  |  |         for class_name, ifacenames in self.allow_classes.items(): | 
					
						
							|  |  |  |             if ifacename in ifacenames: | 
					
						
							|  |  |  |                 classes.append(class_name) | 
					
						
							|  |  |  |         return classes | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |     def process_interfaces(self, filedata): | 
					
						
							| 
									
										
										
										
											2015-02-18 12:28:50 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # process line continuations | 
					
						
							|  |  |  |         filedata = ' '.join(d.strip() for d in filedata.split('\\')) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  |         line_idx = 0 | 
					
						
							|  |  |  |         lines_consumed = 0 | 
					
						
							| 
									
										
										
										
											2014-03-22 22:16:53 -07:00
										 |  |  |         raw_config = filedata.split('\n') | 
					
						
							| 
									
										
										
										
											2014-06-13 06:15:40 -07:00
										 |  |  |         lines = [l.strip(whitespaces) for l in raw_config] | 
					
						
							| 
									
										
										
										
											2013-12-20 13:59:37 -08:00
										 |  |  |         while (line_idx < len(lines)): | 
					
						
							|  |  |  |             if self.ignore_line(lines[line_idx]): | 
					
						
							|  |  |  |                 line_idx += 1 | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2014-06-27 23:44:36 -07:00
										 |  |  |             words = re.split(self._ws_split_regex, lines[line_idx]) | 
					
						
							| 
									
										
										
										
											2014-06-13 06:15:40 -07:00
										 |  |  |             if not words: | 
					
						
							|  |  |  |                 line_idx += 1 | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2013-12-20 13:59:37 -08:00
										 |  |  |             # Check if first element is a supported keyword | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |             if self._is_keyword(words[0]): | 
					
						
							|  |  |  |                 keyword_func = self._get_keyword_func(words[0]) | 
					
						
							| 
									
										
										
										
											2014-04-22 22:25:52 -07:00
										 |  |  |                 lines_consumed = keyword_func(self, lines, line_idx, line_idx+1) | 
					
						
							| 
									
										
										
										
											2013-12-20 13:59:37 -08:00
										 |  |  |                 line_idx += lines_consumed | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |                 self._parse_error(self._currentfile, line_idx + 1, | 
					
						
							|  |  |  |                         'error processing line \'%s\'' %lines[line_idx]) | 
					
						
							| 
									
										
										
										
											2013-12-20 13:59:37 -08:00
										 |  |  |             line_idx += 1 | 
					
						
							|  |  |  |         return 0 | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |     def read_filedata(self, filedata): | 
					
						
							| 
									
										
										
										
											2014-04-25 16:09:14 -07:00
										 |  |  |         self._currentfile_has_template = False | 
					
						
							| 
									
										
										
										
											2013-12-20 13:59:37 -08:00
										 |  |  |         # run through template engine | 
					
						
							| 
									
										
										
										
											2016-07-14 20:09:42 +01:00
										 |  |  |         if filedata and '%' in filedata: | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2016-07-15 12:18:36 +01:00
										 |  |  |                 if not self._template_engine: | 
					
						
							|  |  |  |                     self._template_engine = templateEngine( | 
					
						
							|  |  |  |                         self._template_engine_name, | 
					
						
							|  |  |  |                         self._template_engine_path) | 
					
						
							| 
									
										
										
										
											2016-07-14 20:09:42 +01:00
										 |  |  |                 rendered_filedata = self._template_engine.render(filedata) | 
					
						
							|  |  |  |                 if rendered_filedata is filedata: | 
					
						
							|  |  |  |                     self._currentfile_has_template = False | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     self._currentfile_has_template = True | 
					
						
							|  |  |  |             except Exception, e: | 
					
						
							|  |  |  |                 self._parse_error(self._currentfile, -1, | 
					
						
							|  |  |  |                                   'failed to render template (%s). Continue without template rendering ...' | 
					
						
							|  |  |  |                                   % str(e)) | 
					
						
							|  |  |  |                 rendered_filedata = None | 
					
						
							|  |  |  |             if rendered_filedata: | 
					
						
							|  |  |  |                 self.process_interfaces(rendered_filedata) | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |         self.process_interfaces(filedata) | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def read_file(self, filename, fileiobuf=None): | 
					
						
							|  |  |  |         if fileiobuf: | 
					
						
							|  |  |  |             self.read_filedata(fileiobuf) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         self._filestack.append(filename) | 
					
						
							|  |  |  |         self.logger.info('processing interfaces file %s' %filename) | 
					
						
							| 
									
										
										
										
											2015-12-23 19:36:56 -08:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2016-05-13 19:52:57 +02:00
										 |  |  |             with open(filename) as f: | 
					
						
							|  |  |  |                 filedata = f.read() | 
					
						
							| 
									
										
										
										
											2015-12-23 19:36:56 -08:00
										 |  |  |         except Exception, e: | 
					
						
							|  |  |  |             self.logger.warn('error processing file %s (%s)', | 
					
						
							|  |  |  |                              filename, str(e)) | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |         self.read_filedata(filedata) | 
					
						
							| 
									
										
										
										
											2014-03-28 06:03:14 -07:00
										 |  |  |         self._filestack.pop() | 
					
						
							| 
									
										
										
										
											2013-11-04 06:06:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |     def read_file_json(self, filename, fileiobuf=None): | 
					
						
							|  |  |  |         if fileiobuf: | 
					
						
							|  |  |  |             ifacedicts = json.loads(fileiobuf, encoding="utf-8") | 
					
						
							|  |  |  |                               #object_hook=ifaceJsonDecoder.json_object_hook) | 
					
						
							|  |  |  |         elif filename: | 
					
						
							|  |  |  |             self.logger.info('processing interfaces file %s' %filename) | 
					
						
							| 
									
										
										
										
											2016-05-13 19:52:57 +02:00
										 |  |  |             with open(filename) as fp: | 
					
						
							|  |  |  |                 ifacedicts = json.load(fp) | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |                             #object_hook=ifaceJsonDecoder.json_object_hook) | 
					
						
							| 
									
										
										
										
											2015-02-11 11:37:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # we need to handle both lists and non lists formats (e.g. {{}}) | 
					
						
							|  |  |  |         if not isinstance(ifacedicts,list): | 
					
						
							|  |  |  |             ifacedicts = [ifacedicts] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-22 16:26:14 -08:00
										 |  |  |         errors = 0 | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |         for ifacedict in ifacedicts: | 
					
						
							|  |  |  |             ifaceobj = ifaceJsonDecoder.json_to_ifaceobj(ifacedict) | 
					
						
							|  |  |  |             if ifaceobj: | 
					
						
							|  |  |  |                 self._validate_addr_family(ifaceobj) | 
					
						
							| 
									
										
										
										
											2015-11-22 16:26:14 -08:00
										 |  |  |                 if not self.callbacks.get('validateifaceobj')(ifaceobj): | 
					
						
							|  |  |  |                     errors += 1 | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |                 self.callbacks.get('iface_found')(ifaceobj) | 
					
						
							| 
									
										
										
										
											2015-11-22 16:26:14 -08:00
										 |  |  |         self.errors += errors | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |          | 
					
						
							|  |  |  |     def load(self): | 
					
						
							| 
									
										
										
										
											2014-07-17 11:44:36 -07:00
										 |  |  |         """ This member function loads the networkinterfaces file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Assumes networkinterfaces parser object is initialized with the | 
					
						
							|  |  |  |         parser arguments | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2015-10-09 18:00:49 -04:00
										 |  |  |         if not self.interfacesfile and not self.interfacesfileiobuf: | 
					
						
							|  |  |  |             self.logger.warn('no terminal line stdin used or ') | 
					
						
							|  |  |  |             self.logger.warn('no network interfaces file defined.') | 
					
						
							| 
									
										
										
										
											2015-11-22 16:26:14 -08:00
										 |  |  |             self.warns += 1 | 
					
						
							| 
									
										
										
										
											2015-08-20 22:59:44 -04:00
										 |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 22:33:33 -07:00
										 |  |  |         if self.interfacesfileformat == 'json': | 
					
						
							|  |  |  |             return self.read_file_json(self.interfacesfile, | 
					
						
							|  |  |  |                                        self.interfacesfileiobuf) | 
					
						
							|  |  |  |         return self.read_file(self.interfacesfile, | 
					
						
							|  |  |  |                               self.interfacesfileiobuf) |