|
|
@ -10,6 +10,12 @@ import re
|
|
|
|
|
|
|
|
|
|
|
|
# comment format:
|
|
|
|
# comment format:
|
|
|
|
# hostname.example.com [aM flag1 flag2 key1=value1 key2=option3:value3,option4:value4] selector.example.com
|
|
|
|
# hostname.example.com [aM flag1 flag2 key1=value1 key2=option3:value3,option4:value4] selector.example.com
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# flags:
|
|
|
|
|
|
|
|
# static - do not auto-enable or auto-disable this address (loopbacks, linknets)
|
|
|
|
|
|
|
|
# home - this is the normal home-location of the IP
|
|
|
|
|
|
|
|
# evacuated - this has been moved from this host to elsewhere
|
|
|
|
|
|
|
|
# evacuee - this is an evacuated address
|
|
|
|
|
|
|
|
|
|
|
|
aM1 = re.compile( r"\[aM ?([^]]*)\]" )
|
|
|
|
aM1 = re.compile( r"\[aM ?([^]]*)\]" )
|
|
|
|
def parse_comment( comment ):
|
|
|
|
def parse_comment( comment ):
|
|
|
@ -71,39 +77,42 @@ def connection( host, username = None, password = None, port = 8729 ):
|
|
|
|
return librouteros.connect( **kwargs )
|
|
|
|
return librouteros.connect( **kwargs )
|
|
|
|
|
|
|
|
|
|
|
|
def connect_routers( config, args ):
|
|
|
|
def connect_routers( config, args ):
|
|
|
|
|
|
|
|
routers = config.get( 'router', {} )
|
|
|
|
rval = {}
|
|
|
|
rval = {}
|
|
|
|
if args:
|
|
|
|
with progress.bar.PixelBar( 'Connecting', max = len( routers ) ) as bar:
|
|
|
|
with progress.bar.PixelBar( 'Connecting', max = len( args ) ) as bar:
|
|
|
|
for ( name, kwargs ) in routers.items():
|
|
|
|
for router in args:
|
|
|
|
if ( not args.only ) or ( name in args.only ):
|
|
|
|
rval[ router ] = connection( router )
|
|
|
|
|
|
|
|
bar.next()
|
|
|
|
|
|
|
|
elif config:
|
|
|
|
|
|
|
|
with progress.bar.PixelBar( 'Connecting', max = len( config ) ) as bar:
|
|
|
|
|
|
|
|
for ( name, kwargs ) in config.items():
|
|
|
|
|
|
|
|
if 'host' not in kwargs:
|
|
|
|
if 'host' not in kwargs:
|
|
|
|
kwargs[ 'host' ] = name
|
|
|
|
kwargs[ 'host' ] = name
|
|
|
|
rval[ name ] = connection( **kwargs )
|
|
|
|
rval[ name ] = connection( **kwargs )
|
|
|
|
bar.next()
|
|
|
|
bar.next()
|
|
|
|
return rval
|
|
|
|
return rval
|
|
|
|
|
|
|
|
|
|
|
|
def monty_check( args ):
|
|
|
|
def monty_check( config, args, routers ):
|
|
|
|
for addr in args.addr:
|
|
|
|
for addr in args.addr:
|
|
|
|
for name, api in args.router.items():
|
|
|
|
for ( name, api ) in routers.items():
|
|
|
|
ip_address = api.path( 'ip', 'address' )
|
|
|
|
ip_address = api.path( 'ip', 'address' )
|
|
|
|
|
|
|
|
ipv6_address = api.path( 'ipv6', 'address' )
|
|
|
|
for item in ip_address:
|
|
|
|
for item in ip_address:
|
|
|
|
( sel, rval, hst ) = parse_comment( item.get( 'comment', '' ) )
|
|
|
|
( sel, rval, hst ) = parse_comment( item.get( 'comment', '' ) )
|
|
|
|
active = not item[ 'disabled' ] and not item[ 'invalid' ]
|
|
|
|
active = not item[ 'disabled' ] and not item[ 'invalid' ]
|
|
|
|
if sel == addr or hst == addr:
|
|
|
|
if sel == addr or hst == addr:
|
|
|
|
print( name, ":", 'ENABLED' if active else 'disabled', item[ 'interface' ] )
|
|
|
|
print( name, ": v4", 'ENABLED' if active else 'disabled', item[ 'interface' ] )
|
|
|
|
|
|
|
|
for item in ipv6_address:
|
|
|
|
|
|
|
|
( sel, rval, hst ) = parse_comment( item.get( 'comment', '' ) )
|
|
|
|
|
|
|
|
active = not item[ 'disabled' ] and not item[ 'invalid' ]
|
|
|
|
|
|
|
|
if sel == addr or hst == addr:
|
|
|
|
|
|
|
|
print( name, ": v6", 'ENABLED' if active else 'disabled', item[ 'interface' ] )
|
|
|
|
|
|
|
|
|
|
|
|
def monty_fixup( args ):
|
|
|
|
def monty_fixup( config, args, routers ):
|
|
|
|
global config
|
|
|
|
for ( name, api ) in routers.items():
|
|
|
|
for name, api in args.router.items():
|
|
|
|
|
|
|
|
ip_address = api.path( 'ip', 'address' )
|
|
|
|
ip_address = api.path( 'ip', 'address' )
|
|
|
|
|
|
|
|
ipv6_address = api.path( 'ipv6', 'address' )
|
|
|
|
for item in ip_address:
|
|
|
|
for item in ip_address:
|
|
|
|
if item[ 'interface' ].startswith( "loop" ):
|
|
|
|
if item[ 'interface' ].startswith( "loop" ):
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
if item[ 'address' ] in config[ 'loopbacks' ]:
|
|
|
|
if item[ 'address' ] not in config[ 'loopbacks' ]:
|
|
|
|
|
|
|
|
continue
|
|
|
|
( sel, rval, hst ) = parse_comment( item.get( 'comment', '' ) )
|
|
|
|
( sel, rval, hst ) = parse_comment( item.get( 'comment', '' ) )
|
|
|
|
if sel is None:
|
|
|
|
if sel is None:
|
|
|
|
rval = {}
|
|
|
|
rval = {}
|
|
|
@ -113,6 +122,20 @@ def monty_fixup( args ):
|
|
|
|
new_comment = make_comment( hst, rval, hst )
|
|
|
|
new_comment = make_comment( hst, rval, hst )
|
|
|
|
print( name, ":", item[ 'interface' ], new_comment )
|
|
|
|
print( name, ":", item[ 'interface' ], new_comment )
|
|
|
|
ip_address.update( **{ 'comment': new_comment, '.id': item[ '.id' ] } )
|
|
|
|
ip_address.update( **{ 'comment': new_comment, '.id': item[ '.id' ] } )
|
|
|
|
|
|
|
|
for item in ipv6_address:
|
|
|
|
|
|
|
|
if item[ 'interface' ].startswith( "loop" ):
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
if item[ 'dynamic' ]:
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
( sel, rval, hst ) = parse_comment( item.get( 'comment', '' ) )
|
|
|
|
|
|
|
|
if sel is None:
|
|
|
|
|
|
|
|
rval = {}
|
|
|
|
|
|
|
|
active = not item[ 'disabled' ] and not item[ 'invalid' ]
|
|
|
|
|
|
|
|
if active:
|
|
|
|
|
|
|
|
rval[ 'home' ] = True
|
|
|
|
|
|
|
|
new_comment = make_comment( hst, rval, hst )
|
|
|
|
|
|
|
|
print( name, ":", item[ 'interface' ], new_comment )
|
|
|
|
|
|
|
|
ipv6_address.update( **{ 'comment': new_comment, '.id': item[ '.id' ] } )
|
|
|
|
|
|
|
|
|
|
|
|
def load_configuration():
|
|
|
|
def load_configuration():
|
|
|
|
try:
|
|
|
|
try:
|
|
|
@ -121,15 +144,15 @@ def load_configuration():
|
|
|
|
return {}
|
|
|
|
return {}
|
|
|
|
return yaml.load( config.read(), yaml.SafeLoader )
|
|
|
|
return yaml.load( config.read(), yaml.SafeLoader )
|
|
|
|
|
|
|
|
|
|
|
|
config = load_configuration()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
def main():
|
|
|
|
|
|
|
|
config = load_configuration()
|
|
|
|
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser( prog = "automonty",
|
|
|
|
parser = argparse.ArgumentParser( prog = "automonty",
|
|
|
|
description = 'AutoMonty (re-)configures routers',
|
|
|
|
description = 'AutoMonty (re-)configures routers',
|
|
|
|
)
|
|
|
|
)
|
|
|
|
subparsers = parser.add_subparsers()
|
|
|
|
subparsers = parser.add_subparsers()
|
|
|
|
|
|
|
|
|
|
|
|
parser.add_argument( '--router', action = 'append' )
|
|
|
|
parser.add_argument( '--only', action = 'append' )
|
|
|
|
|
|
|
|
|
|
|
|
parser_check = subparsers.add_parser( 'check' )
|
|
|
|
parser_check = subparsers.add_parser( 'check' )
|
|
|
|
parser_check.add_argument( 'addr', nargs = "*" )
|
|
|
|
parser_check.add_argument( 'addr', nargs = "*" )
|
|
|
@ -139,9 +162,8 @@ def main():
|
|
|
|
parser_fixup.set_defaults( func = monty_fixup )
|
|
|
|
parser_fixup.set_defaults( func = monty_fixup )
|
|
|
|
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
args = parser.parse_args()
|
|
|
|
args.router = connect_routers( config = config.get( 'router', {} ), args = args.router )
|
|
|
|
routers = connect_routers( config, args )
|
|
|
|
|
|
|
|
args.func( config, args, routers )
|
|
|
|
args.func( args )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|
|
|
|
main()
|
|
|
|