Пример #1
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, exc:
        print usage
        print '\nconfiguration issue,', str(exc)
        sys.exit(1)
Пример #2
0
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()
Пример #3
0
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()
Пример #4
0
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)
Пример #5
0
Файл: bgp.py Проект: qoke/exabgp
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)
Пример #6
0
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()
Пример #7
0
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()
Пример #8
0
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)
Пример #9
0
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)