Restructuring properties (#528)
* Moved test property file to one locations Signed-off-by: Jonathan Philip Knoblauch <JonathanPhilip.Knoblauch@bosch-si.com> * Added missing properties Signed-off-by: Jonathan Philip Knoblauch <JonathanPhilip.Knoblauch@bosch-si.com> * Move property defaults to respective modules. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Moved test relevant properties in respective modules. Added missing tests. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * deleted security.filter-order property Signed-off-by: Jonathan Philip Knoblauch <JonathanPhilip.Knoblauch@bosch-si.com> * Remove empty line Signed-off-by: Melanie Retter <melanie.retter@bosch-si.com> * Removed build properties Signed-off-by: Jonathan Philip Knoblauch <JonathanPhilip.Knoblauch@bosch-si.com>
This commit is contained in:
committed by
Kai Zimmermann
parent
352bfcff24
commit
f42d9b6978
@@ -23,11 +23,11 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.exception;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
|
||||
/**
|
||||
* The {@link #InvalidTenantConfigurationKeyException} is thrown when an invalid
|
||||
* configuration key is used.
|
||||
*
|
||||
*/
|
||||
public class InvalidTenantConfigurationKeyException extends AbstractServerRtException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final SpServerError THIS_ERROR = SpServerError.SP_CONFIGURATION_KEY_INVALID;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public InvalidTenantConfigurationKeyException() {
|
||||
super(THIS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public InvalidTenantConfigurationKeyException(final Throwable cause) {
|
||||
super(THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public InvalidTenantConfigurationKeyException(final String message, final Throwable cause) {
|
||||
super(message, THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
*/
|
||||
public InvalidTenantConfigurationKeyException(final String message) {
|
||||
super(message, THIS_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.tenancy.configuration;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
|
||||
/**
|
||||
* This class is a helper for converting a duration into a string and for the
|
||||
* other way. The string is in the format expected in configuration and database
|
||||
* {@link #DURATION_FORMAT}.
|
||||
*
|
||||
*/
|
||||
public final class DurationHelper {
|
||||
|
||||
/**
|
||||
* Duration validation utility class. Checks if the requested duration is in
|
||||
* the defined min/max range.
|
||||
*
|
||||
*/
|
||||
public static final class DurationRangeValidator {
|
||||
final Duration min;
|
||||
final Duration max;
|
||||
|
||||
private DurationRangeValidator(final Duration min, final Duration max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the requested duration is in the defined min/max range.
|
||||
*
|
||||
* @param duration
|
||||
* to checked
|
||||
* @return <code>true</code> if in time range
|
||||
*/
|
||||
public boolean isWithinRange(final Duration duration) {
|
||||
return duration.compareTo(min) >= 0 && duration.compareTo(max) <= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format of the String expected in configuration file and in the database.
|
||||
*/
|
||||
public static final String DURATION_FORMAT = "HH:mm:ss";
|
||||
|
||||
private DurationHelper() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link DurationRangeValidator}.
|
||||
*
|
||||
* @param min
|
||||
* imum of range.
|
||||
* @param max
|
||||
* imum of range.
|
||||
* @return {@link DurationRangeValidator} range.
|
||||
*/
|
||||
public static DurationRangeValidator durationRangeValidator(final Duration min, final Duration max) {
|
||||
return new DurationRangeValidator(min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Duration into a formatted String
|
||||
*
|
||||
* @param duration
|
||||
* duration, which will be converted into a formatted String
|
||||
* @return String in the duration format, specified at
|
||||
* {@link #DURATION_FORMAT}
|
||||
*/
|
||||
public static String durationToFormattedString(final Duration duration) {
|
||||
if (duration == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return LocalTime.ofNanoOfDay(duration.toNanos()).format(DateTimeFormatter.ofPattern(DURATION_FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a formatted String into a Duration object.
|
||||
*
|
||||
* @param formattedDuration
|
||||
* String in {@link #DURATION_FORMAT}
|
||||
* @return duration
|
||||
* @throws DateTimeParseException
|
||||
* when String is in wrong format
|
||||
*/
|
||||
public static Duration formattedStringToDuration(final String formattedDuration) {
|
||||
if (formattedDuration == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final TemporalAccessor ta = DateTimeFormatter.ofPattern(DURATION_FORMAT).parse(formattedDuration.trim());
|
||||
return Duration.between(LocalTime.MIDNIGHT, LocalTime.from(ta));
|
||||
}
|
||||
|
||||
/**
|
||||
* converts values of time constants to a Duration object..
|
||||
*
|
||||
* @param hours
|
||||
* count of hours
|
||||
* @param minutes
|
||||
* count of minutes
|
||||
* @param seconds
|
||||
* count of seconds
|
||||
* @return duration
|
||||
*/
|
||||
public static Duration getDurationByTimeValues(final long hours, final long minutes, final long seconds) {
|
||||
return Duration.ofHours(hours).plusMinutes(minutes).plusSeconds(seconds);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.tenancy.configuration;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.ControllerPollProperties;
|
||||
import org.eclipse.hawkbit.HawkbitServerProperties.Anonymous.Download;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidTenantConfigurationKeyException;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationStringValidator;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidator;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Properties for tenant configuration default values.
|
||||
*
|
||||
*/
|
||||
@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
|
||||
*/
|
||||
public Collection<TenantConfigurationKey> getConfigurationKeys() {
|
||||
return configuration.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param keyName
|
||||
* name of the TenantConfigurationKey
|
||||
* @return the TenantConfigurationKey with the name keyName
|
||||
*/
|
||||
public TenantConfigurationKey fromKeyName(final String keyName) {
|
||||
return configuration.values().stream().filter(conf -> conf.getKeyName().equals(keyName)).findAny()
|
||||
.orElseThrow(() -> new InvalidTenantConfigurationKeyException(
|
||||
"The given configuration key " + keyName + " does not exist."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tenant specific configurations which can be configured for each tenant
|
||||
* separately by means of override of the system defaults.
|
||||
*
|
||||
*/
|
||||
public static class TenantConfigurationKey {
|
||||
/**
|
||||
* Header based authentication enabled.
|
||||
*/
|
||||
public static final String AUTHENTICATION_MODE_HEADER_ENABLED = "authentication.header.enabled";
|
||||
|
||||
/**
|
||||
* Header based authentication authority name.
|
||||
*/
|
||||
public static final String AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME = "authentication.header.authority";
|
||||
/**
|
||||
* Target token based authentication enabled.
|
||||
*/
|
||||
public static final String AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED = "authentication.targettoken.enabled";
|
||||
|
||||
/**
|
||||
* Gateway token based authentication enabled.
|
||||
*/
|
||||
public static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED = "authentication.gatewaytoken.enabled";
|
||||
|
||||
/**
|
||||
* Gateway token value.
|
||||
*/
|
||||
public static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY = "authentication.gatewaytoken.key";
|
||||
|
||||
/**
|
||||
* See system default in
|
||||
* {@link ControllerPollProperties#getPollingTime()}.
|
||||
*/
|
||||
public static final String POLLING_TIME_INTERVAL = "pollingTime";
|
||||
|
||||
/**
|
||||
* See system default in
|
||||
* {@link ControllerPollProperties#getPollingOverdueTime()}.
|
||||
*/
|
||||
public static final String POLLING_OVERDUE_TIME_INTERVAL = "pollingOverdueTime";
|
||||
|
||||
/**
|
||||
* See system default {@link Download#isEnabled()}.
|
||||
*/
|
||||
public static final String ANONYMOUS_DOWNLOAD_MODE_ENABLED = "anonymous.download.enabled";
|
||||
|
||||
private String keyName;
|
||||
private String defaultValue = "";
|
||||
private Class<?> dataType = String.class;
|
||||
private Class<? extends TenantConfigurationValidator> validator = TenantConfigurationStringValidator.class;
|
||||
|
||||
public String getKeyName() {
|
||||
return keyName;
|
||||
}
|
||||
|
||||
public void setKeyName(final String keyName) {
|
||||
this.keyName = keyName;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public void validate(final ApplicationContext context, final Object value) {
|
||||
final TenantConfigurationValidator createdBean = context.getAutowireCapableBeanFactory()
|
||||
.createBean(validator);
|
||||
try {
|
||||
createdBean.validate(value);
|
||||
} finally {
|
||||
context.getAutowireCapableBeanFactory().destroyBean(createdBean);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.tenancy.configuration.validator;
|
||||
|
||||
/**
|
||||
* specific tenant configuration validator, which validates that the given value
|
||||
* is a booleans.
|
||||
*/
|
||||
public class TenantConfigurationBooleanValidator implements TenantConfigurationValidator {
|
||||
|
||||
@Override
|
||||
public Class<?> validateToClass() {
|
||||
return Boolean.class;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.tenancy.configuration.validator;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.format.DateTimeParseException;
|
||||
|
||||
import org.eclipse.hawkbit.ControllerPollProperties;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* This class is used to validate, that the property is a String and that it is
|
||||
* in the correct duration format.
|
||||
*
|
||||
*/
|
||||
public class TenantConfigurationPollingDurationValidator implements TenantConfigurationValidator {
|
||||
|
||||
private final Duration minDuration;
|
||||
|
||||
private final Duration maxDuration;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param properties
|
||||
* property accessor for poll configuration
|
||||
*/
|
||||
@Autowired
|
||||
public TenantConfigurationPollingDurationValidator(final ControllerPollProperties properties) {
|
||||
minDuration = DurationHelper.formattedStringToDuration(properties.getMinPollingTime());
|
||||
maxDuration = DurationHelper.formattedStringToDuration(properties.getMaxPollingTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
// Exception squid:S1166 - Hide origin exception
|
||||
@SuppressWarnings({ "squid:S1166" })
|
||||
public void validate(final Object tenantConfigurationObject) {
|
||||
TenantConfigurationValidator.super.validate(tenantConfigurationObject);
|
||||
final String tenantConfigurationString = (String) tenantConfigurationObject;
|
||||
|
||||
final Duration tenantConfigurationValue;
|
||||
try {
|
||||
tenantConfigurationValue = DurationHelper.formattedStringToDuration(tenantConfigurationString);
|
||||
} catch (final DateTimeParseException ex) {
|
||||
throw new TenantConfigurationValidatorException(
|
||||
String.format("The given configuration value is expected as a string in the format %s.",
|
||||
DurationHelper.DURATION_FORMAT));
|
||||
}
|
||||
|
||||
if (!DurationHelper.durationRangeValidator(minDuration, maxDuration).isWithinRange(tenantConfigurationValue)) {
|
||||
throw new TenantConfigurationValidatorException(
|
||||
String.format("The given configuration value is not in the allowed range from %s to %s.",
|
||||
DurationHelper.durationToFormattedString(minDuration),
|
||||
DurationHelper.durationToFormattedString(maxDuration)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> validateToClass() {
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
|
||||
package org.eclipse.hawkbit.tenancy.configuration.validator;
|
||||
|
||||
/**
|
||||
* specific tenant configuration validator, which validates Strings.
|
||||
*/
|
||||
public class TenantConfigurationStringValidator implements TenantConfigurationValidator {
|
||||
|
||||
@Override
|
||||
public Class<?> validateToClass() {
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.tenancy.configuration.validator;
|
||||
|
||||
/**
|
||||
* base interface for clases which can validate tenant configuration values.
|
||||
*
|
||||
*/
|
||||
public interface TenantConfigurationValidator {
|
||||
|
||||
/**
|
||||
* validates the tenant configuration value
|
||||
*
|
||||
* @param tenantConfigurationValue
|
||||
* value which will be validated.
|
||||
* @throws TenantConfigurationValidatorException
|
||||
* is thrown, when parameter is invalid.
|
||||
*/
|
||||
default void validate(final Object tenantConfigurationValue) {
|
||||
if (tenantConfigurationValue != null
|
||||
&& validateToClass().isAssignableFrom(tenantConfigurationValue.getClass())) {
|
||||
return;
|
||||
}
|
||||
throw new TenantConfigurationValidatorException(
|
||||
"The given configuration value is expected as a " + validateToClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generic class to check the object
|
||||
*
|
||||
* @return the class to check the value
|
||||
*/
|
||||
default Class<?> validateToClass() {
|
||||
return Object.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.tenancy.configuration.validator;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
|
||||
/**
|
||||
* Exception which is thrown, when the validation of the configuration value has
|
||||
* not been successful.
|
||||
*
|
||||
*/
|
||||
public class TenantConfigurationValidatorException extends AbstractServerRtException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final SpServerError THIS_ERROR = SpServerError.SP_CONFIGURATION_VALUE_INVALID;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public TenantConfigurationValidatorException() {
|
||||
super(THIS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public TenantConfigurationValidatorException(final Throwable cause) {
|
||||
super(THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public TenantConfigurationValidatorException(final String message, final Throwable cause) {
|
||||
super(message, THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
*/
|
||||
public TenantConfigurationValidatorException(final String message) {
|
||||
super(message, THIS_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository;
|
||||
|
||||
import org.eclipse.hawkbit.ControllerPollProperties;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
/**
|
||||
* Default configuration that is common to all repository implementations.
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({ RepositoryProperties.class, ControllerPollProperties.class,
|
||||
TenantConfigurationProperties.class })
|
||||
@PropertySource("classpath:/hawkbit-repository-defaults.properties")
|
||||
public class RepositoryDefaultConfiguration {
|
||||
|
||||
}
|
||||
@@ -7,48 +7,14 @@
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
|
||||
logging.level.=INFO
|
||||
logging.level.org.eclipse.persistence=ERROR
|
||||
logging.level.org.eclipse.hawkbit.repository.test.matcher.EventVerifier=ERROR
|
||||
# Defines the polling time for the controllers in HH:MM:SS notation
|
||||
hawkbit.controller.pollingTime=00:05:00
|
||||
hawkbit.controller.pollingOverdueTime=00:05:00
|
||||
hawkbit.controller.maxPollingTime=23:59:59
|
||||
hawkbit.controller.minPollingTime=00:00:30
|
||||
# Attention: if you want to use a maximumPollingTime greater 23:59:59 you have to update the DurationField in the configuration window
|
||||
|
||||
spring.data.mongodb.uri=mongodb://localhost/spArtifactRepository${random.value}
|
||||
spring.data.mongodb.port=28017
|
||||
|
||||
spring.http.multipart.max-file-size=5MB
|
||||
|
||||
hawkbit.server.security.dos.maxStatusEntriesPerAction=100
|
||||
|
||||
hawkbit.server.security.dos.maxAttributeEntriesPerTarget=10
|
||||
|
||||
spring.jpa.database=H2
|
||||
spring.datasource.url=jdbc:h2:mem:sp-db;DB_CLOSE_ON_EXIT=FALSE
|
||||
spring.datasource.driverClassName=org.h2.Driver
|
||||
spring.datasource.tomcat.default-auto-commit=false
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=sa
|
||||
|
||||
spring.datasource.eclipselink.logging.logger=JavaLogger
|
||||
spring.jpa.properties.eclipselink.logging.level=FINE
|
||||
spring.jpa.properties.eclipselink.logging.level.sql=FINE
|
||||
spring.jpa.properties.eclipselink.logging.parameters=true
|
||||
|
||||
flyway.enabled=true
|
||||
flyway.sqlMigrationSuffix=${spring.jpa.database}.sql
|
||||
|
||||
# DDI configuration
|
||||
hawkbit.controller.pollingTime=00:01:00
|
||||
hawkbit.controller.pollingOverdueTime=00:01:00
|
||||
|
||||
# DDI and download security
|
||||
hawkbit.server.ddi.security.authentication.header.authority=
|
||||
hawkbit.server.ddi.security.authentication.targettoken.enabled=false
|
||||
hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false
|
||||
hawkbit.server.download.anonymous.enabled=false
|
||||
hawkbit.server.ddi.security.authentication.header.enabled=true
|
||||
hawkbit.server.ddi.security.authentication.gatewaytoken.name=TestToken
|
||||
hawkbit.server.ddi.security.authentication.gatewaytoken.key=
|
||||
|
||||
# Default tenant configuration properties
|
||||
# Default tenant configuration - START
|
||||
hawkbit.server.tenant.configuration.authentication-header-enabled.keyName=authentication.header.enabled
|
||||
hawkbit.server.tenant.configuration.authentication-header-enabled.defaultValue=${hawkbit.server.ddi.security.authentication.header.enabled}
|
||||
hawkbit.server.tenant.configuration.authentication-header-enabled.dataType=java.lang.Boolean
|
||||
@@ -82,3 +48,4 @@ hawkbit.server.tenant.configuration.anonymous-download-enabled.keyName=anonymous
|
||||
hawkbit.server.tenant.configuration.anonymous-download-enabled.defaultValue=${hawkbit.server.download.anonymous.enabled}
|
||||
hawkbit.server.tenant.configuration.anonymous-download-enabled.dataType=java.lang.Boolean
|
||||
hawkbit.server.tenant.configuration.anonymous-download-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator
|
||||
# Default tenant configuration - END
|
||||
@@ -13,7 +13,6 @@ import java.util.Map;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.eclipse.hawkbit.ControllerPollProperties;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
@@ -21,7 +20,7 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.PropertiesQuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.RepositoryDefaultConfiguration;
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||
@@ -70,7 +69,6 @@ import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -78,7 +76,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.orm.jpa.EntityScan;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
@@ -86,7 +83,9 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.integration.support.locks.LockRegistry;
|
||||
@@ -111,11 +110,11 @@ import com.google.common.collect.Maps;
|
||||
@EnableAspectJAutoProxy
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableConfigurationProperties({ RepositoryProperties.class, ControllerPollProperties.class,
|
||||
TenantConfigurationProperties.class })
|
||||
@EnableScheduling
|
||||
@EnableRetry
|
||||
@EntityScan("org.eclipse.hawkbit.repository.jpa.model")
|
||||
@PropertySource("classpath:/hawkbit-jpa-defaults.properties")
|
||||
@Import({ RepositoryDefaultConfiguration.class })
|
||||
public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
#
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# which accompanies this distribution, and is available at
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
|
||||
### JPA / Datasource - START
|
||||
spring.jpa.database=H2
|
||||
spring.jpa.show-sql=false
|
||||
spring.datasource.tomcat.defaultAutoCommit=false
|
||||
# Logging
|
||||
spring.datasource.eclipselink.logging.logger=JavaLogger
|
||||
spring.jpa.properties.eclipselink.logging.level=off
|
||||
# Cluster aware
|
||||
spring.datasource.eclipselink.query-results-cache=false
|
||||
spring.datasource.eclipselink.cache.shared.default=false
|
||||
# Flyway DDL
|
||||
flyway.enabled=true
|
||||
flyway.initOnMigrate=true
|
||||
flyway.cleanDisabled=true
|
||||
flyway.sqlMigrationSuffix=${spring.jpa.database}.sql
|
||||
### JPA / Datasource - END
|
||||
@@ -30,12 +30,14 @@ import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@SpringApplicationConfiguration(classes = {
|
||||
org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration.class })
|
||||
@TestPropertySource(locations = "classpath:/jpa-test.properties")
|
||||
public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest {
|
||||
|
||||
protected static final String NOT_EXIST_ID = "1234";
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@@ -32,7 +33,10 @@ import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedE
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException;
|
||||
import org.eclipse.hawkbit.repository.exception.TooManyStatusEntriesException;
|
||||
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.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -622,6 +626,79 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
.isEqualTo(testData);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that target attribute update fails if quota hits.")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 2) })
|
||||
public void updateTargetAttributesFailsIfTooManyEntries() throws Exception {
|
||||
final String controllerId = "test123";
|
||||
final int allowedAttributes = 10;
|
||||
testdataFactory.createTarget(controllerId);
|
||||
|
||||
assertThatExceptionOfType(ToManyAttributeEntriesException.class).isThrownBy(() -> securityRule
|
||||
.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
|
||||
writeAttributes(controllerId, allowedAttributes + 1, "key", "value");
|
||||
return null;
|
||||
})).withMessageContaining("" + allowedAttributes);
|
||||
|
||||
// verify that no attributes have been written
|
||||
assertThat(targetManagement.getControllerAttributes(controllerId)).isEmpty();
|
||||
|
||||
// Write allowed number of attributes twice with same key should result
|
||||
// in update but work
|
||||
securityRule.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
|
||||
writeAttributes(controllerId, allowedAttributes, "key", "value1");
|
||||
writeAttributes(controllerId, allowedAttributes, "key", "value2");
|
||||
return null;
|
||||
});
|
||||
assertThat(targetManagement.getControllerAttributes(controllerId)).hasSize(10);
|
||||
|
||||
// Now rite one more
|
||||
assertThatExceptionOfType(ToManyAttributeEntriesException.class).isThrownBy(() -> securityRule
|
||||
.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
|
||||
writeAttributes(controllerId, 1, "additional", "value1");
|
||||
return null;
|
||||
})).withMessageContaining("" + allowedAttributes);
|
||||
assertThat(targetManagement.getControllerAttributes(controllerId)).hasSize(10);
|
||||
|
||||
}
|
||||
|
||||
private void writeAttributes(final String controllerId, final int allowedAttributes, final String keyPrefix,
|
||||
final String valuePrefix) {
|
||||
final Map<String, String> testData = Maps.newHashMapWithExpectedSize(allowedAttributes);
|
||||
for (int i = 0; i < allowedAttributes; i++) {
|
||||
testData.put(keyPrefix + i, valuePrefix);
|
||||
}
|
||||
controllerManagement.updateControllerAttributes(controllerId, testData);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Controller providing status entries fails if providing more than permitted by quota.")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
||||
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1),
|
||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3) })
|
||||
public void controllerProvidesIntermediateFeedbackFailsIfQuotaHit() {
|
||||
final int allowStatusEntries = 10;
|
||||
final Long actionId = createTargetAndAssignDs();
|
||||
|
||||
// Fails as one entry is already in there from the assignment
|
||||
assertThatExceptionOfType(TooManyStatusEntriesException.class).isThrownBy(() -> securityRule
|
||||
.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
|
||||
writeStatus(actionId, allowStatusEntries);
|
||||
return null;
|
||||
})).withMessageContaining("" + allowStatusEntries);
|
||||
|
||||
}
|
||||
|
||||
private void writeStatus(final Long actionId, final int allowedStatusEntries) {
|
||||
for (int i = 0; i < allowedStatusEntries; i++) {
|
||||
controllerManagement.addInformationalActionStatus(
|
||||
entityFactory.actionStatus().create(actionId).status(Status.RUNNING).message("test" + i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test to verify the storage and retrieval of action history.")
|
||||
public void findMessagesByActionStatusId() {
|
||||
|
||||
@@ -16,9 +16,9 @@ import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidTenantConfigurationKeyException;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.InvalidTenantConfigurationKeyException;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException;
|
||||
import org.junit.Assert;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
#
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# which accompanies this distribution, and is available at
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
|
||||
# Quota - START
|
||||
hawkbit.server.security.dos.maxStatusEntriesPerAction=10
|
||||
hawkbit.server.security.dos.maxAttributeEntriesPerTarget=10
|
||||
# Quota - END
|
||||
@@ -53,6 +53,7 @@ import org.springframework.context.annotation.AdviceMode;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
@@ -74,6 +75,7 @@ import org.springframework.util.AntPathMatcher;
|
||||
ControllerPollProperties.class, TenantConfigurationProperties.class })
|
||||
@Profile("test")
|
||||
@EnableAutoConfiguration
|
||||
@PropertySource("classpath:/hawkbit-test-defaults.properties")
|
||||
public class TestConfiguration implements AsyncConfigurer {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#
|
||||
# Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
#
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# which accompanies this distribution, and is available at
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
|
||||
# Test utility properties for easier fault investigation - START
|
||||
## Logging - START
|
||||
logging.level.=INFO
|
||||
logging.level.org.eclipse.persistence=ERROR
|
||||
logging.level.org.eclipse.hawkbit.repository.test.matcher.EventVerifier=ERROR
|
||||
spring.jpa.properties.eclipselink.logging.level=FINE
|
||||
spring.jpa.properties.eclipselink.logging.level.sql=FINE
|
||||
spring.jpa.properties.eclipselink.logging.parameters=true
|
||||
## Logging - END
|
||||
# Test utility properties for easier fault investigation - END
|
||||
|
||||
# Default properties for test that can be overridden during test run - START
|
||||
## JPA Repository - START
|
||||
spring.datasource.url=jdbc:h2:mem:sp-db;DB_CLOSE_ON_EXIT=FALSE
|
||||
## JPA Repository - END
|
||||
# Default properties for test that can be overridden during test run - END
|
||||
|
||||
# Properties that are managed by autoconfigure module at runtime and not available during test - START
|
||||
## DDI and download security - START
|
||||
hawkbit.server.ddi.security.authentication.header.enabled=true
|
||||
hawkbit.server.ddi.security.authentication.header.authority=
|
||||
hawkbit.server.ddi.security.authentication.targettoken.enabled=false
|
||||
hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false
|
||||
hawkbit.server.download.anonymous.enabled=false
|
||||
hawkbit.server.ddi.security.authentication.gatewaytoken.key=
|
||||
hawkbit.server.ddi.security.authentication.gatewaytoken.name=TestToken
|
||||
## DDI and download security - END
|
||||
|
||||
## Download URL Generation - START
|
||||
hawkbit.artifact.url.protocols.download-http.rel=download-http
|
||||
hawkbit.artifact.url.protocols.download-http.hostname=localhost
|
||||
hawkbit.artifact.url.protocols.download-http.ip=127.0.0.1
|
||||
hawkbit.artifact.url.protocols.download-http.protocol=http
|
||||
hawkbit.artifact.url.protocols.download-http.port=8080
|
||||
hawkbit.artifact.url.protocols.download-http.supports=DMF,DDI
|
||||
hawkbit.artifact.url.protocols.download-http.ref={protocol}://{hostnameRequest}:{portRequest}/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}
|
||||
hawkbit.artifact.url.protocols.md5sum-http.rel=md5sum-http
|
||||
hawkbit.artifact.url.protocols.md5sum-http.protocol=${hawkbit.artifact.url.protocols.download-http.protocol}
|
||||
hawkbit.artifact.url.protocols.md5sum-http.hostname=${hawkbit.artifact.url.protocols.download-http.hostname}
|
||||
hawkbit.artifact.url.protocols.md5sum-http.ip=${hawkbit.artifact.url.protocols.download-http.ip}
|
||||
hawkbit.artifact.url.protocols.md5sum-http.port=${hawkbit.artifact.url.protocols.download-http.port}
|
||||
hawkbit.artifact.url.protocols.md5sum-http.supports=DDI
|
||||
hawkbit.artifact.url.protocols.md5sum-http.ref=${hawkbit.artifact.url.protocols.download-http.ref}.MD5SUM
|
||||
## Download URL Generation - END
|
||||
|
||||
# Properties that are managed by autoconfigure module at runtime and not available during test - END
|
||||
Reference in New Issue
Block a user