Tune/fix action cleanup tenant properties (#2782)
* actions.cleanup.onQuotaHit.percent -> action.cleanup.onQuotaHit.percent * action.cleanup.enabled - removed - instead enabled / disable <=> expire < / >= 0 * action.cleanup.actionExpiry -> action.cleanup.auto.expiry and action.cleanup.auto.status - so both are under action.cleanup.auto, and differentiate from on quota hit * auto db convert of props with one backward incompatibility - if you had action.cleanup.enabled=true and not set action.cleanup.actionExpiry (assuming default 30 days) - auto cleanup will be disabled you should set action.cleanup.auto.expiry=2592000000 in order to get the old behavior * Note that if you have configured global action cleanup the properties are changed also this config you shall change manually Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -47,7 +47,6 @@ import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.aspects.ExceptionMappingAspectHandler;
|
||||
import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoActionCleanup;
|
||||
import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoCleanupScheduler;
|
||||
import org.eclipse.hawkbit.repository.jpa.autocleanup.CleanupTask;
|
||||
import org.eclipse.hawkbit.repository.jpa.cluster.DistributedLockRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.cluster.LockProperties;
|
||||
import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
|
||||
@@ -416,8 +415,7 @@ public class JpaRepositoryConfiguration {
|
||||
* @return a new {@link AutoActionCleanup} bean
|
||||
*/
|
||||
@Bean
|
||||
CleanupTask actionCleanup(final DeploymentManagement deploymentManagement,
|
||||
final TenantConfigurationManagement configManagement) {
|
||||
AutoCleanupScheduler.CleanupTask actionCleanup(final DeploymentManagement deploymentManagement, final TenantConfigurationManagement configManagement) {
|
||||
return new AutoActionCleanup(deploymentManagement, configManagement);
|
||||
}
|
||||
|
||||
@@ -434,10 +432,10 @@ public class JpaRepositoryConfiguration {
|
||||
@ConditionalOnMissingBean
|
||||
@Profile("!test")
|
||||
@ConditionalOnProperty(prefix = "hawkbit.autocleanup.scheduler", name = "enabled", matchIfMissing = true)
|
||||
AutoCleanupScheduler autoCleanupScheduler(final SystemManagement systemManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final LockRegistry lockRegistry,
|
||||
final List<CleanupTask> cleanupTasks) {
|
||||
return new AutoCleanupScheduler(systemManagement, systemSecurityContext, lockRegistry, cleanupTasks);
|
||||
AutoCleanupScheduler autoCleanupScheduler(
|
||||
final List<AutoCleanupScheduler.CleanupTask> cleanupTasks,
|
||||
final SystemManagement systemManagement, final SystemSecurityContext systemSecurityContext, final LockRegistry lockRegistry) {
|
||||
return new AutoCleanupScheduler(cleanupTasks, systemManagement, systemSecurityContext, lockRegistry);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,15 +9,12 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.autocleanup;
|
||||
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ACTION_CLEANUP_ACTION_EXPIRY;
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ACTION_CLEANUP_ACTION_STATUS;
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ACTION_CLEANUP_ENABLED;
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ACTION_CLEANUP_AUTO_EXPIRY;
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ACTION_CLEANUP_AUTO_STATUS;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -28,31 +25,20 @@ import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
|
||||
/**
|
||||
* A cleanup task for {@link Action} entities which can be used to delete
|
||||
* actions which are in a certain {@link Action.Status}. It is recommended to
|
||||
* only clean up actions which have terminated already (i.e. actions in status
|
||||
* CANCELLED or ERROR).
|
||||
*
|
||||
* The cleanup task can be enabled /disabled and configured on a per tenant
|
||||
* basis.
|
||||
* A cleanup task for {@link Action} entities which can be used to delete actions which are in a certain {@link Action.Status}.
|
||||
* It is recommended to only clean up actions which have terminated already (i.e. actions in status CANCELLED or ERROR).
|
||||
* <p/>
|
||||
* The cleanup task can be enabled /disabled and configured on a per-tenant basis.
|
||||
*/
|
||||
@Slf4j
|
||||
public class AutoActionCleanup implements CleanupTask {
|
||||
public class AutoActionCleanup implements AutoCleanupScheduler.CleanupTask {
|
||||
|
||||
private static final String ID = "action-cleanup";
|
||||
private static final boolean ACTION_CLEANUP_ENABLED_DEFAULT = false;
|
||||
private static final long ACTION_CLEANUP_ACTION_EXPIRY_DEFAULT = TimeUnit.DAYS.toMillis(30);
|
||||
private static final EnumSet<Status> EMPTY_STATUS_SET = EnumSet.noneOf(Status.class);
|
||||
|
||||
private final DeploymentManagement deploymentMgmt;
|
||||
private final TenantConfigurationManagement config;
|
||||
|
||||
/**
|
||||
* Constructs the action cleanup handler.
|
||||
*
|
||||
* @param deploymentMgmt The {@link DeploymentManagement} to operate on.
|
||||
* @param configMgmt The {@link TenantConfigurationManagement} service.
|
||||
*/
|
||||
public AutoActionCleanup(final DeploymentManagement deploymentMgmt, final TenantConfigurationManagement configMgmt) {
|
||||
this.deploymentMgmt = deploymentMgmt;
|
||||
this.config = configMgmt;
|
||||
@@ -60,17 +46,20 @@ public class AutoActionCleanup implements CleanupTask {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isEnabled()) {
|
||||
final TenantConfigurationValue<Long> expiryCV = config.getConfigurationValue(ACTION_CLEANUP_AUTO_EXPIRY, Long.class);
|
||||
final long expiry = expiryCV != null ? expiryCV.getValue() : -1L;
|
||||
if (expiry < 0L) {
|
||||
log.debug("Action cleanup is disabled for this tenant...");
|
||||
return;
|
||||
}
|
||||
|
||||
final EnumSet<Status> status = getActionStatus();
|
||||
if (!status.isEmpty()) {
|
||||
final long lastModified = System.currentTimeMillis() - getExpiry();
|
||||
final int actionsCount = deploymentMgmt.deleteActionsByStatusAndLastModifiedBefore(status, lastModified);
|
||||
log.debug("Deleted {} actions in status {} which have not been modified since {} ({})", actionsCount,
|
||||
status, Instant.ofEpochMilli(lastModified), lastModified);
|
||||
} else {
|
||||
final EnumSet<Status> status = getActionStatus();
|
||||
if (status.isEmpty()) {
|
||||
log.debug("Action cleanup is disabled for this tenant...");
|
||||
} else {
|
||||
final long lastModified = System.currentTimeMillis() - expiry;
|
||||
final int actionsCount = deploymentMgmt.deleteActionsByStatusAndLastModifiedBefore(status, lastModified);
|
||||
log.debug("Deleted {} actions in status {} which have not been modified since {} ({})",
|
||||
actionsCount, status, Instant.ofEpochMilli(lastModified), lastModified);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,27 +68,12 @@ public class AutoActionCleanup implements CleanupTask {
|
||||
return ID;
|
||||
}
|
||||
|
||||
private long getExpiry() {
|
||||
final TenantConfigurationValue<Long> expiry = getConfigValue(ACTION_CLEANUP_ACTION_EXPIRY, Long.class);
|
||||
return expiry != null ? expiry.getValue() : ACTION_CLEANUP_ACTION_EXPIRY_DEFAULT;
|
||||
}
|
||||
|
||||
private EnumSet<Status> getActionStatus() {
|
||||
final TenantConfigurationValue<String> statusStr = getConfigValue(ACTION_CLEANUP_ACTION_STATUS, String.class);
|
||||
final TenantConfigurationValue<String> statusStr = config.getConfigurationValue(ACTION_CLEANUP_AUTO_STATUS, String.class);
|
||||
if (statusStr != null) {
|
||||
return Arrays.stream(statusStr.getValue().split("[;,]")).map(Status::valueOf)
|
||||
.collect(Collectors.toCollection(() -> EnumSet.noneOf(Status.class)));
|
||||
return Arrays.stream(statusStr.getValue().split("[;,]"))
|
||||
.map(Status::valueOf).collect(Collectors.toCollection(() -> EnumSet.noneOf(Status.class)));
|
||||
}
|
||||
return EMPTY_STATUS_SET;
|
||||
}
|
||||
|
||||
private boolean isEnabled() {
|
||||
final TenantConfigurationValue<Boolean> isEnabled = getConfigValue(ACTION_CLEANUP_ENABLED, Boolean.class);
|
||||
return isEnabled != null ? isEnabled.getValue() : ACTION_CLEANUP_ENABLED_DEFAULT;
|
||||
}
|
||||
|
||||
private <T extends Serializable> TenantConfigurationValue<T> getConfigValue(final String key,
|
||||
final Class<T> valueType) {
|
||||
return config.getConfigurationValue(key, valueType);
|
||||
}
|
||||
}
|
||||
@@ -36,15 +36,14 @@ public class AutoCleanupScheduler {
|
||||
/**
|
||||
* Constructs the cleanup schedulers and initializes it with a set of cleanup handlers.
|
||||
*
|
||||
* @param cleanupTasks A list of cleanup tasks.
|
||||
* @param systemManagement Management APIs to invoke actions in a certain tenant context.
|
||||
* @param systemSecurityContext The system security context.
|
||||
* @param lockRegistry A registry for shared locks.
|
||||
* @param cleanupTasks A list of cleanup tasks.
|
||||
*/
|
||||
public AutoCleanupScheduler(
|
||||
final SystemManagement systemManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final LockRegistry lockRegistry,
|
||||
final List<CleanupTask> cleanupTasks) {
|
||||
final List<CleanupTask> cleanupTasks,
|
||||
final SystemManagement systemManagement, final SystemSecurityContext systemSecurityContext, final LockRegistry lockRegistry) {
|
||||
this.systemManagement = systemManagement;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
this.lockRegistry = lockRegistry;
|
||||
@@ -57,8 +56,7 @@ public class AutoCleanupScheduler {
|
||||
@Scheduled(initialDelayString = PROP_AUTO_CLEANUP_INTERVAL, fixedDelayString = PROP_AUTO_CLEANUP_INTERVAL)
|
||||
public void run() {
|
||||
log.debug("Auto cleanup scheduler has been triggered.");
|
||||
// run this code in system code privileged to have the necessary
|
||||
// permission to query and create entities
|
||||
// run this code in system code privileged to have the necessary permission to query and create entities
|
||||
if (!cleanupTasks.isEmpty()) {
|
||||
systemSecurityContext.runAsSystem(this::executeAutoCleanup);
|
||||
}
|
||||
@@ -70,7 +68,7 @@ public class AutoCleanupScheduler {
|
||||
@SuppressWarnings("squid:S3516")
|
||||
private Void executeAutoCleanup() {
|
||||
systemManagement.forEachTenant(tenant -> cleanupTasks.forEach(task -> {
|
||||
final Lock lock = obtainLock(task, tenant);
|
||||
final Lock lock = lockRegistry.obtain(AUTO_CLEANUP + SEP + task.getId() + SEP + tenant);
|
||||
if (!lock.tryLock()) {
|
||||
return;
|
||||
}
|
||||
@@ -85,7 +83,20 @@ public class AutoCleanupScheduler {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Lock obtainLock(final CleanupTask task, final String tenant) {
|
||||
return lockRegistry.obtain(AUTO_CLEANUP + SEP + task.getId() + SEP + tenant);
|
||||
/**
|
||||
* Interface modeling a cleanup task.
|
||||
*/
|
||||
public interface CleanupTask extends Runnable {
|
||||
|
||||
/**
|
||||
* Executes the cleanup task.
|
||||
*/
|
||||
@Override
|
||||
void run();
|
||||
|
||||
/**
|
||||
* @return The identifier of this cleanup task. Never null.
|
||||
*/
|
||||
String getId();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2018 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.autocleanup;
|
||||
|
||||
/**
|
||||
* Interface modeling a cleanup task.
|
||||
*/
|
||||
public interface CleanupTask extends Runnable {
|
||||
|
||||
/**
|
||||
* Executes the cleanup task.
|
||||
*/
|
||||
@Override
|
||||
void run();
|
||||
|
||||
/**
|
||||
* @return The identifier of this cleanup task. Never null.
|
||||
*/
|
||||
String getId();
|
||||
}
|
||||
@@ -89,6 +89,7 @@ import org.eclipse.hawkbit.repository.model.TargetWithActionType;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
|
||||
@@ -628,7 +629,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
private int getActionsPurgePercentage() {
|
||||
return getConfigValue(TenantConfigurationProperties.TenantConfigurationKey.ACTIONS_PURGE_PERCENTAGE_ON_QUOTA_HIT, Integer.class);
|
||||
return getConfigValue(TenantConfigurationKey.ACTION_PURGE_PERCENTAGE_ON_QUOTA_HIT, Integer.class);
|
||||
}
|
||||
|
||||
protected boolean isActionsAutocloseEnabled() {
|
||||
|
||||
Reference in New Issue
Block a user