From 2bfd9c6a9b0d9ee5b547a31ba97be74b09ac3afc Mon Sep 17 00:00:00 2001
From: Samuel Merritt <sam@swiftstack.com>
Date: Thu, 15 Feb 2018 15:42:09 -0800
Subject: [PATCH] Make DB replicators ignore non-partition directories

If a cluster operator has some tooling that makes directories in
/srv/node/<disk>/accounts, then the account replicator will treat
those directories as partition dirs and may remove empty
subdirectories contained therein. This wastes time and confuses the
operator.

This commit makes DB replicators skip partition directories whose
names don't look like positive integers. This doesn't completely avoid
the problem since an operator can still use an all-digit name, but it
will skip directories like "tmp21945".

Change-Id: I8d6682915a555f537fc0ce8c39c3d52c99ff3056
---
 swift/common/db_replicator.py          | 14 +++++++++++++-
 test/unit/common/test_db_replicator.py |  8 +++++++-
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/swift/common/db_replicator.py b/swift/common/db_replicator.py
index a28f8b0e62..e25ac9124a 100644
--- a/swift/common/db_replicator.py
+++ b/swift/common/db_replicator.py
@@ -69,6 +69,17 @@ def quarantine_db(object_file, server_type):
         renamer(object_dir, quarantine_dir, fsync=False)
 
 
+def looks_like_partition(dir_name):
+    """
+    True if the directory name is a valid partition number, False otherwise.
+    """
+    try:
+        part = int(dir_name)
+        return part >= 0
+    except ValueError:
+        return False
+
+
 def roundrobin_datadirs(datadirs):
     """
     Generator to walk the data dirs in a round robin manner, evenly
@@ -81,7 +92,8 @@ def roundrobin_datadirs(datadirs):
     """
 
     def walk_datadir(datadir, node_id):
-        partitions = os.listdir(datadir)
+        partitions = [pd for pd in os.listdir(datadir)
+                      if looks_like_partition(pd)]
         random.shuffle(partitions)
         for partition in partitions:
             part_dir = os.path.join(datadir, partition)
diff --git a/test/unit/common/test_db_replicator.py b/test/unit/common/test_db_replicator.py
index a1e818cef1..66a07ac1e1 100644
--- a/test/unit/common/test_db_replicator.py
+++ b/test/unit/common/test_db_replicator.py
@@ -1266,9 +1266,11 @@ class TestDBReplicator(unittest.TestCase):
                 return []
             path = path[len('/srv/node/sdx/containers'):]
             if path == '':
-                return ['123', '456', '789', '9999']
+                return ['123', '456', '789', '9999', "-5", "not-a-partition"]
                 # 456 will pretend to be a file
                 # 9999 will be an empty partition with no contents
+                # -5 and not-a-partition were created by something outside
+                #   Swift
             elif path == '/123':
                 return ['abc', 'def.db']  # def.db will pretend to be a file
             elif path == '/123/abc':
@@ -1292,6 +1294,10 @@ class TestDBReplicator(unittest.TestCase):
                         'weird2']  # weird2 will pretend to be a dir, if asked
             elif path == '9999':
                 return []
+            elif path == 'not-a-partition':
+                raise Exception("shouldn't look in not-a-partition")
+            elif path == '-5':
+                raise Exception("shouldn't look in -5")
             return []
 
         def _isdir(path):