Subversion Repositories DevTools

Rev

Rev 7253 | Rev 7358 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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.BuildThread;
7
import com.erggroup.buildtool.ripple.*;
8
import com.erggroup.buildtool.ripple.BuildFile.BuildFileState;
9
import com.erggroup.buildtool.ripple.Package;
10
import com.erggroup.buildtool.ripple.ReleaseManager.BuildResult;
11
import com.erggroup.buildtool.ripple.RunLevel.BuildState;
12
import com.erggroup.buildtool.smtp.CreateUrls;
13
import com.erggroup.buildtool.smtp.Smtpsend;
14
import com.erggroup.buildtool.utilities.*;
15
 
16
import java.io.BufferedReader;
17
import java.io.DataInputStream;
18
import java.io.File;
19
import java.io.FileInputStream;
20
import java.io.InputStreamReader;
21
import java.sql.SQLException;
22
import java.util.Iterator;
23
 
7033 dpurdie 24
import org.slf4j.Logger;
25
import org.slf4j.LoggerFactory;
6914 dpurdie 26
 
27
/**Master Thread sub component
28
 */
29
public class MasterThread extends BuildThread
30
{
31
 
32
    /**Logger
33
     * @attribute
34
     */
7033 dpurdie 35
    private static final Logger mLogger = LoggerFactory.getLogger(MasterThread.class);
6914 dpurdie 36
 
37
    /** Current BuildFile
38
     * 
39
     */
40
    private BuildFile mMasterBuildFile = new BuildFile();
41
 
42
    /** Measure the duration of the current build
43
     * 
44
     */
45
    private ElapseTime mBuildDuration = new ElapseTime();
46
 
47
    /**constructor
48
     * @param rtagId          - Identifies the Release
49
     * @param rconId          - Identifies the Controlling entry
50
     * @param releaseManager  - A ReleaseManager entry to use
51
     * @param unitTest        - Unit Test data 
52
     */
53
    public MasterThread(int rtagId, int rconId, ReleaseManager releaseManager, String unitTest)
54
    {
55
        super(rtagId, rconId, releaseManager, unitTest);
56
        mLogger.warn("MasterThread rtag_id " + rtagId + " rcon_id " + rconId);
57
    }
58
 
59
    /**implements the sequence diagrams coordinate slave threads, generate build files, allowed to proceed, check environment
60
     */
61
    public void run()
62
    {
63
        Integer id = Integer.valueOf(mRtagId);
64
        setName(id.toString());
65
        mLogger.warn("Master Thread run");
66
        boolean exit = false;
67
        mRippleEngine = new RippleEngine(mReleaseManager, mRtagId, true);
68
 
69
        while(!exit)
70
        {
71
            try
72
            {
7176 dpurdie 73
                mLogger.warn("run calling sleepCheck");
6914 dpurdie 74
                mPhase.setPhase("sleepCheck");
75
                sleepCheck();
76
 
7176 dpurdie 77
                mLogger.warn("run calling rippleEngine.collectMetaData");
6914 dpurdie 78
                mPhase.setPhase("collectMetaData", 600);
79
                mRippleEngine.collectMetaData();
80
 
81
                if ( Thread.currentThread().isInterrupted() )
82
                {
83
                    mLogger.warn("run is interrupted");
84
                    // unit test technique
85
                    throw new ExitException();
86
                }
87
 
88
                if ( mUnitTest.compareTo("unit test spawn thread") == 0)
89
                {
90
                    throw new Exception();
91
                }
92
 
93
                if ( !mUnitTest.startsWith("unit test check environment"))
94
                {
95
                    if ( mUnitTest.compareTo("unit test generate build files") != 0)
96
                    {
97
                        if ((mUnitTest.compareTo("unit test allowed to proceed") != 0) &&
98
                                (mUnitTest.compareTo("unit test not allowed to proceed") != 0) &&
99
                                (mUnitTest.compareTo("unit test exit") != 0))
100
                        {
101
                            //---------------------------------------------------------------
102
                            //  Wait for all Slaves to enter waiting or paused state
103
                            //      They may be building
104
                            //      They may be starting up
105
                            //
7176 dpurdie 106
                            mLogger.warn("run changing run level to WAITING (New) for rcon_id {}", mRconId);
6914 dpurdie 107
                            mPhase.setPhase("Wait for Slave Threads");
108
                            mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_WAITING);
109
 
110
                            while (true) 
111
                            {
112
                                StringBuilder waitList = new StringBuilder();
113
                                mLogger.info("run calling mReleaseManager.queryRunLevel");
114
                                mReleaseManager.queryRunLevel(mRtagId);
115
 
116
                                //	Process all run entries
117
 
118
                                for (Iterator<RunLevelData> it = mReleaseManager.mRunLevelCollection.iterator(); it.hasNext(); )
119
                                {
120
                                    RunLevelData rl = it.next();
121
 
122
                                    //
123
                                    // Only examine Slaves.
124
                                    // This is being run on a Master and at this point the Master is not waiting
125
                                    // If there are multiple (misconfigured) Masters, then we can get confused
126
                                    //
127
                                    // If I am no longer a Master we will process till the end of the build cycle
128
                                    // at which point it will be detected.
129
                                    //
130
                                    // If there are other Masters, then we assume that they are not waiting
131
                                    //
132
 
133
                                    // Ignore myself. I am not waiting. I am asking the questions
134
                                    if ( rl.get_rcon_id() == mRconId) {
135
                                        continue;
136
                                    }
137
 
138
                                    // Ignore other Master. They should not be waiting.
139
                                    if ( rl.isMaster()) {
140
                                        continue;
141
                                    }
142
 
143
                                    //
144
                                    // A slave that is 'Paused' is not processing a package
145
                                    //      It will have been included in the build-set, so we must wait for
146
                                    //      the pause to be removed.
147
                                    //
148
                                    // A slave that is 'Waiting' must also have no BuildFile present
149
                                    //      This signals that the buildfile has been taken by the slave
150
                                    // 
151
                                    if (! (rl.isAt(BuildState.DB_WAITING) && !rl.hasBuildFile() )  )
152
                                    {
153
                                        // A non-waiting slave has been found
154
                                        waitList.append(" ");
155
                                        waitList.append(rl.get_rcon_id());
156
                                    }
157
                                }
158
 
159
 
160
                                if ( waitList.length() > 0 )
161
                                {
162
                                    // One or more slaves still processing ...
163
                                    if ( mUnitTest.compareTo("unit test coordinate slave threads") == 0 )
164
                                    {
165
                                        Thread.currentThread().interrupt();
166
                                    }
167
                                    else
168
                                    {
169
 
170
                                        mLogger.warn("Waiting 3 seconds for slaves:" + waitList.toString() );
171
                                        Thread.sleep(3000);
172
                                        mLogger.info("run sleep returned");
173
                                    }
174
                                    continue;
175
                                }
176
                                else
177
                                {
178
                                    // All slaves have completed there tasks
179
                                    break;
180
                                }
181
                            }
182
 
183
                            if ( mUnitTest.compareTo("unit test coordinate slave threads") == 0 )
184
                            {
185
                                throw new ExitException();
186
                            }
187
 
188
                            //---------------------------------------------------------------
189
                            //    Publish Package Build Results
190
                            //        Indicate to RM that we are publishing
191
                            //        Ensure that all build machines have placed a marker in dpkg_archive
192
                            //        Save updated build files into VCS
193
                            // 
7176 dpurdie 194
                            mLogger.warn("run changing run level to PUBLISHING for rcon_id {}", mRconId);
6914 dpurdie 195
                            mPhase.setPhase("Publishing");
196
                            mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_PUBLISHING);
197
 
198
                            mLogger.info("run calling deliverChange on AbtPublish");
199
                            deliverChange("AbtPublish", true, false);
200
 
201
                            //---------------------------------------------------------------
202
                            //    TearDown the build workspace
203
                            //        Remove the build workspace
204
                            //        Save build log files
205
                            //        Don't update the Reporting Information as it will null out
206
                            //        some essential information that has been collected.
207
                            //
208
                            mLogger.info("run calling deliverChange on AbtTearDown");
209
                            mPhase.setPhase("AbtTearDown");
210
                            deliverChange("AbtTearDown", false, true);
211
 
212
                            // Delete the build file now
213
                            //  This will prevent any chance of multiply publishing a package version
214
                            deleteBuildFile();
215
 
216
 
217
                            //---------------------------------------------------------------
218
                            //    Update Release Manager (publish to Release Manager)
219
                            //
220
                            mPhase.setPhase("Update Release Manager");
221
                            if ( mReporting.packageName != null )
222
                            {
223
                                // A dummy build file did not apply
224
                                // Publishing is done outside ant by design
225
                                //      Do ALL Release Manager work outside ant (and JATS)
226
 
227
                                boolean buildErrorOccurred = true;
228
                                boolean publishError = true;
229
 
230
                                try
231
                                {
232
                                    //  Create a build instance entry in the Release Manager database
233
                                    //        Create one per build
234
                                    //        mReporting.packageVersionId will have been updated if this is a new package-version
235
                                    //        Save the build id
236
                                    mPhase.setPhase("Create Build Instance");
237
                                    mReporting.buildId = mReleaseManager.createBuildInstance(
238
                                            mRtagId, 
239
                                            mReporting.packageVersionId,
7253 dpurdie 240
                                            mReporting.buildReason,
241
                                            mReporting.buildRef);
6914 dpurdie 242
                                    //
243
                                    //  Locate and collect the unit test results
244
                                    //
245
                                    mPhase.setPhase("Parse Unit Test Results");
246
                                    BuildTestResults btr = new BuildTestResults(System.getenv("GBE_DPKG"), mReporting, mLogger);
247
                                    mReleaseManager.insertTestResults(mReporting.buildId, btr);
248
 
249
                                    if ( mReporting.isaTestBuild )
250
                                    {
251
 
252
                                        //    Test Build
253
                                        //    Notify the user requesting the build
254
                                        //        Build Failure emails have already been sent
255
                                        //
256
                                        mLogger.info("run completing test build on " + mReporting.packageName + mReporting.packageExtension);
257
                                        mPhase.setPhase("Report Test Build Complete");
7155 dpurdie 258
                                        completeTestBuild(mRippleEngine, mReporting.isFullyPublished);
6914 dpurdie 259
 
260
                                        //
261
                                        //  Determine the total time taken by the build
262
                                        //      Done as late a possible in the process
263
                                        //      Does not include planning time
264
                                        //      Does not handle case where build cycle is broken
265
                                        //      Only record for successful tests. Don't want to record short build times on failure
266
                                        //      in particular if the package has been released. Would be OK for a WIP, but how to identify these
267
                                        if ( mReporting.isFullyPublished)
268
                                        {
269
                                            int buildDuration = mBuildDuration.toIntSecs();
7176 dpurdie 270
                                            mLogger.warn("Build Duration:{}", buildDuration);
6914 dpurdie 271
                                            mReleaseManager.updateBuildDuration(mReporting.packageVersionId, buildDuration);
272
                                        }
273
 
274
                                        mPhase.setPhase("Update Build Instance for Test");
275
                                        mReleaseManager.updateBuildInstance(mReporting.buildId, 0, mReporting.isFullyPublished ? BuildResult.Complete :BuildResult.BuildError );
7333 dpurdie 276
 
277
                                        mPhase.setPhase("Insert BuildInfo for Test");
278
                                        insertBuildInfo(true);
6914 dpurdie 279
 
280
                                        // ... and clean up the mess in the archive
281
                                        publishError = false;
282
                                        throw new Exception();                    
283
                                    }
284
 
285
                                    //    Package not fully published
286
                                    //    An error has occurred in the building of the package
287
                                    if ( !mReporting.isFullyPublished )
288
                                    {
289
                                        mLogger.info("run build error occurred on " + mReporting.packageName + mReporting.packageVersion);
290
 
291
                                        // ... and clean up the mess in the archive
292
                                        publishError = false;
293
                                        throw new Exception();
294
                                    }
295
 
296
                                    //---------------------------------------------------------------
297
                                    //  Package was successfully built and published into dpkg_archive by all daemons
298
                                    //    Update Release Manager - formally release the package
299
                                    //    Insert Package Metrics
300
                                    //    Insert Unit Test Results
301
                                    buildErrorOccurred = false;
302
 
303
                                    //
304
                                    //    Detect Badly formed VCS label returned by the builder
305
                                    //      Have had zero length values returned
306
                                    //      Treat as a publishing error
307
                                    //
308
                                    if ( mReporting.newVcsTag == null || mReporting.newVcsTag.isEmpty() )
309
                                    {
7176 dpurdie 310
                                        mLogger.error("run package not labelled in Version Control on {}{}",mReporting.packageName, mReporting.packageVersion);
6914 dpurdie 311
                                        mReporting.errMsg = "Error publishing to Version Control System";     // Max 50 Characters
312
                                        throw new Exception();
313
                                    }
314
 
315
 
316
                                    // Publish to release manager
317
                                    //    On error mReporting.errMsg will contain error string
318
                                    //    Publishing errors only affect the current package
319
                                    //
7176 dpurdie 320
                                    mLogger.warn("run calling mReleaseManager.autoMakeRelease");
6914 dpurdie 321
                                    mPhase.setPhase("autoMakeRelease");
322
                                    publishError =  mReleaseManager.autoMakeRelease(mReporting);
323
                                    if ( publishError )
324
                                    {
7176 dpurdie 325
                                        mLogger.error("autoMakeRelease publishError: {}", mReporting.errMsg);
6914 dpurdie 326
                                        throw new Exception();
327
                                    }
328
 
329
                                    //
330
                                    //  Determine the total time taken by the build
331
                                    //      Done as late a possible in the process
332
                                    //      Does not include planning time
333
                                    //      Does not handle case where build cycle is broken
334
                                    //
335
                                    int buildDuration = mBuildDuration.toIntSecs();
7176 dpurdie 336
                                    mLogger.warn("Build Duration:{}", buildDuration);
6914 dpurdie 337
                                    mReleaseManager.updateBuildDuration(mReporting.packageVersionId, buildDuration);
338
 
339
                                    //
340
                                    //    Update the Build Instance information
341
                                    //    If this has been a ripple then the pv_id of the build needs to be associated with
342
                                    //    the newly created version
343
 
344
                                    mPhase.setPhase("Update Build Instance");
345
                                    mReleaseManager.updateBuildInstance(mReporting.buildId, mReporting.packageVersionId, BuildResult.Complete );
346
 
347
                                    //
348
                                    //    Insert package metrics into Release Manager
349
                                    //        Metrics have been placed in a file in a format suitable for RM
350
                                    //
351
                                    mReporting.errMsg = "Error publishing Package Metrics";     // Max 50 Characters
352
                                    mPhase.setPhase("Insert Metrics");
353
                                    FileInputStream abtmetrics = new FileInputStream( String.valueOf(mRtagId) + "abtmetrics.txt" );
354
                                    DataInputStream din = new DataInputStream( abtmetrics );
355
                                    InputStreamReader isr = new InputStreamReader( din );
356
                                    BufferedReader br = new BufferedReader( isr );
357
                                    String metrics = br.readLine();
7176 dpurdie 358
                                    mLogger.warn( "execute read metrics string {}", metrics );
6914 dpurdie 359
                                    br.close();
360
                                    isr.close();
361
                                    din.close();
362
 
7176 dpurdie 363
                                    mLogger.warn("run calling mReleaseManager.insertPackageMetrics");                      
6914 dpurdie 364
                                    mReleaseManager.insertPackageMetrics(mRtagId, mReporting.packageName, mReporting.packageExtension, metrics );
7333 dpurdie 365
 
366
                                    //  Insert BuildInfo
367
                                    //      New package PVID has been updated
368
                                    mPhase.setPhase("Insert BuildInfo");
369
                                    insertBuildInfo(false);
6914 dpurdie 370
 
371
                                    //
372
                                    //    Info reporting
373
                                    //    Send an email to track build system usage - may be noise
374
                                    //
375
                                    mReporting.errMsg = null;
7176 dpurdie 376
                                    mLogger.warn("run calling emailBuildComplete");
6914 dpurdie 377
                                    mPhase.setPhase("Post Build Email");
378
                                    emailPostBuild(mRippleEngine, false);
379
 
380
                                    //---------------------------------------------------------------
381
                                    //    All done
382
                                    //    The package has been built and released
383
                                    mPhase.setPhase("Build Complete");
384
                                }
385
                                catch( Exception e)
386
                                {
387
                                    // Some form of error has occurred. Types include
388
                                    //    Test build (Treated as an error so that dpkg_archive gets removed)
389
                                    //        buildErrorOccurred - True
390
                                    //        publishError - False    
391
                                    //    Build Error - Package was not fully published to dpkg_archive
392
                                    //        buildErrorOccurred - True
393
                                    //        publishError - False
394
                                    //     
395
                                    //    Badly formed VCS tag (Error Publishing to Version Control)
396
                                    //        buildErrorOccurred - False
397
                                    //        publishError - True    
398
                                    //    Error Publishing to Release Manager
399
                                    //        buildErrorOccurred - False
400
                                    //        publishError - True    
401
                                    //    Error inserting package metrics
402
                                    //        buildErrorOccurred - False
403
                                    //        publishError - True
404
                                    //    Error inserting unit test results
405
                                    //        buildErrorOccurred - False
406
                                    //        publishError - True
407
                                    // 
408
                                    // Uses
409
                                    //    buildErrorOccurred      - Package not in dpkg_archive as expected (or was a test build)
410
                                    //                              Email should have been sent to the user
411
                                    //    publishError            - Could not publish to Release Manager
412
                                    //                              Post build error. Email has not been sent to user
413
                                    //                              Takes precedence over buildErrorOccurred
414
 
415
                                    // Insert generic message if we don't have one
416
                                    //     Should only occur under unexpected conditions
417
                                    if (mReporting.errMsg == null || mReporting.errMsg.isEmpty())
418
                                    {
419
                                        mReporting.errMsg = "Error publishing to Release Manager";
420
                                        mReporting.errMsgDetail = mPhase.sText;
421
                                    }
422
 
423
                                    // Indicate some form of build error
424
                                    if ( ! mReporting.isaTestBuild )
425
                                    {
426
                                        mPhase.setPhase("Update Build Instance");
427
                                        mReleaseManager.updateBuildInstance(mReporting.buildId, 0, publishError ? BuildResult.SystemError :BuildResult.BuildError );
428
                                    }
429
 
430
                                    // 
431
                                    // Delete the dpkg_archive entry - the package is a dud
432
                                    //
433
                                    mPhase.setPhase("Delete package from archive");
7176 dpurdie 434
                                    mLogger.warn("Delete package from archive");
6914 dpurdie 435
                                    deletePackageVersion();
436
 
437
                                    //    A publishing error. The error occurred, after the build, in the RM publishing
438
                                    //        We won't have a log file, but we will have a rootCause
439
                                    //    Exclude package from the build
440
                                    //        Unless its a test build (handled within mReleaseManager.excludeFromBuild) 
441
                                    //
442
                                    if ( publishError  )
443
                                    {
7033 dpurdie 444
                                        mLogger.error("an error occurred publishing to Version Control or Release Manager");
6914 dpurdie 445
 
446
                                        //  Post Build Error
447
                                        //  eMails have not been sent by the ABT class as the error has occurred outside of that process
448
                                        mPhase.setPhase("Post Build Failure Email");
449
                                        emailPostBuild(mRippleEngine, true);
450
 
7176 dpurdie 451
                                        mLogger.warn("run calling excludeFromBuild");
6914 dpurdie 452
                                        mPhase.setPhase("Excluded from build");
453
                                        mReleaseManager.excludeFromBuild(false, 
454
                                                mReporting.packageVersionId, 
455
                                                null, 
456
                                                mReporting.rtagId, 
457
                                                null, 
458
                                                mReporting.errMsg, 
459
                                                null, 
460
                                                false, mReporting.isaTestBuild);
461
 
462
                                    }
463
                                    else if ( buildErrorOccurred )
464
                                    {
465
                                        //    Build Error Occurred
466
                                        //        Package has not been built on all configured platforms
467
                                        //        Under normal circumstances, this root cause will be masked by a previously reported error
468
                                        //        Under abnormal circumstances amidst build activity such as:
469
                                        //            - slave build machine reboots
470
                                        //            - slave build machines with a read only file system
471
                                        //        The rootCause is required to keep the end user informed
472
                                        //
473
                                        //    Use excludeFromBuild such that this call will not supersede existing entries
474
                                        //    In this manner the log file/cause provided here will only be used if we haven't
475
                                        //    already excluded this package from the build
476
 
477
                                        //    If we have a log file, then provide it to the user, else insert a generic message
478
 
479
                                        mReporting.errMsg = (mReporting.buildFailureLogFile == null) ? "Buildtool env error occurred. Attempt build again" : null;
480
 
7176 dpurdie 481
                                        mLogger.warn("run calling excludeFromBuild"); 
6914 dpurdie 482
                                        mPhase.setPhase("Excluded from build");
483
                                        mReleaseManager.excludeFromBuild(false, 
484
                                                mReporting.packageVersionId, 
485
                                                mReporting.packageVersion,
486
                                                mReporting.rtagId, 
487
                                                null, 
488
                                                mReporting.errMsg, 
489
                                                mReporting.buildFailureLogFile, 
490
                                                false, mReporting.isaTestBuild);
491
                                    }
492
                                    else
493
                                    {
494
                                        //  Not a buildError and not a publishing Error
495
                                        //      Don't know how we got here - I don't think we can
496
                                        //      Will cause an indefinite pause !
497
                                        throw new Exception("an error occurred publishing to Version Control or Release Manager");
498
 
499
                                    }
500
                                } // End Catch
501
                            }
502
 
503
                            if ( mUnitTest.compareTo("unit test coordinate slave threads") == 0 )            
504
                            {
505
                                throw new ExitException();
506
                            }
507
                            mLogger.info("run coordinate slave threads returned");
508
                        }
509
 
510
 
511
                        //---------------------------------------------------------------
512
                        //  Start of a new build cycle
513
                        //      Determine if the daemon has been paused.
514
                        //      Set RunLevel.IDLE (within allowedToProceed)
515
                        //
7176 dpurdie 516
                        mLogger.warn("run calling allowedToProceed");
6914 dpurdie 517
                        mPhase.setPhase("allowedToProceed");
518
                        mReleaseManager.discardVersion();
519
                        mReleaseManager.clearCurrentPackageBeingBuilt(mRconId);
520
                        allowedToProceed(true);
521
                        mLogger.info("run allowedToProceed returned");
522
 
523
                        if ( mUnitTest.compareTo("unit test allowed to proceed") == 0 )            
524
                        {
525
                            throw new ExitException();
526
                        }
527
 
528
                        //  Set up mReleaseConfigCollection
529
                        //  This will be used when creating a build file
7176 dpurdie 530
                        mLogger.warn("Collect fresh MetaData");
6914 dpurdie 531
                        mPhase.setPhase("collectMetaData");
532
                        mRippleEngine.collectMetaData();
533
 
534
                        //---------------------------------------------------------------
535
                        //  Plan the next build
536
                        //      Snap current Release Sequence Number
537
                        //      Determine what is to be built
538
                        //      Generate build files
7176 dpurdie 539
                        mLogger.warn("run calling planRelease");
6914 dpurdie 540
                        mPhase.setPhase("Plan Release", 600);
7169 dpurdie 541
                        mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_PLANNING);
6914 dpurdie 542
                        mReleaseSeqNum =  mReleaseManager.queryReleaseSeqNum(mRtagId, mRconId, BuildDaemon.mHostname); 
543
                        mRippleEngine.planRelease(!mLastBuildWasBenign);
544
 
545
                        // get the build file from the ripple engine
546
                        mPhase.setPhase("Get Build File", 10);
547
                        mMasterBuildFile = mRippleEngine.getFirstBuildFileContent();
548
 
549
                    }
550
                }
551
 
552
                //---------------------------------------------------------------
553
                //  Check that we are good to proceed with the build
554
                //      Check environment
555
                //      Ensure we have enough disk space
556
                //     
7176 dpurdie 557
                mLogger.warn("run calling checkEnvironment"); 
6914 dpurdie 558
                mPhase.setPhase("checkEnvironment");
559
                checkEnvironment();
560
                mLogger.info("run checkEnvironment returned");
561
 
562
                if ( mUnitTest.startsWith("unit test check environment") ) 
563
                {
564
                    throw new ExitException();
565
                }
566
 
567
                mLogger.info("run generated build files");
568
                // Start of a build cycle. Set new log file to capture entire build log
569
                mPhase.setPhase("Start Build Cycle");
570
                flagStartBuildCycle();
571
                mBuildDuration.reset();
572
                mReporting.resetData();
573
                mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_ACTIVE);
