Subversion Repositories DevTools

Rev

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