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

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Stephen Connolly, Thomas J. Black
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.model;
25
26 import hudson.BulkChange;
27 import hudson.DescriptorExtensionList;
28 import hudson.Extension;
29 import hudson.Util;
30 import hudson.XmlFile;
31 import hudson.model.Descriptor.FormException;
32 import hudson.model.listeners.SaveableListener;
33 import hudson.node_monitors.NodeMonitor;
34 import hudson.slaves.NodeDescriptor;
35 import hudson.util.DescribableList;
36 import hudson.util.FormApply;
37 import hudson.util.FormValidation;
38 import jenkins.model.Jenkins;
39 import org.kohsuke.stapler.HttpResponse;
40 import org.kohsuke.stapler.QueryParameter;
41 import org.kohsuke.stapler.StaplerRequest;
42 import org.kohsuke.stapler.StaplerResponse;
43 import org.kohsuke.stapler.export.Exported;
44 import org.kohsuke.stapler.export.ExportedBean;
45 import org.kohsuke.stapler.interceptor.RequirePOST;
46
47 import javax.servlet.ServletException;
48 import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
49 import java.io.File;
50 import java.io.IOException;
51 import java.util.AbstractList;
52 import java.util.ArrayList;
53 import java.util.HashMap;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.logging.Level;
57 import java.util.logging.Logger;
58 import net.sf.json.JSONObject;
59
60 /**
61 * Serves as the top of {@link Computer}s in the URL hierarchy.
62 * <p>
63 * Getter methods are prefixed with '_' to avoid collision with computer names.
64 *
65 * @author Kohsuke Kawaguchi
66 */
67 @ExportedBean
68 public final class ComputerSet extends AbstractModelObject implements Describable<ComputerSet> {
69 /**
70 * This is the owner that persists {@link #monitors}.
71 */
72 private static final Saveable MONITORS_OWNER = new Saveable() {
73 public void save() throws IOException {
74 getConfigFile().write(monitors);
75 SaveableListener.fireOnChange(this, getConfigFile());
76 }
77 };
78
79 private static final DescribableList<NodeMonitor,Descriptor<NodeMonitor>> monitors
80 = new DescribableList<NodeMonitor, Descriptor<NodeMonitor>>(MONITORS_OWNER);
81
82 @Exported
83 public String getDisplayName() {
84 return Messages.ComputerSet_DisplayName();
85 }
86
87 /**
88 * @deprecated as of 1.301
89 * Use {@link #getMonitors()}.
90 */
91 public static List<NodeMonitor> get_monitors() {
92 return monitors.toList();
93 }
94
95 @Exported(name="computer",inline=true)
96 public Computer[] get_all() {
97 return Jenkins.getInstance().getComputers();
98 }
99
100 /**
101 * Exposing {@link NodeMonitor#all()} for Jelly binding.
102 */
103 public DescriptorExtensionList<NodeMonitor,Descriptor<NodeMonitor>> getNodeMonitorDescriptors() {
104 return NodeMonitor.all();
105 }
106
107 public static DescribableList<NodeMonitor,Descriptor<NodeMonitor>> getMonitors() {
108 return monitors;
109 }
110
111 /**
112 * Returns a subset pf {@link #getMonitors()} that are {@linkplain NodeMonitor#isIgnored() not ignored}.
113 */
114 public static Map<Descriptor<NodeMonitor>,NodeMonitor> getNonIgnoredMonitors() {
115 Map<Descriptor<NodeMonitor>,NodeMonitor> r = new HashMap<Descriptor<NodeMonitor>, NodeMonitor>();
116 for (NodeMonitor m : monitors) {
117 if(!m.isIgnored())
118 r.put(m.getDescriptor(),m);
119 }
120 return r;
121 }
122
123 /**
124 * Gets all the slave names.
125 */
126 public List<String> get_slaveNames() {
127 return new AbstractList<String>() {
128 final List<Node> nodes = Jenkins.getInstance().getNodes();
129
130 public String get(int index) {
131 return nodes.get(index).getNodeName();
132 }
133
134 public int size() {
135 return nodes.size();
136 }
137 };
138 }
139
140 /**
141 * Number of total {@link Executor}s that belong to this label that are functioning.
142 * <p>
143 * This excludes executors that belong to offline nodes.
144 */
145 @Exported
146 public int getTotalExecutors() {
147 int r=0;
148 for (Computer c : get_all()) {
149 if(c.isOnline())
150 r += c.countExecutors();
151 }
152 return r;
153 }
154
155 /**
156 * Number of busy {@link Executor}s that are carrying out some work right now.
157 */
158 @Exported
159 public int getBusyExecutors() {
160 int r=0;
161 for (Computer c : get_all()) {
162 if(c.isOnline())
163 r += c.countBusy();
164 }
165 return r;
166 }
167
168 /**
169 * {@code getTotalExecutors()-getBusyExecutors()}, plus executors that are being brought online.
170 */
171 public int getIdleExecutors() {
172 int r=0;
173 for (Computer c : get_all())
174 if((c.isOnline() || c.isConnecting()) && c.isAcceptingTasks())
175 r += c.countIdle();
176 return r;
177 }
178
179 public String getSearchUrl() {
180 return "/computers/";
181 }
182
183 public Computer getDynamic(String token, StaplerRequest req, StaplerResponse rsp) {
184 return Jenkins.getInstance().getComputer(token);
185 }
186
187 public void do_launchAll(StaplerRequest req, StaplerResponse rsp) throws IOException {
188 Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
189
190 for(Computer c : get_all()) {
191 if(c.isLaunchSupported())
192 c.connect(true);
193 }
194 rsp.sendRedirect(".");
195 }
196
197 /**
198 * Triggers the schedule update now.
199 *
200 * TODO: ajax on the client side to wait until the update completion might be nice.
201 */
202 public void doUpdateNow( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
203 Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
204
205 for (NodeMonitor nodeMonitor : NodeMonitor.getAll()) {
206 Thread t = nodeMonitor.triggerUpdate();
207 t.setName(nodeMonitor.getColumnCaption());
208 }
209 rsp.forwardToPreviousPage(req);
210 }
211
212 /**
213 * First check point in creating a new slave.
214 */
215 public synchronized void doCreateItem( StaplerRequest req, StaplerResponse rsp,
216 @QueryParameter String name, @QueryParameter String mode,
217 @QueryParameter String from ) throws IOException, ServletException {
218 final Jenkins app = Jenkins.getInstance();
219 app.checkPermission(Computer.CREATE);
220
221 if(mode!=null && mode.equals("copy")) {
222 name = checkName(name);
223
224 Node src = app.getNode(from);
225 if(src==null) {
226 rsp.setStatus(SC_BAD_REQUEST);
227 if(Util.fixEmpty(from)==null)
228 sendError(Messages.ComputerSet_SpecifySlaveToCopy(),req,rsp);
229 else
230 sendError(Messages.ComputerSet_NoSuchSlave(from),req,rsp);
231 return;
232 }
233
234 // copy through XStream
235 String xml = Jenkins.XSTREAM.toXML(src);
236 Node result = (Node) Jenkins.XSTREAM.fromXML(xml);
237 result.setNodeName(name);
238 if(result instanceof Slave){ //change userId too
239 User user = User.current();
240 ((Slave)result).setUserId(user==null ? "anonymous" : user.getId());
241 }
242 result.holdOffLaunchUntilSave = true;
243
244 app.addNode(result);
245
246 // send the browser to the config page
247 rsp.sendRedirect2(result.getNodeName()+"/configure");
248 } else {
249 // proceed to step 2
250 if(mode==null) {
251 rsp.sendError(SC_BAD_REQUEST);
252 return;
253 }
254
255 NodeDescriptor d = NodeDescriptor.all().findByName(mode);
256 d.handleNewNodePage(this,name,req,rsp);
257 }
258 }
259
260 /**
261 * Really creates a new slave.
262 */
263 public synchronized void doDoCreateItem( StaplerRequest req, StaplerResponse rsp,
264 @QueryParameter String name,
265 @QueryParameter String type ) throws IOException, ServletException, FormException {
266 final Jenkins app = Jenkins.getInstance();
267 app.checkPermission(Computer.CREATE);
268 String fixedName = Util.fixEmptyAndTrim(name);
269 checkName(fixedName);
270
271 JSONObject formData = req.getSubmittedForm();
272 formData.put("name", fixedName);
273
274 Node result = NodeDescriptor.all().find(type).newInstance(req, formData);
275 app.addNode(result);
276
277 // take the user back to the slave list top page
278 rsp.sendRedirect2(".");
279 }
280
281 /**
282 * Makes sure that the given name is good as a slave name.
283 * @return trimmed name if valid; throws ParseException if not
284 */
285 public String checkName(String name) throws Failure {
286 if(name==null)
287 throw new Failure("Query parameter 'name' is required");
288
289 name = name.trim();
290 Jenkins.checkGoodName(name);
291
292 if(Jenkins.getInstance().getNode(name)!=null)
293 throw new Failure(Messages.ComputerSet_SlaveAlreadyExists(name));
294
295 // looks good
296 return name;
297 }
298
299 /**
300 * Makes sure that the given name is good as a slave name.
301 */
302 public FormValidation doCheckName(@QueryParameter String value) throws IOException, ServletException {
303 Jenkins.getInstance().checkPermission(Computer.CREATE);
304
305 if(Util.fixEmpty(value)==null)
306 return FormValidation.ok();
307
308 try {
309 checkName(value);
310 return FormValidation.ok();
311 } catch (Failure e) {
312 return FormValidation.error(e.getMessage());
313 }
314 }
315
316 /**
317 * Accepts submission from the configuration page.
318 */
319 @RequirePOST
320 public synchronized HttpResponse doConfigSubmit( StaplerRequest req) throws IOException, ServletException, FormException {
321 BulkChange bc = new BulkChange(MONITORS_OWNER);
322 try {
323 Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
324 monitors.rebuild(req,req.getSubmittedForm(),getNodeMonitorDescriptors());
325
326 // add in the rest of instances are ignored instances
327 for (Descriptor<NodeMonitor> d : NodeMonitor.all())
328 if(monitors.get(d)==null) {
329 NodeMonitor i = createDefaultInstance(d, true);
330 if(i!=null)
331 monitors.add(i);
332 }
333
334 // recompute the data
335 for (NodeMonitor nm : monitors) {
336 nm.triggerUpdate();
337 }
338
339 return FormApply.success(".");
340 } finally {
341 bc.commit();
342 }
343 }
344
345 /**
346 * {@link NodeMonitor}s are persisted in this file.
347 */
348 private static XmlFile getConfigFile() {
349 return new XmlFile(new File(Jenkins.getInstance().getRootDir(),"nodeMonitors.xml"));
350 }
351
352 public Api getApi() {
353 return new Api(this);
354 }
355
356 public Descriptor<ComputerSet> getDescriptor() {
357 return Jenkins.getInstance().getDescriptorOrDie(ComputerSet.class);
358 }
359
360 @Extension
361 public static class DescriptorImpl extends Descriptor<ComputerSet> {
362 @Override
363 public String getDisplayName() {
364 return "";
365 }
366
367 /**
368 * Auto-completion for the "copy from" field in the new job page.
369 */
370 public AutoCompletionCandidates doAutoCompleteCopyNewItemFrom(@QueryParameter final String value) {
371 final AutoCompletionCandidates r = new AutoCompletionCandidates();
372
373 for (Node n : Jenkins.getInstance().getNodes()) {
374 if (n.getNodeName().startsWith(value))
375 r.add(n.getNodeName());
376 }
377
378 return r;
379 }
380 }
381
382 /**
383 * Just to force the execution of the static initializer.
384 */
385 public static void initialize() {}
386
387 private static final Logger LOGGER = Logger.getLogger(ComputerSet.class.getName());
388
389 static {
390 try {
391 DescribableList<NodeMonitor,Descriptor<NodeMonitor>> r
392 = new DescribableList<NodeMonitor, Descriptor<NodeMonitor>>(Saveable.NOOP);
393
394 // load persisted monitors
395 XmlFile xf = getConfigFile();
396 if(xf.exists()) {
397 DescribableList<NodeMonitor,Descriptor<NodeMonitor>> persisted =
398 (DescribableList<NodeMonitor,Descriptor<NodeMonitor>>) xf.read();
399 List<NodeMonitor> sanitized = new ArrayList<NodeMonitor>();
400 for (NodeMonitor nm : persisted) {
401 try {
402 nm.getDescriptor();
403 sanitized.add(nm);
404 } catch (Throwable e) {
405 // the descriptor didn't load? see JENKINS-15869
406 }
407 }
408 r.replaceBy(sanitized);
409 }
410
411 // if we have any new monitors, let's add them
412 for (Descriptor<NodeMonitor> d : NodeMonitor.all())
413 if(r.get(d)==null) {
414 NodeMonitor i = createDefaultInstance(d,false);
415 if(i!=null)
416 r.add(i);
417 }
418 monitors.replaceBy(r.toList());
419 } catch (IOException e) {
420 LOGGER.log(Level.WARNING, "Failed to instanciate NodeMonitors",e);
421 }
422 }
423
424 private static NodeMonitor createDefaultInstance(Descriptor<NodeMonitor> d, boolean ignored) {
425 try {
426 NodeMonitor nm = d.clazz.newInstance();
427 nm.setIgnored(ignored);
428 return nm;
429 } catch (InstantiationException e) {
430 LOGGER.log(Level.SEVERE, "Failed to instanciate "+d.clazz,e);
431 } catch (IllegalAccessException e) {
432 LOGGER.log(Level.SEVERE, "Failed to instanciate "+d.clazz,e);
433 }
434 return null;
435 }
436 }
437