574
                mReleaseManager.setCurrentPackageBeingBuilt(mRconId, mMasterBuildFile.mPkgId, mMasterBuildFile.mPvId);
575
 
576
                // Save the buildfile
7176 dpurdie 577
                mLogger.warn("Save buildfile");
6914 dpurdie 578
                mPhase.setPhase("Save buildfile");
579
                saveBuildFile(mMasterBuildFile.content);
580
 
581
                // Quick Test to validate the provided Version Control tag/label
582
                mPhase.setPhase("Validate Version Tag");
583
                if ( deliverChange("AbtTestPath", true, false) )
584
                {
585
 
586
                    //---------------------------------------------------------------
587
                    //    Notify all slaves that there is work to be done
588
                    //      This is done by publishing a buildfile for them to consume
589
                    //      A NonGeneric build will be done with a real build file on all machines
590
                    //      Otherwise do a Dummy build on all Machines
591
                    //
592
                    mPhase.setPhase("Notify slaves of work", 10);
593
                    if ( mMasterBuildFile.state != BuildFileState.NonGeneric)
594
                    {
595
                        // publish a dummy build file for either generic or dummy cases
596
                        // this results in the slave not running ant
7176 dpurdie 597
                        mLogger.warn("run calling publishBuildFile on dummy");
6914 dpurdie 598
                        mMasterBuildFile.content = mDummyBuildFileContent;
599
                    }
600
                    else
601
                    {
602
                     // publish the build file
7176 dpurdie 603
                        mLogger.warn("run calling publishBuildFile");    
6914 dpurdie 604
                    }
605
                    mReleaseManager.publishBuildFile(mRtagId, mMasterBuildFile);                    
606
 
607
 
608
                    if ( mUnitTest.compareTo("unit test generate build files") == 0 )
609
                    {
610
                        throw new ExitException();
611
                    }
612
 
613
                    mLogger.info("run changed run levels");
614
 
615
                    //---------------------------------------------------------------
616
                    //  Build the package
617
                    //      Setup the workspace
618
                    //      Build the package - deliver change to product baseline
619
                    //
7176 dpurdie 620
                    mLogger.warn("Build Package {}_{}", mReporting.packageName, mReporting.packageVersion);
6914 dpurdie 621
 
622
                    mLogger.info("run calling setViewUp");
623
                    mPhase.setPhase("Setup View for build");
624
                    deliverChange("AbtSetUp", true, false);
625
 
626
                    mLogger.info("run calling deliverChange - the actual build");
627
                    mPhase.setPhase("Build Package");
628
                    deliverChange(null, true, false);
629
                    mLogger.info("run deliverChange returned");
630
                }
