Optimize DB usage on DDI REST API calls (#2264)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -161,11 +161,10 @@ public class DdiRootController implements DdiRootControllerRestApi {
|
|||||||
public ResponseEntity<DdiControllerBase> getControllerBase(final String tenant, final String controllerId) {
|
public ResponseEntity<DdiControllerBase> getControllerBase(final String tenant, final String controllerId) {
|
||||||
log.debug("getControllerBase({})", controllerId);
|
log.debug("getControllerBase({})", controllerId);
|
||||||
|
|
||||||
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, IpUtil
|
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(
|
||||||
.getClientIpFromRequest(RequestResponseContextHolder.getHttpServletRequest(), securityProperties));
|
controllerId, IpUtil.getClientIpFromRequest(RequestResponseContextHolder.getHttpServletRequest(), securityProperties));
|
||||||
final Action activeAction = controllerManagement.findActiveActionWithHighestWeight(controllerId).orElse(null);
|
final Action activeAction = controllerManagement.findActiveActionWithHighestWeight(controllerId).orElse(null);
|
||||||
|
final Action installedAction = controllerManagement.getInstalledActionByTarget(target).orElse(null);
|
||||||
final Action installedAction = controllerManagement.getInstalledActionByTarget(controllerId).orElse(null);
|
|
||||||
|
|
||||||
checkAndCancelExpiredAction(activeAction);
|
checkAndCancelExpiredAction(activeAction);
|
||||||
|
|
||||||
@@ -173,7 +172,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
|
|||||||
return new ResponseEntity<>(DataConversionHelper.fromTarget(target, installedAction, activeAction,
|
return new ResponseEntity<>(DataConversionHelper.fromTarget(target, installedAction, activeAction,
|
||||||
activeAction == null
|
activeAction == null
|
||||||
? controllerManagement.getPollingTime()
|
? controllerManagement.getPollingTime()
|
||||||
: controllerManagement.getPollingTimeForAction(activeAction.getId()), tenantAware),
|
: controllerManagement.getPollingTimeForAction(activeAction), tenantAware),
|
||||||
HttpStatus.OK);
|
HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,7 +732,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
|
|||||||
private void checkAndCancelExpiredAction(final Action action) {
|
private void checkAndCancelExpiredAction(final Action action) {
|
||||||
if (action != null && action.hasMaintenanceSchedule() && action.isMaintenanceScheduleLapsed()) {
|
if (action != null && action.hasMaintenanceSchedule() && action.isMaintenanceScheduleLapsed()) {
|
||||||
try {
|
try {
|
||||||
controllerManagement.cancelAction(action.getId());
|
controllerManagement.cancelAction(action);
|
||||||
} catch (final CancelActionNotAllowedException e) {
|
} catch (final CancelActionNotAllowedException e) {
|
||||||
log.info("Cancel action not allowed: {}", e.getMessage());
|
log.info("Cancel action not allowed: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ public interface ControllerManagement {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves active {@link Action} with the highest priority that is assigned to a {@link Target}.
|
* Retrieves active {@link Action} with the highest priority that is assigned to a {@link Target}.
|
||||||
*
|
* <p/>
|
||||||
* For performance reasons this method does not throw {@link EntityNotFoundException} in case target with given controllerId
|
* 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.
|
* does not exist but will return an {@link Optional#empty()} instead.
|
||||||
*
|
*
|
||||||
@@ -202,7 +202,7 @@ public interface ControllerManagement {
|
|||||||
String getMinPollingTime();
|
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}.
|
* @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
|
* 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}.
|
* 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}.
|
* @return current {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}.
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
@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.
|
* 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<String> getActionHistoryMessages(long actionId, int messageCount);
|
List<String> 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
|
* Cancels given {@link Action} for this {@link Target}. The method will immediately add a {@link Status#CANCELED}.
|
||||||
* cancellation. The controller needs to acknowledge or reject the cancellation using {@link DdiRootController#postCancelActionFeedback}.
|
* 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}
|
* @return canceled {@link Action}
|
||||||
* @throws CancelActionNotAllowedException in case the given action is not active or is already canceled
|
* @throws CancelActionNotAllowedException in case the given action is not active or is already canceled
|
||||||
* @throws EntityNotFoundException if action with given actionId does not exist.
|
* @throws EntityNotFoundException if action with given actionId does not exist.
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||||
Action cancelAction(long actionId);
|
Action cancelAction(Action action);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates given {@link Action} with its external id.
|
* 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
|
* 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)
|
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||||
Optional<Action> getInstalledActionByTarget(@NotEmpty String controllerId);
|
Optional<Action> getInstalledActionByTarget(@NotNull Target target);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate auto confirmation for a given controllerId
|
* Activate auto confirmation for a given controllerId
|
||||||
|
|||||||
@@ -389,8 +389,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the count to be used for reducing polling interval while calling
|
* Returns the count to be used for reducing polling interval while calling {@link ControllerManagement#getPollingTimeForAction(Action)}.
|
||||||
* {@link ControllerManagement#getPollingTimeForAction(long)}.
|
|
||||||
*
|
*
|
||||||
* @return configured value of
|
* @return configured value of
|
||||||
* {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}.
|
* {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}.
|
||||||
@@ -402,10 +401,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPollingTimeForAction(final long actionId) {
|
public String getPollingTimeForAction(final Action action) {
|
||||||
|
|
||||||
final JpaAction action = getActionAndThrowExceptionIfNotFound(actionId);
|
|
||||||
|
|
||||||
if (!action.hasMaintenanceSchedule() || action.isMaintenanceScheduleLapsed()) {
|
if (!action.hasMaintenanceSchedule() || action.isMaintenanceScheduleLapsed()) {
|
||||||
return getPollingTime();
|
return getPollingTime();
|
||||||
}
|
}
|
||||||
@@ -505,52 +501,35 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
|||||||
return messages.getContent();
|
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
|
@Override
|
||||||
@Modifying
|
@Modifying
|
||||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||||
public Action cancelAction(final long actionId) {
|
public Action cancelAction(final Action action) {
|
||||||
log.debug("cancelAction({})", actionId);
|
log.debug("cancelAction({})", action.getId());
|
||||||
|
|
||||||
final JpaAction action = actionRepository.findById(actionId)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
|
||||||
|
|
||||||
if (action.isCancelingOrCanceled()) {
|
if (action.isCancelingOrCanceled()) {
|
||||||
throw new CancelActionNotAllowedException("Actions in canceling or canceled state cannot be canceled");
|
throw new CancelActionNotAllowedException("Actions in canceling or canceled state cannot be canceled");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.isActive()) {
|
if (action.isActive()) {
|
||||||
log.debug("action ({}) was still active. Change to {}.", action, Status.CANCELING);
|
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
|
// document that the status has been retrieved
|
||||||
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(),
|
actionStatusRepository.save(
|
||||||
"manual cancelation requested"));
|
new JpaActionStatus(jpaAction, Status.CANCELING, System.currentTimeMillis(), "manual cancelation requested"));
|
||||||
final Action saveAction = actionRepository.save(action);
|
final Action saveAction = actionRepository.save(jpaAction);
|
||||||
cancelAssignDistributionSetEvent(action);
|
|
||||||
|
|
||||||
|
cancelAssignDistributionSetEvent(jpaAction);
|
||||||
return saveAction;
|
return saveAction;
|
||||||
} else {
|
} else {
|
||||||
throw new CancelActionNotAllowedException(
|
throw new CancelActionNotAllowedException("Action [id: " + action.getId() + "] is not active and cannot be canceled");
|
||||||
"Action [id: " + action.getId() + "] is not active and cannot be canceled");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateActionExternalRef(final long actionId, @NotEmpty final String externalRef) {
|
public void updateActionExternalRef(final long actionId, @NotEmpty final String externalRef) {
|
||||||
// if access control for target repository is present check that caller has
|
// if access control for target repository is present check that caller has UPDATE access to the target of the action
|
||||||
// UPDATE access to the target of the action
|
|
||||||
targetRepository.getAccessController().ifPresent(
|
targetRepository.getAccessController().ifPresent(
|
||||||
accessController -> accessController.assertOperationAllowed(
|
accessController -> accessController.assertOperationAllowed(
|
||||||
AccessController.Operation.UPDATE,
|
AccessController.Operation.UPDATE,
|
||||||
@@ -574,20 +553,15 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Action> getInstalledActionByTarget(final String controllerId) {
|
public Optional<Action> getInstalledActionByTarget(final Target target) {
|
||||||
final JpaDistributionSet installedDistributionSet = targetRepository.getByControllerId(controllerId).getInstalledDistributionSet();
|
final JpaTarget jpaTarget = (JpaTarget) target;
|
||||||
if (installedDistributionSet != null) {
|
return Optional.ofNullable(jpaTarget.getInstalledDistributionSet())
|
||||||
final JpaTarget jpaTarget = targetRepository.getByControllerId(controllerId);
|
.flatMap(installedDistributionSet -> actionRepository.findFirstByTargetIdAndDistributionSetIdAndStatusOrderByIdDesc(
|
||||||
return actionRepository.findFirstByTargetIdAndDistributionSetIdAndStatusOrderByIdDesc(
|
jpaTarget.getId(), installedDistributionSet.getId(), FINISHED));
|
||||||
jpaTarget.getId(), installedDistributionSet.getId(), FINISHED);
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AutoConfirmationStatus activateAutoConfirmation(final String controllerId, final String initiator,
|
public AutoConfirmationStatus activateAutoConfirmation(final String controllerId, final String initiator, final String remark) {
|
||||||
final String remark) {
|
|
||||||
return confirmationManagement.activateAutoConfirmation(controllerId, initiator, remark);
|
return confirmationManagement.activateAutoConfirmation(controllerId, initiator, remark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import jakarta.validation.constraints.Max;
|
|||||||
import jakarta.validation.constraints.Min;
|
import jakarta.validation.constraints.Min;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
|
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
||||||
@@ -82,6 +83,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Getter
|
||||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||||
@JoinColumn(
|
@JoinColumn(
|
||||||
name = "distribution_set", nullable = false, updatable = false,
|
name = "distribution_set", nullable = false, updatable = false,
|
||||||
@@ -89,6 +91,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
@NotNull
|
@NotNull
|
||||||
private JpaDistributionSet distributionSet;
|
private JpaDistributionSet distributionSet;
|
||||||
|
|
||||||
|
@Getter
|
||||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||||
@JoinColumn(
|
@JoinColumn(
|
||||||
name = "target", updatable = false,
|
name = "target", updatable = false,
|
||||||
@@ -96,14 +99,20 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
@NotNull
|
@NotNull
|
||||||
private JpaTarget target;
|
private JpaTarget target;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
@Column(name = "active")
|
@Column(name = "active")
|
||||||
private boolean active;
|
private boolean active;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
@Column(name = "action_type", nullable = false)
|
@Column(name = "action_type", nullable = false)
|
||||||
@Convert(converter = ActionTypeConverter.class)
|
@Convert(converter = ActionTypeConverter.class)
|
||||||
@NotNull
|
@NotNull
|
||||||
private ActionType actionType;
|
private ActionType actionType;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
@Column(name = "forced_time")
|
@Column(name = "forced_time")
|
||||||
private long forcedTime;
|
private long forcedTime;
|
||||||
|
|
||||||
@@ -113,6 +122,8 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
@Max(Action.WEIGHT_MAX)
|
@Max(Action.WEIGHT_MAX)
|
||||||
private Integer weight;
|
private Integer weight;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
@Column(name = "status", nullable = false)
|
@Column(name = "status", nullable = false)
|
||||||
@Convert(converter = StatusConverter.class)
|
@Convert(converter = StatusConverter.class)
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -121,12 +132,14 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
@OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE })
|
@OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE })
|
||||||
private List<JpaActionStatus> actionStatus = new ArrayList<>();
|
private List<JpaActionStatus> actionStatus = new ArrayList<>();
|
||||||
|
|
||||||
|
@Getter
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(
|
@JoinColumn(
|
||||||
name = "rolloutgroup", updatable = false,
|
name = "rolloutgroup", updatable = false,
|
||||||
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup"))
|
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup"))
|
||||||
private JpaRolloutGroup rolloutGroup;
|
private JpaRolloutGroup rolloutGroup;
|
||||||
|
|
||||||
|
@Getter
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(
|
@JoinColumn(
|
||||||
name = "rollout", updatable = false,
|
name = "rollout", updatable = false,
|
||||||
@@ -135,24 +148,30 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
|
|
||||||
// a cron expression to be used for scheduling.
|
// a cron expression to be used for scheduling.
|
||||||
@Setter
|
@Setter
|
||||||
|
@Getter
|
||||||
@Column(name = "maintenance_cron_schedule", updatable = false, length = Action.MAINTENANCE_WINDOW_SCHEDULE_LENGTH)
|
@Column(name = "maintenance_cron_schedule", updatable = false, length = Action.MAINTENANCE_WINDOW_SCHEDULE_LENGTH)
|
||||||
private String maintenanceWindowSchedule;
|
private String maintenanceWindowSchedule;
|
||||||
|
|
||||||
// the duration of an available maintenance schedule indexes HH:mm:ss format
|
// the duration of an available maintenance schedule indexes HH:mm:ss format
|
||||||
@Setter
|
@Setter
|
||||||
|
@Getter
|
||||||
@Column(name = "maintenance_duration", updatable = false, length = Action.MAINTENANCE_WINDOW_DURATION_LENGTH)
|
@Column(name = "maintenance_duration", updatable = false, length = Action.MAINTENANCE_WINDOW_DURATION_LENGTH)
|
||||||
private String maintenanceWindowDuration;
|
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
|
// 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.
|
// start time of a maintenance window calculated based on the cron expression is relative to this time zone.
|
||||||
@Setter
|
@Setter
|
||||||
|
@Getter
|
||||||
@Column(name = "maintenance_time_zone", updatable = false, length = Action.MAINTENANCE_WINDOW_TIMEZONE_LENGTH)
|
@Column(name = "maintenance_time_zone", updatable = false, length = Action.MAINTENANCE_WINDOW_TIMEZONE_LENGTH)
|
||||||
private String maintenanceWindowTimeZone;
|
private String maintenanceWindowTimeZone;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
@Column(name = "external_ref", length = Action.EXTERNAL_REF_MAX_LENGTH)
|
@Column(name = "external_ref", length = Action.EXTERNAL_REF_MAX_LENGTH)
|
||||||
private String externalRef;
|
private String externalRef;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
|
@Getter
|
||||||
@Column(name = "initiated_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
|
@Column(name = "initiated_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
|
||||||
private String initiatedBy;
|
private String initiatedBy;
|
||||||
|
|
||||||
@@ -160,113 +179,27 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
@Column(name = "last_action_status_code", nullable = true, updatable = true)
|
@Column(name = "last_action_status_code", nullable = true, updatable = true)
|
||||||
private Integer lastActionStatusCode;
|
private Integer lastActionStatusCode;
|
||||||
|
|
||||||
@Override
|
|
||||||
public DistributionSet getDistributionSet() {
|
|
||||||
return distributionSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDistributionSet(final DistributionSet distributionSet) {
|
public void setDistributionSet(final DistributionSet distributionSet) {
|
||||||
this.distributionSet = (JpaDistributionSet) 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) {
|
public void setTarget(final Target target) {
|
||||||
this.target = (JpaTarget) target;
|
this.target = (JpaTarget) target;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getForcedTime() {
|
|
||||||
return forcedTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setForcedTime(final long forcedTime) {
|
|
||||||
this.forcedTime = forcedTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Integer> getWeight() {
|
public Optional<Integer> getWeight() {
|
||||||
return Optional.ofNullable(weight);
|
return Optional.ofNullable(weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public RolloutGroup getRolloutGroup() {
|
|
||||||
return rolloutGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRolloutGroup(final RolloutGroup rolloutGroup) {
|
public void setRolloutGroup(final RolloutGroup rolloutGroup) {
|
||||||
this.rolloutGroup = (JpaRolloutGroup) rolloutGroup;
|
this.rolloutGroup = (JpaRolloutGroup) rolloutGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Rollout getRollout() {
|
|
||||||
return rollout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRollout(final Rollout rollout) {
|
public void setRollout(final Rollout rollout) {
|
||||||
this.rollout = (JpaRollout) 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
|
@Override
|
||||||
public Optional<Integer> getLastActionStatusCode() {
|
public Optional<Integer> getLastActionStatusCode() {
|
||||||
return Optional.ofNullable(lastActionStatusCode);
|
return Optional.ofNullable(lastActionStatusCode);
|
||||||
@@ -285,7 +218,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMaintenanceScheduleLapsed() {
|
public boolean isMaintenanceScheduleLapsed() {
|
||||||
return !getMaintenanceWindowStartTime().isPresent();
|
return getMaintenanceWindowStartTime().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -17,7 +17,12 @@ import io.qameta.allure.Description;
|
|||||||
import io.qameta.allure.Feature;
|
import io.qameta.allure.Feature;
|
||||||
import io.qameta.allure.Story;
|
import io.qameta.allure.Story;
|
||||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
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.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.junit.jupiter.api.Test;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
|
||||||
@@ -130,7 +135,16 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@Description("Tests ControllerManagement#getPollingTimeForAction() method")
|
@Description("Tests ControllerManagement#getPollingTimeForAction() method")
|
||||||
void getPollingTimeForActionPermissionsCheck() {
|
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
|
@Test
|
||||||
@@ -180,7 +194,16 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@Description("Tests ControllerManagement#cancelAction() method")
|
@Description("Tests ControllerManagement#cancelAction() method")
|
||||||
void cancelActionPermissionsCheck() {
|
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
|
@Test
|
||||||
@@ -211,14 +234,17 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@Description("Tests ControllerManagement#getInstalledActionByTarget() method")
|
@Description("Tests ControllerManagement#getInstalledActionByTarget() method")
|
||||||
void getInstalledActionByTargetPermissionsCheck() {
|
void getInstalledActionByTargetPermissionsCheck() {
|
||||||
assertPermissions(() -> controllerManagement.getInstalledActionByTarget("controllerId"),
|
final Target target = testdataFactory.createTarget();
|
||||||
|
assertPermissions(
|
||||||
|
() -> controllerManagement.getInstalledActionByTarget(target),
|
||||||
List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE));
|
List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Tests ControllerManagement#activateAutoConfirmation() method")
|
@Description("Tests ControllerManagement#activateAutoConfirmation() method")
|
||||||
void activateAutoConfirmationPermissionsCheck() {
|
void activateAutoConfirmationPermissionsCheck() {
|
||||||
assertPermissions(() -> controllerManagement.activateAutoConfirmation("controllerId", "initiator", "remark"),
|
assertPermissions(
|
||||||
|
() -> controllerManagement.activateAutoConfirmation("controllerId", "initiator", "remark"),
|
||||||
List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE));
|
List.of(SpPermission.SpringEvalExpressions.CONTROLLER_ROLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.management;
|
|||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ import io.qameta.allure.Feature;
|
|||||||
import io.qameta.allure.Story;
|
import io.qameta.allure.Story;
|
||||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||||
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate;
|
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.AbstractJpaIntegrationTest;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
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.Rollout.RolloutStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
|
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.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.domain.Sort.Direction;
|
import org.springframework.data.domain.Sort.Direction;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,7 +44,13 @@ import org.springframework.test.context.TestPropertySource;
|
|||||||
*/
|
*/
|
||||||
@Feature("Component Tests - Repository")
|
@Feature("Component Tests - Repository")
|
||||||
@Story("Rollout Management (Flow)")
|
@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 {
|
class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@@ -73,6 +85,29 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
|
|||||||
assertGroup(groups.get(i), false, i == 0 ? RolloutGroupStatus.RUNNING : RolloutGroupStatus.SCHEDULED, 3);
|
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);
|
executeStaticWithoutOneTargetFromTheLastGroupAndHandleAll(groups, rollout, amountGroups);
|
||||||
|
|
||||||
rolloutManagement.pauseRollout(rollout.getId());
|
rolloutManagement.pauseRollout(rollout.getId());
|
||||||
|
|||||||
@@ -53,11 +53,9 @@ public final class IpUtil {
|
|||||||
* @return the {@link URI} based IP address from the client which sent the
|
* @return the {@link URI} based IP address from the client which sent the
|
||||||
* request
|
* request
|
||||||
*/
|
*/
|
||||||
public static URI getClientIpFromRequest(final HttpServletRequest request,
|
public static URI getClientIpFromRequest(final HttpServletRequest request, final HawkbitSecurityProperties securityProperties) {
|
||||||
final HawkbitSecurityProperties securityProperties) {
|
return getClientIpFromRequest(
|
||||||
|
request, securityProperties.getClients().getRemoteIpHeader(), securityProperties.getClients().isTrackRemoteIp());
|
||||||
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()));
|
return uri != null && !(AMQP_SCHEME.equals(uri.getScheme()) || HIDDEN_IP.equals(uri.getHost()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader,
|
private static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader, final boolean trackRemoteIp) {
|
||||||
final boolean trackRemoteIp) {
|
|
||||||
String ip;
|
String ip;
|
||||||
|
|
||||||
if (trackRemoteIp) {
|
if (trackRemoteIp) {
|
||||||
ip = request.getHeader(forwardHeader);
|
ip = request.getHeader(forwardHeader);
|
||||||
if (ip == null || (ip = findClientIpAddress(ip)) == null) {
|
if (ip == null || (ip = findClientIpAddress(ip)) == null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user