Fix upload quota check and provide better error message (#893)

* Adjusted upload quota check to include file size and show proper error message

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Fixed failing upload quota tests

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Moved quota check to stream, fixed review findings

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Added missing license header to QuotaInputStream

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Reworked uploadLock, ensured error messages may be translated, review fixes

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Added local artifactrepo to gitignore

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Fixed sonar issues and assignment quota message

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* PR review fixes

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Split quota exceptions, PR fixes

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Removed left over conversion method in quota helper

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>

* Made conversion helper class final

Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>
This commit is contained in:
Alexander Dobler
2019-10-30 11:24:33 +01:00
committed by Dominic Schabel
parent 9b8ab40c55
commit 09f2d8a481
43 changed files with 477 additions and 213 deletions

1
.gitignore vendored
View File

@@ -12,6 +12,7 @@ target
.metadata .metadata
.project .project
.idea .idea
artifactrepo
# Windows image file caches # Windows image file caches
Thumbs.db Thumbs.db

View File

@@ -137,6 +137,16 @@ public enum SpServerError {
*/ */
SP_QUOTA_EXCEEDED("hawkbit.server.error.quota.tooManyEntries", "Too many entries have been inserted."), SP_QUOTA_EXCEEDED("hawkbit.server.error.quota.tooManyEntries", "Too many entries have been inserted."),
/**
* error that describes that size of uploaded file exceeds size quota
*/
SP_FILE_SIZE_QUOTA_EXCEEDED("hawkbit.server.error.quota.fileSizeExceeded", "File exceeds size quota."),
/**
* error that describes that size of uploaded file exceeds storage quota
*/
SP_STORAGE_QUOTA_EXCEEDED("hawkbit.server.error.quota.storageExceeded", "Storage quota will be exceeded if file is uploaded."),
/** /**
* error message, which describes that the action can not be canceled cause * error message, which describes that the action can not be canceled cause
* the action is inactive. * the action is inactive.

View File

@@ -16,7 +16,7 @@ import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException; import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException; import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.TenantNotExistException; import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -72,7 +72,7 @@ public class DelayedRequeueExceptionStrategy extends ConditionalRejectingErrorHa
} }
private static boolean quotaHit(final Throwable cause) { private static boolean quotaHit(final Throwable cause) {
return cause instanceof QuotaExceededException; return cause instanceof AssignmentQuotaExceededException;
} }
private static boolean doesNotExist(final Throwable cause) { private static boolean doesNotExist(final Throwable cause) {

View File

@@ -25,7 +25,7 @@ import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException; import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.ActionStatus;
@@ -56,9 +56,9 @@ public interface ControllerManagement {
* @throws EntityAlreadyExistsException * @throws EntityAlreadyExistsException
* if a given entity already exists * if a given entity already exists
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if more than the allowed number of status entries or messages per * if more than the allowed number of status entries or messages
* entry are inserted * per entry are inserted
* @throws EntityNotFoundException * @throws EntityNotFoundException
* if given action does not exist * if given action does not exist
* @throws ConstraintViolationException * @throws ConstraintViolationException
@@ -101,9 +101,9 @@ public interface ControllerManagement {
* *
* @return created {@link ActionStatus} entity * @return created {@link ActionStatus} entity
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if more than the allowed number of status entries or messages per * if more than the allowed number of status entries or messages
* entry are inserted * per entry are inserted
* @throws EntityNotFoundException * @throws EntityNotFoundException
* if given action does not exist * if given action does not exist
* @throws ConstraintViolationException * @throws ConstraintViolationException
@@ -123,9 +123,9 @@ public interface ControllerManagement {
* *
* @throws EntityAlreadyExistsException * @throws EntityAlreadyExistsException
* if a given entity already exists * if a given entity already exists
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if more than the allowed number of status entries or messages per * if more than the allowed number of status entries or messages
* entry are inserted * per entry are inserted
* @throws EntityNotFoundException * @throws EntityNotFoundException
* if action status not exist * if action status not exist
* @throws ConstraintViolationException * @throws ConstraintViolationException
@@ -361,7 +361,7 @@ public interface ControllerManagement {
* *
* @throws EntityNotFoundException * @throws EntityNotFoundException
* if target that has to be updated could not be found * if target that has to be updated could not be found
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if maximum number of attributes per target is exceeded * if maximum number of attributes per target is exceeded
* @throws InvalidTargetAttributeException * @throws InvalidTargetAttributeException
* if attributes violate constraints * if attributes violate constraints

View File

@@ -23,7 +23,7 @@ import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException; import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
@@ -66,7 +66,7 @@ public interface DeploymentManagement {
* if either provided {@link DistributionSet} or {@link Target}s * if either provided {@link DistributionSet} or {@link Target}s
* do not exist * do not exist
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of targets the distribution set can be * if the maximum number of targets the distribution set can be
* assigned to at once is exceeded * assigned to at once is exceeded
* @throws MultiAssignmentIsNotEnabledException * @throws MultiAssignmentIsNotEnabledException
@@ -97,7 +97,7 @@ public interface DeploymentManagement {
* if either provided {@link DistributionSet} or {@link Target}s * if either provided {@link DistributionSet} or {@link Target}s
* do not exist * do not exist
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of targets the distribution set can be * if the maximum number of targets the distribution set can be
* assigned to at once is exceeded * assigned to at once is exceeded
* @throws MultiAssignmentIsNotEnabledException * @throws MultiAssignmentIsNotEnabledException
@@ -151,7 +151,7 @@ public interface DeploymentManagement {
* if either provided {@link DistributionSet} or {@link Target}s * if either provided {@link DistributionSet} or {@link Target}s
* do not exist * do not exist
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of targets the distribution set can be * if the maximum number of targets the distribution set can be
* assigned to at once is exceeded * assigned to at once is exceeded
* *

View File

@@ -21,7 +21,7 @@ import org.eclipse.hawkbit.repository.builder.DistributionSetUpdate;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException;
@@ -67,7 +67,7 @@ public interface DistributionSetManagement
* if {@link SoftwareModule#getType()} is not supported by this * if {@link SoftwareModule#getType()} is not supported by this
* {@link DistributionSet#getType()}. * {@link DistributionSet#getType()}.
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of {@link SoftwareModule}s is exceeded * if the maximum number of {@link SoftwareModule}s is exceeded
* for the addressed {@link DistributionSet}. * for the addressed {@link DistributionSet}.
*/ */
@@ -109,7 +109,7 @@ public interface DistributionSetManagement
* in case one of the meta data entry already exists for the * in case one of the meta data entry already exists for the
* specific key * specific key
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of {@link MetaData} entries is exceeded * if the maximum number of {@link MetaData} entries is exceeded
* for the addressed {@link DistributionSet} * for the addressed {@link DistributionSet}
*/ */

View File

@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.repository.builder.DistributionSetTypeCreate;
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeUpdate; import org.eclipse.hawkbit.repository.builder.DistributionSetTypeUpdate;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
@@ -65,7 +65,7 @@ public interface DistributionSetTypeManagement
* if the {@link DistributionSetType} while it is already in use * if the {@link DistributionSetType} while it is already in use
* by a {@link DistributionSet} * by a {@link DistributionSet}
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of {@link SoftwareModuleType}s is * if the maximum number of {@link SoftwareModuleType}s is
* exceeded for the addressed {@link DistributionSetType} * exceeded for the addressed {@link DistributionSetType}
*/ */
@@ -90,7 +90,7 @@ public interface DistributionSetTypeManagement
* if the {@link DistributionSetType} while it is already in use * if the {@link DistributionSetType} while it is already in use
* by a {@link DistributionSet} * by a {@link DistributionSet}
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of {@link SoftwareModuleType}s is * if the maximum number of {@link SoftwareModuleType}s is
* exceeded for the addressed {@link DistributionSetType} * exceeded for the addressed {@link DistributionSetType}
*/ */

View File

@@ -22,7 +22,7 @@ import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
import org.eclipse.hawkbit.repository.builder.RolloutUpdate; import org.eclipse.hawkbit.repository.builder.RolloutUpdate;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException; import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
@@ -124,7 +124,7 @@ public interface RolloutManagement {
* if given {@link DistributionSet} does not exist * if given {@link DistributionSet} does not exist
* @throws ConstraintViolationException * @throws ConstraintViolationException
* if rollout or group parameters are invalid. * if rollout or group parameters are invalid.
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of allowed targets per rollout group is * if the maximum number of allowed targets per rollout group is
* exceeded. * exceeded.
*/ */
@@ -161,7 +161,7 @@ public interface RolloutManagement {
* if given {@link DistributionSet} does not exist * if given {@link DistributionSet} does not exist
* @throws ConstraintViolationException * @throws ConstraintViolationException
* if rollout or group parameters are invalid * if rollout or group parameters are invalid
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of allowed targets per rollout group is * if the maximum number of allowed targets per rollout group is
* exceeded. * exceeded.
*/ */

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) 2019 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;
/**
* Helper class that provides simple conversion of byte values to readable
* strings
*/
public final class SizeConversionHelper {
private static final String KB = "KB";
private static final String MB = "MB";
// do not allow to create instances
private SizeConversionHelper() {
}
/**
* Convert byte values to human readable strings with units
*
* @param byteValue
* Value to convert in bytes
*/
public static String byteValueToReadableString(final long byteValue) {
double outputValue = byteValue / 1024.0;
String unit = KB;
if (outputValue >= 1024) {
outputValue = outputValue / 1024.0;
unit = MB;
}
// We cut decimal places to avoid localization handling
return (long) outputValue + " " + unit;
}
}

View File

@@ -23,7 +23,7 @@ import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate; import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
@@ -75,7 +75,7 @@ public interface SoftwareModuleManagement
* @throws EntityNotFoundException * @throws EntityNotFoundException
* if software module with given ID does not exist * if software module with given ID does not exist
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of {@link SoftwareModuleMetadata} * if the maximum number of {@link SoftwareModuleMetadata}
* entries is exceeded for the addressed {@link SoftwareModule} * entries is exceeded for the addressed {@link SoftwareModule}
*/ */
@@ -97,7 +97,7 @@ public interface SoftwareModuleManagement
* @throws EntityNotFoundException * @throws EntityNotFoundException
* if software module with given ID does not exist * if software module with given ID does not exist
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of {@link SoftwareModuleMetadata} * if the maximum number of {@link SoftwareModuleMetadata}
* entries is exceeded for the addressed {@link SoftwareModule} * entries is exceeded for the addressed {@link SoftwareModule}
*/ */

View File

@@ -20,7 +20,7 @@ import org.eclipse.hawkbit.repository.builder.TargetFilterQueryUpdate;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException; import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException; import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
@@ -48,7 +48,7 @@ public interface TargetFilterQueryManagement {
* if fields are not filled as specified. Check * if fields are not filled as specified. Check
* {@link TargetFilterQueryCreate} for field constraints. * {@link TargetFilterQueryCreate} for field constraints.
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of targets that is addressed by the * if the maximum number of targets that is addressed by the
* given query is exceeded (auto-assignments only) * given query is exceeded (auto-assignments only)
*/ */
@@ -208,7 +208,7 @@ public interface TargetFilterQueryManagement {
* if fields are not filled as specified. Check * if fields are not filled as specified. Check
* {@link TargetFilterQueryUpdate} for field constraints. * {@link TargetFilterQueryUpdate} for field constraints.
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the update contains a new query which addresses too many * if the update contains a new query which addresses too many
* targets (auto-assignments only) * targets (auto-assignments only)
*/ */
@@ -231,7 +231,7 @@ public interface TargetFilterQueryManagement {
* if either {@link TargetFilterQuery} and/or autoAssignDs are * if either {@link TargetFilterQuery} and/or autoAssignDs are
* provided but not found * provided but not found
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the query that is already associated with this filter * if the query that is already associated with this filter
* query addresses too many targets (auto-assignments only) * query addresses too many targets (auto-assignments only)
* *
@@ -263,7 +263,7 @@ public interface TargetFilterQueryManagement {
* if either {@link TargetFilterQuery} and/or autoAssignDs are * if either {@link TargetFilterQuery} and/or autoAssignDs are
* provided but not found * provided but not found
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the query that is already associated with this filter * if the query that is already associated with this filter
* query addresses too many targets (auto-assignments only) * query addresses too many targets (auto-assignments only)
* *

View File

@@ -23,7 +23,7 @@ import org.eclipse.hawkbit.repository.builder.TargetCreate;
import org.eclipse.hawkbit.repository.builder.TargetUpdate; import org.eclipse.hawkbit.repository.builder.TargetUpdate;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -698,7 +698,7 @@ public interface TargetManagement {
* in case one of the meta data entry already exists for the * in case one of the meta data entry already exists for the
* specific key * specific key
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the maximum number of {@link MetaData} entries is exceeded * if the maximum number of {@link MetaData} entries is exceeded
* for the addressed {@link Target} * for the addressed {@link Target}
*/ */

View File

@@ -13,44 +13,43 @@ import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.repository.model.BaseEntity; import org.eclipse.hawkbit.repository.model.BaseEntity;
/** /**
* Thrown if too many entries are added to repository. * Thrown if assignment quota is exceeded
*
*/ */
public final class QuotaExceededException extends AbstractServerRtException { public class AssignmentQuotaExceededException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final String ASSIGNMENT_QUOTA_EXCEEDED_MESSAGE = "Quota exceeded: Cannot assign %s more %s entities to %s '%s'. The maximum is %s."; private static final String ASSIGNMENT_QUOTA_EXCEEDED_MESSAGE = "Quota exceeded: Cannot assign %s more %s entities to %s '%s'. The maximum is %s.";
private static final SpServerError errorType = SpServerError.SP_QUOTA_EXCEEDED;
/** /**
* Creates a new QuotaExceededException with * Creates a new AssignmentQuotaExceededException with
* {@link SpServerError#SP_QUOTA_EXCEEDED} error. * {@link SpServerError#SP_QUOTA_EXCEEDED} error.
*/ */
public QuotaExceededException() { public AssignmentQuotaExceededException() {
super(SpServerError.SP_QUOTA_EXCEEDED); super(errorType);
} }
/** /**
* Creates a new QuotaExceededException with a custom error message. * Creates a new AssignmentQuotaExceededException with a custom error
* * message.
*
* @param message * @param message
* The custom error message. * The custom error message.
*/ */
public QuotaExceededException(final String message) { public AssignmentQuotaExceededException(final String message) {
super(message, SpServerError.SP_QUOTA_EXCEEDED); super(message, errorType);
} }
/** /**
* Creates a QuotaExceededException with a custom error message and a root * Creates a AssignmentQuotaExceededException with a custom error message
* cause. * and a root cause.
* *
* @param message * @param message
* The custom error message. * The custom error message.
* @param cause * @param cause
* for the exception * for the exception
*/ */
public QuotaExceededException(final String message, final Throwable cause) { public AssignmentQuotaExceededException(final String message, final Throwable cause) {
super(message, SpServerError.SP_QUOTA_EXCEEDED, cause); super(message, errorType, cause);
} }
/** /**
@@ -61,12 +60,13 @@ public final class QuotaExceededException extends AbstractServerRtException {
* @param quota * @param quota
* that is defined by the repository * that is defined by the repository
*/ */
public QuotaExceededException(final Class<? extends BaseEntity> type, final long inserted, final int quota) { public AssignmentQuotaExceededException(final Class<? extends BaseEntity> type, final long inserted,
final int quota) {
this(type.getSimpleName(), inserted, quota); this(type.getSimpleName(), inserted, quota);
} }
/** /**
* *
* @param type * @param type
* that hit quota * that hit quota
* @param inserted * @param inserted
@@ -74,15 +74,15 @@ public final class QuotaExceededException extends AbstractServerRtException {
* @param quota * @param quota
* that is defined by the repository * that is defined by the repository
*/ */
public QuotaExceededException(final String type, final long inserted, final int quota) { public AssignmentQuotaExceededException(final String type, final long inserted, final int quota) {
super("Request contains too many entries of {" + type + "}. {" + inserted + "} is beyond the permitted {" super("Request contains too many entries of {" + type + "}. {" + inserted + "} is beyond the permitted {"
+ quota + "}.", SpServerError.SP_QUOTA_EXCEEDED); + quota + "}.", errorType);
} }
/** /**
* Creates a QuotaExceededException which is to be thrown when an assignment * Creates a AssignmentQuotaExceededException which is to be thrown when an
* quota is exceeded. * assignment quota is exceeded.
* *
* @param type * @param type
* The type of the entities that shall be assigned to the * The type of the entities that shall be assigned to the
* specified parent entity. * specified parent entity.
@@ -97,15 +97,15 @@ public final class QuotaExceededException extends AbstractServerRtException {
* The maximum number of entities that can be assigned to the * The maximum number of entities that can be assigned to the
* parent entity. * parent entity.
*/ */
public QuotaExceededException(final Class<?> type, final Class<?> parentType, final Long parentId, public AssignmentQuotaExceededException(final Class<?> type, final Class<?> parentType, final Long parentId,
final long requested, final long quota) { final long requested, final long quota) {
this(type.getSimpleName(), parentType.getSimpleName(), parentId, requested, quota); this(type.getSimpleName(), parentType.getSimpleName(), parentId, requested, quota);
} }
/** /**
* Creates a QuotaExceededException which is to be thrown when an assignment * Creates a AssignmentQuotaExceededException which is to be thrown when an
* quota is exceeded. * assignment quota is exceeded.
* *
* @param type * @param type
* The type of the entities that shall be assigned to the * The type of the entities that shall be assigned to the
* specified parent entity. * specified parent entity.
@@ -120,11 +120,9 @@ public final class QuotaExceededException extends AbstractServerRtException {
* The maximum number of entities that can be assigned to the * The maximum number of entities that can be assigned to the
* parent entity. * parent entity.
*/ */
public QuotaExceededException(final String type, final String parentType, final Object parentId, public AssignmentQuotaExceededException(final String type, final String parentType, final Object parentId,
final long requested, final long requested, final long quota) {
final long quota) {
super(String.format(ASSIGNMENT_QUOTA_EXCEEDED_MESSAGE, requested, type, parentType, super(String.format(ASSIGNMENT_QUOTA_EXCEEDED_MESSAGE, requested, type, parentType,
parentId != null ? String.valueOf(parentId) : "<new>", quota), SpServerError.SP_QUOTA_EXCEEDED); parentId != null ? String.valueOf(parentId) : "<new>", quota), errorType);
} }
} }

View File

@@ -0,0 +1,49 @@
/**
* Copyright (c) 2019 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 static org.eclipse.hawkbit.repository.SizeConversionHelper.byteValueToReadableString;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
import org.eclipse.hawkbit.exception.SpServerError;
/**
* Thrown if file size quota is exceeded
*/
public class FileSizeQuotaExceededException extends AbstractServerRtException {
private static final String MAX_ARTIFACT_SIZE_EXCEEDED = "Maximum artifact size (%s) exceeded.";
private static final SpServerError errorType = SpServerError.SP_FILE_SIZE_QUOTA_EXCEEDED;
private final long exceededQuotaValue;
/**
* Creates a new FileSizeQuotaExceededException with a quota value.
*
* @param exceededQuotaValue
* Value by how much the quota was exceeded
*/
public FileSizeQuotaExceededException(final long exceededQuotaValue) {
super(createQuotaErrorMessage(exceededQuotaValue), errorType);
this.exceededQuotaValue = exceededQuotaValue;
}
/**
* Get a readable string of size quota including unit
*
* @return file size quota with unit
*/
public String getExceededQuotaValueString() {
return byteValueToReadableString(exceededQuotaValue);
}
private static String createQuotaErrorMessage(final long exceededQuotaValue) {
return String.format(MAX_ARTIFACT_SIZE_EXCEEDED, byteValueToReadableString(exceededQuotaValue));
}
}

View File

@@ -0,0 +1,49 @@
/**
* Copyright (c) 2019 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 static org.eclipse.hawkbit.repository.SizeConversionHelper.byteValueToReadableString;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
import org.eclipse.hawkbit.exception.SpServerError;
/**
* Thrown if storage quota is exceeded
*/
public class StorageQuotaExceededException extends AbstractServerRtException {
private static final String MAX_ARTIFACT_SIZE_TOTAL_EXCEEDED = "Storage quota exceeded, %s left.";
private static final SpServerError errorType = SpServerError.SP_STORAGE_QUOTA_EXCEEDED;
private final long exceededQuotaValue;
/**
* Creates a new StorageQuotaExceededException with a quota value.
*
* @param exceededQuotaValue
* Value by how much the quota was exceeded
*/
public StorageQuotaExceededException(final long exceededQuotaValue) {
super(createQuotaErrorMessage(exceededQuotaValue), errorType);
this.exceededQuotaValue = exceededQuotaValue;
}
/**
* Get a readable string of size quota including unit
*
* @return file size quota with unit
*/
public String getExceededQuotaValueString() {
return byteValueToReadableString(exceededQuotaValue);
}
private static String createQuotaErrorMessage(final long exceededQuotaValue) {
return String.format(MAX_ARTIFACT_SIZE_TOTAL_EXCEEDED, byteValueToReadableString(exceededQuotaValue));
}
}

View File

@@ -14,7 +14,7 @@ import java.util.stream.Collectors;
import javax.validation.ValidationException; import javax.validation.ValidationException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException; import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
@@ -78,7 +78,7 @@ public final class RolloutHelper {
if (amountGroup <= 0) { if (amountGroup <= 0) {
throw new ValidationException("The amount of groups cannot be lower than zero"); throw new ValidationException("The amount of groups cannot be lower than zero");
} else if (amountGroup > quotaManagement.getMaxRolloutGroupsPerRollout()) { } else if (amountGroup > quotaManagement.getMaxRolloutGroupsPerRollout()) {
throw new QuotaExceededException( throw new AssignmentQuotaExceededException(
"The amount of groups cannot be greater than " + quotaManagement.getMaxRolloutGroupsPerRollout()); "The amount of groups cannot be greater than " + quotaManagement.getMaxRolloutGroupsPerRollout());
} }

View File

@@ -8,6 +8,8 @@
*/ */
package org.eclipse.hawkbit.repository.jpa; package org.eclipse.hawkbit.repository.jpa;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional; import java.util.Optional;
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository; import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
@@ -23,11 +25,11 @@ import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException; import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException; import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants; import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact; import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.jpa.utils.FileSizeAndStorageQuotaCheckingInputStream;
import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.ArtifactUpload; import org.eclipse.hawkbit.repository.model.ArtifactUpload;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
@@ -53,10 +55,6 @@ public class JpaArtifactManagement implements ArtifactManagement {
private static final Logger LOG = LoggerFactory.getLogger(JpaArtifactManagement.class); private static final Logger LOG = LoggerFactory.getLogger(JpaArtifactManagement.class);
private static final String MAX_ARTIFACT_SIZE_EXCEEDED = "Quota exceeded: The artifact '%s' (%s bytes) which has been uploaded for software module '%s' exceeds the maximum artifact size of %s bytes.";
private static final String MAX_ARTIFACT_SIZE_TOTAL_EXCEEDED = "Quota exceeded: The artifact '%s' (%s bytes) cannot be uploaded. The maximum total artifact storage of %s bytes would be exceeded.";
private final LocalArtifactRepository localArtifactRepository; private final LocalArtifactRepository localArtifactRepository;
private final SoftwareModuleRepository softwareModuleRepository; private final SoftwareModuleRepository softwareModuleRepository;
@@ -105,8 +103,6 @@ public class JpaArtifactManagement implements ArtifactManagement {
final Artifact existing = checkForExistingArtifact(filename, artifactUpload.overrideExisting(), softwareModule); final Artifact existing = checkForExistingArtifact(filename, artifactUpload.overrideExisting(), softwareModule);
assertArtifactQuota(moduleId, 1); assertArtifactQuota(moduleId, 1);
assertMaxArtifactSizeQuota(filename, moduleId, artifactUpload.getFilesize());
assertMaxArtifactStorageQuota(filename, artifactUpload.getFilesize());
return getOrCreateArtifact(artifactUpload) return getOrCreateArtifact(artifactUpload)
.map(artifact -> storeArtifactMetadata(softwareModule, filename, artifact, existing)).orElse(null); .map(artifact -> storeArtifactMetadata(softwareModule, filename, artifact, existing)).orElse(null);
@@ -125,11 +121,12 @@ public class JpaArtifactManagement implements ArtifactManagement {
} }
private AbstractDbArtifact storeArtifact(final ArtifactUpload artifactUpload) { private AbstractDbArtifact storeArtifact(final ArtifactUpload artifactUpload) {
try { try(final InputStream quotaStream = wrapInQuotaStream(artifactUpload.getInputStream())) {
return artifactRepository.store(tenantAware.getCurrentTenant(), artifactUpload.getInputStream(), return artifactRepository.store(tenantAware.getCurrentTenant(), quotaStream,
artifactUpload.getFilename(), artifactUpload.getContentType(), artifactUpload.getFilename(), artifactUpload.getContentType(),
new DbArtifactHash(artifactUpload.getProvidedSha1Sum(), artifactUpload.getProvidedMd5Sum(), artifactUpload.getProvidedSha256Sum())); new DbArtifactHash(artifactUpload.getProvidedSha1Sum(), artifactUpload.getProvidedMd5Sum(),
} catch (final ArtifactStoreException e) { artifactUpload.getProvidedSha256Sum()));
} catch (final ArtifactStoreException | IOException e) {
throw new ArtifactUploadFailedException(e); throw new ArtifactUploadFailedException(e);
} catch (final HashNotMatchException e) { } catch (final HashNotMatchException e) {
if (e.getHashFunction().equals(HashNotMatchException.SHA1)) { if (e.getHashFunction().equals(HashNotMatchException.SHA1)) {
@@ -145,31 +142,13 @@ public class JpaArtifactManagement implements ArtifactManagement {
Artifact.class, SoftwareModule.class, localArtifactRepository::countBySoftwareModuleId); Artifact.class, SoftwareModule.class, localArtifactRepository::countBySoftwareModuleId);
} }
private void assertMaxArtifactSizeQuota(final String filename, final long id, final long artifactSize) { private InputStream wrapInQuotaStream(final InputStream in) {
final long maxArtifactSize = quotaManagement.getMaxArtifactSize(); final long maxArtifactSize = quotaManagement.getMaxArtifactSize();
if (maxArtifactSize <= 0) {
return;
}
if (artifactSize > maxArtifactSize) {
final String msg = String.format(MAX_ARTIFACT_SIZE_EXCEEDED, filename, artifactSize, id, maxArtifactSize);
LOG.warn(msg);
throw new QuotaExceededException(msg);
}
}
private void assertMaxArtifactStorageQuota(final String filename, final long artifactSize) { final long currentlyUsed = localArtifactRepository.getSumOfUndeletedArtifactSize().orElse(0L);
final long maxArtifactSizeTotal = quotaManagement.getMaxArtifactStorage(); final long maxArtifactSizeTotal = quotaManagement.getMaxArtifactStorage();
if (maxArtifactSizeTotal <= 0) {
return;
}
final Long currentlyUsed = localArtifactRepository.getSumOfUndeletedArtifactSize().orElse(0L); return new FileSizeAndStorageQuotaCheckingInputStream(in, maxArtifactSize, maxArtifactSizeTotal - currentlyUsed);
if (currentlyUsed + artifactSize > maxArtifactSizeTotal) {
final String msg = String.format(MAX_ARTIFACT_SIZE_TOTAL_EXCEEDED, filename, artifactSize,
maxArtifactSizeTotal);
LOG.warn(msg);
throw new QuotaExceededException(msg);
}
} }
@Override @Override

View File

@@ -23,7 +23,7 @@ import org.eclipse.hawkbit.repository.builder.DistributionSetTypeUpdate;
import org.eclipse.hawkbit.repository.builder.GenericDistributionSetTypeUpdate; import org.eclipse.hawkbit.repository.builder.GenericDistributionSetTypeUpdate;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetTypeCreate; import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetTypeCreate;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants; import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
@@ -163,7 +163,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
* @param requested * @param requested
* number of software module types to check * number of software module types to check
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the software module type quota is exceeded * if the software module type quota is exceeded
*/ */
private void assertSoftwareModuleTypeQuota(final long id, final int requested) { private void assertSoftwareModuleTypeQuota(final long id, final int requested) {

View File

@@ -0,0 +1,81 @@
/**
* Copyright (c) 2019 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.jpa.utils;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.eclipse.hawkbit.repository.exception.FileSizeQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.StorageQuotaExceededException;
/**
* A FilterInputStream that ensures file size and storage quotas are enforced. It check during read operations if the
* quota will be exceeded and throws an QuotaExceededException if this happens.
*/
public class FileSizeAndStorageQuotaCheckingInputStream extends FilterInputStream {
private final long quota;
private final long sizeLimit;
private long size;
/**
* Creates a <code>QuotaInputStream</code> using the input stream in and a
* limiting quota
*
* @param in
* Inner InputStream that read operations will be forwarded to
* @param sizeLimit
* Quota file size limit in byte
* @param storageLeft
* Storage left until quota is reached
*/
public FileSizeAndStorageQuotaCheckingInputStream(final InputStream in, final long sizeLimit, final long storageLeft) {
super(in);
// only limit to lower bound to avoid two checks
this.quota = Math.min(sizeLimit, storageLeft);
this.sizeLimit = sizeLimit;
}
@Override
public int read() throws IOException {
final int read = super.read();
checkQuotaAndUpdateSize(read);
return read;
}
@Override
public int read(final byte[] b) throws IOException {
final int read = super.read(b);
checkQuotaAndUpdateSize(read);
return read;
}
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
final int read = super.read(b, off, len);
checkQuotaAndUpdateSize(read);
return read;
}
private void checkQuotaAndUpdateSize(final int read) {
if ((size + read) > quota) {
// pick exception based on quota type
if (quota == sizeLimit) {
throw new FileSizeQuotaExceededException(quota);
} else {
throw new StorageQuotaExceededException(quota);
}
} else if (read >= 0) {
size += read;
}
}
}

View File

@@ -12,12 +12,12 @@ import java.util.function.ToLongFunction;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Helper class to check assignment quotas. * Helper class to check quotas.
*/ */
public final class QuotaHelper { public final class QuotaHelper {
@@ -26,6 +26,8 @@ public final class QuotaHelper {
*/ */
private static final Logger LOG = LoggerFactory.getLogger(QuotaHelper.class); private static final Logger LOG = LoggerFactory.getLogger(QuotaHelper.class);
private static final String MAX_ASSIGNMENT_QUOTA_EXCEEDED = "Quota exceeded: Cannot assign %s entities at once. The maximum is %s.";
private QuotaHelper() { private QuotaHelper() {
// no need to instantiate this class // no need to instantiate this class
} }
@@ -44,7 +46,7 @@ public final class QuotaHelper {
* @param parentType * @param parentType
* The type of the parent entity. * The type of the parent entity.
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the assignment operation would cause the quota to be * if the assignment operation would cause the quota to be
* exceeded * exceeded
*/ */
@@ -72,7 +74,7 @@ public final class QuotaHelper {
* Function to count the entities that are currently assigned to * Function to count the entities that are currently assigned to
* the parent entity. * the parent entity.
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the assignment operation would cause the quota to be * if the assignment operation would cause the quota to be
* exceeded * exceeded
*/ */
@@ -100,7 +102,7 @@ public final class QuotaHelper {
* Function to count the entities that are currently assigned to * Function to count the entities that are currently assigned to
* the parent entity. * the parent entity.
* *
* @throws QuotaExceededException * @throws AssignmentQuotaExceededException
* if the assignment operation would cause the quota to be * if the assignment operation would cause the quota to be
* exceeded * exceeded
*/ */
@@ -117,7 +119,7 @@ public final class QuotaHelper {
final String parentIdStr = parentId != null ? String.valueOf(parentId) : "<new>"; final String parentIdStr = parentId != null ? String.valueOf(parentId) : "<new>";
LOG.warn("Cannot assign {} {} entities to {} '{}' because of the configured quota limit {}.", requested, LOG.warn("Cannot assign {} {} entities to {} '{}' because of the configured quota limit {}.", requested,
type, parentType, parentIdStr, limit); type, parentType, parentIdStr, limit);
throw new QuotaExceededException(type, parentType, parentId, requested, limit); throw new AssignmentQuotaExceededException(type, parentType, parentId, requested, limit);
} }
if (parentId != null && countFct != null) { if (parentId != null && countFct != null) {
@@ -126,7 +128,7 @@ public final class QuotaHelper {
LOG.warn( LOG.warn(
"Cannot assign {} {} entities to {} '{}' because of the configured quota limit {}. Currently, there are {} {} entities assigned.", "Cannot assign {} {} entities to {} '{}' because of the configured quota limit {}. Currently, there are {} {} entities assigned.",
requested, type, parentType, parentId, limit, currentCount, type); requested, type, parentType, parentId, limit, currentCount, type);
throw new QuotaExceededException(type, parentType, parentId, requested, limit); throw new AssignmentQuotaExceededException(type, parentType, parentId, requested, limit);
} }
} }
} }
@@ -142,10 +144,9 @@ public final class QuotaHelper {
*/ */
public static void assertAssignmentRequestSizeQuota(final long requested, final long limit) { public static void assertAssignmentRequestSizeQuota(final long requested, final long limit) {
if (requested > limit) { if (requested > limit) {
final String message = String.format( final String message = String.format(MAX_ASSIGNMENT_QUOTA_EXCEEDED, requested, limit);
"Quota exceeded: Cannot assign %s entities at once. The maximum is %s.", requested, limit);
LOG.warn(message); LOG.warn(message);
throw new QuotaExceededException(message); throw new AssignmentQuotaExceededException(message);
} }
} }
} }

View File

@@ -30,8 +30,10 @@ import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleDeletedEvent; import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
import org.eclipse.hawkbit.repository.exception.FileSizeQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.StorageQuotaExceededException;
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact; import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.Artifact;
@@ -183,7 +185,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
assertThat(artifactRepository.findBySoftwareModuleId(PAGE, smId).getTotalElements()).isEqualTo(maxArtifacts); assertThat(artifactRepository.findBySoftwareModuleId(PAGE, smId).getTotalElements()).isEqualTo(maxArtifacts);
// create one mode to trigger the quota exceeded error // create one mode to trigger the quota exceeded error
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> createArtifactForSoftwareModule("file" + maxArtifacts, smId, artifactSize)); .isThrownBy(() -> createArtifactForSoftwareModule("file" + maxArtifacts, smId, artifactSize));
// delete one of the artifacts // delete one of the artifacts
@@ -217,7 +219,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
// upload one more artifact to trigger the quota exceeded error // upload one more artifact to trigger the quota exceeded error
final JpaSoftwareModule sm = softwareModuleRepository final JpaSoftwareModule sm = softwareModuleRepository
.save(new JpaSoftwareModule(osType, "smd" + numArtifacts, "1.0", null, null)); .save(new JpaSoftwareModule(osType, "smd" + numArtifacts, "1.0", null, null));
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(StorageQuotaExceededException.class)
.isThrownBy(() -> createArtifactForSoftwareModule("file" + numArtifacts, sm.getId(), artifactSize)); .isThrownBy(() -> createArtifactForSoftwareModule("file" + numArtifacts, sm.getId(), artifactSize));
// delete one of the artifacts // delete one of the artifacts
@@ -227,18 +229,6 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
createArtifactForSoftwareModule("fileXYZ", sm.getId(), artifactSize); createArtifactForSoftwareModule("fileXYZ", sm.getId(), artifactSize);
} }
@Test
@Description("Verifies that the quota specifying the maximum artifact storage is enforced (across software modules).")
public void createArtifactWhichExceedsMaxStorage() throws IOException {
// create one artifact which exceeds the storage quota at once
final long maxBytes = quotaManagement.getMaxArtifactStorage();
final JpaSoftwareModule sm = softwareModuleRepository
.save(new JpaSoftwareModule(osType, "smd345", "1.0", null, null));
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(
() -> createArtifactForSoftwareModule("file345", sm.getId(), Math.toIntExact(maxBytes) + 128));
}
@Test @Test
@Description("Verifies that you cannot create artifacts which exceed the configured maximum size.") @Description("Verifies that you cannot create artifacts which exceed the configured maximum size.")
public void createArtifactFailsIfTooLarge() { public void createArtifactFailsIfTooLarge() {
@@ -249,7 +239,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
// create an artifact that exceeds the configured quota // create an artifact that exceeds the configured quota
final long maxSize = quotaManagement.getMaxArtifactSize(); final long maxSize = quotaManagement.getMaxArtifactSize();
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(FileSizeQuotaExceededException.class)
.isThrownBy(() -> createArtifactForSoftwareModule("file", sm1.getId(), Math.toIntExact(maxSize) + 8)); .isThrownBy(() -> createArtifactForSoftwareModule("file", sm1.getId(), Math.toIntExact(maxSize) + 8));
} }

View File

@@ -53,7 +53,7 @@ import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException; import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.Action.Status;
@@ -989,7 +989,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
final int allowedAttributes = quotaManagement.getMaxAttributeEntriesPerTarget(); final int allowedAttributes = quotaManagement.getMaxAttributeEntriesPerTarget();
testdataFactory.createTarget(controllerId); testdataFactory.createTarget(controllerId);
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> securityRule assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> securityRule
.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { .runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
writeAttributes(controllerId, allowedAttributes + 1, "key", "value"); writeAttributes(controllerId, allowedAttributes + 1, "key", "value");
return null; return null;
@@ -1008,7 +1008,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(targetManagement.getControllerAttributes(controllerId)).hasSize(10); assertThat(targetManagement.getControllerAttributes(controllerId)).hasSize(10);
// Now rite one more // Now rite one more
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> securityRule assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> securityRule
.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { .runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
writeAttributes(controllerId, 1, "additional", "value1"); writeAttributes(controllerId, 1, "additional", "value1");
return null; return null;
@@ -1071,7 +1071,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId = createTargetAndAssignDs(); final Long actionId = createTargetAndAssignDs();
// Fails as one entry is already in there from the assignment // Fails as one entry is already in there from the assignment
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> securityRule assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> securityRule
.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { .runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
writeStatus(actionId, allowStatusEntries); writeStatus(actionId, allowStatusEntries);
return null; return null;
@@ -1127,7 +1127,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
controllerManagement.addInformationalActionStatus(entityFactory.actionStatus().create(actionId1) controllerManagement.addInformationalActionStatus(entityFactory.actionStatus().create(actionId1)
.status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis())); .status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis()));
} }
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> controllerManagement assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> controllerManagement
.addInformationalActionStatus(entityFactory.actionStatus().create(actionId1).status(Status.WARNING))); .addInformationalActionStatus(entityFactory.actionStatus().create(actionId1).status(Status.WARNING)));
// test for update status (and mixed case) // test for update status (and mixed case)
@@ -1138,7 +1138,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId2) controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId2)
.status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis())); .status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis()));
} }
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> controllerManagement assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> controllerManagement
.addInformationalActionStatus(entityFactory.actionStatus().create(actionId2).status(Status.WARNING))); .addInformationalActionStatus(entityFactory.actionStatus().create(actionId2).status(Status.WARNING)));
} }
@@ -1165,7 +1165,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))).isNotNull(); entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))).isNotNull();
messages.add("msg"); messages.add("msg");
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> controllerManagement.addInformationalActionStatus( .isThrownBy(() -> controllerManagement.addInformationalActionStatus(
entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))); entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING)));
@@ -1262,7 +1262,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false); assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false);
} }
@Test(expected = QuotaExceededException.class) @Test(expected = AssignmentQuotaExceededException.class)
@Description("Verifies that quota is asserted when a controller reports too many DOWNLOADED events for a " @Description("Verifies that quota is asserted when a controller reports too many DOWNLOADED events for a "
+ "DOWNLOAD_ONLY action.") + "DOWNLOAD_ONLY action.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@@ -1297,17 +1297,17 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID);
assertThat(actionId).isNotNull(); assertThat(actionId).isNotNull();
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates") .as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates")
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement .isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)))); .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many ERROR updateActionStatus updates") .as("No QuotaExceededException thrown for too many ERROR updateActionStatus updates")
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement .isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR)))); .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR))));
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many FINISHED updateActionStatus updates") .as("No QuotaExceededException thrown for too many FINISHED updateActionStatus updates")
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement .isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED)))); .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED))));
@@ -1325,17 +1325,17 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId = createTargetAndAssignDs(); final Long actionId = createTargetAndAssignDs();
assertThat(actionId).isNotNull(); assertThat(actionId).isNotNull();
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates") .as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates")
.isThrownBy( ()-> IntStream.range(0, maxMessages).forEach(i -> controllerManagement .isThrownBy( ()-> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)))); .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many ERROR updateActionStatus updates") .as("No QuotaExceededException thrown for too many ERROR updateActionStatus updates")
.isThrownBy(()->IntStream.range(0, maxMessages).forEach(i -> controllerManagement .isThrownBy(()->IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR)))); .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR))));
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many FINISHED updateActionStatus updates") .as("No QuotaExceededException thrown for too many FINISHED updateActionStatus updates")
.isThrownBy(()->IntStream.range(0, maxMessages).forEach(i -> controllerManagement .isThrownBy(()->IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED)))); .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED))));