631
 
632
                mLastBuildWasBenign = false;
633
                if ( mMasterBuildFile.state == BuildFileState.Dummy)
634
                {
635
                    // no build requirement, so let things settle
636
                    mLogger.warn("run no build requirement, so let things settle");
637
                    mLastBuildWasBenign = true;
638
                }        
639
            }
640
            //---------------------------------------------------------------
641
            //    Build loop exception handling (only)
642
            //
643
            catch( SQLException e )
644
            {
645
                //  Oracle connection issues
646
                //  Request a prolonged sleep at the start of the build loop
7033 dpurdie 647
                mLogger.error("run oracle connection issues");
6914 dpurdie 648
                mException = true;
649
            }
650
            catch( ExitException e )
651
            {
652
                mLogger.warn("run ExitException");
653
                exit = true;
654
            }
655
            catch( InterruptedException e )
656
            {
657
                mLogger.warn("run InterruptedException");
658
                Thread.currentThread().interrupt();
659
            }
660
            catch (BuildSystemException e) {
661
                // BuildSystem exception - a (possibly) correctable error
662
                // Flag as recoverable
663
                //    - Can't create XML build file
664
                //    - 
665
                // 
7033 dpurdie 666
                mLogger.error("run BuildSystemException");
6914 dpurdie 667
                mPhase.setPhase("BuildSystemException indefinitePause");
668
                notifyIndefinitePause(e.getMessage());
669
                mReleaseManager.indefinitePause(false);
670
                mException = true;
671
                mRecoverable = true;
672
 
673
            }
