From 25f4d2b15e560067c06e8613b23776876f4bd9bc Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sat, 19 Oct 2024 16:56:22 +0200 Subject: [PATCH 01/22] server --- .../buildagent/dto/BuildAgentInformation.java | 6 +++--- .../service/SharedQueueProcessingService.java | 13 ++++++++++++- .../localci/SharedQueueManagementService.java | 2 +- src/main/resources/config/application.yml | 8 ++++++++ .../icl/LocalCIResourceIntegrationTest.java | 3 ++- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java index ab24012f51fa..8e477f79bd5e 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java @@ -11,7 +11,7 @@ // in the future are migrated or cleared. Changes should be communicated in release notes as potentially breaking changes. @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_EMPTY) -public record BuildAgentInformation(String name, int maxNumberOfConcurrentBuildJobs, int numberOfCurrentBuildJobs, List runningBuildJobs, +public record BuildAgentInformation(String name, String memberAddress, int maxNumberOfConcurrentBuildJobs, int numberOfCurrentBuildJobs, List runningBuildJobs, BuildAgentStatus status, List recentBuildJobs, String publicSshKey) implements Serializable { @Serial @@ -24,8 +24,8 @@ public record BuildAgentInformation(String name, int maxNumberOfConcurrentBuildJ * @param recentBuildJobs The list of recent build jobs */ public BuildAgentInformation(BuildAgentInformation agentInformation, List recentBuildJobs) { - this(agentInformation.name(), agentInformation.maxNumberOfConcurrentBuildJobs(), agentInformation.numberOfCurrentBuildJobs(), agentInformation.runningBuildJobs, - agentInformation.status(), recentBuildJobs, agentInformation.publicSshKey()); + this(agentInformation.name(), agentInformation.memberAddress(), agentInformation.maxNumberOfConcurrentBuildJobs(), agentInformation.numberOfCurrentBuildJobs(), + agentInformation.runningBuildJobs, agentInformation.status(), recentBuildJobs, agentInformation.publicSshKey()); } public enum BuildAgentStatus { diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java index 69402e346a1f..32ec72f450bb 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java @@ -117,6 +117,9 @@ public class SharedQueueProcessingService { @Value("${artemis.continuous-integration.pause-grace-period-seconds:15}") private int pauseGracePeriodSeconds; + @Value("${artemis.continuous-integration.build-agent.short-name}") + private String buildAgentShortName; + public SharedQueueProcessingService(@Qualifier("hazelcastInstance") HazelcastInstance hazelcastInstance, ExecutorService localCIBuildExecutorService, BuildJobManagementService buildJobManagementService, BuildLogsMap buildLogsMap, BuildAgentSshKeyService buildAgentSSHKeyService, TaskScheduler taskScheduler) { this.hazelcastInstance = hazelcastInstance; @@ -132,6 +135,13 @@ public SharedQueueProcessingService(@Qualifier("hazelcastInstance") HazelcastIns */ @PostConstruct public void init() { + if (!buildAgentShortName.matches("^[a-z0-9-]+$")) { + String errorMessage = "Build agent short name must not be empty and only contain lowercase letters, numbers and hyphens." + + " Build agent short name should be changed in the application properties under 'artemis.continuous-integration.build-agent.short-name'."; + log.error(errorMessage); + throw new IllegalArgumentException(errorMessage); + } + this.buildAgentInformation = this.hazelcastInstance.getMap("buildAgentInformation"); this.processingJobs = this.hazelcastInstance.getMap("processingJobs"); this.queue = this.hazelcastInstance.getQueue("buildJobQueue"); @@ -324,7 +334,8 @@ private BuildAgentInformation getUpdatedLocalBuildAgentInformation(BuildJobQueue String publicSshKey = buildAgentSSHKeyService.getPublicKeyAsString(); - return new BuildAgentInformation(memberAddress, maxNumberOfConcurrentBuilds, numberOfCurrentBuildJobs, processingJobsOfMember, status, recentBuildJobs, publicSshKey); + return new BuildAgentInformation(buildAgentShortName, memberAddress, maxNumberOfConcurrentBuilds, numberOfCurrentBuildJobs, processingJobsOfMember, status, recentBuildJobs, + publicSshKey); } private List getProcessingJobsOfNode(String memberAddress) { diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java index 9af5fe3b45c1..7797965deaa6 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java @@ -137,7 +137,7 @@ public List getBuildAgentInformation() { } public List getBuildAgentInformationWithoutRecentBuildJobs() { - return buildAgentInformation.values().stream().map(agent -> new BuildAgentInformation(agent.name(), agent.maxNumberOfConcurrentBuildJobs(), + return buildAgentInformation.values().stream().map(agent -> new BuildAgentInformation(agent.name(), agent.memberAddress(), agent.maxNumberOfConcurrentBuildJobs(), agent.numberOfCurrentBuildJobs(), agent.runningBuildJobs(), agent.status(), null, null)).toList(); } diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index 6645696acc2e..ac6ce89e95e3 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -96,6 +96,14 @@ artemis: c_plus_plus: default: "ghcr.io/ls1intum/artemis-cpp-docker:v1.0.0" + # The following properties are used to configure the Artemis build agent. + # The build agent is responsible for executing the buildJob to test student submissions. + build-agent: + # Name of the build agent. Only lowercase letters, numbers and hyphens are allowed. ([a-z0-9-]+) + short-name: "artemis-build-agent-1" + + + management: endpoints: web: diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java index e05b87776154..b2d73eb14e5e 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java @@ -100,7 +100,8 @@ void createJobs() { job1 = new BuildJobQueueItem("1", "job1", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); job2 = new BuildJobQueueItem("2", "job2", "address1", 2, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo2, buildConfig, null); String memberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); - agent1 = new BuildAgentInformation(memberAddress, 1, 0, new ArrayList<>(List.of(job1)), BuildAgentInformation.BuildAgentStatus.IDLE, new ArrayList<>(List.of(job2)), null); + agent1 = new BuildAgentInformation("build-agent", memberAddress, 1, 0, new ArrayList<>(List.of(job1)), BuildAgentInformation.BuildAgentStatus.IDLE, + new ArrayList<>(List.of(job2)), null); BuildJobQueueItem finishedJobQueueItem1 = new BuildJobQueueItem("3", "job3", "address1", 3, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); BuildJobQueueItem finishedJobQueueItem2 = new BuildJobQueueItem("4", "job4", "address1", 4, course.getId() + 1, 1, 1, 1, BuildStatus.FAILED, repositoryInfo, jobTimingInfo2, From 4cee0f5058b5433f72d2d859d7763ef4210955f7 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sat, 19 Oct 2024 21:24:20 +0200 Subject: [PATCH 02/22] client and server fixes --- .../buildagent/dto/BuildJobQueueItem.java | 20 ++++++++-------- .../service/SharedQueueProcessingService.java | 21 +++++++++-------- .../localci/LocalCITriggerService.java | 4 ++-- .../entities/programming/build-agent.model.ts | 1 + .../entities/programming/build-job.model.ts | 1 + .../build-agent-details.component.html | 11 +++++---- .../build-agent-summary.component.html | 13 +++++++++++ .../build-queue/build-queue.component.html | 4 ++-- .../build-queue/build-queue.component.ts | 2 ++ src/main/webapp/i18n/de/buildAgents.json | 1 + src/main/webapp/i18n/en/buildAgents.json | 1 + .../service/BuildAgentDockerServiceTest.java | 2 +- .../icl/LocalCIResourceIntegrationTest.java | 23 ++++++++++--------- .../programming/icl/LocalCIServiceTest.java | 4 ++-- 14 files changed, 67 insertions(+), 41 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildJobQueueItem.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildJobQueueItem.java index d9bfff039c2e..8fcdad140675 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildJobQueueItem.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildJobQueueItem.java @@ -14,8 +14,8 @@ // in the future are migrated or cleared. Changes should be communicated in release notes as potentially breaking changes. @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_EMPTY) -public record BuildJobQueueItem(String id, String name, String buildAgentAddress, long participationId, long courseId, long exerciseId, int retryCount, int priority, - BuildStatus status, RepositoryInfo repositoryInfo, JobTimingInfo jobTimingInfo, BuildConfig buildConfig, ResultDTO submissionResult) implements Serializable { +public record BuildJobQueueItem(String id, String name, String buildAgentName, String buildAgentAddress, long participationId, long courseId, long exerciseId, int retryCount, + int priority, BuildStatus status, RepositoryInfo repositoryInfo, JobTimingInfo jobTimingInfo, BuildConfig buildConfig, ResultDTO submissionResult) implements Serializable { @Serial private static final long serialVersionUID = 1L; @@ -28,8 +28,8 @@ public record BuildJobQueueItem(String id, String name, String buildAgentAddress * @param status The status/result of the build job */ public BuildJobQueueItem(BuildJobQueueItem queueItem, ZonedDateTime buildCompletionDate, BuildStatus status) { - this(queueItem.id(), queueItem.name(), queueItem.buildAgentAddress(), queueItem.participationId(), queueItem.courseId(), queueItem.exerciseId(), queueItem.retryCount(), - queueItem.priority(), status, queueItem.repositoryInfo(), + this(queueItem.id(), queueItem.name(), queueItem.buildAgentName(), queueItem.buildAgentAddress(), queueItem.participationId(), queueItem.courseId(), queueItem.exerciseId(), + queueItem.retryCount(), queueItem.priority(), status, queueItem.repositoryInfo(), new JobTimingInfo(queueItem.jobTimingInfo.submissionDate(), queueItem.jobTimingInfo.buildStartDate(), buildCompletionDate), queueItem.buildConfig(), null); } @@ -39,14 +39,14 @@ public BuildJobQueueItem(BuildJobQueueItem queueItem, ZonedDateTime buildComplet * @param queueItem The queued build job * @param hazelcastMemberAddress The address of the hazelcast member that is processing the build job */ - public BuildJobQueueItem(BuildJobQueueItem queueItem, String hazelcastMemberAddress) { - this(queueItem.id(), queueItem.name(), hazelcastMemberAddress, queueItem.participationId(), queueItem.courseId(), queueItem.exerciseId(), queueItem.retryCount(), - queueItem.priority(), null, queueItem.repositoryInfo(), new JobTimingInfo(queueItem.jobTimingInfo.submissionDate(), ZonedDateTime.now(), null), - queueItem.buildConfig(), null); + public BuildJobQueueItem(BuildJobQueueItem queueItem, String buildAgentName, String hazelcastMemberAddress) { + this(queueItem.id(), queueItem.name(), buildAgentName, hazelcastMemberAddress, queueItem.participationId(), queueItem.courseId(), queueItem.exerciseId(), + queueItem.retryCount(), queueItem.priority(), null, queueItem.repositoryInfo(), + new JobTimingInfo(queueItem.jobTimingInfo.submissionDate(), ZonedDateTime.now(), null), queueItem.buildConfig(), null); } public BuildJobQueueItem(BuildJobQueueItem queueItem, ResultDTO submissionResult) { - this(queueItem.id(), queueItem.name(), queueItem.buildAgentAddress(), queueItem.participationId(), queueItem.courseId(), queueItem.exerciseId(), queueItem.retryCount(), - queueItem.priority(), queueItem.status(), queueItem.repositoryInfo(), queueItem.jobTimingInfo(), queueItem.buildConfig(), submissionResult); + this(queueItem.id(), queueItem.name(), queueItem.buildAgentName(), queueItem.buildAgentAddress(), queueItem.participationId(), queueItem.courseId(), queueItem.exerciseId(), + queueItem.retryCount(), queueItem.priority(), queueItem.status(), queueItem.repositoryInfo(), queueItem.jobTimingInfo(), queueItem.buildConfig(), submissionResult); } } diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java index 32ec72f450bb..e62b4a325c8d 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java @@ -162,14 +162,14 @@ public void init() { ITopic pauseBuildAgentTopic = hazelcastInstance.getTopic("pauseBuildAgentTopic"); pauseBuildAgentTopic.addMessageListener(message -> { - if (message.getMessageObject().equals(hazelcastInstance.getCluster().getLocalMember().getAddress().toString())) { + if (message.getMessageObject().equals(buildAgentShortName)) { pauseBuildAgent(); } }); ITopic resumeBuildAgentTopic = hazelcastInstance.getTopic("resumeBuildAgentTopic"); resumeBuildAgentTopic.addMessageListener(message -> { - if (message.getMessageObject().equals(hazelcastInstance.getCluster().getLocalMember().getAddress().toString())) { + if (message.getMessageObject().equals(buildAgentShortName)) { resumeBuildAgent(); } }); @@ -201,6 +201,9 @@ public void updateBuildAgentInformation() { log.debug("There are only lite member in the cluster. Not updating build agent information."); return; } + // Print buildAgentInformation for debugging + log.debug("Build agent information: {}", buildAgentInformation.values()); + // Remove build agent information of offline nodes removeOfflineNodes(); @@ -253,7 +256,7 @@ private void checkAvailabilityAndProcessNextBuild() { if (buildJob != null) { processingJobs.remove(buildJob.id()); - buildJob = new BuildJobQueueItem(buildJob, ""); + buildJob = new BuildJobQueueItem(buildJob, "", ""); log.info("Adding build job back to the queue: {}", buildJob); queue.add(buildJob); localProcessingJobs.decrementAndGet(); @@ -275,7 +278,7 @@ private BuildJobQueueItem addToProcessingJobs() { if (buildJob != null) { String hazelcastMemberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); - BuildJobQueueItem processingJob = new BuildJobQueueItem(buildJob, hazelcastMemberAddress); + BuildJobQueueItem processingJob = new BuildJobQueueItem(buildJob, buildAgentShortName, hazelcastMemberAddress); processingJobs.put(processingJob.id(), processingJob); localProcessingJobs.incrementAndGet(); @@ -297,10 +300,10 @@ private void updateLocalBuildAgentInformationWithRecentJob(BuildJobQueueItem rec // Add/update BuildAgentInformation info = getUpdatedLocalBuildAgentInformation(recentBuildJob); try { - buildAgentInformation.put(info.name(), info); + buildAgentInformation.put(info.memberAddress(), info); } catch (Exception e) { - log.error("Error while updating build agent information for agent {}", info.name(), e); + log.error("Error while updating build agent information for agent {} with address {}", info.name(), info.memberAddress(), e); } } finally { @@ -372,9 +375,9 @@ private void processBuild(BuildJobQueueItem buildJob) { log.debug("Build job completed: {}", buildJob); JobTimingInfo jobTimingInfo = new JobTimingInfo(buildJob.jobTimingInfo().submissionDate(), buildJob.jobTimingInfo().buildStartDate(), ZonedDateTime.now()); - BuildJobQueueItem finishedJob = new BuildJobQueueItem(buildJob.id(), buildJob.name(), buildJob.buildAgentAddress(), buildJob.participationId(), buildJob.courseId(), - buildJob.exerciseId(), buildJob.retryCount(), buildJob.priority(), BuildStatus.SUCCESSFUL, buildJob.repositoryInfo(), jobTimingInfo, buildJob.buildConfig(), - null); + BuildJobQueueItem finishedJob = new BuildJobQueueItem(buildJob.id(), buildJob.name(), buildJob.buildAgentName(), buildJob.buildAgentAddress(), + buildJob.participationId(), buildJob.courseId(), buildJob.exerciseId(), buildJob.retryCount(), buildJob.priority(), BuildStatus.SUCCESSFUL, + buildJob.repositoryInfo(), jobTimingInfo, buildJob.buildConfig(), null); List buildLogs = buildLogsMap.getBuildLogs(buildJob.id()); buildLogsMap.removeBuildLogs(buildJob.id()); diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java index 5da2860ba799..0983a04f3ff5 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java @@ -196,8 +196,8 @@ else if (triggeredByPushTo.equals(RepositoryType.TESTS)) { BuildConfig buildConfig = getBuildConfig(participation, commitHashToBuild, assignmentCommitHash, testCommitHash, programmingExerciseBuildConfig); - BuildJobQueueItem buildJobQueueItem = new BuildJobQueueItem(buildJobId, participation.getBuildPlanId(), null, participation.getId(), courseId, programmingExercise.getId(), - 0, priority, null, repositoryInfo, jobTimingInfo, buildConfig, null); + BuildJobQueueItem buildJobQueueItem = new BuildJobQueueItem(buildJobId, participation.getBuildPlanId(), null, null, participation.getId(), courseId, + programmingExercise.getId(), 0, priority, null, repositoryInfo, jobTimingInfo, buildConfig, null); queue.add(buildJobQueueItem); log.info("Added build job {} to the queue", buildJobId); diff --git a/src/main/webapp/app/entities/programming/build-agent.model.ts b/src/main/webapp/app/entities/programming/build-agent.model.ts index 86c51ffc8b35..8817ba7ad92d 100644 --- a/src/main/webapp/app/entities/programming/build-agent.model.ts +++ b/src/main/webapp/app/entities/programming/build-agent.model.ts @@ -10,6 +10,7 @@ export enum BuildAgentStatus { export class BuildAgent implements BaseEntity { public id?: number; public name?: string; + public memberAddress?: string; public maxNumberOfConcurrentBuildJobs?: number; public numberOfCurrentBuildJobs?: number; public runningBuildJobs?: BuildJob[]; diff --git a/src/main/webapp/app/entities/programming/build-job.model.ts b/src/main/webapp/app/entities/programming/build-job.model.ts index a36bb9756091..dfea79380097 100644 --- a/src/main/webapp/app/entities/programming/build-job.model.ts +++ b/src/main/webapp/app/entities/programming/build-job.model.ts @@ -8,6 +8,7 @@ import dayjs from 'dayjs/esm'; export class BuildJob implements StringBaseEntity { public id?: string; public name?: string; + public buildAgentName?: string; public buildAgentAddress?: string; public participationId?: number; public courseId?: number; diff --git a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html index 1a88dba6a6d8..0ae374945a5d 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html +++ b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html @@ -2,10 +2,13 @@ @if (buildAgent) {
-
-

