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

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Stephen Connolly
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.slaves;
25
26 import antlr.ANTLRException;
27 import hudson.Extension;
28 import static hudson.Util.fixNull;
29 import hudson.model.Computer;
30 import hudson.model.Descriptor;
31 import hudson.scheduler.CronTabList;
32 import hudson.util.FormValidation;
33 import org.kohsuke.stapler.DataBoundConstructor;
34 import org.kohsuke.stapler.QueryParameter;
35
36 import java.io.InvalidObjectException;
37 import java.io.ObjectStreamException;
38 import java.util.Calendar;
39 import java.util.GregorianCalendar;
40 import java.util.concurrent.ExecutionException;
41 import java.util.logging.Level;
42 import java.util.logging.Logger;
43 import static java.util.logging.Level.INFO;
44
45 /**
46 * {@link RetentionStrategy} that controls the slave based on a schedule.
47 *
48 * @author Stephen Connolly
49 * @since 1.275
50 */
51 public class SimpleScheduledRetentionStrategy extends RetentionStrategy<SlaveComputer> {
52
53 private static final Logger LOGGER = Logger.getLogger(SimpleScheduledRetentionStrategy.class.getName());
54
55 private final String startTimeSpec;
56 private transient CronTabList tabs;
57 private transient Calendar lastChecked;
58 private transient long nextStop = Long.MIN_VALUE;
59 private transient long nextStart = Long.MIN_VALUE;
60 private transient long lastStop = Long.MAX_VALUE;
61 private transient long lastStart = Long.MAX_VALUE;
62 private final int upTimeMins;
63 private final boolean keepUpWhenActive;
64
65 @DataBoundConstructor
66 public SimpleScheduledRetentionStrategy(String startTimeSpec, int upTimeMins, boolean keepUpWhenActive)
67 throws ANTLRException {
68 this.startTimeSpec = startTimeSpec;
69 this.keepUpWhenActive = keepUpWhenActive;
70 this.tabs = CronTabList.create(startTimeSpec);
71 this.lastChecked = new GregorianCalendar();
72 this.upTimeMins = Math.max(1, upTimeMins);
73 this.lastChecked.add(Calendar.MINUTE, -1);
74 }
75
76 public int getUpTimeMins() {
77 return upTimeMins;
78 }
79
80 public boolean isKeepUpWhenActive() {
81 return keepUpWhenActive;
82 }
83
84 public String getStartTimeSpec() {
85 return startTimeSpec;
86 }
87
88 private synchronized void updateStartStopWindow() {
89 if (lastStart == Long.MAX_VALUE && lastStop == Long.MAX_VALUE) {
90 // we need to initialize
91
92 // get some useful default values for the lastStart and lastStop... they should be in the past and at least
93 // less than any useful real last start/stop
94 // so default lastStart = now - upTime * 3, and lastStop = now - upTime * 2
95 Calendar time = new GregorianCalendar();
96 time.add(Calendar.MINUTE, -upTimeMins);
97 time.add(Calendar.MINUTE, -upTimeMins);
98 time.add(Calendar.MINUTE, -upTimeMins);
99 lastStart = time.getTimeInMillis();
100 time.add(Calendar.MINUTE, upTimeMins);
101 lastStop = time.getTimeInMillis();
102
103 // we're only interested in the last start if it is less than the upTimeMins ago
104 // any older and last Start is not relevant as the node should be stopped
105 time = new GregorianCalendar();
106 time.add(Calendar.MINUTE, -upTimeMins);
107 time.add(Calendar.MINUTE, -1);
108
109 while (System.currentTimeMillis() + 1000 > time.getTimeInMillis()) {
110 if (tabs.check(time)) {
111 lastStart = time.getTimeInMillis();
112 time.add(Calendar.MINUTE, upTimeMins);
113 lastStop = time.getTimeInMillis();
114 break;
115 }
116 time.add(Calendar.MINUTE, 1);
117 }
118 nextStart = lastStart;
119 nextStop = lastStop;
120 }
121 if (nextStop < System.currentTimeMillis()) {
122 // next stop is in the past
123 lastStart = nextStart;
124 lastStop = nextStop;
125
126 // we don't want to look too far into the future
127 Calendar time = new GregorianCalendar();
128 time.add(Calendar.MINUTE, Math.min(15, upTimeMins));
129 long stopLooking = time.getTimeInMillis();
130 time.setTimeInMillis(nextStop);
131 while (stopLooking > time.getTimeInMillis()) {
132 if (tabs.check(time)) {
133 nextStart = time.getTimeInMillis();
134 time.add(Calendar.MINUTE, upTimeMins);
135 nextStop = time.getTimeInMillis();
136 break;
137 }
138 time.add(Calendar.MINUTE, 1);
139 }
140 }
141 }
142
143 protected synchronized Object readResolve() throws ObjectStreamException {
144 try {
145 tabs = CronTabList.create(startTimeSpec);
146 lastChecked = new GregorianCalendar();
147 this.lastChecked.add(Calendar.MINUTE, -1);
148 nextStop = Long.MIN_VALUE;
149 nextStart = Long.MIN_VALUE;
150 lastStop = Long.MAX_VALUE;
151 lastStart = Long.MAX_VALUE;
152 } catch (ANTLRException e) {
153 InvalidObjectException x = new InvalidObjectException(e.getMessage());
154 x.initCause(e);
155 throw x;
156 }
157 return this;
158 }
159
160 @Override
161 public boolean isManualLaunchAllowed(final SlaveComputer c) {
162 return isOnlineScheduled();
163 }
164
165 public synchronized long check(final SlaveComputer c) {
166 boolean shouldBeOnline = isOnlineScheduled();
167 LOGGER.log(Level.FINE, "Checking computer {0} against schedule. online = {1}, shouldBeOnline = {2}",
168 new Object[]{c.getName(), c.isOnline(), shouldBeOnline});
169 if (shouldBeOnline && c.isOffline()) {
170 LOGGER.log(INFO, "Trying to launch computer {0} as schedule says it should be on-line at "
171 + "this point in time", new Object[]{c.getName()});
172 if (c.isLaunchSupported()) {
173 Computer.threadPoolForRemoting.submit(new Runnable() {
174 public void run() {
175 try {
176 c.connect(true).get();
177 if (c.isOnline()) {
178 LOGGER.log(INFO, "Launched computer {0} per schedule", new Object[]{c.getName()});
179 }
180 if (keepUpWhenActive && c.isOnline() && !c.isAcceptingTasks()) {
181 LOGGER.log(INFO,
182 "Enabling new jobs for computer {0} as it has started its scheduled uptime",
183 new Object[]{c.getName()});
184 c.setAcceptingTasks(true);
185 }
186 } catch (InterruptedException e) {
187 } catch (ExecutionException e) {
188 }
189 }
190 });
191 }
192 } else if (!shouldBeOnline && c.isOnline()) {
193 if (keepUpWhenActive) {
194 if (!c.isIdle() && c.isAcceptingTasks()) {
195 c.setAcceptingTasks(false);
196 LOGGER.log(INFO,
197 "Disabling new jobs for computer {0} as it has finished its scheduled uptime",
198 new Object[]{c.getName()});
199 return 1;
200 } else if (c.isIdle() && c.isAcceptingTasks()) {
201 LOGGER.log(INFO, "Disconnecting computer {0} as it has finished its scheduled uptime",
202 new Object[]{c.getName()});
203 c.disconnect(OfflineCause.create(Messages._SimpleScheduledRetentionStrategy_FinishedUpTime()));
204 } else if (c.isIdle() && !c.isAcceptingTasks()) {
205 LOGGER.log(INFO, "Disconnecting computer {0} as it has finished all jobs running when "
206 + "it completed its scheduled uptime", new Object[]{c.getName()});
207 c.disconnect(OfflineCause.create(Messages._SimpleScheduledRetentionStrategy_FinishedUpTime()));
208 }
209 } else {
210 LOGGER.log(INFO, "Disconnecting computer {0} as it has finished its scheduled uptime",
211 new Object[]{c.getName()});
212 c.disconnect(OfflineCause.create(Messages._SimpleScheduledRetentionStrategy_FinishedUpTime()));
213 }
214 }
215 return 1;
216 }
217
218 private boolean isOnlineScheduled() {
219 updateStartStopWindow();
220 long now = System.currentTimeMillis();
221 return (lastStart < now && lastStop > now) || (nextStart < now && nextStop > now);
222 }
223
224 @Extension
225 public static class DescriptorImpl extends Descriptor<RetentionStrategy<?>> {
226 public String getDisplayName() {
227 return Messages.SimpleScheduledRetentionStrategy_displayName();
228 }
229
230 /**
231 * Performs syntax check.
232 */
233 public FormValidation doCheck(@QueryParameter String value) {
234 try {
235 String msg = CronTabList.create(fixNull(value)).checkSanity();
236 if (msg != null)
237 return FormValidation.warning(msg);
238 return FormValidation.ok();
239 } catch (ANTLRException e) {
240 return FormValidation.error(e.getMessage());
241 }
242 }
243 }
244 }
245