View File

@@ -39,7 +39,7 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException; import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException; import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants; import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
@@ -170,7 +170,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
.singletonList(new SimpleEntry<String, Long>(testTarget.getControllerId(), ds1.getId()))); .singletonList(new SimpleEntry<String, Long>(testTarget.getControllerId(), ds1.getId())));
} }
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> assignDistributionSet(ds1, Collections.singletonList(testTarget))); .isThrownBy(() -> assignDistributionSet(ds1, Collections.singletonList(testTarget)));
} }
@@ -185,7 +185,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assignDistributionSet(ds1, targets); assignDistributionSet(ds1, targets);
targets.add(testdataFactory.createTarget("assignmentTest2")); targets.add(testdataFactory.createTarget("assignmentTest2"));
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> assignDistributionSet(ds2, targets)); assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> assignDistributionSet(ds2, targets));
} }
@Test @Test
@@ -671,7 +671,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
DeploymentManagement.deploymentRequest(controllerId, dsId).build()); DeploymentManagement.deploymentRequest(controllerId, dsId).build());
enableMultiAssignments(); enableMultiAssignments();
Assertions.assertThatExceptionOfType(QuotaExceededException.class) Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests)); .isThrownBy(() -> deploymentManagement.assignDistributionSets(deploymentRequests));
assertThat(actionRepository.countByTargetControllerId(controllerId)).isEqualTo(0); assertThat(actionRepository.countByTargetControllerId(controllerId)).isEqualTo(0);
} }

