def create_config(self): # Currently, supports only single peer c = CmdBuffer('\n') c << '[DEFAULT]' c << 'log_dir = {0}'.format(self.SHARED_VOLUME) c << 'use_stderr = False' c << '[message]' c << 'write_disk = True' c << 'write_dir = {0}/data/bgp/'.format(self.SHARED_VOLUME) c << 'format = json' if self.peers: info = next(iter(list(self.peers.values()))) remote_as = info['remote_as'] neigh_addr = info['neigh_addr'].split('/')[0] local_as = info['local_as'] or self.asn local_addr = info['local_addr'].split('/')[0] c << '[bgp]' c << 'afi_safi = ipv4, ipv6, vpnv4, vpnv6, flowspec, evpn' c << 'remote_as = {0}'.format(remote_as) c << 'remote_addr = {0}'.format(neigh_addr) c << 'local_as = {0}'.format(local_as) c << 'local_addr = {0}'.format(local_addr) with open('{0}/yabgp.ini'.format(self.config_dir), 'w') as f: print(yellow('[{0}\'s new yabgp.ini]'.format(self.name))) print(yellow(indent(str(c)))) f.writelines(str(c))
def add_missing_file(path, track, dryrun=True): missed = get_missing_file_full_path(path, track) if dryrun: stdout('(dryrun)', missed, 'created') else: new_mark_file(missed) yellow(missed, 'created')
def create_config(self): # Manpage of exabgp.conf(5): # https://github.com/Exa-Networks/exabgp/blob/master/doc/man/exabgp.conf.5 cmd = CmdBuffer('\n') for peer, info in self.peers.items(): cmd << 'neighbor {0} {{'.format(info['neigh_addr'].split('/')[0]) cmd << ' router-id {0};'.format(self.router_id) cmd << ' local-address {0};'.format( info['local_addr'].split('/')[0]) cmd << ' local-as {0};'.format(self.asn) cmd << ' peer-as {0};'.format(peer.asn) caps = [] if info['as2']: caps.append(' asn4 disable;') if info['addpath']: caps.append(' add-path send/receive;') if caps: cmd << ' capability {' for cap in caps: cmd << cap cmd << ' }' if info['passwd']: cmd << ' md5-password "{0}";'.format(info['passwd']) if info['passive']: cmd << ' passive;' cmd << '}' with open('{0}/exabgpd.conf'.format(self.config_dir), 'w') as f: print(yellow('[{0}\'s new exabgpd.conf]'.format(self.name))) print(yellow(str(cmd))) f.write(str(cmd))
def sing_it(force=False): global sung_it # python 3 can do nonlocal but in py2 is readonly elaborated = False if not silent and (force or not sung_it): if elaborated: stdout(init_the_song, end='') # sing it else: yellow('Fixing', project, '/', artist_d, '/', album_d, '/', song_f) sung_it = True
def create_config(self): c = CmdBuffer() c << 'router id {0};'.format(self.router_id) for peer, info in self.peers.items(): c << 'protocol bgp {' c << ' local as {0};'.format(self.asn) n_addr = info['neigh_addr'].split('/')[0] c << ' neighbor {0} as {1};'.format(n_addr, peer.asn) c << ' multihop;' c << '}' with open('{0}/bird.conf'.format(self.config_dir), 'w') as f: print(yellow('[{0}\'s new bird.conf]'.format(self.name))) print(yellow(indent(str(c)))) f.writelines(str(c))
def _create_config_zebra(self): c = CmdBuffer() c << 'hostname zebra' c << 'password zebra' c << 'log file {0}/zebra.log'.format(self.QUAGGA_VOLUME) c << 'debug zebra packet' c << 'debug zebra kernel' c << 'debug zebra rib' c << 'ipv6 forwarding' c << '' with open('{0}/zebra.conf'.format(self.quagga_config_dir), 'w') as f: print(yellow('[{0}\'s new zebra.conf]'.format(self.name))) c = str(c).strip() print(yellow(indent(c))) f.writelines(c)
def _create_config_ospfd(self): c = CmdBuffer() c << 'hostname ospfd' c << 'password zebra' c << 'router ospf' for redistribute in self.ospfd_config.get('redistributes', []): c << ' redistribute {0}'.format(redistribute) for network, area in list(self.ospfd_config.get('networks', {}).items()): c << ' network {0} area {1}'.format(network, area) c << 'log file {0}/ospfd.log'.format(self.QUAGGA_VOLUME) c << '' with open('{0}/ospfd.conf'.format(self.quagga_config_dir), 'w') as f: print(yellow('[{0}\'s new ospfd.conf]'.format(self.name))) print(yellow(indent(str(c)))) f.writelines(str(c))
def main(): program = 'fix_empty_dirs' description = ''' Deletes empty dirs''' parser = argparse.ArgumentParser(prog=program, description=description) parser.add_argument('-p', '--production', help='Enable production run', action='store_true') parser.add_argument('-v', '--verbose', help='Enable verbosity', action='store_true') parser.add_argument('-x', '--path', type=str, help='Root path') args = parser.parse_args() dryrun = not args.production or get_env_var('DRYRUN') verbose = args.verbose or get_env_var('VERBOSE') root = args.path or get_default_root() assert_non_empty_dir(root) mark_dry_or_production_run(dryrun) if dryrun: warn('Dryrun does not check nested empty dirs!') cnt = 0 done = False dryrun_deleted_dirs = [] while not done: cnt_start = cnt for dir_name, sub_dirs, file_names in os.walk(root): if verbose: yellow('Checking', dir_name) if not sub_dirs and not file_names: if dryrun: if dir_name in dryrun_deleted_dirs: continue else: dryrun_deleted_dirs.append(dir_name) remove_dir(dir_name, dryrun=dryrun, verbose=verbose) cnt += 1 done = cnt == cnt_start if cnt: stdout() stdout(cnt, 'dirs deleted')
def _create_config_zebra(self): c = CmdBuffer() c << 'hostname zebra' c << 'password zebra' for name, settings in list( self.zebra_config.get('interfaces', {}).items()): c << 'interface {0}'.format(name) for setting in settings: c << str(setting) for route in self.zebra_config.get('routes', []): c << str(route) c << 'log file {0}/zebra.log'.format(self.SHARED_VOLUME) c << 'debug zebra packet' c << 'debug zebra kernel' c << 'debug zebra rib' c << 'ipv6 forwarding' c << '' with open('{0}/zebra.conf'.format(self.config_dir), 'w') as f: print(yellow('[{0}\'s new zebra.conf]'.format(self.name))) c = str(c).strip() print(yellow(indent(c))) f.writelines(c)
def edit_song(song, debug=False): FILL_UP_TO = 15 done = False while not done: start_cyan() option(0, 'None') option(1, 'SONG FILE'.ljust(FILL_UP_TO) + song.name()) idx = 2 tag_qualifiers = Song.get_tag_keys() for tag in tag_qualifiers: option(idx, tag.ljust(FILL_UP_TO) + song.get(tag)) idx += 1 end_color() stdout() while True: t = numerical_input('Edit file/tag', 0, idx - 1) if t == 0: # exit done = True break elif t == 1: # new song file f = string_input('New SONG FILE', prefill=song.name()) yellow('Updating SONG FILE to', f) rename_file(song.path(), song.name(), f, dryrun=False, silent=True, debug=debug) song = Song(path=song.path(), song_f=f, debug=debug) stdout() else: t = tag_qualifiers[t - 2] f = string_input('New ' + t, prefill=song.get(t)) yellow('Updating', t, 'to', f) song.set(t, f, save=True, dryrun=False) # modify for real! stdout() return song
def create_config(self): c = CmdBuffer() c << '[BGP]' if len(self.ip_addrs) > 0: c << 'local_address={0}'.format(self.ip_addrs[0][1].split('/')[0]) for info in list(self.peers.values()): c << 'peers={0}'.format(info['neigh_addr'].split('/')[0]) c << 'my_as={0}'.format(self.asn) c << 'enable_rtc=True' c << '[API]' c << 'api_host=localhost' c << 'api_port=8082' c << '[DATAPLANE_DRIVER_IPVPN]' c << 'dataplane_driver = DummyDataplaneDriver' c << '[DATAPLANE_DRIVER_EVPN]' c << 'dataplane_driver = DummyDataplaneDriver' with open('{0}/bgp.conf'.format(self.config_dir), 'w') as f: print(yellow(str(c))) f.writelines(str(c))
def _create_config_bgp(self): config = { 'global': { 'config': { 'as': self.asn, 'router-id': self.router_id, }, 'route-selection-options': { 'config': { 'external-compare-router-id': True, }, }, }, 'neighbors': [], } self._merge_dict(config, self.bgp_config) if self.zebra and self.zapi_version == 2: config['global']['use-multiple-paths'] = {'config': {'enabled': True}} for peer, info in self.peers.items(): afi_safi_list = [] if info['interface'] != '': afi_safi_list.append({'config': {'afi-safi-name': 'ipv4-unicast'}}) afi_safi_list.append({'config': {'afi-safi-name': 'ipv6-unicast'}}) else: version = netaddr.IPNetwork(info['neigh_addr']).version if version == 4: afi_safi_list.append({'config': {'afi-safi-name': 'ipv4-unicast'}}) elif version == 6: afi_safi_list.append({'config': {'afi-safi-name': 'ipv6-unicast'}}) else: Exception('invalid ip address version. {0}'.format(version)) if info['vpn']: afi_safi_list.append({'config': {'afi-safi-name': 'l3vpn-ipv4-unicast'}}) afi_safi_list.append({'config': {'afi-safi-name': 'l3vpn-ipv6-unicast'}}) afi_safi_list.append({'config': {'afi-safi-name': 'l2vpn-evpn'}}) afi_safi_list.append({'config': {'afi-safi-name': 'rtc'}, 'route-target-membership': {'config': {'deferral-time': 10}}}) if info['flowspec']: afi_safi_list.append({'config': {'afi-safi-name': 'ipv4-flowspec'}}) afi_safi_list.append({'config': {'afi-safi-name': 'l3vpn-ipv4-flowspec'}}) afi_safi_list.append({'config': {'afi-safi-name': 'ipv6-flowspec'}}) afi_safi_list.append({'config': {'afi-safi-name': 'l3vpn-ipv6-flowspec'}}) neigh_addr = None interface = None peer_as = None if info['interface'] == '': neigh_addr = info['neigh_addr'].split('/')[0] peer_as = info['remote_as'] else: interface = info['interface'] n = { 'config': { 'neighbor-address': neigh_addr, 'neighbor-interface': interface, 'peer-as': peer_as, 'auth-password': info['passwd'], 'vrf': info['vrf'], 'remove-private-as': info['remove_private_as'], }, 'afi-safis': afi_safi_list, 'timers': { 'config': { 'connect-retry': 10, }, }, 'transport': { 'config': {}, }, } n['as-path-options'] = {'config': {}} if info['allow_as_in'] > 0: n['as-path-options']['config']['allow-own-as'] = info['allow_as_in'] if info['replace_peer_as']: n['as-path-options']['config']['replace-peer-as'] = info['replace_peer_as'] if ':' in info['local_addr']: n['transport']['config']['local-address'] = info['local_addr'].split('/')[0] if info['passive']: n['transport']['config']['passive-mode'] = True if info['is_rs_client']: n['route-server'] = {'config': {'route-server-client': True}} if info['local_as']: n['config']['local-as'] = info['local_as'] if info['prefix_limit']: for v in afi_safi_list: v['prefix-limit'] = {'config': {'max-prefixes': info['prefix_limit'], 'shutdown-threshold-pct': 80}} if info['graceful_restart'] is not None: n['graceful-restart'] = {'config': {'enabled': True, 'restart-time': GRACEFUL_RESTART_TIME}} for afi_safi in afi_safi_list: afi_safi['mp-graceful-restart'] = {'config': {'enabled': True}} if info['llgr'] is not None: n['graceful-restart']['config']['restart-time'] = 1 n['graceful-restart']['config']['long-lived-enabled'] = True for afi_safi in afi_safi_list: afi_safi['long-lived-graceful-restart'] = {'config': {'enabled': True, 'restart-time': LONG_LIVED_GRACEFUL_RESTART_TIME}} if info['is_rr_client']: cluster_id = self.router_id if 'cluster_id' in info and info['cluster_id'] is not None: cluster_id = info['cluster_id'] n['route-reflector'] = {'config': {'route-reflector-client': True, 'route-reflector-cluster-id': cluster_id}} if info['addpath']: n['add-paths'] = {'config': {'receive': True, 'send-max': 16}} if len(info.get('default-policy', [])) + len(info.get('policies', [])) > 0: n['apply-policy'] = {'config': {}} for typ, p in info.get('policies', {}).items(): n['apply-policy']['config']['{0}-policy-list'.format(typ)] = [p['name']] def _f(v): if v == 'reject': return 'reject-route' elif v == 'accept': return 'accept-route' raise Exception('invalid default policy type {0}'.format(v)) for typ, d in info.get('default-policy', {}).items(): n['apply-policy']['config']['default-{0}-policy'.format(typ)] = _f(d) if info['treat_as_withdraw']: n['error-handling'] = {'config': {'treat-as-withdraw': True}} config['neighbors'].append(n) config['defined-sets'] = {} if self.prefix_set: config['defined-sets']['prefix-sets'] = self.prefix_set if self.neighbor_set: config['defined-sets']['neighbor-sets'] = self.neighbor_set if self.bgp_set: config['defined-sets']['bgp-defined-sets'] = self.bgp_set policy_list = [] for p in self.policies.values(): policy = {'name': p['name']} if 'statements' in p: policy['statements'] = p['statements'] policy_list.append(policy) if len(policy_list) > 0: config['policy-definitions'] = policy_list if self.zebra: config['zebra'] = {'config': {'enabled': True, 'redistribute-route-type-list': ['connect'], 'version': self.zapi_version}} with open('{0}/gobgpd.conf'.format(self.config_dir), 'w') as f: print(yellow('[{0}\'s new gobgpd.conf]'.format(self.name))) if self.config_format is 'toml': raw = toml.dumps(config) elif self.config_format is 'yaml': raw = yaml.dump(config) elif self.config_format is 'json': raw = json.dumps(config) else: raise Exception('invalid config_format {0}'.format(self.config_format)) raw = raw.strip() print(yellow(indent(raw))) f.write(raw)
def get_filtered_songs(path, song_fs, artist_filter=None, album_filter=None, title_filter=None, sort_per_track=False, post_process_songs=False, print_header=True, no_warn=False, deep_warn=False, mark_missing_songs=False, dryrun=True, verbose=False, silent=False, debug=False): printed_header = False filtered_songs = {} missed_songs = [] warnings = 0 max_track_len = 0 total_album_tracks = None # unknown or inconsistent track_info_per_song = {} for song in song_fs: if is_song_file(song): s = Song(path=path, song_f=song, debug=debug) if ((not artist_filter or artist_filter.lower() in s.get('ALBUMARTIST').lower()) and ((not album_filter or album_filter.lower() in s.get('ALBUM').lower()) and (not title_filter or title_filter.lower() in s.get('TITLE').lower()))): if print_header and not printed_header: green() green('Listing', path) printed_header = True if sort_per_track: track_tag = s.get_track_nbr_as_string(verbose=verbose) track_nbr, total = s.parse_track_nbr(track_tag) track_info_per_song[s.name()] = (track_nbr, total) # build up a list, in case of mixes directory, there would # be track number overlaps f_songs = filtered_songs.get(track_nbr) if f_songs: f_songs.append(s) else: filtered_songs[track_nbr] = [s] else: track_tag = s.get_track_nbr_as_string(verbose=verbose) filtered_songs[len(filtered_songs)] = [s] max_track_len = max(max_track_len, len(track_tag)) if filtered_songs and sort_per_track and post_process_songs: prev_track_nbr = 0 song_that_gave_total_tracks = None total_tracks_is_inconsistent = False for track_nbr in sorted(filtered_songs): first_song = True for song in filtered_songs[track_nbr]: song_f = song.name() song_base = song_f[:-len(SONG_FILE_EXT)] track_nbr, total = track_info_per_song[song_f] if missing_file_exists(path, track_nbr): error('.missing file exists for', song_f, end='\n') error('You must delete it:', get_missing_file_full_path(path, track_nbr), end='\n') if first_song: if track_nbr != prev_track_nbr + 1: # TODO(if last song is missing, we don't report) for i in range(prev_track_nbr + 1, track_nbr): if not missing_file_exists(path, i): if mark_missing_songs: add_missing_file(path, i, dryrun) else: missed_songs.append((path, i)) prev_track_nbr = track_nbr first_song = False if total and not total_tracks_is_inconsistent: if total_album_tracks is None: total_album_tracks = total song_that_gave_total_tracks = song_base elif total_album_tracks != total: total_tracks_is_inconsistent = True total_album_tracks = None if not no_warn: warn('Within', path, 'album,') yellow(' ', song_base, 'has inconsistent total tracks with', song_that_gave_total_tracks) if deep_warn: print_songs(path, song_fs, artist_filter, album_filter, title_filter, sort_per_track=True, verbose=verbose, silent=silent, debug=debug) warnings += 1 if not silent: for song in missed_songs: warn(song[0], '[Track', song[1], '\b] is missing') warnings += 1 return (filtered_songs, missed_songs, total_album_tracks, warnings, max_track_len)
def main(): if is_py2(): warn('Running as python 3 is advised') stdout() program = 'audit_songs' description = ''' Audits songs or list of songs with its directory structure ''' parser = argparse.ArgumentParser(prog=program, description=description) parser.add_argument('-p', '--production', help='Enable production run', action='store_true') parser.add_argument('-j', '--project-filter', type=str, help='Set project filter') parser.add_argument('-a', '--artist-filter', type=str, help='Set artist filter') parser.add_argument('-b', '--album-filter', type=str, help='Set album filter') parser.add_argument('-c', '-t', '--title-filter', type=str, help='Set title filter') parser.add_argument('--dir-structure-as-ref', help=('Set the dir structure as the reference, ' 'opposed to the default\'s song tags'), action='store_true') parser.add_argument('--set-artist', type=str, help='Set (overrules) artists. Always use with ' '--artist-filter') parser.add_argument('--set-album', type=str, help='Set (overrules) album. Always use with ' '--album-filter') parser.add_argument('--set-song', type=str, help='Set (overrules) song title, Always use with ' '--title-filter') parser.add_argument('--provide-report', help='Provide a report of modified songs', action='store_true') parser.add_argument('-x', '--path', type=str, help='Sets root path') parser.add_argument('-n', '--limit-changes', type=int, help='Set a limit to amount of changes') parser.add_argument('-v', '--verbose', help='Enable verbosity', action='store_true') parser.add_argument('-s', '--silent', help='Enable silence', action='store_true') parser.add_argument('-d', '--debug', help='Enable debug', action='store_true') parser.add_argument('--force-write', help='Force-Write', action='store_true') args = parser.parse_args() root = args.path or get_default_root() dryrun = not args.production or get_env_var('DRYRUN') silent = args.silent or get_env_var('SILENT') debug = args.debug or get_env_var('DEBUG') verbose = args.verbose or get_env_var('VERBOSE') or debug provide_report = args.provide_report project_filter = args.project_filter artist_filter = args.artist_filter album_filter = args.album_filter title_filter = args.title_filter dir_structure_as_ref = args.dir_structure_as_ref set_artist = args.set_artist set_album = args.set_album set_song = args.set_song limit_changes = args.limit_changes or 9999999999 if set_artist and not artist_filter: fatal_error('Must set artist filter when setting artist') if set_album and not album_filter: fatal_error('Must set album filter when setting album') if set_song and not title_filter: fatal_error('Must set title filter when setting song title') if title_filter and title_filter.lower().endswith(SONG_FILE_EXT): title_filter = title_filter[:-len(SONG_FILE_EXT)] if set_song and set_song.lower().endswith(SONG_FILE_EXT): set_song = set_song[:-len(SONG_FILE_EXT)] assert_non_empty_dir(root) mark_dry_or_production_run(dryrun) for dir_name, _, filenames in os.walk(root): process, project, artist, album = process_songs_dir( root, dir_name, project_filter, artist_filter, album_filter) if not process: continue if not title_filter and verbose: yellow('Processing', project, artist, album) for song in filenames: if not song.lower().endswith(SONG_FILE_EXT): continue if title_filter: if title_filter.lower() != song[:-len(SONG_FILE_EXT)].lower(): continue elif verbose: yellow('Processing', project, artist, album, song) elif debug: yellow('Processing', project, artist, album, song) reset_artist = [None] reset_album = [None] if audit_song( root, project, artist, album, song, reset_artist, reset_album, dir_structure_as_ref=dir_structure_as_ref, # Once a first song in album fixes the artist, same artist # is dictated to rest of songs. This avoids ping-pong'ing. set_artist=set_artist if set_artist else None, # Once a first song in album fixes the album, same album is # dictated to rest of songs. This avoids ping-pong'ing. set_album=set_album if set_album else None, # User specified song set_song=set_song, force_write=args.force_write, dryrun=dryrun, verbose=verbose, silent=silent, debug=debug): if debug: stdout(errors_fixed, 'errors fixed') if reset_artist[0]: if (artist_filter and artist.lower() == artist_filter.lower()): artist_filter = reset_artist[0] artist = reset_artist[0] # Make sure next songs in album # will load correctly if reset_album[0]: if (album_filter and album.lower() == album_filter.lower()): album_filter = reset_album[0] album = reset_album[0] # Make sure next songs in album # will load correctly if not silent: stdout() if errors_fixed >= limit_changes: break if not silent and errors_fixed >= limit_changes: stdout() stdout(errors_fixed, 'errors were fixed;', errors_unresolved, 'remaining errors found') if provide_report and fixed_songs: stdout('Generating reports', ConsoleColors.ALERT) print_paths(fixed_songs, write_to_file=FIXED_SONGS_REPORT + '.cyg') print_paths(fixed_songs, dos_format=True, write_to_file=FIXED_SONGS_REPORT + '.dos') stdout(ConsoleColors.ENDC + 'Check the report:') stdout(' ', 'cat', FIXED_SONGS_REPORT + '.cyg') stdout(' ', 'cat', FIXED_SONGS_REPORT + '.dos') stdout() stdout('Feed into foobar2000 as:') stdout(' for i in $(cat ' + FIXED_SONGS_REPORT + '.dos); do songs="$songs $i"; done; foobar2000.exe /add $songs') stdout() stdout('Or do a little test:') stdout(' for i in $(cat ' + FIXED_SONGS_REPORT + '.dos); do echo "$i"; done') stdout()
def main(): program = 'fix_non_flac' description = ''' Fix non-FLAC songs''' parser = argparse.ArgumentParser(prog=program, description=description) parser.add_argument('-x', '--path', type=str, help='Root path') parser.add_argument('-p', '--production', help='Enable production run', action='store_true') parser.add_argument('-ir', '--include-reviewed-files', help='Include .reviewed files', action='store_true') parser.add_argument('-f', '--full', help='Full clean, including tolerated extensions', action='store_true') parser.add_argument('-fa', '--full-including-album-art', help='Full clean, including album art and ' 'tolerated extensions', action='store_true') parser.add_argument('-v', '--verbose', help='Enable verbosity', action='store_true') parser.add_argument('-s', '--silent', help='Enable silence', action='store_true') parser.add_argument('-d', '--debug', help='Enable debug', action='store_true') args = parser.parse_args() root = args.path or get_default_root() dryrun = not args.production or get_env_var('DRYRUN') silent = args.silent or get_env_var('SILENT') debug = args.debug or get_env_var('DEBUG') verbose = args.verbose or get_env_var('VERBOSE') or debug assert_non_empty_dir(root) mark_dry_or_production_run(dryrun) cnt = 0 if args.full_including_album_art: protected_extensions = [] elif args.full: protected_extensions = ALBUM_ART_EXT elif args.include_reviewed_files: protected_extensions = MISSING_EXTENSIONS + ALBUM_ART_EXT else: protected_extensions = TOLERATED_FILE_EXTENSIONS + ALBUM_ART_EXT def protected(): for extension in protected_extensions: if file_name.lower().endswith(extension): return True return False for dir_name, _, file_names in os.walk(root): for file_name in file_names: if not is_song_file(file_name): if not protected(): yellow('Deleting', dir_name + '/' + file_name) remove_file(dir_name, file_name, False, dryrun=dryrun, verbose=verbose, silent=silent, debug=debug) cnt += 1 if cnt: stdout() stdout(cnt, 'non-{} files deleted.'.format(SONG_FILE_EXT[1:]))
def create_config(self): with open('{0}/gobgpd.conf'.format(self.config_dir), 'w') as f: print(yellow('[{0}\'s new gobgpd.conf]'.format(self.name))) print(yellow(indent(self.config))) f.write(self.config)
def _create_config_bgp(self): c = CmdBuffer() c << 'hostname bgpd' c << 'password zebra' c << 'router bgp {0}'.format(self.asn) c << 'bgp router-id {0}'.format(self.router_id) if any(info['graceful_restart'] for info in self.peers.values()): c << 'bgp graceful-restart' if 'global' in self.bgpd_config: if 'confederation' in self.bgpd_config['global']: conf = self.bgpd_config['global']['confederation']['config'] c << 'bgp confederation identifier {0}'.format( conf['identifier']) c << 'bgp confederation peers {0}'.format(' '.join( [str(i) for i in conf['member-as-list']])) version = 4 for peer, info in self.peers.items(): version = netaddr.IPNetwork(info['neigh_addr']).version n_addr = info['neigh_addr'].split('/')[0] if version == 6: c << 'no bgp default ipv4-unicast' c << 'neighbor {0} remote-as {1}'.format(n_addr, info['remote_as']) # For rapid convergence c << 'neighbor {0} advertisement-interval 1'.format(n_addr) if info['is_rs_client']: c << 'neighbor {0} route-server-client'.format(n_addr) for typ, p in info['policies'].items(): c << 'neighbor {0} route-map {1} {2}'.format( n_addr, p['name'], typ) if info['passwd']: c << 'neighbor {0} password {1}'.format(n_addr, info['passwd']) if info['passive']: c << 'neighbor {0} passive'.format(n_addr) if version == 6: c << 'address-family ipv6 unicast' c << 'neighbor {0} activate'.format(n_addr) c << 'exit-address-family' if self.zebra: if version == 6: c << 'address-family ipv6 unicast' c << 'redistribute connected' c << 'exit-address-family' else: c << 'redistribute connected' for name, policy in self.policies.items(): c << 'access-list {0} {1} {2}'.format(name, policy['type'], policy['match']) c << 'route-map {0} permit 10'.format(name) c << 'match ip address {0}'.format(name) c << 'set metric {0}'.format(policy['med']) c << 'debug bgp as4' c << 'debug bgp fsm' c << 'debug bgp updates' c << 'debug bgp events' c << 'log file {0}/bgpd.log'.format(self.SHARED_VOLUME) with open('{0}/bgpd.conf'.format(self.config_dir), 'w') as f: print(yellow('[{0}\'s new bgpd.conf]'.format(self.name))) print(yellow(indent(str(c)))) f.writelines(str(c))