From 4f4d88a76dc5001ef5e074ad791c57a96830a751 Mon Sep 17 00:00:00 2001
From: brinn <brinn>
Date: Tue, 22 Jul 2008 13:41:33 +0000
Subject: [PATCH] [DMV-33] add support for password files when connecting to an
 rsync server

SVN: 7396
---
 .../cisd/common/filesystem/IPathCopier.java   | 17 +++--
 .../common/filesystem/rsync/RsyncCopier.java  | 34 ++++++---
 .../filesystem/rsync/RsyncCopierTest.java     | 73 +++++++++++++++----
 .../cisd/datamover/DatamoverConstants.java    | 31 ++++++++
 .../systemsx/cisd/datamover/Parameters.java   |  4 +-
 .../cisd/datamover/PropertyNames.java         |  2 -
 .../filesystem/intf/AbstractFileStore.java    | 21 ++++--
 .../systemsx/cisd/datamover/SelfTestTest.java |  9 ++-
 8 files changed, 148 insertions(+), 43 deletions(-)
 create mode 100644 datamover/source/java/ch/systemsx/cisd/datamover/DatamoverConstants.java

diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/IPathCopier.java b/common/source/java/ch/systemsx/cisd/common/filesystem/IPathCopier.java
index f08adda72e4..b4c68f7a9fe 100644
--- a/common/source/java/ch/systemsx/cisd/common/filesystem/IPathCopier.java
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/IPathCopier.java
@@ -59,10 +59,13 @@ public interface IPathCopier extends ITerminable, ISelfTestable
      *            null if it is local.
      * @param rsyncModuleNameOrNull The name of the rsync module to use in the rsync protocol, or
      *            <code>null</code>, if the bulk transfer should be using an ssh tunnel.
+     * @param rsyncPasswordFileOrNull The name of the password file to use if an rsync server is
+     *            used. May be <code>null</code> or the name of a non-existent file, in which case
+     *            no password is used when accessing the rsync server.
      * @return The status of the operation, {@link Status#OK} if everything went OK.
      */
     Status copyToRemote(File sourcePath, File destinationDirectory, String destinationHostOrNull,
-            String rsyncModuleNameOrNull);
+            String rsyncModuleNameOrNull, String rsyncPasswordFileOrNull);
 
     /**
      * Copies <var>sourcePath</var> on <var>sourceHost</var> to <var>destinationDir</var>.
@@ -75,16 +78,18 @@ public interface IPathCopier extends ITerminable, ISelfTestable
      *            will be overwritten.
      * @param rsyncModuleNameOrNull The name of the rsync module to use in the rsync protocol, or
      *            <code>null</code>, if the bulk transfer should be using an ssh tunnel.
+     * @param rsyncPasswordFileOrNull The name of the password file to use if an rsync server is
+     *            used. May be <code>null</code> or the name of a non-existent file, in which case
+     *            no password is used when accessing the rsync server.
      * @return The status of the operation, {@link Status#OK} if everything went OK.
      */
     Status copyFromRemote(File sourcePath, String sourceHost, File destinationDirectory,
-            String rsyncModuleNameOrNull);
-    
-    
+            String rsyncModuleNameOrNull, String rsyncPasswordFileOrNull);
+
     /**
      * Try to connect to this server now and see whether we can list the module.
      * 
-     * @return <code>true</code> if the connection was successfull and <code>false</code> otherwise. 
+     * @return <code>true</code> if the connection was successful and <code>false</code> otherwise.
      */
-    boolean checkRsyncConnection(String host, String rsyncModule);
+    boolean checkRsyncConnection(String host, String rsyncModule, String rsyncPassworFileOrNull);
 }
diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopier.java b/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopier.java
index a84a103b999..546bced00b4 100644
--- a/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopier.java
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopier.java
@@ -146,19 +146,23 @@ public final class RsyncCopier implements IPathCopier, IDirectoryImmutableCopier
 
     public final Status copy(final File sourcePath, final File destinationDirectory)
     {
-        return copy(sourcePath, null, destinationDirectory, null, null);
+        return copy(sourcePath, null, destinationDirectory, null, null, null);
     }
 
     public final Status copyFromRemote(final File sourcePath, final String sourceHost,
-            final File destinationDirectory, String rsyncModuleNameOrNull)
+            final File destinationDirectory, String rsyncModuleNameOrNull,
+            String rsyncPasswordFileOrNull)
     {
-        return copy(sourcePath, sourceHost, destinationDirectory, null, rsyncModuleNameOrNull);
+        return copy(sourcePath, sourceHost, destinationDirectory, null, rsyncModuleNameOrNull,
+                rsyncPasswordFileOrNull);
     }
 
     public final Status copyToRemote(final File sourcePath, final File destinationDirectory,
-            final String destinationHost, String rsyncModuleNameOrNull)
+            final String destinationHost, String rsyncModuleNameOrNull,
+            String rsyncPasswordFileOrNull)
     {
-        return copy(sourcePath, null, destinationDirectory, destinationHost, rsyncModuleNameOrNull);
+        return copy(sourcePath, null, destinationDirectory, destinationHost, rsyncModuleNameOrNull,
+                rsyncPasswordFileOrNull);
     }
 
     //