View File

@@ -34,7 +34,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedE
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
@@ -351,7 +351,7 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
} }
// quota exceeded // quota exceeded
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> createDistributionSetMetadata(ds1.getId(), createDistributionSetMetadata(ds1.getId(), .isThrownBy(() -> createDistributionSetMetadata(ds1.getId(), createDistributionSetMetadata(ds1.getId(),
new JpaDistributionSetMetadata("k" + maxMetaData, ds1, "v" + maxMetaData)))); new JpaDistributionSetMetadata("k" + maxMetaData, ds1, "v" + maxMetaData))));
@@ -362,7 +362,7 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
metaData2.add(new JpaDistributionSetMetadata("k" + i, ds2, "v" + i)); metaData2.add(new JpaDistributionSetMetadata("k" + i, ds2, "v" + i));
} }
// verify quota is exceeded // verify quota is exceeded
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> createDistributionSetMetadata(ds2.getId(), metaData2)); .isThrownBy(() -> createDistributionSetMetadata(ds2.getId(), metaData2));
// add some meta data entries // add some meta data entries
@@ -378,7 +378,7 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
metaData3.add(new JpaDistributionSetMetadata("kk" + i, ds3, "vv" + i)); metaData3.add(new JpaDistributionSetMetadata("kk" + i, ds3, "vv" + i));
} }
// verify quota is exceeded // verify quota is exceeded
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> createDistributionSetMetadata(ds3.getId(), metaData3)); .isThrownBy(() -> createDistributionSetMetadata(ds3.getId(), metaData3));
} }
@@ -510,7 +510,7 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
distributionSetManagement.assignSoftwareModules(ds1.getId(), Collections.singletonList(modules.get(i))); distributionSetManagement.assignSoftwareModules(ds1.getId(), Collections.singletonList(modules.get(i)));
} }
// add one more to cause the quota to be exceeded // add one more to cause the quota to be exceeded
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> { assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> {
distributionSetManagement.assignSoftwareModules(ds1.getId(), distributionSetManagement.assignSoftwareModules(ds1.getId(),
Collections.singletonList(modules.get(maxModules))); Collections.singletonList(modules.get(maxModules)));
}); });
@@ -518,7 +518,7 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
// assign all software modules at once // assign all software modules at once
final DistributionSet ds2 = testdataFactory.createDistributionSetWithNoSoftwareModules("ds2", "1.0"); final DistributionSet ds2 = testdataFactory.createDistributionSetWithNoSoftwareModules("ds2", "1.0");
// verify quota is exceeded // verify quota is exceeded
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> distributionSetManagement.assignSoftwareModules(ds2.getId(), modules)); .isThrownBy(() -> distributionSetManagement.assignSoftwareModules(ds2.getId(), modules));
// assign some software modules // assign some software modules
@@ -528,7 +528,7 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
distributionSetManagement.assignSoftwareModules(ds3.getId(), Collections.singletonList(modules.get(i))); distributionSetManagement.assignSoftwareModules(ds3.getId(), Collections.singletonList(modules.get(i)));
} }
// assign the remaining modules to cause the quota to be exceeded // assign the remaining modules to cause the quota to be exceeded
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> distributionSetManagement assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> distributionSetManagement
.assignSoftwareModules(ds3.getId(), modules.subList(firstHalf, modules.size()))); .assignSoftwareModules(ds3.getId(), modules.subList(firstHalf, modules.size())));
} }

