]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown/ifupdownmain.py
Addons/tunnel: fix typo in validvals (#31)
[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 exceptions import *
28 from sets import Set
29
30 from ipaddr import IPNetwork, IPv4Network, IPv6Network, IPAddress, IPv4Address, IPv6Address
31
32 """
33 .. module:: ifupdownmain
34 :synopsis: main module for ifupdown package
35
36 .. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
37
38 """
39
40 _tickmark = u'\u2713'
41 _crossmark = u'\u2717'
42 _success_sym = '(%s)' %_tickmark
43 _error_sym = '(%s)' %_crossmark
44
45 class ifupdownMainFlags():
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) or
116 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
117 return
118 # if not a logical interface and addr method is manual,
119 # ignore link admin state changes
120 if (ifaceobj.addr_method == 'manual' and
121 not ifaceobj.link_kind):
122 return
123 if self._delay_admin_state:
124 self._delay_admin_state_iface_queue.append(ifaceobj.name)
125 return
126 # If this object is a link slave, ie its link is controlled
127 # by its link master interface, then dont set the link state.
128 # But do allow user to change state of the link if the interface
129 # is already with its link master (hence the master check).
130 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
131 return
132 if not self.link_exists(ifaceobj.name):
133 return
134 if ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
135 # user has asked to explicitly keep the link down,
136 # so, force link down
137 self.logger.info('%s: keeping link down due to user config' %ifaceobj.name)
138 self.link_down(ifaceobj.name)
139 return
140 self.link_up(ifaceobj.name)
141
142 def run_down(self, ifaceobj):
143 if ((ifaceobj.link_kind & ifaceLinkKind.VRF) or
144 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
145 return
146 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
147 # there is no real interface behind it
148 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
149 return
150 # if not a logical interface and addr method is manual,
151 # ignore link admin state changes
152 if (ifaceobj.addr_method == 'manual' and
153 not ifaceobj.link_kind):
154 return
155 if self._delay_admin_state:
156 self._delay_admin_state_iface_queue.append(ifaceobj.name)
157 return
158 # If this object is a link slave, ie its link is controlled
159 # by its link master interface, then dont set the link state.
160 # But do allow user to change state of the link if the interface
161 # is already with its link master (hence the master check).
162 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
163 return
164 if not self.link_exists(ifaceobj.name):
165 return
166 self.link_down(ifaceobj.name)
167
168 # ifupdown object interface operation handlers
169 ops_handlers = OrderedDict([('up', run_up),
170 ('down', run_down)])
171
172 def run_sched_ifaceobj_posthook(self, ifaceobj, op):
173 if (ifaceobj.priv_flags and (ifaceobj.priv_flags.BUILTIN or
174 ifaceobj.priv_flags.NOCONFIG)):
175 return
176 if self.flags.STATEMANAGER_UPDATE:
177 self.statemanager.ifaceobj_sync(ifaceobj, op)
178
179 # ifupdown object interface scheduler pre and posthooks
180 sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
181
182 def __init__(self, config={},
183 force=False, dryrun=False, nowait=False,
184 perfmode=False, withdepends=False, njobs=1,
185 cache=False, addons_enable=True, statemanager_enable=True,
186 interfacesfile='/etc/network/interfaces',
187 interfacesfileiobuf=None,
188 interfacesfileformat='native',
189 withdefaults=False):
190 """This member function initializes the ifupdownmain object.
191
192 Kwargs:
193 config (dict): config dict from /etc/network/ifupdown2/ifupdown2.conf
194 force (bool): force interface configuration
195 dryrun (bool): dryrun interface configuration
196 withdepends (bool): apply interface configuration on all depends
197 interfacesfile (str): interfaces file. default is /etc/network/interfaces
198 interfacesfileformat (str): default is 'native'. Other choices are 'json'
199
200 Raises:
201 AttributeError, KeyError """
202
203 self.logger = logging.getLogger('ifupdown')
204 ifupdownflags.flags.FORCE = force
205 ifupdownflags.flags.DRYRUN = dryrun
206 ifupdownflags.flags.WITHDEFAULTS = withdefaults
207 ifupdownflags.flags.NOWAIT = nowait
208 ifupdownflags.flags.PERFMODE = perfmode
209 ifupdownflags.flags.CACHE = cache
210 ifupdownflags.flags.WITH_DEPENDS = withdepends
211
212 # Can be used to provide hints for caching
213 ifupdownflags.flags.CACHE_FLAGS = 0x0
214
215 self.flags = ifupdownMainFlags()
216
217 self.flags.STATEMANAGER_ENABLE = statemanager_enable
218 self.interfacesfile = interfacesfile
219 self.interfacesfileiobuf = interfacesfileiobuf
220 self.interfacesfileformat = interfacesfileformat
221 self.config = config
222 self.logger.debug(self.config)
223 self.blacklisted_ifaces_present = False
224
225 self.type = ifaceType.UNKNOWN
226
227 self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
228 self.flags.ADDONS_ENABLE = addons_enable
229
230 self.ifaces = OrderedDict()
231 self.njobs = njobs
232 self.pp = pprint.PrettyPrinter(indent=4)
233 self.modules = OrderedDict({})
234 self.module_attrs = {}
235 self.overridden_ifupdown_scripts = []
236
237 if self.config.get('addon_python_modules_support', '1') == '1':
238 self.load_addon_modules(self.addon_modules_dir)
239 if self.config.get('addon_scripts_support', '0') == '1':
240 self.load_scripts(self.scripts_dir)
241 self.dependency_graph = OrderedDict({})
242
243 self._cache_no_repeats = {}
244
245 if self.flags.STATEMANAGER_ENABLE:
246 try:
247 self.statemanager = statemanager.statemanager_api
248 self.statemanager.read_saved_state()
249 except Exception, e:
250 # XXX Maybe we should continue by ignoring old state
251 self.logger.warning('error reading state (%s)' %str(e))
252 raise
253 else:
254 self.flags.STATEMANAGER_UPDATE = False
255 self._delay_admin_state = True if self.config.get(
256 'delay_admin_state_change', '0') == '1' else False
257 self._delay_admin_state_iface_queue = []
258 if self._delay_admin_state:
259 self.logger.info('\'delay_admin_state_change\' is set. admin ' +
260 'state changes will be delayed till the end.')
261
262 self._link_master_slave = True if self.config.get(
263 'link_master_slave', '0') == '1' else False
264 if self._link_master_slave:
265 self.logger.info('\'link_master_slave\' is set. slave admin ' +
266 'state changes will be delayed till the ' +
267 'masters admin state change.')
268
269 # squash iface objects for same interface both internal and
270 # external representation. It is off by default.
271 self._ifaceobj_squash = True if self.config.get(
272 'ifaceobj_squash', '0') == '1' else False
273
274 # squash iface objects for same interface internal
275 # representation only. External representation as seen by ifquery
276 # will continue to see multiple iface stanzas if it was specified
277 # that way by the user. It is on by default.
278 self._ifaceobj_squash_internal = True if self.config.get(
279 'ifaceobj_squash_internal', '1') == '1' else False
280
281 # initialize global config object with config passed by the user
282 # This makes config available to addon modules
283 ifupdownConfig.config = self.config
284
285 self.validate_keywords = {
286 '<mac>': self._keyword_mac,
287 '<text>': self._keyword_text,
288 '<ipv4>': self._keyword_ipv4,
289 '<ipv6>': self._keyword_ipv6,
290 '<ip>': self._keyword_ip,
291 '<number>': self._keyword_number,
292 '<interface>': self._keyword_interface,
293 '<ipv4-vrf-text>': self._keyword_ipv4_vrf_text,
294 '<number-ipv4-list>': self._keyword_number_ipv4_list,
295 '<interface-list>': self._keyword_interface_list,
296 '<ipv4/prefixlen>': self._keyword_ipv4_prefixlen,
297 '<ipv6/prefixlen>': self._keyword_ipv6_prefixlen,
298 '<ip/prefixlen>': self._keyword_ip_prefixlen,
299 '<number-range-list>': self._keyword_number_range_list,
300 '<interface-range-list>': self._keyword_interface_range_list,
301 '<mac-ip/prefixlen-list>': self._keyword_mac_ip_prefixlen_list,
302 '<number-interface-list>': self._keyword_number_interface_list,
303 '<interface-yes-no-list>': self._keyword_interface_yes_no_list,
304 '<interface-yes-no-0-1-list>': self._keyword_interface_yes_no_0_1_list,
305 '<interface-yes-no-auto-list>': self._keyword_interface_yes_no_auto_list,
306 }
307
308 def link_master_slave_ignore_error(self, errorstr):
309 # If link master slave flag is set,
310 # there may be cases where the lowerdev may not be
311 # up resulting in 'Network is down' error
312 # This can happen if the lowerdev is a LINK_SLAVE
313 # of another interface which is not up yet
314 # example of such a case:
315 # bringing up a vlan on a bond interface and the bond
316 # is a LINK_SLAVE of a bridge (in other words the bond is
317 # part of a bridge) which is not up yet
318 if self._link_master_slave:
319 if 'Network is down' in errorstr:
320 return True
321 return False
322
323 def get_ifaceobjs(self, ifacename):
324 return self.ifaceobjdict.get(ifacename)
325
326 def get_ifaceobjs_saved(self, ifacename):
327 """ Return ifaceobjects from statemanager """
328 if self.flags.STATEMANAGER_ENABLE:
329 return self.statemanager.get_ifaceobjs(ifacename)
330 else:
331 return None
332
333 def get_ifaceobj_first(self, ifacename):
334 ifaceobjs = self.get_ifaceobjs(ifacename)
335 if ifaceobjs:
336 return ifaceobjs[0]
337 return None
338
339 def get_ifacenames(self):
340 return self.ifaceobjdict.keys()
341
342 def get_iface_obj_last(self, ifacename):
343 return self.ifaceobjdict.get(ifacename)[-1]
344
345
346 def must_follow_upperifaces(self, ifacename):
347 #
348 # XXX: This bleeds the knowledge of iface
349 # types in the infrastructure module.
350 # Cant think of a better fix at the moment.
351 # In future maybe the module can set a flag
352 # to indicate if we should follow upperifaces
353 #
354 ifaceobj = self.get_ifaceobj_first(ifacename)
355 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
356 return False
357 return True
358
359 def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
360 increfcnt=False):
361 """ creates a iface object and adds it to the iface dictionary """
362 ifaceobj = iface()
363 ifaceobj.name = ifacename
364 ifaceobj.priv_flags = priv_flags
365 ifaceobj.auto = True
366 if not self._link_master_slave:
367 ifaceobj.link_type = ifaceLinkType.LINK_NA
368 if increfcnt:
369 ifaceobj.inc_refcnt()
370 self.ifaceobjdict[ifacename] = [ifaceobj]
371 return ifaceobj
372
373 def create_n_save_ifaceobjcurr(self, ifaceobj):
374 """ creates a copy of iface object and adds it to the iface
375 dict containing current iface objects
376 """
377 ifaceobjcurr = iface()
378 ifaceobjcurr.name = ifaceobj.name
379 ifaceobjcurr.type = ifaceobj.type
380 ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
381 ifaceobjcurr.priv_flags = copy.deepcopy(ifaceobj.priv_flags)
382 ifaceobjcurr.auto = ifaceobj.auto
383 self.ifaceobjcurrdict.setdefault(ifaceobj.name,
384 []).append(ifaceobjcurr)
385 return ifaceobjcurr
386
387 def get_ifaceobjcurr(self, ifacename, idx=0):
388 ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
389 if not ifaceobjlist:
390 return None
391 if not idx:
392 return ifaceobjlist
393 else:
394 return ifaceobjlist[idx]
395
396 def get_ifaceobjrunning(self, ifacename):
397 return self.ifaceobjrunningdict.get(ifacename)
398
399 def get_iface_refcnt(self, ifacename):
400 """ Return iface ref count """
401 max = 0
402 ifaceobjs = self.get_ifaceobjs(ifacename)
403 if not ifaceobjs:
404 return 0
405 for i in ifaceobjs:
406 if i.refcnt > max:
407 max = i.refcnt
408 return max
409
410 def is_iface_builtin_byname(self, ifacename):
411 """ Returns true if iface name is a builtin interface.
412
413 A builtin interface is an interface which ifupdown understands.
414 The following are currently considered builtin ifaces:
415 - vlan interfaces in the format <ifacename>.<vlanid>
416 """
417 return '.' in ifacename
418
419 def is_ifaceobj_builtin(self, ifaceobj):
420 """ Returns true if iface name is a builtin interface.
421
422 A builtin interface is an interface which ifupdown understands.
423 The following are currently considered builtin ifaces:
424 - vlan interfaces in the format <ifacename>.<vlanid>
425 """
426 if (ifaceobj.priv_flags and ifaceobj.priv_flags.BUILTIN):
427 return True
428 return False
429
430 def is_ifaceobj_noconfig(self, ifaceobj):
431 """ Returns true if iface object did not have a user defined config.
432
433 These interfaces appear only when they are dependents of interfaces
434 which have user defined config
435 """
436 return (ifaceobj.priv_flags and ifaceobj.priv_flags.NOCONFIG)
437
438 def is_iface_noconfig(self, ifacename):
439 """ Returns true if iface has no config """
440
441 ifaceobj = self.get_ifaceobj_first(ifacename)
442 if not ifaceobj: return True
443 return self.is_ifaceobj_noconfig(ifaceobj)
444
445 def check_shared_dependents(self, ifaceobj, dlist):
446 """ ABSOLETE: Check if dlist intersects with any other
447 interface with slave dependents.
448 example: bond and bridges.
449 This function logs such errors """
450 setdlist = Set(dlist)
451 for ifacename, ifacedlist in self.dependency_graph.items():
452 if not ifacedlist:
453 continue
454 check_depends = False
455 iobjs = self.get_ifaceobjs(ifacename)
456 if not iobjs:
457 continue
458 for i in iobjs:
459 if (i.dependency_type == ifaceDependencyType.MASTER_SLAVE):
460 check_depends = True
461 if check_depends:
462 common = Set(ifacedlist).intersection(setdlist)
463 if common:
464 self.logger.error('misconfig..?. iface %s and %s '
465 %(ifaceobj.name, ifacename) +
466 'seem to share dependents/ports %s' %str(list(common)))
467
468 def _set_iface_role(self, ifaceobj, role, upperifaceobj):
469 if (self.flags.CHECK_SHARED_DEPENDENTS and
470 (ifaceobj.role & ifaceRole.SLAVE) and
471 (role == ifaceRole.SLAVE) and (upperifaceobj.role == ifaceRole.MASTER)):
472 self.logger.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
473 %(ifaceobj.name,
474 ifaceLinkPrivFlags.get_all_str(ifaceobj.link_privflags), str(ifaceobj.upperifaces)))
475 ifaceobj.set_status(ifaceStatus.ERROR)
476 return
477 ifaceobj.role = role
478
479 def _set_iface_role_n_kind(self, ifaceobj, upperifaceobj):
480
481 # If addr_method is set and link is not a logical interface,
482 # set flag KEEP_LINK_DOWN. addr_method == 'manual' only applies to
483 # logical interfaces.
484 if (ifaceobj.addr_method == 'manual' and not ifaceobj.link_kind):
485 ifaceobj.link_privflags |= ifaceLinkPrivFlags.KEEP_LINK_DOWN
486
487 if (upperifaceobj.link_kind & ifaceLinkKind.BOND):
488 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
489 ifaceobj.link_privflags |= ifaceLinkPrivFlags.BOND_SLAVE
490
491 if (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
492 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
493 ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_PORT
494
495 if (ifaceobj.link_kind & ifaceLinkKind.VXLAN) \
496 and (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
497 upperifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
498
499 # vrf masters get processed after slaves, which means
500 # check both link_kind vrf and vrf slave
501 if ((upperifaceobj.link_kind & ifaceLinkKind.VRF) or
502 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
503 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
504 ifaceobj.link_privflags |= ifaceLinkPrivFlags.VRF_SLAVE
505 if self._link_master_slave:
506 if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
507 ifaceobj.link_type = ifaceLinkType.LINK_SLAVE
508 else:
509 upperifaceobj.link_type = ifaceLinkType.LINK_NA
510 ifaceobj.link_type = ifaceLinkType.LINK_NA
511
512 def dump_iface_dependency_info(self):
513 """ debug funtion to print raw dependency
514 info - lower and upper devices"""
515
516 for ifacename, ifaceobjs in self.ifaceobjdict.iteritems():
517 iobj = ifaceobjs[0]
518 self.logger.info("%s: refcnt: %d, lower: %s, upper: %s" %(ifacename,
519 self.get_iface_refcnt(ifacename),
520 str(iobj.lowerifaces) if iobj.lowerifaces else [],
521 str(iobj.upperifaces) if iobj.upperifaces else []))
522
523
524 def preprocess_dependency_list(self, upperifaceobj, dlist, ops):
525 """ We go through the dependency list and
526 delete or add interfaces from the interfaces dict by
527 applying the following rules:
528 if flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
529 we only consider devices whose configuration was
530 specified in the network interfaces file. We delete
531 any interface whose config was not specified except
532 for vlan devices. vlan devices get special treatment.
533 Even if they are not present they are created and added
534 to the ifacesdict
535 elif flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
536 we create objects for all dependent devices that are not
537 present in the ifacesdict
538 """
539 del_list = []
540
541 for d in dlist:
542 dilist = self.get_ifaceobjs(d)
543 if not dilist:
544 ni = None
545 if self.is_iface_builtin_byname(d):
546 ni = self.create_n_save_ifaceobj(d,
547 ifacePrivFlags(True, True), True)
548 elif not self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
549 ni = self.create_n_save_ifaceobj(d,
550 ifacePrivFlags(False, True), True)
551 else:
552 del_list.append(d)
553 if ni:
554 ni.add_to_upperifaces(upperifaceobj.name)
555 self._set_iface_role_n_kind(ni, upperifaceobj)
556 else:
557 for di in dilist:
558 di.inc_refcnt()
559 di.add_to_upperifaces(upperifaceobj.name)
560 self._set_iface_role_n_kind(di, upperifaceobj)
561 for d in del_list:
562 dlist.remove(d)
563
564 def preprocess_upperiface(self, lowerifaceobj, ulist, ops):
565 for u in ulist:
566 if (lowerifaceobj.upperifaces and
567 u in lowerifaceobj.upperifaces):
568 continue
569 lowerifaceobj.add_to_upperifaces(u)
570 uifacelist = self.get_ifaceobjs(u)
571 if uifacelist:
572 for ui in uifacelist:
573 lowerifaceobj.inc_refcnt()
574 self._set_iface_role_n_kind(lowerifaceobj, ui)
575 ui.add_to_lowerifaces(lowerifaceobj.name)
576
577 def query_lowerifaces(self, ifaceobj, ops, ifacenames, type=None):
578 """ Gets iface dependents by calling into respective modules """
579 ret_dlist = []
580
581 # Get dependents for interface by querying respective modules
582 for module in self.modules.values():
583 try:
584 if ops[0] == 'query-running':
585 if (not hasattr(module,
586 'get_dependent_ifacenames_running')):
587 continue
588 dlist = module.get_dependent_ifacenames_running(ifaceobj)
589 else:
590 if (not hasattr(module, 'get_dependent_ifacenames')):
591 continue
592 dlist = module.get_dependent_ifacenames(ifaceobj,
593 ifacenames)
594 except Exception, e:
595 self.logger.warn('%s: error getting dependent interfaces (%s)'
596 %(ifaceobj.name, str(e)))
597 dlist = None
598 pass
599 if dlist: ret_dlist.extend(dlist)
600 return list(set(ret_dlist))
601
602 def query_upperifaces(self, ifaceobj, ops, ifacenames, type=None):
603 """ Gets iface upperifaces by calling into respective modules """
604 ret_ulist = []
605
606 # Get upperifaces for interface by querying respective modules
607 for module in self.modules.values():
608 try:
609 if ops[0] == 'query-running':
610 if (not hasattr(module,
611 'get_upper_ifacenames_running')):
612 continue
613 ulist = module.get_upper_ifacenames_running(ifaceobj)
614 else:
615 if (not hasattr(module, 'get_upper_ifacenames')):
616 continue
617 ulist = module.get_upper_ifacenames(ifaceobj, ifacenames)
618 except Exception, e:
619 self.logger.warn('%s: error getting upper interfaces (%s)'
620 %(ifaceobj.name, str(e)))
621 ulist = None
622 pass
623 if ulist: ret_ulist.extend(ulist)
624 return list(set(ret_ulist))
625
626 def populate_dependency_info(self, ops, ifacenames=None):
627 """ recursive function to generate iface dependency info """
628
629 if not ifacenames:
630 ifacenames = self.ifaceobjdict.keys()
631
632 iqueue = deque(ifacenames)
633 while iqueue:
634 i = iqueue.popleft()
635 # Go through all modules and find dependent ifaces
636 dlist = None
637 ulist = None
638 ifaceobjs = self.get_ifaceobjs(i)
639 if not ifaceobjs:
640 continue
641 dependents_processed = False
642
643 # Store all dependency info in the first ifaceobj
644 # but get dependency info from all ifaceobjs
645 ifaceobj = ifaceobjs[0]
646 for iobj in ifaceobjs:
647 ulist = self.query_upperifaces(iobj, ops, ifacenames)
648 if iobj.lowerifaces:
649 dependents_processed = True
650 break
651 dlist = self.query_lowerifaces(iobj, ops, ifacenames)
652 if dlist:
653 break
654 if ulist:
655 self.preprocess_upperiface(ifaceobj, ulist, ops)
656 if dependents_processed:
657 continue
658 if dlist:
659 self.preprocess_dependency_list(ifaceobj,
660 dlist, ops)
661 ifaceobj.lowerifaces = dlist
662 [iqueue.append(d) for d in dlist]
663 #if not self.dependency_graph.get(i):
664 # self.dependency_graph[i] = dlist
665
666 for i in self.ifaceobjdict.keys():
667 iobj = self.get_ifaceobj_first(i)
668 if (not iobj.link_kind and
669 not (iobj.link_privflags & ifaceLinkPrivFlags.LOOPBACK) and
670 iobj.name == 'lo'):
671 iobj.link_privflags |= ifaceLinkPrivFlags.LOOPBACK
672 if iobj.lowerifaces:
673 self.dependency_graph[i] = iobj.lowerifaces
674 else:
675 self.dependency_graph[i] = []
676
677 if not self.blacklisted_ifaces_present:
678 return
679
680 # Walk through the dependency graph and remove blacklisted
681 # interfaces that were picked up as dependents
682 for i in self.dependency_graph.keys():
683 ifaceobj = self.get_ifaceobj_first(i)
684 if not ifaceobj:
685 continue
686
687 if ifaceobj.blacklisted and not ifaceobj.upperifaces:
688 # if blacklisted and was not picked up as a
689 # dependent of a upper interface, delete the
690 # interface from the dependency graph
691 dlist = ifaceobj.lowerifaces
692 if dlist:
693 for d in dlist:
694 difaceobjs = self.get_ifaceobjs(d)
695 if not difaceobjs:
696 continue
697 try:
698 for d in difaceobjs:
699 d.dec_refcnt()
700 d.upperifaces.remove(i)
701 except:
702 self.logger.debug('error removing %s from %s upperifaces' %(i, d))
703 pass
704 self.logger.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
705 del self.dependency_graph[i]
706 continue
707
708 def _check_config_no_repeats(self, ifaceobj):
709 """ check if object has an attribute that is
710 restricted to a single object in the system.
711 if yes, warn and return """
712 for k,v in self._cache_no_repeats.items():
713 iv = ifaceobj.config.get(k)
714 if iv and iv[0] == v:
715 self.logger.error('ignoring interface %s. ' %ifaceobj.name +
716 'Only one object with attribute ' +
717 '\'%s %s\' allowed.' %(k, v))
718 return True
719 for k, v in self.config.get('no_repeats', {}).items():
720 iv = ifaceobj.config.get(k)
721 if iv and iv[0] == v:
722 self._cache_no_repeats[k] = v
723 return False
724
725 def _save_iface_squash(self, ifaceobj):
726 """ squash ifaceobjects belonging to same iface
727 into a single object """
728 if self._check_config_no_repeats(ifaceobj):
729 return
730 ifaceobj.priv_flags = ifacePrivFlags()
731 if not self._link_master_slave:
732 ifaceobj.link_type = ifaceLinkType.LINK_NA
733 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
734 if not currentifaceobjlist:
735 self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
736 return
737 if ifaceobj.compare(currentifaceobjlist[0]):
738 self.logger.warn('duplicate interface %s found' %ifaceobj.name)
739 return
740 for obj in self.ifaceobjdict[ifaceobj.name]:
741 if obj.type == ifaceobj.type:
742 obj.squash(ifaceobj)
743 return
744 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
745
746 def _save_iface(self, ifaceobj):
747 if self._check_config_no_repeats(ifaceobj):
748 return
749 ifaceobj.priv_flags = ifacePrivFlags()
750 if not self._link_master_slave:
751 ifaceobj.link_type = ifaceLinkType.LINK_NA
752 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
753 if not currentifaceobjlist:
754 self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
755 if not self._ifaceobj_squash:
756 ifaceobj.flags |= ifaceobj.YOUNGEST_SIBLING
757 return
758 if ifaceobj.compare(currentifaceobjlist[0]):
759 self.logger.warn('duplicate interface %s found' %ifaceobj.name)
760 return
761 if currentifaceobjlist[0].type == ifaceobj.type:
762 currentifaceobjlist[0].flags |= ifaceobj.HAS_SIBLINGS
763 ifaceobj.flags |= ifaceobj.HAS_SIBLINGS
764 # clear the OLDEST_SIBLING from all the siblings
765 for iface in self.ifaceobjdict[ifaceobj.name]:
766 iface.flags &= ~ifaceobj.OLDEST_SIBLING
767 # current sibling is the oldest
768 ifaceobj.flags |= ifaceobj.OLDEST_SIBLING
769 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
770
771 def _keyword_text(self, value, validrange=None):
772 return isinstance(value, str) and len(value) > 0
773
774 def _keyword_mac(self, value, validrange=None):
775 if value.strip().startswith('ether'):
776 value = value.strip()[6:]
777 return re.match('[0-9a-f]{1,2}([-:])[0-9a-f]{1,2}(\\1[0-9a-f]{1,2}){4}$',
778 value.lower())
779
780 def _keyword_check_list(self, _list, obj, limit=None):
781 try:
782 if limit and limit > 0:
783 for i in xrange(0, limit):
784 obj(_list[i])
785 return len(_list) == limit
786 else:
787 for elem in _list:
788 obj(elem)
789 return True
790 except Exception as e:
791 self.logger.debug('keyword: check list: %s' % str(e))
792 return False
793
794 def _keyword_ipv4(self, value, validrange=None):
795 return self._keyword_check_list(value.split(), IPv4Address, limit=1)
796
797 def _keyword_ipv4_prefixlen(self, value, validrange=None):
798 return self._keyword_check_list(value.split(), IPv4Network, limit=1)
799
800 def _keyword_ipv6(self, value, validrange=None):
801 return self._keyword_check_list(value.split(), IPv6Address, limit=1)
802
803 def _keyword_ipv6_prefixlen(self, value, validrange=None):
804 return self._keyword_check_list(value.split(), IPv6Network, limit=1)
805
806 def _keyword_ip(self, value, validrange=None):
807 return self._keyword_check_list(value.split(), IPAddress, limit=1)
808
809 def _keyword_ip_prefixlen(self, value, validrange=None):
810 return self._keyword_check_list(value.split(), IPNetwork, limit=1)
811
812 def _keyword_mac_ip_prefixlen_list(self, value, validrange=None):
813 """
814 <mac> <ip> [<ip> ...]
815 ex: address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24
816 """
817 try:
818 res = value.split()
819 if len(res) < 2:
820 return False
821 if not self._keyword_mac(res[0]):
822 return False
823 for ip in res[1:]:
824 if not self._keyword_ip_prefixlen(ip):
825 return False
826 return True
827 except Exception as e:
828 self.logger.debug('keyword: mac ipaddr prefixlen: %s' % str(e))
829 return False
830
831 def _keyword_number_ipv4_list(self, value, validrange=None):
832 """
833 <number>=<ipv4> [<number>=<ipv4> ...]
834 ex: bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1
835 """
836 try:
837 elements = value.split(' ')
838 if not elements:
839 return False
840 for elem in elements:
841 v = elem.split('=')
842 int(v[0])
843 IPv4Address(v[1])
844 return True
845 except Exception as e:
846 self.logger.debug('keyword: number ipv4: %s' % str(e))
847 return False
848
849 def _keyword_interface(self, ifacename, validrange=None):
850 return self.get_ifaceobjs(ifacename)
851
852 def _keyword_ipv4_vrf_text(self, value, validrange=None):
853 """
854 <ipv4> "vrf" <text>
855 ex: clagd-backup-ip 10.10.10.42 vrf blue
856 """
857 values = value.split()
858 size = len(values)
859
860 if size > 3 or size < 1:
861 return False
862 try:
863 IPv4Address(values[0])
864 if size > 1:
865 if values[1] != 'vrf':
866 return False
867 if size > 2:
868 if not self._keyword_text(values[2]):
869 return False
870 return True
871 except Exception as e:
872 self.logger.debug('keyword: ipv4 vrf text: %s' % str(e))
873 return False
874
875 def _keyword_interface_list_with_value(self, value, validvals):
876 values = value.split()
877 try:
878 if len(values) == 1:
879 if values[0] in validvals:
880 return True
881 for v in values:
882 iface_value = v.split('=')
883 size = len(iface_value)
884 if size != 2:
885 if iface_value[0] == 'glob' or iface_value[0] == 'regex':
886 continue
887 return False
888 if not iface_value[1] in validvals:
889 return False
890 return True
891 except Exception as e:
892 self.logger.debug('keyword: interface list with value: %s' % str(e))
893 return False
894
895 def _keyword_interface_yes_no_list(self, value, validrange=None):
896 """
897 <yes|no> | ( <interface>=<yes|no> [<interface>=<yes|no> ...] )
898 ex: mstpctl-portrestrrole swp1=yes swp2=no
899 """
900 return self._keyword_interface_list_with_value(value, ['yes', 'no'])
901
902 def _keyword_interface_yes_no_auto_list(self, value, validrange=None):
903 """
904 <yes|no|auto> |
905 ( <interface>=<yes|no|auto> [<interface>=<yes|no|auto> ...] )
906 ex: mstpctl-portp2p swp1=yes swp2=no swp3=auto
907 """
908 return self._keyword_interface_list_with_value(value,
909 ['yes', 'no', 'auto'])
910
911 def _keyword_interface_yes_no_0_1_list(self, value, validrange=None):
912 """
913 <yes|no|0|1> |
914 ( <interface>=<yes|no|0|1> [<interface>=<yes|no|0|1> ...] )
915 ex: bridge-portmcrouter swp1=yes swp2=yes swp3=1
916 """
917 return self._keyword_interface_list_with_value(value,
918 ['yes', 'no', '1', '0'])
919
920 def _keyword_interface_range_list(self, value, validrange):
921 """
922 <number> | ( <interface>=<number> [ <interface>=number> ...] )
923 ex: mstpctl-portpathcost swp1=0 swp2=1
924 """
925 values = value.split()
926 try:
927 if len(values) == 1:
928 try:
929 n = int(values[0])
930 if n < int(validrange[0]) or n > int(
931 validrange[1]):
932 raise invalidValueError('value of out range "%s":'
933 ' valid attribute range: %s'
934 % (values[0],
935 '-'.join(validrange)))
936 return True
937 except invalidValueError as e:
938 raise e
939 except Exception as e:
940 self.logger.debug('keyword: interface range list: %s'
941 % str(e))
942 return False
943 for v in values:
944 iface_value = v.split('=')
945 size = len(iface_value)
946 if size != 2:
947 return False
948 number = int(iface_value[1])
949 if number < int(validrange[0]) or number > int(
950 validrange[1]):
951 raise invalidValueError(
952 'value of out range "%s" for iface "%s":'
953 ' valid attribute range: %s'
954 % (iface_value[1],
955 iface_value[0],
956 '-'.join(validrange)))
957 return True
958 except invalidValueError as e:
959 raise e
960 except Exception as e:
961 self.logger.debug('keyword: interface range list: %s' % str(e))
962 return False
963
964 def _keyword_interface_list(self, value, validrange=None):
965 """
966 [glob|regex] <interface> [ [glob|regex] <interface> ...]
967 ex: bridge-ports swp1 swp2 glob swp3-5.100 regex (swp[6|7|8].100)
968 """
969 interface_list = value.split()
970 size = len(interface_list)
971 i = 0
972 while i < size:
973 if interface_list[i] == 'glob' or interface_list[i] == 'regex':
974 i += 1
975 else:
976 if not self._keyword_interface(interface_list[i]):
977 return False
978 i += 1
979 return True
980
981 def _keyword_number_range_list(self, value, validrange=None):
982 """
983 <number> [<number>-<number>]
984 ex: bridge-vids 42 100-200
985 """
986 number_list = value.split()
987 try:
988 i = 0
989 while i < len(number_list):
990 if '-' in number_list[i]:
991 range = number_list[i].split('-')
992 a = int(range[0])
993 b = int(range[1])
994 if a > b:
995 return False
996 else:
997 int(number_list[i])
998 i += 1
999 return True
1000 except Exception as e:
1001 self.logger.debug('keyword: number range list: %s' % str(e))
1002 return False
1003
1004 def _keyword_number_interface_list(self, value, validrange=None):
1005 """
1006 <number> <interface> [<interface>... [<number> <interface> ... ]]
1007 bridge-waitport 42 swp1 swp2 swp3 9 swp4
1008 """
1009 interface_list = value.split()
1010 if not interface_list:
1011 return False
1012 try:
1013 int(interface_list[0])
1014 prev = True
1015 for elem in interface_list[1:]:
1016 try:
1017 int(elem)
1018 if prev:
1019 return False
1020 prev = True
1021 except:
1022 prev = False
1023 return not prev
1024 except Exception as e:
1025 self.logger.debug('keyword: number interface list: %s' % str(e))
1026 return False
1027
1028 def _keyword_number(self, value, validrange=None):
1029 try:
1030 int(value)
1031 return True
1032 except Exception as e:
1033 self.logger.debug('keyword: number: %s' % str(e))
1034 return False
1035
1036 def _is_keyword(self, value):
1037 if isinstance(value, tuple):
1038 return True
1039 keyword_found = value in self.validate_keywords
1040 if value.startswith('<') and value.endswith('>') and not keyword_found:
1041 raise Exception('%s: invalid keyword, please make sure to use'
1042 ' a valid keyword see `ifquery -s`' % value)
1043 return keyword_found
1044
1045 def _check_validvals_value(self, attrname, value, validvals, validrange):
1046 if validvals and value not in validvals:
1047 is_valid = False
1048 for keyword in validvals:
1049 if self._is_keyword(keyword):
1050 if validrange:
1051 if self.validate_keywords[keyword](value, validrange):
1052 return {'result': True}
1053 else:
1054 if self.validate_keywords[keyword](value):
1055 return {'result': True}
1056 if not is_valid:
1057 return {
1058 'result': False,
1059 'message': 'invalid value "%s": valid attribute values: %s'
1060 % (value, validvals)
1061 }
1062 elif validrange:
1063 if len(validrange) != 2:
1064 raise Exception('%s: invalid range in addon configuration'
1065 % '-'.join(validrange))
1066 _value = int(value)
1067 if _value < int(validrange[0]) or _value > int(validrange[1]):
1068 return {
1069 'result': False,
1070 'message': 'value of out range "%s": '
1071 'valid attribute range: %s'
1072 % (value, '-'.join(validrange))
1073 }
1074 return {'result': True}
1075
1076 def _check_validvals(self, ifacename, module_name, attrs):
1077 ifaceobj = self.get_ifaceobjs(ifacename)
1078 if not ifaceobj:
1079 return
1080 success = True
1081 for attrname, attrvalue in ifaceobj[0].config.items():
1082 try:
1083 attrname_dict = attrs.get(attrname, {})
1084 validvals = attrname_dict.get('validvals', [])
1085 validrange = attrname_dict.get('validrange', [])
1086 for value in attrvalue:
1087 res = self._check_validvals_value(attrname,
1088 value,
1089 validvals,
1090 validrange)
1091 if not res['result']:
1092 self.logger.warn('%s: %s: %s' %
1093 (ifacename, attrname, res['message']))
1094 success = False
1095 except Exception as e:
1096 self.logger.warn('addon \'%s\': %s: %s' % (module_name,
1097 attrname,
1098 str(e)))
1099 success = False
1100 return success
1101
1102 def _module_syntax_check(self, filtered_ifacenames):
1103 result = True
1104 for ifacename in filtered_ifacenames:
1105 for module in self.modules.values():
1106 try:
1107 if hasattr(module, '_modinfo'):
1108 if not self._check_validvals(ifacename,
1109 module.__class__.__name__,
1110 module._modinfo.get('attrs', {})):
1111 result = False
1112 if hasattr(module, 'syntax_check') and callable(module.syntax_check):
1113 if not module.syntax_check(self.get_ifaceobjs(ifacename)[0],
1114 self.get_ifaceobjs):
1115 result = False
1116 except Exception, e:
1117 self.logger.warn('%s: %s' % (ifacename, str(e)))
1118 result = False
1119 return result
1120
1121 def _iface_configattr_syntax_checker(self, attrname, attrval):
1122 for m, mdict in self.module_attrs.items():
1123 if not mdict:
1124 continue
1125 attrsdict = mdict.get('attrs')
1126 try:
1127 a = attrsdict.get(attrname)
1128 if a:
1129 if a.get('deprecated'):
1130 newa = a.get('new-attribute')
1131 if newa:
1132 self.logger.warn('attribute %s is deprecated. use %s instead.' %(attrname, newa))
1133 else:
1134 self.logger.warn('attribute %s is deprecated.'
1135 %attrname)
1136 return True
1137 else:
1138 for key in attrsdict:
1139 if 'aliases' in attrsdict[key]:
1140 if attrname in attrsdict[key]['aliases']:
1141 return True
1142 except AttributeError:
1143 pass
1144 return False
1145
1146 def _ifaceobj_syntax_checker(self, ifaceobj):
1147 ret = True
1148 for attrname, attrvalue in ifaceobj.config.items():
1149 found = False
1150 for k, v in self.module_attrs.items():
1151 if v and v.get('attrs', {}).get(attrname):
1152 found = True
1153 break
1154 if not found:
1155 ret = False
1156 self.logger.warn('%s: unsupported attribute \'%s\'' \
1157 % (ifaceobj.name, attrname))
1158 continue
1159 return ret
1160
1161 def read_iface_config(self):
1162 """ Reads default network interface config /etc/network/interfaces. """
1163 ret = True
1164 nifaces = networkInterfaces(self.interfacesfile,
1165 self.interfacesfileiobuf,
1166 self.interfacesfileformat,
1167 template_enable=self.config.get('template_enable', 0),
1168 template_engine=self.config.get('template_engine'),
1169 template_lookuppath=self.config.get('template_lookuppath'))
1170 if self._ifaceobj_squash or self._ifaceobj_squash_internal:
1171 nifaces.subscribe('iface_found', self._save_iface_squash)
1172 else:
1173 nifaces.subscribe('iface_found', self._save_iface)
1174 if self.config.get('addon_syntax_check', '1') == '1':
1175 nifaces.subscribe('validateifaceattr',
1176 self._iface_configattr_syntax_checker)
1177 nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
1178 nifaces.load()
1179 if nifaces.errors or nifaces.warns:
1180 ret = False
1181 return ret
1182
1183 def read_old_iface_config(self):
1184 """ Reads the saved iface config instead of default iface config.
1185 And saved iface config is already read by the statemanager """
1186 self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
1187
1188 def _load_addon_modules_config(self):
1189 """ Load addon modules config file """
1190
1191 with open(self.addon_modules_configfile, 'r') as f:
1192 lines = f.readlines()
1193 for l in lines:
1194 try:
1195 litems = l.strip(' \n\t\r').split(',')
1196 if not litems or len(litems) < 2:
1197 continue
1198 operation = litems[0]
1199 mname = litems[1]
1200 self.module_ops[operation].append(mname)
1201 except Exception, e:
1202 self.logger.warn('error reading line \'%s\' %s:' %(l, str(e)))
1203 continue
1204
1205 def load_addon_modules(self, modules_dir):
1206 """ load python modules from modules_dir
1207
1208 Default modules_dir is /usr/share/ifupdownmodules
1209
1210 """
1211 self.logger.info('loading builtin modules from %s' %modules_dir)
1212 self._load_addon_modules_config()
1213 if not modules_dir in sys.path:
1214 sys.path.append(modules_dir)
1215 try:
1216 for op, mlist in self.module_ops.items():
1217 for mname in mlist:
1218 if self.modules.get(mname):
1219 continue
1220 mpath = modules_dir + '/' + mname + '.py'
1221 if os.path.exists(mpath):
1222 try:
1223 m = __import__(mname)
1224 mclass = getattr(m, mname)
1225 except:
1226 raise
1227 try:
1228 minstance = mclass()
1229 script_override = minstance.get_overrides_ifupdown_scripts()
1230 self.overridden_ifupdown_scripts.extend(script_override)
1231 except moduleNotSupported, e:
1232 self.logger.info('module %s not loaded (%s)\n'
1233 %(mname, str(e)))
1234 continue
1235 except:
1236 raise
1237 self.modules[mname] = minstance
1238 try:
1239 self.module_attrs[mname] = minstance.get_modinfo()
1240 except:
1241 pass
1242 except:
1243 raise
1244
1245 # Assign all modules to query operations
1246 self.module_ops['query-checkcurr'] = self.modules.keys()
1247 self.module_ops['query-running'] = self.modules.keys()
1248 self.module_ops['query-dependency'] = self.modules.keys()
1249 self.module_ops['query'] = self.modules.keys()
1250 self.module_ops['query-raw'] = self.modules.keys()
1251
1252
1253 def _modules_help(self):
1254 """ Prints addon modules supported syntax """
1255
1256 indent = ' '
1257 for m, mdict in self.module_attrs.items():
1258 if not mdict:
1259 continue
1260 print('%s: %s' %(m, mdict.get('mhelp')))
1261 attrdict = mdict.get('attrs')
1262 if not attrdict:
1263 continue
1264 try:
1265 for attrname, attrvaldict in attrdict.items():
1266 if attrvaldict.get('compat', False):
1267 continue
1268 print('%s%s' %(indent, attrname))
1269 print('%shelp: %s' %(indent + ' ',
1270 attrvaldict.get('help', '')))
1271 print ('%srequired: %s' %(indent + ' ',
1272 attrvaldict.get('required', False)))
1273 default = attrvaldict.get('default')
1274 if default:
1275 print('%sdefault: %s' %(indent + ' ', default))
1276
1277 validrange = attrvaldict.get('validrange')
1278 if validrange:
1279 print('%svalidrange: %s-%s'
1280 %(indent + ' ', validrange[0], validrange[1]))
1281
1282 validvals = attrvaldict.get('validvals')
1283 if validvals:
1284 print('%svalidvals: %s'
1285 %(indent + ' ', ','.join(validvals)))
1286
1287 examples = attrvaldict.get('example')
1288 if not examples:
1289 continue
1290
1291 print '%sexample:' %(indent + ' ')
1292 for e in examples:
1293 print '%s%s' %(indent + ' ', e)
1294 except:
1295 pass
1296 print ''
1297
1298 def load_scripts(self, modules_dir):
1299 """ loading user modules from /etc/network/.
1300
1301 Note that previously loaded python modules override modules found
1302 under /etc/network if any
1303
1304 """
1305
1306 self.logger.info('looking for user scripts under %s' %modules_dir)
1307 for op, mlist in self.script_ops.items():
1308 msubdir = modules_dir + '/if-%s.d' %op
1309 self.logger.info('loading scripts under %s ...' %msubdir)
1310 try:
1311 module_list = os.listdir(msubdir)
1312 for module in module_list:
1313 if self.modules.get(module) or module in self.overridden_ifupdown_scripts:
1314 continue
1315 self.script_ops[op].append(msubdir + '/' + module)
1316 except:
1317 # continue reading
1318 pass
1319
1320 def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False,
1321 followdependents=True, sort=False):
1322 self.logger.debug('scheduling \'%s\' for %s'
1323 %(str(ops), str(ifacenames)))
1324 self._pretty_print_ordered_dict('dependency graph',
1325 self.dependency_graph)
1326 ifaceScheduler.sched_ifaces(self, ifacenames, ops,
1327 dependency_graph=self.dependency_graph,
1328 order=ifaceSchedulerFlags.INORDER
1329 if 'down' in ops[0]
1330 else ifaceSchedulerFlags.POSTORDER,
1331 followdependents=followdependents,
1332 skipupperifaces=skipupperifaces,
1333 sort=True if (sort or ifupdownflags.flags.CLASS) else False)
1334 return ifaceScheduler.get_sched_status()
1335
1336 def _render_ifacename(self, ifacename):
1337 new_ifacenames = []
1338 vlan_match = re.match("^([\d]+)-([\d]+)", ifacename)
1339 if vlan_match:
1340 vlan_groups = vlan_match.groups()
1341 if vlan_groups[0] and vlan_groups[1]:
1342 [new_ifacenames.append('%d' %v)
1343 for v in range(int(vlan_groups[0]),
1344 int(vlan_groups[1])+1)]
1345 return new_ifacenames
1346
1347 def _preprocess_ifacenames(self, ifacenames):
1348 """ validates interface list for config existance.
1349
1350 returns -1 if one or more interface not found. else, returns 0
1351
1352 """
1353 new_ifacenames = []
1354 err_iface = ''
1355 for i in ifacenames:
1356 ifaceobjs = self.get_ifaceobjs(i)
1357 if not ifaceobjs:
1358 # if name not available, render interface name and check again
1359 rendered_ifacenames = utils.expand_iface_range(i)
1360 if rendered_ifacenames:
1361 for ri in rendered_ifacenames:
1362 ifaceobjs = self.get_ifaceobjs(ri)
1363 if not ifaceobjs:
1364 err_iface += ' ' + ri
1365 else:
1366 new_ifacenames.append(ri)
1367 else:
1368 err_iface += ' ' + i
1369 else:
1370 new_ifacenames.append(i)
1371 if err_iface:
1372 raise Exception('cannot find interfaces:%s' %err_iface)
1373 return new_ifacenames
1374
1375 def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
1376 """ Checks if interface is whitelisted depending on set of parameters.
1377
1378 interfaces are checked against the allow_classes and auto lists.
1379
1380 """
1381
1382 ret = True
1383
1384 # Check if interface matches the exclude patter
1385 if excludepats:
1386 for e in excludepats:
1387 if re.search(e, ifacename):
1388 ret = False
1389 ifaceobjs = self.get_ifaceobjs(ifacename)
1390 if not ifaceobjs:
1391 if ret:
1392 self.logger.debug('iface %s' %ifacename + ' not found')
1393 return ret
1394 # If matched exclude pattern, return false
1395 if not ret:
1396 for i in ifaceobjs:
1397 i.blacklisted = True
1398 self.blacklisted_ifaces_present = True
1399 return ret
1400 # Check if interface belongs to the class
1401 # the user is interested in, if not return false
1402 if allow_classes:
1403 ret = False
1404 for i in ifaceobjs:
1405 if i.classes:
1406 common = Set([allow_classes]).intersection(
1407 Set(i.classes))
1408 if common:
1409 ret = True
1410 if not ret:
1411 # If a class was requested and interface does not belong
1412 # to the class, only then mark the ifaceobjs as blacklisted
1413 self.blacklisted_ifaces_present = True
1414 for i in ifaceobjs:
1415 i.blacklisted = True
1416 return ret
1417 # If the user has requested auto class, check if the interface
1418 # is marked auto
1419 if auto:
1420 ret = False
1421 for i in ifaceobjs:
1422 if i.auto:
1423 ret = True
1424 if not ret:
1425 # If auto was requested and interface was not marked auto,
1426 # only then mark all of them as blacklisted
1427 self.blacklisted_ifaces_present = True
1428 for i in ifaceobjs:
1429 i.blacklisted = True
1430 return ret
1431
1432 def _compat_conv_op_to_mode(self, op):
1433 """ Returns old op name to work with existing scripts """
1434 if 'up' in op:
1435 return 'start'
1436 elif 'down' in op:
1437 return 'stop'
1438 else:
1439 return op
1440
1441 def generate_running_env(self, ifaceobj, op):
1442 """ Generates a dictionary with env variables required for
1443 an interface. Used to support script execution for interfaces.
1444 """
1445
1446 cenv = None
1447 iface_env = ifaceobj.get_env()
1448 if iface_env:
1449 cenv = os.environ
1450 if cenv:
1451 cenv.update(iface_env)
1452 else:
1453 cenv = iface_env
1454 else:
1455 cenv = {}
1456 cenv['MODE'] = self._compat_conv_op_to_mode(op)
1457 cenv['PHASE'] = op
1458
1459 return cenv
1460
1461 def _save_state(self):
1462 if (not self.flags.STATEMANAGER_ENABLE or
1463 not self.flags.STATEMANAGER_UPDATE):
1464 return
1465 try:
1466 # Update persistant iface states
1467 self.statemanager.save_state()
1468 except Exception, e:
1469 if self.logger.isEnabledFor(logging.DEBUG):
1470 t = sys.exc_info()[2]
1471 traceback.print_tb(t)
1472 self.logger.warning('error saving state (%s)' %str(e))
1473
1474 def set_type(self, type):
1475 if type == 'iface':
1476 self.type = ifaceType.IFACE
1477 elif type == 'vlan':
1478 self.type = ifaceType.BRIDGE_VLAN
1479 else:
1480 self.type = ifaceType.UNKNOWN
1481
1482 def _process_delay_admin_state_queue(self, op):
1483 if not self._delay_admin_state_iface_queue:
1484 return
1485 if op == 'up':
1486 func = self.link_up
1487 elif op == 'down':
1488 func = self.link_down
1489 else:
1490 return
1491 for i in self._delay_admin_state_iface_queue:
1492 try:
1493 if self.link_exists(i):
1494 func(i)
1495 except Exception, e:
1496 self.logger.warn(str(e))
1497 pass
1498
1499 def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
1500 excludepats=None, printdependency=None, syntaxcheck=False,
1501 type=None, skipupperifaces=False):
1502 """This brings the interface(s) up
1503
1504 Args:
1505 ops (list): list of ops to perform on the interface(s).
1506 Eg: ['pre-up', 'up', 'post-up'
1507
1508 Kwargs:
1509 auto (bool): act on interfaces marked auto
1510 allow_classes (list): act on interfaces belonging to classes in the list
1511 ifacenames (list): act on interfaces specified in this list
1512 excludepats (list): list of patterns of interfaces to exclude
1513 syntaxcheck (bool): only perform syntax check
1514 """
1515
1516 self.set_type(type)
1517
1518 if allow_classes:
1519 ifupdownflags.flags.CLASS = True
1520 if not self.flags.ADDONS_ENABLE:
1521 self.flags.STATEMANAGER_UPDATE = False
1522 if auto:
1523 ifupdownflags.flags.ALL = True
1524 ifupdownflags.flags.WITH_DEPENDS = True
1525 try:
1526 iface_read_ret = self.read_iface_config()
1527 except Exception:
1528 raise
1529
1530 if ifacenames:
1531 ifacenames = self._preprocess_ifacenames(ifacenames)
1532
1533 # if iface list not given by user, assume all from config file
1534 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1535
1536 # filter interfaces based on auto and allow classes
1537 filtered_ifacenames = [i for i in ifacenames
1538 if self._iface_whitelisted(auto, allow_classes,
1539 excludepats, i)]
1540 if not filtered_ifacenames:
1541 raise Exception('no ifaces found matching given allow lists')
1542
1543 if printdependency:
1544 self.populate_dependency_info(ops, filtered_ifacenames)
1545 self.print_dependency(filtered_ifacenames, printdependency)
1546 return
1547 else:
1548 self.populate_dependency_info(ops)
1549
1550 # If only syntax check was requested, return here.
1551 # return here because we want to make sure most
1552 # errors above are caught and reported.
1553 if syntaxcheck:
1554 if not self._module_syntax_check(filtered_ifacenames):
1555 raise Exception()
1556 if not iface_read_ret:
1557 raise Exception()
1558 elif self._any_iface_errors(filtered_ifacenames):
1559 raise Exception()
1560 return
1561
1562 ret = None
1563 try:
1564 ret = self._sched_ifaces(filtered_ifacenames, ops,
1565 skipupperifaces=skipupperifaces,
1566 followdependents=True
1567 if ifupdownflags.flags.WITH_DEPENDS
1568 else False)
1569 finally:
1570 self._process_delay_admin_state_queue('up')
1571 if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE:
1572 self._save_state()
1573
1574 if not iface_read_ret or not ret:
1575 raise Exception()
1576
1577 def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
1578 excludepats=None, printdependency=None, usecurrentconfig=False,
1579 type=None):
1580 """ down an interface """
1581
1582 self.set_type(type)
1583
1584 if allow_classes:
1585 ifupdownflags.flags.CLASS = True
1586 if not self.flags.ADDONS_ENABLE:
1587 self.flags.STATEMANAGER_UPDATE = False
1588 if auto:
1589 ifupdownflags.flags.ALL = True
1590 ifupdownflags.flags.WITH_DEPENDS = True
1591 # For down we need to look at old state, unless usecurrentconfig
1592 # is set
1593 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE and
1594 self.statemanager.ifaceobjdict):
1595 # Since we are using state manager objects,
1596 # skip the updating of state manager objects
1597 self.logger.debug('Looking at old state ..')
1598 self.read_old_iface_config()
1599 else:
1600 # If no old state available
1601 try:
1602 self.read_iface_config()
1603 except Exception, e:
1604 raise Exception('error reading iface config (%s)' %str(e))
1605 if ifacenames:
1606 # If iface list is given by the caller, always check if iface
1607 # is present
1608 try:
1609 ifacenames = self._preprocess_ifacenames(ifacenames)
1610 except Exception, e:
1611 raise Exception('%s' %str(e) +
1612 ' (interface was probably never up ?)')
1613
1614 # if iface list not given by user, assume all from config file
1615 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1616
1617 # filter interfaces based on auto and allow classes
1618 filtered_ifacenames = [i for i in ifacenames
1619 if self._iface_whitelisted(auto, allow_classes,
1620 excludepats, i)]
1621 if not filtered_ifacenames:
1622 raise Exception('no ifaces found matching given allow lists ' +
1623 '(or interfaces were probably never up ?)')
1624
1625 if printdependency:
1626 self.populate_dependency_info(ops, filtered_ifacenames)
1627 self.print_dependency(filtered_ifacenames, printdependency)
1628 return
1629 else:
1630 self.populate_dependency_info(ops)
1631
1632 try:
1633 self._sched_ifaces(filtered_ifacenames, ops,
1634 followdependents=True
1635 if ifupdownflags.flags.WITH_DEPENDS else False)
1636 finally:
1637 self._process_delay_admin_state_queue('down')
1638 if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE:
1639 self._save_state()
1640
1641 def query(self, ops, auto=False, format_list=False, allow_classes=None,
1642 ifacenames=None,
1643 excludepats=None, printdependency=None,
1644 format='native', type=None):
1645 """ query an interface """
1646
1647 self.set_type(type)
1648
1649 # Let us forget internal squashing when it comes to
1650 # ifquery. It can surprise people relying of ifquery
1651 # output
1652 self._ifaceobj_squash_internal = False
1653
1654 if allow_classes:
1655 ifupdownflags.flags.CLASS = True
1656 if self.flags.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
1657 return self.statemanager.dump_pretty(ifacenames)
1658 self.flags.STATEMANAGER_UPDATE = False
1659 if auto:
1660 self.logger.debug('setting flag ALL')
1661 ifupdownflags.flags.ALL = True
1662 ifupdownflags.flags.WITH_DEPENDS = True
1663
1664 if ops[0] == 'query-syntax':
1665 self._modules_help()
1666 return
1667 elif ops[0] == 'query-running':
1668 # create fake devices to all dependents that dont have config
1669 map(lambda i: self.create_n_save_ifaceobj(i,
1670 ifacePrivFlags(False, True)), ifacenames)
1671 else:
1672 try:
1673 self.read_iface_config()
1674 except Exception:
1675 raise
1676
1677 if ifacenames and ops[0] != 'query-running':
1678 # If iface list is given, always check if iface is present
1679 ifacenames = self._preprocess_ifacenames(ifacenames)
1680
1681 # if iface list not given by user, assume all from config file
1682 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1683
1684 # filter interfaces based on auto and allow classes
1685 if ops[0] == 'query-running':
1686 filtered_ifacenames = ifacenames
1687 else:
1688 filtered_ifacenames = [i for i in ifacenames
1689 if self._iface_whitelisted(auto, allow_classes,
1690 excludepats, i)]
1691 if not filtered_ifacenames:
1692 raise Exception('no ifaces found matching ' +
1693 'given allow lists')
1694
1695 self.populate_dependency_info(ops)
1696 if ops[0] == 'query-dependency' and printdependency:
1697 self.print_dependency(filtered_ifacenames, printdependency)
1698 return
1699
1700 if format_list and (ops[0] == 'query' or ops[0] == 'query-raw'):
1701 return self.print_ifaceobjs_list(filtered_ifacenames)
1702
1703 if ops[0] == 'query' and not ifupdownflags.flags.WITHDEFAULTS:
1704 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
1705 elif ops[0] == 'query-raw':
1706 return self.print_ifaceobjs_raw(filtered_ifacenames)
1707
1708 ret = self._sched_ifaces(filtered_ifacenames, ops,
1709 followdependents=True
1710 if ifupdownflags.flags.WITH_DEPENDS else False)
1711
1712 if ops[0] == 'query' and ifupdownflags.flags.WITHDEFAULTS:
1713 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
1714 elif ops[0] == 'query-checkcurr':
1715 ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
1716 if ret != 0:
1717 # if any of the object has an error, signal that silently
1718 raise Exception('')
1719 elif ops[0] == 'query-running':
1720 self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
1721 return
1722
1723 def _reload_currentlyup(self, upops, downops, auto=False, allow=None,
1724 ifacenames=None, excludepats=None, usecurrentconfig=False,
1725 syntaxcheck=False, **extra_args):
1726 """ reload currently up interfaces """
1727 new_ifaceobjdict = {}
1728
1729 self.logger.info('reloading interfaces that are currently up ..')
1730
1731 try:
1732 iface_read_ret = self.read_iface_config()
1733 except:
1734 raise
1735 if not self.ifaceobjdict:
1736 self.logger.warn("nothing to reload ..exiting.")
1737 return
1738 already_up_ifacenames = []
1739 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1740
1741 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
1742 and self.statemanager.ifaceobjdict):
1743 already_up_ifacenames = self.statemanager.ifaceobjdict.keys()
1744
1745 # Get already up interfaces that still exist in the interfaces file
1746 already_up_ifacenames_not_present = Set(
1747 already_up_ifacenames).difference(ifacenames)
1748 already_up_ifacenames_still_present = Set(
1749 already_up_ifacenames).difference(
1750 already_up_ifacenames_not_present)
1751
1752 interfaces_to_up = already_up_ifacenames_still_present
1753
1754 # generate dependency graph of interfaces
1755 self.populate_dependency_info(upops, interfaces_to_up)
1756
1757 # If only syntax check was requested, return here.
1758 # return here because we want to make sure most
1759 # errors above are caught and reported.
1760 if syntaxcheck:
1761 if not self._module_syntax_check(interfaces_to_up):
1762 raise Exception()
1763 if not iface_read_ret:
1764 raise Exception()
1765 elif self._any_iface_errors(interfaces_to_up):
1766 raise Exception()
1767 return
1768
1769 if (already_up_ifacenames_not_present and
1770 self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
1771 self.logger.info('reload: schedule down on interfaces: %s'
1772 %str(already_up_ifacenames_not_present))
1773
1774 # Save a copy of new iface objects and dependency_graph
1775 new_ifaceobjdict = dict(self.ifaceobjdict)
1776 new_dependency_graph = dict(self.dependency_graph)
1777
1778 # old interface config is read into self.ifaceobjdict
1779 self.read_old_iface_config()
1780
1781 # reinitialize dependency graph
1782 self.dependency_graph = OrderedDict({})
1783 falready_up_ifacenames_not_present = [i for i in
1784 already_up_ifacenames_not_present
1785 if self._iface_whitelisted(auto, allow,
1786 excludepats, i)]
1787 self.populate_dependency_info(downops,
1788 falready_up_ifacenames_not_present)
1789 self._sched_ifaces(falready_up_ifacenames_not_present, downops,
1790 followdependents=False, sort=True)
1791 else:
1792 self.logger.info('no interfaces to down ..')
1793
1794 # Now, run 'up' with new config dict
1795 # reset statemanager update flag to default
1796 if auto:
1797 ifupdownflags.flags.ALL = True
1798 ifupdownflags.flags.WITH_DEPENDS = True
1799 if new_ifaceobjdict:
1800 # and now, ifaceobjdict is back to current config
1801 self.ifaceobjdict = new_ifaceobjdict
1802 self.dependency_graph = new_dependency_graph
1803
1804 if not self.ifaceobjdict:
1805 self.logger.info('no interfaces to up')
1806 return
1807 self.logger.info('reload: scheduling up on interfaces: %s'
1808 %str(interfaces_to_up))
1809 ret = self._sched_ifaces(interfaces_to_up, upops,
1810 followdependents=True
1811 if ifupdownflags.flags.WITH_DEPENDS else False)
1812 if ifupdownflags.flags.DRYRUN:
1813 return
1814 self._save_state()
1815
1816 if not iface_read_ret or not ret:
1817 raise Exception()
1818
1819 def _reload_default(self, upops, downops, auto=False, allow=None,
1820 ifacenames=None, excludepats=None, usecurrentconfig=False,
1821 syntaxcheck=False, **extra_args):
1822 """ reload interface config """
1823 new_ifaceobjdict = {}
1824
1825 try:
1826 iface_read_ret = self.read_iface_config()
1827 except:
1828 raise
1829
1830 if not self.ifaceobjdict:
1831 self.logger.warn("nothing to reload ..exiting.")
1832 return
1833
1834 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1835 new_filtered_ifacenames = [i for i in ifacenames
1836 if self._iface_whitelisted(auto, allow,
1837 excludepats, i)]
1838 # generate dependency graph of interfaces
1839 self.populate_dependency_info(upops)
1840
1841 # If only syntax check was requested, return here.
1842 # return here because we want to make sure most
1843 # errors above are caught and reported.
1844 if syntaxcheck:
1845 if not self._module_syntax_check(new_filtered_ifacenames):
1846 raise Exception()
1847 if not iface_read_ret:
1848 raise Exception()
1849 elif self._any_iface_errors(new_filtered_ifacenames):
1850 raise Exception()
1851 return
1852
1853 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
1854 and self.statemanager.ifaceobjdict):
1855 # Save a copy of new iface objects and dependency_graph
1856 new_ifaceobjdict = dict(self.ifaceobjdict)
1857 new_dependency_graph = dict(self.dependency_graph)
1858
1859 self.ifaceobjdict = OrderedDict({})
1860 self.dependency_graph = OrderedDict({})
1861
1862 # if old state is present, read old state and mark op for 'down'
1863 # followed by 'up' aka: reload
1864 # old interface config is read into self.ifaceobjdict
1865 self.read_old_iface_config()
1866 op = 'reload'
1867 else:
1868 # oldconfig not available, continue with 'up' with new config
1869 op = 'up'
1870 new_ifaceobjdict = self.ifaceobjdict
1871 new_dependency_graph = self.dependency_graph
1872
1873 if op == 'reload' and ifacenames:
1874 ifacenames = self.ifaceobjdict.keys()
1875 old_filtered_ifacenames = [i for i in ifacenames
1876 if self._iface_whitelisted(auto, allow,
1877 excludepats, i)]
1878
1879 # generate dependency graph of old interfaces,
1880 # This should make sure built in interfaces are
1881 # populated. disable check shared dependents as an optimization.
1882 # these are saved interfaces and dependency for these
1883 # have been checked before they became part of saved state.
1884 try:
1885 self.flags.CHECK_SHARED_DEPENDENTS = False
1886 self.populate_dependency_info(upops)
1887 self.flags.CHECK_SHARED_DEPENDENTS = True
1888 except Exception, e:
1889 self.logger.info("error generating dependency graph for "
1890 "saved interfaces (%s)" %str(e))
1891 pass
1892
1893 # make sure we pick up built-in interfaces
1894 # if config file had 'ifreload_down_changed' variable
1895 # set, also look for interfaces that changed to down them
1896 down_changed = int(self.config.get('ifreload_down_changed', '1'))
1897
1898 # Generate the interface down list
1899 # Interfaces that go into the down list:
1900 # - interfaces that were present in last config and are not
1901 # present in the new config
1902 # - interfaces that were changed between the last and current
1903 # config
1904 ifacedownlist = []
1905 for ifname in self.ifaceobjdict.keys():
1906 lastifaceobjlist = self.ifaceobjdict.get(ifname)
1907 if not self.is_ifaceobj_builtin(lastifaceobjlist[0]):
1908 # if interface is not built-in and is not in
1909 # old filtered ifacenames
1910 if ifname not in old_filtered_ifacenames:
1911 continue
1912 objidx = 0
1913 # If interface is not present in the new file
1914 # append it to the down list
1915 newifaceobjlist = new_ifaceobjdict.get(ifname)
1916 if not newifaceobjlist:
1917 ifacedownlist.append(ifname)
1918 continue
1919 # If ifaceobj was present in the old interfaces file,
1920 # and does not have a config in the new interfaces file
1921 # but has been picked up as a dependent of another
1922 # interface, catch it here. This catches a common error
1923 # for example: remove a bond section from the interfaces
1924 # file, but leave it around as a bridge port
1925 # XXX: Ideally its better to just add it to the
1926 # ifacedownlist. But we will be cautious here
1927 # and just print a warning
1928 if (self.is_ifaceobj_noconfig(newifaceobjlist[0]) and
1929 not self.is_ifaceobj_builtin(newifaceobjlist[0]) and
1930 lastifaceobjlist[0].is_config_present() and
1931 lastifaceobjlist[0].link_kind):
1932 self.logger.warn('%s: misconfig ? removed but still exists '
1933 'as a dependency of %s.\nPlease remove '
1934 'the dependency manually `ifdown %s` if '
1935 'it is being picked up as part of a regex'
1936 % (newifaceobjlist[objidx].name,
1937 str(newifaceobjlist[objidx].upperifaces),
1938 newifaceobjlist[objidx].name))
1939 if not down_changed:
1940 continue
1941 if len(newifaceobjlist) != len(lastifaceobjlist):
1942 ifacedownlist.append(ifname)
1943 continue
1944
1945 # If interface has changed between the current file
1946 # and the last installed append it to the down list
1947 # compare object list
1948 for objidx in range(0, len(lastifaceobjlist)):
1949 oldobj = lastifaceobjlist[objidx]
1950 newobj = newifaceobjlist[objidx]
1951 if not newobj.compare(oldobj):
1952 ifacedownlist.append(ifname)
1953 continue
1954
1955 if ifacedownlist:
1956 self.logger.info('reload: scheduling down on interfaces: %s'
1957 %str(ifacedownlist))
1958 # reinitialize dependency graph
1959 self.dependency_graph = OrderedDict({})
1960
1961 # Generate dependency info for old config
1962 self.flags.CHECK_SHARED_DEPENDENTS = False
1963 self.populate_dependency_info(downops, ifacedownlist)
1964 self.flags.CHECK_SHARED_DEPENDENTS = True
1965
1966 try:
1967 # XXX: Hack to skip checking upperifaces during down.
1968 # the dependency list is not complete here
1969 # and we dont want to down the upperiface.
1970 # Hence during reload, set this to true.
1971 # This is being added to avoid a failure in
1972 # scheduler._check_upperifaces when we are dowing
1973 # a builtin bridge port
1974 self.flags.SCHED_SKIP_CHECK_UPPERIFACES = True
1975 self._sched_ifaces(ifacedownlist, downops,
1976 followdependents=False,
1977 sort=True)
1978 except Exception, e:
1979 self.logger.error(str(e))
1980 pass
1981 finally:
1982 self.flags.SCHED_SKIP_CHECK_UPPERIFACES = False
1983 self._process_delay_admin_state_queue('down')
1984 else:
1985 self.logger.info('no interfaces to down ..')
1986
1987 # Now, run 'up' with new config dict
1988 # reset statemanager update flag to default
1989 if not new_ifaceobjdict:
1990 self.logger.debug('no interfaces to up')
1991 return
1992
1993 if auto:
1994 ifupdownflags.flags.ALL = True
1995 ifupdownflags.flags.WITH_DEPENDS = True
1996 # and now, we are back to the current config in ifaceobjdict
1997 self.ifaceobjdict = new_ifaceobjdict
1998 self.dependency_graph = new_dependency_graph
1999
2000 self.logger.info('reload: scheduling up on interfaces: %s'
2001 %str(new_filtered_ifacenames))
2002 ifupdownflags.flags.CACHE = True
2003 try:
2004 ret = self._sched_ifaces(new_filtered_ifacenames, upops,
2005 followdependents=True
2006 if ifupdownflags.flags.WITH_DEPENDS
2007 else False)
2008 except Exception, e:
2009 ret = None
2010 self.logger.error(str(e))
2011 finally:
2012 self._process_delay_admin_state_queue('up')
2013 if ifupdownflags.flags.DRYRUN:
2014 return
2015 self._save_state()
2016
2017 if not iface_read_ret or not ret:
2018 raise Exception()
2019
2020 def reload(self, *args, **kargs):
2021 """ reload interface config """
2022 self.logger.debug('reloading interface config ..')
2023 if kargs.get('currentlyup', False):
2024 self._reload_currentlyup(*args, **kargs)
2025 else:
2026 self._reload_default(*args, **kargs)
2027
2028 def _any_iface_errors(self, ifacenames):
2029 for i in ifacenames:
2030 ifaceobjs = self.get_ifaceobjs(i)
2031 if not ifaceobjs: continue
2032 for ifaceobj in ifaceobjs:
2033 if (ifaceobj.status == ifaceStatus.NOTFOUND or
2034 ifaceobj.status == ifaceStatus.ERROR):
2035 return True
2036 return False
2037
2038 def _pretty_print_ordered_dict(self, prefix, argdict):
2039 outbuf = prefix + ' {\n'
2040 for k, vlist in argdict.items():
2041 outbuf += '\t%s : %s\n' %(k, str(vlist))
2042 self.logger.debug(outbuf + '}')
2043
2044 def print_dependency(self, ifacenames, format):
2045 """ prints iface dependency information """
2046
2047 if not ifacenames:
2048 ifacenames = self.ifaceobjdict.keys()
2049 if format == 'list':
2050 for k,v in self.dependency_graph.items():
2051 print '%s : %s' %(k, str(v))
2052 elif format == 'dot':
2053 indegrees = {}
2054 map(lambda i: indegrees.update({i :
2055 self.get_iface_refcnt(i)}),
2056 self.dependency_graph.keys())
2057 graph.generate_dots(self.dependency_graph, indegrees)
2058
2059 def print_ifaceobjs_list(self, ifacenames):
2060 for i in ifacenames:
2061 print i
2062
2063 def print_ifaceobjs_raw(self, ifacenames):
2064 """ prints raw lines for ifaces from config file """
2065
2066 for i in ifacenames:
2067 for ifaceobj in self.get_ifaceobjs(i):
2068 if (self.is_ifaceobj_builtin(ifaceobj) or
2069 not ifaceobj.is_config_present()):
2070 continue
2071 ifaceobj.dump_raw(self.logger)
2072 print '\n'
2073 if (ifupdownflags.flags.WITH_DEPENDS and
2074 not ifupdownflags.flags.ALL):
2075 dlist = ifaceobj.lowerifaces
2076 if not dlist: continue
2077 self.print_ifaceobjs_raw(dlist)
2078
2079 def _get_ifaceobjs_pretty(self, ifacenames, ifaceobjs, running=False):
2080 """ returns iface obj list """
2081
2082 for i in ifacenames:
2083 for ifaceobj in self.get_ifaceobjs(i):
2084 if ((not running and self.is_ifaceobj_noconfig(ifaceobj)) or
2085 (running and not ifaceobj.is_config_present() and
2086 not self.is_iface_builtin_byname(i) and
2087 not ifaceobj.upperifaces)):
2088 continue
2089 ifaceobjs.append(ifaceobj)
2090 if (ifupdownflags.flags.WITH_DEPENDS and
2091 not ifupdownflags.flags.ALL):
2092 dlist = ifaceobj.lowerifaces
2093 if not dlist: continue
2094 self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
2095
2096 def print_ifaceobjs_pretty(self, ifacenames, format='native'):
2097 """ pretty prints iface in format given by keyword arg format """
2098
2099 ifaceobjs = []
2100 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
2101 if not ifaceobjs: return
2102 if format == 'json':
2103 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
2104 indent=4, separators=(',', ': '))
2105 else:
2106 expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
2107 for i in ifaceobjs:
2108 if not expand and (i.flags & iface.IFACERANGE_ENTRY):
2109 # print only the first one
2110 if i.flags & iface.IFACERANGE_START:
2111 i.dump_pretty(use_realname=True)
2112 else:
2113 i.dump_pretty()
2114
2115 def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
2116 ret = 0
2117 for i in ifacenames:
2118 ifaceobjscurr = self.get_ifaceobjcurr(i)
2119 if not ifaceobjscurr: continue
2120 for ifaceobj in ifaceobjscurr:
2121 if (ifaceobj.status == ifaceStatus.NOTFOUND or
2122 ifaceobj.status == ifaceStatus.ERROR):
2123 ret = 1
2124 if self.is_ifaceobj_noconfig(ifaceobj):
2125 continue
2126 ifaceobjs.append(ifaceobj)
2127 if (ifupdownflags.flags.WITH_DEPENDS and
2128 not ifupdownflags.flags.ALL):
2129 dlist = ifaceobj.lowerifaces
2130 if not dlist: continue
2131 dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
2132 if dret: ret = 1
2133 return ret
2134
2135 def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
2136 """ pretty prints current running state of interfaces with status.
2137
2138 returns 1 if any of the interface has an error,
2139 else returns 0
2140 """
2141
2142 ifaceobjs = []
2143 ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
2144 if not ifaceobjs: return
2145
2146 # override ifaceStatusUserStrs
2147 ifaceStatusUserStrs.SUCCESS = self.config.get('ifquery_check_success_str', _success_sym)
2148 ifaceStatusUserStrs.ERROR = self.config.get('ifquery_check_error_str', _error_sym)
2149 ifaceStatusUserStrs.UNKNOWN = self.config.get('ifquery_check_unknown_str', '')
2150 if format == 'json':
2151 print json.dumps(ifaceobjs, cls=ifaceJsonEncoderWithStatus,
2152 indent=2, separators=(',', ': '))
2153 else:
2154 map(lambda i: i.dump_pretty(with_status=True), ifaceobjs)
2155 return ret
2156
2157 def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
2158 """ pretty prints iface running state """
2159
2160 ifaceobjs = []
2161 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs, running=True)
2162 if not ifaceobjs: return
2163 if format == 'json':
2164 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
2165 separators=(',', ': '))
2166 else:
2167 map(lambda i: i.dump_pretty(), ifaceobjs)
2168
2169 def _dump(self):
2170 print 'ifupdown main object dump'
2171 print self.pp.pprint(self.modules)
2172 print self.pp.pprint(self.ifaceobjdict)
2173
2174 def _dump_ifaceobjs(self, ifacenames):
2175 for i in ifacenames:
2176 ifaceobjs = self.get_ifaceobjs(i)
2177 for i in ifaceobjs:
2178 i.dump(self.logger)
2179 print '\n'