@@ -278,10 +282,16 @@ public final class RsyncCopier implements IPathCopier, IDirectoryImmutableCopier
         return false;
     }
 
-    public boolean checkRsyncConnection(String host, String rsyncModule)
+    public boolean checkRsyncConnection(String host, String rsyncModule,
+            String rsyncPasswordFileOrNull)
     {
         final List<String> commandLineList = new ArrayList<String>();
         commandLineList.add(rsyncExecutable);
+        if (rsyncPasswordFileOrNull != null && new File(rsyncPasswordFileOrNull).exists())
+        {
+            commandLineList.add("--password-file");
+            commandLineList.add(rsyncPasswordFileOrNull);
+        }
         commandLineList.add(buildPath(host, new File("/"), rsyncModule, false));
         final ProcessResult processResult = runCommand(commandLineList);
         return processResult.isOK();
@@ -289,7 +299,7 @@ public final class RsyncCopier implements IPathCopier, IDirectoryImmutableCopier
 
     private final Status copy(final File sourcePath, final String sourceHostOrNull,
             final File destinationDirectory, final String destinationHostOrNull,
-            final String rsyncModuleNameOrNull)
+            final String rsyncModuleNameOrNull, final String rsyncPasswordFileOrNull)
     {
         assert sourcePath != null;
         assert sourceHostOrNull != null || sourcePath.exists() : logNonExistent(sourcePath);
@@ -299,7 +309,7 @@ public final class RsyncCopier implements IPathCopier, IDirectoryImmutableCopier
         assert sourceHostOrNull == null || destinationHostOrNull == null;
         final List<String> commandLine =
                 createCommandLineForMutableCopy(sourcePath, sourceHostOrNull, destinationDirectory,
-                        destinationHostOrNull, rsyncModuleNameOrNull);
+                        destinationHostOrNull, rsyncModuleNameOrNull, rsyncPasswordFileOrNull);
         return createStatus(runCommand(commandLine));
     }
 
@@ -317,7 +327,7 @@ public final class RsyncCopier implements IPathCopier, IDirectoryImmutableCopier
     @Private
     final List<String> createCommandLineForMutableCopy(final File sourcePath,
             final String sourceHost, final File destinationDirectory, final String destinationHost,
-            final String rsyncModuleNameOrNull)
+            final String rsyncModuleNameOrNull, final String rsyncPasswordFileOrNull)
     {
         assert sourcePath != null && (sourceHost != null || sourcePath.exists());
         assert destinationDirectory != null
@@ -342,6 +352,12 @@ public final class RsyncCopier implements IPathCopier, IDirectoryImmutableCopier
             commandLineList.add("--rsh");
             commandLineList.add(getSshExecutableArgument(sshExecutable));
         }
+        if (rsyncModuleNameOrNull != null && rsyncPasswordFileOrNull != null
+                && new File(rsyncPasswordFileOrNull).exists())
+        {
+            commandLineList.add("--password-file");
+            commandLineList.add(rsyncPasswordFileOrNull);
+        }
         if (additionalCmdLineFlags != null)
         {
             commandLineList.addAll(additionalCmdLineFlags);
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopierTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopierTest.java
index ef9c23be29a..5ce6c9f5a07 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopierTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopierTest.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.commons.io.FileUtils;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -112,18 +113,16 @@ public final class RsyncCopierTest
     }
 
     @Test
-    public void testCommandLineForMutableCopyLocal() throws IOException,
-            InterruptedException
+    public void testCommandLineForMutableCopyLocal() throws IOException, InterruptedException
     {
         final File rsyncBinary = createRsync(0);
         final RsyncCopier copier = new RsyncCopier(rsyncBinary, rsyncBinary, false, false);
         final List<String> cmdLine =
                 copier.createCommandLineForMutableCopy(sourceDirectory, null, destinationDirectory,
-                        null, null);
+                        null, null, null);
         assertEquals(rsyncBinary.getAbsolutePath(), cmdLine.get(0));
         assertEquals(sourceDirectory.getAbsolutePath(), cmdLine.get(cmdLine.size() - 2));
-        assertEquals(destinationDirectory.getAbsolutePath() + "/", cmdLine.get(cmdLine
-                .size() - 1));
+        assertEquals(destinationDirectory.getAbsolutePath() + "/", cmdLine.get(cmdLine.size() - 1));
     }
 
     @Test
@@ -135,7 +134,8 @@ public final class RsyncCopierTest
         final String host = "hst";
         final RsyncCopier copier = new RsyncCopier(rsyncBinary, rsyncBinary, false, false);
         final List<String> cmdLine =
-                copier.createCommandLineForMutableCopy(sourceDirectory, null, dstPath, host, null);
+                copier.createCommandLineForMutableCopy(sourceDirectory, null, dstPath, host, null,
+                        null);
         assertEquals(rsyncBinary.getAbsolutePath(), cmdLine.get(0));
         assertEquals(sourceDirectory.getAbsolutePath(), cmdLine.get(cmdLine.size() - 2));
         assertEquals(host + ":dst/", cmdLine.get(cmdLine.size() - 1));
@@ -152,8 +152,52 @@ public final class RsyncCopierTest
         final RsyncCopier copier = new RsyncCopier(rsyncBinary, rsyncBinary, false, false);
         final List<String> cmdLine =
                 copier.createCommandLineForMutableCopy(sourceDirectory, null, dstPath, host,
-                        rsyncModule);
+                        rsyncModule, null);
+        assertEquals(rsyncBinary.getAbsolutePath(), cmdLine.get(0));
+        assertEquals(sourceDirectory.getAbsolutePath(), cmdLine.get(cmdLine.size() - 2));
+        assertEquals(host + "::" + rsyncModule + "/", cmdLine.get(cmdLine.size() - 1));
+    }
+
+    @Test
+    public void testCommandLineForMutableCopyToRemoteRsyncModuleWithPwFile() throws IOException,
+            InterruptedException
+    {
+        final File rsyncBinary = createRsync(0);
+        final File dstPath = new File("dst");
+        final String host = "hst";
+        final String rsyncModule = "rsmod";
+        final File pwFile = new File(workingDirectory, "rsync.pwd");
+        FileUtils.touch(pwFile);
+        pwFile.deleteOnExit();
+        final RsyncCopier copier = new RsyncCopier(rsyncBinary, rsyncBinary, false, false);
+        final List<String> cmdLine =
+                copier.createCommandLineForMutableCopy(sourceDirectory, null, dstPath, host,
+                        rsyncModule, pwFile.getPath());
+        assertEquals(rsyncBinary.getAbsolutePath(), cmdLine.get(0));
+        assertEquals("--password-file", cmdLine.get(cmdLine.size() - 4));
+        assertEquals(workingDirectory + "/rsync.pwd", cmdLine.get(cmdLine.size() - 3));
+        assertEquals(sourceDirectory.getAbsolutePath(), cmdLine.get(cmdLine.size() - 2));
+        assertEquals(host + "::" + rsyncModule + "/", cmdLine.get(cmdLine.size() - 1));
+    }
+
+    @Test
+    public void testCommandLineForMutableCopyToRemoteRsyncModuleWithNonExistentPwFile()
+            throws IOException, InterruptedException
+    {
+        final File rsyncBinary = createRsync(0);
+        final File dstPath = new File("dst");
+        final String host = "hst";
+        final String rsyncModule = "rsmod";
+        final File pwFile = new File(workingDirectory, "rsync.pwd");
+        pwFile.delete();
+        assertFalse(pwFile.exists());
+        final RsyncCopier copier = new RsyncCopier(rsyncBinary, rsyncBinary, false, false);
+        final List<String> cmdLine =
+                copier.createCommandLineForMutableCopy(sourceDirectory, null, dstPath, host,
+                        rsyncModule, pwFile.getPath());
         assertEquals(rsyncBinary.getAbsolutePath(), cmdLine.get(0));
+        assertFalse("--password-file".equals(cmdLine.get(cmdLine.size() - 4)));
+        assertFalse((workingDirectory + "/rsync.pwd").equals(cmdLine.get(cmdLine.size() - 3)));
         assertEquals(sourceDirectory.getAbsolutePath(), cmdLine.get(cmdLine.size() - 2));
         assertEquals(host + "::" + rsyncModule + "/", cmdLine.get(cmdLine.size() - 1));
     }
