]> git.proxmox.com Git - mirror_ifupdown2.git/blame - pkg/networkinterfaces.py
More fixes and changes
[mirror_ifupdown2.git] / pkg / networkinterfaces.py
CommitLineData
a6f80f0e 1#!/usr/bin/python
3e8ee54f 2#
3# Copyright 2013. Cumulus Networks, Inc.
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6# networkInterfaces --
7# ifupdown network interfaces file parser
8#
a6f80f0e 9
10import collections
a6f80f0e 11import logging
12import glob
739f665b 13import re
3e8ee54f 14from iface import *
a6f80f0e 15
16class networkInterfaces():
17
18 hotplugs = {}
19 auto_ifaces = []
20 callbacks = {}
21
22 ifaces_file = "/etc/network/interfaces"
23
24 def __init__(self):
25 self.logger = logging.getLogger('ifupdown.' +
26 self.__class__.__name__)
27 self.callbacks = {'iface_found' : None}
28 self.allow_classes = {}
29
30
31 def subscribe(self, callback_name, callback_func):
32 if callback_name not in self.callbacks.keys():
33 print 'warning: invalid callback ' + callback_name
34 return -1
35
36 self.callbacks[callback_name] = callback_func
37
38
39 def ignore_line(self, line):
40 l = line.strip('\n ')
41
42 if len(l) == 0 or l[0] == '#':
43 return 1
44
45 return 0
46
47 def process_allow(self, lines, cur_idx, lineno):
3e8ee54f 48 allow_line = lines[cur_idx]
a6f80f0e 49
50 words = allow_line.split()
51 if len(words) <= 1:
52 raise Exception('invalid allow line \'%s\'' %allow_line)
53
54 allow_class = words[0].split('-')[1]
55 ifacenames = words[1:]
56
57 if self.allow_classes.get(allow_class) is not None:
58 for i in ifacenames:
59 self.allow_classes[allow_class].append(i)
60 else:
61 self.allow_classes[allow_class] = ifacenames
62
63 return 0
64
65
66 def process_source(self, lines, cur_idx, lineno):
67 # Support regex
37c0543d 68 self.logger.debug('processing sourced line ..\'%s\'' %lines[cur_idx])
a6f80f0e 69 sourced_file = lines[cur_idx].split(' ', 2)[1]
70 if sourced_file is not None:
71 for f in glob.glob(sourced_file):
eab25b7c 72 self.read_file(f)
a6f80f0e 73 else:
74 self.logger.warn('unable to read source line at %d', lineno)
75
76 return 0
77
78 def process_auto(self, lines, cur_idx, lineno):
79 # XXX: Need to do more
80 attrs = lines[cur_idx].split()
81 if len(attrs) != 2:
82 raise Exception('line%d: ' %lineno + 'incomplete \'auto\' line')
83
84 self.auto_ifaces.append(lines[cur_idx].split()[1])
85
86 return 0
87
88
89 def process_iface(self, lines, cur_idx, lineno):
90 lines_consumed = 0
579b3f25 91 line_idx = cur_idx
a6f80f0e 92
93 ifaceobj = iface()
94
95 iface_line = lines[cur_idx].strip('\n ')
96 iface_attrs = iface_line.split()
739f665b 97 ifacename = iface_attrs[1]
a6f80f0e 98
99 ifaceobj.raw_lines.append(iface_line)
100
101 iface_config = collections.OrderedDict()
102 for line_idx in range(cur_idx + 1, len(lines)):
103 l = lines[line_idx].strip('\n\t ')
104
105 if self.ignore_line(l) == 1:
106 continue
107
a6f80f0e 108 if self.is_keyword(l.split()[0]) == True:
109 line_idx -= 1
110 break
111
eab25b7c 112 ifaceobj.raw_lines.append(l)
113
739f665b 114 # preprocess vars (XXX: only preprocesses $IFACE for now)
115 l = re.sub(r'\$IFACE', ifacename, l)
116
eab25b7c 117 attrs = l.split(' ', 1)
118 if len(attrs) < 2:
119 self.logger.warn('invalid syntax at line %d' %(line_idx + 1))
120 continue
a6f80f0e 121
eab25b7c 122 if iface_config.get(attrs[0]) == None:
123 iface_config[attrs[0]] = [attrs[1].strip(' ')]
a6f80f0e 124 else:
eab25b7c 125 iface_config[attrs[0]].append(attrs[1].strip(' '))
a6f80f0e 126
127 lines_consumed = line_idx - cur_idx
128
129 # Create iface object
37c0543d 130 if ifacename.find(':') != -1:
131 ifaceobj.set_name(ifacename.split(':')[0])
132 else:
133 ifaceobj.set_name(ifacename)
134
a6f80f0e 135 ifaceobj.set_config(iface_config)
136 ifaceobj.generate_env()
137 if len(iface_attrs) > 2:
138 ifaceobj.set_addr_family(iface_attrs[2])
139 ifaceobj.set_addr_method(iface_attrs[3])
140
141 if ifaceobj.get_name() in self.auto_ifaces:
142 ifaceobj.set_auto()
143
144 classes = ifaceobj.set_classes(
145 self.get_allow_classes_for_iface(ifaceobj.get_name()))
146 if classes is not None and len(classes) > 0:
147 for c in classes:
148 ifaceobj.set_class(c)
149
150 # Call iface found callback
37c0543d 151 #self.logger.debug('saving interface %s' %ifaceobj.get_name())
a6f80f0e 152 self.callbacks.get('iface_found')(ifaceobj)
153
154 return lines_consumed # Return next index
155
156
157 network_elems = { 'source' : process_source,
158 'allow' : process_allow,
159 'auto' : process_auto,
160 'iface' : process_iface}
161
162
163 def is_keyword(self, str):
164
165 # The additional split here is for allow- keyword
166 tmp_str = str.split('-')[0]
167 if tmp_str in self.network_elems.keys():
168 return 1
169
170 return 0
171
172 def get_keyword_func(self, str):
173 tmp_str = str.split('-')[0]
174
175 return self.network_elems.get(tmp_str)
176
177 def get_allow_classes_for_iface(self, ifacename):
178 classes = []
179 for class_name, ifacenames in self.allow_classes.items():
180 if ifacename in ifacenames:
181 classes.append(class_name)
182
183 return classes
184
579b3f25 185 def process_filedata(self, filedata):
a6f80f0e 186 lineno = 0
187 line_idx = 0
188 lines_consumed = 0
189
579b3f25 190 raw_lines = filedata.split('\n')
191 lines = [l.strip(' \n') for l in raw_lines]
a6f80f0e 192
579b3f25 193 while (line_idx < len(lines)):
194 lineno = lineno + 1
a6f80f0e 195
579b3f25 196 if self.ignore_line(lines[line_idx]):
197 line_idx += 1
198 continue
199
200 words = lines[line_idx].split()
a6f80f0e 201
579b3f25 202 # Check if first element is a supported keyword
203 if self.is_keyword(words[0]):
204 keyword_func = self.get_keyword_func(words[0])
205 lines_consumed = keyword_func(self, lines, line_idx, lineno)
206 line_idx += lines_consumed
207 else:
208 self.logger.warning('could not process line %s' %l + ' at' +
209 ' lineno %d' %lineno)
a6f80f0e 210
579b3f25 211 line_idx += 1
a6f80f0e 212
579b3f25 213 return 0
a6f80f0e 214
579b3f25 215 def run_template_engine(self, textdata):
216 try:
217 from mako.template import Template
218 except:
37c0543d 219 self.logger.warning('template engine mako not found. ' +
220 'skip template parsing ..');
579b3f25 221 return textdata
a6f80f0e 222
579b3f25 223 t = Template(text=textdata, output_encoding='utf-8')
224 return t.render()
a6f80f0e 225
579b3f25 226 def read_file(self, filename=None):
227 ifaces_file = filename
228 if ifaces_file == None:
229 ifaces_file=self.ifaces_file
230
37c0543d 231 self.logger.debug('reading interfaces file %s' %ifaces_file)
579b3f25 232 f = open(ifaces_file)
233 filedata = f.read()
234 f.close()
235
236 # process line continuations
237 filedata = ' '.join(d.strip() for d in filedata.split('\\'))
238
239 # run through template engine
240 filedata = self.run_template_engine(filedata)
241
242 self.process_filedata(filedata)
a6f80f0e 243
244
245 def load(self, filename=None):
a6f80f0e 246 return self.read_file(filename)