]> git.proxmox.com Git - mirror_ifupdown2.git/blob - pkg/iface.py
Remove upper device check warnings + implicitly follow upperifaces when
[mirror_ifupdown2.git] / pkg / iface.py
1 #!/usr/bin/python
2 #
3 # Copyright 2013. Cumulus Networks, Inc.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6 # iface --
7 # interface object
8 #
9
10 """ifupdown2 network interface object
11
12 It closely resembles the 'iface' object in /etc/network/interfaces
13 file. But can be extended to include any other network interface format
14
15
16 The module contains the following public classes:
17
18 - ifaceState -- enumerates iface object state
19
20 - ifaceStatus -- enumerates iface object status (success/error)
21
22 - ifaceJsonEncoder -- Json encoder for the iface object
23
24 - iface -- network in terface object class
25
26 """
27
28 from collections import OrderedDict
29 import json
30 import logging
31
32 _tickmark = ' (' + u'\u2713'.encode('utf8') + ')'
33 _crossmark = ' (' + u'\u2717'.encode('utf8') + ')'
34
35 class ifaceStatus():
36 """Enumerates iface status """
37
38 UNKNOWN = 0x1
39 SUCCESS = 0x2
40 ERROR = 0x3
41 NOTFOUND = 0x4
42
43 @classmethod
44 def to_str(cls, state):
45 if state == cls.UNKNOWN:
46 return 'unknown'
47 elif state == cls.SUCCESS:
48 return 'success'
49 elif state == cls.ERROR:
50 return 'error'
51 elif state == cls.NOTFOUND:
52 return 'notfound'
53
54 @classmethod
55 def from_str(cls, state_str):
56 if state_str == 'unknown':
57 return cls.UNKNOWN
58 elif state_str == 'success':
59 return cls.SUCCESS
60 elif state_str == 'error':
61 return cls.ERROR
62
63 class ifaceState():
64 """Enumerates iface state """
65
66 UNKNOWN = 0x1
67 NEW = 0x2
68 PRE_UP = 0x3
69 UP = 0x4
70 POST_UP = 0x5
71 PRE_DOWN = 0x6
72 DOWN = 0x7
73 POST_DOWN = 0x8
74
75 # Pseudo states
76 QUERY_CHECKCURR = 0x9
77 QUERY_RUNNING = 0xa
78
79 @classmethod
80 def to_str(cls, state):
81 if state == cls.UNKNOWN:
82 return 'unknown'
83 elif state == cls.NEW:
84 return 'new'
85 elif state == cls.PRE_UP:
86 return 'pre-up'
87 elif state == cls.UP:
88 return 'up'
89 elif state == cls.POST_UP:
90 return 'post-up'
91 elif state == cls.PRE_DOWN:
92 return 'pre-down'
93 elif state == cls.DOWN:
94 return 'down'
95 elif state == cls.POST_DOWN:
96 return 'post-down'
97 elif state == cls.QUERY_CHECKCURR:
98 return 'query-checkcurr'
99 elif state == cls.QUERY_RUNNING:
100 return 'query-running'
101
102 @classmethod
103 def from_str(cls, state_str):
104 if state_str == 'unknown':
105 return cls.UNKNOWN
106 elif state_str == 'new':
107 return cls.NEW
108 elif state_str == 'pre-up':
109 return cls.PRE_UP
110 elif state_str == 'up':
111 return cls.UP
112 elif state_str == 'post-up':
113 return cls.POST_UP
114 elif state_str == 'pre-down':
115 return cls.PRE_DOWN
116 elif state_str == 'down':
117 return cls.DOWN
118 elif state_str == 'post-down':
119 return cls.POST_DOWN
120 elif state_str == 'query-checkcurr':
121 return cls.QUERY_CHECKCURR
122 elif state_str == 'query-running':
123 return cls.QUERY_RUNNING
124
125 class ifaceJsonEncoder(json.JSONEncoder):
126 def default(self, o):
127 retconfig = {}
128 if o.config:
129 for k, v in o.config.items():
130 if len(v) == 1:
131 retconfig[k] = v[0]
132 else:
133 retconfig[k] = v
134
135 return OrderedDict({'name' : o.name,
136 'addr_method' : o.addr_method,
137 'addr_family' : o.addr_family,
138 'auto' : o.auto,
139 'config' : retconfig})
140
141 class iface():
142 """ ifupdown2 interface object class
143
144 Attributes:
145 name Name of the interface
146 addr_family Address family eg, inet, inet6. Can be None to indicate both address families
147 addr_method Address method eg, static, manual or None for static
148 address method
149 config dictionary of config lines for this interface
150 state Configuration state of an interface as defined by
151 ifaceState
152 status Configuration status of an interface as defined by
153 ifaceStatus
154 flags Internal flags used by iface processing
155 priv_flags private flags owned by module using this class
156 refcnt reference count, indicating number of interfaces
157 dependent on this iface
158 lowerifaces list of interface names lower to this interface or
159 this interface depends on
160 upperifaces list of interface names upper to this interface or
161 the interfaces that depend on this interface
162 auto True if interface belongs to the auto class
163 classes List of classes the interface belongs to
164 env shell environment the interface needs during execution
165 raw_config raw interface config from file
166 """
167
168 # flag to indicate that the object was created from pickled state
169 _PICKLED = 0x1
170
171 version = '0.1'
172
173 def __init__(self):
174 self.name = None
175 self.addr_family = None
176 self.addr_method = None
177 self.config = OrderedDict()
178 self._config_status = {}
179 self.state = ifaceState.NEW
180 self.status = ifaceStatus.UNKNOWN
181 self.flags = 0x0
182 self.priv_flags = 0x0
183 self.refcnt = 0
184 self.lowerifaces = None
185 self.upperifaces = None
186 self.auto = False
187 self.classes = []
188 self.env = None
189 self.raw_config = []
190 self.linkstate = None
191
192 def inc_refcnt(self):
193 self.refcnt += 1
194
195 def dec_refcnt(self):
196 self.refcnt -= 1
197
198 def is_config_present(self):
199 addr_method = self.addr_method
200 if addr_method:
201 if (addr_method.find('dhcp') != -1 or
202 addr_method.find('dhcp6') != -1):
203 return True
204 if not self.config:
205 return False
206 else:
207 return True
208
209 def set_class(self, classname):
210 """ Appends a class to the list """
211 self.classes.append(classname)
212
213 def set_state_n_status(self, state, status):
214 self.state = state
215 self.status = status
216
217 def set_flag(self, flag):
218 self.flags |= flag
219
220 def clear_flag(self, flag):
221 self.flags &= ~flag
222
223 def add_to_upperifaces(self, upperifacename):
224 if self.upperifaces:
225 if upperifacename not in self.upperifaces:
226 self.upperifaces.append(upperifacename)
227 else:
228 self.upperifaces = [upperifacename]
229
230 def get_attr_value(self, attr_name):
231 return self.config.get(attr_name)
232
233 def get_attr_value_first(self, attr_name):
234 attr_value_list = self.config.get(attr_name)
235 if attr_value_list:
236 return attr_value_list[0]
237 return None
238
239 def get_attr_value_n(self, attr_name, attr_index):
240 attr_value_list = self.config.get(attr_name)
241 if attr_value_list:
242 try:
243 return attr_value_list[attr_index]
244 except:
245 return None
246 return None
247
248 @property
249 def get_env(self):
250 if not self.env:
251 self.generate_env()
252 return self.env
253
254 def generate_env(self):
255 env = {}
256 config = self.config
257 env['IFACE'] = self.name
258 for attr, attr_value in config.items():
259 attr_env_name = 'IF_%s' %attr.upper()
260 env[attr_env_name] = attr_value[0]
261 if env:
262 self.env = env
263
264 def update_config(self, attr_name, attr_value):
265 self.config.setdefault(attr_name, []).append(attr_value)
266
267 def update_config_dict(self, attrdict):
268 self.config.update(attrdict)
269
270 def update_config_with_status(self, attr_name, attr_value, attr_status=0):
271 if not attr_value:
272 attr_value = ''
273
274 self.config.setdefault(attr_name, []).append(attr_value)
275 self._config_status.setdefault(attr_name, []).append(attr_status)
276
277 # set global iface state
278 if attr_status:
279 self.status = ifaceStatus.ERROR
280 elif self.status != ifaceStatus.ERROR:
281 # Not already error, mark success
282 self.status = ifaceStatus.SUCCESS
283
284 def get_config_attr_status(self, attr_name, idx=0):
285 return self._config_status.get(attr_name, [])[idx]
286
287 def get_config_attr_status_str(self, attr_name, idx=0):
288 ret = self.get_config_attr_status(attr_name, idx)
289 if ret:
290 return _crossmark
291 else:
292 return _tickmark
293
294 def compare(self, dstiface):
295 """ Compares two objects
296
297 Returns True if object self is same as dstiface and False otherwise """
298
299 if self.name != dstiface.name: return False
300 if self.addr_family != dstiface.addr_family: return False
301 if self.addr_method != dstiface.addr_method: return False
302 if self.auto != dstiface.auto: return False
303 if self.classes != dstiface.classes: return False
304 if any(True for k in self.config if k not in dstiface.config):
305 return False
306 if any(True for k,v in self.config.items()
307 if v != dstiface.config.get(k)): return False
308 return True
309
310 def __getstate__(self):
311 odict = self.__dict__.copy()
312 del odict['state']
313 del odict['status']
314 del odict['lowerifaces']
315 del odict['upperifaces']
316 del odict['refcnt']
317 del odict['_config_status']
318 del odict['flags']
319 del odict['priv_flags']
320 del odict['raw_config']
321 del odict['linkstate']
322 del odict['env']
323 return odict
324
325 def __setstate__(self, dict):
326 self.__dict__.update(dict)
327 self._config_status = {}
328 self.state = ifaceState.NEW
329 self.status = ifaceStatus.UNKNOWN
330 self.refcnt = 0
331 self.flags = 0
332 self.lowerifaces = None
333 self.upperifaces = None
334 self.linkstate = None
335 self.env = None
336 self.priv_flags = 0
337 self.raw_config = []
338 self.flags |= self._PICKLED
339
340 def dump_raw(self, logger):
341 indent = ' '
342 if self.auto:
343 print 'auto %s' %self.name
344 print (self.raw_config[0])
345 for i in range(1, len(self.raw_config)):
346 print(indent + self.raw_config[i])
347
348 def dump(self, logger):
349 indent = '\t'
350 logger.info(self.name + ' : {')
351 logger.info(indent + 'family: %s' %self.addr_family)
352 logger.info(indent + 'method: %s' %self.addr_method)
353 logger.info(indent + 'flags: %x' %self.flags)
354 logger.info(indent + 'state: %s'
355 %ifaceState.to_str(self.state))
356 logger.info(indent + 'status: %s'
357 %ifaceStatus.to_str(self.status))
358 logger.info(indent + 'refcnt: %d' %self.refcnt)
359 d = self.lowerifaces
360 if d:
361 logger.info(indent + 'lowerdevs: %s' %str(d))
362 else:
363 logger.info(indent + 'lowerdevs: None')
364
365 logger.info(indent + 'config: ')
366 config = self.config
367 if config:
368 logger.info(indent + indent + str(config))
369 logger.info('}')
370
371 def dump_pretty(self, with_status=False):
372 indent = '\t'
373 outbuf = ''
374 if self.auto:
375 outbuf += 'auto %s\n' %self.name
376 outbuf += 'iface %s' %self.name
377 if self.addr_family:
378 outbuf += ' %s' %self.addr_family
379 if self.addr_method:
380 outbuf += ' %s' %self.addr_method
381 outbuf += '\n'
382 config = self.config
383 if config:
384 for cname, cvaluelist in config.items():
385 idx = 0
386 for cv in cvaluelist:
387 if with_status:
388 outbuf += indent + '%s %s %s\n' %(cname, cv,
389 self.get_config_attr_status_str(cname, idx))
390 else:
391 outbuf += indent + '%s %s\n' %(cname, cv)
392 idx += 1
393 print outbuf
394
395 def dump_json(self, with_status=False):
396 print json.dumps(self, cls=ifaceJsonEncoder, indent=4)