]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown/ifupdownmain.py
addons: bridge: disabling ipv6 on bridge if any VXLAN port
[mirror_ifupdown2.git] / ifupdown / ifupdownmain.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6 # ifupdownMain --
7 # ifupdown main module
8 #
9
10 import os
11 import re
12 import imp
13 import pprint
14 import logging
15 import sys, traceback
16 import copy
17 import json
18 import ifupdown.statemanager as statemanager
19 import ifupdown.ifupdownconfig as ifupdownConfig
20 import ifupdown.ifupdownflags as ifupdownflags
21 from networkinterfaces import *
22 from iface import *
23 from scheduler import *
24 from collections import deque
25 from collections import OrderedDict
26 from graph import *
27 from sets import Set
28
29 """
30 .. module:: ifupdownmain
31 :synopsis: main module for ifupdown package
32
33 .. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
34
35 """
36
37 _tickmark = u'\u2713'
38 _crossmark = u'\u2717'
39 _success_sym = '(%s)' %_tickmark
40 _error_sym = '(%s)' %_crossmark
41
42 class ifupdownMainFlags():
43 WITH_DEPENDS = False
44 ALL = False
45 IFACE_CLASS = False
46 COMPAT_EXEC_SCRIPTS = False
47 STATEMANAGER_ENABLE = True
48 STATEMANAGER_UPDATE = True
49 ADDONS_ENABLE = False
50 DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
51 SCHED_SKIP_CHECK_UPPERIFACES = False
52 CHECK_SHARED_DEPENDENTS = True
53
54 class ifacePrivFlags():
55 # priv flags to mark iface objects
56 BUILTIN = False
57 NOCONFIG = False
58
59 def __init__(self, builtin=False, noconfig=False):
60 self.BUILTIN = builtin
61 self.NOCONFIG = noconfig
62
63 class ifupdownMain(ifupdownBase):
64 """ ifupdown2 main class """
65
66 scripts_dir='/etc/network'
67 addon_modules_dir='/usr/share/ifupdown2/addons'
68 addon_modules_configfile='/etc/network/ifupdown2/addons.conf'
69
70 # iface dictionary in the below format:
71 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
72 # eg:
73 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
74 #
75 # Each ifaceobject corresponds to a configuration block for
76 # that interface
77 # The value in the dictionary is a list because the network
78 # interface configuration file supports more than one iface section
79 # in the interfaces file
80 ifaceobjdict = OrderedDict()
81
82 # iface dictionary representing the curr running state of an iface
83 # in the below format:
84 # {'<ifacename>' : <ifaceobject>}
85 ifaceobjcurrdict = OrderedDict()
86
87 # Dictionary representing operation and modules
88 # for every operation
89 module_ops = OrderedDict([('pre-up', []),
90 ('up' , []),
91 ('post-up' , []),
92 ('query-checkcurr', []),
93 ('query-running', []),
94 ('query-dependency', []),
95 ('query', []),
96 ('query-raw', []),
97 ('pre-down', []),
98 ('down' , []),
99 ('post-down' , [])])
100
101 # For old style /etc/network/ bash scripts
102 script_ops = OrderedDict([('pre-up', []),
103 ('up' , []),
104 ('post-up' , []),
105 ('pre-down', []),
106 ('down' , []),
107 ('post-down' , [])])
108
109 # Handlers for ops that ifupdown2 owns
110 def run_up(self, ifaceobj):
111 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
112 # there is no real interface behind it
113 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
114 return
115 if ifaceobj.link_kind & ifaceLinkKind.VRF:
116 return
117 if (ifaceobj.addr_method and
118 ifaceobj.addr_method == 'manual'):
119 return
120 if self._delay_admin_state:
121 self._delay_admin_state_iface_queue.append(ifaceobj.name)
122 return
123 # If this object is a link slave, ie its link is controlled
124 # by its link master interface, then dont set the link state.
125 # But do allow user to change state of the link if the interface
126 # is already with its link master (hence the master check).
127 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
128 return
129 if not self.link_exists(ifaceobj.name):
130 return
131 self.link_up(ifaceobj.name)
132
133 def run_down(self, ifaceobj):
134 if ifaceobj.link_kind & ifaceLinkKind.VRF:
135 return
136 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
137 # there is no real interface behind it
138 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
139 return
140 if (ifaceobj.addr_method and
141 ifaceobj.addr_method == 'manual'):
142 return
143 if self._delay_admin_state:
144 self._delay_admin_state_iface_queue.append(ifaceobj.name)
145 return
146 # If this object is a link slave, ie its link is controlled
147 # by its link master interface, then dont set the link state.
148 # But do allow user to change state of the link if the interface
149 # is already with its link master (hence the master check).
150 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
151 return
152 if not self.link_exists(ifaceobj.name):
153 return
154 self.link_down(ifaceobj.name)
155
156 # ifupdown object interface operation handlers
157 ops_handlers = OrderedDict([('up', run_up),
158 ('down', run_down)])
159
160 def run_sched_ifaceobj_posthook(self, ifaceobj, op):
161 if (ifaceobj.priv_flags and (ifaceobj.priv_flags.BUILTIN or
162 ifaceobj.priv_flags.NOCONFIG)):
163 return
164 if self.flags.STATEMANAGER_UPDATE:
165 self.statemanager.ifaceobj_sync(ifaceobj, op)
166
167 # ifupdown object interface scheduler pre and posthooks
168 sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
169
170 def __init__(self, config={},
171 force=False, dryrun=False, nowait=False,
172 perfmode=False, withdepends=False, njobs=1,
173 cache=False, addons_enable=True, statemanager_enable=True,
174 interfacesfile='/etc/network/interfaces',
175 interfacesfileiobuf=None,
176 interfacesfileformat='native',
177 withdefaults=False):
178 """This member function initializes the ifupdownmain object.
179
180 Kwargs:
181 config (dict): config dict from /etc/network/ifupdown2/ifupdown2.conf
182 force (bool): force interface configuration
183 dryrun (bool): dryrun interface configuration
184 withdepends (bool): apply interface configuration on all depends
185 interfacesfile (str): interfaces file. default is /etc/network/interfaces
186 interfacesfileformat (str): default is 'native'. Other choices are 'json'
187
188 Raises:
189 AttributeError, KeyError """
190
191 self.logger = logging.getLogger('ifupdown')
192 ifupdownflags.flags.FORCE = force
193 ifupdownflags.flags.DRYRUN = dryrun
194 ifupdownflags.flags.WITHDEFAULTS = withdefaults
195 ifupdownflags.flags.NOWAIT = nowait
196 ifupdownflags.flags.PERFMODE = perfmode
197 ifupdownflags.flags.CACHE = cache
198
199 # Can be used to provide hints for caching
200 ifupdownflags.flags.CACHE_FLAGS = 0x0
201
202 self.flags = ifupdownMainFlags()
203
204 self.flags.WITH_DEPENDS = withdepends
205 self.flags.STATEMANAGER_ENABLE = statemanager_enable
206 self.interfacesfile = interfacesfile
207 self.interfacesfileiobuf = interfacesfileiobuf
208 self.interfacesfileformat = interfacesfileformat
209 self.config = config
210 self.logger.debug(self.config)
211 self.blacklisted_ifaces_present = False
212
213 self.type = ifaceType.UNKNOWN
214
215 self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
216 self.flags.ADDONS_ENABLE = addons_enable
217
218 self.ifaces = OrderedDict()
219 self.njobs = njobs
220 self.pp = pprint.PrettyPrinter(indent=4)
221 self.modules = OrderedDict({})
222 self.module_attrs = {}
223
224 self.load_addon_modules(self.addon_modules_dir)
225 if self.flags.COMPAT_EXEC_SCRIPTS:
226 self.load_scripts(self.scripts_dir)
227 self.dependency_graph = OrderedDict({})
228
229 self._cache_no_repeats = {}
230
231 if self.flags.STATEMANAGER_ENABLE:
232 try:
233 self.statemanager = statemanager.statemanager_api
234 self.statemanager.read_saved_state()
235 except Exception, e:
236 # XXX Maybe we should continue by ignoring old state
237 self.logger.warning('error reading state (%s)' %str(e))
238 raise
239 else:
240 self.flags.STATEMANAGER_UPDATE = False
241 self._delay_admin_state = True if self.config.get(
242 'delay_admin_state_change', '0') == '1' else False
243 self._delay_admin_state_iface_queue = []
244 if self._delay_admin_state:
245 self.logger.info('\'delay_admin_state_change\' is set. admin ' +
246 'state changes will be delayed till the end.')
247
248 self._link_master_slave = True if self.config.get(
249 'link_master_slave', '0') == '1' else False
250 if self._link_master_slave:
251 self.logger.info('\'link_master_slave\' is set. slave admin ' +
252 'state changes will be delayed till the ' +
253 'masters admin state change.')
254
255 # squash iface objects for same interface both internal and
256 # external representation. It is off by default.
257 self._ifaceobj_squash = True if self.config.get(
258 'ifaceobj_squash', '0') == '1' else False
259
260 # squash iface objects for same interface internal
261 # representation only. External representation as seen by ifquery
262 # will continue to see multiple iface stanzas if it was specified
263 # that way by the user. It is on by default.
264 self._ifaceobj_squash_internal = True if self.config.get(
265 'ifaceobj_squash_internal', '1') == '1' else False
266
267 # initialize global config object with config passed by the user
268 # This makes config available to addon modules
269 ifupdownConfig.config = self.config
270
271 def link_master_slave_ignore_error(self, errorstr):
272 # If link master slave flag is set,
273 # there may be cases where the lowerdev may not be
274 # up resulting in 'Network is down' error
275 # This can happen if the lowerdev is a LINK_SLAVE
276 # of another interface which is not up yet
277 # example of such a case:
278 # bringing up a vlan on a bond interface and the bond
279 # is a LINK_SLAVE of a bridge (in other words the bond is
280 # part of a bridge) which is not up yet
281 if self._link_master_slave:
282 if 'Network is down':
283 return True
284 return False
285
286 def get_ifaceobjs(self, ifacename):
287 return self.ifaceobjdict.get(ifacename)
288
289 def get_ifaceobjs_saved(self, ifacename):
290 """ Return ifaceobjects from statemanager """
291 if self.flags.STATEMANAGER_ENABLE:
292 return self.statemanager.get_ifaceobjs(ifacename)
293 else:
294 None
295
296 def get_ifaceobj_first(self, ifacename):
297 ifaceobjs = self.get_ifaceobjs(ifacename)
298 if ifaceobjs:
299 return ifaceobjs[0]
300 return None
301
302 def get_ifacenames(self):
303 return self.ifaceobjdict.keys()
304
305 def get_iface_obj_last(self, ifacename):
306 return self.ifaceobjdict.get(ifacename)[-1]
307
308
309 def must_follow_upperifaces(self, ifacename):
310 #
311 # XXX: This bleeds the knowledge of iface
312 # types in the infrastructure module.
313 # Cant think of a better fix at the moment.
314 # In future maybe the module can set a flag
315 # to indicate if we should follow upperifaces
316 #
317 ifaceobj = self.get_ifaceobj_first(ifacename)
318 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
319 return False
320 return True
321
322 def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
323 increfcnt=False):
324 """ creates a iface object and adds it to the iface dictionary """
325 ifaceobj = iface()
326 ifaceobj.name = ifacename
327 ifaceobj.priv_flags = priv_flags
328 ifaceobj.auto = True
329 if not self._link_master_slave:
330 ifaceobj.link_type = ifaceLinkType.LINK_NA
331 if increfcnt:
332 ifaceobj.inc_refcnt()
333 self.ifaceobjdict[ifacename] = [ifaceobj]
334 return ifaceobj
335
336 def create_n_save_ifaceobjcurr(self, ifaceobj):
337 """ creates a copy of iface object and adds it to the iface
338 dict containing current iface objects
339 """
340 ifaceobjcurr = iface()
341 ifaceobjcurr.name = ifaceobj.name
342 ifaceobjcurr.type = ifaceobj.type
343 ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
344 ifaceobjcurr.priv_flags = copy.deepcopy(ifaceobj.priv_flags)
345 ifaceobjcurr.auto = ifaceobj.auto
346 self.ifaceobjcurrdict.setdefault(ifaceobj.name,
347 []).append(ifaceobjcurr)
348 return ifaceobjcurr
349
350 def get_ifaceobjcurr(self, ifacename, idx=0):
351 ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
352 if not ifaceobjlist:
353 return None
354 if not idx:
355 return ifaceobjlist
356 else:
357 return ifaceobjlist[idx]
358
359 def get_ifaceobjrunning(self, ifacename):
360 return self.ifaceobjrunningdict.get(ifacename)
361
362 def get_iface_refcnt(self, ifacename):
363 """ Return iface ref count """
364 max = 0
365 ifaceobjs = self.get_ifaceobjs(ifacename)
366 if not ifaceobjs:
367 return 0
368 for i in ifaceobjs:
369 if i.refcnt > max:
370 max = i.refcnt
371 return max
372
373 def is_iface_builtin_byname(self, ifacename):
374 """ Returns true if iface name is a builtin interface.
375
376 A builtin interface is an interface which ifupdown understands.
377 The following are currently considered builtin ifaces:
378 - vlan interfaces in the format <ifacename>.<vlanid>
379 """
380 return '.' in ifacename
381
382 def is_ifaceobj_builtin(self, ifaceobj):
383 """ Returns true if iface name is a builtin interface.
384
385 A builtin interface is an interface which ifupdown understands.
386 The following are currently considered builtin ifaces:
387 - vlan interfaces in the format <ifacename>.<vlanid>
388 """
389
390 return (ifaceobj.priv_flags and ifaceobj.priv_flags.BUILTIN)
391
392 def is_ifaceobj_noconfig(self, ifaceobj):
393 """ Returns true if iface object did not have a user defined config.
394
395 These interfaces appear only when they are dependents of interfaces
396 which have user defined config
397 """
398 return (ifaceobj.priv_flags and ifaceobj.priv_flags.NOCONFIG)
399
400 def is_iface_noconfig(self, ifacename):
401 """ Returns true if iface has no config """
402
403 ifaceobj = self.get_ifaceobj_first(ifacename)
404 if not ifaceobj: return True
405 return self.is_ifaceobj_noconfig(ifaceobj)
406
407 def check_shared_dependents(self, ifaceobj, dlist):
408 """ ABSOLETE: Check if dlist intersects with any other
409 interface with slave dependents.
410 example: bond and bridges.
411 This function logs such errors """
412 setdlist = Set(dlist)
413 for ifacename, ifacedlist in self.dependency_graph.items():
414 if not ifacedlist:
415 continue
416 check_depends = False
417 iobjs = self.get_ifaceobjs(ifacename)
418 if not iobjs:
419 continue
420 for i in iobjs:
421 if (i.dependency_type == ifaceDependencyType.MASTER_SLAVE):
422 check_depends = True
423 if check_depends:
424 common = Set(ifacedlist).intersection(setdlist)
425 if common:
426 self.logger.error('misconfig..?. iface %s and %s '
427 %(ifaceobj.name, ifacename) +
428 'seem to share dependents/ports %s' %str(list(common)))
429
430 def _set_iface_role(self, ifaceobj, role, upperifaceobj):
431 if (self.flags.CHECK_SHARED_DEPENDENTS and
432 (ifaceobj.role & ifaceRole.SLAVE) and
433 (role == ifaceRole.SLAVE) and (upperifaceobj.role == ifaceRole.MASTER)):
434 self.logger.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
435 %(ifaceobj.name,
436 ifaceLinkPrivFlags.get_all_str(ifaceobj.link_privflags), str(ifaceobj.upperifaces)))
437 ifaceobj.set_status(ifaceStatus.ERROR)
438 return
439 ifaceobj.role = role
440
441 def _set_iface_role_n_kind(self, ifaceobj, upperifaceobj):
442
443 if (upperifaceobj.link_kind & ifaceLinkKind.BOND):
444 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
445 ifaceobj.link_privflags |= ifaceLinkPrivFlags.BOND_SLAVE
446
447 if (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
448 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
449 ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_PORT
450
451 if (ifaceobj.link_kind & ifaceLinkKind.VXLAN) \
452 and (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
453 upperifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
454
455 # vrf masters get processed after slaves, which means
456 # check both link_kind vrf and vrf slave
457 if ((upperifaceobj.link_kind & ifaceLinkKind.VRF) or
458 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
459 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
460 ifaceobj.link_privflags |= ifaceLinkPrivFlags.VRF_SLAVE
461 if self._link_master_slave:
462 if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
463 ifaceobj.link_type = ifaceLinkType.LINK_SLAVE
464 else:
465 upperifaceobj.link_type = ifaceLinkType.LINK_NA
466 ifaceobj.link_type = ifaceLinkType.LINK_NA
467
468 def dump_iface_dependency_info(self):
469 """ debug funtion to print raw dependency
470 info - lower and upper devices"""
471
472 for ifacename, ifaceobjs in self.ifaceobjdict.iteritems():
473 iobj = ifaceobjs[0]
474 self.logger.info("%s: refcnt: %d, lower: %s, upper: %s" %(ifacename,
475 self.get_iface_refcnt(ifacename),
476 str(iobj.lowerifaces) if iobj.lowerifaces else [],
477 str(iobj.upperifaces) if iobj.upperifaces else []))
478
479
480 def preprocess_dependency_list(self, upperifaceobj, dlist, ops):
481 """ We go through the dependency list and
482 delete or add interfaces from the interfaces dict by
483 applying the following rules:
484 if flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
485 we only consider devices whose configuration was
486 specified in the network interfaces file. We delete
487 any interface whose config was not specified except
488 for vlan devices. vlan devices get special treatment.
489 Even if they are not present they are created and added
490 to the ifacesdict
491 elif flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
492 we create objects for all dependent devices that are not
493 present in the ifacesdict
494 """
495 del_list = []
496
497 for d in dlist:
498 dilist = self.get_ifaceobjs(d)
499 if not dilist:
500 ni = None
501 if self.is_iface_builtin_byname(d):
502 ni = self.create_n_save_ifaceobj(d,
503 ifacePrivFlags(True, True), True)
504 elif not self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
505 ni = self.create_n_save_ifaceobj(d,
506 ifacePrivFlags(False, True), True)
507 else:
508 del_list.append(d)
509 if ni:
510 ni.add_to_upperifaces(upperifaceobj.name)
511 self._set_iface_role_n_kind(ni, upperifaceobj)
512 else:
513 for di in dilist:
514 di.inc_refcnt()
515 di.add_to_upperifaces(upperifaceobj.name)
516 self._set_iface_role_n_kind(di, upperifaceobj)
517 for d in del_list:
518 dlist.remove(d)
519
520 def preprocess_upperiface(self, lowerifaceobj, ulist, ops):
521 for u in ulist:
522 if (lowerifaceobj.upperifaces and
523 u in lowerifaceobj.upperifaces):
524 continue
525 lowerifaceobj.add_to_upperifaces(u)
526 uifacelist = self.get_ifaceobjs(u)
527 if uifacelist:
528 for ui in uifacelist:
529 lowerifaceobj.inc_refcnt()
530 self._set_iface_role_n_kind(lowerifaceobj, ui)
531 ui.add_to_lowerifaces(lowerifaceobj.name)
532
533 def query_lowerifaces(self, ifaceobj, ops, ifacenames, type=None):
534 """ Gets iface dependents by calling into respective modules """
535 ret_dlist = []
536
537 # Get dependents for interface by querying respective modules
538 for module in self.modules.values():
539 try:
540 if ops[0] == 'query-running':
541 if (not hasattr(module,
542 'get_dependent_ifacenames_running')):
543 continue
544 dlist = module.get_dependent_ifacenames_running(ifaceobj)
545 else:
546 if (not hasattr(module, 'get_dependent_ifacenames')):
547 continue
548 dlist = module.get_dependent_ifacenames(ifaceobj,
549 ifacenames)
550 except Exception, e:
551 self.logger.warn('%s: error getting dependent interfaces (%s)'
552 %(ifaceobj.name, str(e)))
553 dlist = None
554 pass
555 if dlist: ret_dlist.extend(dlist)
556 return list(set(ret_dlist))
557
558 def query_upperifaces(self, ifaceobj, ops, ifacenames, type=None):
559 """ Gets iface upperifaces by calling into respective modules """
560 ret_ulist = []
561
562 # Get upperifaces for interface by querying respective modules
563 for module in self.modules.values():
564 try:
565 if ops[0] == 'query-running':
566 if (not hasattr(module,
567 'get_upper_ifacenames_running')):
568 continue
569 ulist = module.get_upper_ifacenames_running(ifaceobj)
570 else:
571 if (not hasattr(module, 'get_upper_ifacenames')):
572 continue
573 ulist = module.get_upper_ifacenames(ifaceobj, ifacenames)
574 except Exception, e:
575 self.logger.warn('%s: error getting upper interfaces (%s)'
576 %(ifaceobj.name, str(e)))
577 ulist = None
578 pass
579 if ulist: ret_ulist.extend(ulist)
580 return list(set(ret_ulist))
581
582 def populate_dependency_info(self, ops, ifacenames=None):
583 """ recursive function to generate iface dependency info """
584
585 if not ifacenames:
586 ifacenames = self.ifaceobjdict.keys()
587
588 iqueue = deque(ifacenames)
589 while iqueue:
590 i = iqueue.popleft()
591 # Go through all modules and find dependent ifaces
592 dlist = None
593 ulist = None
594 ifaceobjs = self.get_ifaceobjs(i)
595 if not ifaceobjs:
596 continue
597 dependents_processed = False
598
599 # Store all dependency info in the first ifaceobj
600 # but get dependency info from all ifaceobjs
601 ifaceobj = ifaceobjs[0]
602 for iobj in ifaceobjs:
603 ulist = self.query_upperifaces(iobj, ops, ifacenames)
604 if iobj.lowerifaces:
605 dependents_processed = True
606 break
607 dlist = self.query_lowerifaces(iobj, ops, ifacenames)
608 if dlist:
609 break
610 if ulist:
611 self.preprocess_upperiface(ifaceobj, ulist, ops)
612 if dependents_processed:
613 continue
614 if dlist:
615 self.preprocess_dependency_list(ifaceobj,
616 dlist, ops)
617 ifaceobj.lowerifaces = dlist
618 [iqueue.append(d) for d in dlist]
619 #if not self.dependency_graph.get(i):
620 # self.dependency_graph[i] = dlist
621
622 for i in self.ifaceobjdict.keys():
623 iobj = self.get_ifaceobj_first(i)
624 if iobj.lowerifaces:
625 self.dependency_graph[i] = iobj.lowerifaces
626 else:
627 self.dependency_graph[i] = []
628
629 if not self.blacklisted_ifaces_present:
630 return
631
632 # Walk through the dependency graph and remove blacklisted
633 # interfaces that were picked up as dependents
634 for i in self.dependency_graph.keys():
635 ifaceobj = self.get_ifaceobj_first(i)
636 if not ifaceobj:
637 continue
638
639 if ifaceobj.blacklisted and not ifaceobj.upperifaces:
640 # if blacklisted and was not picked up as a
641 # dependent of a upper interface, delete the
642 # interface from the dependency graph
643 dlist = ifaceobj.lowerifaces
644 if dlist:
645 for d in dlist:
646 difaceobjs = self.get_ifaceobjs(d)
647 if not difaceobjs:
648 continue
649 try:
650 for d in difaceobjs:
651 d.dec_refcnt()
652 d.upperifaces.remove(i)
653 except:
654 self.logger.debug('error removing %s from %s upperifaces' %(i, d))
655 pass
656 self.logger.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
657 del self.dependency_graph[i]
658 continue
659
660 def _check_config_no_repeats(self, ifaceobj):
661 """ check if object has an attribute that is
662 restricted to a single object in the system.
663 if yes, warn and return """
664 for k,v in self._cache_no_repeats.items():
665 iv = ifaceobj.config.get(k)
666 if iv and iv[0] == v:
667 self.logger.error('ignoring interface %s. ' %ifaceobj.name +
668 'Only one object with attribute ' +
669 '\'%s %s\' allowed.' %(k, v))
670 return True
671 for k, v in self.config.get('no_repeats', {}).items():
672 iv = ifaceobj.config.get(k)
673 if iv and iv[0] == v:
674 self._cache_no_repeats[k] = v
675 return False
676
677 def _save_iface_squash(self, ifaceobj):
678 """ squash ifaceobjects belonging to same iface
679 into a single object """
680 if self._check_config_no_repeats(ifaceobj):
681 return
682 ifaceobj.priv_flags = ifacePrivFlags()
683 if not self._link_master_slave:
684 ifaceobj.link_type = ifaceLinkType.LINK_NA
685 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
686 if not currentifaceobjlist:
687 self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
688 return
689 if ifaceobj.compare(currentifaceobjlist[0]):
690 self.logger.warn('duplicate interface %s found' %ifaceobj.name)
691 return
692 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
693 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
694 else:
695 currentifaceobjlist[0].squash(ifaceobj)
696
697 def _save_iface(self, ifaceobj):
698 if self._check_config_no_repeats(ifaceobj):
699 return
700 ifaceobj.priv_flags = ifacePrivFlags()
701 if not self._link_master_slave:
702 ifaceobj.link_type = ifaceLinkType.LINK_NA
703 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
704 if not currentifaceobjlist:
705 self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
706 if not self._ifaceobj_squash:
707 ifaceobj.flags |= ifaceobj.YOUNGEST_SIBLING
708 return
709 if ifaceobj.compare(currentifaceobjlist[0]):
710 self.logger.warn('duplicate interface %s found' %ifaceobj.name)
711 return
712 if currentifaceobjlist[0].type == ifaceobj.type:
713 currentifaceobjlist[0].flags |= ifaceobj.HAS_SIBLINGS
714 ifaceobj.flags |= ifaceobj.HAS_SIBLINGS
715 # clear the OLDEST_SIBLING from all the siblings
716 for iface in self.ifaceobjdict[ifaceobj.name]:
717 iface.flags &= ~ifaceobj.OLDEST_SIBLING
718 # current sibling is the oldest
719 ifaceobj.flags |= ifaceobj.OLDEST_SIBLING
720 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
721
722 def _iface_configattr_syntax_checker(self, attrname, attrval):
723 for m, mdict in self.module_attrs.items():
724 if not mdict:
725 continue
726 attrsdict = mdict.get('attrs')
727 try:
728 a = attrsdict.get(attrname)
729 if a:
730 if a.get('deprecated'):
731 newa = a.get('new-attribute')
732 if newa:
733 self.logger.warn('attribute %s is deprecated. Use %s instead' %(attrname, newa))
734 else:
735 self.logger.warn('attribute %s is deprecated'
736 %attrname)
737 return True
738 except AttributeError:
739 pass
740 return False
741
742 def _ifaceobj_syntax_checker(self, ifaceobj):
743 ret = True
744 for attrname, attrvalue in ifaceobj.config.items():
745 found = False
746 for k, v in self.module_attrs.items():
747 if v and v.get('attrs', {}).get(attrname):
748 found = True
749 break
750 if not found:
751 ret = False
752 self.logger.warn('%s: unsupported attribute \'%s\'' \
753 % (ifaceobj.name, attrname))
754 continue
755 return ret
756
757 def read_iface_config(self):
758 """ Reads default network interface config /etc/network/interfaces. """
759 ret = True
760 nifaces = networkInterfaces(self.interfacesfile,
761 self.interfacesfileiobuf,
762 self.interfacesfileformat,
763 template_engine=self.config.get('template_engine'),
764 template_lookuppath=self.config.get('template_lookuppath'))
765 if self._ifaceobj_squash or self._ifaceobj_squash_internal:
766 nifaces.subscribe('iface_found', self._save_iface_squash)
767 else:
768 nifaces.subscribe('iface_found', self._save_iface)
769 nifaces.subscribe('validateifaceattr',
770 self._iface_configattr_syntax_checker)
771 nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
772 nifaces.load()
773 if nifaces.errors or nifaces.warns:
774 ret = False
775 return ret
776
777 def read_old_iface_config(self):
778 """ Reads the saved iface config instead of default iface config.
779 And saved iface config is already read by the statemanager """
780 self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
781
782 def _load_addon_modules_config(self):
783 """ Load addon modules config file """
784
785 with open(self.addon_modules_configfile, 'r') as f:
786 lines = f.readlines()
787 for l in lines:
788 try:
789 litems = l.strip(' \n\t\r').split(',')
790 if not litems or len(litems) < 2:
791 continue
792 operation = litems[0]
793 mname = litems[1]
794 self.module_ops[operation].append(mname)
795 except Exception, e:
796 self.logger.warn('error reading line \'%s\'' %(l, str(e)))
797 continue
798
799 def load_addon_modules(self, modules_dir):
800 """ load python modules from modules_dir
801
802 Default modules_dir is /usr/share/ifupdownmodules
803
804 """
805 self.logger.info('loading builtin modules from %s' %modules_dir)
806 self._load_addon_modules_config()
807 if not modules_dir in sys.path:
808 sys.path.append(modules_dir)
809 try:
810 for op, mlist in self.module_ops.items():
811 for mname in mlist:
812 if self.modules.get(mname):
813 continue
814 mpath = modules_dir + '/' + mname + '.py'
815 if os.path.exists(mpath):
816 try:
817 m = __import__(mname)
818 mclass = getattr(m, mname)
819 except:
820 raise
821 minstance = mclass()
822 self.modules[mname] = minstance
823 try:
824 self.module_attrs[mname] = minstance.get_modinfo()
825 except:
826 pass
827 except:
828 raise
829
830 # Assign all modules to query operations
831 self.module_ops['query-checkcurr'] = self.modules.keys()
832 self.module_ops['query-running'] = self.modules.keys()
833 self.module_ops['query-dependency'] = self.modules.keys()
834 self.module_ops['query'] = self.modules.keys()
835 self.module_ops['query-raw'] = self.modules.keys()
836
837
838 def _modules_help(self):
839 """ Prints addon modules supported syntax """
840
841 indent = ' '
842 for m, mdict in self.module_attrs.items():
843 if not mdict:
844 continue
845 print('%s: %s' %(m, mdict.get('mhelp')))
846 attrdict = mdict.get('attrs')
847 if not attrdict:
848 continue
849 try:
850 for attrname, attrvaldict in attrdict.items():
851 if attrvaldict.get('compat', False):
852 continue
853 print('%s%s' %(indent, attrname))
854 print('%shelp: %s' %(indent + ' ',
855 attrvaldict.get('help', '')))
856 print ('%srequired: %s' %(indent + ' ',
857 attrvaldict.get('required', False)))
858 default = attrvaldict.get('default')
859 if default:
860 print('%sdefault: %s' %(indent + ' ', default))
861
862 validrange = attrvaldict.get('validrange')
863 if validrange:
864 print('%svalidrange: %s-%s'
865 %(indent + ' ', validrange[0], validrange[1]))
866
867 validvals = attrvaldict.get('validvals')
868 if validvals:
869 print('%svalidvals: %s'
870 %(indent + ' ', ','.join(validvals)))
871
872 examples = attrvaldict.get('example')
873 if not examples:
874 continue
875
876 print '%sexample:' %(indent + ' ')
877 for e in examples:
878 print '%s%s' %(indent + ' ', e)
879 except:
880 pass
881 print ''
882
883 def load_scripts(self, modules_dir):
884 """ loading user modules from /etc/network/.
885
886 Note that previously loaded python modules override modules found
887 under /etc/network if any
888
889 """
890
891 self.logger.info('looking for user scripts under %s' %modules_dir)
892 for op, mlist in self.script_ops.items():
893 msubdir = modules_dir + '/if-%s.d' %op
894 self.logger.info('loading scripts under %s ...' %msubdir)
895 try:
896 module_list = os.listdir(msubdir)
897 for module in module_list:
898 if self.modules.get(module) is not None:
899 continue
900 self.script_ops[op].append(
901 msubdir + '/' + module)
902 except:
903 # continue reading
904 pass
905
906 def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False,
907 followdependents=True, sort=False):
908 self.logger.debug('scheduling \'%s\' for %s'
909 %(str(ops), str(ifacenames)))
910 self._pretty_print_ordered_dict('dependency graph',
911 self.dependency_graph)
912 ifaceScheduler.sched_ifaces(self, ifacenames, ops,
913 dependency_graph=self.dependency_graph,
914 order=ifaceSchedulerFlags.INORDER
915 if 'down' in ops[0]
916 else ifaceSchedulerFlags.POSTORDER,
917 followdependents=followdependents,
918 skipupperifaces=skipupperifaces,
919 sort=True if (sort or self.flags.IFACE_CLASS) else False)
920 return ifaceScheduler.get_sched_status()
921
922 def _render_ifacename(self, ifacename):
923 new_ifacenames = []
924 vlan_match = re.match("^([\d]+)-([\d]+)", ifacename)
925 if vlan_match:
926 vlan_groups = vlan_match.groups()
927 if vlan_groups[0] and vlan_groups[1]:
928 [new_ifacenames.append('%d' %v)
929 for v in range(int(vlan_groups[0]),
930 int(vlan_groups[1])+1)]
931 return new_ifacenames
932
933 def _preprocess_ifacenames(self, ifacenames):
934 """ validates interface list for config existance.
935
936 returns -1 if one or more interface not found. else, returns 0
937
938 """
939 new_ifacenames = []
940 err_iface = ''
941 for i in ifacenames:
942 ifaceobjs = self.get_ifaceobjs(i)
943 if not ifaceobjs:
944 # if name not available, render interface name and check again
945 rendered_ifacenames = utils.expand_iface_range(i)
946 if rendered_ifacenames:
947 for ri in rendered_ifacenames:
948 ifaceobjs = self.get_ifaceobjs(ri)
949 if not ifaceobjs:
950 err_iface += ' ' + ri
951 else:
952 new_ifacenames.append(ri)
953 else:
954 err_iface += ' ' + i
955 else:
956 new_ifacenames.append(i)
957 if err_iface:
958 raise Exception('cannot find interfaces:%s' %err_iface)
959 return new_ifacenames
960
961 def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
962 """ Checks if interface is whitelisted depending on set of parameters.
963
964 interfaces are checked against the allow_classes and auto lists.
965
966 """
967
968 ret = True
969
970 # Check if interface matches the exclude patter
971 if excludepats:
972 for e in excludepats:
973 if re.search(e, ifacename):
974 ret = False
975 ifaceobjs = self.get_ifaceobjs(ifacename)
976 if not ifaceobjs:
977 if ret:
978 self.logger.debug('iface %s' %ifacename + ' not found')
979 return ret
980 # If matched exclude pattern, return false
981 if not ret:
982 for i in ifaceobjs:
983 i.blacklisted = True
984 self.blacklisted_ifaces_present = True
985 return ret
986 # Check if interface belongs to the class
987 # the user is interested in, if not return false
988 if allow_classes:
989 ret = False
990 for i in ifaceobjs:
991 if i.classes:
992 common = Set([allow_classes]).intersection(
993 Set(i.classes))
994 if common:
995 ret = True
996 if not ret:
997 # If a class was requested and interface does not belong
998 # to the class, only then mark the ifaceobjs as blacklisted
999 self.blacklisted_ifaces_present = True
1000 for i in ifaceobjs:
1001 i.blacklisted = True
1002 return ret
1003 # If the user has requested auto class, check if the interface
1004 # is marked auto
1005 if auto:
1006 ret = False
1007 for i in ifaceobjs:
1008 if i.auto:
1009 ret = True
1010 if not ret:
1011 # If auto was requested and interface was not marked auto,
1012 # only then mark all of them as blacklisted
1013 self.blacklisted_ifaces_present = True
1014 for i in ifaceobjs:
1015 i.blacklisted = True
1016 return ret
1017
1018 def _compat_conv_op_to_mode(self, op):
1019 """ Returns old op name to work with existing scripts """
1020 if op == 'pre-up':
1021 return 'start'
1022 elif op == 'pre-down':
1023 return 'stop'
1024 else:
1025 return op
1026
1027 def generate_running_env(self, ifaceobj, op):
1028 """ Generates a dictionary with env variables required for
1029 an interface. Used to support script execution for interfaces.
1030 """
1031
1032 cenv = None
1033 iface_env = ifaceobj.env
1034 if iface_env:
1035 cenv = os.environ
1036 if cenv:
1037 cenv.update(iface_env)
1038 else:
1039 cenv = iface_env
1040 cenv['MODE'] = self._compat_conv_op_to_mode(op)
1041 return cenv
1042
1043 def _save_state(self):
1044 if (not self.flags.STATEMANAGER_ENABLE or
1045 not self.flags.STATEMANAGER_UPDATE):
1046 return
1047 try:
1048 # Update persistant iface states
1049 self.statemanager.save_state()
1050 except Exception, e:
1051 if self.logger.isEnabledFor(logging.DEBUG):
1052 t = sys.exc_info()[2]
1053 traceback.print_tb(t)
1054 self.logger.warning('error saving state (%s)' %str(e))
1055
1056 def set_type(self, type):
1057 if type == 'iface':
1058 self.type = ifaceType.IFACE
1059 elif type == 'vlan':
1060 self.type = ifaceType.BRIDGE_VLAN
1061 else:
1062 self.type = ifaceType.UNKNOWN
1063
1064 def _process_delay_admin_state_queue(self, op):
1065 if not self._delay_admin_state_iface_queue:
1066 return
1067 if op == 'up':
1068 func = self.link_up
1069 elif op == 'down':
1070 func = self.link_down
1071 else:
1072 return
1073 for i in self._delay_admin_state_iface_queue:
1074 try:
1075 if self.link_exists(i):
1076 func(i)
1077 except Exception, e:
1078 self.logger.warn(str(e))
1079 pass
1080
1081 def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
1082 excludepats=None, printdependency=None, syntaxcheck=False,
1083 type=None, skipupperifaces=False):
1084 """This brings the interface(s) up
1085
1086 Args:
1087 ops (list): list of ops to perform on the interface(s).
1088 Eg: ['pre-up', 'up', 'post-up'
1089
1090 Kwargs:
1091 auto (bool): act on interfaces marked auto
1092 allow_classes (list): act on interfaces belonging to classes in the list
1093 ifacenames (list): act on interfaces specified in this list
1094 excludepats (list): list of patterns of interfaces to exclude
1095 syntaxcheck (bool): only perform syntax check
1096 """
1097
1098 self.set_type(type)
1099
1100 if allow_classes:
1101 self.flags.IFACE_CLASS = True
1102 if not self.flags.ADDONS_ENABLE:
1103 self.flags.STATEMANAGER_UPDATE = False
1104 if auto:
1105 self.flags.ALL = True
1106 self.flags.WITH_DEPENDS = True
1107 try:
1108 iface_read_ret = self.read_iface_config()
1109 except Exception:
1110 raise
1111
1112 if ifacenames:
1113 ifacenames = self._preprocess_ifacenames(ifacenames)
1114
1115 # if iface list not given by user, assume all from config file
1116 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1117
1118 # filter interfaces based on auto and allow classes
1119 filtered_ifacenames = [i for i in ifacenames
1120 if self._iface_whitelisted(auto, allow_classes,
1121 excludepats, i)]
1122 if not filtered_ifacenames:
1123 raise Exception('no ifaces found matching given allow lists')
1124
1125 if printdependency:
1126 self.populate_dependency_info(ops, filtered_ifacenames)
1127 self.print_dependency(filtered_ifacenames, printdependency)
1128 return
1129 else:
1130 self.populate_dependency_info(ops)
1131
1132 # If only syntax check was requested, return here.
1133 # return here because we want to make sure most
1134 # errors above are caught and reported.
1135 if syntaxcheck:
1136 if not iface_read_ret:
1137 raise Exception()
1138 return
1139
1140 try:
1141 ret = self._sched_ifaces(filtered_ifacenames, ops,
1142 skipupperifaces=skipupperifaces,
1143 followdependents=True
1144 if self.flags.WITH_DEPENDS else False)
1145 finally:
1146 self._process_delay_admin_state_queue('up')
1147 if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE:
1148 self._save_state()
1149
1150 if not iface_read_ret or not ret:
1151 raise Exception()
1152
1153 def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
1154 excludepats=None, printdependency=None, usecurrentconfig=False,
1155 type=None):
1156 """ down an interface """
1157
1158 self.set_type(type)
1159
1160 if allow_classes:
1161 self.flags.IFACE_CLASS = True
1162 if not self.flags.ADDONS_ENABLE:
1163 self.flags.STATEMANAGER_UPDATE = False
1164 if auto:
1165 self.flags.ALL = True
1166 self.flags.WITH_DEPENDS = True
1167 # For down we need to look at old state, unless usecurrentconfig
1168 # is set
1169 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE and
1170 self.statemanager.ifaceobjdict):
1171 # Since we are using state manager objects,
1172 # skip the updating of state manager objects
1173 self.logger.debug('Looking at old state ..')
1174 self.read_old_iface_config()
1175 else:
1176 # If no old state available
1177 try:
1178 self.read_iface_config()
1179 except Exception, e:
1180 raise Exception('error reading iface config (%s)' %str(e))
1181 if ifacenames:
1182 # If iface list is given by the caller, always check if iface
1183 # is present
1184 try:
1185 ifacenames = self._preprocess_ifacenames(ifacenames)
1186 except Exception, e:
1187 raise Exception('%s' %str(e) +
1188 ' (interface was probably never up ?)')
1189
1190 # if iface list not given by user, assume all from config file
1191 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1192
1193 # filter interfaces based on auto and allow classes
1194 filtered_ifacenames = [i for i in ifacenames
1195 if self._iface_whitelisted(auto, allow_classes,
1196 excludepats, i)]
1197 if not filtered_ifacenames:
1198 raise Exception('no ifaces found matching given allow lists ' +
1199 '(or interfaces were probably never up ?)')
1200
1201 if printdependency:
1202 self.populate_dependency_info(ops, filtered_ifacenames)
1203 self.print_dependency(filtered_ifacenames, printdependency)
1204 return
1205 else:
1206 self.populate_dependency_info(ops)
1207
1208 try:
1209 self._sched_ifaces(filtered_ifacenames, ops,
1210 followdependents=True
1211 if self.flags.WITH_DEPENDS else False)
1212 finally:
1213 self._process_delay_admin_state_queue('down')
1214 if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE:
1215 self._save_state()
1216
1217 def query(self, ops, auto=False, format_list=False, allow_classes=None,
1218 ifacenames=None,
1219 excludepats=None, printdependency=None,
1220 format='native', type=None):
1221 """ query an interface """
1222
1223 self.set_type(type)
1224
1225 # Let us forget internal squashing when it comes to
1226 # ifquery. It can surprise people relying of ifquery
1227 # output
1228 self._ifaceobj_squash_internal = False
1229
1230 if allow_classes:
1231 self.flags.IFACE_CLASS = True
1232 if self.flags.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
1233 return self.statemanager.dump_pretty(ifacenames)
1234 self.flags.STATEMANAGER_UPDATE = False
1235 if auto:
1236 self.logger.debug('setting flag ALL')
1237 self.flags.ALL = True
1238 self.flags.WITH_DEPENDS = True
1239
1240 if ops[0] == 'query-syntax':
1241 self._modules_help()
1242 return
1243 elif ops[0] == 'query-running':
1244 # create fake devices to all dependents that dont have config
1245 map(lambda i: self.create_n_save_ifaceobj(i,
1246 ifacePrivFlags(False, True)), ifacenames)
1247 else:
1248 try:
1249 self.read_iface_config()
1250 except Exception:
1251 raise
1252
1253 if ifacenames and ops[0] != 'query-running':
1254 # If iface list is given, always check if iface is present
1255 ifacenames = self._preprocess_ifacenames(ifacenames)
1256
1257 # if iface list not given by user, assume all from config file
1258 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1259
1260 # filter interfaces based on auto and allow classes
1261 if ops[0] == 'query-running':
1262 filtered_ifacenames = ifacenames
1263 else:
1264 filtered_ifacenames = [i for i in ifacenames
1265 if self._iface_whitelisted(auto, allow_classes,
1266 excludepats, i)]
1267 if not filtered_ifacenames:
1268 raise Exception('no ifaces found matching ' +
1269 'given allow lists')
1270
1271 self.populate_dependency_info(ops)
1272 if ops[0] == 'query-dependency' and printdependency:
1273 self.print_dependency(filtered_ifacenames, printdependency)
1274 return
1275
1276 if format_list and (ops[0] == 'query' or ops[0] == 'query-raw'):
1277 return self.print_ifaceobjs_list(filtered_ifacenames)
1278
1279 if ops[0] == 'query':
1280 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
1281 elif ops[0] == 'query-raw':
1282 return self.print_ifaceobjs_raw(filtered_ifacenames)
1283
1284 ret = self._sched_ifaces(filtered_ifacenames, ops,
1285 followdependents=True
1286 if self.flags.WITH_DEPENDS else False)
1287
1288 if ops[0] == 'query-checkcurr':
1289 ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
1290 if ret != 0:
1291 # if any of the object has an error, signal that silently
1292 raise Exception('')
1293 elif ops[0] == 'query-running':
1294 self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
1295 return
1296
1297 def _reload_currentlyup(self, upops, downops, auto=True, allow=None,
1298 ifacenames=None, excludepats=None, usecurrentconfig=False,
1299 syntaxcheck=False, **extra_args):
1300 """ reload currently up interfaces """
1301 new_ifaceobjdict = {}
1302
1303 # Override auto to true
1304 auto = True
1305 try:
1306 iface_read_ret = self.read_iface_config()
1307 except:
1308 raise
1309 if not self.ifaceobjdict:
1310 self.logger.warn("nothing to reload ..exiting.")
1311 return
1312 already_up_ifacenames = []
1313 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1314 filtered_ifacenames = [i for i in ifacenames
1315 if self._iface_whitelisted(auto, allow,
1316 excludepats, i)]
1317
1318 # generate dependency graph of interfaces
1319 self.populate_dependency_info(upops)
1320
1321 # If only syntax check was requested, return here.
1322 # return here because we want to make sure most
1323 # errors above are caught and reported.
1324 if syntaxcheck:
1325 if not iface_read_ret:
1326 raise Exception()
1327 return
1328
1329 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
1330 and self.statemanager.ifaceobjdict):
1331 already_up_ifacenames = self.statemanager.ifaceobjdict.keys()
1332
1333 # Get already up interfaces that still exist in the interfaces file
1334 already_up_ifacenames_not_present = Set(
1335 already_up_ifacenames).difference(ifacenames)
1336 already_up_ifacenames_still_present = Set(
1337 already_up_ifacenames).difference(
1338 already_up_ifacenames_not_present)
1339 interfaces_to_up = Set(already_up_ifacenames_still_present).union(
1340 filtered_ifacenames)
1341
1342 if (already_up_ifacenames_not_present and
1343 self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
1344 self.logger.info('reload: schedule down on interfaces: %s'
1345 %str(already_up_ifacenames_not_present))
1346
1347 # Save a copy of new iface objects and dependency_graph
1348 new_ifaceobjdict = dict(self.ifaceobjdict)
1349 new_dependency_graph = dict(self.dependency_graph)
1350
1351 # old interface config is read into self.ifaceobjdict
1352 self.read_old_iface_config()
1353
1354 # reinitialize dependency graph
1355 self.dependency_graph = OrderedDict({})
1356 falready_up_ifacenames_not_present = [i for i in
1357 already_up_ifacenames_not_present
1358 if self._iface_whitelisted(auto, allow,
1359 excludepats, i)]
1360 self.populate_dependency_info(downops,
1361 falready_up_ifacenames_not_present)
1362 self._sched_ifaces(falready_up_ifacenames_not_present, downops,
1363 followdependents=False, sort=True)
1364 else:
1365 self.logger.debug('no interfaces to down ..')
1366
1367 # Now, run 'up' with new config dict
1368 # reset statemanager update flag to default
1369 if auto:
1370 self.flags.ALL = True
1371 self.flags.WITH_DEPENDS = True
1372 if new_ifaceobjdict:
1373 # and now, ifaceobjdict is back to current config
1374 self.ifaceobjdict = new_ifaceobjdict
1375 self.dependency_graph = new_dependency_graph
1376
1377 if not self.ifaceobjdict:
1378 return
1379 self.logger.info('reload: scheduling up on interfaces: %s'
1380 %str(interfaces_to_up))
1381 ret = self._sched_ifaces(interfaces_to_up, upops,
1382 followdependents=True
1383 if self.flags.WITH_DEPENDS else False)
1384 if ifupdownflags.flags.DRYRUN:
1385 return
1386 self._save_state()
1387
1388 if not iface_read_ret or not ret:
1389 raise Exception()
1390
1391 def _reload_default(self, upops, downops, auto=False, allow=None,
1392 ifacenames=None, excludepats=None, usecurrentconfig=False,
1393 syntaxcheck=False, **extra_args):
1394 """ reload interface config """
1395 new_ifaceobjdict = {}
1396
1397 try:
1398 iface_read_ret = self.read_iface_config()
1399 except:
1400 raise
1401
1402 if not self.ifaceobjdict:
1403 self.logger.warn("nothing to reload ..exiting.")
1404 return
1405
1406 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1407 new_filtered_ifacenames = [i for i in ifacenames
1408 if self._iface_whitelisted(auto, allow,
1409 excludepats, i)]
1410 # generate dependency graph of interfaces
1411 self.populate_dependency_info(upops)
1412
1413 # If only syntax check was requested, return here.
1414 # return here because we want to make sure most
1415 # errors above are caught and reported.
1416 if syntaxcheck:
1417 if not iface_read_ret:
1418 raise Exception()
1419 return
1420
1421 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
1422 and self.statemanager.ifaceobjdict):
1423 # Save a copy of new iface objects and dependency_graph
1424 new_ifaceobjdict = dict(self.ifaceobjdict)
1425 new_dependency_graph = dict(self.dependency_graph)
1426
1427 self.ifaceobjdict = OrderedDict({})
1428 self.dependency_graph = OrderedDict({})
1429
1430 # if old state is present, read old state and mark op for 'down'
1431 # followed by 'up' aka: reload
1432 # old interface config is read into self.ifaceobjdict
1433 self.read_old_iface_config()
1434 op = 'reload'
1435 else:
1436 # oldconfig not available, continue with 'up' with new config
1437 op = 'up'
1438 new_ifaceobjdict = self.ifaceobjdict
1439 new_dependency_graph = self.dependency_graph
1440
1441 if op == 'reload' and ifacenames:
1442 ifacenames = self.ifaceobjdict.keys()
1443 old_filtered_ifacenames = [i for i in ifacenames
1444 if self._iface_whitelisted(auto, allow,
1445 excludepats, i)]
1446
1447 # generate dependency graph of old interfaces,
1448 # This should make sure built in interfaces are
1449 # populated. disable check shared dependents as an optimization.
1450 # these are saved interfaces and dependency for these
1451 # have been checked before they became part of saved state.
1452 try:
1453 self.flags.CHECK_SHARED_DEPENDENTS = False
1454 self.populate_dependency_info(upops)
1455 self.flags.CHECK_SHARED_DEPENDENTS = True
1456 except Exception, e:
1457 self.logger.info("error generating dependency graph for "
1458 "saved interfaces (%s)" %str(e))
1459 pass
1460
1461 # make sure we pick up built-in interfaces
1462 # if config file had 'ifreload_down_changed' variable
1463 # set, also look for interfaces that changed to down them
1464 down_changed = int(self.config.get('ifreload_down_changed', '1'))
1465
1466 # Generate the interface down list
1467 # Interfaces that go into the down list:
1468 # - interfaces that were present in last config and are not
1469 # present in the new config
1470 # - interfaces that were changed between the last and current
1471 # config
1472 ifacedownlist = []
1473 for ifname in self.ifaceobjdict.keys():
1474 lastifaceobjlist = self.ifaceobjdict.get(ifname)
1475 if not self.is_ifaceobj_builtin(lastifaceobjlist[0]):
1476 # if interface is not built-in and is not in
1477 # old filtered ifacenames
1478 if ifname not in old_filtered_ifacenames:
1479 continue
1480 objidx = 0
1481 # If interface is not present in the new file
1482 # append it to the down list
1483 newifaceobjlist = new_ifaceobjdict.get(ifname)
1484 if not newifaceobjlist:
1485 ifacedownlist.append(ifname)
1486 continue
1487 # If ifaceobj was present in the old interfaces file,
1488 # and does not have a config in the new interfaces file
1489 # but has been picked up as a dependent of another
1490 # interface, catch it here. This catches a common error
1491 # for example: remove a bond section from the interfaces
1492 # file, but leave it around as a bridge port
1493 # XXX: Ideally its better to just add it to the
1494 # ifacedownlist. But we will be cautious here
1495 # and just print a warning
1496 if (self.is_ifaceobj_noconfig(newifaceobjlist[0]) and
1497 not self.is_ifaceobj_builtin(newifaceobjlist[0]) and
1498 lastifaceobjlist[0].is_config_present()):
1499 self.logger.warn('%s: misconfig ? removed but still exists as a dependency of %s' %(newifaceobjlist[objidx].name,
1500 str(newifaceobjlist[objidx].upperifaces)))
1501 if not down_changed:
1502 continue
1503 if len(newifaceobjlist) != len(lastifaceobjlist):
1504 ifacedownlist.append(ifname)
1505 continue
1506
1507 # If interface has changed between the current file
1508 # and the last installed append it to the down list
1509 # compare object list
1510 for objidx in range(0, len(lastifaceobjlist)):
1511 oldobj = lastifaceobjlist[objidx]
1512 newobj = newifaceobjlist[objidx]
1513 if not newobj.compare(oldobj):
1514 ifacedownlist.append(ifname)
1515 continue
1516
1517 if ifacedownlist:
1518 self.logger.info('reload: scheduling down on interfaces: %s'
1519 %str(ifacedownlist))
1520 # reinitialize dependency graph
1521 self.dependency_graph = OrderedDict({})
1522
1523 # Generate dependency info for old config
1524 self.flags.CHECK_SHARED_DEPENDENTS = False
1525 self.populate_dependency_info(downops, ifacedownlist)
1526 self.flags.CHECK_SHARED_DEPENDENTS = True
1527
1528 try:
1529 # XXX: Hack to skip checking upperifaces during down.
1530 # the dependency list is not complete here
1531 # and we dont want to down the upperiface.
1532 # Hence during reload, set this to true.
1533 # This is being added to avoid a failure in
1534 # scheduler._check_upperifaces when we are dowing
1535 # a builtin bridge port
1536 self.flags.SCHED_SKIP_CHECK_UPPERIFACES = True
1537 self._sched_ifaces(ifacedownlist, downops,
1538 followdependents=False,
1539 sort=True)
1540 except Exception, e:
1541 self.logger.error(str(e))
1542 pass
1543 finally:
1544 self.flags.SCHED_SKIP_CHECK_UPPERIFACES = False
1545 self._process_delay_admin_state_queue('down')
1546 else:
1547 self.logger.debug('no interfaces to down ..')
1548
1549 # Now, run 'up' with new config dict
1550 # reset statemanager update flag to default
1551 if not new_ifaceobjdict:
1552 self.logger.debug('no interfaces to up')
1553 return
1554
1555 if auto:
1556 self.flags.ALL = True
1557 self.flags.WITH_DEPENDS = True
1558 # and now, we are back to the current config in ifaceobjdict
1559 self.ifaceobjdict = new_ifaceobjdict
1560 self.dependency_graph = new_dependency_graph
1561
1562 self.logger.info('reload: scheduling up on interfaces: %s'
1563 %str(new_filtered_ifacenames))
1564 try:
1565 ret = self._sched_ifaces(new_filtered_ifacenames, upops,
1566 followdependents=True
1567 if self.flags.WITH_DEPENDS else False)
1568 except Exception, e:
1569 self.logger.error(str(e))
1570 pass
1571 finally:
1572 self._process_delay_admin_state_queue('up')
1573 if ifupdownflags.flags.DRYRUN:
1574 return
1575 self._save_state()
1576
1577 if not iface_read_ret or not ret:
1578 raise Exception()
1579
1580 def reload(self, *args, **kargs):
1581 """ reload interface config """
1582 self.logger.debug('reloading interface config ..')
1583 if kargs.get('currentlyup', False):
1584 self._reload_currentlyup(*args, **kargs)
1585 else:
1586 self._reload_default(*args, **kargs)
1587
1588 def _pretty_print_ordered_dict(self, prefix, argdict):
1589 outbuf = prefix + ' {\n'
1590 for k, vlist in argdict.items():
1591 outbuf += '\t%s : %s\n' %(k, str(vlist))
1592 self.logger.debug(outbuf + '}')
1593
1594 def print_dependency(self, ifacenames, format):
1595 """ prints iface dependency information """
1596
1597 if not ifacenames:
1598 ifacenames = self.ifaceobjdict.keys()
1599 if format == 'list':
1600 for k,v in self.dependency_graph.items():
1601 print '%s : %s' %(k, str(v))
1602 elif format == 'dot':
1603 indegrees = {}
1604 map(lambda i: indegrees.update({i :
1605 self.get_iface_refcnt(i)}),
1606 self.dependency_graph.keys())
1607 graph.generate_dots(self.dependency_graph, indegrees)
1608
1609 def print_ifaceobjs_list(self, ifacenames):
1610 for i in ifacenames:
1611 print i
1612
1613 def print_ifaceobjs_raw(self, ifacenames):
1614 """ prints raw lines for ifaces from config file """
1615
1616 for i in ifacenames:
1617 for ifaceobj in self.get_ifaceobjs(i):
1618 if (self.is_ifaceobj_builtin(ifaceobj) or
1619 not ifaceobj.is_config_present()):
1620 continue
1621 ifaceobj.dump_raw(self.logger)
1622 print '\n'
1623 if self.flags.WITH_DEPENDS and not self.flags.ALL:
1624 dlist = ifaceobj.lowerifaces
1625 if not dlist: continue
1626 self.print_ifaceobjs_raw(dlist)
1627
1628 def _get_ifaceobjs_pretty(self, ifacenames, ifaceobjs, running=False):
1629 """ returns iface obj list """
1630
1631 for i in ifacenames:
1632 for ifaceobj in self.get_ifaceobjs(i):
1633 if ((not running and self.is_ifaceobj_noconfig(ifaceobj)) or
1634 (running and not ifaceobj.is_config_present())):
1635 continue
1636 ifaceobjs.append(ifaceobj)
1637 if self.flags.WITH_DEPENDS and not self.flags.ALL:
1638 dlist = ifaceobj.lowerifaces
1639 if not dlist: continue
1640 self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
1641
1642 def print_ifaceobjs_pretty(self, ifacenames, format='native'):
1643 """ pretty prints iface in format given by keyword arg format """
1644
1645 ifaceobjs = []
1646 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
1647 if not ifaceobjs: return
1648 if format == 'json':
1649 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
1650 indent=4, separators=(',', ': '))
1651 else:
1652 expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
1653 for i in ifaceobjs:
1654 if not expand and (i.flags & iface.IFACERANGE_ENTRY):
1655 # print only the first one
1656 if i.flags & iface.IFACERANGE_START:
1657 i.dump_pretty(use_realname=True)
1658 else:
1659 i.dump_pretty()
1660
1661 def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
1662 ret = 0
1663 for i in ifacenames:
1664 ifaceobjscurr = self.get_ifaceobjcurr(i)
1665 if not ifaceobjscurr: continue
1666 for ifaceobj in ifaceobjscurr:
1667 if (ifaceobj.status == ifaceStatus.NOTFOUND or
1668 ifaceobj.status == ifaceStatus.ERROR):
1669 ret = 1
1670 if self.is_ifaceobj_noconfig(ifaceobj):
1671 continue
1672 ifaceobjs.append(ifaceobj)
1673 if self.flags.WITH_DEPENDS and not self.flags.ALL:
1674 dlist = ifaceobj.lowerifaces
1675 if not dlist: continue
1676 dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
1677 if dret: ret = 1
1678 return ret
1679
1680 def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
1681 """ pretty prints current running state of interfaces with status.
1682
1683 returns 1 if any of the interface has an error,
1684 else returns 0
1685 """
1686
1687 ifaceobjs = []
1688 ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
1689 if not ifaceobjs: return
1690
1691 # override ifaceStatusUserStrs
1692 ifaceStatusUserStrs.SUCCESS = self.config.get('ifquery_check_success_str', _success_sym)
1693 ifaceStatusUserStrs.ERROR = self.config.get('ifquery_check_error_str', _error_sym)
1694 ifaceStatusUserStrs.UNKNOWN = self.config.get('ifquery_check_unknown_str', '')
1695 if format == 'json':
1696 print json.dumps(ifaceobjs, cls=ifaceJsonEncoderWithStatus,
1697 indent=2, separators=(',', ': '))
1698 else:
1699 map(lambda i: i.dump_pretty(with_status=True), ifaceobjs)
1700 return ret
1701
1702 def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
1703 """ pretty prints iface running state """
1704
1705 ifaceobjs = []
1706 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs, running=True)
1707 if not ifaceobjs: return
1708 if format == 'json':
1709 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
1710 separators=(',', ': '))
1711 else:
1712 map(lambda i: i.dump_pretty(), ifaceobjs)
1713
1714 def _dump(self):
1715 print 'ifupdown main object dump'
1716 print self.pp.pprint(self.modules)
1717 print self.pp.pprint(self.ifaceobjdict)
1718
1719 def _dump_ifaceobjs(self, ifacenames):
1720 for i in ifacenames:
1721 ifaceobjs = self.get_ifaceobjs(i)
1722 for i in ifaceobjs:
1723 i.dump(self.logger)
1724 print '\n'