674
            catch( BuildToolException e)
675
            {
676
                // Buildtool exception - an uncorrectable error
677
                //    - Can't parse XML build file
678
                // 
7033 dpurdie 679
                mLogger.error("run BuildToolException");
6914 dpurdie 680
                mPhase.setPhase("BuildToolException indefinitePause");
681
                notifyIndefinitePause(e.getMessage());
682
                mReleaseManager.indefinitePause(false);
683
                mException = true;
684
            }
685
            catch( Exception e )
686
            {
687
                //  Uncaptured exception
688
                //  These are not good. Current mechanism to handle this condition is:
689
                //      1) Email build system administrator
690
                //      2) Pause the build system
691
                //  
7176 dpurdie 692
                mLogger.error("run indefinitePause {}", e);
6914 dpurdie 693
 
694
                // DEVI 51366 force sleep at beginning of while loop
695
                mException = true;
696
 
697
                String cause = e.getMessage();
698
                if ( cause == null || cause.compareTo("null") == 0 )
699
                {
700
                    cause = "Internal Error: " + e.toString();
701
                }
702
 
703
                try
704
                {
705
                    // notify first
706
                    // many reasons for indefinite pause, including database related, so do database last
707
                    mRecoverable = false;
708
 
709
                    if ( cause.compareTo(Package.mRecoverable) == 0 )
710
                    {
711
                        mRecoverable = true;
712
                    }
713
 
714
                    mPhase.setPhase("Notify indefinitePause");
715
                    notifyIndefinitePause(cause);
716
                    mReleaseManager.indefinitePause(mRecoverable);
717
                    mReleaseManager.updateBuildInstance(mReporting.buildId, 0, BuildResult.SystemError );
718
                }
719
                catch( Exception f )
720
                {
721
                    mLogger.error("run indefinitePause failed");
722
                }
723
            }
