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