This should fix an issue I've seen exactly once during testing. It might have
been caused by parallel RPC calls to archive jobs.

[…] ganeti-noded:112 ERROR Error in RPC call […]
 File "/usr/lib/python2.4/site-packages/ganeti/backend.py", line 2365, in 
JobQueueRename
   utils.RenameFile(old, new, mkdir=True)
 File "/usr/lib/python2.4/site-packages/ganeti/utils.py", line 322, in 
RenameFile
   os.makedirs(os.path.dirname(new), mkdir_mode)
 File "/usr/lib/python2.4/os.py", line 159, in makedirs
   mkdir(name, mode)
OSError: [Errno 17] File exists: '/var/lib/ganeti/queue/archive/0'

Signed-off-by: Michael Hanselmann <[email protected]>
---
 lib/utils.py                  |   11 ++++++++++-
 test/ganeti.utils_unittest.py |   11 +++++++++++
 2 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/lib/utils.py b/lib/utils.py
index 65ef2c3..8fb3dd5 100644
--- a/lib/utils.py
+++ b/lib/utils.py
@@ -319,8 +319,17 @@ def RenameFile(old, new, mkdir=False, mkdir_mode=0750):
     # as efficient.
     if mkdir and err.errno == errno.ENOENT:
       # Create directory and try again
-      os.makedirs(os.path.dirname(new), mkdir_mode)
+      dirname = os.path.dirname(new)
+      try:
+        os.makedirs(dirname, mode=mkdir_mode)
+      except OSError, err:
+        # Ignore EEXISTS. This is only handled in os.makedirs as included in
+        # Python 2.5 and above.
+        if err.errno != errno.EEXIST or not os.path.exists(dirname):
+          raise
+
       return os.rename(old, new)
+
     raise
 
 
diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index 62f4805..fe7464d 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -295,16 +295,27 @@ class TestRename(unittest.TestCase):
   def testSimpleRename1(self):
     """Simple rename 1"""
     utils.RenameFile(self.tmpfile, os.path.join(self.tmpdir, "xyz"))
+    self.assert_(os.path.isfile(os.path.join(self.tmpdir, "xyz")))
 
   def testSimpleRename2(self):
     """Simple rename 2"""
     utils.RenameFile(self.tmpfile, os.path.join(self.tmpdir, "xyz"),
                      mkdir=True)
+    self.assert_(os.path.isfile(os.path.join(self.tmpdir, "xyz")))
 
   def testRenameMkdir(self):
     """Rename with mkdir"""
     utils.RenameFile(self.tmpfile, os.path.join(self.tmpdir, "test/xyz"),
                      mkdir=True)
+    self.assert_(os.path.isdir(os.path.join(self.tmpdir, "test")))
+    self.assert_(os.path.isfile(os.path.join(self.tmpdir, "test/xyz")))
+
+    utils.RenameFile(os.path.join(self.tmpdir, "test/xyz"),
+                     os.path.join(self.tmpdir, "test/foo/bar/baz"),
+                     mkdir=True)
+    self.assert_(os.path.isdir(os.path.join(self.tmpdir, "test")))
+    self.assert_(os.path.isdir(os.path.join(self.tmpdir, "test/foo/bar")))
+    self.assert_(os.path.isfile(os.path.join(self.tmpdir, "test/foo/bar/baz")))
 
 
 class TestMatchNameComponent(unittest.TestCase):
-- 
1.6.4.3

Reply via email to