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