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 self
._delay
_admin
_state
:
101 self
._delay
_admin
_state
_iface
_queue
.append(ifaceobj
.name
)
103 # If this object is a link slave, ie its link is controlled
104 # by its link master interface, then dont set the link state.
105 # But do allow user to change state of the link if the interface
106 # is already with its link master (hence the master check).
107 if ifaceobj
.link_type
== ifaceLinkType
.LINK_SLAVE
:
109 if not self
.link_exists(ifaceobj
.name
):
111 if self
._keep
_link
_down
(ifaceobj
):
114 self
.link_up(ifaceobj
.name
)
116 if ifaceobj
.addr_method
== 'manual':
121 def _keep_link_down(self
, ifaceobj
):
122 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.KEEP_LINK_DOWN
:
123 # user has asked to explicitly keep the link down,
124 # so, force link down
125 self
.logger
.info('%s: keeping link down due to user config' %ifaceobj
.name
)
126 self
.link_down(ifaceobj
.name
)
130 def run_down(self
, ifaceobj
):
131 if ((ifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
132 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
134 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
135 # there is no real interface behind it
136 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
138 if self
._delay
_admin
_state
:
139 self
._delay
_admin
_state
_iface
_queue
.append(ifaceobj
.name
)
141 # If this object is a link slave, ie its link is controlled
142 # by its link master interface, then dont set the link state.
143 # But do allow user to change state of the link if the interface
144 # is already with its link master (hence the master check).
145 if ifaceobj
.link_type
== ifaceLinkType
.LINK_SLAVE
:
147 if not self
.link_exists(ifaceobj
.name
):
150 self
.link_down(ifaceobj
.name
)
152 if ifaceobj
.addr_method
== 'manual':
157 # ifupdown object interface operation handlers
158 ops_handlers
= OrderedDict([('up', run_up
),
161 def run_sched_ifaceobj_posthook(self
, ifaceobj
, op
):
162 if (ifaceobj
.priv_flags
and (ifaceobj
.priv_flags
.BUILTIN
or
163 ifaceobj
.priv_flags
.NOCONFIG
)):
165 if self
.flags
.STATEMANAGER_UPDATE
:
166 self
.statemanager
.ifaceobj_sync(ifaceobj
, op
)
168 # ifupdown object interface scheduler pre and posthooks
169 sched_hooks
= {'posthook' : run_sched_ifaceobj_posthook
}
171 def reset_ifupdown2(self
):
172 ifaceScheduler
.reset()
174 ifupdown2
.ifupdown
.statemanager
.reset()
175 ifupdown2
.ifupdown
.policymanager
.reset()
176 ifupdown2
.ifupdown
.ifupdownflags
.reset()
177 ifupdownConfig
.reset()
178 ifupdown2
.ifupdownaddons
.mstpctlutil
.mstpctlutil
.reset()
179 ifupdown2
.ifupdownaddons
.LinkUtils
.LinkUtils
.reset()
181 ifupdown2
.ifupdownaddons
.cache
.linkCache
.reset()
182 ifupdown2
.ifupdownaddons
.cache
.MSTPAttrsCache
.invalidate()
184 def __init__(self
, config
={},
185 daemon
=False, force
=False, dryrun
=False, nowait
=False,
186 perfmode
=False, withdepends
=False, njobs
=1,
187 cache
=False, addons_enable
=True, statemanager_enable
=True,
188 interfacesfile
='/etc/network/interfaces',
189 interfacesfileiobuf
=None,
190 interfacesfileformat
='native',
192 """This member function initializes the ifupdownmain object.
195 config (dict): config dict from /etc/network/ifupdown2/ifupdown2.conf
196 force (bool): force interface configuration
197 dryrun (bool): dryrun interface configuration
198 withdepends (bool): apply interface configuration on all depends
199 interfacesfile (str): interfaces file. default is /etc/network/interfaces
200 interfacesfileformat (str): default is 'native'. Other choices are 'json'
203 AttributeError, KeyError """
206 self
.reset_ifupdown2()
208 # iface dictionary in the below format:
209 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
211 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
213 # Each ifaceobject corresponds to a configuration block for
215 # The value in the dictionary is a list because the network
216 # interface configuration file supports more than one iface section
217 # in the interfaces file
218 self
.ifaceobjdict
= OrderedDict()
220 # iface dictionary representing the curr running state of an iface
221 # in the below format:
222 # {'<ifacename>' : <ifaceobject>}
223 self
.ifaceobjcurrdict
= OrderedDict()
225 # Dictionary representing operation and modules
226 # for every operation
227 self
.module_ops
= OrderedDict([('pre-up', []),
230 ('query-checkcurr', []),
231 ('query-running', []),
232 ('query-dependency', []),
239 # For old style /etc/network/ bash scripts
240 self
.script_ops
= OrderedDict([('pre-up', []),
248 self
.logger
= logging
.getLogger('ifupdown')
249 ifupdownflags
.flags
.FORCE
= force
250 ifupdownflags
.flags
.DRYRUN
= dryrun
251 ifupdownflags
.flags
.WITHDEFAULTS
= withdefaults
252 ifupdownflags
.flags
.NOWAIT
= nowait
253 ifupdownflags
.flags
.PERFMODE
= perfmode
254 ifupdownflags
.flags
.CACHE
= cache
255 ifupdownflags
.flags
.WITH_DEPENDS
= withdepends
257 # Can be used to provide hints for caching
258 ifupdownflags
.flags
.CACHE_FLAGS
= 0x0
260 self
.flags
= ifupdownMainFlags()
262 self
.flags
.STATEMANAGER_ENABLE
= statemanager_enable
263 self
.interfacesfile
= interfacesfile
264 self
.interfacesfileiobuf
= interfacesfileiobuf
265 self
.interfacesfileformat
= interfacesfileformat
267 self
.logger
.debug(self
.config
)
268 self
.blacklisted_ifaces_present
= False
270 self
.type = ifaceType
.UNKNOWN
272 self
.flags
.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
= False
273 self
.flags
.ADDONS_ENABLE
= addons_enable
275 self
.ifaces
= OrderedDict()
277 self
.pp
= pprint
.PrettyPrinter(indent
=4)
278 self
.modules
= OrderedDict({})
279 self
.module_attrs
= {}
280 self
.overridden_ifupdown_scripts
= []
282 if self
.config
.get('addon_python_modules_support', '1') == '1':
283 self
.load_addon_modules(self
.addon_modules_dir
)
284 if self
.config
.get('addon_scripts_support', '0') == '1':
285 self
.load_scripts(self
.scripts_dir
)
286 self
.dependency_graph
= OrderedDict({})
288 self
._cache
_no
_repeats
= {}
290 if self
.flags
.STATEMANAGER_ENABLE
:
291 self
.statemanager
= statemanager
.statemanager_api
293 self
.statemanager
.read_saved_state()
295 # if read_saved_state fails, state file might be corrupt.
296 # Ignore old state and continue
297 self
.logger
.warning('error reading state (%s)' %str
(e
))
299 self
.flags
.STATEMANAGER_UPDATE
= False
300 self
._delay
_admin
_state
= True if self
.config
.get(
301 'delay_admin_state_change', '0') == '1' else False
302 self
._delay
_admin
_state
_iface
_queue
= []
303 if self
._delay
_admin
_state
:
304 self
.logger
.info('\'delay_admin_state_change\' is set. admin ' +
305 'state changes will be delayed till the end.')
307 self
._link
_master
_slave
= True if self
.config
.get(
308 'link_master_slave', '0') == '1' else False
309 if self
._link
_master
_slave
:
310 self
.logger
.info('\'link_master_slave\' is set. slave admin ' +
311 'state changes will be delayed till the ' +
312 'masters admin state change.')
314 # squash iface objects for same interface both internal and
315 # external representation. It is off by default.
316 self
._ifaceobj
_squash
= True if self
.config
.get(
317 'ifaceobj_squash', '0') == '1' else False
319 # squash iface objects for same interface internal
320 # representation only. External representation as seen by ifquery
321 # will continue to see multiple iface stanzas if it was specified
322 # that way by the user. It is on by default.
323 self
._ifaceobj
_squash
_internal
= True if self
.config
.get(
324 'ifaceobj_squash_internal', '1') == '1' else False
326 # initialize global config object with config passed by the user
327 # This makes config available to addon modules
328 ifupdownConfig
.config
= self
.config
330 self
.validate_keywords
= {
331 '<mac>': self
._keyword
_mac
,
332 '<text>': self
._keyword
_text
,
333 '<ipv4>': self
._keyword
_ipv
4,
334 '<ipv6>': self
._keyword
_ipv
6,
335 '<ip>': self
._keyword
_ip
,
336 '<number>': self
._keyword
_number
,
337 '<interface>': self
._keyword
_interface
,
338 '<ipv4-vrf-text>': self
._keyword
_ipv
4_vrf
_text
,
339 '<number-ipv4-list>': self
._keyword
_number
_ipv
4_list
,
340 '<interface-list>': self
._keyword
_interface
_list
,
341 '<ipv4/prefixlen>': self
._keyword
_ipv
4_prefixlen
,
342 '<ipv6/prefixlen>': self
._keyword
_ipv
6_prefixlen
,
343 '<ip/prefixlen>': self
._keyword
_ip
_prefixlen
,
344 '<number-range-list>': self
._keyword
_number
_range
_list
,
345 '<number-comma-range-list>': self
._keyword
_number
_comma
_range
_list
,
346 '<interface-range-list>': self
._keyword
_interface
_range
_list
,
347 '<interface-range-list-multiple-of-16>': self
._keyword
_interface
_range
_list
_multiple
_of
_16,
348 '<mac-ip/prefixlen-list>': self
._keyword
_mac
_ip
_prefixlen
_list
,
349 '<number-interface-list>': self
._keyword
_number
_interface
_list
,
350 '<interface-yes-no-list>': self
._keyword
_interface
_yes
_no
_list
,
351 '<interface-on-off-list>': self
._keyword
_interface
_on
_off
_list
,
352 '<interface-yes-no-0-1-list>': self
._keyword
_interface
_yes
_no
_0_1_list
,
353 '<interface-disabled-automatic-enabled>': self
._keyword
_interface
_disabled
_automatic
_enabled
_list
,
354 '<interface-yes-no-auto-list>': self
._keyword
_interface
_yes
_no
_auto
_list
,
355 '<interface-l2protocol-tunnel-list>': self
._keyword
_interface
_l2protocol
_tunnel
_list
358 def link_master_slave_ignore_error(self
, errorstr
):
359 # If link master slave flag is set,
360 # there may be cases where the lowerdev may not be
361 # up resulting in 'Network is down' error
362 # This can happen if the lowerdev is a LINK_SLAVE
363 # of another interface which is not up yet
364 # example of such a case:
365 # bringing up a vlan on a bond interface and the bond
366 # is a LINK_SLAVE of a bridge (in other words the bond is
367 # part of a bridge) which is not up yet
368 if self
._link
_master
_slave
:
369 if 'Network is down' in errorstr
:
373 def get_ifaceobjs(self
, ifacename
):
374 return self
.ifaceobjdict
.get(ifacename
)
376 def get_ifaceobjs_saved(self
, ifacename
):
377 """ Return ifaceobjects from statemanager """
378 if self
.flags
.STATEMANAGER_ENABLE
:
379 return self
.statemanager
.get_ifaceobjs(ifacename
)
383 def get_ifaceobj_first(self
, ifacename
):
384 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
389 def get_ifacenames(self
):
390 return self
.ifaceobjdict
.keys()
392 def get_iface_obj_last(self
, ifacename
):
393 return self
.ifaceobjdict
.get(ifacename
)[-1]
396 def must_follow_upperifaces(self
, ifacename
):
398 # XXX: This bleeds the knowledge of iface
399 # types in the infrastructure module.
400 # Cant think of a better fix at the moment.
401 # In future maybe the module can set a flag
402 # to indicate if we should follow upperifaces
404 ifaceobj
= self
.get_ifaceobj_first(ifacename
)
405 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
409 def create_n_save_ifaceobj(self
, ifacename
, priv_flags
=None,
411 """ creates a iface object and adds it to the iface dictionary """
413 ifaceobj
.name
= ifacename
414 ifaceobj
.priv_flags
= priv_flags
416 if not self
._link
_master
_slave
:
417 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
419 ifaceobj
.inc_refcnt()
420 self
.ifaceobjdict
[ifacename
] = [ifaceobj
]
423 def create_n_save_ifaceobjcurr(self
, ifaceobj
):
424 """ creates a copy of iface object and adds it to the iface
425 dict containing current iface objects
427 ifaceobjcurr
= iface()
428 ifaceobjcurr
.name
= ifaceobj
.name
429 ifaceobjcurr
.type = ifaceobj
.type
430 ifaceobjcurr
.lowerifaces
= ifaceobj
.lowerifaces
431 ifaceobjcurr
.priv_flags
= copy
.deepcopy(ifaceobj
.priv_flags
)
432 ifaceobjcurr
.auto
= ifaceobj
.auto
433 self
.ifaceobjcurrdict
.setdefault(ifaceobj
.name
,
434 []).append(ifaceobjcurr
)
437 def get_ifaceobjcurr(self
, ifacename
, idx
=0):
438 ifaceobjlist
= self
.ifaceobjcurrdict
.get(ifacename
)
444 return ifaceobjlist
[idx
]
446 def get_ifaceobjrunning(self
, ifacename
):
447 return self
.ifaceobjrunningdict
.get(ifacename
)
449 def get_iface_refcnt(self
, ifacename
):
450 """ Return iface ref count """
452 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
460 def is_iface_builtin_byname(self
, ifacename
):
461 """ Returns true if iface name is a builtin interface.
463 A builtin interface is an interface which ifupdown understands.
464 The following are currently considered builtin ifaces:
465 - vlan interfaces in the format <ifacename>.<vlanid>
467 return '.' in ifacename
469 def is_ifaceobj_builtin(self
, ifaceobj
):
470 """ Returns true if iface name is a builtin interface.
472 A builtin interface is an interface which ifupdown understands.
473 The following are currently considered builtin ifaces:
474 - vlan interfaces in the format <ifacename>.<vlanid>
476 if (ifaceobj
.priv_flags
and ifaceobj
.priv_flags
.BUILTIN
):
480 def is_ifaceobj_noconfig(self
, ifaceobj
):
481 """ Returns true if iface object did not have a user defined config.
483 These interfaces appear only when they are dependents of interfaces
484 which have user defined config
486 return (ifaceobj
.priv_flags
and ifaceobj
.priv_flags
.NOCONFIG
)
488 def is_iface_noconfig(self
, ifacename
):
489 """ Returns true if iface has no config """
491 ifaceobj
= self
.get_ifaceobj_first(ifacename
)
492 if not ifaceobj
: return True
493 return self
.is_ifaceobj_noconfig(ifaceobj
)
495 def check_shared_dependents(self
, ifaceobj
, dlist
):
496 """ ABSOLETE: Check if dlist intersects with any other
497 interface with slave dependents.
498 example: bond and bridges.
499 This function logs such errors """
500 setdlist
= Set(dlist
)
501 for ifacename
, ifacedlist
in self
.dependency_graph
.items():
504 check_depends
= False
505 iobjs
= self
.get_ifaceobjs(ifacename
)
509 if (i
.dependency_type
== ifaceDependencyType
.MASTER_SLAVE
):
512 common
= Set(ifacedlist
).intersection(setdlist
)
514 self
.logger
.error('misconfig..?. iface %s and %s '
515 %(ifaceobj
.name
, ifacename
) +
516 'seem to share dependents/ports %s' %str
(list(common
)))
518 def _set_iface_role(self
, ifaceobj
, role
, upperifaceobj
):
519 if (self
.flags
.CHECK_SHARED_DEPENDENTS
and
520 (ifaceobj
.role
& ifaceRole
.SLAVE
) and
521 (role
== ifaceRole
.SLAVE
) and (upperifaceobj
.role
& ifaceRole
.MASTER
)):
522 self
.logger
.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
524 ifaceLinkPrivFlags
.get_all_str(ifaceobj
.link_privflags
), str(ifaceobj
.upperifaces
)))
525 ifaceobj
.set_status(ifaceStatus
.ERROR
)
529 def _set_iface_role_n_kind(self
, ifaceobj
, upperifaceobj
):
530 if (upperifaceobj
.link_kind
& ifaceLinkKind
.BOND
):
531 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
532 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BOND_SLAVE
534 if (upperifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
535 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
536 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_PORT
538 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
) \
539 and (upperifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
540 upperifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VXLAN
542 # vrf masters get processed after slaves, which means
543 # check both link_kind vrf and vrf slave
544 if ((upperifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
545 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
546 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
547 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
548 if self
._link
_master
_slave
:
549 if upperifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
550 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
552 upperifaceobj
.link_type
= ifaceLinkType
.LINK_NA
553 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
555 def dump_iface_dependency_info(self
):
556 """ debug funtion to print raw dependency
557 info - lower and upper devices"""
559 for ifacename
, ifaceobjs
in self
.ifaceobjdict
.iteritems():
561 self
.logger
.info("%s: refcnt: %d, lower: %s, upper: %s" %(ifacename
,
562 self
.get_iface_refcnt(ifacename
),
563 str(iobj
.lowerifaces
) if iobj
.lowerifaces
else [],
564 str(iobj
.upperifaces
) if iobj
.upperifaces
else []))
567 def preprocess_dependency_list(self
, upperifaceobj
, dlist
, ops
):
568 """ We go through the dependency list and
569 delete or add interfaces from the interfaces dict by
570 applying the following rules:
571 if flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
572 we only consider devices whose configuration was
573 specified in the network interfaces file. We delete
574 any interface whose config was not specified except
575 for vlan devices. vlan devices get special treatment.
576 Even if they are not present they are created and added
578 elif flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
579 we create objects for all dependent devices that are not
580 present in the ifacesdict
585 dilist
= self
.get_ifaceobjs(d
)
588 if self
.is_iface_builtin_byname(d
):
589 ni
= self
.create_n_save_ifaceobj(d
,
590 ifacePrivFlags(True, True), True)
591 elif not self
.flags
.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
:
592 ni
= self
.create_n_save_ifaceobj(d
,
593 ifacePrivFlags(False, True), True)
597 ni
.add_to_upperifaces(upperifaceobj
.name
)
598 self
._set
_iface
_role
_n
_kind
(ni
, upperifaceobj
)
602 di
.add_to_upperifaces(upperifaceobj
.name
)
603 self
._set
_iface
_role
_n
_kind
(di
, upperifaceobj
)
607 def preprocess_upperiface(self
, lowerifaceobj
, ulist
, ops
):
609 if (lowerifaceobj
.upperifaces
and
610 u
in lowerifaceobj
.upperifaces
):
612 lowerifaceobj
.add_to_upperifaces(u
)
613 uifacelist
= self
.get_ifaceobjs(u
)
615 for ui
in uifacelist
:
616 lowerifaceobj
.inc_refcnt()
617 self
._set
_iface
_role
_n
_kind
(lowerifaceobj
, ui
)
618 ui
.add_to_lowerifaces(lowerifaceobj
.name
)
620 def query_lowerifaces(self
, ifaceobj
, ops
, ifacenames
, type=None):
621 """ Gets iface dependents by calling into respective modules """
624 # Get dependents for interface by querying respective modules
625 for module
in self
.modules
.values():
627 if ops
[0] == 'query-running':
628 if (not hasattr(module
,
629 'get_dependent_ifacenames_running')):
631 dlist
= module
.get_dependent_ifacenames_running(ifaceobj
)
633 if (not hasattr(module
, 'get_dependent_ifacenames')):
635 dlist
= module
.get_dependent_ifacenames(ifaceobj
,
638 self
.logger
.warn('%s: error getting dependent interfaces (%s)'
639 %(ifaceobj
.name
, str(e
)))
642 if dlist
: ret_dlist
.extend(dlist
)
643 return list(set(ret_dlist
))
645 def query_upperifaces(self
, ifaceobj
, ops
, ifacenames
, type=None):
646 """ Gets iface upperifaces by calling into respective modules """
649 # Get upperifaces for interface by querying respective modules
650 for module
in self
.modules
.values():
652 if ops
[0] == 'query-running':
653 if (not hasattr(module
,
654 'get_upper_ifacenames_running')):
656 ulist
= module
.get_upper_ifacenames_running(ifaceobj
)
658 if (not hasattr(module
, 'get_upper_ifacenames')):
660 ulist
= module
.get_upper_ifacenames(ifaceobj
, ifacenames
)
662 self
.logger
.warn('%s: error getting upper interfaces (%s)'
663 %(ifaceobj
.name
, str(e
)))
666 if ulist
: ret_ulist
.extend(ulist
)
667 return list(set(ret_ulist
))
669 def populate_dependency_info(self
, ops
, ifacenames
=None):
670 """ recursive function to generate iface dependency info """
673 ifacenames
= self
.ifaceobjdict
.keys()
675 iqueue
= deque(ifacenames
)
678 # Go through all modules and find dependent ifaces
681 ifaceobjs
= self
.get_ifaceobjs(i
)
684 dependents_processed
= False
686 # Store all dependency info in the first ifaceobj
687 # but get dependency info from all ifaceobjs
688 ifaceobj
= ifaceobjs
[0]
689 for iobj
in ifaceobjs
:
690 ulist
= self
.query_upperifaces(iobj
, ops
, ifacenames
)
692 dependents_processed
= True
694 dlist
= self
.query_lowerifaces(iobj
, ops
, ifacenames
)
698 self
.preprocess_upperiface(ifaceobj
, ulist
, ops
)
699 if dependents_processed
:
702 self
.preprocess_dependency_list(ifaceobj
,
704 ifaceobj
.lowerifaces
= dlist
705 [iqueue
.append(d
) for d
in dlist
]
706 #if not self.dependency_graph.get(i):
707 # self.dependency_graph[i] = dlist
709 for i
in self
.ifaceobjdict
.keys():
710 iobj
= self
.get_ifaceobj_first(i
)
711 if (not iobj
.link_kind
and
712 not (iobj
.link_privflags
& ifaceLinkPrivFlags
.LOOPBACK
) and
714 iobj
.link_privflags |
= ifaceLinkPrivFlags
.LOOPBACK
716 self
.dependency_graph
[i
] = iobj
.lowerifaces
718 self
.dependency_graph
[i
] = []
720 if not self
.blacklisted_ifaces_present
:
723 # Walk through the dependency graph and remove blacklisted
724 # interfaces that were picked up as dependents
725 for i
in self
.dependency_graph
.keys():
726 ifaceobj
= self
.get_ifaceobj_first(i
)
730 if ifaceobj
.blacklisted
and not ifaceobj
.upperifaces
:
731 # if blacklisted and was not picked up as a
732 # dependent of a upper interface, delete the
733 # interface from the dependency graph
734 dlist
= ifaceobj
.lowerifaces
737 difaceobjs
= self
.get_ifaceobjs(d
)
743 d
.upperifaces
.remove(i
)
745 self
.logger
.debug('error removing %s from %s upperifaces' %(i
, d
))
747 self
.logger
.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
748 del self
.dependency_graph
[i
]
751 def _check_config_no_repeats(self
, ifaceobj
):
752 """ check if object has an attribute that is
753 restricted to a single object in the system.
754 if yes, warn and return """
755 for k
,v
in self
._cache
_no
_repeats
.items():
756 iv
= ifaceobj
.config
.get(k
)
757 if iv
and iv
[0] == v
:
758 self
.logger
.error('ignoring interface %s. ' %ifaceobj
.name
+
759 'Only one object with attribute ' +
760 '\'%s %s\' allowed.' %(k
, v
))
762 for k
, v
in self
.config
.get('no_repeats', {}).items():
763 iv
= ifaceobj
.config
.get(k
)
764 if iv
and iv
[0] == v
:
765 self
._cache
_no
_repeats
[k
] = v
768 def _save_iface_squash(self
, ifaceobj
):
769 """ squash ifaceobjects belonging to same iface
770 into a single object """
771 if self
._check
_config
_no
_repeats
(ifaceobj
):
773 ifaceobj
.priv_flags
= ifacePrivFlags()
774 if not self
._link
_master
_slave
:
775 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
776 currentifaceobjlist
= self
.ifaceobjdict
.get(ifaceobj
.name
)
777 if not currentifaceobjlist
:
778 self
.ifaceobjdict
[ifaceobj
.name
] = [ifaceobj
]
780 if ifaceobj
.compare(currentifaceobjlist
[0]):
781 self
.logger
.warn('duplicate interface %s found' %ifaceobj
.name
)
783 for obj
in self
.ifaceobjdict
[ifaceobj
.name
]:
784 if obj
.type == ifaceobj
.type:
787 self
.ifaceobjdict
[ifaceobj
.name
].append(ifaceobj
)
789 def _save_iface(self
, ifaceobj
):
790 if self
._check
_config
_no
_repeats
(ifaceobj
):
792 ifaceobj
.priv_flags
= ifacePrivFlags()
793 if not self
._link
_master
_slave
:
794 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
795 currentifaceobjlist
= self
.ifaceobjdict
.get(ifaceobj
.name
)
796 if not currentifaceobjlist
:
797 self
.ifaceobjdict
[ifaceobj
.name
]= [ifaceobj
]
798 if not self
._ifaceobj
_squash
:
799 ifaceobj
.flags |
= ifaceobj
.YOUNGEST_SIBLING
801 if ifaceobj
.compare(currentifaceobjlist
[0]):
802 self
.logger
.warn('duplicate interface %s found' %ifaceobj
.name
)
804 if currentifaceobjlist
[0].type == ifaceobj
.type:
805 currentifaceobjlist
[0].flags |
= ifaceobj
.HAS_SIBLINGS
806 ifaceobj
.flags |
= ifaceobj
.HAS_SIBLINGS
807 # clear the OLDEST_SIBLING from all the siblings
808 for iface
in self
.ifaceobjdict
[ifaceobj
.name
]:
809 iface
.flags
&= ~ifaceobj
.OLDEST_SIBLING
810 # current sibling is the oldest
811 ifaceobj
.flags |
= ifaceobj
.OLDEST_SIBLING
812 self
.ifaceobjdict
[ifaceobj
.name
].append(ifaceobj
)
814 def _keyword_text(self
, value
, validrange
=None):
815 return isinstance(value
, str) and len(value
) > 0
817 def _keyword_mac(self
, value
, validrange
=None):
818 if value
.strip().startswith('ether'):
819 value
= value
.strip()[6:]
820 return re
.match('[0-9a-f]{1,2}([-:])[0-9a-f]{1,2}(\\1[0-9a-f]{1,2}){4}$',
823 def _keyword_check_list(self
, _list
, obj
, limit
=None):
825 if limit
and limit
> 0:
826 for i
in xrange(0, limit
):
828 return len(_list
) == limit
833 except Exception as e
:
834 self
.logger
.debug('keyword: check list: %s' % str(e
))
837 def _keyword_ipv4(self
, value
, validrange
=None):
838 return self
._keyword
_check
_list
(value
.split(), IPv4Address
, limit
=1)
840 def _keyword_ipv4_prefixlen(self
, value
, validrange
=None):
841 return self
._keyword
_check
_list
(value
.split(), IPv4Network
, limit
=1)
843 def _keyword_ipv6(self
, value
, validrange
=None):
844 return self
._keyword
_check
_list
(value
.split(), IPv6Address
, limit
=1)
846 def _keyword_ipv6_prefixlen(self
, value
, validrange
=None):
847 return self
._keyword
_check
_list
(value
.split(), IPv6Network
, limit
=1)
849 def _keyword_ip(self
, value
, validrange
=None):
850 return self
._keyword
_check
_list
(value
.split(), IPAddress
, limit
=1)
852 def _keyword_ip_prefixlen(self
, value
, validrange
=None):
853 return self
._keyword
_check
_list
(value
.split(), IPNetwork
, limit
=1)
855 def _keyword_mac_ip_prefixlen_list(self
, value
, validrange
=None):
857 <mac> <ip> [<ip> ...]
858 ex: address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24
864 if not self
._keyword
_mac
(res
[0]):
867 if not self
._keyword
_ip
_prefixlen
(ip
):
870 except Exception as e
:
871 self
.logger
.debug('keyword: mac ipaddr prefixlen: %s' % str(e
))
874 def _keyword_number_ipv4_list(self
, value
, validrange
=None):
876 <number>=<ipv4> [<number>=<ipv4> ...]
877 ex: bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1
880 elements
= value
.split(' ')
883 for elem
in elements
:
888 except Exception as e
:
889 self
.logger
.debug('keyword: number ipv4: %s' % str(e
))
892 def _keyword_interface(self
, ifacename
, validrange
=None):
893 return self
.get_ifaceobjs(ifacename
)
895 def _keyword_ipv4_vrf_text(self
, value
, validrange
=None):
898 ex: clagd-backup-ip 10.10.10.42 vrf blue
900 values
= value
.split()
903 if size
> 3 or size
< 1:
906 IPv4Address(values
[0])
908 if values
[1] != 'vrf':
911 if not self
._keyword
_text
(values
[2]):
914 except Exception as e
:
915 self
.logger
.debug('keyword: ipv4 vrf text: %s' % str(e
))
918 def _keyword_interface_list_with_value(self
, value
, validvals
):
919 values
= value
.split()
922 if values
[0] in validvals
:
925 iface_value
= v
.split('=')
926 size
= len(iface_value
)
928 if iface_value
[0] == 'glob' or iface_value
[0] == 'regex':
931 if not iface_value
[1] in validvals
:
934 except Exception as e
:
935 self
.logger
.debug('keyword: interface list with value: %s' % str(e
))
938 def _keyword_interface_on_off_list(self
, value
, validrange
=None):
940 <yes|no> | ( <interface>=<on|off> [<interface>=<on|off> ...] )
941 ex: bridge-learning swp1=on swp2=off
943 return self
._keyword
_interface
_list
_with
_value
(value
, ['on', 'off'])
945 def _keyword_interface_yes_no_list(self
, value
, validrange
=None):
947 <yes|no> | ( <interface>=<yes|no> [<interface>=<yes|no> ...] )
948 ex: mstpctl-portrestrrole swp1=yes swp2=no
950 return self
._keyword
_interface
_list
_with
_value
(value
, ['yes', 'no'])
952 def _keyword_interface_yes_no_auto_list(self
, value
, validrange
=None):
955 ( <interface>=<yes|no|auto> [<interface>=<yes|no|auto> ...] )
956 ex: mstpctl-portp2p swp1=yes swp2=no swp3=auto
958 return self
._keyword
_interface
_list
_with
_value
(value
,
959 ['yes', 'no', 'auto'])
961 def _keyword_interface_l2protocol_tunnel_list(self
, value
, validrange
=None):
963 bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all
964 bridge-l2protocol-tunnel lacp stp,lldp,cdp
965 bridge-l2protocol-tunnel stp lacp cdp
966 bridge-l2protocol-tunnel lldp pvst
967 bridge-l2protocol-tunnel stp
968 bridge-l2protocol-tunnel all
972 for intf_arg
in value
.split():
973 intf_arg_split
= intf_arg
.split('=')
974 for arg
in re
.split(',|\s*', intf_arg_split
[1]):
975 if arg
not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
978 for arg
in re
.split(',|\s*', value
):
979 if arg
not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
985 def _keyword_interface_yes_no_0_1_list(self
, value
, validrange
=None):
988 ( <interface>=<yes|no|0|1> [<interface>=<yes|no|0|1> ...] )
989 ex: bridge-portmcrouter swp1=yes swp2=yes swp3=1
991 return self
._keyword
_interface
_list
_with
_value
(value
,
992 ['yes', 'no', '1', '0', '2'])
994 def _keyword_interface_disabled_automatic_enabled_list(self
, value
, validrange
=None):
995 return self
._keyword
_interface
_list
_with
_value
(value
, [
996 '0', 'disabled', 'no',
997 '1', 'automatic', 'yes',
1000 def _keyword_interface_range_list_multiple_of_16(self
, value
, validrange
):
1001 return self
._keyword
_interface
_range
_list
(value
, validrange
, multiple
=16)
1003 def _keyword_interface_range_list(self
, value
, validrange
, multiple
=None):
1005 <number> | ( <interface>=<number> [ <interface>=number> ...] )
1006 ex: mstpctl-portpathcost swp1=0 swp2=1
1008 values
= value
.split()
1010 if len(values
) == 1 and '=' not in values
[0]:
1013 if n
< int(validrange
[0]) or n
> int(
1015 raise invalidValueError('value of out range "%s":'
1016 ' valid attribute range: %s'
1018 '-'.join(validrange
)))
1020 if multiple
is not None:
1021 if not (n
% multiple
== 0):
1022 raise invalidValueError('invalid value %s: must be a multiple of %s' % (n
, multiple
))
1025 except invalidValueError
as e
:
1027 except Exception as e
:
1028 self
.logger
.debug('keyword: interface range list: %s'
1032 iface_value
= v
.split('=')
1033 size
= len(iface_value
)
1036 number
= int(iface_value
[1])
1037 if number
< int(validrange
[0]) or number
> int(
1039 raise invalidValueError(
1040 'value of out range "%s" for iface "%s":'
1041 ' valid attribute range: %s'
1044 '-'.join(validrange
)))
1046 if multiple
is not None:
1047 if not (number
% multiple
== 0):
1048 raise invalidValueError('invalid value %s: must be a multiple of %s' % (number
, multiple
))
1051 except invalidValueError
as e
:
1053 except Exception as e
:
1054 self
.logger
.debug('keyword: interface range list: %s' % str(e
))
1057 def _keyword_interface_list(self
, value
, validrange
=None):
1059 [glob|regex] <interface> [ [glob|regex] <interface> ...]
1060 ex: bridge-ports swp1 swp2 glob swp3-5.100 regex (swp[6|7|8].100)
1062 interface_list
= value
.split()
1063 size
= len(interface_list
)
1066 if interface_list
[i
] == 'glob' or interface_list
[i
] == 'regex':
1069 if not self
._keyword
_interface
(interface_list
[i
]):
1074 def _keyword_number_range_list(self
, value
, validrange
=None):
1076 <number> [<number>-<number>]
1077 ex: bridge-vids 42 100-200
1079 number_list
= value
.split()
1082 while i
< len(number_list
):
1083 if '-' in number_list
[i
]:
1084 range = number_list
[i
].split('-')
1093 except Exception as e
:
1094 self
.logger
.debug('keyword: number range list: %s' % str(e
))
1097 def _keyword_number_interface_list(self
, value
, validrange
=None):
1099 <number> <interface> [<interface>... [<number> <interface> ... ]]
1100 bridge-waitport 42 swp1 swp2 swp3 9 swp4
1102 interface_list
= value
.split()
1103 if not interface_list
:
1106 int(interface_list
[0])
1108 for elem
in interface_list
[1:]:
1117 except Exception as e
:
1118 self
.logger
.debug('keyword: number interface list: %s' % str(e
))
1121 def _keyword_number(self
, value
, validrange
=None):
1125 except Exception as e
:
1126 self
.logger
.debug('keyword: number: %s' % str(e
))
1129 def _is_keyword(self
, value
):
1130 if isinstance(value
, tuple):
1132 keyword_found
= value
in self
.validate_keywords
1133 if value
.startswith('<') and value
.endswith('>') and not keyword_found
:
1134 raise Exception('%s: invalid keyword, please make sure to use'
1135 ' a valid keyword see `ifquery -s`' % value
)
1136 return keyword_found
1138 def _check_validvals_value(self
, attrname
, value
, validvals
, validrange
):
1139 if validvals
and value
not in validvals
:
1141 for keyword
in validvals
:
1142 if self
._is
_keyword
(keyword
):
1144 if self
.validate_keywords
[keyword
](value
, validrange
):
1145 return {'result': True}
1147 if self
.validate_keywords
[keyword
](value
):
1148 return {'result': True}
1152 'message': 'invalid value "%s": valid attribute values: %s'
1153 % (value
, validvals
)
1155 elif validvals
and value
in validvals
:
1158 if len(validrange
) != 2:
1159 raise Exception('%s: invalid range in addon configuration'
1160 % '-'.join(validrange
))
1162 if _value
< int(validrange
[0]) or _value
> int(validrange
[1]):
1165 'message': 'value of out range "%s": '
1166 'valid attribute range: %s'
1167 % (value
, '-'.join(validrange
))
1169 return {'result': True}
1171 def _check_validvals(self
, ifacename
, module_name
, attrs
):
1172 ifaceobj
= self
.get_ifaceobjs(ifacename
)
1176 for attrname
, attrvalue
in ifaceobj
[0].config
.items():
1178 attrname_dict
= attrs
.get(attrname
, {})
1179 validvals
= attrname_dict
.get('validvals', [])
1180 validrange
= attrname_dict
.get('validrange', [])
1181 for value
in attrvalue
:
1182 res
= self
._check
_validvals
_value
(attrname
,
1186 if not res
['result']:
1187 self
.logger
.warn('%s: %s: %s' %
1188 (ifacename
, attrname
, res
['message']))
1190 except Exception as e
:
1191 self
.logger
.warn('addon \'%s\': %s: %s' % (module_name
,
1197 def _module_syntax_check(self
, filtered_ifacenames
):
1199 for ifacename
in filtered_ifacenames
:
1200 for module
in self
.modules
.values():
1202 if hasattr(module
, '_modinfo'):
1203 if not self
._check
_validvals
(ifacename
,
1204 module
.__class
__.__name
__,
1205 module
._modinfo
.get('attrs', {})):
1207 if hasattr(module
, 'syntax_check') and callable(module
.syntax_check
):
1208 if not module
.syntax_check(self
.get_ifaceobjs(ifacename
)[0],
1209 self
.get_ifaceobjs
):
1211 except Exception, e
:
1212 self
.logger
.warn('%s: %s' % (ifacename
, str(e
)))
1216 def _iface_configattr_syntax_checker(self
, attrname
, attrval
):
1217 for m
, mdict
in self
.module_attrs
.items():
1220 attrsdict
= mdict
.get('attrs')
1222 a
= attrsdict
.get(attrname
)
1224 if a
.get('deprecated'):
1225 newa
= a
.get('new-attribute')
1227 self
.logger
.warn('attribute %s is deprecated. use %s instead.' %(attrname
, newa
))
1229 self
.logger
.warn('attribute %s is deprecated.'
1233 for key
in attrsdict
:
1234 if 'aliases' in attrsdict
[key
]:
1235 if attrname
in attrsdict
[key
]['aliases']:
1237 except AttributeError:
1241 def _ifaceobj_syntax_checker(self
, ifaceobj
):
1243 for attrname
, attrvalue
in ifaceobj
.config
.items():
1245 for k
, v
in self
.module_attrs
.items():
1246 if v
and v
.get('attrs', {}).get(attrname
):
1251 self
.logger
.warn('%s: unsupported attribute \'%s\'' \
1252 % (ifaceobj
.name
, attrname
))
1256 def read_iface_config(self
):
1257 """ Reads default network interface config /etc/network/interfaces. """
1259 nifaces
= networkInterfaces(self
.interfacesfile
,
1260 self
.interfacesfileiobuf
,
1261 self
.interfacesfileformat
,
1262 template_enable
=self
.config
.get('template_enable', 0),
1263 template_engine
=self
.config
.get('template_engine'),
1264 template_lookuppath
=self
.config
.get('template_lookuppath'))
1265 if self
._ifaceobj
_squash
or self
._ifaceobj
_squash
_internal
:
1266 nifaces
.subscribe('iface_found', self
._save
_iface
_squash
)
1268 nifaces
.subscribe('iface_found', self
._save
_iface
)
1269 if self
.config
.get('addon_syntax_check', '1') == '1':
1270 nifaces
.subscribe('validateifaceattr',
1271 self
._iface
_configattr
_syntax
_checker
)
1272 nifaces
.subscribe('validateifaceobj', self
._ifaceobj
_syntax
_checker
)
1274 if nifaces
.errors
or nifaces
.warns
:
1278 def read_old_iface_config(self
):
1279 """ Reads the saved iface config instead of default iface config.
1280 And saved iface config is already read by the statemanager """
1281 self
.ifaceobjdict
= copy
.deepcopy(self
.statemanager
.ifaceobjdict
)
1283 def _load_addon_modules_config(self
):
1284 """ Load addon modules config file """
1286 with
open(self
.addon_modules_configfile
, 'r') as f
:
1287 lines
= f
.readlines()
1290 litems
= l
.strip(' \n\t\r').split(',')
1291 if not litems
or len(litems
) < 2:
1293 operation
= litems
[0]
1295 self
.module_ops
[operation
].append(mname
)
1296 except Exception, e
:
1297 self
.logger
.warn('error reading line \'%s\' %s:' %(l
, str(e
)))
1300 def load_addon_modules(self
, modules_dir_list
):
1301 """ load python modules from modules_dir
1303 Default modules_dir is /usr/share/ifupdownmodules
1306 failed_import
= list()
1308 self
.logger
.info('loading builtin modules from %s' % str(modules_dir_list
))
1309 self
._load
_addon
_modules
_config
()
1311 for modules_dir
in modules_dir_list
:
1312 if not modules_dir
in sys
.path
:
1313 sys
.path
.insert(1, modules_dir
)
1315 for op
, mlist
in self
.module_ops
.items():
1317 if self
.modules
.get(mname
):
1319 mpath
= modules_dir
+ '/' + mname
+ '.py'
1320 if os
.path
.exists(mpath
) and mpath
not in failed_import
:
1322 m
= __import__(mname
)
1323 mclass
= getattr(m
, mname
)
1324 except Exception as e
:
1325 self
.logger
.warning('cannot load "%s" module: %s' % (mname
, str(e
)))
1326 failed_import
.append(mpath
)
1329 minstance
= mclass()
1330 script_override
= minstance
.get_overrides_ifupdown_scripts()
1331 self
.overridden_ifupdown_scripts
.extend(script_override
)
1332 except moduleNotSupported
, e
:
1333 self
.logger
.info('module %s not loaded (%s)\n'
1338 self
.modules
[mname
] = minstance
1340 self
.module_attrs
[mname
] = minstance
.get_modinfo()
1346 # Assign all modules to query operations
1347 self
.module_ops
['query-checkcurr'] = self
.modules
.keys()
1348 self
.module_ops
['query-running'] = self
.modules
.keys()
1349 self
.module_ops
['query-dependency'] = self
.modules
.keys()
1350 self
.module_ops
['query'] = self
.modules
.keys()
1351 self
.module_ops
['query-raw'] = self
.modules
.keys()
1353 def _keyword_number_comma_range_list(self
, value
, validrange
=None):
1354 return self
._keyword
_number
_range
_list
(value
.replace(',', ' '), validrange
=validrange
)
1357 def _modules_help(self
, fmt
):
1358 """ Prints addon modules supported syntax """
1362 for key
, value
in self
.modules
.items():
1363 if hasattr(value
, '_modinfo'):
1365 'mhelp': value
._modinfo
['mhelp'],
1366 'attrs': value
.merge_modinfo_with_policy_files()
1368 print json
.dumps(modinfos
)
1371 for m
, mdict
in self
.module_attrs
.items():
1374 print('%s: %s' %(m
, mdict
.get('mhelp')))
1375 attrdict
= self
.modules
[m
].merge_modinfo_with_policy_files()
1379 for attrname
, attrvaldict
in attrdict
.items():
1380 if attrvaldict
.get('compat', False):
1382 print('%s%s' %(indent
, attrname
))
1383 print('%shelp: %s' %(indent
+ ' ',
1384 attrvaldict
.get('help', '')))
1385 print ('%srequired: %s' %(indent
+ ' ',
1386 attrvaldict
.get('required', False)))
1387 default
= attrvaldict
.get('default')
1389 print('%sdefault: %s' %(indent
+ ' ', default
))
1391 validrange
= attrvaldict
.get('validrange')
1393 print('%svalidrange: %s-%s'
1394 %(indent
+ ' ', validrange
[0], validrange
[1]))
1396 validvals
= attrvaldict
.get('validvals')
1398 print('%svalidvals: %s'
1399 %(indent
+ ' ', ','.join(validvals
)))
1401 examples
= attrvaldict
.get('example')
1405 print '%sexample:' %(indent
+ ' ')
1407 print '%s%s' %(indent
+ ' ', e
)
1412 def load_scripts(self
, modules_dir
):
1413 """ loading user modules from /etc/network/.
1415 Note that previously loaded python modules override modules found
1416 under /etc/network if any
1420 self
.logger
.info('looking for user scripts under %s' %modules_dir
)
1421 for op
, mlist
in self
.script_ops
.items():
1422 msubdir
= modules_dir
+ '/if-%s.d' %op
1423 self
.logger
.info('loading scripts under %s ...' %msubdir
)
1425 module_list
= os
.listdir(msubdir
)
1426 for module
in module_list
:
1427 if self
.modules
.get(module
) or module
in self
.overridden_ifupdown_scripts
:
1429 self
.script_ops
[op
].append(msubdir
+ '/' + module
)
1434 def _sched_ifaces(self
, ifacenames
, ops
, skipupperifaces
=False,
1435 followdependents
=True, sort
=False):
1436 self
.logger
.debug('scheduling \'%s\' for %s'
1437 %(str(ops
), str(ifacenames
)))
1438 self
._pretty
_print
_ordered
_dict
('dependency graph',
1439 self
.dependency_graph
)
1440 ifaceScheduler
.sched_ifaces(self
, ifacenames
, ops
,
1441 dependency_graph
=self
.dependency_graph
,
1442 order
=ifaceSchedulerFlags
.INORDER
1444 else ifaceSchedulerFlags
.POSTORDER
,
1445 followdependents
=followdependents
,
1446 skipupperifaces
=skipupperifaces
,
1447 sort
=True if (sort
or ifupdownflags
.flags
.CLASS
) else False)
1448 return ifaceScheduler
.get_sched_status()
1450 def _render_ifacename(self
, ifacename
):
1452 vlan_match
= re
.match("^([\d]+)-([\d]+)", ifacename
)
1454 vlan_groups
= vlan_match
.groups()
1455 if vlan_groups
[0] and vlan_groups
[1]:
1456 [new_ifacenames
.append('%d' %v
)
1457 for v
in range(int(vlan_groups
[0]),
1458 int(vlan_groups
[1])+1)]
1459 return new_ifacenames
1461 def _preprocess_ifacenames(self
, ifacenames
):
1462 """ validates interface list for config existance.
1464 returns -1 if one or more interface not found. else, returns 0
1469 for i
in ifacenames
:
1470 ifaceobjs
= self
.get_ifaceobjs(i
)
1472 # if name not available, render interface name and check again
1473 rendered_ifacenames
= utils
.expand_iface_range(i
)
1474 if rendered_ifacenames
:
1475 for ri
in rendered_ifacenames
:
1476 ifaceobjs
= self
.get_ifaceobjs(ri
)
1478 err_iface
+= ' ' + ri
1480 new_ifacenames
.append(ri
)
1482 err_iface
+= ' ' + i
1484 new_ifacenames
.append(i
)
1486 raise Exception('cannot find interfaces:%s' %err_iface
)
1487 return new_ifacenames
1489 def _iface_whitelisted(self
, auto
, allow_classes
, excludepats
, ifacename
):
1490 """ Checks if interface is whitelisted depending on set of parameters.
1492 interfaces are checked against the allow_classes and auto lists.
1498 # Check if interface matches the exclude patter
1500 for e
in excludepats
:
1501 if re
.search(e
, ifacename
):
1503 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
1506 self
.logger
.debug('iface %s' %ifacename
+ ' not found')
1508 # If matched exclude pattern, return false
1511 i
.blacklisted
= True
1512 self
.blacklisted_ifaces_present
= True
1514 # Check if interface belongs to the class
1515 # the user is interested in, if not return false
1520 common
= Set(allow_classes
).intersection(
1525 # If a class was requested and interface does not belong
1526 # to the class, only then mark the ifaceobjs as blacklisted
1527 self
.blacklisted_ifaces_present
= True
1529 i
.blacklisted
= True
1531 # If the user has requested auto class, check if the interface
1539 # If auto was requested and interface was not marked auto,
1540 # only then mark all of them as blacklisted
1541 self
.blacklisted_ifaces_present
= True
1543 i
.blacklisted
= True
1546 def _compat_conv_op_to_mode(self
, op
):
1547 """ Returns old op name to work with existing scripts """
1555 def generate_running_env(self
, ifaceobj
, op
):
1556 """ Generates a dictionary with env variables required for
1557 an interface. Used to support script execution for interfaces.
1561 iface_env
= ifaceobj
.get_env()
1563 cenv
= dict(os
.environ
)
1565 cenv
.update(iface_env
)
1570 cenv
['MODE'] = self
._compat
_conv
_op
_to
_mode
(op
)
1575 def _save_state(self
):
1576 if (not self
.flags
.STATEMANAGER_ENABLE
or
1577 not self
.flags
.STATEMANAGER_UPDATE
):
1580 # Update persistant iface states
1581 self
.statemanager
.save_state()
1582 except Exception, e
:
1583 if self
.logger
.isEnabledFor(logging
.DEBUG
):
1584 t
= sys
.exc_info()[2]
1585 traceback
.print_tb(t
)
1586 self
.logger
.warning('error saving state (%s)' %str
(e
))
1588 def set_type(self
, type):
1590 self
.type = ifaceType
.IFACE
1591 elif type == 'vlan':
1592 self
.type = ifaceType
.BRIDGE_VLAN
1594 self
.type = ifaceType
.UNKNOWN
1596 def _process_delay_admin_state_queue(self
, op
):
1597 if not self
._delay
_admin
_state
_iface
_queue
:
1602 func
= self
.link_down
1605 for i
in self
._delay
_admin
_state
_iface
_queue
:
1607 if self
.link_exists(i
):
1609 except Exception, e
:
1610 self
.logger
.warn(str(e
))
1613 def up(self
, ops
, auto
=False, allow_classes
=None, ifacenames
=None,
1614 excludepats
=None, printdependency
=None, syntaxcheck
=False,
1615 type=None, skipupperifaces
=False):
1616 """This brings the interface(s) up
1619 ops (list): list of ops to perform on the interface(s).
1620 Eg: ['pre-up', 'up', 'post-up'
1623 auto (bool): act on interfaces marked auto
1624 allow_classes (list): act on interfaces belonging to classes in the list
1625 ifacenames (list): act on interfaces specified in this list
1626 excludepats (list): list of patterns of interfaces to exclude
1627 syntaxcheck (bool): only perform syntax check
1633 ifupdownflags
.flags
.CLASS
= True
1634 if not self
.flags
.ADDONS_ENABLE
:
1635 self
.flags
.STATEMANAGER_UPDATE
= False
1637 ifupdownflags
.flags
.ALL
= True
1638 ifupdownflags
.flags
.WITH_DEPENDS
= True
1640 iface_read_ret
= self
.read_iface_config()
1644 filtered_ifacenames
= None
1646 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1649 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1651 # if iface list not given by user, assume all from config file
1652 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1654 if not filtered_ifacenames
:
1655 # filter interfaces based on auto and allow classes
1656 filtered_ifacenames
= [i
for i
in ifacenames
1657 if self
._iface
_whitelisted
(auto
, allow_classes
,
1660 if not filtered_ifacenames
:
1661 raise Exception('no ifaces found matching given allow lists')
1664 self
.populate_dependency_info(ops
, filtered_ifacenames
)
1665 self
.print_dependency(filtered_ifacenames
, printdependency
)
1668 self
.populate_dependency_info(ops
)
1670 # If only syntax check was requested, return here.
1671 # return here because we want to make sure most
1672 # errors above are caught and reported.
1674 if not self
._module
_syntax
_check
(filtered_ifacenames
):
1676 if not iface_read_ret
:
1678 elif self
._any
_iface
_errors
(filtered_ifacenames
):
1684 ret
= self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1685 skipupperifaces
=skipupperifaces
,
1686 followdependents
=True
1687 if ifupdownflags
.flags
.WITH_DEPENDS
1690 self
._process
_delay
_admin
_state
_queue
('up')
1691 if not ifupdownflags
.flags
.DRYRUN
and self
.flags
.ADDONS_ENABLE
:
1694 if not iface_read_ret
or not ret
:
1697 def _get_filtered_ifacenames_with_classes(self
, auto
, allow_classes
, excludepats
, ifacenames
):
1698 # if user has specified ifacelist and allow_classes
1699 # append the allow_classes interfaces to user
1701 filtered_ifacenames
= [i
for i
in self
.ifaceobjdict
.keys()
1702 if self
._iface
_whitelisted
(auto
, allow_classes
,
1704 filtered_ifacenames
+= ifacenames
1706 for intf
in ifacenames
:
1707 for obj
in self
.get_ifaceobjs(intf
) or []:
1708 obj
.blacklisted
= False
1710 return filtered_ifacenames
1712 def down(self
, ops
, auto
=False, allow_classes
=None, ifacenames
=None,
1713 excludepats
=None, printdependency
=None, usecurrentconfig
=False,
1715 """ down an interface """
1720 ifupdownflags
.flags
.CLASS
= True
1721 if not self
.flags
.ADDONS_ENABLE
:
1722 self
.flags
.STATEMANAGER_UPDATE
= False
1724 ifupdownflags
.flags
.ALL
= True
1725 ifupdownflags
.flags
.WITH_DEPENDS
= True
1726 # For down we need to look at old state, unless usecurrentconfig
1728 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
and
1729 self
.statemanager
.ifaceobjdict
):
1730 # Since we are using state manager objects,
1731 # skip the updating of state manager objects
1732 self
.logger
.debug('Looking at old state ..')
1733 self
.read_old_iface_config()
1735 # If no old state available
1737 self
.read_iface_config()
1738 except Exception, e
:
1739 raise Exception('error reading iface config (%s)' %str
(e
))
1740 filtered_ifacenames
= None
1742 # If iface list is given by the caller, always check if iface
1745 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1748 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1750 except Exception, e
:
1751 raise Exception('%s' %str
(e
) +
1752 ' (interface was probably never up ?)')
1755 # if iface list not given by user, assume all from config file
1756 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1758 if not filtered_ifacenames
:
1759 # filter interfaces based on auto and allow classes
1760 filtered_ifacenames
= [i
for i
in ifacenames
1761 if self
._iface
_whitelisted
(auto
, allow_classes
,
1764 if not filtered_ifacenames
:
1765 raise Exception('no ifaces found matching given allow lists ' +
1766 '(or interfaces were probably never up ?)')
1769 self
.populate_dependency_info(ops
, filtered_ifacenames
)
1770 self
.print_dependency(filtered_ifacenames
, printdependency
)
1773 self
.populate_dependency_info(ops
)
1776 self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1777 followdependents
=True
1778 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
1780 self
._process
_delay
_admin
_state
_queue
('down')
1781 if not ifupdownflags
.flags
.DRYRUN
and self
.flags
.ADDONS_ENABLE
:
1784 def query(self
, ops
, auto
=False, format_list
=False, allow_classes
=None,
1786 excludepats
=None, printdependency
=None,
1787 format
='native', type=None):
1788 """ query an interface """
1792 # Let us forget internal squashing when it comes to
1793 # ifquery. It can surprise people relying of ifquery
1795 self
._ifaceobj
_squash
_internal
= False
1798 ifupdownflags
.flags
.CLASS
= True
1799 if self
.flags
.STATEMANAGER_ENABLE
and ops
[0] == 'query-savedstate':
1800 return self
.statemanager
.dump_pretty(ifacenames
)
1801 self
.flags
.STATEMANAGER_UPDATE
= False
1803 self
.logger
.debug('setting flag ALL')
1804 ifupdownflags
.flags
.ALL
= True
1805 ifupdownflags
.flags
.WITH_DEPENDS
= True
1807 if ops
[0] == 'query-syntax':
1808 self
._modules
_help
(format
)
1810 elif ops
[0] == 'query-running':
1811 # create fake devices to all dependents that dont have config
1812 map(lambda i
: self
.create_n_save_ifaceobj(i
,
1813 ifacePrivFlags(False, True)), ifacenames
)
1816 self
.read_iface_config()
1820 if ifacenames
and ops
[0] != 'query-running':
1821 # If iface list is given, always check if iface is present
1822 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1825 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1827 # if iface list not given by user, assume all from config file
1828 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1830 # filter interfaces based on auto and allow classes
1831 if ops
[0] == 'query-running':
1832 filtered_ifacenames
= ifacenames
1833 elif not allow_classes
:
1834 filtered_ifacenames
= [
1835 i
for i
in ifacenames
1836 if self
._iface
_whitelisted
(
1843 if not filtered_ifacenames
:
1844 raise Exception('no ifaces found matching ' +
1845 'given allow lists')
1847 self
.populate_dependency_info(ops
)
1848 if ops
[0] == 'query-dependency' and printdependency
:
1849 self
.print_dependency(filtered_ifacenames
, printdependency
)
1852 if format_list
and (ops
[0] == 'query' or ops
[0] == 'query-raw'):
1853 return self
.print_ifaceobjs_list(filtered_ifacenames
)
1855 if ops
[0] == 'query' and not ifupdownflags
.flags
.WITHDEFAULTS
:
1856 return self
.print_ifaceobjs_pretty(filtered_ifacenames
, format
)
1857 elif ops
[0] == 'query-raw':
1858 return self
.print_ifaceobjs_raw(filtered_ifacenames
)
1860 ret
= self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1861 followdependents
=True
1862 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
1864 if ops
[0] == 'query' and ifupdownflags
.flags
.WITHDEFAULTS
:
1865 return self
.print_ifaceobjs_pretty(filtered_ifacenames
, format
)
1866 elif ops
[0] == 'query-checkcurr':
1867 ret
= self
.print_ifaceobjscurr_pretty(filtered_ifacenames
, format
)
1869 # if any of the object has an error, signal that silently
1871 elif ops
[0] == 'query-running':
1872 self
.print_ifaceobjsrunning_pretty(filtered_ifacenames
, format
)
1875 def _reload_currentlyup(self
, upops
, downops
, auto
=False, allow
=None,
1876 ifacenames
=None, excludepats
=None, usecurrentconfig
=False,
1877 syntaxcheck
=False, **extra_args
):
1878 """ reload currently up interfaces """
1879 new_ifaceobjdict
= {}
1881 self
.logger
.info('reloading interfaces that are currently up ..')
1884 iface_read_ret
= self
.read_iface_config()
1887 if not self
.ifaceobjdict
:
1888 self
.logger
.warn("nothing to reload ..exiting.")
1890 already_up_ifacenames
= []
1891 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1893 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
1894 and self
.statemanager
.ifaceobjdict
):
1895 already_up_ifacenames
= self
.statemanager
.ifaceobjdict
.keys()
1897 # Get already up interfaces that still exist in the interfaces file
1898 already_up_ifacenames_not_present
= Set(
1899 already_up_ifacenames
).difference(ifacenames
)
1900 already_up_ifacenames_still_present
= Set(
1901 already_up_ifacenames
).difference(
1902 already_up_ifacenames_not_present
)
1904 interfaces_to_up
= already_up_ifacenames_still_present
1906 # generate dependency graph of interfaces
1907 self
.populate_dependency_info(upops
, interfaces_to_up
)
1909 # If only syntax check was requested, return here.
1910 # return here because we want to make sure most
1911 # errors above are caught and reported.
1913 if not self
._module
_syntax
_check
(interfaces_to_up
):
1915 if not iface_read_ret
:
1917 elif self
._any
_iface
_errors
(interfaces_to_up
):
1921 if (already_up_ifacenames_not_present
and
1922 self
.config
.get('ifreload_currentlyup_down_notpresent') == '1'):
1923 self
.logger
.info('reload: schedule down on interfaces: %s'
1924 %str
(already_up_ifacenames_not_present
))
1926 # Save a copy of new iface objects and dependency_graph
1927 new_ifaceobjdict
= dict(self
.ifaceobjdict
)
1928 new_dependency_graph
= dict(self
.dependency_graph
)
1930 # old interface config is read into self.ifaceobjdict
1931 self
.read_old_iface_config()
1933 # reinitialize dependency graph
1934 self
.dependency_graph
= OrderedDict({})
1935 falready_up_ifacenames_not_present
= [i
for i
in
1936 already_up_ifacenames_not_present
1937 if self
._iface
_whitelisted
(auto
, allow
,
1939 self
.populate_dependency_info(downops
,
1940 falready_up_ifacenames_not_present
)
1941 self
._sched
_ifaces
(falready_up_ifacenames_not_present
, downops
,
1942 followdependents
=False, sort
=True)
1944 self
.logger
.info('no interfaces to down ..')
1946 # Now, run 'up' with new config dict
1947 # reset statemanager update flag to default
1949 ifupdownflags
.flags
.ALL
= True
1950 ifupdownflags
.flags
.WITH_DEPENDS
= True
1951 if new_ifaceobjdict
:
1952 # and now, ifaceobjdict is back to current config
1953 self
.ifaceobjdict
= new_ifaceobjdict
1954 self
.dependency_graph
= new_dependency_graph
1956 if not self
.ifaceobjdict
:
1957 self
.logger
.info('no interfaces to up')
1959 self
.logger
.info('reload: scheduling up on interfaces: %s'
1960 %str
(interfaces_to_up
))
1961 ret
= self
._sched
_ifaces
(interfaces_to_up
, upops
,
1962 followdependents
=True
1963 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
1964 if ifupdownflags
.flags
.DRYRUN
:
1968 if not iface_read_ret
or not ret
:
1971 def _reload_default(self
, upops
, downops
, auto
=False, allow
=None,
1972 ifacenames
=None, excludepats
=None, usecurrentconfig
=False,
1973 syntaxcheck
=False, **extra_args
):
1974 """ reload interface config """
1975 new_ifaceobjdict
= {}
1978 iface_read_ret
= self
.read_iface_config()
1982 if not self
.ifaceobjdict
:
1983 self
.logger
.warn("nothing to reload ..exiting.")
1986 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1987 new_filtered_ifacenames
= [i
for i
in ifacenames
1988 if self
._iface
_whitelisted
(auto
, allow
,
1990 # generate dependency graph of interfaces
1991 self
.populate_dependency_info(upops
)
1993 # If only syntax check was requested, return here.
1994 # return here because we want to make sure most
1995 # errors above are caught and reported.
1997 if not self
._module
_syntax
_check
(new_filtered_ifacenames
):
1999 if not iface_read_ret
:
2001 elif self
._any
_iface
_errors
(new_filtered_ifacenames
):
2005 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
2006 and self
.statemanager
.ifaceobjdict
):
2007 # Save a copy of new iface objects and dependency_graph
2008 new_ifaceobjdict
= dict(self
.ifaceobjdict
)
2009 new_dependency_graph
= dict(self
.dependency_graph
)
2011 self
.ifaceobjdict
= OrderedDict({})
2012 self
.dependency_graph
= OrderedDict({})
2014 # if old state is present, read old state and mark op for 'down'
2015 # followed by 'up' aka: reload
2016 # old interface config is read into self.ifaceobjdict
2017 self
.read_old_iface_config()
2020 # oldconfig not available, continue with 'up' with new config
2022 new_ifaceobjdict
= self
.ifaceobjdict
2023 new_dependency_graph
= self
.dependency_graph
2025 if op
== 'reload' and ifacenames
:
2026 ifacenames
= self
.ifaceobjdict
.keys()
2027 old_filtered_ifacenames
= [i
for i
in ifacenames
2028 if self
._iface
_whitelisted
(auto
, allow
,
2031 # generate dependency graph of old interfaces,
2032 # This should make sure built in interfaces are
2033 # populated. disable check shared dependents as an optimization.
2034 # these are saved interfaces and dependency for these
2035 # have been checked before they became part of saved state.
2037 self
.flags
.CHECK_SHARED_DEPENDENTS
= False
2038 self
.populate_dependency_info(upops
)
2039 self
.flags
.CHECK_SHARED_DEPENDENTS
= True
2040 except Exception, e
:
2041 self
.logger
.info("error generating dependency graph for "
2042 "saved interfaces (%s)" %str
(e
))
2045 # make sure we pick up built-in interfaces
2046 # if config file had 'ifreload_down_changed' variable
2047 # set, also look for interfaces that changed to down them
2048 down_changed
= int(self
.config
.get('ifreload_down_changed', '1'))
2050 # Generate the interface down list
2051 # Interfaces that go into the down list:
2052 # - interfaces that were present in last config and are not
2053 # present in the new config
2054 # - interfaces that were changed between the last and current
2057 for ifname
in self
.ifaceobjdict
.keys():
2058 lastifaceobjlist
= self
.ifaceobjdict
.get(ifname
)
2059 if not self
.is_ifaceobj_builtin(lastifaceobjlist
[0]):
2060 # if interface is not built-in and is not in
2061 # old filtered ifacenames
2062 if ifname
not in old_filtered_ifacenames
:
2065 # If interface is not present in the new file
2066 # append it to the down list
2067 newifaceobjlist
= new_ifaceobjdict
.get(ifname
)
2068 if not newifaceobjlist
:
2069 ifacedownlist
.append(ifname
)
2071 # If ifaceobj was present in the old interfaces file,
2072 # and does not have a config in the new interfaces file
2073 # but has been picked up as a dependent of another
2074 # interface, catch it here. This catches a common error
2075 # for example: remove a bond section from the interfaces
2076 # file, but leave it around as a bridge port
2077 # XXX: Ideally its better to just add it to the
2078 # ifacedownlist. But we will be cautious here
2079 # and just print a warning
2080 if (self
.is_ifaceobj_noconfig(newifaceobjlist
[0]) and
2081 not self
.is_ifaceobj_builtin(newifaceobjlist
[0]) and
2082 lastifaceobjlist
[0].is_config_present() and
2083 lastifaceobjlist
[0].link_kind
):
2084 self
.logger
.warn('%s: misconfig ? removed but still exists '
2085 'as a dependency of %s.\nPlease remove '
2086 'the dependency manually `ifdown %s` if '
2087 'it is being picked up as part of a regex'
2088 % (newifaceobjlist
[objidx
].name
,
2089 str(newifaceobjlist
[objidx
].upperifaces
),
2090 newifaceobjlist
[objidx
].name
))
2091 if (lastifaceobjlist
[0].link_kind
and
2092 not newifaceobjlist
[0].link_kind
):
2093 self
.logger
.warn('%s: moved from being a %s to a'
2094 ' physical interface (non-logical interface).'
2095 'This interface will be downed.\n'
2096 ' If this was not intentional, please restore the'
2097 ' original interface definition and execute ifreload'
2098 % (newifaceobjlist
[objidx
].name
,
2099 ifaceLinkKind
.to_str(lastifaceobjlist
[0].link_kind
)))
2100 ifacedownlist
.append(newifaceobjlist
[objidx
].name
)
2101 if not down_changed
:
2103 if len(newifaceobjlist
) != len(lastifaceobjlist
):
2104 ifacedownlist
.append(ifname
)
2107 # If interface has changed between the current file
2108 # and the last installed append it to the down list
2109 # compare object list
2110 for objidx
in range(0, len(lastifaceobjlist
)):
2111 oldobj
= lastifaceobjlist
[objidx
]
2112 newobj
= newifaceobjlist
[objidx
]
2113 if not newobj
.compare(oldobj
):
2114 ifacedownlist
.append(ifname
)
2118 self
.logger
.info('reload: scheduling down on interfaces: %s'
2119 %str
(ifacedownlist
))
2120 # reinitialize dependency graph
2121 self
.dependency_graph
= OrderedDict({})
2123 # Generate dependency info for old config
2124 self
.flags
.CHECK_SHARED_DEPENDENTS
= False
2125 self
.populate_dependency_info(downops
, ifacedownlist
)
2126 self
.flags
.CHECK_SHARED_DEPENDENTS
= True
2129 # XXX: Hack to skip checking upperifaces during down.
2130 # the dependency list is not complete here
2131 # and we dont want to down the upperiface.
2132 # Hence during reload, set this to true.
2133 # This is being added to avoid a failure in
2134 # scheduler._check_upperifaces when we are dowing
2135 # a builtin bridge port
2136 self
.flags
.SCHED_SKIP_CHECK_UPPERIFACES
= True
2137 self
._sched
_ifaces
(ifacedownlist
, downops
,
2138 followdependents
=False,
2140 except Exception, e
:
2141 self
.logger
.error(str(e
))
2144 self
.flags
.SCHED_SKIP_CHECK_UPPERIFACES
= False
2145 self
._process
_delay
_admin
_state
_queue
('down')
2147 self
.logger
.info('no interfaces to down ..')
2149 # Now, run 'up' with new config dict
2150 # reset statemanager update flag to default
2151 if not new_ifaceobjdict
:
2152 self
.logger
.debug('no interfaces to up')
2156 ifupdownflags
.flags
.ALL
= True
2157 ifupdownflags
.flags
.WITH_DEPENDS
= True
2158 # and now, we are back to the current config in ifaceobjdict
2159 self
.ifaceobjdict
= new_ifaceobjdict
2160 self
.dependency_graph
= new_dependency_graph
2162 self
.logger
.info('reload: scheduling up on interfaces: %s'
2163 %str
(new_filtered_ifacenames
))
2164 ifupdownflags
.flags
.CACHE
= True
2166 ret
= self
._sched
_ifaces
(new_filtered_ifacenames
, upops
,
2167 followdependents
=True
2168 if ifupdownflags
.flags
.WITH_DEPENDS
2170 except Exception, e
:
2172 self
.logger
.error(str(e
))
2174 self
._process
_delay
_admin
_state
_queue
('up')
2175 if ifupdownflags
.flags
.DRYRUN
:
2179 if not iface_read_ret
or not ret
:
2182 def reload(self
, *args
, **kargs
):
2183 """ reload interface config """
2184 self
.logger
.debug('reloading interface config ..')
2185 if kargs
.get('currentlyup', False):
2186 self
._reload
_currentlyup
(*args
, **kargs
)
2188 self
._reload
_default
(*args
, **kargs
)
2190 def _any_iface_errors(self
, ifacenames
):
2191 for i
in ifacenames
:
2192 ifaceobjs
= self
.get_ifaceobjs(i
)
2193 if not ifaceobjs
: continue
2194 for ifaceobj
in ifaceobjs
:
2195 if (ifaceobj
.status
== ifaceStatus
.NOTFOUND
or
2196 ifaceobj
.status
== ifaceStatus
.ERROR
):
2200 def _pretty_print_ordered_dict(self
, prefix
, argdict
):
2201 outbuf
= prefix
+ ' {\n'
2202 for k
, vlist
in argdict
.items():
2203 outbuf
+= '\t%s : %s\n' %(k
, str(vlist
))
2204 self
.logger
.debug(outbuf
+ '}')
2206 def print_dependency(self
, ifacenames
, format
):
2207 """ prints iface dependency information """
2210 ifacenames
= self
.ifaceobjdict
.keys()
2211 if format
== 'list':
2212 for k
,v
in self
.dependency_graph
.items():
2213 print '%s : %s' %(k
, str(v
))
2214 elif format
== 'dot':
2216 map(lambda i
: indegrees
.update({i
:
2217 self
.get_iface_refcnt(i
)}),
2218 self
.dependency_graph
.keys())
2219 graph
.generate_dots(self
.dependency_graph
, indegrees
)
2221 def print_ifaceobjs_list(self
, ifacenames
):
2222 for i
in ifacenames
:
2225 def print_ifaceobjs_raw(self
, ifacenames
):
2226 """ prints raw lines for ifaces from config file """
2228 for i
in ifacenames
:
2229 for ifaceobj
in self
.get_ifaceobjs(i
):
2230 if self
.is_ifaceobj_builtin(ifaceobj
):
2232 ifaceobj
.dump_raw(self
.logger
)
2233 if (ifupdownflags
.flags
.WITH_DEPENDS
and
2234 not ifupdownflags
.flags
.ALL
):
2235 dlist
= ifaceobj
.lowerifaces
2236 if not dlist
: continue
2237 self
.print_ifaceobjs_raw(dlist
)
2239 def _get_ifaceobjs_pretty(self
, ifacenames
, ifaceobjs
, running
=False):
2240 """ returns iface obj list """
2242 for i
in ifacenames
:
2243 for ifaceobj
in self
.get_ifaceobjs(i
):
2244 if ((not running
and self
.is_ifaceobj_noconfig(ifaceobj
)) or
2245 (running
and not ifaceobj
.is_config_present() and
2246 not self
.is_iface_builtin_byname(i
) and
2247 not ifaceobj
.upperifaces
)):
2249 ifaceobjs
.append(ifaceobj
)
2250 if (ifupdownflags
.flags
.WITH_DEPENDS
and
2251 not ifupdownflags
.flags
.ALL
):
2252 dlist
= ifaceobj
.lowerifaces
2253 if not dlist
: continue
2254 self
._get
_ifaceobjs
_pretty
(dlist
, ifaceobjs
, running
)
2256 def print_ifaceobjs_pretty(self
, ifacenames
, format
='native'):
2257 """ pretty prints iface in format given by keyword arg format """
2260 self
._get
_ifaceobjs
_pretty
(ifacenames
, ifaceobjs
)
2261 if not ifaceobjs
: return
2262 if format
== 'json':
2263 print json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoder
,
2264 indent
=4, separators
=(',', ': '))
2266 expand
= int(self
.config
.get('ifquery_ifacename_expand_range', '0'))
2268 if not expand
and (i
.flags
& iface
.IFACERANGE_ENTRY
):
2269 # print only the first one
2270 if i
.flags
& iface
.IFACERANGE_START
:
2271 i
.dump_pretty(use_realname
=True)
2275 def _get_ifaceobjscurr_pretty(self
, ifacenames
, ifaceobjs
):
2277 for i
in ifacenames
:
2278 ifaceobjscurr
= self
.get_ifaceobjcurr(i
)
2279 if not ifaceobjscurr
: continue
2280 for ifaceobj
in ifaceobjscurr
:
2281 if (ifaceobj
.status
== ifaceStatus
.NOTFOUND
or
2282 ifaceobj
.status
== ifaceStatus
.ERROR
):
2284 if self
.is_ifaceobj_noconfig(ifaceobj
):
2286 ifaceobjs
.append(ifaceobj
)
2287 if (ifupdownflags
.flags
.WITH_DEPENDS
and
2288 not ifupdownflags
.flags
.ALL
):
2289 dlist
= ifaceobj
.lowerifaces
2290 if not dlist
: continue
2291 dret
= self
._get
_ifaceobjscurr
_pretty
(dlist
, ifaceobjs
)
2295 def print_ifaceobjscurr_pretty(self
, ifacenames
, format
='native'):
2296 """ pretty prints current running state of interfaces with status.
2298 returns 1 if any of the interface has an error,
2303 ret
= self
._get
_ifaceobjscurr
_pretty
(ifacenames
, ifaceobjs
)
2304 if not ifaceobjs
: return
2306 # override ifaceStatusUserStrs
2307 ifaceStatusUserStrs
.SUCCESS
= self
.config
.get('ifquery_check_success_str', _success_sym
)
2308 ifaceStatusUserStrs
.ERROR
= self
.config
.get('ifquery_check_error_str', _error_sym
)
2309 ifaceStatusUserStrs
.UNKNOWN
= self
.config
.get('ifquery_check_unknown_str', '')
2310 if format
== 'json':
2311 print json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoderWithStatus
,
2312 indent
=2, separators
=(',', ': '))
2314 map(lambda i
: i
.dump_pretty(with_status
=True), ifaceobjs
)
2317 def print_ifaceobjsrunning_pretty(self
, ifacenames
, format
='native'):
2318 """ pretty prints iface running state """
2321 self
._get
_ifaceobjs
_pretty
(ifacenames
, ifaceobjs
, running
=True)
2322 if not ifaceobjs
: return
2323 if format
== 'json':
2324 print json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoder
, indent
=2,
2325 separators
=(',', ': '))
2327 map(lambda i
: i
.dump_pretty(), ifaceobjs
)
2330 print 'ifupdown main object dump'
2331 print self
.pp
.pprint(self
.modules
)
2332 print self
.pp
.pprint(self
.ifaceobjdict
)
2334 def _dump_ifaceobjs(self
, ifacenames
):
2335 for i
in ifacenames
:
2336 ifaceobjs
= self
.get_ifaceobjs(i
)