From: <di...@us...> - 2008-11-19 18:17:02
|
Revision: 622 http://safekeep.svn.sourceforge.net/safekeep/?rev=622&view=rev Author: dimi Date: 2008-11-19 18:16:58 +0000 (Wed, 19 Nov 2008) Log Message: ----------- First cut at implementing bandwidth limiting based on trickle. Modified Paths: -------------- safekeep/trunk/TODO safekeep/trunk/safekeep safekeep/trunk/safekeep.spec.in Modified: safekeep/trunk/TODO =================================================================== --- safekeep/trunk/TODO 2008-11-19 16:39:56 UTC (rev 621) +++ safekeep/trunk/TODO 2008-11-19 18:16:58 UTC (rev 622) @@ -5,7 +5,6 @@ * Avoid snapshotting snapshots * Don't snapshot a device if a snapshot is already present * Protect against multiple safekeep instance running at once - * Use -l with ssh to limit the bandwidth used during the backup Feedback from users: * Øyvind Skaar <os...@op...>: FreeBSD have snapshot capabilities Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2008-11-19 16:39:56 UTC (rev 621) +++ safekeep/trunk/safekeep 2008-11-19 18:16:58 UTC (rev 622) @@ -45,14 +45,17 @@ config_file = '/etc/safekeep/safekeep.conf' config_ext = '.backup' +trickle_cmd = 'trickle' logbuf = [] is_client = False verbosity_level = 1 verbosity_ssh = '' +verbosity_trickle = '' work_user = getpass.getuser() backup_user = None home_dir = None base_dir = None +default_bandwidth = {} PROTOCOL = "1.1" VERSION = "1.0.5" @@ -99,7 +102,7 @@ if line.startswith(marker): marker = None continue - if (line.startswith("Errors ")): + if line.startswith("Errors "): errs = int(line[6:]) info(line.rstrip()) finally: @@ -118,6 +121,17 @@ def error(msg): log(msg, 'ERR') +def try_to_run(cmd): + cmd = cmd.split(' ')[0] + proc = popen2.Popen4(args) + proc.tochild.close() + for line in proc.fromchild: + info(line.rstrip()) + proc.fromchild.close() + rc = proc.wait() + + return os.WIFEXITED(rc) + def spawn(args): if isinstance(args, str) or isinstance(args, unicode): debug('Run [' + args + ']') @@ -239,6 +253,13 @@ raise ConfigException('Empty ' + clude_el.tagName) return { 'type' : clude_el.tagName, 'path' : path, 'glob' : glob, 'regexp' : regexp } +def parse_bandwidth(bw_el): + return { + 'overall': int(bw_el.getAttribute('overall') or 0), + 'download': int(bw_el.getAttribute('download') or 0), + 'upload': int(bw_el.getAttribute('upload') or 0) + } + def parse_config(backup_el, dflt_id): if backup_el.tagName != 'backup': raise ConfigException('Invalid config file, the top level element must be <backup>') @@ -264,6 +285,13 @@ if key_data and not os.path.isabs(key_data): key_data = os.path.join(home_dir, key_data) + bw = {} + bw_el = backup_el.getElementsByTagName('bandwidth') + if len(bw_el) == 1: + bw = parse_bandwidth(bw_el[0]) + elif len(bw_el) > 1: + raise ConfigException('Can not have more than a bandwidth element') + repo_el = backup_el.getElementsByTagName('repo') dir = None retention = None @@ -323,7 +351,7 @@ return { 'id': id, 'host' : host, 'user' : user, 'key_ctrl' : key_ctrl, 'key_data' : key_data, 'dir' : dir, 'retention' : retention, 'dumps' : dumps, 'snaps' : snaps, - 'cludes' : cludes, 'options' : options} + 'cludes' : cludes, 'options' : options, 'bw': bw} def parse_locs(cfglocs): cfgfiles = [] @@ -709,13 +737,35 @@ def do_server_rdiff(cfg, bdir, nice, force): args = [] - if (nice) + if nice: args.extend(['nice', '-n' + nice]) args.extend(['rdiff-backup']) if cfg['host']: - schema = 'ssh %s -i %s %%s rdiff-backup --server' % (verbosity_ssh, cfg['key_data']) + trickle = '' + + def get_bw(vals, dir): + return vals.get(dir) or vals.get('overall') + + def get_bandwidth(cfg, dir): + return get_bw(cfg['bw'], dir) or get_bw(default_bandwidth, dir) + + limit_dl = get_bandwidth(cfg, 'download') + limit_ul = get_bandwidth(cfg, 'upload') + if limit_dl or limit_ul: + trickle = trickle_cmd + ' ' + verbosity_trickle + if limit_dl: + trickle += ' -d ' + limit_dl + if limit_ul: + trickle += ' -u ' + limit_ul + + if trickle: + if !try_to_run(trickle_cmd + ' -V'): + warn('Trickle not available, bandwidth limiting disabled') + trickle = '' + + schema = '% ssh %s -i %s %%s rdiff-backup --server' % (trickle, verbosity_ssh, cfg['key_data']) args.extend(['--remote-schema', schema]) if force: @@ -1227,6 +1277,13 @@ else: cfgfile = config_file props = {} + + def get_int(prop): + v = props.get(p) + if v is not None and v is not '': + return int(v) + return None + if 'backup.user' in props: backup_user = props['backup.user'] if 'base.dir' in props: @@ -1235,10 +1292,13 @@ smtp = props['email.smtp.server'] if 'email.to' in props: email = props['email.to'].split(',') - if 'nice.adjustment' in props: - nice_srv = props['nice.adjustment'] - if (nice_srv) nice_srv = int(nice_srv) + nice_srv = get_int('nice.adjustment') + global default_bandwidth + default_bandwidth['overall'] = get_int('bandwidth.limit') or 0 + default_bandwidth['download'] = get_int('bandwidth.limit.download') or 0 + default_bandwidth['upload'] = get_int('bandwidth.limit.upload') or 0 + if len(cfglocs) == 0: locs = os.path.join(os.path.dirname(cfgfile), 'backup.d') if os.path.isdir(locs): cfglocs.append(locs) @@ -1274,10 +1334,10 @@ if not ok: sys.exit(2) try: - global is_client, verbosity_level, verbosity_ssh + global is_client, verbosity_level, verbosity_ssh, verbosity_trickle if verbosity > 0: - verbosity_ssh = '-' + verbosity * 'v' + verbosity_trickle = verbosity_ssh = '-' + verbosity * 'v' if mode is 'server': is_client = False verbosity_level = 1 + verbosity Modified: safekeep/trunk/safekeep.spec.in =================================================================== --- safekeep/trunk/safekeep.spec.in 2008-11-19 16:39:56 UTC (rev 621) +++ safekeep/trunk/safekeep.spec.in 2008-11-19 18:16:58 UTC (rev 622) @@ -116,6 +116,7 @@ %doc sample.backup %changelog + - Implement bandwidth limiting, based on trickle - By default, run safekeep with nice +10 on the server side - Run ssh/rdiff through nice so we can control the load better on the server - Do not compress the SSH traffic, it is handled by rdiff-backup This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |