package water.deploy; import java.io.File; import java.util.ArrayList; import java.util.Set; import water.H2O; import water.util.Log; import water.util.Utils; public class Host { public static final String SSH_OPTS; static { SSH_OPTS = "" // + " -o UserKnownHostsFile=/dev/null" // + " -o StrictHostKeyChecking=no" // + " -o LogLevel=quiet" // + " -o ServerAliveInterval=15" // + " -o ServerAliveCountMax=3"; } public static final String FOLDER = "h2o_rsync"; private final String _address, _user, _key; public Host(String addr) { this(addr, null); } public Host(String addr, String user) { this(addr, user, null); } public Host(String addr, String user, String key) { _address = addr; _user = user != null ? user : System.getProperty("user.name"); _key = key; } public String address() { return _address; } public String user() { return _user; } public String key() { return _key; } public void rsync(Set<String> includes, Set<String> excludes, boolean delete) { rsync(includes, excludes, delete, FOLDER); } public void rsync(Set<String> includes, Set<String> excludes, boolean delete, String folder) { Process process = null; try { ArrayList<String> args = new ArrayList<String>(); args.add("rsync"); args.add("-vrzute"); args.add(sshWithArgs()); args.add("--chmod=u=rwx"); for( String s : includes ) args.add(new File(s).getCanonicalPath()); // --exclude seems ignored on Linux (?) so use --exclude-from File file = Utils.writeFile(Utils.join('\n', excludes)); args.add("--exclude-from"); args.add(file.getCanonicalPath()); if( delete ) args.add("--delete"); args.add(_address + ":" + "~" + _user + "/" + folder); ProcessBuilder builder = new ProcessBuilder(args); process = builder.start(); String log = "rsync " + H2O.findInetAddressForSelf() + " -> " + _address; NodeVM.inheritIO(process, Log.padRight(log + ": ", 24)); process.waitFor(); } catch( Exception ex ) { throw new RuntimeException(ex); } finally { if( process != null ) { try { process.destroy(); } catch( Exception xe ) { // Ignore } } } } public static void rsync(final Host[] hosts, final Set<String> includes, final Set<String> excludes, final boolean delete) { ArrayList<Thread> threads = new ArrayList<Thread>(); for( int i = 0; i < hosts.length; i++ ) { final int i_ = i; Thread t = new Thread() { @Override public void run() { hosts[i_].rsync(includes, excludes, delete); } }; t.setDaemon(true); t.start(); threads.add(t); } for( Thread t : threads ) { try { t.join(); } catch( InterruptedException e ) { throw Log.errRTExcept(e); } } } String sshWithArgs() { String k = ""; if( _key != null ) { assert new File(_key).exists(); // Git doesn't set permissions, so force them each time try { Process p = Runtime.getRuntime().exec("chmod 600 " + _key); p.waitFor(); } catch( Exception e ) { throw Log.errRTExcept(e); } k = " -i " + _key; } return "ssh -l " + _user + " -A" + k + SSH_OPTS; } @Override public String toString() { return "Host " + _address; } }