1 package org.apache.continuum.builder.distributed.manager;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.continuum.buildagent.NoBuildAgentException;
23 import org.apache.continuum.buildagent.NoBuildAgentInGroupException;
24 import org.apache.continuum.builder.distributed.executor.ThreadedDistributedBuildTaskQueueExecutor;
25 import org.apache.continuum.builder.distributed.util.DistributedBuildUtil;
26 import org.apache.continuum.builder.utils.ContinuumBuildConstant;
27 import org.apache.continuum.configuration.BuildAgentConfiguration;
28 import org.apache.continuum.configuration.BuildAgentGroupConfiguration;
29 import org.apache.continuum.dao.BuildDefinitionDao;
30 import org.apache.continuum.dao.BuildResultDao;
31 import org.apache.continuum.dao.ProjectDao;
32 import org.apache.continuum.dao.ProjectScmRootDao;
33 import org.apache.continuum.distributed.transport.slave.SlaveBuildAgentTransportClient;
34 import org.apache.continuum.distributed.transport.slave.SlaveBuildAgentTransportService;
35 import org.apache.continuum.model.project.ProjectRunSummary;
36 import org.apache.continuum.model.project.ProjectScmRoot;
37 import org.apache.continuum.taskqueue.BuildProjectTask;
38 import org.apache.continuum.taskqueue.OverallDistributedBuildQueue;
39 import org.apache.continuum.taskqueue.PrepareBuildProjectsTask;
40 import org.apache.continuum.utils.ContinuumUtils;
41 import org.apache.continuum.utils.ProjectSorter;
42 import org.apache.continuum.utils.build.BuildTrigger;
43 import org.apache.maven.continuum.ContinuumException;
44 import org.apache.maven.continuum.configuration.ConfigurationService;
45 import org.apache.maven.continuum.model.project.BuildDefinition;
46 import org.apache.maven.continuum.model.project.BuildResult;
47 import org.apache.maven.continuum.model.project.Project;
48 import org.apache.maven.continuum.model.system.Installation;
49 import org.apache.maven.continuum.model.system.Profile;
50 import org.apache.maven.continuum.project.ContinuumProjectState;
51 import org.apache.maven.continuum.store.ContinuumStoreException;
52 import org.codehaus.plexus.PlexusConstants;
53 import org.codehaus.plexus.PlexusContainer;
54 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
55 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
56 import org.codehaus.plexus.context.Context;
57 import org.codehaus.plexus.context.ContextException;
58 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
59 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
60 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
61 import org.codehaus.plexus.personality.plexus.lifecycle.phase.StoppingException;
62 import org.codehaus.plexus.taskqueue.Task;
63 import org.codehaus.plexus.taskqueue.TaskQueueException;
64 import org.codehaus.plexus.util.StringUtils;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68 import java.net.MalformedURLException;
69 import java.net.URL;
70 import java.util.ArrayList;
71 import java.util.Collections;
72 import java.util.Date;
73 import java.util.HashMap;
74 import java.util.List;
75 import java.util.Map;
76
77
78
79
80
81 public class DefaultDistributedBuildManager
82 implements DistributedBuildManager, Contextualizable, Initializable
83 {
84 private static final Logger log = LoggerFactory.getLogger( DefaultDistributedBuildManager.class );
85
86 private Map<String, OverallDistributedBuildQueue> overallDistributedBuildQueues = Collections.synchronizedMap(
87 new HashMap<String, OverallDistributedBuildQueue>() );
88
89 private List<ProjectRunSummary> currentRuns = Collections.synchronizedList( new ArrayList<ProjectRunSummary>() );
90
91
92
93
94 private ConfigurationService configurationService;
95
96
97
98
99 private ProjectDao projectDao;
100
101
102
103
104 private BuildDefinitionDao buildDefinitionDao;
105
106
107
108
109 private BuildResultDao buildResultDao;
110
111
112
113
114 private ProjectScmRootDao projectScmRootDao;
115
116
117
118
119 private DistributedBuildUtil distributedBuildUtil;
120
121 private PlexusContainer container;
122
123
124
125
126 public void contextualize( Context context )
127 throws ContextException
128 {
129 container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
130 }
131
132 public void initialize()
133 throws InitializationException
134 {
135 List<BuildAgentConfiguration> agents = configurationService.getBuildAgents();
136
137 if ( agents != null )
138 {
139 synchronized ( overallDistributedBuildQueues )
140 {
141 for ( BuildAgentConfiguration agent : agents )
142 {
143 if ( agent.isEnabled() )
144 {
145 try
146 {
147 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
148 agent.getUrl() );
149
150 if ( client.ping() )
151 {
152 log.debug( "agent is enabled, create distributed build queue for build agent '{}'",
153 agent.getUrl() );
154 createDistributedBuildQueueForAgent( agent.getUrl() );
155 }
156 else
157 {
158 log.debug( "unable to ping build agent '{}'", agent.getUrl() );
159 }
160 }
161 catch ( MalformedURLException e )
162 {
163
164 log.error( "Invalid build agent URL {}, not creating distributed build queue",
165 agent.getUrl() );
166 }
167 catch ( ContinuumException e )
168 {
169 throw new InitializationException( "Error while initializing distributed build queues", e );
170 }
171 catch ( Exception e )
172 {
173 agent.setEnabled( false );
174 log.debug( "unable to ping build agent '{}' : {}", agent.getUrl(),
175 ContinuumUtils.throwableToString( e ) );
176 }
177 }
178 else
179 {
180 log.debug( "agent {} is disabled, not creating distributed build queue", agent.getUrl() );
181 }
182 }
183 }
184 }
185 }
186
187 public void reload()
188 throws ContinuumException
189 {
190 List<BuildAgentConfiguration> agents = configurationService.getBuildAgents();
191
192 if ( agents == null )
193 {
194 return;
195 }
196
197 synchronized ( overallDistributedBuildQueues )
198 {
199 for ( BuildAgentConfiguration agent : agents )
200 {
201 if ( agent.isEnabled() && !overallDistributedBuildQueues.containsKey( agent.getUrl() ) )
202 {
203 SlaveBuildAgentTransportService client = null;
204
205 try
206 {
207 client = createSlaveBuildAgentTransportClientConnection( agent.getUrl() );
208 }
209 catch ( MalformedURLException e )
210 {
211 log.error( "Invalid build agent URL {}, not creating distributed build queue", agent.getUrl() );
212 throw new ContinuumException( "Malformed build agent url " + agent.getUrl() );
213 }
214 catch ( Exception e )
215 {
216 agent.setEnabled( false );
217 configurationService.updateBuildAgent( agent );
218
219 log.error( "Error binding build agent {} service : {} ", agent.getUrl(),
220 ContinuumUtils.throwableToString( e ) );
221 throw new ContinuumException( e.getMessage() );
222 }
223
224 boolean ping = false;
225
226 try
227 {
228 ping = client.ping();
229 }
230 catch ( Exception e )
231 {
232 agent.setEnabled( false );
233 log.error( "Unable to ping build agent '{}': {}", agent.getUrl(),
234 ContinuumUtils.throwableToString( e ) );
235 }
236
237 if ( ping )
238 {
239 try
240 {
241 createDistributedBuildQueueForAgent( agent.getUrl() );
242 log.debug( "Agent is enabled, create distributed build queue for build agent '{}'",
243 agent.getUrl() );
244 }
245 catch ( Exception e )
246 {
247 agent.setEnabled( false );
248 log.error( "Unable to create distributed queue for build agent {} : {}", agent.getUrl(),
249 ContinuumUtils.throwableToString( e ) );
250 }
251 }
252 else
253 {
254 agent.setEnabled( false );
255 log.error( "Unable to ping build agent '{}'", agent.getUrl() );
256 }
257
258 configurationService.updateBuildAgent( agent );
259 }
260 else if ( !agent.isEnabled() && overallDistributedBuildQueues.containsKey( agent.getUrl() ) )
261 {
262 log.debug( "agent is disabled, remove distributed build queue for build agent '{}'",
263 agent.getUrl() );
264 removeDistributedBuildQueueOfAgent( agent.getUrl() );
265 }
266 }
267 }
268 }
269
270 public void update( BuildAgentConfiguration agent )
271 throws ContinuumException
272 {
273 synchronized ( overallDistributedBuildQueues )
274 {
275 if ( agent.isEnabled() && !overallDistributedBuildQueues.containsKey( agent.getUrl() ) )
276 {
277 SlaveBuildAgentTransportService client;
278
279 try
280 {
281 client = createSlaveBuildAgentTransportClientConnection( agent.getUrl() );
282 }
283 catch ( MalformedURLException e )
284 {
285 log.error( "Invalid build agent URL {}, not creating distributed build queue", agent.getUrl() );
286 throw new ContinuumException( "Malformed build agent url " + agent.getUrl() );
287 }
288 catch ( Exception e )
289 {
290 log.error( "Error binding build agent {} service : {} ", agent.getUrl(),
291 ContinuumUtils.throwableToString( e ) );
292 throw new ContinuumException( e.getMessage() );
293 }
294
295 boolean ping;
296
297 try
298 {
299 ping = client.ping();
300 }
301 catch ( Exception e )
302 {
303 log.error( "Unable to ping build agent '{}': {}", agent.getUrl(), ContinuumUtils.throwableToString(
304 e ) );
305 throw new ContinuumException( "Unable to ping build agent " + agent.getUrl() );
306 }
307
308 if ( ping )
309 {
310 try
311 {
312 createDistributedBuildQueueForAgent( agent.getUrl() );
313 log.debug( "Agent is enabled, create distributed build queue for build agent '{}'",
314 agent.getUrl() );
315 }
316 catch ( Exception e )
317 {
318 log.error( "Unable to create distributed queue for build agent {} : {}", agent.getUrl(),
319 ContinuumUtils.throwableToString( e ) );
320 }
321 }
322 else
323 {
324 log.error( "Unable to ping build agent '{}'", agent.getUrl() );
325 throw new ContinuumException( "Unable to ping build agent " + agent.getUrl() );
326 }
327 }
328 else if ( !agent.isEnabled() && overallDistributedBuildQueues.containsKey( agent.getUrl() ) )
329 {
330 log.debug( "agent is disabled, remove distributed build queue for build agent '{}'", agent.getUrl() );
331 removeDistributedBuildQueueOfAgent( agent.getUrl() );
332 }
333 }
334 }
335
336 @SuppressWarnings( "unused" )
337 public void prepareBuildProjects( Map<Integer, Integer> projectsBuildDefinitionsMap, BuildTrigger buildTrigger,
338 int projectGroupId, String projectGroupName, String scmRootAddress, int scmRootId,
339 List<ProjectScmRoot> scmRoots )
340 throws ContinuumException, NoBuildAgentException, NoBuildAgentInGroupException
341 {
342 PrepareBuildProjectsTask task = new PrepareBuildProjectsTask( projectsBuildDefinitionsMap, buildTrigger,
343 projectGroupId, projectGroupName, scmRootAddress,
344 scmRootId );
345
346 if ( buildTrigger.getTrigger() == ContinuumProjectState.TRIGGER_FORCED )
347 {
348 log.debug( "Build project (projectGroupId={}) triggered manually by {}", projectGroupId,
349 buildTrigger.getTriggeredBy() );
350 }
351 else
352 {
353 log.debug( "Build project (projectGroupId={}) triggered by schedule {}", projectGroupId,
354 buildTrigger.getTriggeredBy() );
355 }
356
357 if ( log.isDebugEnabled() )
358 {
359 Map<String, BuildProjectTask> buildTasks = getProjectsCurrentlyBuilding();
360
361 for ( String key : buildTasks.keySet() )
362 {
363 log.debug( "Current build of agent {} :: Project {}", key, buildTasks.get( key ).getProjectName() );
364 }
365
366 Map<String, List<BuildProjectTask>> buildQueues = getProjectsInBuildQueue();
367
368 for ( String key : buildQueues.keySet() )
369 {
370 for ( BuildProjectTask buildTask : buildQueues.get( key ) )
371 {
372 log.debug( "Build Queue of agent {} :: Project {}", key, buildTask.getProjectName() );
373 }
374 }
375
376 Map<String, PrepareBuildProjectsTask> prepareBuildTasks = getProjectsCurrentlyPreparingBuild();
377
378 for ( String key : prepareBuildTasks.keySet() )
379 {
380 PrepareBuildProjectsTask prepareBuildTask = prepareBuildTasks.get( key );
381 log.debug( "Current prepare build of agent {} :: Project Group {} - Scm Root {}",
382 new Object[]{key, prepareBuildTask.getProjectGroupName(),
383 prepareBuildTask.getProjectScmRootId()} );
384 }
385
386 Map<String, List<PrepareBuildProjectsTask>> prepareBuildQueues = getProjectsInPrepareBuildQueue();
387
388 for ( String key : prepareBuildQueues.keySet() )
389 {
390 for ( PrepareBuildProjectsTask prepareBuildTask : prepareBuildQueues.get( key ) )
391 {
392 log.debug( "Prepare Build Queue of agent {} : Project Group {} - Scm Root {}",
393 new Object[]{key, prepareBuildTask.getProjectGroupName(),
394 prepareBuildTask.getProjectScmRootId()} );
395 }
396 }
397 }
398
399 log.debug( "Determining which build agent should build the project..." );
400
401 OverallDistributedBuildQueue overallDistributedBuildQueue = getOverallDistributedBuildQueueByGroup(
402 projectGroupId, scmRoots, scmRootId );
403
404 if ( overallDistributedBuildQueue == null )
405 {
406 log.debug(
407 "No projects with the same continuum group is currently building, checking if build definition has an attached build agent group" );
408
409 if ( hasBuildagentGroup( projectsBuildDefinitionsMap ) )
410 {
411 log.debug(
412 "Build definition used has an attached build agent group, checking if there are configured build agents in the group" );
413
414 if ( !hasBuildagentInGroup( projectsBuildDefinitionsMap ) )
415 {
416 log.warn( "No build agent configured in build agent group. Not building projects." );
417
418 throw new NoBuildAgentInGroupException( "No build agent configured in build agent group" );
419 }
420 else
421 {
422
423 log.info( "Getting the least busy build agent within the build agent group" );
424 overallDistributedBuildQueue = getOverallDistributedBuildQueueByAgentGroup(
425 projectsBuildDefinitionsMap );
426 }
427 }
428 else
429 {
430
431 log.info( "Project does not have a build agent group, getting the least busy of all build agents" );
432 overallDistributedBuildQueue = getOverallDistributedBuildQueue();
433 }
434 }
435
436 if ( overallDistributedBuildQueue != null )
437 {
438 try
439 {
440 String agentUrl = overallDistributedBuildQueue.getBuildAgentUrl();
441 log.info( "Building project in the least busy agent {}", agentUrl );
442 overallDistributedBuildQueue.addToDistributedBuildQueue( task );
443 createProjectRunSummaries( task, agentUrl );
444 }
445 catch ( TaskQueueException e )
446 {
447 log.error( "Error while enqueuing prepare build task", e );
448 throw new ContinuumException( "Error occurred while enqueuing prepare build task", e );
449 }
450 }
451 else
452 {
453 log.warn(
454 "Unable to determine which build agent should build the project. No build agent configured. Not building projects." );
455
456 throw new NoBuildAgentException( "No build agent configured" );
457 }
458
459
460 reload();
461 }
462
463 public void removeDistributedBuildQueueOfAgent( String buildAgentUrl )
464 throws ContinuumException
465 {
466 if ( overallDistributedBuildQueues.containsKey( buildAgentUrl ) )
467 {
468 List<PrepareBuildProjectsTask> tasks = null;
469
470 synchronized ( overallDistributedBuildQueues )
471 {
472 OverallDistributedBuildQueue overallDistributedBuildQueue = overallDistributedBuildQueues.get(
473 buildAgentUrl );
474
475 try
476 {
477 if ( overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor().getCurrentTask() != null )
478 {
479 log.error( "Unable to remove build agent because it is currently being used" );
480 throw new ContinuumException(
481 "Unable to remove build agent because it is currently being used" );
482 }
483
484 tasks = overallDistributedBuildQueue.getProjectsInQueue();
485
486 overallDistributedBuildQueue.getDistributedBuildQueue().removeAll( tasks );
487
488 ( (ThreadedDistributedBuildTaskQueueExecutor) overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor() ).stop();
489
490 container.release( overallDistributedBuildQueue );
491
492 overallDistributedBuildQueues.remove( buildAgentUrl );
493
494 log.debug( "remove distributed build queue for build agent '{}'", buildAgentUrl );
495 }
496 catch ( TaskQueueException e )
497 {
498 log.error( "Error occurred while removing build agent {}", buildAgentUrl, e );
499 throw new ContinuumException( "Error occurred while removing build agent " + buildAgentUrl, e );
500 }
501 catch ( ComponentLifecycleException e )
502 {
503 log.error( "Error occurred while removing build agent {}", buildAgentUrl, e );
504 throw new ContinuumException( "Error occurred while removing build agent " + buildAgentUrl, e );
505 }
506 catch ( StoppingException e )
507 {
508 log.error( "Error occurred while removing build agent {}", buildAgentUrl, e );
509 throw new ContinuumException( "Error occurred while removing build agent " + buildAgentUrl, e );
510 }
511 }
512 }
513 }
514
515 public Map<String, List<PrepareBuildProjectsTask>> getProjectsInPrepareBuildQueue()
516 throws ContinuumException
517 {
518 Map<String, List<PrepareBuildProjectsTask>> map = new HashMap<String, List<PrepareBuildProjectsTask>>();
519
520 synchronized ( overallDistributedBuildQueues )
521 {
522 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
523 {
524 List<PrepareBuildProjectsTask> tasks = new ArrayList<PrepareBuildProjectsTask>();
525
526 try
527 {
528 if ( isAgentAvailable( buildAgentUrl ) )
529 {
530 log.debug( "Getting projects in prepare build queue of build agent {}", buildAgentUrl );
531
532 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
533 buildAgentUrl );
534
535 List<Map<String, Object>> projects = client.getProjectsInPrepareBuildQueue();
536
537 for ( Map<String, Object> context : projects )
538 {
539 tasks.add( getPrepareBuildProjectsTask( context ) );
540 }
541
542 map.put( buildAgentUrl, tasks );
543 }
544 else
545 {
546 log.debug( "Unable to get projects in prepare build queue. Build agent {} not available",
547 buildAgentUrl );
548 }
549 }
550 catch ( MalformedURLException e )
551 {
552 throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
553 }
554 catch ( Exception e )
555 {
556 throw new ContinuumException( "Error while retrieving projects in prepare build queue", e );
557 }
558 }
559 }
560
561
562 reload();
563
564 return map;
565 }
566
567 public Map<String, PrepareBuildProjectsTask> getProjectsCurrentlyPreparingBuild()
568 throws ContinuumException
569 {
570 Map<String, PrepareBuildProjectsTask> map = new HashMap<String, PrepareBuildProjectsTask>();
571
572 synchronized ( overallDistributedBuildQueues )
573 {
574 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
575 {
576 try
577 {
578 if ( isAgentAvailable( buildAgentUrl ) )
579 {
580 log.debug( "Getting project currently preparing build in build agent {}", buildAgentUrl );
581
582 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
583 buildAgentUrl );
584 Map<String, Object> project = client.getProjectCurrentlyPreparingBuild();
585
586 if ( !project.isEmpty() )
587 {
588 map.put( buildAgentUrl, getPrepareBuildProjectsTask( project ) );
589 }
590 }
591 else
592 {
593 log.debug( "Unable to get projects currently preparing build. Build agent {} is not available",
594 buildAgentUrl );
595 }
596 }
597 catch ( MalformedURLException e )
598 {
599 throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
600 }
601 catch ( Exception e )
602 {
603 throw new ContinuumException(
604 "Error retrieving projects currently preparing build in " + buildAgentUrl, e );
605 }
606 }
607 }
608
609
610 reload();
611
612 return map;
613 }
614
615 public Map<String, BuildProjectTask> getProjectsCurrentlyBuilding()
616 throws ContinuumException
617 {
618 Map<String, BuildProjectTask> map = new HashMap<String, BuildProjectTask>();
619
620 synchronized ( overallDistributedBuildQueues )
621 {
622 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
623 {
624 try
625 {
626 if ( isAgentAvailable( buildAgentUrl ) )
627 {
628 log.debug( "Getting projects currently building in build agent {}", buildAgentUrl );
629
630 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
631 buildAgentUrl );
632 Map<String, Object> project = client.getProjectCurrentlyBuilding();
633
634 if ( !project.isEmpty() )
635 {
636 map.put( buildAgentUrl, getBuildProjectTask( project ) );
637 }
638 }
639 else
640 {
641 log.debug( "Unable to get projects currently building. Build agent {} is not available",
642 buildAgentUrl );
643 }
644 }
645 catch ( MalformedURLException e )
646 {
647 throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
648 }
649 catch ( Exception e )
650 {
651 throw new ContinuumException( "Error retrieving projects currently building in " + buildAgentUrl,
652 e );
653 }
654 }
655 }
656
657
658 reload();
659
660 return map;
661 }
662
663 public Map<String, List<BuildProjectTask>> getProjectsInBuildQueue()
664 throws ContinuumException
665 {
666 Map<String, List<BuildProjectTask>> map = new HashMap<String, List<BuildProjectTask>>();
667
668 synchronized ( overallDistributedBuildQueues )
669 {
670 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
671 {
672 List<BuildProjectTask> tasks = new ArrayList<BuildProjectTask>();
673
674 try
675 {
676 if ( isAgentAvailable( buildAgentUrl ) )
677 {
678 log.debug( "Getting projects in build queue in build agent {}", buildAgentUrl );
679
680 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
681 buildAgentUrl );
682 List<Map<String, Object>> projects = client.getProjectsInBuildQueue();
683
684 for ( Map<String, Object> context : projects )
685 {
686 tasks.add( getBuildProjectTask( context ) );
687 }
688
689 map.put( buildAgentUrl, tasks );
690 }
691 else
692 {
693 log.debug( "Unable to get projects in build queue. Build agent {} is not available",
694 buildAgentUrl );
695 }
696 }
697 catch ( MalformedURLException e )
698 {
699 throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
700 }
701 catch ( Exception e )
702 {
703 throw new ContinuumException( "Error while retrieving projects in build queue", e );
704 }
705 }
706 }
707
708
709 reload();
710
711 return map;
712 }
713
714 public boolean isBuildAgentBusy( String buildAgentUrl )
715 {
716 synchronized ( overallDistributedBuildQueues )
717 {
718 OverallDistributedBuildQueue overallDistributedBuildQueue = overallDistributedBuildQueues.get(
719 buildAgentUrl );
720
721 if ( overallDistributedBuildQueue != null &&
722 overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor().getCurrentTask() != null )
723 {
724 log.debug( "build agent '" + buildAgentUrl + "' is busy" );
725 return true;
726 }
727
728 log.debug( "build agent '" + buildAgentUrl + "' is not busy" );
729 return false;
730 }
731 }
732
733 public void cancelDistributedBuild( String buildAgentUrl )
734 throws ContinuumException
735 {
736 try
737 {
738 if ( isAgentAvailable( buildAgentUrl ) )
739 {
740 log.debug( "Cancelling build in build agent {}", buildAgentUrl );
741
742 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
743 buildAgentUrl );
744
745 client.cancelBuild();
746 }
747 else
748 {
749 log.debug( "Unable to cancel build, build agent {} is not available", buildAgentUrl );
750 }
751
752
753 reload();
754 }
755 catch ( MalformedURLException e )
756 {
757 log.error( "Error cancelling build in build agent: Invalid build agent url " + buildAgentUrl );
758 throw new ContinuumException(
759 "Error cancelling build in build agent: Invalid build agent url " + buildAgentUrl );
760 }
761 catch ( Exception e )
762 {
763 log.error( "Error occurred while cancelling build in build agent " + buildAgentUrl, e );
764 throw new ContinuumException( "Error occurred while cancelling build in build agent " + buildAgentUrl, e );
765 }
766 }
767
768 public void cancelGroupBuild( int projectGroupId )
769 throws ContinuumException
770 {
771 log.debug( "Cancelling all builds of project group {}", projectGroupId );
772
773 List<ProjectRunSummary> runsToDelete = new ArrayList<ProjectRunSummary>();
774
775 synchronized ( currentRuns )
776 {
777 for ( ProjectRunSummary run : currentRuns )
778 {
779 if ( run.getProjectGroupId() == projectGroupId )
780 {
781 cancelCurrentRun( run, runsToDelete );
782 }
783 }
784
785 if ( runsToDelete.size() > 0 )
786 {
787 currentRuns.removeAll( runsToDelete );
788 }
789 }
790 }
791
792 public void cancelBuild( int projectId )
793 throws ContinuumException
794 {
795 log.debug( "Cancelling all builds of project {}", projectId );
796
797 List<ProjectRunSummary> runsToDelete = new ArrayList<ProjectRunSummary>();
798
799 synchronized ( currentRuns )
800 {
801 for ( ProjectRunSummary run : currentRuns )
802 {
803 if ( run.getProjectId() == projectId )
804 {
805 cancelCurrentRun( run, runsToDelete );
806 }
807 }
808
809 if ( runsToDelete.size() > 0 )
810 {
811 currentRuns.removeAll( runsToDelete );
812 }
813 }
814 }
815
816 private void cancelCurrentRun( ProjectRunSummary run, List<ProjectRunSummary> runsToDelete )
817 throws ContinuumException
818 {
819 int projectId = run.getProjectId();
820 int buildDefinitionId = run.getBuildDefinitionId();
821 String buildAgentUrl = run.getBuildAgentUrl();
822
823
824 removeFromPrepareBuildQueue( buildAgentUrl, run.getProjectGroupId(), run.getProjectScmRootId() );
825 removeFromBuildQueue( buildAgentUrl, projectId, buildDefinitionId );
826
827 if ( isProjectCurrentlyPreparingBuild( projectId, buildDefinitionId ) )
828 {
829 log.debug(
830 "Unable to cancel build of projectId={}, buildDefinitionId={} in build agent{}. Project is currently doing scm update." );
831 return;
832 }
833 else if ( isProjectCurrentlyBuilding( projectId, buildDefinitionId ) )
834 {
835 log.debug( "Cancel build of projectId={}, buildDefinitionId={} in build agent {}",
836 new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
837 cancelDistributedBuild( buildAgentUrl );
838 runsToDelete.add( run );
839 }
840 else
841 {
842 try
843 {
844 ProjectScmRoot scmRoot = projectScmRootDao.getProjectScmRoot( run.getProjectScmRootId() );
845
846 if ( scmRoot != null && scmRoot.getState() == ContinuumProjectState.UPDATING )
847 {
848
849 scmRoot.setState( ContinuumProjectState.ERROR );
850 scmRoot.setError(
851 "Problem encountered while returning scm update result to master by build agent '" +
852 buildAgentUrl + "'. \n" +
853 "Make sure build agent is configured properly. Check the logs for more information." );
854 projectScmRootDao.updateProjectScmRoot( scmRoot );
855
856 log.debug(
857 "projectId={}, buildDefinitionId={} is not updating anymore. Problem encountered while return scm update result by build agent {}. Stopping the build.",
858 new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
859 runsToDelete.add( run );
860 }
861 else if ( scmRoot != null && scmRoot.getState() == ContinuumProjectState.ERROR )
862 {
863 log.debug(
864 "projectId={}, buildDefinitionId={} is not updating anymore. Problem encountered while return scm update result by build agent {}. Stopping the build.",
865 new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
866 runsToDelete.add( run );
867 }
868 else
869 {
870 Project project = projectDao.getProject( projectId );
871 BuildDefinition buildDefinition = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
872
873
874 BuildResult buildResult = new BuildResult();
875 buildResult.setBuildDefinition( buildDefinition );
876 buildResult.setBuildUrl( run.getBuildAgentUrl() );
877 buildResult.setTrigger( run.getTrigger() );
878 buildResult.setUsername( run.getTriggeredBy() );
879 buildResult.setState( ContinuumProjectState.ERROR );
880 buildResult.setSuccess( false );
881 buildResult.setStartTime( new Date().getTime() );
882 buildResult.setEndTime( new Date().getTime() );
883 buildResult.setExitCode( 1 );
884 buildResult.setError(
885 "Problem encountered while returning build result to master by build agent '" + buildAgentUrl +
886 "'. \n" +
887 "Make sure build agent is configured properly. Check the logs for more information." );
888 buildResultDao.addBuildResult( project, buildResult );
889
890 project.setState( ContinuumProjectState.ERROR );
891 project.setLatestBuildId( buildResult.getId() );
892 projectDao.updateProject( project );
893
894 log.debug(
895 "projectId={}, buildDefinitionId={} is not building anymore. Problem encountered while return build result by build agent {}. Stopping the build.",
896 new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
897
898
899 runsToDelete.add( run );
900 }
901 }
902 catch ( Exception e )
903 {
904 log.error( "Unable to end build for projectId={}, buildDefinitionId={} : {}",
905 new Object[]{projectId, buildDefinitionId, e.getMessage()} );
906 }
907 }
908 }
909
910 public Map<String, Object> getBuildResult( int projectId )
911 throws ContinuumException
912 {
913 Map<String, Object> map = new HashMap<String, Object>();
914
915 String buildAgentUrl = getBuildAgent( projectId );
916
917 if ( buildAgentUrl == null )
918 {
919 log.debug( "Unable to determine the build agent where project is building" );
920 return null;
921 }
922
923 try
924 {
925 if ( isAgentAvailable( buildAgentUrl ) )
926 {
927 log.debug( "Getting build result of project in build agent {}", buildAgentUrl );
928 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
929 buildAgentUrl );
930
931 Map<String, Object> result = client.getBuildResult( projectId );
932
933 if ( result != null )
934 {
935 int buildDefinitionId = ContinuumBuildConstant.getBuildDefinitionId( result );
936
937 Project project = projectDao.getProjectWithAllDetails( projectId );
938 BuildDefinition buildDefinition = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
939
940 BuildResult oldBuildResult = buildResultDao.getLatestBuildResultForBuildDefinition( projectId,
941 buildDefinitionId );
942
943 BuildResult buildResult = distributedBuildUtil.convertMapToBuildResult( result );
944 buildResult.setBuildDefinition( buildDefinition );
945 buildResult.setBuildNumber( project.getBuildNumber() + 1 );
946 buildResult.setModifiedDependencies( distributedBuildUtil.getModifiedDependencies( oldBuildResult,
947 result ) );
948 buildResult.setScmResult( distributedBuildUtil.getScmResult( result ) );
949
950 String buildOutput = ContinuumBuildConstant.getBuildOutput( result );
951
952 map.put( ContinuumBuildConstant.KEY_BUILD_RESULT, buildResult );
953 map.put( ContinuumBuildConstant.KEY_BUILD_OUTPUT, buildOutput );
954 }
955 else
956 {
957 log.debug( "No build result returned by build agent {}", buildAgentUrl );
958 }
959 }
960 else
961 {
962 log.debug( "Unable to get build result of project. Build agent {} is not available", buildAgentUrl );
963 }
964 }
965 catch ( MalformedURLException e )
966 {
967 throw new ContinuumException( "Invalid build agent URL '" + buildAgentUrl + "'" );
968 }
969 catch ( Exception e )
970 {
971 throw new ContinuumException( "Error while retrieving build result for project" + projectId, e );
972 }
973
974
975 reload();
976
977 return map;
978 }
979
980 public String getBuildAgentPlatform( String buildAgentUrl )
981 throws ContinuumException
982 {
983 try
984 {
985 String platform = "";
986 if ( isAgentAvailable( buildAgentUrl ) )
987 {
988 log.debug( "Getting build agent {} platform", buildAgentUrl );
989
990 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
991 buildAgentUrl );
992 platform = client.getBuildAgentPlatform();
993 }
994 else
995 {
996 log.debug( "Unable to get build agent platform. Build agent {} is not available", buildAgentUrl );
997 }
998
999 reload();
1000 return platform;
1001 }
1002 catch ( Exception e )
1003 {
1004 throw new ContinuumException( "Unable to get platform of build agent", e );
1005 }
1006 }
1007
1008
1009 public List<Installation> getAvailableInstallations( String buildAgentUrl )
1010 throws ContinuumException
1011 {
1012 List<Installation> installations = new ArrayList<Installation>();
1013
1014 try
1015 {
1016 if ( isAgentAvailable( buildAgentUrl ) )
1017 {
1018 log.debug( "Getting available installations in build agent {}", buildAgentUrl );
1019
1020 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1021 buildAgentUrl );
1022
1023 List<Map<String, String>> installationsList = client.getAvailableInstallations();
1024
1025 for ( Map context : installationsList )
1026 {
1027 Installation installation = new Installation();
1028 installation.setName( ContinuumBuildConstant.getInstallationName( context ) );
1029 installation.setType( ContinuumBuildConstant.getInstallationType( context ) );
1030 installation.setVarName( ContinuumBuildConstant.getInstallationVarName( context ) );
1031 installation.setVarValue( ContinuumBuildConstant.getInstallationVarValue( context ) );
1032 installations.add( installation );
1033 }
1034 }
1035 else
1036 {
1037 log.debug( "Unable to get available installations. Build agent {} is not available", buildAgentUrl );
1038 }
1039
1040
1041 reload();
1042
1043 return installations;
1044 }
1045 catch ( Exception e )
1046 {
1047 throw new ContinuumException( "Unable to get available installations of build agent", e );
1048 }
1049 }
1050
1051 public String generateWorkingCopyContent( int projectId, String directory, String baseUrl, String imageBaseUrl )
1052 throws ContinuumException
1053 {
1054 BuildResult buildResult = buildResultDao.getLatestBuildResultForProject( projectId );
1055
1056 if ( buildResult != null )
1057 {
1058 String buildAgentUrl = buildResult.getBuildUrl();
1059
1060 if ( buildAgentUrl == null )
1061 {
1062 log.debug( "Unable to determine the build agent where project last built" );
1063
1064 return "";
1065 }
1066
1067 try
1068 {
1069 if ( directory == null )
1070 {
1071 directory = "";
1072 }
1073
1074 if ( isAgentAvailable( buildAgentUrl ) )
1075 {
1076 log.debug( "Generating working copy content of project in build agent {}", buildAgentUrl );
1077
1078 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1079 buildAgentUrl );
1080 return client.generateWorkingCopyContent( projectId, directory, baseUrl, imageBaseUrl );
1081 }
1082 else
1083 {
1084 log.debug( "Unable to generate working copy content of project. Build agent {} is not available",
1085 buildAgentUrl );
1086 }
1087 }
1088 catch ( MalformedURLException e )
1089 {
1090 log.error( "Invalid build agent url " + buildAgentUrl );
1091 }
1092 catch ( Exception e )
1093 {
1094 log.error( "Error while generating working copy content from build agent " + buildAgentUrl, e );
1095 }
1096 }
1097 else
1098 {
1099 log.debug( "Unable to generate working copy content. Project hasn't been built yet." );
1100 }
1101
1102
1103 reload();
1104
1105 return "";
1106 }
1107
1108 public Map<String, Object> getFileContent( int projectId, String directory, String filename )
1109 throws ContinuumException
1110 {
1111 BuildResult buildResult = buildResultDao.getLatestBuildResultForProject( projectId );
1112
1113 if ( buildResult != null )
1114 {
1115 String buildAgentUrl = buildResult.getBuildUrl();
1116
1117 if ( buildAgentUrl == null )
1118 {
1119 log.debug( "Unable to determine build agent where project last built" );
1120 return null;
1121 }
1122
1123 try
1124 {
1125 if ( isAgentAvailable( buildAgentUrl ) )
1126 {
1127 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1128 buildAgentUrl );
1129 return client.getProjectFile( projectId, directory, filename );
1130 }
1131 }
1132 catch ( MalformedURLException e )
1133 {
1134 log.error( "Invalid build agent url " + buildAgentUrl );
1135 }
1136 catch ( Exception e )
1137 {
1138 log.error( "Error while retrieving content of " + filename, e );
1139 }
1140 }
1141 else
1142 {
1143 log.debug( "Unable to get file content because project hasn't been built yet" );
1144 }
1145
1146
1147 reload();
1148
1149 return null;
1150 }
1151
1152 public void removeFromPrepareBuildQueue( String buildAgentUrl, int projectGroupId, int scmRootId )
1153 throws ContinuumException
1154 {
1155 try
1156 {
1157 if ( isAgentAvailable( buildAgentUrl ) )
1158 {
1159 log.info( "Removing projectGroupId {} from prepare build queue of build agent {}", projectGroupId,
1160 buildAgentUrl );
1161
1162 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1163 buildAgentUrl );
1164 client.removeFromPrepareBuildQueue( projectGroupId, scmRootId );
1165 }
1166 else
1167 {
1168 log.debug(
1169 "Unable to remove projectGroupId {} from prepare build queue. Build agent {} is not available",
1170 projectGroupId, buildAgentUrl );
1171 }
1172 }
1173 catch ( MalformedURLException e )
1174 {
1175 log.error( "Unable to remove projectGroupId=" + projectGroupId + " scmRootId=" + scmRootId +
1176 " from prepare build queue: Invalid build agent url " + buildAgentUrl );
1177 throw new ContinuumException(
1178 "Unable to remove projectGroupId=" + projectGroupId + " scmRootId=" + scmRootId +
1179 " from prepare build queue: Invalid build agent url " + buildAgentUrl );
1180 }
1181 catch ( Exception e )
1182 {
1183 log.error( "Error occurred while removing projectGroupId=" + projectGroupId + " scmRootId=" + scmRootId +
1184 " from prepare build queue of agent " + buildAgentUrl, e );
1185 throw new ContinuumException(
1186 "Error occurred while removing projectGroupId=" + projectGroupId + " scmRootId=" +
1187 scmRootId + " from prepare build queue of agent " + buildAgentUrl, e );
1188 }
1189
1190
1191 reload();
1192 }
1193
1194 public void removeFromBuildQueue( String buildAgentUrl, int projectId, int buildDefinitionId )
1195 throws ContinuumException
1196 {
1197 try
1198 {
1199 if ( isAgentAvailable( buildAgentUrl ) )
1200 {
1201 log.info( "Removing projectId {} from build queue of build agent {}", projectId, buildAgentUrl );
1202 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1203 buildAgentUrl );
1204 client.removeFromBuildQueue( projectId, buildDefinitionId );
1205 }
1206 else
1207 {
1208 log.debug( "Unable to remove projectId {} from build queue. Build agent {} is not available", projectId,
1209 buildAgentUrl );
1210 }
1211 }
1212 catch ( MalformedURLException e )
1213 {
1214 log.error( "Unable to remove project " + projectId +
1215 " from build queue: Invalid build agent url " + buildAgentUrl );
1216 throw new ContinuumException( "Unable to remove project " + projectId +
1217 " from build queue: Invalid build agent url " + buildAgentUrl );
1218 }
1219 catch ( Exception e )
1220 {
1221 log.error( "Error occurred while removing project " + projectId +
1222 " from build queue of agent " + buildAgentUrl, e );
1223 throw new ContinuumException( "Error occurred while removing project " + projectId +
1224 " from build queue of agent " + buildAgentUrl, e );
1225 }
1226
1227
1228 reload();
1229 }
1230
1231 public void removeFromPrepareBuildQueue( List<String> hashCodes )
1232 throws ContinuumException
1233 {
1234 synchronized ( overallDistributedBuildQueues )
1235 {
1236 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1237 {
1238 try
1239 {
1240 if ( isAgentAvailable( buildAgentUrl ) )
1241 {
1242 log.info( "Removing project groups from prepare build queue of build agent {}", buildAgentUrl );
1243
1244 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1245 buildAgentUrl );
1246 client.removeFromPrepareBuildQueue( hashCodes );
1247 }
1248 else
1249 {
1250 log.debug(
1251 "Unable to remove project groups from prepare build queue. Build agent {} is not available",
1252 buildAgentUrl );
1253 }
1254 }
1255 catch ( MalformedURLException e )
1256 {
1257 log.error( "Error trying to remove projects from prepare build queue. Invalid build agent url: " +
1258 buildAgentUrl );
1259 }
1260 catch ( Exception e )
1261 {
1262 log.error( "Error trying to remove projects from prepare build queue of agent " + buildAgentUrl,
1263 e );
1264 }
1265 }
1266 }
1267
1268
1269 reload();
1270 }
1271
1272 public void removeFromBuildQueue( List<String> hashCodes )
1273 throws ContinuumException
1274 {
1275 synchronized ( overallDistributedBuildQueues )
1276 {
1277 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1278 {
1279 try
1280 {
1281 if ( isAgentAvailable( buildAgentUrl ) )
1282 {
1283 log.info( "Removing projects from build queue of build agent {}", buildAgentUrl );
1284
1285 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1286 buildAgentUrl );
1287 client.removeFromBuildQueue( hashCodes );
1288 }
1289 else
1290 {
1291 log.debug( "Unable to remove projects from build queue. Build agent {} is not available",
1292 buildAgentUrl );
1293 }
1294 }
1295 catch ( MalformedURLException e )
1296 {
1297 log.error(
1298 "Error trying to remove projects from build queue. Invalid build agent url: " + buildAgentUrl );
1299 }
1300 catch ( Exception e )
1301 {
1302 log.error( "Error trying to remove projects from build queue of agent " + buildAgentUrl, e );
1303 }
1304 }
1305 }
1306
1307
1308 reload();
1309 }
1310
1311 public boolean isProjectInAnyPrepareBuildQueue( int projectId, int buildDefinitionId )
1312 throws ContinuumException
1313 {
1314 boolean found = false;
1315
1316 synchronized ( overallDistributedBuildQueues )
1317 {
1318 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1319 {
1320 try
1321 {
1322 if ( isAgentAvailable( buildAgentUrl ) )
1323 {
1324 log.debug( "Checking if project {} is in prepare build queue of build agent {}", projectId,
1325 buildAgentUrl );
1326
1327 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1328 buildAgentUrl );
1329
1330 List<Map<String, Object>> projects = client.getProjectsAndBuildDefinitionsInPrepareBuildQueue();
1331
1332 for ( Map<String, Object> context : projects )
1333 {
1334 int pid = ContinuumBuildConstant.getProjectId( context );
1335 int buildId = ContinuumBuildConstant.getBuildDefinitionId( context );
1336
1337 if ( pid == projectId && ( buildId == buildDefinitionId || buildDefinitionId == -1 ) )
1338 {
1339 found = true;
1340 break;
1341 }
1342
1343 }
1344 }
1345 else
1346 {
1347 log.debug(
1348 "Unable to check if project {} is in prepare build queue. Build agent {} is not available",
1349 projectId, buildAgentUrl );
1350 }
1351
1352 if ( found )
1353 {
1354 break;
1355 }
1356 }
1357 catch ( MalformedURLException e )
1358 {
1359 throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
1360 }
1361 catch ( Exception e )
1362 {
1363 throw new ContinuumException( "Error while retrieving projects in prepare build queue", e );
1364 }
1365 }
1366 }
1367
1368
1369 reload();
1370
1371 if ( found )
1372 {
1373 return true;
1374 }
1375 else
1376 {
1377 return false;
1378 }
1379 }
1380
1381 public boolean isProjectInAnyBuildQueue( int projectId, int buildDefinitionId )
1382 throws ContinuumException
1383 {
1384 Map<String, List<BuildProjectTask>> map = getProjectsInBuildQueue();
1385
1386 for ( String url : map.keySet() )
1387 {
1388 for ( BuildProjectTask task : map.get( url ) )
1389 {
1390 if ( task.getProjectId() == projectId &&
1391 ( buildDefinitionId == -1 || task.getBuildDefinitionId() == buildDefinitionId ) )
1392 {
1393 return true;
1394 }
1395 }
1396 }
1397
1398 return false;
1399 }
1400
1401 public boolean isProjectCurrentlyPreparingBuild( int projectId, int buildDefinitionId )
1402 throws ContinuumException
1403 {
1404 boolean found = false;
1405
1406 synchronized ( overallDistributedBuildQueues )
1407 {
1408 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1409 {
1410 try
1411 {
1412 if ( isAgentAvailable( buildAgentUrl ) )
1413 {
1414 log.debug( "Checking if project {} is currently preparing build in build agent {}", projectId,
1415 buildAgentUrl );
1416
1417 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1418 buildAgentUrl );
1419 List<Map<String, Object>> projects =
1420 client.getProjectsAndBuildDefinitionsCurrentlyPreparingBuild();
1421
1422 for ( Map<String, Object> context : projects )
1423 {
1424 int pid = ContinuumBuildConstant.getProjectId( context );
1425 int buildId = ContinuumBuildConstant.getBuildDefinitionId( context );
1426
1427 if ( pid == projectId && ( buildDefinitionId == -1 || buildId == buildDefinitionId ) )
1428 {
1429 found = true;
1430 break;
1431 }
1432 }
1433 }
1434 else
1435 {
1436 log.debug(
1437 "Unable to check if project {} is currently preparing build. Build agent {} is not available",
1438 projectId, buildAgentUrl );
1439 }
1440
1441 if ( found )
1442 {
1443 break;
1444 }
1445 }
1446 catch ( MalformedURLException e )
1447 {
1448 throw new ContinuumException( "Invalid build agent url: " + buildAgentUrl );
1449 }
1450 catch ( Exception e )
1451 {
1452 throw new ContinuumException(
1453 "Error retrieving projects currently preparing build in " + buildAgentUrl, e );
1454 }
1455 }
1456 }
1457
1458
1459 reload();
1460
1461 if ( found )
1462 {
1463 return true;
1464 }
1465 else
1466 {
1467 return false;
1468 }
1469 }
1470
1471 public boolean isProjectCurrentlyBuilding( int projectId, int buildDefinitionId )
1472 throws ContinuumException
1473 {
1474 Map<String, BuildProjectTask> map = getProjectsCurrentlyBuilding();
1475
1476 for ( String url : map.keySet() )
1477 {
1478 BuildProjectTask task = map.get( url );
1479
1480 if ( task.getProjectId() == projectId &&
1481 ( buildDefinitionId == -1 || task.getBuildDefinitionId() == buildDefinitionId ) )
1482 {
1483 return true;
1484 }
1485 }
1486
1487 return false;
1488 }
1489
1490 private String getBuildAgent( int projectId )
1491 throws ContinuumException
1492 {
1493 String agentUrl = null;
1494
1495 synchronized ( overallDistributedBuildQueues )
1496 {
1497 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1498 {
1499 OverallDistributedBuildQueue overallDistributedBuildQueue = overallDistributedBuildQueues.get(
1500 buildAgentUrl );
1501
1502 if ( overallDistributedBuildQueue != null )
1503 {
1504 try
1505 {
1506 if ( isAgentAvailable( buildAgentUrl ) )
1507 {
1508 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1509 buildAgentUrl );
1510
1511
1512
1513
1514 if ( client.isProjectCurrentlyBuilding( projectId, -1 ) )
1515 {
1516 agentUrl = buildAgentUrl;
1517 break;
1518 }
1519 }
1520 else
1521 {
1522 log.debug(
1523 "Unable to check if project {} is currently building. Build agent {} is not available",
1524 projectId, buildAgentUrl );
1525 }
1526 }
1527 catch ( MalformedURLException e )
1528 {
1529 log.warn(
1530 "Unable to check if project {} is currently building in agent: Invalid build agent url {}",
1531 projectId, buildAgentUrl );
1532 }
1533 catch ( Exception e )
1534 {
1535 log.warn( "Unable to check if project {} is currently building in agent", projectId, e );
1536 }
1537 }
1538 }
1539 }
1540
1541
1542 reload();
1543
1544 return agentUrl;
1545 }
1546
1547 public String getBuildAgentUrl( int projectId, int buildDefinitionId )
1548 throws ContinuumException
1549 {
1550 String agentUrl = null;
1551
1552 synchronized ( overallDistributedBuildQueues )
1553 {
1554 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1555 {
1556 OverallDistributedBuildQueue overallDistributedBuildQueue = overallDistributedBuildQueues.get(
1557 buildAgentUrl );
1558
1559 if ( overallDistributedBuildQueue != null )
1560 {
1561 try
1562 {
1563 if ( isAgentAvailable( buildAgentUrl ) )
1564 {
1565 log.debug(
1566 "Checking if project {} with build definition {} is currently queued or processed in agent {}",
1567 new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
1568
1569 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1570 buildAgentUrl );
1571
1572 if ( client.isProjectInPrepareBuildQueue( projectId, buildDefinitionId ) ||
1573 client.isProjectCurrentlyPreparingBuild( projectId, buildDefinitionId ) ||
1574 client.isProjectInBuildQueue( projectId, buildDefinitionId ) ||
1575 client.isProjectCurrentlyBuilding( projectId, buildDefinitionId ) )
1576 {
1577 log.debug(
1578 "Project {} with build definition {} is currently queued or processed in agent {}",
1579 new Object[]{projectId, buildDefinitionId, buildAgentUrl} );
1580 agentUrl = buildAgentUrl;
1581 break;
1582 }
1583 }
1584 else
1585 {
1586 log.debug(
1587 "Unable to check if project {} is currently queued or processed in agent. Build agent {} is not available",
1588 projectId, buildAgentUrl );
1589 }
1590 }
1591 catch ( MalformedURLException e )
1592 {
1593 log.warn(
1594 "Unable to check if project {} is currently queued or processed in agent: Invalid build agent url {}",
1595 projectId, buildAgentUrl );
1596 }
1597 catch ( Exception e )
1598 {
1599 log.warn( "Unable to check if project {} is currently queued or processed in agent", projectId,
1600 e );
1601 }
1602 }
1603 }
1604 }
1605
1606
1607 reload();
1608
1609 return agentUrl;
1610 }
1611
1612 private void createDistributedBuildQueueForAgent( String buildAgentUrl )
1613 throws ComponentLookupException
1614 {
1615 if ( !overallDistributedBuildQueues.containsKey( buildAgentUrl ) )
1616 {
1617 OverallDistributedBuildQueue overallDistributedBuildQueue = (OverallDistributedBuildQueue) container.lookup(
1618 OverallDistributedBuildQueue.class );
1619 overallDistributedBuildQueue.setBuildAgentUrl( buildAgentUrl );
1620 overallDistributedBuildQueue.getDistributedBuildTaskQueueExecutor().setBuildAgentUrl( buildAgentUrl );
1621
1622 overallDistributedBuildQueues.put( buildAgentUrl, overallDistributedBuildQueue );
1623 }
1624 }
1625
1626 private OverallDistributedBuildQueue getOverallDistributedBuildQueueByScmRoot( ProjectScmRoot scmRoot,
1627 int projectGroupId )
1628 throws ContinuumException
1629 {
1630 int scmRootId = scmRoot.getId();
1631
1632 synchronized ( overallDistributedBuildQueues )
1633 {
1634 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1635 {
1636 OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
1637
1638 try
1639 {
1640 for ( PrepareBuildProjectsTask task : distributedBuildQueue.getProjectsInQueue() )
1641 {
1642 if ( task.getProjectScmRootId() == scmRootId )
1643 {
1644 log.debug(
1645 "Projects in the same continuum group are building in build agent: {}. Also building project in the same agent.",
1646 buildAgentUrl );
1647 return distributedBuildQueue;
1648 }
1649 }
1650
1651 Task task = distributedBuildQueue.getDistributedBuildTaskQueueExecutor().getCurrentTask();
1652 if ( task != null && ( (PrepareBuildProjectsTask) task ).getProjectScmRootId() == scmRootId )
1653 {
1654 log.debug(
1655 "Projects in the same continuum group are building in build agent: {}. Also building project in the same agent.",
1656 buildAgentUrl );
1657 return distributedBuildQueue;
1658 }
1659
1660 if ( isAgentAvailable( buildAgentUrl ) )
1661 {
1662 List<Project> projects = projectDao.getProjectsInGroup( projectGroupId );
1663 List<Integer> pIds = new ArrayList<Integer>();
1664
1665 for ( Project project : projects )
1666 {
1667 if ( project.getScmUrl().startsWith( scmRoot.getScmRootAddress() ) )
1668 {
1669 pIds.add( project.getId() );
1670 }
1671 }
1672
1673 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1674 buildAgentUrl );
1675
1676 if ( client.isProjectScmRootInQueue( scmRootId, pIds ) )
1677 {
1678 log.debug(
1679 "Projects in the same continuum group are building in build agent: {}. Also building project in the same agent.",
1680 buildAgentUrl );
1681 return distributedBuildQueue;
1682 }
1683 }
1684 else
1685 {
1686 log.debug( "Build agent {} is not available. Skipping...", buildAgentUrl );
1687 }
1688 }
1689 catch ( TaskQueueException e )
1690 {
1691 log.error( "Error occurred while retrieving distributed build queue of scmRootId=" + scmRootId, e );
1692 throw new ContinuumException( "Error occurred while retrieving distributed build queue of scmRoot",
1693 e );
1694 }
1695 catch ( MalformedURLException e )
1696 {
1697 log.error( "Error occurred while retrieving distributed build queue of scmRootId=" + scmRootId +
1698 ": Invalid build agent url " + buildAgentUrl );
1699 throw new ContinuumException(
1700 "Error occurred while retrieving distributed build queue of scmRootId=" + scmRootId +
1701 ": Invalid build agent url " + buildAgentUrl );
1702 }
1703 catch ( Exception e )
1704 {
1705 log.error( "Error occurred while retrieving distributed build queue of scmRootId=" + scmRootId, e );
1706 throw new ContinuumException( "Error occurred while retrieving distributed build queue of scmRoot",
1707 e );
1708 }
1709 }
1710 }
1711
1712 return null;
1713 }
1714
1715 private OverallDistributedBuildQueue getOverallDistributedBuildQueueByGroup( int projectGroupId,
1716 List<ProjectScmRoot> scmRoots,
1717 int scmRootId )
1718 throws ContinuumException
1719 {
1720 if ( scmRoots != null )
1721 {
1722 log.debug( "Checking if the project group is already building in one of the build agents" );
1723
1724 for ( ProjectScmRoot scmRoot : scmRoots )
1725 {
1726 if ( scmRoot.getId() == scmRootId )
1727 {
1728 break;
1729 }
1730 else if ( scmRoot.getProjectGroup().getId() == projectGroupId )
1731 {
1732 return getOverallDistributedBuildQueueByScmRoot( scmRoot, projectGroupId );
1733 }
1734 }
1735 }
1736 return null;
1737 }
1738
1739 private OverallDistributedBuildQueue getOverallDistributedBuildQueueByAgentGroup(
1740 Map<Integer, Integer> projectsAndBuildDefinitionsMap )
1741 throws ContinuumException
1742 {
1743 OverallDistributedBuildQueue whereToBeQueued = null;
1744
1745 BuildAgentGroupConfiguration buildAgentGroup = getBuildAgentGroup( projectsAndBuildDefinitionsMap );
1746
1747 if ( buildAgentGroup != null )
1748 {
1749 List<BuildAgentConfiguration> buildAgents = buildAgentGroup.getBuildAgents();
1750
1751 if ( buildAgents != null && buildAgents.size() > 0 )
1752 {
1753 List<String> buildAgentUrls = new ArrayList<String>();
1754
1755 for ( BuildAgentConfiguration buildAgent : buildAgents )
1756 {
1757 buildAgentUrls.add( buildAgent.getUrl() );
1758 }
1759
1760 synchronized ( overallDistributedBuildQueues )
1761 {
1762 int idx = 0;
1763 int size = 0;
1764
1765 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1766 {
1767 if ( !buildAgentUrls.isEmpty() && buildAgentUrls.contains( buildAgentUrl ) )
1768 {
1769 OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get(
1770 buildAgentUrl );
1771
1772 if ( distributedBuildQueue != null )
1773 {
1774 try
1775 {
1776 if ( isAgentAvailable( buildAgentUrl ) )
1777 {
1778 log.debug( "Build agent {} is available", buildAgentUrl );
1779
1780 SlaveBuildAgentTransportService client =
1781 createSlaveBuildAgentTransportClientConnection( buildAgentUrl );
1782 int agentBuildSize = client.getBuildSizeOfAgent();
1783
1784 log.debug( "Number of projects currently building in agent: {}",
1785 agentBuildSize );
1786 if ( idx == 0 )
1787 {
1788 log.debug( "Current least busy agent: {}", buildAgentUrl );
1789 whereToBeQueued = distributedBuildQueue;
1790 size = agentBuildSize;
1791 idx++;
1792 }
1793
1794 if ( agentBuildSize < size )
1795 {
1796 log.debug( "Current least busy agent: {}", buildAgentUrl );
1797 whereToBeQueued = distributedBuildQueue;
1798 size = agentBuildSize;
1799 }
1800 }
1801 else
1802 {
1803 log.debug( "Build agent {} is not available. Skipping...", buildAgentUrl );
1804 }
1805 }
1806 catch ( MalformedURLException e )
1807 {
1808 log.error(
1809 "Error occurred while retrieving distributed build queue: Invalid build agent url " +
1810 buildAgentUrl );
1811 }
1812 catch ( Exception e )
1813 {
1814 log.error( "Error occurred while retrieving distributed build queue ", e );
1815 }
1816 }
1817 }
1818 }
1819 }
1820 }
1821 }
1822
1823 return whereToBeQueued;
1824 }
1825
1826 private OverallDistributedBuildQueue getOverallDistributedBuildQueue()
1827 throws ContinuumException
1828 {
1829 OverallDistributedBuildQueue whereToBeQueued = null;
1830
1831 synchronized ( overallDistributedBuildQueues )
1832 {
1833 if ( overallDistributedBuildQueues.isEmpty() )
1834 {
1835 log.info( "No distributed build queues are configured for build agents" );
1836 return null;
1837 }
1838
1839 int idx = 0;
1840 int size = 0;
1841
1842 for ( String buildAgentUrl : overallDistributedBuildQueues.keySet() )
1843 {
1844 OverallDistributedBuildQueue distributedBuildQueue = overallDistributedBuildQueues.get( buildAgentUrl );
1845
1846 if ( distributedBuildQueue != null )
1847 {
1848 try
1849 {
1850 if ( isAgentAvailable( buildAgentUrl ) )
1851 {
1852 log.debug( "Build agent {} is available", buildAgentUrl );
1853
1854 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection(
1855 buildAgentUrl );
1856 int agentBuildSize = client.getBuildSizeOfAgent();
1857
1858 log.debug( "Number of projects currently building in agent: {}", agentBuildSize );
1859 if ( idx == 0 )
1860 {
1861 log.debug( "Current least busy agent: {}", buildAgentUrl );
1862 whereToBeQueued = distributedBuildQueue;
1863 size = agentBuildSize;
1864 idx++;
1865 }
1866
1867 if ( agentBuildSize < size )
1868 {
1869 log.debug( "Current least busy agent: {}", buildAgentUrl );
1870 whereToBeQueued = distributedBuildQueue;
1871 size = agentBuildSize;
1872 }
1873 }
1874 else
1875 {
1876 log.debug( "Build agent {} is not available. Skipping...", buildAgentUrl );
1877 }
1878 }
1879 catch ( MalformedURLException e )
1880 {
1881 log.error( "Error occurred while retrieving distributed build queue: invalid build agent url " +
1882 buildAgentUrl );
1883 }
1884 catch ( Exception e )
1885 {
1886 log.error( "Error occurred while retrieving distributed build queue", e );
1887 throw new ContinuumException( "Error occurred while retrieving distributed build queue", e );
1888 }
1889 }
1890 }
1891 }
1892
1893 return whereToBeQueued;
1894 }
1895
1896 private BuildAgentGroupConfiguration getBuildAgentGroup( Map<Integer, Integer> projectsAndBuildDefinitions )
1897 throws ContinuumException
1898 {
1899 if ( projectsAndBuildDefinitions == null )
1900 {
1901 return null;
1902 }
1903
1904 try
1905 {
1906 List<Project> projects = new ArrayList<Project>();
1907
1908 for ( Integer projectId : projectsAndBuildDefinitions.keySet() )
1909 {
1910 projects.add( projectDao.getProjectWithDependencies( projectId ) );
1911 }
1912
1913 projects = ProjectSorter.getSortedProjects( projects, log );
1914
1915 int buildDefinitionId = projectsAndBuildDefinitions.get( projects.get( 0 ).getId() );
1916 BuildDefinition buildDefinition = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
1917
1918 Profile profile = buildDefinition.getProfile();
1919
1920 if ( profile != null && !StringUtils.isEmpty( profile.getBuildAgentGroup() ) )
1921 {
1922 String groupName = profile.getBuildAgentGroup();
1923
1924 BuildAgentGroupConfiguration buildAgentGroup = configurationService.getBuildAgentGroup( groupName );
1925
1926 return buildAgentGroup;
1927 }
1928 }
1929 catch ( ContinuumStoreException e )
1930 {
1931 log.error( "Error while getting build agent group", e );
1932 throw new ContinuumException( "Error while getting build agent group", e );
1933 }
1934
1935 log.info( "profile build agent group is null" );
1936
1937 return null;
1938 }
1939
1940 private PrepareBuildProjectsTask getPrepareBuildProjectsTask( Map context )
1941 {
1942 int projectGroupId = ContinuumBuildConstant.getProjectGroupId( context );
1943 int scmRootId = ContinuumBuildConstant.getScmRootId( context );
1944 String scmRootAddress = ContinuumBuildConstant.getScmRootAddress( context );
1945 BuildTrigger buildTrigger = new BuildTrigger( ContinuumBuildConstant.getTrigger( context ),
1946 ContinuumBuildConstant.getUsername( context ) );
1947
1948 return new PrepareBuildProjectsTask( null, buildTrigger, projectGroupId, null, scmRootAddress, scmRootId );
1949 }
1950
1951 private BuildProjectTask getBuildProjectTask( Map context )
1952 {
1953 int projectId = ContinuumBuildConstant.getProjectId( context );
1954 int buildDefinitionId = ContinuumBuildConstant.getBuildDefinitionId( context );
1955 BuildTrigger buildTrigger = new BuildTrigger( ContinuumBuildConstant.getTrigger( context ),
1956 ContinuumBuildConstant.getUsername( context ) );
1957 int projectGroupId = ContinuumBuildConstant.getProjectGroupId( context );
1958 String buildDefinitionLabel = ContinuumBuildConstant.getBuildDefinitionLabel( context );
1959
1960 return new BuildProjectTask( projectId, buildDefinitionId, buildTrigger, null, buildDefinitionLabel, null,
1961 projectGroupId );
1962 }
1963
1964 public boolean isAgentAvailable( String buildAgentUrl )
1965 throws ContinuumException
1966 {
1967 try
1968 {
1969 if ( pingBuildAgent( buildAgentUrl ) )
1970 {
1971 return true;
1972 }
1973 }
1974 catch ( Exception e )
1975 {
1976 log.warn( "Disable build agent: {}; Unable to ping due to {}", buildAgentUrl, e );
1977 }
1978
1979
1980 disableBuildAgent( buildAgentUrl );
1981
1982 return false;
1983 }
1984
1985 public boolean pingBuildAgent( String buildAgentUrl )
1986 throws ContinuumException
1987 {
1988 try
1989 {
1990 SlaveBuildAgentTransportService client = createSlaveBuildAgentTransportClientConnection( buildAgentUrl );
1991
1992 return client.ping();
1993 }
1994 catch ( MalformedURLException e )
1995 {
1996 log.warn( "Invalid build agent url {}", buildAgentUrl );
1997 }
1998 catch ( Exception e )
1999 {
2000 throw new ContinuumException( "Unable to ping build agent " + buildAgentUrl + " : " + e.getMessage() );
2001 }
2002
2003 return false;
2004 }
2005
2006 public List<ProjectRunSummary> getCurrentRuns()
2007 {
2008 return currentRuns;
2009 }
2010
2011 public void removeCurrentRun( int projectId, int buildDefinitionId )
2012 {
2013 synchronized ( currentRuns )
2014 {
2015 boolean found = false;
2016 ProjectRunSummary runToDelete = null;
2017
2018 for ( ProjectRunSummary currentRun : currentRuns )
2019 {
2020 if ( currentRun.getProjectId() == projectId && currentRun.getBuildDefinitionId() == buildDefinitionId )
2021 {
2022 found = true;
2023 runToDelete = currentRun;
2024 break;
2025 }
2026 }
2027
2028 if ( found )
2029 {
2030 currentRuns.remove( runToDelete );
2031 }
2032 }
2033 }
2034
2035 private void createProjectRunSummaries( PrepareBuildProjectsTask task, String buildAgentUrl )
2036 {
2037 synchronized ( currentRuns )
2038 {
2039 int projectGroupId = task.getProjectGroupId();
2040 int projectScmRootId = task.getProjectScmRootId();
2041 Map<Integer, Integer> map = task.getProjectsBuildDefinitionsMap();
2042
2043 for ( int projectId : map.keySet() )
2044 {
2045 int buildDefinitionId = map.get( projectId );
2046
2047 ProjectRunSummary runToDelete = null;
2048
2049
2050 for ( ProjectRunSummary currentRun : currentRuns )
2051 {
2052 if ( currentRun.getProjectId() == projectId &&
2053 currentRun.getBuildDefinitionId() == buildDefinitionId )
2054 {
2055 runToDelete = currentRun;
2056 break;
2057 }
2058 }
2059
2060 if ( runToDelete != null )
2061 {
2062
2063
2064 currentRuns.remove( runToDelete );
2065 }
2066
2067 ProjectRunSummary run = new ProjectRunSummary();
2068 run.setProjectGroupId( projectGroupId );
2069 run.setProjectScmRootId( projectScmRootId );
2070 run.setProjectId( projectId );
2071 run.setBuildDefinitionId( buildDefinitionId );
2072 run.setTriggeredBy( task.getBuildTrigger().getTriggeredBy() );
2073 run.setTrigger( task.getBuildTrigger().getTrigger() );
2074 run.setBuildAgentUrl( buildAgentUrl );
2075 currentRuns.add( run );
2076 }
2077 }
2078 }
2079
2080 private void disableBuildAgent( String buildAgentUrl )
2081 throws ContinuumException
2082 {
2083 List<BuildAgentConfiguration> agents = configurationService.getBuildAgents();
2084
2085 for ( BuildAgentConfiguration agent : agents )
2086 {
2087 if ( agent.getUrl().equals( buildAgentUrl ) )
2088 {
2089 agent.setEnabled( false );
2090 configurationService.updateBuildAgent( agent );
2091
2092 try
2093 {
2094 configurationService.store();
2095
2096 log.debug( "Disabled build agent {}", buildAgentUrl );
2097 }
2098 catch ( Exception e )
2099 {
2100 throw new ContinuumException( "Unable to disable build agent: " + buildAgentUrl, e );
2101 }
2102 }
2103 }
2104 }
2105
2106 private boolean hasBuildagentGroup( Map<Integer, Integer> projectsAndBuildDefinitionsMap )
2107 throws ContinuumException
2108 {
2109 BuildAgentGroupConfiguration buildAgentGroup = getBuildAgentGroup( projectsAndBuildDefinitionsMap );
2110
2111 return buildAgentGroup != null && buildAgentGroup.getName().length() > 0 ? true : false;
2112 }
2113
2114 private boolean hasBuildagentInGroup( Map<Integer, Integer> projectsAndBuildDefinitionsMap )
2115 throws ContinuumException
2116 {
2117 BuildAgentGroupConfiguration buildAgentGroup = getBuildAgentGroup( projectsAndBuildDefinitionsMap );
2118
2119 return buildAgentGroup != null && buildAgentGroup.getBuildAgents().size() > 0 ? true : false;
2120 }
2121
2122 public SlaveBuildAgentTransportService createSlaveBuildAgentTransportClientConnection( String buildAgentUrl )
2123 throws MalformedURLException, Exception
2124 {
2125 return new SlaveBuildAgentTransportClient( new URL( buildAgentUrl ), "",
2126 configurationService.getSharedSecretPassword() );
2127 }
2128
2129
2130
2131 public void setOverallDistributedBuildQueues(
2132 Map<String, OverallDistributedBuildQueue> overallDistributedBuildQueues )
2133 {
2134 this.overallDistributedBuildQueues = overallDistributedBuildQueues;
2135 }
2136
2137 public void setConfigurationService( ConfigurationService configurationService )
2138 {
2139 this.configurationService = configurationService;
2140 }
2141
2142 public void setProjectDao( ProjectDao projectDao )
2143 {
2144 this.projectDao = projectDao;
2145 }
2146
2147 public void setBuildDefinitionDao( BuildDefinitionDao buildDefinitionDao )
2148 {
2149 this.buildDefinitionDao = buildDefinitionDao;
2150 }
2151
2152 public void setBuildResultDao( BuildResultDao buildResultDao )
2153 {
2154 this.buildResultDao = buildResultDao;
2155 }
2156
2157 public void setContainer( PlexusContainer container )
2158 {
2159 this.container = container;
2160 }
2161
2162 public void setCurrentRuns( List<ProjectRunSummary> currentRuns )
2163 {
2164 this.currentRuns = currentRuns;
2165 }
2166
2167 public void setProjectScmRootDao( ProjectScmRootDao projectScmRootDao )
2168 {
2169 this.projectScmRootDao = projectScmRootDao;
2170 }
2171 }