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 args(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 = syslog.LOG_DEBUG |
37
|
|
|
|
38
|
|
|
log.init() |
39
|
|
|
|
40
|
|
|
if cmdarg.pdb: |
41
|
|
|
env.debug.pdb = True |
42
|
|
|
|
43
|
|
|
if cmdarg.verbose: |
44
|
|
|
env.log.parser = True |
45
|
|
|
|
46
|
|
|
for configuration in cmdarg.configuration: |
47
|
|
|
log.notice(f'loading {configuration}', 'configuration') |
48
|
|
|
location = getconf(configuration) |
49
|
|
|
if not location: |
50
|
|
|
log.critical(f'{configuration} is not an exabgp config file', 'configuration') |
51
|
|
|
sys.exit(1) |
52
|
|
|
|
53
|
|
|
config = Reactor([location]).configuration |
54
|
|
|
|
55
|
|
|
if not config.reload(): |
56
|
|
|
log.critical(f'{configuration} is not a valid config file', 'configuration') |
57
|
|
|
sys.exit(1) |
58
|
|
|
log.info(f'\u2713 loading', 'configuration') |
59
|
|
|
|
60
|
|
|
if cmdarg.neighbor: |
61
|
|
|
log.notice(f'checking neighbors', 'configuration') |
62
|
|
|
for name, neighbor in config.neighbors.items(): |
63
|
|
|
reparsed = neighbor.string() |
64
|
|
|
for line in reparsed.split('\n'): |
65
|
|
|
log.debug(line, configuration) |
66
|
|
|
log.info(f'\u2713 neighbor {name.split()[1]}', 'configuration') |
67
|
|
|
|
68
|
|
|
if cmdarg.route: |
69
|
|
|
log.notice(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
|
|
|
args(parser) |
79
|
|
|
trace_interceptor() |
80
|
|
|
cmdline(parser, parser.parse_args()) |
81
|
|
|
|
82
|
|
|
|
83
|
|
|
if __name__ == '__main__': |
84
|
|
|
main() |
85
|
|
|
|