@@ -167,11 +211,10 @@ public final class RsyncCopierTest
         final RsyncCopier copier = new RsyncCopier(rsyncBinary, rsyncBinary, false, false);
         final List<String> cmdLine =
                 copier.createCommandLineForMutableCopy(sourceDirectory, host, destinationDirectory,
-                        null, null);
+                        null, null, null);
         assertEquals(rsyncBinary.getAbsolutePath(), cmdLine.get(0));
         assertEquals(host + ":" + sourceDirectory.getPath(), cmdLine.get(cmdLine.size() - 2));
-        assertEquals(destinationDirectory.getAbsolutePath() + "/", cmdLine.get(cmdLine
-                .size() - 1));
+        assertEquals(destinationDirectory.getAbsolutePath() + "/", cmdLine.get(cmdLine.size() - 1));
     }
 
     @Test
@@ -181,14 +224,18 @@ public final class RsyncCopierTest
         final File rsyncBinary = createRsync(0);
         final String host = "hst";
         final String rsyncModule = "rsmod";
+        final File pwFile = new File(workingDirectory, "rsync.pwd");
+        FileUtils.touch(pwFile);
+        pwFile.deleteOnExit();
         final RsyncCopier copier = new RsyncCopier(rsyncBinary, rsyncBinary, false, false);
         final List<String> cmdLine =
                 copier.createCommandLineForMutableCopy(sourceDirectory, host, destinationDirectory,
-                        null, rsyncModule);
+                        null, rsyncModule, pwFile.getPath());
         assertEquals(rsyncBinary.getAbsolutePath(), cmdLine.get(0));
+        assertEquals("--password-file", cmdLine.get(cmdLine.size() - 4));
+        assertEquals(workingDirectory + "/rsync.pwd", cmdLine.get(cmdLine.size() - 3));
         assertEquals(host + "::" + rsyncModule, cmdLine.get(cmdLine.size() - 2));
