1
|
|
|
# encoding: utf-8 |
2
|
|
|
|
3
|
|
|
"""exabgp configuration validation""" |
4
|
|
|
|
5
|
|
|
|
6
|
|
|
import sys |
7
|
|
|
import syslog |
8
|
|
|
import argparse |
9
|
|
|
|
10
|
|
|
from exabgp.environment import getenv |
11
|
|
|
from exabgp.environment import getconf |
12
|
|
|
|
13
|
|
|
from exabgp.debug import trace_interceptor |
14
|
|
|
from exabgp.logger import log |
15
|
|
|
|
16
|
|
|
from exabgp.reactor.loop import Reactor |
17
|
|
|
from exabgp.configuration.check import check_generation |
18
|
|
|
|
19
|
|
|
|
20
|
|
|
def setargs(sub): |
21
|
|
|
# fmt:off |
22
|
|
|
sub.add_argument('-n', '--neighbor', help='check the parsing of the neighbors', action='store_true') |
23
|
|
|
sub.add_argument('-r', '--route', help='check the parsing of the routes', action='store_true') |
24
|
|
|
sub.add_argument('-v', '--verbose', help='be verbose in the display', action='store_true') |
25
|
|
|
sub.add_argument('-p', '--pdb', help='fire the debugger on critical logging, SIGTERM, and exceptions (shortcut for exabgp.pdb.enable=true)', action='store_true') |
26
|
|
|
sub.add_argument('configuration', help='configuration file(s)', nargs='+', type=str) |
27
|
|
|
# fmt:on |
28
|
|
|
|
29
|
|
|
|
30
|
|
|
def cmdline(cmdarg): |
31
|
|
|
env = getenv() |
32
|
|
|
|
33
|
|
|
# Must be done before setting the logger as it modify its behaviour |
34
|
|
|
if cmdarg.verbose: |
35
|
|
|
env.log.all = True |
36
|
|
|
env.log.level = 'DEBUG' |
37
|
|
|
|
38
|
|
|
if cmdarg.pdb: |
39
|
|
|
env.debug.pdb = True |
40
|
|
|
|
41
|
|
|
log.init(env) |
42
|
|
|
trace_interceptor(env.debug.pdb) |
43
|
|
|
|
44
|
|
|
if cmdarg.verbose: |
45
|
|
|
env.log.parser = True |
46
|
|
|
|
47
|
|
|
for configuration in cmdarg.configuration: |
48
|
|
|
log.info(f'loading {configuration}', 'configuration') |
49
|
|
|
location = getconf(configuration) |
50
|
|
|
if not location: |
51
|
|
|
log.critical(f'{configuration} is not an exabgp config file', 'configuration') |
52
|
|
|
sys.exit(1) |
53
|
|
|
|
54
|
|
|
config = Reactor([location]).configuration |
55
|
|
|
|
56
|
|
|
if not config.reload(): |
57
|
|
|
log.critical(f'{configuration} is not a valid config file', 'configuration') |
58
|
|
|
sys.exit(1) |
59
|
|
|
log.info(f'\u2713 loading', 'configuration') |
60
|
|
|
|
61
|
|
|
if cmdarg.neighbor: |
62
|
|
|
log.warning(f'checking neighbors', 'configuration') |
63
|
|
|
for name, neighbor in config.neighbors.items(): |
64
|
|
|
reparsed = neighbor.string() |
65
|
|
|
log.debug(reparsed, configuration) |
66
|
|
|
log.info(f'\u2713 neighbor {name.split()[1]}', 'configuration') |
67
|
|
|
|
68
|
|
|
if cmdarg.route: |
69
|
|
|
log.warning(f'checking routes', 'configuration') |
70
|
|
|
if not check_generation(config.neighbors): |
71
|
|
|
log.critical(f'{configuration} has an invalid route', 'configuration') |
72
|
|
|
sys.exit(1) |
73
|
|
|
log.info(f'\u2713 routes', 'configuration') |
74
|
|
|
|
75
|
|
|
|
76
|
|
|
def main(): |
77
|
|
|
parser = argparse.ArgumentParser(description=sys.modules[__name__].__doc__) |
78
|
|
|
setargs(parser) |
79
|
|
|
cmdline(parser, parser.parse_args()) |
80
|
|
|
|
81
|
|
|
|
82
|
|
|
if __name__ == '__main__': |
83
|
|
|
main() |
84
|
|
|
|