]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/SshFilesDeployment.java
Improve deployment
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.simple / src / main / java / org / argeo / slc / jsch / SshFilesDeployment.java
1 package org.argeo.slc.jsch;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.StringTokenizer;
8
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11 import org.argeo.slc.SlcException;
12 import org.argeo.slc.core.deploy.DigestCheck;
13 import org.argeo.slc.core.deploy.ResourceSet;
14 import org.springframework.core.io.Resource;
15
16 import com.jcraft.jsch.Session;
17
18 public class SshFilesDeployment extends AbstractJschTask implements Runnable {
19 private final static Log log = LogFactory.getLog(SshFilesDeployment.class);
20 private String targetBase = "";
21 private ResourceSet resourceSet;
22 /**
23 * Activate with algorithm as per
24 * http://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html#AppA
25 */
26 private String checksum = "MD5";
27 private int remoteChecksumsPerCall = 20;
28
29 public SshFilesDeployment() {
30 }
31
32 public SshFilesDeployment(SshTarget sshTarget, ResourceSet resourceSet) {
33 setSshTarget(sshTarget);
34 this.resourceSet = resourceSet;
35 }
36
37 @Override
38 void run(Session session) {
39 JschMultiTasks multiTasks = new JschMultiTasks();
40
41 Map<String, Resource> resources = resourceSet.listResources();
42
43 // Analyze set
44 List<String> subDirs = new ArrayList<String>();
45 Map<String, String> targetPaths = new HashMap<String, String>();
46 for (String relPath : resources.keySet()) {
47 String parentDir;
48 int lastIndexSubDir = relPath.lastIndexOf('/');
49 if (lastIndexSubDir > 0)
50 parentDir = targetBase + '/'
51 + relPath.substring(0, lastIndexSubDir);
52 else
53 parentDir = targetBase;
54
55 boolean skipDir = false;
56 registerDirs: for (String registeredDir : new ArrayList<String>(
57 subDirs)) {
58 if (parentDir.equals(registeredDir)) {
59 if (log.isTraceEnabled())
60 log.trace("Already registered, skip " + parentDir);
61 skipDir = true;
62 break registerDirs;
63 }
64
65 if (parentDir.startsWith(registeredDir))
66 if (subDirs.contains(registeredDir)) {
67 subDirs.remove(registeredDir);
68 if (log.isTraceEnabled())
69 log.trace("Remove parent " + registeredDir + " of "
70 + parentDir);
71 continue registerDirs;
72 }
73
74 if (registeredDir.startsWith(parentDir)) {
75 skipDir = true;
76 if (log.isTraceEnabled())
77 log.trace("Skip " + parentDir
78 + " because child already registered.");
79 break registerDirs;
80 }
81 }
82
83 if (!subDirs.contains(parentDir) && !skipDir) {
84 subDirs.add(parentDir);
85 }
86
87 targetPaths.put(relPath, targetBase + "/" + relPath);
88 }
89
90 // checksum
91 List<String> targetPathsEqualsToLocal = new ArrayList<String>();
92 if (checksum != null) {
93 Map<String, String> remoteChecksums = new HashMap<String, String>();
94 List<String> csLines = new ArrayList<String>();
95 String csExecutable;
96 if ("MD5".equals(checksum))
97 csExecutable = "/usr/bin/md5sum";
98 else if ("SHA".equals(checksum))
99 csExecutable = "/usr/bin/sha1sum";
100 else if ("SHA-256".equals(checksum))
101 csExecutable = "/usr/bin/sha256sum";
102 else if ("SHA-512".equals(checksum))
103 csExecutable = "/usr/bin/sha512sum";
104 else
105 throw new SlcException(
106 "Don't know how to remotely execute checksum "
107 + checksum);
108
109 StringBuffer csCmd = new StringBuffer(csExecutable);
110 int numberOfPaths = targetPaths.size();
111 int count = 0;
112 for (String targetPath : targetPaths.values()) {
113 csCmd.append(" ").append(targetPath);
114 count++;
115
116 if ((count % remoteChecksumsPerCall == 0)
117 || count == numberOfPaths) {
118 RemoteExec remoteCs = new RemoteExec();
119 remoteCs.setSshTarget(getSshTarget());
120 remoteCs.setCommand(csCmd.toString());
121 remoteCs.setStdOutLines(csLines);
122 remoteCs.setFailOnBadExitStatus(false);
123 remoteCs.run(session);
124 csCmd = new StringBuffer(csExecutable);
125 }
126
127 }
128
129 remoteChecksums: for (String csLine : csLines) {
130 StringTokenizer st = new StringTokenizer(csLine, ": ");
131 String cs = st.nextToken();
132 if (cs.equals(csExecutable)) {
133 // remote does not exist
134 continue remoteChecksums;
135 } else {
136 String targetPath = st.nextToken();
137 if (log.isTraceEnabled())
138 log.trace("REMOTE: " + targetPath + "=" + cs);
139 remoteChecksums.put(targetPath, cs);
140 }
141 }
142
143 // Local checksums
144 for (String relPath : resources.keySet()) {
145 Resource resource = resources.get(relPath);
146 String targetPath = targetPaths.get(relPath);
147 if (remoteChecksums.containsKey(targetPath)) {
148 String cs = DigestCheck.digest(checksum, resource);
149 if (log.isTraceEnabled())
150 log.trace("LOCAL : " + targetPath + "=" + cs);
151 if (remoteChecksums.get(targetPath).equals(cs))
152 targetPathsEqualsToLocal.add(targetPath);
153 }
154 }
155 }
156
157 // Prepare multitask
158
159 // Create dirs
160 StringBuffer mkdirCmd = new StringBuffer("mkdir -p");
161 RemoteExec remoteExec = new RemoteExec();
162 for (String dir : subDirs) {
163 // remoteExec.getCommands().add("mkdir -p " + dir);
164 mkdirCmd.append(' ');
165 if (dir.indexOf(' ') >= 0)
166 mkdirCmd.append('\"').append(dir).append('\"');
167 else
168 mkdirCmd.append(dir);
169 }
170 remoteExec.setCommand(mkdirCmd.toString());
171 multiTasks.getTasks().add(remoteExec);
172
173 // Perform copies
174 int copied = 0;
175 int skipped = 0;
176 copy: for (String relPath : resources.keySet()) {
177 String targetPath = targetPaths.get(relPath);
178 if (targetPathsEqualsToLocal.contains(targetPath)) {
179 if (log.isTraceEnabled())
180 log.trace("Skip copy of " + relPath
181 + " since it is equal to remote " + targetPath);
182 skipped++;
183 continue copy;
184 }
185 // Copy resource
186 Resource resource = resources.get(relPath);
187 ScpTo scpTo = new ScpTo();
188 scpTo.setLocalResource(resource);
189 scpTo.setRemotePath(targetPath);
190 multiTasks.getTasks().add(scpTo);
191 copied++;
192 // TODO: set permissions
193 }
194
195 multiTasks.setSshTarget(getSshTarget());
196 multiTasks.run(session);
197
198 if (checksum != null && log.isDebugEnabled())
199 log.debug("Copied " + copied + " files, skipped " + skipped
200 + " with same checksum.");
201 }
202
203 public void setTargetBase(String targetBase) {
204 this.targetBase = targetBase;
205 }
206
207 public void setResourceSet(ResourceSet resourceSet) {
208 this.resourceSet = resourceSet;
209 }
210
211 public void setChecksum(String checksum) {
212 this.checksum = checksum;
213 }
214
215 /** Number of remote checksums per remote call */
216 public void setRemoteChecksumsPerCall(int remoteChecksumsPerCall) {
217 this.remoteChecksumsPerCall = remoteChecksumsPerCall;
218 }
219 }