]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown/ifupdownmain.py
Fix refcnt issue when multiple iface stanzas were presented for a white
[mirror_ifupdown2.git] / ifupdown / ifupdownmain.py
CommitLineData
a6f80f0e 1#!/usr/bin/python
3e8ee54f 2#
904908bc 3# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
3e8ee54f 4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6# ifupdownMain --
7# ifupdown main module
8#
a6f80f0e 9
10import os
11import re
3e8ee54f 12import imp
13import pprint
14import logging
15import sys, traceback
cb7cc592 16import copy
2cd06f78 17import json
55072bd1 18import ifupdown.statemanager as statemanager
a6f80f0e 19from networkinterfaces import *
20from iface import *
21from scheduler import *
22from collections import deque
23from collections import OrderedDict
a6f80f0e 24from graph import *
3e8ee54f 25from sets import Set
a6f80f0e 26
2c0ad8b3
RP
27"""
28.. module:: ifupdownmain
29:synopsis: main module for ifupdown package
30
31.. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
32
33"""
34
86fc62e2 35_tickmark = u'\u2713'
36_crossmark = u'\u2717'
e74d01e1
RP
37_success_sym = '(%s)' %_tickmark
38_error_sym = '(%s)' %_crossmark
86fc62e2 39
84ca006f
RP
40class ifupdownFlags():
41 FORCE = False
42 DRYRUN = False
43 NOWAIT = False
44 PERFMODE = False
45 CACHE = False
46
47 # Flags
48 CACHE_FLAGS = 0x0
49
be0b20f2 50class ifupdownMain(ifupdownBase):
53b00224 51 """ ifupdown2 main class """
52
a6f80f0e 53 # Flags
cca03c30 54 WITH_DEPENDS = False
a6f80f0e 55 ALL = False
5ee3e1a8 56 IFACE_CLASS = False
6bd7fc74 57 COMPAT_EXEC_SCRIPTS = False
20dd6242 58 STATEMANAGER_ENABLE = True
59 STATEMANAGER_UPDATE = True
60 ADDONS_ENABLE = False
a6f80f0e 61
37c0543d 62 # priv flags to mark iface objects
a070c90e
RP
63 BUILTIN = 0x0001
64 NOCONFIG = 0x0010
37c0543d 65
66 scripts_dir='/etc/network'
67 addon_modules_dir='/usr/share/ifupdownaddons'
14dc390d 68 addon_modules_configfile='/var/lib/ifupdownaddons/addons.conf'
a6f80f0e 69
70 # iface dictionary in the below format:
71 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
72 # eg:
53b00224 73 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
a6f80f0e 74 #
75 # Each ifaceobject corresponds to a configuration block for
76 # that interface
53b00224 77 # The value in the dictionary is a list because the network
78 # interface configuration file supports more than one iface section
79 # in the interfaces file
a6f80f0e 80 ifaceobjdict = OrderedDict()
81
a6f80f0e 82 # iface dictionary representing the curr running state of an iface
83 # in the below format:
84 # {'<ifacename>' : <ifaceobject>}
85 ifaceobjcurrdict = OrderedDict()
86
be0b20f2 87 # Dictionary representing operation and modules
88 # for every operation
89 module_ops = OrderedDict([('pre-up', []),
d08d5f54 90 ('up' , []),
91 ('post-up' , []),
92 ('query-checkcurr', []),
93 ('query-running', []),
94 ('query-dependency', []),
75730152 95 ('query', []),
96 ('query-raw', []),
d08d5f54 97 ('pre-down', []),
98 ('down' , []),
99 ('post-down' , [])])
37c0543d 100
101 # For old style /etc/network/ bash scripts
be0b20f2 102 script_ops = OrderedDict([('pre-up', []),
d08d5f54 103 ('up' , []),
104 ('post-up' , []),
105 ('pre-down', []),
106 ('down' , []),
107 ('post-down' , [])])
a6f80f0e 108
be0b20f2 109 # Handlers for ops that ifupdown2 owns
110 def run_up(self, ifaceobj):
496745cd
RP
111 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
112 # there is no real interface behind it
113 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
114 return
a070c90e
RP
115 if (ifaceobj.addr_method and
116 ifaceobj.addr_method == 'manual'):
117 return
118 if self._delay_admin_state:
119 self._delay_admin_state_iface_queue.append(ifaceobj.name)
120 return
7f045fd8
RP
121 # If this object is a link slave, ie its link is controlled
122 # by its link master interface, then dont set the link state.
123 # But do allow user to change state of the link if the interface
124 # is already with its link master (hence the master check).
7e2e64fb 125 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
7f045fd8 126 return
a070c90e 127 if not self.link_exists(ifaceobj.name):
7e2e64fb 128 return
a070c90e 129 self.link_up(ifaceobj.name)
be0b20f2 130
131 def run_down(self, ifaceobj):
496745cd
RP
132 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
133 # there is no real interface behind it
134 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
135 return
a070c90e
RP
136 if (ifaceobj.addr_method and
137 ifaceobj.addr_method == 'manual'):
138 return
139 if self._delay_admin_state:
140 self._delay_admin_state_iface_queue.append(ifaceobj.name)
141 return
7f045fd8
RP
142 # If this object is a link slave, ie its link is controlled
143 # by its link master interface, then dont set the link state.
144 # But do allow user to change state of the link if the interface
145 # is already with its link master (hence the master check).
7e2e64fb
RP
146 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
147 return
a070c90e 148 if not self.link_exists(ifaceobj.name):
7e2e64fb 149 return
a070c90e 150 self.link_down(ifaceobj.name)
be0b20f2 151
31a5f4c3 152 # ifupdown object interface operation handlers
be0b20f2 153 ops_handlers = OrderedDict([('up', run_up),
154 ('down', run_down)])
a6f80f0e 155
cb7cc592 156 def run_sched_ifaceobj_posthook(self, ifaceobj, op):
5c721925 157 if ((ifaceobj.priv_flags & self.BUILTIN) or
158 (ifaceobj.priv_flags & self.NOCONFIG)):
159 return
20dd6242 160 if self.STATEMANAGER_UPDATE:
cb7cc592 161 self.statemanager.ifaceobj_sync(ifaceobj, op)
31a5f4c3 162
163 # ifupdown object interface scheduler pre and posthooks
164 sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
165
14dc390d 166 def __init__(self, config={},
167 force=False, dryrun=False, nowait=False,
cca03c30 168 perfmode=False, withdepends=False, njobs=1,
14dc390d 169 cache=False, addons_enable=True, statemanager_enable=True,
3dcc1d0e 170 interfacesfile='/etc/network/interfaces',
171 interfacesfileiobuf=None,
172 interfacesfileformat='native'):
2c0ad8b3
RP
173 """This member function initializes the ifupdownmain object.
174
175 Kwargs:
176 config (dict): config dict from /etc/network/ifupdown2/ifupdown2.conf
177 force (bool): force interface configuration
178 dryrun (bool): dryrun interface configuration
179 withdepends (bool): apply interface configuration on all depends
180 interfacesfile (str): interfaces file. default is /etc/network/interfaces
181 interfacesfileformat (str): default is 'native'. Other choices are 'json'
182
183 Raises:
184 AttributeError, KeyError """
185
a6f80f0e 186 self.logger = logging.getLogger('ifupdown')
eab25b7c 187 self.FORCE = force
188 self.DRYRUN = dryrun
189 self.NOWAIT = nowait
190 self.PERFMODE = perfmode
cca03c30 191 self.WITH_DEPENDS = withdepends
20dd6242 192 self.STATEMANAGER_ENABLE = statemanager_enable
739f665b 193 self.CACHE = cache
14dc390d 194 self.interfacesfile = interfacesfile
3dcc1d0e 195 self.interfacesfileiobuf = interfacesfileiobuf
196 self.interfacesfileformat = interfacesfileformat
14dc390d 197 self.config = config
198 self.logger.debug(self.config)
67cfaeb1 199 self.blacklisted_ifaces_present = False
a690dfae 200
2da58137
RP
201 self.type = ifaceType.UNKNOWN
202
a690dfae 203 # Can be used to provide hints for caching
204 self.CACHE_FLAGS = 0x0
37c0543d 205 self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
20dd6242 206 self.ADDONS_ENABLE = addons_enable
eab25b7c 207
84ca006f
RP
208 # Copy flags into ifupdownFlags
209 # XXX: before we transition fully to ifupdownFlags
210 ifupdownFlags.FORCE = force
211 ifupdownFlags.DRYRUN = dryrun
212 ifupdownFlags.NOWAIT = nowait
213 ifupdownFlags.PERFMODE = perfmode
214 ifupdownFlags.CACHE = cache
215
a6f80f0e 216 self.ifaces = OrderedDict()
eab25b7c 217 self.njobs = njobs
a6f80f0e 218 self.pp = pprint.PrettyPrinter(indent=4)
37c0543d 219 self.modules = OrderedDict({})
d08d5f54 220 self.module_attrs = {}
20dd6242 221
37c0543d 222 self.load_addon_modules(self.addon_modules_dir)
e938bfec 223 if self.COMPAT_EXEC_SCRIPTS:
224 self.load_scripts(self.scripts_dir)
d08d5f54 225 self.dependency_graph = OrderedDict({})
a6f80f0e 226
8e113d63
RP
227 self._cache_no_repeats = {}
228
20dd6242 229 if self.STATEMANAGER_ENABLE:
230 try:
55072bd1 231 self.statemanager = statemanager.statemanager_api
20dd6242 232 self.statemanager.read_saved_state()
233 except Exception, e:
234 # XXX Maybe we should continue by ignoring old state
235 self.logger.warning('error reading state (%s)' %str(e))
236 raise
237 else:
238 self.STATEMANAGER_UPDATE = False
a070c90e
RP
239 self._delay_admin_state = True if self.config.get(
240 'delay_admin_state_change', '0') == '1' else False
241 self._delay_admin_state_iface_queue = []
cebe79c9
RP
242 if self._delay_admin_state:
243 self.logger.info('\'delay_admin_state_change\' is set. admin ' +
244 'state changes will be delayed till the end.')
245
246 self._link_master_slave = True if self.config.get(
a070c90e 247 'link_master_slave', '0') == '1' else False
cebe79c9
RP
248 if self._link_master_slave:
249 self.logger.info('\'link_master_slave\' is set. slave admin ' +
250 'state changes will be delayed till the ' +
251 'masters admin state change.')
a6f80f0e 252
61c4d724
RP
253 def link_master_slave_ignore_error(self, errorstr):
254 # If link master slave flag is set,
255 # there may be cases where the lowerdev may not be
256 # up resulting in 'Network is down' error
257 # This can happen if the lowerdev is a LINK_SLAVE
258 # of another interface which is not up yet
259 # example of such a case:
260 # bringing up a vlan on a bond interface and the bond
261 # is a LINK_SLAVE of a bridge (in other words the bond is
262 # part of a bridge) which is not up yet
263 if self._link_master_slave:
264 if 'Network is down':
265 return True
266 return False
267
31a5f4c3 268 def get_ifaceobjs(self, ifacename):
a6f80f0e 269 return self.ifaceobjdict.get(ifacename)
270
a9ab1b4f
RP
271 def get_ifaceobjs_saved(self, ifacename):
272 """ Return ifaceobjects from statemanager """
273 if self.STATEMANAGER_ENABLE:
274 return self.statemanager.get_ifaceobjs(ifacename)
275 else:
276 None
277
31a5f4c3 278 def get_ifaceobj_first(self, ifacename):
279 ifaceobjs = self.get_ifaceobjs(ifacename)
280 if ifaceobjs:
a6f80f0e 281 return ifaceobjs[0]
282 return None
283
c798b0f4 284 def get_ifacenames(self):
285 return self.ifaceobjdict.keys()
286
a6f80f0e 287 def get_iface_obj_last(self, ifacename):
288 return self.ifaceobjdict.get(ifacename)[-1]
289
a9ab1b4f 290
8c13865c
RP
291 def must_follow_upperifaces(self, ifacename):
292 #
293 # XXX: This bleeds the knowledge of iface
294 # types in the infrastructure module.
295 # Cant think of a better fix at the moment.
296 # In future maybe the module can set a flag
297 # to indicate if we should follow upperifaces
298 #
299 ifaceobj = self.get_ifaceobj_first(ifacename)
cb46a208 300 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
8c13865c
RP
301 return False
302 return True
303
53b00224 304 def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
305 increfcnt=False):
306 """ creates a iface object and adds it to the iface dictionary """
307 ifaceobj = iface()
308 ifaceobj.name = ifacename
309 ifaceobj.priv_flags = priv_flags
310 ifaceobj.auto = True
f3b69969
RP
311 if not self._link_master_slave:
312 ifaceobj.link_type = ifaceLinkType.LINK_NA
53b00224 313 if increfcnt:
314 ifaceobj.inc_refcnt()
315 self.ifaceobjdict[ifacename] = [ifaceobj]
316 return ifaceobj
317
d08d5f54 318 def create_n_save_ifaceobjcurr(self, ifaceobj):
923290bd 319 """ creates a copy of iface object and adds it to the iface
320 dict containing current iface objects
53b00224 321 """
739f665b 322 ifaceobjcurr = iface()
53b00224 323 ifaceobjcurr.name = ifaceobj.name
cb46a208 324 ifaceobjcurr.type = ifaceobj.type
62ddec8b 325 ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
326 ifaceobjcurr.priv_flags = ifaceobj.priv_flags
2cd06f78 327 ifaceobjcurr.auto = ifaceobj.auto
923290bd 328 self.ifaceobjcurrdict.setdefault(ifaceobj.name,
329 []).append(ifaceobjcurr)
d08d5f54 330 return ifaceobjcurr
a6f80f0e 331
923290bd 332 def get_ifaceobjcurr(self, ifacename, idx=0):
333 ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
334 if not ifaceobjlist:
335 return None
336 if not idx:
337 return ifaceobjlist
338 else:
339 return ifaceobjlist[idx]
a6f80f0e 340
739f665b 341 def get_ifaceobjrunning(self, ifacename):
342 return self.ifaceobjrunningdict.get(ifacename)
343
a6f80f0e 344 def get_iface_refcnt(self, ifacename):
53b00224 345 """ Return iface ref count """
a6f80f0e 346 max = 0
31a5f4c3 347 ifaceobjs = self.get_ifaceobjs(ifacename)
20dd6242 348 if not ifaceobjs:
349 return 0
a6f80f0e 350 for i in ifaceobjs:
62ddec8b 351 if i.refcnt > max:
352 max = i.refcnt
a6f80f0e 353 return max
354
d08d5f54 355 def is_iface_builtin_byname(self, ifacename):
cca03c30 356 """ Returns true if iface name is a builtin interface.
a6f80f0e 357
cca03c30 358 A builtin interface is an interface which ifupdown understands.
359 The following are currently considered builtin ifaces:
360 - vlan interfaces in the format <ifacename>.<vlanid>
a6f80f0e 361 """
d08d5f54 362 return '.' in ifacename
a6f80f0e 363
37c0543d 364 def is_ifaceobj_builtin(self, ifaceobj):
365 """ Returns true if iface name is a builtin interface.
366
367 A builtin interface is an interface which ifupdown understands.
368 The following are currently considered builtin ifaces:
369 - vlan interfaces in the format <ifacename>.<vlanid>
370 """
d08d5f54 371 return (ifaceobj.priv_flags & self.BUILTIN)
37c0543d 372
373 def is_ifaceobj_noconfig(self, ifaceobj):
53b00224 374 """ Returns true if iface object did not have a user defined config.
37c0543d 375
376 These interfaces appear only when they are dependents of interfaces
377 which have user defined config
378 """
d08d5f54 379 return (ifaceobj.priv_flags & self.NOCONFIG)
37c0543d 380
d08d5f54 381 def is_iface_noconfig(self, ifacename):
382 """ Returns true if iface has no config """
37c0543d 383
31a5f4c3 384 ifaceobj = self.get_ifaceobj_first(ifacename)
d08d5f54 385 if not ifaceobj: return True
d08d5f54 386 return self.is_ifaceobj_noconfig(ifaceobj)
387
45ca0b6d
RP
388 def check_shared_dependents(self, ifaceobj, dlist):
389 """ Check if dlist intersects with any other
390 interface with slave dependents.
391 example: bond and bridges.
392 This function logs such errors """
393 setdlist = Set(dlist)
394 for ifacename, ifacedlist in self.dependency_graph.items():
395 if not ifacedlist:
396 continue
397 check_depends = False
398 iobjs = self.get_ifaceobjs(ifacename)
399 for i in iobjs:
400 if (i.dependency_type == ifaceDependencyType.MASTER_SLAVE):
401 check_depends = True
402 if check_depends:
403 common = Set(ifacedlist).intersection(setdlist)
404 if common:
1cda1e43 405 self.logger.error('misconfig..?. iface %s and %s '
45ca0b6d 406 %(ifaceobj.name, ifacename) +
1cda1e43 407 'seem to share dependents/ports %s' %str(list(common)))
45ca0b6d 408
65e0c276
RP
409 def _set_iface_role_n_kind(self, ifaceobj, upperifaceobj):
410 if (upperifaceobj.link_kind & ifaceLinkKind.BOND):
411 ifaceobj.role |= ifaceRole.SLAVE
412 ifaceobj.link_kind |= ifaceLinkKind.BOND_SLAVE
413 if (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
414 ifaceobj.role |= ifaceRole.SLAVE
415 ifaceobj.link_kind |= ifaceLinkKind.BRIDGE_PORT
416 if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
417 ifaceobj.link_type = ifaceLinkType.LINK_SLAVE
21289e4a
RP
418 if (ifaceobj.link_kind == ifaceLinkKind.BOND_SLAVE and
419 len(ifaceobj.upperifaces) > 1):
420 self.logger.warn("misconfig..? bond slave \'%s\' is enslaved to multiple interfaces %s" %(ifaceobj.name, str(ifaceobj.upperifaces)))
65e0c276 421
7f045fd8 422 def preprocess_dependency_list(self, upperifaceobj, dlist, ops):
739f665b 423 """ We go through the dependency list and
424 delete or add interfaces from the interfaces dict by
425 applying the following rules:
426 if flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
427 we only consider devices whose configuration was
428 specified in the network interfaces file. We delete
429 any interface whose config was not specified except
430 for vlan devices. vlan devices get special treatment.
431 Even if they are not present they are created and added
432 to the ifacesdict
433 elif flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
434 we create objects for all dependent devices that are not
435 present in the ifacesdict
436 """
a6f80f0e 437 del_list = []
438
45ca0b6d
RP
439 if (upperifaceobj.dependency_type ==
440 ifaceDependencyType.MASTER_SLAVE):
441 self.check_shared_dependents(upperifaceobj, dlist)
442
a6f80f0e 443 for d in dlist:
31a5f4c3 444 dilist = self.get_ifaceobjs(d)
d08d5f54 445 if not dilist:
7f045fd8 446 ni = None
d08d5f54 447 if self.is_iface_builtin_byname(d):
a070c90e
RP
448 ni = self.create_n_save_ifaceobj(d,
449 self.BUILTIN | self.NOCONFIG, True)
f3215127 450 elif not self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
7f045fd8
RP
451 ni = self.create_n_save_ifaceobj(d, self.NOCONFIG,
452 True)
a6f80f0e 453 else:
a6f80f0e 454 del_list.append(d)
7f045fd8
RP
455 if ni:
456 ni.add_to_upperifaces(upperifaceobj.name)
21289e4a 457 self._set_iface_role_n_kind(ni, upperifaceobj)
a6f80f0e 458 else:
459 for di in dilist:
460 di.inc_refcnt()
7f045fd8 461 di.add_to_upperifaces(upperifaceobj.name)
21289e4a 462 self._set_iface_role_n_kind(di, upperifaceobj)
a6f80f0e 463 for d in del_list:
464 dlist.remove(d)
465
2da58137 466 def query_dependents(self, ifaceobj, ops, ifacenames, type=None):
a6f80f0e 467 """ Gets iface dependents by calling into respective modules """
41febf89 468 ret_dlist = []
a6f80f0e 469
20dd6242 470 # Get dependents for interface by querying respective modules
ee3fcf44 471 for module in self.modules.values():
7949b8a5 472 try:
473 if ops[0] == 'query-running':
474 if (not hasattr(module,
475 'get_dependent_ifacenames_running')):
476 continue
477 dlist = module.get_dependent_ifacenames_running(ifaceobj)
478 else:
479 if (not hasattr(module, 'get_dependent_ifacenames')):
480 continue
481 dlist = module.get_dependent_ifacenames(ifaceobj,
ee3fcf44 482 ifacenames)
7949b8a5 483 except Exception, e:
484 self.logger.warn('%s: error getting dependent interfaces (%s)'
485 %(ifaceobj.name, str(e)))
486 dlist = None
487 pass
41febf89 488 if dlist: ret_dlist.extend(dlist)
84ca006f 489 return list(set(ret_dlist))
20dd6242 490
45ca0b6d 491
e1601369
RP
492 def populate_dependency_info(self, ops, ifacenames=None):
493 """ recursive function to generate iface dependency info """
494
495 if not ifacenames:
496 ifacenames = self.ifaceobjdict.keys()
497
498 iqueue = deque(ifacenames)
499 while iqueue:
500 i = iqueue.popleft()
501 # Go through all modules and find dependent ifaces
502 dlist = None
503 ifaceobj = self.get_ifaceobj_first(i)
504 if not ifaceobj:
505 continue
506 dlist = ifaceobj.lowerifaces
507 if not dlist:
508 dlist = self.query_dependents(ifaceobj, ops, ifacenames)
509 else:
510 continue
511 if dlist:
7f045fd8 512 self.preprocess_dependency_list(ifaceobj,
e1601369
RP
513 dlist, ops)
514 ifaceobj.lowerifaces = dlist
515 [iqueue.append(d) for d in dlist]
516 if not self.dependency_graph.get(i):
517 self.dependency_graph[i] = dlist
518
67cfaeb1
RP
519 if not self.blacklisted_ifaces_present:
520 return
521
522 # Walk through the dependency graph and remove blacklisted
523 # interfaces that were picked up as dependents
524 for i in self.dependency_graph.keys():
525 ifaceobj = self.get_ifaceobj_first(i)
526 if not ifaceobj:
527 continue
528 if ifaceobj.blacklisted and not ifaceobj.upperifaces:
529 # if blacklisted and was not picked up as a
530 # dependent of a upper interface, delete the
531 # interface from the dependency graph
532 dlist = ifaceobj.lowerifaces
533 if dlist:
534 for d in dlist:
397214a5
RP
535 difaceobjs = self.get_ifaceobjs(d)
536 if not difaceobjs:
67cfaeb1 537 continue
67cfaeb1 538 try:
397214a5
RP
539 for d in difaceobjs:
540 d.dec_refcnt()
541 d.upperifaces.remove(i)
67cfaeb1
RP
542 except:
543 self.logger.debug('error removing %s from %s upperifaces' %(i, d))
544 pass
545 self.logger.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
546 del self.dependency_graph[i]
547
8e113d63
RP
548 def _check_config_no_repeats(self, ifaceobj):
549 """ check if object has an attribute that is
550 restricted to a single object in the system.
551 if yes, warn and return """
552 for k,v in self._cache_no_repeats.items():
553 iv = ifaceobj.config.get(k)
554 if iv and iv[0] == v:
555 self.logger.error('ignoring interface %s. ' %ifaceobj.name +
556 'Only one object with attribute ' +
557 '\'%s %s\' allowed.' %(k, v))
558 return True
559 for k, v in self.config.get('no_repeats', {}).items():
560 iv = ifaceobj.config.get(k)
561 if iv and iv[0] == v:
562 self._cache_no_repeats[k] = v
563 return False
a6f80f0e 564
41febf89 565 def _save_iface(self, ifaceobj):
8e113d63
RP
566 if self._check_config_no_repeats(ifaceobj):
567 return
7e2e64fb
RP
568 if not self._link_master_slave:
569 ifaceobj.link_type = ifaceLinkType.LINK_NA
679e6567
RP
570 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
571 if not currentifaceobjlist:
572 self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
573 return
574 if ifaceobj.compare(currentifaceobjlist[0]):
575 self.logger.warn('duplicate interface %s found' %ifaceobj.name)
576 return
8e113d63 577 if currentifaceobjlist[0].type == ifaceobj.type:
7444feea
ST
578 currentifaceobjlist[0].flags |= ifaceobj.HAS_SIBLINGS
579 ifaceobj.flags |= ifaceobj.HAS_SIBLINGS
580 # clear the OLDEST_SIBLING from all the siblings
581 for iface in self.ifaceobjdict[ifaceobj.name]:
582 iface.flags &= ~ifaceobj.OLDEST_SIBLING
583 # current sibling is the oldest
584 ifaceobj.flags |= ifaceobj.OLDEST_SIBLING
679e6567 585 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
41febf89 586
3dcc1d0e 587 def _iface_configattr_syntax_checker(self, attrname, attrval):
d08d5f54 588 for m, mdict in self.module_attrs.items():
7949b8a5 589 if not mdict:
590 continue
d08d5f54 591 attrsdict = mdict.get('attrs')
7949b8a5 592 try:
593 if attrsdict.get(attrname):
594 return True
595 except AttributeError:
596 pass
d08d5f54 597 return False
598
3dcc1d0e 599 def _ifaceobj_syntax_checker(self, ifaceobj):
600 err = False
8e113d63 601 for attrname, attrvalue in ifaceobj.config.items():
3dcc1d0e 602 found = False
603 for k, v in self.module_attrs.items():
604 if v and v.get('attrs', {}).get(attrname):
605 found = True
606 break
607 if not found:
608 err = True
fa714fa2
ST
609 self.logger.warn('%s: unsupported attribute \'%s\'' \
610 % (ifaceobj.name, attrname))
3dcc1d0e 611 continue
612 return err
613
14dc390d 614 def read_iface_config(self):
a6f80f0e 615 """ Reads default network interface config /etc/network/interfaces. """
14dc390d 616 nifaces = networkInterfaces(self.interfacesfile,
3dcc1d0e 617 self.interfacesfileiobuf,
618 self.interfacesfileformat,
14dc390d 619 template_engine=self.config.get('template_engine'),
620 template_lookuppath=self.config.get('template_lookuppath'))
d08d5f54 621 nifaces.subscribe('iface_found', self._save_iface)
3dcc1d0e 622 nifaces.subscribe('validateifaceattr',
623 self._iface_configattr_syntax_checker)
624 nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
a6f80f0e 625 nifaces.load()
626
a6f80f0e 627 def read_old_iface_config(self):
14dc390d 628 """ Reads the saved iface config instead of default iface config.
629 And saved iface config is already read by the statemanager """
cb7cc592 630 self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
a6f80f0e 631
53b00224 632 def _load_addon_modules_config(self):
633 """ Load addon modules config file """
a6f80f0e 634
37c0543d 635 with open(self.addon_modules_configfile, 'r') as f:
636 lines = f.readlines()
637 for l in lines:
7bbc9340
RP
638 try:
639 litems = l.strip(' \n\t\r').split(',')
640 if not litems or len(litems) < 2:
641 continue
642 operation = litems[0]
643 mname = litems[1]
644 self.module_ops[operation].append(mname)
645 except Exception, e:
646 self.logger.warn('error reading line \'%s\'' %(l, str(e)))
647 continue
37c0543d 648
649 def load_addon_modules(self, modules_dir):
a6f80f0e 650 """ load python modules from modules_dir
651
652 Default modules_dir is /usr/share/ifupdownmodules
653
654 """
a6f80f0e 655 self.logger.info('loading builtin modules from %s' %modules_dir)
53b00224 656 self._load_addon_modules_config()
a6f80f0e 657 if not modules_dir in sys.path:
37c0543d 658 sys.path.append(modules_dir)
a6f80f0e 659 try:
be0b20f2 660 for op, mlist in self.module_ops.items():
d08d5f54 661 for mname in mlist:
53b00224 662 if self.modules.get(mname):
d08d5f54 663 continue
664 mpath = modules_dir + '/' + mname + '.py'
665 if os.path.exists(mpath):
666 try:
667 m = __import__(mname)
668 mclass = getattr(m, mname)
669 except:
670 raise
671 minstance = mclass(force=self.FORCE,
672 dryrun=self.DRYRUN,
673 nowait=self.NOWAIT,
674 perfmode=self.PERFMODE,
a690dfae 675 cache=self.CACHE,
676 cacheflags=self.CACHE_FLAGS)
d08d5f54 677 self.modules[mname] = minstance
53b00224 678 try:
d08d5f54 679 self.module_attrs[mname] = minstance.get_modinfo()
53b00224 680 except:
681 pass
a6f80f0e 682 except:
683 raise
684
37c0543d 685 # Assign all modules to query operations
be0b20f2 686 self.module_ops['query-checkcurr'] = self.modules.keys()
687 self.module_ops['query-running'] = self.modules.keys()
688 self.module_ops['query-dependency'] = self.modules.keys()
689 self.module_ops['query'] = self.modules.keys()
690 self.module_ops['query-raw'] = self.modules.keys()
d08d5f54 691
14dc390d 692
53b00224 693 def _modules_help(self):
694 """ Prints addon modules supported syntax """
695
d08d5f54 696 indent = ' '
697 for m, mdict in self.module_attrs.items():
698 if not mdict:
699 continue
700 print('%s: %s' %(m, mdict.get('mhelp')))
701 attrdict = mdict.get('attrs')
702 if not attrdict:
703 continue
704 try:
705 for attrname, attrvaldict in attrdict.items():
706 if attrvaldict.get('compat', False):
707 continue
708 print('%s%s' %(indent, attrname))
709 print('%shelp: %s' %(indent + ' ',
710 attrvaldict.get('help', '')))
711 print ('%srequired: %s' %(indent + ' ',
712 attrvaldict.get('required', False)))
713 default = attrvaldict.get('default')
714 if default:
715 print('%sdefault: %s' %(indent + ' ', default))
716
717 validrange = attrvaldict.get('validrange')
718 if validrange:
1b0b81a2 719 print('%svalidrange: %s-%s'
7949b8a5 720 %(indent + ' ', validrange[0], validrange[1]))
d08d5f54 721
722 validvals = attrvaldict.get('validvals')
723 if validvals:
724 print('%svalidvals: %s'
725 %(indent + ' ', ','.join(validvals)))
726
727 examples = attrvaldict.get('example')
728 if not examples:
729 continue
a6f80f0e 730
d08d5f54 731 print '%sexample:' %(indent + ' ')
732 for e in examples:
733 print '%s%s' %(indent + ' ', e)
734 except:
735 pass
736 print ''
737
37c0543d 738 def load_scripts(self, modules_dir):
a6f80f0e 739 """ loading user modules from /etc/network/.
740
741 Note that previously loaded python modules override modules found
742 under /etc/network if any
743
744 """
745
37c0543d 746 self.logger.info('looking for user scripts under %s' %modules_dir)
be0b20f2 747 for op, mlist in self.script_ops.items():
d08d5f54 748 msubdir = modules_dir + '/if-%s.d' %op
749 self.logger.info('loading scripts under %s ...' %msubdir)
750 try:
751 module_list = os.listdir(msubdir)
752 for module in module_list:
753 if self.modules.get(module) is not None:
754 continue
be0b20f2 755 self.script_ops[op].append(
a6f80f0e 756 msubdir + '/' + module)
d08d5f54 757 except:
f802fe3c 758 # continue reading
759 pass
a6f80f0e 760
a4912b99 761 def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False,
e308cb82 762 followdependents=True, sort=False):
c798b0f4 763 self.logger.debug('scheduling \'%s\' for %s'
d08d5f54 764 %(str(ops), str(ifacenames)))
7538dc77 765 self._pretty_print_ordered_dict('dependency graph',
766 self.dependency_graph)
c798b0f4 767 return ifaceScheduler.sched_ifaces(self, ifacenames, ops,
768 dependency_graph=self.dependency_graph,
d08d5f54 769 order=ifaceSchedulerFlags.INORDER
770 if 'down' in ops[0]
c798b0f4 771 else ifaceSchedulerFlags.POSTORDER,
a4912b99 772 followdependents=followdependents,
e308cb82
RP
773 skipupperifaces=skipupperifaces,
774 sort=True if (sort or self.IFACE_CLASS) else False)
a6f80f0e 775
41febf89
RP
776 def _render_ifacename(self, ifacename):
777 new_ifacenames = []
679e6567 778 vlan_match = re.match("^([\d]+)-([\d]+)", ifacename)
41febf89
RP
779 if vlan_match:
780 vlan_groups = vlan_match.groups()
781 if vlan_groups[0] and vlan_groups[1]:
679e6567 782 [new_ifacenames.append('%d' %v)
41febf89
RP
783 for v in range(int(vlan_groups[0]),
784 int(vlan_groups[1])+1)]
785 return new_ifacenames
786
787 def _preprocess_ifacenames(self, ifacenames):
a6f80f0e 788 """ validates interface list for config existance.
789
790 returns -1 if one or more interface not found. else, returns 0
791
792 """
41febf89 793 new_ifacenames = []
a6f80f0e 794 err_iface = ''
795 for i in ifacenames:
31a5f4c3 796 ifaceobjs = self.get_ifaceobjs(i)
797 if not ifaceobjs:
41febf89 798 # if name not available, render interface name and check again
679e6567 799 rendered_ifacenames = utils.expand_iface_range(i)
41febf89
RP
800 if rendered_ifacenames:
801 for ri in rendered_ifacenames:
802 ifaceobjs = self.get_ifaceobjs(ri)
803 if not ifaceobjs:
804 err_iface += ' ' + ri
805 else:
806 new_ifacenames.append(ri)
807 else:
808 err_iface += ' ' + i
809 else:
810 new_ifacenames.append(i)
fe0a57d3 811 if err_iface:
31c58787 812 raise Exception('cannot find interfaces:%s' %err_iface)
41febf89 813 return new_ifacenames
a6f80f0e 814
53b00224 815 def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
a6f80f0e 816 """ Checks if interface is whitelisted depending on set of parameters.
817
a6f80f0e 818 interfaces are checked against the allow_classes and auto lists.
819
820 """
1042b709 821
0532f0a3
RP
822 ret = True
823
19e2bf8c 824 # Check if interface matches the exclude patter
fe0a57d3 825 if excludepats:
3e8ee54f 826 for e in excludepats:
d08d5f54 827 if re.search(e, ifacename):
0532f0a3 828 ret = False
31a5f4c3 829 ifaceobjs = self.get_ifaceobjs(ifacename)
830 if not ifaceobjs:
0532f0a3
RP
831 if ret:
832 self.logger.debug('iface %s' %ifacename + ' not found')
833 return ret
67cfaeb1 834 # If matched exclude pattern, return false
0532f0a3
RP
835 if not ret:
836 for i in ifaceobjs:
837 i.blacklisted = True
67cfaeb1 838 self.blacklisted_ifaces_present = True
0532f0a3
RP
839 return ret
840 # Check if interface belongs to the class
67cfaeb1 841 # the user is interested in, if not return false
fe0a57d3 842 if allow_classes:
19e2bf8c 843 ret = False
a6f80f0e 844 for i in ifaceobjs:
62ddec8b 845 if i.classes:
3e8ee54f 846 common = Set([allow_classes]).intersection(
62ddec8b 847 Set(i.classes))
fe0a57d3 848 if common:
0532f0a3 849 ret = True
0532f0a3 850 if not ret:
19e2bf8c
RP
851 # If a class was requested and interface does not belong
852 # to the class, only then mark the ifaceobjs as blacklisted
853 self.blacklisted_ifaces_present = True
854 for i in ifaceobjs:
855 i.blacklisted = True
856 return ret
67cfaeb1
RP
857 # If the user has requested auto class, check if the interface
858 # is marked auto
d08d5f54 859 if auto:
19e2bf8c 860 ret = False
a6f80f0e 861 for i in ifaceobjs:
62ddec8b 862 if i.auto:
0532f0a3 863 ret = True
19e2bf8c
RP
864 if not ret:
865 # If auto was requested and interface was not marked auto,
866 # only then mark all of them as blacklisted
867 self.blacklisted_ifaces_present = True
868 for i in ifaceobjs:
0532f0a3
RP
869 i.blacklisted = True
870 return ret
a6f80f0e 871
53b00224 872 def _compat_conv_op_to_mode(self, op):
873 """ Returns old op name to work with existing scripts """
874 if op == 'pre-up':
875 return 'start'
876 elif op == 'pre-down':
877 return 'stop'
878 else:
879 return op
880
a6f80f0e 881 def generate_running_env(self, ifaceobj, op):
739f665b 882 """ Generates a dictionary with env variables required for
883 an interface. Used to support script execution for interfaces.
a6f80f0e 884 """
885
886 cenv = None
62ddec8b 887 iface_env = ifaceobj.env
888 if iface_env:
a6f80f0e 889 cenv = os.environ
d08d5f54 890 if cenv:
a6f80f0e 891 cenv.update(iface_env)
892 else:
893 cenv = iface_env
53b00224 894 cenv['MODE'] = self._compat_conv_op_to_mode(op)
a6f80f0e 895 return cenv
896
53b00224 897 def _save_state(self):
20dd6242 898 if not self.STATEMANAGER_ENABLE or not self.STATEMANAGER_UPDATE:
899 return
900 try:
901 # Update persistant iface states
902 self.statemanager.save_state()
903 except Exception, e:
904 if self.logger.isEnabledFor(logging.DEBUG):
905 t = sys.exc_info()[2]
906 traceback.print_tb(t)
907 self.logger.warning('error saving state (%s)' %str(e))
908
2da58137
RP
909 def set_type(self, type):
910 if type == 'iface':
911 self.type = ifaceType.IFACE
912 elif type == 'vlan':
913 self.type = ifaceType.BRIDGE_VLAN
914 else:
915 self.type = ifaceType.UNKNOWN
916
a070c90e
RP
917 def _process_delay_admin_state_queue(self, op):
918 if not self._delay_admin_state_iface_queue:
919 return
920 if op == 'up':
921 func = self.link_up
922 elif op == 'down':
923 func = self.link_down
924 else:
925 return
926 for i in self._delay_admin_state_iface_queue:
927 try:
928 if self.link_exists(i):
929 func(i)
930 except Exception, e:
931 self.logger.warn(str(e))
932 pass
933
d08d5f54 934 def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
2da58137 935 excludepats=None, printdependency=None, syntaxcheck=False,
ad25e7bb 936 type=None, skipupperifaces=False):
2c0ad8b3
RP
937 """This brings the interface(s) up
938
939 Args:
41febf89
RP
940 ops (list): list of ops to perform on the interface(s).
941 Eg: ['pre-up', 'up', 'post-up'
2c0ad8b3
RP
942
943 Kwargs:
944 auto (bool): act on interfaces marked auto
945 allow_classes (list): act on interfaces belonging to classes in the list
946 ifacenames (list): act on interfaces specified in this list
947 excludepats (list): list of patterns of interfaces to exclude
948 syntaxcheck (bool): only perform syntax check
949 """
53b00224 950
2da58137
RP
951 self.set_type(type)
952
5ee3e1a8
RP
953 if allow_classes:
954 self.IFACE_CLASS = True
7538dc77 955 if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
d08d5f54 956 if auto:
a6f80f0e 957 self.ALL = True
cca03c30 958 self.WITH_DEPENDS = True
d08d5f54 959 try:
960 self.read_iface_config()
62ddec8b 961 except Exception:
d08d5f54 962 raise
a6f80f0e 963
31a5f4c3 964 if ifacenames:
41febf89 965 ifacenames = self._preprocess_ifacenames(ifacenames)
a6f80f0e 966
967 # if iface list not given by user, assume all from config file
31a5f4c3 968 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
a6f80f0e 969
970 # filter interfaces based on auto and allow classes
cca03c30 971 filtered_ifacenames = [i for i in ifacenames
53b00224 972 if self._iface_whitelisted(auto, allow_classes,
d08d5f54 973 excludepats, i)]
fe0a57d3 974 if not filtered_ifacenames:
d08d5f54 975 raise Exception('no ifaces found matching given allow lists')
a6f80f0e 976
20dd6242 977 if printdependency:
c798b0f4 978 self.populate_dependency_info(ops, filtered_ifacenames)
d08d5f54 979 self.print_dependency(filtered_ifacenames, printdependency)
739f665b 980 return
cca03c30 981 else:
c798b0f4 982 self.populate_dependency_info(ops)
983
21289e4a
RP
984 # If only syntax check was requested, return here
985 if syntaxcheck:
986 return
987
525f0a30 988 try:
ad25e7bb 989 self._sched_ifaces(filtered_ifacenames, ops,
a4912b99
RP
990 skipupperifaces=skipupperifaces,
991 followdependents=True if self.WITH_DEPENDS else False)
525f0a30 992 finally:
a070c90e 993 self._process_delay_admin_state_queue('up')
525f0a30 994 if not self.DRYRUN and self.ADDONS_ENABLE:
995 self._save_state()
a6f80f0e 996
d08d5f54 997 def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
2da58137
RP
998 excludepats=None, printdependency=None, usecurrentconfig=False,
999 type=None):
53b00224 1000 """ down an interface """
1001
2da58137
RP
1002 self.set_type(type)
1003
5ee3e1a8
RP
1004 if allow_classes:
1005 self.IFACE_CLASS = True
7538dc77 1006 if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
d08d5f54 1007 if auto:
1008 self.ALL = True
1009 self.WITH_DEPENDS = True
5c721925 1010 # For down we need to look at old state, unless usecurrentconfig
1011 # is set
1012 if (not usecurrentconfig and self.STATEMANAGER_ENABLE and
53b00224 1013 self.statemanager.ifaceobjdict):
31a5f4c3 1014 # Since we are using state manager objects,
1015 # skip the updating of state manager objects
5c721925 1016 self.logger.debug('Looking at old state ..')
d08d5f54 1017 self.read_old_iface_config()
fe0a57d3 1018 else:
d08d5f54 1019 # If no old state available
d08d5f54 1020 try:
1021 self.read_iface_config()
1022 except Exception, e:
1023 raise Exception('error reading iface config (%s)' %str(e))
d08d5f54 1024 if ifacenames:
1025 # If iface list is given by the caller, always check if iface
1026 # is present
31c58787 1027 try:
41febf89 1028 ifacenames = self._preprocess_ifacenames(ifacenames)
31c58787 1029 except Exception, e:
1030 raise Exception('%s' %str(e) +
1031 ' (interface was probably never up ?)')
1032
d08d5f54 1033 # if iface list not given by user, assume all from config file
fe0a57d3 1034 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
53b00224 1035
d08d5f54 1036 # filter interfaces based on auto and allow classes
1037 filtered_ifacenames = [i for i in ifacenames
53b00224 1038 if self._iface_whitelisted(auto, allow_classes,
d08d5f54 1039 excludepats, i)]
fe0a57d3 1040 if not filtered_ifacenames:
c0071225 1041 raise Exception('no ifaces found matching given allow lists ' +
41febf89 1042 '(or interfaces were probably never up ?)')
14dc390d 1043
d08d5f54 1044 if printdependency:
99b212b0 1045 self.populate_dependency_info(ops, filtered_ifacenames)
d08d5f54 1046 self.print_dependency(filtered_ifacenames, printdependency)
1047 return
99b212b0 1048 else:
1049 self.populate_dependency_info(ops)
525f0a30 1050
1051 try:
a4912b99
RP
1052 self._sched_ifaces(filtered_ifacenames, ops,
1053 followdependents=True if self.WITH_DEPENDS else False)
525f0a30 1054 finally:
a070c90e 1055 self._process_delay_admin_state_queue('down')
525f0a30 1056 if not self.DRYRUN and self.ADDONS_ENABLE:
1057 self._save_state()
d08d5f54 1058
1059 def query(self, ops, auto=False, allow_classes=None, ifacenames=None,
739f665b 1060 excludepats=None, printdependency=None,
2da58137 1061 format='native', type=None):
53b00224 1062 """ query an interface """
1063
2da58137
RP
1064 self.set_type(type)
1065
5ee3e1a8
RP
1066 if allow_classes:
1067 self.IFACE_CLASS = True
5c721925 1068 if self.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
1069 return self.statemanager.dump_pretty(ifacenames)
20dd6242 1070 self.STATEMANAGER_UPDATE = False
d08d5f54 1071 if auto:
739f665b 1072 self.logger.debug('setting flag ALL')
1073 self.ALL = True
37c0543d 1074 self.WITH_DEPENDS = True
739f665b 1075
d08d5f54 1076 if ops[0] == 'query-syntax':
53b00224 1077 self._modules_help()
d08d5f54 1078 return
1079 elif ops[0] == 'query-running':
739f665b 1080 # create fake devices to all dependents that dont have config
37c0543d 1081 map(lambda i: self.create_n_save_ifaceobj(i, self.NOCONFIG),
1082 ifacenames)
739f665b 1083 else:
1084 try:
1085 self.read_iface_config()
1086 except Exception:
1087 raise
1088
53b00224 1089 if ifacenames and ops[0] != 'query-running':
41febf89
RP
1090 # If iface list is given, always check if iface is present
1091 ifacenames = self._preprocess_ifacenames(ifacenames)
739f665b 1092
1093 # if iface list not given by user, assume all from config file
31a5f4c3 1094 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
739f665b 1095
1096 # filter interfaces based on auto and allow classes
d08d5f54 1097 if ops[0] == 'query-running':
739f665b 1098 filtered_ifacenames = ifacenames
1099 else:
1100 filtered_ifacenames = [i for i in ifacenames
53b00224 1101 if self._iface_whitelisted(auto, allow_classes,
d08d5f54 1102 excludepats, i)]
fe0a57d3 1103 if not filtered_ifacenames:
739f665b 1104 raise Exception('no ifaces found matching ' +
1105 'given allow lists')
37c0543d 1106
e1601369 1107 self.populate_dependency_info(ops)
d08d5f54 1108 if ops[0] == 'query-dependency' and printdependency:
1109 self.print_dependency(filtered_ifacenames, printdependency)
1110 return
739f665b 1111
75730152 1112 if ops[0] == 'query':
1113 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
1114 elif ops[0] == 'query-raw':
1115 return self.print_ifaceobjs_raw(filtered_ifacenames)
1116
a4912b99
RP
1117 self._sched_ifaces(filtered_ifacenames, ops,
1118 followdependents=True if self.WITH_DEPENDS else False)
739f665b 1119
d08d5f54 1120 if ops[0] == 'query-checkcurr':
1121 ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
739f665b 1122 if ret != 0:
1123 # if any of the object has an error, signal that silently
1124 raise Exception('')
d08d5f54 1125 elif ops[0] == 'query-running':
1126 self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
739f665b 1127 return
1128
2da58137
RP
1129 def _reload_currentlyup(self, upops, downops, auto=True, allow=None,
1130 ifacenames=None, excludepats=None, usecurrentconfig=False,
1131 **extra_args):
1132 """ reload currently up interfaces """
c0071225 1133 new_ifaceobjdict = {}
739f665b 1134
2da58137
RP
1135 # Override auto to true
1136 auto = True
2da58137
RP
1137 try:
1138 self.read_iface_config()
1139 except:
1140 raise
2da58137
RP
1141 if not self.ifaceobjdict:
1142 self.logger.warn("nothing to reload ..exiting.")
1143 return
2da58137 1144 already_up_ifacenames = []
1042b709
RP
1145 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1146 filtered_ifacenames = [i for i in ifacenames
1147 if self._iface_whitelisted(auto, allow,
1148 excludepats, i)]
1149
2da58137
RP
1150 # generate dependency graph of interfaces
1151 self.populate_dependency_info(upops)
1152 if (not usecurrentconfig and self.STATEMANAGER_ENABLE
1153 and self.statemanager.ifaceobjdict):
1154 already_up_ifacenames = self.statemanager.ifaceobjdict.keys()
1155
2da58137
RP
1156 # Get already up interfaces that still exist in the interfaces file
1157 already_up_ifacenames_not_present = Set(
1158 already_up_ifacenames).difference(ifacenames)
1159 already_up_ifacenames_still_present = Set(
1160 already_up_ifacenames).difference(
1161 already_up_ifacenames_not_present)
1162 interfaces_to_up = Set(already_up_ifacenames_still_present).union(
1163 filtered_ifacenames)
1164
1165 if (already_up_ifacenames_not_present and
1166 self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
1167 self.logger.info('reload: schedule down on interfaces: %s'
1168 %str(already_up_ifacenames_not_present))
1169
1170 # Save a copy of new iface objects and dependency_graph
1171 new_ifaceobjdict = dict(self.ifaceobjdict)
1172 new_dependency_graph = dict(self.dependency_graph)
1173
1174 # old interface config is read into self.ifaceobjdict
1175 self.read_old_iface_config()
1176
1177 # reinitialize dependency graph
1178 self.dependency_graph = OrderedDict({})
1042b709
RP
1179 falready_up_ifacenames_not_present = [i for i in
1180 already_up_ifacenames_not_present
1181 if self._iface_whitelisted(auto, allow,
1182 excludepats, i)]
2da58137 1183 self.populate_dependency_info(downops,
1042b709
RP
1184 falready_up_ifacenames_not_present)
1185 self._sched_ifaces(falready_up_ifacenames_not_present, downops,
e308cb82 1186 followdependents=False, sort=True)
2da58137
RP
1187 else:
1188 self.logger.debug('no interfaces to down ..')
1189
1190 # Now, run 'up' with new config dict
1191 # reset statemanager update flag to default
e308cb82
RP
1192 if auto:
1193 self.ALL = True
1194 self.WITH_DEPENDS = True
2da58137 1195 if new_ifaceobjdict:
3d44fbd0 1196 # and now, ifaceobjdict is back to current config
2da58137
RP
1197 self.ifaceobjdict = new_ifaceobjdict
1198 self.dependency_graph = new_dependency_graph
1199
1200 if not self.ifaceobjdict:
1201 return
1202 self.logger.info('reload: scheduling up on interfaces: %s'
1203 %str(interfaces_to_up))
a4912b99
RP
1204 self._sched_ifaces(interfaces_to_up, upops,
1205 followdependents=True if self.WITH_DEPENDS else False)
2da58137
RP
1206 if self.DRYRUN:
1207 return
1208 self._save_state()
1209
1210 def _reload_default(self, upops, downops, auto=False, allow=None,
1211 ifacenames=None, excludepats=None, usecurrentconfig=False,
1212 **extra_args):
1213 """ reload interface config """
2da58137 1214 new_ifaceobjdict = {}
739f665b 1215
1216 try:
1217 self.read_iface_config()
20dd6242 1218 except:
739f665b 1219 raise
1220
c0071225
RP
1221 if not self.ifaceobjdict:
1222 self.logger.warn("nothing to reload ..exiting.")
1223 return
1042b709
RP
1224
1225 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1226 new_filtered_ifacenames = [i for i in ifacenames
1227 if self._iface_whitelisted(auto, allow,
1228 excludepats, i)]
37c0543d 1229 # generate dependency graph of interfaces
c798b0f4 1230 self.populate_dependency_info(upops)
1042b709 1231
14dc390d 1232 if (not usecurrentconfig and self.STATEMANAGER_ENABLE
1233 and self.statemanager.ifaceobjdict):
1234 # Save a copy of new iface objects and dependency_graph
1235 new_ifaceobjdict = dict(self.ifaceobjdict)
1236 new_dependency_graph = dict(self.dependency_graph)
37c0543d 1237
739f665b 1238 # if old state is present, read old state and mark op for 'down'
1239 # followed by 'up' aka: reload
37c0543d 1240 # old interface config is read into self.ifaceobjdict
739f665b 1241 self.read_old_iface_config()
1242 op = 'reload'
1243 else:
1244 # oldconfig not available, continue with 'up' with new config
1245 op = 'up'
1246
20dd6242 1247 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
fe0a57d3 1248 if op == 'reload' and ifacenames:
1042b709
RP
1249 old_filtered_ifacenames = [i for i in ifacenames
1250 if self._iface_whitelisted(auto, allow,
d08d5f54 1251 excludepats, i)]
e308cb82
RP
1252
1253 # if config file had 'ifreload_down_changed' variable
1254 # set, also look for interfaces that changed to down them
1255 down_changed = int(self.config.get('ifreload_down_changed', '1'))
1256
37c0543d 1257 # Generate the interface down list
1258 # Interfaces that go into the down list:
1259 # - interfaces that were present in last config and are not
1260 # present in the new config
1261 # - interfaces that were changed between the last and current
1262 # config
37c0543d 1263 ifacedownlist = []
1042b709 1264 for ifname in old_filtered_ifacenames:
2da58137 1265 lastifaceobjlist = self.ifaceobjdict.get(ifname)
37c0543d 1266 objidx = 0
37c0543d 1267 # If interface is not present in the new file
1268 # append it to the down list
53b00224 1269 newifaceobjlist = new_ifaceobjdict.get(ifname)
1270 if not newifaceobjlist:
37c0543d 1271 ifacedownlist.append(ifname)
1272 continue
21289e4a
RP
1273 # If ifaceobj was present in the old interfaces file,
1274 # and does not have a config in the new interfaces file
1275 # but has been picked up as a dependent of another
1276 # interface, catch it here. This catches a common error
1277 # for example: remove a bond section from the interfaces
1278 # file, but leave it around as a bridge port
1279 # XXX: Ideally its better to just add it to the
1280 # ifacedownlist. But we will be cautious here
1281 # and just print a warning
1282 if (self.is_ifaceobj_noconfig(newifaceobjlist[0]) and
1283 lastifaceobjlist[0].is_config_present()):
1284 self.logger.warn('%s: misconfig ? removed but still exists as a dependency of %s' %(newifaceobjlist[objidx].name,
1285 str(newifaceobjlist[objidx].upperifaces)))
26434da6
RP
1286 if not down_changed:
1287 continue
53b00224 1288 if len(newifaceobjlist) != len(lastifaceobjlist):
37c0543d 1289 ifacedownlist.append(ifname)
1290 continue
e308cb82
RP
1291
1292 # If interface has changed between the current file
1293 # and the last installed append it to the down list
37c0543d 1294 # compare object list
53b00224 1295 for objidx in range(0, len(lastifaceobjlist)):
1296 oldobj = lastifaceobjlist[objidx]
1297 newobj = newifaceobjlist[objidx]
ca3f4fc7 1298 if not newobj.compare(oldobj):
37c0543d 1299 ifacedownlist.append(ifname)
1300 continue
1301
fe0a57d3 1302 if ifacedownlist:
2da58137 1303 self.logger.info('reload: scheduling down on interfaces: %s'
739f665b 1304 %str(ifacedownlist))
20dd6242 1305 # reinitialize dependency graph
1306 self.dependency_graph = OrderedDict({})
37c0543d 1307 # Generate dependency info for old config
14dc390d 1308 self.populate_dependency_info(downops, ifacedownlist)
a070c90e 1309 try:
a4912b99 1310 self._sched_ifaces(ifacedownlist, downops,
e308cb82
RP
1311 followdependents=False,
1312 sort=True)
a070c90e
RP
1313 except Exception, e:
1314 self.logger.error(str(e))
1315 pass
1316 finally:
1317 self._process_delay_admin_state_queue('down')
37c0543d 1318 else:
1319 self.logger.debug('no interfaces to down ..')
739f665b 1320
20dd6242 1321 # Now, run 'up' with new config dict
1322 # reset statemanager update flag to default
c0071225
RP
1323 if not new_ifaceobjdict:
1324 return
e308cb82
RP
1325
1326 if auto:
1327 self.ALL = True
1328 self.WITH_DEPENDS = True
3d44fbd0 1329 # and now, we are back to the current config in ifaceobjdict
53b00224 1330 self.ifaceobjdict = new_ifaceobjdict
1331 self.dependency_graph = new_dependency_graph
739f665b 1332 ifacenames = self.ifaceobjdict.keys()
c798b0f4 1333
2da58137 1334 self.logger.info('reload: scheduling up on interfaces: %s'
1042b709 1335 %str(new_filtered_ifacenames))
a070c90e 1336 try:
1042b709 1337 self._sched_ifaces(new_filtered_ifacenames, upops,
a4912b99 1338 followdependents=True if self.WITH_DEPENDS else False)
a070c90e
RP
1339 except Exception, e:
1340 self.logger.error(str(e))
1341 pass
1342 finally:
1343 self._process_delay_admin_state_queue('up')
e37ad4a6 1344 if self.DRYRUN:
1345 return
53b00224 1346 self._save_state()
a6f80f0e 1347
2da58137
RP
1348 def reload(self, *args, **kargs):
1349 """ reload interface config """
2da58137
RP
1350 self.logger.debug('reloading interface config ..')
1351 if kargs.get('currentlyup', False):
1352 self._reload_currentlyup(*args, **kargs)
1353 else:
1354 self._reload_default(*args, **kargs)
1355
7538dc77 1356 def _pretty_print_ordered_dict(self, prefix, argdict):
525f0a30 1357 outbuf = prefix + ' {\n'
53b00224 1358 for k, vlist in argdict.items():
525f0a30 1359 outbuf += '\t%s : %s\n' %(k, str(vlist))
7538dc77 1360 self.logger.debug(outbuf + '}')
a6f80f0e 1361
53b00224 1362 def print_dependency(self, ifacenames, format):
1363 """ prints iface dependency information """
a6f80f0e 1364
53b00224 1365 if not ifacenames:
1366 ifacenames = self.ifaceobjdict.keys()
1367 if format == 'list':
1368 for k,v in self.dependency_graph.items():
1369 print '%s : %s' %(k, str(v))
1370 elif format == 'dot':
1371 indegrees = {}
1372 map(lambda i: indegrees.update({i :
1373 self.get_iface_refcnt(i)}),
1374 self.dependency_graph.keys())
1375 graph.generate_dots(self.dependency_graph, indegrees)
a6f80f0e 1376
739f665b 1377 def print_ifaceobjs_raw(self, ifacenames):
53b00224 1378 """ prints raw lines for ifaces from config file """
1379
739f665b 1380 for i in ifacenames:
31a5f4c3 1381 for ifaceobj in self.get_ifaceobjs(i):
75730152 1382 if (self.is_ifaceobj_builtin(ifaceobj) or
1383 not ifaceobj.is_config_present()):
1384 continue
1385 ifaceobj.dump_raw(self.logger)
739f665b 1386 print '\n'
339026c8 1387 if self.WITH_DEPENDS and not self.ALL:
62ddec8b 1388 dlist = ifaceobj.lowerifaces
fe0a57d3 1389 if not dlist: continue
53b00224 1390 self.print_ifaceobjs_raw(dlist)
739f665b 1391
2cd06f78 1392 def _get_ifaceobjs_pretty(self, ifacenames, ifaceobjs, running=False):
1393 """ returns iface obj list """
53b00224 1394
a6f80f0e 1395 for i in ifacenames:
31a5f4c3 1396 for ifaceobj in self.get_ifaceobjs(i):
2cd06f78 1397 if ((not running and self.is_ifaceobj_noconfig(ifaceobj)) or
1398 (running and not ifaceobj.is_config_present())):
75730152 1399 continue
2cd06f78 1400 ifaceobjs.append(ifaceobj)
339026c8 1401 if self.WITH_DEPENDS and not self.ALL:
62ddec8b 1402 dlist = ifaceobj.lowerifaces
fe0a57d3 1403 if not dlist: continue
2cd06f78 1404 self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
739f665b 1405
2cd06f78 1406 def print_ifaceobjs_pretty(self, ifacenames, format='native'):
1407 """ pretty prints iface in format given by keyword arg format """
eab25b7c 1408
2cd06f78 1409 ifaceobjs = []
1410 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
1411 if not ifaceobjs: return
1412 if format == 'json':
3dcc1d0e 1413 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
1414 indent=4, separators=(',', ': '))
2cd06f78 1415 else:
2da58137
RP
1416 expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
1417 for i in ifaceobjs:
1418 if not expand and (i.flags & iface.IFACERANGE_ENTRY):
1419 # print only the first one
1420 if i.flags & iface.IFACERANGE_START:
1421 i.dump_pretty(use_realname=True)
1422 else:
1423 i.dump_pretty()
53b00224 1424
2cd06f78 1425 def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
eab25b7c 1426 ret = 0
a6f80f0e 1427 for i in ifacenames:
923290bd 1428 ifaceobjscurr = self.get_ifaceobjcurr(i)
1429 if not ifaceobjscurr: continue
1430 for ifaceobj in ifaceobjscurr:
1431 if (ifaceobj.status == ifaceStatus.NOTFOUND or
1432 ifaceobj.status == ifaceStatus.ERROR):
1433 ret = 1
1434 if self.is_ifaceobj_noconfig(ifaceobj):
1435 continue
1436 ifaceobjs.append(ifaceobj)
1437 if self.WITH_DEPENDS and not self.ALL:
1438 dlist = ifaceobj.lowerifaces
1439 if not dlist: continue
1440 dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
1441 if dret: ret = 1
2cd06f78 1442 return ret
1443
1444 def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
1445 """ pretty prints current running state of interfaces with status.
1446
1447 returns 1 if any of the interface has an error,
1448 else returns 0
1449 """
1450
1451 ifaceobjs = []
1452 ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
1453 if not ifaceobjs: return
fb10449e
RP
1454 ifaceStatusStrs.SUCCESS = self.config.get('ifquery_check_success_str',
1455 _success_sym)
1456 ifaceStatusStrs.ERROR = self.config.get('ifquery_check_error_str',
1457 _error_sym)
1458 ifaceStatusStrs.UNKNOWN = self.config.get('ifquery_check_unknown_str',
1459 '')
2cd06f78 1460 if format == 'json':
f012209e 1461 print json.dumps(ifaceobjs, cls=ifaceJsonEncoderWithStatus, indent=2,
2cd06f78 1462 separators=(',', ': '))
1463 else:
fb10449e 1464 map(lambda i: i.dump_pretty(with_status=True), ifaceobjs)
eab25b7c 1465 return ret
a6f80f0e 1466
d08d5f54 1467 def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
53b00224 1468 """ pretty prints iface running state """
1469
2cd06f78 1470 ifaceobjs = []
1471 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs, running=True)
1472 if not ifaceobjs: return
1473 if format == 'json':
1474 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
1475 separators=(',', ': '))
1476 else:
1477 map(lambda i: i.dump_pretty(), ifaceobjs)
53b00224 1478
1479 def _dump(self):
1480 print 'ifupdown main object dump'
1481 print self.pp.pprint(self.modules)
1482 print self.pp.pprint(self.ifaceobjdict)
1483
1484 def _dump_ifaceobjs(self, ifacenames):
1485 for i in ifacenames:
1486 ifaceobjs = self.get_ifaceobjs(i)
1487 for i in ifaceobjs:
1488 i.dump(self.logger)
1489 print '\n'