]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdown/iface.py
bridge: vlan-aware: add new boolean policy "vlan_aware_bridge_address_support"
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / iface.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014-2017 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 import json
17
18 from collections import OrderedDict
19
20
21 class ifaceStatusUserStrs():
22 """ This class declares strings user can see during an ifquery --check
23 for example. These strings can be overridden by user defined strings from
24 config file """
25 SUCCESS = "success",
26 FAILURE = "error",
27 UNKNOWN = "unknown"
28
29 class ifaceType():
30 UNKNOWN = 0x00
31 IFACE = 0x01
32 BRIDGE_VLAN = 0x10
33
34 class ifaceRole():
35 """ ifaceRole is used to classify the ifaceobj.role of
36 MASTER or SLAVE where there is a bond or bridge
37 with bond-slaves or bridge-ports. A bond in a bridge
38 is both a master and slave (0x3)
39 """
40 UNKNOWN = 0x00
41 SLAVE = 0x01
42 MASTER = 0x10
43
44 class ifaceLinkKind():
45 """ ifaceLlinkKind is used to identify interfaces
46 in the ifaceobj.link_kind attribute. Dependents of the bridge or
47 bond have an ifaceobj.role attribute of SLAVE and the bridge or
48 bond itself has ifaceobj.role of MASTER.
49 """
50 UNKNOWN = 0x000000
51 BRIDGE = 0x000001
52 BOND = 0x000010
53 VLAN = 0x000100
54 VXLAN = 0x001000
55 VRF = 0x010000
56 # to indicate logical interface created by an external entity.
57 # the 'kind' of which ifupdown2 does not really understand
58 OTHER = 0x100000
59
60 @classmethod
61 def to_str(cls, kind):
62 if kind == cls.BRIDGE:
63 return "bridge"
64 elif kind == cls.BOND:
65 return "bond"
66 elif kind == cls.VLAN:
67 return "vlan"
68 elif kind == cls.VXLAN:
69 return "vxlan"
70 elif kind == cls.VRF:
71 return "vrf"
72
73 class ifaceLinkPrivFlags():
74 """ This corresponds to kernel netdev->priv_flags
75 and can be BRIDGE_PORT, BOND_SLAVE etc """
76 UNKNOWN = 0x00000
77 BRIDGE_PORT = 0x00001
78 BOND_SLAVE = 0x00010
79 VRF_SLAVE = 0x00100
80 BRIDGE_VLAN_AWARE = 0x01000
81 BRIDGE_VXLAN = 0x10000
82 ADDRESS_VIRTUAL_SLAVE = 0x100000
83 LOOPBACK = 0x1000000
84 KEEP_LINK_DOWN = 0x10000000
85
86 @classmethod
87 def get_str(cls, flag):
88 if flag == cls.UNKNOWN:
89 return 'unknown'
90 elif flag == cls.BRIDGE_PORT:
91 return 'bridge port'
92 elif flag == cls.BOND_SLAVE:
93 return 'bond slave'
94 elif flag == cls.VRF_SLAVE:
95 return 'vrf slave'
96 elif flag == cls.BRIDGE_VLAN_AWARE:
97 return 'vlan aware bridge'
98 elif flag == cls.BRIDGE_VXLAN:
99 return 'vxlan bridge'
100
101 @classmethod
102 def get_all_str(cls, flags):
103 str = ''
104 if flags & cls.BRIDGE_PORT:
105 str += 'bridgeport '
106 if flags & cls.BOND_SLAVE:
107 str += 'bondslave '
108 if flags & cls.VRF_SLAVE:
109 str += 'vrfslave '
110 if flags & cls.BRIDGE_VLAN_AWARE:
111 str += 'vlanawarebridge '
112 if flags & cls.BRIDGE_VXLAN:
113 str += 'vxlanbridge '
114 return str
115
116 class ifaceLinkType():
117 LINK_UNKNOWN = 0x0
118 LINK_SLAVE = 0x1
119 LINK_MASTER = 0x2
120 LINK_NA = 0x3
121
122 class VlanProtocols():
123 # Picked ID values from
124 # http://www.microhowto.info/howto/configure_an_ethernet_interface_as_a_qinq_vlan_trunk.html
125 ETHERTYPES_TO_ID = {
126 '802.1Q' : '0x8100',
127 '802.1AD' : '0x88a8',
128 }
129 ID_TO_ETHERTYPES = {
130 '0x8100' : '802.1Q',
131 '0x88a8' : '802.1AD',
132 }
133
134 class ifaceDependencyType():
135 """ Indicates type of dependency.
136
137 This class enumerates types of dependency relationships
138 between interfaces.
139
140 iface dependency relationships can be classified
141 into:
142 - link
143 - master/slave
144
145 In a 'link' dependency relationship, dependency can be shared
146 between interfaces. example: swp1.100 and
147 swp1.200 can both have 'link' swp1. swp1 is also a dependency
148 of swp1.100 and swp1.200. As you can see dependency
149 swp1 is shared between swp1.100 and swp1.200.
150
151 In a master/slave relationship like bridge and
152 its ports: eg: bridge br0 and its ports swp1 and swp2.
153 dependency swp1 and swp2 cannot be shared with any other
154 interface with the same dependency relationship.
155 ie, swp1 and swp2 cannot be in a slave relationship
156 with another interface. Understanding the dependency type is
157 required for any semantic checks between dependencies.
158
159 """
160 UNKNOWN = 0x0
161 LINK = 0x1
162 MASTER_SLAVE = 0x2
163
164 class ifaceStatus():
165 """Enumerates iface status """
166
167 UNKNOWN = 0x1
168 SUCCESS = 0x2
169 WARNING = 0x3
170 ERROR = 0x4
171 NOTFOUND = 0x5
172
173 @classmethod
174 def to_str(cls, state):
175 if state == cls.UNKNOWN:
176 return 'unknown'
177 elif state == cls.SUCCESS:
178 return 'success'
179 elif state == cls.ERROR:
180 return 'error'
181 elif state == cls.NOTFOUND:
182 return 'notfound'
183
184 @classmethod
185 def from_str(cls, state_str):
186 if state_str == 'unknown':
187 return cls.UNKNOWN
188 elif state_str == 'success':
189 return cls.SUCCESS
190 elif state_str == 'error':
191 return cls.ERROR
192
193 class ifaceState():
194 """Enumerates iface state """
195
196 UNKNOWN = 0x1
197 NEW = 0x2
198 PRE_UP = 0x3
199 UP = 0x4
200 POST_UP = 0x5
201 PRE_DOWN = 0x6
202 DOWN = 0x7
203 POST_DOWN = 0x8
204
205 # Pseudo states
206 QUERY_CHECKCURR = 0x9
207 QUERY_RUNNING = 0xa
208
209 @classmethod
210 def to_str(cls, state):
211 if state == cls.UNKNOWN:
212 return 'unknown'
213 elif state == cls.NEW:
214 return 'new'
215 elif state == cls.PRE_UP:
216 return 'pre-up'
217 elif state == cls.UP:
218 return 'up'
219 elif state == cls.POST_UP:
220 return 'post-up'
221 elif state == cls.PRE_DOWN:
222 return 'pre-down'
223 elif state == cls.DOWN:
224 return 'down'
225 elif state == cls.POST_DOWN:
226 return 'post-down'
227 elif state == cls.QUERY_CHECKCURR:
228 return 'query-checkcurr'
229 elif state == cls.QUERY_RUNNING:
230 return 'query-running'
231
232 @classmethod
233 def from_str(cls, state_str):
234 if state_str == 'unknown':
235 return cls.UNKNOWN
236 elif state_str == 'new':
237 return cls.NEW
238 elif state_str == 'pre-up':
239 return cls.PRE_UP
240 elif state_str == 'up':
241 return cls.UP
242 elif state_str == 'post-up':
243 return cls.POST_UP
244 elif state_str == 'pre-down':
245 return cls.PRE_DOWN
246 elif state_str == 'down':
247 return cls.DOWN
248 elif state_str == 'post-down':
249 return cls.POST_DOWN
250 elif state_str == 'query-checkcurr':
251 return cls.QUERY_CHECKCURR
252 elif state_str == 'query-running':
253 return cls.QUERY_RUNNING
254
255 class ifaceJsonEncoder(json.JSONEncoder):
256 def default(self, o):
257 retconfig = {}
258 retifacedict = OrderedDict([])
259 if o.config:
260 retconfig = dict((k, (v[0] if len(v) == 1 else v))
261 for k,v in o.config.items())
262 retifacedict['name'] = o.name
263 if o.addr_method:
264 if 'inet' in o.addr_family and 'dhcp' in o.addr_method:
265 retifacedict['addr_method'] = 'dhcp'
266 else:
267 retifacedict['addr_method'] = o.addr_method
268 if o.addr_family:
269 if len(o.addr_family) > 1:
270 retifacedict['addr_family'] = o.addr_family
271 else:
272 retifacedict['addr_family'] = ' '.join(o.addr_family)
273 retifacedict['auto'] = o.auto
274 retifacedict['config'] = retconfig
275
276 return retifacedict
277
278 class ifaceJsonEncoderWithStatus(json.JSONEncoder):
279 def default(self, o):
280 retconfig = {}
281 retconfig_status = {}
282 retifacedict = OrderedDict([])
283 if o.config:
284 for k,v in o.config.items():
285 idx = 0
286 vitem_status = []
287 for vitem in v:
288 s = o.get_config_attr_status(k, idx)
289 if s == 1:
290 status_str = ifaceStatusUserStrs.ERROR
291 elif s == 0:
292 status_str = ifaceStatusUserStrs.SUCCESS
293 else:
294 status_str = ifaceStatusUserStrs.UNKNOWN
295 vitem_status.append('%s' %status_str)
296 idx += 1
297 retconfig[k] = v[0] if len(v) == 1 else v
298 retconfig_status[k] = vitem_status[0] if len(vitem_status) == 1 else vitem_status
299
300 if (o.status == ifaceStatus.NOTFOUND or
301 o.status == ifaceStatus.ERROR):
302 status = ifaceStatusUserStrs.ERROR
303 else:
304 status = ifaceStatusUserStrs.SUCCESS
305
306 retifacedict['name'] = o.name
307 if o.addr_method:
308 retifacedict['addr_method'] = o.addr_method
309 if o.addr_family:
310 if len(o.addr_family) > 1:
311 retifacedict['addr_family'] = o.addr_family
312 else:
313 retifacedict['addr_family'] = ' '.join(o.addr_family)
314 retifacedict['auto'] = o.auto
315 retifacedict['config'] = retconfig
316 retifacedict['config_status'] = retconfig_status
317 retifacedict['status'] = status
318
319 return retifacedict
320
321 class ifaceJsonDecoder():
322 @classmethod
323 def json_to_ifaceobj(cls, ifaceattrdict):
324 ifaceattrdict['config'] = OrderedDict([(k, (v if isinstance(v, list)
325 else [v.strip()]))
326 for k,v in ifaceattrdict.get('config',
327 OrderedDict()).items()])
328 return iface(attrsdict=ifaceattrdict)
329
330 class iface():
331 """ ifupdown2 iface object class
332 Attributes:
333 **name** Name of the interface
334
335 **addr_family** Address family eg, inet, inet6. Can be None to
336 indicate both address families
337
338 **addr_method** Address method eg, static, manual or None for
339 static address method
340
341 **config** dictionary of config lines for this interface
342
343 **state** Configuration state of an interface as defined by
344 ifaceState
345
346 **status** Configuration status of an interface as defined by
347 ifaceStatus
348
349 **flags** Internal flags used by iface processing
350
351 **priv_flags** private flags owned by module using this class
352
353 **module_flags** module flags owned by module using this class
354
355 **refcnt** reference count, indicating number of interfaces
356 dependent on this iface
357
358 **lowerifaces** list of interface names lower to this interface or
359 this interface depends on
360
361 **upperifaces** list of interface names upper to this interface or
362 the interfaces that depend on this interface
363
364 **auto** True if interface belongs to the auto class
365
366 **classes** List of classes the interface belongs to
367
368 **env** shell environment the interface needs during
369 execution
370
371 **raw_config** raw interface config from file
372 """
373
374 # flag to indicate that the object was created from pickled state
375 # XXX: Move these flags into a separate iface flags class
376 _PICKLED = 0x00000001
377 HAS_SIBLINGS = 0x00000010
378 IFACERANGE_ENTRY = 0x00000100
379 IFACERANGE_START = 0x00001000
380 OLDEST_SIBLING = 0x00010000
381 YOUNGEST_SIBLING = 0x00100000
382
383 version = '0.1'
384
385 def __init__(self, attrsdict={}):
386 self.addr_family = []
387
388 self._set_attrs_from_dict(attrsdict)
389 self._config_status = {}
390 """dict with config status of iface attributes"""
391 self.state = ifaceState.NEW
392 """iface state (of type ifaceState) """
393 self.status = ifaceStatus.UNKNOWN
394 """iface status (of type ifaceStatus) """
395 self.status_str = None
396 """iface status str (string representing the status) """
397 self.flags = 0x0
398 """iface flags """
399 self.priv_flags = None
400 """iface module flags dictionary with module name: flags"""
401 self.module_flags = {}
402 """iface priv flags. can be used by the external object manager """
403 self.refcnt = 0
404 """iface refcnt (incremented for each dependent this interface has) """
405 self.lowerifaces = None
406 """lower iface list (in other words: slaves of this interface """
407 self.upperifaces = None
408 """upper iface list (in other words: master of this interface """
409 self.classes = []
410 """interface classes this iface belongs to """
411 self.env = None
412 """environment variable dict required for this interface to run"""
413 self.raw_config = []
414 """interface config/attributes in raw format (eg: as it appeared in the interfaces file)"""
415 self.linkstate = None
416 """linkstate of the interface"""
417 self.type = ifaceType.UNKNOWN
418 """interface type"""
419 self.priv_data = None
420 self.role = ifaceRole.UNKNOWN
421 self.realname = None
422 self.link_type = ifaceLinkType.LINK_UNKNOWN
423 self.link_kind = ifaceLinkKind.UNKNOWN
424 self.link_privflags = ifaceLinkPrivFlags.UNKNOWN
425
426 # The below attribute is used to disambiguate between various
427 # types of dependencies
428 self.dependency_type = ifaceDependencyType.UNKNOWN
429 self.blacklisted = False
430
431 def _set_attrs_from_dict(self, attrdict):
432 self.auto = attrdict.get('auto', False)
433 self.name = attrdict.get('name')
434 self.addr_method = attrdict.get('addr_method')
435 self.config = attrdict.get('config', OrderedDict())
436
437 addr_family = attrdict.get('addr_family')
438 if addr_family:
439 self.addr_family.append(addr_family)
440
441 def inc_refcnt(self):
442 """ increment refcnt of the interface. Usually used to indicate that
443 it has dependents """
444 self.refcnt += 1
445
446 def dec_refcnt(self):
447 """ decrement refcnt of the interface. Usually used to indicate that
448 it has lost its dependent """
449 self.refcnt -= 1
450
451 def is_config_present(self):
452 """ returns true if the interface has user provided config,
453 false otherwise """
454 addr_method = self.addr_method
455 if addr_method and addr_method in ['dhcp', 'dhcp6', 'loopback']:
456 return True
457 if not self.config:
458 return False
459 else:
460 return True
461
462 def set_class(self, classname):
463 """ appends class to the interfaces class list """
464 self.classes.append(classname)
465
466 def set_state_n_status(self, state, status):
467 """ sets state and status of an interface """
468 self.state = state
469 if status > self.status:
470 self.status = status
471
472 def set_status(self, status):
473 """ sets status of an interface """
474 if status > self.status:
475 self.status = status
476
477 def set_flag(self, flag):
478 self.flags |= flag
479
480 def clear_flag(self, flag):
481 self.flags &= ~flag
482
483 def add_to_upperifaces(self, upperifacename):
484 """ add to the list of upperifaces """
485 if self.upperifaces:
486 if upperifacename not in self.upperifaces:
487 self.upperifaces.append(upperifacename)
488 else:
489 self.upperifaces = [upperifacename]
490
491 def add_to_lowerifaces(self, lowerifacename):
492 """ add to the list of lowerifaces """
493 if self.lowerifaces:
494 if lowerifacename not in self.lowerifaces:
495 self.lowerifaces.append(lowerifacename)
496 else:
497 self.lowerifaces = [lowerifacename]
498
499 def get_attr_value(self, attr_name):
500 """ add to the list of upperifaces """
501 return self.config.get(attr_name)
502
503 def get_attr_value_first(self, attr_name):
504 """ get first value of the specified attr name """
505 attr_value_list = self.config.get(attr_name)
506 if attr_value_list:
507 return attr_value_list[0]
508 return None
509
510 def get_attrs_value_first(self, attrs):
511 """ get first value of the first attr in the list.
512 Useful when you have multiple attrs representing the
513 same thing.
514 """
515 for attr in attrs:
516 attr_value_list = self.config.get(attr)
517 if attr_value_list:
518 return attr_value_list[0]
519 return None
520
521 def get_attr_value_n(self, attr_name, attr_index):
522 """ get n'th value of the specified attr name """
523 attr_value_list = self.config.get(attr_name)
524 if attr_value_list:
525 try:
526 return attr_value_list[attr_index]
527 except:
528 return None
529 return None
530
531 def get_env(self):
532 """ get shell environment variables the interface must execute in """
533 if not self.env:
534 self.generate_env()
535 return self.env
536
537 def generate_env(self):
538 """ generate shell environment variables dict interface must execute
539 in. This is used to support legacy ifupdown scripts
540 """
541 env = {}
542 config = self.config
543 env['IFACE'] = self.name
544 for attr, attr_value in config.items():
545 attr_env_name = 'IF_%s' %attr.upper().replace("-", "_")
546 env[attr_env_name] = attr_value[0]
547 self.env = env
548
549 def update_config(self, attr_name, attr_value):
550 """ add attribute name and value to the interface config """
551 self.config.setdefault(attr_name, []).append(attr_value)
552
553 def replace_config(self, attr_name, attr_value):
554 """ add attribute name and value to the interface config """
555 self.config[attr_name] = [attr_value]
556
557 def delete_config(self, attr_name):
558 """ add attribute name and value to the interface config """
559 try:
560 del self.config[attr_name]
561 except:
562 pass
563
564 def update_config_dict(self, attrdict):
565 self.config.update(attrdict)
566
567 def update_config_with_status(self, attr_name, attr_value, attr_status=0):
568 """ add attribute name and value to the interface config and also
569 update the config_status dict with status of this attribute config """
570 if not attr_value:
571 attr_value = ''
572 self.config.setdefault(attr_name, []).append(attr_value)
573 self._config_status.setdefault(attr_name, []).append(attr_status)
574 # set global iface state
575 if attr_status == 1:
576 self.status = ifaceStatus.ERROR
577 elif self.status != ifaceStatus.ERROR:
578 # Not already error, mark success
579 self.status = ifaceStatus.SUCCESS
580
581 def check_n_update_config_with_status_many(self, ifaceobjorig, attr_names,
582 attr_status=0):
583 # set multiple attribute status to zero
584 # also updates status only if the attribute is present
585 for attr_name in attr_names:
586 if not ifaceobjorig.get_attr_value_first(attr_name):
587 continue
588 self.config.setdefault(attr_name, []).append('')
589 self._config_status.setdefault(attr_name, []).append(attr_status)
590
591 def get_config_attr_status(self, attr_name, idx=0):
592 """ get status of a attribute config on this interface.
593
594 Looks at the iface _config_status dict"""
595 return self._config_status.get(attr_name, [])[idx]
596
597 def compare(self, dstiface):
598 """ compares iface object with iface object passed as argument
599
600 Returns True if object self is same as dstiface and False otherwise """
601
602 if self.name != dstiface.name: return False
603 if self.type != dstiface.type: return False
604 if self.addr_family != dstiface.addr_family: return False
605 if self.addr_method != dstiface.addr_method: return False
606 if self.auto != dstiface.auto: return False
607 if self.classes != dstiface.classes: return False
608 if len(self.config) != len(dstiface.config):
609 return False
610 if any(True for k in self.config if k not in dstiface.config):
611 return False
612 if any(True for k,v in self.config.items()
613 if v != dstiface.config.get(k)): return False
614 return True
615
616 def squash(self, newifaceobj):
617 """ This squashes the iface object """
618 for attrname, attrlist in newifaceobj.config.iteritems():
619 # if allready present add it to the list
620 # else add it to the end of the dictionary
621 # We need to maintain order.
622 if self.config.get(attrname):
623 self.config[attrname].extend(attrlist)
624 else:
625 self.config.update([(attrname, attrlist)])
626 # we now support inet and inet6 together
627 self.addr_family.extend(newifaceobj.addr_family)
628 # if auto %ifacename is not part of the first stanza
629 # we need to squash it
630 if not self.auto and newifaceobj.auto:
631 self.auto = True
632
633 def __getstate__(self):
634 odict = self.__dict__.copy()
635 del odict['state']
636 del odict['status']
637 del odict['lowerifaces']
638 del odict['upperifaces']
639 del odict['refcnt']
640 del odict['_config_status']
641 del odict['flags']
642 del odict['priv_flags']
643 del odict['module_flags']
644 del odict['raw_config']
645 del odict['linkstate']
646 del odict['env']
647 del odict['link_type']
648 del odict['link_kind']
649 del odict['link_privflags']
650 del odict['role']
651 del odict['dependency_type']
652 del odict['blacklisted']
653 return odict
654
655 def __setstate__(self, dict):
656 self.__dict__.update(dict)
657 self._config_status = {}
658 self.state = ifaceState.NEW
659 self.status = ifaceStatus.UNKNOWN
660 self.refcnt = 0
661 self.flags = 0
662 self.lowerifaces = None
663 self.upperifaces = None
664 self.linkstate = None
665 self.env = None
666 self.role = ifaceRole.UNKNOWN
667 self.priv_flags = None
668 self.module_flags = {}
669 self.raw_config = []
670 self.flags |= self._PICKLED
671 self.link_type = ifaceLinkType.LINK_NA
672 self.link_kind = ifaceLinkKind.UNKNOWN
673 self.link_privflags = ifaceLinkPrivFlags.UNKNOWN
674 self.dependency_type = ifaceDependencyType.UNKNOWN
675 self.blacklisted = False
676
677 def dump_raw(self, logger):
678 indent = ' '
679 if self.auto:
680 print 'auto %s' %self.name
681 print (self.raw_config[0])
682 for i in range(1, len(self.raw_config)):
683 print(indent + self.raw_config[i])
684
685 def dump(self, logger):
686 indent = '\t'
687 logger.info(self.name + ' : {')
688 logger.info(indent + 'family: %s' % ' '.join(self.addr_family))
689 logger.info(indent + 'method: %s' %self.addr_method)
690 logger.info(indent + 'flags: %x' %self.flags)
691 logger.info(indent + 'state: %s'
692 %ifaceState.to_str(self.state))
693 logger.info(indent + 'status: %s'
694 %ifaceStatus.to_str(self.status))
695 logger.info(indent + 'refcnt: %d' %self.refcnt)
696 d = self.lowerifaces
697 if d:
698 logger.info(indent + 'lowerdevs: %s' %str(d))
699 else:
700 logger.info(indent + 'lowerdevs: None')
701
702 d = self.upperifaces
703 if d:
704 logger.info(indent + 'upperdevs: %s' %str(d))
705 else:
706 logger.info(indent + 'upperdevs: None')
707
708 logger.info(indent + 'config: ')
709 config = self.config
710 if config:
711 logger.info(indent + indent + str(config))
712 logger.info('}')
713
714 def _dump_pretty(self, family, first, addr_method, with_status=False, use_realname=False):
715 indent = '\t'
716 outbuf = ''
717 if use_realname and self.realname:
718 name = '%s' %self.realname
719 else:
720 name = '%s' %self.name
721 if self.auto:
722 outbuf += 'auto %s\n' %name
723 ifaceline = ''
724 if self.type == ifaceType.BRIDGE_VLAN:
725 ifaceline += 'vlan %s' %name
726 else:
727 ifaceline += 'iface %s' %name
728 if family:
729 ifaceline += ' %s' % family
730 if addr_method:
731 ifaceline += ' %s' % addr_method
732 if with_status:
733 status_str = None
734 if (self.status == ifaceStatus.ERROR or
735 self.status == ifaceStatus.NOTFOUND):
736 if self.status_str:
737 ifaceline += ' (%s)' %self.status_str
738 status_str = '[%s]' %ifaceStatusUserStrs.ERROR
739 elif self.status == ifaceStatus.SUCCESS:
740 status_str = '[%s]' %ifaceStatusUserStrs.SUCCESS
741 if status_str:
742 outbuf += '{0:65} {1:>8}'.format(ifaceline, status_str) + '\n'
743 else:
744 outbuf += ifaceline + '\n'
745 if self.status == ifaceStatus.NOTFOUND:
746 outbuf = (outbuf.encode('utf8')
747 if isinstance(outbuf, unicode) else outbuf)
748 print outbuf + '\n'
749 return
750 else:
751 outbuf += ifaceline + '\n'
752 config = self.config
753 if config and first:
754 for cname, cvaluelist in config.items():
755 idx = 0
756 for cv in cvaluelist:
757 status_str = None
758 if with_status:
759 s = self.get_config_attr_status(cname, idx)
760 if s == -1:
761 status_str = '[%s]' %ifaceStatusUserStrs.UNKNOWN
762 elif s == 1:
763 status_str = '[%s]' %ifaceStatusUserStrs.ERROR
764 elif s == 0:
765 status_str = '[%s]' %ifaceStatusUserStrs.SUCCESS
766 if status_str:
767 outbuf += (indent + '{0:55} {1:>10}'.format(
768 '%s %s' %(cname, cv), status_str)) + '\n'
769 else:
770 outbuf += indent + '%s %s\n' %(cname, cv)
771 idx += 1
772 if with_status:
773 outbuf = (outbuf.encode('utf8')
774 if isinstance(outbuf, unicode) else outbuf)
775 print outbuf
776
777 def dump_pretty(self, with_status=False, use_realname=False):
778 if not self.addr_family:
779 self._dump_pretty(None, True,
780 self.addr_method,
781 with_status=with_status,
782 use_realname=use_realname)
783 else:
784 # To allow both inet and inet6 on an interface we changed the
785 # addr_family attribute, it's now a list. Depending on how
786 # stanzas were squashed (and what command was used ie. ifquery -r)
787 # we want to dump the ifaceobj as usual but we will output an
788 # empty stanza for each additional addr_family. The config will
789 # only be displayed once, in the first stanza. Example:
790 # $ ifquery eth0 -r
791 # auto etho
792 # iface eth0 inet dhcp
793 # config...
794 #
795 # auto eth0
796 # iface eth0 inet6 dhcp
797 # $
798 first = True
799 for family in self.addr_family:
800 addr_method = self.addr_method
801 # We need to make sure we display 'dhcp' for inet family.
802 # In some cases it might take the value 'dhcp6' even if it has
803 # both inet and inet6 addr_family
804 if addr_method and family == 'inet' and 'dhcp' in addr_method:
805 addr_method = 'dhcp'
806 self._dump_pretty(family, first,
807 addr_method=addr_method,
808 with_status=with_status,
809 use_realname=use_realname)
810 first = False