View File

@@ -28,7 +28,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeCre
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.DistributionSetType;
@@ -242,9 +242,9 @@ public class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTes
// assign all types at once // assign all types at once
final DistributionSetType dsType1 = distributionSetTypeManagement final DistributionSetType dsType1 = distributionSetTypeManagement
.create(entityFactory.distributionSetType().create().key("dst1").name("dst1")); .create(entityFactory.distributionSetType().create().key("dst1").name("dst1"));
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy( assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(
() -> distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(dsType1.getId(), moduleTypeIds)); () -> distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(dsType1.getId(), moduleTypeIds));
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy( assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(
() -> distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(dsType1.getId(), moduleTypeIds)); () -> distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(dsType1.getId(), moduleTypeIds));
// assign as many mandatory modules as possible // assign as many mandatory modules as possible
@@ -256,7 +256,7 @@ public class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTes
assertThat(distributionSetTypeManagement.get(dsType2.getId()).get().getMandatoryModuleTypes().size()) assertThat(distributionSetTypeManagement.get(dsType2.getId()).get().getMandatoryModuleTypes().size())
.isEqualTo(quota); .isEqualTo(quota);
// assign one more to trigger the quota exceeded error // assign one more to trigger the quota exceeded error
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(dsType2.getId(), .isThrownBy(() -> distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(dsType2.getId(),
Collections.singletonList(moduleTypeIds.get(quota)))); Collections.singletonList(moduleTypeIds.get(quota))));
@@ -269,7 +269,7 @@ public class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTes
assertThat(distributionSetTypeManagement.get(dsType3.getId()).get().getOptionalModuleTypes().size()) assertThat(distributionSetTypeManagement.get(dsType3.getId()).get().getOptionalModuleTypes().size())
.isEqualTo(quota); .isEqualTo(quota);
// assign one more to trigger the quota exceeded error // assign one more to trigger the quota exceeded error
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(dsType3.getId(), .isThrownBy(() -> distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(dsType3.getId(),
Collections.singletonList(moduleTypeIds.get(quota)))); Collections.singletonList(moduleTypeIds.get(quota))));

