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