diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java index 85f94395a..c90e0aa99 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -34,6 +34,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; import org.eclipse.hawkbit.repository.model.MetaData; import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.Statistic; import org.eclipse.hawkbit.repository.model.Tag; import org.eclipse.hawkbit.repository.model.Target; import org.springframework.data.domain.Page; @@ -517,6 +518,45 @@ public interface DistributionSetManagement @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) long countByTypeId(long typeId); + /** + * Count all {@link org.eclipse.hawkbit.repository.model.Rollout}s by status for + * Distribution Set. + * + * @param dsId + * to look for + * + * @return List of Statistics for {@link org.eclipse.hawkbit.repository.model.Rollout}s status counts + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List countRolloutsByStatusForDistributionSet(@NotNull Long dsId); + + /** + * Count all {@link org.eclipse.hawkbit.repository.model.Action}s by status for + * Distribution Set. + * + * @param dsId + * to look for + * + * @return List of Statistics for {@link org.eclipse.hawkbit.repository.model.Action}s status counts + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List countActionsByStatusForDistributionSet(@NotNull Long dsId); + + /** + * Count all {@link org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate}s + * for Distribution Set. + * + * @param dsId + * to look for + * + * @return number of {@link org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate}s + * + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countAutoAssignmentsForDistributionSet(@NotNull Long dsId); + /** * Sets the specified {@link DistributionSet} as invalidated. * diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Statistic.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Statistic.java new file mode 100644 index 000000000..ced2e29f3 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Statistic.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2023 Bosch.IO GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.hawkbit.repository.model; + +public interface Statistic { + + /** + * + * @return the key of the Statistic entity. + */ + Object getName(); + + /** + * + * @return the value of the Statistic entity. + */ + Object getData(); +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java index 50573b298..1071001e6 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java @@ -15,6 +15,7 @@ import java.util.Optional; import javax.persistence.EntityManager; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaStatistic; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Rollout; @@ -50,6 +51,37 @@ public interface DistributionSetRepository @Query(value = "Select Distinct ds from JpaDistributionSet ds join ds.tags dst where dst.id = :tag and ds.deleted = 0") Page findByTag(Pageable pageable, @Param("tag") Long tagId); + /** + * Count {@link Rollout}s by Status for Distribution set. + * + * @param dsId + * to be found + * @return map for {@link Rollout}s status counts + */ + @Query(value = "SELECT r.status as name, COUNT(r.status) as data FROM JpaRollout r WHERE r.distributionSet.id = :dsId GROUP BY r.status") + List countRolloutsByStatusForDistributionSet(@Param("dsId") Long dsId); + + + /** + * Count {@link Action}s by Status for Distribution set. + * + * @param dsId + * to be found + * @return map for {@link Action}s status counts + */ + @Query(value = "SELECT a.status as name, COUNT(a.status) as data FROM JpaAction a WHERE a.distributionSet.id = :dsId GROUP BY a.status") + List countActionsByStatusForDistributionSet(@Param("dsId") Long dsId); + + /** + * Count total AutoAssignments for Distribution set. + * + * @param dsId + * to be found + * @return number of Auto Assignments for Distribution set + */ + @Query(value = "SELECT COUNT(f.autoAssignDistributionSet) FROM JpaTargetFilterQuery f WHERE f.autoAssignDistributionSet.id = :dsId GROUP BY f.autoAssignDistributionSet") + Long countAutoAssignmentsForDistributionSet(@Param("dsId") Long dsId); + /** * deletes the {@link DistributionSet}s with the given IDs. * diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index 4ef04ce55..73b6d589e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -57,6 +57,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.MetaData; import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.Statistic; import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.tenancy.TenantAware; @@ -160,6 +161,21 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { return distributionSetRepository.countByTypeId(typeId); } + @Override + public List countRolloutsByStatusForDistributionSet(Long dsId) { + return distributionSetRepository.countRolloutsByStatusForDistributionSet(dsId).stream().map(Statistic.class::cast).collect(Collectors.toList()); + } + + @Override + public List countActionsByStatusForDistributionSet(Long dsId) { + return distributionSetRepository.countActionsByStatusForDistributionSet(dsId).stream().map(Statistic.class::cast).collect(Collectors.toList()); + } + + @Override + public Long countAutoAssignmentsForDistributionSet(Long dsId) { + return distributionSetRepository.countAutoAssignmentsForDistributionSet(dsId); + } + @Override @Transactional @Retryable(include = { @@ -664,6 +680,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { } + + private void throwEntityNotFoundExceptionIfDsTagDoesNotExist(final Long tagId) { if (!distributionSetTagRepository.existsById(tagId)) { throw new EntityNotFoundException(DistributionSetTag.class, tagId); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java index 094342730..e95c8524d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java @@ -98,7 +98,6 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event @Convert("rolloutstatus") @NotNull private RolloutStatus status = RolloutStatus.CREATING; - @Column(name = "last_check") private long lastCheck; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaStatistic.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaStatistic.java new file mode 100644 index 000000000..137e5414d --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaStatistic.java @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2023 Bosch.IO GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.hawkbit.repository.jpa.model; + + +import org.eclipse.hawkbit.repository.model.Statistic; + +public interface JpaStatistic extends Statistic { + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java index 6ddf0f7fe..cc80508b9 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java @@ -55,7 +55,9 @@ import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.MetaData; import org.eclipse.hawkbit.repository.model.NamedEntity; import org.eclipse.hawkbit.repository.model.NamedVersionedEntity; +import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.Statistic; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.test.matcher.Expect; import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents; @@ -1157,6 +1159,67 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest { .updateMetaData(ds.getId(), entityFactory.generateDsMetadata(knownKey1, knownUpdateValue))); } + @Test + @Description("Get the Rollouts count by status statistics for a specific Distribution Set") + void getRolloutsCountStatisticsForDistributionSet() { + DistributionSet ds1 = testdataFactory.createDistributionSet("DS1"); + DistributionSet ds2 = testdataFactory.createDistributionSet("DS2"); + DistributionSet ds3 = testdataFactory.createDistributionSet("DS3"); + testdataFactory.createTargets("targets", 4); + Rollout rollout1 = testdataFactory.createRolloutByVariables("rollout1", "description", + 1, "name==targets*", ds1, "50", "5", false); + Rollout rollout2 = testdataFactory.createRolloutByVariables("rollout2", "description", + 1, "name==targets*", ds2, "50", "5", false); + + rolloutManagement.start(rollout2.getId()); + + assertThat(distributionSetManagement.countRolloutsByStatusForDistributionSet(ds1.getId())).hasSize(1); + assertThat(distributionSetManagement.countRolloutsByStatusForDistributionSet(ds2.getId())).hasSize(1); + assertThat(distributionSetManagement.countRolloutsByStatusForDistributionSet(ds3.getId())).isEmpty(); + + Optional rollout = rolloutManagement.get(rollout1.getId()); + rollout.ifPresent(value -> assertThat(Rollout.RolloutStatus.valueOf(String.valueOf(distributionSetManagement.countRolloutsByStatusForDistributionSet(ds1.getId()).get(0).getName()))).isEqualTo(value.getStatus())); + + rollout = rolloutManagement.get(rollout2.getId()); + rollout.ifPresent(value -> assertThat(Rollout.RolloutStatus.valueOf(String.valueOf(distributionSetManagement.countRolloutsByStatusForDistributionSet(ds2.getId()).get(0).getName()))).isEqualTo(value.getStatus())); + } + + @Test + @Description("Get the Rollouts count by status statistics for a specific Distribution Set") + void getActionsCountStatisticsForDistributionSet() { + DistributionSet ds = testdataFactory.createDistributionSet("DS"); + DistributionSet ds2 = testdataFactory.createDistributionSet("DS2"); + testdataFactory.createTargets("targets", 4); + Rollout rollout = testdataFactory.createRolloutByVariables("rollout", "description", + 1, "name==targets*", ds, "50", "5", false); + + rolloutManagement.start(rollout.getId()); + rolloutHandler.handleAll(); + + List statistics = distributionSetManagement.countActionsByStatusForDistributionSet(ds.getId()); + + assertThat(statistics).hasSize(1); + assertThat(distributionSetManagement.countActionsByStatusForDistributionSet(ds2.getId())).isEmpty(); + + statistics.forEach(statistic -> assertThat(Status.valueOf(String.valueOf(statistic.getName()))).isEqualTo(Status.RUNNING)); + } + + @Test + @Description("Get the Rollouts count by status statistics for a specific Distribution Set") + void getAutoAssignmentsCountStatisticsForDistributionSet() { + DistributionSet ds = testdataFactory.createDistributionSet("DS"); + DistributionSet ds2 = testdataFactory.createDistributionSet("DS2"); + testdataFactory.createTargets("targets", 4); + targetFilterQueryManagement.create( + entityFactory.targetFilterQuery().create().name("test filter 1").autoAssignDistributionSet(ds.getId()).query("name==targets*")); + + targetFilterQueryManagement.create( + entityFactory.targetFilterQuery().create().name("test filter 2").autoAssignDistributionSet(ds.getId()).query("name==targets*")); + + assertThat(distributionSetManagement.countAutoAssignmentsForDistributionSet(ds.getId())).isEqualTo(2); + assertThat(distributionSetManagement.countAutoAssignmentsForDistributionSet(ds2.getId())).isNull(); + } + // can be removed with java-11 private T getOrThrow(final Optional opt) { return opt.orElseThrow(NoSuchElementException::new); diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetStatistics.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetStatistics.java new file mode 100644 index 000000000..75ba4b208 --- /dev/null +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetStatistics.java @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2023 Bosch.IO GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.hawkbit.mgmt.json.model.distributionset; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class MgmtDistributionSetStatistics { + private static final String TOTAL = "total"; + + @JsonProperty + private Map totalActionsPerStatus; + + @JsonProperty + private Map totalRolloutsPerStatus; + + @JsonProperty + private Long totalAutoAssignments; + + private MgmtDistributionSetStatistics() { + // Private constructor to enforce the use of the builder pattern + } + + public Map getTotalActionsPerStatus() { + return totalActionsPerStatus; + } + + public Map getTotalRolloutsPerStatus() { + return totalRolloutsPerStatus; + } + + public Long getTotalAutoAssignments() { + return totalAutoAssignments; + } + + public static class Builder { + private Map totalActionsPerStatus; + private Map totalRolloutsPerStatus; + + private Long totalAutoAssignments; + + public Builder() { + totalActionsPerStatus = new HashMap<>(); + totalRolloutsPerStatus = new HashMap<>(); + } + + public Builder addTotalActionPerStatus(String status, Long count) { + totalActionsPerStatus.put(status, count); + return this; + } + + public Builder addTotalRolloutPerStatus(String status, Long count) { + totalRolloutsPerStatus.put(status, count); + return this; + } + + public Builder addTotalAutoAssignments(Long count) { + totalAutoAssignments = count; + return this; + } + + public MgmtDistributionSetStatistics build() { + MgmtDistributionSetStatistics statistics = new MgmtDistributionSetStatistics(); + statistics.totalActionsPerStatus = calculateTotalWithStatus(totalActionsPerStatus); + statistics.totalRolloutsPerStatus = calculateTotalWithStatus(totalRolloutsPerStatus); + statistics.totalAutoAssignments = totalAutoAssignments; + return statistics; + } + + private Map calculateTotalWithStatus(Map statusMap) { + if (statusMap.isEmpty()) { + return null; + } + + long total = statusMap.values().stream().mapToLong(Long::longValue).sum(); + statusMap.put(TOTAL, total); + return statusMap; + } + } +} + diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java index 92b479f61..a3af5b34b 100644 --- a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetRestApi.java @@ -18,6 +18,7 @@ import org.eclipse.hawkbit.mgmt.json.model.PagedList; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPut; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetStatistics; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtInvalidateDistributionSetRequestBody; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentRequestBody; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody; @@ -397,6 +398,62 @@ public interface MgmtDistributionSetRestApi { @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) int pagingLimitParam, @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) String sortParam); + /** + * Handles the GET request of retrieving Rollouts count by Status + * for Distribution Set. + * + * @param distributionSetId + * the ID of the set to retrieve + * + * @return a DistributionSetStatistics with status OK. + * + */ + @GetMapping(value = MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/statistics/rollouts", produces = { + MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getRolloutsCountByStatusForDistributionSet(@PathVariable("distributionSetId") Long distributionSetId); + + /** + * Handles the GET request of retrieving Actions count by Status + * for Distribution Set. + * + * @param distributionSetId + * the ID of the set to retrieve + * + * @return a DistributionSetStatistics with status OK. + * + */ + @GetMapping(value = MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/statistics/actions", produces = { + MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getActionsCountByStatusForDistributionSet(@PathVariable("distributionSetId") Long distributionSetId); + + /** + * Handles the GET request of retrieving Auto Assignments count + * for Distribution Set. + * + * @param distributionSetId + * the ID of the set to retrieve + * + * @return a DistributionSetStatistics with status OK. + * + */ + @GetMapping(value = MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/statistics/autoassignments", produces = { + MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getAutoAssignmentsCountForDistributionSet(@PathVariable("distributionSetId") Long distributionSetId); + + /** + * Handles the GET request of retrieving Rollouts, Actions and + * Auto Assignments counts by Status for Distribution Set. + * + * @param distributionSetId + * the ID of the set to retrieve + * + * @return a DistributionSetStatistics with status OK. + * + */ + @GetMapping(value = MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/statistics", produces = { + MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }) + ResponseEntity getStatisticsForDistributionSet(@PathVariable("distributionSetId") Long distributionSetId); + /** * Invalidates a distribution set * diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java index f7f74dde4..e3e58452d 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResource.java @@ -26,6 +26,7 @@ import org.eclipse.hawkbit.mgmt.json.model.PagedList; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPut; +import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetStatistics; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtInvalidateDistributionSetRequestBody; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentRequestBody; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody; @@ -414,6 +415,40 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi { softwaremodules.getTotalElements())); } + @Override + public ResponseEntity getRolloutsCountByStatusForDistributionSet(Long distributionSetId) { + MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(); + distributionSetManagement.countRolloutsByStatusForDistributionSet(distributionSetId).forEach(statistic -> + statistics.addTotalRolloutPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString()))); + return ResponseEntity.ok(statistics.build()); + } + + @Override + public ResponseEntity getActionsCountByStatusForDistributionSet(Long distributionSetId) { + MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(); + distributionSetManagement.countActionsByStatusForDistributionSet(distributionSetId).forEach(statistic -> + statistics.addTotalActionPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString()))); + return ResponseEntity.ok(statistics.build()); + } + + @Override + public ResponseEntity getAutoAssignmentsCountForDistributionSet(Long distributionSetId) { + MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(); + statistics.addTotalAutoAssignments(distributionSetManagement.countAutoAssignmentsForDistributionSet(distributionSetId)); + return ResponseEntity.ok(statistics.build()); + } + + @Override + public ResponseEntity getStatisticsForDistributionSet(Long distributionSetId) { + MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(); + distributionSetManagement.countRolloutsByStatusForDistributionSet(distributionSetId).forEach(statistic -> + statistics.addTotalRolloutPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString()))); + distributionSetManagement.countActionsByStatusForDistributionSet(distributionSetId).forEach(statistic -> + statistics.addTotalActionPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString()))); + statistics.addTotalAutoAssignments(distributionSetManagement.countAutoAssignmentsForDistributionSet(distributionSetId)); + return ResponseEntity.ok(statistics.build()); + } + @Override public ResponseEntity invalidateDistributionSet( @PathVariable("distributionSetId") final Long distributionSetId, diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java index 383f2f2db..8bdeeead3 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java @@ -77,7 +77,6 @@ import io.qameta.allure.Step; import io.qameta.allure.Story; import org.springframework.util.Assert; -import javax.validation.constraints.AssertTrue; @Feature("Component Tests - Management API") @Story("Distribution Set Resource") @@ -1442,6 +1441,130 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr assertThat(actions.get(0).getWeight()).get().isEqualTo(weight); } + @Test + @Description("Request to get the count of all Rollouts by status for specific Distribution set") + public void statisticsForRolloutsCountByStatus() throws Exception { + testdataFactory.createTargets("targets", 4); + DistributionSet ds1 = testdataFactory.createDistributionSet("DS1"); + DistributionSet ds2 = testdataFactory.createDistributionSet("DS2"); + + testdataFactory.createRolloutByVariables("rollout1", "description", + 1, "name==targets*", ds1, "50", "5", false); + Rollout rollout = testdataFactory.createRolloutByVariables("rollout2", "description", + 1, "name==targets*", ds1, "50", "5", false); + rolloutManagement.start(rollout.getId()); + rolloutHandler.handleAll(); + + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{ds}/statistics/rollouts", ds1.getId()).contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("totalRolloutsPerStatus.READY", equalTo(1))) + .andExpect(jsonPath("totalRolloutsPerStatus.RUNNING", equalTo(1))) + .andExpect(jsonPath("totalRolloutsPerStatus.total", equalTo(2))) + .andExpect(jsonPath("totalActionsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalAutoAssignments").doesNotExist()); + + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{ds}/statistics/rollouts", ds2.getId()).contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("totalRolloutsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalActionsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalAutoAssignments").doesNotExist()); + } + + @Test + @Description("Request to get the count of all Actions by status for specific Distribution set") + public void statisticsForActionsCountByStatus() throws Exception { + testdataFactory.createTargets("targets", 4); + + DistributionSet ds1 = testdataFactory.createDistributionSet("DS1"); + DistributionSet ds2 = testdataFactory.createDistributionSet("DS2"); + + Rollout rollout = testdataFactory.createRolloutByVariables("rollout", "description", + 1, "name==targets*", ds1, "50", "5", false); + rolloutManagement.start(rollout.getId()); + rolloutHandler.handleAll(); + + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{ds}/statistics/actions", ds1.getId()).contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("totalActionsPerStatus.RUNNING", equalTo(4))) + .andExpect(jsonPath("totalActionsPerStatus.total", equalTo(4))) + .andExpect(jsonPath("totalRolloutsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalAutoAssignments").doesNotExist()); + + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{ds}/statistics/actions", ds2.getId()).contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("totalRolloutsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalActionsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalAutoAssignments").doesNotExist()); + } + + @Test + @Description("Request to get the count of all Auto Assignments for specific Distribution set") + public void statisticsForAutoAssignmentsCount() throws Exception { + testdataFactory.createTargets("targets", 4); + DistributionSet ds1 = testdataFactory.createDistributionSet("DS1"); + DistributionSet ds2 = testdataFactory.createDistributionSet("DS2"); + + targetFilterQueryManagement.create( + entityFactory.targetFilterQuery().create().name("test filter 1").autoAssignDistributionSet(ds1.getId()).query("name==targets*")); + + targetFilterQueryManagement.create( + entityFactory.targetFilterQuery().create().name("test filter 2").autoAssignDistributionSet(ds1.getId()).query("name==targets*")); + + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{ds}/statistics/autoassignments", ds1.getId()).contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("totalAutoAssignments", equalTo(2))) + .andExpect(jsonPath("totalRolloutsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalActionsPerStatus").doesNotExist()); + + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{ds}/statistics/autoassignments", ds2.getId()).contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("totalRolloutsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalActionsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalAutoAssignments").doesNotExist()); + } + + @Test + @Description("Request to get full Statistics for specific Distribution set") + public void statisticsForDistributionSet() throws Exception { + testdataFactory.createTargets("targets", 4); + testdataFactory.createTargets("autoAssignments", 4); + DistributionSet ds1 = testdataFactory.createDistributionSet("DS1"); + DistributionSet ds2 = testdataFactory.createDistributionSet("DS2"); + + targetFilterQueryManagement.create( + entityFactory.targetFilterQuery().create().name("test filter 1").autoAssignDistributionSet(ds1.getId()).query("name==autoAssignments*")); + + Rollout rollout = testdataFactory.createRolloutByVariables("rollout", "description", + 1, "name==targets*", ds1, "50", "5", false); + rolloutManagement.start(rollout.getId()); + rolloutHandler.handleAll(); + + + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{ds}/statistics", ds1.getId()).contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("totalAutoAssignments", equalTo(1))) + .andExpect(jsonPath("totalActionsPerStatus.RUNNING", equalTo(4))) + .andExpect(jsonPath("totalActionsPerStatus.total", equalTo(4))) + .andExpect(jsonPath("totalRolloutsPerStatus.RUNNING", equalTo(1))) + .andExpect(jsonPath("totalRolloutsPerStatus.total", equalTo(1))); + + + mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{ds}/statistics/autoassignments", ds2.getId()).contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("totalRolloutsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalActionsPerStatus").doesNotExist()) + .andExpect(jsonPath("totalAutoAssignments").doesNotExist()); + } + + @Test @Description("Verify invalidation of distribution sets that removes distribution sets from auto assignments, stops rollouts and cancels assignments") public void invalidateDistributionSet() throws Exception {