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:
37
pkg/iface.py
37
pkg/iface.py
@@ -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
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user