[#1651] Implement tenant level config for DistributionSet implicit lock (#1678)

enabled by default

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-03-08 12:43:53 +02:00
committed by GitHub
parent ce9918ce00
commit 9ac51ab988
12 changed files with 58 additions and 73 deletions

View File

@@ -35,5 +35,4 @@ public interface TenantConfiguration extends TenantAwareBaseEntity {
* @return value of the entry
*/
String getValue();
}
}

View File

@@ -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 <T>
* type of the configuration value
* @param <T> type of the configuration value
*/
@Data
@Builder
public final class TenantConfigurationValue<T extends Serializable> implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private T value;

View File

@@ -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<String, TenantConfigurationKey> configuration = new HashMap<>();
/**
* @return full map of all configured tenant properties
*/
public Map<String, TenantConfigurationKey> 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<? extends Serializable> dataType = String.class;
private Class<? extends TenantConfigurationValidator> 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 <T> Class<T> getDataType() {
return (Class<T>) 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<? extends TenantConfigurationValidator> getValidator() {
return validator;
}
public void setValidator(final Class<? extends TenantConfigurationValidator> 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()

View File

@@ -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 extends Serializable> T getConfigValue(final String key, final Class<T> 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);
}
}

View File

@@ -22,7 +22,7 @@ import java.util.Optional;
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString
@ToString(callSuper = true)
@Accessors(fluent = true)
public class GenericDistributionSetUpdate extends AbstractDistributionSetUpdateCreate<DistributionSetUpdate>
implements DistributionSetUpdate {

View File

@@ -22,7 +22,7 @@ import java.util.Optional;
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString
@ToString(callSuper = true)
@Accessors(fluent = true)
public class GenericSoftwareModuleUpdate extends AbstractSoftwareModuleUpdateCreate<SoftwareModuleUpdate>
implements SoftwareModuleUpdate {

View File

@@ -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

View File

@@ -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());

View File

@@ -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());
}

View File

@@ -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());
}

View File

@@ -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<T>)configurationKey.getDataType());
}
@Override

View File

@@ -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" : "",