diff --git a/lib/utils.py b/lib/utils.py index 5f659200083d0502eb50d6c3e62443f07e7020f4..76adfc5771a4b18e28141c84ad7c8fba0ed550b6 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -285,6 +285,32 @@ def RemoveFile(filename): raise +def RenameFile(old, new, mkdir=False, mkdir_mode=0750): + """Renames a file. + + @type old: string + @param old: Original path + @type new: string + @param new: New path + @type mkdir: bool + @param mkdir: Whether to create target directory if it doesn't exist + @type mkdir_mode: int + @param mkdir_mode: Mode for newly created directories + + """ + try: + return os.rename(old, new) + except OSError, err: + # In at least one use case of this function, the job queue, directory + # creation is very rare. Checking for the directory before renaming is not + # as efficient. + if mkdir and err.errno == errno.ENOENT: + # Create directory and try again + os.makedirs(os.path.dirname(new), mkdir_mode) + return os.rename(old, new) + raise + + def _FingerprintFile(filename): """Compute the fingerprint of a file. diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index 34b992894f816f10e21696a01d9a31f4636df838..29fddfdd0563d79ef0692128ce8871680ab638fd 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -277,6 +277,36 @@ class TestRemoveFile(unittest.TestCase): self.fail("File '%s' not removed" % symlink) +class TestRename(unittest.TestCase): + """Test case for RenameFile""" + + def setUp(self): + """Create a temporary directory""" + self.tmpdir = tempfile.mkdtemp() + self.tmpfile = os.path.join(self.tmpdir, "test1") + + # Touch the file + open(self.tmpfile, "w").close() + + def tearDown(self): + """Remove temporary directory""" + shutil.rmtree(self.tmpdir) + + def testSimpleRename1(self): + """Simple rename 1""" + utils.RenameFile(self.tmpfile, os.path.join(self.tmpdir, "xyz")) + + def testSimpleRename2(self): + """Simple rename 2""" + utils.RenameFile(self.tmpfile, os.path.join(self.tmpdir, "xyz"), + mkdir=True) + + def testRenameMkdir(self): + """Rename with mkdir""" + utils.RenameFile(self.tmpfile, os.path.join(self.tmpdir, "test/xyz"), + mkdir=True) + + class TestCheckdict(unittest.TestCase): """Test case for the CheckDict function"""