def main(): options = docopt.docopt(usage, help=False) major = int(sys.version[0]) minor = int(sys.version[2]) if major != 2 or minor < 5: sys.exit( 'This program can not work (is not tested) with your python version (< 2.5 or >= 3.0)' ) if options["--version"]: print 'ExaBGP : %s' % version print 'Python : %s' % sys.version.replace('\n', ' ') print 'Uname : %s' % ' '.join(platform.uname()[:5]) sys.exit(0) if options["--folder"]: folder = os.path.realpath(os.path.normpath(options["--folder"])) elif sys.argv[0].endswith('/bin/exabgp'): folder = sys.argv[0][:-len('/bin/exabgp')] + '/etc/exabgp' elif sys.argv[0].endswith('/sbin/exabgp'): folder = sys.argv[0][:-len('/sbin/exabgp')] + '/etc/exabgp' else: folder = '/etc/exabgp' os.environ['EXABGP_ETC'] = folder # This is not most pretty if options["--run"]: sys.argv = sys.argv[sys.argv.index('--run') + 1:] if sys.argv[0] == 'healthcheck': from exabgp.application import run_healthcheck run_healthcheck() elif sys.argv[0] == 'cli': from exabgp.application import run_cli run_cli() else: print(usage) sys.exit(0) return envfile = 'exabgp.env' if not options["--env"] else options["--env"] if not envfile.startswith('/'): envfile = '%s/%s' % (folder, envfile) from exabgp.configuration.setup import environment try: env = environment.setup(envfile) except environment.Error, exc: print usage print '\nconfiguration issue,', str(exc) sys.exit(1)
def main(): options = docopt.docopt(usage, help=False) options['--env'] = '' # exabgp compatibility root = root_folder(options, [ '/bin/exabgpcli', '/sbin/exabgpcli', '/lib/exabgp/application/cli.py' ]) etc = root + '/etc/exabgp' envfile = get_envfile(options, etc) env = get_env(envfile) pipename = env['api']['pipename'] if options['--help']: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) if not options['<command>']: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) command = ' '.join(options['<command>']) pipes = named_pipe(root) if len(pipes) != 1: sys.stdout.write( 'could not find ExaBGP\'s named pipes (%s.in and %s.out) for the cli\n' % (pipename, pipename)) sys.stdout.write( 'we scanned the following folders (the number is your PID):\n - ') sys.stdout.write('\n - '.join(pipes)) sys.stdout.flush() sys.exit(1) send = pipes[0] + pipename + '.in' recv = pipes[0] + pipename + '.out' if not check_fifo(send): sys.stdout.write( 'could not find write named pipe to connect to ExaBGP') sys.stdout.flush() sys.exit(1) if not check_fifo(recv): sys.stdout.write('could not find read named pipe to connect to ExaBGP') sys.stdout.flush() sys.exit(1) def write_timeout(signum, frame): sys.stderr.write('could not send command to ExaBGP') sys.stderr.flush() sys.exit(1) signal.signal(signal.SIGALRM, write_timeout) signal.alarm(2) try: writer = os.open(send, os.O_WRONLY | os.O_EXCL) os.write(writer, command.encode('utf-8') + b'\n') os.close(writer) except OSError as exc: if exc.errno == errno.ENXIO: sys.stdout.write( 'ExaBGP is not running / using the configured named pipe') sys.stdout.flush() sys.exit(1) sys.stdout.write('could not communicate with ExaBGP') sys.stdout.flush() sys.exit(1) except IOError as exc: sys.stdout.write('could not communicate with ExaBGP') sys.stdout.flush() sys.exit(1) signal.alarm(0) if command == 'reset': sys.exit(0) def read_timeout(signum, frame): sys.stderr.write('could not read answer to ExaBGP') sys.stderr.flush() sys.exit(1) signal.signal(signal.SIGALRM, read_timeout) try: signal.alarm(5) reader = os.open(recv, os.O_RDONLY | os.O_EXCL) signal.alarm(0) buf = b'' done = False while not done: try: raw = os.read(reader, 4096) buf += raw while b'\n' in buf: line, buf = buf.split(b'\n', 1) if line == b'done': done = True break if line == b'shutdown': sys.stderr.write( 'ExaBGP is shutting down, command aborted\n') sys.stderr.flush() done = True break if line == b'error': done = True sys.stderr.write('ExaBGP returns an error\n') sys.stderr.flush() break sys.stdout.write('%s\n' % line.decode()) sys.stdout.flush() select.select([reader], [], [], 0.01) except OSError as exc: if exc.errno in error.block: break except IOError as exc: if exc.errno in error.block: break os.close(reader) sys.exit(0) except IOError: sys.stdout.write('could not read answer from ExaBGP') sys.stdout.flush() except OSError: sys.stdout.write('could not read answer from ExaBGP') sys.stdout.flush()
def main (): options = docopt.docopt(usage, help=False) options['--env'] = '' # exabgp compatibility root = root_folder(options,['/bin/exabgpcli','/sbin/exabgpcli','/lib/exabgp/application/cli.py']) etc = root + '/etc/exabgp' envfile = get_envfile(options,etc) env = get_env(envfile) pipename = env['api']['pipename'] if options['--help']: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) if not options['<command>']: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) command = ' '.join(options['<command>']) pipes = named_pipe(root) if len(pipes) != 1: sys.stdout.write('Could not find ExaBGP\'s named pipes (%s.in and %s.out) for the cli in any of ' % (pipename,pipename) + ', '.join(pipes)) sys.stdout.flush() sys.exit(1) send = pipes[0] + pipename + '.in' recv = pipes[0] + pipename + '.out' if not check_fifo(send): sys.stdout.write('could not find write named pipe to connect to ExaBGP') sys.stdout.flush() sys.exit(1) if not check_fifo(recv): sys.stdout.write('could not find read named pipe to connect to ExaBGP') sys.stdout.flush() sys.exit(1) def write_timeout(signum, frame): sys.stderr.write('could not send command to ExaBGP') sys.stderr.flush() sys.exit(1) signal.signal(signal.SIGALRM, write_timeout) signal.alarm(2) try: writer = os.open(send, os.O_WRONLY | os.O_EXCL) os.write(writer,command + '\n') os.close(writer) except OSError as exc: if exc.errno == errno.ENXIO: sys.stdout.write('ExaBGP is not running / using the configured named pipe') sys.stdout.flush() sys.exit(1) sys.stdout.write('could not communicate with ExaBGP') sys.stdout.flush() sys.exit(1) except IOError as exc: sys.stdout.write('could not communicate with ExaBGP') sys.stdout.flush() sys.exit(1) signal.alarm(0) if command == 'reset': sys.exit(0) def read_timeout(signum, frame): sys.stderr.write('could not read answer to ExaBGP') sys.stderr.flush() sys.exit(1) signal.signal(signal.SIGALRM, read_timeout) try: signal.alarm(5) reader = os.open(recv, os.O_RDONLY | os.O_EXCL) signal.alarm(0) buf = '' done = False while not done: try: raw = os.read(reader,4096) buf += raw while '\n' in buf: line,buf = buf.split('\n',1) if line == 'done': done = True break if line == 'shutdown': sys.stderr.write('ExaBGP is shutting down, command aborted\n') sys.stderr.flush() done = True break if line == 'error': done = True sys.stderr.write('ExaBGP returns an error\n') sys.stderr.flush() break sys.stdout.write('%s\n' % line) sys.stdout.flush() select.select([reader],[],[],0.01) except OSError as exc: if exc.errno in error.block: break except IOError as exc: if exc.errno in error.block: break os.close(reader) sys.exit(0) except IOError: sys.stdout.write('could not read answer from ExaBGP') sys.stdout.flush() except OSError: sys.stdout.write('could not read answer from ExaBGP') sys.stdout.flush()
def main (): options = docopt.docopt(usage, help=False) if options['--env'] is None: options['--env'] = '' root = root_folder(options,['/bin/exabgpcli','/sbin/exabgpcli','/lib/exabgp/application/cli.py']) prefix = '' if root == '/usr' else root etc = prefix + '/etc/exabgp' envfile = get_envfile(options,etc) env = get_env(envfile) pipename = env['api']['pipename'] if options['--help']: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) if not options['<command>']: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) command = ' '.join(options['<command>']) pipes = named_pipe(root, pipename) if len(pipes) != 1: sys.stdout.write('could not find ExaBGP\'s named pipes (%s.in and %s.out) for the cli\n' % (pipename, pipename)) sys.stdout.write('we scanned the following folders (the number is your PID):\n - ') sys.stdout.write('\n - '.join(pipes)) sys.stdout.flush() sys.exit(1) send = pipes[0] + pipename + '.in' recv = pipes[0] + pipename + '.out' if not check_fifo(send): sys.stdout.write('could not find write named pipe to connect to ExaBGP') sys.stdout.flush() sys.exit(1) if not check_fifo(recv): sys.stdout.write('could not find read named pipe to connect to ExaBGP') sys.stdout.flush() sys.exit(1) reader = open_reader(recv) rbuffer = b'' start = time.time() while True: try: while select.select([reader], [], [], 0) != ([], [], []): rbuffer += os.read(reader,4096) rbuffer = rbuffer[-AnswerStream.buffer_size:] except IOError as exc: if exc.errno in error.block: continue sys.stdout.write('could not clear named pipe from potential previous command data (%s)' % str(exc)) sys.stdout.flush() sys.exit(1) except OSError as exc: if exc.errno in error.block: continue sys.stdout.write('could not clear named pipe from potential previous command data (%s)' % str(exc)) sys.stdout.write(exc) sys.stdout.flush() sys.exit(1) # we are not ack'ing the command and probably have read all there is if time.time() > start + 1.5: break # we read nothing, nothing to do if not rbuffer: break # we read some data but it is not ending by a new line (ie: not a command completion) if rbuffer[-1] != 10: # \n continue if AnswerStream.done.endswith(rbuffer[-len(AnswerStream.done):]): break if AnswerStream.error.endswith(rbuffer[-len(AnswerStream.error):]): break if AnswerStream.shutdown.endswith(rbuffer[-len(AnswerStream.shutdown):]): break renamed = [''] for pos, token in enumerate(command.split()): for nickname, name, match in ( ('a', 'announce', lambda pos, pre: pos == 0 or pre.count('.') == 3 or pre.count(':') != 0), ('a', 'attributes', lambda pos, pre: pre[-1] == 'announce' or pre[-1] == 'withdraw'), ('c', 'configuration', lambda pos, pre: True), ('e', 'eor', lambda pos, pre: pre[-1] == 'announce'), ('e', 'extensive', lambda _, pre: 'show' in pre), ('f', 'flow', lambda pos, pre: pre[-1] == 'announce' or pre[-1] == 'withdraw'), ('f', 'flush', lambda pos, pre: pos == 0 or pre.count('.') == 3 or pre.count(':') != 0), ('h', 'help', lambda pos, pre: pos == 0), ('i', 'in', lambda pos, pre: pre[-1] == 'adj-rib'), ('n', 'neighbor', lambda pos, pre: pos == 0 or pre[-1] == 'show'), ('r', 'route', lambda pos, pre: pre == 'announce' or pre == 'withdraw'), ('rr', 'route-refresh', lambda _, pre: pre == 'announce'), ('s', 'show', lambda pos, pre: pos == 0), ('t', 'teardown', lambda pos, pre: pos == 0 or pre.count('.') == 3 or pre.count(':') != 0), ('s', 'summary', lambda pos, pre: pos != 0), ('v', 'vps', lambda pos, pre: pre[-1] == 'announce' or pre[-1] == 'withdraw'), ('o', 'operation', lambda pos, pre: pre[-1] == 'announce'), ('o', 'out', lambda pos, pre: pre[-1] == 'adj-rib'), ('a', 'adj-rib', lambda pos, pre: pre[-1] in ['clear','flush','show']), ('w', 'withdraw', lambda pos, pre: pos == 0 or pre.count('.') == 3 or pre.count(':') != 0), ('w', 'watchdog', lambda pos, pre: pre[-1] == 'announce' or pre[-1] == 'withdraw'), ('neighbour', 'neighbor', lambda pos, pre: True), ('neigbour', 'neighbor', lambda pos, pre: True), ('neigbor', 'neighbor', lambda pos, pre: True), ): if (token == nickname or name.startswith(token)) and match(pos,renamed): renamed.append(name) break else: renamed.append(token) sending = ' '.join(renamed).strip() # This does not change the behaviour for well formed command if sending != command: print('command: %s' % sending) writer = open_writer(send) try: os.write(writer, sending.encode('utf-8') + b'\n') os.close(writer) except IOError as exc: sys.stdout.write('could not send command to ExaBGP (%s)' % str(exc)) sys.stdout.flush() sys.exit(1) except OSError as exc: sys.stdout.write('could not send command to ExaBGP (%s)' % str(exc)) sys.stdout.flush() sys.exit(1) if command == 'reset': sys.exit(0) waited = 0.0 buf = b'' done = False done_time_diff = 0.5 while not done: try: r, _, _ = select.select([reader], [], [], 0.01) except OSError as exc: if exc.errno in error.block: continue sys.stdout.write('could not get answer from ExaBGP (%s)' % str(exc)) sys.stdout.flush() sys.exit(1) except IOError as exc: if exc.errno in error.block: continue sys.stdout.write('could not get answer from ExaBGP (%s)' % str(exc)) sys.stdout.flush() sys.exit(1) if waited > 5.0: sys.stderr.write('\n') sys.stderr.write('warning: no end of command message received\n') sys.stderr.write('warning: normal if exabgp.api.ack is set to false otherwise some data may get stuck on the pipe\n') sys.stderr.write('warning: otherwise it may cause exabgp reactor to block\n') sys.exit(0) elif not r: waited += 0.01 continue else: waited = 0.0 try: raw = os.read(reader, 4096) except OSError as exc: if exc.errno in error.block: continue sys.stdout.write('could not read answer from ExaBGP (%s)' % str(exc)) sys.stdout.flush() sys.exit(1) except IOError as exc: if exc.errno in error.block: continue sys.stdout.write('could not read answer from ExaBGP (%s)' % str(exc)) sys.stdout.flush() sys.exit(1) buf += raw while b'\n' in buf: line,buf = buf.split(b'\n',1) string = line.decode() if string == Answer.done: done = True break if string == Answer.shutdown: sys.stderr.write('ExaBGP is shutting down, command aborted\n') sys.stderr.flush() done = True break if string == Answer.error: done = True sys.stderr.write('ExaBGP returns an error (see ExaBGP\'s logs for more information)\n') sys.stderr.write('use help for a list of available commands\n') sys.stderr.flush() break sys.stdout.write('%s\n' % string) sys.stdout.flush() if not env.get('api').get('ack') and not raw.decode(): this_moment = time.time() recv_epoch_time = os.path.getmtime(recv) time_diff = this_moment - recv_epoch_time if time_diff >= done_time_diff: done = True try: os.close(reader) except Exception: pass sys.exit(0)
def main(): options = docopt.docopt(usage, help=False) major = int(sys.version[0]) minor = int(sys.version[2]) if major != 2 or minor < 5: sys.exit( 'This program can not work (is not tested) with your python version (< 2.5 or >= 3.0)' ) if options["--version"]: print('ExaBGP : %s' % version) print('Python : %s' % sys.version.replace('\n', ' ')) print('Uname : %s' % ' '.join(platform.uname()[:5])) sys.exit(0) if options["--folder"]: folder = os.path.realpath(os.path.normpath(options["--folder"])) elif sys.argv[0].endswith('/bin/exabgp'): folder = sys.argv[0][:-len('/bin/exabgp')] + '/etc/exabgp' elif sys.argv[0].endswith('/sbin/exabgp'): folder = sys.argv[0][:-len('/sbin/exabgp')] + '/etc/exabgp' else: folder = '/etc/exabgp' os.environ['EXABGP_ETC'] = folder # This is not most pretty if options["--run"]: sys.argv = sys.argv[sys.argv.index('--run') + 1:] if sys.argv[0] == 'healthcheck': from exabgp.application import run_healthcheck run_healthcheck() elif sys.argv[0] == 'cli': from exabgp.application import run_cli run_cli() else: print(usage) sys.exit(0) return envfile = 'exabgp.env' if not options["--env"] else options["--env"] if not envfile.startswith('/'): envfile = '%s/%s' % (folder, envfile) from exabgp.configuration.setup import environment try: env = environment.setup(envfile) except environment.Error as exc: print(usage) print('\nconfiguration issue,', str(exc)) sys.exit(1) # Must be done before setting the logger as it modify its behaviour if options["--debug"]: env.log.all = True env.log.level = syslog.LOG_DEBUG logger = Logger() named_pipe = os.environ.get('NAMED_PIPE', '') if named_pipe: from exabgp.application.control import main as control control(named_pipe) sys.exit(0) if options["--decode"]: decode = ''.join(options["--decode"]).replace(':', '').replace(' ', '') if not is_bgp(decode): print(usage) print('Environment values are:\n' + '\n'.join(' - %s' % _ for _ in environment.default())) print("") print("The BGP message must be an hexadecimal string.") print("") print("All colons or spaces are ignored, for example:") print("") print(" --decode 001E0200000007900F0003000101") print(" --decode 001E:02:0000:0007:900F:0003:0001:01") print( " --decode FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF001E0200000007900F0003000101" ) print( " --decode FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001E:02:0000:0007:900F:0003:0001:01" ) print( " --decode 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 001E02 00000007900F0003000101'" ) sys.exit(1) else: decode = '' # Make sure our child has a named pipe name if env.api.file: os.environ['NAMED_PIPE'] = env.api.file duration = options["--signal"] if duration and duration.isdigit(): pid = os.fork() if pid: import time import signal try: time.sleep(int(duration)) os.kill(pid, signal.SIGUSR1) except KeyboardInterrupt: pass try: pid, code = os.wait() sys.exit(code) except KeyboardInterrupt: try: pid, code = os.wait() sys.exit(code) except Exception: sys.exit(0) if options["--help"]: print(usage) print('Environment values are:\n' + '\n'.join(' - %s' % _ for _ in environment.default())) sys.exit(0) if options["--decode"]: env.log.parser = True env.debug.route = decode env.tcp.bind = '' if options["--profile"]: env.profile.enable = True if options["--profile"].lower() in ['1', 'true']: env.profile.file = True elif options["--profile"].lower() in ['0', 'false']: env.profile.file = False else: env.profile.file = options["--profile"] if envfile and not os.path.isfile(envfile): comment = 'environment file missing\ngenerate it using "exabgp --fi > %s"' % envfile else: comment = '' if options["--full-ini"] or options["--fi"]: for line in environment.iter_ini(): print(line) sys.exit(0) if options["--full-env"] or options["--fe"]: print() for line in environment.iter_env(): print(line) sys.exit(0) if options["--diff-ini"] or options["--di"]: for line in environment.iter_ini(True): print(line) sys.exit(0) if options["--diff-env"] or options["--de"]: for line in environment.iter_env(True): print(line) sys.exit(0) if options["--once"]: env.tcp.once = True if options["--pdb"]: # The following may fail on old version of python (but is required for debug.py) os.environ['PDB'] = 'true' env.debug.pdb = True if options["--test"]: env.debug.selfcheck = True env.log.parser = True if options["--memory"]: env.debug.memory = True configurations = [] # check the file only once that we have parsed all the command line options and allowed them to run if options["<configuration>"]: for f in options["<configuration>"]: normalised = os.path.realpath(os.path.normpath(f)) if os.path.isfile(normalised): configurations.append(normalised) continue if f.startswith('etc/exabgp'): normalised = os.path.join(folder, f[11:]) if os.path.isfile(normalised): configurations.append(normalised) continue logger.configuration( 'one of the arguments passed as configuration is not a file (%s)' % f, 'error') sys.exit(1) else: print(usage) print('Environment values are:\n' + '\n'.join(' - %s' % _ for _ in environment.default())) print('\nno configuration file provided') sys.exit(1) from exabgp.bgp.message.update.attribute import Attribute Attribute.caching = env.cache.attributes if env.debug.rotate or len(configurations) == 1: run(env, comment, configurations) if not (env.log.destination in ('syslog', 'stdout', 'stderr') or env.log.destination.startswith('host:')): logger.configuration( 'can not log to files when running multiple configuration (as we fork)', 'error') sys.exit(1) try: # run each configuration in its own process pids = [] for configuration in configurations: pid = os.fork() if pid == 0: run(env, comment, [configuration], os.getpid()) else: pids.append(pid) # If we get a ^C / SIGTERM, ignore just continue waiting for our child process import signal signal.signal(signal.SIGINT, signal.SIG_IGN) # wait for the forked processes for pid in pids: os.waitpid(pid, 0) except OSError as exc: logger.reactor( 'Can not fork, errno %d : %s' % (exc.errno, exc.strerror), 'critical') sys.exit(1)
def main(): options = docopt.docopt(usage, help=False) options['--env'] = '' # exabgp compatibility root = root_folder(options, [ '/bin/exabgpcli', '/sbin/exabgpcli', '/lib/exabgp/application/cli.py' ]) prefix = '' if root == '/usr' else root etc = prefix + '/etc/exabgp' envfile = get_envfile(options, etc) env = get_env(envfile) pipename = env['api']['pipename'] if options['--help']: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) if not options['<command>']: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) command = ' '.join(options['<command>']) pipes = named_pipe(root) if len(pipes) != 1: sys.stdout.write( 'could not find ExaBGP\'s named pipes (%s.in and %s.out) for the cli\n' % (pipename, pipename)) sys.stdout.write( 'we scanned the following folders (the number is your PID):\n - ') sys.stdout.write('\n - '.join(pipes)) sys.stdout.flush() sys.exit(1) send = pipes[0] + pipename + '.in' recv = pipes[0] + pipename + '.out' if not check_fifo(send): sys.stdout.write( 'could not find write named pipe to connect to ExaBGP') sys.stdout.flush() sys.exit(1) if not check_fifo(recv): sys.stdout.write('could not find read named pipe to connect to ExaBGP') sys.stdout.flush() sys.exit(1) def write_timeout(signum, frame): sys.stderr.write('could not send command to ExaBGP') sys.stderr.flush() sys.exit(1) buffer = '' start = time.time() try: reader = os.open(recv, os.O_RDONLY | os.O_EXCL | os.O_NONBLOCK) while True: while select.select([reader], [], [], 0) != ([], [], []): buffer += os.read(reader, 4096) buffer = buffer[-AnswerStream.buffer_size:] # we read nothing, nothing to do if not buffer: break # we read some data but it is not ending by a new line (ie: not a command completion) if buffer[-1] != '\n': continue if AnswerStream.done.endswith(buffer[-len(AnswerStream.done):]): break if AnswerStream.error.endswith(buffer[-len(AnswerStream.error):]): break if AnswerStream.shutdown.endswith( buffer[-len(AnswerStream.shutdown):]): break # we are not ack'ing the command and probably have read all there is if time.time() > start + 1.5: break except Exception as exc: sys.stdout.write( 'could not clear named pipe from potential previous command data') sys.stdout.write(exc) sys.stdout.flush() signal.signal(signal.SIGALRM, write_timeout) signal.alarm(2) try: writer = os.open(send, os.O_WRONLY | os.O_EXCL) os.write(writer, command.encode('utf-8') + b'\n') os.close(writer) except OSError as exc: if exc.errno == errno.ENXIO: sys.stdout.write( 'ExaBGP is not running / using the configured named pipe') sys.stdout.flush() sys.exit(1) sys.stdout.write('could not communicate with ExaBGP') sys.stdout.flush() sys.exit(1) except IOError as exc: sys.stdout.write('could not communicate with ExaBGP') sys.stdout.flush() sys.exit(1) signal.alarm(0) if command == 'reset': sys.exit(0) def read_timeout(signum, frame): sys.stderr.write('could not read answer to ExaBGP') sys.stderr.flush() sys.exit(1) signal.signal(signal.SIGALRM, read_timeout) try: signal.alarm(5) reader = os.open(recv, os.O_RDONLY | os.O_EXCL) signal.alarm(0) buf = b'' done = False while not done: try: raw = os.read(reader, 4096) buf += raw while b'\n' in buf: line, buf = buf.split(b'\n', 1) string = line.decode() if string == Answer.done: done = True break if string == Answer.shutdown: sys.stderr.write( 'ExaBGP is shutting down, command aborted\n') sys.stderr.flush() done = True break if string == Answer.error: done = True sys.stderr.write( 'ExaBGP returns an error (see ExaBGP\'s logs for more information)\n' ) sys.stderr.write( 'use help for a list of available commands\n') sys.stderr.flush() break sys.stdout.write('%s\n' % string) sys.stdout.flush() select.select([reader], [], [], 0.01) except OSError as exc: if exc.errno in error.block: break except IOError as exc: if exc.errno in error.block: break os.close(reader) sys.exit(0) except IOError: sys.stdout.write('could not read answer from ExaBGP') sys.stdout.flush() except OSError: sys.stdout.write('could not read answer from ExaBGP') sys.stdout.flush()
def main (): options = docopt.docopt(usage, help=False) options['--env'] = '' # exabgp compatibility root = root_folder(options,['/bin/exabgpcli','/sbin/exabgpcli','/lib/exabgp/application/cli.py']) prefix = '' if root == '/usr' else root etc = prefix + '/etc/exabgp' envfile = get_envfile(options,etc) env = get_env(envfile) pipename = env['api']['pipename'] if options['--help']: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) if not options['<command>']: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) command = ' '.join(options['<command>']) pipes = named_pipe(root) if len(pipes) != 1: sys.stdout.write('could not find ExaBGP\'s named pipes (%s.in and %s.out) for the cli\n' % (pipename, pipename)) sys.stdout.write('we scanned the following folders (the number is your PID):\n - ') sys.stdout.write('\n - '.join(pipes)) sys.stdout.flush() sys.exit(1) send = pipes[0] + pipename + '.in' recv = pipes[0] + pipename + '.out' if not check_fifo(send): sys.stdout.write('could not find write named pipe to connect to ExaBGP') sys.stdout.flush() sys.exit(1) if not check_fifo(recv): sys.stdout.write('could not find read named pipe to connect to ExaBGP') sys.stdout.flush() sys.exit(1) def write_timeout(signum, frame): sys.stderr.write('could not send command to ExaBGP') sys.stderr.flush() sys.exit(1) buffer = '' start = time.time() try: reader = os.open(recv, os.O_RDONLY | os.O_EXCL | os.O_NONBLOCK) while True: while select.select([reader], [], [], 0) != ([], [], []): buffer += os.read(reader,4096) buffer = buffer[-AnswerStream.buffer_size:] # we read nothing, nothing to do if not buffer: break # we read some data but it is not ending by a new line (ie: not a command completion) if buffer[-1] != '\n': continue if AnswerStream.done.endswith(buffer[-len(AnswerStream.done):]): break if AnswerStream.error.endswith(buffer[-len(AnswerStream.error):]): break if AnswerStream.shutdown.endswith(buffer[-len(AnswerStream.shutdown):]): break # we are not ack'ing the command and probably have read all there is if time.time() > start + 1.5: break except Exception as exc: sys.stdout.write('could not clear named pipe from potential previous command data') sys.stdout.write(exc) sys.stdout.flush() signal.signal(signal.SIGALRM, write_timeout) signal.alarm(2) try: writer = os.open(send, os.O_WRONLY | os.O_EXCL) os.write(writer,command.encode('utf-8') + b'\n') os.close(writer) except OSError as exc: if exc.errno == errno.ENXIO: sys.stdout.write('ExaBGP is not running / using the configured named pipe') sys.stdout.flush() sys.exit(1) sys.stdout.write('could not communicate with ExaBGP') sys.stdout.flush() sys.exit(1) except IOError as exc: sys.stdout.write('could not communicate with ExaBGP') sys.stdout.flush() sys.exit(1) signal.alarm(0) if command == 'reset': sys.exit(0) def read_timeout(signum, frame): sys.stderr.write('could not read answer to ExaBGP') sys.stderr.flush() sys.exit(1) signal.signal(signal.SIGALRM, read_timeout) try: signal.alarm(5) reader = os.open(recv, os.O_RDONLY | os.O_EXCL) signal.alarm(0) buf = b'' done = False while not done: try: raw = os.read(reader,4096) buf += raw while b'\n' in buf: line,buf = buf.split(b'\n',1) string = line.decode() if string == Answer.done: done = True break if string == Answer.shutdown: sys.stderr.write('ExaBGP is shutting down, command aborted\n') sys.stderr.flush() done = True break if string == Answer.error: done = True sys.stderr.write('ExaBGP returns an error (see ExaBGP\'s logs for more information)\n') sys.stderr.write('use help for a list of available commands\n') sys.stderr.flush() break sys.stdout.write('%s\n' % string) sys.stdout.flush() select.select([reader],[],[],0.01) except OSError as exc: if exc.errno in error.block: break except IOError as exc: if exc.errno in error.block: break os.close(reader) sys.exit(0) except IOError: sys.stdout.write('could not read answer from ExaBGP') sys.stdout.flush() except OSError: sys.stdout.write('could not read answer from ExaBGP') sys.stdout.flush()
def main (): major = int(sys.version[0]) minor = int(sys.version[2]) if major <= 2 and minor < 5: sys.stdout.write('This program can not work (is not tested) with your python version (< 2.5)\n') sys.stdout.flush() sys.exit(1) cli_named_pipe = os.environ.get('exabgp_cli_pipe','') if cli_named_pipe: from exabgp.application.control import main as control control(cli_named_pipe) sys.exit(0) options = docopt.docopt(usage, help=False) if options["--run"]: sys.argv = sys.argv[sys.argv.index('--run')+1:] if sys.argv[0] == 'healthcheck': from exabgp.application import run_healthcheck run_healthcheck() elif sys.argv[0] == 'cli': from exabgp.application import run_cli run_cli() else: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) return root = root_folder(options,['/bin/exabgp','/sbin/exabgp','/lib/exabgp/application/bgp.py','/lib/exabgp/application/control.py']) etc = root + '/etc/exabgp' os.environ['EXABGP_ETC'] = etc # This is not most pretty if options["--version"]: sys.stdout.write('ExaBGP : %s\n' % version) sys.stdout.write('Python : %s\n' % sys.version.replace('\n',' ')) sys.stdout.write('Uname : %s\n' % ' '.join(platform.uname()[:5])) sys.stdout.write('Root : %s\n' % root) sys.stdout.flush() sys.exit(0) envfile = get_envfile(options,etc) env = get_env(envfile) # Must be done before setting the logger as it modify its behaviour if options["--debug"]: env.log.all = True env.log.level = syslog.LOG_DEBUG logger = Logger() from exabgp.configuration.setup import environment if options["--decode"]: decode = ''.join(options["--decode"]).replace(':','').replace(' ','') if not is_bgp(decode): sys.stdout.write(usage) sys.stdout.write('Environment values are:\n%s\n\n' % '\n'.join(' - %s' % _ for _ in environment.default())) sys.stdout.write('The BGP message must be an hexadecimal string.\n\n') sys.stdout.write('All colons or spaces are ignored, for example:\n\n') sys.stdout.write(' --decode 001E0200000007900F0003000101\n') sys.stdout.write(' --decode 001E:02:0000:0007:900F:0003:0001:01\n') sys.stdout.write(' --decode FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF001E0200000007900F0003000101\n') sys.stdout.write(' --decode FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001E:02:0000:0007:900F:0003:0001:01\n') sys.stdout.write(' --decode \'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 001E02 00000007900F0003000101\n\'') sys.stdout.flush() sys.exit(1) else: decode = '' duration = options["--signal"] if duration and duration.isdigit(): pid = os.fork() if pid: import time import signal try: time.sleep(int(duration)) os.kill(pid,signal.SIGUSR1) except KeyboardInterrupt: pass try: pid,code = os.wait() sys.exit(code) except KeyboardInterrupt: try: pid,code = os.wait() sys.exit(code) except Exception: sys.exit(0) if options["--help"]: sys.stdout.write(usage) sys.stdout.write('Environment values are:\n' + '\n'.join(' - %s' % _ for _ in environment.default())) sys.stdout.flush() sys.exit(0) if options["--decode"]: env.log.parser = True env.debug.route = decode env.tcp.bind = '' if options["--profile"]: env.profile.enable = True if options["--profile"].lower() in ['1','true']: env.profile.file = True elif options["--profile"].lower() in ['0','false']: env.profile.file = False else: env.profile.file = options["--profile"] if envfile and not os.path.isfile(envfile): comment = 'environment file missing\ngenerate it using "exabgp --fi > %s"' % envfile else: comment = '' if options["--full-ini"] or options["--fi"]: for line in environment.iter_ini(): sys.stdout.write('%s\n' % line) sys.stdout.flush() sys.exit(0) if options["--full-env"] or options["--fe"]: print() for line in environment.iter_env(): sys.stdout.write('%s\n' % line) sys.stdout.flush() sys.exit(0) if options["--diff-ini"] or options["--di"]: for line in environment.iter_ini(True): sys.stdout.write('%s\n' % line) sys.stdout.flush() sys.exit(0) if options["--diff-env"] or options["--de"]: for line in environment.iter_env(True): sys.stdout.write('%s\n' % line) sys.stdout.flush() sys.exit(0) if options["--once"]: env.tcp.once = True if options["--pdb"]: # The following may fail on old version of python (but is required for debug.py) os.environ['PDB'] = 'true' env.debug.pdb = True if options["--test"]: env.debug.selfcheck = True env.log.parser = True if options["--memory"]: env.debug.memory = True configurations = [] # check the file only once that we have parsed all the command line options and allowed them to run if options["<configuration>"]: for f in options["<configuration>"]: normalised = os.path.realpath(os.path.normpath(f)) if os.path.isfile(normalised): configurations.append(normalised) continue if f.startswith('etc/exabgp'): normalised = os.path.join(etc,f[11:]) if os.path.isfile(normalised): configurations.append(normalised) continue logger.debug('one of the arguments passed as configuration is not a file (%s)' % f,'configuration') sys.exit(1) else: sys.stdout.write(usage) sys.stdout.write('Environment values are:\n%s\n\n' % '\n'.join(' - %s' % _ for _ in environment.default())) sys.stdout.write('no configuration file provided') sys.stdout.flush() sys.exit(1) from exabgp.bgp.message.update.attribute import Attribute Attribute.caching = env.cache.attributes if env.debug.rotate or len(configurations) == 1: run(env,comment,configurations,root,options["--validate"]) if not (env.log.destination in ('syslog','stdout','stderr') or env.log.destination.startswith('host:')): logger.error('can not log to files when running multiple configuration (as we fork)','configuration') sys.exit(1) try: # run each configuration in its own process pids = [] for configuration in configurations: pid = os.fork() if pid == 0: run(env,comment,[configuration],root,options["--validate"],os.getpid()) else: pids.append(pid) # If we get a ^C / SIGTERM, ignore just continue waiting for our child process import signal signal.signal(signal.SIGINT, signal.SIG_IGN) # wait for the forked processes for pid in pids: os.waitpid(pid,0) except OSError as exc: logger.critical('can not fork, errno %d : %s' % (exc.errno,exc.strerror),'reactor') sys.exit(1)
def main(): major = int(sys.version[0]) minor = int(sys.version[2]) if major <= 2 and minor < 5: sys.stdout.write( 'This program can not work (is not tested) with your python version (< 2.5)\n' ) sys.stdout.flush() sys.exit(1) cli_named_pipe = os.environ.get('exabgp_cli_pipe', '') if cli_named_pipe: from exabgp.application.control import main as control control(cli_named_pipe) sys.exit(0) options = docopt.docopt(usage, help=False) if options["--run"]: sys.argv = sys.argv[sys.argv.index('--run') + 1:] if sys.argv[0] == 'healthcheck': from exabgp.application import run_healthcheck run_healthcheck() elif sys.argv[0] == 'cli': from exabgp.application import run_cli run_cli() else: sys.stdout.write(usage) sys.stdout.flush() sys.exit(0) return root = root_folder(options, [ '/bin/exabgp', '/sbin/exabgp', '/lib/exabgp/application/bgp.py', '/lib/exabgp/application/control.py' ]) prefix = '' if root == '/usr' else root etc = prefix + '/etc/exabgp' os.environ['EXABGP_ETC'] = etc # This is not most pretty if options["--version"]: sys.stdout.write('ExaBGP : %s\n' % version) sys.stdout.write('Python : %s\n' % sys.version.replace('\n', ' ')) sys.stdout.write('Uname : %s\n' % ' '.join(platform.uname()[:5])) sys.stdout.write('Root : %s\n' % root) sys.stdout.flush() sys.exit(0) envfile = get_envfile(options, etc) env = get_env(envfile) # Must be done before setting the logger as it modify its behaviour if options["--debug"]: env.log.all = True env.log.level = syslog.LOG_DEBUG logger = Logger() from exabgp.configuration.setup import environment if options["--decode"]: decode = ''.join(options["--decode"]).replace(':', '').replace(' ', '') if not is_bgp(decode): sys.stdout.write(usage) sys.stdout.write('Environment values are:\n%s\n\n' % '\n'.join(' - %s' % _ for _ in environment.default())) sys.stdout.write( 'The BGP message must be an hexadecimal string.\n\n') sys.stdout.write( 'All colons or spaces are ignored, for example:\n\n') sys.stdout.write(' --decode 001E0200000007900F0003000101\n') sys.stdout.write( ' --decode 001E:02:0000:0007:900F:0003:0001:01\n') sys.stdout.write( ' --decode FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF001E0200000007900F0003000101\n' ) sys.stdout.write( ' --decode FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001E:02:0000:0007:900F:0003:0001:01\n' ) sys.stdout.write( ' --decode \'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 001E02 00000007900F0003000101\n\'' ) sys.stdout.flush() sys.exit(1) else: decode = '' duration = options["--signal"] if duration and duration.isdigit(): pid = os.fork() if pid: import time import signal try: time.sleep(int(duration)) os.kill(pid, signal.SIGUSR1) except KeyboardInterrupt: pass try: pid, code = os.wait() sys.exit(code) except KeyboardInterrupt: try: pid, code = os.wait() sys.exit(code) except Exception: sys.exit(0) if options["--help"]: sys.stdout.write(usage) sys.stdout.write('Environment values are:\n' + '\n'.join(' - %s' % _ for _ in environment.default())) sys.stdout.flush() sys.exit(0) if options["--decode"]: env.log.parser = True env.debug.route = decode env.tcp.bind = '' if options["--profile"]: env.profile.enable = True if options["--profile"].lower() in ['1', 'true']: env.profile.file = True elif options["--profile"].lower() in ['0', 'false']: env.profile.file = False else: env.profile.file = options["--profile"] if envfile and not os.path.isfile(envfile): comment = 'environment file missing\ngenerate it using "exabgp --fi > %s"' % envfile else: comment = '' if options["--full-ini"] or options["--fi"]: for line in environment.iter_ini(): sys.stdout.write('%s\n' % line) sys.stdout.flush() sys.exit(0) if options["--full-env"] or options["--fe"]: print() for line in environment.iter_env(): sys.stdout.write('%s\n' % line) sys.stdout.flush() sys.exit(0) if options["--diff-ini"] or options["--di"]: for line in environment.iter_ini(True): sys.stdout.write('%s\n' % line) sys.stdout.flush() sys.exit(0) if options["--diff-env"] or options["--de"]: for line in environment.iter_env(True): sys.stdout.write('%s\n' % line) sys.stdout.flush() sys.exit(0) if options["--once"]: env.tcp.once = True if options["--pdb"]: # The following may fail on old version of python (but is required for debug.py) os.environ['PDB'] = 'true' env.debug.pdb = True if options["--test"]: env.debug.selfcheck = True env.log.parser = True if options["--memory"]: env.debug.memory = True configurations = [] # check the file only once that we have parsed all the command line options and allowed them to run if options["<configuration>"]: for f in options["<configuration>"]: # some users are using symlinks for atomic change of the configuration file # using mv may however be better practice :p normalised = os.path.realpath(os.path.normpath(f)) target = os.path.realpath(normalised) if os.path.isfile(target): configurations.append(normalised) continue if f.startswith('etc/exabgp'): normalised = os.path.join(etc, f[11:]) if os.path.isfile(normalised): configurations.append(normalised) continue logger.debug( 'one of the arguments passed as configuration is not a file (%s)' % f, 'configuration') sys.exit(1) else: sys.stdout.write(usage) sys.stdout.write('Environment values are:\n%s\n\n' % '\n'.join(' - %s' % _ for _ in environment.default())) sys.stdout.write('no configuration file provided') sys.stdout.flush() sys.exit(1) from exabgp.bgp.message.update.attribute import Attribute Attribute.caching = env.cache.attributes if env.debug.rotate or len(configurations) == 1: run(env, comment, configurations, root, options["--validate"]) if not (env.log.destination in ('syslog', 'stdout', 'stderr') or env.log.destination.startswith('host:')): logger.error( 'can not log to files when running multiple configuration (as we fork)', 'configuration') sys.exit(1) try: # run each configuration in its own process pids = [] for configuration in configurations: pid = os.fork() if pid == 0: run(env, comment, [configuration], root, options["--validate"], os.getpid()) else: pids.append(pid) # If we get a ^C / SIGTERM, ignore just continue waiting for our child process import signal signal.signal(signal.SIGINT, signal.SIG_IGN) # wait for the forked processes for pid in pids: os.waitpid(pid, 0) except OSError as exc: logger.critical( 'can not fork, errno %d : %s' % (exc.errno, exc.strerror), 'reactor') sys.exit(1)