Commit 1cbc54bd authored by Mark Schouten's avatar Mark Schouten
Browse files

Try to parse configuration and do config validation

parent c089baf2
#!/usr/bin/env python3
from yaml import load, dump
from sys import exit
from copy import deepcopy
import re, socket
def Get(cfg):
try:
f = open(cfg)
except Exception as e:
raise e
try:
document = load(f.read())
except:
raise ValueError("YAML Error in configuration")
return document
def Validate(document):
def ipv4(teststring):
regex = re.compile('^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/([1-9]|1[0-9]|2[0-4])$')
if regex.match(teststring):
return teststring
else:
raise ValueError("This is not a valid IPv4 address: %s" % (teststring))
def ipv6(teststring):
if teststring.startswith('fe80:'):
raise ValueError("Do not configure link-local addresses")
try:
if len(teststring.split('/')) == 2:
socket.inet_pton(socket.AF_INET6, teststring.split('/')[0])
if 128 >= int(teststring.split('/')[1]) > 0:
return teststring.lower()
except:
raise ValueError("This is not a valid IPv6 address: %s" % (teststring))
def IP(ip):
if ':' in ip:
return ipv6(ip)
else:
return ipv4(ip)
def Adminstate(state):
if state.upper() in ['UP', 'DOWN']:
return state.upper()
else:
raise ValueError("Adminstate must be UP or DOWN")
def Mtu(mtu):
if 65536 >= mtu > 1280:
return mtu
else:
raise ValueError("Invalid value for MTU")
def Interface(iface, iname):
ret = {}
ret['name'] = iname
if iname == 'lo':
ret['type'] = 'loopback'
else:
ret['type'] = 'default'
try:
for address in iface['addresses']:
try:
ret['addresses']
except KeyError:
ret['addresses'] = []
ret['addresses'].append(IP(address))
except ValueError as e:
raise e
except (KeyError, TypeError):
pass
try:
ret['adminstate'] = Adminstate(iface['adminstate'])
except ValueError as e:
raise e
except KeyError:
ret['adminstate'] = 'UP'
try:
ret['mtu'] = Mtu(iface['mtu'])
except ValueError as e:
raise e
except KeyError:
if iname == 'lo':
ret['mtu'] = 65536
else:
ret['mtu'] = '1500'
try:
if iface['vlans']:
vlans = []
for vlan in iface['vlans']:
vname = ''
try:
vname = vlan['name']
except KeyError:
vname = "%s.%s" % (iname, vlan['vlanid'])
vlan['type'] = 'vlan'
vlan = Interface(vlan, vname)
if int(vlan['mtu']) > int(ret['mtu']):
ret['mtu'] = vlan['mtu']
vlans.append(vlan)
ret['vlans'] = vlans
except ValueError as e:
raise e
except KeyError:
pass
try:
if iface['slaves']:
ret['type'] = 'bond'
ret['slaves'] = iface['slaves']
except KeyError:
pass
return ret
# First, check if any weird values occur
olddoc = deepcopy(document)
for iface in olddoc.keys():
document[iface] = Interface(document[iface], iface)
# Then, check if interfaces used in bonds are actually unconfigured
olddoc = deepcopy(document)
for iface in olddoc.keys():
if document[iface]['type'] == 'bond':
for s in document[iface]['slaves']:
try:
if document[s]['vlans']:
raise ValueError("Interface %s is used as a slave and has vlans configured" % (s))
except ValueError as e:
raise e
except KeyError:
pass
try:
if document[s]['addresses']:
raise ValueError("Interface %s is used as a slave and has addresses configured" % (s))
except ValueError as e:
raise e
except KeyError:
pass
try:
document[s]
except KeyError:
document[s] = {}
document[s]['mtu'] = document[iface]['mtu']
document[s]['adminstate'] = 'UP'
document[s]['name'] = s
document[s]['type'] = 'slave'
return document
#!/usr/bin/env python3
"""This script should be able to create a configfile from all the current (supported) interfaces"""
import sys
from socket import AF_INET
from pyroute2 import IPRoute
from pprint import pprint
from pyroute2 import IPDB
from tabulate import tabulate
from yaml import load, dump
#from pyface import Iface, Vlan
with IPDB() as ip:
#
# Create bridge and add ports and addresses.
#
# Transaction will be started by `with` statement
# and will be committed at the end of the block
with ip.create(kind='bond', ifname='rhev') as i:
i.add_port('eth1')
#!/usr/bin/env python3
"""This script should be able to create a configfile from all the current (supported) interfaces"""
import sys
from socket import AF_INET
from pyroute2 import IPRoute
from pprint import pprint
from pyroute2 import IPDB
from tabulate import tabulate
from yaml import load, dump
#from pyface import Iface, Vlan
linkstate = ['DOWN', 'UP']
ip = IPRoute()
ifaces = {}
for iface in ip.get_links():
pprint(iface)
this = {}
iname = iface.get_attr('IFLA_IFNAME')
addrs = []
for addr in ip.get_addr(index=iface['index']):
if addr.get_attr('IFA_ADDRESS').startswith('fe80:'):
# We don't store link-locals
continue
fa = '/'.join([addr.get_attr('IFA_ADDRESS'), str(addr['prefixlen'])])
addrs.append(fa)
if len(addrs) > 0:
this['addresses'] = addrs
this['adminstate'] = iface.get_attr('IFLA_OPERSTATE')
this['mtu'] = iface.get_attr('IFLA_MTU')
if iface.get_attr('IFLA_LINKINFO'):
try:
linfo = iface.get_attr('IFLA_LINKINFO')
if linfo.get_attr('IFLA_INFO_KIND') == 'vlan':
# Get the parents name
pname = ip.get_links(iface.get_attr('IFLA_LINK'))[0].get_attr('IFLA_IFNAME')
try:
ifaces[pname]
except KeyError:
ifaces[pname] = {}
try:
ifaces[pname]['vlans']
except KeyError:
ifaces[pname]['vlans'] = []
this['name'] = iname
this['vlanid'] = linfo.get_attr('IFLA_INFO_DATA').get_attr('IFLA_VLAN_ID')
ifaces[pname]['vlans'].append(this)
except Exception as e:
print(e)
pass
else:
ifaces[iname] = this
print(dump(ifaces,default_flow_style=False))
# #ip.link("add",
# # ifname="v100",
# # kind="vlan",
# # link=ip.link_lookup(ifname="eth1")[0],
# # vlan_id=100)
# #pprint(iface)
# ##print(iface.get_attr('IFLA_IFNAME'))
# #print(iface.get_attr('IFLA_OPERSTATE'))
# ##print(iface['index'])
#pprint(ip.get_addr(index=iface['index']))
\ No newline at end of file
#!/usr/bin/env python3
from pprint import pprint, pformat
class Iface(object):
def __init__(self, nlinfo=None, cinfo=None):
self.name = str()
self.addresses = []
self.mtu = 1500
self.adminstate = 0
if nlinfo:
self.parse_nlinfo(nlinfo)
elif cinfo:
self.parse_config(cinfo)
def setname(self, name):
self.name = name
def setmtu(self, mtu):
self.mtu = mtu
def setadminstate(self, adminstate):
if not adminstate in ['UP', 'DOWN', 'UNKNOWN']:
raise ValueError("Unknown value for adminstate: %s" % (adminstate))
self.adminstate = adminstate
def parse_nlinfo(self, nlinfo):
self.setmtu(nlinfo.get_attr('IFLA_MTU'))
self.setname(nlinfo.get_attr('IFLA_IFNAME'))
self.setadminstate(nlinfo.get_attr('IFLA_OPERSTATE'))
def __str__(self):
return pformat(vars(self))
class Eth(Iface):
def __init__(self, nlinfo=None, cinfo=None):
super(self.__class__, self).__init__()
del(self.vlans)
self.vlanid = int()
self.parent = int()
if nlinfo:
self.parse_nlinfo(nlinfo)
elif cinfo:
self.parse_config(cinfo)
self.vlans = []
class Vlan(Iface):
def __init__(self, nlinfo=None):
super(self.__class__, self).__init__()
del(self.vlans)
self.vlanid = int()
self.parent = int()
if nlinfo:
self.parse_nlinfo(nlinfo)
elif cinfo:
self.parse_config(cinfo)
def parse_nlinfo(self, nlinfo):
self.setmtu(nlinfo.get_attr('IFLA_MTU'))
self.setname(nlinfo.get_attr('IFLA_IFNAME'))
self.setadminstate(nlinfo.get_attr('IFLA_OPERSTATE'))
self.setparent(nlinfo.get_attr(''))
eth0:
addresses:
- 192.168.1.4/24
- fd00::192:168:1:4/64
adminstate: UP
mtu: 1500
eth1:
vlans:
- addresses:
- 192.168.2.4/24
- fd00::192:168:2:4/64
name: foobar
vlanid: 200
mtu: 9000
lo:
addresses:
- 127.0.0.1/8
- ::1/128
mtu: 65536
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Usage:
ypconfig configtest [--cfg=configfile]
ypconfig createconfig
Options:
-h --help Show this help
--cfg=<configfile> Location of the configfile [default: /etc/ypconfig/ypconfig.yml]
"""
import sys, os
sys.path.insert(0, '/home/mark/src/ypconfig/lib')
from ypconfig import Config
from docopt import docopt
from schema import Schema, And, Or, Use, SchemaError, Optional
from pprint import pprint
if __name__ == '__main__':
args = docopt(__doc__)
schema = Schema({
'--cfg': str,
'configtest': bool,
'createconfig': bool
})
try:
args = schema.validate(args)
except SchemaError as e:
sys.exit(e)
try:
cfgdoc = Config.Get(args['--cfg'])
except FileNotFoundError as e:
print(e)
sys.exit(1)
if args['configtest']:
try:
cfg = Config.Validate(cfgdoc)
except Exception as e:
print("Errors in configuration:\n - %s" % (e))
sys.exit(1)
else:
print("Configuration is ok!")
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment