1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00

support json input + multiple instance running check

Ticket: CM-1438
Reviewed By:
Testing Done: Tested sanity and interfaces file in json format
This commit is contained in:
roopa
2014-04-28 22:33:33 -07:00
parent d40e96ee4e
commit 3dcc1d0eeb
4 changed files with 128 additions and 48 deletions

View File

@@ -29,8 +29,8 @@ from collections import OrderedDict
import logging
import json
_tickmark = ' (' + u'\u2713'.encode('utf8') + ')'
_crossmark = ' (' + u'\u2717'.encode('utf8') + ')'
_tickmark = ' (' + u'\u2713' + ')'
_crossmark = ' (' + u'\u2717' + ')'
_success_sym = _tickmark
_error_sym = _crossmark
@@ -128,13 +128,23 @@ class ifaceJsonEncoder(json.JSONEncoder):
def default(self, o):
retconfig = {}
if o.config:
retconfig = dict((k, (v[0] if len(v) == 1 else v)) for k,v in o.config.items())
retconfig = dict((k, (v[0] if len(v) == 1 else v))
for k,v in o.config.items())
return OrderedDict({'name' : o.name,
'addr_method' : o.addr_method,
'addr_family' : o.addr_family,
'auto' : o.auto,
'config' : retconfig})
class ifaceJsonDecoder():
@classmethod
def json_to_ifaceobj(cls, ifaceattrdict):
ifaceattrdict['config'] = OrderedDict([(k, (v if isinstance(v, list)
else [v]))
for k,v in ifaceattrdict.get('config',
OrderedDict()).items()])
return iface(attrsdict=ifaceattrdict)
class iface():
""" ifupdown2 interface object class
@@ -167,11 +177,8 @@ class iface():
version = '0.1'
def __init__(self):
self.name = None
self.addr_family = None
self.addr_method = None
self.config = OrderedDict()
def __init__(self, attrsdict={}):
self._set_attrs_from_dict(attrsdict)
self._config_status = {}
self.state = ifaceState.NEW
self.status = ifaceStatus.UNKNOWN
@@ -180,12 +187,18 @@ class iface():
self.refcnt = 0
self.lowerifaces = None
self.upperifaces = None
self.auto = False
self.classes = []
self.env = None
self.raw_config = []
self.linkstate = None
def _set_attrs_from_dict(self, attrdict):
self.auto = attrdict.get('auto', False)
self.name = attrdict.get('name')
self.addr_family = attrdict.get('addr_family')
self.addr_method = attrdict.get('addr_method')
self.config = attrdict.get('config', OrderedDict())
def inc_refcnt(self):
self.refcnt += 1
@@ -380,6 +393,9 @@ class iface():
else:
outbuf += ' %s' %_success_sym
if self.status == ifaceStatus.NOTFOUND:
if with_status:
outbuf = (outbuf.encode('utf8')
if isinstance(outbuf, unicode) else outbuf)
print outbuf + '\n'
return
outbuf += '\n'
@@ -395,4 +411,7 @@ class iface():
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

View File

@@ -111,7 +111,9 @@ class ifupdownMain(ifupdownBase):
force=False, dryrun=False, nowait=False,
perfmode=False, withdepends=False, njobs=1,
cache=False, addons_enable=True, statemanager_enable=True,
interfacesfile='/etc/network/interfaces'):
interfacesfile='/etc/network/interfaces',
interfacesfileiobuf=None,
interfacesfileformat='native'):
self.logger = logging.getLogger('ifupdown')
self.FORCE = force
self.DRYRUN = dryrun
@@ -121,6 +123,8 @@ class ifupdownMain(ifupdownBase):
self.STATEMANAGER_ENABLE = statemanager_enable
self.CACHE = cache
self.interfacesfile = interfacesfile
self.interfacesfileiobuf = interfacesfileiobuf
self.interfacesfileformat = interfacesfileformat
self.config = config
self.logger.debug(self.config)
@@ -342,7 +346,7 @@ class ifupdownMain(ifupdownBase):
return
self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
def _module_syntax_checker(self, attrname, attrval):
def _iface_configattr_syntax_checker(self, attrname, attrval):
for m, mdict in self.module_attrs.items():
if not mdict:
continue
@@ -354,13 +358,31 @@ class ifupdownMain(ifupdownBase):
pass
return False
def _ifaceobj_syntax_checker(self, ifaceobj):
err = False
for attrname in ifaceobj.config:
found = False
for k, v in self.module_attrs.items():
if v and v.get('attrs', {}).get(attrname):
found = True
break
if not found:
err = True
self.logger.warn('%s: unsupported attribute \'%s\'' %attrname)
continue
return err
def read_iface_config(self):
""" Reads default network interface config /etc/network/interfaces. """
nifaces = networkInterfaces(self.interfacesfile,
self.interfacesfileiobuf,
self.interfacesfileformat,
template_engine=self.config.get('template_engine'),
template_lookuppath=self.config.get('template_lookuppath'))
nifaces.subscribe('iface_found', self._save_iface)
nifaces.subscribe('validate', self._module_syntax_checker)
nifaces.subscribe('validateifaceattr',
self._iface_configattr_syntax_checker)
nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
nifaces.load()
def read_old_iface_config(self):
@@ -901,8 +923,8 @@ class ifupdownMain(ifupdownBase):
self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
if not ifaceobjs: return
if format == 'json':
print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=4,
separators=(',', ': '))
print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
indent=4, separators=(',', ': '))
else:
map(lambda i: i.dump_pretty(), ifaceobjs)

View File

@@ -25,13 +25,17 @@ class networkInterfaces():
'inet6' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6']}
def __init__(self, interfacesfile='/etc/network/interfaces',
interfacesfileiobuf=None, interfacesfileformat='native',
template_engine=None, template_lookuppath=None):
self.logger = logging.getLogger('ifupdown.' +
self.__class__.__name__)
self.callbacks = {'iface_found' : None,
'validate' : None}
'validateifaceattr' : None,
'validateifaceobj' : None}
self.allow_classes = {}
self.interfacesfile = interfacesfile
self.interfacesfileiobuf = interfacesfileiobuf
self.interfacesfileformat = interfacesfileformat
self._filestack = [self.interfacesfile]
self._template_engine = templateEngine(template_engine,
template_lookuppath)
@@ -50,7 +54,7 @@ class networkInterfaces():
else:
self.logger.error('%s: line%d: %s' %(filename, lineno, msg))
def _validate_addr_family(self, ifaceobj, lineno):
def _validate_addr_family(self, ifaceobj, lineno=-1):
if ifaceobj.addr_family:
if not self._addrfams.get(ifaceobj.addr_family):
self._parse_error(self._currentfile, lineno,
@@ -124,7 +128,7 @@ class networkInterfaces():
attrval, lineno):
newattrname = attrname.replace("_", "-")
try:
if not self.callbacks.get('validate')(newattrname, attrval):
if not self.callbacks.get('validateifaceattr')(newattrname, attrval):
self._parse_error(self._currentfile, lineno,
'iface %s: unsupported keyword (%s)'
%(ifacename, attrname))
@@ -239,7 +243,7 @@ class networkInterfaces():
classes.append(class_name)
return classes
def process_filedata(self, filedata):
def process_interfaces(self, filedata):
line_idx = 0
lines_consumed = 0
raw_config = filedata.split('\n')
@@ -260,15 +264,7 @@ class networkInterfaces():
line_idx += 1
return 0
def read_file(self, filename=None):
interfacesfile = filename
if not interfacesfile:
interfacesfile=self.interfacesfile
self._filestack.append(interfacesfile)
self.logger.info('reading interfaces file %s' %interfacesfile)
f = open(interfacesfile)
filedata = f.read()
f.close()
def read_filedata(self, filedata):
self._currentfile_has_template = False
# process line continuations
filedata = ' '.join(d.strip() for d in filedata.split('\\'))
@@ -285,12 +281,42 @@ class networkInterfaces():
'Continue without template rendering ...')
rendered_filedata = None
pass
self.logger.info('parsing interfaces file %s ...' %interfacesfile)
if rendered_filedata:
self.process_filedata(rendered_filedata)
self.process_interfaces(rendered_filedata)
else:
self.process_filedata(filedata)
self.process_interfaces(filedata)
def read_file(self, filename, fileiobuf=None):
if fileiobuf:
self.read_filedata(fileiobuf)
return
self._filestack.append(filename)
self.logger.info('processing interfaces file %s' %filename)
f = open(filename)
filedata = f.read()
f.close()
self.read_filedata(filedata)
self._filestack.pop()
def load(self, filename=None):
return self.read_file(filename)
def read_file_json(self, filename, fileiobuf=None):
if fileiobuf:
ifacedicts = json.loads(fileiobuf, encoding="utf-8")
#object_hook=ifaceJsonDecoder.json_object_hook)
elif filename:
self.logger.info('processing interfaces file %s' %filename)
fp = open(filename)
ifacedicts = json.load(fp)
#object_hook=ifaceJsonDecoder.json_object_hook)
for ifacedict in ifacedicts:
ifaceobj = ifaceJsonDecoder.json_to_ifaceobj(ifacedict)
if ifaceobj:
self._validate_addr_family(ifaceobj)
self.callbacks.get('validateifaceobj')(ifaceobj)
self.callbacks.get('iface_found')(ifaceobj)
def load(self):
if self.interfacesfileformat == 'json':
return self.read_file_json(self.interfacesfile,
self.interfacesfileiobuf)
return self.read_file(self.interfacesfile,
self.interfacesfileiobuf)

View File

@@ -15,6 +15,7 @@ lockfile="/run/network/.lock"
configfile="/etc/network/ifupdown2/ifupdown2.conf"
configmap_g=None
logger = None
interfacesfileiobuf=None
ENVPATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
def run_up(args):
@@ -36,7 +37,9 @@ def run_up(args):
cache=cachearg,
addons_enable=not args.noaddons,
statemanager_enable=not args.noaddons,
interfacesfile=args.interfacesfile)
interfacesfile=args.interfacesfile,
interfacesfileiobuf=interfacesfileiobuf,
interfacesfileformat=args.interfacesfileformat)
if args.noaddons:
ifupdown_handle.up(['up'], args.all, args.CLASS, iflist,
excludepats=args.excludepats,
@@ -63,7 +66,9 @@ def run_down(args):
dryrun=args.noact,
addons_enable=not args.noaddons,
statemanager_enable=not args.noaddons,
interfacesfile=args.interfacesfile)
interfacesfile=args.interfacesfile,
interfacesfileiobuf=interfacesfileiobuf,
interfacesfileformat=args.interfacesfileformat)
ifupdown_handle.down(['pre-down', 'down', 'post-down'],
args.all, args.CLASS, iflist,
@@ -104,7 +109,9 @@ def run_query(args):
withdepends=args.withdepends,
perfmode=args.perfmode,
cache=cachearg,
interfacesfile=args.interfacesfile)
interfacesfile=args.interfacesfile,
interfacesfileiobuf=interfacesfileiobuf,
interfacesfileformat=args.interfacesfileformat)
ifupdown_handle.query([qop], args.all, args.CLASS, iflist,
excludepats=args.excludepats,
@@ -131,6 +138,7 @@ def run_reload(args):
def init(args):
global logger
global interfacesfileiobuf
log_level = logging.WARNING
if args.verbose:
@@ -149,6 +157,9 @@ def init(args):
except:
raise
# If interfaces file is stdin, read
if hasattr(args, 'interfacesfile') and args.interfacesfile == '-':
interfacesfileiobuf = sys.stdin.read()
def deinit():
{}
@@ -189,6 +200,11 @@ def update_argparser(argparser):
default='/etc/network/interfaces',
help='use interfaces file instead of default ' +
'/etc/network/interfaces')
argparser.add_argument('-t', '--interfaces-format',
dest='interfacesfileformat',
default='native',
choices=['native', 'json'],
help='interfaces file format')
def update_ifupdown_argparser(argparser):
""" common arg parser for ifup and ifdown """
@@ -276,10 +292,10 @@ def update_ifreload_argparser(argparser):
help=argparse.SUPPRESS)
#argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
# default=-1, choices=range(1,12), help=argparse.SUPPRESS)
argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
default='/etc/network/interfaces',
help='use interfaces file instead of default ' +
'/etc/network/interfaces')
#argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
# default='/etc/network/interfaces',
# help='use interfaces file instead of default ' +
# '/etc/network/interfaces')
argparser.add_argument('--use-current-config',
dest='usecurrentconfig', action='store_true',
help='By default ifreload looks at saved state for ' +
@@ -317,10 +333,10 @@ handlers = {'up' : run_up,
'reload' : run_reload }
def validate_args(op, args):
if op == 'up' and args.syntaxcheck:
if args.iflist or args.all:
print 'ignoring interface options ..'
return True
#if op == 'up' and args.syntaxcheck:
# if args.iflist or args.all:
# print 'ignoring interface options ..'
# return True
if op == 'query' and args.syntaxhelp:
return True
if not args.iflist and not args.all:
@@ -387,12 +403,9 @@ if __name__ == "__main__":
print 'error: must be root to run this command'
exit(1)
"""
#XXX: Cannot use this. A spawned dhclient process can hold the lock
if not utils.lockFile(lockfile):
print 'Another instance of this program is already running.'
exit(0)
"""
# required during boot
os.putenv('PATH', ENVPATH)