Changeset b03406a in trunk


Ignore:
Timestamp:
2010-01-20T09:42:49Z (15 years ago)
Author:
francois <francois@…>
Branches:
master
Children:
00b895c
Parents:
66646d9d
Message:

tahoe_backup.py: display warnings on errors instead of stopping the whole backup. Fix #729.

This patch displays a warning to the user in two cases:

  1. When special files like symlinks, fifos, devices, etc. are found in the local source.


  1. If files or directories are not readables by the user running the 'tahoe backup' command.

In verbose mode, the number of skipped files and directories is printed at the
end of the backup.

Exit status returned by 'tahoe backup':

  • 0 everything went fine
  • 1 the backup failed
  • 2 files were skipped during the backup
Location:
src/allmydata
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified src/allmydata/scripts/tahoe_backup.py

    r66646d9d rb03406a  
    6666        self.files_reused = 0
    6767        self.files_checked = 0
     68        self.files_skipped = 0
    6869        self.directories_created = 0
    6970        self.directories_reused = 0
    7071        self.directories_checked = 0
     72        self.directories_skipped = 0
    7173
    7274    def run(self):
     
    124126        if self.verbosity >= 1:
    125127            print >>stdout, (" %d files uploaded (%d reused), "
    126                              "%d directories created (%d reused)"
     128                             "%d files skipped, "
     129                             "%d directories created (%d reused), "
     130                             "%d directories skipped"
    127131                             % (self.files_uploaded,
    128132                                self.files_reused,
     133                                self.files_skipped,
    129134                                self.directories_created,
    130                                 self.directories_reused))
     135                                self.directories_reused,
     136                                self.directories_skipped))
    131137            if self.verbosity >= 2:
    132138                print >>stdout, (" %d files checked, %d directories checked"
     
    134140                                    self.directories_checked))
    135141            print >>stdout, " backup done, elapsed time: %s" % elapsed_time
     142
     143        # The command exits with code 2 if files or directories were skipped
     144        if self.files_skipped or self.directories_skipped:
     145            return 2
     146
    136147        # done!
    137148        return 0
     
    141152            print >>self.options.stdout, msg
    142153
     154    def warn(self, msg):
     155        print >>self.options.stderr, msg
     156
    143157    def process(self, localpath):
    144158        # returns newdircap
     
    147161        create_contents = {} # childname -> (type, rocap, metadata)
    148162        compare_contents = {} # childname -> rocap
    149         for child in self.options.filter_listdir(os.listdir(localpath)):
     163
     164        try:
     165            children = os.listdir(localpath)
     166        except EnvironmentError:
     167            self.directories_skipped += 1
     168            self.warn("WARNING: permission denied on directory %s" % localpath)
     169            children = []
     170
     171        for child in self.options.filter_listdir(children):
    150172            childpath = os.path.join(localpath, child)
    151173            child = unicode(child)
     
    158180                compare_contents[child] = childcap
    159181            elif os.path.isfile(childpath):
    160                 childcap, metadata = self.upload(childpath)
    161                 assert isinstance(childcap, str)
    162                 create_contents[child] = ("filenode", childcap, metadata)
    163                 compare_contents[child] = childcap
     182                try:
     183                    childcap, metadata = self.upload(childpath)
     184                    assert isinstance(childcap, str)
     185                    create_contents[child] = ("filenode", childcap, metadata)
     186                    compare_contents[child] = childcap
     187                except EnvironmentError:
     188                    self.files_skipped += 1
     189                    self.warn("WARNING: permission denied on file %s" % childpath)
    164190            else:
    165                 raise BackupProcessingError("Cannot backup child %r" % childpath)
     191                self.files_skipped += 1
     192                self.warn("WARNING: cannot backup special file %s" % childpath)
    166193
    167194        must_create, r = self.check_backupdb_directory(compare_contents)
     
    246273        return False, r
    247274
     275    # This function will raise an IOError exception when called on an unreadable file
    248276    def upload(self, childpath):
    249277        #self.verboseprint("uploading %s.." % childpath)
  • TabularUnified src/allmydata/test/test_cli.py

    r66646d9d rb03406a  
    10731073
    10741074    def count_output(self, out):
    1075         mo = re.search(r"(\d)+ files uploaded \((\d+) reused\), (\d+) directories created \((\d+) reused\)", out)
     1075        mo = re.search(r"(\d)+ files uploaded \((\d+) reused\), "
     1076                        "(\d)+ files skipped, "
     1077                        "(\d+) directories created \((\d+) reused\), "
     1078                        "(\d+) directories skipped", out)
    10761079        return [int(s) for s in mo.groups()]
    10771080
     
    11181121            self.failUnlessEqual(err, "")
    11191122            self.failUnlessEqual(rc, 0)
    1120             fu, fr, dc, dr = self.count_output(out)
     1123            fu, fr, fs, dc, dr, ds = self.count_output(out)
    11211124            # foo.txt, bar.txt, blah.txt
    11221125            self.failUnlessEqual(fu, 3)
    11231126            self.failUnlessEqual(fr, 0)
     1127            self.failUnlessEqual(fs, 0)
    11241128            # empty, home, home/parent, home/parent/subdir
    11251129            self.failUnlessEqual(dc, 4)
    11261130            self.failUnlessEqual(dr, 0)
     1131            self.failUnlessEqual(ds, 0)
    11271132        d.addCallback(_check0)
    11281133
     
    11731178            self.failUnlessEqual(rc, 0)
    11741179            if have_bdb:
    1175                 fu, fr, dc, dr = self.count_output(out)
     1180                fu, fr, fs, dc, dr, ds = self.count_output(out)
    11761181                # foo.txt, bar.txt, blah.txt
    11771182                self.failUnlessEqual(fu, 0)
    11781183                self.failUnlessEqual(fr, 3)
     1184                self.failUnlessEqual(fs, 0)
    11791185                # empty, home, home/parent, home/parent/subdir
    11801186                self.failUnlessEqual(dc, 0)
    11811187                self.failUnlessEqual(dr, 4)
     1188                self.failUnlessEqual(ds, 0)
    11821189        d.addCallback(_check4a)
    11831190
     
    12041211                self.failUnlessEqual(err, "")
    12051212                self.failUnlessEqual(rc, 0)
    1206                 fu, fr, dc, dr = self.count_output(out)
     1213                fu, fr, fs, dc, dr, ds = self.count_output(out)
    12071214                fchecked, dchecked = self.count_output2(out)
    12081215                self.failUnlessEqual(fchecked, 3)
    12091216                self.failUnlessEqual(fu, 0)
    12101217                self.failUnlessEqual(fr, 3)
     1218                self.failUnlessEqual(fs, 0)
    12111219                self.failUnlessEqual(dchecked, 4)
    12121220                self.failUnlessEqual(dc, 0)
    12131221                self.failUnlessEqual(dr, 4)
     1222                self.failUnlessEqual(ds, 0)
    12141223            d.addCallback(_check4b)
    12151224
     
    12481257            self.failUnlessEqual(rc, 0)
    12491258            if have_bdb:
    1250                 fu, fr, dc, dr = self.count_output(out)
     1259                fu, fr, fs, dc, dr, ds = self.count_output(out)
    12511260                # new foo.txt, surprise file, subfile, empty
    12521261                self.failUnlessEqual(fu, 4)
    12531262                # old bar.txt
    12541263                self.failUnlessEqual(fr, 1)
     1264                self.failUnlessEqual(fs, 0)
    12551265                # home, parent, subdir, blah.txt, surprisedir
    12561266                self.failUnlessEqual(dc, 5)
    12571267                self.failUnlessEqual(dr, 0)
     1268                self.failUnlessEqual(ds, 0)
    12581269        d.addCallback(_check5a)
    12591270        d.addCallback(lambda res: self.do_cli("ls", "tahoe:backups/Archives"))
     
    13571368                         ('nice_doc.lyx',))
    13581369
     1370    def test_ignore_symlinks(self):
     1371        if not hasattr(os, 'symlink'):
     1372            raise unittest.SkipTest("There is no symlink on this platform.")
     1373
     1374        self.basedir = os.path.dirname(self.mktemp())
     1375        self.set_up_grid()
     1376
     1377        source = os.path.join(self.basedir, "home")
     1378        self.writeto("foo.txt", "foo")
     1379        os.symlink(os.path.join(source, "foo.txt"), os.path.join(source, "foo2.txt"))
     1380
     1381        d = self.do_cli("create-alias", "tahoe")
     1382        d.addCallback(lambda res: self.do_cli("backup", "--verbose", source, "tahoe:test"))
     1383
     1384        def _check((rc, out, err)):
     1385            self.failUnlessEqual(rc, 2)
     1386            self.failUnlessEqual(err, "WARNING: cannot backup special file %s\n" % os.path.join(source, "foo2.txt"))
     1387
     1388            fu, fr, fs, dc, dr, ds = self.count_output(out)
     1389            # foo.txt
     1390            self.failUnlessEqual(fu, 1)
     1391            self.failUnlessEqual(fr, 0)
     1392            # foo2.txt
     1393            self.failUnlessEqual(fs, 1)
     1394            # home
     1395            self.failUnlessEqual(dc, 1)
     1396            self.failUnlessEqual(dr, 0)
     1397            self.failUnlessEqual(ds, 0)
     1398
     1399        d.addCallback(_check)
     1400        return d
     1401
     1402    def test_ignore_unreadable_file(self):
     1403        self.basedir = os.path.dirname(self.mktemp())
     1404        self.set_up_grid()
     1405
     1406        source = os.path.join(self.basedir, "home")
     1407        self.writeto("foo.txt", "foo")
     1408        os.chmod(os.path.join(source, "foo.txt"), 0000)
     1409
     1410        d = self.do_cli("create-alias", "tahoe")
     1411        d.addCallback(lambda res: self.do_cli("backup", source, "tahoe:test"))
     1412
     1413        def _check((rc, out, err)):
     1414            self.failUnlessEqual(rc, 2)
     1415            self.failUnlessEqual(err, "WARNING: permission denied on file %s\n" % os.path.join(source, "foo.txt"))
     1416
     1417            fu, fr, fs, dc, dr, ds = self.count_output(out)
     1418            self.failUnlessEqual(fu, 0)
     1419            self.failUnlessEqual(fr, 0)
     1420            # foo.txt
     1421            self.failUnlessEqual(fs, 1)
     1422            # home
     1423            self.failUnlessEqual(dc, 1)
     1424            self.failUnlessEqual(dr, 0)
     1425            self.failUnlessEqual(ds, 0)
     1426        d.addCallback(_check)
     1427
     1428        # This is necessary for the temp files to be correctly removed
     1429        def _cleanup(self):
     1430            os.chmod(os.path.join(source, "foo.txt"), 0644)
     1431        d.addCallback(_cleanup)
     1432        d.addErrback(_cleanup)
     1433
     1434        return d
     1435
     1436    def test_ignore_unreadable_directory(self):
     1437        self.basedir = os.path.dirname(self.mktemp())
     1438        self.set_up_grid()
     1439
     1440        source = os.path.join(self.basedir, "home")
     1441        os.mkdir(source)
     1442        os.mkdir(os.path.join(source, "test"))
     1443        os.chmod(os.path.join(source, "test"), 0000)
     1444
     1445        d = self.do_cli("create-alias", "tahoe")
     1446        d.addCallback(lambda res: self.do_cli("backup", source, "tahoe:test"))
     1447
     1448        def _check((rc, out, err)):
     1449            self.failUnlessEqual(rc, 2)
     1450            self.failUnlessEqual(err, "WARNING: permission denied on directory %s\n" % os.path.join(source, "test"))
     1451
     1452            fu, fr, fs, dc, dr, ds = self.count_output(out)
     1453            self.failUnlessEqual(fu, 0)
     1454            self.failUnlessEqual(fr, 0)
     1455            self.failUnlessEqual(fs, 0)
     1456            # home, test
     1457            self.failUnlessEqual(dc, 2)
     1458            self.failUnlessEqual(dr, 0)
     1459            # test
     1460            self.failUnlessEqual(ds, 1)
     1461        d.addCallback(_check)
     1462
     1463        # This is necessary for the temp files to be correctly removed
     1464        def _cleanup(self):
     1465            os.chmod(os.path.join(source, "test"), 0655)
     1466        d.addCallback(_cleanup)
     1467        d.addErrback(_cleanup)
     1468        return d
     1469
     1470
    13591471class Check(GridTestMixin, CLITestMixin, unittest.TestCase):
    13601472
Note: See TracChangeset for help on using the changeset viewer.