4344 |
08 Feb 17 |
nicklas |
1 |
package net.sf.basedb.reggie.plugins.release; |
4344 |
08 Feb 17 |
nicklas |
2 |
|
4344 |
08 Feb 17 |
nicklas |
3 |
import java.io.IOException; |
4344 |
08 Feb 17 |
nicklas |
4 |
import java.io.OutputStream; |
4423 |
27 Mar 17 |
nicklas |
5 |
import java.util.HashMap; |
4344 |
08 Feb 17 |
nicklas |
6 |
import java.util.HashSet; |
4423 |
27 Mar 17 |
nicklas |
7 |
import java.util.Map; |
4344 |
08 Feb 17 |
nicklas |
8 |
import java.util.Set; |
4344 |
08 Feb 17 |
nicklas |
9 |
import java.util.zip.GZIPOutputStream; |
4344 |
08 Feb 17 |
nicklas |
10 |
|
4344 |
08 Feb 17 |
nicklas |
11 |
import net.sf.basedb.core.FileServer; |
6962 |
19 Dec 22 |
nicklas |
12 |
import net.sf.basedb.core.ProgressReporter; |
4344 |
08 Feb 17 |
nicklas |
13 |
import net.sf.basedb.core.plugin.ExportOutputStream; |
4344 |
08 Feb 17 |
nicklas |
14 |
import net.sf.basedb.opengrid.CmdResult; |
4344 |
08 Feb 17 |
nicklas |
15 |
import net.sf.basedb.opengrid.OpenGrid; |
4344 |
08 Feb 17 |
nicklas |
16 |
import net.sf.basedb.opengrid.RemoteHost; |
4344 |
08 Feb 17 |
nicklas |
17 |
import net.sf.basedb.opengrid.RemoteSession; |
4344 |
08 Feb 17 |
nicklas |
18 |
import net.sf.basedb.opengrid.config.ConnectionInfo; |
4344 |
08 Feb 17 |
nicklas |
19 |
import net.sf.basedb.opengrid.filetransfer.FilePermission; |
4423 |
27 Mar 17 |
nicklas |
20 |
import net.sf.basedb.reggie.grid.ScriptUtil; |
4344 |
08 Feb 17 |
nicklas |
21 |
|
4344 |
08 Feb 17 |
nicklas |
22 |
/** |
4344 |
08 Feb 17 |
nicklas |
An output location that write files to a remote |
4344 |
08 Feb 17 |
nicklas |
FileServer (assuming that the FileServer is reachable |
4344 |
08 Feb 17 |
nicklas |
with SSH). |
4344 |
08 Feb 17 |
nicklas |
26 |
|
4344 |
08 Feb 17 |
nicklas |
@author nicklas |
4344 |
08 Feb 17 |
nicklas |
@since 4.10 |
4344 |
08 Feb 17 |
nicklas |
29 |
*/ |
4344 |
08 Feb 17 |
nicklas |
30 |
public class FileServerOutputLocation |
4344 |
08 Feb 17 |
nicklas |
31 |
extends OutputLocation |
4344 |
08 Feb 17 |
nicklas |
32 |
{ |
4344 |
08 Feb 17 |
nicklas |
33 |
|
4344 |
08 Feb 17 |
nicklas |
34 |
private final FileServer server; |
4344 |
08 Feb 17 |
nicklas |
35 |
private final RemoteSession session; |
4430 |
28 Mar 17 |
nicklas |
36 |
private final String releaseVersion; |
6019 |
12 Oct 20 |
nicklas |
37 |
private final int searchTimeout; |
4344 |
08 Feb 17 |
nicklas |
38 |
private final String rootPath; |
4421 |
24 Mar 17 |
nicklas |
39 |
private final String releasePath; |
4344 |
08 Feb 17 |
nicklas |
40 |
private final Set<String> mkdirs; |
4423 |
27 Mar 17 |
nicklas |
41 |
private Map<String, String> releasedFiles; |
4344 |
08 Feb 17 |
nicklas |
42 |
|
4344 |
08 Feb 17 |
nicklas |
43 |
/** |
4344 |
08 Feb 17 |
nicklas |
Create a new location on the given file server. |
4421 |
24 Mar 17 |
nicklas |
The release directory is created by taking the |
4421 |
24 Mar 17 |
nicklas |
server root path and adding a subdirectory with the |
4421 |
24 Mar 17 |
nicklas |
release version. |
6019 |
12 Oct 20 |
nicklas |
@param searchTimeout Timeout in seconds when searching for existing files |
6962 |
19 Dec 22 |
nicklas |
(should be between 60 and 600 seconds). |
4344 |
08 Feb 17 |
nicklas |
50 |
*/ |
6019 |
12 Oct 20 |
nicklas |
51 |
public FileServerOutputLocation(FileServer server, String releaseVersion, int searchTimeout) |
4344 |
08 Feb 17 |
nicklas |
52 |
{ |
4344 |
08 Feb 17 |
nicklas |
53 |
this.server = server; |
4430 |
28 Mar 17 |
nicklas |
54 |
this.releaseVersion = releaseVersion; |
6962 |
19 Dec 22 |
nicklas |
55 |
this.searchTimeout = Math.min(600, Math.max(60, searchTimeout)); |
4423 |
27 Mar 17 |
nicklas |
56 |
this.rootPath = ScriptUtil.checkValidPath(server.getRootPath(), true, false); |
4421 |
24 Mar 17 |
nicklas |
57 |
this.releasePath = makePath(rootPath, releaseVersion); |
4344 |
08 Feb 17 |
nicklas |
58 |
this.mkdirs = new HashSet<String>(); |
4344 |
08 Feb 17 |
nicklas |
59 |
|
4344 |
08 Feb 17 |
nicklas |
60 |
ConnectionInfo ci = new ConnectionInfo(server); |
4344 |
08 Feb 17 |
nicklas |
61 |
RemoteHost host = new RemoteHost(ci); |
4344 |
08 Feb 17 |
nicklas |
62 |
this.session = host.connect(5); |
4344 |
08 Feb 17 |
nicklas |
63 |
} |
4344 |
08 Feb 17 |
nicklas |
64 |
|
4421 |
24 Mar 17 |
nicklas |
65 |
|
4344 |
08 Feb 17 |
nicklas |
66 |
@Override |
4421 |
24 Mar 17 |
nicklas |
67 |
public String getRootPath() |
4421 |
24 Mar 17 |
nicklas |
68 |
{ |
4421 |
24 Mar 17 |
nicklas |
69 |
return rootPath; |
4421 |
24 Mar 17 |
nicklas |
70 |
} |
4421 |
24 Mar 17 |
nicklas |
71 |
|
4421 |
24 Mar 17 |
nicklas |
72 |
@Override |
4421 |
24 Mar 17 |
nicklas |
73 |
public String getReleasePath() |
4421 |
24 Mar 17 |
nicklas |
74 |
{ |
4421 |
24 Mar 17 |
nicklas |
75 |
return releasePath; |
4421 |
24 Mar 17 |
nicklas |
76 |
} |
4421 |
24 Mar 17 |
nicklas |
77 |
|
6962 |
19 Dec 22 |
nicklas |
78 |
/** |
6962 |
19 Dec 22 |
nicklas |
Search the current release archive for existing file items. |
6962 |
19 Dec 22 |
nicklas |
80 |
*/ |
4421 |
24 Mar 17 |
nicklas |
81 |
@Override |
6962 |
19 Dec 22 |
nicklas |
82 |
public void init(ProgressReporter progress) |
4421 |
24 Mar 17 |
nicklas |
83 |
{ |
6962 |
19 Dec 22 |
nicklas |
84 |
releasedFiles = new HashMap<>(); |
6962 |
19 Dec 22 |
nicklas |
85 |
|
6962 |
19 Dec 22 |
nicklas |
// Find top-level directories for *.0 releases. Each directory corresponds |
6962 |
19 Dec 22 |
nicklas |
// to one release. |
6962 |
19 Dec 22 |
nicklas |
// The -L parameter is important since it allows us to symlink releases |
6962 |
19 Dec 22 |
nicklas |
// if the original disk gets full |
6962 |
19 Dec 22 |
nicklas |
// -printf format gives us one release version number per line |
6962 |
19 Dec 22 |
nicklas |
// The final 'sort' is required since if, for some reason, a REAL file is present |
6962 |
19 Dec 22 |
nicklas |
// in more than one relase we link to the latest file we find (-n = numerical sort) |
6963 |
19 Dec 22 |
nicklas |
93 |
String findReleases = "find -L " + rootPath + " -mindepth 1 -maxdepth 1 -type d -executable \\( -name '*.0' -o -name '2.2' \\) -printf \"%P\\n\" | sort -n"; |
6962 |
19 Dec 22 |
nicklas |
94 |
CmdResult<String> find = session.executeCmd(findReleases, 10); |
6962 |
19 Dec 22 |
nicklas |
95 |
find.throwExceptionIfNonZeroExitStatus(); |
6962 |
19 Dec 22 |
nicklas |
96 |
|
6962 |
19 Dec 22 |
nicklas |
97 |
String[] allReleases = find.getResult().split("\n"); |
6962 |
19 Dec 22 |
nicklas |
98 |
int numReleases = allReleases.length; |
6962 |
19 Dec 22 |
nicklas |
99 |
int releaseNo = 0; |
6962 |
19 Dec 22 |
nicklas |
100 |
for (String version : allReleases) |
4423 |
27 Mar 17 |
nicklas |
101 |
{ |
6962 |
19 Dec 22 |
nicklas |
102 |
releaseNo++; |
6962 |
19 Dec 22 |
nicklas |
// If the current release already exists, ignore it |
6962 |
19 Dec 22 |
nicklas |
104 |
if (version.equals(releaseVersion)) continue; |
4423 |
27 Mar 17 |
nicklas |
105 |
|
6962 |
19 Dec 22 |
nicklas |
106 |
if (progress != null) |
6962 |
19 Dec 22 |
nicklas |
107 |
{ |
6962 |
19 Dec 22 |
nicklas |
108 |
progress.display(2+10*releaseNo/numReleases, "Finding files in existing release "+version+"..."); |
6962 |
19 Dec 22 |
nicklas |
109 |
} |
6962 |
19 Dec 22 |
nicklas |
110 |
|
6962 |
19 Dec 22 |
nicklas |
// For each release we will find all REAL files in the release |
6962 |
19 Dec 22 |
nicklas |
// Symlinks that are pointing to older releases are ignored |
6962 |
19 Dec 22 |
nicklas |
// -H parameter is important since it allows us to follow the symlink |
6962 |
19 Dec 22 |
nicklas |
// for the top-level release directory (if any) but not for individual files |
6962 |
19 Dec 22 |
nicklas |
// -printf format gives us the path to the file relative the release directory |
6962 |
19 Dec 22 |
nicklas |
// including an important forward slash at the start |
6962 |
19 Dec 22 |
nicklas |
117 |
String findFiles = "find -H " + makePath(rootPath, version) + " -type d ! -executable -prune , -type f -readable -printf \"/%P\\n\""; |
6962 |
19 Dec 22 |
nicklas |
118 |
find = session.executeCmd(findFiles, searchTimeout); |
4423 |
27 Mar 17 |
nicklas |
119 |
find.throwExceptionIfNonZeroExitStatus(); |
6962 |
19 Dec 22 |
nicklas |
120 |
|
6962 |
19 Dec 22 |
nicklas |
121 |
String[] allFiles = find.getResult().split("\n"); |
6962 |
19 Dec 22 |
nicklas |
122 |
for (String filePath : allFiles) |
4423 |
27 Mar 17 |
nicklas |
123 |
{ |
6962 |
19 Dec 22 |
nicklas |
// For example: /S00001/l.r.m.c.lib.g/S00001.l.r.m.c.lib.g_R1.fastq.gz --> 1.0 |
6962 |
19 Dec 22 |
nicklas |
125 |
releasedFiles.put(filePath, version); |
4423 |
27 Mar 17 |
nicklas |
126 |
} |
4423 |
27 Mar 17 |
nicklas |
127 |
} |
4423 |
27 Mar 17 |
nicklas |
128 |
|
6962 |
19 Dec 22 |
nicklas |
129 |
} |
6962 |
19 Dec 22 |
nicklas |
130 |
|
6962 |
19 Dec 22 |
nicklas |
131 |
|
6962 |
19 Dec 22 |
nicklas |
132 |
@Override |
6962 |
19 Dec 22 |
nicklas |
133 |
public String findReleasedFile(String path) |
6962 |
19 Dec 22 |
nicklas |
134 |
{ |
6962 |
19 Dec 22 |
nicklas |
135 |
if (releasedFiles == null) init(null); |
4423 |
27 Mar 17 |
nicklas |
136 |
return releasedFiles.get(path); |
4421 |
24 Mar 17 |
nicklas |
137 |
} |
4421 |
24 Mar 17 |
nicklas |
138 |
|
4421 |
24 Mar 17 |
nicklas |
139 |
@Override |
4427 |
27 Mar 17 |
nicklas |
140 |
public ExportOutputStream getOutputStream(String path, boolean executable) |
4344 |
08 Feb 17 |
nicklas |
141 |
{ |
4421 |
24 Mar 17 |
nicklas |
142 |
String fullPath = makePath(releasePath, path); |
4344 |
08 Feb 17 |
nicklas |
143 |
if (getCompress()) fullPath += ".gz"; |
4344 |
08 Feb 17 |
nicklas |
144 |
|
4344 |
08 Feb 17 |
nicklas |
// Check if directory needs to be created |
4344 |
08 Feb 17 |
nicklas |
146 |
String dir = fullPath.substring(0, fullPath.lastIndexOf('/')); |
4344 |
08 Feb 17 |
nicklas |
147 |
if (!mkdirs.contains(dir)) |
4344 |
08 Feb 17 |
nicklas |
148 |
{ |
4344 |
08 Feb 17 |
nicklas |
149 |
CmdResult<String> r = session.mkdirs(FilePermission.USER_RWX, dir); |
4344 |
08 Feb 17 |
nicklas |
150 |
r.throwExceptionIfNonZeroExitStatus(); |
4344 |
08 Feb 17 |
nicklas |
151 |
mkdirs.add(dir); |
4344 |
08 Feb 17 |
nicklas |
152 |
} |
4344 |
08 Feb 17 |
nicklas |
153 |
|
4427 |
27 Mar 17 |
nicklas |
154 |
OutputStream out = session.writeFile(fullPath, getOverwrite(), null, executable ? FilePermission.USER_RWX : FilePermission.USER_RW); |
4344 |
08 Feb 17 |
nicklas |
155 |
if (getCompress()) |
4344 |
08 Feb 17 |
nicklas |
156 |
{ |
4344 |
08 Feb 17 |
nicklas |
157 |
try |
4344 |
08 Feb 17 |
nicklas |
158 |
{ |
4344 |
08 Feb 17 |
nicklas |
159 |
out = new GZIPOutputStream(out); |
4344 |
08 Feb 17 |
nicklas |
160 |
} |
4344 |
08 Feb 17 |
nicklas |
161 |
catch (IOException ex) |
4344 |
08 Feb 17 |
nicklas |
162 |
{ |
4344 |
08 Feb 17 |
nicklas |
163 |
throw new RuntimeException(ex); |
4344 |
08 Feb 17 |
nicklas |
164 |
} |
4344 |
08 Feb 17 |
nicklas |
165 |
} |
4344 |
08 Feb 17 |
nicklas |
166 |
return new ExportOutputStream(out); |
4344 |
08 Feb 17 |
nicklas |
167 |
} |
4344 |
08 Feb 17 |
nicklas |
168 |
|
4344 |
08 Feb 17 |
nicklas |
169 |
@Override |
4344 |
08 Feb 17 |
nicklas |
170 |
public void close() |
4344 |
08 Feb 17 |
nicklas |
171 |
{ |
4344 |
08 Feb 17 |
nicklas |
172 |
OpenGrid.close(session); |
4344 |
08 Feb 17 |
nicklas |
173 |
} |
4344 |
08 Feb 17 |
nicklas |
174 |
|
4421 |
24 Mar 17 |
nicklas |
175 |
|
4344 |
08 Feb 17 |
nicklas |
176 |
} |