Support user consent flow (#1293)

* Introduce user consent flow
* Add permissions to confirmation management
* rename from consent to confirmation
* Reformat code. Remove unused imports. Change and add permission checks when configuring auto-confirmation.
* Do not include null values for DDI confirmation base endpoint
* fix confirmation required checkbox id
* Remove unused import. Fix consume/produce type of new API's.
* Change term processing to proceeding when activating user consent flow
* Align formatting and extend integration test cases for DMF and DDI.
* Extend DMF test cases to consider auto-confirmation
* Refactor action management to fix problem of handling action status updates on closed actions.
* remove unsupported validation
* use new confirmation api for DMF. Extend test cases.,
* Remove unnecessary fields.
* Extend API documentation for DDI and MGMT API.
* adapt ddi api docs adoc file
* Fixed the duplicate migration version for db files
* fix method to support confirmation
* Fixed PR comments
* Addressed PR comments
* Fixed after merge compilation issue
* Fixed after merge compilation issue
* Fix failing tests in MgmtRolloutResourceTest
* Fixed the permissions issue reflected by integration tests
* Added back the missing line of code lost during merge
* Fix the failing test on Jenkins

Signed-off-by: Stanislav Trailov <stanislav.trailov@bosch.io>
Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>
Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io>
Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
Co-authored-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
This commit is contained in:
Michael Herdt
2023-01-25 12:11:05 +01:00
committed by GitHub
parent b919ceda5c
commit 21f1569881
208 changed files with 7830 additions and 831 deletions

View File

@@ -0,0 +1,115 @@
/**
* Copyright (c) 2022 Bosch.IO GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.security.access.prepost.PreAuthorize;
import javax.validation.constraints.NotEmpty;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
/**
* Service layer for all confirmation related operations.
*/
public interface ConfirmationManagement {
/**
* Find active actions in the {@link Action.Status#WAIT_FOR_CONFIRMATION} state
* for a specific target with a specified controllerId.
*
* @param controllerId
* of the target to check
* @return a list of {@link Action}
*/
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
List<Action> findActiveActionsWaitingConfirmation(@NotEmpty String controllerId);
/**
* Activate auto confirmation for a given controller ID. In case auto
* confirmation is active already, this method will fail with an exception.
*
* @param controllerId
* to activate the feature for
* @param initiator
* who initiated this operation. If 'null' we will take the current
* user from {@link TenantAware#getCurrentUsername()}
* @param remark
* optional field to set a remark
* @return the persisted {@link AutoConfirmationStatus}
*/
@PreAuthorize(SpPermission.SpringEvalExpressions.IS_CONTROLLER_OR_HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
AutoConfirmationStatus activateAutoConfirmation(@NotEmpty String controllerId, final String initiator,
final String remark);
/**
* Get the current state of auto-confirmation for a given controllerId
*
* @param controllerId
* to check the state for
* @return instance of {@link AutoConfirmationStatus} wrapped in an
* {@link Optional}. Present if active and empty if disabled.
*/
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_TARGET)
Optional<AutoConfirmationStatus> getStatus(@NotEmpty String controllerId);
/**
* Auto confirm active actions for a specific controller ID having the
* {@link Action.Status#WAIT_FOR_CONFIRMATION} status.
*
* @param controllerId
* to confirm actions for
* @return a list of confirmed actions
*/
@PreAuthorize(SpPermission.SpringEvalExpressions.IS_CONTROLLER_OR_HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
List<Action> autoConfirmActiveActions(@NotEmpty String controllerId);
/**
* Confirm a given action to put it from
* {@link Action.Status#WAIT_FOR_CONFIRMATION} to {@link Action.Status#RUNNING}
* state.
*
* @param actionId
* mandatory to know which action to confirm
* @param code
* optional value to specify a code for the created action status
* @param messages
* optional value to specify message for the created action status
*/
@PreAuthorize(SpPermission.SpringEvalExpressions.IS_CONTROLLER_OR_HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
Action confirmAction(long actionId, Integer code, Collection<String> messages);
/**
* Deny a given action and leave it in
* {@link Action.Status#WAIT_FOR_CONFIRMATION} state.
*
* @param actionId
* mandatory to know which action to deny
* @param code
* optional value to specify a code for the created action status
* @param messages
* optional value to specify message for the created action status
*/
@PreAuthorize(SpPermission.SpringEvalExpressions.IS_CONTROLLER_OR_HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
Action denyAction(long actionId, Integer code, Collection<String> messages);
/**
* Deactivate auto confirmation for a specific controller id
*
* @param controllerId
* to disable auto confirmation for
*/
@PreAuthorize(SpPermission.SpringEvalExpressions.IS_CONTROLLER_OR_HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
void deactivateAutoConfirmation(@NotEmpty String controllerId);
}

View File

@@ -29,6 +29,7 @@ import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.Target;
@@ -508,4 +509,28 @@ public interface ControllerManagement {
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
Optional<Action> getInstalledActionByTarget(@NotEmpty String controllerId);
/**
* Activate auto confirmation for a given controllerId
*
* @param controllerId
* to activate auto-confirmation on
* @param initiator
* can be set optionally (fallback is the current acting security
* user)
* @param remark
* (optional) remark
* @return the persisted {@link AutoConfirmationStatus}
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
AutoConfirmationStatus activateAutoConfirmation(@NotEmpty String controllerId, String initiator, String remark);
/**
* Deactivate auto confirmation for a given controllerId
*
* @param controllerId
* to deactivate auto-confirmation on
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
void deactivateAutoConfirmation(@NotEmpty String controllerId);
}

View File

@@ -449,8 +449,8 @@ public interface DeploymentManagement {
Page<Action> findInActiveActionsByTarget(@NotNull Pageable pageable, @NotEmpty String controllerId);
/**
* Retrieves active {@link Action}s with highest weight that are assigned to
* a {@link Target}.
* 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
@@ -522,6 +522,8 @@ public interface DeploymentManagement {
*
* @param rolloutId
* the rollout the actions belong to
* @param distributionSetId
* to assign
* @param rolloutGroupParentId
* the parent rollout group the actions should reference. null
* references the first group

View File

@@ -108,27 +108,28 @@ public interface RolloutManagement {
/**
* Persists a new rollout entity. The filter within the
* {@link Rollout#getTargetFilterQuery()} is used to retrieve the targets
* which are effected by this rollout to create. The amount of groups will
* be defined as equally sized.
* {@link Rollout#getTargetFilterQuery()} is used to retrieve the targets which
* are effected by this rollout to create. The amount of groups will be defined
* as equally sized.
*
* The rollout is not started. Only the preparation of the rollout is done,
* creating and persisting all the necessary groups. The Rollout and the
* groups are persisted in {@link RolloutStatus#CREATING} and
* creating and persisting all the necessary groups. The Rollout and the groups
* are persisted in {@link RolloutStatus#CREATING} and
* {@link RolloutGroupStatus#CREATING}.
*
* The RolloutScheduler will start to assign targets to the groups. Once all
* targets have been assigned to the groups, the rollout status is changed
* to {@link RolloutStatus#READY} so it can be started with
* {@link #start(Rollout)}.
* targets have been assigned to the groups, the rollout status is changed to
* {@link RolloutStatus#READY} so it can be started with .
*
* @param create
* the rollout entity to create
* @param amountGroup
* the amount of groups to split the rollout into
* @param confirmationRequired
* if a confirmation is required by the device group(s) of the rollout
* @param conditions
* the rolloutgroup conditions and actions which should be
* applied for each {@link RolloutGroup}
* the rolloutgroup conditions and actions which should be applied
* for each {@link RolloutGroup}
* @return the persisted rollout.
*
* @throws EntityNotFoundException
@@ -140,22 +141,23 @@ public interface RolloutManagement {
* exceeded.
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE)
Rollout create(@NotNull @Valid RolloutCreate create, int amountGroup, @NotNull RolloutGroupConditions conditions);
Rollout create(@NotNull @Valid RolloutCreate create, int amountGroup, boolean confirmationRequired,
@NotNull RolloutGroupConditions conditions);
/**
* Persists a new rollout entity. The filter within the
* {@link Rollout#getTargetFilterQuery()} is used to filter the targets
* which are affected by this rollout. The given groups will be used to
* create the groups.
* {@link Rollout#getTargetFilterQuery()} is used to filter the targets which
* are affected by this rollout. The given groups will be used to create the
* groups.
*
* The rollout is not started. Only the preparation of the rollout is done,
* creating and persisting all the necessary groups. The Rollout and the
* groups are persisted in {@link RolloutStatus#CREATING} and
* creating and persisting all the necessary groups. The Rollout and the groups
* are persisted in {@link RolloutStatus#CREATING} and
* {@link RolloutGroupStatus#CREATING}.
*
* The RolloutScheduler will start to assign targets to the groups. Once all
* targets have been assigned to the groups, the rollout status is changed
* to {@link RolloutStatus#READY} so it can be started with
* targets have been assigned to the groups, the rollout status is changed to
* {@link RolloutStatus#READY} so it can be started with
* {@link #start(Rollout)}.
*
* @param rollout
@@ -163,9 +165,9 @@ public interface RolloutManagement {
* @param groups
* optional definition of groups
* @param conditions
* the rollout group conditions and actions which should be
* applied for each {@link RolloutGroup} if not defined by the
* RolloutGroup itself
* the rollout group conditions and actions which should be applied
* for each {@link RolloutGroup} if not defined by the RolloutGroup
* itself
* @return the persisted rollout.
*
* @throws EntityNotFoundException

View File

@@ -29,6 +29,8 @@ public class AutoAssignDistributionSetUpdate {
@Max(Action.WEIGHT_MAX)
private Integer weight;
private Boolean confirmationRequired;
/**
* Constructor
*
@@ -75,6 +77,19 @@ public class AutoAssignDistributionSetUpdate {
return this;
}
/**
* Specify initial confirmation state of resulting {@link Action}
*
* @param confirmationRequired
* if confirmation is required for this auto assignment (considered
* with confirmation flow active)
* @return updated builder instance
*/
public AutoAssignDistributionSetUpdate confirmationRequired(final boolean confirmationRequired) {
this.confirmationRequired = confirmationRequired;
return this;
}
public Long getDsId() {
return dsId;
}
@@ -87,6 +102,10 @@ public class AutoAssignDistributionSetUpdate {
return weight;
}
public Boolean isConfirmationRequired() {
return confirmationRequired;
}
public long getTargetFilterId() {
return targetFilterId;
}

View File

@@ -63,6 +63,14 @@ public interface RolloutGroupCreate {
*/
RolloutGroupCreate conditions(RolloutGroupConditions conditions);
/**
* @param confirmationRequired
* if confirmation is required for this rollout group (considered
* with confirmation flow active)
* @return updated builder instance
*/
RolloutGroupCreate confirmationRequired(boolean confirmationRequired);
/**
* @return peek on current state of {@link RolloutGroup} in the builder
*/

View File

@@ -83,6 +83,17 @@ public interface TargetFilterQueryCreate {
*/
TargetFilterQueryCreate autoAssignWeight(Integer weight);
/**
* Specify initial confirmation state of resulting {@link Action} in auto
* assignment
*
* @param confirmationRequired
* if confirmation is required for configured auto assignment (considered
* with confirmation flow active)
* @return updated builder instance
*/
TargetFilterQueryCreate confirmationRequired(boolean confirmationRequired);
/**
* @return peek on current state of {@link TargetFilterQuery} in the builder
*/

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) 2022 Bosch.IO 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;
/**
* The {@link AutoConfirmationAlreadyActiveException} is thrown when auto
* confirmation is already active for a device but the
* {@link org.eclipse.hawkbit.repository.ConfirmationManagement#activateAutoConfirmation}
* is getting called.
*/
public class AutoConfirmationAlreadyActiveException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_REPO_AUTO_CONFIRMATION_ALREADY_ACTIVE;
/**
* Default constructor.
*/
public AutoConfirmationAlreadyActiveException() {
super(THIS_ERROR);
}
/**
* Parameterized constructor.
*
* @param cause
* of the exception
*/
public AutoConfirmationAlreadyActiveException(final Throwable cause) {
super(THIS_ERROR, cause);
}
/**
* Parameterized constructor for auto confirmation is already active for given
* controller ID
*
* @param controllerId
* of affected device
*/
public AutoConfirmationAlreadyActiveException(final String controllerId) {
super("Auto confirmation is already active for device " + controllerId, THIS_ERROR);
}
}

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2022 Bosch.IO 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 indicating that the confirmation feedback cannot be
* processed for a specific actions for different reasons which are listed as
* enum {@link Reason}.
*/
public class InvalidConfirmationFeedbackException extends AbstractServerRtException {
private static final long serialVersionUID = 1L;
private static final SpServerError THIS_ERROR = SpServerError.SP_CONFIRMATION_FEEDBACK_INVALID;
private final Reason reason;
protected InvalidConfirmationFeedbackException(final Reason reason) {
super(THIS_ERROR);
this.reason = reason;
}
public InvalidConfirmationFeedbackException(final Reason reason, final String message) {
super(message, THIS_ERROR);
this.reason = reason;
}
public Reason getReason() {
return reason;
}
public enum Reason {
ACTION_CLOSED, NOT_AWAITING_CONFIRMATION
}
}

View File

@@ -259,7 +259,12 @@ public interface Action extends TenantAwareBaseEntity {
* Action has been downloaded by the target and waiting for update to
* start.
*/
DOWNLOADED
DOWNLOADED,
/**
* Action is waiting to be confirmed by the user
*/
WAIT_FOR_CONFIRMATION
}
/**
@@ -330,4 +335,11 @@ public interface Action extends TenantAwareBaseEntity {
* @return true if maintenance window is available, else false.
*/
boolean isMaintenanceWindowAvailable();
/**
* Checks if the action is waiting for confirmation.
* @return true if the action is waiting for confirmation, else false
*/
boolean isWaitingConfirmation();
}

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.repository.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.io.Serializable;
/**
@@ -22,6 +24,8 @@ public class ActionProperties implements Serializable {
private String tenant;
private boolean maintenanceWindowAvailable;
private Action.Status status;
public ActionProperties() {
}
@@ -35,6 +39,7 @@ public class ActionProperties implements Serializable {
this.actionType = action.getActionType();
this.tenant = action.getTenant();
this.maintenanceWindowAvailable = action.isMaintenanceWindowAvailable();
this.status = action.getStatus();
}
public void setId(final Long id) {
@@ -68,4 +73,13 @@ public class ActionProperties implements Serializable {
public void setActionType(final Action.ActionType actionType) {
this.actionType = actionType;
}
public Action.Status getStatus() {
return status;
}
@JsonIgnore
public boolean isWaitingConfirmation() {
return status == Action.Status.WAIT_FOR_CONFIRMATION;
}
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2022 Bosch.IO 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.model;
/**
* {@link AutoConfirmationStatus} of a {@link Target}.
*
*/
public interface AutoConfirmationStatus extends BaseEntity {
/**
* For which target this status is corresponding to.
*
* @return the {@link Target}
*/
Target getTarget();
/**
* The user who initiated the auto confirmation. Will be set on auto
* confirmation activation and could be null. In this case the created_by can be
* considered as initiator.
*
* @return the user
*/
String getInitiator();
/**
* Unix timestamp of the activation.
*
* @return activation time as unix timestamp
*/
long getActivatedAt();
/**
* Optional value, which can be set during activation.
*
* @return the remark
*/
String getRemark();
/**
* Construct the action message based on the current status.
*
* @return the constructed message which can be used for the action status as a
* message
*/
String constructActionMessage();
}

View File

@@ -25,8 +25,8 @@ public class DeploymentRequest {
private final TargetWithActionType targetWithActionType;
/**
* Constructor that also accepts maintenance schedule parameters and checks
* for validity of the specified maintenance schedule.
* Constructor that also accepts maintenance schedule parameters and checks for
* validity of the specified maintenance schedule.
*
* @param controllerId
* for which the action is created.
@@ -48,18 +48,30 @@ public class DeploymentRequest {
* window, for example 00:30:00 for 30 minutes
* @param maintenanceWindowTimeZone
* is the time zone specified as +/-hh:mm offset from UTC, for
* example +02:00 for CET summer time and +00:00 for UTC. The
* start time of a maintenance window calculated based on the
* cron expression is relative to this time zone.
* example +02:00 for CET summer time and +00:00 for UTC. The start
* time of a maintenance window calculated based on the cron
* expression is relative to this time zone.
*
* @param confirmationRequired
* is a flag whether the confirmation should be required for the
* resulting {@link Action} or not. In case the confirmation is not
* required, the action will be automatically confirmed and put in
* the
* {@link org.eclipse.hawkbit.repository.model.Action.Status#RUNNING}
* state. Otherwise the confirmation flow will be triggered
* and the {@link Action} will stay in the
* {@link org.eclipse.hawkbit.repository.model.Action.Status#WAIT_FOR_CONFIRMATION}
* state until the confirmation is given. (Only considered
* with CONFIRMATION_FLOW active via tenant configuration)
* @throws InvalidMaintenanceScheduleException
* 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 Integer weight, final String maintenanceSchedule,
final String maintenanceWindowDuration, final String maintenanceWindowTimeZone) {
final String maintenanceWindowDuration, final String maintenanceWindowTimeZone,
final boolean confirmationRequired) {
this.targetWithActionType = new TargetWithActionType(controllerId, actionType, forceTime, weight,
maintenanceSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
maintenanceSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone, confirmationRequired);
this.distributionSetId = distributionSetId;
}
@@ -78,11 +90,11 @@ public class DeploymentRequest {
@Override
public String toString() {
return String.format(
"DeploymentRequest [controllerId=%s, distributionSetId=%d, actionType=%s, forceTime=%d, weight=%d, maintenanceSchedule=%s, maintenanceWindowDuration=%s, maintenanceWindowTimeZone=%s]",
"DeploymentRequest [controllerId=%s, distributionSetId=%d, actionType=%s, forceTime=%d, weight=%d, maintenanceSchedule=%s, maintenanceWindowDuration=%s, maintenanceWindowTimeZone=%s, confirmationRequired=%s]",
targetWithActionType.getControllerId(), getDistributionSetId(), targetWithActionType.getActionType(),
targetWithActionType.getForceTime(), targetWithActionType.getWeight(),
targetWithActionType.getMaintenanceSchedule(), targetWithActionType.getMaintenanceWindowDuration(),
targetWithActionType.getMaintenanceWindowTimeZone());
targetWithActionType.getMaintenanceWindowTimeZone(), targetWithActionType.isConfirmationRequired());
}
@Override

View File

@@ -24,6 +24,7 @@ public class DeploymentRequestBuilder {
private String maintenanceSchedule;
private String maintenanceWindowDuration;
private String maintenanceWindowTimeZone;
private boolean confirmationRequired;
/**
* Create a builder for a target distribution set assignment with the
@@ -100,6 +101,18 @@ public class DeploymentRequestBuilder {
return this;
}
/**
* Set if a confirmation is required.
*
* @param confirmationRequired
* if a confirmation is required for the {@link Action}
* @return builder
*/
public DeploymentRequestBuilder setConfirmationRequired(final boolean confirmationRequired) {
this.confirmationRequired = confirmationRequired;
return this;
}
/**
* build the request
*
@@ -107,7 +120,7 @@ public class DeploymentRequestBuilder {
*/
public DeploymentRequest build() {
return new DeploymentRequest(controllerId, distributionSetId, actionType, forceTime, weight,
maintenanceSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
maintenanceSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone, confirmationRequired);
}
}

View File

@@ -109,6 +109,12 @@ public interface RolloutGroup extends NamedEntity {
*/
float getTargetPercentage();
/**
* @return if a confirmation is required for the resulting actions (considered
* with confirmation flow active only)
*/
boolean isConfirmationRequired();
/**
* Rollout group state machine.
*

View File

@@ -98,6 +98,14 @@ public interface Target extends NamedEntity {
*/
PollStatus getPollStatus();
/**
* The auto confirmation status is present, when it's active for the target.
* Will only be considered in case the confirmation flow is active.
*
* @return the {@link AutoConfirmationStatus} if activated
*/
AutoConfirmationStatus getAutoConfirmationStatus();
/**
* @return <code>true</code> if the {@link Target} has not jet provided
* {@link #getControllerAttributes()}.

View File

@@ -81,4 +81,10 @@ public interface TargetFilterQuery extends TenantAwareBaseEntity {
* @return the user that triggered the auto assignment
*/
String getAutoAssignInitiatedBy();
/**
* @return if confirmation is required for configured auto assignment
* (considered with confirmation flow active)
*/
boolean isConfirmationRequired();
}

View File

@@ -30,6 +30,7 @@ public class TargetWithActionType {
private String maintenanceSchedule;
private String maintenanceWindowDuration;
private String maintenanceWindowTimeZone;
private final boolean confirmationRequired;
/**
* Constructor that uses {@link ActionType#FORCED}
@@ -38,7 +39,7 @@ public class TargetWithActionType {
* ID if the controller
*/
public TargetWithActionType(final String controllerId) {
this(controllerId, ActionType.FORCED, 0, null);
this(controllerId, ActionType.FORCED, 0, null, false);
}
/**
@@ -49,17 +50,22 @@ public class TargetWithActionType {
* @param actionType
* specified for the action.
* @param forceTime
* after that point in time the action is exposed as forced in
* case the type is {@link ActionType#TIMEFORCED}
* 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 confirmationRequired
* sets the confirmation required flag when starting the
* {@link Action}
*/
public TargetWithActionType(final String controllerId, final ActionType actionType, final long forceTime,
final Integer weight) {
public TargetWithActionType(
final String controllerId, final ActionType actionType, final long forceTime,
final Integer weight, final boolean confirmationRequired) {
this.controllerId = controllerId;
this.actionType = actionType != null ? actionType : ActionType.FORCED;
this.forceTime = forceTime;
this.weight = weight;
this.confirmationRequired = confirmationRequired;
}
/**
@@ -93,8 +99,8 @@ public class TargetWithActionType {
*/
public TargetWithActionType(final String controllerId, final ActionType actionType, final long forceTime,
final Integer weight, final String maintenanceSchedule, final String maintenanceWindowDuration,
final String maintenanceWindowTimeZone) {
this(controllerId, actionType, forceTime, weight);
final String maintenanceWindowTimeZone, final boolean confirmationRequired) {
this(controllerId, actionType, forceTime, weight, confirmationRequired);
this.maintenanceSchedule = maintenanceSchedule;
this.maintenanceWindowDuration = maintenanceWindowDuration;
@@ -152,18 +158,27 @@ public class TargetWithActionType {
return maintenanceWindowTimeZone;
}
/**
* Return if a confirmation is required for this assignment (depends on confirmation flow active)
*
* @return the flag
*/
public boolean isConfirmationRequired() {
return confirmationRequired;
}
@Override
public String toString() {
return "TargetWithActionType [controllerId=" + controllerId + ", actionType=" + getActionType() + ", forceTime="
+ getForceTime() + ", weight=" + getWeight() + ", maintenanceSchedule=" + getMaintenanceSchedule()
+ ", maintenanceWindowDuration=" + getMaintenanceWindowDuration() + ", maintenanceWindowTimeZone="
+ getMaintenanceWindowTimeZone() + "]";
+ getMaintenanceWindowTimeZone() + ", confirmationRequired=" + isConfirmationRequired() + "]";
}
@Override
public int hashCode() {
return Objects.hash(actionType, controllerId, forceTime, weight, maintenanceSchedule, maintenanceWindowDuration,
maintenanceWindowTimeZone);
return Objects.hash(actionType, controllerId, forceTime, weight, confirmationRequired, maintenanceSchedule,
maintenanceWindowDuration, maintenanceWindowTimeZone);
}
@SuppressWarnings("squid:S1067")
@@ -181,8 +196,10 @@ 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(weight, other.weight)
&& Objects.equals(confirmationRequired, other.confirmationRequired)
&& Objects.equals(maintenanceSchedule, other.maintenanceSchedule)
&& Objects.equals(maintenanceWindowDuration, other.maintenanceWindowDuration)
&& Objects.equals(maintenanceWindowTimeZone, other.maintenanceWindowTimeZone);
}
}

View File

@@ -161,6 +161,7 @@ public class TotalTargetCountStatus {
case RUNNING:
case WARNING:
case DOWNLOAD:
case WAIT_FOR_CONFIRMATION:
case CANCELING:
return Status.RUNNING;
case DOWNLOADED:

View File

@@ -152,6 +152,11 @@ public class TenantConfigurationProperties {
*/
public static final String BATCH_ASSIGNMENTS_ENABLED = "batch.assignments.enabled";
/**
* Switch to enable/disable the user-confirmation flow
*/
public static final String USER_CONFIRMATION_ENABLED = "user.confirmation.flow.enabled";
private String keyName;
private String defaultValue = "";
private Class<?> dataType = String.class;

View File

@@ -0,0 +1,64 @@
/**
* 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.utils;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.USER_CONFIRMATION_ENABLED;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.security.SystemSecurityContext;
/**
* A collection of static helper methods for the tenant configuration
*/
public final class TenantConfigHelper {
private final TenantConfigurationManagement tenantConfigurationManagement;
private final SystemSecurityContext systemSecurityContext;
private TenantConfigHelper(final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
this.systemSecurityContext = systemSecurityContext;
this.tenantConfigurationManagement = tenantConfigurationManagement;
}
/**
* Setting the context of the tenant.
*
* @param systemSecurityContext
* Security context used to get the tenant and for execution
* @param tenantConfigurationManagement
* to get the value from
* @return is active
*/
public static TenantConfigHelper usingContext(final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
return new TenantConfigHelper(systemSecurityContext, tenantConfigurationManagement);
}
/**
* Is multi-assignments enabled for the current tenant
*
* @return is active
*/
public boolean isMultiAssignmentsEnabled() {
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
.getConfigurationValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class).getValue());
}
/**
* Is confirmation flow enabled for the current tenant
*
* @return is enabled
*/
public boolean isConfirmationFlowEnabled() {
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
.getConfigurationValue(USER_CONFIRMATION_ENABLED, Boolean.class).getValue());
}
}