-        assertEquals(destinationDirectory.getAbsolutePath() + "/", cmdLine.get(cmdLine
-                .size() - 1));
+        assertEquals(destinationDirectory.getAbsolutePath() + "/", cmdLine.get(cmdLine.size() - 1));
     }
 
     @Test(groups =
diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/DatamoverConstants.java b/datamover/source/java/ch/systemsx/cisd/datamover/DatamoverConstants.java
new file mode 100644
index 00000000000..9b3d917b508
--- /dev/null
+++ b/datamover/source/java/ch/systemsx/cisd/datamover/DatamoverConstants.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed 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 ch.systemsx.cisd.datamover;
+
+/**
+ * Global constants used in datamover. 
+ *
+ * @author Bernd Rinn
+ */
+public class DatamoverConstants
+{
+    static final String SERVICE_PROPERTIES_FILE = "etc/service.properties";
+    
+    public static final String RSYNC_PASSWORD_FILE_INCOMING = "etc/rsync_incoming.passwd"; 
+
+    public static final String RSYNC_PASSWORD_FILE_OUTGOING = "etc/rsync_outgoing.passwd";
+}
diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java b/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java
index 4cf1354d98a..ff60424def5 100644
--- a/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java
+++ b/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java
@@ -552,7 +552,7 @@ public final class Parameters implements ITimingParameters, IFileSysParameters
         final Properties properties = new Properties();
         try
         {
-            final InputStream is = new FileInputStream(PropertyNames.SERVICE_PROPERTIES_FILE);
+            final InputStream is = new FileInputStream(DatamoverConstants.SERVICE_PROPERTIES_FILE);
             try
             {
                 properties.load(is);
@@ -565,7 +565,7 @@ public final class Parameters implements ITimingParameters, IFileSysParameters
         {
             final String msg =
                     "Could not load the service properties from resource '"
-                            + PropertyNames.SERVICE_PROPERTIES_FILE + "'.";
+                            + DatamoverConstants.SERVICE_PROPERTIES_FILE + "'.";
             operationLog.warn(msg, ex);
             throw new ConfigurationFailureException(msg, ex);
         }
diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/PropertyNames.java b/datamover/source/java/ch/systemsx/cisd/datamover/PropertyNames.java
index caf45e071fa..cfffb54a59e 100644
--- a/datamover/source/java/ch/systemsx/cisd/datamover/PropertyNames.java
+++ b/datamover/source/java/ch/systemsx/cisd/datamover/PropertyNames.java
@@ -77,8 +77,6 @@ public final class PropertyNames
 
     static final String USE_RSYNC_FOR_EXTRA_COPIES = "use-rsync-for-extra-copies";
 
-    static final String SERVICE_PROPERTIES_FILE = "etc/service.properties";
-
     static final String SSH_EXECUTABLE = "ssh-executable";
 
     static final String TREAT_INCOMING_AS_REMOTE = "treat-incoming-as-remote";
diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/AbstractFileStore.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/AbstractFileStore.java
index dc3f416fee4..96f8b5f48cd 100644
--- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/AbstractFileStore.java
+++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/AbstractFileStore.java
@@ -29,6 +29,7 @@ import ch.systemsx.cisd.common.filesystem.IPathCopier;
 import ch.systemsx.cisd.common.highwatermark.HostAwareFileWithHighwaterMark;
 import ch.systemsx.cisd.common.utilities.FileUtilities;
 import ch.systemsx.cisd.common.utilities.StoreItem;
+import ch.systemsx.cisd.datamover.DatamoverConstants;
 
 /**
  * The abstract super-class of classes that represent a file store.
@@ -112,13 +113,15 @@ public abstract class AbstractFileStore implements IFileStore
                         } else
                         {
                             return copier.copyToRemote(srcItem, destPath, destHostOrNull,
-                                    destinationStore.tryGetRsyncModuleName());
+                                    destinationStore.tryGetRsyncModuleName(),
+                                    DatamoverConstants.RSYNC_PASSWORD_FILE_OUTGOING);
                         }
                     } else
                     {
                         assert destHostOrNull == null;
                         return copier.copyFromRemote(srcItem, srcHostOrNull, destPath,
-                                tryGetRsyncModuleName());
+                                tryGetRsyncModuleName(),
+                                DatamoverConstants.RSYNC_PASSWORD_FILE_INCOMING);
                     }
                 }
 
@@ -131,22 +134,24 @@ public abstract class AbstractFileStore implements IFileStore
                 {
                     if (srcHostOrNull != null && tryGetRsyncModuleName() != null)
                     {
-                        check(srcHostOrNull, tryGetRsyncModuleName());
+                        check(srcHostOrNull, tryGetRsyncModuleName(),
+                                DatamoverConstants.RSYNC_PASSWORD_FILE_INCOMING);
                     }
                     if (destHostOrNull != null && destinationStore.tryGetRsyncModuleName() != null)
                     {
-                        check(destHostOrNull, destinationStore.tryGetRsyncModuleName());
+                        check(destHostOrNull, destinationStore.tryGetRsyncModuleName(),
+                                DatamoverConstants.RSYNC_PASSWORD_FILE_OUTGOING);
                     }
                 }
 
-                private void check(String host, String rsyncModule)
+                private void check(String host, String rsyncModule, String rsyncPasswordFileOrNull)
                 {
-                    final boolean connectionOK = copier.checkRsyncConnection(host, rsyncModule);
+                    final boolean connectionOK =
+                            copier.checkRsyncConnection(host, rsyncModule, rsyncPasswordFileOrNull);
                     if (connectionOK == false)
                     {
                         throw new ConfigurationFailureException(String.format(
-                                "Connection to rsync module %s::%s failed", srcHostOrNull,
-                                tryGetRsyncModuleName()));
+                                "Connection to rsync module %s::%s failed", host, rsyncModule));
                     }
 
                 }
diff --git a/datamover/sourceTest/java/ch/systemsx/cisd/datamover/SelfTestTest.java b/datamover/sourceTest/java/ch/systemsx/cisd/datamover/SelfTestTest.java
index 26b6c6e56d7..7faee105f35 100644
--- a/datamover/sourceTest/java/ch/systemsx/cisd/datamover/SelfTestTest.java
+++ b/datamover/sourceTest/java/ch/systemsx/cisd/datamover/SelfTestTest.java
@@ -105,13 +105,15 @@ public class SelfTestTest
                 }
 
                 public Status copyFromRemote(File sourcePath, String sourceHost,
-                        File destinationDirectory, String rsyncModuleNameOrNull)
+                        File destinationDirectory, String rsyncModuleNameOrNull,
+                        String rsyncPasswordFileOrNull)
                 {
                     throw new AssertionError();
                 }
 
                 public Status copyToRemote(File sourcePath, File destinationDirectory,
-                        String destinationHostOrNull, String rsyncModuleNameOrNull)
+                        String destinationHostOrNull, String rsyncModuleNameOrNull,
+                        String rsyncPasswordFileOrNull)
                 {
                     throw new AssertionError();
                 }
@@ -131,7 +133,8 @@ public class SelfTestTest
                     return false;
                 }
 
-                public boolean checkRsyncConnection(String host, String rsyncModule)
+                public boolean checkRsyncConnection(String host, String rsyncModule,
+                        String rsyncPassworFileOrNull)
                 {
                     throw new AssertionError();
                 }
-- 
GitLab