724
        }
725
        try {
726
            mReleaseManager.clearCurrentPackageBeingBuilt(mRconId);
727
        } catch (Exception e) {
7176 dpurdie 728
            mLogger.error("Exception in clearCurrentPackageBeingBuilt: {}", e.getMessage());
6914 dpurdie 729
        }
730
        mPhase.setPhase("Exit Thread");
731
    }
732
 
7333 dpurdie 733
    /**
734
     * Locate the <rtagId>abtBuildInfo.properties file and insert data into Release Manager
735
     * Insert mPlatforms and mBuildPlatforms
736
     * @param bIsaTestBuild - True. Is a test build
737
     * @throws Exception 
738
     */
739
    private void insertBuildInfo(boolean bIsaTestBuild) throws Exception {
740
 
741
        File buildInfoFile = new File (mRtagId + "abtBuildInfo.properties");
742
        if ( buildInfoFile.exists() )
743
        {
744
            BuildInfo bi = new BuildInfo(buildInfoFile);
745
            mLogger.warn("Can build for: {}", bi.mPlatforms);
746
            mLogger.warn("Built for: {}", bi.mBuildPlatforms);
747
            mReleaseManager.insertBuildInfo(bIsaTestBuild, mReporting, bi);
748
        }
749
        else
750
        {
751
            mLogger.warn("No BuildInfo file. {}", buildInfoFile);
752
        }
753
    }
