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

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi,
5 * Erik Ramfelt, Martin Eigenbrodt, Stephen Connolly, Tom Huybrechts
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25 package hudson.model;
26
27 import hudson.FilePath;
28 import hudson.Launcher;
29 import hudson.Util;
30 import hudson.Launcher.RemoteLauncher;
31 import hudson.model.Descriptor.FormException;
32 import hudson.remoting.Callable;
33 import hudson.remoting.VirtualChannel;
34 import hudson.slaves.CommandLauncher;
35 import hudson.slaves.ComputerLauncher;
36 import hudson.slaves.DumbSlave;
37 import hudson.slaves.JNLPLauncher;
38 import hudson.slaves.NodeDescriptor;
39 import hudson.slaves.NodeProperty;
40 import hudson.slaves.NodePropertyDescriptor;
41 import hudson.slaves.RetentionStrategy;
42 import hudson.slaves.SlaveComputer;
43 import hudson.util.ClockDifference;
44 import hudson.util.DescribableList;
45 import hudson.util.FormValidation;
46
47 import java.io.File;
48 import java.io.IOException;
49 import java.io.InputStream;
50 import java.io.Serializable;
51 import java.net.MalformedURLException;
52 import java.net.URL;
53 import java.net.URLConnection;
54 import java.util.ArrayList;
55 import java.util.List;
56 import java.util.Set;
57
58 import javax.servlet.ServletException;
59
60 import jenkins.model.Jenkins;
61 import org.apache.commons.io.IOUtils;
62 import org.kohsuke.stapler.DataBoundConstructor;
63 import org.kohsuke.stapler.HttpResponse;
64 import org.kohsuke.stapler.QueryParameter;
65 import org.kohsuke.stapler.StaplerRequest;
66 import org.kohsuke.stapler.StaplerResponse;
67
68 /**
69 * Information about a Hudson slave node.
70 *
71 * <p>
72 * Ideally this would have been in the <tt>hudson.slaves</tt> package,
73 * but for compatibility reasons, it can't.
74 *
75 * <p>
76 * TODO: move out more stuff to {@link DumbSlave}.
77 *
78 * @author Kohsuke Kawaguchi
79 */
80 public abstract class Slave extends Node implements Serializable {
81 /**
82 * Name of this slave node.
83 */
84 protected String name;
85
86 /**
87 * Description of this node.
88 */
89 private final String description;
90
91 /**
92 * Path to the root of the workspace
93 * from the view point of this node, such as "/hudson"
94 */
95 protected final String remoteFS;
96
97 /**
98 * Number of executors of this node.
99 */
100 private int numExecutors = 2;
101
102 /**
103 * Job allocation strategy.
104 */
105 private Mode mode;
106
107 /**
108 * Slave availablility strategy.
109 */
110 private RetentionStrategy retentionStrategy;
111
112 /**
113 * The starter that will startup this slave.
114 */
115 private ComputerLauncher launcher;
116
117 /**
118 * Whitespace-separated labels.
119 */
120 private String label="";
121
122 private /*almost final*/ DescribableList<NodeProperty<?>,NodePropertyDescriptor> nodeProperties = new DescribableList<NodeProperty<?>,NodePropertyDescriptor>(Jenkins.getInstance());
123
124 /**
125 * Lazily computed set of labels from {@link #label}.
126 */
127 private transient volatile Set<Label> labels;
128
129 /**
130 * Id of user which creates this slave {@link User}.
131 */
132 private String userId;
133
134 @DataBoundConstructor
135 public Slave(String name, String nodeDescription, String remoteFS, String numExecutors,
136 Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy retentionStrategy, List<? extends NodeProperty<?>> nodeProperties) throws FormException, IOException {
137 this(name,nodeDescription,remoteFS,Util.tryParseNumber(numExecutors, 1).intValue(),mode,labelString,launcher,retentionStrategy, nodeProperties);
138 }
139
140 /**
141 * @deprecated since 2009-02-20.
142 */
143 @Deprecated
144 public Slave(String name, String nodeDescription, String remoteFS, int numExecutors,
145 Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy retentionStrategy) throws FormException, IOException {
146 this(name, nodeDescription, remoteFS, numExecutors, mode, labelString, launcher, retentionStrategy, new ArrayList());
147 }
148
149 public Slave(String name, String nodeDescription, String remoteFS, int numExecutors,
150 Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy retentionStrategy, List<? extends NodeProperty<?>> nodeProperties) throws FormException, IOException {
151 this.name = name;
152 this.description = nodeDescription;
153 this.numExecutors = numExecutors;
154 this.mode = mode;
155 this.remoteFS = Util.fixNull(remoteFS).trim();
156 this.label = Util.fixNull(labelString).trim();
157 this.launcher = launcher;
158 this.retentionStrategy = retentionStrategy;
159 getAssignedLabels(); // compute labels now
160
161 this.nodeProperties.replaceBy(nodeProperties);
162 Slave node = (Slave) Jenkins.getInstance().getNode(name);
163
164 if(node!=null){
165 this.userId= node.getUserId(); //slave has already existed
166 }
167 else{
168 User user = User.current();
169 userId = user!=null ? user.getId() : "anonymous";
170 }
171 if (name.equals(""))
172 throw new FormException(Messages.Slave_InvalidConfig_NoName(), null);
173
174 // if (remoteFS.equals(""))
175 // throw new FormException(Messages.Slave_InvalidConfig_NoRemoteDir(name), null);
176
177 if (this.numExecutors<=0)
178 throw new FormException(Messages.Slave_InvalidConfig_Executors(name), null);
179 }
180
181 /**
182 * Return id of user which created this slave
183 *
184 * @return id of user
185 */
186 public String getUserId() {
187 return userId;
188 }
189
190 public void setUserId(String userId){
191 this.userId = userId;
192 }
193
194 public ComputerLauncher getLauncher() {
195 return launcher == null ? new JNLPLauncher() : launcher;
196 }
197
198 public void setLauncher(ComputerLauncher launcher) {
199 this.launcher = launcher;
200 }
201
202 public String getRemoteFS() {
203 return remoteFS;
204 }
205
206 public String getNodeName() {
207 return name;
208 }
209
210 public void setNodeName(String name) {
211 this.name = name;
212 }
213
214 public String getNodeDescription() {
215 return description;
216 }
217
218 public int getNumExecutors() {
219 return numExecutors;
220 }
221
222 public Mode getMode() {
223 return mode;
224 }
225
226 public void setMode(Mode mode) {
227 this.mode = mode;
228 }
229
230 public DescribableList<NodeProperty<?>, NodePropertyDescriptor> getNodeProperties() {
231 return nodeProperties;
232 }
233
234 public RetentionStrategy getRetentionStrategy() {
235 return retentionStrategy == null ? RetentionStrategy.Always.INSTANCE : retentionStrategy;
236 }
237
238 public void setRetentionStrategy(RetentionStrategy availabilityStrategy) {
239 this.retentionStrategy = availabilityStrategy;
240 }
241
242 public String getLabelString() {
243 return Util.fixNull(label).trim();
244 }
245
246 @Override
247 public void setLabelString(String labelString) throws IOException {
248 this.label = Util.fixNull(labelString).trim();
249 // Compute labels now.
250 getAssignedLabels();
251 }
252
253 public ClockDifference getClockDifference() throws IOException, InterruptedException {
254 VirtualChannel channel = getChannel();
255 if(channel==null)
256 throw new IOException(getNodeName()+" is offline");
257
258 long startTime = System.currentTimeMillis();
259 long slaveTime = channel.call(new GetSystemTime());
260 long endTime = System.currentTimeMillis();
261
262 return new ClockDifference((startTime+endTime)/2 - slaveTime);
263 }
264
265 public Computer createComputer() {
266 return new SlaveComputer(this);
267 }
268
269 public FilePath getWorkspaceFor(TopLevelItem item) {
270 FilePath r = getWorkspaceRoot();
271 if(r==null) return null; // offline
272 return r.child(item.getFullName());
273 }
274
275 public FilePath getRootPath() {
276 return createPath(remoteFS);
277 }
278
279 /**
280 * Root directory on this slave where all the job workspaces are laid out.
281 * @return
282 * null if not connected.
283 */
284 public FilePath getWorkspaceRoot() {
285 FilePath r = getRootPath();
286 if(r==null) return null;
287 return r.child(WORKSPACE_ROOT);
288 }
289
290 /**
291 * Web-bound object used to serve jar files for JNLP.
292 */
293 public static final class JnlpJar implements HttpResponse {
294 private final String fileName;
295
296 public JnlpJar(String fileName) {
297 this.fileName = fileName;
298 }
299
300 public void doIndex( StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
301 URLConnection con = connect();
302 // since we end up redirecting users to jnlpJars/foo.jar/, set the content disposition
303 // so that browsers can download them in the right file name.
304 // see http://support.microsoft.com/kb/260519 and http://www.boutell.com/newfaq/creating/forcedownload.html
305 rsp.setHeader("Content-Disposition", "attachment; filename=" + fileName);
306 InputStream in = con.getInputStream();
307 rsp.serveFile(req, in, con.getLastModified(), con.getContentLength(), "*.jar" );
308 in.close();
309 }
310
311 public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
312 doIndex(req,rsp);
313 }
314
315 private URLConnection connect() throws IOException {
316 URL res = getURL();
317 return res.openConnection();
318 }
319
320 public URL getURL() throws MalformedURLException {
321 String name = fileName;
322 if (name.equals("hudson-cli.jar")) name="jenkins-cli.jar";
323 URL res = Jenkins.getInstance().servletContext.getResource("/WEB-INF/" + name);
324 if(res==null) {
325 // during the development this path doesn't have the files.
326 res = new URL(new File(".").getAbsoluteFile().toURI().toURL(),"target/jenkins/WEB-INF/"+name);
327 }
328 return res;
329 }
330
331 public byte[] readFully() throws IOException {
332 InputStream in = connect().getInputStream();
333 try {
334 return IOUtils.toByteArray(in);
335 } finally {
336 in.close();
337 }
338 }
339
340 }
341
342 public Launcher createLauncher(TaskListener listener) {
343 SlaveComputer c = getComputer();
344 return new RemoteLauncher(listener, c.getChannel(), c.isUnix()).decorateFor(this);
345 }
346
347 /**
348 * Gets the corresponding computer object.
349 */
350 public SlaveComputer getComputer() {
351 return (SlaveComputer)toComputer();
352 }
353
354 @Override
355 public boolean equals(Object o) {
356 if (this == o) return true;
357 if (o == null || getClass() != o.getClass()) return false;
358
359 final Slave that = (Slave) o;
360
361 return name.equals(that.name);
362 }
363
364 @Override
365 public int hashCode() {
366 return name.hashCode();
367 }
368
369 /**
370 * Invoked by XStream when this object is read into memory.
371 */
372 protected Object readResolve() {
373 // convert the old format to the new one
374 if (launcher == null) {
375 launcher = (agentCommand == null || agentCommand.trim().length() == 0)
376 ? new JNLPLauncher()
377 : new CommandLauncher(agentCommand);
378 }
379 if(nodeProperties==null)
380 nodeProperties = new DescribableList<NodeProperty<?>,NodePropertyDescriptor>(Jenkins.getInstance());
381 return this;
382 }
383
384 public SlaveDescriptor getDescriptor() {
385 Descriptor d = Jenkins.getInstance().getDescriptorOrDie(getClass());
386 if (d instanceof SlaveDescriptor)
387 return (SlaveDescriptor) d;
388 throw new IllegalStateException(d.getClass()+" needs to extend from SlaveDescriptor");
389 }
390
391 public static abstract class SlaveDescriptor extends NodeDescriptor {
392 public FormValidation doCheckNumExecutors(@QueryParameter String value) {
393 return FormValidation.validatePositiveInteger(value);
394 }
395
396 /**
397 * Performs syntactical check on the remote FS for slaves.
398 */
399 public FormValidation doCheckRemoteFS(@QueryParameter String value) throws IOException, ServletException {
400 if(Util.fixEmptyAndTrim(value)==null)
401 return FormValidation.error(Messages.Slave_Remote_Director_Mandatory());
402
403 if(value.startsWith("\\\\") || value.startsWith("/net/"))
404 return FormValidation.warning(Messages.Slave_Network_Mounted_File_System_Warning());
405
406 return FormValidation.ok();
407 }
408 }
409
410
411 //
412 // backward compatibility
413 //
414 /**
415 * Command line to launch the agent, like
416 * "ssh myslave java -jar /path/to/hudson-remoting.jar"
417 * @deprecated in 1.216
418 */
419 private transient String agentCommand;
420
421 /**
422 * Obtains the system clock.
423 */
424 private static final class GetSystemTime implements Callable<Long,RuntimeException> {
425 public Long call() {
426 return System.currentTimeMillis();
427 }
428
429 private static final long serialVersionUID = 1L;
430 }
431
432 /**
433 * Determines the workspace root file name for those who really really need the shortest possible path name.
434 */
435 private static final String WORKSPACE_ROOT = System.getProperty(Slave.class.getName()+".workspaceRoot","workspace");
436 }
437