| 6914 |
dpurdie |
1 |
package com.erggroup.buildtool.daemon;
|
|
|
2 |
|
|
|
3 |
import com.erggroup.buildtool.abt.BuildToolException;
|
|
|
4 |
import com.erggroup.buildtool.daemon.BuildThread;
|
|
|
5 |
import com.erggroup.buildtool.ripple.Package;
|
|
|
6 |
import com.erggroup.buildtool.ripple.ReleaseManager;
|
|
|
7 |
import com.erggroup.buildtool.ripple.RippleEngine;
|
|
|
8 |
import com.erggroup.buildtool.ripple.RunLevel.BuildState;
|
|
|
9 |
import com.erggroup.buildtool.utilities.MutableDate;
|
|
|
10 |
|
|
|
11 |
import java.sql.SQLException;
|
|
|
12 |
|
| 7033 |
dpurdie |
13 |
import org.slf4j.Logger;
|
|
|
14 |
import org.slf4j.LoggerFactory;
|
| 6914 |
dpurdie |
15 |
|
|
|
16 |
/**
|
|
|
17 |
* Slave Thread sub component
|
|
|
18 |
*/
|
|
|
19 |
public class SlaveThread extends BuildThread
|
|
|
20 |
{
|
|
|
21 |
|
|
|
22 |
/**
|
|
|
23 |
* Logger
|
|
|
24 |
*
|
|
|
25 |
* @attribute
|
|
|
26 |
*/
|
| 7033 |
dpurdie |
27 |
private static final Logger mLogger = LoggerFactory.getLogger(SlaveThread.class);
|
| 6914 |
dpurdie |
28 |
|
|
|
29 |
/** Holds the buildFile content
|
|
|
30 |
*
|
|
|
31 |
*/
|
|
|
32 |
protected String mBuildFileContent = null;
|
|
|
33 |
|
|
|
34 |
/**constructor
|
|
|
35 |
* @param rtagId - Identifies the Release
|
|
|
36 |
* @param rconId - Identifies the Controlling entry
|
|
|
37 |
* @param releaseManager - A ReleaseManager entry to use
|
|
|
38 |
* @param unitTest - Unit Test data
|
|
|
39 |
*/
|
|
|
40 |
public SlaveThread(int rtagId, int rconId, ReleaseManager releaseManager, String unitTest)
|
|
|
41 |
{
|
|
|
42 |
super(rtagId, rconId, releaseManager, unitTest);
|
|
|
43 |
mLogger.warn("SlaveThread rtag_id " + rtagId + " rcon_id " + rconId);
|
|
|
44 |
}
|
|
|
45 |
|
|
|
46 |
/**
|
|
|
47 |
* implements the sequence diagrams consume build files, allowed to proceed,
|
|
|
48 |
* check environment
|
|
|
49 |
*/
|
|
|
50 |
public void run()
|
|
|
51 |
{
|
|
|
52 |
Integer id = Integer.valueOf(mRtagId);
|
|
|
53 |
setName(id.toString());
|
|
|
54 |
mLogger.warn("run");
|
|
|
55 |
boolean exit = false;
|
|
|
56 |
mRippleEngine = new RippleEngine(mReleaseManager, mRtagId, true);
|
|
|
57 |
|
|
|
58 |
while (!exit)
|
|
|
59 |
{
|
|
|
60 |
try
|
|
|
61 |
{
|
| 7033 |
dpurdie |
62 |
mLogger.error("run calling sleepCheck");
|
| 6914 |
dpurdie |
63 |
mPhase.setPhase("sleepCheck");
|
|
|
64 |
sleepCheck();
|
|
|
65 |
|
| 7033 |
dpurdie |
66 |
mLogger.error("run calling rippleEngine.collectMetaData");
|
| 6914 |
dpurdie |
67 |
mPhase.setPhase("collectMetaData");
|
|
|
68 |
mRippleEngine.collectMetaData();
|
|
|
69 |
|
|
|
70 |
if (Thread.currentThread().isInterrupted())
|
|
|
71 |
{
|
|
|
72 |
mLogger.warn("run is interrupted");
|
|
|
73 |
// unit test technique
|
|
|
74 |
throw new ExitException();
|
|
|
75 |
}
|
|
|
76 |
|
|
|
77 |
if (mUnitTest.compareTo("unit test spawn thread") == 0)
|
|
|
78 |
{
|
|
|
79 |
throw new Exception();
|
|
|
80 |
}
|
|
|
81 |
|
|
|
82 |
// allowed to proceed
|
|
|
83 |
if (mUnitTest.compareTo("unit test consume build files") != 0)
|
|
|
84 |
{
|
| 7033 |
dpurdie |
85 |
mLogger.error("run calling allowedToProceed");
|
| 6914 |
dpurdie |
86 |
mPhase.setPhase("allowedToProceed");
|
|
|
87 |
allowedToProceed(false);
|
|
|
88 |
mLogger.info("run allowedToProceed returned");
|
|
|
89 |
}
|
|
|
90 |
|
|
|
91 |
// Indicate that the Slave is WAITING - for a job
|
|
|
92 |
mPhase.setPhase("Waiting for work");
|
| 7033 |
dpurdie |
93 |
mLogger.error("run changing run level to WAITING for rcon_id " + mRconId);
|
| 6914 |
dpurdie |
94 |
|
|
|
95 |
|
|
|
96 |
// Wait for Slave to be set as Active
|
|
|
97 |
while (!BuildDaemon.mShutDown)
|
|
|
98 |
{
|
|
|
99 |
// Periodically indicate, to Release Manager, that the slave is still alive
|
|
|
100 |
// A warning will be raised after 10 minutes, so it must be less than that
|
|
|
101 |
mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_WAITING);
|
|
|
102 |
|
|
|
103 |
//
|
|
|
104 |
// Wait to be notified that a build request is present
|
|
|
105 |
// Have a timeout just to be sure to be sure
|
|
|
106 |
//
|
|
|
107 |
if (mUnitTest.length() == 0) {
|
|
|
108 |
synchronized (mActiveBuildMonitor) {
|
|
|
109 |
try {
|
|
|
110 |
mActiveBuildMonitor.wait(120 * 1000L);
|
|
|
111 |
}
|
|
|
112 |
catch ( InterruptedException e ) {
|
|
|
113 |
Thread.currentThread().interrupt();
|
|
|
114 |
mLogger.error("InterruptedException in Wait for Active Build");
|
|
|
115 |
}
|
|
|
116 |
}
|
|
|
117 |
}
|
|
|
118 |
|
|
|
119 |
//
|
|
|
120 |
// Determine if the build cycle can proceed
|
|
|
121 |
// May be a shutdown request
|
|
|
122 |
// May be no longer configured
|
|
|
123 |
// May be stopped
|
|
|
124 |
// May be paused
|
|
|
125 |
// May be indefinite pause
|
|
|
126 |
// Will throw exception if we shouldn't continue on this cycle
|
|
|
127 |
//
|
|
|
128 |
mLogger.info("run allowedToContinue");
|
|
|
129 |
allowedToContinue(false);
|
|
|
130 |
|
|
|
131 |
// Detect build Request
|
|
|
132 |
// A non-null buildfile published in the database
|
|
|
133 |
mLogger.info("run calling mReleaseManager.queryBuildFile");
|
|
|
134 |
mBuildFileContent = mReleaseManager.queryBuildFile(mRconId);
|
|
|
135 |
if (mBuildFileContent != null )
|
|
|
136 |
{
|
|
|
137 |
// Build request detected
|
|
|
138 |
mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_ACTIVE);
|
|
|
139 |
break;
|
|
|
140 |
}
|
|
|
141 |
|
|
|
142 |
}
|
|
|
143 |
|
|
|
144 |
//
|
|
|
145 |
// Build Request detected
|
|
|
146 |
// Buildfile has been extracted from the database, but not yet saved
|
|
|
147 |
//
|
|
|
148 |
if (BuildDaemon.mShutDown)
|
|
|
149 |
{
|
|
|
150 |
mLogger.warn("Slave run ShutDown requested");
|
|
|
151 |
throw new ExitException();
|
|
|
152 |
}
|
|
|
153 |
|
|
|
154 |
mLogger.info("run consumed build files");
|
|
|
155 |
if (mUnitTest.compareTo("unit test consume build files") == 0)
|
|
|
156 |
{
|
|
|
157 |
throw new ExitException();
|
|
|
158 |
}
|
|
|
159 |
|
|
|
160 |
// set CURRENT_BUILD_FILES to null
|
|
|
161 |
// Indicates that we have taken the file and will prevent multiple builds
|
|
|
162 |
mLogger.info("run calling mReleaseManager.clearBuildFile");
|
|
|
163 |
mPhase.setPhase("clearBuildFile");
|
|
|
164 |
mReleaseManager.clearBuildFile(mRconId);
|
|
|
165 |
|
|
|
166 |
// check environment
|
|
|
167 |
mLogger.warn("run checkEnvironment");
|
|
|
168 |
mPhase.setPhase("checkEnvironment");
|
|
|
169 |
checkEnvironment();
|
|
|
170 |
mLogger.info("run checkEnvironment returned");
|
|
|
171 |
|
|
|
172 |
mLastBuildWasBenign = true;
|
|
|
173 |
if (mBuildFileContent.compareTo(mDummyBuildFileContent) != 0)
|
|
|
174 |
{
|
|
|
175 |
mLastBuildWasBenign = false;
|
|
|
176 |
|
|
|
177 |
// Start of a build cycle. Set new log file to capture
|
|
|
178 |
// entire build log
|
|
|
179 |
mPhase.setPhase("flagStartBuildCycle");
|
|
|
180 |
flagStartBuildCycle();
|
|
|
181 |
mReporting.resetData();
|
|
|
182 |
|
| 7033 |
dpurdie |
183 |
mLogger.error("Collect fresh MetaData");
|
| 6914 |
dpurdie |
184 |
mPhase.setPhase("collectMetaData");
|
|
|
185 |
mRippleEngine.collectMetaData();
|
|
|
186 |
|
|
|
187 |
// Save the build file
|
| 7033 |
dpurdie |
188 |
mLogger.error("Save buildfile");
|
| 6914 |
dpurdie |
189 |
mPhase.setPhase("Save buildfile");
|
|
|
190 |
saveBuildFile(mBuildFileContent);
|
|
|
191 |
|
|
|
192 |
// deliver change to product baseline
|
| 7033 |
dpurdie |
193 |
mLogger.error("run calling setViewUp");
|
| 6914 |
dpurdie |
194 |
mPhase.setPhase("Setup View for build");
|
|
|
195 |
deliverChange("AbtSetUp", true, true);
|
|
|
196 |
|
| 7033 |
dpurdie |
197 |
mLogger.error("run calling deliverChange - the actual build");
|
| 6914 |
dpurdie |
198 |
mPhase.setPhase("deliverChange for Build");
|
|
|
199 |
deliverChange(null, true, false);
|
|
|
200 |
|
| 7033 |
dpurdie |
201 |
mLogger.error("run calling deliverChange on AbtTearDown");
|
| 6914 |
dpurdie |
202 |
mPhase.setPhase("AbtTearDown");
|
|
|
203 |
deliverChange("AbtTearDown", false, true);
|
|
|
204 |
|
|
|
205 |
if (mReporting.buildFailureLogFile != null)
|
|
|
206 |
{
|
| 7033 |
dpurdie |
207 |
mLogger.error("run calling excludeFromBuild");
|
| 6914 |
dpurdie |
208 |
mPhase.setPhase("excludeFromBuild");
|
|
|
209 |
mReleaseManager.excludeFromBuild(false,
|
|
|
210 |
mReporting.packageVersionId,
|
|
|
211 |
mReporting.packageVersion,
|
|
|
212 |
mRtagId,
|
|
|
213 |
null,
|
|
|
214 |
null,
|
|
|
215 |
mReporting.buildFailureLogFile,
|
|
|
216 |
false, mReporting.isaTestBuild);
|
|
|
217 |
}
|
|
|
218 |
|
|
|
219 |
mLogger.info("run deliverChange returned");
|
|
|
220 |
mPhase.setPhase("End of Build Cycle");
|
|
|
221 |
}
|
|
|
222 |
mReleaseManager.clearCurrentPackageBeingBuilt(mRconId);
|
|
|
223 |
}
|
|
|
224 |
//---------------------------------------------------------------
|
|
|
225 |
// Build loop exception handling (only)
|
|
|
226 |
//
|
|
|
227 |
catch (ShouldNotContinueExpection e)
|
|
|
228 |
{
|
| 7033 |
dpurdie |
229 |
mLogger.error("ShouldNotContinueExpection:" + e.getMessage());
|
| 6914 |
dpurdie |
230 |
}
|
|
|
231 |
catch (SQLException e)
|
|
|
232 |
{
|
|
|
233 |
// oracle connection issues
|
|
|
234 |
// Request a prolonged sleep at the start of the build loop
|
| 7033 |
dpurdie |
235 |
mLogger.error("run oracle connection issues");
|
| 6914 |
dpurdie |
236 |
mException = true;
|
|
|
237 |
}
|
|
|
238 |
catch (ExitException e)
|
|
|
239 |
{
|
|
|
240 |
mLogger.warn("run ExitException");
|
|
|
241 |
exit = true;
|
|
|
242 |
}
|
|
|
243 |
catch (InterruptedException e)
|
|
|
244 |
{
|
|
|
245 |
mLogger.warn("run InterruptedException");
|
|
|
246 |
Thread.currentThread().interrupt();
|
|
|
247 |
}
|
|
|
248 |
catch (BuildSystemException e) {
|
|
|
249 |
// BuildSystem exception - a (possibly) correctable error
|
|
|
250 |
// Flag as recoverable
|
|
|
251 |
// - Can't create XML build file
|
|
|
252 |
// -
|
|
|
253 |
//
|
| 7033 |
dpurdie |
254 |
mLogger.error("run BuildSystemException");
|
| 6914 |
dpurdie |
255 |
mPhase.setPhase("BuildSystemException indefinitePause");
|
|
|
256 |
notifyIndefinitePause(e.getMessage());
|
|
|
257 |
mReleaseManager.indefinitePause(false);
|
|
|
258 |
mException = true;
|
|
|
259 |
mRecoverable = true;
|
|
|
260 |
|
|
|
261 |
}
|
|
|
262 |
catch( BuildToolException e)
|
|
|
263 |
{
|
|
|
264 |
// Buildtool exception - an uncorrectable error
|
|
|
265 |
// - Can't parse XML build file
|
|
|
266 |
// -
|
|
|
267 |
//
|
| 7033 |
dpurdie |
268 |
mLogger.error("run BuildToolException");
|
| 6914 |
dpurdie |
269 |
mPhase.setPhase("BuildToolException indefinitePause");
|
|
|
270 |
notifyIndefinitePause(e.getMessage());
|
|
|
271 |
mReleaseManager.indefinitePause(false);
|
|
|
272 |
mException = true;
|
|
|
273 |
}
|
|
|
274 |
catch (Exception e)
|
|
|
275 |
{
|
|
|
276 |
// Uncaptured exception
|
|
|
277 |
// These are not good. Current mechanism to handle this condition is:
|
|
|
278 |
// 1) Email build system administrator
|
|
|
279 |
// 2) Pause the build system
|
|
|
280 |
//
|
|
|
281 |
mLogger.error("run indefinitePause " + e.toString());
|
|
|
282 |
|
|
|
283 |
// DEVI 51366 force sleep at beginning of while loop
|
|
|
284 |
mException = true;
|
|
|
285 |
|
|
|
286 |
String cause = e.getMessage();
|
|
|
287 |
if ( cause == null || cause.compareTo("null") == 0 )
|
|
|
288 |
{
|
|
|
289 |
cause = "Internal Error: " + e.toString();
|
|
|
290 |
}
|
|
|
291 |
|
|
|
292 |
try
|
|
|
293 |
{
|
|
|
294 |
// notify first
|
|
|
295 |
// many reasons for indefinite pause, including database related, so do database last
|
|
|
296 |
mRecoverable = false;
|
|
|
297 |
|
|
|
298 |
if (cause.compareTo(Package.mRecoverable) == 0)
|
|
|
299 |
{
|
|
|
300 |
mRecoverable = true;
|
|
|
301 |
}
|
|
|
302 |
|
|
|
303 |
mPhase.setPhase("Notify indefinitePause");
|
|
|
304 |
notifyIndefinitePause(cause);
|
|
|
305 |
mReleaseManager.indefinitePause(mRecoverable);
|
|
|
306 |
}
|
|
|
307 |
catch( Exception f )
|
|
|
308 |
{
|
|
|
309 |
mLogger.error("run indefinitePause failed");
|
|
|
310 |
}
|
|
|
311 |
}
|
|
|
312 |
}
|
|
|
313 |
try {
|
|
|
314 |
mReleaseManager.clearCurrentPackageBeingBuilt(mRconId);
|
|
|
315 |
} catch (Exception e) {
|
|
|
316 |
mLogger.error("Exception in clearCurrentPackageBeingBuilt:" + e.getMessage());
|
|
|
317 |
}
|
|
|
318 |
mPhase.setPhase("Exit Thread");
|
|
|
319 |
}
|
|
|
320 |
|
|
|
321 |
/** Determine if we are allowed to continue in this build cycle
|
|
|
322 |
* May be no longer configured
|
|
|
323 |
* May be stopped
|
|
|
324 |
* May be paused
|
|
|
325 |
* May be indefinite pause
|
|
|
326 |
* Will throw exceptions if we shouldn't continue on this cycle
|
|
|
327 |
* Does not hang around waiting for condition to clear - thats done elsewhere
|
|
|
328 |
*
|
|
|
329 |
* @param master - is a master machine making this call
|
|
|
330 |
* @throws ExitException
|
|
|
331 |
* @throws ShouldNotContinueExpection
|
|
|
332 |
* @throws SQLException
|
|
|
333 |
*/
|
|
|
334 |
private void allowedToContinue(boolean master) throws ExitException, ShouldNotContinueExpection, SQLException, Exception {
|
|
|
335 |
|
|
|
336 |
if (BuildDaemon.mShutDown)
|
|
|
337 |
{
|
|
|
338 |
mLogger.warn("allowedToContinue. ShutDown requested");
|
|
|
339 |
throw new ExitException();
|
|
|
340 |
}
|
|
|
341 |
|
|
|
342 |
try
|
|
|
343 |
{
|
| 7033 |
dpurdie |
344 |
mLogger.error("allowedToContinue calling mReleaseManager.connect");
|
| 6914 |
dpurdie |
345 |
mReleaseManager.connect();
|
|
|
346 |
|
|
|
347 |
// Ensure that the machine is a part of the current build set
|
| 7033 |
dpurdie |
348 |
mLogger.error("allowedToContinue calling mReleaseManager.queryReleaseConfig");
|
| 6914 |
dpurdie |
349 |
if ( !mReleaseManager.queryReleaseConfig(mRtagId, mRconId, BuildDaemon.mHostname, getMode(), mStartTime) )
|
|
|
350 |
{
|
|
|
351 |
mLogger.warn("allowedToContinue queryReleaseConfig failed");
|
|
|
352 |
mReleaseManager.disconnect();
|
|
|
353 |
throw new ExitException();
|
|
|
354 |
}
|
|
|
355 |
|
|
|
356 |
|
|
|
357 |
// Check for scheduled downtime or indefinite pause
|
|
|
358 |
MutableDate resumeTime = new MutableDate();
|
| 7033 |
dpurdie |
359 |
mLogger.error("allowedToContinue calling mReleaseManager.queryRunLevelSchedule");
|
| 6914 |
dpurdie |
360 |
if ( !mReleaseManager.queryRunLevelSchedule(resumeTime) )
|
|
|
361 |
{
|
|
|
362 |
mLogger.info("allowedToContinue scheduled downtime");
|
|
|
363 |
mReleaseManager.disconnect();
|
|
|
364 |
throw new ShouldNotContinueExpection("Scheduled downtime");
|
|
|
365 |
}
|
|
|
366 |
|
|
|
367 |
//
|
|
|
368 |
// If commanded to pause, then wait around until the command has been removed.
|
|
|
369 |
//
|
| 7033 |
dpurdie |
370 |
mLogger.error("allowedToContinue calling mReleaseManager.queryDirectedRunLevel");
|
| 6914 |
dpurdie |
371 |
if ( !mReleaseManager.queryDirectedRunLevel(mRconId) )
|
|
|
372 |
{
|
| 7033 |
dpurdie |
373 |
mLogger.error("allowedToContinue Pause Detected");
|
| 6914 |
dpurdie |
374 |
throw new ShouldNotContinueExpection("Pause Detected");
|
|
|
375 |
}
|
|
|
376 |
|
|
|
377 |
}
|
|
|
378 |
finally
|
|
|
379 |
{
|
|
|
380 |
// this block is executed regardless of what happens in the try block
|
|
|
381 |
// even if an exception is thrown
|
|
|
382 |
// ensure disconnect
|
| 7033 |
dpurdie |
383 |
mLogger.error("allowedToContinue calling mReleaseManager.disconnect");
|
| 6914 |
dpurdie |
384 |
mReleaseManager.disconnect();
|
|
|
385 |
}
|
|
|
386 |
|
|
|
387 |
// One last test for a shut down request
|
|
|
388 |
if (BuildDaemon.mShutDown)
|
|
|
389 |
{
|
|
|
390 |
mLogger.warn("allowedToContinue. ShutDown requested");
|
|
|
391 |
throw new ExitException();
|
|
|
392 |
}
|
|
|
393 |
|
|
|
394 |
}
|
|
|
395 |
|
|
|
396 |
/**
|
|
|
397 |
* returns 'S'
|
|
|
398 |
*/
|
|
|
399 |
protected char getMode()
|
|
|
400 |
{
|
|
|
401 |
mLogger.debug("getMode");
|
|
|
402 |
return 'S';
|
|
|
403 |
}
|
|
|
404 |
}
|