4747DEFAULT_BGP_LISTEN_PORT = 179
4848
4949http_api_py = '''\
50- from flask import Flask, request
50+ from __future__ import print_function
51+ import tornado.ioloop
52+ import tornado.web
5153import sys
52- import six
53-
54- #Disable banner msg from app.run, or the output might be caught by exabgp and run as command
55- cli = sys.modules['flask.cli']
56- cli.show_server_banner = lambda *x: None
57-
58- app = Flask(__name__)
59-
60- # Setup a command route to listen for prefix advertisements
61- @app.route('/', methods=['POST'])
62- def run_command():
63- # code made compatible to run in Py2 or Py3 environment
64- # to support back-porting
65- request_has_commands = False
66- if six.PY2:
67- request_has_commands = request.form.has_key('commands')
68- else:
69- request_has_commands = 'commands' in request.form
70-
71- if request_has_commands:
72- cmds = request.form['commands'].split(';')
73- else:
74- cmds = [ request.form['command'] ]
75- for cmd in cmds:
76- sys.stdout.write("%s\\ n" % cmd)
77- sys.stdout.flush()
78- return "OK\\ n"
7954
80- if __name__ == '__main__':
81- # with werkzeug 3.x the default size of max_form_memory_size
82- # is 500K. Routes reach a bit beyond that and the client
83- # receives HTTP 413.
84- # Configure the max size to 4 MB to be safe.
85- if not six.PY2:
86- from werkzeug import Request
87- max_content_length = 4 * 1024 * 1024
88- Request.max_content_length = max_content_length
89- Request.max_form_memory_size = max_content_length
90- Request.max_form_parts = max_content_length
91- app.run(host='0.0.0.0', port=sys.argv[1])
55+ class route_handler(tornado.web.RequestHandler):
56+ def post(self):
57+ # Read the form data
58+ command = self.get_body_argument("command", None)
59+ commands = self.get_body_argument("commands", None)
60+
61+ # Process and print the command values
62+ if command:
63+ out_str = "{}\\ n".format(command)
64+ sys.stdout.write(out_str)
65+ if commands:
66+ values = commands.split(';')
67+ for value in values:
68+ out_str = "{}\\ n".format(value)
69+ sys.stdout.write(out_str)
70+
71+ sys.stdout.flush()
72+ self.write("OK\\ n")
73+
74+ def make_app():
75+ return tornado.web.Application([
76+ (r"/upload", UploadHandler),
77+ ])
78+
79+ if __name__ == "__main__":
80+ app = tornado.web.Application([
81+ ("/", route_handler),
82+ ])
83+ app.listen(int(sys.argv[1]))
84+ tornado.ioloop.IOLoop.current().start()
9285'''
9386
94- dump_config_tmpl = '''\
87+ exabgp3_dump_config_tmpl = '''\
9588 process dump {
89+ run /usr/bin/python {{ dump_script }};
9690 encoder json;
9791 receive {
9892 parsed;
9993 update;
10094 }
101- run /usr/bin/python {{ dump_script }};
10295 }
10396'''
10497
@@ -132,6 +125,14 @@ def run_command():
132125# Example configs are available here
133126# https://github.com/Exa-Networks/exabgp/tree/master/etc/exabgp
134127# Look for sample for a given section for details
128+
129+ exabgp4_dump_config_tmpl = '''\
130+ process dump {
131+ run /usr/bin/python {{ dump_script }};
132+ encoder json;
133+ }
134+ '''
135+
135136exabgp4_config_template = '''\
136137 {{ dump_config }}
137138process http-api {
@@ -149,15 +150,34 @@ def run_command():
149150 passive;
150151 listen {{ listen_port }};
151152 {%- endif %}
152- api {
153+ api http_api {
153154 processes [ http-api ];
154155 }
156+ {%- if dump_config %}
157+ api dumper {
158+ processes [ dump ];
159+ receive {
160+ parsed;
161+ update;
162+ }
163+ }
164+ {%- endif %}
155165}
156166'''
157167
158- exabgp_supervisord_conf_tmpl = '''\
168+ # Unlike in ExaBGP V3.x, in V4+ the process API is expected to acknowledge
169+ # with 'done' or 'error' string back to ExaBGP. Else the pipe becomes blocked
170+ # and ExaBGP will hang. Alternatively the acknowledgement can be disabled.
171+ # https://github.com/Exa-Networks/exabgp/wiki/Migration-from-3.4-to-4.x#api
172+ exabgp_v4_env_tmpl = '''\
173+ [exabgp.api]
174+ ack = false
175+ '''
176+
177+ exabgp_supervisord_conf_tmpl_p1 = '''\
159178 [program:exabgp-{{ name }}]
160- command=/usr/local/bin/exabgp /etc/exabgp/{{ name }}.conf
179+ '''
180+ exabgp_supervisord_conf_tmpl_p3 = '''\
161181 stdout_logfile=/tmp/exabgp-{{ name }}.out.log
162182stderr_logfile=/tmp/exabgp-{{ name }}.err.log
163183stdout_logfile_maxbytes=10000000
@@ -170,6 +190,18 @@ def run_command():
170190startsecs=1
171191numprocs=1
172192'''
193+ exabgp_supervisord_conf_tmpl_p2_v3 = '''\
194+ command=/usr/local/bin/exabgp /etc/exabgp/{{ name }}.conf
195+ '''
196+ exabgp_supervisord_conf_tmpl_p2_v3_debug = '''\
197+ command=/usr/local/bin/exabgp --debug /etc/exabgp/{{ name }}.conf
198+ '''
199+ exabgp_supervisord_conf_tmpl_p2_v4 = '''\
200+ command=/usr/local/bin/exabgp --env /etc/exabgp/exabgp.env /etc/exabgp/{{ name }}.conf
201+ '''
202+ exabgp_supervisord_conf_tmpl_p2_v4_debug = '''\
203+ command=/usr/local/bin/exabgp --debug --env /etc/exabgp/exabgp.env /etc/exabgp/{{ name }}.conf
204+ '''
173205
174206
175207def exec_command (module , cmd , ignore_error = False , msg = "executing command" ):
@@ -234,8 +266,12 @@ def setup_exabgp_conf(name, router_id, local_ip, peer_ip, local_asn, peer_asn, p
234266
235267 dump_config = ""
236268 if dump_script :
237- dump_config = jinja2 .Template (
238- dump_config_tmpl ).render (dump_script = dump_script )
269+ if six .PY2 :
270+ dump_config = jinja2 .Template (
271+ exabgp3_dump_config_tmpl ).render (dump_script = dump_script )
272+ else :
273+ dump_config = jinja2 .Template (
274+ exabgp4_dump_config_tmpl ).render (dump_script = dump_script )
239275
240276 # backport friendly checking; not required if everything is Py3
241277 t = None
@@ -259,14 +295,42 @@ def setup_exabgp_conf(name, router_id, local_ip, peer_ip, local_asn, peer_asn, p
259295 out_file .write (data )
260296
261297
298+ def setup_exabgp_env ():
299+ try :
300+ os .mkdir ("/etc/exabgp" , 0o755 )
301+ except OSError :
302+ pass
303+ with open ("/etc/exabgp/exabgp.env" , 'w' ) as out_file :
304+ out_file .write (exabgp_v4_env_tmpl )
305+
306+
262307def remove_exabgp_conf (name ):
263308 try :
264309 os .remove ("/etc/exabgp/%s.conf" % name )
265310 except Exception :
266311 pass
267312
268313
269- def setup_exabgp_supervisord_conf (name ):
314+ def setup_exabgp_supervisord_conf (name , debug = False ):
315+ exabgp_supervisord_conf_tmpl = None
316+ if six .PY2 :
317+ if debug :
318+ exabgp_supervisord_conf_tmpl = exabgp_supervisord_conf_tmpl_p1 + \
319+ exabgp_supervisord_conf_tmpl_p2_v3_debug + \
320+ exabgp_supervisord_conf_tmpl_p3
321+ else :
322+ exabgp_supervisord_conf_tmpl = exabgp_supervisord_conf_tmpl_p1 + \
323+ exabgp_supervisord_conf_tmpl_p2_v3 + \
324+ exabgp_supervisord_conf_tmpl_p3
325+ else :
326+ if debug :
327+ exabgp_supervisord_conf_tmpl = exabgp_supervisord_conf_tmpl_p1 + \
328+ exabgp_supervisord_conf_tmpl_p2_v4_debug + \
329+ exabgp_supervisord_conf_tmpl_p3
330+ else :
331+ exabgp_supervisord_conf_tmpl = exabgp_supervisord_conf_tmpl_p1 + \
332+ exabgp_supervisord_conf_tmpl_p2_v4 + \
333+ exabgp_supervisord_conf_tmpl_p3
270334 t = jinja2 .Template (exabgp_supervisord_conf_tmpl )
271335 data = t .render (name = name )
272336 with open ("/etc/supervisor/conf.d/exabgp-%s.conf" % name , 'w' ) as out_file :
@@ -302,7 +366,8 @@ def main():
302366 peer_asn = dict (required = False , type = 'int' ),
303367 port = dict (required = False , type = 'int' , default = 5000 ),
304368 dump_script = dict (required = False , type = 'str' , default = None ),
305- passive = dict (required = False , type = 'bool' , default = False )
369+ passive = dict (required = False , type = 'bool' , default = False ),
370+ debug = dict (required = False , type = 'bool' , default = False )
306371 ),
307372 supports_check_mode = False )
308373
@@ -316,32 +381,35 @@ def main():
316381 port = module .params ['port' ]
317382 dump_script = module .params ['dump_script' ]
318383 passive = module .params ['passive' ]
384+ debug = module .params ['debug' ]
319385
320386 setup_exabgp_processor ()
387+ if not six .PY2 :
388+ setup_exabgp_env ()
321389
322390 result = {}
323391 try :
324392 if state == 'started' :
325393 setup_exabgp_conf (name , router_id , local_ip , peer_ip , local_asn ,
326394 peer_asn , port , dump_script = dump_script , passive = passive )
327- setup_exabgp_supervisord_conf (name )
395+ setup_exabgp_supervisord_conf (name , debug = debug )
328396 refresh_supervisord (module )
329397 start_exabgp (module , name )
330398 elif state == 'restarted' :
331399 setup_exabgp_conf (name , router_id , local_ip , peer_ip , local_asn ,
332400 peer_asn , port , dump_script = dump_script , passive = passive )
333- setup_exabgp_supervisord_conf (name )
401+ setup_exabgp_supervisord_conf (name , debug = debug )
334402 refresh_supervisord (module )
335403 restart_exabgp (module , name )
336404 elif state == 'present' :
337405 setup_exabgp_conf (name , router_id , local_ip , peer_ip , local_asn ,
338406 peer_asn , port , dump_script = dump_script , passive = passive )
339- setup_exabgp_supervisord_conf (name )
407+ setup_exabgp_supervisord_conf (name , debug = debug )
340408 refresh_supervisord (module )
341409 elif state == 'configure' :
342410 setup_exabgp_conf (name , router_id , local_ip , peer_ip , local_asn ,
343411 peer_asn , port , dump_script = dump_script , passive = passive )
344- setup_exabgp_supervisord_conf (name )
412+ setup_exabgp_supervisord_conf (name , debug = debug )
345413 elif state == 'stopped' :
346414 stop_exabgp (module , name )
347415 elif state == 'absent' :
0 commit comments