754
 
6914 dpurdie 755
    /**   Delete a specified version of a package from dpkg_archive
756
     *    Used during error processing to cleanup packages that did not build correctly
757
     *    
758
     *    The package-version is in dpkg_archive. This may be on a remote server
759
     *    Execute the deletion command on the remote server as it will be a lot faster
760
     *    for large packages.
761
     *    
762
     *    Ensure that the file system cache is cleared before we attempt to look
763
     *    for the directory
764
     */
765
    private void deletePackageVersion()
766
    {
767
 
768
        //    Setup a Remote Execution environment
769
        //    The logging interface is is hard part
770
        RemoteExecution mRemoteExecution = new RemoteExecution(new LogOutput(){
771
 
772
            @Override
773
            public void data(String message) {
774
                mLogger.info(message);
775
            }
776
 
777
            @Override
778
            public void fatal(String message) {
7033 dpurdie 779
                mLogger.error(message);
6914 dpurdie 780
            }
781
 
782
            @Override
783
            public void info(String message) {
784
                mLogger.info(message);
785
            }});
786
 
787
 
788
        //    Execute the remote command
789
        //    This is a best effort deletion - can't really handle conditions
790
        //    where the command fails.
791
        CommandBuilder cmd = new CommandBuilder();
792
 
793
        cmd.add("sudo","-n", "-u", "buildadm", "/home/releasem/sbin/jatsTool", "assemble_dpkg");
794
        cmd.add("-DeleteVersion");
795
        cmd.add(!ReleaseManager.getUseMutex(), "-testArchive");
796
        cmd.add("'-pname=" + mReporting.packageName + "'");
797
        cmd.add("'-pversion=" + mReporting.packageVersion + "'");
798
 
7176 dpurdie 799
        mLogger.warn("run remote command to delete {}, {}", mReporting.packageName, mReporting.packageVersion);
6914 dpurdie 800
        int rv = mRemoteExecution.execute(cmd.toString());
7176 dpurdie 801
        mLogger.info("run remote command to delete. Returned {}", rv);
6914 dpurdie 802
 
803
        //    Belt and Braces
804
        //    Ensure that the package-version has been deleted, 
805
        //    and if not then try to delete it the slow way.
806
        //
807
        //    Note: Need to flush NFS cache before we check existence 
808
 
809
        String dpkgArchiveEntry = utilities.catDir(Package.mGbeDpkg, mReporting.packageName, mReporting.packageVersion);
810
        File dpkgArchiveEntryFile = utilities.freshFile(dpkgArchiveEntry);
7176 dpurdie 811
        mLogger.debug("run checking existence of {}",dpkgArchiveEntry);
6914 dpurdie 812
 
813
        if ( dpkgArchiveEntryFile.exists() )
814
        {
815
            if ( dpkgArchiveEntryFile.isDirectory() )
816
            {
7176 dpurdie 817
                mLogger.warn("run calling deleteDirectory on {}", dpkgArchiveEntryFile);                      
6914 dpurdie 818
                deleteDirectory(dpkgArchiveEntryFile);
819
            }
820
        }
821
    }