View File

@@ -42,7 +42,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException; import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
@@ -1348,7 +1348,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition)
.errorAction(RolloutGroupErrorAction.PAUSE, null).build(); .errorAction(RolloutGroupErrorAction.PAUSE, null).build();
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> rolloutManagement.create( assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> rolloutManagement.create(
entityFactory.rollout().create().name(rolloutName).description(rolloutName) entityFactory.rollout().create().name(rolloutName).description(rolloutName)
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet), .targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet),
amountGroups, conditions)); amountGroups, conditions));
@@ -1376,7 +1376,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
.targetPercentage(100.0F); .targetPercentage(100.0F);
// group1 exceeds the quota // group1 exceeds the quota
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> rolloutManagement.create( assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> rolloutManagement.create(
entityFactory.rollout().create().name(rolloutName).description(rolloutName) entityFactory.rollout().create().name(rolloutName).description(rolloutName)
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet), .targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet),
Arrays.asList(group1, group2), conditions)); Arrays.asList(group1, group2), conditions));
@@ -1388,7 +1388,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
.targetPercentage(100.0F); .targetPercentage(100.0F);
// group4 exceeds the quota // group4 exceeds the quota
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> rolloutManagement.create( assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> rolloutManagement.create(
entityFactory.rollout().create().name(rolloutName).description(rolloutName) entityFactory.rollout().create().name(rolloutName).description(rolloutName)
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet), .targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet),
Arrays.asList(group3, group4), conditions)); Arrays.asList(group3, group4), conditions));
@@ -1571,7 +1571,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
final RolloutCreate rollout = generateTargetsAndRollout(rolloutName, targets); final RolloutCreate rollout = generateTargetsAndRollout(rolloutName, targets);
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> rolloutManagement.create(rollout, maxGroups + 1, conditions)) .isThrownBy(() -> rolloutManagement.create(rollout, maxGroups + 1, conditions))
.withMessageContaining("not be greater than " + maxGroups); .withMessageContaining("not be greater than " + maxGroups);

