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