Subversion Repositories DevTools

Rev

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