822
 
823
    /**   Sends email notification and mark the successful completion of a build
824
     *    Used simply to keep an email trail of build operations
825
     */
826
    public void emailPostBuild( RippleEngine rippleEngine, boolean isaError )
827
    {
828
        mLogger.debug("emailPostBuild");
829
        String subject;
830
        String emailTo;
831
        String mailBody = "";
832
 
833
        if (isaError)
834
        {
835
            subject = "BUILD FAILURE on package " + mReporting.packageName + " " + mReporting.packageVersion;
836
            emailTo = mReporting.packageOwners;
837
            mailBody="An error occured within the build system after the package had been built<p><hr>";
838
        }
839
        else
840
        {
841
            subject = "BUILD SUCCESS on package " + mReporting.packageName + " " + mReporting.packageVersion;
842
            emailTo = rippleEngine.getMailSender();
843
        }
844
 
845
        //  Cleanup the dependency string
846
        //      Expecting: 'junit','3.7.0.cots';'ant-ejbdoclet','1.0000.cr'
847
        String indent = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";
848
        String depends = mReporting.packageDepends.replace("','", " ");
849
        depends = depends.replace("';'",indent);
850
        depends = depends.replace("'","");
851
 
852
        //  Cleanup the build standard string
853
        //      Expecting win32: jats all;linux_i386: jats prod
854
        String buildStandards = mReporting.packageBuildInfo;
855
        buildStandards = buildStandards.replace(";",indent);
856
 
857
        mailBody += "Release      : " + rippleEngine.mBaselineName + "<br>" +
858
                "Package      : " + mReporting.packageName + "<br>" +
859
                "Version      : " + mReporting.packageVersion + "<br>";
860
        if (isaError)
861
        {
862
            mailBody += "Cause        : " + mReporting.errMsg + "<br>";
863
            if (mReporting.errMsgDetail != null && mReporting.errMsgDetail.length() > 0)
864
            {
865
                mailBody += "Detail       : " + mReporting.errMsgDetail + "<br>";
866
            }
867
        }
868
 
869
        mailBody += "RM Link      : " + CreateUrls.generateRmUrl(mRtagId,mReporting.packageVersionId) + "<br>" +
870
                "PVID         : " + mReporting.packageVersionId + "<br>" +
871
                "VcsTag       : " + mReporting.newVcsTag + "<br>" +
872
                "Ripple       : " + (mReporting.isRipple ? "Yes" : "No") + "<br>" +
873
                "Dependencies : " + indent + depends + "<br>" +
874
                "Build Standards : " + indent + buildStandards;
875
 
876
        mailBody += "<p><hr>";
877
        try
878
        {
7155 dpurdie 879
            Smtpsend.send( rippleEngine.getMailServer(),    // mailServer
6914 dpurdie 880
                    rippleEngine.getMailSender(),           // source
7155 dpurdie 881
                    emailTo,                                // target - send to package owners, or myself
6914 dpurdie 882
                    rippleEngine.getMailSender(),           // cc
7155 dpurdie 883
                    null,                                   // bcc
884
                    subject,                                // subject
885
                    mailBody,                               // body
886
                    null                                    // attachment
6914 dpurdie 887
                    );
888
        }
889
        catch( Exception e )
890
        {
891
            mLogger.warn("Email Failure: emailPostBuild:" + e.getMessage());
892
        }
893
        mLogger.debug("emailPostBuild. Returning");
894
    }
