]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdownaddons/modulebase.py
Import python-nlmanager mirror copy
[mirror_ifupdown2.git] / ifupdownaddons / modulebase.py
CommitLineData
15ef32ea
RP
1#!/usr/bin/python
2#
3# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6
19f8bb0b 7import os
15ef32ea
RP
8import re
9import io
10import logging
15ef32ea 11import traceback
a4a53f4b
JF
12
13from ifupdown.utils import utils
15ef32ea 14from ifupdown.iface import *
717cee31 15import ifupdown.policymanager as policymanager
fc5e1735 16import ifupdown.ifupdownflags as ifupdownflags
15ef32ea
RP
17
18class moduleBase(object):
19 """ Base class for ifupdown addon modules
20
21 Provides common infrastructure methods for all addon modules """
22
23 def __init__(self, *args, **kargs):
24 modulename = self.__class__.__name__
25 self.logger = logging.getLogger('ifupdown.' + modulename)
15ef32ea 26
717cee31
RP
27 # vrfs are a global concept and a vrf context can be applicable
28 # to all global vrf commands. Get the default vrf-exec-cmd-prefix
29 # here so that all modules can use it
30 self.vrf_exec_cmd_prefix = policymanager.policymanager_api.get_module_globals('vrf', attr='vrf-exec-cmd-prefix')
31
b3745e05 32 def log_warn(self, str, ifaceobj=None):
15ef32ea
RP
33 """ log a warning if err str is not one of which we should ignore """
34 if not self.ignore_error(str):
35 if self.logger.getEffectiveLevel() == logging.DEBUG:
36 traceback.print_stack()
37 self.logger.warn(str)
b3745e05
RP
38 if ifaceobj:
39 ifaceobj.set_status(ifaceStatus.WARNING)
15ef32ea
RP
40 pass
41
bf3eda91 42 def log_error(self, str, ifaceobj=None, raise_error=True):
15ef32ea
RP
43 """ log an err if err str is not one of which we should ignore and raise an exception """
44 if not self.ignore_error(str):
45 if self.logger.getEffectiveLevel() == logging.DEBUG:
46 traceback.print_stack()
b3745e05
RP
47 if ifaceobj:
48 ifaceobj.set_status(ifaceStatus.ERROR)
bf3eda91
RP
49 if raise_error:
50 raise Exception(str)
15ef32ea
RP
51 else:
52 pass
53
fff589ea 54 def is_process_running(self, procName):
55 try:
a193d8d1 56 utils.exec_command('/bin/pidof -x %s' % procName)
fff589ea 57 except:
58 return False
59 else:
60 return True
61
15ef32ea
RP
62 def get_ifaces_from_proc(self):
63 ifacenames = []
64 with open('/proc/net/dev') as f:
65 try:
66 lines = f.readlines()
0c8332bc 67 for line in lines[2:]:
15ef32ea
RP
68 ifacenames.append(line.split()[0].strip(': '))
69 except:
70 raise
71 return ifacenames
72
0c8332bc 73 def parse_regex(self, ifacename, expr, ifacenames=None):
15ef32ea
RP
74 try:
75 proc_ifacenames = self.get_ifaces_from_proc()
76 except:
0c8332bc
RP
77 self.logger.warn('%s: error reading ifaces from proc' %ifacename)
78
15ef32ea 79 for proc_ifacename in proc_ifacenames:
0c8332bc
RP
80 try:
81 if re.search(expr + '$', proc_ifacename):
82 yield proc_ifacename
83 except Exception, e:
84 raise Exception('%s: error searching regex \'%s\' in %s (%s)'
85 %(ifacename, expr, proc_ifacename, str(e)))
15ef32ea
RP
86 if not ifacenames:
87 return
88 for ifacename in ifacenames:
0c8332bc
RP
89 try:
90 if re.search(expr + '$', ifacename):
91 yield ifacename
92 except Exception, e:
93 raise Exception('%s: error searching regex \'%s\' in %s (%s)'
94 %(ifacename, expr, ifacename, str(e)))
15ef32ea 95
0c8332bc 96 def parse_glob(self, ifacename, expr):
15ef32ea 97 errmsg = ('error parsing glob expression \'%s\'' %expr +
139662ee
ST
98 ' (supported glob syntax: swp1-10.300 or swp[1-10].300' +
99 ' or swp[1-10]sub[0-4].300')
100
101 # explanations are shown below in each if clause
102 regexs = [re.compile(r"([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\]([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\](.*)"),
103 re.compile(r"([A-Za-z0-9\-]+[A-Za-z])(\d+)\-(\d+)(.*)"),
104 re.compile(r"([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\](.*)")]
105
106 if regexs[0].match(expr):
107 # the first regex checks for exactly two levels of ranges defined only with square brackets
108 # (e.g. swpxyz[10-23]subqwe[0-4].100) to handle naming with two levels of port names.
109 m = regexs[0].match(expr)
110 mlist = m.groups()
111 if len(mlist) < 7:
112 # we have problems and should not continue
0c8332bc 113 raise Exception('%s: error: unhandled glob expression %s\n%s' % (ifacename, expr,errmsg))
139662ee
ST
114
115 prefix = mlist[0]
116 suffix = mlist[6]
117 start_index = int(mlist[1])
118 end_index = int(mlist[2])
119 sub_string = mlist[3]
120 start_sub = int(mlist[4])
121 end_sub = int(mlist[5])
122 for i in range(start_index, end_index + 1):
123 for j in range(start_sub, end_sub + 1):
124 yield prefix + '%d%s%d' % (i,sub_string,j) + suffix
125
126 elif regexs[1].match(expr) or regexs[2].match(expr):
127 # the second regex for 1 level with a range (e.g. swp10-14.100
128 # the third regex checks for 1 level with [] (e.g. swp[10-14].100)
129 start_index = 0
130 end_index = 0
131 if regexs[1].match(expr):
132 m = regexs[1].match(expr)
133 else:
134 m = regexs[2].match(expr)
135 mlist = m.groups()
136 if len(mlist) != 4:
0c8332bc 137 raise Exception('%s: ' %ifacename + errmsg + '(unexpected len)')
139662ee
ST
138 prefix = mlist[0]
139 suffix = mlist[3]
140 start_index = int(mlist[1])
141 end_index = int(mlist[2])
15ef32ea
RP
142 for i in range(start_index, end_index + 1):
143 yield prefix + '%d' %i + suffix
144
139662ee
ST
145 else:
146 # Could not match anything.
0c8332bc 147 self.logger.warn('%s: %s' %(ifacename, errmsg))
139662ee
ST
148 yield expr
149
0c8332bc 150 def parse_port_list(self, ifacename, port_expr, ifacenames=None):
15ef32ea
RP
151 """ parse port list containing glob and regex
152
153 Args:
154 port_expr (str): expression
155 ifacenames (list): list of interface names. This needs to be specified if the expression has a regular expression
156 """
157 regex = 0
158 glob = 0
159 portlist = []
160
161 if not port_expr:
162 return None
0c8332bc 163 exprs = re.split(r'[\s\t]\s*', port_expr)
77d9d664 164 self.logger.debug('%s: evaluating port expr \'%s\''
0c8332bc
RP
165 %(ifacename, str(exprs)))
166 for expr in exprs:
84ca006f
RP
167 if expr == 'noregex':
168 regex = 0
169 elif expr == 'noglob':
170 glob = 0
171 elif expr == 'regex':
15ef32ea
RP
172 regex = 1
173 elif expr == 'glob':
174 glob = 1
175 elif regex:
0c8332bc 176 for port in self.parse_regex(ifacename, expr, ifacenames):
15ef32ea
RP
177 if port not in portlist:
178 portlist.append(port)
179 regex = 0
180 elif glob:
9a8ad21a 181 for port in self.parse_glob(ifacename, expr):
15ef32ea
RP
182 portlist.append(port)
183 glob = 0
184 else:
185 portlist.append(expr)
186 if not portlist:
187 return None
188 return portlist
189
190 def ignore_error(self, errmsg):
fc5e1735 191 if (ifupdownflags.flags.FORCE or re.search(r'exists', errmsg,
15ef32ea
RP
192 re.IGNORECASE | re.MULTILINE)):
193 return True
194 return False
195
196 def write_file(self, filename, strexpr):
197 """ writes string to a file """
198 try:
199 self.logger.info('writing \'%s\'' %strexpr +
200 ' to file %s' %filename)
fc5e1735 201 if ifupdownflags.flags.DRYRUN:
15ef32ea
RP
202 return 0
203 with open(filename, 'w') as f:
204 f.write(strexpr)
205 except IOError, e:
206 self.logger.warn('error writing to file %s'
207 %filename + '(' + str(e) + ')')
208 return -1
209 return 0
210
211 def read_file(self, filename):
212 """ read file and return lines from the file """
213 try:
214 self.logger.info('reading \'%s\'' %filename)
215 with open(filename, 'r') as f:
216 return f.readlines()
217 except:
218 return None
219 return None
220
221 def read_file_oneline(self, filename):
222 """ reads and returns first line from the file """
223 try:
224 self.logger.info('reading \'%s\'' %filename)
225 with open(filename, 'r') as f:
226 return f.readline().strip('\n')
227 except:
228 return None
229 return None
230
231 def sysctl_set(self, variable, value):
232 """ set sysctl variable to value passed as argument """
a193d8d1 233 utils.exec_command('sysctl %s=%s' % (variable, value))
15ef32ea
RP
234
235 def sysctl_get(self, variable):
236 """ get value of sysctl variable """
a193d8d1 237 return utils.exec_command('sysctl %s' % variable).split('=')[1].strip()
15ef32ea
RP
238
239 def set_iface_attr(self, ifaceobj, attr_name, attr_valsetfunc,
240 prehook=None, prehookargs=None):
241 ifacename = ifaceobj.name
242 attrvalue = ifaceobj.get_attr_value_first(attr_name)
243 if attrvalue:
244 if prehook:
245 if prehookargs:
246 prehook(prehookargs)
247 else:
248 prehook(ifacename)
249 attr_valsetfunc(ifacename, attrvalue)
250
251 def query_n_update_ifaceobjcurr_attr(self, ifaceobj, ifaceobjcurr,
252 attr_name, attr_valgetfunc,
253 attr_valgetextraarg=None):
254 attrvalue = ifaceobj.get_attr_value_first(attr_name)
255 if not attrvalue:
256 return
257 if attr_valgetextraarg:
258 runningattrvalue = attr_valgetfunc(ifaceobj.name,
259 attr_valgetextraarg)
260 else:
261 runningattrvalue = attr_valgetfunc(ifaceobj.name)
262 if (not runningattrvalue or
263 (runningattrvalue != attrvalue)):
264 ifaceobjcurr.update_config_with_status(attr_name,
265 runningattrvalue, 1)
266 else:
267 ifaceobjcurr.update_config_with_status(attr_name,
268 runningattrvalue, 0)
269
270 def dict_key_subset(self, a, b):
271 """ returns a list of differing keys """
272 return [x for x in a if x in b]
273
274 def get_mod_attrs(self):
1553a881
RP
275 """ returns list of all module attrs defined in the module _modinfo
276 dict
277 """
15ef32ea 278 try:
1553a881
RP
279 retattrs = []
280 attrsdict = self._modinfo.get('attrs')
281 for attrname, attrvals in attrsdict.iteritems():
282 if not attrvals or attrvals.get('deprecated'):
283 continue
284 retattrs.append(attrname)
285 return retattrs
15ef32ea
RP
286 except:
287 return None
288
289 def get_mod_attr(self, attrname):
290 """ returns module attr info """
291 try:
292 return self._modinfo.get('attrs', {}).get(attrname)
293 except:
294 return None
295
296 def get_mod_subattr(self, attrname, subattrname):
297 """ returns module attrs defined in the module _modinfo dict"""
298 try:
299 return reduce(lambda d, k: d[k], ['attrs', attrname, subattrname],
300 self._modinfo)
301 except:
302 return None
303
304 def get_modinfo(self):
305 """ return module info """
306 try:
307 return self._modinfo
308 except:
309 return None
310
2da58137
RP
311 def _get_reserved_vlan_range(self):
312 start = end = 0
313 get_resvvlan = '/usr/share/python-ifupdown2/get_reserved_vlan_range.sh'
19f8bb0b
RP
314 if not os.path.exists(get_resvvlan):
315 return (start, end)
2da58137 316 try:
a193d8d1 317 (s, e) = utils.exec_command(get_resvvlan).strip('\n').split('-')
ad25e7bb
RP
318 start = int(s)
319 end = int(e)
19f8bb0b
RP
320 except Exception, e:
321 self.logger.debug('%s failed (%s)' %(get_resvvlan, str(e)))
2da58137
RP
322 # ignore errors
323 pass
324 return (start, end)
cd3059b8 325
2708f915 326 def _handle_reserved_vlan(self, vlanid, logprefix=''):
cd3059b8
RP
327 """ Helper function to check and warn if the vlanid falls in the
328 reserved vlan range """
329 if vlanid in range(self._resv_vlan_range[0],
330 self._resv_vlan_range[1]):
2708f915
RP
331 self.logger.error('%s: reserved vlan %d being used'
332 %(logprefix, vlanid) + ' (reserved vlan range %d-%d)'
333 %(self._resv_vlan_range[0], self._resv_vlan_range[1]))
cd3059b8
RP
334 return True
335 return False
5828d8c5
RP
336
337 def _valid_ethaddr(self, ethaddr):
338 """ Check if address is 00:00:00:00:00:00 """
339 if not ethaddr or re.match('00:00:00:00:00:00', ethaddr):
340 return False
341 return True