- : -

{{ buildAgent.name }}

+
+
+

+ : +

{{ buildAgent.name }}

+
+ {{ buildAgent.memberAddress }}
@if (buildAgent.status === 'PAUSED') { diff --git a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html index 0982463d75a9..7dddcf193bc7 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html +++ b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html @@ -33,6 +33,19 @@

+ + + + + + + + + + + + + diff --git a/src/main/webapp/app/localci/build-queue/build-queue.component.html b/src/main/webapp/app/localci/build-queue/build-queue.component.html index 4e0e1e095754..bea45c87ae79 100644 --- a/src/main/webapp/app/localci/build-queue/build-queue.component.html +++ b/src/main/webapp/app/localci/build-queue/build-queue.component.html @@ -114,8 +114,8 @@

- - + + {{ value }} diff --git a/src/main/webapp/app/localci/build-queue/build-queue.component.ts b/src/main/webapp/app/localci/build-queue/build-queue.component.ts index 79ca4931786c..0215d9153aef 100644 --- a/src/main/webapp/app/localci/build-queue/build-queue.component.ts +++ b/src/main/webapp/app/localci/build-queue/build-queue.component.ts @@ -232,9 +232,11 @@ export class BuildQueueComponent implements OnInit, OnDestroy { this.websocketService.subscribe(`/topic/admin/queued-jobs`); this.websocketService.subscribe(`/topic/admin/running-jobs`); this.websocketService.receive(`/topic/admin/queued-jobs`).subscribe((queuedBuildJobs) => { + console.log('queuedBuildJobs', queuedBuildJobs); this.queuedBuildJobs = queuedBuildJobs; }); this.websocketService.receive(`/topic/admin/running-jobs`).subscribe((runningBuildJobs) => { + console.log('runningBuildJobs', runningBuildJobs); this.runningBuildJobs = this.updateBuildJobDuration(runningBuildJobs); }); } diff --git a/src/main/webapp/i18n/de/buildAgents.json b/src/main/webapp/i18n/de/buildAgents.json index 2cd4ca72def3..186bd1432540 100644 --- a/src/main/webapp/i18n/de/buildAgents.json +++ b/src/main/webapp/i18n/de/buildAgents.json @@ -5,6 +5,7 @@ "summary": "Build Agenten Zusammenfassung", "details": "Build Agenten Details", "name": "Name", + "memberAddress": "Agentenadresse", "maxNumberOfConcurrentBuildJobs": "Maximale Anzahl an parallelen Build Jobs", "numberOfCurrentBuildJobs": "Anzahl aktueller Build Jobs", "runningBuildJobs": "Laufende Build Jobs", diff --git a/src/main/webapp/i18n/en/buildAgents.json b/src/main/webapp/i18n/en/buildAgents.json index e1401d97e272..1610e1bd0847 100644 --- a/src/main/webapp/i18n/en/buildAgents.json +++ b/src/main/webapp/i18n/en/buildAgents.json @@ -5,6 +5,7 @@ "summary": "Build Agents Summary", "details": "Build Agents Details", "name": "Name", + "memberAddress": "Member Address", "maxNumberOfConcurrentBuildJobs": "Max # of concurrent build jobs", "numberOfCurrentBuildJobs": "# of current build jobs", "runningBuildJobs": "Running build jobs", diff --git a/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java index b4012d1f7a6f..91158a46ec83 100644 --- a/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java @@ -92,7 +92,7 @@ void testPullDockerImage() { doReturn(inspectImageCmd).when(dockerClient).inspectImageCmd(anyString()); doThrow(new NotFoundException("")).when(inspectImageCmd).exec(); BuildConfig buildConfig = new BuildConfig("echo 'test'", "test-image-name", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); - var build = new BuildJobQueueItem("1", "job1", "address1", 1, 1, 1, 1, 1, BuildStatus.SUCCESSFUL, null, null, buildConfig, null); + var build = new BuildJobQueueItem("1", "job1", "buildagent1", "address1", 1, 1, 1, 1, 1, BuildStatus.SUCCESSFUL, null, null, buildConfig, null); // Pull image try { buildAgentDockerService.pullDockerImage(build, new BuildLogsMap()); diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java index b2d73eb14e5e..b1bbdc1dae1f 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java @@ -97,19 +97,19 @@ void createJobs() { BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); - job1 = new BuildJobQueueItem("1", "job1", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); - job2 = new BuildJobQueueItem("2", "job2", "address1", 2, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo2, buildConfig, null); + job1 = new BuildJobQueueItem("1", "job1", "buildagent1", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); + job2 = new BuildJobQueueItem("2", "job2", "buildagent1", "address1", 2, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo2, buildConfig, null); String memberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); agent1 = new BuildAgentInformation("build-agent", memberAddress, 1, 0, new ArrayList<>(List.of(job1)), BuildAgentInformation.BuildAgentStatus.IDLE, new ArrayList<>(List.of(job2)), null); - BuildJobQueueItem finishedJobQueueItem1 = new BuildJobQueueItem("3", "job3", "address1", 3, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, - buildConfig, null); - BuildJobQueueItem finishedJobQueueItem2 = new BuildJobQueueItem("4", "job4", "address1", 4, course.getId() + 1, 1, 1, 1, BuildStatus.FAILED, repositoryInfo, jobTimingInfo2, - buildConfig, null); - BuildJobQueueItem finishedJobQueueItem3 = new BuildJobQueueItem("5", "job5", "address1", 5, course.getId() + 2, 1, 1, 1, BuildStatus.FAILED, repositoryInfo, jobTimingInfo3, - buildConfig, null); - BuildJobQueueItem finishedJobQueueItemForLogs = new BuildJobQueueItem("6", "job5", "address1", 5, course.getId(), programmingExercise.getId(), 1, 1, BuildStatus.FAILED, - repositoryInfo, jobTimingInfo3, buildConfig, null); + BuildJobQueueItem finishedJobQueueItem1 = new BuildJobQueueItem("3", "job3", "buildagent1", "address1", 3, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, + jobTimingInfo1, buildConfig, null); + BuildJobQueueItem finishedJobQueueItem2 = new BuildJobQueueItem("4", "job4", "buildagent1", "address1", 4, course.getId() + 1, 1, 1, 1, BuildStatus.FAILED, repositoryInfo, + jobTimingInfo2, buildConfig, null); + BuildJobQueueItem finishedJobQueueItem3 = new BuildJobQueueItem("5", "job5", "buildagent1", "address1", 5, course.getId() + 2, 1, 1, 1, BuildStatus.FAILED, repositoryInfo, + jobTimingInfo3, buildConfig, null); + BuildJobQueueItem finishedJobQueueItemForLogs = new BuildJobQueueItem("6", "job5", "buildagent1", "address1", 5, course.getId(), programmingExercise.getId(), 1, 1, + BuildStatus.FAILED, repositoryInfo, jobTimingInfo3, buildConfig, null); var result1 = new Result().successful(true).rated(true).score(100D).assessmentType(AssessmentType.AUTOMATIC).completionDate(ZonedDateTime.now()); var result2 = new Result().successful(false).rated(true).score(0D).assessmentType(AssessmentType.AUTOMATIC).completionDate(ZonedDateTime.now()); var result3 = new Result().successful(false).rated(true).score(0D).assessmentType(AssessmentType.AUTOMATIC).completionDate(ZonedDateTime.now()); @@ -289,7 +289,8 @@ void testGetFinishedBuildJobs_returnsFilteredJobs() throws Exception { ZonedDateTime.now().plusDays(1).plusMinutes(10)); BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); - var failedJob1 = new BuildJobQueueItem("5", "job5", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.FAILED, repositoryInfo, jobTimingInfo, buildConfig, null); + var failedJob1 = new BuildJobQueueItem("5", "job5", "buildagent1", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.FAILED, repositoryInfo, jobTimingInfo, buildConfig, + null); var jobResult = new Result().successful(false).rated(true).score(0D).assessmentType(AssessmentType.AUTOMATIC).completionDate(ZonedDateTime.now()); var failedFinishedJob = new BuildJob(failedJob1, BuildStatus.FAILED, jobResult); diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java index b935eb8d2d67..d8a009ebca42 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java @@ -104,9 +104,9 @@ void testReturnCorrectBuildStatus() { BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); - BuildJobQueueItem job1 = new BuildJobQueueItem("1", "job1", "address1", participation.getId(), course.getId(), 1, 1, 1, + BuildJobQueueItem job1 = new BuildJobQueueItem("1", "job1", "buildagent1", "address1", participation.getId(), course.getId(), 1, 1, 1, de.tum.cit.aet.artemis.programming.domain.build.BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo, buildConfig, null); - BuildJobQueueItem job2 = new BuildJobQueueItem("2", "job2", "address1", participation.getId(), course.getId(), 1, 1, 1, + BuildJobQueueItem job2 = new BuildJobQueueItem("2", "job2", "buildagent1", "address1", participation.getId(), course.getId(), 1, 1, 1, de.tum.cit.aet.artemis.programming.domain.build.BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo, buildConfig, null); queuedJobs = hazelcastInstance.getQueue("buildJobQueue"); From df34feed3b6befa0c550ea4bde3c0b4babb40cd3 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sat, 19 Oct 2024 21:43:24 +0200 Subject: [PATCH 03/22] fix tests --- .../aet/artemis/programming/icl/LocalCIIntegrationTest.java | 6 +++--- src/test/resources/config/application.yml | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIIntegrationTest.java index 4563d7c9f95c..4f0b7ee31f20 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIIntegrationTest.java @@ -515,8 +515,8 @@ void testCustomCheckoutPaths() { @Test @WithMockUser(username = TEST_PREFIX + "student1", roles = "USER") void testPauseAndResumeBuildAgent() { - String memberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); - hazelcastInstance.getTopic("pauseBuildAgentTopic").publish(memberAddress); + String buildAgentName = "artemis-build-agent-test"; + hazelcastInstance.getTopic("pauseBuildAgentTopic").publish(buildAgentName); ProgrammingExerciseStudentParticipation studentParticipation = localVCLocalCITestService.createParticipation(programmingExercise, student1Login); @@ -529,7 +529,7 @@ void testPauseAndResumeBuildAgent() { return buildJobQueueItem != null && buildJobQueueItem.buildConfig().commitHashToBuild().equals(commitHash) && !buildJobMap.containsKey(buildJobQueueItem.id()); }); - hazelcastInstance.getTopic("resumeBuildAgentTopic").publish(memberAddress); + hazelcastInstance.getTopic("resumeBuildAgentTopic").publish(buildAgentName); localVCLocalCITestService.testLatestSubmission(studentParticipation.getId(), commitHash, 1, false); } } diff --git a/src/test/resources/config/application.yml b/src/test/resources/config/application.yml index 16c56a619dd9..ff0163e0a7ef 100644 --- a/src/test/resources/config/application.yml +++ b/src/test/resources/config/application.yml @@ -74,6 +74,8 @@ artemis: default: "~~invalid~~" c_plus_plus: default: "~~invalid~~" + build-agent: + short-name: "artemis-build-agent-test" spring: application: From 897e5a6e7910e71db7e03b6dc0850701af1cce78 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sat, 19 Oct 2024 21:47:35 +0200 Subject: [PATCH 04/22] remove code --- .../build-agent-summary/build-agent-summary.component.html | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html index 7dddcf193bc7..08879c33b5a5 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html +++ b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html @@ -40,11 +40,6 @@

- - - - - From 5b778fc3da13e28939faf1ab5483f1f8241ddd53 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sat, 19 Oct 2024 21:52:30 +0200 Subject: [PATCH 05/22] remove useless code --- .../webapp/app/localci/build-queue/build-queue.component.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/webapp/app/localci/build-queue/build-queue.component.ts b/src/main/webapp/app/localci/build-queue/build-queue.component.ts index 0215d9153aef..79ca4931786c 100644 --- a/src/main/webapp/app/localci/build-queue/build-queue.component.ts +++ b/src/main/webapp/app/localci/build-queue/build-queue.component.ts @@ -232,11 +232,9 @@ export class BuildQueueComponent implements OnInit, OnDestroy { this.websocketService.subscribe(`/topic/admin/queued-jobs`); this.websocketService.subscribe(`/topic/admin/running-jobs`); this.websocketService.receive(`/topic/admin/queued-jobs`).subscribe((queuedBuildJobs) => { - console.log('queuedBuildJobs', queuedBuildJobs); this.queuedBuildJobs = queuedBuildJobs; }); this.websocketService.receive(`/topic/admin/running-jobs`).subscribe((runningBuildJobs) => { - console.log('runningBuildJobs', runningBuildJobs); this.runningBuildJobs = this.updateBuildJobDuration(runningBuildJobs); }); } From 7623686d041f3a252d532e6b5c619152f5c2db6c Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sat, 19 Oct 2024 22:49:50 +0200 Subject: [PATCH 06/22] fix tests --- .../buildagent/service/SharedQueueProcessingService.java | 2 -- .../programming/icl/LocalCIResourceIntegrationTest.java | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java index e62b4a325c8d..0be2f26872dd 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java @@ -201,8 +201,6 @@ public void updateBuildAgentInformation() { log.debug("There are only lite member in the cluster. Not updating build agent information."); return; } - // Print buildAgentInformation for debugging - log.debug("Build agent information: {}", buildAgentInformation.values()); // Remove build agent information of offline nodes removeOfflineNodes(); diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java index b1bbdc1dae1f..2fe55544f0c4 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java @@ -100,7 +100,7 @@ void createJobs() { job1 = new BuildJobQueueItem("1", "job1", "buildagent1", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); job2 = new BuildJobQueueItem("2", "job2", "buildagent1", "address1", 2, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo2, buildConfig, null); String memberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); - agent1 = new BuildAgentInformation("build-agent", memberAddress, 1, 0, new ArrayList<>(List.of(job1)), BuildAgentInformation.BuildAgentStatus.IDLE, + agent1 = new BuildAgentInformation("artemis-build-agent-test", memberAddress, 1, 0, new ArrayList<>(List.of(job1)), BuildAgentInformation.BuildAgentStatus.IDLE, new ArrayList<>(List.of(job2)), null); BuildJobQueueItem finishedJobQueueItem1 = new BuildJobQueueItem("3", "job3", "buildagent1", "address1", 3, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); @@ -370,9 +370,9 @@ void testGetBuildJobStatistics() throws Exception { @WithMockUser(username = TEST_PREFIX + "admin", roles = "ADMIN") void testPauseBuildAgent() throws Exception { request.put("/api/admin/agent/" + URLEncoder.encode(agent1.name(), StandardCharsets.UTF_8) + "/pause", null, HttpStatus.NO_CONTENT); - await().until(() -> buildAgentInformation.get(agent1.name()).status() == BuildAgentInformation.BuildAgentStatus.PAUSED); + await().until(() -> buildAgentInformation.get(agent1.memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.PAUSED); request.put("/api/admin/agent/" + URLEncoder.encode(agent1.name(), StandardCharsets.UTF_8) + "/resume", null, HttpStatus.NO_CONTENT); - await().until(() -> buildAgentInformation.get(agent1.name()).status() == BuildAgentInformation.BuildAgentStatus.IDLE); + await().until(() -> buildAgentInformation.get(agent1.memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.IDLE); } } From 34d69db0416f3f06145d97b4e44be7c668bedc08 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sat, 19 Oct 2024 23:07:11 +0200 Subject: [PATCH 07/22] change grace period to 60 seconds --- .../buildagent/service/SharedQueueProcessingService.java | 2 +- src/main/resources/config/application-buildagent.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java index 0be2f26872dd..0305c666b209 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java @@ -114,7 +114,7 @@ public class SharedQueueProcessingService { */ private final AtomicBoolean processResults = new AtomicBoolean(true); - @Value("${artemis.continuous-integration.pause-grace-period-seconds:15}") + @Value("${artemis.continuous-integration.pause-grace-period-seconds:60}") private int pauseGracePeriodSeconds; @Value("${artemis.continuous-integration.build-agent.short-name}") diff --git a/src/main/resources/config/application-buildagent.yml b/src/main/resources/config/application-buildagent.yml index 1439567b2cc9..fc3e4847f25e 100644 --- a/src/main/resources/config/application-buildagent.yml +++ b/src/main/resources/config/application-buildagent.yml @@ -33,6 +33,7 @@ artemis: container-cleanup: expiry-minutes: 5 cleanup-schedule-minutes: 60 + pause-grace-period-seconds: 60 git: name: Artemis email: artemis@xcit.tum.de From a7b4188f5c157a6e7d1d67bcee8eb9a31936f69f Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sun, 20 Oct 2024 10:43:48 +0200 Subject: [PATCH 08/22] add docs --- docs/admin/setup/distributed.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/admin/setup/distributed.rst b/docs/admin/setup/distributed.rst index 1fa74024dc2d..65be6918a232 100644 --- a/docs/admin/setup/distributed.rst +++ b/docs/admin/setup/distributed.rst @@ -617,8 +617,12 @@ These credentials are used to clone repositories via HTTPS. You must also add th container-cleanup: expiry-minutes: 5 # Time after a hanging container will automatically be removed cleanup-schedule-minutes: 60 # Schedule for container cleanup + build-agent: + short-name: "artemis-build-agent-X" # Short name of the build agent. This should be unique for each build agent. Only lowercase letters, numbers and hyphens are allowed. +Please note that ``artemis.build-agent.short-name`` must be provided. Otherwise, the build agent will not start. + Build agents run as `Hazelcast Lite Members `__ and require a full member, in our case a core node, to be running. Thus, before starting a build agent make sure that at least the primary node is running. You can then add and remove build agents to the cluster as desired. From b9cce768784e5f025a26bd1cd9f1f851cc4b0563 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sun, 20 Oct 2024 11:18:07 +0200 Subject: [PATCH 09/22] fix docs --- docs/admin/setup/distributed.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/admin/setup/distributed.rst b/docs/admin/setup/distributed.rst index 65be6918a232..7b925af0f35b 100644 --- a/docs/admin/setup/distributed.rst +++ b/docs/admin/setup/distributed.rst @@ -621,7 +621,7 @@ These credentials are used to clone repositories via HTTPS. You must also add th short-name: "artemis-build-agent-X" # Short name of the build agent. This should be unique for each build agent. Only lowercase letters, numbers and hyphens are allowed. -Please note that ``artemis.build-agent.short-name`` must be provided. Otherwise, the build agent will not start. +Please note that ``artemis.continuous-integration.build-agent.short-name`` must be provided. Otherwise, the build agent will not start. Build agents run as `Hazelcast Lite Members `__ and require a full member, in our case a core node, to be running. Thus, before starting a build agent make sure that at least the primary node is running. You can then add and remove build agents to the cluster as desired. From ae63dcf4a8520a54d10349a0fc89d802f6cd77c5 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Mon, 21 Oct 2024 17:20:33 +0200 Subject: [PATCH 10/22] server --- .../buildagent/dto/BuildAgentInformation.java | 12 ++++++--- .../service/SharedQueueProcessingService.java | 13 +++++++--- .../web/admin/AdminBuildJobQueueResource.java | 4 +-- .../localci/LocalCIQueueWebsocketService.java | 8 +++--- .../LocalCIWebsocketMessagingService.java | 2 +- .../localci/SharedQueueManagementService.java | 2 +- .../icl/LocalCIResourceIntegrationTest.java | 25 ++++++++++++------- 7 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java index 8e477f79bd5e..9a8321857169 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java @@ -11,7 +11,7 @@ // in the future are migrated or cleared. Changes should be communicated in release notes as potentially breaking changes. @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_EMPTY) -public record BuildAgentInformation(String name, String memberAddress, int maxNumberOfConcurrentBuildJobs, int numberOfCurrentBuildJobs, List runningBuildJobs, +public record BuildAgentInformation(BuildAgent buildAgent, int maxNumberOfConcurrentBuildJobs, int numberOfCurrentBuildJobs, List runningBuildJobs, BuildAgentStatus status, List recentBuildJobs, String publicSshKey) implements Serializable { @Serial @@ -24,11 +24,17 @@ public record BuildAgentInformation(String name, String memberAddress, int maxNu * @param recentBuildJobs The list of recent build jobs */ public BuildAgentInformation(BuildAgentInformation agentInformation, List recentBuildJobs) { - this(agentInformation.name(), agentInformation.memberAddress(), agentInformation.maxNumberOfConcurrentBuildJobs(), agentInformation.numberOfCurrentBuildJobs(), - agentInformation.runningBuildJobs, agentInformation.status(), recentBuildJobs, agentInformation.publicSshKey()); + this(agentInformation.buildAgent(), agentInformation.maxNumberOfConcurrentBuildJobs(), agentInformation.numberOfCurrentBuildJobs(), agentInformation.runningBuildJobs, + agentInformation.status(), recentBuildJobs, agentInformation.publicSshKey()); } public enum BuildAgentStatus { ACTIVE, IDLE, PAUSED } + + public record BuildAgent(String name, String memberAddress, String displayName) implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + } } diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java index 0305c666b209..7481502a4392 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java @@ -44,6 +44,7 @@ import com.hazelcast.topic.ITopic; import de.tum.cit.aet.artemis.buildagent.dto.BuildAgentInformation; +import de.tum.cit.aet.artemis.buildagent.dto.BuildAgentInformation.BuildAgent; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; import de.tum.cit.aet.artemis.buildagent.dto.BuildResult; import de.tum.cit.aet.artemis.buildagent.dto.JobTimingInfo; @@ -120,6 +121,9 @@ public class SharedQueueProcessingService { @Value("${artemis.continuous-integration.build-agent.short-name}") private String buildAgentShortName; + @Value("${artemis.continuous-integration.build-agent.display-name:}") + private String buildAgentDisplayName; + public SharedQueueProcessingService(@Qualifier("hazelcastInstance") HazelcastInstance hazelcastInstance, ExecutorService localCIBuildExecutorService, BuildJobManagementService buildJobManagementService, BuildLogsMap buildLogsMap, BuildAgentSshKeyService buildAgentSSHKeyService, TaskScheduler taskScheduler) { this.hazelcastInstance = hazelcastInstance; @@ -298,10 +302,10 @@ private void updateLocalBuildAgentInformationWithRecentJob(BuildJobQueueItem rec // Add/update BuildAgentInformation info = getUpdatedLocalBuildAgentInformation(recentBuildJob); try { - buildAgentInformation.put(info.memberAddress(), info); + buildAgentInformation.put(info.buildAgent().memberAddress(), info); } catch (Exception e) { - log.error("Error while updating build agent information for agent {} with address {}", info.name(), info.memberAddress(), e); + log.error("Error while updating build agent information for agent {} with address {}", info.buildAgent().name(), info.buildAgent().memberAddress(), e); } } finally { @@ -335,8 +339,9 @@ private BuildAgentInformation getUpdatedLocalBuildAgentInformation(BuildJobQueue String publicSshKey = buildAgentSSHKeyService.getPublicKeyAsString(); - return new BuildAgentInformation(buildAgentShortName, memberAddress, maxNumberOfConcurrentBuilds, numberOfCurrentBuildJobs, processingJobsOfMember, status, recentBuildJobs, - publicSshKey); + BuildAgent agentInfo = new BuildAgent(buildAgentShortName, memberAddress, buildAgentDisplayName); + + return new BuildAgentInformation(agentInfo, maxNumberOfConcurrentBuilds, numberOfCurrentBuildJobs, processingJobsOfMember, status, recentBuildJobs, publicSshKey); } private List getProcessingJobsOfNode(String memberAddress) { diff --git a/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java b/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java index 33e7bd099155..19075018440a 100644 --- a/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java +++ b/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java @@ -95,8 +95,8 @@ public ResponseEntity> getBuildAgentSummary() { @GetMapping("build-agent") public ResponseEntity getBuildAgentDetails(@RequestParam String agentName) { log.debug("REST request to get information on build agent {}", agentName); - BuildAgentInformation buildAgentDetails = localCIBuildJobQueueService.getBuildAgentInformation().stream().filter(agent -> agent.name().equals(agentName)).findFirst() - .orElse(null); + BuildAgentInformation buildAgentDetails = localCIBuildJobQueueService.getBuildAgentInformation().stream().filter(agent -> agent.buildAgent().name().equals(agentName)) + .findFirst().orElse(null); return ResponseEntity.ok(buildAgentDetails); } diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIQueueWebsocketService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIQueueWebsocketService.java index bfd04f5ba49d..5a805ff54d03 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIQueueWebsocketService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIQueueWebsocketService.java @@ -84,7 +84,7 @@ private void sendBuildAgentSummaryOverWebsocket() { } private void sendBuildAgentDetailsOverWebsocket(String agentName) { - sharedQueueManagementService.getBuildAgentInformation().stream().filter(agent -> agent.name().equals(agentName)).findFirst() + sharedQueueManagementService.getBuildAgentInformation().stream().filter(agent -> agent.buildAgent().name().equals(agentName)).findFirst() .ifPresent(localCIWebsocketMessagingService::sendBuildAgentDetails); } @@ -127,19 +127,19 @@ private class BuildAgentListener @Override public void entryAdded(com.hazelcast.core.EntryEvent event) { log.debug("Build agent added: {}", event.getValue()); - sendBuildAgentInformationOverWebsocket(event.getValue().name()); + sendBuildAgentInformationOverWebsocket(event.getValue().buildAgent().name()); } @Override public void entryRemoved(com.hazelcast.core.EntryEvent event) { log.debug("Build agent removed: {}", event.getOldValue()); - sendBuildAgentInformationOverWebsocket(event.getOldValue().name()); + sendBuildAgentInformationOverWebsocket(event.getOldValue().buildAgent().name()); } @Override public void entryUpdated(com.hazelcast.core.EntryEvent event) { log.debug("Build agent updated: {}", event.getValue()); - sendBuildAgentInformationOverWebsocket(event.getValue().name()); + sendBuildAgentInformationOverWebsocket(event.getValue().buildAgent().name()); } } } diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIWebsocketMessagingService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIWebsocketMessagingService.java index 7c527a155b49..e27ec440d5aa 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIWebsocketMessagingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIWebsocketMessagingService.java @@ -100,7 +100,7 @@ public void sendBuildAgentSummary(List buildAgentInfo) { } public void sendBuildAgentDetails(BuildAgentInformation buildAgentDetails) { - String channel = "/topic/admin/build-agent/" + buildAgentDetails.name(); + String channel = "/topic/admin/build-agent/" + buildAgentDetails.buildAgent().name(); log.debug("Sending message on topic {}: {}", channel, buildAgentDetails); websocketMessagingService.sendMessage(channel, buildAgentDetails); } diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java index 7797965deaa6..7a15c9e46e92 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java @@ -137,7 +137,7 @@ public List getBuildAgentInformation() { } public List getBuildAgentInformationWithoutRecentBuildJobs() { - return buildAgentInformation.values().stream().map(agent -> new BuildAgentInformation(agent.name(), agent.memberAddress(), agent.maxNumberOfConcurrentBuildJobs(), + return buildAgentInformation.values().stream().map(agent -> new BuildAgentInformation(agent.buildAgent(), agent.maxNumberOfConcurrentBuildJobs(), agent.numberOfCurrentBuildJobs(), agent.runningBuildJobs(), agent.status(), null, null)).toList(); } diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java index 2fe55544f0c4..e1dcd4556702 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.util.LinkedMultiValueMap; @@ -85,6 +86,12 @@ protected String getTestPrefix() { return TEST_PREFIX; } + @Value("${artemis.continuous-integration.build-agent.short-name}") + private String buildAgentShortName; + + @Value("${artemis.continuous-integration.build-agent.display-name:}") + private String buildAgentDisplayName; + @BeforeEach void createJobs() { // temporarily remove listener to avoid triggering build job processing @@ -100,8 +107,8 @@ void createJobs() { job1 = new BuildJobQueueItem("1", "job1", "buildagent1", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); job2 = new BuildJobQueueItem("2", "job2", "buildagent1", "address1", 2, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo2, buildConfig, null); String memberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); - agent1 = new BuildAgentInformation("artemis-build-agent-test", memberAddress, 1, 0, new ArrayList<>(List.of(job1)), BuildAgentInformation.BuildAgentStatus.IDLE, - new ArrayList<>(List.of(job2)), null); + BuildAgentInformation.BuildAgent buildAgent = new BuildAgentInformation.BuildAgent(buildAgentShortName, memberAddress, buildAgentDisplayName); + agent1 = new BuildAgentInformation(buildAgent, 1, 0, new ArrayList<>(List.of(job1)), BuildAgentInformation.BuildAgentStatus.IDLE, new ArrayList<>(List.of(job2)), null); BuildJobQueueItem finishedJobQueueItem1 = new BuildJobQueueItem("3", "job3", "buildagent1", "address1", 3, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); BuildJobQueueItem finishedJobQueueItem2 = new BuildJobQueueItem("4", "job4", "buildagent1", "address1", 4, course.getId() + 1, 1, 1, 1, BuildStatus.FAILED, repositoryInfo, @@ -206,8 +213,8 @@ void testGetBuildAgents_returnsAgents() throws Exception { @Test @WithMockUser(username = TEST_PREFIX + "admin", roles = "ADMIN") void testGetBuildAgentDetails_returnsAgent() throws Exception { - var retrievedAgent = request.get("/api/admin/build-agent?agentName=" + agent1.name(), HttpStatus.OK, BuildAgentInformation.class); - assertThat(retrievedAgent.name()).isEqualTo(agent1.name()); + var retrievedAgent = request.get("/api/admin/build-agent?agentName=" + agent1.buildAgent().name(), HttpStatus.OK, BuildAgentInformation.class); + assertThat(retrievedAgent.buildAgent().name()).isEqualTo(agent1.buildAgent().name()); } @Test @@ -260,7 +267,7 @@ void testCancelAllRunningBuildJobsForCourse() throws Exception { @Test @WithMockUser(username = TEST_PREFIX + "admin", roles = "ADMIN") void testCancelAllRunningBuildJobsForAgent() throws Exception { - request.delete("/api/admin/cancel-all-running-jobs-for-agent?agentName=" + agent1.name(), HttpStatus.NO_CONTENT); + request.delete("/api/admin/cancel-all-running-jobs-for-agent?agentName=" + agent1.buildAgent().name(), HttpStatus.NO_CONTENT); } @Test @@ -369,10 +376,10 @@ void testGetBuildJobStatistics() throws Exception { @Test @WithMockUser(username = TEST_PREFIX + "admin", roles = "ADMIN") void testPauseBuildAgent() throws Exception { - request.put("/api/admin/agent/" + URLEncoder.encode(agent1.name(), StandardCharsets.UTF_8) + "/pause", null, HttpStatus.NO_CONTENT); - await().until(() -> buildAgentInformation.get(agent1.memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.PAUSED); + request.put("/api/admin/agent/" + URLEncoder.encode(agent1.buildAgent().name(), StandardCharsets.UTF_8) + "/pause", null, HttpStatus.NO_CONTENT); + await().until(() -> buildAgentInformation.get(agent1.buildAgent().memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.PAUSED); - request.put("/api/admin/agent/" + URLEncoder.encode(agent1.name(), StandardCharsets.UTF_8) + "/resume", null, HttpStatus.NO_CONTENT); - await().until(() -> buildAgentInformation.get(agent1.memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.IDLE); + request.put("/api/admin/agent/" + URLEncoder.encode(agent1.buildAgent().name(), StandardCharsets.UTF_8) + "/resume", null, HttpStatus.NO_CONTENT); + await().until(() -> buildAgentInformation.get(agent1.buildAgent().memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.IDLE); } } From 5b7b32aafc8e6ba374a26e8aaee54cc52376843e Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Mon, 21 Oct 2024 17:48:38 +0200 Subject: [PATCH 11/22] client --- .../entities/programming/build-agent.model.ts | 9 +++++++-- .../build-agent-details.component.html | 5 +++-- .../build-agent-details.component.ts | 18 +++++++++--------- .../build-agent-summary.component.html | 12 ++++++------ .../build-agent-summary.component.ts | 12 ++++++------ .../build-agents/build-agents.service.ts | 10 +++++----- .../build-agent-details.component.spec.ts | 18 +++++++++--------- .../build-agent-summary.component.spec.ts | 12 ++++++------ .../build-agents/build-agents.service.spec.ts | 8 ++++---- 9 files changed, 55 insertions(+), 49 deletions(-) diff --git a/src/main/webapp/app/entities/programming/build-agent.model.ts b/src/main/webapp/app/entities/programming/build-agent.model.ts index 8817ba7ad92d..2532e0bc1eb8 100644 --- a/src/main/webapp/app/entities/programming/build-agent.model.ts +++ b/src/main/webapp/app/entities/programming/build-agent.model.ts @@ -7,10 +7,15 @@ export enum BuildAgentStatus { IDLE = 'IDLE', } -export class BuildAgent implements BaseEntity { - public id?: number; +export class BuildAgent { public name?: string; public memberAddress?: string; + public displayName?: string; +} + +export class BuildAgentInformation implements BaseEntity { + public id?: number; + public buildAgent?: BuildAgent; public maxNumberOfConcurrentBuildJobs?: number; public numberOfCurrentBuildJobs?: number; public runningBuildJobs?: BuildJob[]; diff --git a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html index 0ae374945a5d..735533885348 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html +++ b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html @@ -6,9 +6,10 @@

: -

{{ buildAgent.name }}

+

{{ buildAgent.buildAgent?.displayName }}

- {{ buildAgent.memberAddress }} + {{ buildAgent.buildAgent?.name }} + {{ buildAgent.buildAgent?.memberAddress }}

@if (buildAgent.status === 'PAUSED') { diff --git a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts index de19544b01ad..e917cb1f5305 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts +++ b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts @@ -1,5 +1,5 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { BuildAgent } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation } from 'app/entities/programming/build-agent.model'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; import { Subscription } from 'rxjs'; import { faCircleCheck, faExclamationCircle, faExclamationTriangle, faPause, faPlay, faTimes } from '@fortawesome/free-solid-svg-icons'; @@ -17,7 +17,7 @@ import { AlertService, AlertType } from 'app/core/util/alert.service'; }) export class BuildAgentDetailsComponent implements OnInit, OnDestroy { protected readonly TriggeredByPushTo = TriggeredByPushTo; - buildAgent: BuildAgent; + buildAgent: BuildAgentInformation; agentName: string; websocketSubscription: Subscription; restSubscription: Subscription; @@ -77,7 +77,7 @@ export class BuildAgentDetailsComponent implements OnInit, OnDestroy { }); } - private updateBuildAgent(buildAgent: BuildAgent) { + private updateBuildAgent(buildAgent: BuildAgentInformation) { this.buildAgent = buildAgent; this.setRecentBuildJobsDuration(); } @@ -100,8 +100,8 @@ export class BuildAgentDetailsComponent implements OnInit, OnDestroy { } cancelAllBuildJobs() { - if (this.buildAgent.name) { - this.buildQueueService.cancelAllRunningBuildJobsForAgent(this.buildAgent.name).subscribe(); + if (this.buildAgent.buildAgent?.name) { + this.buildQueueService.cancelAllRunningBuildJobsForAgent(this.buildAgent.buildAgent?.name).subscribe(); } } @@ -111,8 +111,8 @@ export class BuildAgentDetailsComponent implements OnInit, OnDestroy { } pauseBuildAgent(): void { - if (this.buildAgent.name) { - this.buildAgentsService.pauseBuildAgent(this.buildAgent.name).subscribe({ + if (this.buildAgent.buildAgent?.name) { + this.buildAgentsService.pauseBuildAgent(this.buildAgent.buildAgent.name).subscribe({ next: () => { this.alertService.addAlert({ type: AlertType.SUCCESS, @@ -135,8 +135,8 @@ export class BuildAgentDetailsComponent implements OnInit, OnDestroy { } resumeBuildAgent(): void { - if (this.buildAgent.name) { - this.buildAgentsService.resumeBuildAgent(this.buildAgent.name).subscribe({ + if (this.buildAgent.buildAgent?.name) { + this.buildAgentsService.resumeBuildAgent(this.buildAgent.buildAgent.name).subscribe({ next: () => { this.alertService.addAlert({ type: AlertType.SUCCESS, diff --git a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html index 08879c33b5a5..54ca48a8bc25 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html +++ b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html @@ -20,20 +20,20 @@

- + - + - - + + {{ value }} - + @@ -83,7 +83,7 @@

{{ value }} @if (value > 0) { - diff --git a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts index b7f232bf0fc4..1441ced29ad9 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts +++ b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts @@ -1,5 +1,5 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { BuildAgent } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation } from 'app/entities/programming/build-agent.model'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; import { Subscription } from 'rxjs'; @@ -13,7 +13,7 @@ import { Router } from '@angular/router'; styleUrl: './build-agent-summary.component.scss', }) export class BuildAgentSummaryComponent implements OnInit, OnDestroy { - buildAgents: BuildAgent[] = []; + buildAgents: BuildAgentInformation[] = []; buildCapacity = 0; currentBuilds = 0; channel: string = '/topic/admin/build-agents'; @@ -56,7 +56,7 @@ export class BuildAgentSummaryComponent implements OnInit, OnDestroy { }); } - private updateBuildAgents(buildAgents: BuildAgent[]) { + private updateBuildAgents(buildAgents: BuildAgentInformation[]) { this.buildAgents = buildAgents; this.buildCapacity = this.buildAgents.reduce((sum, agent) => sum + (agent.maxNumberOfConcurrentBuildJobs || 0), 0); this.currentBuilds = this.buildAgents.reduce((sum, agent) => sum + (agent.numberOfCurrentBuildJobs || 0), 0); @@ -76,9 +76,9 @@ export class BuildAgentSummaryComponent implements OnInit, OnDestroy { } cancelAllBuildJobs(buildAgentName: string) { - const buildAgent = this.buildAgents.find((agent) => agent.name === buildAgentName); - if (buildAgent && buildAgent.name) { - this.buildQueueService.cancelAllRunningBuildJobsForAgent(buildAgent.name).subscribe(); + const buildAgent = this.buildAgents.find((agent) => agent.buildAgent?.name === buildAgentName); + if (buildAgent && buildAgent.buildAgent?.name) { + this.buildQueueService.cancelAllRunningBuildJobsForAgent(buildAgent.buildAgent?.name).subscribe(); } } } diff --git a/src/main/webapp/app/localci/build-agents/build-agents.service.ts b/src/main/webapp/app/localci/build-agents/build-agents.service.ts index b701b85fe5d0..a4a823970ca2 100644 --- a/src/main/webapp/app/localci/build-agents/build-agents.service.ts +++ b/src/main/webapp/app/localci/build-agents/build-agents.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; -import { BuildAgent } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation } from 'app/entities/programming/build-agent.model'; import { catchError } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) @@ -13,15 +13,15 @@ export class BuildAgentsService { /** * Get all build agents */ - getBuildAgentSummary(): Observable { - return this.http.get(`${this.adminResourceUrl}/build-agents`); + getBuildAgentSummary(): Observable { + return this.http.get(`${this.adminResourceUrl}/build-agents`); } /** * Get build agent details */ - getBuildAgentDetails(agentName: string): Observable { - return this.http.get(`${this.adminResourceUrl}/build-agent`, { params: { agentName } }).pipe( + getBuildAgentDetails(agentName: string): Observable { + return this.http.get(`${this.adminResourceUrl}/build-agent`, { params: { agentName } }).pipe( catchError((err) => { return throwError(() => new Error(`Failed to fetch build agent details ${agentName}\n${err.message}`)); }), diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts index 2db5c31ac80b..84284cb20de9 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts @@ -9,7 +9,7 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { DataTableComponent } from 'app/shared/data-table/data-table.component'; import { MockComponent, MockPipe, MockProvider } from 'ng-mocks'; import { NgxDatatableModule } from '@siemens/ngx-datatable'; -import { BuildAgent, BuildAgentStatus } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation, BuildAgentStatus } from 'app/entities/programming/build-agent.model'; import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; import { BuildConfig } from 'app/entities/programming/build-config.model'; @@ -110,9 +110,9 @@ describe('BuildAgentDetailsComponent', () => { }, ]; - const mockBuildAgent: BuildAgent = { + const mockBuildAgent: BuildAgentInformation = { id: 1, - name: 'buildagent1', + buildAgent: { name: 'agent1', memberAddress: 'localhost:8080', displayName: 'Agent 1' }, maxNumberOfConcurrentBuildJobs: 2, numberOfCurrentBuildJobs: 2, runningBuildJobs: mockRunningJobs1, @@ -139,7 +139,7 @@ describe('BuildAgentDetailsComponent', () => { fixture = TestBed.createComponent(BuildAgentDetailsComponent); component = fixture.componentInstance; activatedRoute = fixture.debugElement.injector.get(ActivatedRoute) as MockActivatedRoute; - activatedRoute.setParameters({ agentName: mockBuildAgent.name }); + activatedRoute.setParameters({ agentName: mockBuildAgent.buildAgent?.name }); alertService = TestBed.inject(AlertService); alertServiceAddAlertStub = jest.spyOn(alertService, 'addAlert'); })); @@ -164,8 +164,8 @@ describe('BuildAgentDetailsComponent', () => { component.ngOnInit(); expect(component.buildAgent).toEqual(mockBuildAgent); - expect(mockWebsocketService.subscribe).toHaveBeenCalledWith('/topic/admin/build-agent/' + component.buildAgent.name); - expect(mockWebsocketService.receive).toHaveBeenCalledWith('/topic/admin/build-agent/' + component.buildAgent.name); + expect(mockWebsocketService.subscribe).toHaveBeenCalledWith('/topic/admin/build-agent/' + component.buildAgent.buildAgent?.name); + expect(mockWebsocketService.receive).toHaveBeenCalledWith('/topic/admin/build-agent/' + component.buildAgent.buildAgent?.name); }); it('should unsubscribe from the websocket channel on destruction', () => { @@ -175,7 +175,7 @@ describe('BuildAgentDetailsComponent', () => { component.ngOnDestroy(); - expect(mockWebsocketService.unsubscribe).toHaveBeenCalledWith('/topic/admin/build-agent/' + component.buildAgent.name); + expect(mockWebsocketService.unsubscribe).toHaveBeenCalledWith('/topic/admin/build-agent/' + component.buildAgent.buildAgent?.name); }); it('should set recent build jobs duration', () => { @@ -213,7 +213,7 @@ describe('BuildAgentDetailsComponent', () => { }); it('should show an alert when pausing build agent without a name', () => { - component.buildAgent = { ...mockBuildAgent, name: '' }; + component.buildAgent = { ...mockBuildAgent, buildAgent: { ...mockBuildAgent.buildAgent, name: '' } }; component.pauseBuildAgent(); expect(alertServiceAddAlertStub).toHaveBeenCalledWith({ @@ -223,7 +223,7 @@ describe('BuildAgentDetailsComponent', () => { }); it('should show an alert when resuming build agent without a name', () => { - component.buildAgent = { ...mockBuildAgent, name: '' }; + component.buildAgent = { ...mockBuildAgent, buildAgent: { ...mockBuildAgent.buildAgent, name: '' } }; component.resumeBuildAgent(); expect(alertServiceAddAlertStub).toHaveBeenCalledWith({ diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts index 9a4e94b1cb7e..9e84fd55b8fa 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts @@ -10,7 +10,7 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { DataTableComponent } from 'app/shared/data-table/data-table.component'; import { MockComponent, MockPipe } from 'ng-mocks'; import { NgxDatatableModule } from '@siemens/ngx-datatable'; -import { BuildAgent, BuildAgentStatus } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation, BuildAgentStatus } from 'app/entities/programming/build-agent.model'; import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; import { BuildConfig } from 'app/entities/programming/build-config.model'; @@ -117,10 +117,10 @@ describe('BuildAgentSummaryComponent', () => { }, ]; - const mockBuildAgents: BuildAgent[] = [ + const mockBuildAgents: BuildAgentInformation[] = [ { id: 1, - name: 'buildagent1', + buildAgent: { name: 'buildagent1', displayName: 'Build Agent 1', memberAddress: 'agent1' }, maxNumberOfConcurrentBuildJobs: 2, numberOfCurrentBuildJobs: 2, runningBuildJobs: mockRunningJobs1, @@ -128,7 +128,7 @@ describe('BuildAgentSummaryComponent', () => { }, { id: 2, - name: 'buildagent2', + buildAgent: { name: 'buildagent2', displayName: 'Build Agent 2', memberAddress: 'agent2' }, maxNumberOfConcurrentBuildJobs: 2, numberOfCurrentBuildJobs: 2, runningBuildJobs: mockRunningJobs2, @@ -196,9 +196,9 @@ describe('BuildAgentSummaryComponent', () => { const spy = jest.spyOn(component, 'cancelAllBuildJobs'); component.ngOnInit(); - component.cancelAllBuildJobs(buildAgent.name!); + component.cancelAllBuildJobs(buildAgent.buildAgent?.name!); - expect(spy).toHaveBeenCalledExactlyOnceWith(buildAgent.name!); + expect(spy).toHaveBeenCalledExactlyOnceWith(buildAgent.buildAgent?.name!); }); it('should calculate the build capacity and current builds', () => { diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts index c73f5d49ee15..b8720ac5c1dc 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts @@ -8,7 +8,7 @@ import { BuildJob } from 'app/entities/programming/build-job.model'; import dayjs from 'dayjs/esm'; import { lastValueFrom } from 'rxjs'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; -import { BuildAgent } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation } from 'app/entities/programming/build-agent.model'; import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; import { BuildConfig } from 'app/entities/programming/build-config.model'; @@ -16,7 +16,7 @@ import { BuildConfig } from 'app/entities/programming/build-config.model'; describe('BuildAgentsService', () => { let service: BuildAgentsService; let httpMock: HttpTestingController; - let element: BuildAgent; + let element: BuildAgentInformation; const repositoryInfo: RepositoryInfo = { repositoryName: 'repo2', @@ -82,9 +82,9 @@ describe('BuildAgentsService', () => { }); service = TestBed.inject(BuildAgentsService); httpMock = TestBed.inject(HttpTestingController); - element = new BuildAgent(); + element = new BuildAgentInformation(); element.id = 1; - element.name = 'BuildAgent1'; + element.buildAgent = { name: 'buildAgent1', memberAddress: 'localhost:8080', displayName: 'Build Agent 1' }; element.maxNumberOfConcurrentBuildJobs = 3; element.numberOfCurrentBuildJobs = 1; element.runningBuildJobs = mockRunningJobs; From e8c1f68581167bdd701746d633a59e89bcbb31bc Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Mon, 21 Oct 2024 18:52:25 +0200 Subject: [PATCH 12/22] fix cancel all --- .../buildagent/service/SharedQueueProcessingService.java | 5 +++++ .../service/localci/SharedQueueManagementService.java | 2 +- src/main/resources/config/application.yml | 1 + .../build-agent-details/build-agent-details.component.html | 3 +-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java index 7481502a4392..26b527770b03 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java @@ -26,6 +26,7 @@ import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; @@ -146,6 +147,10 @@ public void init() { throw new IllegalArgumentException(errorMessage); } + if (StringUtils.isBlank(buildAgentDisplayName)) { + buildAgentDisplayName = buildAgentShortName; + } + this.buildAgentInformation = this.hazelcastInstance.getMap("buildAgentInformation"); this.processingJobs = this.hazelcastInstance.getMap("processingJobs"); this.queue = this.hazelcastInstance.getQueue("buildJobQueue"); diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java index 7a15c9e46e92..3151161055b6 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java @@ -208,7 +208,7 @@ public void cancelAllRunningBuildJobs() { * @param agentName name of the agent */ public void cancelAllRunningBuildJobsForAgent(String agentName) { - processingJobs.values().stream().filter(job -> Objects.equals(job.buildAgentAddress(), agentName)).forEach(job -> cancelBuildJob(job.id())); + processingJobs.values().stream().filter(job -> Objects.equals(job.buildAgentName(), agentName)).forEach(job -> cancelBuildJob(job.id())); } /** diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index ac6ce89e95e3..c9228d9fc46b 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -101,6 +101,7 @@ artemis: build-agent: # Name of the build agent. Only lowercase letters, numbers and hyphens are allowed. ([a-z0-9-]+) short-name: "artemis-build-agent-1" + display-name: "Artemis Build Agent 1" diff --git a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html index 735533885348..ca64b85617f6 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html +++ b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.html @@ -8,8 +8,7 @@

:

{{ buildAgent.buildAgent?.displayName }}

- {{ buildAgent.buildAgent?.name }} - {{ buildAgent.buildAgent?.memberAddress }} + {{ buildAgent.buildAgent?.name }} - {{ buildAgent.buildAgent?.memberAddress }}
@if (buildAgent.status === 'PAUSED') { From af624da630c706ad285be5ba2aa653a51c5d0c87 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Mon, 21 Oct 2024 23:30:13 +0200 Subject: [PATCH 13/22] client fixes --- .../build-agent-summary/build-agent-summary.component.html | 6 +++--- .../build-agent-summary/build-agent-summary.component.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html index 54ca48a8bc25..5e9c3fd22631 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html +++ b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html @@ -22,7 +22,7 @@

- + @@ -35,9 +35,9 @@

- + - + diff --git a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts index 1441ced29ad9..34db9243a3dd 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts +++ b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts @@ -77,7 +77,7 @@ export class BuildAgentSummaryComponent implements OnInit, OnDestroy { cancelAllBuildJobs(buildAgentName: string) { const buildAgent = this.buildAgents.find((agent) => agent.buildAgent?.name === buildAgentName); - if (buildAgent && buildAgent.buildAgent?.name) { + if (buildAgent?.buildAgent?.name) { this.buildQueueService.cancelAllRunningBuildJobsForAgent(buildAgent.buildAgent?.name).subscribe(); } } From d2e212ea3b630a36a402a3857e58a6787caee0a3 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Mon, 21 Oct 2024 23:45:01 +0200 Subject: [PATCH 14/22] server change BuildJobQueueItem --- .../artemis/buildagent/dto/BuildAgent.java | 10 +++++++ .../buildagent/dto/BuildAgentInformation.java | 6 ---- .../buildagent/dto/BuildJobQueueItem.java | 23 +++++++-------- .../service/SharedQueueProcessingService.java | 14 ++++----- .../programming/domain/build/BuildJob.java | 2 +- .../LocalCIResultProcessingService.java | 8 ++--- .../localci/LocalCITriggerService.java | 5 +++- .../localci/SharedQueueManagementService.java | 2 +- .../service/BuildAgentDockerServiceTest.java | 5 +++- .../icl/LocalCIResourceIntegrationTest.java | 29 ++++++++++--------- .../programming/icl/LocalCIServiceTest.java | 8 +++-- 11 files changed, 64 insertions(+), 48 deletions(-) create mode 100644 src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgent.java diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgent.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgent.java new file mode 100644 index 000000000000..a76099810feb --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgent.java @@ -0,0 +1,10 @@ +package de.tum.cit.aet.artemis.buildagent.dto; + +import java.io.Serial; +import java.io.Serializable; + +public record BuildAgent(String name, String memberAddress, String displayName) implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java index 9a8321857169..405f44b6092a 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java @@ -31,10 +31,4 @@ public BuildAgentInformation(BuildAgentInformation agentInformation, List getProcessingJobsOfNode(String memberAddress) { - return processingJobs.values().stream().filter(job -> Objects.equals(job.buildAgentAddress(), memberAddress)).toList(); + return processingJobs.values().stream().filter(job -> Objects.equals(job.buildAgent().memberAddress(), memberAddress)).toList(); } private void removeOfflineNodes() { @@ -383,9 +383,9 @@ private void processBuild(BuildJobQueueItem buildJob) { log.debug("Build job completed: {}", buildJob); JobTimingInfo jobTimingInfo = new JobTimingInfo(buildJob.jobTimingInfo().submissionDate(), buildJob.jobTimingInfo().buildStartDate(), ZonedDateTime.now()); - BuildJobQueueItem finishedJob = new BuildJobQueueItem(buildJob.id(), buildJob.name(), buildJob.buildAgentName(), buildJob.buildAgentAddress(), - buildJob.participationId(), buildJob.courseId(), buildJob.exerciseId(), buildJob.retryCount(), buildJob.priority(), BuildStatus.SUCCESSFUL, - buildJob.repositoryInfo(), jobTimingInfo, buildJob.buildConfig(), null); + BuildJobQueueItem finishedJob = new BuildJobQueueItem(buildJob.id(), buildJob.name(), buildJob.buildAgent(), buildJob.participationId(), buildJob.courseId(), + buildJob.exerciseId(), buildJob.retryCount(), buildJob.priority(), BuildStatus.SUCCESSFUL, buildJob.repositoryInfo(), jobTimingInfo, buildJob.buildConfig(), + null); List buildLogs = buildLogsMap.getBuildLogs(buildJob.id()); buildLogsMap.removeBuildLogs(buildJob.id()); diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/domain/build/BuildJob.java b/src/main/java/de/tum/cit/aet/artemis/programming/domain/build/BuildJob.java index 53f3b75305f2..7a6aeafdbd04 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/domain/build/BuildJob.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/domain/build/BuildJob.java @@ -88,7 +88,7 @@ public BuildJob(BuildJobQueueItem queueItem, BuildStatus buildStatus, Result res this.courseId = queueItem.courseId(); this.participationId = queueItem.participationId(); this.result = result; - this.buildAgentAddress = queueItem.buildAgentAddress(); + this.buildAgentAddress = queueItem.buildAgent().memberAddress(); this.buildStartDate = queueItem.jobTimingInfo().buildStartDate(); this.buildCompletionDate = queueItem.jobTimingInfo().buildCompletionDate(); this.repositoryType = queueItem.repositoryInfo().repositoryType(); diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIResultProcessingService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIResultProcessingService.java index 4507f1a4e76d..e55d7992166f 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIResultProcessingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIResultProcessingService.java @@ -211,8 +211,8 @@ public void processResult() { */ private void addResultToBuildAgentsRecentBuildJobs(BuildJobQueueItem buildJob, Result result) { try { - buildAgentInformation.lock(buildJob.buildAgentAddress()); - BuildAgentInformation buildAgent = buildAgentInformation.get(buildJob.buildAgentAddress()); + buildAgentInformation.lock(buildJob.buildAgent().memberAddress()); + BuildAgentInformation buildAgent = buildAgentInformation.get(buildJob.buildAgent().memberAddress()); if (buildAgent != null) { List recentBuildJobs = buildAgent.recentBuildJobs(); for (int i = 0; i < recentBuildJobs.size(); i++) { @@ -221,11 +221,11 @@ private void addResultToBuildAgentsRecentBuildJobs(BuildJobQueueItem buildJob, R break; } } - buildAgentInformation.put(buildJob.buildAgentAddress(), new BuildAgentInformation(buildAgent, recentBuildJobs)); + buildAgentInformation.put(buildJob.buildAgent().memberAddress(), new BuildAgentInformation(buildAgent, recentBuildJobs)); } } finally { - buildAgentInformation.unlock(buildJob.buildAgentAddress()); + buildAgentInformation.unlock(buildJob.buildAgent().memberAddress()); } } diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java index 0983a04f3ff5..eaceb62f879c 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java @@ -22,6 +22,7 @@ import com.hazelcast.core.HazelcastInstance; import com.hazelcast.map.IMap; +import de.tum.cit.aet.artemis.buildagent.dto.BuildAgent; import de.tum.cit.aet.artemis.buildagent.dto.BuildConfig; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; import de.tum.cit.aet.artemis.buildagent.dto.JobTimingInfo; @@ -196,7 +197,9 @@ else if (triggeredByPushTo.equals(RepositoryType.TESTS)) { BuildConfig buildConfig = getBuildConfig(participation, commitHashToBuild, assignmentCommitHash, testCommitHash, programmingExerciseBuildConfig); - BuildJobQueueItem buildJobQueueItem = new BuildJobQueueItem(buildJobId, participation.getBuildPlanId(), null, null, participation.getId(), courseId, + BuildAgent buildAgent = new BuildAgent(null, null, null); + + BuildJobQueueItem buildJobQueueItem = new BuildJobQueueItem(buildJobId, participation.getBuildPlanId(), buildAgent, participation.getId(), courseId, programmingExercise.getId(), 0, priority, null, repositoryInfo, jobTimingInfo, buildConfig, null); queue.add(buildJobQueueItem); diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java index 3151161055b6..87b44d4872ba 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/SharedQueueManagementService.java @@ -208,7 +208,7 @@ public void cancelAllRunningBuildJobs() { * @param agentName name of the agent */ public void cancelAllRunningBuildJobsForAgent(String agentName) { - processingJobs.values().stream().filter(job -> Objects.equals(job.buildAgentName(), agentName)).forEach(job -> cancelBuildJob(job.id())); + processingJobs.values().stream().filter(job -> Objects.equals(job.buildAgent().name(), agentName)).forEach(job -> cancelBuildJob(job.id())); } /** diff --git a/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java index 91158a46ec83..4e41ff746a02 100644 --- a/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java @@ -28,6 +28,7 @@ import com.hazelcast.core.HazelcastInstance; import com.hazelcast.map.IMap; +import de.tum.cit.aet.artemis.buildagent.dto.BuildAgent; import de.tum.cit.aet.artemis.buildagent.dto.BuildConfig; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; import de.tum.cit.aet.artemis.core.exception.LocalCIException; @@ -92,7 +93,9 @@ void testPullDockerImage() { doReturn(inspectImageCmd).when(dockerClient).inspectImageCmd(anyString()); doThrow(new NotFoundException("")).when(inspectImageCmd).exec(); BuildConfig buildConfig = new BuildConfig("echo 'test'", "test-image-name", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); - var build = new BuildJobQueueItem("1", "job1", "buildagent1", "address1", 1, 1, 1, 1, 1, BuildStatus.SUCCESSFUL, null, null, buildConfig, null); + + BuildAgent buildAgent = new BuildAgent("buildagent1", "address1", "buildagent1"); + var build = new BuildJobQueueItem("1", "job1", buildAgent, 1, 1, 1, 1, 1, BuildStatus.SUCCESSFUL, null, null, buildConfig, null); // Pull image try { buildAgentDockerService.pullDockerImage(build, new BuildLogsMap()); diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java index e1dcd4556702..585707bb680c 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java @@ -27,6 +27,7 @@ import de.tum.cit.aet.artemis.assessment.domain.AssessmentType; import de.tum.cit.aet.artemis.assessment.domain.Result; +import de.tum.cit.aet.artemis.buildagent.dto.BuildAgent; import de.tum.cit.aet.artemis.buildagent.dto.BuildAgentInformation; import de.tum.cit.aet.artemis.buildagent.dto.BuildConfig; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; @@ -92,6 +93,8 @@ protected String getTestPrefix() { @Value("${artemis.continuous-integration.build-agent.display-name:}") private String buildAgentDisplayName; + private BuildAgent buildAgent; + @BeforeEach void createJobs() { // temporarily remove listener to avoid triggering build job processing @@ -104,19 +107,20 @@ void createJobs() { BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); - job1 = new BuildJobQueueItem("1", "job1", "buildagent1", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); - job2 = new BuildJobQueueItem("2", "job2", "buildagent1", "address1", 2, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo2, buildConfig, null); String memberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); - BuildAgentInformation.BuildAgent buildAgent = new BuildAgentInformation.BuildAgent(buildAgentShortName, memberAddress, buildAgentDisplayName); + buildAgent = new BuildAgent(buildAgentShortName, memberAddress, buildAgentDisplayName); + + job1 = new BuildJobQueueItem("1", "job1", buildAgent, 1, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); + job2 = new BuildJobQueueItem("2", "job2", buildAgent, 2, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo2, buildConfig, null); agent1 = new BuildAgentInformation(buildAgent, 1, 0, new ArrayList<>(List.of(job1)), BuildAgentInformation.BuildAgentStatus.IDLE, new ArrayList<>(List.of(job2)), null); - BuildJobQueueItem finishedJobQueueItem1 = new BuildJobQueueItem("3", "job3", "buildagent1", "address1", 3, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, - jobTimingInfo1, buildConfig, null); - BuildJobQueueItem finishedJobQueueItem2 = new BuildJobQueueItem("4", "job4", "buildagent1", "address1", 4, course.getId() + 1, 1, 1, 1, BuildStatus.FAILED, repositoryInfo, - jobTimingInfo2, buildConfig, null); - BuildJobQueueItem finishedJobQueueItem3 = new BuildJobQueueItem("5", "job5", "buildagent1", "address1", 5, course.getId() + 2, 1, 1, 1, BuildStatus.FAILED, repositoryInfo, - jobTimingInfo3, buildConfig, null); - BuildJobQueueItem finishedJobQueueItemForLogs = new BuildJobQueueItem("6", "job5", "buildagent1", "address1", 5, course.getId(), programmingExercise.getId(), 1, 1, - BuildStatus.FAILED, repositoryInfo, jobTimingInfo3, buildConfig, null); + BuildJobQueueItem finishedJobQueueItem1 = new BuildJobQueueItem("3", "job3", buildAgent, 3, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, + buildConfig, null); + BuildJobQueueItem finishedJobQueueItem2 = new BuildJobQueueItem("4", "job4", buildAgent, 4, course.getId() + 1, 1, 1, 1, BuildStatus.FAILED, repositoryInfo, jobTimingInfo2, + buildConfig, null); + BuildJobQueueItem finishedJobQueueItem3 = new BuildJobQueueItem("5", "job5", buildAgent, 5, course.getId() + 2, 1, 1, 1, BuildStatus.FAILED, repositoryInfo, jobTimingInfo3, + buildConfig, null); + BuildJobQueueItem finishedJobQueueItemForLogs = new BuildJobQueueItem("6", "job5", buildAgent, 5, course.getId(), programmingExercise.getId(), 1, 1, BuildStatus.FAILED, + repositoryInfo, jobTimingInfo3, buildConfig, null); var result1 = new Result().successful(true).rated(true).score(100D).assessmentType(AssessmentType.AUTOMATIC).completionDate(ZonedDateTime.now()); var result2 = new Result().successful(false).rated(true).score(0D).assessmentType(AssessmentType.AUTOMATIC).completionDate(ZonedDateTime.now()); var result3 = new Result().successful(false).rated(true).score(0D).assessmentType(AssessmentType.AUTOMATIC).completionDate(ZonedDateTime.now()); @@ -296,8 +300,7 @@ void testGetFinishedBuildJobs_returnsFilteredJobs() throws Exception { ZonedDateTime.now().plusDays(1).plusMinutes(10)); BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); - var failedJob1 = new BuildJobQueueItem("5", "job5", "buildagent1", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.FAILED, repositoryInfo, jobTimingInfo, buildConfig, - null); + var failedJob1 = new BuildJobQueueItem("5", "job5", buildAgent, 1, course.getId(), 1, 1, 1, BuildStatus.FAILED, repositoryInfo, jobTimingInfo, buildConfig, null); var jobResult = new Result().successful(false).rated(true).score(0D).assessmentType(AssessmentType.AUTOMATIC).completionDate(ZonedDateTime.now()); var failedFinishedJob = new BuildJob(failedJob1, BuildStatus.FAILED, jobResult); diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java index d8a009ebca42..06181948a01b 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java @@ -23,6 +23,7 @@ import com.hazelcast.core.HazelcastInstance; import com.hazelcast.map.IMap; +import de.tum.cit.aet.artemis.buildagent.dto.BuildAgent; import de.tum.cit.aet.artemis.buildagent.dto.BuildConfig; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; import de.tum.cit.aet.artemis.buildagent.dto.JobTimingInfo; @@ -104,9 +105,12 @@ void testReturnCorrectBuildStatus() { BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); - BuildJobQueueItem job1 = new BuildJobQueueItem("1", "job1", "buildagent1", "address1", participation.getId(), course.getId(), 1, 1, 1, + String memberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); + BuildAgent buildAgent = new BuildAgent("artemis-build-agent-test", memberAddress, "artemis-build-agent-test"); + + BuildJobQueueItem job1 = new BuildJobQueueItem("1", "job1", buildAgent, participation.getId(), course.getId(), 1, 1, 1, de.tum.cit.aet.artemis.programming.domain.build.BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo, buildConfig, null); - BuildJobQueueItem job2 = new BuildJobQueueItem("2", "job2", "buildagent1", "address1", participation.getId(), course.getId(), 1, 1, 1, + BuildJobQueueItem job2 = new BuildJobQueueItem("2", "job2", buildAgent, participation.getId(), course.getId(), 1, 1, 1, de.tum.cit.aet.artemis.programming.domain.build.BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo, buildConfig, null); queuedJobs = hazelcastInstance.getQueue("buildJobQueue"); From c80d1fc183f4a961e3a34203e07fbe9160397d64 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 22 Oct 2024 00:12:31 +0200 Subject: [PATCH 15/22] fix test --- .../programming/icl/LocalCIResourceIntegrationTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java index 585707bb680c..218f443dabc9 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java @@ -10,6 +10,7 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -379,10 +380,13 @@ void testGetBuildJobStatistics() throws Exception { @Test @WithMockUser(username = TEST_PREFIX + "admin", roles = "ADMIN") void testPauseBuildAgent() throws Exception { + // We need to clear the processing jobs to avoid the agent being set to ACTIVE again + processingJobs.clear(); + request.put("/api/admin/agent/" + URLEncoder.encode(agent1.buildAgent().name(), StandardCharsets.UTF_8) + "/pause", null, HttpStatus.NO_CONTENT); - await().until(() -> buildAgentInformation.get(agent1.buildAgent().memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.PAUSED); + await().atMost(10, TimeUnit.HOURS).until(() -> buildAgentInformation.get(agent1.buildAgent().memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.PAUSED); request.put("/api/admin/agent/" + URLEncoder.encode(agent1.buildAgent().name(), StandardCharsets.UTF_8) + "/resume", null, HttpStatus.NO_CONTENT); - await().until(() -> buildAgentInformation.get(agent1.buildAgent().memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.IDLE); + await().atMost(10, TimeUnit.HOURS).until(() -> buildAgentInformation.get(agent1.buildAgent().memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.IDLE); } } From c57b798cac8a9a73dc1f5e5eba43cdb73ccf4de7 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 22 Oct 2024 00:34:38 +0200 Subject: [PATCH 16/22] client --- .../build-agent-information.model.ts | 19 +++++++++++++++++++ .../entities/programming/build-agent.model.ts | 19 ------------------- .../entities/programming/build-job.model.ts | 4 ++-- .../build-agent-details.component.ts | 2 +- .../build-agent-summary.component.ts | 2 +- .../build-agents/build-agents.service.ts | 2 +- .../build-queue/build-queue.component.html | 8 ++++---- .../build-agent-details.component.spec.ts | 8 ++++---- .../build-agent-summary.component.spec.ts | 10 +++++----- .../build-agents/build-agents.service.spec.ts | 2 +- 10 files changed, 38 insertions(+), 38 deletions(-) create mode 100644 src/main/webapp/app/entities/programming/build-agent-information.model.ts diff --git a/src/main/webapp/app/entities/programming/build-agent-information.model.ts b/src/main/webapp/app/entities/programming/build-agent-information.model.ts new file mode 100644 index 000000000000..c9e5c3c9e71d --- /dev/null +++ b/src/main/webapp/app/entities/programming/build-agent-information.model.ts @@ -0,0 +1,19 @@ +import { BaseEntity } from 'app/shared/model/base-entity'; +import { BuildJob } from 'app/entities/programming/build-job.model'; +import { BuildAgent } from 'app/entities/programming/build-agent.model'; + +export enum BuildAgentStatus { + ACTIVE = 'ACTIVE', + PAUSED = 'PAUSED', + IDLE = 'IDLE', +} + +export class BuildAgentInformation implements BaseEntity { + public id?: number; + public buildAgent?: BuildAgent; + public maxNumberOfConcurrentBuildJobs?: number; + public numberOfCurrentBuildJobs?: number; + public runningBuildJobs?: BuildJob[]; + public status?: BuildAgentStatus; + public recentBuildJobs?: BuildJob[]; +} diff --git a/src/main/webapp/app/entities/programming/build-agent.model.ts b/src/main/webapp/app/entities/programming/build-agent.model.ts index 2532e0bc1eb8..f67bfbcd9dd1 100644 --- a/src/main/webapp/app/entities/programming/build-agent.model.ts +++ b/src/main/webapp/app/entities/programming/build-agent.model.ts @@ -1,24 +1,5 @@ -import { BaseEntity } from 'app/shared/model/base-entity'; -import { BuildJob } from 'app/entities/programming/build-job.model'; - -export enum BuildAgentStatus { - ACTIVE = 'ACTIVE', - PAUSED = 'PAUSED', - IDLE = 'IDLE', -} - export class BuildAgent { public name?: string; public memberAddress?: string; public displayName?: string; } - -export class BuildAgentInformation implements BaseEntity { - public id?: number; - public buildAgent?: BuildAgent; - public maxNumberOfConcurrentBuildJobs?: number; - public numberOfCurrentBuildJobs?: number; - public runningBuildJobs?: BuildJob[]; - public status?: BuildAgentStatus; - public recentBuildJobs?: BuildJob[]; -} diff --git a/src/main/webapp/app/entities/programming/build-job.model.ts b/src/main/webapp/app/entities/programming/build-job.model.ts index dfea79380097..2c88534d2626 100644 --- a/src/main/webapp/app/entities/programming/build-job.model.ts +++ b/src/main/webapp/app/entities/programming/build-job.model.ts @@ -4,12 +4,12 @@ import { JobTimingInfo } from 'app/entities/job-timing-info.model'; import { BuildConfig } from 'app/entities/programming/build-config.model'; import { Result } from 'app/entities/result.model'; import dayjs from 'dayjs/esm'; +import { BuildAgent } from 'app/entities/programming/build-agent.model'; export class BuildJob implements StringBaseEntity { public id?: string; public name?: string; - public buildAgentName?: string; - public buildAgentAddress?: string; + public buildAgent?: BuildAgent; public participationId?: number; public courseId?: number; public exerciseId?: number; diff --git a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts index e917cb1f5305..1408b83c2495 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts +++ b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts @@ -1,5 +1,5 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { BuildAgentInformation } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation } from 'app/entities/programming/build-agent-information.model'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; import { Subscription } from 'rxjs'; import { faCircleCheck, faExclamationCircle, faExclamationTriangle, faPause, faPlay, faTimes } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts index 34db9243a3dd..f44b75871b74 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts +++ b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts @@ -1,5 +1,5 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { BuildAgentInformation } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation } from 'app/entities/programming/build-agent-information.model'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; import { Subscription } from 'rxjs'; diff --git a/src/main/webapp/app/localci/build-agents/build-agents.service.ts b/src/main/webapp/app/localci/build-agents/build-agents.service.ts index a4a823970ca2..6aac582940d3 100644 --- a/src/main/webapp/app/localci/build-agents/build-agents.service.ts +++ b/src/main/webapp/app/localci/build-agents/build-agents.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; -import { BuildAgentInformation } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation } from 'app/entities/programming/build-agent-information.model'; import { catchError } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) diff --git a/src/main/webapp/app/localci/build-queue/build-queue.component.html b/src/main/webapp/app/localci/build-queue/build-queue.component.html index bea45c87ae79..a8f9a582cbf3 100644 --- a/src/main/webapp/app/localci/build-queue/build-queue.component.html +++ b/src/main/webapp/app/localci/build-queue/build-queue.component.html @@ -107,15 +107,15 @@

+ - + - + - + {{ value }} diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts index 84284cb20de9..0b14d136c97c 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts @@ -9,7 +9,7 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { DataTableComponent } from 'app/shared/data-table/data-table.component'; import { MockComponent, MockPipe, MockProvider } from 'ng-mocks'; import { NgxDatatableModule } from '@siemens/ngx-datatable'; -import { BuildAgentInformation, BuildAgentStatus } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation, BuildAgentStatus } from '../../../../../../main/webapp/app/entities/programming/build-agent-information.model'; import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; import { BuildConfig } from 'app/entities/programming/build-config.model'; @@ -69,7 +69,7 @@ describe('BuildAgentDetailsComponent', () => { { id: '2', name: 'Build Job 2', - buildAgentAddress: 'agent2', + buildAgent: { name: 'agent2', memberAddress: 'localhost:8080', displayName: 'Agent 2' }, participationId: 102, courseId: 10, exerciseId: 100, @@ -82,7 +82,7 @@ describe('BuildAgentDetailsComponent', () => { { id: '4', name: 'Build Job 4', - buildAgentAddress: 'agent4', + buildAgent: { name: 'agent4', memberAddress: 'localhost:8080', displayName: 'Agent 4' }, participationId: 104, courseId: 10, exerciseId: 100, @@ -98,7 +98,7 @@ describe('BuildAgentDetailsComponent', () => { { id: '1', name: 'Build Job 1', - buildAgentAddress: 'agent1', + buildAgent: { name: 'agent1', memberAddress: 'localhost:8080', displayName: 'Agent 1' }, participationId: 101, courseId: 10, exerciseId: 100, diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts index 9e84fd55b8fa..8e7946480914 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts @@ -10,7 +10,7 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { DataTableComponent } from 'app/shared/data-table/data-table.component'; import { MockComponent, MockPipe } from 'ng-mocks'; import { NgxDatatableModule } from '@siemens/ngx-datatable'; -import { BuildAgentInformation, BuildAgentStatus } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation, BuildAgentStatus } from '../../../../../../main/webapp/app/entities/programming/build-agent-information.model'; import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; import { BuildConfig } from 'app/entities/programming/build-config.model'; @@ -63,7 +63,7 @@ describe('BuildAgentSummaryComponent', () => { { id: '2', name: 'Build Job 2', - buildAgentAddress: 'agent2', + buildAgent: { name: 'agent2', memberAddress: 'localhost:8080', displayName: 'Agent 2' }, participationId: 102, courseId: 10, exerciseId: 100, @@ -76,7 +76,7 @@ describe('BuildAgentSummaryComponent', () => { { id: '4', name: 'Build Job 4', - buildAgentAddress: 'agent4', + buildAgent: { name: 'agent4', memberAddress: 'localhost:8080', displayName: 'Agent 4' }, participationId: 104, courseId: 10, exerciseId: 100, @@ -92,7 +92,7 @@ describe('BuildAgentSummaryComponent', () => { { id: '1', name: 'Build Job 1', - buildAgentAddress: 'agent1', + buildAgent: { name: 'agent1', memberAddress: 'localhost:8080', displayName: 'Agent 1' }, participationId: 101, courseId: 10, exerciseId: 100, @@ -105,7 +105,7 @@ describe('BuildAgentSummaryComponent', () => { { id: '3', name: 'Build Job 3', - buildAgentAddress: 'agent3', + buildAgent: { name: 'agent3', memberAddress: 'localhost:8080', displayName: 'Agent 3' }, participationId: 103, courseId: 10, exerciseId: 100, diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts index b8720ac5c1dc..809267f6245a 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts @@ -8,7 +8,7 @@ import { BuildJob } from 'app/entities/programming/build-job.model'; import dayjs from 'dayjs/esm'; import { lastValueFrom } from 'rxjs'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; -import { BuildAgentInformation } from 'app/entities/programming/build-agent.model'; +import { BuildAgentInformation } from '../../../../../../main/webapp/app/entities/programming/build-agent-information.model'; import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; import { BuildConfig } from 'app/entities/programming/build-config.model'; From 5faac94f42049c75d8b1415ac92ff2cf8a7f2d5d Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 22 Oct 2024 00:37:58 +0200 Subject: [PATCH 17/22] fix client tests --- .../localci/build-agents/build-agents.service.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts index 809267f6245a..261acf610ff2 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts @@ -50,7 +50,7 @@ describe('BuildAgentsService', () => { { id: '2', name: 'Build Job 2', - buildAgentAddress: 'agent2', + buildAgent: { name: 'agent2', memberAddress: 'localhost:8080', displayName: 'Agent 2' }, participationId: 102, courseId: 10, exerciseId: 100, @@ -63,7 +63,7 @@ describe('BuildAgentsService', () => { { id: '4', name: 'Build Job 4', - buildAgentAddress: 'agent4', + buildAgent: { name: 'agent4', memberAddress: 'localhost:8080', displayName: 'Agent 4' }, participationId: 104, courseId: 10, exerciseId: 100, From 997035925c0bbea1f23d9c16fd241f82e7335d3b Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 22 Oct 2024 00:52:26 +0200 Subject: [PATCH 18/22] coderabbit suggestions --- .../buildagent/service/SharedQueueProcessingService.java | 4 ++-- .../programming/icl/LocalCIResourceIntegrationTest.java | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java index ef8089bf2529..80737be9c73a 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java @@ -171,14 +171,14 @@ public void init() { ITopic pauseBuildAgentTopic = hazelcastInstance.getTopic("pauseBuildAgentTopic"); pauseBuildAgentTopic.addMessageListener(message -> { - if (message.getMessageObject().equals(buildAgentShortName)) { + if (Objects.equals(message.getMessageObject(), buildAgentShortName)) { pauseBuildAgent(); } }); ITopic resumeBuildAgentTopic = hazelcastInstance.getTopic("resumeBuildAgentTopic"); resumeBuildAgentTopic.addMessageListener(message -> { - if (message.getMessageObject().equals(buildAgentShortName)) { + if (Objects.equals(message.getMessageObject(), buildAgentShortName)) { resumeBuildAgent(); } }); diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java index 218f443dabc9..01bde957a2a0 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java @@ -10,7 +10,6 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -384,9 +383,9 @@ void testPauseBuildAgent() throws Exception { processingJobs.clear(); request.put("/api/admin/agent/" + URLEncoder.encode(agent1.buildAgent().name(), StandardCharsets.UTF_8) + "/pause", null, HttpStatus.NO_CONTENT); - await().atMost(10, TimeUnit.HOURS).until(() -> buildAgentInformation.get(agent1.buildAgent().memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.PAUSED); + await().until(() -> buildAgentInformation.get(agent1.buildAgent().memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.PAUSED); request.put("/api/admin/agent/" + URLEncoder.encode(agent1.buildAgent().name(), StandardCharsets.UTF_8) + "/resume", null, HttpStatus.NO_CONTENT); - await().atMost(10, TimeUnit.HOURS).until(() -> buildAgentInformation.get(agent1.buildAgent().memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.IDLE); + await().until(() -> buildAgentInformation.get(agent1.buildAgent().memberAddress()).status() == BuildAgentInformation.BuildAgentStatus.IDLE); } } From 2cb68fe13c808ef6c0ad8bdda717084eda7739b6 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 22 Oct 2024 00:54:33 +0200 Subject: [PATCH 19/22] update docs --- docs/admin/setup/distributed.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/admin/setup/distributed.rst b/docs/admin/setup/distributed.rst index 7b925af0f35b..b2d1a12822d3 100644 --- a/docs/admin/setup/distributed.rst +++ b/docs/admin/setup/distributed.rst @@ -619,6 +619,7 @@ These credentials are used to clone repositories via HTTPS. You must also add th cleanup-schedule-minutes: 60 # Schedule for container cleanup build-agent: short-name: "artemis-build-agent-X" # Short name of the build agent. This should be unique for each build agent. Only lowercase letters, numbers and hyphens are allowed. + display-name: "Artemis Build Agent X" # This value is optional. If omitted, the short name will be used as display name. Display name of the build agent. This is shown in the Artemis UI. Please note that ``artemis.continuous-integration.build-agent.short-name`` must be provided. Otherwise, the build agent will not start. From f13c768b9a8bd98a071f7ed0f9fd56744ea232a5 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 22 Oct 2024 17:20:48 +0200 Subject: [PATCH 20/22] feedback --- .../core/web/admin/AdminBuildJobQueueResource.java | 3 +++ .../build-agent-summary.component.html | 2 +- .../build-agent-summary.component.ts | 13 +++++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java b/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java index 19075018440a..0e0313c342de 100644 --- a/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java +++ b/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java @@ -97,6 +97,9 @@ public ResponseEntity getBuildAgentDetails(@RequestParam log.debug("REST request to get information on build agent {}", agentName); BuildAgentInformation buildAgentDetails = localCIBuildJobQueueService.getBuildAgentInformation().stream().filter(agent -> agent.buildAgent().name().equals(agentName)) .findFirst().orElse(null); + if (buildAgentDetails == null) { + return ResponseEntity.notFound().build(); + } return ResponseEntity.ok(buildAgentDetails); } diff --git a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html index 5e9c3fd22631..7021b3f79c4d 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html +++ b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.html @@ -83,7 +83,7 @@

{{ value }} @if (value > 0) { - diff --git a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts index f44b75871b74..711fa4a40dce 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts +++ b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts @@ -6,6 +6,7 @@ import { Subscription } from 'rxjs'; import { faTimes } from '@fortawesome/free-solid-svg-icons'; import { BuildQueueService } from 'app/localci/build-queue/build-queue.service'; import { Router } from '@angular/router'; +import { BuildAgent } from 'app/entities/programming/build-agent.model'; @Component({ selector: 'jhi-build-agents', @@ -75,10 +76,14 @@ export class BuildAgentSummaryComponent implements OnInit, OnDestroy { this.buildQueueService.cancelBuildJob(buildJobId).subscribe(); } - cancelAllBuildJobs(buildAgentName: string) { - const buildAgent = this.buildAgents.find((agent) => agent.buildAgent?.name === buildAgentName); - if (buildAgent?.buildAgent?.name) { - this.buildQueueService.cancelAllRunningBuildJobsForAgent(buildAgent.buildAgent?.name).subscribe(); + cancelAllBuildJobs(buildAgent?: BuildAgent) { + if (!buildAgent?.name) { + return; + } + + const buildAgentToCancel = this.buildAgents.find((agent) => agent.buildAgent?.name === buildAgent.name); + if (buildAgentToCancel?.buildAgent?.name) { + this.buildQueueService.cancelAllRunningBuildJobsForAgent(buildAgentToCancel.buildAgent?.name).subscribe(); } } } From 7422d0c1a0a70956a1a2e0945d7800592d28efc0 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 22 Oct 2024 17:22:00 +0200 Subject: [PATCH 21/22] test --- .../build-agents/build-agent-summary.component.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts index 8e7946480914..fe898f69474a 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts @@ -196,9 +196,9 @@ describe('BuildAgentSummaryComponent', () => { const spy = jest.spyOn(component, 'cancelAllBuildJobs'); component.ngOnInit(); - component.cancelAllBuildJobs(buildAgent.buildAgent?.name!); + component.cancelAllBuildJobs(buildAgent.buildAgent); - expect(spy).toHaveBeenCalledExactlyOnceWith(buildAgent.buildAgent?.name!); + expect(spy).toHaveBeenCalledExactlyOnceWith(buildAgent.buildAgent); }); it('should calculate the build capacity and current builds', () => { From 6b8e6d4f2321c770cd039b29d9291320528d021e Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Wed, 23 Oct 2024 18:18:59 +0200 Subject: [PATCH 22/22] feedback --- .../dto/{BuildAgent.java => BuildAgentDTO.java} | 2 +- .../buildagent/dto/BuildAgentInformation.java | 2 +- .../artemis/buildagent/dto/BuildJobQueueItem.java | 4 ++-- .../service/SharedQueueProcessingService.java | 12 ++++++------ .../core/web/admin/AdminBuildJobQueueResource.java | 9 +++++---- .../service/localci/LocalCITriggerService.java | 4 ++-- .../service/BuildAgentDockerServiceTest.java | 4 ++-- .../icl/LocalCIResourceIntegrationTest.java | 6 +++--- .../artemis/programming/icl/LocalCIServiceTest.java | 4 ++-- 9 files changed, 24 insertions(+), 23 deletions(-) rename src/main/java/de/tum/cit/aet/artemis/buildagent/dto/{BuildAgent.java => BuildAgentDTO.java} (60%) diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgent.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentDTO.java similarity index 60% rename from src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgent.java rename to src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentDTO.java index a76099810feb..2ffa0f2daa61 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgent.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentDTO.java @@ -3,7 +3,7 @@ import java.io.Serial; import java.io.Serializable; -public record BuildAgent(String name, String memberAddress, String displayName) implements Serializable { +public record BuildAgentDTO(String name, String memberAddress, String displayName) implements Serializable { @Serial private static final long serialVersionUID = 1L; diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java index 405f44b6092a..40af5049060e 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildAgentInformation.java @@ -11,7 +11,7 @@ // in the future are migrated or cleared. Changes should be communicated in release notes as potentially breaking changes. @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_EMPTY) -public record BuildAgentInformation(BuildAgent buildAgent, int maxNumberOfConcurrentBuildJobs, int numberOfCurrentBuildJobs, List runningBuildJobs, +public record BuildAgentInformation(BuildAgentDTO buildAgent, int maxNumberOfConcurrentBuildJobs, int numberOfCurrentBuildJobs, List runningBuildJobs, BuildAgentStatus status, List recentBuildJobs, String publicSshKey) implements Serializable { @Serial diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildJobQueueItem.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildJobQueueItem.java index ec9667d647ae..7a4220399819 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildJobQueueItem.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildJobQueueItem.java @@ -14,7 +14,7 @@ // in the future are migrated or cleared. Changes should be communicated in release notes as potentially breaking changes. @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_EMPTY) -public record BuildJobQueueItem(String id, String name, BuildAgent buildAgent, long participationId, long courseId, long exerciseId, int retryCount, int priority, +public record BuildJobQueueItem(String id, String name, BuildAgentDTO buildAgent, long participationId, long courseId, long exerciseId, int retryCount, int priority, BuildStatus status, RepositoryInfo repositoryInfo, JobTimingInfo jobTimingInfo, BuildConfig buildConfig, ResultDTO submissionResult) implements Serializable { @Serial @@ -39,7 +39,7 @@ public BuildJobQueueItem(BuildJobQueueItem queueItem, ZonedDateTime buildComplet * @param queueItem The queued build job * @param buildAgent The build agent that will process the build job */ - public BuildJobQueueItem(BuildJobQueueItem queueItem, BuildAgent buildAgent) { + public BuildJobQueueItem(BuildJobQueueItem queueItem, BuildAgentDTO buildAgent) { this(queueItem.id(), queueItem.name(), buildAgent, queueItem.participationId(), queueItem.courseId(), queueItem.exerciseId(), queueItem.retryCount(), queueItem.priority(), null, queueItem.repositoryInfo(), new JobTimingInfo(queueItem.jobTimingInfo.submissionDate(), ZonedDateTime.now(), null), queueItem.buildConfig(), null); } diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java index 80737be9c73a..bab6e7c9f147 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/SharedQueueProcessingService.java @@ -44,7 +44,7 @@ import com.hazelcast.map.IMap; import com.hazelcast.topic.ITopic; -import de.tum.cit.aet.artemis.buildagent.dto.BuildAgent; +import de.tum.cit.aet.artemis.buildagent.dto.BuildAgentDTO; import de.tum.cit.aet.artemis.buildagent.dto.BuildAgentInformation; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; import de.tum.cit.aet.artemis.buildagent.dto.BuildResult; @@ -171,14 +171,14 @@ public void init() { ITopic pauseBuildAgentTopic = hazelcastInstance.getTopic("pauseBuildAgentTopic"); pauseBuildAgentTopic.addMessageListener(message -> { - if (Objects.equals(message.getMessageObject(), buildAgentShortName)) { + if (buildAgentShortName.equals(message.getMessageObject())) { pauseBuildAgent(); } }); ITopic resumeBuildAgentTopic = hazelcastInstance.getTopic("resumeBuildAgentTopic"); resumeBuildAgentTopic.addMessageListener(message -> { - if (Objects.equals(message.getMessageObject(), buildAgentShortName)) { + if (buildAgentShortName.equals(message.getMessageObject())) { resumeBuildAgent(); } }); @@ -263,7 +263,7 @@ private void checkAvailabilityAndProcessNextBuild() { if (buildJob != null) { processingJobs.remove(buildJob.id()); - buildJob = new BuildJobQueueItem(buildJob, new BuildAgent("", "", "")); + buildJob = new BuildJobQueueItem(buildJob, new BuildAgentDTO("", "", "")); log.info("Adding build job back to the queue: {}", buildJob); queue.add(buildJob); localProcessingJobs.decrementAndGet(); @@ -285,7 +285,7 @@ private BuildJobQueueItem addToProcessingJobs() { if (buildJob != null) { String hazelcastMemberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); - BuildJobQueueItem processingJob = new BuildJobQueueItem(buildJob, new BuildAgent(buildAgentShortName, hazelcastMemberAddress, buildAgentDisplayName)); + BuildJobQueueItem processingJob = new BuildJobQueueItem(buildJob, new BuildAgentDTO(buildAgentShortName, hazelcastMemberAddress, buildAgentDisplayName)); processingJobs.put(processingJob.id(), processingJob); localProcessingJobs.incrementAndGet(); @@ -344,7 +344,7 @@ private BuildAgentInformation getUpdatedLocalBuildAgentInformation(BuildJobQueue String publicSshKey = buildAgentSSHKeyService.getPublicKeyAsString(); - BuildAgent agentInfo = new BuildAgent(buildAgentShortName, memberAddress, buildAgentDisplayName); + BuildAgentDTO agentInfo = new BuildAgentDTO(buildAgentShortName, memberAddress, buildAgentDisplayName); return new BuildAgentInformation(agentInfo, maxNumberOfConcurrentBuilds, numberOfCurrentBuildJobs, processingJobsOfMember, status, recentBuildJobs, publicSshKey); } diff --git a/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java b/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java index 0e0313c342de..27cd50a6e4b9 100644 --- a/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java +++ b/src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminBuildJobQueueResource.java @@ -4,6 +4,7 @@ import java.time.ZonedDateTime; import java.util.List; +import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -95,12 +96,12 @@ public ResponseEntity> getBuildAgentSummary() { @GetMapping("build-agent") public ResponseEntity getBuildAgentDetails(@RequestParam String agentName) { log.debug("REST request to get information on build agent {}", agentName); - BuildAgentInformation buildAgentDetails = localCIBuildJobQueueService.getBuildAgentInformation().stream().filter(agent -> agent.buildAgent().name().equals(agentName)) - .findFirst().orElse(null); - if (buildAgentDetails == null) { + Optional buildAgentDetails = localCIBuildJobQueueService.getBuildAgentInformation().stream() + .filter(agent -> agent.buildAgent().name().equals(agentName)).findFirst(); + if (buildAgentDetails.isEmpty()) { return ResponseEntity.notFound().build(); } - return ResponseEntity.ok(buildAgentDetails); + return ResponseEntity.ok(buildAgentDetails.get()); } /** diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java index eaceb62f879c..cb4e894c90f7 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java @@ -22,7 +22,7 @@ import com.hazelcast.core.HazelcastInstance; import com.hazelcast.map.IMap; -import de.tum.cit.aet.artemis.buildagent.dto.BuildAgent; +import de.tum.cit.aet.artemis.buildagent.dto.BuildAgentDTO; import de.tum.cit.aet.artemis.buildagent.dto.BuildConfig; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; import de.tum.cit.aet.artemis.buildagent.dto.JobTimingInfo; @@ -197,7 +197,7 @@ else if (triggeredByPushTo.equals(RepositoryType.TESTS)) { BuildConfig buildConfig = getBuildConfig(participation, commitHashToBuild, assignmentCommitHash, testCommitHash, programmingExerciseBuildConfig); - BuildAgent buildAgent = new BuildAgent(null, null, null); + BuildAgentDTO buildAgent = new BuildAgentDTO(null, null, null); BuildJobQueueItem buildJobQueueItem = new BuildJobQueueItem(buildJobId, participation.getBuildPlanId(), buildAgent, participation.getId(), courseId, programmingExercise.getId(), 0, priority, null, repositoryInfo, jobTimingInfo, buildConfig, null); diff --git a/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java index 4e41ff746a02..eab5c2190d4c 100644 --- a/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java @@ -28,7 +28,7 @@ import com.hazelcast.core.HazelcastInstance; import com.hazelcast.map.IMap; -import de.tum.cit.aet.artemis.buildagent.dto.BuildAgent; +import de.tum.cit.aet.artemis.buildagent.dto.BuildAgentDTO; import de.tum.cit.aet.artemis.buildagent.dto.BuildConfig; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; import de.tum.cit.aet.artemis.core.exception.LocalCIException; @@ -94,7 +94,7 @@ void testPullDockerImage() { doThrow(new NotFoundException("")).when(inspectImageCmd).exec(); BuildConfig buildConfig = new BuildConfig("echo 'test'", "test-image-name", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); - BuildAgent buildAgent = new BuildAgent("buildagent1", "address1", "buildagent1"); + BuildAgentDTO buildAgent = new BuildAgentDTO("buildagent1", "address1", "buildagent1"); var build = new BuildJobQueueItem("1", "job1", buildAgent, 1, 1, 1, 1, 1, BuildStatus.SUCCESSFUL, null, null, buildConfig, null); // Pull image try { diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java index 01bde957a2a0..cd717f376537 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java @@ -27,7 +27,7 @@ import de.tum.cit.aet.artemis.assessment.domain.AssessmentType; import de.tum.cit.aet.artemis.assessment.domain.Result; -import de.tum.cit.aet.artemis.buildagent.dto.BuildAgent; +import de.tum.cit.aet.artemis.buildagent.dto.BuildAgentDTO; import de.tum.cit.aet.artemis.buildagent.dto.BuildAgentInformation; import de.tum.cit.aet.artemis.buildagent.dto.BuildConfig; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; @@ -93,7 +93,7 @@ protected String getTestPrefix() { @Value("${artemis.continuous-integration.build-agent.display-name:}") private String buildAgentDisplayName; - private BuildAgent buildAgent; + private BuildAgentDTO buildAgent; @BeforeEach void createJobs() { @@ -108,7 +108,7 @@ void createJobs() { RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); String memberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); - buildAgent = new BuildAgent(buildAgentShortName, memberAddress, buildAgentDisplayName); + buildAgent = new BuildAgentDTO(buildAgentShortName, memberAddress, buildAgentDisplayName); job1 = new BuildJobQueueItem("1", "job1", buildAgent, 1, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); job2 = new BuildJobQueueItem("2", "job2", buildAgent, 2, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo2, buildConfig, null); diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java index 06181948a01b..61adfe127cd0 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java @@ -23,7 +23,7 @@ import com.hazelcast.core.HazelcastInstance; import com.hazelcast.map.IMap; -import de.tum.cit.aet.artemis.buildagent.dto.BuildAgent; +import de.tum.cit.aet.artemis.buildagent.dto.BuildAgentDTO; import de.tum.cit.aet.artemis.buildagent.dto.BuildConfig; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; import de.tum.cit.aet.artemis.buildagent.dto.JobTimingInfo; @@ -106,7 +106,7 @@ void testReturnCorrectBuildStatus() { RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); String memberAddress = hazelcastInstance.getCluster().getLocalMember().getAddress().toString(); - BuildAgent buildAgent = new BuildAgent("artemis-build-agent-test", memberAddress, "artemis-build-agent-test"); + BuildAgentDTO buildAgent = new BuildAgentDTO("artemis-build-agent-test", memberAddress, "artemis-build-agent-test"); BuildJobQueueItem job1 = new BuildJobQueueItem("1", "job1", buildAgent, participation.getId(), course.getId(), 1, 1, 1, de.tum.cit.aet.artemis.programming.domain.build.BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo, buildConfig, null);