]>
git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdown/iface.py
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
10 """ifupdown2 network interface object
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
16 from collections
import OrderedDict
27 """ ifaceRole is used to classify the ifaceobj.role of
28 MASTER or SLAVE where there is a bond or bridge
29 with bond-slaves or bridge-ports. A bond in a bridge
30 is both a master and slave (0x3)
36 class ifaceLinkKind():
37 """ ifaceLlinkKind is used to identify interfaces
38 in the ifaceobj.link_kind attribute. Dependents of the bridge or
39 bond have an ifaceobj.role attribute of SLAVE and the bridge or
40 bond itself has ifaceobj.role of MASTER.
48 class ifaceLinkType():
54 class ifaceDependencyType():
55 """ Indicates type of dependency.
57 This class enumerates types of dependency relationships
60 iface dependency relationships can be classified
65 In a 'link' dependency relationship, dependency can be shared
66 between interfaces. example: swp1.100 and
67 swp1.200 can both have 'link' swp1. swp1 is also a dependency
68 of swp1.100 and swp1.200. As you can see dependency
69 swp1 is shared between swp1.100 and swp1.200.
71 In a master/slave relationship like bridge and
72 its ports: eg: bridge br0 and its ports swp1 and swp2.
73 dependency swp1 and swp2 cannot be shared with any other
74 interface with the same dependency relationship.
75 ie, swp1 and swp2 cannot be in a slave relationship
76 with another interface. Understanding the dependency type is
77 required for any semantic checks between dependencies.
85 """Enumerates iface status """
93 def to_str(cls
, state
):
94 if state
== cls
.UNKNOWN
:
96 elif state
== cls
.SUCCESS
:
98 elif state
== cls
.ERROR
:
100 elif state
== cls
.NOTFOUND
:
104 def from_str(cls
, state_str
):
105 if state_str
== 'unknown':
107 elif state_str
== 'success':
109 elif state_str
== 'error':
113 """Enumerates iface state """
125 QUERY_CHECKCURR
= 0x9
129 def to_str(cls
, state
):
130 if state
== cls
.UNKNOWN
:
132 elif state
== cls
.NEW
:
134 elif state
== cls
.PRE_UP
:
136 elif state
== cls
.UP
:
138 elif state
== cls
.POST_UP
:
140 elif state
== cls
.PRE_DOWN
:
142 elif state
== cls
.DOWN
:
144 elif state
== cls
.POST_DOWN
:
146 elif state
== cls
.QUERY_CHECKCURR
:
147 return 'query-checkcurr'
148 elif state
== cls
.QUERY_RUNNING
:
149 return 'query-running'
152 def from_str(cls
, state_str
):
153 if state_str
== 'unknown':
155 elif state_str
== 'new':
157 elif state_str
== 'pre-up':
159 elif state_str
== 'up':
161 elif state_str
== 'post-up':
163 elif state_str
== 'pre-down':
165 elif state_str
== 'down':
167 elif state_str
== 'post-down':
169 elif state_str
== 'query-checkcurr':
170 return cls
.QUERY_CHECKCURR
171 elif state_str
== 'query-running':
172 return cls
.QUERY_RUNNING
174 class ifaceJsonEncoder(json
.JSONEncoder
):
175 def default(self
, o
):
178 retconfig
= dict((k
, (v
[0] if len(v
) == 1 else v
))
179 for k
,v
in o
.config
.items())
180 return OrderedDict({'name' : o
.name
,
181 'addr_method' : o
.addr_method
,
182 'addr_family' : o
.addr_family
,
184 'config' : retconfig
})
186 class ifaceJsonDecoder():
188 def json_to_ifaceobj(cls
, ifaceattrdict
):
189 ifaceattrdict
['config'] = OrderedDict([(k
, (v
if isinstance(v
, list)
191 for k
,v
in ifaceattrdict
.get('config',
192 OrderedDict()).items()])
193 return iface(attrsdict
=ifaceattrdict
)
196 """ ifupdown2 iface object class
199 **name** Name of the interface
201 **addr_family** Address family eg, inet, inet6. Can be None to
202 indicate both address families
204 **addr_method** Address method eg, static, manual or None for
205 static address method
207 **config** dictionary of config lines for this interface
209 **state** Configuration state of an interface as defined by
212 **status** Configuration status of an interface as defined by
215 **flags** Internal flags used by iface processing
217 **priv_flags** private flags owned by module using this class
219 **module_flags** module flags owned by module using this class
221 **refcnt** reference count, indicating number of interfaces
222 dependent on this iface
224 **lowerifaces** list of interface names lower to this interface or
225 this interface depends on
227 **upperifaces** list of interface names upper to this interface or
228 the interfaces that depend on this interface
230 **auto** True if interface belongs to the auto class
232 **classes** List of classes the interface belongs to
234 **env** shell environment the interface needs during
237 **raw_config** raw interface config from file
240 # flag to indicate that the object was created from pickled state
241 _PICKLED
= 0x00000001
242 HAS_SIBLINGS
= 0x00000010
243 IFACERANGE_ENTRY
= 0x00000100
244 IFACERANGE_START
= 0x00001000
248 def __init__(self
, attrsdict
={}):
249 self
._set
_attrs
_from
_dict
(attrsdict
)
250 self
._config
_status
= {}
251 """dict with config status of iface attributes"""
252 self
.state
= ifaceState
.NEW
253 """iface state (of type ifaceState) """
254 self
.status
= ifaceStatus
.UNKNOWN
255 """iface status (of type ifaceStatus) """
256 self
.status_str
= None
257 """iface status str (string representing the status) """
260 self
.priv_flags
= 0x0
261 """iface module flags dictionary with module name: flags"""
262 self
.module_flags
= {}
263 """iface priv flags. can be used by the external object manager """
265 """iface refcnt (incremented for each dependent this interface has) """
266 self
.lowerifaces
= None
267 """lower iface list (in other words: slaves of this interface """
268 self
.upperifaces
= None
269 """upper iface list (in other words: master of this interface """
271 """interface classes this iface belongs to """
273 """environment variable dict required for this interface to run"""
275 """interface config/attributes in raw format (eg: as it appeared in the interfaces file)"""
276 self
.linkstate
= None
277 """linkstate of the interface"""
278 self
.type = ifaceType
.UNKNOWN
280 self
.priv_data
= None
281 self
.role
= ifaceRole
.UNKNOWN
283 self
.link_type
= ifaceLinkType
.LINK_UNKNOWN
284 self
.link_kind
= ifaceLinkKind
.UNKNOWN
286 # The below attribute is used to disambiguate between various
287 # types of dependencies
288 self
.dependency_type
= ifaceDependencyType
.UNKNOWN
290 def _set_attrs_from_dict(self
, attrdict
):
291 self
.auto
= attrdict
.get('auto', False)
292 self
.name
= attrdict
.get('name')
293 self
.addr_family
= attrdict
.get('addr_family')
294 self
.addr_method
= attrdict
.get('addr_method')
295 self
.config
= attrdict
.get('config', OrderedDict())
297 def inc_refcnt(self
):
298 """ increment refcnt of the interface. Usually used to indicate that
299 it has dependents """
302 def dec_refcnt(self
):
303 """ decrement refcnt of the interface. Usually used to indicate that
304 it has lost its dependent """
307 def is_config_present(self
):
308 """ returns true if the interface has user provided config,
310 addr_method
= self
.addr_method
311 if addr_method
and addr_method
in ['dhcp', 'dhcp6', 'loopback']:
318 def set_class(self
, classname
):
319 """ appends class to the interfaces class list """
320 self
.classes
.append(classname
)
322 def set_state_n_status(self
, state
, status
):
323 """ sets state and status of an interface """
327 def set_flag(self
, flag
):
330 def clear_flag(self
, flag
):
333 def add_to_upperifaces(self
, upperifacename
):
334 """ add to the list of upperifaces """
336 if upperifacename
not in self
.upperifaces
:
337 self
.upperifaces
.append(upperifacename
)
339 self
.upperifaces
= [upperifacename
]
341 def get_attr_value(self
, attr_name
):
342 """ add to the list of upperifaces """
343 return self
.config
.get(attr_name
)
345 def get_attr_value_first(self
, attr_name
):
346 """ get first value of the specified attr name """
347 attr_value_list
= self
.config
.get(attr_name
)
349 return attr_value_list
[0]
352 def get_attrs_value_first(self
, attrs
):
353 """ get first value of the first attr in the list.
354 Useful when you have multiple attrs representing the
358 attr_value_list
= self
.config
.get(attr
)
360 return attr_value_list
[0]
363 def get_attr_value_n(self
, attr_name
, attr_index
):
364 """ get n'th value of the specified attr name """
365 attr_value_list
= self
.config
.get(attr_name
)
368 return attr_value_list
[attr_index
]
375 """ get shell environment variables the interface must execute in """
380 def generate_env(self
):
381 """ generate shell environment variables dict interface must execute
382 in. This is used to support legacy ifupdown scripts
386 env
['IFACE'] = self
.name
387 for attr
, attr_value
in config
.items():
388 attr_env_name
= 'IF_%s' %attr
.upper()
389 env
[attr_env_name
] = attr_value
[0]
393 def update_config(self
, attr_name
, attr_value
):
394 """ add attribute name and value to the interface config """
395 self
.config
.setdefault(attr_name
, []).append(attr_value
)
397 def replace_config(self
, attr_name
, attr_value
):
398 """ add attribute name and value to the interface config """
399 self
.config
[attr_name
] = [attr_value
]
401 def delete_config(self
, attr_name
):
402 """ add attribute name and value to the interface config """
404 del self
.config
[attr_name
]
408 def update_config_dict(self
, attrdict
):
409 self
.config
.update(attrdict
)
411 def update_config_with_status(self
, attr_name
, attr_value
, attr_status
=0):
412 """ add attribute name and value to the interface config and also
413 update the config_status dict with status of this attribute config """
416 self
.config
.setdefault(attr_name
, []).append(attr_value
)
417 self
._config
_status
.setdefault(attr_name
, []).append(attr_status
)
418 # set global iface state
420 self
.status
= ifaceStatus
.ERROR
421 elif self
.status
!= ifaceStatus
.ERROR
:
422 # Not already error, mark success
423 self
.status
= ifaceStatus
.SUCCESS
425 def check_n_update_config_with_status_many(self
, ifaceobjorig
, attr_names
,
427 # set multiple attribute status to zero
428 # also updates status only if the attribute is present
429 for attr_name
in attr_names
:
430 if not ifaceobjorig
.get_attr_value_first(attr_name
):
432 self
.config
.setdefault(attr_name
, []).append('')
433 self
._config
_status
.setdefault(attr_name
, []).append(attr_status
)
435 def get_config_attr_status(self
, attr_name
, idx
=0):
436 """ get status of a attribute config on this interface.
438 Looks at the iface _config_status dict"""
439 return self
._config
_status
.get(attr_name
, [])[idx
]
441 def compare(self
, dstiface
):
442 """ compares iface object with iface object passed as argument
444 Returns True if object self is same as dstiface and False otherwise """
446 if self
.name
!= dstiface
.name
: return False
447 if self
.type != dstiface
.type: return False
448 if self
.addr_family
!= dstiface
.addr_family
: return False
449 if self
.addr_method
!= dstiface
.addr_method
: return False
450 if self
.auto
!= dstiface
.auto
: return False
451 if self
.classes
!= dstiface
.classes
: return False
452 if len(self
.config
) != len(dstiface
.config
):
454 if any(True for k
in self
.config
if k
not in dstiface
.config
):
456 if any(True for k
,v
in self
.config
.items()
457 if v
!= dstiface
.config
.get(k
)): return False
461 def __getstate__(self
):
462 odict
= self
.__dict
__.copy()
465 del odict
['lowerifaces']
466 del odict
['upperifaces']
468 del odict
['_config_status']
470 del odict
['priv_flags']
471 del odict
['module_flags']
472 del odict
['raw_config']
473 del odict
['linkstate']
475 del odict
['link_type']
476 del odict
['link_kind']
478 del odict
['dependency_type']
481 def __setstate__(self
, dict):
482 self
.__dict
__.update(dict)
483 self
._config
_status
= {}
484 self
.state
= ifaceState
.NEW
485 self
.status
= ifaceStatus
.UNKNOWN
488 self
.lowerifaces
= None
489 self
.upperifaces
= None
490 self
.linkstate
= None
492 self
.role
= ifaceRole
.UNKNOWN
494 self
.module_flags
= {}
496 self
.flags |
= self
._PICKLED
497 self
.link_type
= ifaceLinkType
.LINK_NA
498 self
.link_kind
= ifaceLinkKind
.UNKNOWN
499 self
.dependency_type
= ifaceDependencyType
.UNKNOWN
501 def dump_raw(self
, logger
):
504 print 'auto %s' %self
.name
505 print (self
.raw_config
[0])
506 for i
in range(1, len(self
.raw_config
)):
507 print(indent
+ self
.raw_config
[i
])
509 def dump(self
, logger
):
511 logger
.info(self
.name
+ ' : {')
512 logger
.info(indent
+ 'family: %s' %self
.addr_family
)
513 logger
.info(indent
+ 'method: %s' %self
.addr_method
)
514 logger
.info(indent
+ 'flags: %x' %self
.flags
)
515 logger
.info(indent
+ 'state: %s'
516 %ifaceState
.to_str(self
.state
))
517 logger
.info(indent
+ 'status: %s'
518 %ifaceStatus
.to_str(self
.status
))
519 logger
.info(indent
+ 'refcnt: %d' %self
.refcnt
)
522 logger
.info(indent
+ 'lowerdevs: %s' %str
(d
))
524 logger
.info(indent
+ 'lowerdevs: None')
526 logger
.info(indent
+ 'config: ')
529 logger
.info(indent
+ indent
+ str(config
))
532 def dump_pretty(self
, with_status
=False,
533 successstr
='success', errorstr
='error',
534 unknownstr
='unknown', use_realname
=False):
537 if use_realname
and self
.realname
:
538 name
= '%s' %self
.realname
540 name
= '%s' %self
.name
542 outbuf
+= 'auto %s\n' %name
544 if self
.type == ifaceType
.BRIDGE_VLAN
:
545 ifaceline
+= 'vlan %s' %name
547 ifaceline
+= 'iface %s' %name
549 ifaceline
+= ' %s' %self
.addr_family
551 ifaceline
+= ' %s' %self
.addr_method
554 if (self
.status
== ifaceStatus
.ERROR
or
555 self
.status
== ifaceStatus
.NOTFOUND
):
557 ifaceline
+= ' (%s)' %self
.status_str
558 status_str
= errorstr
559 elif self
.status
== ifaceStatus
.SUCCESS
:
560 status_str
= successstr
562 outbuf
+= '{0:65} {1:>8}'.format(ifaceline
, status_str
) + '\n'
564 outbuf
+= ifaceline
+ '\n'
565 if self
.status
== ifaceStatus
.NOTFOUND
:
566 outbuf
= (outbuf
.encode('utf8')
567 if isinstance(outbuf
, unicode) else outbuf
)
571 outbuf
+= ifaceline
+ '\n'
574 for cname
, cvaluelist
in config
.items():
576 for cv
in cvaluelist
:
578 s
= self
.get_config_attr_status(cname
, idx
)
580 status_str
= unknownstr
582 status_str
= errorstr
584 status_str
= successstr
585 outbuf
+= (indent
+ '{0:55} {1:>10}'.format(
586 '%s %s' %(cname
, cv
), status_str
)) + '\n'
588 outbuf
+= indent
+ '%s %s\n' %(cname
, cv
)
591 outbuf
= (outbuf
.encode('utf8')
592 if isinstance(outbuf
, unicode) else outbuf
)