7155 dpurdie 895
 
896
    /**
897
     * End of Processing for a Test Build
898
     *     - sends email notification
899
     *     - marks the instruction complete in the database
900
     */
901
    public void completeTestBuild(RippleEngine rippleEngine, boolean success) throws SQLException, Exception
902
    {
903
        mLogger.debug("completeTestBuild");
6914 dpurdie 904
 
7155 dpurdie 905
        if (!mReporting.isaTestBuild)
906
        {
907
            mLogger.info("completeTestBuild. Not Build Instruction");
908
            return;
909
        }
910
 
911
        //  Email Subject
912
        String subject = (success ? "TEST BUILD COMPLETED SUCCESSFULLY" : "TEST BUILD FAILED") 
913
                + " on package "
914
                + mReporting.packageName +  mReporting.packageExtension;
915
 
916
        //  Cleanup the dependency string
917
        //      Expecting: 'junit','3.7.0.cots';'ant-ejbdoclet','1.0000.cr'
918
        String indent = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";
919
        String depends = mReporting.packageDepends.replace("','", " ");
920
        depends = depends.replace("';'",indent);
921
        depends = depends.replace("'","");
922
 
923
        //  Cleanup the build standard string
924
        //      Expecting win32: jats all;linux_i386: jats prod
925
        String buildStandards = mReporting.packageBuildInfo;
926
        buildStandards = buildStandards.replace(";",indent);
927
 
928
        // Email Body
929
        String mailBody = "";
930
        if ( !success )
931
        {
932
            mailBody += "Test build issues are identified in preceding build failure email.<p>"; 
933
        }
934
        mailBody += "Release: " + rippleEngine.mBaselineName + "<br>" 
935
                  + "Package: " + mReporting.packageName +  mReporting.packageExtension + "<br>" 
936
                  + "Rm Ref: " + CreateUrls.generateRmUrl(mReporting.rtagId, mReporting.packageVersionId) + "<br>" 
937
                  + "VcsTag: " + mReporting.vcsTag + "<br>"
938
                  + "Dependencies : " + indent + depends + "<br>"
939
                  + "Build Standards : " + indent + buildStandards;
940
 
941
        mailBody += "<p><hr>";
942
        try
943
        {
7176 dpurdie 944
            mLogger.info("completeTestBuildEmail Server: {}", rippleEngine.getMailServer());
945
            mLogger.info("completeTestBuildEmail Sender: {}", rippleEngine.getMailSender());
946
            mLogger.info("completeTestBuildEmail Target: {}", mReporting.packageOwners);
7155 dpurdie 947
 
948
            Smtpsend.send(rippleEngine.getMailServer(),     // mailServer
949
                    rippleEngine.getMailSender(),           // source
950
                    mReporting.packageOwners,               // target
951
                    rippleEngine.getMailSender(),           // cc
952
                    null,                                   // bcc
953
                    subject,                                // subject
954
                    mailBody,                               // body
955
                    null                                    // attachment
956
            );
957
        } catch (Exception e)
958
        {
959
            mLogger.warn("Email Failure: completeTestBuild:{}", e.getMessage());
960
        }
961
 
962
        // Update the Release Manager Database
963
        mReleaseManager.markDaemonInstCompleted(mReporting.testBuildId);
7176 dpurdie 964
        mLogger.warn("completeTest. Returning");
7155 dpurdie 965
    }
966
 
967
 
6914 dpurdie 968
    /**returns 'M'
969
     */
970
    protected char getMode()
971
    {
972
        mLogger.debug("getMode");
973
        return 'M';
974
    }
975
 
976
 
977
}