Fix sonar issues and add DMF tests for maintenance window feature (#655)
* Fix sonar issues. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * POM cleanup and more sonar issues fixed. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Remove unneeded JavaDocs. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * More sonar issues. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * More issues. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Adapt maintenance window to naming. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Add DMF tests. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Readibility. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Typos fixed. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -129,8 +129,9 @@ public abstract class AbstractDsAssignmentStrategy {
|
||||
return;
|
||||
}
|
||||
|
||||
afterCommit.afterCommit(() -> eventPublisher.publishEvent(
|
||||
new TargetAssignDistributionSetEvent(tenant, distributionSetId, actions, applicationContext.getId())));
|
||||
afterCommit.afterCommit(
|
||||
() -> eventPublisher.publishEvent(new TargetAssignDistributionSetEvent(tenant, distributionSetId,
|
||||
actions, applicationContext.getId(), actions.get(0).isMaintenanceWindowAvailable())));
|
||||
}
|
||||
|
||||
protected void sendTargetUpdatedEvent(final JpaTarget target) {
|
||||
|
||||
@@ -14,10 +14,6 @@ import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.util.Collection;
|
||||
import java.time.Duration;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -62,6 +58,7 @@ import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
@@ -210,31 +207,17 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
.getConfigurationValue(TenantConfigurationKey.MAINTENANCE_WINDOW_POLL_COUNT, Integer.class).getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns polling time based on the maintenance window for an action.
|
||||
* Server will reduce the polling interval as the start time for maintenance
|
||||
* window approaches, so that at least these many attempts are made between
|
||||
* current polling until start of maintenance window. 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 action
|
||||
* id the {@link Action} for which polling time is calculated
|
||||
* based on it having maintenance window or not
|
||||
*
|
||||
* @return current {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}.
|
||||
*/
|
||||
@Override
|
||||
public String getPollingTimeForAction(final Action action) {
|
||||
if (action == null || !action.hasMaintenanceSchedule() || action.isMaintenanceScheduleLapsed()) {
|
||||
public String getPollingTimeForAction(final long actionId) {
|
||||
|
||||
final JpaAction action = getActionAndThrowExceptionIfNotFound(actionId);
|
||||
|
||||
if (!action.hasMaintenanceSchedule() || action.isMaintenanceScheduleLapsed()) {
|
||||
return getPollingTime();
|
||||
}
|
||||
|
||||
JpaAction jpaAction = getActionAndThrowExceptionIfNotFound(action.getId());
|
||||
return (new EventTimer(getPollingTime(), getMinPollingTime(), ChronoUnit.SECONDS))
|
||||
.timeToNextEvent(getMaintenanceWindowPollCount(), jpaAction.getMaintenanceWindowStartTime().get());
|
||||
.timeToNextEvent(getMaintenanceWindowPollCount(), action.getMaintenanceWindowStartTime().orElse(null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,7 +227,7 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
* polling, should happen when timer expires. Class makes use of java.time
|
||||
* package to manipulate and calculate timer duration.
|
||||
*/
|
||||
private class EventTimer {
|
||||
private static class EventTimer {
|
||||
|
||||
private final String defaultEventInterval;
|
||||
private final Duration defaultEventIntervalDuration;
|
||||
@@ -266,7 +249,7 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
* @param timerUnit
|
||||
* representing the unit of time to be used for timer.
|
||||
*/
|
||||
EventTimer(String defaultEventInterval, String minimumEventInterval, TemporalUnit timeUnit) {
|
||||
EventTimer(final String defaultEventInterval, final String minimumEventInterval, final TemporalUnit timeUnit) {
|
||||
this.defaultEventInterval = defaultEventInterval;
|
||||
this.defaultEventIntervalDuration = Duration
|
||||
.parse(MaintenanceScheduleHelper.convertToISODuration(defaultEventInterval));
|
||||
@@ -294,8 +277,8 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
*
|
||||
* @return String in HH:mm:ss format for time to next event.
|
||||
*/
|
||||
String timeToNextEvent(int eventCount, ZonedDateTime timerResetTime) {
|
||||
ZonedDateTime currentTime = ZonedDateTime.now();
|
||||
String timeToNextEvent(final int eventCount, final ZonedDateTime timerResetTime) {
|
||||
final ZonedDateTime currentTime = ZonedDateTime.now();
|
||||
|
||||
// If there is no reset time, or if we already past the reset time,
|
||||
// return the default interval.
|
||||
@@ -304,7 +287,7 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
}
|
||||
|
||||
// Calculate the interval timer based on desired event count.
|
||||
Duration currentIntervalDuration = Duration.of(currentTime.until(timerResetTime, timeUnit), timeUnit)
|
||||
final Duration currentIntervalDuration = Duration.of(currentTime.until(timerResetTime, timeUnit), timeUnit)
|
||||
.dividedBy(eventCount);
|
||||
|
||||
// Need not return interval greater than the default.
|
||||
@@ -810,7 +793,8 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
// For negative and large value of messageCount, limit the number of
|
||||
// messages.
|
||||
final int limit = messageCount < 0 || messageCount >= RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT
|
||||
? RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT : messageCount;
|
||||
? RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT
|
||||
: messageCount;
|
||||
|
||||
final PageRequest pageable = new PageRequest(0, limit, new Sort(Direction.DESC, "occurredAt"));
|
||||
final Page<String> messages = actionStatusRepository.findMessagesByActionIdAndMessageNotLike(pageable, actionId,
|
||||
@@ -913,9 +897,10 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
* @throws EntityNotFoundException
|
||||
* if action with given actionId does not exist.
|
||||
*/
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||
public Action cancelAction(long actionId) {
|
||||
public Action cancelAction(final long actionId) {
|
||||
LOG.debug("cancelAction({})", actionId);
|
||||
|
||||
final JpaAction action = actionRepository.findById(actionId)
|
||||
|
||||
@@ -402,6 +402,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
}
|
||||
|
||||
final String tenant = rolloutGroupActions.getContent().get(0).getTenant();
|
||||
final boolean maintenanceWindowAvailable = rolloutGroupActions.getContent().get(0)
|
||||
.isMaintenanceWindowAvailable();
|
||||
|
||||
final List<Action> targetAssignments = rolloutGroupActions.getContent().stream()
|
||||
.map(action -> (JpaAction) action).map(this::closeActionIfSetWasAlreadyAssigned)
|
||||
@@ -410,7 +412,7 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
|
||||
if (!CollectionUtils.isEmpty(targetAssignments)) {
|
||||
afterCommit.afterCommit(() -> eventPublisher.publishEvent(new TargetAssignDistributionSetEvent(tenant,
|
||||
distributionSetId, targetAssignments, applicationContext.getId())));
|
||||
distributionSetId, targetAssignments, applicationContext.getId(), maintenanceWindowAvailable)));
|
||||
}
|
||||
|
||||
return rolloutGroupActions.getTotalElements();
|
||||
|
||||
@@ -101,7 +101,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
@ConversionValue(objectValue = "DOWNLOAD", dataValue = "7"),
|
||||
@ConversionValue(objectValue = "SCHEDULED", dataValue = "8"),
|
||||
@ConversionValue(objectValue = "CANCEL_REJECTED", dataValue = "9"),
|
||||
@ConversionValue(objectValue = "DOWNLOADED", dataValue = "10")})
|
||||
@ConversionValue(objectValue = "DOWNLOADED", dataValue = "10") })
|
||||
@Convert("status")
|
||||
@NotNull
|
||||
private Status status;
|
||||
@@ -118,13 +118,13 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
@JoinColumn(name = "rollout", updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout"))
|
||||
private JpaRollout rollout;
|
||||
|
||||
@Column(name = "maintenance_cron_schedule", length = Action.MAINTENANCE_SCHEDULE_CRON_LENGTH)
|
||||
@Column(name = "maintenance_cron_schedule", updatable = false, length = Action.MAINTENANCE_SCHEDULE_CRON_LENGTH)
|
||||
private String maintenanceSchedule;
|
||||
|
||||
@Column(name = "maintenance_duration", length = Action.MAINTENANCE_WINDOW_DURATION_LENGTH)
|
||||
@Column(name = "maintenance_duration", updatable = false, length = Action.MAINTENANCE_WINDOW_DURATION_LENGTH)
|
||||
private String maintenanceWindowDuration;
|
||||
|
||||
@Column(name = "maintenance_time_zone", length = Action.MAINTENANCE_WINDOW_TIMEZONE_LENGTH)
|
||||
@Column(name = "maintenance_time_zone", updatable = false, length = Action.MAINTENANCE_WINDOW_TIMEZONE_LENGTH)
|
||||
private String maintenanceWindowTimeZone;
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
* @param maintenanceSchedule
|
||||
* is a cron expression to be used for scheduling.
|
||||
*/
|
||||
public void setMaintenanceSchedule(String maintenanceSchedule) {
|
||||
public void setMaintenanceSchedule(final String maintenanceSchedule) {
|
||||
this.maintenanceSchedule = maintenanceSchedule;
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
* is the duration of an available maintenance schedule in
|
||||
* HH:mm:ss format.
|
||||
*/
|
||||
public void setMaintenanceWindowDuration(String maintenanceWindowDuration) {
|
||||
public void setMaintenanceWindowDuration(final String maintenanceWindowDuration) {
|
||||
this.maintenanceWindowDuration = maintenanceWindowDuration;
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
* start time of a maintenance window calculated based on the
|
||||
* cron expression is relative to this time zone.
|
||||
*/
|
||||
public void setMaintenanceWindowTimeZone(String maintenanceWindowTimeZone) {
|
||||
public void setMaintenanceWindowTimeZone(final String maintenanceWindowTimeZone) {
|
||||
this.maintenanceWindowTimeZone = maintenanceWindowTimeZone;
|
||||
}
|
||||
|
||||
@@ -277,10 +277,9 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
*
|
||||
* @return the {@link MaintenanceScheduleHelper} object.
|
||||
*/
|
||||
MaintenanceScheduleHelper getScheduler() {
|
||||
private MaintenanceScheduleHelper getScheduler() {
|
||||
if (this.scheduleHelper == null) {
|
||||
this.scheduleHelper = new MaintenanceScheduleHelper(maintenanceSchedule, maintenanceWindowDuration,
|
||||
maintenanceWindowTimeZone);
|
||||
this.scheduleHelper = new MaintenanceScheduleHelper(maintenanceSchedule);
|
||||
}
|
||||
return this.scheduleHelper;
|
||||
}
|
||||
@@ -290,7 +289,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
*
|
||||
* @return the {@link Duration} of each maintenance window.
|
||||
*/
|
||||
Duration getMaintenanceWindowDuration() {
|
||||
private Duration getMaintenanceWindowDuration() {
|
||||
return Duration.parse(MaintenanceScheduleHelper.convertToISODuration(this.maintenanceWindowDuration));
|
||||
}
|
||||
|
||||
@@ -302,7 +301,7 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
* @return the start time as {@link Optional<ZonedDateTime>}.
|
||||
*/
|
||||
public Optional<ZonedDateTime> getMaintenanceWindowStartTime() {
|
||||
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.of(maintenanceWindowTimeZone));
|
||||
final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.of(maintenanceWindowTimeZone));
|
||||
return getScheduler().nextExecution(now.minus(getMaintenanceWindowDuration()));
|
||||
}
|
||||
|
||||
@@ -313,50 +312,21 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
*
|
||||
* @return the end time of window as {@link Optional<ZonedDateTime>}.
|
||||
*/
|
||||
public Optional<ZonedDateTime> getMaintenanceWindowEndTime() {
|
||||
if (getMaintenanceWindowStartTime().isPresent()) {
|
||||
return Optional.of(getMaintenanceWindowStartTime().get().plus(getMaintenanceWindowDuration()));
|
||||
}
|
||||
return Optional.empty();
|
||||
private Optional<ZonedDateTime> getMaintenanceWindowEndTime() {
|
||||
return getMaintenanceWindowStartTime().map(start -> start.plus(getMaintenanceWindowDuration()));
|
||||
}
|
||||
|
||||
/**
|
||||
* The method checks whether the action has a maintenance schedule defined
|
||||
* for it. A maintenance schedule defines a set of maintenance windows
|
||||
* during which actual update can be performed. A valid schedule defines at
|
||||
* least one maintenance window.
|
||||
*
|
||||
* @return true if action has a maintenance schedule, else false.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasMaintenanceSchedule() {
|
||||
return this.maintenanceSchedule != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The method checks whether the maintenance schedule has already lapsed for
|
||||
* the action, i.e. there are no more windows available for maintenance.
|
||||
* Controller manager uses the method to check if the maintenance schedule
|
||||
* has lapsed, and automatically cancels the action if it is lapsed.
|
||||
*
|
||||
* @return true if maintenance schedule has lapsed, else false.
|
||||
*/
|
||||
@Override
|
||||
public boolean isMaintenanceScheduleLapsed() {
|
||||
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.of(maintenanceWindowTimeZone));
|
||||
final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.of(maintenanceWindowTimeZone));
|
||||
return !getScheduler().nextExecution(now.minus(getMaintenanceWindowDuration())).isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* The method checks whether a maintenance window is available for the
|
||||
* action to proceed. If it is available, a 'true' value is returned. The
|
||||
* maintenance window is considered available: 1) If there is no maintenance
|
||||
* schedule at all, in which case device can start update any time after
|
||||
* download is finished; or 2) the current time is within a scheduled
|
||||
* maintenance window start and end time.
|
||||
*
|
||||
* @return true if maintenance window is available, else false.
|
||||
*/
|
||||
@Override
|
||||
public boolean isMaintenanceWindowAvailable() {
|
||||
if (!hasMaintenanceSchedule()) {
|
||||
@@ -368,10 +338,12 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
// available.
|
||||
return false;
|
||||
} else {
|
||||
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.of(maintenanceWindowTimeZone));
|
||||
if (this.getMaintenanceWindowStartTime().isPresent() && this.getMaintenanceWindowEndTime().isPresent()) {
|
||||
return now.isAfter(this.getMaintenanceWindowStartTime().get())
|
||||
&& now.isBefore(this.getMaintenanceWindowEndTime().get());
|
||||
final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.of(maintenanceWindowTimeZone));
|
||||
final Optional<ZonedDateTime> start = getMaintenanceWindowStartTime();
|
||||
final Optional<ZonedDateTime> end = getMaintenanceWindowEndTime();
|
||||
|
||||
if (start.isPresent() && end.isPresent()) {
|
||||
return now.isAfter(start.get()) && now.isBefore(end.get());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user