1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00
Julien Fortin 594fb088e8 small easy: support (0|1) or (off|on) attribute while keeping backward compatibility
Ticket: CM-8866
Reviewed By: Roopa
Testing Done:

added support for:
* bond-lacp-bypass-allow (0|1)
* bond-use-carrier (0|1)
* bridge-mcqifaddr (0|1)
* bridge-mcquerier (0|1)
* bridge-mcrouter (0|1)
* bridge-mcsnoop (0|1)
* bridge-portmcrouter (0|1)
* link-autoneg (off|on)
* vxlan-learning (off|on)

these 2 are not yet supported by ifupdown2:
* bond-lacp-bypass-all-active (0|1)
* bond-lacp-fallback-allow (0|1)

This one is left untouched. yes/no doesn't make sense for this attribute.
* bond-lacp-rate (0|1)

Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
2016-06-16 03:37:36 +01:00

244 lines
7.8 KiB
Python

#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# utils --
# helper class
#
import os
import re
import shlex
import fcntl
import signal
import logging
import subprocess
import ifupdownflags
from functools import partial
def signal_handler_f(ps, sig, frame):
if ps:
ps.send_signal(sig)
if sig == signal.SIGINT:
raise KeyboardInterrupt
class utils():
logger = logging.getLogger('ifupdown')
DEVNULL = open(os.devnull, 'w')
_string_values = {
"on": True,
"yes": True,
"1": True,
"off": False,
"no": False,
"0": False,
}
_binary_bool = {
True: "1",
False: "0",
}
_yesno_bool = {
True: 'yes',
False: 'no'
}
_onoff_bool = {
'yes': 'on',
'no': 'off'
}
@staticmethod
def get_onoff_bool(value):
if value in utils._onoff_bool:
return utils._onoff_bool[value]
return value
@staticmethod
def get_boolean_from_string(value):
if value in utils._string_values:
return utils._string_values[value]
return False
@staticmethod
def get_yesno_boolean(bool):
return utils._yesno_bool[bool]
@staticmethod
def boolean_support_binary(value):
return utils._binary_bool[utils.get_boolean_from_string(value)]
@staticmethod
def is_binary_bool(value):
return value == '0' or value == '1'
@staticmethod
def support_yesno_attrs(attrsdict, attrslist, ifaceobj=None):
if ifaceobj:
for attr in attrslist:
value = ifaceobj.get_attr_value_first(attr)
if value and not utils.is_binary_bool(value):
if attr in attrsdict:
bool = utils.get_boolean_from_string(attrsdict[attr])
attrsdict[attr] = utils.get_yesno_boolean(bool)
else:
for attr in attrslist:
if attr in attrsdict:
attrsdict[attr] = utils.boolean_support_binary(attrsdict[attr])
@classmethod
def importName(cls, modulename, name):
""" Import a named object """
try:
module = __import__(modulename, globals(), locals(), [name])
except ImportError:
return None
return getattr(module, name)
@classmethod
def lockFile(cls, lockfile):
try:
fp = os.open(lockfile, os.O_CREAT | os.O_TRUNC | os.O_WRONLY)
fcntl.flock(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
fcntl.fcntl(fp, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
except IOError:
return False
return True
@classmethod
def parse_iface_range(cls, name):
range_match = re.match("^([\w\.]+)\[([\d]+)-([\d]+)\]", name)
if range_match:
range_groups = range_match.groups()
if range_groups[1] and range_groups[2]:
return (range_groups[0], int(range_groups[1], 10),
int(range_groups[2], 10))
return None
@classmethod
def expand_iface_range(cls, name):
ifacenames = []
iface_range = cls.parse_iface_range(name)
if iface_range:
for i in range(iface_range[1], iface_range[2]):
ifacenames.append('%s-%d' %(iface_range[0], i))
return ifacenames
@classmethod
def check_ifname_size_invalid(cls, name=''):
""" IFNAMSIZ in include/linux/if.h is 16 so we check this """
IFNAMSIZ = 16
if len(name) > IFNAMSIZ - 1:
return True
else:
return False
@classmethod
def enable_subprocess_signal_forwarding(cls, ps, sig):
signal.signal(sig, partial(signal_handler_f, ps))
@classmethod
def disable_subprocess_signal_forwarding(cls, sig):
signal.signal(sig, signal.SIG_DFL)
@classmethod
def _log_command_exec(cls, cmd, stdin):
if stdin:
cls.logger.info('executing %s [%s]' % (cmd, stdin))
else:
cls.logger.info('executing %s' % cmd)
@classmethod
def _format_error(cls, cmd, cmd_returncode, cmd_output, stdin):
if type(cmd) is list:
cmd = ' '.join(cmd)
if stdin:
cmd = '%s [%s]' % (cmd, stdin)
if cmd_output:
return 'cmd \'%s\' failed: returned %d (%s)' % \
(cmd, cmd_returncode, cmd_output)
else:
return 'cmd \'%s\' failed: returned %d' % (cmd, cmd_returncode)
@classmethod
def _execute_subprocess(cls, cmd,
env=None,
shell=False,
close_fds=False,
stdout=True,
stdin=None,
stderr=subprocess.STDOUT):
"""
exec's commands using subprocess Popen
Args:
cmd, should be shlex.split if not shell
returns: output
Note: close_fds=True is affecting performance (2~3 times slower)
"""
if ifupdownflags.flags.DRYRUN:
return ''
cmd_output = None
try:
ch = subprocess.Popen(cmd,
env=env,
shell=shell,
close_fds=close_fds,
stdin=subprocess.PIPE if stdin else None,
stdout=subprocess.PIPE if stdout else cls.DEVNULL,
stderr=stderr)
utils.enable_subprocess_signal_forwarding(ch, signal.SIGINT)
if stdout or stdin:
cmd_output = ch.communicate(input=stdin)[0]
cmd_returncode = ch.wait()
except Exception as e:
raise Exception('cmd \'%s\' failed (%s)' % (' '.join(cmd), str(e)))
finally:
utils.disable_subprocess_signal_forwarding(signal.SIGINT)
if cmd_returncode != 0:
raise Exception(cls._format_error(cmd,
cmd_returncode,
cmd_output,
stdin))
return cmd_output
@classmethod
def exec_user_command(cls, cmd, close_fds=False, stdout=True,
stdin=None, stderr=subprocess.STDOUT):
cls._log_command_exec(cmd, stdin)
return cls._execute_subprocess(cmd,
shell=True,
close_fds=close_fds,
stdout=stdout,
stdin=stdin,
stderr=stderr)
@classmethod
def exec_command(cls, cmd, env=None, close_fds=False, stdout=True,
stdin=None, stderr=subprocess.STDOUT):
cls._log_command_exec(cmd, stdin)
return cls._execute_subprocess(shlex.split(cmd),
env=env,
close_fds=close_fds,
stdout=stdout,
stdin=stdin,
stderr=stderr)
@classmethod
def exec_commandl(cls, cmdl, env=None, close_fds=False, stdout=True,
stdin=None, stderr=subprocess.STDOUT):
cls._log_command_exec(' '.join(cmdl), stdin)
return cls._execute_subprocess(cmdl,
env=env,
close_fds=close_fds,
stdout=stdout,
stdin=stdin,
stderr=stderr)
fcntl.fcntl(utils.DEVNULL, fcntl.F_SETFD, fcntl.FD_CLOEXEC)