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