File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\FileSystemProvisioner.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson;
25
26 import hudson.FilePath.TarCompression;
27 import hudson.matrix.MatrixBuild;
28 import hudson.model.AbstractBuild;
29 import hudson.model.AbstractProject;
30 import hudson.model.Computer;
31 import hudson.model.Describable;
32 import hudson.model.Job;
33 import hudson.model.TaskListener;
34 import hudson.util.DirScanner.Glob;
35 import hudson.util.io.ArchiverFactory;
36 import jenkins.model.Jenkins;
37 import hudson.model.listeners.RunListener;
38 import hudson.scm.SCM;
39
40 import java.io.BufferedOutputStream;
41 import java.io.File;
42 import java.io.FileOutputStream;
43 import java.io.IOException;
44 import java.io.OutputStream;
45
46 /**
47 * Prepares and provisions workspaces for {@link AbstractProject}s.
48 *
49 * <p>
50 *
51 *
52 * <p>
53 * STILL A WORK IN PROGRESS. SUBJECT TO CHANGE! DO NOT EXTEND.
54 *
55 * TODO: is this per {@link Computer}? Per {@link Job}?
56 * -> probably per slave.
57 *
58 * <h2>Design Problems</h2>
59 * <ol>
60 * <li>
61 * Garbage collection of snapshots. When do we discard snapshots?
62 * In one use case, it would be convenient to keep the snapshot of the
63 * last promoted/successful build. So we need to define a mechanism
64 * to veto GC of snapshot? like an interface that Action can implement?
65 *
66 * Snapshot should be obtained per user's direction. That would be a good
67 * moment for the user to specify the retention policy.
68 *
69 * <li>
70 * Configuration mechanism. Should we auto-detect FileSystemProvisioner
71 * per OS? (but for example, zfs support would require the root access.)
72 * People probably needs to be able to disable this feature, which means
73 * one more configuration option. It's especially tricky because
74 * during the configuration we don't know the OS type.
75 *
76 * OTOH special slave type like the ones for network.com grid can
77 * hide this.
78 * </ol>
79 *
80 *
81 * <h2>Recap</h2>
82 *
83 * To recap,
84 *
85 * - when a slave connects, we auto-detect the file system provisioner.
86 * (for example, ZFS FSP would check the slave root user prop
87 * and/or attempt to "pfexec zfs create" and take over.)
88 *
89 * - the user may configure jobs for snapshot collection, along with
90 * the retention policy.
91 *
92 * - keep workspace snapshots that correspond to the permalinks
93 * In ZFS, use a user property to remember the build and the job.
94 *
95 * Can't the 2nd step happen automatically, when someone else depends on
96 * the workspace snapshot of the upstream? Yes, by using {@link RunListener}.
97 * So this becomes like a special SCM type.
98 *
99 *
100 *
101 * <h2>Design take 2</h2>
102 * <p>
103 * The first piece of this is the custom {@link SCM}, which inherits the
104 * workspace of another job. When this executes, it picks up
105 * {@link WorkspaceSnapshot} from the other job and use it to obtain the workspace.
106 *
107 * <p>
108 * Then there's {@link RunListener}, which creates a snapshot if
109 * someone else is interested in using a snapshot later.
110 *
111 * <h3>TODOs</h3>
112 * <ul>
113 * <li>
114 * Garbage collection of workspace snapshots.
115 *
116 * </ul>
117 *
118 * @author Kohsuke Kawaguchi
119 * @since 1.235
120 */
121 public abstract class FileSystemProvisioner implements ExtensionPoint, Describable<FileSystemProvisioner> {
122 /**
123 * Called very early in the build (before a build places any files
124 * in the workspace, such as SCM checkout) to provision a workspace
125 * for the build.
126 *
127 * <p>
128 * This method can prepare the underlying file system in preparation
129 * for the later {@link #snapshot(AbstractBuild, FilePath, TaskListener)}.
130 *
131 * TODO : the method needs to be able to see the snapshot would
132 * be later needed. In fact, perhaps we should only call this method
133 * when Hudson knows that a snapshot is later needed?
134 *
135 * @param ws
136 * New workspace should be prepared in this location. This is the same value as
137 * {@code build.getProject().getWorkspace()} but passed separately for convenience.
138 */
139 public abstract void prepareWorkspace(AbstractBuild<?,?> build, FilePath ws, TaskListener listener) throws IOException, InterruptedException;
140
141 /**
142 * When a project is deleted, this method is called to undo the effect of
143 * {@link #prepareWorkspace(AbstractBuild, FilePath, TaskListener)}.
144 *
145 * @param project
146 * Project whose workspace is being discarded.
147 * @param ws
148 * Workspace to be discarded. This workspace is on the node
149 * this {@link FileSystemProvisioner} is provisioned for.
150 */
151 public abstract void discardWorkspace(AbstractProject<?, ?> project, FilePath ws) throws IOException, InterruptedException;
152
153 // public abstract void moveWorkspace(AbstractProject<?,?> project, File oldWorkspace, File newWorkspace) throws IOException;
154
155 /**
156 * Obtains the snapshot of the workspace of the given build.
157 *
158 * <p>
159 * The state of the build when this method is invoked depends on
160 * the project type. Most would call this at the end of the build,
161 * but for example {@link MatrixBuild} would call this after
162 * SCM check out so that the state of the fresh workspace
163 * can be then propagated to elsewhere.
164 *
165 * <p>
166 * If the implementation of this method needs to store data in a file system,
167 * do so under {@link AbstractBuild#getRootDir()}, since the lifecycle of
168 * the snapshot is tied to the life cycle of a build.
169 *
170 * @param ws
171 * New workspace should be prepared in this location. This is the same value as
172 * {@code build.getWorkspace()} but passed separately for convenience.
173 * @param glob
174 * Ant-style file glob for files to include in the snapshot. May not be pertinent for all
175 * implementations.
176 */
177 public abstract WorkspaceSnapshot snapshot(AbstractBuild<?,?> build, FilePath ws, String glob, TaskListener listener) throws IOException, InterruptedException;
178
179 public FileSystemProvisionerDescriptor getDescriptor() {
180 return (FileSystemProvisionerDescriptor) Jenkins.getInstance().getDescriptorOrDie(getClass());
181 }
182
183 /**
184 * Default implementation.
185 */
186 public static final FileSystemProvisioner DEFAULT = new Default();
187
188 /**
189 * Returns all the registered {@link FileSystemProvisioner} descriptors.
190 */
191 public static DescriptorExtensionList<FileSystemProvisioner,FileSystemProvisionerDescriptor> all() {
192 return Jenkins.getInstance().<FileSystemProvisioner,FileSystemProvisionerDescriptor>getDescriptorList(FileSystemProvisioner.class);
193 }
194
195 /**
196 * Default implementation that doesn't rely on any file system specific capability,
197 * and thus can be used anywhere that Hudson runs.
198 */
199 public static final class Default extends FileSystemProvisioner {
200 public void prepareWorkspace(AbstractBuild<?, ?> build, FilePath ws, TaskListener listener) throws IOException, InterruptedException {
201 }
202
203 public void discardWorkspace(AbstractProject<?, ?> project, FilePath ws) throws IOException, InterruptedException {
204 }
205
206 /**
207 * @deprecated as of 1.350
208 */
209 public WorkspaceSnapshot snapshot(AbstractBuild<?, ?> build, FilePath ws, TaskListener listener) throws IOException, InterruptedException {
210 return snapshot(build, ws, "**/*", listener);
211 }
212
213 /**
214 * Creates a tar ball.
215 */
216 public WorkspaceSnapshot snapshot(AbstractBuild<?, ?> build, FilePath ws, String glob, TaskListener listener) throws IOException, InterruptedException {
217 File wss = new File(build.getRootDir(),"workspace.tgz");
218 OutputStream os = new BufferedOutputStream(new FileOutputStream(wss));
219 try {
220 ws.archive(ArchiverFactory.TARGZ,os,glob);
221 } finally {
222 os.close();
223 }
224 return new WorkspaceSnapshotImpl();
225 }
226
227 public static final class WorkspaceSnapshotImpl extends WorkspaceSnapshot {
228 public void restoreTo(AbstractBuild<?,?> owner, FilePath dst, TaskListener listener) throws IOException, InterruptedException {
229 File zip = new File(owner.getRootDir(),"workspace.zip");
230 if (zip.exists()) {// we used to keep it in zip
231 new FilePath(zip).unzip(dst);
232 } else {// but since 1.456 we do tgz
233 File tgz = new File(owner.getRootDir(),"workspace.tgz");
234 new FilePath(tgz).untar(dst, TarCompression.GZIP);
235 }
236 }
237 }
238
239 @Extension
240 public static final class DescriptorImpl extends FileSystemProvisionerDescriptor {
241 public boolean discard(FilePath ws, TaskListener listener) throws IOException, InterruptedException {
242 // the default provisioner doens't do anything special,
243 // so allow other types to manage it
244 return false;
245 }
246
247 public String getDisplayName() {
248 return "Default";
249 }
250 }
251 }
252 }
253