View File

@@ -24,7 +24,7 @@ import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate; import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
@@ -676,7 +676,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
} }
// quota exceeded // quota exceeded
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata() .isThrownBy(() -> softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata()
.create(module.getId()).key("k" + maxMetaData).value("v" + maxMetaData))); .create(module.getId()).key("k" + maxMetaData).value("v" + maxMetaData)));
@@ -687,7 +687,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
create.add(entityFactory.softwareModuleMetadata().create(module2.getId()).key("k" + i).value("v" + i)); create.add(entityFactory.softwareModuleMetadata().create(module2.getId()).key("k" + i).value("v" + i));
} }
// quota exceeded // quota exceeded
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> softwareModuleManagement.createMetaData(create)); .isThrownBy(() -> softwareModuleManagement.createMetaData(create));
// add some meta data entries // add some meta data entries
@@ -704,7 +704,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
create2.add(entityFactory.softwareModuleMetadata().create(module3.getId()).key("kk" + i).value("vv" + i)); create2.add(entityFactory.softwareModuleMetadata().create(module3.getId()).key("kk" + i).value("vv" + i));
} }
// quota exceeded // quota exceeded
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> softwareModuleManagement.createMetaData(create2)); .isThrownBy(() -> softwareModuleManagement.createMetaData(create2));
} }

View File

@@ -28,7 +28,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetFilterQueryCreat
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException; import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException; import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -112,7 +112,7 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
final DistributionSet set = testdataFactory.createDistributionSet(); final DistributionSet set = testdataFactory.createDistributionSet();
// creation is supposed to work as there is no distribution set // creation is supposed to work as there is no distribution set
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create() .isThrownBy(() -> targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create()
.name("testfilter").autoAssignDistributionSet(set.getId()).query("name==target*"))); .name("testfilter").autoAssignDistributionSet(set.getId()).query("name==target*")));
} }
@@ -282,7 +282,7 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
// assigning a distribution set is supposed to fail as the query // assigning a distribution set is supposed to fail as the query
// addresses too many targets // addresses too many targets
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> targetFilterQueryManagement assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> targetFilterQueryManagement
.updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId())); .updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId()));
} }
@@ -300,7 +300,7 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
.create().name("testfilter").autoAssignDistributionSet(set.getId()).query("name==foo")); .create().name("testfilter").autoAssignDistributionSet(set.getId()).query("name==foo"));
// update with a query string that addresses too many targets // update with a query string that addresses too many targets
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> targetFilterQueryManagement assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> targetFilterQueryManagement
.update(entityFactory.targetFilterQuery().update(targetFilterQuery.getId()).query("name==target*"))); .update(entityFactory.targetFilterQuery().update(targetFilterQuery.getId()).query("name==target*")));
} }

View File

@@ -41,7 +41,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException; import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.TenantNotExistException; import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata;
@@ -958,7 +958,7 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
} }
// quota exceeded // quota exceeded
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> insertTargetMetadata("k" + maxMetaData, "v" + maxMetaData, target1)); .isThrownBy(() -> insertTargetMetadata("k" + maxMetaData, "v" + maxMetaData, target1));
// add multiple meta data entries at once // add multiple meta data entries at once
@@ -968,7 +968,7 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
metaData2.add(new JpaTargetMetadata("k" + i, "v" + i, target2)); metaData2.add(new JpaTargetMetadata("k" + i, "v" + i, target2));
} }
// verify quota is exceeded // verify quota is exceeded
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> targetManagement.createMetaData(target2.getControllerId(), metaData2)); .isThrownBy(() -> targetManagement.createMetaData(target2.getControllerId(), metaData2));
// add some meta data entries // add some meta data entries
@@ -984,7 +984,7 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
metaData3.add(new JpaTargetMetadata("kk" + i, "vv" + i, target3)); metaData3.add(new JpaTargetMetadata("kk" + i, "vv" + i, target3));
} }
// verify quota is exceeded // verify quota is exceeded
assertThatExceptionOfType(QuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> targetManagement.createMetaData(target3.getControllerId(), metaData3)); .isThrownBy(() -> targetManagement.createMetaData(target3.getControllerId(), metaData3));
} }

View File

@@ -25,7 +25,7 @@ import java.util.Map;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants; import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException; import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.rest.util.JsonBuilder; import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
@@ -155,7 +155,7 @@ public class DdiConfigDataTest extends AbstractDDiApiIntegrationTest {
mvc.perform(put("/{tenant}/controller/v1/4717/configData", tenantAware.getCurrentTenant()) mvc.perform(put("/{tenant}/controller/v1/4717/configData", tenantAware.getCurrentTenant())
.content(JsonBuilder.configData("", attributes, "closed").toString()) .content(JsonBuilder.configData("", attributes, "closed").toString())
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isForbidden()) .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
} }

View File

@@ -34,7 +34,7 @@ import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -210,7 +210,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(JsonBuilder.ids(Collections.singletonList(moduleIDs.get(moduleIDs.size() - 1))))) .content(JsonBuilder.ids(Collections.singletonList(moduleIDs.get(moduleIDs.size() - 1)))))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
// verify quota is also enforced for bulk uploads // verify quota is also enforced for bulk uploads
@@ -218,7 +218,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet2.getId() + "/assignedSM") mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + disSet2.getId() + "/assignedSM")
.contentType(MediaType.APPLICATION_JSON).content(JsonBuilder.ids(moduleIDs))) .contentType(MediaType.APPLICATION_JSON).content(JsonBuilder.ids(moduleIDs)))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
// verify size is still 0 // verify size is still 0

View File

@@ -31,7 +31,7 @@ import org.assertj.core.util.Lists;
import org.eclipse.hawkbit.exception.SpServerError; import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate; import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.NamedEntity; import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
@@ -274,7 +274,7 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractManagementApiIn
.content("{\"id\":" + moduleTypeIds.get(moduleTypeIds.size() - 1) + "}") .content("{\"id\":" + moduleTypeIds.get(moduleTypeIds.size() - 1) + "}")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden()) .andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
// verify quota enforcement for mandatory module types // verify quota enforcement for mandatory module types
@@ -293,7 +293,7 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractManagementApiIn
.content("{\"id\":" + moduleTypeIds.get(moduleTypeIds.size() - 1) + "}") .content("{\"id\":" + moduleTypeIds.get(moduleTypeIds.size() - 1) + "}")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden()) .andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
} }

View File

@@ -31,7 +31,7 @@ import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.RolloutGroupManagement; import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout;
@@ -147,7 +147,7 @@ public class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTes
new RolloutGroupConditionBuilder().withDefaults().build())) new RolloutGroupConditionBuilder().withDefaults().build()))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
} }
@@ -165,7 +165,7 @@ public class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTes
new RolloutGroupConditionBuilder().withDefaults().build())) new RolloutGroupConditionBuilder().withDefaults().build()))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden()) .andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
} }

View File

@@ -37,7 +37,9 @@ import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact; import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.Constants; import org.eclipse.hawkbit.repository.Constants;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.FileSizeQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.StorageQuotaExceededException;
import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.ArtifactUpload; import org.eclipse.hawkbit.repository.model.ArtifactUpload;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -205,7 +207,9 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
// try to upload // try to upload
mvc.perform(fileUpload("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file) mvc.perform(fileUpload("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden()); .andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(FileSizeQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_FILE_SIZE_QUOTA_EXCEEDED.getKey())));
} }
@Test @Test
@@ -385,7 +389,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
mvc.perform(fileUpload("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file) mvc.perform(fileUpload("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden()) .andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
} }
@@ -430,8 +434,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
mvc.perform(fileUpload("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file) mvc.perform(fileUpload("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) .accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden()) .andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath("$.exceptionClass", equalTo(StorageQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_STORAGE_QUOTA_EXCEEDED.getKey())));
} }

View File

