3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
12 from collections
import OrderedDict
14 from ipaddr
import IPNetwork
, IPv4Network
, IPv6Network
, IPAddress
, IPv4Address
, IPv6Address
17 import ifupdown2
.ifupdownaddons
.cache
18 import ifupdown2
.ifupdownaddons
.LinkUtils
19 import ifupdown2
.ifupdownaddons
.mstpctlutil
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
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
34 import ifupdownaddons
.cache
35 import ifupdownaddons
.LinkUtils
36 import ifupdownaddons
.mstpctlutil
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
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
53 .. module:: ifupdownmain
54 :synopsis: main module for ifupdown package
56 .. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
61 _crossmark
= u
'\u2717'
62 _success_sym
= '(%s)' %_tickmark
63 _error_sym
= '(%s)' %_crossmark
65 class ifupdownMainFlags():
66 COMPAT_EXEC_SCRIPTS
= False
67 STATEMANAGER_ENABLE
= True
68 STATEMANAGER_UPDATE
= True
70 DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
= False
71 SCHED_SKIP_CHECK_UPPERIFACES
= False
72 CHECK_SHARED_DEPENDENTS
= True
74 class ifacePrivFlags():
75 # priv flags to mark iface objects
79 def __init__(self
, builtin
=False, noconfig
=False):
80 self
.BUILTIN
= builtin
81 self
.NOCONFIG
= noconfig
83 class ifupdownMain(ifupdownBase
):
84 """ ifupdown2 main class """
86 scripts_dir
= '/etc/network'
87 addon_modules_dir
= ADDON_MODULES_DIR
88 addon_modules_configfile
= ADDONS_CONF_PATH
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
:
96 if ((ifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
97 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
98 self
._keep
_link
_down
(ifaceobj
)
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
):
105 if self
._delay
_admin
_state
:
106 self
._delay
_admin
_state
_iface
_queue
.append(ifaceobj
.name
)
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
:
114 if not self
.link_exists(ifaceobj
.name
):
116 if self
._keep
_link
_down
(ifaceobj
):
118 self
.link_up(ifaceobj
.name
)
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
)
129 def run_down(self
, ifaceobj
):
130 if ((ifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
131 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
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
:
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
):
142 if self
._delay
_admin
_state
:
143 self
._delay
_admin
_state
_iface
_queue
.append(ifaceobj
.name
)
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
:
151 if not self
.link_exists(ifaceobj
.name
):
153 self
.link_down(ifaceobj
.name
)
155 # ifupdown object interface operation handlers
156 ops_handlers
= OrderedDict([('up', run_up
),
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
)):
163 if self
.flags
.STATEMANAGER_UPDATE
:
164 self
.statemanager
.ifaceobj_sync(ifaceobj
, op
)
166 # ifupdown object interface scheduler pre and posthooks
167 sched_hooks
= {'posthook' : run_sched_ifaceobj_posthook
}
169 def reset_ifupdown2(self
):
170 ifaceScheduler
.reset()
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()
179 ifupdown2
.ifupdownaddons
.cache
.linkCache
.reset()
180 ifupdown2
.ifupdownaddons
.cache
.MSTPAttrsCache
.invalidate()
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',
190 """This member function initializes the ifupdownmain object.
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'
201 AttributeError, KeyError """
204 self
.reset_ifupdown2()
206 # iface dictionary in the below format:
207 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
209 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
211 # Each ifaceobject corresponds to a configuration block for
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()
218 # iface dictionary representing the curr running state of an iface
219 # in the below format:
220 # {'<ifacename>' : <ifaceobject>}
221 self
.ifaceobjcurrdict
= OrderedDict()
223 # Dictionary representing operation and modules
224 # for every operation
225 self
.module_ops
= OrderedDict([('pre-up', []),
228 ('query-checkcurr', []),
229 ('query-running', []),
230 ('query-dependency', []),
237 # For old style /etc/network/ bash scripts
238 self
.script_ops
= OrderedDict([('pre-up', []),
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
255 # Can be used to provide hints for caching
256 ifupdownflags
.flags
.CACHE_FLAGS
= 0x0
258 self
.flags
= ifupdownMainFlags()
260 self
.flags
.STATEMANAGER_ENABLE
= statemanager_enable
261 self
.interfacesfile
= interfacesfile
262 self
.interfacesfileiobuf
= interfacesfileiobuf
263 self
.interfacesfileformat
= interfacesfileformat
265 self
.logger
.debug(self
.config
)
266 self
.blacklisted_ifaces_present
= False
268 self
.type = ifaceType
.UNKNOWN
270 self
.flags
.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
= False
271 self
.flags
.ADDONS_ENABLE
= addons_enable
273 self
.ifaces
= OrderedDict()
275 self
.pp
= pprint
.PrettyPrinter(indent
=4)
276 self
.modules
= OrderedDict({})
277 self
.module_attrs
= {}
278 self
.overridden_ifupdown_scripts
= []
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({})
286 self
._cache
_no
_repeats
= {}
288 if self
.flags
.STATEMANAGER_ENABLE
:
289 self
.statemanager
= statemanager
.statemanager_api
291 self
.statemanager
.read_saved_state()
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
))
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.')
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.')
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
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
324 # initialize global config object with config passed by the user
325 # This makes config available to addon modules
326 ifupdownConfig
.config
= self
.config
328 self
.validate_keywords
= {
329 '<mac>': self
._keyword
_mac
,
330 '<text>': self
._keyword
_text
,
331 '<ipv4>': self
._keyword
_ipv
4,
332 '<ipv6>': self
._keyword
_ipv
6,
333 '<ip>': self
._keyword
_ip
,
334 '<number>': self
._keyword
_number
,
335 '<interface>': self
._keyword
_interface
,
336 '<ipv4-vrf-text>': self
._keyword
_ipv
4_vrf
_text
,
337 '<number-ipv4-list>': self
._keyword
_number
_ipv
4_list
,
338 '<interface-list>': self
._keyword
_interface
_list
,
339 '<ipv4/prefixlen>': self
._keyword
_ipv
4_prefixlen
,
340 '<ipv6/prefixlen>': self
._keyword
_ipv
6_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
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
:
371 def get_ifaceobjs(self
, ifacename
):
372 return self
.ifaceobjdict
.get(ifacename
)
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
)
381 def get_ifaceobj_first(self
, ifacename
):
382 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
387 def get_ifacenames(self
):
388 return self
.ifaceobjdict
.keys()
390 def get_iface_obj_last(self
, ifacename
):
391 return self
.ifaceobjdict
.get(ifacename
)[-1]
394 def must_follow_upperifaces(self
, ifacename
):
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
402 ifaceobj
= self
.get_ifaceobj_first(ifacename
)
403 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
407 def create_n_save_ifaceobj(self
, ifacename
, priv_flags
=None,
409 """ creates a iface object and adds it to the iface dictionary """
411 ifaceobj
.name
= ifacename
412 ifaceobj
.priv_flags
= priv_flags
414 if not self
._link
_master
_slave
:
415 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
417 ifaceobj
.inc_refcnt()
418 self
.ifaceobjdict
[ifacename
] = [ifaceobj
]
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
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
)
435 def get_ifaceobjcurr(self
, ifacename
, idx
=0):
436 ifaceobjlist
= self
.ifaceobjcurrdict
.get(ifacename
)
442 return ifaceobjlist
[idx
]
444 def get_ifaceobjrunning(self
, ifacename
):
445 return self
.ifaceobjrunningdict
.get(ifacename
)
447 def get_iface_refcnt(self
, ifacename
):
448 """ Return iface ref count """
450 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
458 def is_iface_builtin_byname(self
, ifacename
):
459 """ Returns true if iface name is a builtin interface.
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>
465 return '.' in ifacename
467 def is_ifaceobj_builtin(self
, ifaceobj
):
468 """ Returns true if iface name is a builtin interface.
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>
474 if (ifaceobj
.priv_flags
and ifaceobj
.priv_flags
.BUILTIN
):
478 def is_ifaceobj_noconfig(self
, ifaceobj
):
479 """ Returns true if iface object did not have a user defined config.
481 These interfaces appear only when they are dependents of interfaces
482 which have user defined config
484 return (ifaceobj
.priv_flags
and ifaceobj
.priv_flags
.NOCONFIG
)
486 def is_iface_noconfig(self
, ifacename
):
487 """ Returns true if iface has no config """
489 ifaceobj
= self
.get_ifaceobj_first(ifacename
)
490 if not ifaceobj
: return True
491 return self
.is_ifaceobj_noconfig(ifaceobj
)
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():
502 check_depends
= False
503 iobjs
= self
.get_ifaceobjs(ifacename
)
507 if (i
.dependency_type
== ifaceDependencyType
.MASTER_SLAVE
):
510 common
= Set(ifacedlist
).intersection(setdlist
)
512 self
.logger
.error('misconfig..?. iface %s and %s '
513 %(ifaceobj
.name
, ifacename
) +
514 'seem to share dependents/ports %s' %str
(list(common
)))
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"
522 ifaceLinkPrivFlags
.get_all_str(ifaceobj
.link_privflags
), str(ifaceobj
.upperifaces
)))
523 ifaceobj
.set_status(ifaceStatus
.ERROR
)
527 def _set_iface_role_n_kind(self
, ifaceobj
, upperifaceobj
):
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
535 if (upperifaceobj
.link_kind
& ifaceLinkKind
.BOND
):
536 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
537 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BOND_SLAVE
539 if (upperifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
540 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
541 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_PORT
543 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
) \
544 and (upperifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
545 upperifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VXLAN
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
557 upperifaceobj
.link_type
= ifaceLinkType
.LINK_NA
558 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
560 def dump_iface_dependency_info(self
):
561 """ debug funtion to print raw dependency
562 info - lower and upper devices"""
564 for ifacename
, ifaceobjs
in self
.ifaceobjdict
.iteritems():
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 []))
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
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
590 dilist
= self
.get_ifaceobjs(d
)
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)
602 ni
.add_to_upperifaces(upperifaceobj
.name
)
603 self
._set
_iface
_role
_n
_kind
(ni
, upperifaceobj
)
607 di
.add_to_upperifaces(upperifaceobj
.name
)
608 self
._set
_iface
_role
_n
_kind
(di
, upperifaceobj
)
612 def preprocess_upperiface(self
, lowerifaceobj
, ulist
, ops
):
614 if (lowerifaceobj
.upperifaces
and
615 u
in lowerifaceobj
.upperifaces
):
617 lowerifaceobj
.add_to_upperifaces(u
)
618 uifacelist
= self
.get_ifaceobjs(u
)
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
)
625 def query_lowerifaces(self
, ifaceobj
, ops
, ifacenames
, type=None):
626 """ Gets iface dependents by calling into respective modules """
629 # Get dependents for interface by querying respective modules
630 for module
in self
.modules
.values():
632 if ops
[0] == 'query-running':
633 if (not hasattr(module
,
634 'get_dependent_ifacenames_running')):
636 dlist
= module
.get_dependent_ifacenames_running(ifaceobj
)
638 if (not hasattr(module
, 'get_dependent_ifacenames')):
640 dlist
= module
.get_dependent_ifacenames(ifaceobj
,
643 self
.logger
.warn('%s: error getting dependent interfaces (%s)'
644 %(ifaceobj
.name
, str(e
)))
647 if dlist
: ret_dlist
.extend(dlist
)
648 return list(set(ret_dlist
))
650 def query_upperifaces(self
, ifaceobj
, ops
, ifacenames
, type=None):
651 """ Gets iface upperifaces by calling into respective modules """
654 # Get upperifaces for interface by querying respective modules
655 for module
in self
.modules
.values():
657 if ops
[0] == 'query-running':
658 if (not hasattr(module
,
659 'get_upper_ifacenames_running')):
661 ulist
= module
.get_upper_ifacenames_running(ifaceobj
)
663 if (not hasattr(module
, 'get_upper_ifacenames')):
665 ulist
= module
.get_upper_ifacenames(ifaceobj
, ifacenames
)
667 self
.logger
.warn('%s: error getting upper interfaces (%s)'
668 %(ifaceobj
.name
, str(e
)))
671 if ulist
: ret_ulist
.extend(ulist
)
672 return list(set(ret_ulist
))
674 def populate_dependency_info(self
, ops
, ifacenames
=None):
675 """ recursive function to generate iface dependency info """
678 ifacenames
= self
.ifaceobjdict
.keys()
680 iqueue
= deque(ifacenames
)
683 # Go through all modules and find dependent ifaces
686 ifaceobjs
= self
.get_ifaceobjs(i
)
689 dependents_processed
= False
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
)
697 dependents_processed
= True
699 dlist
= self
.query_lowerifaces(iobj
, ops
, ifacenames
)
703 self
.preprocess_upperiface(ifaceobj
, ulist
, ops
)
704 if dependents_processed
:
707 self
.preprocess_dependency_list(ifaceobj
,
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
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
719 iobj
.link_privflags |
= ifaceLinkPrivFlags
.LOOPBACK
721 self
.dependency_graph
[i
] = iobj
.lowerifaces
723 self
.dependency_graph
[i
] = []
725 if not self
.blacklisted_ifaces_present
:
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
)
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
742 difaceobjs
= self
.get_ifaceobjs(d
)
748 d
.upperifaces
.remove(i
)
750 self
.logger
.debug('error removing %s from %s upperifaces' %(i
, d
))
752 self
.logger
.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
753 del self
.dependency_graph
[i
]
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
))
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
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
):
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
]
785 if ifaceobj
.compare(currentifaceobjlist
[0]):
786 self
.logger
.warn('duplicate interface %s found' %ifaceobj
.name
)
788 for obj
in self
.ifaceobjdict
[ifaceobj
.name
]:
789 if obj
.type == ifaceobj
.type:
792 self
.ifaceobjdict
[ifaceobj
.name
].append(ifaceobj
)
794 def _save_iface(self
, ifaceobj
):
795 if self
._check
_config
_no
_repeats
(ifaceobj
):
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
806 if ifaceobj
.compare(currentifaceobjlist
[0]):
807 self
.logger
.warn('duplicate interface %s found' %ifaceobj
.name
)
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
)
819 def _keyword_text(self
, value
, validrange
=None):
820 return isinstance(value
, str) and len(value
) > 0
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}$',
828 def _keyword_check_list(self
, _list
, obj
, limit
=None):
830 if limit
and limit
> 0:
831 for i
in xrange(0, limit
):
833 return len(_list
) == limit
838 except Exception as e
:
839 self
.logger
.debug('keyword: check list: %s' % str(e
))
842 def _keyword_ipv4(self
, value
, validrange
=None):
843 return self
._keyword
_check
_list
(value
.split(), IPv4Address
, limit
=1)
845 def _keyword_ipv4_prefixlen(self
, value
, validrange
=None):
846 return self
._keyword
_check
_list
(value
.split(), IPv4Network
, limit
=1)
848 def _keyword_ipv6(self
, value
, validrange
=None):
849 return self
._keyword
_check
_list
(value
.split(), IPv6Address
, limit
=1)
851 def _keyword_ipv6_prefixlen(self
, value
, validrange
=None):
852 return self
._keyword
_check
_list
(value
.split(), IPv6Network
, limit
=1)
854 def _keyword_ip(self
, value
, validrange
=None):
855 return self
._keyword
_check
_list
(value
.split(), IPAddress
, limit
=1)
857 def _keyword_ip_prefixlen(self
, value
, validrange
=None):
858 return self
._keyword
_check
_list
(value
.split(), IPNetwork
, limit
=1)
860 def _keyword_mac_ip_prefixlen_list(self
, value
, validrange
=None):
862 <mac> <ip> [<ip> ...]
863 ex: address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24
869 if not self
._keyword
_mac
(res
[0]):
872 if not self
._keyword
_ip
_prefixlen
(ip
):
875 except Exception as e
:
876 self
.logger
.debug('keyword: mac ipaddr prefixlen: %s' % str(e
))
879 def _keyword_number_ipv4_list(self
, value
, validrange
=None):
881 <number>=<ipv4> [<number>=<ipv4> ...]
882 ex: bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1
885 elements
= value
.split(' ')
888 for elem
in elements
:
893 except Exception as e
:
894 self
.logger
.debug('keyword: number ipv4: %s' % str(e
))
897 def _keyword_interface(self
, ifacename
, validrange
=None):
898 return self
.get_ifaceobjs(ifacename
)
900 def _keyword_ipv4_vrf_text(self
, value
, validrange
=None):
903 ex: clagd-backup-ip 10.10.10.42 vrf blue
905 values
= value
.split()
908 if size
> 3 or size
< 1:
911 IPv4Address(values
[0])
913 if values
[1] != 'vrf':
916 if not self
._keyword
_text
(values
[2]):
919 except Exception as e
:
920 self
.logger
.debug('keyword: ipv4 vrf text: %s' % str(e
))
923 def _keyword_interface_list_with_value(self
, value
, validvals
):
924 values
= value
.split()
927 if values
[0] in validvals
:
930 iface_value
= v
.split('=')
931 size
= len(iface_value
)
933 if iface_value
[0] == 'glob' or iface_value
[0] == 'regex':
936 if not iface_value
[1] in validvals
:
939 except Exception as e
:
940 self
.logger
.debug('keyword: interface list with value: %s' % str(e
))
943 def _keyword_interface_on_off_list(self
, value
, validrange
=None):
945 <yes|no> | ( <interface>=<on|off> [<interface>=<on|off> ...] )
946 ex: bridge-learning swp1=on swp2=off
948 return self
._keyword
_interface
_list
_with
_value
(value
, ['on', 'off'])
950 def _keyword_interface_yes_no_list(self
, value
, validrange
=None):
952 <yes|no> | ( <interface>=<yes|no> [<interface>=<yes|no> ...] )
953 ex: mstpctl-portrestrrole swp1=yes swp2=no
955 return self
._keyword
_interface
_list
_with
_value
(value
, ['yes', 'no'])
957 def _keyword_interface_yes_no_auto_list(self
, value
, validrange
=None):
960 ( <interface>=<yes|no|auto> [<interface>=<yes|no|auto> ...] )
961 ex: mstpctl-portp2p swp1=yes swp2=no swp3=auto
963 return self
._keyword
_interface
_list
_with
_value
(value
,
964 ['yes', 'no', 'auto'])
966 def _keyword_interface_l2protocol_tunnel_list(self
, value
, validrange
=None):
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
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']:
983 for arg
in re
.split(',|\s*', value
):
984 if arg
not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
990 def _keyword_interface_yes_no_0_1_list(self
, value
, validrange
=None):
993 ( <interface>=<yes|no|0|1> [<interface>=<yes|no|0|1> ...] )
994 ex: bridge-portmcrouter swp1=yes swp2=yes swp3=1
996 return self
._keyword
_interface
_list
_with
_value
(value
,
997 ['yes', 'no', '1', '0', '2'])
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',
1005 def _keyword_interface_range_list_multiple_of_16(self
, value
, validrange
):
1006 return self
._keyword
_interface
_range
_list
(value
, validrange
, multiple
=16)
1008 def _keyword_interface_range_list(self
, value
, validrange
, multiple
=None):
1010 <number> | ( <interface>=<number> [ <interface>=number> ...] )
1011 ex: mstpctl-portpathcost swp1=0 swp2=1
1013 values
= value
.split()
1015 if len(values
) == 1 and '=' not in values
[0]:
1018 if n
< int(validrange
[0]) or n
> int(
1020 raise invalidValueError('value of out range "%s":'
1021 ' valid attribute range: %s'
1023 '-'.join(validrange
)))
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
))
1030 except invalidValueError
as e
:
1032 except Exception as e
:
1033 self
.logger
.debug('keyword: interface range list: %s'
1037 iface_value
= v
.split('=')
1038 size
= len(iface_value
)
1041 number
= int(iface_value
[1])
1042 if number
< int(validrange
[0]) or number
> int(
1044 raise invalidValueError(
1045 'value of out range "%s" for iface "%s":'
1046 ' valid attribute range: %s'
1049 '-'.join(validrange
)))
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
))
1056 except invalidValueError
as e
:
1058 except Exception as e
:
1059 self
.logger
.debug('keyword: interface range list: %s' % str(e
))
1062 def _keyword_interface_list(self
, value
, validrange
=None):
1064 [glob|regex] <interface> [ [glob|regex] <interface> ...]
1065 ex: bridge-ports swp1 swp2 glob swp3-5.100 regex (swp[6|7|8].100)
1067 interface_list
= value
.split()
1068 size
= len(interface_list
)
1071 if interface_list
[i
] == 'glob' or interface_list
[i
] == 'regex':
1074 if not self
._keyword
_interface
(interface_list
[i
]):
1079 def _keyword_number_range_list(self
, value
, validrange
=None):
1081 <number> [<number>-<number>]
1082 ex: bridge-vids 42 100-200
1084 number_list
= value
.split()
1087 while i
< len(number_list
):
1088 if '-' in number_list
[i
]:
1089 range = number_list
[i
].split('-')
1098 except Exception as e
:
1099 self
.logger
.debug('keyword: number range list: %s' % str(e
))
1102 def _keyword_number_interface_list(self
, value
, validrange
=None):
1104 <number> <interface> [<interface>... [<number> <interface> ... ]]
1105 bridge-waitport 42 swp1 swp2 swp3 9 swp4
1107 interface_list
= value
.split()
1108 if not interface_list
:
1111 int(interface_list
[0])
1113 for elem
in interface_list
[1:]:
1122 except Exception as e
:
1123 self
.logger
.debug('keyword: number interface list: %s' % str(e
))
1126 def _keyword_number(self
, value
, validrange
=None):
1130 except Exception as e
:
1131 self
.logger
.debug('keyword: number: %s' % str(e
))
1134 def _is_keyword(self
, value
):
1135 if isinstance(value
, tuple):
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
1143 def _check_validvals_value(self
, attrname
, value
, validvals
, validrange
):
1144 if validvals
and value
not in validvals
:
1146 for keyword
in validvals
:
1147 if self
._is
_keyword
(keyword
):
1149 if self
.validate_keywords
[keyword
](value
, validrange
):
1150 return {'result': True}
1152 if self
.validate_keywords
[keyword
](value
):
1153 return {'result': True}
1157 'message': 'invalid value "%s": valid attribute values: %s'
1158 % (value
, validvals
)
1160 elif validvals
and value
in validvals
:
1163 if len(validrange
) != 2:
1164 raise Exception('%s: invalid range in addon configuration'
1165 % '-'.join(validrange
))
1167 if _value
< int(validrange
[0]) or _value
> int(validrange
[1]):
1170 'message': 'value of out range "%s": '
1171 'valid attribute range: %s'
1172 % (value
, '-'.join(validrange
))
1174 return {'result': True}
1176 def _check_validvals(self
, ifacename
, module_name
, attrs
):
1177 ifaceobj
= self
.get_ifaceobjs(ifacename
)
1181 for attrname
, attrvalue
in ifaceobj
[0].config
.items():
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
,
1191 if not res
['result']:
1192 self
.logger
.warn('%s: %s: %s' %
1193 (ifacename
, attrname
, res
['message']))
1195 except Exception as e
:
1196 self
.logger
.warn('addon \'%s\': %s: %s' % (module_name
,
1202 def _module_syntax_check(self
, filtered_ifacenames
):
1204 for ifacename
in filtered_ifacenames
:
1205 for module
in self
.modules
.values():
1207 if hasattr(module
, '_modinfo'):
1208 if not self
._check
_validvals
(ifacename
,
1209 module
.__class
__.__name
__,
1210 module
._modinfo
.get('attrs', {})):
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
):
1216 except Exception, e
:
1217 self
.logger
.warn('%s: %s' % (ifacename
, str(e
)))
1221 def _iface_configattr_syntax_checker(self
, attrname
, attrval
):
1222 for m
, mdict
in self
.module_attrs
.items():
1225 attrsdict
= mdict
.get('attrs')
1227 a
= attrsdict
.get(attrname
)
1229 if a
.get('deprecated'):
1230 newa
= a
.get('new-attribute')
1232 self
.logger
.warn('attribute %s is deprecated. use %s instead.' %(attrname
, newa
))
1234 self
.logger
.warn('attribute %s is deprecated.'
1238 for key
in attrsdict
:
1239 if 'aliases' in attrsdict
[key
]:
1240 if attrname
in attrsdict
[key
]['aliases']:
1242 except AttributeError:
1246 def _ifaceobj_syntax_checker(self
, ifaceobj
):
1248 for attrname
, attrvalue
in ifaceobj
.config
.items():
1250 for k
, v
in self
.module_attrs
.items():
1251 if v
and v
.get('attrs', {}).get(attrname
):
1256 self
.logger
.warn('%s: unsupported attribute \'%s\'' \
1257 % (ifaceobj
.name
, attrname
))
1261 def read_iface_config(self
):
1262 """ Reads default network interface config /etc/network/interfaces. """
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
)
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
)
1279 if nifaces
.errors
or nifaces
.warns
:
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
)
1288 def _load_addon_modules_config(self
):
1289 """ Load addon modules config file """
1291 with
open(self
.addon_modules_configfile
, 'r') as f
:
1292 lines
= f
.readlines()
1295 litems
= l
.strip(' \n\t\r').split(',')
1296 if not litems
or len(litems
) < 2:
1298 operation
= litems
[0]
1300 self
.module_ops
[operation
].append(mname
)
1301 except Exception, e
:
1302 self
.logger
.warn('error reading line \'%s\' %s:' %(l
, str(e
)))
1305 def load_addon_modules(self
, modules_dir_list
):
1306 """ load python modules from modules_dir
1308 Default modules_dir is /usr/share/ifupdownmodules
1311 failed_import
= list()
1313 self
.logger
.info('loading builtin modules from %s' % str(modules_dir_list
))
1314 self
._load
_addon
_modules
_config
()
1316 for modules_dir
in modules_dir_list
:
1317 if not modules_dir
in sys
.path
:
1318 sys
.path
.insert(1, modules_dir
)
1320 for op
, mlist
in self
.module_ops
.items():
1322 if self
.modules
.get(mname
):
1324 mpath
= modules_dir
+ '/' + mname
+ '.py'
1325 if os
.path
.exists(mpath
) and mpath
not in failed_import
:
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
)
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'
1343 self
.modules
[mname
] = minstance
1345 self
.module_attrs
[mname
] = minstance
.get_modinfo()
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()
1358 def _keyword_number_comma_range_list(self
, value
, validrange
=None):
1359 return self
._keyword
_number
_range
_list
(value
.replace(',', ' '), validrange
=validrange
)
1362 def _modules_help(self
, fmt
):
1363 """ Prints addon modules supported syntax """
1367 for key
, value
in self
.modules
.items():
1368 if hasattr(value
, '_modinfo'):
1370 'mhelp': value
._modinfo
['mhelp'],
1371 'attrs': value
.merge_modinfo_with_policy_files()
1373 print json
.dumps(modinfos
)
1376 for m
, mdict
in self
.module_attrs
.items():
1379 print('%s: %s' %(m
, mdict
.get('mhelp')))
1380 attrdict
= self
.modules
[m
].merge_modinfo_with_policy_files()
1384 for attrname
, attrvaldict
in attrdict
.items():
1385 if attrvaldict
.get('compat', False):
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')
1394 print('%sdefault: %s' %(indent
+ ' ', default
))
1396 validrange
= attrvaldict
.get('validrange')
1398 print('%svalidrange: %s-%s'
1399 %(indent
+ ' ', validrange
[0], validrange
[1]))
1401 validvals
= attrvaldict
.get('validvals')
1403 print('%svalidvals: %s'
1404 %(indent
+ ' ', ','.join(validvals
)))
1406 examples
= attrvaldict
.get('example')
1410 print '%sexample:' %(indent
+ ' ')
1412 print '%s%s' %(indent
+ ' ', e
)
1417 def load_scripts(self
, modules_dir
):
1418 """ loading user modules from /etc/network/.
1420 Note that previously loaded python modules override modules found
1421 under /etc/network if any
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
)
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
:
1434 self
.script_ops
[op
].append(msubdir
+ '/' + module
)
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
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()
1455 def _render_ifacename(self
, ifacename
):
1457 vlan_match
= re
.match("^([\d]+)-([\d]+)", ifacename
)
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
1466 def _preprocess_ifacenames(self
, ifacenames
):
1467 """ validates interface list for config existance.
1469 returns -1 if one or more interface not found. else, returns 0
1474 for i
in ifacenames
:
1475 ifaceobjs
= self
.get_ifaceobjs(i
)
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
)
1483 err_iface
+= ' ' + ri
1485 new_ifacenames
.append(ri
)
1487 err_iface
+= ' ' + i
1489 new_ifacenames
.append(i
)
1491 raise Exception('cannot find interfaces:%s' %err_iface
)
1492 return new_ifacenames
1494 def _iface_whitelisted(self
, auto
, allow_classes
, excludepats
, ifacename
):
1495 """ Checks if interface is whitelisted depending on set of parameters.
1497 interfaces are checked against the allow_classes and auto lists.
1503 # Check if interface matches the exclude patter
1505 for e
in excludepats
:
1506 if re
.search(e
, ifacename
):
1508 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
1511 self
.logger
.debug('iface %s' %ifacename
+ ' not found')
1513 # If matched exclude pattern, return false
1516 i
.blacklisted
= True
1517 self
.blacklisted_ifaces_present
= True
1519 # Check if interface belongs to the class
1520 # the user is interested in, if not return false
1525 common
= Set(allow_classes
).intersection(
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
1534 i
.blacklisted
= True
1536 # If the user has requested auto class, check if the interface
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
1548 i
.blacklisted
= True
1551 def _compat_conv_op_to_mode(self
, op
):
1552 """ Returns old op name to work with existing scripts """
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.
1566 iface_env
= ifaceobj
.get_env()
1568 cenv
= dict(os
.environ
)
1570 cenv
.update(iface_env
)
1575 cenv
['MODE'] = self
._compat
_conv
_op
_to
_mode
(op
)
1580 def _save_state(self
):
1581 if (not self
.flags
.STATEMANAGER_ENABLE
or
1582 not self
.flags
.STATEMANAGER_UPDATE
):
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
))
1593 def set_type(self
, type):
1595 self
.type = ifaceType
.IFACE
1596 elif type == 'vlan':
1597 self
.type = ifaceType
.BRIDGE_VLAN
1599 self
.type = ifaceType
.UNKNOWN
1601 def _process_delay_admin_state_queue(self
, op
):
1602 if not self
._delay
_admin
_state
_iface
_queue
:
1607 func
= self
.link_down
1610 for i
in self
._delay
_admin
_state
_iface
_queue
:
1612 if self
.link_exists(i
):
1614 except Exception, e
:
1615 self
.logger
.warn(str(e
))
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
1624 ops (list): list of ops to perform on the interface(s).
1625 Eg: ['pre-up', 'up', 'post-up'
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
1638 ifupdownflags
.flags
.CLASS
= True
1639 if not self
.flags
.ADDONS_ENABLE
:
1640 self
.flags
.STATEMANAGER_UPDATE
= False
1642 ifupdownflags
.flags
.ALL
= True
1643 ifupdownflags
.flags
.WITH_DEPENDS
= True
1645 iface_read_ret
= self
.read_iface_config()
1649 filtered_ifacenames
= None
1651 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1654 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1656 # if iface list not given by user, assume all from config file
1657 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
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
,
1665 if not filtered_ifacenames
:
1666 raise Exception('no ifaces found matching given allow lists')
1669 self
.populate_dependency_info(ops
, filtered_ifacenames
)
1670 self
.print_dependency(filtered_ifacenames
, printdependency
)
1673 self
.populate_dependency_info(ops
)
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.
1679 if not self
._module
_syntax
_check
(filtered_ifacenames
):
1681 if not iface_read_ret
:
1683 elif self
._any
_iface
_errors
(filtered_ifacenames
):
1689 ret
= self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1690 skipupperifaces
=skipupperifaces
,
1691 followdependents
=True
1692 if ifupdownflags
.flags
.WITH_DEPENDS
1695 self
._process
_delay
_admin
_state
_queue
('up')
1696 if not ifupdownflags
.flags
.DRYRUN
and self
.flags
.ADDONS_ENABLE
:
1699 if not iface_read_ret
or not ret
:
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
1706 filtered_ifacenames
= [i
for i
in self
.ifaceobjdict
.keys()
1707 if self
._iface
_whitelisted
(auto
, allow_classes
,
1709 filtered_ifacenames
+= ifacenames
1711 for intf
in ifacenames
:
1712 for obj
in self
.get_ifaceobjs(intf
) or []:
1713 obj
.blacklisted
= False
1715 return filtered_ifacenames
1717 def down(self
, ops
, auto
=False, allow_classes
=None, ifacenames
=None,
1718 excludepats
=None, printdependency
=None, usecurrentconfig
=False,
1720 """ down an interface """
1725 ifupdownflags
.flags
.CLASS
= True
1726 if not self
.flags
.ADDONS_ENABLE
:
1727 self
.flags
.STATEMANAGER_UPDATE
= False
1729 ifupdownflags
.flags
.ALL
= True
1730 ifupdownflags
.flags
.WITH_DEPENDS
= True
1731 # For down we need to look at old state, unless usecurrentconfig
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()
1740 # If no old state available
1742 self
.read_iface_config()
1743 except Exception, e
:
1744 raise Exception('error reading iface config (%s)' %str
(e
))
1745 filtered_ifacenames
= None
1747 # If iface list is given by the caller, always check if iface
1750 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1753 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1755 except Exception, e
:
1756 raise Exception('%s' %str
(e
) +
1757 ' (interface was probably never up ?)')
1760 # if iface list not given by user, assume all from config file
1761 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
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
,
1769 if not filtered_ifacenames
:
1770 raise Exception('no ifaces found matching given allow lists ' +
1771 '(or interfaces were probably never up ?)')
1774 self
.populate_dependency_info(ops
, filtered_ifacenames
)
1775 self
.print_dependency(filtered_ifacenames
, printdependency
)
1778 self
.populate_dependency_info(ops
)
1781 self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1782 followdependents
=True
1783 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
1785 self
._process
_delay
_admin
_state
_queue
('down')
1786 if not ifupdownflags
.flags
.DRYRUN
and self
.flags
.ADDONS_ENABLE
:
1789 def query(self
, ops
, auto
=False, format_list
=False, allow_classes
=None,
1791 excludepats
=None, printdependency
=None,
1792 format
='native', type=None):
1793 """ query an interface """
1797 # Let us forget internal squashing when it comes to
1798 # ifquery. It can surprise people relying of ifquery
1800 self
._ifaceobj
_squash
_internal
= False
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
1808 self
.logger
.debug('setting flag ALL')
1809 ifupdownflags
.flags
.ALL
= True
1810 ifupdownflags
.flags
.WITH_DEPENDS
= True
1812 if ops
[0] == 'query-syntax':
1813 self
._modules
_help
(format
)
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
)
1821 self
.read_iface_config()
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
)
1830 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1832 # if iface list not given by user, assume all from config file
1833 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
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
(
1848 if not filtered_ifacenames
:
1849 raise Exception('no ifaces found matching ' +
1850 'given allow lists')
1852 self
.populate_dependency_info(ops
)
1853 if ops
[0] == 'query-dependency' and printdependency
:
1854 self
.print_dependency(filtered_ifacenames
, printdependency
)
1857 if format_list
and (ops
[0] == 'query' or ops
[0] == 'query-raw'):
1858 return self
.print_ifaceobjs_list(filtered_ifacenames
)
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
)
1865 ret
= self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1866 followdependents
=True
1867 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
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
)
1874 # if any of the object has an error, signal that silently
1876 elif ops
[0] == 'query-running':
1877 self
.print_ifaceobjsrunning_pretty(filtered_ifacenames
, format
)
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
= {}
1886 self
.logger
.info('reloading interfaces that are currently up ..')
1889 iface_read_ret
= self
.read_iface_config()
1892 if not self
.ifaceobjdict
:
1893 self
.logger
.warn("nothing to reload ..exiting.")
1895 already_up_ifacenames
= []
1896 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1898 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
1899 and self
.statemanager
.ifaceobjdict
):
1900 already_up_ifacenames
= self
.statemanager
.ifaceobjdict
.keys()
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
)
1909 interfaces_to_up
= already_up_ifacenames_still_present
1911 # generate dependency graph of interfaces
1912 self
.populate_dependency_info(upops
, interfaces_to_up
)
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.
1918 if not self
._module
_syntax
_check
(interfaces_to_up
):
1920 if not iface_read_ret
:
1922 elif self
._any
_iface
_errors
(interfaces_to_up
):
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
))
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
)
1935 # old interface config is read into self.ifaceobjdict
1936 self
.read_old_iface_config()
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
,
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)
1949 self
.logger
.info('no interfaces to down ..')
1951 # Now, run 'up' with new config dict
1952 # reset statemanager update flag to default
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
1961 if not self
.ifaceobjdict
:
1962 self
.logger
.info('no interfaces to up')
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
:
1973 if not iface_read_ret
or not ret
:
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
= {}
1983 iface_read_ret
= self
.read_iface_config()
1987 if not self
.ifaceobjdict
:
1988 self
.logger
.warn("nothing to reload ..exiting.")
1991 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1992 new_filtered_ifacenames
= [i
for i
in ifacenames
1993 if self
._iface
_whitelisted
(auto
, allow
,
1995 # generate dependency graph of interfaces
1996 self
.populate_dependency_info(upops
)
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.
2002 if not self
._module
_syntax
_check
(new_filtered_ifacenames
):
2004 if not iface_read_ret
:
2006 elif self
._any
_iface
_errors
(new_filtered_ifacenames
):
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
)
2016 self
.ifaceobjdict
= OrderedDict({})
2017 self
.dependency_graph
= OrderedDict({})
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()
2025 # oldconfig not available, continue with 'up' with new config
2027 new_ifaceobjdict
= self
.ifaceobjdict
2028 new_dependency_graph
= self
.dependency_graph
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
,
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.
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
))
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'))
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
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
:
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
)
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
:
2108 if len(newifaceobjlist
) != len(lastifaceobjlist
):
2109 ifacedownlist
.append(ifname
)
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
)
2123 self
.logger
.info('reload: scheduling down on interfaces: %s'
2124 %str
(ifacedownlist
))
2125 # reinitialize dependency graph
2126 self
.dependency_graph
= OrderedDict({})
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
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,
2145 except Exception, e
:
2146 self
.logger
.error(str(e
))
2149 self
.flags
.SCHED_SKIP_CHECK_UPPERIFACES
= False
2150 self
._process
_delay
_admin
_state
_queue
('down')
2152 self
.logger
.info('no interfaces to down ..')
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')
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
2167 self
.logger
.info('reload: scheduling up on interfaces: %s'
2168 %str
(new_filtered_ifacenames
))
2169 ifupdownflags
.flags
.CACHE
= True
2171 ret
= self
._sched
_ifaces
(new_filtered_ifacenames
, upops
,
2172 followdependents
=True
2173 if ifupdownflags
.flags
.WITH_DEPENDS
2175 except Exception, e
:
2177 self
.logger
.error(str(e
))
2179 self
._process
_delay
_admin
_state
_queue
('up')
2180 if ifupdownflags
.flags
.DRYRUN
:
2184 if not iface_read_ret
or not ret
:
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
)
2193 self
._reload
_default
(*args
, **kargs
)
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
):
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
+ '}')
2211 def print_dependency(self
, ifacenames
, format
):
2212 """ prints iface dependency information """
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':
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
)
2226 def print_ifaceobjs_list(self
, ifacenames
):
2227 for i
in ifacenames
:
2230 def print_ifaceobjs_raw(self
, ifacenames
):
2231 """ prints raw lines for ifaces from config file """
2233 for i
in ifacenames
:
2234 for ifaceobj
in self
.get_ifaceobjs(i
):
2235 if self
.is_ifaceobj_builtin(ifaceobj
):
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
)
2244 def _get_ifaceobjs_pretty(self
, ifacenames
, ifaceobjs
, running
=False):
2245 """ returns iface obj list """
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
)):
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
)
2261 def print_ifaceobjs_pretty(self
, ifacenames
, format
='native'):
2262 """ pretty prints iface in format given by keyword arg format """
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
=(',', ': '))
2271 expand
= int(self
.config
.get('ifquery_ifacename_expand_range', '0'))
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)
2280 def _get_ifaceobjscurr_pretty(self
, ifacenames
, ifaceobjs
):
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
):
2289 if self
.is_ifaceobj_noconfig(ifaceobj
):
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
)
2300 def print_ifaceobjscurr_pretty(self
, ifacenames
, format
='native'):
2301 """ pretty prints current running state of interfaces with status.
2303 returns 1 if any of the interface has an error,
2308 ret
= self
._get
_ifaceobjscurr
_pretty
(ifacenames
, ifaceobjs
)
2309 if not ifaceobjs
: return
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
=(',', ': '))
2319 map(lambda i
: i
.dump_pretty(with_status
=True), ifaceobjs
)
2322 def print_ifaceobjsrunning_pretty(self
, ifacenames
, format
='native'):
2323 """ pretty prints iface running state """
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
=(',', ': '))
2332 map(lambda i
: i
.dump_pretty(), ifaceobjs
)
2335 print 'ifupdown main object dump'
2336 print self
.pp
.pprint(self
.modules
)
2337 print self
.pp
.pprint(self
.ifaceobjdict
)
2339 def _dump_ifaceobjs(self
, ifacenames
):
2340 for i
in ifacenames
:
2341 ifaceobjs
= self
.get_ifaceobjs(i
)