You can subscribe to this list here.
2007 |
Jan
(76) |
Feb
(76) |
Mar
(54) |
Apr
(14) |
May
(23) |
Jun
(21) |
Jul
|
Aug
|
Sep
(9) |
Oct
(14) |
Nov
(12) |
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2008 |
Jan
|
Feb
(18) |
Mar
(3) |
Apr
|
May
|
Jun
(2) |
Jul
(3) |
Aug
|
Sep
|
Oct
(17) |
Nov
(13) |
Dec
|
2009 |
Jan
(1) |
Feb
(1) |
Mar
(15) |
Apr
(2) |
May
(18) |
Jun
(1) |
Jul
|
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
|
2010 |
Jan
(1) |
Feb
(5) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(61) |
Dec
|
2011 |
Jan
|
Feb
|
Mar
(18) |
Apr
|
May
|
Jun
(5) |
Jul
|
Aug
(1) |
Sep
(2) |
Oct
(4) |
Nov
(10) |
Dec
(9) |
2012 |
Jan
(10) |
Feb
(23) |
Mar
|
Apr
(5) |
May
(2) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
(4) |
2013 |
Jan
(17) |
Feb
(1) |
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <di...@us...> - 2010-11-19 17:17:43
|
Revision: 698 http://safekeep.svn.sourceforge.net/safekeep/?rev=698&view=rev Author: dimi Date: 2010-11-19 17:17:37 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Cleanup error handling Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 17:01:47 UTC (rev 697) +++ safekeep/trunk/safekeep 2010-11-19 17:17:37 UTC (rev 698) @@ -778,6 +778,7 @@ should_cleanup = True bdir = '/' cfg = do_client_config_parse('<backup/>', 'def') + ex = None try: while True: try: @@ -813,12 +814,14 @@ send('ERROR Unknown command: %s' % line) break except Exception, e: - traceback.print_exc(file=sys.stdout) - send('ERROR %s' % e) + ex = e + break finally: if should_cleanup: do_client_cleanup(cfg, bdir) + if ex: + send('ERROR %s' % (ex or '')) ###################################################################### # Server implementation @@ -1482,8 +1485,7 @@ else: assert False, 'Unknown mode: %s' % (mode) except Exception, ex: - traceback.print_exc(file=sys.stdout) - error('ERROR: %s' % ex) + error('ERROR: %s' % (ex or '')) if email and not noemail: send_notification(email, smtp) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 17:01:53
|
Revision: 697 http://safekeep.svn.sourceforge.net/safekeep/?rev=697&view=rev Author: dimi Date: 2010-11-19 17:01:47 +0000 (Fri, 19 Nov 2010) Log Message: ----------- We have to deal with strings here Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 16:59:55 UTC (rev 696) +++ safekeep/trunk/safekeep 2010-11-19 17:01:47 UTC (rev 697) @@ -105,7 +105,7 @@ log(msg, 'ERR') def do_spawn(args, stdin=None, stdout=False): - debug('Run [' + args + ']') + debug('Run [' + ' '.joint(args) + ']') _shell = isinstance(args, types.StringTypes) if stdin: _stdin = subprocess.PIPE This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 17:00:03
|
Revision: 696 http://safekeep.svn.sourceforge.net/safekeep/?rev=696&view=rev Author: dimi Date: 2010-11-19 16:59:55 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Better handle errors in case things go really bad Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 16:50:18 UTC (rev 695) +++ safekeep/trunk/safekeep 2010-11-19 16:59:55 UTC (rev 696) @@ -642,6 +642,9 @@ if not line: raise ConfigException('Unexpected end of file') cfgStr += line + do_client_config_parse(cfgStr, dflt_id) + +def do_client_config_parse(cfgStr, dflt_id=None): dom = xml.dom.minidom.parseString(cfgStr) try: return parse_config(dom.documentElement, dflt_id) @@ -774,6 +777,7 @@ debug("Do client main loop") should_cleanup = True bdir = '/' + cfg = do_client_config_parse('<backup/>', 'def') try: while True: try: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 16:50:24
|
Revision: 695 http://safekeep.svn.sourceforge.net/safekeep/?rev=695&view=rev Author: dimi Date: 2010-11-19 16:50:18 +0000 (Fri, 19 Nov 2010) Log Message: ----------- More cleanup of the subprocess usage Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 16:44:13 UTC (rev 694) +++ safekeep/trunk/safekeep 2010-11-19 16:50:18 UTC (rev 695) @@ -22,8 +22,6 @@ import getpass, pwd, xml.dom.minidom import socket, smtplib -from subprocess import PIPE, STDOUT - ###################################################################### # Global settings ###################################################################### @@ -108,12 +106,20 @@ def do_spawn(args, stdin=None, stdout=False): debug('Run [' + args + ']') - shell = isinstance(args, types.StringTypes) - proc = subprocess.Popen(args, bufsize=1, shell=shell, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) + _shell = isinstance(args, types.StringTypes) + if stdin: + _stdin = subprocess.PIPE + else: + _stdin = None + if stdout: + _stderr = None + else: + _stderr = subprocess.STDOUT + proc = subprocess.Popen(args, bufsize=1, shell=_shell, stdin=_stdin, stdout=subprocess.PIPE, stderr=_stderr, close_fds=True) if stdin: proc.stdin.write(stdin) - proc.stdin.close() + proc.stdin.close() lines=[] for line in proc.stdout: if stdout: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 16:44:19
|
Revision: 694 http://safekeep.svn.sourceforge.net/safekeep/?rev=694&view=rev Author: dimi Date: 2010-11-19 16:44:13 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Cleanup Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 16:43:36 UTC (rev 693) +++ safekeep/trunk/safekeep 2010-11-19 16:44:13 UTC (rev 694) @@ -124,7 +124,7 @@ return (proc.wait(), ''.join(lines)) def _spawn(args, stdin=None, stdout=False): - if isinstance(args, str) or isinstance(args, unicode): + if isinstance(args, types.StringTypes): cmd = args.split(None)[0] else: cmd = args[0] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 16:43:42
|
Revision: 693 http://safekeep.svn.sourceforge.net/safekeep/?rev=693&view=rev Author: dimi Date: 2010-11-19 16:43:36 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Auto "shell" detection: if the command is a string, it will be executed via the shell, otherwise it will be executed directly. Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 16:36:52 UTC (rev 692) +++ safekeep/trunk/safekeep 2010-11-19 16:43:36 UTC (rev 693) @@ -16,7 +16,7 @@ # along with Safekeep. If not, see <http://www.gnu.org/licenses/>. from __future__ import generators -import getopt, os, os.path, re, sys, fnmatch, stat +import getopt, os, os.path, re, sys, fnmatch, stat, types import subprocess import commands, tempfile, time, traceback import getpass, pwd, xml.dom.minidom @@ -106,8 +106,9 @@ def error(msg): log(msg, 'ERR') -def do_spawn(args, shell=False, stdin=None, stdout=False): +def do_spawn(args, stdin=None, stdout=False): debug('Run [' + args + ']') + shell = isinstance(args, types.StringTypes) proc = subprocess.Popen(args, bufsize=1, shell=shell, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) if stdin: @@ -122,14 +123,14 @@ proc.stdout.close() return (proc.wait(), ''.join(lines)) -def _spawn(args, shell=False, stdin=None, stdout=False): +def _spawn(args, stdin=None, stdout=False): if isinstance(args, str) or isinstance(args, unicode): cmd = args.split(None)[0] else: cmd = args[0] try: - rc, out = do_spawn(args, shell, stdin, stdout) + rc, out = do_spawn(args, stdin, stdout) except OSError, ex: ret = "OSError: %s" % (ex) error('%s failed: %s' % (cmd, ret)); @@ -149,15 +150,15 @@ # this just spawns an external program (optionally through a shell) # and returns True it it fails, and False if it successed -def spawn(args, shell=False): - rc, out = _spawn(args, shell) +def spawn(args): + rc, out = _spawn(args) return rc # this spawans an external program (optionally through a shell), # feeds it any input via stdin, captures the output and returns it. # if it fails it returns None, otherwise it returns the output -def call(args, shell=False, stdin=None): - rc, out = _spawn(args, shell, stdin, stdout=True) +def call(args, stdin=None): + rc, out = _spawn(args, stdin, stdout=True) if not rc: return None return out @@ -505,7 +506,7 @@ if passwdfile: os.environ['PGPASSFILE'] = passwdfile try: - ec = spawn(cmd, shell=True) + ec = spawn(cmd) finally: if passwdfile: del os.environ['PGPASSFILE'] @@ -1149,7 +1150,7 @@ if deploy: cmd = '%s %s@%s "umask 077; test -d .ssh || mkdir .ssh; cat >> .ssh/authorized_keys"' % (basessh, cfg['user'], cfg['host']) keys = '%s\n' % '\n'.join([key[4] for key in new_keys]) - out = call(cmd, shell=True, stdin=keys) + out = call(cmd, stdin=keys) if out is None: error('Failed to deliver the keys to the client') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 16:36:58
|
Revision: 692 http://safekeep.svn.sourceforge.net/safekeep/?rev=692&view=rev Author: dimi Date: 2010-11-19 16:36:52 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Typo Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 16:35:45 UTC (rev 691) +++ safekeep/trunk/safekeep 2010-11-19 16:36:52 UTC (rev 692) @@ -955,7 +955,7 @@ cmd = [] if cfg['host']: - cmd.extend(['ssh', verbosity_ssh, '-T', '-i', cfg['key_ctrl'], '-l', cfg['user'], cfg['host']) + cmd.extend(['ssh', verbosity_ssh, '-T', '-i', cfg['key_ctrl'], '-l', cfg['user'], cfg['host']]) cmd.extend(['safekeep', '--client']) (cin,cout) = os.popen2(cmd) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 16:35:51
|
Revision: 691 http://safekeep.svn.sourceforge.net/safekeep/?rev=691&view=rev Author: dimi Date: 2010-11-19 16:35:45 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Get rid of the direct subprocess call. Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 16:22:38 UTC (rev 690) +++ safekeep/trunk/safekeep 2010-11-19 16:35:45 UTC (rev 691) @@ -957,10 +957,8 @@ if cfg['host']: cmd.extend(['ssh', verbosity_ssh, '-T', '-i', cfg['key_ctrl'], '-l', cfg['user'], cfg['host']) cmd.extend(['safekeep', '--client']) - - proc = subprocess.Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) - cin = proc.stdin - cout = proc.stdout + + (cin,cout) = os.popen2(cmd) cin.write('ALOHA: %s, %s\n' % (PROTOCOL, VERSION)) cin.flush() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 16:22:44
|
Revision: 690 http://safekeep.svn.sourceforge.net/safekeep/?rev=690&view=rev Author: dimi Date: 2010-11-19 16:22:38 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Get rid of a bunch of subprocess calls Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 16:13:21 UTC (rev 689) +++ safekeep/trunk/safekeep 2010-11-19 16:22:38 UTC (rev 690) @@ -184,11 +184,7 @@ server.quit() else: cmd = ['/usr/sbin/sendmail', '-t'] - pin = subprocess.Popen(cmd, stdin=PIPE).stdin - try: - pin.write(msg) - finally: - pin.close() + call(cmd, stdin=msg) def is_temp_root(dir): return dir != '/' @@ -1134,10 +1130,8 @@ if status or deploy: cmd = '%s %s@%s "if test -f .ssh/authorized_keys; then cat .ssh/authorized_keys; fi"' % (basessh, cfg['user'], cfg['host']) - debug(cmd) - out = subprocess.Popen(cmd, shell=True, stdout=PIPE).stdout - authtext = out.read() - if out.close(): + authtext = call(cmd) + if authtext is None: warn('%s: Failed to read the authorized_keys file.' % id) auth_keys = parse_authorized_keys(authtext) this_keys = parse_authorized_keys(output) @@ -1156,10 +1150,9 @@ print '%s: Keys will be deployed on the client.' % id if deploy: cmd = '%s %s@%s "umask 077; test -d .ssh || mkdir .ssh; cat >> .ssh/authorized_keys"' % (basessh, cfg['user'], cfg['host']) - debug(cmd) - pipe = subprocess.Popen(cmd, shell=True, stdin=PIPE).stdin - pipe.write('%s\n' % '\n'.join([key[4] for key in new_keys])) - if pipe.close(): + keys = '%s\n' % '\n'.join([key[4] for key in new_keys]) + out = call(cmd, shell=True, stdin=keys) + if out is None: error('Failed to deliver the keys to the client') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 16:13:32
|
Revision: 689 http://safekeep.svn.sourceforge.net/safekeep/?rev=689&view=rev Author: dimi Date: 2010-11-19 16:13:21 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Get rid of args_to_list() Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 15:07:44 UTC (rev 688) +++ safekeep/trunk/safekeep 2010-11-19 16:13:21 UTC (rev 689) @@ -106,24 +106,10 @@ def error(msg): log(msg, 'ERR') -def args_to_list(args): - if isinstance(args, str) or isinstance(args, unicode): - return args.split(None) - else: - return args - def do_spawn(args, shell=False, stdin=None, stdout=False): - global cmd - argslist = args_to_list(args) - cmd = argslist[0] - if shell: - # If passed to a shell then give args exactly as specified. - debug('Run [' + args + ']') - proc = subprocess.Popen(args, bufsize=1, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) - else: - # Otherwise split into separate elements. - debug('Run [' + ' '.join(argslist) + ']') - proc = subprocess.Popen(argslist, bufsize=1, shell=False, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) + debug('Run [' + args + ']') + proc = subprocess.Popen(args, bufsize=1, shell=shell, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) + if stdin: proc.stdin.write(stdin) proc.stdin.close() @@ -137,7 +123,11 @@ return (proc.wait(), ''.join(lines)) def _spawn(args, shell=False, stdin=None, stdout=False): - global cmd + if isinstance(args, str) or isinstance(args, unicode): + cmd = args.split(None)[0] + else: + cmd = args[0] + try: rc, out = do_spawn(args, shell, stdin, stdout) except OSError, ex: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 15:07:50
|
Revision: 688 http://safekeep.svn.sourceforge.net/safekeep/?rev=688&view=rev Author: dimi Date: 2010-11-19 15:07:44 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Get rid of cmd_run function. Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 14:56:46 UTC (rev 687) +++ safekeep/trunk/safekeep 2010-11-19 15:07:44 UTC (rev 688) @@ -179,12 +179,6 @@ return False return rc in (0,1) -def cmd_run(args): - argslist = args_to_list(args) - debug('Run [' + ' '.join(argslist) + ']') - p = subprocess.Popen(argslist, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) - return (p.stdin, p.stdout) - def send_notification(email, smtp): global logbuf if not logbuf: return @@ -545,10 +539,7 @@ (dump['file'], dump['db'], e)) def lvm_snap_information(): - (cin, cout) = cmd_run(['lvs', '--separator', ':', '--noheadings']) - lines = cout.readlines() - cout.close() - cin.close() + lines = call(['lvs', '--separator', ':', '--noheadings']) or '' lvms = [] for line in lines: if line.count(':') > 3: @@ -558,10 +549,7 @@ return lvms def mount_information(reverse = False): - (cin, cout) = cmd_run(['mount']) - lines = cout.readlines() - cout.close() - cin.close() + lines = call(['mount']) or '' mounts = [] pattern = re.compile(r"^(\S+) on (.+) type (\S+) \((\S+)\)") if reverse: @@ -979,11 +967,14 @@ if cfg['retention'] and os.path.isdir(rdiff_logdir) and not cleanup: do_server_data_cleanup(cfg) + cmd = [] if cfg['host']: - cmd = 'ssh %s -T -i %s -l %s %s safekeep --client' % (verbosity_ssh, cfg['key_ctrl'], cfg['user'], cfg['host']) - else: - cmd = 'safekeep --client' - (cin, cout) = cmd_run(cmd) + cmd.extend(['ssh', verbosity_ssh, '-T', '-i', cfg['key_ctrl'], '-l', cfg['user'], cfg['host']) + cmd.extend(['safekeep', '--client']) + + proc = subprocess.Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) + cin = proc.stdin + cout = proc.stdout cin.write('ALOHA: %s, %s\n' % (PROTOCOL, VERSION)) cin.flush() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 14:56:52
|
Revision: 687 http://safekeep.svn.sourceforge.net/safekeep/?rev=687&view=rev Author: dimi Date: 2010-11-19 14:56:46 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Provide a more expressive function to call external commands and deal with the standard input/output. Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 14:41:04 UTC (rev 686) +++ safekeep/trunk/safekeep 2010-11-19 14:56:46 UTC (rev 687) @@ -112,7 +112,7 @@ else: return args -def do_spawn(args, shell=False, stdout=False): +def do_spawn(args, shell=False, stdin=None, stdout=False): global cmd argslist = args_to_list(args) cmd = argslist[0] @@ -124,6 +124,8 @@ # Otherwise split into separate elements. debug('Run [' + ' '.join(argslist) + ']') proc = subprocess.Popen(argslist, bufsize=1, shell=False, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) + if stdin: + proc.stdin.write(stdin) proc.stdin.close() lines=[] for line in proc.stdout: @@ -134,12 +136,14 @@ proc.stdout.close() return (proc.wait(), ''.join(lines)) -def spawn(args, shell=False): +def _spawn(args, shell=False, stdin=None, stdout=False): global cmd try: - rc, out = do_spawn(args, shell=shell) + rc, out = do_spawn(args, shell, stdin, stdout) except OSError, ex: - error("OSError: %s: %s" % (cmd, ex)) + ret = "OSError: %s" % (ex) + error('%s failed: %s' % (cmd, ret)); + return ret if not rc: ret = None @@ -151,8 +155,23 @@ ret = 'unknown exit status: %d' % rc if ret: error('%s failed: %s' % (cmd, ret)); - return ret + return (ret, out) +# this just spawns an external program (optionally through a shell) +# and returns True it it fails, and False if it successed +def spawn(args, shell=False): + rc, out = _spawn(args, shell) + return rc + +# this spawans an external program (optionally through a shell), +# feeds it any input via stdin, captures the output and returns it. +# if it fails it returns None, otherwise it returns the output +def call(args, shell=False, stdin=None): + rc, out = _spawn(args, shell, stdin, stdout=True) + if not rc: + return None + return out + def try_to_run(args): try: rc, out = do_spawn(args) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 14:41:10
|
Revision: 686 http://safekeep.svn.sourceforge.net/safekeep/?rev=686&view=rev Author: dimi Date: 2010-11-19 14:41:04 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Add ability to capture the output of a spawned proccess Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 08:57:27 UTC (rev 685) +++ safekeep/trunk/safekeep 2010-11-19 14:41:04 UTC (rev 686) @@ -112,7 +112,7 @@ else: return args -def do_spawn(args, shell=False): +def do_spawn(args, shell=False, stdout=False): global cmd argslist = args_to_list(args) cmd = argslist[0] @@ -125,15 +125,19 @@ debug('Run [' + ' '.join(argslist) + ']') proc = subprocess.Popen(argslist, bufsize=1, shell=False, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) proc.stdin.close() + lines=[] for line in proc.stdout: - info(line.rstrip()) + if stdout: + lines.append(line) + else: + info(line.rstrip()) proc.stdout.close() - return proc.wait() + return (proc.wait(), ''.join(lines)) def spawn(args, shell=False): global cmd try: - rc = do_spawn(args, shell=shell) + rc, out = do_spawn(args, shell=shell) except OSError, ex: error("OSError: %s: %s" % (cmd, ex)) @@ -151,7 +155,7 @@ def try_to_run(args): try: - rc = do_spawn(args) + rc, out = do_spawn(args) except OSError, ex: return False return rc in (0,1) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 08:57:33
|
Revision: 685 http://safekeep.svn.sourceforge.net/safekeep/?rev=685&view=rev Author: dimi Date: 2010-11-19 08:57:27 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Avoid subprocess where we can easily Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 08:34:35 UTC (rev 684) +++ safekeep/trunk/safekeep 2010-11-19 08:57:27 UTC (rev 685) @@ -149,9 +149,9 @@ error('%s failed: %s' % (cmd, ret)); return ret -def try_to_run(args, shell=False): +def try_to_run(args): try: - rc = do_spawn(args, shell=shell) + rc = do_spawn(args) except OSError, ex: return False return rc in (0,1) @@ -1104,7 +1104,7 @@ if backup_user is not work_user: gencmd = 'su -s /bin/sh -c %s - %s' % (commands.mkarg(gencmd), backup_user) debug(gencmd) - if subprocess.Popen(gencmd, shell=True).wait(): + if os.system(gencmd): error('%s: Failed to generate key %s. Skipping client.' % (id, privatekeyfile)) break if not os.path.isfile(publickeyfile): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 08:34:41
|
Revision: 684 http://safekeep.svn.sourceforge.net/safekeep/?rev=684&view=rev Author: dimi Date: 2010-11-19 08:34:35 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Use the Popen call directly Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 08:30:06 UTC (rev 683) +++ safekeep/trunk/safekeep 2010-11-19 08:34:35 UTC (rev 684) @@ -1104,7 +1104,7 @@ if backup_user is not work_user: gencmd = 'su -s /bin/sh -c %s - %s' % (commands.mkarg(gencmd), backup_user) debug(gencmd) - if subprocess.call(gencmd, shell=True): + if subprocess.Popen(gencmd, shell=True).wait(): error('%s: Failed to generate key %s. Skipping client.' % (id, privatekeyfile)) break if not os.path.isfile(publickeyfile): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 08:30:12
|
Revision: 683 http://safekeep.svn.sourceforge.net/safekeep/?rev=683&view=rev Author: dimi Date: 2010-11-19 08:30:06 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Simpler Modified Paths: -------------- safekeep/trunk/ANNOUNCE Modified: safekeep/trunk/ANNOUNCE =================================================================== --- safekeep/trunk/ANNOUNCE 2010-11-19 07:38:15 UTC (rev 682) +++ safekeep/trunk/ANNOUNCE 2010-11-19 08:30:06 UTC (rev 683) @@ -17,11 +17,9 @@ Thanks go to Frank Crawford and Bertrand Lecervoisier for providing patches and reports for the problems addressed in this release. -Because of lags created by using mirrors, this message may reach you before -the release is available at the public sites. Sources and binaries will be -available from the following locations: +Sources and binaries are available from the following locations: - - RedHat EL/CentOS 3-6 Fedora 4-14: + - RedHat EL/CentOS 5,6 Fedora 8,9,10,11,12,13,14: http://prdownloads.sourceforge.net/safekeep/safekeep-common-1.3.0-1.noarch.rpm http://prdownloads.sourceforge.net/safekeep/safekeep-client-1.3.0-1.noarch.rpm http://prdownloads.sourceforge.net/safekeep/safekeep-server-1.3.0-1.noarch.rpm @@ -38,14 +36,6 @@ To find out more about the project visit on our website: http://safekeep.sourceforge.net -You can also get the current source directly from the Subversion (SVN) -repositories: - http://safekeep.sourceforge.net/download.shtml#svn - -Patches should be submitted to "saf...@li...". -Please don't forget to include a ChangeLog entry. If you submitted a patch, -please check to make sure it has been included in the new release. - -- Dimi Paun <di...@la...> Lattica, Inc. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 07:38:23
|
Revision: 682 http://safekeep.svn.sourceforge.net/safekeep/?rev=682&view=rev Author: dimi Date: 2010-11-19 07:38:15 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Tag safekeep 1.3.0 Added Paths: ----------- safekeep/tags/Release-safekeep-1_3_0/ safekeep/tags/Release-safekeep-1_3_0/safekeep Removed Paths: ------------- safekeep/tags/Release-safekeep-1_3_0/safekeep Deleted: safekeep/tags/Release-safekeep-1_3_0/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 07:32:28 UTC (rev 680) +++ safekeep/tags/Release-safekeep-1_3_0/safekeep 2010-11-19 07:38:15 UTC (rev 682) @@ -1,1488 +0,0 @@ -#!/usr/bin/env python - -# Copyright (C) 2006-2010 Lattica, Inc. -# -# SafeKeep is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# Safekeep is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Safekeep. If not, see <http://www.gnu.org/licenses/>. - -from __future__ import generators -import getopt, os, os.path, re, sys, fnmatch, stat -import subprocess -import commands, tempfile, time, traceback -import getpass, pwd, xml.dom.minidom -import socket, smtplib - -from subprocess import PIPE, STDOUT - -###################################################################### -# Global settings -###################################################################### - -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 = {} -cmd = "<Missing>" - -PROTOCOL = "1.1" -VERSION = "1.3.0" -VEBOSITY_BY_CLASS = {'DBG': 3, 'INFO': 2, 'WARN': 1, 'ERR': 0} - -###################################################################### -# Miscellaneous support functions -###################################################################### - -def send(msg): - print msg.encode('utf-8') - sys.stdout.flush() - -def log(msg, cls=None): - global logbuf - if cls: - if is_client: cls = cls.lower() - msg = '%s: %s' % (cls, msg) - else: - for c in VEBOSITY_BY_CLASS.keys(): - if msg.startswith(c + ': '): - cls = c - break - else: - cls = 'UNK' - - cutoff = VEBOSITY_BY_CLASS.get(cls.upper()) - if cutoff is None: cutoff = 3 - if is_client or verbosity_level >= cutoff: - logbuf.append(msg) - if is_client: - send(msg) - else: - print >> sys.stderr, msg.encode('utf-8') - -def info_file(file, marker=None): - info('## File: ' + file) - errs = 0; - fin = open(file, 'r') - try: - for line in fin.readlines(): - if marker: - if line.startswith(marker): - marker = None - continue - if line.startswith("Errors "): - errs = int(line[6:]) - info(line.rstrip()) - finally: - fin.close() - return errs - -def debug(msg): - log(msg, 'DBG') - -def info(msg): - log(msg, 'INFO') - -def warn(msg): - log(msg, 'WARN') - -def error(msg): - log(msg, 'ERR') - -def args_to_list(args): - if isinstance(args, str) or isinstance(args, unicode): - return args.split(None) - else: - return args - -def do_spawn(args, shell=False): - global cmd - argslist = args_to_list(args) - cmd = argslist[0] - if shell: - # If passed to a shell then give args exactly as specified. - debug('Run [' + args + ']') - proc = subprocess.Popen(args, bufsize=1, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) - else: - # Otherwise split into separate elements. - debug('Run [' + ' '.join(argslist) + ']') - proc = subprocess.Popen(argslist, bufsize=1, shell=False, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) - proc.stdin.close() - for line in proc.stdout: - info(line.rstrip()) - proc.stdout.close() - return proc.wait() - -def spawn(args, shell=False): - global cmd - try: - rc = do_spawn(args, shell=shell) - except OSError, ex: - error("OSError: %s: %s" % (cmd, ex)) - - if not rc: - ret = None - elif rc > 0: - ret = 'exited with non zero status: %d' % rc - elif rc < 0: - ret = 'killed by signal: %d' % -rc - else: - ret = 'unknown exit status: %d' % rc - if ret: - error('%s failed: %s' % (cmd, ret)); - return ret - -def try_to_run(args, shell=False): - try: - rc = do_spawn(args, shell=shell) - except OSError, ex: - return False - return rc in (0,1) - -def cmd_run(args): - argslist = args_to_list(args) - debug('Run [' + ' '.join(argslist) + ']') - p = subprocess.Popen(argslist, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) - return (p.stdin, p.stdout) - -def send_notification(email, smtp): - global logbuf - if not logbuf: return - info('Sending email to %s via %s' % (','.join(email), smtp)) - hostname = socket.gethostname() - msg = 'From: SafeKeep@' + hostname + \ - '\r\nTo: ' + ', '.join(email) + \ - '\r\nSubject: SafeKeep results for ' + hostname + \ - '\r\n\r\n' + '\r\n'.join(logbuf) - if smtp: - server = smtplib.SMTP(smtp) - server.sendmail('SafeKeep@' + hostname, email, msg) - server.quit() - else: - cmd = ['/usr/sbin/sendmail', '-t'] - pin = subprocess.Popen(cmd, stdin=PIPE).stdin - try: - pin.write(msg) - finally: - pin.close() - -def is_temp_root(dir): - return dir != '/' - -def reroot(root, path): - if root == '/': return path - if root.endswith('/'): root = root[:-1] - if not path: return root - if path.startswith('/'): return root + path - return os.path.join(root, path) - -def parse_prop_file(file): - props = {} - fin = open(file) - lines = fin.readlines() - fin.close() - for line in lines: - line = line.strip() - if len(line) is 0 or line[0] is '#': continue - if '=' in line: - key, value = line.split('=', 1) - props[key.strip()] = value.strip() - else: - props[line] = None - return props - -###################################################################### -# Configuration file parser -###################################################################### - -class ConfigException (Exception): - def __init__(self, value): - self.value = value - def __str__(self): - return repr(self.value) - -def parse_dump(dump_el): - type = dump_el.getAttribute('type') - if not type: - raise ConfigException('You need to specify the database type') - if type not in ('postgres', 'postgresql', 'pgsql', 'mysql'): - raise ConfigException('Invalid database type: %s' % type) - db = dump_el.getAttribute('db') - user = dump_el.getAttribute('user') - dbuser = dump_el.getAttribute('dbuser') - dbpasswd = dump_el.getAttribute('dbpasswd') - opts = (dump_el.getAttribute('options') or '').split() - - file = dump_el.getAttribute('file') - if not file: - raise ConfigException('You need to specify where the database should be dumped') - cleanup = dump_el.getAttribute('cleanup') - return { 'type' : type, 'db' : db, 'user' : user, 'dbuser' : dbuser, 'dbpasswd': dbpasswd, - 'opts' : opts, 'file' : file, 'cleanup' : cleanup } - -def parse_snap(snap_el): - device = snap_el.getAttribute('device') - if not device: - raise ConfigException('Please specify the device to be snapshot') - if device.rfind('/') == -1 or device.endswith('/'): - raise ConfigException('The device name seems incorrect: ' + device) - size = snap_el.getAttribute('size') - if not size: - raise ConfigException('Please specify the size for the snapshot') - return { 'device' : device, 'size' : size } - -def parse_clude(clude_el): - path = clude_el.getAttribute('path') - path = path.replace('*', '\*').replace('?', '\?') - path = path.replace('[', '\[').replace(']', '\]') - glob = clude_el.getAttribute('glob') - regexp = clude_el.getAttribute('regexp') - if not path and not glob and not regexp: - 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_data_attributes(data_el): - return { - 'exclude-devices': (data_el.getAttribute('exclude-devices') or 'false'), - 'exclude-sockets': (data_el.getAttribute('exclude-sockets') or 'false'), - 'exclude-fifos': (data_el.getAttribute('exclude-fifos') or 'false') - } - -def parse_config(backup_el, dflt_id): - if backup_el.tagName != 'backup': - raise ConfigException('Invalid config file, the top level element must be <backup>') - id = backup_el.getAttribute('id') - if not id: id = dflt_id - - host_el = backup_el.getElementsByTagName('host') - if host_el: - host = host_el[0].getAttribute('name') - user = host_el[0].getAttribute('user') - nice = host_el[0].getAttribute('nice') - key_ctrl = host_el[0].getAttribute('key-ctrl') - key_data = host_el[0].getAttribute('key-data') - else: - host = user = key_ctrl = key_data = None - if host and not user: - user = 'root' - if host and not key_ctrl: - key_ctrl = os.path.join('.ssh', 'safekeep-server-ctrl-key') - if host and not key_data: - key_data = os.path.join('.ssh', 'safekeep-server-data-key') - if key_ctrl and not os.path.isabs(key_ctrl): - key_ctrl = os.path.join(home_dir, key_ctrl) - 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 one bandwidth element') - - repo_el = backup_el.getElementsByTagName('repo') - dir = None - retention = None - if len(repo_el) == 1: - dir = repo_el[0].getAttribute('path') - retention = repo_el[0].getAttribute('retention') - elif len(repo_el) > 1: - raise ConfigException('Can not have more than one repo element') - if not dir: dir = id - dir = os.path.join(base_dir, dir) - - options_els = backup_el.getElementsByTagName('options') - options = [] - if len(options_els) > 0: - for options_el in options_els[0].childNodes: - if options_el.nodeType != options_el.ELEMENT_NODE: - continue - option = options_el.nodeName - if option == 'special-files': - warn('options element special-files is deprecated, use data attributes instead') - if option in ('special-files', 'rdiff-backup'): - if options_el.hasAttributes(): - for key, value in options_el.attributes.items(): - options.append({ option : { key : value } }) - else: - raise ConfigException('Option "%s" has no value' % option) - else: - raise ConfigException('Unknown option "%s"' % option) - - setup_el = backup_el.getElementsByTagName('setup') - dumps = [] - snaps = [] - script = None - if len(setup_el) > 0: - dump_els = setup_el[0].getElementsByTagName('dump') - for dump_el in dump_els: - dumps.append(parse_dump(dump_el)) - snap_els = setup_el[0].getElementsByTagName('snapshot') - for snap_el in snap_els: - snaps.append(parse_snap(snap_el)) - script_el = setup_el[0].getElementsByTagName('script') - if len(script_el) == 1: - script = script_el[0].getAttribute('path') - elif len(script_el) > 1: - raise ConfigException('Can not have more than one setup script element') - - data_options = {} - data_el = backup_el.getElementsByTagName('data') - - if len(data_el) == 1: - data_options = parse_data_attributes(data_el[0]) - child_els = data_el[0].childNodes - cludes = [] - for child_el in child_els: - if child_el.nodeType != child_el.ELEMENT_NODE: - continue - if child_el.tagName not in ('include', 'exclude'): - continue - cludes.append(parse_clude(child_el)) - cludes.append({ 'type' : 'exclude', 'path' : '', 'glob' : '', 'regexp' : '.*' }) - elif len(data_el) > 1: - raise ConfigException('Can not have more than one data element') - else: - path_xcludes = [ '/dev/', '/media/', '/mnt/', '/net/', '/proc/', '/selinux/', '/sys/', - '/tmp/', '/var/cache', '/var/lock', '/var/run', '/var/tmp', - '/var/named/chroot/dev', '/var/named/chroot/proc', - '/var/named/chroot/var/run', '/var/named/chroot/var/tmp' ] - cludes = [{ 'type' : 'exclude', 'path' : path, 'glob' : None, 'regexp' : None } for path in path_xcludes] - - return { 'id': id, 'host' : host, 'nice' : nice, 'user' : user, 'key_ctrl' : key_ctrl, 'key_data' : key_data, - 'dir' : dir, 'retention' : retention, 'dumps' : dumps, 'snaps' : snaps, 'script' : script, - 'cludes' : cludes, 'data_options' : data_options, 'options' : options, 'bw' : bw} - -def parse_locs(cfglocs): - cfgfiles = [] - for cfg in cfglocs: - if os.path.isdir(cfg): - for ent in os.listdir(cfg): - if not ent.endswith(config_ext): - warn('Ignoring file %s not ending in %s' % (os.path.join(cfg, ent), config_ext)) - continue - filepath = os.path.join(cfg, ent) - if not os.path.isfile(filepath): - continue - cfgfiles.append(filepath) - elif os.path.isfile(cfg): - cfgfiles.append(cfg) - else: - warn('Inaccessible configuration, ignoring: %s' % cfg) - - cfgs = {} - for filepath in cfgfiles: - filename = os.path.splitext(os.path.basename(filepath))[0] - - cfg_file = open(filepath) - cfg_str = cfg_file.read().strip() - cfg_file.close() - - dom = xml.dom.minidom.parseString(cfg_str) - try: - cfg = parse_config(dom.documentElement, filename) - finally: - dom.unlink() - cfg['text'] = cfg_str - if cfg['id'] in cfgs: - raise ConfigException('Duplicate client ID: %s' % cfg['id']) - cfgs[cfg['id']] = cfg - - return cfgs - -###################################################################### -# Script, DB and SNAPSHOT support -# setup methods can raise exception to signal errors -# teardown methods must succeed and cleanup the state -###################################################################### - -def check_script_permissions(script): - if not os.path.isfile(script): - return '%s is not a regular file' % script - if not os.access(script, os.X_OK): - return '%s is not executable' % script - - statinfo = os.stat(script) - if statinfo.st_uid and statinfo.st_uid != os.getuid(): - return '%s is owned by others' % script - - if (statinfo.st_mode & (stat.S_IWGRP | stat.S_IWOTH)): - return '%s is writable by others' % script - - return None - -def client_side_script(step, cfg, bdir): - debug('Do client_side_script: step %s' % step) - - ret = None - script = cfg['script'] - - if script: - debug('client_side_script: script = %s' % script) - if os.path.exists(script): - ret = check_script_permissions(script) - if not ret: - ret = spawn([script, step, cfg['id'], bdir]) - else: - debug('client_side_script: %s not found' % script) - - return ret - -def do_client_dbdump(cfg): - debug('Doing DB dumps') - for dump in cfg['dumps']: - type = dump['type'] - opts = dump['opts'] - passwdfile = None - if type in ('postgres', 'postgresql', 'pgsql'): - if dump['db']: - args = ['pg_dump'] - args.extend(['-C']) - else: - args = ['pg_dumpall'] - if dump['dbuser']: - args.extend(['-U', dump['dbuser']]) - args.extend(opts) - if dump['db']: - args.extend([dump['db']]) - if dump['dbpasswd']: - (fd, passwdfile) = tempfile.mkstemp() - f = os.fdopen(fd, 'w') - f.write(dump['dbpasswd']) - f.close() - - elif type in ('mysql'): - args = ['mysqldump'] - if dump['dbuser']: - args.extend(['-u', dump['dbuser']]) - if dump['dbpasswd']: - args.extend(['-p%s' % dump['dbpasswd']]) - if not dump['db']: - args.extend(['-A']) - args.extend(opts) - if dump['db']: - args.extend([dump['db']]) - - else: - warn('Invalid database type: ' + type) - continue - - if dump['user']: - cmd = ' '.join([commands.mkarg(arg) for arg in args]) - args = [ 'su', '-c', cmd, '-', dump['user'] ] - cmd = ' '.join([commands.mkarg(arg) for arg in args]) - cmd = '%s > %s' % (cmd, commands.mkarg(dump['file'])) - - - if passwdfile: - os.environ['PGPASSFILE'] = passwdfile - try: - ec = spawn(cmd, shell=True) - finally: - if passwdfile: - del os.environ['PGPASSFILE'] - os.remove(passwdfile) - if ec: - warn('Can not dump the database: %s' % dump['db']) - -def do_client_dbdump_teardown(cfg): - debug('Tear down DB dumps') - for dump in cfg['dumps']: - if dump['cleanup'].lower() != 'true': - continue - try: - os.remove(dump['file']) - except Exception, e: - warn('Unable to remove dump file: %s for database %s because: %s' % - (dump['file'], dump['db'], e)) - -def lvm_snap_information(): - (cin, cout) = cmd_run(['lvs', '--separator', ':', '--noheadings']) - lines = cout.readlines() - cout.close() - cin.close() - lvms = [] - for line in lines: - if line.count(':') > 3: - (volume, group, attr, blah1) = line.lstrip().split(':', 3) - if fnmatch.fnmatch(volume, '*_snap_safekeep-*') and attr[0].lower() == 's': - lvms.append([volume, group]) - return lvms - -def mount_information(reverse = False): - (cin, cout) = cmd_run(['mount']) - lines = cout.readlines() - cout.close() - cin.close() - mounts = [] - pattern = re.compile(r"^(\S+) on (.+) type (\S+) \((\S+)\)") - if reverse: - lines.reverse() - for line in lines: - matches = pattern.match(line) - if not matches is None: - mounts.append(matches.groups()) - return mounts - -def map_lvm_device(device): - device = device.replace('/mapper','').replace('-','/').replace('//', '-') - return device.split('/')[-2:] - -def check_lvm_information(device): - (group, volume) = map_lvm_device(device) - for (lvm_volume, lvm_group) in lvm_snap_information(): - if lvm_group == group and lvm_volume.startswith(volume): - return True - return False - -def gather_lvm_information(device): - (group, volume) = map_lvm_device(device) - for (device, mountpoint, mounttype, mountoptions) in mount_information(False): - if [group, volume] == map_lvm_device(device): - return (group, volume, mountpoint, mounttype) - return (None, None, None, None) - -def gather_snap_information(device, bdir): - (group, volume, mountpoint, mounttype) = gather_lvm_information(device) - if not mountpoint: return (None, None, None, None) - lvmdev = os.path.join('/dev', group, volume) - if bdir[-1] == '/': bdir = bdir[:-1] - snapname = '%s_snap_%s' % (volume, os.path.basename(bdir)) - snapdev = os.path.join('/dev', group, snapname) - if os.path.isabs(mountpoint[0]): mountpoint = mountpoint[1:] - return (lvmdev, snapdev, os.path.join(bdir, mountpoint), mounttype) - -def do_client_snap(cfg, bdir): - assert is_temp_root(bdir) - debug('Doing FS snapshots') - for snap in cfg['snaps']: - device = snap['device'] - (lvmdev, snapdev, snapmnt, snaptyp) = gather_snap_information(device, bdir) - if not snapmnt: - warn('Cannot find the mountpoint for: %s' % device) - continue - args = ['lvcreate', '--snapshot', '--size', snap['size'], - '--name', os.path.basename(snapdev), lvmdev] - ec = spawn(args) - if ec: - warn('Can not snapshot the device: %s' % device) - continue - # no need to mkdir since the mountpoint already exists - args = ['mount', '-t', snaptyp, snapdev, snapmnt] - ec = spawn(args) - if ec: - warn('Can not mount the snapshot: %s' % device) - ret = spawn(['lvremove', '--force', snapdev]) - if ret: - warn('Can not tear down snapshot: %s' % device) - -def do_client_snap_teardown(cfg, bdir): - assert is_temp_root(bdir) - debug('Tear down FS snapshots dumps') - snaps = list(cfg['snaps']) - snaps.reverse() - for snap in snaps: - device = snap['device'] - (lvmdev, snapdev, snapmnt, snaptyp) = gather_snap_information(device, bdir) - if not snapmnt: - warn('Can not find the mountpoint for: %s' % device) - continue - ret = spawn(['umount', snapmnt]) - if ret: - warn('Can not umount the snapshot: %s' % snapmnt) - - # stupid workaround for https://bugzilla.redhat.com/show_bug.cgi?id=577798 - for i in range(1,10): - ret = spawn(['lvremove', '--force', snapdev]) - if not ret: - break - - if ret: - warn('Can not tear down snapshot: %s' % device) - -###################################################################### -# Client implementation -###################################################################### - -def do_client_config(cmd): - cfgStr = '' - - (cfg_cmd, cnt_str, dflt_id) = cmd.split(':', 2) - for i in xrange(int(cnt_str)): - line = sys.stdin.readline() - if not line: raise ConfigException('Unexpected end of file') - cfgStr += line - - dom = xml.dom.minidom.parseString(cfgStr) - try: - return parse_config(dom.documentElement, dflt_id) - finally: - dom.unlink() - -def do_client_setup(cfg): - debug('Do setup of %s' % cfg['host']) - - do_client_dbdump(cfg) - - if len(cfg['snaps']) > 0: - debug('Checking FS snapshots') - for snap in cfg['snaps']: - device = snap['device'] - if check_lvm_information(device): - raise Exception("Previous snapshots found for %s: run 'safekeep --server --cleanup' to correct" % device) - - ret = spawn(['modprobe', 'dm-snapshot']) - if ret: - warn('modprobe dm-snapshot failed, continuing') - bdir = tempfile.mkdtemp("-rbind", "safekeep-", "/mnt") - ret = spawn(['mount', '--rbind', '/', bdir]) - if ret: - warn('mount --rbind failed, snapshotting will be disabled') - try: - os.rmdir(bdir) - except Exception, e: - warn('Failed to remove: %s' % bdir) - bdir = '/' - else: - do_client_snap(cfg, bdir) - else: - bdir = '/' - debug('Working root is %s' % bdir) - - return bdir - -def do_client_cleanup(cfg, bdir): - debug('Do cleanup of %s in %s' % (cfg['host'], bdir)) - if is_temp_root(bdir): - do_client_snap_teardown(cfg, bdir) - - ret = spawn(['umount', '-l', bdir]) - if ret: - warn('Failed to unmount: %s' % bdir) - else: - try: - os.rmdir(bdir) - except Exception, e: - warn('Unable to remove: ' + bdir) - - do_client_dbdump_teardown(cfg) - -def do_client_compat(server_versions): - debug('Server versions: %s' % server_versions) - -def do_client_scrub(): - debug("Do client scrub loop") - - if os.getuid(): - if is_client: - raise Exception('client not running as root') - else: - warn('--cleanup should be run as root on client') - info('No cleanup performed') - else: - scrubbed = False - - if os.environ['PATH'][-1] == ':': - os.environ['PATH'] += '/sbin:/usr/sbin:/usr/local/sbin:' - else: - os.environ['PATH'] += ':/sbin:/usr/sbin:/usr/local/sbin' - - # Go through and unmount anythings that are still hanging around - - debug("Cleaning up existing mounts") - for (device, mountpoint, mounttype, mountoptions) in mount_information(True): - if mountpoint.startswith('/mnt/safekeep-'): - info("Removing mount %s" % mountpoint) - if device == '/' and 'bind' in mountoptions.split(','): - info("Removing rbind directory %s" % mountpoint) - ret = spawn(['umount', '-l', mountpoint]) - if ret: - warn('Failed to unmount: %s' % mountpoint) - else: - try: - os.rmdir(mountpoint) - except Exception, e: - warn('Failed to remove: %s' % mountpoint) - else: - ret = spawn(['umount', mountpoint]) - if ret: - warn('Can not unmount the snapshot: %s' % mountpoint) - if fnmatch.fnmatch(device, '*_snap_safekeep-*'): - info("Removing snapshot %s" % device) - ret = spawn(['lvremove', '--force', device]) - if ret: - warn('Can not tear down snapshot: %s' % device) - scrubbed = True - - # Now cleanup any snapshots still hanging around - - debug("Cleaning up remaining snapshots") - for (volume, group) in lvm_snap_information(): - device = os.path.join('/dev', group, volume) - info("Removing snapshot %s" % device) - ret = spawn(['lvremove', '--force', device]) - if ret: - warn('Can not tear down snapshot: %s' % device) - scrubbed = True - - # Now cleanup any safekeep directories still hanging around - - debug("Cleaning up remaining safekeep directories") - if os.path.isdir('/mnt'): - for ent in os.listdir('/mnt'): - mountpoint = os.path.join('/mnt', ent) - if ent.startswith('safekeep-') and os.path.isdir(mountpoint): - info("Removing rbind directory %s" % mountpoint) - try: - os.rmdir(mountpoint) - except Exception, e: - warn('Failed to remove: %s' % mountpoint) - - if not scrubbed: - info('No cleanup required') - -def do_client(): - debug("Do client main loop") - should_cleanup = True - bdir = '/' - try: - while True: - try: - line = sys.stdin.readline() - if line.startswith('ALOHA'): - do_client_compat(line.strip().split(':', 1)[1]) - send('OK %s, %s' % (PROTOCOL, VERSION)) - elif line.startswith('CONFIG'): - cfg = do_client_config(line) - ret = client_side_script('STARTUP', cfg, bdir) - if ret: - send('ERROR Client-side setup script failed: %s' % ret) - else: - send('OK') - elif line.startswith('SETUP'): - client_side_script('PRE-SETUP', cfg, bdir) - bdir = do_client_setup(cfg) - client_side_script('POST-SETUP', cfg, bdir) - send('OK ' + bdir) - elif line.startswith('CLEANUP'): - dir = line[7:].strip() - if dir == bdir: should_cleanup = False - do_client_cleanup(cfg, dir) - client_side_script('POST-BACKUP', cfg, bdir) - send('OK') - elif line.startswith('SCRUB'): - do_client_scrub() - client_side_script('POST-SCRUB', cfg, bdir) - send('OK') - elif not line: - break - else: - send('ERROR Unknown command: %s' % line) - break - except Exception, e: - traceback.print_exc(file=sys.stdout) - send('ERROR %s' % e) - finally: - if should_cleanup: - do_client_cleanup(cfg, bdir) - - -###################################################################### -# Server implementation -###################################################################### - -def do_server_getanswer(cout): - while True: - line = cout.readline() - if line.startswith('OK'): - return line[2:-1].strip() - elif line.startswith('ERROR'): - raise Exception(line[5:].strip()) - elif not line: - raise Exception('client died unexpectedly') - else: - log(line[:-1]) - -def do_server_rdiff(cfg, bdir, nice, force): - args = [] - - if nice: - args.extend(['nice', '-n' + str(nice)]) - - args.extend(['rdiff-backup']) - - if cfg['host']: - 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 ' + str(limit_dl) - if limit_ul: - trickle += ' -u ' + str(limit_ul) - - if trickle: - if not try_to_run(trickle_cmd + ' -V'): - warn('Trickle not available, bandwidth limiting disabled') - trickle = '' - - schema = '%s ssh %s -i %s %%s rdiff-backup --server' % (trickle, verbosity_ssh, cfg['key_data']) - args.extend(['--remote-schema', schema]) - - if force: - args.extend(['--force']) - - options_append = [] - - special_files = [] - if cfg['data_options'].get('exclude-devices').lower() == 'true': - special_files.extend(['--exclude-device-files']) - if cfg['data_options'].get('exclude-sockets').lower() == 'true': - special_files.extend(['--exclude-sockets']) - if cfg['data_options'].get('exclude-fifos').lower() == 'true': - special_files.extend(['--exclude-fifos']) - - for option in cfg['options']: - if 'special-files' in option: - if 'include' in option['special-files']: - if 'true' == option['special-files']['include'].lower(): - special_files = ['--include-special-files'] - - # Note if we ever add other backends this section should only be run - # when rback-diff is the current option. - - if 'rdiff-backup' in option: - if 'append' in option['rdiff-backup']: - options_append.extend(option['rdiff-backup']['append'].split(None)) - - args.extend(special_files) - args.extend(options_append) - - for clude in cfg['cludes']: - opt = '--' + clude['type'] - if clude['path']: - args.extend([opt, reroot(bdir, clude['path'])]) - if clude['glob']: - args.extend([opt, reroot(bdir, clude['glob'])]) - if clude['regexp']: - args.extend([opt + '-regexp', bdir + clude['regexp']]) - - userhost = '' - if cfg['host']: - userhost = '%s@%s' % (cfg['user'], cfg['host']) - args.extend([userhost + '::' + bdir, cfg['dir']]) - ret = spawn(args) - if ret: - raise Exception('Failed to run rdiff-backup') - -def do_server_rdiff_cleanup(cfg): - args = ['rdiff-backup', '--check-destination-dir', cfg['dir']] - ret = spawn(args) - if ret: - warn('Failed to cleanup old data, please fix the problem manually') - -def do_server_data_cleanup(cfg): - args = ['rdiff-backup', '--force', '--remove-older-than', cfg['retention'], cfg['dir']] - ret = spawn(args) - if ret: - warn('Failed to cleanup old data, please fix the problem manually') - -def do_server_compat(client_versions): - (client_protocol, client_version) = client_versions.split(',') - (client_major, client_minor) = client_protocol.strip().split('.') - (server_major, server_minor) = PROTOCOL.split('.') - if server_major != client_major: - raise Exception('Incompatible protocols: %s <> %s' % (PROTOCOL, client_protocol)) - elif server_minor > client_minor: - warn('Protocol mismatch: %s <> %s' % (PROTOCOL, client_protocol)) - -def do_server(cfgs, ids, nice, force, cleanup): - debug("Do server main loop") - for cfg in cfgs.itervalues(): - id = cfg['id'] - if ids and id not in ids: continue - info('------------------------------------------------------------------') - info('Server backup starting for client %s' % id) - - cleaned_up = 0 - try: - if cfg['host']: - if not os.path.isfile(cfg['key_ctrl']): - raise Exception('Client %(id)s missing ctrl key %(key_ctrl)s' % cfg) - if not os.path.isfile(cfg['key_data']): - raise Exception('Client %(id)s missing data key %(id)s' % cfg) - - datadir = os.path.join(os.getcwd(), cfg['dir']) - if not os.path.isdir(datadir): - try: - os.makedirs(datadir) - except EnvironmentError, ex: - raise Exception('Can not create data store dir: %s' % datadir) - - rdiff_logdir = os.path.join(datadir, 'rdiff-backup-data') - if cfg['retention'] and os.path.isdir(rdiff_logdir) and not cleanup: - do_server_data_cleanup(cfg) - - if cfg['host']: - cmd = 'ssh %s -T -i %s -l %s %s safekeep --client' % (verbosity_ssh, cfg['key_ctrl'], cfg['user'], cfg['host']) - else: - cmd = 'safekeep --client' - (cin, cout) = cmd_run(cmd) - - cin.write('ALOHA: %s, %s\n' % (PROTOCOL, VERSION)) - cin.flush() - client_versions = do_server_getanswer(cout) - do_server_compat(client_versions) - - cin.write('CONFIG: %d: %s\n' % (len(cfg['text'].splitlines()), id)) - cin.write(cfg['text'] + '\n') - cin.flush() - do_server_getanswer(cout) - if cleanup: - cin.write('SCRUB\n') - cin.flush() - do_server_getanswer(cout) - bdir = '/' # Fake directory for the rest of the cleanup - do_server_rdiff_cleanup(cfg) - cleaned_up = 1 - errs = 0 - else: - cin.write('SETUP\n') - cin.flush() - bdir = do_server_getanswer(cout) - - if os.path.isdir(rdiff_logdir): - rdiff_logpre = os.listdir(rdiff_logdir) - else: - rdiff_logpre = [] - - backup_log = os.path.join(rdiff_logdir, 'backup.log') - if os.path.isfile(backup_log): - backup_marker = '=== Backup session on %s ===' % time.asctime() - fbm = open(backup_log, 'a') - fbm.write(backup_marker + '\n') - fbm.close() - else: - backup_marker = None - - do_server_rdiff(cfg, bdir, nice, force) - - errs = 0 - if os.path.isdir(rdiff_logdir): - info_file(backup_log, backup_marker) - rdiff_logpost = os.listdir(rdiff_logdir) - for lfn in rdiff_logpost: - if lfn.startswith('session_statistics.') and lfn.endswith('.data') and lfn not in rdiff_logpre: - errs += info_file(os.path.join(rdiff_logdir, lfn)) - else: - warn('Log dir does not exist.') - - cin.write('CLEANUP %s\n' % bdir) - cin.flush() - do_server_getanswer(cout) - - if errs == 0: - info('Server backup for client %s: OK' % id) - else: - info('Server backup for client %s: OK (%d WARNINGS)' % (id, errs)) - - except Exception, e: - if cleanup and not cleaned_up: - info('Client-side cleanup for client %s: FAILED' % id) - do_server_rdiff_cleanup(cfg) - else: - error(e) - error('Server backup for client %s: FAILED' % id) - - info('------------------------------------------------------------------') - debug('Server backup done') - -def do_list(cfgs, ids, list_type, list_date, list_parsable): - debug("Do server listing main loop") - for cfg in cfgs.itervalues(): - id = cfg['id'] - if ids and id not in ids: continue - if list_parsable: - info('Client: %s' % id) - else: - info('------------------------------------------------------------------') - info('Server listing for client %s' % id) - - - args = ['rdiff-backup'] - - if list_type is 'increments': - args.extend(['--list-increments']) - elif list_type is 'sizes': - args.extend(['--list-increment-sizes']) - elif list_type is 'changed': - args.extend(['--list-changed-since', list_date]) - elif list_type is 'attime': - args.extend(['--list-at-time', list_date]) - else: - assert False, 'Unknown list type: ' + list_type - - if list_parsable: - args.extend(['--parsable-output']) - - args.extend([cfg['dir']]) - ret = spawn(args) - if ret: - raise Exception('Failed to run rdiff-backup') - - if not list_parsable: - info('------------------------------------------------------------------') - debug('Server listing done') - -def do_keys(cfgs, ids, nice_rem, identity, status, dump, deploy): - for cfg in cfgs.itervalues(): - id = cfg['id'] - if ids and id not in ids: continue - info('Handling keys for client: %s' % id) - if not cfg['host']: - info('%s: Client is local, it needs no keys' % id) - continue - - nice = cfg['nice'] or nice_rem - if nice: - nice_cmd = 'nice -n%s ' % (nice) - else: - nice_cmd = '' - - cmds = ['safekeep --client', 'rdiff-backup --server --restrict-read-only /'] - privatekeyfiles = [cfg.get('key_ctrl'), cfg.get('key_data')] - lines = [] - keys_ok = False - for (cmd, privatekeyfile) in zip(cmds, privatekeyfiles): - publickeyfile = privatekeyfile + '.pub' - if not os.path.isfile(privatekeyfile): - if os.path.isfile(publickeyfile): - error('%s: Public key exists %s, but private key is missing. Skipping client.' % (id, publickeyfile)) - break - if dump: - print '%s: Key does not exist: %s.' % (id, privatekeyfile) - break - if status: - print '%s: Key does not exist: %s. Will be generated.' % (id, privatekeyfile) - break - if deploy: - info('%s: Key do not exist, generating it now: %s' % (id, privatekeyfile)) - gencmd = 'ssh-keygen -q -b 1024 -t dsa -N "" -C "SafeKeep auto generated key at %s@%s" -f %s' % (backup_user, os.uname()[1], privatekeyfile) - if backup_user is not work_user: - gencmd = 'su -s /bin/sh -c %s - %s' % (commands.mkarg(gencmd), backup_user) - debug(gencmd) - if subprocess.call(gencmd, shell=True): - error('%s: Failed to generate key %s. Skipping client.' % (id, privatekeyfile)) - break - if not os.path.isfile(publickeyfile): - error('%s: Private key exists %s, but public key is missing. Skipping client.' % (id, privatekeyfile)) - break - fin = open(publickeyfile, 'r') - publickey = fin.read() - fin.close() - line = 'command="%s%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s' % (nice_cmd, cmd, publickey.strip()) - lines.append(line) - else: - keys_ok = True - - if not keys_ok: - continue - - output = '\n'.join(lines) - if dump: - print output - - basessh = 'ssh' - if identity: basessh += ' -i %s' % (commands.mkarg(identity)) - - if status or deploy: - cmd = '%s %s@%s "if test -f .ssh/authorized_keys; then cat .ssh/authorized_keys; fi"' % (basessh, cfg['user'], cfg['host']) - debug(cmd) - out = subprocess.Popen(cmd, shell=True, stdout=PIPE).stdout - authtext = out.read() - if out.close(): - warn('%s: Failed to read the authorized_keys file.' % id) - auth_keys = parse_authorized_keys(authtext) - this_keys = parse_authorized_keys(output) - new_keys = [] - for this_key in this_keys: - for auth_key in auth_keys: - if this_key[2] == auth_key[2]: break - else: - new_keys.append(this_key) - if not new_keys: - if status: - print '%s: Client is up to date.' % id - continue - - if status: - print '%s: Keys will be deployed on the client.' % id - if deploy: - cmd = '%s %s@%s "umask 077; test -d .ssh || mkdir .ssh; cat >> .ssh/authorized_keys"' % (basessh, cfg['user'], cfg['host']) - debug(cmd) - pipe = subprocess.Popen(cmd, shell=True, stdin=PIPE).stdin - pipe.write('%s\n' % '\n'.join([key[4] for key in new_keys])) - if pipe.close(): - error('Failed to deliver the keys to the client') - - -# parses authozied_keys, see sshd(8) man page for details -def parse_authorized_keys(keystext): - keys = [] - for line in keystext.splitlines(): - line = line.strip() - if not line or line[0] == '#': continue - if line[0] in '0123456789': - warn('SSH Protocol 1 keys are ignored: %s' % line) - continue - opts ='' - if line[0:7] not in ('ssh-dss', 'ssh-rsa'): - in_str = False - in_esc = False - for i, c in enumerate(line): - if in_str: - if in_esc: in_esc = False - elif c is '\'': in_esc = True - elif c is '"': in_str = False - else: - if c is ' ': - rest = line[i:].strip() - break - elif c is '"': in_str = True - opts += c - else: - info('Invalid key line, ignoring: %s' % line) - continue - else: - rest = line - - if rest[0] in '0123456789': - warn('SSH Protocol 1 keys are ignored: %s' % line) - continue - - parts = rest.split(None, 2) - if len(parts) < 2: - error('Invalid key line, skipping: %s' % line) - continue - - type = parts[0] - if type not in ('ssh-dss', 'ssh-rsa'): - error('Invalid key type "%s", skipping: %s' % (type, line)) - continue - - base46enc = parts[1] - - if len(parts) is 2: - comment = None - else: - comment = parts[2] - - keys.append((opts, type, base46enc, comment, line)) - - return keys - -###################################################################### -# Main routine -###################################################################### - -def usage(exitcode=None): - print 'usage: %s --server [common options] [server options] <client-id>*' % (sys.argv[0]) - print ' %s --keys [common options] [keys options] <client-id>*' % (sys.argv[0]) - print ' %s --list [common options] [list options] <client-id>*' % (sys.argv[0]) - print - print 'mode selection (you must pick one):' - print '--server launch in server mode' - print '--keys launch in keys management mode' - print '--list list previous backup status' - print - print 'common options:' - print '-c, --conf=FILE use the FILE configuration file' - print '-h, --help show this help message and exit' - print '-q, --quiet decreases the verbosity level' - print '-v, --verbose increases the verbosity level' - print '-V, --version show the version number and exit' - print '--noemail disables the sending of email' - print - print 'server options:' - print '--force force backup destination overwriting, dangerous!' - print '--cleanup perform cleanup actions after a failure' - print - print 'keys options:' - print '-i FILE use FILE as identity for RSA/DSA authentication' - print '--status display the key status for the clients (default)' - print '--print display the authorization keys' - print '--deploy deploy the authorization keys' - print - print 'list options:' - print '--increments list number and dates of increments' - print '--parsable-output tailor output for parsing by other programs' - print '--sizes list sizes of all the increments' - print '--changed=time list files that have changed since time' - print '--at-time=time list files in the archive at given time' - if exitcode is not None: sys.exit(exitcode) - -def main(): - try: - opts, args = getopt.getopt(sys.argv[1:], 'c:e:i:hs:qvV', - [ 'conf=', 'client', 'clientid=', 'deploy', - 'email=', 'force', 'help', 'keys', - 'list', 'increments', 'sizes', - 'parsable-output', 'changed=', 'at-time=', - 'noemail', 'cleanup', - 'print', 'quiet', 'server', 'smtp=', - 'status', 'verbose', 'version']) - except getopt.GetoptError: - usage(2) - - global backup_user, home_dir, base_dir - mode = None - email = [] - smtp = None - cfgfile = None - cfglocs = [] - verbosity = 0 - clientid = None - force = 0 - cleanup = 0 - noemail = 0 - list_type = None - list_parsable = 0 - list_date = None - identity = None - keys_status = None - keys_print = None - keys_deploy = None - nice_srv = None - for o, a in opts: - if o in ('-c', '--conf'): - if os.path.isdir(a) or a.endswith(config_ext): - warn('Adding client config files/dirs via this switch is deprecated') - cfglocs.append(a) - elif cfgfile is None: - cfgfile = a - else: - error('A main configuration file can be specified only once!') - sys.exit(2) - elif o in ('-e', '--email'): - warn('The -e/--email options are deprecated and will be removed in the future') - warn('Please use the /etc/safekeep/safekeep.conf file instead') - email.append(a) - elif o in ('-h', '--help'): - usage(0) - elif o in ('-s', '--smtp'): - warn('The -s/--smtp options are deprecated and will be removed in the future') - warn('Please use the /etc/safekeep/safekeep.conf file instead') - smtp = a - elif o in ('--server', ): - if mode: usage(2) - mode = 'server' - elif o in ('--list', ): - if mode: usage(2) - mode = 'list' - elif o in ('--client', ): - if mode: usage(2) - mode = 'client' - elif o in ('--keys', ): - if mode: usage(2) - mode = 'keys' - elif o in ('--force', ): - force = 1 - elif o in ('--cleanup', ): - cleanup = 1 - elif o in ('--noemail', ): - noemail = 1 - elif o in ('--increments', ): - if list_type: usage(2) - list_type = 'increments' - elif o in ('--sizes', ): - if list_type: usage(2) - list_type = 'sizes' - elif o in ('--parsable-output', ): - list_parsable = 1 - elif o in ('--changed', ): - if list_type: usage(2) - list_type = 'changed' - list_date = a - elif o in ('--at-time', ): - if list_type: usage(2) - list_type = 'attime' - list_date = a - elif o in ('-i', ): - identity = a - elif o in ('--status', ): - keys_status = True - elif o in ('--print', ): - keys_print = True - elif o in ('--deploy', ): - keys_deploy = True - elif o in ('-q', '--quiet'): - verbosity -= 1 - elif o in ('-v', '--verbose'): - verbosity += 1 - elif o in ('-V', '--version'): - print 'safekeep', VERSION - return - - if mode is None: - usage(2) - - if mode is not 'keys' and (identity or keys_status or keys_print or keys_deploy): - usage(2) - - if mode is not 'list' and (list_type or list_date or list_parsable): - usage(2) - - if mode is not 'server' and (email or smtp): - usage(2) - - if not mode in ['server', 'client'] and cleanup: - usage(2) - - if mode is 'client' and cfglocs: - usage(2) - - if mode is not 'client': - if cfgfile is None and os.path.isfile(config_file): - cfgfile = config_file - if cfgfile and os.path.isfile(cfgfile): - props = parse_prop_file(cfgfile) - else: - if cfgfile: - warn('Configuration file does not exist, skipping: %s' % cfgfile) - else: - cfgfile = config_file - props = {} - - def get_int(p): - 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: - base_dir = props['base.dir'] - if 'email.smtp.server' in props: - smtp = props['email.smtp.server'] - if 'email.to' in props: - email = props['email.to'].split(',') - nice_def = get_int('nice.adjustment') - nice_srv = get_int('nice.adjustment.server') or nice_def - nice_cln = get_int('nice.adjustment.client') or nice_def - - 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) - - if backup_user and backup_user != work_user: - (user, pswd, uid, gid, gecos, home_dir, shell) = pwd.getpwnam(backup_user) - if mode is not 'keys': - os.setregid(gid, gid) - os.setreuid(uid, uid) - os.environ['HOME'] = home_dir - else: - backup_user = work_user - home_dir = os.getenv('HOME', '/') - - if not base_dir: - base_dir = home_dir - - if len(cfglocs) > 0: - cfgs = parse_locs(cfglocs) - else: - cfgs = {} - - if mode is 'client': - if len(args) > 0: usage(2) - else: - ok = True - for arg in args: - if arg in cfgs: continue - error('Unknown client ID: %s' % arg) - if os.path.isfile(arg): - error('It appears to be a file, configuration files are passed via the -c/--conf switch.') - ok = False - if not ok: sys.exit(2) - - try: - global is_client, verbosity_level, verbosity_ssh, verbosity_trickle - - if verbosity > 2: - verbosity_trickle = verbosity_ssh = '-' + (verbosity-2) * 'v' - if mode is 'server': - is_client = False - verbosity_level = 1 + verbosity - do_server(cfgs, args, nice_srv, force, cleanup) - elif mode is 'list': - if list_type is None: - list_type = 'increments' - is_client = False - verbosity_level = 2 + verbosity - do_list(cfgs, args, list_type, list_date, list_parsable) - elif mode is 'client': - if cleanup: - is_client = False - verbosity_level = 1 + verbosity - do_client_scrub() - else: - is_client = True - verbosity_level = 3 + verbosity - do_client() - elif mode is 'keys': - is_client = False - verbosity_level = 1 + verbosity - if not keys_status and not keys_print and not keys_deploy: - keys_status = True - do_keys(cfgs, args, nice_cln, identity, keys_status, keys_print, keys_deploy) - else: - assert False, 'Unknown mode: %s' % (mode) - except Exception, ex: - traceback.print_exc(file=sys.stdout) - error('ERROR: %s' % ex) - - if email and not noemail: - send_notification(email, smtp) - -if __name__ == '__main__': - main() - -# vim: et ts=8 sw=4 sts=4 Copied: safekeep/tags/Release-safekeep-1_3_0/safekeep (from rev 681, safekeep/trunk/safekeep) =================================================================== --- safekeep/tags/Release-safekeep-1_3_0/safekeep (rev 0) +++ safekeep/tags/Release-safekeep-1_3_0/safekeep 2010-11-19 07:38:15 UTC (rev 682) @@ -0,0 +1,1488 @@ +#!/usr/bin/env python + +# Copyright (C) 2006-2010 Lattica, Inc. +# +# SafeKeep is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# Safekeep is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Safekeep. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import generators +import getopt, os, os.path, re, sys, fnmatch, stat +import subprocess +import commands, tempfile, time, traceback +import getpass, pwd, xml.dom.minidom +import socket, smtplib + +from subprocess import PIPE, STDOUT + +###################################################################### +# Global settings +###################################################################### + +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 = {} +cmd = "<Missing>" + +PROTOCOL = "1.1" +VERSION = "1.3.0" +VEBOSITY_BY_CLASS = {'DBG': 3, 'INFO': 2, 'WARN': 1, 'ERR': 0} + +###################################################################### +# Miscellaneous support functions +###################################################################### + +def send(msg): + print msg.encode('utf-8') + sys.stdout.flush() + +def log(msg, cls=None): + global logbuf + if cls: + if is_client: cls = cls.lower() + msg = '%s: %s' % (cls, msg) + else: + for c in VEBOSITY_BY_CLASS.keys(): + if msg.startswith(c + ': '): + cls = c + break + else: + cls = 'UNK' + + cutoff = VEBOSITY_BY_CLASS.get(cls.upper()) + if cutoff is None: cutoff = 3 + if is_client or verbosity_level >= cutoff: + logbuf.append(msg) + if is_client: + send(msg) + else: + print >> sys.stderr, msg.encode('utf-8') + +def info_file(file, marker=None): + info('## File: ' + file) + errs = 0; + fin = open(file, 'r') + try: + for line in fin.readlines(): + if marker: + if line.startswith(marker): + marker = None + continue + if line.startswith("Errors "): + errs = int(line[6:]) + info(line.rstrip()) + finally: + fin.close() + return errs + +def debug(msg): + log(msg, 'DBG') + +def info(msg): + log(msg, 'INFO') + +def warn(msg): + log(msg, 'WARN') + +def error(msg): + log(msg, 'ERR') + +def args_to_list(args): + if isinstance(args, str) or isinstance(args, unicode): + return args.split(None) + else: + return args + +def do_spawn(args, shell=False): + global cmd + argslist = args_to_list(args) + cmd = argslist[0] + if shell: + # If passed to a shell then give args exactly as specified. + debug('Run [' + args + ']') + proc = subprocess.Popen(args, bufsize=1, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) + else: + # Otherwise split into separate elements. + debug('Run [' + ' '.join(argslist) + ']') + proc = subprocess.Popen(argslist, bufsize=1, shell=False, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) + proc.stdin.close() + for line in proc.stdout: + info(line.rstrip()) + proc.stdout.close() + return proc.wait() + +def spawn(args, shell=False): + global cmd + try: + rc = do_spawn(args, shell=shell) + except OSError, ex: + error("OSError: %s: %s" % (cmd, ex)) + + if not rc: + ret = None + elif rc > 0: + ret = 'exited with non zero status: %d' % rc + elif rc < 0: + ret = 'killed by signal: %d' % -rc + else: + ret = 'unknown exit status: %d' % rc + if ret: + error('%s failed: %s' % (cmd, ret... [truncated message content] |
From: <di...@us...> - 2010-11-19 07:34:18
|
Revision: 681 http://safekeep.svn.sourceforge.net/safekeep/?rev=681&view=rev Author: dimi Date: 2010-11-19 07:34:12 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Make sure we init the var Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 07:32:28 UTC (rev 680) +++ safekeep/trunk/safekeep 2010-11-19 07:34:12 UTC (rev 681) @@ -286,7 +286,7 @@ key_ctrl = host_el[0].getAttribute('key-ctrl') key_data = host_el[0].getAttribute('key-data') else: - host = user = key_ctrl = key_data = None + host = user = nice = key_ctrl = key_data = None if host and not user: user = 'root' if host and not key_ctrl: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 07:32:35
|
Revision: 680 http://safekeep.svn.sourceforge.net/safekeep/?rev=680&view=rev Author: dimi Date: 2010-11-19 07:32:28 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Prep release 1.3.0 Modified Paths: -------------- safekeep/trunk/ANNOUNCE Modified: safekeep/trunk/ANNOUNCE =================================================================== --- safekeep/trunk/ANNOUNCE 2010-11-19 07:24:53 UTC (rev 679) +++ safekeep/trunk/ANNOUNCE 2010-11-19 07:32:28 UTC (rev 680) @@ -1,30 +1,39 @@ -This is release 1.2.1 of SafeKeep, a centralized and easy to use +This is release 1.3.0 of SafeKeep, a centralized and easy to use backup application that combines the best features of a mirror and an incremental backup. What's new in this release: - - Fix error while trying to nice the server + - Allow control of nice value on both server and client + - Fix password handling when dumping MySQL databases. + - Fix MySQL dumps when passing a username (for newer versions). + - Handle correctly Unicode strings, such as localized DB names. + - Fix a bug when dumping a specific Postgresql database. + - Prepare the code for newer Python versions + - Drop support for Python < 2.4, subprocess module isn't supported. + - Try to remove a snapshot up to 10 times in a row to workaround + silly udev bug: https://bugzilla.redhat.com/show_bug.cgi?id=577798 + - Multiple internal cleanups, and minor bugs fixes. -Thanks go to Bryan Talbot and Frank Crawford for providing patches -for the problems addressed in this release. +Thanks go to Frank Crawford and Bertrand Lecervoisier for providing +patches and reports for the problems addressed in this release. Because of lags created by using mirrors, this message may reach you before the release is available at the public sites. Sources and binaries will be available from the following locations: - - RedHat EL 3,4,5, CentOS 3,4,5, Fedora 4,5,6,7,8,9,10: - http://prdownloads.sourceforge.net/safekeep/safekeep-common-1.2.1-1.noarch.rpm - http://prdownloads.sourceforge.net/safekeep/safekeep-client-1.2.1-1.noarch.rpm - http://prdownloads.sourceforge.net/safekeep/safekeep-server-1.2.1-1.noarch.rpm - http://prdownloads.sourceforge.net/safekeep/safekeep-1.2.1-1.src.rpm + - RedHat EL/CentOS 3-6 Fedora 4-14: + http://prdownloads.sourceforge.net/safekeep/safekeep-common-1.3.0-1.noarch.rpm + http://prdownloads.sourceforge.net/safekeep/safekeep-client-1.3.0-1.noarch.rpm + http://prdownloads.sourceforge.net/safekeep/safekeep-server-1.3.0-1.noarch.rpm + http://prdownloads.sourceforge.net/safekeep/safekeep-1.3.0-1.src.rpm - - Ubuntu Edgy, Dapper, and Breezy: - http://prdownloads.sourceforge.net/safekeep/safekeep-common_1.2.1_all.deb - http://prdownloads.sourceforge.net/safekeep/safekeep-client_1.2.1_all.deb - http://prdownloads.sourceforge.net/safekeep/safekeep-server_1.2.1_all.deb + - Ubuntu Edgy, Dapper, Breezy, Hardy, Karmic, Lucid, Maverick, and Natty: + http://prdownloads.sourceforge.net/safekeep/safekeep-common_1.3.0_all.deb + http://prdownloads.sourceforge.net/safekeep/safekeep-client_1.3.0_all.deb + http://prdownloads.sourceforge.net/safekeep/safekeep-server_1.3.0_all.deb - Source: - http://prdownloads.sourceforge.net/safekeep/safekeep-1.2.1.tar.gz + http://prdownloads.sourceforge.net/safekeep/safekeep-1.3.0.tar.gz To find out more about the project visit on our website: http://safekeep.sourceforge.net This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 07:24:59
|
Revision: 679 http://safekeep.svn.sourceforge.net/safekeep/?rev=679&view=rev Author: dimi Date: 2010-11-19 07:24:53 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Work around for udev bug https://bugzilla.redhat.com/show_bug.cgi?id=577798 Modified Paths: -------------- safekeep/trunk/safekeep safekeep/trunk/safekeep.spec.in Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 07:14:31 UTC (rev 678) +++ safekeep/trunk/safekeep 2010-11-19 07:24:53 UTC (rev 679) @@ -615,7 +615,13 @@ ret = spawn(['umount', snapmnt]) if ret: warn('Can not umount the snapshot: %s' % snapmnt) - ret = spawn(['lvremove', '--force', snapdev]) + + # stupid workaround for https://bugzilla.redhat.com/show_bug.cgi?id=577798 + for i in range(1,10): + ret = spawn(['lvremove', '--force', snapdev]) + if not ret: + break + if ret: warn('Can not tear down snapshot: %s' % device) Modified: safekeep/trunk/safekeep.spec.in =================================================================== --- safekeep/trunk/safekeep.spec.in 2010-11-19 07:14:31 UTC (rev 678) +++ safekeep/trunk/safekeep.spec.in 2010-11-19 07:24:53 UTC (rev 679) @@ -124,6 +124,8 @@ - Fix a bug when dumping a specific Postgresql database. - Prepare the code for newer Python versions - Drop support for Python < 2.4, subprocess module isn't supported. + - Try to remove a snapshot up to 10 times in a row to workaround + silly udev bug: https://bugzilla.redhat.com/show_bug.cgi?id=577798 - Multiple internal cleanups, and minor bugs fixes. * Thu Apr 30 2009 Dimi Paun <di...@la...> 1.2.1-1 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 07:14:37
|
Revision: 678 http://safekeep.svn.sourceforge.net/safekeep/?rev=678&view=rev Author: dimi Date: 2010-11-19 07:14:31 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Prep release Modified Paths: -------------- safekeep/trunk/safekeep safekeep/trunk/safekeep.spec.in Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 07:02:19 UTC (rev 677) +++ safekeep/trunk/safekeep 2010-11-19 07:14:31 UTC (rev 678) @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2006-2007 Lattica, Inc. +# Copyright (C) 2006-2010 Lattica, Inc. # # SafeKeep is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -44,7 +44,7 @@ cmd = "<Missing>" PROTOCOL = "1.1" -VERSION = "1.2.1" +VERSION = "1.3.0" VEBOSITY_BY_CLASS = {'DBG': 3, 'INFO': 2, 'WARN': 1, 'ERR': 0} ###################################################################### Modified: safekeep/trunk/safekeep.spec.in =================================================================== --- safekeep/trunk/safekeep.spec.in 2010-11-19 07:02:19 UTC (rev 677) +++ safekeep/trunk/safekeep.spec.in 2010-11-19 07:14:31 UTC (rev 678) @@ -24,7 +24,7 @@ Summary: The SafeKeep backup system (common component) Group: Applications/System Requires: rdiff-backup -Requires: python >= 2.2 +Requires: python >= 2.4 %description common SafeKeep is a client/server backup system which enhances the @@ -116,6 +116,16 @@ %doc samples/sample.backup %changelog +* Fri Nov 19 2010 Dimi Paun <di...@la...> 1.3.0-1 + - Allow control of nice value on both server and client + - Fix password handling when dumping MySQL databases. + - Fix MySQL dumps when passing a username (for newer versions). + - Handle correctly Unicode strings, such as localized DB names. + - Fix a bug when dumping a specific Postgresql database. + - Prepare the code for newer Python versions + - Drop support for Python < 2.4, subprocess module isn't supported. + - Multiple internal cleanups, and minor bugs fixes. + * Thu Apr 30 2009 Dimi Paun <di...@la...> 1.2.1-1 - Fix error while trying to nice the server This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 07:02:25
|
Revision: 677 http://safekeep.svn.sourceforge.net/safekeep/?rev=677&view=rev Author: dimi Date: 2010-11-19 07:02:19 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Oops, typo Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 06:55:25 UTC (rev 676) +++ safekeep/trunk/safekeep 2010-11-19 07:02:19 UTC (rev 677) @@ -1072,7 +1072,7 @@ nice = cfg['nice'] or nice_rem if nice: - nice_cmd = 'nice -n%s' % (nice) + nice_cmd = 'nice -n%s ' % (nice) else: nice_cmd = '' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 06:55:31
|
Revision: 676 http://safekeep.svn.sourceforge.net/safekeep/?rev=676&view=rev Author: dimi Date: 2010-11-19 06:55:25 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Add precise control of nice values for both server and client side of things. By default, safekeep will run now as nice +10 on both sides. However, existing installs will have to redeploy keys to get this running on the client side. Modified Paths: -------------- safekeep/trunk/doc/safekeep.backup.txt safekeep/trunk/doc/safekeep.conf.txt safekeep/trunk/safekeep safekeep/trunk/safekeep.conf safekeep/trunk/samples/sample.backup Modified: safekeep/trunk/doc/safekeep.backup.txt =================================================================== --- safekeep/trunk/doc/safekeep.backup.txt 2010-11-19 05:58:45 UTC (rev 675) +++ safekeep/trunk/doc/safekeep.backup.txt 2010-11-19 06:55:25 UTC (rev 676) @@ -25,7 +25,7 @@ <!-- the client backup host, the user under which the servers will connect, the SSH keys used for control and data transfer --> <host - name="myhost" user="root" + name="myhost" user="root" nice="10" key-ctrl="/home/jdoe/.ssh/backup_id_dsa" key-data="/home/jdoe/.ssh/backup2_id_dsa" /> @@ -113,6 +113,12 @@ so it most likely needs to be 'root'. Optional, defaults to 'root'. +/backup/host/@nice:: + The nice adjustment for the client. This settings is normally + not all that important, as most of the load rests on the server side. + NB: if you change this value, you will have to re-deploy the auth keys. + Optional, defaults to no nice level. + /backup/host/@key-ctrl:: This is the private key used to establish the SSH connection to the client for the control channel. Use of the default value Modified: safekeep/trunk/doc/safekeep.conf.txt =================================================================== --- safekeep/trunk/doc/safekeep.conf.txt 2010-11-19 05:58:45 UTC (rev 675) +++ safekeep/trunk/doc/safekeep.conf.txt 2010-11-19 06:55:25 UTC (rev 676) @@ -46,13 +46,23 @@ `/usr/sbin/sendmail` to deliver the mail. nice.adjustment:: - The nice level adjustment for safekeep, for the time - being used only on the server side. + The default nice level adjustment for safekeep. It specifies an integer to be added to the current nice level. Nicenesses range from -20 (most favorable scheduling) to 19 (least favorable). If no nice level is specified, safekeep is not niced. +nice.adjustment.server:: + The nice level adjustment for safekeep, used on the server side. + It overrides the generic setting in nice.adjustment. + +nice.adjustment.client:: + The default nice adjustment for the client. This settings is normally + not all that important, as most of the load is on the server side. + You can also set the remove nice level on a per-client basis in + the .backup file (see /backup/host/@nice). + NB: if you change this value, you will have to re-deploy the auth keys. + bandwidth.overall:: This is the default bandwidth limit for both upload and download for all the clients. It is an integer number of KB/s Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-11-19 05:58:45 UTC (rev 675) +++ safekeep/trunk/safekeep 2010-11-19 06:55:25 UTC (rev 676) @@ -282,6 +282,7 @@ if host_el: host = host_el[0].getAttribute('name') user = host_el[0].getAttribute('user') + nice = host_el[0].getAttribute('nice') key_ctrl = host_el[0].getAttribute('key-ctrl') key_data = host_el[0].getAttribute('key-data') else: @@ -373,7 +374,7 @@ '/var/named/chroot/var/run', '/var/named/chroot/var/tmp' ] cludes = [{ 'type' : 'exclude', 'path' : path, 'glob' : None, 'regexp' : None } for path in path_xcludes] - return { 'id': id, 'host' : host, 'user' : user, 'key_ctrl' : key_ctrl, 'key_data' : key_data, + return { 'id': id, 'host' : host, 'nice' : nice, 'user' : user, 'key_ctrl' : key_ctrl, 'key_data' : key_data, 'dir' : dir, 'retention' : retention, 'dumps' : dumps, 'snaps' : snaps, 'script' : script, 'cludes' : cludes, 'data_options' : data_options, 'options' : options, 'bw' : bw} @@ -1060,7 +1061,7 @@ info('------------------------------------------------------------------') debug('Server listing done') -def do_keys(cfgs, ids, identity, status, dump, deploy): +def do_keys(cfgs, ids, nice_rem, identity, status, dump, deploy): for cfg in cfgs.itervalues(): id = cfg['id'] if ids and id not in ids: continue @@ -1068,6 +1069,13 @@ if not cfg['host']: info('%s: Client is local, it needs no keys' % id) continue + + nice = cfg['nice'] or nice_rem + if nice: + nice_cmd = 'nice -n%s' % (nice) + else: + nice_cmd = '' + cmds = ['safekeep --client', 'rdiff-backup --server --restrict-read-only /'] privatekeyfiles = [cfg.get('key_ctrl'), cfg.get('key_data')] lines = [] @@ -1099,7 +1107,7 @@ fin = open(publickeyfile, 'r') publickey = fin.read() fin.close() - line = 'command="%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s' % (cmd, publickey.strip()) + line = 'command="%s%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s' % (nice_cmd, cmd, publickey.strip()) lines.append(line) else: keys_ok = True @@ -1386,7 +1394,9 @@ smtp = props['email.smtp.server'] if 'email.to' in props: email = props['email.to'].split(',') - nice_srv = get_int('nice.adjustment') + nice_def = get_int('nice.adjustment') + nice_srv = get_int('nice.adjustment.server') or nice_def + nice_cln = get_int('nice.adjustment.client') or nice_def global default_bandwidth default_bandwidth['overall'] = get_int('bandwidth.limit') or 0 @@ -1456,7 +1466,7 @@ verbosity_level = 1 + verbosity if not keys_status and not keys_print and not keys_deploy: keys_status = True - do_keys(cfgs, args, identity, keys_status, keys_print, keys_deploy) + do_keys(cfgs, args, nice_cln, identity, keys_status, keys_print, keys_deploy) else: assert False, 'Unknown mode: %s' % (mode) except Exception, ex: Modified: safekeep/trunk/safekeep.conf =================================================================== --- safekeep/trunk/safekeep.conf 2010-11-19 05:58:45 UTC (rev 675) +++ safekeep/trunk/safekeep.conf 2010-11-19 06:55:25 UTC (rev 676) @@ -10,7 +10,10 @@ # the base directory for data repository relative paths base.dir = /var/lib/safekeep -# by default, be nice to the server during backup +# by default, be nice during backup +# you can control the server/client nice level via +# nice.adjustment.server and nice.adjustment.client +# or even on a per-client box in the .backup file. nice.adjustment = 10 # A default bandwidth limit for both download/upload Modified: safekeep/trunk/samples/sample.backup =================================================================== --- safekeep/trunk/samples/sample.backup 2010-11-19 05:58:45 UTC (rev 675) +++ safekeep/trunk/samples/sample.backup 2010-11-19 06:55:25 UTC (rev 676) @@ -4,7 +4,7 @@ <!-- the client backup host, the user under which the servers will connect, the SSH keys used for launching "safekeep -c" and "rdiff-backup" --> <host - name="my_box.corp.com" user="root" + name="my_box.corp.com" user="root" nice="10" key-ctrl="/home/jdoe/.ssh/backup_id_dsa" key-data="/home/jdoe/.ssh/backup2_id_dsa" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-11-19 05:58:51
|
Revision: 675 http://safekeep.svn.sourceforge.net/safekeep/?rev=675&view=rev Author: dimi Date: 2010-11-19 05:58:45 +0000 (Fri, 19 Nov 2010) Log Message: ----------- Ack Frank, he's done a lot of good work on this one Modified Paths: -------------- safekeep/trunk/AUTHORS Modified: safekeep/trunk/AUTHORS =================================================================== --- safekeep/trunk/AUTHORS 2010-02-10 16:06:37 UTC (rev 674) +++ safekeep/trunk/AUTHORS 2010-11-19 05:58:45 UTC (rev 675) @@ -1,6 +1,7 @@ SafeKeep is available thanks to the work of: Dimi Paun <di...@la...> Stelian Pop <st...@la...> + Frank Crawford <fr...@cr...> Special thanks for testing, ideas, and support go to: Bogdan Mincic <bo...@la...> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <di...@us...> - 2010-02-10 16:06:43
|
Revision: 674 http://safekeep.svn.sourceforge.net/safekeep/?rev=674&view=rev Author: dimi Date: 2010-02-10 16:06:37 +0000 (Wed, 10 Feb 2010) Log Message: ----------- Bertrand Lecervoisier <ber...@la...> Use the correct package name. Modified Paths: -------------- safekeep/trunk/safekeep Modified: safekeep/trunk/safekeep =================================================================== --- safekeep/trunk/safekeep 2010-02-09 16:01:11 UTC (rev 673) +++ safekeep/trunk/safekeep 2010-02-10 16:06:37 UTC (rev 674) @@ -499,7 +499,7 @@ if passwdfile: - environ['PGPASSFILE'] = passwdfile + os.environ['PGPASSFILE'] = passwdfile try: ec = spawn(cmd, shell=True) finally: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |