mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
This is a major update coming all at once from master-next branch master-next branch was started with --orphan option which is basically a new branch without history. The major changes are: - repackaging - cleanup the directory tree - rewritte setup.py to allow install from deb file or pypi (pip install) - add a Makefile to make things (like building a deb) easier - review all debian files Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
811 lines
28 KiB
Python
811 lines
28 KiB
Python
#!/usr/bin/python
|
|
#
|
|
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
|
|
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
|
#
|
|
# iface --
|
|
# interface object
|
|
#
|
|
|
|
"""ifupdown2 network interface object
|
|
|
|
It is modeled based on the 'iface' section in /etc/network/interfaces
|
|
file. But can be extended to include any other network interface format
|
|
"""
|
|
|
|
import json
|
|
|
|
from collections import OrderedDict
|
|
|
|
|
|
class ifaceStatusUserStrs():
|
|
""" This class declares strings user can see during an ifquery --check
|
|
for example. These strings can be overridden by user defined strings from
|
|
config file """
|
|
SUCCESS = "success",
|
|
FAILURE = "error",
|
|
UNKNOWN = "unknown"
|
|
|
|
class ifaceType():
|
|
UNKNOWN = 0x00
|
|
IFACE = 0x01
|
|
BRIDGE_VLAN = 0x10
|
|
|
|
class ifaceRole():
|
|
""" ifaceRole is used to classify the ifaceobj.role of
|
|
MASTER or SLAVE where there is a bond or bridge
|
|
with bond-slaves or bridge-ports. A bond in a bridge
|
|
is both a master and slave (0x3)
|
|
"""
|
|
UNKNOWN = 0x00
|
|
SLAVE = 0x01
|
|
MASTER = 0x10
|
|
|
|
class ifaceLinkKind():
|
|
""" ifaceLlinkKind is used to identify interfaces
|
|
in the ifaceobj.link_kind attribute. Dependents of the bridge or
|
|
bond have an ifaceobj.role attribute of SLAVE and the bridge or
|
|
bond itself has ifaceobj.role of MASTER.
|
|
"""
|
|
UNKNOWN = 0x000000
|
|
BRIDGE = 0x000001
|
|
BOND = 0x000010
|
|
VLAN = 0x000100
|
|
VXLAN = 0x001000
|
|
VRF = 0x010000
|
|
# to indicate logical interface created by an external entity.
|
|
# the 'kind' of which ifupdown2 does not really understand
|
|
OTHER = 0x100000
|
|
|
|
@classmethod
|
|
def to_str(cls, kind):
|
|
if kind == cls.BRIDGE:
|
|
return "bridge"
|
|
elif kind == cls.BOND:
|
|
return "bond"
|
|
elif kind == cls.VLAN:
|
|
return "vlan"
|
|
elif kind == cls.VXLAN:
|
|
return "vxlan"
|
|
elif kind == cls.VRF:
|
|
return "vrf"
|
|
|
|
class ifaceLinkPrivFlags():
|
|
""" This corresponds to kernel netdev->priv_flags
|
|
and can be BRIDGE_PORT, BOND_SLAVE etc """
|
|
UNKNOWN = 0x00000
|
|
BRIDGE_PORT = 0x00001
|
|
BOND_SLAVE = 0x00010
|
|
VRF_SLAVE = 0x00100
|
|
BRIDGE_VLAN_AWARE = 0x01000
|
|
BRIDGE_VXLAN = 0x10000
|
|
ADDRESS_VIRTUAL_SLAVE = 0x100000
|
|
LOOPBACK = 0x1000000
|
|
KEEP_LINK_DOWN = 0x10000000
|
|
|
|
@classmethod
|
|
def get_str(cls, flag):
|
|
if flag == cls.UNKNOWN:
|
|
return 'unknown'
|
|
elif flag == cls.BRIDGE_PORT:
|
|
return 'bridge port'
|
|
elif flag == cls.BOND_SLAVE:
|
|
return 'bond slave'
|
|
elif flag == cls.VRF_SLAVE:
|
|
return 'vrf slave'
|
|
elif flag == cls.BRIDGE_VLAN_AWARE:
|
|
return 'vlan aware bridge'
|
|
elif flag == cls.BRIDGE_VXLAN:
|
|
return 'vxlan bridge'
|
|
|
|
@classmethod
|
|
def get_all_str(cls, flags):
|
|
str = ''
|
|
if flags & cls.BRIDGE_PORT:
|
|
str += 'bridgeport '
|
|
if flags & cls.BOND_SLAVE:
|
|
str += 'bondslave '
|
|
if flags & cls.VRF_SLAVE:
|
|
str += 'vrfslave '
|
|
if flags & cls.BRIDGE_VLAN_AWARE:
|
|
str += 'vlanawarebridge '
|
|
if flags & cls.BRIDGE_VXLAN:
|
|
str += 'vxlanbridge '
|
|
return str
|
|
|
|
class ifaceLinkType():
|
|
LINK_UNKNOWN = 0x0
|
|
LINK_SLAVE = 0x1
|
|
LINK_MASTER = 0x2
|
|
LINK_NA = 0x3
|
|
|
|
class VlanProtocols():
|
|
# Picked ID values from
|
|
# http://www.microhowto.info/howto/configure_an_ethernet_interface_as_a_qinq_vlan_trunk.html
|
|
ETHERTYPES_TO_ID = {
|
|
'802.1Q' : '0x8100',
|
|
'802.1AD' : '0x88a8',
|
|
}
|
|
ID_TO_ETHERTYPES = {
|
|
'0x8100' : '802.1Q',
|
|
'0x88a8' : '802.1AD',
|
|
}
|
|
|
|
class ifaceDependencyType():
|
|
""" Indicates type of dependency.
|
|
|
|
This class enumerates types of dependency relationships
|
|
between interfaces.
|
|
|
|
iface dependency relationships can be classified
|
|
into:
|
|
- link
|
|
- master/slave
|
|
|
|
In a 'link' dependency relationship, dependency can be shared
|
|
between interfaces. example: swp1.100 and
|
|
swp1.200 can both have 'link' swp1. swp1 is also a dependency
|
|
of swp1.100 and swp1.200. As you can see dependency
|
|
swp1 is shared between swp1.100 and swp1.200.
|
|
|
|
In a master/slave relationship like bridge and
|
|
its ports: eg: bridge br0 and its ports swp1 and swp2.
|
|
dependency swp1 and swp2 cannot be shared with any other
|
|
interface with the same dependency relationship.
|
|
ie, swp1 and swp2 cannot be in a slave relationship
|
|
with another interface. Understanding the dependency type is
|
|
required for any semantic checks between dependencies.
|
|
|
|
"""
|
|
UNKNOWN = 0x0
|
|
LINK = 0x1
|
|
MASTER_SLAVE = 0x2
|
|
|
|
class ifaceStatus():
|
|
"""Enumerates iface status """
|
|
|
|
UNKNOWN = 0x1
|
|
SUCCESS = 0x2
|
|
WARNING = 0x3
|
|
ERROR = 0x4
|
|
NOTFOUND = 0x5
|
|
|
|
@classmethod
|
|
def to_str(cls, state):
|
|
if state == cls.UNKNOWN:
|
|
return 'unknown'
|
|
elif state == cls.SUCCESS:
|
|
return 'success'
|
|
elif state == cls.ERROR:
|
|
return 'error'
|
|
elif state == cls.NOTFOUND:
|
|
return 'notfound'
|
|
|
|
@classmethod
|
|
def from_str(cls, state_str):
|
|
if state_str == 'unknown':
|
|
return cls.UNKNOWN
|
|
elif state_str == 'success':
|
|
return cls.SUCCESS
|
|
elif state_str == 'error':
|
|
return cls.ERROR
|
|
|
|
class ifaceState():
|
|
"""Enumerates iface state """
|
|
|
|
UNKNOWN = 0x1
|
|
NEW = 0x2
|
|
PRE_UP = 0x3
|
|
UP = 0x4
|
|
POST_UP = 0x5
|
|
PRE_DOWN = 0x6
|
|
DOWN = 0x7
|
|
POST_DOWN = 0x8
|
|
|
|
# Pseudo states
|
|
QUERY_CHECKCURR = 0x9
|
|
QUERY_RUNNING = 0xa
|
|
|
|
@classmethod
|
|
def to_str(cls, state):
|
|
if state == cls.UNKNOWN:
|
|
return 'unknown'
|
|
elif state == cls.NEW:
|
|
return 'new'
|
|
elif state == cls.PRE_UP:
|
|
return 'pre-up'
|
|
elif state == cls.UP:
|
|
return 'up'
|
|
elif state == cls.POST_UP:
|
|
return 'post-up'
|
|
elif state == cls.PRE_DOWN:
|
|
return 'pre-down'
|
|
elif state == cls.DOWN:
|
|
return 'down'
|
|
elif state == cls.POST_DOWN:
|
|
return 'post-down'
|
|
elif state == cls.QUERY_CHECKCURR:
|
|
return 'query-checkcurr'
|
|
elif state == cls.QUERY_RUNNING:
|
|
return 'query-running'
|
|
|
|
@classmethod
|
|
def from_str(cls, state_str):
|
|
if state_str == 'unknown':
|
|
return cls.UNKNOWN
|
|
elif state_str == 'new':
|
|
return cls.NEW
|
|
elif state_str == 'pre-up':
|
|
return cls.PRE_UP
|
|
elif state_str == 'up':
|
|
return cls.UP
|
|
elif state_str == 'post-up':
|
|
return cls.POST_UP
|
|
elif state_str == 'pre-down':
|
|
return cls.PRE_DOWN
|
|
elif state_str == 'down':
|
|
return cls.DOWN
|
|
elif state_str == 'post-down':
|
|
return cls.POST_DOWN
|
|
elif state_str == 'query-checkcurr':
|
|
return cls.QUERY_CHECKCURR
|
|
elif state_str == 'query-running':
|
|
return cls.QUERY_RUNNING
|
|
|
|
class ifaceJsonEncoder(json.JSONEncoder):
|
|
def default(self, o):
|
|
retconfig = {}
|
|
retifacedict = OrderedDict([])
|
|
if o.config:
|
|
retconfig = dict((k, (v[0] if len(v) == 1 else v))
|
|
for k,v in o.config.items())
|
|
retifacedict['name'] = o.name
|
|
if o.addr_method:
|
|
if 'inet' in o.addr_family and 'dhcp' in o.addr_method:
|
|
retifacedict['addr_method'] = 'dhcp'
|
|
else:
|
|
retifacedict['addr_method'] = o.addr_method
|
|
if o.addr_family:
|
|
if len(o.addr_family) > 1:
|
|
retifacedict['addr_family'] = o.addr_family
|
|
else:
|
|
retifacedict['addr_family'] = ' '.join(o.addr_family)
|
|
retifacedict['auto'] = o.auto
|
|
retifacedict['config'] = retconfig
|
|
|
|
return retifacedict
|
|
|
|
class ifaceJsonEncoderWithStatus(json.JSONEncoder):
|
|
def default(self, o):
|
|
retconfig = {}
|
|
retconfig_status = {}
|
|
retifacedict = OrderedDict([])
|
|
if o.config:
|
|
for k,v in o.config.items():
|
|
idx = 0
|
|
vitem_status = []
|
|
for vitem in v:
|
|
s = o.get_config_attr_status(k, idx)
|
|
if s == 1:
|
|
status_str = ifaceStatusUserStrs.ERROR
|
|
elif s == 0:
|
|
status_str = ifaceStatusUserStrs.SUCCESS
|
|
else:
|
|
status_str = ifaceStatusUserStrs.UNKNOWN
|
|
vitem_status.append('%s' %status_str)
|
|
idx += 1
|
|
retconfig[k] = v[0] if len(v) == 1 else v
|
|
retconfig_status[k] = vitem_status[0] if len(vitem_status) == 1 else vitem_status
|
|
|
|
if (o.status == ifaceStatus.NOTFOUND or
|
|
o.status == ifaceStatus.ERROR):
|
|
status = ifaceStatusUserStrs.ERROR
|
|
else:
|
|
status = ifaceStatusUserStrs.SUCCESS
|
|
|
|
retifacedict['name'] = o.name
|
|
if o.addr_method:
|
|
retifacedict['addr_method'] = o.addr_method
|
|
if o.addr_family:
|
|
if len(o.addr_family) > 1:
|
|
retifacedict['addr_family'] = o.addr_family
|
|
else:
|
|
retifacedict['addr_family'] = ' '.join(o.addr_family)
|
|
retifacedict['auto'] = o.auto
|
|
retifacedict['config'] = retconfig
|
|
retifacedict['config_status'] = retconfig_status
|
|
retifacedict['status'] = status
|
|
|
|
return retifacedict
|
|
|
|
class ifaceJsonDecoder():
|
|
@classmethod
|
|
def json_to_ifaceobj(cls, ifaceattrdict):
|
|
ifaceattrdict['config'] = OrderedDict([(k, (v if isinstance(v, list)
|
|
else [v.strip()]))
|
|
for k,v in ifaceattrdict.get('config',
|
|
OrderedDict()).items()])
|
|
return iface(attrsdict=ifaceattrdict)
|
|
|
|
class iface():
|
|
""" ifupdown2 iface object class
|
|
Attributes:
|
|
**name** Name of the interface
|
|
|
|
**addr_family** Address family eg, inet, inet6. Can be None to
|
|
indicate both address families
|
|
|
|
**addr_method** Address method eg, static, manual or None for
|
|
static address method
|
|
|
|
**config** dictionary of config lines for this interface
|
|
|
|
**state** Configuration state of an interface as defined by
|
|
ifaceState
|
|
|
|
**status** Configuration status of an interface as defined by
|
|
ifaceStatus
|
|
|
|
**flags** Internal flags used by iface processing
|
|
|
|
**priv_flags** private flags owned by module using this class
|
|
|
|
**module_flags** module flags owned by module using this class
|
|
|
|
**refcnt** reference count, indicating number of interfaces
|
|
dependent on this iface
|
|
|
|
**lowerifaces** list of interface names lower to this interface or
|
|
this interface depends on
|
|
|
|
**upperifaces** list of interface names upper to this interface or
|
|
the interfaces that depend on this interface
|
|
|
|
**auto** True if interface belongs to the auto class
|
|
|
|
**classes** List of classes the interface belongs to
|
|
|
|
**env** shell environment the interface needs during
|
|
execution
|
|
|
|
**raw_config** raw interface config from file
|
|
"""
|
|
|
|
# flag to indicate that the object was created from pickled state
|
|
# XXX: Move these flags into a separate iface flags class
|
|
_PICKLED = 0x00000001
|
|
HAS_SIBLINGS = 0x00000010
|
|
IFACERANGE_ENTRY = 0x00000100
|
|
IFACERANGE_START = 0x00001000
|
|
OLDEST_SIBLING = 0x00010000
|
|
YOUNGEST_SIBLING = 0x00100000
|
|
|
|
version = '0.1'
|
|
|
|
def __init__(self, attrsdict={}):
|
|
self.addr_family = []
|
|
|
|
self._set_attrs_from_dict(attrsdict)
|
|
self._config_status = {}
|
|
"""dict with config status of iface attributes"""
|
|
self.state = ifaceState.NEW
|
|
"""iface state (of type ifaceState) """
|
|
self.status = ifaceStatus.UNKNOWN
|
|
"""iface status (of type ifaceStatus) """
|
|
self.status_str = None
|
|
"""iface status str (string representing the status) """
|
|
self.flags = 0x0
|
|
"""iface flags """
|
|
self.priv_flags = None
|
|
"""iface module flags dictionary with module name: flags"""
|
|
self.module_flags = {}
|
|
"""iface priv flags. can be used by the external object manager """
|
|
self.refcnt = 0
|
|
"""iface refcnt (incremented for each dependent this interface has) """
|
|
self.lowerifaces = None
|
|
"""lower iface list (in other words: slaves of this interface """
|
|
self.upperifaces = None
|
|
"""upper iface list (in other words: master of this interface """
|
|
self.classes = []
|
|
"""interface classes this iface belongs to """
|
|
self.env = None
|
|
"""environment variable dict required for this interface to run"""
|
|
self.raw_config = []
|
|
"""interface config/attributes in raw format (eg: as it appeared in the interfaces file)"""
|
|
self.linkstate = None
|
|
"""linkstate of the interface"""
|
|
self.type = ifaceType.UNKNOWN
|
|
"""interface type"""
|
|
self.priv_data = None
|
|
self.role = ifaceRole.UNKNOWN
|
|
self.realname = None
|
|
self.link_type = ifaceLinkType.LINK_UNKNOWN
|
|
self.link_kind = ifaceLinkKind.UNKNOWN
|
|
self.link_privflags = ifaceLinkPrivFlags.UNKNOWN
|
|
|
|
# The below attribute is used to disambiguate between various
|
|
# types of dependencies
|
|
self.dependency_type = ifaceDependencyType.UNKNOWN
|
|
self.blacklisted = False
|
|
|
|
def _set_attrs_from_dict(self, attrdict):
|
|
self.auto = attrdict.get('auto', False)
|
|
self.name = attrdict.get('name')
|
|
self.addr_method = attrdict.get('addr_method')
|
|
self.config = attrdict.get('config', OrderedDict())
|
|
|
|
addr_family = attrdict.get('addr_family')
|
|
if addr_family:
|
|
self.addr_family.append(addr_family)
|
|
|
|
def inc_refcnt(self):
|
|
""" increment refcnt of the interface. Usually used to indicate that
|
|
it has dependents """
|
|
self.refcnt += 1
|
|
|
|
def dec_refcnt(self):
|
|
""" decrement refcnt of the interface. Usually used to indicate that
|
|
it has lost its dependent """
|
|
self.refcnt -= 1
|
|
|
|
def is_config_present(self):
|
|
""" returns true if the interface has user provided config,
|
|
false otherwise """
|
|
addr_method = self.addr_method
|
|
if addr_method and addr_method in ['dhcp', 'dhcp6', 'loopback']:
|
|
return True
|
|
if not self.config:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
def set_class(self, classname):
|
|
""" appends class to the interfaces class list """
|
|
self.classes.append(classname)
|
|
|
|
def set_state_n_status(self, state, status):
|
|
""" sets state and status of an interface """
|
|
self.state = state
|
|
if status > self.status:
|
|
self.status = status
|
|
|
|
def set_status(self, status):
|
|
""" sets status of an interface """
|
|
if status > self.status:
|
|
self.status = status
|
|
|
|
def set_flag(self, flag):
|
|
self.flags |= flag
|
|
|
|
def clear_flag(self, flag):
|
|
self.flags &= ~flag
|
|
|
|
def add_to_upperifaces(self, upperifacename):
|
|
""" add to the list of upperifaces """
|
|
if self.upperifaces:
|
|
if upperifacename not in self.upperifaces:
|
|
self.upperifaces.append(upperifacename)
|
|
else:
|
|
self.upperifaces = [upperifacename]
|
|
|
|
def add_to_lowerifaces(self, lowerifacename):
|
|
""" add to the list of lowerifaces """
|
|
if self.lowerifaces:
|
|
if lowerifacename not in self.lowerifaces:
|
|
self.lowerifaces.append(lowerifacename)
|
|
else:
|
|
self.lowerifaces = [lowerifacename]
|
|
|
|
def get_attr_value(self, attr_name):
|
|
""" add to the list of upperifaces """
|
|
return self.config.get(attr_name)
|
|
|
|
def get_attr_value_first(self, attr_name):
|
|
""" get first value of the specified attr name """
|
|
attr_value_list = self.config.get(attr_name)
|
|
if attr_value_list:
|
|
return attr_value_list[0]
|
|
return None
|
|
|
|
def get_attrs_value_first(self, attrs):
|
|
""" get first value of the first attr in the list.
|
|
Useful when you have multiple attrs representing the
|
|
same thing.
|
|
"""
|
|
for attr in attrs:
|
|
attr_value_list = self.config.get(attr)
|
|
if attr_value_list:
|
|
return attr_value_list[0]
|
|
return None
|
|
|
|
def get_attr_value_n(self, attr_name, attr_index):
|
|
""" get n'th value of the specified attr name """
|
|
attr_value_list = self.config.get(attr_name)
|
|
if attr_value_list:
|
|
try:
|
|
return attr_value_list[attr_index]
|
|
except:
|
|
return None
|
|
return None
|
|
|
|
def get_env(self):
|
|
""" get shell environment variables the interface must execute in """
|
|
if not self.env:
|
|
self.generate_env()
|
|
return self.env
|
|
|
|
def generate_env(self):
|
|
""" generate shell environment variables dict interface must execute
|
|
in. This is used to support legacy ifupdown scripts
|
|
"""
|
|
env = {}
|
|
config = self.config
|
|
env['IFACE'] = self.name
|
|
for attr, attr_value in config.items():
|
|
attr_env_name = 'IF_%s' %attr.upper().replace("-", "_")
|
|
env[attr_env_name] = attr_value[0]
|
|
self.env = env
|
|
|
|
def update_config(self, attr_name, attr_value):
|
|
""" add attribute name and value to the interface config """
|
|
self.config.setdefault(attr_name, []).append(attr_value)
|
|
|
|
def replace_config(self, attr_name, attr_value):
|
|
""" add attribute name and value to the interface config """
|
|
self.config[attr_name] = [attr_value]
|
|
|
|
def delete_config(self, attr_name):
|
|
""" add attribute name and value to the interface config """
|
|
try:
|
|
del self.config[attr_name]
|
|
except:
|
|
pass
|
|
|
|
def update_config_dict(self, attrdict):
|
|
self.config.update(attrdict)
|
|
|
|
def update_config_with_status(self, attr_name, attr_value, attr_status=0):
|
|
""" add attribute name and value to the interface config and also
|
|
update the config_status dict with status of this attribute config """
|
|
if not attr_value:
|
|
attr_value = ''
|
|
self.config.setdefault(attr_name, []).append(attr_value)
|
|
self._config_status.setdefault(attr_name, []).append(attr_status)
|
|
# set global iface state
|
|
if attr_status == 1:
|
|
self.status = ifaceStatus.ERROR
|
|
elif self.status != ifaceStatus.ERROR:
|
|
# Not already error, mark success
|
|
self.status = ifaceStatus.SUCCESS
|
|
|
|
def check_n_update_config_with_status_many(self, ifaceobjorig, attr_names,
|
|
attr_status=0):
|
|
# set multiple attribute status to zero
|
|
# also updates status only if the attribute is present
|
|
for attr_name in attr_names:
|
|
if not ifaceobjorig.get_attr_value_first(attr_name):
|
|
continue
|
|
self.config.setdefault(attr_name, []).append('')
|
|
self._config_status.setdefault(attr_name, []).append(attr_status)
|
|
|
|
def get_config_attr_status(self, attr_name, idx=0):
|
|
""" get status of a attribute config on this interface.
|
|
|
|
Looks at the iface _config_status dict"""
|
|
return self._config_status.get(attr_name, [])[idx]
|
|
|
|
def compare(self, dstiface):
|
|
""" compares iface object with iface object passed as argument
|
|
|
|
Returns True if object self is same as dstiface and False otherwise """
|
|
|
|
if self.name != dstiface.name: return False
|
|
if self.type != dstiface.type: return False
|
|
if self.addr_family != dstiface.addr_family: return False
|
|
if self.addr_method != dstiface.addr_method: return False
|
|
if self.auto != dstiface.auto: return False
|
|
if self.classes != dstiface.classes: return False
|
|
if len(self.config) != len(dstiface.config):
|
|
return False
|
|
if any(True for k in self.config if k not in dstiface.config):
|
|
return False
|
|
if any(True for k,v in self.config.items()
|
|
if v != dstiface.config.get(k)): return False
|
|
return True
|
|
|
|
def squash(self, newifaceobj):
|
|
""" This squashes the iface object """
|
|
for attrname, attrlist in newifaceobj.config.iteritems():
|
|
# if allready present add it to the list
|
|
# else add it to the end of the dictionary
|
|
# We need to maintain order.
|
|
if self.config.get(attrname):
|
|
self.config[attrname].extend(attrlist)
|
|
else:
|
|
self.config.update([(attrname, attrlist)])
|
|
# we now support inet and inet6 together
|
|
self.addr_family.extend(newifaceobj.addr_family)
|
|
# if auto %ifacename is not part of the first stanza
|
|
# we need to squash it
|
|
if not self.auto and newifaceobj.auto:
|
|
self.auto = True
|
|
|
|
def __getstate__(self):
|
|
odict = self.__dict__.copy()
|
|
del odict['state']
|
|
del odict['status']
|
|
del odict['lowerifaces']
|
|
del odict['upperifaces']
|
|
del odict['refcnt']
|
|
del odict['_config_status']
|
|
del odict['flags']
|
|
del odict['priv_flags']
|
|
del odict['module_flags']
|
|
del odict['raw_config']
|
|
del odict['linkstate']
|
|
del odict['env']
|
|
del odict['link_type']
|
|
del odict['link_kind']
|
|
del odict['link_privflags']
|
|
del odict['role']
|
|
del odict['dependency_type']
|
|
del odict['blacklisted']
|
|
return odict
|
|
|
|
def __setstate__(self, dict):
|
|
self.__dict__.update(dict)
|
|
self._config_status = {}
|
|
self.state = ifaceState.NEW
|
|
self.status = ifaceStatus.UNKNOWN
|
|
self.refcnt = 0
|
|
self.flags = 0
|
|
self.lowerifaces = None
|
|
self.upperifaces = None
|
|
self.linkstate = None
|
|
self.env = None
|
|
self.role = ifaceRole.UNKNOWN
|
|
self.priv_flags = None
|
|
self.module_flags = {}
|
|
self.raw_config = []
|
|
self.flags |= self._PICKLED
|
|
self.link_type = ifaceLinkType.LINK_NA
|
|
self.link_kind = ifaceLinkKind.UNKNOWN
|
|
self.link_privflags = ifaceLinkPrivFlags.UNKNOWN
|
|
self.dependency_type = ifaceDependencyType.UNKNOWN
|
|
self.blacklisted = False
|
|
|
|
def dump_raw(self, logger):
|
|
indent = ' '
|
|
if self.auto:
|
|
print 'auto %s' %self.name
|
|
print (self.raw_config[0])
|
|
for i in range(1, len(self.raw_config)):
|
|
print(indent + self.raw_config[i])
|
|
|
|
def dump(self, logger):
|
|
indent = '\t'
|
|
logger.info(self.name + ' : {')
|
|
logger.info(indent + 'family: %s' % ' '.join(self.addr_family))
|
|
logger.info(indent + 'method: %s' %self.addr_method)
|
|
logger.info(indent + 'flags: %x' %self.flags)
|
|
logger.info(indent + 'state: %s'
|
|
%ifaceState.to_str(self.state))
|
|
logger.info(indent + 'status: %s'
|
|
%ifaceStatus.to_str(self.status))
|
|
logger.info(indent + 'refcnt: %d' %self.refcnt)
|
|
d = self.lowerifaces
|
|
if d:
|
|
logger.info(indent + 'lowerdevs: %s' %str(d))
|
|
else:
|
|
logger.info(indent + 'lowerdevs: None')
|
|
|
|
d = self.upperifaces
|
|
if d:
|
|
logger.info(indent + 'upperdevs: %s' %str(d))
|
|
else:
|
|
logger.info(indent + 'upperdevs: None')
|
|
|
|
logger.info(indent + 'config: ')
|
|
config = self.config
|
|
if config:
|
|
logger.info(indent + indent + str(config))
|
|
logger.info('}')
|
|
|
|
def _dump_pretty(self, family, first, addr_method, with_status=False, use_realname=False):
|
|
indent = '\t'
|
|
outbuf = ''
|
|
if use_realname and self.realname:
|
|
name = '%s' %self.realname
|
|
else:
|
|
name = '%s' %self.name
|
|
if self.auto:
|
|
outbuf += 'auto %s\n' %name
|
|
ifaceline = ''
|
|
if self.type == ifaceType.BRIDGE_VLAN:
|
|
ifaceline += 'vlan %s' %name
|
|
else:
|
|
ifaceline += 'iface %s' %name
|
|
if family:
|
|
ifaceline += ' %s' % family
|
|
if addr_method:
|
|
ifaceline += ' %s' % addr_method
|
|
if with_status:
|
|
status_str = None
|
|
if (self.status == ifaceStatus.ERROR or
|
|
self.status == ifaceStatus.NOTFOUND):
|
|
if self.status_str:
|
|
ifaceline += ' (%s)' %self.status_str
|
|
status_str = '[%s]' %ifaceStatusUserStrs.ERROR
|
|
elif self.status == ifaceStatus.SUCCESS:
|
|
status_str = '[%s]' %ifaceStatusUserStrs.SUCCESS
|
|
if status_str:
|
|
outbuf += '{0:65} {1:>8}'.format(ifaceline, status_str) + '\n'
|
|
else:
|
|
outbuf += ifaceline + '\n'
|
|
if self.status == ifaceStatus.NOTFOUND:
|
|
outbuf = (outbuf.encode('utf8')
|
|
if isinstance(outbuf, unicode) else outbuf)
|
|
print outbuf + '\n'
|
|
return
|
|
else:
|
|
outbuf += ifaceline + '\n'
|
|
config = self.config
|
|
if config and first:
|
|
for cname, cvaluelist in config.items():
|
|
idx = 0
|
|
for cv in cvaluelist:
|
|
status_str = None
|
|
if with_status:
|
|
s = self.get_config_attr_status(cname, idx)
|
|
if s == -1:
|
|
status_str = '[%s]' %ifaceStatusUserStrs.UNKNOWN
|
|
elif s == 1:
|
|
status_str = '[%s]' %ifaceStatusUserStrs.ERROR
|
|
elif s == 0:
|
|
status_str = '[%s]' %ifaceStatusUserStrs.SUCCESS
|
|
if status_str:
|
|
outbuf += (indent + '{0:55} {1:>10}'.format(
|
|
'%s %s' %(cname, cv), status_str)) + '\n'
|
|
else:
|
|
outbuf += indent + '%s %s\n' %(cname, cv)
|
|
idx += 1
|
|
if with_status:
|
|
outbuf = (outbuf.encode('utf8')
|
|
if isinstance(outbuf, unicode) else outbuf)
|
|
print outbuf
|
|
|
|
def dump_pretty(self, with_status=False, use_realname=False):
|
|
if not self.addr_family:
|
|
self._dump_pretty(None, True,
|
|
self.addr_method,
|
|
with_status=with_status,
|
|
use_realname=use_realname)
|
|
else:
|
|
# To allow both inet and inet6 on an interface we changed the
|
|
# addr_family attribute, it's now a list. Depending on how
|
|
# stanzas were squashed (and what command was used ie. ifquery -r)
|
|
# we want to dump the ifaceobj as usual but we will output an
|
|
# empty stanza for each additional addr_family. The config will
|
|
# only be displayed once, in the first stanza. Example:
|
|
# $ ifquery eth0 -r
|
|
# auto etho
|
|
# iface eth0 inet dhcp
|
|
# config...
|
|
#
|
|
# auto eth0
|
|
# iface eth0 inet6 dhcp
|
|
# $
|
|
first = True
|
|
for family in self.addr_family:
|
|
addr_method = self.addr_method
|
|
# We need to make sure we display 'dhcp' for inet family.
|
|
# In some cases it might take the value 'dhcp6' even if it has
|
|
# both inet and inet6 addr_family
|
|
if addr_method and family == 'inet' and 'dhcp' in addr_method:
|
|
addr_method = 'dhcp'
|
|
self._dump_pretty(family, first,
|
|
addr_method=addr_method,
|
|
with_status=with_status,
|
|
use_realname=use_realname)
|
|
first = False
|