@@ -25,13 +25,12 @@ import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException; import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException; import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignDistributionSetException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.rest.exception.MessageNotReadableException; import org.eclipse.hawkbit.rest.exception.MessageNotReadableException;
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo; import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONObject; import org.json.JSONObject;
import org.junit.Test; import org.junit.Test;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@@ -313,7 +312,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId() + "/autoAssignDS") post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId() + "/autoAssignDS")
.content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON)) .content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(print()).andExpect(status().isForbidden()) .andDo(print()).andExpect(status().isForbidden())
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
} }
@@ -345,7 +344,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId()) mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId())
.content("{\"query\":\"controllerId==target*\"}").contentType(MediaType.APPLICATION_JSON)) .content("{\"query\":\"controllerId==target*\"}").contentType(MediaType.APPLICATION_JSON))
.andDo(print()).andExpect(status().isForbidden()) .andDo(print()).andExpect(status().isForbidden())
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(QuotaExceededException.class.getName()))) .andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey()))); .andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
} }

View File

@@ -61,6 +61,8 @@ public class ResponseExceptionHandler {
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ARTIFACT_DELETE_FAILED, HttpStatus.INTERNAL_SERVER_ERROR); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ARTIFACT_DELETE_FAILED, HttpStatus.INTERNAL_SERVER_ERROR);
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ARTIFACT_LOAD_FAILED, HttpStatus.INTERNAL_SERVER_ERROR); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ARTIFACT_LOAD_FAILED, HttpStatus.INTERNAL_SERVER_ERROR);
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_QUOTA_EXCEEDED, HttpStatus.FORBIDDEN); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_QUOTA_EXCEEDED, HttpStatus.FORBIDDEN);
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_FILE_SIZE_QUOTA_EXCEEDED, HttpStatus.FORBIDDEN);
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_STORAGE_QUOTA_EXCEEDED, HttpStatus.FORBIDDEN);
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ACTION_NOT_CANCELABLE, HttpStatus.METHOD_NOT_ALLOWED); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ACTION_NOT_CANCELABLE, HttpStatus.METHOD_NOT_ALLOWED);
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ACTION_NOT_FORCE_QUITABLE, HttpStatus.METHOD_NOT_ALLOWED); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ACTION_NOT_FORCE_QUITABLE, HttpStatus.METHOD_NOT_ALLOWED);
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_DS_CREATION_FAILED_MISSING_MODULE, HttpStatus.BAD_REQUEST); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_DS_CREATION_FAILED_MISSING_MODULE, HttpStatus.BAD_REQUEST);

View File

@@ -14,14 +14,18 @@ import java.io.OutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.Lock;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.RegexCharacterCollection; import org.eclipse.hawkbit.repository.RegexCharacterCollection;
import org.eclipse.hawkbit.repository.RegexCharacterCollection.RegexChar; import org.eclipse.hawkbit.repository.RegexCharacterCollection.RegexChar;
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException; import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
import org.eclipse.hawkbit.repository.exception.FileSizeQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException; import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException; import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.StorageQuotaExceededException;
import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.ArtifactUpload; import org.eclipse.hawkbit.repository.model.ArtifactUpload;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
@@ -36,7 +40,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.vaadin.spring.events.EventBus; import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventBus.UIEventBus; import org.vaadin.spring.events.EventBus.UIEventBus;
import com.vaadin.ui.UI; import com.vaadin.ui.UI;
/** /**
@@ -48,6 +51,7 @@ public abstract class AbstractFileTransferHandler implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(AbstractFileTransferHandler.class); private static final Logger LOG = LoggerFactory.getLogger(AbstractFileTransferHandler.class);
private static final String MESSAGE_UPLOAD_FAILED = "message.upload.failed";
private volatile boolean uploadInterrupted; private volatile boolean uploadInterrupted;
@@ -63,15 +67,18 @@ public abstract class AbstractFileTransferHandler implements Serializable {
protected final UINotification uiNotification; protected final UINotification uiNotification;
private final transient Lock uploadLock;
protected static final RegexCharacterCollection ILLEGAL_FILENAME_CHARACTERS = new RegexCharacterCollection( protected static final RegexCharacterCollection ILLEGAL_FILENAME_CHARACTERS = new RegexCharacterCollection(
RegexChar.GREATER_THAN, RegexChar.LESS_THAN, RegexChar.SLASHES); RegexChar.GREATER_THAN, RegexChar.LESS_THAN, RegexChar.SLASHES);
AbstractFileTransferHandler(final ArtifactManagement artifactManagement, final VaadinMessageSource i18n) { AbstractFileTransferHandler(final ArtifactManagement artifactManagement, final VaadinMessageSource i18n, final Lock uploadLock) {
this.artifactManagement = artifactManagement; this.artifactManagement = artifactManagement;
this.i18n = i18n; this.i18n = i18n;
this.eventBus = SpringContextHelper.getBean(EventBus.UIEventBus.class); this.eventBus = SpringContextHelper.getBean(EventBus.UIEventBus.class);
this.artifactUploadState = SpringContextHelper.getBean(ArtifactUploadState.class); this.artifactUploadState = SpringContextHelper.getBean(ArtifactUploadState.class);
this.uiNotification = SpringContextHelper.getBean(UINotification.class); this.uiNotification = SpringContextHelper.getBean(UINotification.class);
this.uploadLock = uploadLock;
} }
protected boolean isUploadInterrupted() { protected boolean isUploadInterrupted() {
@@ -94,7 +101,7 @@ public abstract class AbstractFileTransferHandler implements Serializable {
protected void startTransferToRepositoryThread(final InputStream inputStream, final FileUploadId fileUploadId, protected void startTransferToRepositoryThread(final InputStream inputStream, final FileUploadId fileUploadId,
final String mimeType) { final String mimeType) {
SpringContextHelper.getBean("asyncExecutor", ExecutorService.class).execute( SpringContextHelper.getBean("asyncExecutor", ExecutorService.class).execute(
new TransferArtifactToRepositoryRunnable(inputStream, fileUploadId, mimeType, UI.getCurrent())); new TransferArtifactToRepositoryRunnable(inputStream, fileUploadId, mimeType, UI.getCurrent(), uploadLock));
} }
private void interruptUploadAndSetReason(final String failureReason) { private void interruptUploadAndSetReason(final String failureReason) {
@@ -103,7 +110,19 @@ public abstract class AbstractFileTransferHandler implements Serializable {
} }
protected void interruptUploadDueToUploadFailed() { protected void interruptUploadDueToUploadFailed() {
interruptUploadAndSetReason(i18n.getMessage("message.upload.failed")); interruptUploadAndSetReason(i18n.getMessage(MESSAGE_UPLOAD_FAILED));
}
protected void interruptUploadDueToAssignmentQuotaExceeded() {
interruptUploadAndSetReason(i18n.getMessage("message.upload.assignmentQuota"));
}
protected void interruptUploadDueToFileSizeQuotaExceeded(final String exceededValue) {
interruptUploadAndSetReason(i18n.getMessage("message.upload.fileSizeQuota", exceededValue));
}
protected void interruptUploadDueToStorageQuotaExceeded(final String exceededValue) {
interruptUploadAndSetReason(i18n.getMessage("message.upload.storageQuota", exceededValue));
} }
protected void interruptUploadDueToDuplicateFile() { protected void interruptUploadDueToDuplicateFile() {
@@ -177,7 +196,7 @@ public abstract class AbstractFileTransferHandler implements Serializable {
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId, final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
FileUploadStatus.UPLOAD_FAILED, FileUploadStatus.UPLOAD_FAILED,
StringUtils.isBlank(failureReason) ? i18n.getMessage("message.upload.failed") : failureReason); StringUtils.isBlank(failureReason) ? i18n.getMessage(MESSAGE_UPLOAD_FAILED) : failureReason);
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress); artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
eventBus.publish(this, fileUploadProgress); eventBus.publish(this, fileUploadProgress);
publishUploadFinishedEvent(fileUploadId); publishUploadFinishedEvent(fileUploadId);
@@ -216,26 +235,45 @@ public abstract class AbstractFileTransferHandler implements Serializable {
private final FileUploadId fileUploadId; private final FileUploadId fileUploadId;
private final String mimeType; private final String mimeType;
private final UI vaadinUi; private final UI vaadinUi;
private final Lock uploadLock;
public TransferArtifactToRepositoryRunnable(final InputStream inputStream, final FileUploadId fileUploadId, public TransferArtifactToRepositoryRunnable(final InputStream inputStream, final FileUploadId fileUploadId,
final String mimeType, final UI vaadinUi) { final String mimeType, final UI vaadinUi, final Lock uploadLock) {
this.inputStream = inputStream; this.inputStream = inputStream;
this.fileUploadId = fileUploadId; this.fileUploadId = fileUploadId;
this.mimeType = mimeType; this.mimeType = mimeType;
this.vaadinUi = vaadinUi; this.vaadinUi = vaadinUi;
this.uploadLock = uploadLock;
} }
/**
* a lock object is used here that is propagated down from
* {@link org.eclipse.hawkbit.ui.artifacts.UploadArtifactView}. It ensures that from within the same UI instance
* all uploads are executed sequentially to avoid issues that occur when multiple files are processed at the
* same time (e.g. regarding quota checks)
*/
@Override @Override
public void run() { public void run() {
try { try {
UI.setCurrent(vaadinUi); UI.setCurrent(vaadinUi);
uploadLock.lock();
streamToRepository(); streamToRepository();
} catch (final FileSizeQuotaExceededException e) {
interruptUploadDueToFileSizeQuotaExceeded(e.getExceededQuotaValueString());
LOG.debug("Upload failed due to file size quota exceeded:", e);
} catch (final StorageQuotaExceededException e) {
interruptUploadDueToStorageQuotaExceeded(e.getExceededQuotaValueString());
LOG.debug("Upload failed due to storage quota exceeded:", e);
} catch (final AssignmentQuotaExceededException e) {
interruptUploadDueToAssignmentQuotaExceeded();
LOG.debug("Upload failed due to assignment quota exceeded:", e);
} catch (final RuntimeException e) { } catch (final RuntimeException e) {
interruptUploadDueToUploadFailed(); interruptUploadDueToUploadFailed();
publishUploadFailedAndFinishedEvent(fileUploadId, e); publishUploadFailedAndFinishedEvent(fileUploadId, e);
LOG.error("Failed to transfer file to repository", e); LOG.error("Failed to transfer file to repository", e);
} finally { } finally {
tryToCloseIOStream(inputStream); tryToCloseIOStream(inputStream);
uploadLock.unlock();
} }
} }

