From 9ac51ab988784da135eb3a7fc374adc04e08d324 Mon Sep 17 00:00:00 2001 From: Avgustin Marinov Date: Fri, 8 Mar 2024 12:43:53 +0200 Subject: [PATCH] [#1651] Implement tenant level config for DistributionSet implicit lock (#1678) enabled by default Signed-off-by: Marinov Avgustin --- .../repository/model/TenantConfiguration.java | 3 +- .../model/TenantConfigurationValue.java | 5 +- .../TenantConfigurationProperties.java | 76 +++++-------------- .../hawkbit/utils/TenantConfigHelper.java | 13 +++- .../builder/GenericDistributionSetUpdate.java | 2 +- .../builder/GenericSoftwareModuleUpdate.java | 2 +- .../hawkbit-repository-defaults.properties | 5 ++ .../management/JpaDeploymentManagement.java | 4 +- .../jpa/management/JpaRolloutManagement.java | 9 ++- .../JpaTargetFilterQueryManagement.java | 9 ++- .../JpaTenantConfigurationManagement.java | 2 +- .../MgmtSystemTenantConfigurationValue.java | 1 + 12 files changed, 58 insertions(+), 73 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfiguration.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfiguration.java index 07120546f..ed3324b86 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfiguration.java @@ -35,5 +35,4 @@ public interface TenantConfiguration extends TenantAwareBaseEntity { * @return value of the entry */ String getValue(); - -} +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfigurationValue.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfigurationValue.java index b15335038..552494a4a 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfigurationValue.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TenantConfigurationValue.java @@ -12,18 +12,19 @@ package org.eclipse.hawkbit.repository.model; import lombok.Builder; import lombok.Data; +import java.io.Serial; import java.io.Serializable; /** * Represents a tenant configuration value including some meta data * - * @param - * type of the configuration value + * @param type of the configuration value */ @Data @Builder public final class TenantConfigurationValue implements Serializable { + @Serial private static final long serialVersionUID = 1L; private T value; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java index 68aebd813..13cb792a6 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java @@ -9,10 +9,13 @@ */ package org.eclipse.hawkbit.tenancy.configuration; +import java.io.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import lombok.Data; +import lombok.ToString; import org.eclipse.hawkbit.ControllerPollProperties; import org.eclipse.hawkbit.HawkbitServerProperties.Anonymous.Download; import org.eclipse.hawkbit.repository.exception.InvalidTenantConfigurationKeyException; @@ -24,20 +27,14 @@ import org.springframework.context.ApplicationContext; /** * Properties for tenant configuration default values. - * */ +@Data +@ToString @ConfigurationProperties("hawkbit.server.tenant") public class TenantConfigurationProperties { private final Map configuration = new HashMap<>(); - /** - * @return full map of all configured tenant properties - */ - public Map getConfiguration() { - return configuration; - } - /** * @return full list of {@link TenantConfigurationKey}s */ @@ -46,8 +43,7 @@ public class TenantConfigurationProperties { } /** - * @param keyName - * name of the TenantConfigurationKey + * @param keyName name of the TenantConfigurationKey * @return the TenantConfigurationKey with the name keyName */ public TenantConfigurationKey fromKeyName(final String keyName) { @@ -59,8 +55,9 @@ public class TenantConfigurationProperties { /** * Tenant specific configurations which can be configured for each tenant * separately by means of override of the system defaults. - * */ + @Data + @ToString public static class TenantConfigurationKey { /** @@ -158,59 +155,22 @@ public class TenantConfigurationProperties { */ public static final String USER_CONFIRMATION_ENABLED = "user.confirmation.flow.enabled"; + /** + * Switch to enable/disable the implicit locking + */ + public static final String IMPLICIT_LOCK_ENABLED = "implicit.lock.enabled"; + private String keyName; private String defaultValue = ""; - private Class dataType = String.class; + private Class dataType = String.class; private Class validator = TenantConfigurationStringValidator.class; - public String getKeyName() { - return keyName; - } - - public void setKeyName(final String keyName) { - this.keyName = keyName; - } - /** + * validates if a object matches the allowed data format of the corresponding key * - * @return the data type of the tenant configuration value. (e.g. - * Integer.class, String.class) - */ - @SuppressWarnings("unchecked") - public Class getDataType() { - return (Class) dataType; - } - - public void setDataType(final Class dataType) { - this.dataType = dataType; - } - - public String getDefaultValue() { - return defaultValue; - } - - public void setDefaultValue(final String defaultValue) { - this.defaultValue = defaultValue; - } - - public Class getValidator() { - return validator; - } - - public void setValidator(final Class validator) { - this.validator = validator; - } - - /** - * validates if a object matches the allowed data format of the - * corresponding key - * - * @param context - * application context - * @param value - * which will be validated - * @throws TenantConfigurationValidatorException - * is thrown, when object is invalid + * @param context application context + * @param value which will be validated + * @throws TenantConfigurationValidatorException is thrown, when object is invalid */ public void validate(final ApplicationContext context, final Object value) { final TenantConfigurationValidator createdBean = context.getAutowireCapableBeanFactory() diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/utils/TenantConfigHelper.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/utils/TenantConfigHelper.java index ee6508f58..df145b10e 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/utils/TenantConfigHelper.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/utils/TenantConfigHelper.java @@ -15,6 +15,8 @@ import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationPrope import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.security.SystemSecurityContext; +import java.io.Serializable; + /** * A collection of static helper methods for the tenant configuration */ @@ -43,14 +45,18 @@ public final class TenantConfigHelper { return new TenantConfigHelper(systemSecurityContext, tenantConfigurationManagement); } + public T getConfigValue(final String key, final Class valueType) { + return systemSecurityContext + .runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue()); + } + /** * Is multi-assignments enabled for the current tenant * * @return is active */ public boolean isMultiAssignmentsEnabled() { - return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement - .getConfigurationValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class).getValue()); + return getConfigValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class); } /** @@ -59,7 +65,6 @@ public final class TenantConfigHelper { * @return is enabled */ public boolean isConfirmationFlowEnabled() { - return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement - .getConfigurationValue(USER_CONFIRMATION_ENABLED, Boolean.class).getValue()); + return getConfigValue(USER_CONFIRMATION_ENABLED, Boolean.class); } } diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericDistributionSetUpdate.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericDistributionSetUpdate.java index e7f36b206..7fe8a40e6 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericDistributionSetUpdate.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericDistributionSetUpdate.java @@ -22,7 +22,7 @@ import java.util.Optional; */ @Data @EqualsAndHashCode(callSuper = true) -@ToString +@ToString(callSuper = true) @Accessors(fluent = true) public class GenericDistributionSetUpdate extends AbstractDistributionSetUpdateCreate implements DistributionSetUpdate { diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericSoftwareModuleUpdate.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericSoftwareModuleUpdate.java index 9bf995e04..c3f909d2e 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericSoftwareModuleUpdate.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericSoftwareModuleUpdate.java @@ -22,7 +22,7 @@ import java.util.Optional; */ @Data @EqualsAndHashCode(callSuper = true) -@ToString +@ToString(callSuper = true) @Accessors(fluent = true) public class GenericSoftwareModuleUpdate extends AbstractSoftwareModuleUpdateCreate implements SoftwareModuleUpdate { diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/resources/hawkbit-repository-defaults.properties b/hawkbit-repository/hawkbit-repository-core/src/main/resources/hawkbit-repository-defaults.properties index 64a879dfd..314cd1029 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/resources/hawkbit-repository-defaults.properties +++ b/hawkbit-repository/hawkbit-repository-core/src/main/resources/hawkbit-repository-defaults.properties @@ -107,4 +107,9 @@ hawkbit.server.tenant.configuration.user-confirmation-enabled.defaultValue=false hawkbit.server.tenant.configuration.user-confirmation-enabled.dataType=java.lang.Boolean hawkbit.server.tenant.configuration.user-confirmation-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator +hawkbit.server.tenant.configuration.implicit-lock-enabled.keyName=user.confirmation.flow.enabled +hawkbit.server.tenant.configuration.implicit-lock-enabled.defaultValue=true +hawkbit.server.tenant.configuration.implicit-lock-enabled.dataType=java.lang.Boolean +hawkbit.server.tenant.configuration.implicit-lock-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator + # Default tenant configuration - END diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java index f0997f34d..1559fb7dc 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java @@ -9,6 +9,7 @@ */ package org.eclipse.hawkbit.repository.jpa.management; +import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.IMPLICIT_LOCK_ENABLED; import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED; import java.io.Serializable; @@ -371,8 +372,9 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl final AbstractDsAssignmentStrategy assignmentStrategy) { final JpaDistributionSet distributionSet = (JpaDistributionSet) distributionSetManagement.getValidAndComplete(dsId); + // implicit lock - if (!distributionSet.isLocked()) { + if (!distributionSet.isLocked() && getConfigValue(IMPLICIT_LOCK_ENABLED, Boolean.class)) { // without new transaction DS changed event is not thrown DeploymentHelper.runInNewTransaction(txManager, "Implicit lock", status -> { distributionSetManagement.lock(distributionSet.getId()); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutManagement.java index 5d0b782ea..d54037e12 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaRolloutManagement.java @@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa.management; import static org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupCreate.addSuccessAndErrorConditionsAndActions; +import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.IMPLICIT_LOCK_ENABLED; import java.util.ArrayList; import java.util.Arrays; @@ -17,7 +18,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -75,6 +75,7 @@ import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.security.SystemSecurityContext; +import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.data.domain.Page; @@ -143,6 +144,8 @@ public class JpaRolloutManagement implements RolloutManagement { private final ContextAware contextAware; private final Database database; + private final TenantConfigHelper tenantConfigHelper; + public JpaRolloutManagement(final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement, final EventPublisherHolder eventPublisherHolder, final VirtualPropertyReplacer virtualPropertyReplacer, final Database database, @@ -159,6 +162,8 @@ public class JpaRolloutManagement implements RolloutManagement { this.systemSecurityContext = systemSecurityContext; this.eventPublisherHolder = eventPublisherHolder; this.contextAware = contextAware; + + tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement); } @Override @@ -225,7 +230,7 @@ public class JpaRolloutManagement implements RolloutManagement { rollout.setTotalTargets(totalTargets); // implicit lock - if (!distributionSet.isLocked()) { + if (!distributionSet.isLocked() && tenantConfigHelper.getConfigValue(IMPLICIT_LOCK_ENABLED, Boolean.class)) { distributionSetManagement.lock(distributionSet.getId()); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetFilterQueryManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetFilterQueryManagement.java index e9348d101..e58f3c5df 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetFilterQueryManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetFilterQueryManagement.java @@ -9,6 +9,8 @@ */ package org.eclipse.hawkbit.repository.jpa.management; +import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.IMPLICIT_LOCK_ENABLED; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -87,6 +89,8 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme private final Database database; + private final TenantConfigHelper tenantConfigHelper; + public JpaTargetFilterQueryManagement(final TargetFilterQueryRepository targetFilterQueryRepository, final TargetManagement targetManagement, final VirtualPropertyReplacer virtualPropertyReplacer, final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement, @@ -103,6 +107,8 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme this.repositoryProperties = repositoryProperties; this.systemSecurityContext = systemSecurityContext; this.contextAware = contextAware; + + tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement); } @Override @@ -278,8 +284,9 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme assertMaxTargetsQuota(targetFilterQuery.getQuery(), targetFilterQuery.getName(), update.getDsId()); final JpaDistributionSet distributionSet = (JpaDistributionSet) distributionSetManagement .getValidAndComplete(update.getDsId()); + // implicit lock - if (!distributionSet.isLocked()) { + if (!distributionSet.isLocked() && tenantConfigHelper.getConfigValue(IMPLICIT_LOCK_ENABLED, Boolean.class)) { distributionSetManagement.lock(distributionSet.getId()); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantConfigurationManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantConfigurationManagement.java index ea71fcab0..b0592b091 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantConfigurationManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTenantConfigurationManagement.java @@ -130,7 +130,7 @@ public class JpaTenantConfigurationManagement implements TenantConfigurationMana final String configurationKeyName) { final TenantConfigurationKey configurationKey = tenantConfigurationProperties.fromKeyName(configurationKeyName); - return getConfigurationValue(configurationKeyName, configurationKey.getDataType()); + return getConfigurationValue(configurationKeyName, (Class)configurationKey.getDataType()); } @Override diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/system/MgmtSystemTenantConfigurationValue.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/system/MgmtSystemTenantConfigurationValue.java index 36879478e..76ebd233a 100644 --- a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/system/MgmtSystemTenantConfigurationValue.java +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/system/MgmtSystemTenantConfigurationValue.java @@ -53,6 +53,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; * **pollingOverdueTime** - String, The configuration key 'pollingOverdueTime' defines the period of time after the SP server will recognize a target, which is not performing pull requests anymore. * **multi.assignments.enabled** - Boolean, The configuration key 'multi.assignments.enabled' defines if multiple distribution sets can be assigned to the same targets. * **batch.assignments.enabled** - Boolean, The configuration key 'batch.assignments.enabled' defines if distribution set can be assigned to multiple targets in a single batch message. + * **implicit.lock.enabled** - Boolean (true by default), The configuration key 'implicit.lock.enabled' defines if distribution set and their software modules shall be implicitly locked when assigned to target, rollout or target filter. """, example = """ { "value" : "",