| 6914 |
dpurdie |
1 |
package com.erggroup.buildtool.daemon;
|
|
|
2 |
|
|
|
3 |
import com.erggroup.buildtool.abt.BuildToolException;
|
|
|
4 |
import com.erggroup.buildtool.abt.RemoteExecution;
|
|
|
5 |
import com.erggroup.buildtool.abt.RemoteExecution.LogOutput;
|
|
|
6 |
import com.erggroup.buildtool.daemon.BuildDaemon.NagiosInfo;
|
|
|
7 |
import com.erggroup.buildtool.daemon.ResumeTimerTask;
|
|
|
8 |
import com.erggroup.buildtool.ripple.Package;
|
|
|
9 |
import com.erggroup.buildtool.ripple.Phase;
|
|
|
10 |
import com.erggroup.buildtool.ripple.ReleaseManager;
|
| 7023 |
dpurdie |
11 |
import com.erggroup.buildtool.ripple.DaemonInstruction;
|
| 6914 |
dpurdie |
12 |
import com.erggroup.buildtool.ripple.ReportingData;
|
|
|
13 |
import com.erggroup.buildtool.ripple.RunLevel;
|
|
|
14 |
import com.erggroup.buildtool.smtp.CreateUrls;
|
|
|
15 |
import com.erggroup.buildtool.smtp.Smtpsend;
|
|
|
16 |
import com.erggroup.buildtool.utilities.MutableDate;
|
|
|
17 |
import com.erggroup.buildtool.utilities.utilities;
|
|
|
18 |
import com.erggroup.buildtool.ripple.RippleEngine;
|
|
|
19 |
import com.erggroup.buildtool.ripple.RunLevel.BuildState;
|
|
|
20 |
import com.erggroup.buildtool.daemon.BuildDaemon;
|
|
|
21 |
|
|
|
22 |
import java.io.BufferedReader;
|
|
|
23 |
import java.io.File;
|
|
|
24 |
import java.io.FileNotFoundException;
|
|
|
25 |
import java.io.FileWriter;
|
|
|
26 |
import java.io.FilenameFilter;
|
|
|
27 |
import java.io.IOException;
|
|
|
28 |
import java.io.PrintStream;
|
|
|
29 |
import java.io.StringReader;
|
|
|
30 |
import java.sql.SQLException;
|
|
|
31 |
import java.text.SimpleDateFormat;
|
|
|
32 |
import java.util.Date;
|
|
|
33 |
import java.util.LinkedHashMap;
|
|
|
34 |
import java.util.Map;
|
|
|
35 |
import java.util.Timer;
|
|
|
36 |
|
| 7033 |
dpurdie |
37 |
import org.slf4j.Logger;
|
|
|
38 |
import org.slf4j.LoggerFactory;
|
| 6914 |
dpurdie |
39 |
import org.apache.tools.ant.BuildException;
|
|
|
40 |
import org.apache.tools.ant.DefaultLogger;
|
|
|
41 |
import org.apache.tools.ant.Project;
|
|
|
42 |
import org.apache.tools.ant.ProjectHelper;
|
|
|
43 |
|
|
|
44 |
/**Build Thread sub component
|
|
|
45 |
*/
|
|
|
46 |
public abstract class BuildThread
|
|
|
47 |
extends Thread
|
|
|
48 |
{
|
|
|
49 |
/**baseline identifier (which release manager release this BuildThread is dealing with)
|
|
|
50 |
* @attribute
|
|
|
51 |
*/
|
|
|
52 |
protected int mRtagId = 0;
|
|
|
53 |
|
|
|
54 |
/**unique identifier of this BuildThread
|
|
|
55 |
* @attribute
|
|
|
56 |
*/
|
|
|
57 |
protected int mRconId = 0;
|
|
|
58 |
|
|
|
59 |
/**
|
|
|
60 |
* Used as a monitor for:
|
|
|
61 |
* Slave: Indication that a command has been issued by the master
|
|
|
62 |
* Master: Not yet used
|
|
|
63 |
*/
|
|
|
64 |
protected Object mActiveBuildMonitor = new Object();
|
|
|
65 |
|
|
|
66 |
|
|
|
67 |
/**
|
|
|
68 |
* @aggregation composite
|
|
|
69 |
*/
|
|
|
70 |
protected RunLevel mRunLevel = new RunLevel(BuildState.DB_IDLE);
|
|
|
71 |
|
|
|
72 |
/**
|
|
|
73 |
* @aggregation composite
|
|
|
74 |
*/
|
|
|
75 |
protected ReleaseManager mReleaseManager;
|
|
|
76 |
|
|
|
77 |
/**
|
|
|
78 |
*
|
|
|
79 |
*/
|
|
|
80 |
protected RippleEngine mRippleEngine;
|
|
|
81 |
|
|
|
82 |
/** Parsed ANT project
|
|
|
83 |
*
|
|
|
84 |
*/
|
|
|
85 |
Project mProject = null;
|
|
|
86 |
|
|
|
87 |
/**
|
|
|
88 |
* Indicate the start time of the thread
|
|
|
89 |
* Not nanosecond accurate, just an indication of when it was started
|
|
|
90 |
*/
|
|
|
91 |
protected final long mStartTime = System.currentTimeMillis();
|
|
|
92 |
|
|
|
93 |
/**unit test support
|
|
|
94 |
* @attribute
|
|
|
95 |
*/
|
|
|
96 |
protected String mUnitTest = "";
|
|
|
97 |
|
|
|
98 |
/**
|
|
|
99 |
* @aggregation composite
|
|
|
100 |
*/
|
|
|
101 |
protected ResumeTimerTask mResumeTimerTask;
|
|
|
102 |
|
|
|
103 |
/**
|
|
|
104 |
* @aggregation composite
|
|
|
105 |
*/
|
|
|
106 |
private Timer mTimer;
|
|
|
107 |
|
|
|
108 |
/**Synchroniser object
|
|
|
109 |
* Use to Synchronize on by multiple threads
|
|
|
110 |
* @attribute
|
|
|
111 |
*/
|
|
|
112 |
static final Object mSynchroniser = new Object();
|
|
|
113 |
|
|
|
114 |
/**BuildThread group
|
|
|
115 |
* @attribute
|
|
|
116 |
*/
|
|
|
117 |
public static final ThreadGroup mThreadGroup = new ThreadGroup("BuildThread");
|
|
|
118 |
|
|
|
119 |
/**the advertised build file content when either
|
|
|
120 |
* a) no package in the baseline has a build requirement
|
|
|
121 |
* b) the next package in the baseline with a build requirement is generic
|
|
|
122 |
* @attribute
|
|
|
123 |
*/
|
|
|
124 |
protected static final String mDummyBuildFileContent = "<dummy/>";
|
|
|
125 |
|
|
|
126 |
/**Set true when last build cycle was benign.
|
|
|
127 |
* @attribute
|
|
|
128 |
*/
|
|
|
129 |
protected boolean mLastBuildWasBenign;
|
|
|
130 |
|
|
|
131 |
/** Last retrieved release sequence number
|
|
|
132 |
* Used to determine if the Release Content has been changed by a user
|
|
|
133 |
* The sequence number does not take into account changes by the build system
|
|
|
134 |
*/
|
|
|
135 |
protected int mReleaseSeqNum = -1;
|
|
|
136 |
|
|
|
137 |
/** Holds the current buildfile
|
|
|
138 |
*
|
|
|
139 |
*/
|
|
|
140 |
protected File mBuildFile = new File("");
|
|
|
141 |
|
|
|
142 |
/**Set true when last build cycle caught SQLException or Exception.
|
|
|
143 |
* @attribute
|
|
|
144 |
*/
|
|
|
145 |
protected boolean mException;
|
|
|
146 |
|
|
|
147 |
/**Set true when ant error reported on any target.
|
|
|
148 |
* @attribute
|
|
|
149 |
*/
|
|
|
150 |
protected boolean mErrorReported;
|
|
|
151 |
|
|
|
152 |
/**Logger
|
|
|
153 |
* @attribute
|
|
|
154 |
*/
|
| 7033 |
dpurdie |
155 |
private static final Logger mLogger = LoggerFactory.getLogger(BuildThread.class);
|
| 6914 |
dpurdie |
156 |
|
|
|
157 |
/** Data about the package that is being built
|
|
|
158 |
* @attribute
|
|
|
159 |
*/
|
|
|
160 |
protected ReportingData mReporting = new ReportingData();
|
|
|
161 |
|
|
|
162 |
/**Indicate the type of indefinite pause being processed
|
|
|
163 |
* If true, then it is one that the daemon threads can recover from
|
|
|
164 |
* If false, then wait for RM Database to indicate that its OK to proceed
|
|
|
165 |
* @attribute
|
|
|
166 |
*/
|
|
|
167 |
protected boolean mRecoverable;
|
|
|
168 |
|
|
|
169 |
/**Logger for the entire build process
|
|
|
170 |
* @attribute
|
|
|
171 |
*/
|
|
|
172 |
DefaultLogger mBuildLogger ;
|
|
|
173 |
|
|
|
174 |
/**Nagios Monitoring
|
|
|
175 |
* @attribute
|
|
|
176 |
*/
|
|
|
177 |
Phase mPhase = new Phase();
|
|
|
178 |
|
|
|
179 |
|
|
|
180 |
/**constructor
|
| 7033 |
dpurdie |
181 |
* @param rtagId - Identifies the Release
|
| 6914 |
dpurdie |
182 |
* @param rconId - Identifies the Controlling entry
|
|
|
183 |
* @param releaseManager - A ReleaseManager entry to use
|
|
|
184 |
* @param unitTest - Unit Test data
|
|
|
185 |
*/
|
|
|
186 |
BuildThread(int rtagId, int rconId, ReleaseManager releaseManager, String unitTest)
|
|
|
187 |
{
|
|
|
188 |
super(mThreadGroup, "");
|
|
|
189 |
mLogger.debug("BuildThread");
|
|
|
190 |
mLastBuildWasBenign = true;
|
|
|
191 |
mException = false;
|
|
|
192 |
mErrorReported = false;
|
|
|
193 |
mRecoverable = false;
|
|
|
194 |
|
|
|
195 |
mRtagId = rtagId;
|
|
|
196 |
mRconId = rconId;
|
|
|
197 |
mReleaseManager = releaseManager;
|
|
|
198 |
mBuildFile = new File(mRtagId + "build.xml");
|
|
|
199 |
mUnitTest = ( unitTest == null ) ? "" : unitTest;
|
|
|
200 |
|
|
|
201 |
// no need to be synchronized - BuildThreads are instantiated in a single thread
|
|
|
202 |
if ( mResumeTimerTask == null )
|
|
|
203 |
{
|
|
|
204 |
mResumeTimerTask = new ResumeTimerTask();
|
|
|
205 |
mTimer = new Timer();
|
|
|
206 |
mResumeTimerTask.setTimer(mTimer);
|
|
|
207 |
}
|
|
|
208 |
}
|
|
|
209 |
|
|
|
210 |
/**Flags that a new build cycle is about to start
|
|
|
211 |
* Create a new logger to capture all the complete build log
|
|
|
212 |
* even though its done in stages we want a complete log.
|
|
|
213 |
*/
|
|
|
214 |
void flagStartBuildCycle()
|
|
|
215 |
{
|
|
|
216 |
try
|
|
|
217 |
{
|
|
|
218 |
mBuildLogger = new DefaultLogger();
|
|
|
219 |
PrintStream ps = new PrintStream(mRtagId + ".log");
|
|
|
220 |
mBuildLogger.setOutputPrintStream(ps);
|
|
|
221 |
mBuildLogger.setMessageOutputLevel(Project.MSG_INFO);
|
|
|
222 |
}
|
|
|
223 |
catch( FileNotFoundException e )
|
|
|
224 |
{
|
|
|
225 |
mLogger.error("BuildThread caught FileNotFoundException");
|
|
|
226 |
}
|
|
|
227 |
}
|
|
|
228 |
|
|
|
229 |
/**
|
|
|
230 |
* Sleeps when mException is set
|
|
|
231 |
* Called at the top of the run() loop, just after exception processing
|
|
|
232 |
*/
|
|
|
233 |
protected void sleepCheck()
|
|
|
234 |
{
|
|
|
235 |
if (mException && ! BuildDaemon.mShutDown)
|
|
|
236 |
{
|
|
|
237 |
Integer sleepTime = 5 * 60;
|
| 7033 |
dpurdie |
238 |
mLogger.warn("sleepCheck sleep {} secs", sleepTime);
|
| 6914 |
dpurdie |
239 |
BuildDaemon.daemonSleepSecs(sleepTime);
|
|
|
240 |
mLogger.info("sleepCheck sleep returned");
|
|
|
241 |
|
|
|
242 |
// Force planning cycle when recovering from an exception
|
|
|
243 |
mReleaseSeqNum = -1;
|
|
|
244 |
}
|
|
|
245 |
mException = false;
|
|
|
246 |
}
|
|
|
247 |
|
|
|
248 |
/**initially changes the run level to IDLE
|
|
|
249 |
* <br>Determines if the BuildThread is still configured
|
|
|
250 |
* <br>Detects shutdown requests
|
|
|
251 |
* <br>a) Determines if the BuildThread is running in scheduled down time
|
|
|
252 |
* <br>b) Determines if the BuildThread is directed to pause
|
|
|
253 |
* <br>Changes the run level to PAUSED if a) or b) are true
|
|
|
254 |
* <br>throws ExitException when not configured or shutdown request
|
|
|
255 |
*
|
|
|
256 |
* @param master True: Master Daemon
|
|
|
257 |
* @exception ExitException
|
|
|
258 |
* @exception SQLException
|
|
|
259 |
* @exception Exception
|
|
|
260 |
*/
|
|
|
261 |
protected void allowedToProceed(boolean master) throws ExitException, SQLException, Exception
|
|
|
262 |
{
|
|
|
263 |
mLogger.debug("allowedToProceed");
|
|
|
264 |
|
|
|
265 |
// Release Manager Database operations
|
|
|
266 |
// Change the run level to IDLE
|
|
|
267 |
// Discard any reserved version numbers
|
|
|
268 |
// Reset the current package being built
|
|
|
269 |
try
|
|
|
270 |
{
|
| 7033 |
dpurdie |
271 |
mLogger.error("allowedToProceed changing run level to IDLE for rcon_id {}", mRconId);
|
| 6914 |
dpurdie |
272 |
mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_IDLE);
|
|
|
273 |
}
|
|
|
274 |
catch(SQLException e)
|
|
|
275 |
{
|
|
|
276 |
mLogger.warn("allowedToProceed caught SQLException");
|
|
|
277 |
}
|
|
|
278 |
|
|
|
279 |
// Sleep for the required time - if the last build cycle was benign
|
|
|
280 |
// Slaves sleep for 3 seconds
|
|
|
281 |
// Masters will sleep for up to 60 minutes
|
|
|
282 |
if (mLastBuildWasBenign && !BuildDaemon.mShutDown)
|
|
|
283 |
{
|
|
|
284 |
if (master)
|
|
|
285 |
{
|
|
|
286 |
long startMasterWait = System.currentTimeMillis();
|
|
|
287 |
while(!BuildDaemon.mShutDown)
|
|
|
288 |
{
|
|
|
289 |
int masterCount = mReleaseManager.queryMasterCount( mRtagId );
|
|
|
290 |
if ( masterCount != 1)
|
|
|
291 |
{
|
| 7033 |
dpurdie |
292 |
mLogger.warn("allowedToProceed Invalid MasterCount: {}", masterCount);
|
| 6914 |
dpurdie |
293 |
throw new ExitException();
|
|
|
294 |
}
|
|
|
295 |
|
|
|
296 |
int seqNum = mReleaseManager.queryReleaseSeqNum(mRtagId, mRconId, BuildDaemon.mHostname);
|
|
|
297 |
if ( seqNum < 0 )
|
|
|
298 |
{
|
|
|
299 |
mLogger.warn("allowedToProceed Not part of buildset");
|
|
|
300 |
throw new ExitException();
|
|
|
301 |
}
|
|
|
302 |
if ( seqNum != mReleaseSeqNum)
|
|
|
303 |
{
|
|
|
304 |
// Release Content has been modified
|
|
|
305 |
mReleaseSeqNum = seqNum;
|
| 7033 |
dpurdie |
306 |
mLogger.error("allowedToProceed. Release Sequence changed");
|
| 6914 |
dpurdie |
307 |
break;
|
|
|
308 |
}
|
|
|
309 |
|
| 7023 |
dpurdie |
310 |
// Check daemon instructions that need to be processed
|
| 6914 |
dpurdie |
311 |
//
|
| 7023 |
dpurdie |
312 |
DaemonInstruction di = new DaemonInstruction(mRtagId, -1, true);
|
|
|
313 |
if ( mReleaseManager.getDaemonInst( di ) )
|
|
|
314 |
{
|
|
|
315 |
// At least one daemon instruction has expired
|
| 7033 |
dpurdie |
316 |
mLogger.error("allowedToProceed. Deamon instruction to be scheduled");
|
| 7023 |
dpurdie |
317 |
break;
|
|
|
318 |
}
|
|
|
319 |
|
|
|
320 |
//
|
| 6914 |
dpurdie |
321 |
// Backup plan
|
|
|
322 |
// Force a planning session every 60 minutes
|
|
|
323 |
//
|
|
|
324 |
if ( System.currentTimeMillis() - startMasterWait > 60 * 60 * 1000)
|
|
|
325 |
{
|
| 7033 |
dpurdie |
326 |
mLogger.error("allowedToProceed. Force periodic plan");
|
| 6914 |
dpurdie |
327 |
break;
|
|
|
328 |
}
|
|
|
329 |
|
|
|
330 |
// Have no reason to suspect that we need to plan a release
|
|
|
331 |
// Persist idle state to indicate the master is polling
|
|
|
332 |
// Wait 60 seconds and test again
|
|
|
333 |
//
|
|
|
334 |
mLogger.warn("allowedToProceed sleep 60 secs no build requirement");
|
|
|
335 |
mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_IDLE);
|
|
|
336 |
BuildDaemon.daemonSleepSecs(60);
|
|
|
337 |
mLogger.info("allowedToProceed sleep returned");
|
|
|
338 |
}
|
|
|
339 |
}
|
|
|
340 |
else
|
|
|
341 |
{
|
|
|
342 |
// Slave - Wait 3 seconds
|
|
|
343 |
mLogger.warn("allowedToProceed sleep 3 secs no build requirement");
|
|
|
344 |
BuildDaemon.daemonSleepSecs(3);
|
|
|
345 |
mLogger.info("allowedToProceed sleep returned");
|
|
|
346 |
}
|
|
|
347 |
}
|
|
|
348 |
|
|
|
349 |
if (BuildDaemon.mShutDown)
|
|
|
350 |
{
|
|
|
351 |
mLogger.warn("allowedToProceed ShutDown requested");
|
|
|
352 |
throw new ExitException();
|
|
|
353 |
}
|
|
|
354 |
|
|
|
355 |
// Loop until this daemon can proceed - or no longer configured as a part of the build set
|
|
|
356 |
// Things that will hold it up:
|
|
|
357 |
// Indefinite pause
|
|
|
358 |
// Scheduled down time
|
|
|
359 |
// Waiting for recoverable error (dpkg_archive access)
|
|
|
360 |
|
|
|
361 |
boolean proceed = false;
|
|
|
362 |
try
|
|
|
363 |
{
|
|
|
364 |
while ( !proceed && !BuildDaemon.mShutDown )
|
|
|
365 |
{
|
| 7033 |
dpurdie |
366 |
mLogger.error("allowedToProceed calling mReleaseManager.connect");
|
| 6914 |
dpurdie |
367 |
mReleaseManager.connect();
|
|
|
368 |
|
|
|
369 |
// Ensure that the machine is a part of the current build set
|
| 7033 |
dpurdie |
370 |
mLogger.error("allowedToProceed calling mReleaseManager.queryReleaseConfig");
|
| 6914 |
dpurdie |
371 |
if ( !mReleaseManager.queryReleaseConfig(mRtagId, mRconId, BuildDaemon.mHostname, getMode(), mStartTime) )
|
|
|
372 |
{
|
|
|
373 |
mLogger.warn("allowedToProceed queryReleaseConfig failed");
|
|
|
374 |
mReleaseManager.disconnect();
|
|
|
375 |
throw new ExitException();
|
|
|
376 |
}
|
|
|
377 |
|
|
|
378 |
// If dpkg_archive has been flagged as unavailable, then check for its recovery
|
|
|
379 |
//
|
|
|
380 |
if ( mRecoverable )
|
|
|
381 |
{
|
|
|
382 |
if ( Package.recover() )
|
|
|
383 |
{
|
|
|
384 |
// Package archive(s) exist
|
|
|
385 |
// clear the indefinite pause condition
|
|
|
386 |
mReleaseManager.resumeIndefinitePause();
|
|
|
387 |
notifyIndefiniteRecovery();
|
|
|
388 |
mRecoverable = false;
|
|
|
389 |
}
|
|
|
390 |
}
|
|
|
391 |
|
|
|
392 |
if ( mUnitTest.compareTo("unit test not allowed to proceed") == 0 )
|
|
|
393 |
{
|
|
|
394 |
mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_PAUSED);
|
|
|
395 |
throw new ExitException();
|
|
|
396 |
}
|
|
|
397 |
|
|
|
398 |
// Check for scheduled downtime or indefinite pause
|
|
|
399 |
MutableDate resumeTime = new MutableDate();
|
| 7033 |
dpurdie |
400 |
mLogger.error("allowedToProceed calling mReleaseManager.queryRunLevelSchedule");
|
| 6914 |
dpurdie |
401 |
if ( !mReleaseManager.queryRunLevelSchedule(resumeTime) )
|
|
|
402 |
{
|
|
|
403 |
mLogger.info("allowedToProceed scheduled downtime");
|
|
|
404 |
mReleaseManager.disconnect();
|
|
|
405 |
|
| 7033 |
dpurdie |
406 |
mLogger.error("allowedToProceed changing run level to PAUSED for rcon_id {}", mRconId);
|
| 6914 |
dpurdie |
407 |
mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_PAUSED);
|
|
|
408 |
|
|
|
409 |
//
|
|
|
410 |
// Limit the pause to 10 minutes at a time
|
|
|
411 |
// Allows early get out for the daemons
|
|
|
412 |
long tenMinutesFromNow = System.currentTimeMillis() + 10 * 60 * 1000;
|
|
|
413 |
if (resumeTime.value.getTime() > tenMinutesFromNow)
|
|
|
414 |
{
|
|
|
415 |
resumeTime.value.setTime(tenMinutesFromNow);
|
|
|
416 |
mLogger.warn("allowedToProceed delay limited to 10 minutes");
|
|
|
417 |
}
|
|
|
418 |
|
|
|
419 |
synchronized(mSynchroniser)
|
|
|
420 |
{
|
|
|
421 |
// contain the schedule and wait in the same synchronized block to prevent a deadlock
|
|
|
422 |
// eg this thread calls schedule, timer thread calls notifyall, this thread calls wait (forever)
|
|
|
423 |
try
|
|
|
424 |
{
|
|
|
425 |
if (mResumeTimerTask.isCancelled())
|
|
|
426 |
{
|
|
|
427 |
mResumeTimerTask = new ResumeTimerTask();
|
|
|
428 |
mTimer = new Timer();
|
|
|
429 |
mResumeTimerTask.setTimer(mTimer);
|
|
|
430 |
}
|
| 7033 |
dpurdie |
431 |
mLogger.warn("allowedToProceed schedule passed {}", resumeTime.value.getTime());
|
| 6914 |
dpurdie |
432 |
mTimer.schedule(mResumeTimerTask, resumeTime.value);
|
|
|
433 |
}
|
|
|
434 |
catch( IllegalStateException e )
|
|
|
435 |
{
|
|
|
436 |
// this may be thrown by schedule if already scheduled
|
|
|
437 |
// it signifies another BuildThread has already scheduled the ResumeTimerTask
|
|
|
438 |
mLogger.warn("allowedToProceed already scheduled");
|
|
|
439 |
}
|
|
|
440 |
|
|
|
441 |
try
|
|
|
442 |
{
|
|
|
443 |
mLogger.warn("allowedToProceed wait");
|
|
|
444 |
mSynchroniser.wait();
|
|
|
445 |
mLogger.warn("allowedToProceed wait returned");
|
|
|
446 |
}
|
|
|
447 |
catch( InterruptedException e )
|
|
|
448 |
{
|
|
|
449 |
mLogger.warn("allowedToProceed caught InterruptedException");
|
|
|
450 |
Thread.currentThread().interrupt();
|
|
|
451 |
}
|
|
|
452 |
}
|
|
|
453 |
|
|
|
454 |
}
|
|
|
455 |
else
|
|
|
456 |
{
|
|
|
457 |
//
|
|
|
458 |
// If commanded to pause, then wait around until the command has been removed.
|
|
|
459 |
//
|
| 7033 |
dpurdie |
460 |
mLogger.error("allowedToProceed calling mReleaseManager.queryDirectedRunLevel");
|
| 6914 |
dpurdie |
461 |
if ( !mReleaseManager.queryDirectedRunLevel(mRconId) && !BuildDaemon.mShutDown )
|
|
|
462 |
{
|
| 7033 |
dpurdie |
463 |
mLogger.error("allowedToProceed changing run level to PAUSED for rcon_id {}", mRconId);
|
| 6914 |
dpurdie |
464 |
mReleaseManager.disconnect();
|
|
|
465 |
mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_PAUSED);
|
|
|
466 |
|
|
|
467 |
// Sleep for periodicMs
|
|
|
468 |
mLogger.warn("allowedToProceed sleep 1 mins directed downtime");
|
|
|
469 |
BuildDaemon.daemonSleepSecs(60);
|
|
|
470 |
mLogger.info("allowedToProceed sleep returned");
|
|
|
471 |
}
|
|
|
472 |
else
|
|
|
473 |
{
|
|
|
474 |
mReleaseManager.disconnect();
|
|
|
475 |
proceed = true;
|
|
|
476 |
}
|
|
|
477 |
}
|
|
|
478 |
}
|
|
|
479 |
}
|
|
|
480 |
finally
|
|
|
481 |
{
|
|
|
482 |
// this block is executed regardless of what happens in the try block
|
|
|
483 |
// even if an exception is thrown
|
|
|
484 |
// ensure disconnect
|
| 7033 |
dpurdie |
485 |
mLogger.error("allowedToProceed calling mReleaseManager.disconnect");
|
| 6914 |
dpurdie |
486 |
mReleaseManager.disconnect();
|
|
|
487 |
}
|
|
|
488 |
|
|
|
489 |
if (BuildDaemon.mShutDown)
|
|
|
490 |
{
|
|
|
491 |
mLogger.warn("allowedToProceed ShutDown requested");
|
|
|
492 |
throw new ExitException();
|
|
|
493 |
}
|
|
|
494 |
|
|
|
495 |
}
|
|
|
496 |
|
|
|
497 |
/**periodically
|
|
|
498 |
* <br>a) performs disk housekeeping
|
|
|
499 |
* <br>b) determines if a minimum threshold of disk space is available
|
|
|
500 |
* <br>c) determines if a file can be touched
|
|
|
501 |
* <br>d) Master: Checks that a ssh connection can be established to the package server
|
|
|
502 |
* <br>changes the run level to CANNOT_CONTINUE if insufficient disk space
|
|
|
503 |
* <br>otherwise changes the run level to ACTIVE and returns
|
|
|
504 |
* <p>This function does not return until all check have passed
|
|
|
505 |
*
|
|
|
506 |
* @return true - The task was delayed until all checks passed. The caller may
|
|
|
507 |
* wish to reevaluate the ability to continue the current task.
|
|
|
508 |
*
|
|
|
509 |
*/
|
|
|
510 |
protected boolean checkEnvironment() throws Exception
|
|
|
511 |
{
|
|
|
512 |
mLogger.debug("checkEnvironment");
|
|
|
513 |
boolean exit = false;
|
|
|
514 |
boolean waitPerformed = false;
|
|
|
515 |
String reason;
|
|
|
516 |
|
|
|
517 |
while( !exit )
|
|
|
518 |
{
|
|
|
519 |
mPhase.setPhase("checkEnvironment");
|
|
|
520 |
exit = false;
|
|
|
521 |
reason = "No Reason";
|
|
|
522 |
|
|
|
523 |
// Ugly Unit Testing Hook
|
|
|
524 |
if ( mUnitTest.startsWith("unit test") )
|
|
|
525 |
{
|
|
|
526 |
if ( mUnitTest.startsWith("unit test check environment") )
|
|
|
527 |
{
|
|
|
528 |
if (mUnitTest.endsWith("Pass2"))
|
|
|
529 |
{
|
|
|
530 |
exit = true;
|
|
|
531 |
}
|
|
|
532 |
else
|
|
|
533 |
{
|
|
|
534 |
mUnitTest += ".Pass2";
|
|
|
535 |
reason = "Unit Test Check";
|
|
|
536 |
}
|
|
|
537 |
}
|
|
|
538 |
else
|
|
|
539 |
{
|
|
|
540 |
exit= true;
|
|
|
541 |
}
|
|
|
542 |
}
|
|
|
543 |
else
|
|
|
544 |
{
|
|
|
545 |
housekeep();
|
|
|
546 |
|
|
|
547 |
// Perform checks in order
|
|
|
548 |
// Failure of the first one terminates the check
|
|
|
549 |
//
|
|
|
550 |
|
|
|
551 |
if ( ! hasSufficientDiskSpace() )
|
|
|
552 |
{
|
|
|
553 |
mLogger.warn("checkEnvironment below disk free threshold");
|
|
|
554 |
mPhase.setPhase("checkEnvironment:Wait for diskspace");
|
|
|
555 |
reason = "Insufficient disk space";
|
|
|
556 |
}
|
|
|
557 |
else if (!touch() )
|
|
|
558 |
{
|
|
|
559 |
mLogger.warn("checkEnvironment read only file system detected");
|
|
|
560 |
mPhase.setPhase("checkEnvironment:Wait for writable files system");
|
|
|
561 |
reason = "Readonly file system";
|
|
|
562 |
}
|
|
|
563 |
else if ( !checkRemoteExecution() )
|
|
|
564 |
{
|
|
|
565 |
mLogger.warn("checkEnvironment Remote connection not established");
|
|
|
566 |
mPhase.setPhase("checkEnvironment:Wait for remote execution");
|
|
|
567 |
reason = "No remote connection";
|
|
|
568 |
}
|
|
|
569 |
else
|
|
|
570 |
{
|
|
|
571 |
exit = true;
|
|
|
572 |
mPhase.setPhase("checkEnvironment");
|
|
|
573 |
reason = "No Reason";
|
|
|
574 |
}
|
|
|
575 |
}
|
|
|
576 |
if ( !exit )
|
|
|
577 |
{
|
|
|
578 |
waitPerformed = true;
|
| 7033 |
dpurdie |
579 |
mLogger.error("checkEnvironment changing run level to CANNOT_CONTINUE for rcon_id {}", mRconId);
|
| 6914 |
dpurdie |
580 |
mRunLevel.persistFault(mReleaseManager, mRconId, reason);
|
|
|
581 |
|
|
|
582 |
if ( !mUnitTest.startsWith("unit test check environment") )
|
|
|
583 |
{
|
|
|
584 |
mLogger.warn("checkEnvironment sleep 5 mins");
|
|
|
585 |
exit = BuildDaemon.daemonSleepSecs(5 * 60);
|
|
|
586 |
mLogger.info("checkEnvironment sleep returned");
|
|
|
587 |
}
|
|
|
588 |
}
|
|
|
589 |
}
|
|
|
590 |
|
| 7033 |
dpurdie |
591 |
mLogger.error("checkEnvironment changing run level to ACTIVE for rcon_id {}", mRconId);
|
| 6914 |
dpurdie |
592 |
mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_ACTIVE);
|
|
|
593 |
|
|
|
594 |
return waitPerformed;
|
|
|
595 |
}
|
|
|
596 |
|
|
|
597 |
/** Perform check of the remote execution target machine
|
|
|
598 |
* Used so that we know at the start of a build that the target machine can be contacted
|
|
|
599 |
* Check is only done on the master
|
|
|
600 |
*
|
|
|
601 |
* @return true - the check has passed
|
|
|
602 |
*
|
|
|
603 |
*/
|
|
|
604 |
private boolean checkRemoteExecution()
|
|
|
605 |
{
|
|
|
606 |
if ( getMode() != 'M' || mUnitTest.startsWith("unit test") )
|
|
|
607 |
{
|
|
|
608 |
// Don't check if
|
|
|
609 |
// This thread is not a master
|
|
|
610 |
// This is a unit test
|
|
|
611 |
return true;
|
|
|
612 |
}
|
|
|
613 |
|
|
|
614 |
RemoteExecution mRemoteExecution = new RemoteExecution(new LogOutput(){
|
|
|
615 |
|
|
|
616 |
@Override
|
|
|
617 |
public void data(String message) {
|
|
|
618 |
mLogger.info(message);
|
|
|
619 |
}
|
|
|
620 |
|
|
|
621 |
@Override
|
|
|
622 |
public void fatal(String message) {
|
| 7033 |
dpurdie |
623 |
mLogger.error(message);
|
| 6914 |
dpurdie |
624 |
}
|
|
|
625 |
|
|
|
626 |
@Override
|
|
|
627 |
public void info(String message) {
|
|
|
628 |
mLogger.info(message);
|
|
|
629 |
}});
|
|
|
630 |
|
|
|
631 |
return mRemoteExecution.testConnection();
|
|
|
632 |
|
|
|
633 |
}
|
|
|
634 |
|
|
|
635 |
|
|
|
636 |
/**performs disk housekeeping which involves deleting build directories > 5 days old
|
|
|
637 |
* refer to the sequence diagram check environment
|
|
|
638 |
*/
|
|
|
639 |
private void housekeep()
|
|
|
640 |
{
|
|
|
641 |
mLogger.debug("housekeep");
|
|
|
642 |
FilenameFilter filter = new FilenameFilter()
|
|
|
643 |
{
|
|
|
644 |
|
|
|
645 |
// Filter function to process the files processed within this routine
|
|
|
646 |
public boolean accept(File file, String name)
|
|
|
647 |
{
|
| 7033 |
dpurdie |
648 |
mLogger.debug("accept {}", name);
|
| 6914 |
dpurdie |
649 |
boolean retVal = false;
|
|
|
650 |
|
|
|
651 |
if ( file.isDirectory() && !name.startsWith( "." ) )
|
|
|
652 |
{
|
|
|
653 |
retVal = true;
|
|
|
654 |
}
|
|
|
655 |
|
| 7033 |
dpurdie |
656 |
mLogger.info("accept returned {}", retVal);
|
| 6914 |
dpurdie |
657 |
return retVal;
|
|
|
658 |
}
|
|
|
659 |
};
|
|
|
660 |
|
|
|
661 |
try
|
|
|
662 |
{
|
|
|
663 |
// DEVI 46729, 46730, solaris 10 core dumps implicate deleteDirectory
|
|
|
664 |
// let each BuildThread look after its own housekeeping
|
|
|
665 |
String cwdPath = utilities.catDir(BuildDaemon.mGbeLog ,BuildDaemon.mHostname ,String.valueOf( mRtagId ));
|
|
|
666 |
File cwd = utilities.freshFile(cwdPath);
|
|
|
667 |
|
|
|
668 |
File[] children = cwd.listFiles( filter );
|
|
|
669 |
|
|
|
670 |
if ( children != null )
|
|
|
671 |
{
|
|
|
672 |
for ( int child=0; child < children.length; child++ )
|
|
|
673 |
{
|
|
|
674 |
// child is named uniquely to encapsulate a build
|
|
|
675 |
// 5 days = 432,000,000 milliseconds
|
|
|
676 |
if ( ( System.currentTimeMillis() - children[ child ].lastModified() ) > 432000000 )
|
|
|
677 |
{
|
|
|
678 |
// the directory is over 5 days old
|
| 7033 |
dpurdie |
679 |
mLogger.warn("housekeep deleting directory {}", children[ child ].getName());
|
| 6914 |
dpurdie |
680 |
deleteDirectory( children[ child ] );
|
|
|
681 |
}
|
|
|
682 |
}
|
|
|
683 |
}
|
|
|
684 |
}
|
|
|
685 |
catch( SecurityException e )
|
|
|
686 |
{
|
|
|
687 |
// this can be thrown by lastModified
|
|
|
688 |
mLogger.warn("housekeep caught SecurityException");
|
|
|
689 |
}
|
|
|
690 |
|
|
|
691 |
}
|
|
|
692 |
|
|
|
693 |
/**returns true if a file exists and can be deleted,
|
|
|
694 |
* created and exists in the file system
|
|
|
695 |
* this is to guard against read-only file systems
|
|
|
696 |
*/
|
|
|
697 |
private boolean touch()
|
|
|
698 |
{
|
|
|
699 |
mLogger.debug("touch");
|
|
|
700 |
boolean retVal = true;
|
|
|
701 |
|
|
|
702 |
try
|
|
|
703 |
{
|
|
|
704 |
File touch = new File( String.valueOf( mRtagId ) + "touch" );
|
|
|
705 |
|
|
|
706 |
if ( touch.exists() )
|
|
|
707 |
{
|
|
|
708 |
// delete it
|
|
|
709 |
retVal = touch.delete();
|
|
|
710 |
}
|
|
|
711 |
|
|
|
712 |
if ( retVal )
|
|
|
713 |
{
|
|
|
714 |
// file does not exist
|
|
|
715 |
retVal = touch.createNewFile();
|
|
|
716 |
}
|
|
|
717 |
}
|
|
|
718 |
catch( SecurityException e )
|
|
|
719 |
{
|
|
|
720 |
// this can be thrown by exists, delete, createNewFile
|
|
|
721 |
retVal = false;
|
|
|
722 |
mLogger.warn("touch caught SecurityException");
|
|
|
723 |
}
|
|
|
724 |
catch( IOException e )
|
|
|
725 |
{
|
|
|
726 |
// this can be thrown by createNewFile
|
|
|
727 |
retVal = false;
|
|
|
728 |
mLogger.warn("touch caught IOException");
|
|
|
729 |
}
|
|
|
730 |
|
| 7033 |
dpurdie |
731 |
mLogger.info("touch returned {}", retVal);
|
| 6914 |
dpurdie |
732 |
return retVal;
|
|
|
733 |
}
|
|
|
734 |
|
|
|
735 |
/**returns true if free disk space > 5G
|
|
|
736 |
* this may become configurable if the need arises
|
|
|
737 |
* refer to the sequence diagram check environment
|
|
|
738 |
*/
|
|
|
739 |
private boolean hasSufficientDiskSpace()
|
|
|
740 |
{
|
|
|
741 |
mLogger.debug("hasSufficientDiskSpace");
|
|
|
742 |
boolean retVal = true;
|
|
|
743 |
long freeSpace = 0;
|
|
|
744 |
|
|
|
745 |
try
|
|
|
746 |
{
|
|
|
747 |
File cwd = new File( "." );
|
|
|
748 |
|
|
|
749 |
// 5G = 5368709120 bytes
|
|
|
750 |
// 1G = 1073741824 bytes - useful for testing
|
|
|
751 |
freeSpace = cwd.getUsableSpace();
|
|
|
752 |
|
|
|
753 |
if ( freeSpace < 5368709120L )
|
|
|
754 |
{
|
| 7033 |
dpurdie |
755 |
mLogger.warn("hasSufficientDiskSpace failed: {} freespace {}", cwd.getAbsolutePath() , freeSpace);
|
| 6914 |
dpurdie |
756 |
retVal = false;
|
|
|
757 |
}
|
|
|
758 |
}
|
|
|
759 |
catch( SecurityException e )
|
|
|
760 |
{
|
|
|
761 |
// this can be thrown by getFreeSpace
|
|
|
762 |
mLogger.warn("hasSufficientDiskSpace caught SecurityException");
|
|
|
763 |
}
|
|
|
764 |
|
| 7033 |
dpurdie |
765 |
mLogger.info("hasSufficientDiskSpace returned {} {}", retVal, freeSpace);
|
| 6914 |
dpurdie |
766 |
return retVal;
|
|
|
767 |
}
|
|
|
768 |
|
|
|
769 |
/**abstract method
|
|
|
770 |
*/
|
|
|
771 |
@Override
|
|
|
772 |
public abstract void run();
|
|
|
773 |
|
|
|
774 |
/** deletes directory and all its files
|
|
|
775 |
* Will set files and directories to be writable in case the user has messed with
|
|
|
776 |
* file permissions
|
|
|
777 |
*/
|
|
|
778 |
FilenameFilter deleteDirectoryFilter = new FilenameFilter()
|
|
|
779 |
{
|
|
|
780 |
public boolean accept(File file, String name)
|
|
|
781 |
{
|
| 7033 |
dpurdie |
782 |
mLogger.debug("accept {}", name);
|
| 6914 |
dpurdie |
783 |
boolean retVal = false;
|
|
|
784 |
|
|
|
785 |
if ( name.compareTo(".") != 0 && ( name.compareTo("..") != 0 ) )
|
|
|
786 |
{
|
|
|
787 |
retVal = true;
|
|
|
788 |
}
|
|
|
789 |
|
| 7033 |
dpurdie |
790 |
mLogger.info("accept returned {}", retVal);
|
| 6914 |
dpurdie |
791 |
return retVal;
|
|
|
792 |
}
|
|
|
793 |
};
|
|
|
794 |
|
|
|
795 |
|
|
|
796 |
@SuppressWarnings("squid:S899")
|
|
|
797 |
protected void deleteDirectory(File directory)
|
|
|
798 |
{
|
| 7033 |
dpurdie |
799 |
mLogger.debug("deleteDirectory {}", directory.getName());
|
| 6914 |
dpurdie |
800 |
try
|
|
|
801 |
{
|
|
|
802 |
if ( directory.exists() )
|
|
|
803 |
{
|
|
|
804 |
|
|
|
805 |
//
|
|
|
806 |
directory.setWritable(true);
|
|
|
807 |
File[] children = directory.listFiles( deleteDirectoryFilter );
|
|
|
808 |
|
|
|
809 |
if ( children != null )
|
|
|
810 |
{
|
|
|
811 |
for ( int child=0; child < children.length; child++ )
|
|
|
812 |
{
|
|
|
813 |
if ( children[ child ].isDirectory() )
|
|
|
814 |
{
|
|
|
815 |
deleteDirectory( children[ child ] );
|
|
|
816 |
}
|
|
|
817 |
else
|
|
|
818 |
{
|
|
|
819 |
children[ child ].setWritable(true);
|
|
|
820 |
children[ child ].delete();
|
|
|
821 |
}
|
|
|
822 |
}
|
|
|
823 |
}
|
|
|
824 |
directory.delete();
|
|
|
825 |
}
|
|
|
826 |
}
|
|
|
827 |
catch( SecurityException e )
|
|
|
828 |
{
|
|
|
829 |
// this can be thrown by exists and delete
|
|
|
830 |
mLogger.warn("deleteDirectory caught SecurityException");
|
|
|
831 |
}
|
|
|
832 |
}
|
|
|
833 |
|
|
|
834 |
/**
|
|
|
835 |
* abstract method. Re-implemented by each class
|
|
|
836 |
* Returns the Mode in which the thread is operating.
|
|
|
837 |
*
|
|
|
838 |
* @return M if Master, S if Slave
|
|
|
839 |
*/
|
|
|
840 |
protected abstract char getMode();
|
|
|
841 |
|
|
|
842 |
/** Save the buildfile to disk
|
|
|
843 |
* @param buildFileContent The generated build file that will control this run
|
|
|
844 |
* @throws Exception
|
|
|
845 |
*
|
|
|
846 |
*/
|
|
|
847 |
protected void saveBuildFile(String buildFileContent) throws BuildSystemException
|
|
|
848 |
{
|
|
|
849 |
mReporting.buildFailureLogFile = null;
|
|
|
850 |
mErrorReported = false;
|
|
|
851 |
|
|
|
852 |
mBuildFile.delete();
|
|
|
853 |
FileWriter buildFileWriter = null;
|
|
|
854 |
BufferedReader buildFileBufferedReader = null;
|
|
|
855 |
boolean errorSeen = false;
|
|
|
856 |
|
|
|
857 |
if ( buildFileContent != null ) {
|
|
|
858 |
|
|
|
859 |
try {
|
|
|
860 |
|
|
|
861 |
StringReader buildFileContentStringReader = new StringReader(buildFileContent);
|
|
|
862 |
buildFileBufferedReader = new BufferedReader(buildFileContentStringReader);
|
|
|
863 |
|
|
|
864 |
// Sanitize the buildFileContent
|
|
|
865 |
// it may contain line.separators of "\n", "\r", or "\r\n" variety,
|
|
|
866 |
// depending on the location of the ripple engine
|
|
|
867 |
StringBuilder sanitisedBFC = new StringBuilder ();
|
|
|
868 |
String lf = System.getProperty("line.separator") ;
|
|
|
869 |
String line;
|
|
|
870 |
|
|
|
871 |
while( ( line = buildFileBufferedReader.readLine() ) != null)
|
|
|
872 |
{
|
|
|
873 |
sanitisedBFC.append (line).append(lf);
|
|
|
874 |
}
|
|
|
875 |
buildFileBufferedReader.close();
|
|
|
876 |
buildFileBufferedReader = null;
|
|
|
877 |
|
|
|
878 |
buildFileWriter = new FileWriter(mBuildFile);
|
|
|
879 |
buildFileWriter.write(sanitisedBFC.toString());
|
|
|
880 |
buildFileWriter.close();
|
|
|
881 |
buildFileWriter = null;
|
|
|
882 |
|
|
|
883 |
}
|
|
|
884 |
catch( IOException e )
|
|
|
885 |
{
|
|
|
886 |
mLogger.error("SaveBuildFile caught IOException");
|
|
|
887 |
errorSeen = true;
|
|
|
888 |
|
|
|
889 |
}
|
|
|
890 |
finally
|
|
|
891 |
{
|
|
|
892 |
if ( buildFileWriter!= null ) {
|
|
|
893 |
try {
|
|
|
894 |
buildFileWriter.close();
|
|
|
895 |
} catch (IOException e) {
|
|
|
896 |
errorSeen = true;
|
|
|
897 |
|
|
|
898 |
}
|
|
|
899 |
}
|
|
|
900 |
if ( buildFileBufferedReader != null) {
|
|
|
901 |
try {
|
|
|
902 |
buildFileBufferedReader.close();
|
|
|
903 |
} catch (IOException e) {
|
|
|
904 |
errorSeen = true;
|
|
|
905 |
}
|
|
|
906 |
}
|
|
|
907 |
}
|
|
|
908 |
}
|
|
|
909 |
|
|
|
910 |
if (errorSeen) {
|
|
|
911 |
mBuildFile.delete();
|
|
|
912 |
throw new BuildSystemException("SaveBuildFile caught FileNotFoundException");
|
|
|
913 |
}
|
|
|
914 |
}
|
|
|
915 |
|
|
|
916 |
/** Delete the build file
|
|
|
917 |
*
|
|
|
918 |
*/
|
|
|
919 |
protected void deleteBuildFile()
|
|
|
920 |
{
|
|
|
921 |
if ( mBuildFile.exists() )
|
|
|
922 |
{
|
|
|
923 |
mBuildFile.delete(); //NOSONAR
|
|
|
924 |
}
|
|
|
925 |
}
|
|
|
926 |
|
|
|
927 |
/** Parse the ANT project
|
|
|
928 |
* Done once per build - useful information is extracted for use within the build
|
|
|
929 |
* @param updateReporting
|
|
|
930 |
*/
|
|
|
931 |
protected void parseBuildFile(boolean updateReporting)
|
|
|
932 |
{
|
|
|
933 |
mLogger.debug("parseBuildFile");
|
|
|
934 |
|
|
|
935 |
//try
|
|
|
936 |
{
|
|
|
937 |
mProject = null;
|
|
|
938 |
if (updateReporting) {
|
|
|
939 |
mReporting.resetData();
|
|
|
940 |
}
|
|
|
941 |
|
|
|
942 |
if ( mBuildFile.exists() )
|
|
|
943 |
{
|
|
|
944 |
mProject = new Project();
|
|
|
945 |
mProject.setProperty("ant.file", mBuildFile.getAbsolutePath());
|
|
|
946 |
|
|
|
947 |
// Add listener for logging the complete build process
|
|
|
948 |
// If the daemon has been restarted, then the listener will not have been
|
|
|
949 |
// set up - so don't add it. Perhaps we need a way to open an existing
|
| 7033 |
dpurdie |
950 |
// log file to append.
|
| 6914 |
dpurdie |
951 |
if ( mBuildLogger != null ) {
|
|
|
952 |
mProject.addBuildListener(mBuildLogger);
|
|
|
953 |
}
|
|
|
954 |
|
|
|
955 |
// parse can throw BuildException, this is serious
|
|
|
956 |
// Generate a general exception to force an indefinite pause
|
|
|
957 |
// Delete build file to prevent attempts to use it
|
|
|
958 |
try {
|
|
|
959 |
mProject.init();
|
|
|
960 |
ProjectHelper pH = ProjectHelper.getProjectHelper();
|
|
|
961 |
mProject.addReference("ant.projectHelper", pH);
|
|
|
962 |
pH.parse(mProject, mBuildFile);
|
|
|
963 |
}
|
|
|
964 |
catch (BuildException be)
|
|
|
965 |
{
|
| 7033 |
dpurdie |
966 |
mLogger.error("Parse Error: {}", be );
|
| 6914 |
dpurdie |
967 |
|
|
|
968 |
mBuildFile.delete(); //NOSONAR
|
|
|
969 |
throw new BuildToolException("Error parsing build file:"+ be.getCause());
|
|
|
970 |
}
|
|
|
971 |
|
|
|
972 |
if (updateReporting) {
|
|
|
973 |
// set up project properties for reporting purposes
|
|
|
974 |
// this first group are hard coded in the build file
|
|
|
975 |
|
|
|
976 |
mReporting.rtagId = mRtagId;
|
|
|
977 |
mReporting.buildRef = mProject.getProperty("abt_daemon");
|
|
|
978 |
mReporting.packageName = mProject.getProperty("abt_package_name");
|
|
|
979 |
mReporting.packageVersion = mProject.getProperty("abt_package_version");
|
|
|
980 |
mReporting.packageExtension = mProject.getProperty("abt_package_extension");
|
|
|
981 |
mReporting.packageLocation = mProject.getProperty("basedir") + mProject.getProperty("abt_package_location");
|
|
|
982 |
mReporting.packageDepends = mProject.getProperty("abt_package_depends");
|
|
|
983 |
mReporting.packageOwners = mProject.getProperty("abt_package_ownerlist");
|
|
|
984 |
mReporting.packageBuildInfo = mProject.getProperty("abt_package_build_info");
|
|
|
985 |
mReporting.isRipple = ReportingData.toBool(mProject.getProperty("abt_is_ripple"));
|
|
|
986 |
mReporting.buildReason = ReportingData.toBuildReason(mProject.getProperty("abt_build_reason"));
|
|
|
987 |
mReporting.packageVersionId = ReportingData.toInt(mProject.getProperty("abt_package_version_id"), -1);
|
|
|
988 |
mReporting.doesNotRequireSourceControlInteraction = ReportingData.toBool(mProject.getProperty("abt_does_not_require_source_control_interaction"));
|
|
|
989 |
mReporting.isaTestBuild = ReportingData.toBool (mProject.getProperty("abt_test_build_instruction"));
|
|
|
990 |
}
|
|
|
991 |
//
|
|
|
992 |
// Log the abt_daemon value so that we can trace the build log
|
|
|
993 |
// Build logs from all machines are stored with this number
|
|
|
994 |
// Only do it at the start of the build
|
|
|
995 |
|
| 7033 |
dpurdie |
996 |
mLogger.error("BuildRef: {}", mReporting.buildRef );
|
| 6914 |
dpurdie |
997 |
|
|
|
998 |
}
|
|
|
999 |
}
|
|
|
1000 |
}
|
|
|
1001 |
|
|
|
1002 |
|
|
|
1003 |
/**
|
|
|
1004 |
* builds a buildFile from the buildFileContent
|
|
|
1005 |
* triggers ant to operate on the buildFile
|
|
|
1006 |
*
|
|
|
1007 |
* @param target The command to be run. This is one of the commands known to the ABT class
|
|
|
1008 |
* @param updateReporting True to update the mReportingData from the buildfiles properties
|
|
|
1009 |
* @param forceOpr True - force operation on errors
|
|
|
1010 |
* @throws Exception
|
|
|
1011 |
* @throws BuildException
|
|
|
1012 |
* @return Success - False on error
|
|
|
1013 |
*/
|
|
|
1014 |
protected boolean deliverChange(String target, boolean updateReporting, boolean forceOpr) throws Exception
|
|
|
1015 |
{
|
|
|
1016 |
mLogger.debug("deliverChange");
|
|
|
1017 |
|
|
|
1018 |
// Bypass the operation if an error is being propagated
|
|
|
1019 |
// Always perform a AbtSetUp and AbtTearDown
|
|
|
1020 |
//
|
|
|
1021 |
if (!forceOpr) {
|
|
|
1022 |
if ( mErrorReported ) {
|
|
|
1023 |
// SaveBuildFile, AbtTestPath, AbtSetUp or the build failed
|
|
|
1024 |
// the default target will inevitably fail and will generate further email if allowed to proceed
|
|
|
1025 |
// do not mask the root cause
|
|
|
1026 |
mLogger.debug("deliverChange - Error already detected");
|
|
|
1027 |
return false;
|
|
|
1028 |
}
|
|
|
1029 |
}
|
|
|
1030 |
|
|
|
1031 |
// Parse the build file
|
|
|
1032 |
parseBuildFile(updateReporting);
|
|
|
1033 |
if (mProject != null)
|
|
|
1034 |
{
|
|
|
1035 |
|
|
|
1036 |
if ( target == null ) {
|
|
|
1037 |
target = mProject.getDefaultTarget();
|
|
|
1038 |
}
|
| 7033 |
dpurdie |
1039 |
mLogger.warn("deliverChange ant launched: {} Target: {}", mBuildFile.getAbsolutePath() , target);
|
| 6914 |
dpurdie |
1040 |
|
|
|
1041 |
try {
|
|
|
1042 |
mProject.executeTarget(target);
|
|
|
1043 |
mLogger.warn("deliverChange ant returned");
|
|
|
1044 |
}
|
|
|
1045 |
|
|
|
1046 |
//
|
|
|
1047 |
// Do not catch ALL exceptions. The MasterThread::run and SlaveThread::run
|
|
|
1048 |
// relies on exceptions propagating upwards for the indefinite pause feature
|
|
|
1049 |
//
|
|
|
1050 |
catch( BuildException e )
|
|
|
1051 |
{
|
|
|
1052 |
|
|
|
1053 |
if ( mReporting.buildFailureLogFile == null )
|
|
|
1054 |
{
|
|
|
1055 |
mReporting.buildFailureLogFile = e.getMessage();
|
|
|
1056 |
}
|
| 7033 |
dpurdie |
1057 |
mLogger.debug("deliverChange caught BuildException, big deal, the build failed {}", mReporting.buildFailureLogFile);
|
| 6914 |
dpurdie |
1058 |
mErrorReported = true;
|
|
|
1059 |
}
|
|
|
1060 |
|
|
|
1061 |
|
|
|
1062 |
if (updateReporting )
|
|
|
1063 |
{
|
|
|
1064 |
// this group is set at run time (by the AbtPublish target only)
|
|
|
1065 |
// they will be null for every other target,
|
|
|
1066 |
// and null if an error occurs in the AbtPublish target
|
|
|
1067 |
mReporting.isFullyPublished = ReportingData.toBool(mProject.getProperty("abt_fully_published"));
|
|
|
1068 |
mReporting.newVcsTag = mProject.getProperty("abt_new_vcstag");
|
|
|
1069 |
}
|
|
|
1070 |
}
|
|
|
1071 |
|
|
|
1072 |
return !mErrorReported;
|
|
|
1073 |
}
|
|
|
1074 |
|
|
|
1075 |
/**
|
|
|
1076 |
* eMail an indefinite pause notification
|
|
|
1077 |
*
|
|
|
1078 |
* @param cause Reason for the pause
|
|
|
1079 |
*/
|
|
|
1080 |
protected void notifyIndefinitePause(String cause)
|
|
|
1081 |
{
|
|
|
1082 |
mLogger.debug("indefinitePause");
|
|
|
1083 |
|
|
|
1084 |
String body =
|
|
|
1085 |
"Hostname: " + BuildDaemon.mHostname + "<p>" +
|
|
|
1086 |
"Release: " + mRippleEngine.mBaselineName + "<p>" +
|
|
|
1087 |
"Cause: " + cause + "<p>" +
|
|
|
1088 |
"RmRef: " + CreateUrls.generateReleaseUrl(mRippleEngine.getRtagId()) +"<p>";
|
|
|
1089 |
|
|
|
1090 |
try
|
|
|
1091 |
{
|
|
|
1092 |
Smtpsend.send(
|
|
|
1093 |
mRippleEngine.getMailServer(), // mailServer
|
|
|
1094 |
mRippleEngine.getMailSender(), // source
|
|
|
1095 |
mRippleEngine.getMailGlobalTarget(), // target (list)
|
| 7033 |
dpurdie |
1096 |
null, // cc
|
|
|
1097 |
null, // bcc
|
|
|
1098 |
"BUILD DAEMON Indefinite Pause", // subject
|
|
|
1099 |
body, // body
|
|
|
1100 |
null // attachment
|
| 6914 |
dpurdie |
1101 |
);
|
|
|
1102 |
}
|
|
|
1103 |
catch( Exception e )
|
|
|
1104 |
{
|
|
|
1105 |
}
|
|
|
1106 |
}
|
|
|
1107 |
|
|
|
1108 |
|
|
|
1109 |
/**
|
|
|
1110 |
* eMail an indefinite pause recovery notification
|
|
|
1111 |
*/
|
|
|
1112 |
private void notifyIndefiniteRecovery()
|
|
|
1113 |
{
|
|
|
1114 |
mLogger.debug("indefiniteRecovery");
|
|
|
1115 |
|
|
|
1116 |
String body =
|
|
|
1117 |
"Hostname: " + BuildDaemon.mHostname + "<p>" +
|
|
|
1118 |
"Release: " + mRippleEngine.mBaselineName + "<p>" +
|
|
|
1119 |
"Cause: " + "Recovery of previous condition" + "<p>" +
|
|
|
1120 |
"RmRef: " + CreateUrls.generateReleaseUrl(mRippleEngine.getRtagId()) +"<p>";
|
|
|
1121 |
|
|
|
1122 |
try
|
|
|
1123 |
{
|
|
|
1124 |
Smtpsend.send(
|
|
|
1125 |
mRippleEngine.getMailServer(), // mailServer
|
|
|
1126 |
mRippleEngine.getMailSender(), // source
|
|
|
1127 |
mRippleEngine.getMailGlobalTarget(), // target (list)
|
| 7033 |
dpurdie |
1128 |
null, // cc
|
|
|
1129 |
null, // bcc
|
|
|
1130 |
"BUILD DAEMON Indefinite Pause Recovery", // subject
|
|
|
1131 |
body, // body
|
|
|
1132 |
null // attachment
|
| 6914 |
dpurdie |
1133 |
);
|
|
|
1134 |
}
|
|
|
1135 |
catch( Exception e )
|
|
|
1136 |
{
|
|
|
1137 |
}
|
|
|
1138 |
|
|
|
1139 |
}
|
|
|
1140 |
|
|
|
1141 |
|
|
|
1142 |
/**
|
|
|
1143 |
* Nagios interface
|
|
|
1144 |
* Returns true if the thread looks OK
|
|
|
1145 |
* @param nagInfo
|
|
|
1146 |
*/
|
|
|
1147 |
boolean checkThread(NagiosInfo nagInfo)
|
|
|
1148 |
{
|
|
|
1149 |
boolean retVal = true;
|
|
|
1150 |
if ( mRunLevel.mBuildState == BuildState.DB_CANNOT_CONTINUE ) {
|
|
|
1151 |
retVal = false;
|
|
|
1152 |
nagInfo.extendedReason.add("[" + mRtagId + "] " + mRunLevel.toString());
|
|
|
1153 |
} else {
|
|
|
1154 |
retVal = checkThreadExtended(nagInfo);
|
|
|
1155 |
}
|
|
|
1156 |
|
|
|
1157 |
if (this.getMode() == 'M') {
|
|
|
1158 |
nagInfo.masterCount++;
|
|
|
1159 |
} else {
|
|
|
1160 |
nagInfo.slaveCount++;
|
|
|
1161 |
}
|
|
|
1162 |
|
| 7033 |
dpurdie |
1163 |
mLogger.warn("checkThread[{}] returned {}",mRtagId, retVal);
|
| 6914 |
dpurdie |
1164 |
return retVal;
|
|
|
1165 |
}
|
|
|
1166 |
|
|
|
1167 |
/**
|
|
|
1168 |
* Nagios interface extension
|
|
|
1169 |
* This method should be overridden by classes that extend this class
|
|
|
1170 |
* If not overridden then the test indicates OK
|
|
|
1171 |
*
|
|
|
1172 |
* Returns true if the thread looks OK
|
|
|
1173 |
*/
|
|
|
1174 |
boolean checkThreadExtended(NagiosInfo nagInfo)
|
|
|
1175 |
{
|
|
|
1176 |
boolean retVal = mPhase.isHappy();
|
|
|
1177 |
if ( ! retVal) {
|
|
|
1178 |
nagInfo.extendedReason.add("[" + mRtagId + "] " + mPhase.happyText());
|
|
|
1179 |
}
|
| 7033 |
dpurdie |
1180 |
mLogger.info("checkThreadExtended: {}:{}",retVal, mPhase.toStringSecs() );
|
| 6914 |
dpurdie |
1181 |
return retVal;
|
|
|
1182 |
}
|
|
|
1183 |
|
|
|
1184 |
|
|
|
1185 |
/**
|
|
|
1186 |
* Nagios interface extension
|
|
|
1187 |
* This method should be overridden by classes that extend this class
|
|
|
1188 |
* If not overridden then the test indicates OK
|
|
|
1189 |
*
|
|
|
1190 |
* Returns true if the thread looks OK
|
|
|
1191 |
* @param wr Output buffer
|
|
|
1192 |
* @param nagInfo
|
|
|
1193 |
* @param estatus
|
|
|
1194 |
* @throws IOException
|
|
|
1195 |
*/
|
|
|
1196 |
public void extendedStatus(NagiosInfo nagInfo, Map<String, Object> estatus)
|
|
|
1197 |
{
|
|
|
1198 |
LinkedHashMap<String, Object> data = new LinkedHashMap<String, Object>();
|
|
|
1199 |
estatus.put(String.valueOf(mRtagId), data);
|
|
|
1200 |
|
|
|
1201 |
data.put("rtagId", Integer.valueOf(mRtagId));
|
|
|
1202 |
data.put("rconId", Integer.valueOf(mRconId));
|
|
|
1203 |
data.put("Thread Start Text", new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").format(new Date(mStartTime)));
|
|
|
1204 |
data.put("Thread Start", Long.valueOf(mStartTime));
|
|
|
1205 |
data.put("Thread Alive:", Boolean.valueOf(this.isAlive() ));
|
|
|
1206 |
data.put("Thread Check:", Boolean.valueOf(checkThread(nagInfo) ));
|
|
|
1207 |
data.put("Mode" , String.valueOf(this.getMode() ));
|
|
|
1208 |
data.put("mRunLevel" , mRunLevel.toString() );
|
|
|
1209 |
data.put("mLastBuildWasBenign" , Boolean.valueOf(mLastBuildWasBenign));
|
|
|
1210 |
data.put("mException" , Boolean.valueOf(mException));
|
|
|
1211 |
data.put("mErrorReported" , Boolean.valueOf(mErrorReported));
|
|
|
1212 |
data.put("mRecoverable", Boolean.valueOf(mRecoverable));
|
|
|
1213 |
data.put("mPhase" , mPhase.sText);
|
|
|
1214 |
data.put("mPhaseDelta" , mPhase.getDeltaSecs());
|
|
|
1215 |
if ( mReleaseManager != null)
|
|
|
1216 |
data.put("Rm Mutex" , mReleaseManager.mMutexState );
|
|
|
1217 |
else
|
|
|
1218 |
data.put("Rm Mutex" , null );
|
|
|
1219 |
}
|
|
|
1220 |
|
|
|
1221 |
}
|