]>
git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdownaddons/modulebase.py
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
13 from ifupdown
.iface
import *
14 #from ifupdownaddons.iproute2 import *
15 #from ifupdownaddons.dhclient import *
16 #from ifupdownaddons.bridgeutils import *
17 #from ifupdownaddons.mstpctlutil import *
18 #from ifupdownaddons.bondutil import *
20 class moduleBase(object):
21 """ Base class for ifupdown addon modules
23 Provides common infrastructure methods for all addon modules """
25 def __init__(self
, *args
, **kargs
):
26 modulename
= self
.__class
__.__name
__
27 self
.logger
= logging
.getLogger('ifupdown.' + modulename
)
28 self
.FORCE
= kargs
.get('force', False)
29 """force interface configuration"""
30 self
.DRYRUN
= kargs
.get('dryrun', False)
31 """only predend you are applying configuration, dont really do it"""
32 self
.NOWAIT
= kargs
.get('nowait', False)
33 self
.PERFMODE
= kargs
.get('perfmode', False)
34 self
.CACHE
= kargs
.get('cache', False)
35 self
.CACHE_FLAGS
= kargs
.get('cacheflags', 0x0)
37 def log_warn(self
, str):
38 """ log a warning if err str is not one of which we should ignore """
39 if not self
.ignore_error(str):
40 if self
.logger
.getEffectiveLevel() == logging
.DEBUG
:
41 traceback
.print_stack()
45 def log_error(self
, str):
46 """ log an err if err str is not one of which we should ignore and raise an exception """
47 if not self
.ignore_error(str):
48 if self
.logger
.getEffectiveLevel() == logging
.DEBUG
:
49 traceback
.print_stack()
54 def is_process_running(self
, procName
):
56 self
.exec_command('/bin/pidof -x %s' % procName
)
62 def exec_command(self
, cmd
, cmdenv
=None):
63 """ execute command passed as argument.
66 cmd (str): command to execute
69 cmdenv (dict): environment variable name value pairs
75 self
.logger
.info('Executing ' + cmd
)
78 ch
= subprocess
.Popen(cmd
.split(),
79 stdout
=subprocess
.PIPE
,
80 shell
=False, env
=cmdenv
,
81 stderr
=subprocess
.STDOUT
,
83 cmdout
= ch
.communicate()[0]
84 cmd_returncode
= ch
.wait()
86 raise Exception('could not execute ' + cmd
+
88 if cmd_returncode
!= 0:
89 raise Exception('error executing cmd \'%s\'' %cmd
+
90 '(' + cmdout
.strip('\n ') + ')')
93 def exec_command_talk_stdin(self
, cmd
, stdinbuf
):
94 """ execute command passed as argument and write contents of stdinbuf
98 cmd (str): command to execute
99 stdinbuf (str): string to write to stdin of the cmd process
105 self
.logger
.info('Executing %s (stdin=%s)' %(cmd
, stdinbuf
))
108 ch
= subprocess
.Popen(cmd
.split(),
109 stdout
=subprocess
.PIPE
,
110 stdin
=subprocess
.PIPE
,
111 shell
=False, env
=cmdenv
,
112 stderr
=subprocess
.STDOUT
,
114 cmdout
= ch
.communicate(input=stdinbuf
)[0]
115 cmd_returncode
= ch
.wait()
117 raise Exception('could not execute ' + cmd
+
119 if cmd_returncode
!= 0:
120 raise Exception('error executing cmd \'%s (%s)\''
121 %(cmd
, stdinbuf
) + '(' + cmdout
.strip('\n ') + ')')
124 def get_ifaces_from_proc(self
):
126 with
open('/proc/net/dev') as f
:
128 lines
= f
.readlines()
130 ifacenames
.append(line
.split()[0].strip(': '))
135 def parse_regex(self
, expr
, ifacenames
=None):
137 proc_ifacenames
= self
.get_ifaces_from_proc()
139 self
.logger
.warn('error reading ifaces from proc')
140 for proc_ifacename
in proc_ifacenames
:
141 if re
.search(expr
+ '$', proc_ifacename
):
145 for ifacename
in ifacenames
:
146 if re
.search(expr
+ '$', ifacename
):
149 def parse_glob(self
, expr
):
150 errmsg
= ('error parsing glob expression \'%s\'' %expr
+
151 ' (supported glob syntax: swp1-10.300 or swp[1-10].300' +
152 ' or swp[1-10]sub[0-4].300')
154 # explanations are shown below in each if clause
155 regexs
= [re
.compile(r
"([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\]([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\](.*)"),
156 re
.compile(r
"([A-Za-z0-9\-]+[A-Za-z])(\d+)\-(\d+)(.*)"),
157 re
.compile(r
"([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\](.*)")]
159 if regexs
[0].match(expr
):
160 # the first regex checks for exactly two levels of ranges defined only with square brackets
161 # (e.g. swpxyz[10-23]subqwe[0-4].100) to handle naming with two levels of port names.
162 m
= regexs
[0].match(expr
)
165 # we have problems and should not continue
166 raise Exception('Error: unhandled glob expression %s\n%s' % (expr
,errmsg
))
170 start_index
= int(mlist
[1])
171 end_index
= int(mlist
[2])
172 sub_string
= mlist
[3]
173 start_sub
= int(mlist
[4])
174 end_sub
= int(mlist
[5])
175 for i
in range(start_index
, end_index
+ 1):
176 for j
in range(start_sub
, end_sub
+ 1):
177 yield prefix
+ '%d%s%d' % (i
,sub_string
,j
) + suffix
179 elif regexs
[1].match(expr
) or regexs
[2].match(expr
):
180 # the second regex for 1 level with a range (e.g. swp10-14.100
181 # the third regex checks for 1 level with [] (e.g. swp[10-14].100)
184 if regexs
[1].match(expr
):
185 m
= regexs
[1].match(expr
)
187 m
= regexs
[2].match(expr
)
190 raise Exception(errmsg
+ '(unexpected len)')
193 start_index
= int(mlist
[1])
194 end_index
= int(mlist
[2])
195 for i
in range(start_index
, end_index
+ 1):
196 yield prefix
+ '%d' %i + suffix
199 # Could not match anything.
200 self
.logger
.warn('%s' %(errmsg))
203 def parse_port_list(self
, port_expr
, ifacenames
=None):
204 """ parse port list containing glob and regex
207 port_expr (str): expression
208 ifacenames (list): list of interface names. This needs to be specified if the expression has a regular expression
216 for expr
in re
.split(r
'[\s\t]\s*', port_expr
):
217 if expr
== 'noregex':
219 elif expr
== 'noglob':
221 elif expr
== 'regex':
226 for port
in self
.parse_regex(expr
, ifacenames
):
227 if port
not in portlist
:
228 portlist
.append(port
)
231 for port
in self
.parse_glob(expr
):
232 portlist
.append(port
)
235 portlist
.append(expr
)
240 def ignore_error(self
, errmsg
):
241 if (self
.FORCE
or re
.search(r
'exists', errmsg
,
242 re
.IGNORECASE | re
.MULTILINE
)):
246 def write_file(self
, filename
, strexpr
):
247 """ writes string to a file """
249 self
.logger
.info('writing \'%s\'' %strexpr
+
250 ' to file %s' %filename
)
253 with
open(filename
, 'w') as f
:
256 self
.logger
.warn('error writing to file %s'
257 %filename
+ '(' + str(e
) + ')')
261 def read_file(self
, filename
):
262 """ read file and return lines from the file """
264 self
.logger
.info('reading \'%s\'' %filename
)
265 with
open(filename
, 'r') as f
:
271 def read_file_oneline(self
, filename
):
272 """ reads and returns first line from the file """
274 self
.logger
.info('reading \'%s\'' %filename
)
275 with
open(filename
, 'r') as f
:
276 return f
.readline().strip('\n')
281 def sysctl_set(self
, variable
, value
):
282 """ set sysctl variable to value passed as argument """
283 self
.exec_command('sysctl %s=' %variable
+ '%s' %value
)
285 def sysctl_get(self
, variable
):
286 """ get value of sysctl variable """
287 return self
.exec_command('sysctl %s' %variable
).split('=')[1].strip()
289 def set_iface_attr(self
, ifaceobj
, attr_name
, attr_valsetfunc
,
290 prehook
=None, prehookargs
=None):
291 ifacename
= ifaceobj
.name
292 attrvalue
= ifaceobj
.get_attr_value_first(attr_name
)
299 attr_valsetfunc(ifacename
, attrvalue
)
301 def query_n_update_ifaceobjcurr_attr(self
, ifaceobj
, ifaceobjcurr
,
302 attr_name
, attr_valgetfunc
,
303 attr_valgetextraarg
=None):
304 attrvalue
= ifaceobj
.get_attr_value_first(attr_name
)
307 if attr_valgetextraarg
:
308 runningattrvalue
= attr_valgetfunc(ifaceobj
.name
,
311 runningattrvalue
= attr_valgetfunc(ifaceobj
.name
)
312 if (not runningattrvalue
or
313 (runningattrvalue
!= attrvalue
)):
314 ifaceobjcurr
.update_config_with_status(attr_name
,
317 ifaceobjcurr
.update_config_with_status(attr_name
,
320 def dict_key_subset(self
, a
, b
):
321 """ returns a list of differing keys """
322 return [x
for x
in a
if x
in b
]
324 def get_mod_attrs(self
):
325 """ returns list of all module attrs defined in the module _modinfo dict"""
327 return self
._modinfo
.get('attrs').keys()
331 def get_mod_attr(self
, attrname
):
332 """ returns module attr info """
334 return self
._modinfo
.get('attrs', {}).get(attrname
)
338 def get_mod_subattr(self
, attrname
, subattrname
):
339 """ returns module attrs defined in the module _modinfo dict"""
341 return reduce(lambda d
, k
: d
[k
], ['attrs', attrname
, subattrname
],
346 def get_modinfo(self
):
347 """ return module info """
354 return dict(force
=self
.FORCE
, dryrun
=self
.DRYRUN
, nowait
=self
.NOWAIT
,
355 perfmode
=self
.PERFMODE
, cache
=self
.CACHE
,
356 cacheflags
=self
.CACHE_FLAGS
)
358 def _get_reserved_vlan_range(self
):
360 get_resvvlan
= '/usr/share/python-ifupdown2/get_reserved_vlan_range.sh'
361 if not os
.path
.exists(get_resvvlan
):
364 (s
, e
) = self
.exec_command(get_resvvlan
).strip('\n').split('-')
368 self
.logger
.debug('%s failed (%s)' %(get_resvvlan
, str(e
)))
373 def _handle_reserved_vlan(self
, vlanid
, logprefix
=''):
374 """ Helper function to check and warn if the vlanid falls in the
375 reserved vlan range """
376 if vlanid
in range(self
._resv
_vlan
_range
[0],
377 self
._resv
_vlan
_range
[1]):
378 self
.logger
.error('%s: reserved vlan %d being used'
379 %(logprefix
, vlanid
) + ' (reserved vlan range %d-%d)'
380 %(self
._resv
_vlan
_range
[0], self
._resv
_vlan
_range
[1]))
384 def _valid_ethaddr(self
, ethaddr
):
385 """ Check if address is 00:00:00:00:00:00 """
386 if not ethaddr
or re
.match('00:00:00:00:00:00', ethaddr
):