You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sj...@apache.org on 2014/08/12 16:57:58 UTC

[1/2] git commit: BROOKLYN-46: persist files with 600 permission

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 1a691465b -> ed87adaab


BROOKLYN-46: persist files with 600 permission


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/1f119dac
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/1f119dac
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/1f119dac

Branch: refs/heads/master
Commit: 1f119dac38bc8baccd196b8030e06d9d06761d4b
Parents: 230819b
Author: Aled Sage <al...@gmail.com>
Authored: Fri Aug 8 15:45:20 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Aug 12 11:45:34 2014 +0100

----------------------------------------------------------------------
 .../rebind/persister/FileBasedObjectStore.java  |  53 +++---
 .../persister/FileBasedStoreObjectAccessor.java |   6 +-
 .../persister/FileBasedObjectStoreTest.java     | 100 +++++++++++
 .../FileBasedStoreObjectAccessorWriterTest.java |  17 +-
 .../main/java/brooklyn/util/io/FileUtil.java    | 175 +++++++++++++++++++
 .../java/brooklyn/util/io/FileUtilTest.java     | 118 +++++++++++++
 6 files changed, 436 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1f119dac/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java b/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java
index e08aa91..691f43c 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java
@@ -33,7 +33,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.annotation.Nullable;
 
-import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -45,6 +44,7 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.FatalConfigurationRuntimeException;
 import brooklyn.util.internal.ssh.process.ProcessTool;
+import brooklyn.util.io.FileUtil;
 import brooklyn.util.os.Os;
 import brooklyn.util.os.Os.DeletionResult;
 
@@ -120,9 +120,16 @@ public class FileBasedObjectStore implements PersistenceObjectStore {
         if (!prepared) throw new IllegalStateException("Not yet prepared: "+this);
         
         File dir = new File(getBaseDir(), subPath);
-        if (!dir.mkdir())
+        if (dir.mkdir()) {
+            try {
+                FileUtil.setFilePermissionsTo700(dir);
+            } catch (IOException e) {
+                log.warn("Unable to set sub-directory permissions to 700 (continuing): "+dir);
+            }
+        } else {
             if (!dir.exists())
-                throw new IllegalStateException("Cannot create "+dir+"; call returned false"); 
+                throw new IllegalStateException("Cannot create "+dir+"; call returned false");
+        }
         checkPersistenceDirAccessible(dir);
     }
 