View File

@@ -12,6 +12,7 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PipedInputStream; import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.util.concurrent.locks.Lock;
import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.RegexCharacterCollection; import org.eclipse.hawkbit.repository.RegexCharacterCollection;
@@ -48,8 +49,8 @@ public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandl
FileTransferHandlerStreamVariable(final String fileName, final long fileSize, final long maxSize, FileTransferHandlerStreamVariable(final String fileName, final long fileSize, final long maxSize,
final String mimeType, final SoftwareModule selectedSw, final ArtifactManagement artifactManagement, final String mimeType, final SoftwareModule selectedSw, final ArtifactManagement artifactManagement,
final VaadinMessageSource i18n) { final VaadinMessageSource i18n, final Lock uploadLock) {
super(artifactManagement, i18n); super(artifactManagement, i18n, uploadLock);
this.fileSize = fileSize; this.fileSize = fileSize;
this.maxSize = maxSize; this.maxSize = maxSize;
this.mimeType = mimeType; this.mimeType = mimeType;

View File

@@ -12,6 +12,7 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PipedInputStream; import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.util.concurrent.locks.Lock;
import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.RegexCharacterCollection; import org.eclipse.hawkbit.repository.RegexCharacterCollection;
@@ -55,8 +56,8 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
private volatile FileUploadId fileUploadId; private volatile FileUploadId fileUploadId;
FileTransferHandlerVaadinUpload(final long maxSize, final SoftwareModuleManagement softwareManagement, FileTransferHandlerVaadinUpload(final long maxSize, final SoftwareModuleManagement softwareManagement,
final ArtifactManagement artifactManagement, final VaadinMessageSource i18n) { final ArtifactManagement artifactManagement, final VaadinMessageSource i18n, final Lock uploadLock) {
super(artifactManagement, i18n); super(artifactManagement, i18n, uploadLock);
this.maxSize = maxSize; this.maxSize = maxSize;
this.softwareModuleManagement = softwareManagement; this.softwareModuleManagement = softwareManagement;
} }

View File

@@ -42,6 +42,9 @@ import com.vaadin.ui.Label;
import com.vaadin.ui.UI; import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalLayout;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/** /**
* Container for drag and drop area in the upload view. * Container for drag and drop area in the upload view.
*/ */
@@ -68,6 +71,8 @@ public class UploadDropAreaLayout extends AbstractComponent {
private final UploadProgressButtonLayout uploadButtonLayout; private final UploadProgressButtonLayout uploadButtonLayout;
private final transient Lock uploadLock = new ReentrantLock();
/** /**
* Creates a new {@link UploadDropAreaLayout} instance. * Creates a new {@link UploadDropAreaLayout} instance.
* *
@@ -99,7 +104,7 @@ public class UploadDropAreaLayout extends AbstractComponent {
this.softwareManagement = softwareManagement; this.softwareManagement = softwareManagement;
this.artifactManagement = artifactManagement; this.artifactManagement = artifactManagement;
this.uploadButtonLayout = new UploadProgressButtonLayout(i18n, eventBus, artifactUploadState, this.uploadButtonLayout = new UploadProgressButtonLayout(i18n, eventBus, artifactUploadState,
multipartConfigElement, artifactManagement, softwareManagement); multipartConfigElement, artifactManagement, softwareManagement, uploadLock);
buildLayout(); buildLayout();
@@ -186,7 +191,7 @@ public class UploadDropAreaLayout extends AbstractComponent {
} else { } else {
file.setStreamVariable(new FileTransferHandlerStreamVariable(file.getFileName(), file.getFileSize(), file.setStreamVariable(new FileTransferHandlerStreamVariable(file.getFileName(), file.getFileSize(),
multipartConfigElement.getMaxFileSize(), file.getType(), softwareModule, artifactManagement, multipartConfigElement.getMaxFileSize(), file.getType(), softwareModule, artifactManagement,
i18n)); i18n, uploadLock));
} }
} }
if (duplicateFound) { if (duplicateFound) {

View File

@@ -29,6 +29,8 @@ import com.vaadin.ui.Button;
import com.vaadin.ui.UI; import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalLayout;
import java.util.concurrent.locks.Lock;
/** /**
* Container for upload and progress button. * Container for upload and progress button.
*/ */
@@ -54,6 +56,8 @@ public class UploadProgressButtonLayout extends VerticalLayout {
private final ArtifactUploadState artifactUploadState; private final ArtifactUploadState artifactUploadState;
private final transient Lock uploadLock;
/** /**
* Creates a new {@link UploadProgressButtonLayout} instance. * Creates a new {@link UploadProgressButtonLayout} instance.
* *
@@ -71,10 +75,12 @@ public class UploadProgressButtonLayout extends VerticalLayout {
* @param artifactManagement * @param artifactManagement
* the {@link ArtifactManagement} for storing the uploaded * the {@link ArtifactManagement} for storing the uploaded
* artifacts * artifacts
* @param uploadLock
* A common upload lock that enforced sequential upload within an UI instance
*/ */
public UploadProgressButtonLayout(final VaadinMessageSource i18n, final UIEventBus eventBus, public UploadProgressButtonLayout(final VaadinMessageSource i18n, final UIEventBus eventBus,
final ArtifactUploadState artifactUploadState, final MultipartConfigElement multipartConfigElement, final ArtifactUploadState artifactUploadState, final MultipartConfigElement multipartConfigElement,
final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareManagement) { final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareManagement, final Lock uploadLock) {
this.artifactUploadState = artifactUploadState; this.artifactUploadState = artifactUploadState;
this.artifactManagement = artifactManagement; this.artifactManagement = artifactManagement;
this.uploadInfoWindow = new UploadProgressInfoWindow(eventBus, artifactUploadState, i18n); this.uploadInfoWindow = new UploadProgressInfoWindow(eventBus, artifactUploadState, i18n);
@@ -89,6 +95,7 @@ public class UploadProgressButtonLayout extends VerticalLayout {
this.multipartConfigElement = multipartConfigElement; this.multipartConfigElement = multipartConfigElement;
this.softwareModuleManagement = softwareManagement; this.softwareModuleManagement = softwareManagement;
this.upload = new UploadFixed(); this.upload = new UploadFixed();
this.uploadLock = uploadLock;
createComponents(); createComponents();
buildLayout(); buildLayout();
@@ -144,7 +151,7 @@ public class UploadProgressButtonLayout extends VerticalLayout {
private void buildLayout() { private void buildLayout() {
final FileTransferHandlerVaadinUpload uploadHandler = new FileTransferHandlerVaadinUpload( final FileTransferHandlerVaadinUpload uploadHandler = new FileTransferHandlerVaadinUpload(
multipartConfigElement.getMaxFileSize(), softwareModuleManagement, artifactManagement, i18n); multipartConfigElement.getMaxFileSize(), softwareModuleManagement, artifactManagement, i18n, uploadLock);
upload.setButtonCaption(i18n.getMessage("upload.file")); upload.setButtonCaption(i18n.getMessage("upload.file"));
upload.setImmediate(true); upload.setImmediate(true);
upload.setReceiver(uploadHandler); upload.setReceiver(uploadHandler);

View File

@@ -25,6 +25,7 @@ import com.vaadin.server.ClientConnector.ConnectorErrorEvent;
import com.vaadin.server.DefaultErrorHandler; import com.vaadin.server.DefaultErrorHandler;
import com.vaadin.server.ErrorEvent; import com.vaadin.server.ErrorEvent;
import com.vaadin.server.Page; import com.vaadin.server.Page;
import com.vaadin.server.UploadException;
import com.vaadin.shared.Connector; import com.vaadin.shared.Connector;
import com.vaadin.ui.Component; import com.vaadin.ui.Component;
import com.vaadin.ui.Notification.Type; import com.vaadin.ui.Notification.Type;
@@ -45,6 +46,11 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler {
@Override @Override
public void error(final ErrorEvent event) { public void error(final ErrorEvent event) {
// filter upload exceptions
if (event.getThrowable() instanceof UploadException) {
return;
}
final HawkbitErrorNotificationMessage message = buildNotification(getRootExceptionFrom(event)); final HawkbitErrorNotificationMessage message = buildNotification(getRootExceptionFrom(event));
if (event instanceof ConnectorErrorEvent) { if (event instanceof ConnectorErrorEvent) {
final Connector connector = ((ConnectorErrorEvent) event).getConnector(); final Connector connector = ((ConnectorErrorEvent) event).getConnector();

View File

@@ -465,7 +465,10 @@ message.no.duplicateFiles = Duplicate files selected
message.delete.artifact = Are you sure you want to delete artifact {0} ? message.delete.artifact = Are you sure you want to delete artifact {0} ?
message.swModule.deleted = {0} Software Module(s) deleted message.swModule.deleted = {0} Software Module(s) deleted
message.error.swModule.notDeleted = Upload is running for Software Module(s) message.error.swModule.notDeleted = Upload is running for Software Module(s)
message.upload.failed = Streaming Failed message.upload.failed = Upload failed
message.upload.assignmentQuota = Max assignments per software module exceeded
message.upload.fileSizeQuota = Maximum artifact size ({0}) exceeded
message.upload.storageQuota = Storage quota exceeded, {0} left
message.uploadedfile.size.exceeded = File size exceeded. Allowed size {0} bytes message.uploadedfile.size.exceeded = File size exceeded. Allowed size {0} bytes
message.uploadedfile.illegalFilename = Filename contains illegal characters message.uploadedfile.illegalFilename = Filename contains illegal characters
message.artifact.deleted = Artifact with file {0} deleted successfully message.artifact.deleted = Artifact with file {0} deleted successfully