From 0fc076aacad4f7ed837f25aadb8c05ae04e103a1 Mon Sep 17 00:00:00 2001 From: Avgustin Marinov Date: Fri, 7 Feb 2025 12:32:51 +0200 Subject: [PATCH] Optimize DB usage on DDI REST API calls (#2264) Signed-off-by: Avgustin Marinov --- .../ddi/rest/resource/DdiRootController.java | 11 +- .../repository/ControllerManagement.java | 21 ++-- .../management/JpaControllerManagement.java | 62 +++------- .../repository/jpa/model/JpaAction.java | 107 ++++-------------- .../ControllerManagementSecurityTest.java | 34 +++++- .../management/RolloutManagementFlowTest.java | 37 +++++- .../java/org/eclipse/hawkbit/util/IpUtil.java | 12 +- 7 files changed, 124 insertions(+), 160 deletions(-) diff --git a/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java b/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java index 14c9a263f..8096ef28d 100644 --- a/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java +++ b/hawkbit-ddi/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java @@ -161,11 +161,10 @@ public class DdiRootController implements DdiRootControllerRestApi { public ResponseEntity getControllerBase(final String tenant, final String controllerId) { log.debug("getControllerBase({})", controllerId); - final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, IpUtil - .getClientIpFromRequest(RequestResponseContextHolder.getHttpServletRequest(), securityProperties)); + final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist( + controllerId, IpUtil.getClientIpFromRequest(RequestResponseContextHolder.getHttpServletRequest(), securityProperties)); final Action activeAction = controllerManagement.findActiveActionWithHighestWeight(controllerId).orElse(null); - - final Action installedAction = controllerManagement.getInstalledActionByTarget(controllerId).orElse(null); + final Action installedAction = controllerManagement.getInstalledActionByTarget(target).orElse(null); checkAndCancelExpiredAction(activeAction); @@ -173,7 +172,7 @@ public class DdiRootController implements DdiRootControllerRestApi { return new ResponseEntity<>(DataConversionHelper.fromTarget(target, installedAction, activeAction, activeAction == null ? controllerManagement.getPollingTime() - : controllerManagement.getPollingTimeForAction(activeAction.getId()), tenantAware), + : controllerManagement.getPollingTimeForAction(activeAction), tenantAware), HttpStatus.OK); } @@ -733,7 +732,7 @@ public class DdiRootController implements DdiRootControllerRestApi { private void checkAndCancelExpiredAction(final Action action) { if (action != null && action.hasMaintenanceSchedule() && action.isMaintenanceScheduleLapsed()) { try { - controllerManagement.cancelAction(action.getId()); + controllerManagement.cancelAction(action); } catch (final CancelActionNotAllowedException e) { log.info("Cancel action not allowed: {}", e.getMessage()); } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java index 8fd132ede..32218c302 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java @@ -105,7 +105,7 @@ public interface ControllerManagement { /** * Retrieves active {@link Action} with the highest priority that is assigned to a {@link Target}. - * + *

* For performance reasons this method does not throw {@link EntityNotFoundException} in case target with given controllerId * does not exist but will return an {@link Optional#empty()} instead. * @@ -202,7 +202,7 @@ public interface ControllerManagement { String getMinPollingTime(); /** - * Returns the count to be used for reducing polling interval while calling {@link ControllerManagement#getPollingTimeForAction(long)}. + * Returns the count to be used for reducing polling interval while calling {@link ControllerManagement#getPollingTimeForAction(Action)}. * * @return configured value of {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}. */ @@ -215,11 +215,11 @@ public interface ControllerManagement { * Poll time keeps reducing with MinPollingTime as lower limit {@link TenantConfigurationKey#MIN_POLLING_TIME_INTERVAL}. After the start * of maintenance window, it resets to default {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}. * - * @param actionId id the {@link Action} for which polling time is calculated based on it having maintenance window or not + * @param action {@link Action} for which polling time is calculated based on it having maintenance window or not * @return current {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}. */ @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - String getPollingTimeForAction(long actionId); + String getPollingTimeForAction(Action action); /** * Checks if a given target has currently or has even been assigned to the given artifact through the action history list. This can e.g. @@ -315,16 +315,17 @@ public interface ControllerManagement { List getActionHistoryMessages(long actionId, int messageCount); /** - * Cancels given {@link Action} for this {@link Target}. However, it might be possible that the controller will continue to work on the - * cancellation. The controller needs to acknowledge or reject the cancellation using {@link DdiRootController#postCancelActionFeedback}. + * Cancels given {@link Action} for this {@link Target}. The method will immediately add a {@link Status#CANCELED}. + * However, it might be possible that the controller will continue to work on the cancellation. The controller needs to acknowledge or + * reject the cancellation using DdiRootController#postCancelActionFeedback * - * @param actionId to be canceled + * @param action to be canceled * @return canceled {@link Action} * @throws CancelActionNotAllowedException in case the given action is not active or is already canceled * @throws EntityNotFoundException if action with given actionId does not exist. */ @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Action cancelAction(long actionId); + Action cancelAction(Action action); /** * Updates given {@link Action} with its external id. @@ -355,10 +356,10 @@ public interface ControllerManagement { /** * Finds an {@link Action} based on the target that it's assigned to * - * @param controllerId of the target the action is assigned to + * @param target the target the action is assigned to */ @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Optional getInstalledActionByTarget(@NotEmpty String controllerId); + Optional getInstalledActionByTarget(@NotNull Target target); /** * Activate auto confirmation for a given controllerId diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java index 4e5881a95..96b1f75ab 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java @@ -389,8 +389,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont } /** - * Returns the count to be used for reducing polling interval while calling - * {@link ControllerManagement#getPollingTimeForAction(long)}. + * Returns the count to be used for reducing polling interval while calling {@link ControllerManagement#getPollingTimeForAction(Action)}. * * @return configured value of * {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}. @@ -402,10 +401,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont } @Override - public String getPollingTimeForAction(final long actionId) { - - final JpaAction action = getActionAndThrowExceptionIfNotFound(actionId); - + public String getPollingTimeForAction(final Action action) { if (!action.hasMaintenanceSchedule() || action.isMaintenanceScheduleLapsed()) { return getPollingTime(); } @@ -505,52 +501,35 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont return messages.getContent(); } - /** - * Cancels given {@link Action} for this {@link Target}. The method will - * immediately add a {@link Status#CANCELED} status to the action. However, - * it might be possible that the controller will continue to work on the - * cancellation. The controller needs to acknowledge or reject the - * cancellation using {@link DdiRootController#postCancelActionFeedback}. - * - * @param actionId to be canceled - * @return canceled {@link Action} - * @throws CancelActionNotAllowedException in case the given action is not active or is already canceled - * @throws EntityNotFoundException if action with given actionId does not exist. - */ @Override @Modifying @Transactional(isolation = Isolation.READ_COMMITTED) - public Action cancelAction(final long actionId) { - log.debug("cancelAction({})", actionId); - - final JpaAction action = actionRepository.findById(actionId) - .orElseThrow(() -> new EntityNotFoundException(Action.class, actionId)); - + public Action cancelAction(final Action action) { + log.debug("cancelAction({})", action.getId()); if (action.isCancelingOrCanceled()) { throw new CancelActionNotAllowedException("Actions in canceling or canceled state cannot be canceled"); } if (action.isActive()) { log.debug("action ({}) was still active. Change to {}.", action, Status.CANCELING); - action.setStatus(Status.CANCELING); + final JpaAction jpaAction = (JpaAction)action; + jpaAction.setStatus(Status.CANCELING); // document that the status has been retrieved - actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(), - "manual cancelation requested")); - final Action saveAction = actionRepository.save(action); - cancelAssignDistributionSetEvent(action); + actionStatusRepository.save( + new JpaActionStatus(jpaAction, Status.CANCELING, System.currentTimeMillis(), "manual cancelation requested")); + final Action saveAction = actionRepository.save(jpaAction); + cancelAssignDistributionSetEvent(jpaAction); return saveAction; } else { - throw new CancelActionNotAllowedException( - "Action [id: " + action.getId() + "] is not active and cannot be canceled"); + throw new CancelActionNotAllowedException("Action [id: " + action.getId() + "] is not active and cannot be canceled"); } } @Override public void updateActionExternalRef(final long actionId, @NotEmpty final String externalRef) { - // if access control for target repository is present check that caller has - // UPDATE access to the target of the action + // if access control for target repository is present check that caller has UPDATE access to the target of the action targetRepository.getAccessController().ifPresent( accessController -> accessController.assertOperationAllowed( AccessController.Operation.UPDATE, @@ -574,20 +553,15 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont } @Override - public Optional getInstalledActionByTarget(final String controllerId) { - final JpaDistributionSet installedDistributionSet = targetRepository.getByControllerId(controllerId).getInstalledDistributionSet(); - if (installedDistributionSet != null) { - final JpaTarget jpaTarget = targetRepository.getByControllerId(controllerId); - return actionRepository.findFirstByTargetIdAndDistributionSetIdAndStatusOrderByIdDesc( - jpaTarget.getId(), installedDistributionSet.getId(), FINISHED); - } else { - return Optional.empty(); - } + public Optional getInstalledActionByTarget(final Target target) { + final JpaTarget jpaTarget = (JpaTarget) target; + return Optional.ofNullable(jpaTarget.getInstalledDistributionSet()) + .flatMap(installedDistributionSet -> actionRepository.findFirstByTargetIdAndDistributionSetIdAndStatusOrderByIdDesc( + jpaTarget.getId(), installedDistributionSet.getId(), FINISHED)); } @Override - public AutoConfirmationStatus activateAutoConfirmation(final String controllerId, final String initiator, - final String remark) { + public AutoConfirmationStatus activateAutoConfirmation(final String controllerId, final String initiator, final String remark) { return confirmationManagement.activateAutoConfirmation(controllerId, initiator, remark); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java index 18f801c54..499cb83ed 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java @@ -40,6 +40,7 @@ import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; +import lombok.Getter; import lombok.Setter; import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper; import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent; @@ -82,6 +83,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio @Serial private static final long serialVersionUID = 1L; + @Getter @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn( name = "distribution_set", nullable = false, updatable = false, @@ -89,6 +91,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio @NotNull private JpaDistributionSet distributionSet; + @Getter @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn( name = "target", updatable = false, @@ -96,14 +99,20 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio @NotNull private JpaTarget target; + @Setter + @Getter @Column(name = "active") private boolean active; + @Setter + @Getter @Column(name = "action_type", nullable = false) @Convert(converter = ActionTypeConverter.class) @NotNull private ActionType actionType; + @Setter + @Getter @Column(name = "forced_time") private long forcedTime; @@ -113,6 +122,8 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio @Max(Action.WEIGHT_MAX) private Integer weight; + @Setter + @Getter @Column(name = "status", nullable = false) @Convert(converter = StatusConverter.class) @NotNull @@ -121,12 +132,14 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio @OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE }) private List actionStatus = new ArrayList<>(); + @Getter @ManyToOne(fetch = FetchType.LAZY) @JoinColumn( name = "rolloutgroup", updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup")) private JpaRolloutGroup rolloutGroup; + @Getter @ManyToOne(fetch = FetchType.LAZY) @JoinColumn( name = "rollout", updatable = false, @@ -135,24 +148,30 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio // a cron expression to be used for scheduling. @Setter + @Getter @Column(name = "maintenance_cron_schedule", updatable = false, length = Action.MAINTENANCE_WINDOW_SCHEDULE_LENGTH) private String maintenanceWindowSchedule; // the duration of an available maintenance schedule indexes HH:mm:ss format @Setter + @Getter @Column(name = "maintenance_duration", updatable = false, length = Action.MAINTENANCE_WINDOW_DURATION_LENGTH) private String maintenanceWindowDuration; // the time zone specified as +/-hh:mm offset from UTC for example +02:00 for CET summer time and +00:00 for UTC. The // start time of a maintenance window calculated based on the cron expression is relative to this time zone. @Setter + @Getter @Column(name = "maintenance_time_zone", updatable = false, length = Action.MAINTENANCE_WINDOW_TIMEZONE_LENGTH) private String maintenanceWindowTimeZone; + @Setter + @Getter @Column(name = "external_ref", length = Action.EXTERNAL_REF_MAX_LENGTH) private String externalRef; @Setter + @Getter @Column(name = "initiated_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH) private String initiatedBy; @@ -160,113 +179,27 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio @Column(name = "last_action_status_code", nullable = true, updatable = true) private Integer lastActionStatusCode; - @Override - public DistributionSet getDistributionSet() { - return distributionSet; - } - public void setDistributionSet(final DistributionSet distributionSet) { this.distributionSet = (JpaDistributionSet) distributionSet; } - @Override - public Status getStatus() { - return status; - } - - public void setStatus(final Status status) { - this.status = status; - } - - @Override - public boolean isActive() { - return active; - } - - public void setActive(final boolean active) { - this.active = active; - } - - @Override - public ActionType getActionType() { - return actionType; - } - - public void setActionType(final ActionType actionType) { - this.actionType = actionType; - } - - @Override - public Target getTarget() { - return target; - } - public void setTarget(final Target target) { this.target = (JpaTarget) target; } - @Override - public long getForcedTime() { - return forcedTime; - } - - public void setForcedTime(final long forcedTime) { - this.forcedTime = forcedTime; - } - @Override public Optional getWeight() { return Optional.ofNullable(weight); } - @Override - public RolloutGroup getRolloutGroup() { - return rolloutGroup; - } - public void setRolloutGroup(final RolloutGroup rolloutGroup) { this.rolloutGroup = (JpaRolloutGroup) rolloutGroup; } - @Override - public Rollout getRollout() { - return rollout; - } - public void setRollout(final Rollout rollout) { this.rollout = (JpaRollout) rollout; } - @Override - public String getMaintenanceWindowSchedule() { - return maintenanceWindowSchedule; - } - - @Override - public String getMaintenanceWindowDuration() { - return maintenanceWindowDuration; - } - - @Override - public String getMaintenanceWindowTimeZone() { - return maintenanceWindowTimeZone; - } - - @Override - public String getExternalRef() { - return externalRef; - } - - @Override - public void setExternalRef(final String externalRef) { - this.externalRef = externalRef; - } - - @Override - public String getInitiatedBy() { - return initiatedBy; - } - @Override public Optional getLastActionStatusCode() { return Optional.ofNullable(lastActionStatusCode); @@ -285,7 +218,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio @Override public boolean isMaintenanceScheduleLapsed() { - return !getMaintenanceWindowStartTime().isPresent(); + return getMaintenanceWindowStartTime().isEmpty(); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ControllerManagementSecurityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ControllerManagementSecurityTest.java index f616024e0..89e99ee8e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ControllerManagementSecurityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ControllerManagementSecurityTest.java @@ -17,7 +17,12 @@ import io.qameta.allure.Description; import io.qameta.allure.Feature; import io.qameta.allure.Story; import org.eclipse.hawkbit.im.authentication.SpPermission; +import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.model.Target; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Pageable; @@ -130,7 +135,16 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest { @Test @Description("Tests ControllerManagement#getPollingTimeForAction() method") void getPollingTimeForActionPermissionsCheck() { - assertPermissions(() -> controllerManagement.getPollingTimeForAction(1L), List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE)); + final JpaAction action = new JpaAction(); + action.setId(1L); + assertPermissions(() -> { + try { + controllerManagement.getPollingTimeForAction(action); + } catch (final CancelActionNotAllowedException e) { + // expected since action is not found + } + return null; + }, List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE)); } @Test @@ -180,7 +194,16 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest { @Test @Description("Tests ControllerManagement#cancelAction() method") void cancelActionPermissionsCheck() { - assertPermissions(() -> controllerManagement.cancelAction(1L), List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE)); + final JpaAction action = new JpaAction(); + action.setId(1L); + assertPermissions(() -> { + try { + controllerManagement.cancelAction(action); + } catch (final CancelActionNotAllowedException e) { + // expected since action is not found + } + return null; + }, List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE)); } @Test @@ -211,14 +234,17 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest { @Test @Description("Tests ControllerManagement#getInstalledActionByTarget() method") void getInstalledActionByTargetPermissionsCheck() { - assertPermissions(() -> controllerManagement.getInstalledActionByTarget("controllerId"), + final Target target = testdataFactory.createTarget(); + assertPermissions( + () -> controllerManagement.getInstalledActionByTarget(target), List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE)); } @Test @Description("Tests ControllerManagement#activateAutoConfirmation() method") void activateAutoConfirmationPermissionsCheck() { - assertPermissions(() -> controllerManagement.activateAutoConfirmation("controllerId", "initiator", "remark"), + assertPermissions( + () -> controllerManagement.activateAutoConfirmation("controllerId", "initiator", "remark"), List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE)); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementFlowTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementFlowTest.java index f5e7c4556..96885ba91 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementFlowTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/RolloutManagementFlowTest.java @@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.management; import static org.assertj.core.api.Assertions.assertThat; +import java.net.URI; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -19,6 +20,7 @@ import io.qameta.allure.Feature; import io.qameta.allure.Story; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate; +import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.model.Action; @@ -27,10 +29,14 @@ import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.util.IpUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.test.context.TestPropertySource; /** @@ -38,7 +44,13 @@ import org.springframework.test.context.TestPropertySource; */ @Feature("Component Tests - Repository") @Story("Rollout Management (Flow)") -@TestPropertySource(properties = { "hawkbit.server.repository.dynamicRolloutsMinInvolvePeriodMS=-1" }) +@TestPropertySource(properties = { "hawkbit.server.repository.dynamicRolloutsMinInvolvePeriodMS=-1", + "logging.level.org.eclipse.persistence=DEBUG", + "spring.jpa.properties.eclipselink.logging.level=FINE", + "spring.jpa.properties.eclipselink.logging.level.sql=FINE", + "spring.jpa.properties.eclipselink.logging.parameters=true", + "logging.level.org.hibernate.SQL=TRACE", + "logging.level.org.hibernate.stat=TRACE"}) class RolloutManagementFlowTest extends AbstractJpaIntegrationTest { @BeforeEach @@ -73,6 +85,29 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest { assertGroup(groups.get(i), false, i == 0 ? RolloutGroupStatus.RUNNING : RolloutGroupStatus.SCHEDULED, 3); } + System.out.println("--------------------------"); + final String controllerId = targetPrefix + 1; + final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, URI.create("http://***")); + System.out.println("--------------------------1"); + final Action activeAction = controllerManagement.findActiveActionWithHighestWeight(controllerId).orElse(null); + System.out.println("--------------------------2"); + final Action installedAction = controllerManagement.getInstalledActionByTarget(target).orElse(null); + System.out.println("--------------------------3"); + + if (activeAction != null && activeAction.hasMaintenanceSchedule() && activeAction.isMaintenanceScheduleLapsed()) { + try { + controllerManagement.cancelAction(activeAction); + System.out.println("--------------------------4"); + } catch (final CancelActionNotAllowedException e) { + e.printStackTrace(); + } + } + + var t = activeAction == null + ? controllerManagement.getPollingTime() + : controllerManagement.getPollingTimeForAction(activeAction); + System.out.println("--------------------------"); + executeStaticWithoutOneTargetFromTheLastGroupAndHandleAll(groups, rollout, amountGroups); rolloutManagement.pauseRollout(rollout.getId()); diff --git a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java b/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java index b9921a45f..4579f1ee3 100644 --- a/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java +++ b/hawkbit-security/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java @@ -53,11 +53,9 @@ public final class IpUtil { * @return the {@link URI} based IP address from the client which sent the * request */ - public static URI getClientIpFromRequest(final HttpServletRequest request, - final HawkbitSecurityProperties securityProperties) { - - return getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader(), - securityProperties.getClients().isTrackRemoteIp()); + public static URI getClientIpFromRequest(final HttpServletRequest request, final HawkbitSecurityProperties securityProperties) { + return getClientIpFromRequest( + request, securityProperties.getClients().getRemoteIpHeader(), securityProperties.getClients().isTrackRemoteIp()); } /** @@ -145,10 +143,8 @@ public final class IpUtil { return uri != null && !(AMQP_SCHEME.equals(uri.getScheme()) || HIDDEN_IP.equals(uri.getHost())); } - private static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader, - final boolean trackRemoteIp) { + private static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader, final boolean trackRemoteIp) { String ip; - if (trackRemoteIp) { ip = request.getHeader(forwardHeader); if (ip == null || (ip = findClientIpAddress(ip)) == null) {