]> git.proxmox.com Git - mirror_ifupdown2.git/blame - pkg/iface.py
Remove upper device check warnings + implicitly follow upperifaces when
[mirror_ifupdown2.git] / pkg / iface.py
CommitLineData
a6f80f0e 1#!/usr/bin/python
3e8ee54f 2#
3# Copyright 2013. Cumulus Networks, Inc.
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6# iface --
7# interface object
8#
62ddec8b 9
10"""ifupdown2 network interface object
11
12It closely resembles the 'iface' object in /etc/network/interfaces
13file. But can be extended to include any other network interface format
14
15
16The module contains the following public classes:
17
18 - ifaceState -- enumerates iface object state
19
20 - ifaceStatus -- enumerates iface object status (success/error)
21
22 - ifaceJsonEncoder -- Json encoder for the iface object
23
24 - iface -- network in terface object class
25
26"""
27
cca03c30 28from collections import OrderedDict
551a3627 29import json
d08d5f54 30import logging
a6f80f0e 31
62ddec8b 32_tickmark = ' (' + u'\u2713'.encode('utf8') + ')'
33_crossmark = ' (' + u'\u2717'.encode('utf8') + ')'
a6f80f0e 34
35class ifaceStatus():
62ddec8b 36 """Enumerates iface status """
37
a6f80f0e 38 UNKNOWN = 0x1
39 SUCCESS = 0x2
40 ERROR = 0x3
10720a53 41 NOTFOUND = 0x4
a6f80f0e 42
43 @classmethod
44 def to_str(cls, state):
45 if state == cls.UNKNOWN:
46 return 'unknown'
47 elif state == cls.SUCCESS:
48 return 'success'
49 elif state == cls.ERROR:
50 return 'error'
739f665b 51 elif state == cls.NOTFOUND:
69f58278 52 return 'notfound'
a6f80f0e 53
54 @classmethod
55 def from_str(cls, state_str):
56 if state_str == 'unknown':
57 return cls.UNKNOWN
58 elif state_str == 'success':
59 return cls.SUCCESS
60 elif state_str == 'error':
61 return cls.ERROR
62
63class ifaceState():
62ddec8b 64 """Enumerates iface state """
a6f80f0e 65
a6f80f0e 66 UNKNOWN = 0x1
67 NEW = 0x2
68 PRE_UP = 0x3
69 UP = 0x4
70 POST_UP = 0x5
71 PRE_DOWN = 0x6
72 DOWN = 0x7
73 POST_DOWN = 0x8
74
d08d5f54 75 # Pseudo states
76 QUERY_CHECKCURR = 0x9
77 QUERY_RUNNING = 0xa
78
a6f80f0e 79 @classmethod
80 def to_str(cls, state):
81 if state == cls.UNKNOWN:
82 return 'unknown'
83 elif state == cls.NEW:
84 return 'new'
85 elif state == cls.PRE_UP:
86 return 'pre-up'
87 elif state == cls.UP:
88 return 'up'
89 elif state == cls.POST_UP:
90 return 'post-up'
91 elif state == cls.PRE_DOWN:
92 return 'pre-down'
d08d5f54 93 elif state == cls.DOWN:
94 return 'down'
a6f80f0e 95 elif state == cls.POST_DOWN:
96 return 'post-down'
d08d5f54 97 elif state == cls.QUERY_CHECKCURR:
98 return 'query-checkcurr'
99 elif state == cls.QUERY_RUNNING:
100 return 'query-running'
a6f80f0e 101
102 @classmethod
103 def from_str(cls, state_str):
104 if state_str == 'unknown':
105 return cls.UNKNOWN
106 elif state_str == 'new':
107 return cls.NEW
108 elif state_str == 'pre-up':
109 return cls.PRE_UP
110 elif state_str == 'up':
111 return cls.UP
112 elif state_str == 'post-up':
113 return cls.POST_UP
114 elif state_str == 'pre-down':
115 return cls.PRE_DOWN
d08d5f54 116 elif state_str == 'down':
117 return cls.DOWN
a6f80f0e 118 elif state_str == 'post-down':
119 return cls.POST_DOWN
d08d5f54 120 elif state_str == 'query-checkcurr':
121 return cls.QUERY_CHECKCURR
122 elif state_str == 'query-running':
123 return cls.QUERY_RUNNING
a6f80f0e 124
d08d5f54 125class ifaceJsonEncoder(json.JSONEncoder):
126 def default(self, o):
83c1f241 127 retconfig = {}
128 if o.config:
129 for k, v in o.config.items():
130 if len(v) == 1:
131 retconfig[k] = v[0]
132 else:
133 retconfig[k] = v
134
75730152 135 return OrderedDict({'name' : o.name,
136 'addr_method' : o.addr_method,
137 'addr_family' : o.addr_family,
138 'auto' : o.auto,
83c1f241 139 'config' : retconfig})
d08d5f54 140
a6f80f0e 141class iface():
62ddec8b 142 """ ifupdown2 interface object class
143
144 Attributes:
145 name Name of the interface
146 addr_family Address family eg, inet, inet6. Can be None to indicate both address families
147 addr_method Address method eg, static, manual or None for static
148 address method
149 config dictionary of config lines for this interface
150 state Configuration state of an interface as defined by
151 ifaceState
152 status Configuration status of an interface as defined by
153 ifaceStatus
154 flags Internal flags used by iface processing
155 priv_flags private flags owned by module using this class
156 refcnt reference count, indicating number of interfaces
157 dependent on this iface
158 lowerifaces list of interface names lower to this interface or
159 this interface depends on
160 upperifaces list of interface names upper to this interface or
161 the interfaces that depend on this interface
162 auto True if interface belongs to the auto class
163 classes List of classes the interface belongs to
164 env shell environment the interface needs during execution
165 raw_config raw interface config from file
166 """
167
31a5f4c3 168 # flag to indicate that the object was created from pickled state
62ddec8b 169 _PICKLED = 0x1
a6f80f0e 170
37c0543d 171 version = '0.1'
172
a6f80f0e 173 def __init__(self):
174 self.name = None
175 self.addr_family = None
176 self.addr_method = None
cca03c30 177 self.config = OrderedDict()
62ddec8b 178 self._config_status = {}
a6f80f0e 179 self.state = ifaceState.NEW
180 self.status = ifaceStatus.UNKNOWN
181 self.flags = 0x0
37c0543d 182 self.priv_flags = 0x0
a6f80f0e 183 self.refcnt = 0
f3215127 184 self.lowerifaces = None
185 self.upperifaces = None
a6f80f0e 186 self.auto = False
187 self.classes = []
188 self.env = None
62ddec8b 189 self.raw_config = []
a6f80f0e 190 self.linkstate = None
191
192 def inc_refcnt(self):
a6f80f0e 193 self.refcnt += 1
194
195 def dec_refcnt(self):
196 self.refcnt -= 1
197
cca03c30 198 def is_config_present(self):
62ddec8b 199 addr_method = self.addr_method
fe0a57d3 200 if addr_method:
37c0543d 201 if (addr_method.find('dhcp') != -1 or
202 addr_method.find('dhcp6') != -1):
203 return True
fe0a57d3 204 if not self.config:
cca03c30 205 return False
fe0a57d3 206 else:
207 return True
cca03c30 208
3e8ee54f 209 def set_class(self, classname):
210 """ Appends a class to the list """
a6f80f0e 211 self.classes.append(classname)
212
31a5f4c3 213 def set_state_n_status(self, state, status):
214 self.state = state
215 self.status = status
216
a6f80f0e 217 def set_flag(self, flag):
218 self.flags |= flag
219
220 def clear_flag(self, flag):
221 self.flags &= ~flag
222
f3215127 223 def add_to_upperifaces(self, upperifacename):
224 if self.upperifaces:
225 if upperifacename not in self.upperifaces:
226 self.upperifaces.append(upperifacename)
227 else:
228 self.upperifaces = [upperifacename]
229
a6f80f0e 230 def get_attr_value(self, attr_name):
62ddec8b 231 return self.config.get(attr_name)
a6f80f0e 232
233 def get_attr_value_first(self, attr_name):
62ddec8b 234 attr_value_list = self.config.get(attr_name)
fe0a57d3 235 if attr_value_list:
a6f80f0e 236 return attr_value_list[0]
a6f80f0e 237 return None
238
239 def get_attr_value_n(self, attr_name, attr_index):
62ddec8b 240 attr_value_list = self.config.get(attr_name)
fe0a57d3 241 if attr_value_list:
a6f80f0e 242 try:
243 return attr_value_list[attr_index]
244 except:
245 return None
a6f80f0e 246 return None
247
62ddec8b 248 @property
a6f80f0e 249 def get_env(self):
fe0a57d3 250 if not self.env:
a6f80f0e 251 self.generate_env()
252 return self.env
253
a6f80f0e 254 def generate_env(self):
255 env = {}
62ddec8b 256 config = self.config
257 env['IFACE'] = self.name
a6f80f0e 258 for attr, attr_value in config.items():
259 attr_env_name = 'IF_%s' %attr.upper()
260 env[attr_env_name] = attr_value[0]
fe0a57d3 261 if env:
62ddec8b 262 self.env = env
a6f80f0e 263
739f665b 264 def update_config(self, attr_name, attr_value):
62ddec8b 265 self.config.setdefault(attr_name, []).append(attr_value)
739f665b 266
267 def update_config_dict(self, attrdict):
268 self.config.update(attrdict)
269
270 def update_config_with_status(self, attr_name, attr_value, attr_status=0):
69f58278 271 if not attr_value:
a6f80f0e 272 attr_value = ''
69f58278 273
62ddec8b 274 self.config.setdefault(attr_name, []).append(attr_value)
275 self._config_status.setdefault(attr_name, []).append(attr_status)
69f58278 276
277 # set global iface state
d08d5f54 278 if attr_status:
62ddec8b 279 self.status = ifaceStatus.ERROR
280 elif self.status != ifaceStatus.ERROR:
69f58278 281 # Not already error, mark success
62ddec8b 282 self.status = ifaceStatus.SUCCESS
69f58278 283
284 def get_config_attr_status(self, attr_name, idx=0):
62ddec8b 285 return self._config_status.get(attr_name, [])[idx]
69f58278 286
287 def get_config_attr_status_str(self, attr_name, idx=0):
62ddec8b 288 ret = self.get_config_attr_status(attr_name, idx)
69f58278 289 if ret:
62ddec8b 290 return _crossmark
eab25b7c 291 else:
62ddec8b 292 return _tickmark
a6f80f0e 293
ca3f4fc7 294 def compare(self, dstiface):
295 """ Compares two objects
296
297 Returns True if object self is same as dstiface and False otherwise """
298
299 if self.name != dstiface.name: return False
300 if self.addr_family != dstiface.addr_family: return False
301 if self.addr_method != dstiface.addr_method: return False
302 if self.auto != dstiface.auto: return False
303 if self.classes != dstiface.classes: return False
37c0543d 304 if any(True for k in self.config if k not in dstiface.config):
ca3f4fc7 305 return False
37c0543d 306 if any(True for k,v in self.config.items()
ca3f4fc7 307 if v != dstiface.config.get(k)): return False
308 return True
d08d5f54 309
310 def __getstate__(self):
311 odict = self.__dict__.copy()
312 del odict['state']
313 del odict['status']
f3215127 314 del odict['lowerifaces']
c798b0f4 315 del odict['upperifaces']
d08d5f54 316 del odict['refcnt']
62ddec8b 317 del odict['_config_status']
5c721925 318 del odict['flags']
319 del odict['priv_flags']
62ddec8b 320 del odict['raw_config']
5c721925 321 del odict['linkstate']
322 del odict['env']
d08d5f54 323 return odict
324
325 def __setstate__(self, dict):
326 self.__dict__.update(dict)
62ddec8b 327 self._config_status = {}
d08d5f54 328 self.state = ifaceState.NEW
329 self.status = ifaceStatus.UNKNOWN
330 self.refcnt = 0
5c721925 331 self.flags = 0
f3215127 332 self.lowerifaces = None
c798b0f4 333 self.upperifaces = None
d08d5f54 334 self.linkstate = None
5c721925 335 self.env = None
336 self.priv_flags = 0
62ddec8b 337 self.raw_config = []
338 self.flags |= self._PICKLED
37c0543d 339
a6f80f0e 340 def dump_raw(self, logger):
341 indent = ' '
53b00224 342 if self.auto:
343 print 'auto %s' %self.name
62ddec8b 344 print (self.raw_config[0])
345 for i in range(1, len(self.raw_config)):
53b00224 346 print(indent + self.raw_config[i])
a6f80f0e 347
a6f80f0e 348 def dump(self, logger):
349 indent = '\t'
62ddec8b 350 logger.info(self.name + ' : {')
351 logger.info(indent + 'family: %s' %self.addr_family)
352 logger.info(indent + 'method: %s' %self.addr_method)
31a5f4c3 353 logger.info(indent + 'flags: %x' %self.flags)
a6f80f0e 354 logger.info(indent + 'state: %s'
62ddec8b 355 %ifaceState.to_str(self.state))
a6f80f0e 356 logger.info(indent + 'status: %s'
62ddec8b 357 %ifaceStatus.to_str(self.status))
358 logger.info(indent + 'refcnt: %d' %self.refcnt)
359 d = self.lowerifaces
fe0a57d3 360 if d:
f3215127 361 logger.info(indent + 'lowerdevs: %s' %str(d))
a6f80f0e 362 else:
f3215127 363 logger.info(indent + 'lowerdevs: None')
739f665b 364
a6f80f0e 365 logger.info(indent + 'config: ')
62ddec8b 366 config = self.config
fe0a57d3 367 if config:
a6f80f0e 368 logger.info(indent + indent + str(config))
369 logger.info('}')
370
69f58278 371 def dump_pretty(self, with_status=False):
a6f80f0e 372 indent = '\t'
cca03c30 373 outbuf = ''
62ddec8b 374 if self.auto:
375 outbuf += 'auto %s\n' %self.name
376 outbuf += 'iface %s' %self.name
377 if self.addr_family:
378 outbuf += ' %s' %self.addr_family
379 if self.addr_method:
380 outbuf += ' %s' %self.addr_method
a6f80f0e 381 outbuf += '\n'
62ddec8b 382 config = self.config
fe0a57d3 383 if config:
eab25b7c 384 for cname, cvaluelist in config.items():
69f58278 385 idx = 0
eab25b7c 386 for cv in cvaluelist:
69f58278 387 if with_status:
388 outbuf += indent + '%s %s %s\n' %(cname, cv,
389 self.get_config_attr_status_str(cname, idx))
390 else:
391 outbuf += indent + '%s %s\n' %(cname, cv)
392 idx += 1
a6f80f0e 393 print outbuf
551a3627 394
69f58278 395 def dump_json(self, with_status=False):
75730152 396 print json.dumps(self, cls=ifaceJsonEncoder, indent=4)