Prioritisation of assignments via mgmt-API (#895)

* Updating the schema for targetfilterquery and rollout
* Updating the weight validation logic and tests
* Make weight optional
* Fix existing multi assignment tests by adding weight, remove weight from TargetFilterQuery
* Add weight validation tests, fix tests
* Add mgmt api tests for assignment and getting action with weight
* Add management layer validation and tests for creating rollouts with weight
* Fix amqp test, add repo level validation to resource tests
* Add weight to rollout mgmt-api and tests
* Add weight to mgmt api target Filter create and update
* Add target filter auto assign weight. disable enforcement of setting a weight in multiassign mode
* Remove ignored tests, fix api doc
* Fix minor findings
* Fix findings
* Remove hardcoded min weight
* Add docu text, fix findings
* Fix api documentation
* Expose weight via DMF
* Expose actions according to weight via ddi
* Fix documentation
* Add method to get actions ordered by weight to deploymentManagement
* Updating the schema for targetfilterquery and rollout
* Updated the indentation
* Updated the helper class, fixed the randomUID in test factory
* Updated the class name with prefix JPA
* Adding the missing License for WeightValidationHelper class
* Adding documentation to the dmf api on weight
* Removed the merger markers
* Updated the class name
* Removed the redundant method
* Addressed final PR comments
* Updated the missing testcase with latest default weight value
* Reverting the default value of weight back to 1000 and updated tests

Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>
This commit is contained in:
Stefan Klotz
2019-11-08 10:47:35 +01:00
committed by Stefan Behl
parent 09f2d8a481
commit 9cb5d31396
98 changed files with 2425 additions and 875 deletions

View File

@@ -46,13 +46,13 @@ import org.springframework.security.access.prepost.PreAuthorize;
public interface ControllerManagement {
/**
* Adds an {@link ActionStatus} for a cancel {@link Action} including potential
* state changes for the target and the {@link Action} itself.
* Adds an {@link ActionStatus} for a cancel {@link Action} including
* potential state changes for the target and the {@link Action} itself.
*
* @param create
* to be added
* @return the updated {@link Action}
*
*
* @throws EntityAlreadyExistsException
* if a given entity already exists
*
@@ -93,8 +93,8 @@ public interface ControllerManagement {
@NotNull Collection<Long> moduleId);
/**
* Simple addition of a new {@link ActionStatus} entry to the {@link Action} .
* No state changes.
* Simple addition of a new {@link ActionStatus} entry to the
* {@link Action}. No state changes.
*
* @param create
* to add to the action
@@ -136,36 +136,48 @@ public interface ControllerManagement {
Action addUpdateActionStatus(@NotNull @Valid ActionStatusCreate create);
/**
* Retrieves oldest {@link Action} that is active and assigned to a
* {@link Target}.
*
* Retrieves active {@link Action} with highest priority that is assigned to
* a {@link Target}.
*
* For performance reasons this method does not throw
* {@link EntityNotFoundException} in case target with given controlelrId
* {@link EntityNotFoundException} in case target with given controllerId
* does not exist but will return an {@link Optional#empty()} instead.
*
* @param controllerId
* identifies the target to retrieve the actions from
* @return a list of actions assigned to given target which are active
*
* identifies the target to retrieve the action from
* @return the action
*
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
Optional<Action> findOldestActiveActionByTarget(@NotEmpty String controllerId);
Optional<Action> findActiveActionWithHighestWeight(@NotEmpty String controllerId);
/**
* Retrieves all active actions which are assigned to the target with the given
* controller ID.
*
* @param pageable
* pagination parameter
* Retrieves active {@link Action}s with highest weight that are assigned to
* a {@link Target}.
*
* @param controllerId
* of the target
* @return the requested {@link Page} with {@link Action}s
* identifies the target to retrieve the action from
* @param maxActionCount
* max size of returned list
* @return the action
*
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
Page<Action> findActiveActionsByTarget(@NotNull Pageable pageable, @NotEmpty String controllerId);
List<Action> findActiveActionsWithHighestWeight(@NotEmpty String controllerId, int maxActionCount);
/**
* Get the {@link Action} entity for given actionId with all lazy attributes.
* Get weight of an Action. Returns the default value if the weight is null
* according to the properties.
*
* @param action
* to extract the weight from
* @return weight of the action
*/
int getWeightConsideringDefault(final Action action);
/**
* Get the {@link Action} entity for given actionId with all lazy
* attributes.
*
* @param actionId
* to be id of the action
@@ -175,7 +187,8 @@ public interface ControllerManagement {
Optional<Action> findActionWithDetails(long actionId);
/**
* Retrieves all the {@link ActionStatus} entries of the given {@link Action}.
* Retrieves all the {@link ActionStatus} entries of the given
* {@link Action}.
*
* @param pageReq
* pagination parameter
@@ -190,10 +203,11 @@ public interface ControllerManagement {
Page<ActionStatus> findActionStatusByAction(@NotNull Pageable pageReq, long actionId);
/**
* Register new target in the repository (plug-and-play) and in case it already
* exists updates {@link Target#getAddress()} and
* Register new target in the repository (plug-and-play) and in case it
* already exists updates {@link Target#getAddress()} and
* {@link Target#getLastTargetQuery()} and switches if
* {@link TargetUpdateStatus#UNKNOWN} to {@link TargetUpdateStatus#REGISTERED}.
* {@link TargetUpdateStatus#UNKNOWN} to
* {@link TargetUpdateStatus#REGISTERED}.
*
* @param controllerId
* reference
@@ -205,10 +219,11 @@ public interface ControllerManagement {
Target findOrRegisterTargetIfItDoesNotExist(@NotEmpty String controllerId, @NotNull URI address);
/**
* Register new target in the repository (plug-and-play) and in case it already
* exists updates {@link Target#getAddress()} and
* {@link Target#getLastTargetQuery()} and {@link Target#getName()} and switches if
* {@link TargetUpdateStatus#UNKNOWN} to {@link TargetUpdateStatus#REGISTERED}.
* Register new target in the repository (plug-and-play) and in case it
* already exists updates {@link Target#getAddress()} and
* {@link Target#getLastTargetQuery()} and {@link Target#getName()} and
* switches if {@link TargetUpdateStatus#UNKNOWN} to
* {@link TargetUpdateStatus#REGISTERED}.
*
* @param controllerId
* reference
@@ -222,14 +237,14 @@ public interface ControllerManagement {
Target findOrRegisterTargetIfItDoesNotExist(@NotEmpty String controllerId, @NotNull URI address, String name);
/**
* Retrieves last {@link Action} for a download of an artifact of given module
* and target if exists and is not canceled.
* Retrieves last {@link Action} for a download of an artifact of given
* module and target if exists and is not canceled.
*
* @param controllerId
* to look for
* @param moduleId
* of the the {@link SoftwareModule} that should be assigned to the
* target
* of the the {@link SoftwareModule} that should be assigned to
* the target
* @return last {@link Action} for given combination
*
* @throws EntityNotFoundException
@@ -267,18 +282,18 @@ public interface ControllerManagement {
int getMaintenanceWindowPollCount();
/**
* Returns polling time based on the maintenance window for an action. Server
* will reduce the polling interval as the start time for maintenance window
* approaches, so that at least these many attempts are made between current
* polling until start of maintenance window. Poll time keeps reducing with
* MinPollingTime as lower limit
* {@link TenantConfigurationKey#MIN_POLLING_TIME_INTERVAL}. After the start of
* maintenance window, it resets to default
* Returns polling time based on the maintenance window for an action.
* Server will reduce the polling interval as the start time for maintenance
* window approaches, so that at least these many attempts are made between
* current polling until start of maintenance window. Poll time keeps
* reducing with MinPollingTime as lower limit
* {@link TenantConfigurationKey#MIN_POLLING_TIME_INTERVAL}. After the start
* of maintenance window, it resets to default
* {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}.
*
* @param actionId
* id the {@link Action} for which polling time is calculated based
* on it having maintenance window or not
* id the {@link Action} for which polling time is calculated
* based on it having maintenance window or not
*
* @return current {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}.
*/
@@ -286,20 +301,20 @@ public interface ControllerManagement {
String getPollingTimeForAction(long actionId);
/**
* Checks if a given target has currently or has even been assigned to the given
* artifact through the action history list. This can e.g. indicate if a target
* is allowed to download a given artifact because it has currently assigned or
* had ever been assigned to the target and so it's visible to a specific target
* e.g. for downloading.
* Checks if a given target has currently or has even been assigned to the
* given artifact through the action history list. This can e.g. indicate if
* a target is allowed to download a given artifact because it has currently
* assigned or had ever been assigned to the target and so it's visible to a
* specific target e.g. for downloading.
*
* @param controllerId
* the ID of the target to check
* @param sha1Hash
* of the artifact to verify if the given target had even been
* assigned to
* @return {@code true} if the given target has currently or had ever a relation
* to the given artifact through the action history, otherwise
* {@code false}
* @return {@code true} if the given target has currently or had ever a
* relation to the given artifact through the action history,
* otherwise {@code false}
*
* @throws EntityNotFoundException
* if target with given ID does not exist
@@ -308,20 +323,20 @@ public interface ControllerManagement {
boolean hasTargetArtifactAssigned(@NotEmpty String controllerId, @NotEmpty String sha1Hash);
/**
* Checks if a given target has currently or has even been assigned to the given
* artifact through the action history list. This can e.g. indicate if a target
* is allowed to download a given artifact because it has currently assigned or
* had ever been assigned to the target and so it's visible to a specific target
* e.g. for downloading.
* Checks if a given target has currently or has even been assigned to the
* given artifact through the action history list. This can e.g. indicate if
* a target is allowed to download a given artifact because it has currently
* assigned or had ever been assigned to the target and so it's visible to a
* specific target e.g. for downloading.
*
* @param targetId
* the ID of the target to check
* @param sha1Hash
* of the artifact to verify if the given target had even been
* assigned to
* @return {@code true} if the given target has currently or had ever a relation
* to the given artifact through the action history, otherwise
* {@code false}
* @return {@code true} if the given target has currently or had ever a
* relation to the given artifact through the action history,
* otherwise {@code false}
*
* @throws EntityNotFoundException
* if target with given ID does not exist
@@ -330,8 +345,8 @@ public interface ControllerManagement {
boolean hasTargetArtifactAssigned(long targetId, @NotEmpty String sha1Hash);
/**
* Registers retrieved status for given {@link Target} and {@link Action} if it
* does not exist yet.
* Registers retrieved status for given {@link Target} and {@link Action} if
* it does not exist yet.
*
* @param actionId
* to the handle status for
@@ -385,8 +400,9 @@ public interface ControllerManagement {
Optional<Target> getByControllerId(@NotEmpty String controllerId);
/**
* Finds {@link Target} based on given ID returns found Target without details,
* i.e. NO {@link Target#getTags()} and {@link Target#getActions()} possible.
* Finds {@link Target} based on given ID returns found Target without
* details, i.e. NO {@link Target#getTags()} and {@link Target#getActions()}
* possible.
*
* @param targetId
* to look for.
@@ -398,20 +414,21 @@ public interface ControllerManagement {
Optional<Target> get(long targetId);
/**
* Retrieves the specified number of messages from action history of the given
* {@link Action} based on messageCount. Regardless of the value of
* Retrieves the specified number of messages from action history of the
* given {@link Action} based on messageCount. Regardless of the value of
* messageCount, in order to restrict resource utilisation by controllers,
* maximum number of messages that are retrieved from database is limited by
* {@link RepositoryConstants#MAX_ACTION_HISTORY_MSG_COUNT}. messageCount less
* then zero, retrieves the maximum allowed number of action status messages
* from history; messageCount equal zero, does not retrieve any message; and
* messageCount larger then zero, retrieves the specified number of messages,
* limited by maximum allowed number. A controller sends the feedback for an
* {@link ActionStatus} as a list of messages; while returning the messages,
* even though the messages from multiple {@link ActionStatus} are retrieved in
* descending order by the reported time ({@link ActionStatus#getOccurredAt()}),
* i.e. latest ActionStatus first, the sub-ordering of messages from within
* single {@link ActionStatus} is unspecified.
* {@link RepositoryConstants#MAX_ACTION_HISTORY_MSG_COUNT}. messageCount
* less then zero, retrieves the maximum allowed number of action status
* messages from history; messageCount equal zero, does not retrieve any
* message; and messageCount larger then zero, retrieves the specified
* number of messages, limited by maximum allowed number. A controller sends
* the feedback for an {@link ActionStatus} as a list of messages; while
* returning the messages, even though the messages from multiple
* {@link ActionStatus} are retrieved in descending order by the reported
* time ({@link ActionStatus#getOccurredAt()}), i.e. latest ActionStatus
* first, the sub-ordering of messages from within single
* {@link ActionStatus} is unspecified.
*
* @param actionId
* to be filtered on
@@ -424,10 +441,10 @@ public interface ControllerManagement {
List<String> getActionHistoryMessages(long actionId, int messageCount);
/**
* Cancels given {@link Action} for this {@link Target}. However, it might be
* possible that the controller will continue to work on the cancellation. The
* controller needs to acknowledge or reject the cancellation using
* {@link DdiRootController#postCancelActionFeedback}.
* Cancels given {@link Action} for this {@link Target}. However, it might
* be possible that the controller will continue to work on the
* cancellation. The controller needs to acknowledge or reject the
* cancellation using {@link DdiRootController#postCancelActionFeedback}.
*
* @param actionId
* to be canceled
@@ -454,8 +471,9 @@ public interface ControllerManagement {
void updateActionExternalRef(long actionId, @NotEmpty String externalRef);
/**
* Retrieves list of {@link Action}s which matches the provided externalRefs.
*
* Retrieves list of {@link Action}s which matches the provided
* externalRefs.
*
* @param externalRefs
* for which the actions need to be fetched.
* @return list of {@link Action}s matching the externalRefs.

View File

@@ -14,6 +14,7 @@ import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@@ -76,7 +77,7 @@ public interface DeploymentManagement {
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
List<DistributionSetAssignmentResult> assignDistributionSets(
@NotEmpty List<DeploymentRequest> deploymentRequests);
@Valid @NotEmpty List<DeploymentRequest> deploymentRequests);
/**
* Assigns {@link DistributionSet}s to {@link Target}s according to the
@@ -107,9 +108,9 @@ public interface DeploymentManagement {
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
List<DistributionSetAssignmentResult> assignDistributionSets(
@NotEmpty List<DeploymentRequest> deploymentRequests, String actionMessage);
/**
@Valid @NotEmpty List<DeploymentRequest> deploymentRequests, String actionMessage);
/**
* build a {@link DeploymentRequest} for a target distribution set
* assignment
*
@@ -372,6 +373,30 @@ public interface DeploymentManagement {
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
Page<Action> findInActiveActionsByTarget(@NotNull Pageable pageable, @NotEmpty String controllerId);
/**
* Retrieves active {@link Action}s with highest weight that are assigned to
* a {@link Target}.
*
* @param controllerId
* identifies the target to retrieve the action from
* @param maxActionCount
* max size of returned list
* @return the action
*
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
List<Action> findActiveActionsWithHighestWeight(@NotEmpty String controllerId, int maxActionCount);
/**
* Get weight of an Action. Returns the default value if the weight is null
* according to the properties.
*
* @param action
* to extract the weight from
* @return weight of the action
*/
int getWeightConsideringDefault(final Action action);
/**
* Force cancels given {@link Action} for given {@link Target}. Force
* canceling means that the action is marked as canceled on the SP server

View File

@@ -27,8 +27,8 @@ public class RepositoryProperties {
* especially useful if the action status feedback channel order from the
* device cannot be guaranteed.
*
* Note: if this is enforced you have to make sure that the feedback
* channel from the devices is in order.
* Note: if this is enforced you have to make sure that the feedback channel
* from the devices is in order.
*/
private boolean rejectActionStatusForClosedAction;
@@ -54,6 +54,11 @@ public class RepositoryProperties {
*/
private boolean eagerPollPersistence;
/**
* If an {@link Action} has a weight of null this value is used as weight.
*/
private int actionWeightIfAbsent = 1000;
public boolean isEagerPollPersistence() {
return eagerPollPersistence;
}
@@ -94,4 +99,12 @@ public class RepositoryProperties {
this.publishTargetPollEvent = publishTargetPollEvent;
}
public int getActionWeightIfAbsent() {
return actionWeightIfAbsent;
}
public void setActionWeightIfAbsent(final int actionWeightIfAbsent) {
this.actionWeightIfAbsent = actionWeightIfAbsent;
}
}

View File

@@ -129,7 +129,7 @@ public interface RolloutManagement {
* exceeded.
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE)
Rollout create(@NotNull RolloutCreate create, int amountGroup, @NotNull RolloutGroupConditions conditions);
Rollout create(@NotNull @Valid RolloutCreate create, int amountGroup, @NotNull RolloutGroupConditions conditions);
/**
* Persists a new rollout entity. The filter within the
@@ -166,7 +166,7 @@ public interface RolloutManagement {
* exceeded.
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE)
Rollout create(@NotNull @Valid RolloutCreate rollout, @NotNull @Valid List<RolloutGroupCreate> groups,
Rollout create(@Valid @NotNull RolloutCreate rollout, @NotNull @Valid List<RolloutGroupCreate> groups,
RolloutGroupConditions conditions);
/**
@@ -342,9 +342,9 @@ public interface RolloutManagement {
/**
* Approves or denies a created rollout being in state
* {@link RolloutStatus#WAITING_FOR_APPROVAL}. If the rollout is approved, it
* switches state to {@link RolloutStatus#READY}, otherwise it switches to state
* {@link RolloutStatus#APPROVAL_DENIED}
* {@link RolloutStatus#WAITING_FOR_APPROVAL}. If the rollout is approved,
* it switches state to {@link RolloutStatus#READY}, otherwise it switches
* to state {@link RolloutStatus#APPROVAL_DENIED}
*
* @param rolloutId
* the rollout to be approved or denied.
@@ -365,9 +365,9 @@ public interface RolloutManagement {
/**
* Approves or denies a created rollout being in state
* {@link RolloutStatus#WAITING_FOR_APPROVAL}. If the rollout is approved, it
* switches state to {@link RolloutStatus#READY}, otherwise it switches to state
* {@link RolloutStatus#APPROVAL_DENIED}
* {@link RolloutStatus#WAITING_FOR_APPROVAL}. If the rollout is approved,
* it switches state to {@link RolloutStatus#READY}, otherwise it switches
* to state {@link RolloutStatus#APPROVAL_DENIED}
*
* @param rolloutId
* the rollout to be approved or denied.

View File

@@ -15,6 +15,7 @@ import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryUpdate;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
@@ -208,7 +209,7 @@ public interface TargetFilterQueryManagement {
* if fields are not filled as specified. Check
* {@link TargetFilterQueryUpdate} for field constraints.
*
* @throws AssignmentQuotaExceededException
* @throws QuotaExceededException
* if the update contains a new query which addresses too many
* targets (auto-assignments only)
*/
@@ -216,46 +217,10 @@ public interface TargetFilterQueryManagement {
TargetFilterQuery update(@NotNull @Valid TargetFilterQueryUpdate update);
/**
* Updates the the auto-assign {@link DistributionSet} and sets default
* (FORCED) {@link ActionType} of the addressed {@link TargetFilterQuery}.
*
* @param queryId
* of the target filter query to be updated
* @param dsId
* to be updated or <code>null</code> in order to remove it
* together with the auto-assign {@link ActionType}
* Updates the auto assign settings of an {@link TargetFilterQuery}.
*
* @return the updated {@link TargetFilterQuery}
*
* @throws EntityNotFoundException
* if either {@link TargetFilterQuery} and/or autoAssignDs are
* provided but not found
*
* @throws AssignmentQuotaExceededException
* if the query that is already associated with this filter
* query addresses too many targets (auto-assignments only)
*
* @throws InvalidAutoAssignDistributionSetException
* if the provided auto-assign {@link DistributionSet} is not
* valid (incomplete or soft deleted)
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
default TargetFilterQuery updateAutoAssignDS(final long queryId, final Long dsId) {
return updateAutoAssignDSWithActionType(queryId, dsId, null);
}
/**
* Updates the the auto-assign {@link DistributionSet} and
* {@link ActionType} of the addressed {@link TargetFilterQuery}.
*
* @param queryId
* of the target filter query to be updated
* @param dsId
* to be updated or <code>null</code> in order to remove it
* together with the auto-assign {@link ActionType}
* @param actionType
* to be updated or <code>null</code> for default (FORCED) if
* distribution set Id is present
* @param autoAssignDistributionSetUpdate
* the new auto assignment
*
* @return the updated {@link TargetFilterQuery}
*
@@ -276,5 +241,6 @@ public interface TargetFilterQueryManagement {
* valid (incomplete or soft deleted)
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
TargetFilterQuery updateAutoAssignDSWithActionType(long queryId, Long dsId, ActionType actionType);
TargetFilterQuery updateAutoAssignDS(
@NotNull @Valid AutoAssignDistributionSetUpdate autoAssignDistributionSetUpdate);
}

View File

@@ -0,0 +1,94 @@
/**
* 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.builder;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
/**
* Builder to update the auto assign {@link DistributionSet} of a
* {@link TargetFilterQuery} entry. Defines all fields that can be updated.
*/
public class AutoAssignDistributionSetUpdate {
private final long targetFilterId;
private Long dsId;
private ActionType actionType;
@Min(Action.WEIGHT_MIN)
@Max(Action.WEIGHT_MAX)
private Integer weight;
/**
* Constructor
*
* @param targetFilterId
* ID of {@link TargetFilterQuery} to update
*/
public AutoAssignDistributionSetUpdate(final long targetFilterId) {
this.targetFilterId = targetFilterId;
}
/**
* Specify {@link DistributionSet}
*
* @param dsId
* ID of the {@link DistributionSet}
* @return updated builder instance
*/
public AutoAssignDistributionSetUpdate ds(final Long dsId) {
this.dsId = dsId;
return this;
}
/**
* Specify {@link DistributionSet}
*
* @param actionType
* {@link ActionType} used for the auto assignment
* @return updated builder instance
*/
public AutoAssignDistributionSetUpdate actionType(final ActionType actionType) {
this.actionType = actionType;
return this;
}
/**
* Specify weight of resulting {@link Action}
*
* @param weight
* weight used for the auto assignment
* @return updated builder instance
*/
public AutoAssignDistributionSetUpdate weight(final Integer weight) {
this.weight = weight;
return this;
}
public Long getDsId() {
return dsId;
}
public ActionType getActionType() {
return actionType;
}
public Integer getWeight() {
return weight;
}
public long getTargetFilterId() {
return targetFilterId;
}
}

View File

@@ -28,6 +28,8 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
*/
public interface RolloutCreate {
/**
* Set name
*
* @param name
* for {@link Rollout#getName()}
* @return updated builder instance
@@ -35,6 +37,8 @@ public interface RolloutCreate {
RolloutCreate name(@Size(min = 1, max = NamedEntity.NAME_MAX_SIZE) @NotNull String name);
/**
* Set description
*
* @param description
* for {@link Rollout#getDescription()}
* @return updated builder instance
@@ -42,6 +46,8 @@ public interface RolloutCreate {
RolloutCreate description(@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE) String description);
/**
* Set the {@link DistributionSet}
*
* @param set
* for {@link Rollout#getDistributionSet()}
* @return updated builder instance
@@ -51,6 +57,8 @@ public interface RolloutCreate {
}
/**
* Set the id of the {@link DistributionSet}
*
* @param setId
* for {@link Rollout#getDistributionSet()}
* @return updated builder instance
@@ -58,6 +66,8 @@ public interface RolloutCreate {
RolloutCreate set(long setId);
/**
* Set the {@link TargetFilterQuery}
*
* @param targetFilterQuery
* for {@link Rollout#getTargetFilterQuery()}
* @return updated builder instance
@@ -66,6 +76,8 @@ public interface RolloutCreate {
@Size(min = 1, max = TargetFilterQuery.QUERY_MAX_SIZE) @NotNull String targetFilterQuery);
/**
* Set the {@link ActionType}
*
* @param actionType
* for {@link Rollout#getActionType()}
* @return updated builder instance
@@ -73,6 +85,8 @@ public interface RolloutCreate {
RolloutCreate actionType(@NotNull ActionType actionType);
/**
* Set the forcedTime of the resulting {@link Actions}
*
* @param forcedTime
* for {@link Rollout#getForcedTime()}
* @return updated builder instance
@@ -80,6 +94,17 @@ public interface RolloutCreate {
RolloutCreate forcedTime(Long forcedTime);
/**
* Set the weight of the resulting {@link Actions}
*
* @param weight
* for {@link Rollout#getWeight()}
* @return updated builder instance
*/
RolloutCreate weight(Integer weight);
/**
* set start
*
* @param startAt
* for {@link Rollout#getStartAt()}
* @return updated builder instance

View File

@@ -12,6 +12,7 @@ import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.Rollout;
@@ -22,6 +23,8 @@ import org.eclipse.hawkbit.repository.model.Rollout;
*/
public interface RolloutUpdate {
/**
* Set name of the {@link Rollout}
*
* @param name
* for {@link Rollout#getName()}
* @return updated builder instance
@@ -29,6 +32,8 @@ public interface RolloutUpdate {
RolloutUpdate name(@Size(min = 1, max = NamedEntity.NAME_MAX_SIZE) @NotNull String name);
/**
* Set description of the {@link Rollout}
*
* @param description
* for {@link Rollout#getDescription()}
* @return updated builder instance
@@ -36,6 +41,8 @@ public interface RolloutUpdate {
RolloutUpdate description(@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE) String description);
/**
* Set ID of {@link DistributionSet} of the {@link Rollout}
*
* @param setId
* for {@link Rollout#getDistributionSet()}
* @return updated builder instance
@@ -43,6 +50,8 @@ public interface RolloutUpdate {
RolloutUpdate set(long setId);
/**
* Set action type of the {@link Rollout}
*
* @param actionType
* for {@link Rollout#getActionType()}
* @return updated builder instance
@@ -50,6 +59,8 @@ public interface RolloutUpdate {
RolloutUpdate actionType(@NotNull Action.ActionType actionType);
/**
* Set forcedTime of the {@link Rollout}
*
* @param forcedTime
* for {@link Rollout#getForcedTime()}
* @return updated builder instance
@@ -57,10 +68,20 @@ public interface RolloutUpdate {
RolloutUpdate forcedTime(Long forcedTime);
/**
* Set weight of {@link Action}s created by the {@link Rollout}
*
* @param weight
* for {@link Rollout#getWeight()}
* @return updated builder instance
*/
RolloutUpdate weight(Integer weight);
/**
* Set start time of the {@link Rollout}
*
* @param startAt
* for {@link Rollout#getStartAt()}
* @return updated builder instance
*/
RolloutUpdate startAt(Long startAt);
}

View File

@@ -16,12 +16,23 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
*/
public interface TargetFilterQueryBuilder {
/**
* Used to update a {@link TargetFilterQuery}
*
* @param id
* of the updatable entity
* @return builder instance
*/
TargetFilterQueryUpdate update(long id);
/**
* Used to update a the auto assignment of a {@link TargetFilterQuery}
*
* @param id
* of the updatable entity
* @return builder instance
*/
AutoAssignDistributionSetUpdate updateAutoAssign(long id);
/**
* @return builder instance
*/

View File

@@ -13,6 +13,7 @@ import java.util.Optional;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -27,6 +28,8 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
*/
public interface TargetFilterQueryCreate {
/**
* Set filter name
*
* @param name
* of {@link TargetFilterQuery#getName()}
* @return updated builder instance
@@ -34,6 +37,8 @@ public interface TargetFilterQueryCreate {
TargetFilterQueryCreate name(@Size(min = 1, max = NamedEntity.NAME_MAX_SIZE) @NotNull String name);
/**
* Set filter query
*
* @param query
* of {@link TargetFilterQuery#getQuery()}
* @return updated builder instance
@@ -41,6 +46,8 @@ public interface TargetFilterQueryCreate {
TargetFilterQueryCreate query(@Size(min = 1, max = TargetFilterQuery.QUERY_MAX_SIZE) @NotNull String query);
/**
* Set {@link DistributionSet} for auto assignment
*
* @param distributionSet
* for {@link TargetFilterQuery#getAutoAssignDistributionSet()}
* @return updated builder instance
@@ -50,6 +57,8 @@ public interface TargetFilterQueryCreate {
}
/**
* Set ID of {@link DistributionSet} for auto assignment
*
* @param dsId
* for {@link TargetFilterQuery#getAutoAssignDistributionSet()}
* @return updated builder instance
@@ -57,12 +66,23 @@ public interface TargetFilterQueryCreate {
TargetFilterQueryCreate autoAssignDistributionSet(Long dsId);
/**
* Set {@link ActionType} for auto assignment
*
* @param actionType
* for {@link TargetFilterQuery#getAutoAssignActionType()}
* @return updated builder instance
*/
TargetFilterQueryCreate autoAssignActionType(ActionType actionType);
/**
* Set weight of {@link Action} created during auto assignment
*
* @param weight
* weight of {@link Action} generated within auto assignment
* @return updated builder instance
*/
TargetFilterQueryCreate autoAssignWeight(Integer weight);
/**
* @return peek on current state of {@link TargetFilterQuery} in the builder
*/

View File

@@ -32,5 +32,4 @@ public interface TargetFilterQueryUpdate {
* @return updated builder instance
*/
TargetFilterQueryUpdate query(@Size(min = 1, max = TargetFilterQuery.QUERY_MAX_SIZE) String query);
}

View File

@@ -0,0 +1,63 @@
/**
* 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 org.eclipse.hawkbit.exception.AbstractServerRtException;
import org.eclipse.hawkbit.exception.SpServerError;
/**
* This exception is thrown if multi assignments is enabled and an target
* distribution set assignment request does not contain a weight value
*
*/
public class NoWeightProvidedInMultiAssignmentModeException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_NO_WEIGHT_PROVIDED_IN_MULTIASSIGNMENT_MODE;
/**
* Default constructor.
*/
public NoWeightProvidedInMultiAssignmentModeException() {
super(THIS_ERROR);
}
/**
* Parameterized constructor.
*
* @param cause
* of the exception
*/
public NoWeightProvidedInMultiAssignmentModeException(final Throwable cause) {
super(THIS_ERROR, cause);
}
/**
* Parameterized constructor.
*
* @param message
* of the exception
* @param cause
* of the exception
*/
public NoWeightProvidedInMultiAssignmentModeException(final String message, final Throwable cause) {
super(message, THIS_ERROR, cause);
}
/**
* Parameterized constructor.
*
* @param message
* of the exception
*/
public NoWeightProvidedInMultiAssignmentModeException(final String message) {
super(message, THIS_ERROR);
}
}

View File

@@ -38,7 +38,16 @@ public interface Action extends TenantAwareBaseEntity {
* Maximum length of external reference.
*/
int EXTERNAL_REF_MAX_LENGTH = 512;
/**
* Minimum weight to indicate the priority of {@link Action}.
*/
int WEIGHT_MIN = 0;
/**
* Maximum weight to indicate the priority of {@link Action}.
*/
int WEIGHT_MAX = 1000;
/**
* @return the distributionSet
*/
@@ -80,6 +89,11 @@ public interface Action extends TenantAwareBaseEntity {
*/
long getForcedTime();
/**
* @return priority of the {@link Action}.
*/
Optional<Integer> getWeight();
/**
* @return rolloutGroup related to this {@link Action}.
*/
@@ -106,10 +120,11 @@ public interface Action extends TenantAwareBaseEntity {
String getMaintenanceWindowTimeZone();
/**
* @param externalRef associated with this action
* @param externalRef
* associated with this action
*/
void setExternalRef(@NotEmpty String externalRef);
/**
* @return externalRef of the action
*/

View File

@@ -10,6 +10,8 @@ package org.eclipse.hawkbit.repository.model;
import java.util.Objects;
import javax.validation.Valid;
import org.eclipse.hawkbit.repository.exception.InvalidMaintenanceScheduleException;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
@@ -19,6 +21,7 @@ import org.eclipse.hawkbit.repository.model.Action.ActionType;
*/
public class DeploymentRequest {
private final Long distributionSetId;
@Valid
private final TargetWithActionType targetWithActionType;
/**
@@ -34,6 +37,8 @@ public class DeploymentRequest {
* specified for the action.
* @param forceTime
* at what time the type soft turns into forced.
* @param weight
* the priority of an {@link Action}.
* @param maintenanceSchedule
* is the cron expression to be used for scheduling maintenance
* windows. Expression has 6 mandatory fields and 1 last optional
@@ -51,11 +56,10 @@ public class DeploymentRequest {
* if the parameters do not define a valid maintenance schedule.
*/
public DeploymentRequest(final String controllerId, final Long distributionSetId, final ActionType actionType,
final long forceTime, final String maintenanceSchedule, final String maintenanceWindowDuration,
final String maintenanceWindowTimeZone) {
this.targetWithActionType = new TargetWithActionType(controllerId, actionType, forceTime, maintenanceSchedule,
maintenanceWindowDuration,
maintenanceWindowTimeZone);
final long forceTime, final Integer weight, final String maintenanceSchedule,
final String maintenanceWindowDuration, final String maintenanceWindowTimeZone) {
this.targetWithActionType = new TargetWithActionType(controllerId, actionType, forceTime, weight,
maintenanceSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
this.distributionSetId = distributionSetId;
}
@@ -71,14 +75,13 @@ public class DeploymentRequest {
return targetWithActionType;
}
@Override
public String toString() {
return String.format(
"DeploymentRequest [controllerId=%s, distributionSetId=%d, actionType=%s, forceTime=%d, maintenanceSchedule=%s, maintenanceWindowDuration=%s, maintenanceWindowTimeZone=%s]",
"DeploymentRequest [controllerId=%s, distributionSetId=%d, actionType=%s, forceTime=%d, weight=%d, maintenanceSchedule=%s, maintenanceWindowDuration=%s, maintenanceWindowTimeZone=%s]",
targetWithActionType.getControllerId(), getDistributionSetId(), targetWithActionType.getActionType(),
targetWithActionType.getForceTime(), targetWithActionType.getMaintenanceSchedule(),
targetWithActionType.getMaintenanceWindowDuration(),
targetWithActionType.getForceTime(), targetWithActionType.getWeight(),
targetWithActionType.getMaintenanceSchedule(), targetWithActionType.getMaintenanceWindowDuration(),
targetWithActionType.getMaintenanceWindowTimeZone());
}
@@ -86,7 +89,7 @@ public class DeploymentRequest {
public int hashCode() {
return Objects.hash(distributionSetId, targetWithActionType);
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {

View File

@@ -18,7 +18,7 @@ public class DeploymentRequestBuilder {
private final String controllerId;
private final Long distributionSetId;
private Integer weight;
private long forceTime = RepositoryModelConstants.NO_FORCE_TIME;
private ActionType actionType = ActionType.FORCED;
private String maintenanceSchedule;
@@ -63,6 +63,18 @@ public class DeploymentRequestBuilder {
return this;
}
/**
* Set the weight of the action.
*
* @param weight
* the priority given to the action.
* @return builder
*/
public DeploymentRequestBuilder setWeight(final Integer weight) {
this.weight = weight;
return this;
}
/**
* Set a maintenanceWindow
*
@@ -94,8 +106,8 @@ public class DeploymentRequestBuilder {
* @return the request object
*/
public DeploymentRequest build() {
return new DeploymentRequest(controllerId, distributionSetId, actionType, forceTime, maintenanceSchedule,
maintenanceWindowDuration, maintenanceWindowTimeZone);
return new DeploymentRequest(controllerId, distributionSetId, actionType, forceTime, weight,
maintenanceSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
}
}

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.repository.model;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
@@ -101,6 +102,11 @@ public interface Rollout extends NamedEntity {
*/
String getApprovalRemark();
/**
* @return the priority of {@link Rollout}.
*/
Optional<Integer> getWeight();
/**
*
* State machine for rollout.
@@ -197,5 +203,4 @@ public interface Rollout extends NamedEntity {
*/
DENIED
}
}

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.model;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
@@ -70,4 +71,10 @@ public interface TargetFilterQuery extends TenantAwareBaseEntity {
*/
ActionType getAutoAssignActionType();
/**
* @return the weight of the {@link Action}s created during an auto
* assignment.
*/
Optional<Integer> getAutoAssignWeight();
}

View File

@@ -10,6 +10,9 @@ package org.eclipse.hawkbit.repository.model;
import java.util.Objects;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import org.eclipse.hawkbit.repository.exception.InvalidMaintenanceScheduleException;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
@@ -21,6 +24,9 @@ public class TargetWithActionType {
private final String controllerId;
private final ActionType actionType;
private final long forceTime;
@Min(Action.WEIGHT_MIN)
@Max(Action.WEIGHT_MAX)
private final Integer weight;
private String maintenanceSchedule;
private String maintenanceWindowDuration;
private String maintenanceWindowTimeZone;
@@ -32,7 +38,7 @@ public class TargetWithActionType {
* ID if the controller
*/
public TargetWithActionType(final String controllerId) {
this(controllerId, ActionType.FORCED, 0);
this(controllerId, ActionType.FORCED, 0, null);
}
/**
@@ -43,13 +49,17 @@ public class TargetWithActionType {
* @param actionType
* specified for the action.
* @param forceTime
* after that point in time the action is exposed as forcen in
* after that point in time the action is exposed as forced in
* case the type is {@link ActionType#TIMEFORCED}
* @param weight
* the priority of an {@link Action}
*/
public TargetWithActionType(final String controllerId, final ActionType actionType, final long forceTime) {
public TargetWithActionType(final String controllerId, final ActionType actionType, final long forceTime,
final Integer weight) {
this.controllerId = controllerId;
this.actionType = actionType != null ? actionType : ActionType.FORCED;
this.forceTime = forceTime;
this.weight = weight;
}
/**
@@ -61,8 +71,10 @@ public class TargetWithActionType {
* @param actionType
* specified for the action.
* @param forceTime
* after that point in time the action is exposed as forcen in
* after that point in time the action is exposed as forced in
* case the type is {@link ActionType#TIMEFORCED}
* @param weight
* the priority of an {@link Action}
* @param maintenanceSchedule
* is the cron expression to be used for scheduling maintenance
* windows. Expression has 6 mandatory fields and 1 last optional
@@ -80,9 +92,9 @@ public class TargetWithActionType {
* if the parameters do not define a valid maintenance schedule.
*/
public TargetWithActionType(final String controllerId, final ActionType actionType, final long forceTime,
final String maintenanceSchedule, final String maintenanceWindowDuration,
final Integer weight, final String maintenanceSchedule, final String maintenanceWindowDuration,
final String maintenanceWindowTimeZone) {
this(controllerId, actionType, forceTime);
this(controllerId, actionType, forceTime, weight);
this.maintenanceSchedule = maintenanceSchedule;
this.maintenanceWindowDuration = maintenanceWindowDuration;
@@ -104,6 +116,11 @@ public class TargetWithActionType {
return RepositoryModelConstants.NO_FORCE_TIME;
}
public Integer getWeight() {
return weight;
}
public String getControllerId() {
return controllerId;
}
@@ -138,14 +155,14 @@ public class TargetWithActionType {
@Override
public String toString() {
return "TargetWithActionType [controllerId=" + controllerId + ", actionType=" + getActionType() + ", forceTime="
+ getForceTime() + ", maintenanceSchedule=" + getMaintenanceSchedule() + ", maintenanceWindowDuration="
+ getMaintenanceWindowDuration() + ", maintenanceWindowTimeZone=" + getMaintenanceWindowTimeZone()
+ "]";
+ getForceTime() + ", weight=" + getWeight() + ", maintenanceSchedule=" + getMaintenanceSchedule()
+ ", maintenanceWindowDuration=" + getMaintenanceWindowDuration() + ", maintenanceWindowTimeZone="
+ getMaintenanceWindowTimeZone() + "]";
}
@Override
public int hashCode() {
return Objects.hash(actionType, controllerId, forceTime, maintenanceSchedule, maintenanceWindowDuration,
return Objects.hash(actionType, controllerId, forceTime, weight, maintenanceSchedule, maintenanceWindowDuration,
maintenanceWindowTimeZone);
}
@@ -163,10 +180,9 @@ public class TargetWithActionType {
}
final TargetWithActionType other = (TargetWithActionType) obj;
return Objects.equals(actionType, other.actionType) && Objects.equals(controllerId, other.controllerId)
&& Objects.equals(forceTime, other.forceTime)
&& Objects.equals(forceTime, other.forceTime) && Objects.equals(weight, other.weight)
&& Objects.equals(maintenanceSchedule, other.maintenanceSchedule)
&& Objects.equals(maintenanceWindowDuration, other.maintenanceWindowDuration)
&& Objects.equals(maintenanceWindowTimeZone, other.maintenanceWindowTimeZone);
}
}