@@ -260,7 +267,9 @@ public class FileBasedObjectStore implements PersistenceObjectStore {
 
             if (!dir.exists()) {
                 boolean success = dir.mkdirs();
-                if (!success) {
+                if (success) {
+                    FileUtil.setFilePermissionsTo700(dir);
+                } else {
                     throw new FatalConfigurationRuntimeException("Failed to create persistence directory "+dir);
                 }
             }
@@ -304,7 +313,9 @@ public class FileBasedObjectStore implements PersistenceObjectStore {
         String timestamp = new SimpleDateFormat("yyyyMMdd-hhmmssSSS").format(new Date());
         File backupDir = new File(parentDir, simpleName+"."+timestamp+".bak");
         
-        copyDir(dir, backupDir);
+        FileUtil.copyDir(dir, backupDir);
+        FileUtil.setFilePermissionsTo700(backupDir);
+        
         return backupDir;
     }
 
@@ -314,7 +325,7 @@ public class FileBasedObjectStore implements PersistenceObjectStore {
         String timestamp = new SimpleDateFormat("yyyyMMdd-hhmmssSSS").format(new Date());
         File newDir = new File(parentDir, simpleName+"."+timestamp+".bak");
 
-        moveDir(dir, newDir);
+        FileUtil.moveDir(dir, newDir);
         return newDir;
     }
 
@@ -364,34 +375,15 @@ public class FileBasedObjectStore implements PersistenceObjectStore {
         srcFile.delete();
         throw new IOException("Could not move "+destFile+" to "+srcFile);
     }
-    static void moveDir(File srcDir, File destDir) throws IOException, InterruptedException {
-        if (!Os.isMicrosoftWindows()) {
-            String cmd = "mv '"+srcDir.getAbsolutePath()+"' '"+destDir.getAbsolutePath()+"'";
-            Process proc = Runtime.getRuntime().exec(cmd);
-            proc.waitFor();
-            if (proc.exitValue() == 0) return;
-        }
-        
-        FileUtils.moveDirectory(srcDir, destDir);
-    }
-    static void copyDir(File srcDir, File destDir) throws IOException, InterruptedException {
-        if (!Os.isMicrosoftWindows()) {
-            String cmd = "cp -R '"+srcDir.getAbsolutePath()+"' '"+destDir.getAbsolutePath()+"'";
-            Process proc = Runtime.getRuntime().exec(cmd);
-            proc.waitFor();
-            if (proc.exitValue() == 0) return;
-        }
-        
-        FileUtils.copyDirectory(srcDir, destDir);
-    }
-
+    
     /**
-     * Empty if directory exists, but is entirely empty, or only contains empty directories.
+     * True if directory exists, but is entirely empty, or only contains empty directories.
      */
-    public static boolean isMementoDirExistButEmpty(String dir) {
+    static boolean isMementoDirExistButEmpty(String dir) {
         return isMementoDirExistButEmpty(new File(dir));
     }
-    public static boolean isMementoDirExistButEmpty(File dir) {
+    
+    static boolean isMementoDirExistButEmpty(File dir) {
         if (!dir.exists()) return false;
         for (File sub : dir.listFiles()) {
             if (sub.isFile()) return false;
@@ -410,5 +402,4 @@ public class FileBasedObjectStore implements PersistenceObjectStore {
         if (!result.wasSuccessful())
             log.warn("Unable to delete persistence dir "+d);
     }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1f119dac/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedStoreObjectAccessor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedStoreObjectAccessor.java b/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedStoreObjectAccessor.java
index ac6c4eb..88aeb63 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedStoreObjectAccessor.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedStoreObjectAccessor.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.util.Date;
 
 import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.io.FileUtil;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Charsets;
@@ -65,10 +66,13 @@ public class FileBasedStoreObjectAccessor implements PersistenceObjectStore.Stor
         return file.exists();
     }
 
+    // Setting permissions to 600 reduces objectAccessor.put performance from about 5000 per second to 3000 per second
+    // in java 6. With Java 7's Files.setPosixFilePermissions, this might well improve.
     @Override
     public void put(String val) {
         try {
             if (val==null) val = "";
+            FileUtil.setFilePermissionsTo600(tmpFile);
             Files.write(val, tmpFile, Charsets.UTF_8);
             FileBasedObjectStore.moveFile(tmpFile, file);
             
@@ -83,6 +87,7 @@ public class FileBasedStoreObjectAccessor implements PersistenceObjectStore.Stor
     public void append(String val) {
         try {
             if (val==null) val = "";
+            FileUtil.setFilePermissionsTo600(file);
             Files.append(val, file, Charsets.UTF_8);
             
         } catch (IOException e) {
@@ -107,5 +112,4 @@ public class FileBasedStoreObjectAccessor implements PersistenceObjectStore.Stor
     public String toString() {
         return Objects.toStringHelper(this).add("file", file).toString();
     }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1f119dac/core/src/test/java/brooklyn/entity/rebind/persister/FileBasedObjectStoreTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/persister/FileBasedObjectStoreTest.java b/core/src/test/java/brooklyn/entity/rebind/persister/FileBasedObjectStoreTest.java
new file mode 100644
index 0000000..291f3a8
--- /dev/null
+++ b/core/src/test/java/brooklyn/entity/rebind/persister/FileBasedObjectStoreTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.entity.rebind.persister;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.management.ha.HighAvailabilityMode;
+import brooklyn.test.entity.LocalManagementContextForTests;
+import brooklyn.util.io.FileUtil;
+import brooklyn.util.os.Os;
+
+import com.google.common.io.Files;
+
+public class FileBasedObjectStoreTest {
+
+    private LocalManagementContextForTests mgmt;
+    private File parentdir;
+    private File basedir;
+    private FileBasedObjectStore store;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        mgmt = new LocalManagementContextForTests();
+        parentdir = Files.createTempDir();
+        basedir = new File(parentdir, "mystore");
+        store = new FileBasedObjectStore(basedir);
+        store.injectManagementContext(mgmt);
+        store.prepareForSharedUse(PersistMode.AUTO, HighAvailabilityMode.DISABLED);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (store != null) store.close();
+        if (parentdir != null) Os.deleteRecursively(basedir);
+        if (mgmt != null) Entities.destroyAll(mgmt);
+    }
+    
+    @Test(groups="Integration")
+    public void testSubPathCreatedWithPermission700() throws Exception {
+        store.createSubPath("mysubdir");
+        File subdir = new File(basedir, "mysubdir");
+        
+        assertFilePermission700(basedir);
+        assertFilePermission700(subdir);
+    }
+    
+    @Test
+    public void testIsMementoDirExistsButEmpty() throws Exception {
+        basedir = new File(parentdir, "testIsMementoDirExistsButEmpty");
+        assertFalse(FileBasedObjectStore.isMementoDirExistButEmpty(basedir));
+        assertFalse(FileBasedObjectStore.isMementoDirExistButEmpty(basedir.getAbsolutePath()));
+        
+        basedir.mkdir();
+        assertTrue(FileBasedObjectStore.isMementoDirExistButEmpty(basedir));
+        assertTrue(FileBasedObjectStore.isMementoDirExistButEmpty(basedir.getAbsolutePath()));
+        
+        new File(basedir, "entities").mkdir();
+        new File(basedir, "locations").mkdir();
+        assertTrue(FileBasedObjectStore.isMementoDirExistButEmpty(basedir));
+        assertTrue(FileBasedObjectStore.isMementoDirExistButEmpty(basedir.getAbsolutePath()));
+        
+        new File(new File(basedir, "locations"), "afile").createNewFile();
+        assertFalse(FileBasedObjectStore.isMementoDirExistButEmpty(basedir));
+        assertFalse(FileBasedObjectStore.isMementoDirExistButEmpty(basedir.getAbsolutePath()));
+    }
+    
+    static void assertFilePermission700(File file) throws FileNotFoundException {
+        assertEquals(FileUtil.getFilePermissions(file).get().substring(1), "rwx------");
+    }
+    
+    static void assertFilePermission600(File file) throws Exception {
+        assertEquals(FileUtil.getFilePermissions(file).get().substring(1), "rw-------");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1f119dac/core/src/test/java/brooklyn/entity/rebind/persister/FileBasedStoreObjectAccessorWriterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/persister/FileBasedStoreObjectAccessorWriterTest.java b/core/src/test/java/brooklyn/entity/rebind/persister/FileBasedStoreObjectAccessorWriterTest.java
index 4ab3d6d..0ad5162 100644
--- a/core/src/test/java/brooklyn/entity/rebind/persister/FileBasedStoreObjectAccessorWriterTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/persister/FileBasedStoreObjectAccessorWriterTest.java
@@ -18,6 +18,8 @@
  */
 package brooklyn.entity.rebind.persister;
 
+import static org.testng.Assert.assertEquals;
+
 import java.io.File;
 import java.io.IOException;
 
@@ -27,11 +29,17 @@ import brooklyn.entity.rebind.persister.PersistenceObjectStore.StoreObjectAccess
 import brooklyn.util.os.Os;
 import brooklyn.util.time.Duration;
 
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.Files;
+
 @Test
 public class FileBasedStoreObjectAccessorWriterTest extends PersistenceStoreObjectAccessorWriterTestFixture {
 
+    private File file;
+    
     protected StoreObjectAccessorWithLock newPersistenceStoreObjectAccessor() throws IOException {
-        File file = Os.newTempFile(getClass(), "txt");
+        file = Os.newTempFile(getClass(), "txt");
         return new StoreObjectAccessorLocking(new FileBasedStoreObjectAccessor(file, ".tmp"));
     }
     
@@ -46,4 +54,11 @@ public class FileBasedStoreObjectAccessorWriterTest extends PersistenceStoreObje
         super.testLastModifiedTime();
     }
     
+    @Test(groups="Integration")
+    public void testFilePermissions600() throws Exception {
+        accessor.put("abc");
+        assertEquals(Files.readLines(file, Charsets.UTF_8), ImmutableList.of("abc"));
+        
+        FileBasedObjectStoreTest.assertFilePermission600(file);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1f119dac/utils/common/src/main/java/brooklyn/util/io/FileUtil.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/io/FileUtil.java b/utils/common/src/main/java/brooklyn/util/io/FileUtil.java
new file mode 100644
index 0000000..208717a
--- /dev/null
+++ b/utils/common/src/main/java/brooklyn/util/io/FileUtil.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.util.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.os.Os;
+import brooklyn.util.stream.StreamGobbler;
+import brooklyn.util.stream.Streams;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+
+public class FileUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FileUtil.class);
+
+    private static boolean loggedSetFilePermissionsWarning = false;
+    
+    // When we move to java 7, we can use Files.setPosixFilePermissions
+    public static void setFilePermissionsTo700(File file) throws IOException {
+        file.createNewFile();
+        boolean setRead = file.setReadable(false, false) & file.setReadable(true, true);
+        boolean setWrite = file.setWritable(false, false) & file.setWritable(true, true);
+        boolean setExec = file.setExecutable(false, false) & file.setExecutable(true, true);
+        
+        if (setRead && setWrite && setExec) {
+            if (LOG.isTraceEnabled()) LOG.trace("Set permissions to 700 for file {}", file.getAbsolutePath());
+        } else {
+            if (loggedSetFilePermissionsWarning) {
+                if (LOG.isTraceEnabled()) LOG.trace("Failed to set permissions to 700 for file {}: setRead={}, setWrite={}, setExecutable={}",
+                        new Object[] {file.getAbsolutePath(), setRead, setWrite, setExec});
+            } else {
+                LOG.warn("Failed to set permissions to 700 for file {}: setRead={}, setWrite={}, setExecutable={}; subsequent failures (on any file) will be logged at trace",
+                        new Object[] {file.getAbsolutePath(), setRead, setWrite, setExec});
+                loggedSetFilePermissionsWarning = true;
+            }
+        }
+    }
+    
+    // When we move to java 7, we can use Files.setPosixFilePermissions
+    public static void setFilePermissionsTo600(File file) throws IOException {
+        file.createNewFile();
+        file.setExecutable(false, false);
+        file.setReadable(false, false);
+        file.setWritable(false, false);
+        file.setReadable(true, true);
+        file.setWritable(true, true);
+        
+        boolean setRead = file.setReadable(false, false) & file.setReadable(true, true);
+        boolean setWrite = file.setWritable(false, false) & file.setWritable(true, true);
+        boolean setExec = file.setExecutable(false, false);
+        
+        if (setRead && setWrite && setExec) {
+            if (LOG.isTraceEnabled()) LOG.trace("Set permissions to 600 for file {}", file.getAbsolutePath());
+        } else {
+            if (loggedSetFilePermissionsWarning) {
+                if (LOG.isTraceEnabled()) LOG.trace("Failed to set permissions to 600 for file {}: setRead={}, setWrite={}, setExecutable={}",
+                        new Object[] {file.getAbsolutePath(), setRead, setWrite, setExec});
+            } else {
+                LOG.warn("Failed to set permissions to 600 for file {}: setRead={}, setWrite={}, setExecutable={}; subsequent failures (on any file) will be logged at trace",
+                        new Object[] {file.getAbsolutePath(), setRead, setWrite, setExec});
+                loggedSetFilePermissionsWarning = true;
+            }
+        }
+    }
+    
+    public static void moveDir(File srcDir, File destDir) throws IOException, InterruptedException {
+        if (!Os.isMicrosoftWindows()) {
+            String cmd = "mv '"+srcDir.getAbsolutePath()+"' '"+destDir.getAbsolutePath()+"'";
+            Process proc = Runtime.getRuntime().exec(cmd);
+            proc.waitFor();
+            if (proc.exitValue() == 0) return;
+        }
+        
+        FileUtils.moveDirectory(srcDir, destDir);
+    }
+    
+    public static void copyDir(File srcDir, File destDir) throws IOException, InterruptedException {
+        if (!Os.isMicrosoftWindows()) {
+            String cmd = "cp -R '"+srcDir.getAbsolutePath()+"' '"+destDir.getAbsolutePath()+"'";
+            Process proc = Runtime.getRuntime().exec(cmd);
+            proc.waitFor();
+            if (proc.exitValue() == 0) return;
+        }
+        
+        FileUtils.copyDirectory(srcDir, destDir);
+    }
+    
+    /**
+     * This utility will be deleted when we move to Java 7
+     * 
+     * @return The file permission (in a form like "-rwxr--r--"), or null if the permissions could not be determined.
+     */
+    @Beta
+    public static Maybe<String> getFilePermissions(File file) throws FileNotFoundException {
+        if (!file.exists()) throw new FileNotFoundException();
+        
+        if (Os.isMicrosoftWindows()) {
+            return Maybe.absent("Cannot determine permissions on windows");
+        } else {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            ByteArrayOutputStream err = new ByteArrayOutputStream();
+            int exitcode = exec(ImmutableList.of("ls", "-ld", file.getAbsolutePath()), out, err);
+            if (exitcode != 0) {
+                if (LOG.isDebugEnabled()) LOG.debug("Could not determine permissions of file "+file+"; exit code "+exitcode+"; stderr "+new String(err.toByteArray()));
+                return Maybe.absent("Could not determine permission of file "+file+"; exit code "+exitcode);
+            }
+            String stdout = new String(out.toByteArray());
+            return (stdout.trim().isEmpty() ? Maybe.<String>absent("empty output") : Maybe.of(stdout.split("\\s")[0]));
+        }
+    }
+    
+    private static int exec(List<String> cmds, OutputStream out, OutputStream err) {
+        StreamGobbler errgobbler = null;
+        StreamGobbler outgobbler = null;
+        
+        ProcessBuilder pb = new ProcessBuilder(cmds);
+        
+        try {
+            Process p = pb.start();
+            
+            if (out != null) {
+                InputStream outstream = p.getInputStream();
+                outgobbler = new StreamGobbler(outstream, out, (Logger) null);
+                outgobbler.start();
+            }
+            if (err != null) {
+                InputStream errstream = p.getErrorStream();
+                errgobbler = new StreamGobbler(errstream, err, (Logger) null);
+                errgobbler.start();
+            }
+            
+            int result = p.waitFor();
+            
+            if (outgobbler != null) outgobbler.blockUntilFinished();
+            if (errgobbler != null) errgobbler.blockUntilFinished();
+            
+            return result;
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        } finally {
+            Streams.closeQuietly(outgobbler);
+            Streams.closeQuietly(errgobbler);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1f119dac/utils/common/src/test/java/brooklyn/util/io/FileUtilTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/brooklyn/util/io/FileUtilTest.java b/utils/common/src/test/java/brooklyn/util/io/FileUtilTest.java
new file mode 100644
index 0000000..eb2c4b1
--- /dev/null
+++ b/utils/common/src/test/java/brooklyn/util/io/FileUtilTest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.util.io;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import java.io.File;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.util.os.Os;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.Files;
+
+public class FileUtilTest {
+
+    private File file;
+    private File dir;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        file = File.createTempFile("fileUtilsTest", ".tmp");
+        dir = Files.createTempDir();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (file != null) file.delete();
+        if (dir != null) Os.deleteRecursively(dir);
+    }
+    
+    @Test(groups="Integration")
+    public void testSetFilePermission600() throws Exception {
+        FileUtil.setFilePermissionsTo600(file);
+        String permissions = FileUtil.getFilePermissions(file).get();
+        assertEquals(permissions, "-rw-------");
+    }
+    
+    @Test(groups="Integration")
+    public void testSetFilePermission700() throws Exception {
+        FileUtil.setFilePermissionsTo700(file);
+        String permissions = FileUtil.getFilePermissions(file).get();
+        assertEquals(permissions, "-rwx------");
+    }
+
+    @Test(groups="Integration")
+    public void testSetDirPermission700() throws Exception {
+        FileUtil.setFilePermissionsTo700(dir);
+        String permissions = FileUtil.getFilePermissions(dir).get();
+        assertEquals(permissions, "drwx------");
+    }
+    
+    @Test(groups="Integration")
+    public void testMoveDir() throws Exception {
+        File destParent = Files.createTempDir();
+        try {
+            Files.write("abc", new File(dir, "afile"), Charsets.UTF_8);
+            File destDir = new File(destParent, "dest");
+            
+            FileUtil.moveDir(dir, destDir);
+            
+            assertEquals(Files.readLines(new File(destDir, "afile"), Charsets.UTF_8), ImmutableList.of("abc"));
+            assertFalse(dir.exists());
+        } finally {
+            if (destParent != null) Os.deleteRecursively(destParent);
+        }
+    }
+    
+    @Test(groups="Integration")
+    public void testCopyDir() throws Exception {
+        File destParent = Files.createTempDir();
+        try {
+            Files.write("abc", new File(dir, "afile"), Charsets.UTF_8);
+            File destDir = new File(destParent, "dest");
+            
+            FileUtil.copyDir(dir, destDir);
+            
+            assertEquals(Files.readLines(new File(destDir, "afile"), Charsets.UTF_8), ImmutableList.of("abc"));
+            assertEquals(Files.readLines(new File(dir, "afile"), Charsets.UTF_8), ImmutableList.of("abc"));
+        } finally {
+            if (destParent != null) Os.deleteRecursively(destParent);
+        }
+    }
+    
+    // Never run this as root! You really don't want to mess with permissions of these files!
+    // Visual inspection test that we get the log message just once saying:
+    //     WARN  Failed to set permissions to 600 for file /etc/hosts: setRead=false, setWrite=false, setExecutable=false; subsequent failures (on any file) will be logged at trace
+    // Disabled because really don't want to mess up anyone's system, and also no automated assertions about log messages.
+    @Test(groups="Integration", enabled=false)
+    public void testLogsWarningOnceIfCannotSetPermission() throws Exception {
+        File file = new File("/etc/hosts");
+        FileUtil.setFilePermissionsTo600(file);
+        FileUtil.setFilePermissionsTo600(file);
+        FileUtil.setFilePermissionsTo700(file);
+        FileUtil.setFilePermissionsTo700(file);
+    }
+}


[2/2] git commit: This closes #114

Posted by sj...@apache.org.
This closes #114


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/ed87adaa
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/ed87adaa
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/ed87adaa

Branch: refs/heads/master
Commit: ed87adaab2d8e84f2724e6d277177c8340d94cdb
Parents: 1a69146 1f119da
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Tue Aug 12 15:57:35 2014 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Tue Aug 12 15:57:35 2014 +0100

----------------------------------------------------------------------
 .../rebind/persister/FileBasedObjectStore.java  |  53 +++---
 .../persister/FileBasedStoreObjectAccessor.java |   6 +-
 .../persister/FileBasedObjectStoreTest.java     | 100 +++++++++++
 .../FileBasedStoreObjectAccessorWriterTest.java |  17 +-
 .../main/java/brooklyn/util/io/FileUtil.java    | 175 +++++++++++++++++++
 .../java/brooklyn/util/io/FileUtilTest.java     | 118 +++++++++++++
 6 files changed, 436 insertions(+), 33 deletions(-)
----------------------------------------------------------------------