Remove Rollout(Group) builders (#2603)

* Fix entityManager.merge for ds and sm

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>

* Remove Rollout(Group) builders

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>

* Remove EntityFactory

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>

---------

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-08-11 14:01:03 +03:00
committed by GitHub
parent 861483f0d6
commit 124fef189e
66 changed files with 776 additions and 1753 deletions

View File

@@ -175,26 +175,17 @@ public class ObjectCopyUtil {
} }
@NotNull @NotNull
private static Method getMethod(final Class<?> clazz, final String methodName, final Class<?> parameterType) private static Method getMethod(final Class<?> clazz, final String methodName, final Class<?> parameterType) throws NoSuchMethodException {
throws NoSuchMethodException {
try { try {
return getMethod(clazz, clazz, methodName, parameterType); return getMethod(clazz, clazz, methodName, parameterType);
} catch (final NoSuchMethodException e) { } catch (final NoSuchMethodException e) {
if (parameterType == Boolean.class) { final Method assignable = getMethodAssignable(clazz, methodName, parameterType);
try { if (assignable != null) {
return getMethod(clazz, methodName, boolean.class); return assignable;
} catch (final NoSuchMethodException e2) { }
throw e; final Method moreSpecific = getMethodMoreSpecific(clazz, methodName, parameterType);
} if (moreSpecific != null) {
} else { return moreSpecific;
final Method assignable = getMethodAssignable(clazz, methodName, parameterType);
if (assignable != null) {
return assignable;
}
final Method moreSpecific = getMethodMoreSpecific(clazz, methodName, parameterType);
if (moreSpecific != null) {
return moreSpecific;
}
} }
throw e; throw e;
} }
@@ -218,11 +209,26 @@ public class ObjectCopyUtil {
} }
} }
@SuppressWarnings("java:S3011") // low-level, reflection utility. intentionally changes the accessibility // java:S3011 - low-level, reflection utility. intentionally changes the accessibility
// java:S3776 - complexity is due to reflection and dynamic method invocation
@SuppressWarnings({"java:S3011", "java:S3776"})
private static Method getMethodAssignable(final Class<?> clazz, final String methodName, final Class<?> parameterType) { private static Method getMethodAssignable(final Class<?> clazz, final String methodName, final Class<?> parameterType) {
return Arrays.stream(clazz.getDeclaredMethods()) return Arrays.stream(clazz.getDeclaredMethods())
.filter(method -> methodName.equals(method.getName())) .filter(method -> methodName.equals(method.getName()))
.filter(method -> method.getParameterCount() == 1 && method.getParameterTypes()[0].isAssignableFrom(parameterType)) .filter(method -> {
if (method.getParameterCount() == 1) {
if (method.getParameterTypes()[0].isAssignableFrom(parameterType)) {
return true;
}
if ((parameterType == boolean.class && method.getParameterTypes()[0] == Boolean.class) ||
(parameterType == Boolean.class && method.getParameterTypes()[0] == boolean.class) ||
(parameterType == long.class && method.getParameterTypes()[0] == Long.class) ||
(parameterType == Long.class && method.getParameterTypes()[0] == long.class)) {
return true; // in/out boxing
}
}
return false;
})
.findFirst() .findFirst()
.map(method -> { .map(method -> {
method.setAccessible(true); method.setAccessible(true);

View File

@@ -21,8 +21,6 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.artifact.model.DbArtifact;
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrlHandler;
import org.eclipse.hawkbit.audit.AuditLog; import org.eclipse.hawkbit.audit.AuditLog;
import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback; import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback;
import org.eclipse.hawkbit.ddi.json.model.DdiActionHistory; import org.eclipse.hawkbit.ddi.json.model.DdiActionHistory;
@@ -49,11 +47,11 @@ import org.eclipse.hawkbit.ddi.rest.api.DdiRootControllerRestApi;
import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ConfirmationManagement; import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.UpdateMode;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate; import org.eclipse.hawkbit.repository.artifact.model.DbArtifact;
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrlHandler;
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent; import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNotFoundException; import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNotFoundException;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
@@ -61,6 +59,8 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException; import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException;
import org.eclipse.hawkbit.repository.exception.SoftwareModuleNotAssignedToTargetException; import org.eclipse.hawkbit.repository.exception.SoftwareModuleNotAssignedToTargetException;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate.ActionStatusCreateBuilder;
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;
import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.Artifact;
@@ -105,7 +105,6 @@ public class DdiRootController implements DdiRootControllerRestApi {
private final ApplicationEventPublisher eventPublisher; private final ApplicationEventPublisher eventPublisher;
private final HawkbitSecurityProperties securityProperties; private final HawkbitSecurityProperties securityProperties;
private final TenantAware tenantAware; private final TenantAware tenantAware;
private final EntityFactory entityFactory;
@SuppressWarnings("java:S107") @SuppressWarnings("java:S107")
public DdiRootController( public DdiRootController(
@@ -113,7 +112,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
final ArtifactManagement artifactManagement, final ArtifactUrlHandler artifactUrlHandler, final ArtifactManagement artifactManagement, final ArtifactUrlHandler artifactUrlHandler,
final SystemManagement systemManagement, final SystemManagement systemManagement,
final ApplicationEventPublisher eventPublisher, final ApplicationEventPublisher eventPublisher,
final HawkbitSecurityProperties securityProperties, final TenantAware tenantAware, final EntityFactory entityFactory) { final HawkbitSecurityProperties securityProperties, final TenantAware tenantAware) {
this.controllerManagement = controllerManagement; this.controllerManagement = controllerManagement;
this.confirmationManagement = confirmationManagement; this.confirmationManagement = confirmationManagement;
this.artifactManagement = artifactManagement; this.artifactManagement = artifactManagement;
@@ -122,7 +121,6 @@ public class DdiRootController implements DdiRootControllerRestApi {
this.eventPublisher = eventPublisher; this.eventPublisher = eventPublisher;
this.securityProperties = securityProperties; this.securityProperties = securityProperties;
this.tenantAware = tenantAware; this.tenantAware = tenantAware;
this.entityFactory = entityFactory;
} }
@Override @Override
@@ -334,7 +332,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
final Target target = findTarget(controllerId); final Target target = findTarget(controllerId);
final Action action = findActionForTarget(actionId, target); final Action action = findActionForTarget(actionId, target);
controllerManagement.addCancelActionStatus(generateActionCancelStatus(feedback, target, action.getId(), entityFactory)); controllerManagement.addCancelActionStatus(generateActionCancelStatus(feedback, target, action.getId()));
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
} }
@@ -504,8 +502,9 @@ public class DdiRootController implements DdiRootControllerRestApi {
} }
private static ActionStatusCreate generateActionCancelStatus( private static ActionStatusCreate generateActionCancelStatus(
final DdiActionFeedback feedback, final Target target, final Long actionId, final EntityFactory entityFactory) { final DdiActionFeedback feedback, final Target target, final Long actionId) {
final ActionStatusCreate actionStatusCreate = entityFactory.actionStatus().create(actionId).occurredAt(feedback.getTimestamp()); final ActionStatusCreateBuilder actionStatusCreate = ActionStatusCreate.builder()
.actionId(actionId).occurredAt(feedback.getTimestamp());
final List<String> messages = new ArrayList<>(); final List<String> messages = new ArrayList<>();
final Status status; final Status status;
switch (feedback.getStatus().getExecution()) { switch (feedback.getStatus().getExecution()) {
@@ -540,7 +539,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
messages.add("Device reported status code: " + code); messages.add("Device reported status code: " + code);
} }
return actionStatusCreate.status(status).messages(messages); return actionStatusCreate.status(status).messages(messages).build();
} }
private static Status handleCancelClosedCase(final DdiActionFeedback feedback, final List<String> messages) { private static Status handleCancelClosedCase(final DdiActionFeedback feedback, final List<String> messages) {
@@ -604,14 +603,16 @@ public class DdiRootController implements DdiRootControllerRestApi {
.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), module) .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), module)
.orElseThrow(() -> new SoftwareModuleNotAssignedToTargetException(module, target.getControllerId())); .orElseThrow(() -> new SoftwareModuleNotAssignedToTargetException(module, target.getControllerId()));
return controllerManagement.addInformationalActionStatus( return controllerManagement.addInformationalActionStatus(
entityFactory.actionStatus() ActionStatusCreate.builder()
.create(action.getId()) .actionId(action.getId())
.status(Status.DOWNLOAD) .status(Status.DOWNLOAD)
.message(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads " + request.getRequestURI())); .messages(List.of(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads " + request.getRequestURI()))
.build());
} }
private ActionStatusCreate generateUpdateStatus(final DdiActionFeedback feedback, final String controllerId, final Long actionId) { private ActionStatusCreate generateUpdateStatus(final DdiActionFeedback feedback, final String controllerId, final Long actionId) {
final ActionStatusCreate actionStatusCreate = entityFactory.actionStatus().create(actionId).occurredAt(feedback.getTimestamp()); final ActionStatusCreateBuilder actionStatusCreate = ActionStatusCreate.builder()
.actionId(actionId).occurredAt(feedback.getTimestamp());
final List<String> messages = new ArrayList<>(); final List<String> messages = new ArrayList<>();
if (!CollectionUtils.isEmpty(feedback.getStatus().getDetails())) { if (!CollectionUtils.isEmpty(feedback.getStatus().getDetails())) {
@@ -664,7 +665,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
} }
} }
return actionStatusCreate.status(status).messages(messages); return actionStatusCreate.status(status).messages(messages).build();
} }
private Status handleDefaultCase( private Status handleDefaultCase(

View File

@@ -39,14 +39,14 @@ import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.ConfirmationManagement; import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.UpdateMode;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate.ActionStatusCreateBuilder;
import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionProperties; import org.eclipse.hawkbit.repository.model.ActionProperties;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -81,7 +81,6 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
private final AmqpMessageDispatcherService amqpMessageDispatcherService; private final AmqpMessageDispatcherService amqpMessageDispatcherService;
private final ConfirmationManagement confirmationManagement; private final ConfirmationManagement confirmationManagement;
private final EntityFactory entityFactory;
private final TenantConfigurationManagement tenantConfigurationManagement; private final TenantConfigurationManagement tenantConfigurationManagement;
private final SystemSecurityContext systemSecurityContext; private final SystemSecurityContext systemSecurityContext;
private ControllerManagement controllerManagement; private ControllerManagement controllerManagement;
@@ -92,7 +91,6 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
* @param rabbitTemplate for converting messages * @param rabbitTemplate for converting messages
* @param amqpMessageDispatcherService to sending events to DMF client * @param amqpMessageDispatcherService to sending events to DMF client
* @param controllerManagement for target repo access * @param controllerManagement for target repo access
* @param entityFactory to create entities
* @param systemSecurityContext the system Security Context * @param systemSecurityContext the system Security Context
* @param tenantConfigurationManagement the tenant configuration Management * @param tenantConfigurationManagement the tenant configuration Management
* @param confirmationManagement the confirmation management * @param confirmationManagement the confirmation management
@@ -100,13 +98,11 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
public AmqpMessageHandlerService( public AmqpMessageHandlerService(
final RabbitTemplate rabbitTemplate, final RabbitTemplate rabbitTemplate,
final AmqpMessageDispatcherService amqpMessageDispatcherService, final AmqpMessageDispatcherService amqpMessageDispatcherService,
final ControllerManagement controllerManagement, final EntityFactory entityFactory, final ControllerManagement controllerManagement, final SystemSecurityContext systemSecurityContext,
final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement, final ConfirmationManagement confirmationManagement) { final TenantConfigurationManagement tenantConfigurationManagement, final ConfirmationManagement confirmationManagement) {
super(rabbitTemplate); super(rabbitTemplate);
this.amqpMessageDispatcherService = amqpMessageDispatcherService; this.amqpMessageDispatcherService = amqpMessageDispatcherService;
this.controllerManagement = controllerManagement; this.controllerManagement = controllerManagement;
this.entityFactory = entityFactory;
this.systemSecurityContext = systemSecurityContext; this.systemSecurityContext = systemSecurityContext;
this.tenantConfigurationManagement = tenantConfigurationManagement; this.tenantConfigurationManagement = tenantConfigurationManagement;
this.confirmationManagement = confirmationManagement; this.confirmationManagement = confirmationManagement;
@@ -459,14 +455,15 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
} else if (actionUpdateStatus.getActionStatus() == DmfActionStatus.DENIED) { } else if (actionUpdateStatus.getActionStatus() == DmfActionStatus.DENIED) {
updatedAction = confirmationManagement.denyAction(action.getId(), actionUpdateStatus.getCode(), messages); updatedAction = confirmationManagement.denyAction(action.getId(), actionUpdateStatus.getCode(), messages);
} else { } else {
final ActionStatusCreate actionStatus = entityFactory.actionStatus().create(action.getId()).status(status).messages(messages); final ActionStatusCreateBuilder actionStatus = ActionStatusCreate.builder()
.actionId(action.getId()).status(status).messages(messages);
Optional.ofNullable(actionUpdateStatus.getCode()).ifPresent(code -> { Optional.ofNullable(actionUpdateStatus.getCode()).ifPresent(code -> {
actionStatus.code(code); actionStatus.code(code);
actionStatus.message("Device reported status code: " + code); actionStatus.messages(List.of("Device reported status code: " + code));
}); });
updatedAction = Status.CANCELED == status || Status.CANCEL_REJECTED == status updatedAction = Status.CANCELED == status || Status.CANCEL_REJECTED == status
? controllerManagement.addCancelActionStatus(actionStatus) ? controllerManagement.addCancelActionStatus(actionStatus.build())
: controllerManagement.addUpdateActionStatus(actionStatus); : controllerManagement.addUpdateActionStatus(actionStatus.build());
} }
if (shouldTargetProceed(updatedAction) || actionUpdateStatus.getActionStatus() == DmfActionStatus.CONFIRMED) { if (shouldTargetProceed(updatedAction) || actionUpdateStatus.getActionStatus() == DmfActionStatus.CONFIRMED) {

View File

@@ -24,7 +24,6 @@ import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TargetManagement;
@@ -220,7 +219,6 @@ public class DmfApiConfiguration {
* @param rabbitTemplate for converting messages * @param rabbitTemplate for converting messages
* @param amqpMessageDispatcherService to sending events to DMF client * @param amqpMessageDispatcherService to sending events to DMF client
* @param controllerManagement for target repo access * @param controllerManagement for target repo access
* @param entityFactory to create entities
* @return handler service bean * @return handler service bean
*/ */
@Bean @Bean
@@ -228,13 +226,12 @@ public class DmfApiConfiguration {
public AmqpMessageHandlerService amqpMessageHandlerService( public AmqpMessageHandlerService amqpMessageHandlerService(
final RabbitTemplate rabbitTemplate, final RabbitTemplate rabbitTemplate,
final AmqpMessageDispatcherService amqpMessageDispatcherService, final AmqpMessageDispatcherService amqpMessageDispatcherService,
final ControllerManagement controllerManagement, final EntityFactory entityFactory, final ControllerManagement controllerManagement, final SystemSecurityContext systemSecurityContext,
final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement, final TenantConfigurationManagement tenantConfigurationManagement,
final ConfirmationManagement confirmationManagement) { final ConfirmationManagement confirmationManagement) {
return new AmqpMessageHandlerService( return new AmqpMessageHandlerService(
rabbitTemplate, amqpMessageDispatcherService, controllerManagement, rabbitTemplate, amqpMessageDispatcherService, controllerManagement,
entityFactory, systemSecurityContext, tenantConfigurationManagement, confirmationManagement); systemSecurityContext, tenantConfigurationManagement, confirmationManagement);
} }
/** /**

View File

@@ -37,14 +37,9 @@ import org.eclipse.hawkbit.dmf.json.model.DmfCreateThing;
import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode; import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode;
import org.eclipse.hawkbit.repository.ConfirmationManagement; import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.UpdateMode;
import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusBuilder;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
import org.eclipse.hawkbit.repository.SecurityTokenGeneratorHolder; import org.eclipse.hawkbit.repository.SecurityTokenGeneratorHolder;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.ActionProperties; import org.eclipse.hawkbit.repository.model.ActionProperties;
@@ -96,8 +91,6 @@ class AmqpMessageHandlerServiceTest {
@Mock @Mock
private ConfirmationManagement confirmationManagementMock; private ConfirmationManagement confirmationManagementMock;
@Mock @Mock
private EntityFactory entityFactoryMock;
@Mock
private TenantConfigurationManagement tenantConfigurationManagement; private TenantConfigurationManagement tenantConfigurationManagement;
@Mock @Mock
private RabbitTemplate rabbitTemplate; private RabbitTemplate rabbitTemplate;
@@ -137,7 +130,7 @@ class AmqpMessageHandlerServiceTest {
final SystemSecurityContext systemSecurityContext = new SystemSecurityContext(tenantAware); final SystemSecurityContext systemSecurityContext = new SystemSecurityContext(tenantAware);
amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherServiceMock, amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherServiceMock,
controllerManagementMock, entityFactoryMock, systemSecurityContext, tenantConfigurationManagement, controllerManagementMock, systemSecurityContext, tenantConfigurationManagement,
confirmationManagementMock); confirmationManagementMock);
} }
@@ -439,12 +432,6 @@ class AmqpMessageHandlerServiceTest {
final Message message = createMessage(actionUpdateStatus, messageProperties); final Message message = createMessage(actionUpdateStatus, messageProperties);
final Action action = mock(Action.class); final Action action = mock(Action.class);
when(action.getId()).thenReturn(2L); when(action.getId()).thenReturn(2L);
final ActionStatusBuilder builder = mock(ActionStatusBuilder.class);
final ActionStatusCreate create = mock(ActionStatusCreate.class);
when(builder.create(2L)).thenReturn(create);
when(create.status(any())).thenReturn(create);
when(create.messages(any())).thenReturn(create);
when(entityFactoryMock.actionStatus()).thenReturn(builder);
when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.of(action)); when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.of(action));
when(controllerManagementMock.addUpdateActionStatus(any())).thenThrow(new AssignmentQuotaExceededException()); when(controllerManagementMock.addUpdateActionStatus(any())).thenThrow(new AssignmentQuotaExceededException());
@@ -464,12 +451,6 @@ class AmqpMessageHandlerServiceTest {
final Action action = createActionWithTarget(22L); final Action action = createActionWithTarget(22L);
when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.of(action)); when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.of(action));
when(controllerManagementMock.addUpdateActionStatus(any())).thenReturn(action); when(controllerManagementMock.addUpdateActionStatus(any())).thenReturn(action);
final ActionStatusBuilder builder = mock(ActionStatusBuilder.class);
final ActionStatusCreate create = mock(ActionStatusCreate.class);
when(builder.create(22L)).thenReturn(create);
when(create.status(any())).thenReturn(create);
when(create.messages(any())).thenReturn(create);
when(entityFactoryMock.actionStatus()).thenReturn(builder);
// for the test the same action can be used // for the test the same action can be used
when(controllerManagementMock.findActiveActionWithHighestWeight(any())).thenReturn(Optional.of(action)); when(controllerManagementMock.findActiveActionWithHighestWeight(any())).thenReturn(Optional.of(action));
@@ -502,8 +483,6 @@ class AmqpMessageHandlerServiceTest {
final Action action = createActionWithTarget(22L); final Action action = createActionWithTarget(22L);
when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.of(action)); when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.of(action));
when(controllerManagementMock.addUpdateActionStatus(any())).thenReturn(action); when(controllerManagementMock.addUpdateActionStatus(any())).thenReturn(action);
final ActionStatusBuilder builder = new JpaActionStatusBuilder();
when(entityFactoryMock.actionStatus()).thenReturn(builder);
// for the test the same action can be used // for the test the same action can be used
when(controllerManagementMock.findActiveActionWithHighestWeight(any())).thenReturn(Optional.of(action)); when(controllerManagementMock.findActiveActionWithHighestWeight(any())).thenReturn(Optional.of(action));
@@ -517,16 +496,6 @@ class AmqpMessageHandlerServiceTest {
// test // test
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST);
final ArgumentCaptor<ActionStatusCreate> actionPropertiesCaptor = ArgumentCaptor.forClass(ActionStatusCreate.class);
verify(controllerManagementMock, times(1)).addUpdateActionStatus(actionPropertiesCaptor.capture());
final JpaActionStatus jpaActionStatus = (JpaActionStatus) actionPropertiesCaptor.getValue().build();
assertThat(jpaActionStatus.getCode()).as("Action status for reported code is missing").contains(12);
assertThat(jpaActionStatus.getMessages())
.as("Action status message for reported code is missing")
.contains("Device reported status code: 12");
} }
/** /**

View File

@@ -32,13 +32,12 @@ import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtRolloutMapper;
import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTargetMapper; import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTargetMapper;
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility; import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
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.RolloutManagement.Create;
import org.eclipse.hawkbit.repository.RolloutManagement.GroupCreate;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -67,20 +66,18 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
private final RolloutGroupManagement rolloutGroupManagement; private final RolloutGroupManagement rolloutGroupManagement;
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement; private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
private final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement; private final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement;
private final EntityFactory entityFactory;
private final TenantConfigHelper tenantConfigHelper; private final TenantConfigHelper tenantConfigHelper;
MgmtRolloutResource( MgmtRolloutResource(
final RolloutManagement rolloutManagement, final RolloutGroupManagement rolloutGroupManagement, final RolloutManagement rolloutManagement, final RolloutGroupManagement rolloutGroupManagement,
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement, final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement, final EntityFactory entityFactory, final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement,
final SystemSecurityContext systemSecurityContext, final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) { final TenantConfigurationManagement tenantConfigurationManagement) {
this.rolloutManagement = rolloutManagement; this.rolloutManagement = rolloutManagement;
this.rolloutGroupManagement = rolloutGroupManagement; this.rolloutGroupManagement = rolloutGroupManagement;
this.distributionSetManagement = distributionSetManagement; this.distributionSetManagement = distributionSetManagement;
this.targetFilterQueryManagement = targetFilterQueryManagement; this.targetFilterQueryManagement = targetFilterQueryManagement;
this.entityFactory = entityFactory;
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement); this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
} }
@@ -99,7 +96,7 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
: rolloutManagement.findByRsqlWithDetailedStatus(rsqlParam, false, pageable); : rolloutManagement.findByRsqlWithDetailedStatus(rsqlParam, false, pageable);
rest = MgmtRolloutMapper.toResponseRolloutWithDetails(rollouts.getContent()); rest = MgmtRolloutMapper.toResponseRolloutWithDetails(rollouts.getContent());
} else { } else {
rollouts = rsqlParam == null rollouts = rsqlParam == null
? rolloutManagement.findAll(false, pageable) ? rolloutManagement.findAll(false, pageable)
: rolloutManagement.findByRsql(rsqlParam, false, pageable); : rolloutManagement.findByRsql(rsqlParam, false, pageable);
rest = MgmtRolloutMapper.toResponseRollout(rollouts.getContent()); rest = MgmtRolloutMapper.toResponseRollout(rollouts.getContent());
@@ -124,10 +121,9 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
throw new RSQLParameterSyntaxException("Cannot create a Rollout with an empty target query filter!"); throw new RSQLParameterSyntaxException("Cannot create a Rollout with an empty target query filter!");
} }
targetFilterQueryManagement.verifyTargetFilterQuerySyntax(targetFilterQuery); targetFilterQueryManagement.verifyTargetFilterQuerySyntax(targetFilterQuery);
final DistributionSet distributionSet = distributionSetManagement final DistributionSet distributionSet = distributionSetManagement.getValidAndComplete(rolloutRequestBody.getDistributionSetId());
.getValidAndComplete(rolloutRequestBody.getDistributionSetId());
final RolloutGroupConditions rolloutGroupConditions = MgmtRolloutMapper.fromRequest(rolloutRequestBody, true); final RolloutGroupConditions rolloutGroupConditions = MgmtRolloutMapper.fromRequest(rolloutRequestBody, true);
final RolloutCreate create = MgmtRolloutMapper.fromRequest(entityFactory, rolloutRequestBody, distributionSet); final Create create = MgmtRolloutMapper.fromRequest(rolloutRequestBody, distributionSet);
final boolean confirmationFlowActive = tenantConfigHelper.isConfirmationFlowEnabled(); final boolean confirmationFlowActive = tenantConfigHelper.isConfirmationFlowEnabled();
final Rollout rollout; final Rollout rollout;
@@ -138,13 +134,11 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
if (rolloutRequestBody.getAmountGroups() != null) { if (rolloutRequestBody.getAmountGroups() != null) {
throw new ValidationException("Either 'amountGroups' or 'groups' must be defined in the request"); throw new ValidationException("Either 'amountGroups' or 'groups' must be defined in the request");
} }
final List<RolloutGroupCreate> rolloutGroups = rolloutRequestBody.getGroups().stream() final List<GroupCreate> rolloutGroups = rolloutRequestBody.getGroups().stream()
.map(mgmtRolloutGroup -> { .map(mgmtRolloutGroup -> MgmtRolloutMapper.fromRequest(
final boolean confirmationRequired = isConfirmationRequiredForGroup(mgmtRolloutGroup, mgmtRolloutGroup,
rolloutRequestBody).orElse(confirmationFlowActive); isConfirmationRequiredForGroup(mgmtRolloutGroup, rolloutRequestBody).orElse(confirmationFlowActive)))
return MgmtRolloutMapper.fromRequest(entityFactory, mgmtRolloutGroup) .toList();
.confirmationRequired(confirmationRequired);
}).toList();
rollout = rolloutManagement.create(create, rolloutGroups, rolloutGroupConditions); rollout = rolloutManagement.create(create, rolloutGroups, rolloutGroupConditions);
} else if (rolloutRequestBody.getAmountGroups() != null) { } else if (rolloutRequestBody.getAmountGroups() != null) {
final boolean confirmationRequired = rolloutRequestBody.getConfirmationRequired() == null final boolean confirmationRequired = rolloutRequestBody.getConfirmationRequired() == null
@@ -161,7 +155,7 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
@Override @Override
public ResponseEntity<MgmtRolloutResponseBody> update(final Long rolloutId, final MgmtRolloutRestRequestBodyPut rolloutUpdateBody) { public ResponseEntity<MgmtRolloutResponseBody> update(final Long rolloutId, final MgmtRolloutRestRequestBodyPut rolloutUpdateBody) {
final Rollout updated = rolloutManagement.update(MgmtRolloutMapper.fromRequest(entityFactory, rolloutUpdateBody, rolloutId)); final Rollout updated = rolloutManagement.update(MgmtRolloutMapper.fromRequest(rolloutUpdateBody, rolloutId));
return ResponseEntity.ok(MgmtRolloutMapper.toResponseRollout(updated, true)); return ResponseEntity.ok(MgmtRolloutMapper.toResponseRollout(updated, true));
} }
@@ -282,7 +276,7 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
throw new ValidationException("Rollout must be finished in order to be retried!"); throw new ValidationException("Rollout must be finished in order to be retried!");
} }
final RolloutCreate create = MgmtRolloutMapper.fromRetriedRollout(entityFactory, rolloutForRetry); final Create create = MgmtRolloutMapper.fromRetriedRollout(rolloutForRetry);
final RolloutGroupConditions groupConditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions groupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
final Rollout retriedRollout = rolloutManagement.create(create, 1, false, groupConditions, null); final Rollout retriedRollout = rolloutManagement.create(create, 1, false, groupConditions, null);

View File

@@ -25,7 +25,6 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetFilterQueryRestApi;
import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtDistributionSetMapper; import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtDistributionSetMapper;
import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTargetFilterQueryMapper; import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTargetFilterQueryMapper;
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility; import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.AutoAssignDistributionSetUpdate; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.AutoAssignDistributionSetUpdate;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
@@ -36,7 +35,6 @@ import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.utils.TenantConfigHelper; import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;

View File

@@ -25,7 +25,6 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi;
import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTagMapper; import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTagMapper;
import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTargetMapper; import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtTargetMapper;
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility; import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTagManagement; import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
@@ -38,7 +37,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;

View File

@@ -35,11 +35,11 @@ import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroup;
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroupResponseBody; import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroupResponseBody;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi; import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate; import org.eclipse.hawkbit.repository.RolloutManagement.Create;
import org.eclipse.hawkbit.repository.builder.RolloutCreate; import org.eclipse.hawkbit.repository.RolloutManagement.GroupCreate;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate; import org.eclipse.hawkbit.repository.RolloutManagement.Update;
import org.eclipse.hawkbit.repository.builder.RolloutUpdate; 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;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
@@ -125,49 +125,54 @@ public final class MgmtRolloutMapper {
return body; return body;
} }
public static RolloutCreate fromRequest( public static Create fromRequest(final MgmtRolloutRestRequestBodyPost restRequest, final DistributionSet distributionSet) {
final EntityFactory entityFactory, final MgmtRolloutRestRequestBodyPost restRequest, final DistributionSet distributionSet) { return Create.builder()
return entityFactory.rollout().create()
.name(restRequest.getName()) .name(restRequest.getName())
.description(restRequest.getDescription()) .description(restRequest.getDescription())
.distributionSetId(distributionSet) .distributionSet(distributionSet)
.targetFilterQuery(restRequest.getTargetFilterQuery()) .targetFilterQuery(restRequest.getTargetFilterQuery())
.actionType(MgmtRestModelMapper.convertActionType(restRequest.getType())) .actionType(Optional.ofNullable(MgmtRestModelMapper.convertActionType(restRequest.getType())).orElse(Action.ActionType.FORCED))
.forcedTime(restRequest.getForcetime()).startAt(restRequest.getStartAt()) .forcedTime(restRequest.getForcetime()).startAt(restRequest.getStartAt())
.weight(restRequest.getWeight()) .weight(restRequest.getWeight())
.dynamic(restRequest.isDynamic()); .dynamic(restRequest.isDynamic())
.build();
} }
public static RolloutUpdate fromRequest( public static Update fromRequest(final MgmtRolloutRestRequestBodyPut restRequest, final long rolloutId) {
final EntityFactory entityFactory, final MgmtRolloutRestRequestBodyPut restRequest, final long rolloutId) { return Update.builder().id(rolloutId)
return entityFactory.rollout().update(rolloutId)
.name(restRequest.getName()) .name(restRequest.getName())
.description(restRequest.getDescription()); .description(restRequest.getDescription())
.build();
} }
public static RolloutCreate fromRetriedRollout(final EntityFactory entityFactory, final Rollout rollout) { public static Create fromRetriedRollout(final Rollout rollout) {
return entityFactory.rollout().create() return Create.builder()
.name(rollout.getName().concat("_retry")) .name(rollout.getName().concat("_retry"))
.description(rollout.getDescription()) .description(rollout.getDescription())
.distributionSetId(rollout.getDistributionSet()) .distributionSet(rollout.getDistributionSet())
.targetFilterQuery("failedrollout==".concat(String.valueOf(rollout.getId()))) .targetFilterQuery("failedrollout==".concat(String.valueOf(rollout.getId())))
.actionType(rollout.getActionType()) .actionType(rollout.getActionType())
.forcedTime(rollout.getForcedTime()) .forcedTime(rollout.getForcedTime())
.startAt(rollout.getStartAt()) .startAt(rollout.getStartAt())
.weight(null); .weight(null)
.build();
} }
public static RolloutGroupCreate fromRequest(final EntityFactory entityFactory, final MgmtRolloutGroup restRequest) { public static GroupCreate fromRequest(final MgmtRolloutGroup restRequest, final boolean confirmationRequired) {
return entityFactory.rolloutGroup().create().name(restRequest.getName()) return GroupCreate.builder()
.name(restRequest.getName())
.description(restRequest.getDescription()).targetFilterQuery(restRequest.getTargetFilterQuery()) .description(restRequest.getDescription()).targetFilterQuery(restRequest.getTargetFilterQuery())
.targetPercentage(restRequest.getTargetPercentage()).conditions(fromRequest(restRequest, false)); .targetPercentage(restRequest.getTargetPercentage())
.conditions(fromRequest((AbstractMgmtRolloutConditionsEntity)restRequest, false))
.confirmationRequired(confirmationRequired)
.build();
} }
public static DynamicRolloutGroupTemplate fromRequest(final MgmtDynamicRolloutGroupTemplate restRequest) { public static RolloutManagement.DynamicRolloutGroupTemplate fromRequest(final MgmtDynamicRolloutGroupTemplate restRequest) {
if (restRequest == null) { if (restRequest == null) {
return null; return null;
} }
return DynamicRolloutGroupTemplate.builder() return RolloutManagement.DynamicRolloutGroupTemplate.builder()
.nameSuffix(Optional.ofNullable(restRequest.getNameSuffix()).orElse("")) .nameSuffix(Optional.ofNullable(restRequest.getNameSuffix()).orElse(""))
.targetCount(restRequest.getTargetCount()) .targetCount(restRequest.getTargetCount())
.build(); .build();

View File

@@ -23,7 +23,6 @@ import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTagRestApi; import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTagRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi; import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.TargetTagManagement; import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.Tag; import org.eclipse.hawkbit.repository.model.Tag;

View File

@@ -23,8 +23,6 @@ import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQueryReq
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi; import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetFilterQueryRestApi; import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetFilterQueryRestApi;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.AutoAssignDistributionSetUpdate; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.AutoAssignDistributionSetUpdate;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.Create; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.Create;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;

View File

@@ -17,12 +17,11 @@ import java.util.Map;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.RolloutManagement.GroupCreate;
import org.eclipse.hawkbit.repository.TargetManagement.Create; import org.eclipse.hawkbit.repository.TargetManagement.Create;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
import org.eclipse.hawkbit.repository.model.Target;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@@ -93,14 +92,14 @@ class JsonBuilder {
static String rolloutWithGroups(final String name, final String description, final Integer groupSize, static String rolloutWithGroups(final String name, final String description, final Integer groupSize,
final long distributionSetId, final String targetFilterQuery, final RolloutGroupConditions conditions, final long distributionSetId, final String targetFilterQuery, final RolloutGroupConditions conditions,
final List<RolloutGroup> groups) { final List<GroupCreate> groups) {
return rolloutWithGroups(name, description, groupSize, distributionSetId, targetFilterQuery, conditions, groups, return rolloutWithGroups(name, description, groupSize, distributionSetId, targetFilterQuery, conditions, groups,
null, null, null); null, null, null);
} }
static String rolloutWithGroups(final String name, final String description, final Integer groupSize, static String rolloutWithGroups(final String name, final String description, final Integer groupSize,
final long distributionSetId, final String targetFilterQuery, final RolloutGroupConditions conditions, final long distributionSetId, final String targetFilterQuery, final RolloutGroupConditions conditions,
final List<RolloutGroup> groups, final String type, final Integer weight, final List<GroupCreate> groups, final String type, final Integer weight,
final Boolean confirmationRequired) { final Boolean confirmationRequired) {
final List<String> rolloutGroupsJson = groups.stream().map(JsonBuilder::rolloutGroup).toList(); final List<String> rolloutGroupsJson = groups.stream().map(JsonBuilder::rolloutGroup).toList();
return rollout( return rollout(
@@ -198,10 +197,14 @@ class JsonBuilder {
return json.toString(); return json.toString();
} }
static String rolloutGroup(final RolloutGroup rolloutGroup) { static String rolloutGroup(final GroupCreate create) {
return rolloutGroup(create, null);
}
static String rolloutGroup(final GroupCreate create, final RolloutGroup rolloutGroup) {
final RolloutGroupConditions conditions = getConditions(rolloutGroup); final RolloutGroupConditions conditions = getConditions(rolloutGroup);
return rolloutGroup(rolloutGroup.getName(), rolloutGroup.getDescription(), rolloutGroup.getTargetFilterQuery(), return rolloutGroup(create.getName(), create.getDescription(), create.getTargetFilterQuery(),
rolloutGroup.getTargetPercentage(), rolloutGroup.isConfirmationRequired(), conditions); create.getTargetPercentage(), create.isConfirmationRequired(), conditions);
} }
@@ -278,10 +281,14 @@ class JsonBuilder {
} }
private static RolloutGroupConditions getConditions(final RolloutGroup rolloutGroup) { private static RolloutGroupConditions getConditions(final RolloutGroup rolloutGroup) {
return new RolloutGroupConditionBuilder() if (rolloutGroup == null) {
.errorCondition(rolloutGroup.getErrorCondition(), rolloutGroup.getErrorConditionExp()) return new RolloutGroupConditionBuilder().withDefaults().build();
.errorAction(rolloutGroup.getErrorAction(), rolloutGroup.getErrorActionExp()) } else {
.successAction(rolloutGroup.getSuccessAction(), rolloutGroup.getSuccessActionExp()) return new RolloutGroupConditionBuilder()
.successCondition(rolloutGroup.getSuccessCondition(), rolloutGroup.getSuccessConditionExp()).build(); .errorCondition(rolloutGroup.getErrorCondition(), rolloutGroup.getErrorConditionExp())
.errorAction(rolloutGroup.getErrorAction(), rolloutGroup.getErrorActionExp())
.successAction(rolloutGroup.getSuccessAction(), rolloutGroup.getSuccessActionExp())
.successCondition(rolloutGroup.getSuccessCondition(), rolloutGroup.getSuccessConditionExp()).build();
}
} }
} }

View File

@@ -210,8 +210,8 @@ class MgmtActionResourceTest extends AbstractManagementApiIntegrationTest {
// then simulate a status update with code 200 for the first action // then simulate a status update with code 200 for the first action
final Action action = actions.get(0); final Action action = actions.get(0);
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).code(200) controllerManagement.addUpdateActionStatus(Action.ActionStatusCreate.builder()
.message("Update succeeded").status(Status.FINISHED)); .actionId(action.getId()).code(200).messages(List.of("Update succeeded")).status(Status.FINISHED).build());
// verify that one result is returned if the actions are filtered for status code 200 // verify that one result is returned if the actions are filtered for status code 200
final String rsqlStatusCode = "lastStatusCode==200"; final String rsqlStatusCode = "lastStatusCode==200";
@@ -284,7 +284,7 @@ class MgmtActionResourceTest extends AbstractManagementApiIntegrationTest {
@Test @Test
void filterActionsByRollout() throws Exception { void filterActionsByRollout() throws Exception {
// prepare test // prepare test
final DistributionSet ds = testdataFactory.createDistributionSet(); final DistributionSet ds = testdataFactory.createDistributionSetLocked();
final Target target0 = testdataFactory.createTarget("t0"); final Target target0 = testdataFactory.createTarget("t0");
// manual assignment // manual assignment

View File

@@ -38,10 +38,14 @@ import org.awaitility.core.ConditionFactory;
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.mgmt.rest.resource.mapper.MgmtRestModelMapper; import org.eclipse.hawkbit.mgmt.rest.resource.mapper.MgmtRestModelMapper;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
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.RolloutManagement.Create;
import org.eclipse.hawkbit.repository.RolloutManagement.GroupCreate;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; 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.ActionStatusCreate;
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;
import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout;
@@ -90,6 +94,8 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
private RolloutGroupManagement rolloutGroupManagement; private RolloutGroupManagement rolloutGroupManagement;
@Autowired @Autowired
private RolloutTestApprovalStrategy approvalStrategy; private RolloutTestApprovalStrategy approvalStrategy;
@Autowired
private DistributionSetManagement distributionSetManagement;
/** /**
* Handles the GET request of retrieving a single rollout. * Handles the GET request of retrieving a single rollout.
@@ -105,12 +111,11 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create a running rollout for the created targets // create a running rollout for the created targets
final Rollout rollout = rolloutManagement.create( final Rollout rollout = rolloutManagement.create(
entityFactory Create.builder()
.rollout()
.create()
.name("rollout1") .name("rollout1")
.distributionSetId(dsA.getId()) .distributionSet(dsA)
.targetFilterQuery("controllerId==rollout*"), .targetFilterQuery("controllerId==rollout*")
.build(),
4, false, new RolloutGroupConditionBuilder().withDefaults() 4, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
@@ -135,7 +140,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
void getRolloutDeployGroupTargetsWithParameters() throws Exception { void getRolloutDeployGroupTargetsWithParameters() throws Exception {
testdataFactory.createTargets(4, "rollout", "description"); testdataFactory.createTargets(4, "rollout", "description");
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 2, dsA, "controllerId==rollout*");
final RolloutGroup firstRolloutGroup = rolloutGroupManagement final RolloutGroup firstRolloutGroup = rolloutGroupManagement
.findByRollout(rollout.getId(), PageRequest.of(0, 1)).getContent().get(0); .findByRollout(rollout.getId(), PageRequest.of(0, 1)).getContent().get(0);
@@ -157,7 +162,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
try { try {
testdataFactory.createTargets(4, "rollout", "description"); testdataFactory.createTargets(4, "rollout", "description");
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
final Rollout rollout = createRollout("rollout1", 3, dsA.getId(), "controllerId==rollout*", false); final Rollout rollout = createRollout("rollout1", 3, dsA, "controllerId==rollout*", false);
mvc.perform(post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/approve", rollout.getId()) mvc.perform(post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/approve", rollout.getId())
.accept(MediaTypes.HAL_JSON_VALUE)) .accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()) .andDo(MockMvcResultPrinter.print())
@@ -176,7 +181,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
try { try {
testdataFactory.createTargets(4, "rollout", "description"); testdataFactory.createTargets(4, "rollout", "description");
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
final Rollout rollout = createRollout("rollout1", 3, dsA.getId(), "controllerId==rollout*", false); final Rollout rollout = createRollout("rollout1", 3, dsA, "controllerId==rollout*", false);
mvc.perform(post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/deny", rollout.getId()) mvc.perform(post(MgmtRestConstants.ROLLOUT_V1_REQUEST_MAPPING + "/{rolloutId}/deny", rollout.getId())
.accept(MediaTypes.HAL_JSON_VALUE)) .accept(MediaTypes.HAL_JSON_VALUE))
.andDo(MockMvcResultPrinter.print()) .andDo(MockMvcResultPrinter.print())
@@ -197,7 +202,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final String remark = "Some remark"; final String remark = "Some remark";
testdataFactory.createTargets(amountTargets, "rollout"); testdataFactory.createTargets(amountTargets, "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
final Rollout rollout = createRollout("rollout1", 3, dsA.getId(), "controllerId==rollout*", false); final Rollout rollout = createRollout("rollout1", 3, dsA, "controllerId==rollout*", false);
rolloutHandler.handleAll(); rolloutHandler.handleAll();
@@ -459,11 +464,9 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final float percentTargetsInGroup1 = 20; final float percentTargetsInGroup1 = 20;
final float percentTargetsInGroup2 = 100; final float percentTargetsInGroup2 = 100;
final List<RolloutGroup> rolloutGroups = Arrays.asList( final List<GroupCreate> rolloutGroups = List.of(
entityFactory.rolloutGroup().create().name("Group1").description("Group1desc") GroupCreate.builder().name("Group1").description("Group1desc").targetPercentage(percentTargetsInGroup1).build(),
.targetPercentage(percentTargetsInGroup1).build(), GroupCreate.builder().name("Group2").description("Group2desc").targetPercentage(percentTargetsInGroup2).build());
entityFactory.rolloutGroup().create().name("Group2").description("Group2desc")
.targetPercentage(percentTargetsInGroup2).build());
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
@@ -572,11 +575,9 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final int amountTargets = 10; final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "ro-target", "rollout"); testdataFactory.createTargets(amountTargets, "ro-target", "rollout");
final List<RolloutGroup> rolloutGroups = Arrays.asList( final List<GroupCreate> rolloutGroups = List.of(
entityFactory.rolloutGroup().create().name("Group1").description("Group1desc").targetPercentage(0F) GroupCreate.builder().name("Group1").description("Group1desc").targetPercentage(0F).build(),
.build(), GroupCreate.builder().name("Group2").description("Group2desc").targetPercentage(100F).build());
entityFactory.rolloutGroup().create().name("Group2").description("Group2desc").targetPercentage(100F)
.build());
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
@@ -600,11 +601,9 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final int amountTargets = 10; final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "ro-target", "rollout"); testdataFactory.createTargets(amountTargets, "ro-target", "rollout");
final List<RolloutGroup> rolloutGroups = Arrays.asList( final List<GroupCreate> rolloutGroups = List.of(
entityFactory.rolloutGroup().create().name("Group1").description("Group1desc").targetPercentage(1F) GroupCreate.builder().name("Group1").description("Group1desc").targetPercentage(1F).build(),
.build(), GroupCreate.builder().name("Group2").description("Group2desc").targetPercentage(101F).build());
entityFactory.rolloutGroup().create().name("Group2").description("Group2desc").targetPercentage(101F)
.build());
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
@@ -627,12 +626,11 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create a running rollout for the created targets // create a running rollout for the created targets
final Rollout rollout = rolloutManagement.create( final Rollout rollout = rolloutManagement.create(
entityFactory Create.builder()
.rollout()
.create()
.name("rollout1") .name("rollout1")
.distributionSetId(dsA.getId()) .distributionSet(dsA)
.targetFilterQuery("controllerId==rollout*"), .targetFilterQuery("controllerId==rollout*")
.build(),
4, false, new RolloutGroupConditionBuilder().withDefaults() 4, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
@@ -669,8 +667,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = rolloutManagement.create( final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("rollout1").distributionSetId(dsA.getId()) Create.builder().name("rollout1").distributionSet(dsA).targetFilterQuery("controllerId==rollout*").build(),
.targetFilterQuery("controllerId==rollout*"),
4, false, new RolloutGroupConditionBuilder().withDefaults() 4, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
@@ -690,8 +687,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
// create a running rollout for the created targets // create a running rollout for the created targets
final Rollout rollout = rolloutManagement.create( final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("rollout1").distributionSetId(dsA.getId()) Create.builder().name("rollout1").distributionSet(dsA).targetFilterQuery("controllerId==rollout*").build(),
.targetFilterQuery("controllerId==rollout*"),
4, false, new RolloutGroupConditionBuilder().withDefaults() 4, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
@@ -730,18 +726,16 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
@Test @Test
void retrieveRolloutListFullRepresentationWithFilter() throws Exception { void retrieveRolloutListFullRepresentationWithFilter() throws Exception {
testdataFactory.createTargets(20, "rollout", "rollout"); testdataFactory.createTargets(20, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSetLocked("");
// create a running rollout for the created targets // create a running rollout for the created targets
final Rollout rollout = rolloutManagement.create( final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("rollout1").distributionSetId(dsA.getId()) Create.builder().name("rollout1").distributionSet(dsA).targetFilterQuery("controllerId==rollout*").build(),
.targetFilterQuery("controllerId==rollout*"),
4, false, new RolloutGroupConditionBuilder().withDefaults() 4, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
rolloutManagement.create( rolloutManagement.create(
entityFactory.rollout().create().name("rollout2").distributionSetId(dsA.getId()) Create.builder().name("rollout2").distributionSet(dsA).targetFilterQuery("controllerId==rollout*").build(),
.targetFilterQuery("controllerId==rollout*"),
4, false, new RolloutGroupConditionBuilder().withDefaults() 4, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
@@ -789,8 +783,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = rolloutManagement.create( final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("rollout1").distributionSetId(dsA.getId()) Create.builder().name("rollout1").distributionSet(dsA).targetFilterQuery("controllerId==rollout*").build(),
.targetFilterQuery("controllerId==rollout*"),
4, false, new RolloutGroupConditionBuilder().withDefaults() 4, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
@@ -887,11 +880,9 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
final List<String> rolloutGroups = Arrays.asList( final List<String> rolloutGroups = List.of(
JsonBuilder.rolloutGroup("Group1", "Group1desc", null, percentTargetsInGroup1, false, JsonBuilder.rolloutGroup("Group1", "Group1desc", null, percentTargetsInGroup1, false, rolloutGroupConditions),
rolloutGroupConditions), JsonBuilder.rolloutGroup("Group2", "Group1desc", null, percentTargetsInGroup2, null, rolloutGroupConditions));
JsonBuilder.rolloutGroup("Group2", "Group1desc", null, percentTargetsInGroup2, null,
rolloutGroupConditions));
mvc.perform(post("/rest/v1/rollouts") mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout2", "desc", null, dsA.getId(), "id==ro-target*", .content(JsonBuilder.rollout("rollout2", "desc", null, dsA.getId(), "id==ro-target*",
@@ -1040,7 +1031,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
} }
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*", final Rollout rollout = createRollout("rollout1", 4, dsA, "controllerId==rollout*",
confirmationRequired); confirmationRequired);
// retrieve rollout groups from created rollout // retrieve rollout groups from created rollout
@@ -1077,14 +1068,11 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
// setup // setup
final int amountTargets = 8; final int amountTargets = 8;
testdataFactory.createTargets(amountTargets, "rollout", "rollout"); testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSetLocked("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout1 = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*", final Rollout rollout1 = createRollout("rollout1", 4, dsA, "controllerId==rollout*",false);
false); final Rollout rollout2 = createRollout("rollout2", 1, dsA, "controllerId==rollout*", false);
final Rollout rollout2 = createRollout("rollout2", 1, dsA.getId(), "controllerId==rollout*",
false);
rolloutManagement.start(rollout1.getId()); rolloutManagement.start(rollout1.getId());
rolloutManagement.start(rollout2.getId()); rolloutManagement.start(rollout2.getId());
@@ -1111,7 +1099,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 4, dsA, "controllerId==rollout*");
// starting rollout // starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())) mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId()))
@@ -1149,7 +1137,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 4, dsA, "controllerId==rollout*");
// starting rollout // starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())) mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId()))
@@ -1184,7 +1172,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 4, dsA, "controllerId==rollout*");
// starting rollout // starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())) mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId()))
@@ -1224,7 +1212,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 4, dsA, "controllerId==rollout*");
// starting rollout // starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())) mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId()))
@@ -1252,7 +1240,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 4, dsA, "controllerId==rollout*");
// resume not yet started rollout // resume not yet started rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/resume", rollout.getId())) mvc.perform(post("/rest/v1/rollouts/{rolloutId}/resume", rollout.getId()))
@@ -1272,7 +1260,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 2, dsA, "controllerId==rollout*");
// starting rollout // starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())) mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId()))
@@ -1313,8 +1301,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = rolloutManagement.create( final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("rollout1").distributionSetId(dsA.getId()) Create.builder().name("rollout1").distributionSet(dsA).targetFilterQuery("controllerId==rollout*").build(),
.targetFilterQuery("controllerId==rollout*"),
4, confirmationRequired, new RolloutGroupConditionBuilder().withDefaults() 4, confirmationRequired, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
@@ -1339,7 +1326,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 2, dsA, "controllerId==rollout*");
final RolloutGroup firstGroup = rolloutGroupManagement final RolloutGroup firstGroup = rolloutGroupManagement
.findByRollout(rollout.getId(), PageRequest.of(0, 1, Direction.ASC, "id")).getContent().get(0); .findByRollout(rollout.getId(), PageRequest.of(0, 1, Direction.ASC, "id")).getContent().get(0);
@@ -1366,7 +1353,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 2, dsA, "controllerId==rollout*");
final RolloutGroup firstGroup = rolloutGroupManagement final RolloutGroup firstGroup = rolloutGroupManagement
.findByRollout(rollout.getId(), PageRequest.of(0, 1, Direction.ASC, "id")).getContent().get(0); .findByRollout(rollout.getId(), PageRequest.of(0, 1, Direction.ASC, "id")).getContent().get(0);
@@ -1396,7 +1383,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 2, dsA, "controllerId==rollout*");
rolloutManagement.start(rollout.getId()); rolloutManagement.start(rollout.getId());
@@ -1428,7 +1415,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 4, dsA, "controllerId==rollout*");
// starting rollout // starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())) mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId()))
@@ -1452,7 +1439,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rolloutDelete", 4, dsA.getId(), "controllerId==rolloutDelete*"); final Rollout rollout = createRollout("rolloutDelete", 4, dsA, "controllerId==rolloutDelete*");
mvc.perform(delete("/rest/v1/rollouts/{rolloutid}", rollout.getId())) mvc.perform(delete("/rest/v1/rollouts/{rolloutid}", rollout.getId()))
.andDo(MockMvcResultPrinter.print()) .andDo(MockMvcResultPrinter.print())
@@ -1481,7 +1468,6 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
*/ */
@Test @Test
void getRolloutWithRSQLParam() throws Exception { void getRolloutWithRSQLParam() throws Exception {
final int amountTargetsRollout1 = 25; final int amountTargetsRollout1 = 25;
final int amountTargetsRollout2 = 25; final int amountTargetsRollout2 = 25;
final int amountTargetsRollout3 = 25; final int amountTargetsRollout3 = 25;
@@ -1490,12 +1476,12 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
testdataFactory.createTargets(amountTargetsRollout2, "rollout2", "rollout2"); testdataFactory.createTargets(amountTargetsRollout2, "rollout2", "rollout2");
testdataFactory.createTargets(amountTargetsRollout3, "rollout3", "rollout3"); testdataFactory.createTargets(amountTargetsRollout3, "rollout3", "rollout3");
testdataFactory.createTargets(amountTargetsOther, "other1", "other1"); testdataFactory.createTargets(amountTargetsOther, "other1", "other1");
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSetLocked("");
createRollout("rollout1", 5, dsA.getId(), "controllerId==rollout1*"); createRollout("rollout1", 5, dsA, "controllerId==rollout1*");
final Rollout rollout2 = createRollout("rollout2", 5, dsA.getId(), "controllerId==rollout2*"); final Rollout rollout2 = createRollout("rollout2", 5, dsA, "controllerId==rollout2*");
createRollout("rollout3", 5, dsA.getId(), "controllerId==rollout3*"); createRollout("rollout3", 5, dsA, "controllerId==rollout3*");
createRollout("other1", 5, dsA.getId(), "controllerId==other1*"); createRollout("other1", 5, dsA, "controllerId==other1*");
mvc.perform(get("/rest/v1/rollouts").param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==*2") mvc.perform(get("/rest/v1/rollouts").param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==*2")
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
@@ -1535,7 +1521,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout' // create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 4, dsA, "controllerId==rollout*");
// retrieve rollout groups from created rollout // retrieve rollout groups from created rollout
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId()) mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId())
@@ -1580,8 +1566,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
// create a running rollout for the created targets // create a running rollout for the created targets
final Rollout rollout = rolloutManagement.create( final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("rollout1").distributionSetId(dsA.getId()) Create.builder().name("rollout1").distributionSet(dsA).targetFilterQuery("controllerId==rollout*").build(),
.targetFilterQuery("controllerId==rollout*"),
4, false, new RolloutGroupConditionBuilder().withDefaults() 4, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
@@ -1667,7 +1652,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
testdataFactory.createTargets(amountTargets, "rollout", "rollout"); testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*"); final Rollout rollout = createRollout("rollout1", 4, dsA, "controllerId==rollout*");
rolloutManagement.start(rollout.getId()); rolloutManagement.start(rollout.getId());
rolloutHandler.handleAll(); rolloutHandler.handleAll();
@@ -1691,7 +1676,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet(""); final DistributionSet dsA = testdataFactory.createDistributionSet("");
// CREATING state // CREATING state
final Rollout rollout = createRollout("rollout1", 3, dsA.getId(), "controllerId==rollout*", false); final Rollout rollout = createRollout("rollout1", 3, dsA, "controllerId==rollout*", false);
triggerNextGroupAndExpect(rollout, status().isBadRequest()); triggerNextGroupAndExpect(rollout, status().isBadRequest());
// READY state // READY state
@@ -1720,7 +1705,6 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
setTargetsStatus(targets, Status.FINISHED); setTargetsStatus(targets, Status.FINISHED);
rolloutHandler.handleAll(); rolloutHandler.handleAll();
triggerNextGroupAndExpect(rollout, status().isBadRequest()); triggerNextGroupAndExpect(rollout, status().isBadRequest());
} }
private static Stream<Arguments> confirmationOptions() { private static Stream<Arguments> confirmationOptions() {
@@ -1923,8 +1907,10 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
} }
private static final Duration ROLLOUT_AT_LEAST = Duration.ofMillis(Integer.getInteger("hawkbit.it.rest.await.rolloutAtLeastMs", 50)); private static final Duration ROLLOUT_AT_LEAST = Duration.ofMillis(Integer.getInteger("hawkbit.it.rest.await.rolloutAtLeastMs", 50));
private static final Duration ROLLOUT_POLL_INTERVAL = Duration.ofMillis(Integer.getInteger("hawkbit.it.rest.await.rolloutPollIntervalMs", 100)); private static final Duration ROLLOUT_POLL_INTERVAL = Duration.ofMillis(
Integer.getInteger("hawkbit.it.rest.await.rolloutPollIntervalMs", 100));
private static final Duration ROLLOUT_TIMEOUT = Duration.ofMillis(Integer.getInteger("hawkbit.it.rest.await.rolloutTimeoutMs", 60_000)); private static final Duration ROLLOUT_TIMEOUT = Duration.ofMillis(Integer.getInteger("hawkbit.it.rest.await.rolloutTimeoutMs", 60_000));
private ConditionFactory awaitRollout() { private ConditionFactory awaitRollout() {
return Awaitility.await().atLeast(ROLLOUT_AT_LEAST).pollInterval(ROLLOUT_POLL_INTERVAL).atMost(ROLLOUT_TIMEOUT); return Awaitility.await().atLeast(ROLLOUT_AT_LEAST).pollInterval(ROLLOUT_POLL_INTERVAL).atMost(ROLLOUT_TIMEOUT);
} }
@@ -1987,15 +1973,16 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
"$._links.groups.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), containsString("/deploygroups")))); "$._links.groups.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), containsString("/deploygroups"))));
} }
private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId, private Rollout createRollout(
final String targetFilterQuery) { final String name, final int amountGroups, final DistributionSet distributionSet, final String targetFilterQuery) {
return createRollout(name, amountGroups, distributionSetId, targetFilterQuery, false); return createRollout(name, amountGroups, distributionSet, targetFilterQuery, false);
} }
private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId, private Rollout createRollout(
final String targetFilterQuery, final boolean confirmationRequired) { final String name, final int amountGroups, final DistributionSet distributionSet, final String targetFilterQuery,
final boolean confirmationRequired) {
final Rollout rollout = rolloutManagement.create( final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name(name).distributionSetId(distributionSetId).targetFilterQuery(targetFilterQuery), Create.builder().name(name).distributionSet(distributionSet).targetFilterQuery(targetFilterQuery).build(),
amountGroups, confirmationRequired, new RolloutGroupConditionBuilder().withDefaults() amountGroups, confirmationRequired, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
@@ -2013,10 +2000,9 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
private void setTargetsStatus(final List<Target> targets, final Status status) { private void setTargetsStatus(final List<Target> targets, final Status status) {
for (final Target target : targets) { for (final Target target : targets) {
final Long action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).toList().get(0) final Long action = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE).toList().get(0).getId();
.getId(); controllerManagement.addUpdateActionStatus(
controllerManagement ActionStatusCreate.builder().actionId(action).status(status).messages(List.of("test")).build());
.addUpdateActionStatus(entityFactory.actionStatus().create(action).status(status).message("test"));
} }
} }

View File

@@ -56,13 +56,11 @@ import org.eclipse.hawkbit.repository.ActionFields;
import org.eclipse.hawkbit.repository.Identifiable; import org.eclipse.hawkbit.repository.Identifiable;
import org.eclipse.hawkbit.repository.TargetManagement.Create; import org.eclipse.hawkbit.repository.TargetManagement.Create;
import org.eclipse.hawkbit.repository.TargetTypeManagement; import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
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;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository; import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.Action.Status;
@@ -287,7 +285,8 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
final String expectedStatusMessage2 = "some-custom-message2"; final String expectedStatusMessage2 = "some-custom-message2";
final Status expectedStatusAfterActionConfirmationCall = Status.RUNNING; final Status expectedStatusAfterActionConfirmationCall = Status.RUNNING;
final long actionId = doAssignmentAndTestConfirmation("targetId"); final long actionId = doAssignmentAndTestConfirmation("targetId");
testActionConfirmation("targetId", actionId, MgmtActionConfirmationRequestBodyPut.Confirmation.CONFIRMED, expectedStatusCode, new String[]{expectedStatusMessage1, expectedStatusMessage2}, HttpStatus.OK ,expectedStatusAfterActionConfirmationCall); testActionConfirmation("targetId", actionId, MgmtActionConfirmationRequestBodyPut.Confirmation.CONFIRMED, expectedStatusCode,
new String[] { expectedStatusMessage1, expectedStatusMessage2 }, HttpStatus.OK, expectedStatusAfterActionConfirmationCall);
} }
/** /**
@@ -300,7 +299,8 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
final String expectedStatusMessage2 = "some-error-custom-message2"; final String expectedStatusMessage2 = "some-error-custom-message2";
final Status expectedStatusAfterActionConfirmationCall = Status.WAIT_FOR_CONFIRMATION; final Status expectedStatusAfterActionConfirmationCall = Status.WAIT_FOR_CONFIRMATION;
final long actionId = doAssignmentAndTestConfirmation("targetId"); final long actionId = doAssignmentAndTestConfirmation("targetId");
testActionConfirmation("targetId", actionId, MgmtActionConfirmationRequestBodyPut.Confirmation.DENIED, expectedStatusCode, new String[]{expectedStatusMessage1, expectedStatusMessage2}, HttpStatus.OK, expectedStatusAfterActionConfirmationCall); testActionConfirmation("targetId", actionId, MgmtActionConfirmationRequestBodyPut.Confirmation.DENIED, expectedStatusCode,
new String[] { expectedStatusMessage1, expectedStatusMessage2 }, HttpStatus.OK, expectedStatusAfterActionConfirmationCall);
} }
/** /**
@@ -316,10 +316,10 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
// test that target id and action id are checked correctly and only actions assigned to given targets are confirmed/denied // test that target id and action id are checked correctly and only actions assigned to given targets are confirmed/denied
// if action is not assigned to the target, confirmation call must fail // if action is not assigned to the target, confirmation call must fail
testActionConfirmation("controller1", controller2Action, MgmtActionConfirmationRequestBodyPut.Confirmation.CONFIRMED, testActionConfirmation("controller1", controller2Action, MgmtActionConfirmationRequestBodyPut.Confirmation.CONFIRMED,
payloadCallCode, new String[]{payloadCallMessage1, payloadCallMessage2}, HttpStatus.NOT_FOUND, payloadCallCode, new String[] { payloadCallMessage1, payloadCallMessage2 }, HttpStatus.NOT_FOUND,
Status.WAIT_FOR_CONFIRMATION); Status.WAIT_FOR_CONFIRMATION);
testActionConfirmation("controller2", controller1Action, MgmtActionConfirmationRequestBodyPut.Confirmation.CONFIRMED, testActionConfirmation("controller2", controller1Action, MgmtActionConfirmationRequestBodyPut.Confirmation.CONFIRMED,
payloadCallCode, new String[]{payloadCallMessage1, payloadCallMessage2}, HttpStatus.NOT_FOUND, payloadCallCode, new String[] { payloadCallMessage1, payloadCallMessage2 }, HttpStatus.NOT_FOUND,
Status.WAIT_FOR_CONFIRMATION); Status.WAIT_FOR_CONFIRMATION);
} }
@@ -339,10 +339,11 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
return action.getId(); return action.getId();
} }
void testActionConfirmation(final String controllerId, final long actionId, final MgmtActionConfirmationRequestBodyPut.Confirmation payloadConfirmation, final int payloadCode, final String[] payloadMessages, final HttpStatus expectedHttpResponseStatus,final Status expectedGeneratedStatus) throws Exception { void testActionConfirmation(final String controllerId, final long actionId,
final MgmtActionConfirmationRequestBodyPut.Confirmation payloadConfirmation, final int payloadCode, final String[] payloadMessages,
final HttpStatus expectedHttpResponseStatus, final Status expectedGeneratedStatus) throws Exception {
String url = MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + controllerId + "/" + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId + "/confirmation"; String url = MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + controllerId + "/" + MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId + "/confirmation";
mvc.perform(put(url) mvc.perform(put(url).content(String.format("{\"confirmation\":\"%s\",\"details\":[\"%s\",\"%s\"],\"code\":%d}",
.content(String.format("{\"confirmation\":\"%s\",\"details\":[\"%s\",\"%s\"],\"code\":%d}",
payloadConfirmation.getName(), payloadConfirmation.getName(),
payloadMessages[0], payloadMessages[0],
payloadMessages[1], payloadMessages[1],
@@ -352,7 +353,6 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
.andDo(MockMvcResultPrinter.print()) .andDo(MockMvcResultPrinter.print())
.andExpect(status().is(expectedHttpResponseStatus.value())); .andExpect(status().is(expectedHttpResponseStatus.value()));
// check status after confirmation is done (either confirmed or denied) // check status after confirmation is done (either confirmed or denied)
final List<Action> actionHistory = deploymentManagement.findActionsByTarget(controllerId, PAGE).getContent(); final List<Action> actionHistory = deploymentManagement.findActionsByTarget(controllerId, PAGE).getContent();
assertThat(actionHistory).hasSize(1); assertThat(actionHistory).hasSize(1);
@@ -362,18 +362,18 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
// confirmation call was successful, check if Action status ,status code and messages are updated appropriately // confirmation call was successful, check if Action status ,status code and messages are updated appropriately
if (expectedHttpResponseStatus == HttpStatus.OK) { if (expectedHttpResponseStatus == HttpStatus.OK) {
assertThat(jpaAction.getStatus()).isEqualTo(expectedGeneratedStatus); assertThat(jpaAction.getStatus()).isEqualTo(expectedGeneratedStatus);
assertThat(jpaAction.getLastActionStatusCode().get()).isEqualTo(payloadCode); assertThat(jpaAction.getLastActionStatusCode()).hasValue(payloadCode);
actionStatuses.sort(Comparator.comparingLong(Identifiable::getId)); actionStatuses.sort(Comparator.comparingLong(Identifiable::getId));
assertThat(actionStatuses.size()).isEqualTo(2); assertThat(actionStatuses).hasSize(2);
assertThat((actionStatuses.get(0)).getStatus()).isEqualTo(Status.WAIT_FOR_CONFIRMATION); assertThat((actionStatuses.get(0)).getStatus()).isEqualTo(Status.WAIT_FOR_CONFIRMATION);
assertThat((actionStatuses.get(0)).getCode().isEmpty()).isTrue(); assertThat((actionStatuses.get(0)).getCode()).isEmpty();
assertThat((actionStatuses.get(1)).getStatus()).isEqualTo(expectedGeneratedStatus); assertThat((actionStatuses.get(1)).getStatus()).isEqualTo(expectedGeneratedStatus);
assertThat((actionStatuses.get(1)).getCode().get()).isEqualTo(payloadCode); assertThat((actionStatuses.get(1)).getCode()).hasValue(payloadCode);
assertThat(((JpaActionStatus) actionStatuses.get(1)).getMessages()).contains(payloadMessages[0], payloadMessages[1]); assertThat(((JpaActionStatus) actionStatuses.get(1)).getMessages()).contains(payloadMessages[0], payloadMessages[1]);
} else { // confirmation call not successful, check if Action status is not updated, no new Action status added as well. } else { // confirmation call not successful, check if Action status is not updated, no new Action status added as well.
assertThat(jpaAction.getStatus()).isEqualTo(Status.WAIT_FOR_CONFIRMATION); assertThat(jpaAction.getStatus()).isEqualTo(Status.WAIT_FOR_CONFIRMATION);
assertThat(jpaAction.getLastActionStatusCode().isEmpty()).isTrue(); assertThat(jpaAction.getLastActionStatusCode()).isEmpty();
assertThat(jpaAction.getActionStatus()).hasSize(1); assertThat(jpaAction.getActionStatus()).hasSize(1);
} }
} }
@@ -949,7 +949,7 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
final SoftwareModule os = findFirstModuleByType(ds, osType).orElseThrow(); final SoftwareModule os = findFirstModuleByType(ds, osType).orElseThrow();
final SoftwareModule jvm = findFirstModuleByType(ds, runtimeType).orElseThrow(); final SoftwareModule jvm = findFirstModuleByType(ds, runtimeType).orElseThrow();
final SoftwareModule bApp = findFirstModuleByType(ds,appType).orElseThrow(); final SoftwareModule bApp = findFirstModuleByType(ds, appType).orElseThrow();
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId + "/assignedDS")) mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId + "/assignedDS"))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print()) .andDo(MockMvcResultPrinter.print())
@@ -1161,9 +1161,9 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
assertThat((Object) JsonPath.compile("[0]._links.self.href").read(mvcResult.getResponse().getContentAsString())) assertThat((Object) JsonPath.compile("[0]._links.self.href").read(mvcResult.getResponse().getContentAsString()))
.hasToString("http://localhost/rest/v1/targets/id1"); .hasToString("http://localhost/rest/v1/targets/id1");
assertThat((Object)JsonPath.compile("[1]._links.self.href").read(mvcResult.getResponse().getContentAsString())) assertThat((Object) JsonPath.compile("[1]._links.self.href").read(mvcResult.getResponse().getContentAsString()))
.hasToString("http://localhost/rest/v1/targets/id2"); .hasToString("http://localhost/rest/v1/targets/id2");
assertThat((Object)JsonPath.compile("[2]._links.self.href").read(mvcResult.getResponse().getContentAsString())) assertThat((Object) JsonPath.compile("[2]._links.self.href").read(mvcResult.getResponse().getContentAsString()))
.hasToString("http://localhost/rest/v1/targets/id3"); .hasToString("http://localhost/rest/v1/targets/id3");
final Target t1 = assertTarget("id1", "testname1", "testid1"); final Target t1 = assertTarget("id1", "testname1", "testid1");
@@ -1723,7 +1723,7 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
} }
/** /**
* Verifies that an offline DS to target assignment is reflected by the repository and that repeating * Verifies that an offline DS to target assignment is reflected by the repository and that repeating
* the assignment does not change the target. * the assignment does not change the target.
*/ */
@Test @Test
@@ -3066,15 +3066,15 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
assertThat(action).isNotNull(); assertThat(action).isNotNull();
assertThat(status).isNotNull(); assertThat(status).isNotNull();
final ActionStatusCreate actionStatus = entityFactory.actionStatus().create(action.getId()); final Action.ActionStatusCreate.ActionStatusCreateBuilder actionStatus = Action.ActionStatusCreate.builder().actionId(action.getId());
actionStatus.status(status); actionStatus.status(status);
if (statusCode != null) { if (statusCode != null) {
actionStatus.code(statusCode); actionStatus.code(statusCode);
} }
if (message != null) { if (message != null) {
actionStatus.message(message); actionStatus.messages(List.of(message));
} }
return controllerManagement.addUpdateActionStatus(actionStatus); return controllerManagement.addUpdateActionStatus(actionStatus.build());
} }
} }

View File

@@ -21,13 +21,13 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; 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.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
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;
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus; import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;

View File

@@ -1,36 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository;
import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutGroupBuilder;
import org.eclipse.hawkbit.repository.model.BaseEntity;
/**
* Central {@link BaseEntity} generation service. Objects are created but not persisted.
*/
public interface EntityFactory {
/**
* @return {@link ActionStatusBuilder} object
*/
ActionStatusBuilder actionStatus();
/**
* @return {@link RolloutGroupBuilder} object
*/
RolloutGroupBuilder rolloutGroup();
/**
* @return {@link RolloutBuilder} object
*/
RolloutBuilder rollout();
}

View File

@@ -11,46 +11,54 @@ package org.eclipse.hawkbit.repository;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import jakarta.validation.ConstraintViolationException; import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate;
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
import org.eclipse.hawkbit.repository.builder.RolloutUpdate;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
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.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;
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.NamedEntity;
import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
import org.eclipse.hawkbit.repository.model.RolloutGroupsValidation; import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
/** /**
* RolloutManagement to control rollouts e.g. like creating, starting, resuming * RolloutManagement to control rollouts e.g. like creating, starting, resuming and pausing rollouts. This service secures all the
* and pausing rollouts. This service secures all the functionality based on the * functionality based on the {@link PreAuthorize} annotation on methods.
* {@link PreAuthorize} annotation on methods.
*/ */
public interface RolloutManagement { public interface RolloutManagement {
/** /**
* Counts all {@link Rollout}s in the repository that are not marked as deleted. * Counts all {@link Rollout}s in the repository that are not marked as deleted.
* *
* @return number of roll outs * @return number of rollouts
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ)
long count(); long count();
@@ -96,7 +104,7 @@ public interface RolloutManagement {
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE)
Rollout create( Rollout create(
@NotNull @Valid RolloutCreate create, int amountGroup, boolean confirmationRequired, @NotNull @Valid Create create, int amountGroup, boolean confirmationRequired,
@NotNull RolloutGroupConditions conditions, DynamicRolloutGroupTemplate dynamicRolloutGroupTemplate); @NotNull RolloutGroupConditions conditions, DynamicRolloutGroupTemplate dynamicRolloutGroupTemplate);
/** /**
@@ -126,7 +134,7 @@ public interface RolloutManagement {
* exceeded. * exceeded.
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE)
Rollout create(@NotNull @Valid RolloutCreate create, int amountGroup, boolean confirmationRequired, Rollout create(@NotNull @Valid Create create, int amountGroup, boolean confirmationRequired,
@NotNull RolloutGroupConditions conditions); @NotNull RolloutGroupConditions conditions);
/** /**
@@ -157,25 +165,7 @@ public interface RolloutManagement {
* exceeded. * exceeded.
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE)
Rollout create(@Valid @NotNull RolloutCreate rollout, @NotNull @Valid List<RolloutGroupCreate> groups, Rollout create(@Valid @NotNull Create rollout, @NotNull @Valid List<GroupCreate> groups, RolloutGroupConditions conditions);
RolloutGroupConditions conditions);
/**
* Calculates how many targets are addressed by each rollout group and
* returns the validation information.
*
* @param groups a list of rollout groups
* @param targetFilter the rollout
* @param createdAt timestamp when the rollout was created
* @param dsTypeId ID of the type of distribution set of the rollout
* @return the validation information
* @throws RolloutIllegalStateException thrown when no targets are targeted by the rollout
* @throws ConstraintViolationException if fields are not filled as specified. Check
* {@link RolloutGroupCreate} for field constraints.
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ)
CompletableFuture<RolloutGroupsValidation> validateTargetsInGroups(
@Valid List<RolloutGroupCreate> groups, String targetFilter, Long createdAt, @NotNull Long dsTypeId);
/** /**
* Retrieves all rollouts. * Retrieves all rollouts.
@@ -274,45 +264,36 @@ public interface RolloutManagement {
* running will be untouched. {@link RolloutGroup}s which are * running will be untouched. {@link RolloutGroup}s which are
* {@link RolloutGroupStatus#SCHEDULED} will not be started and keep in * {@link RolloutGroupStatus#SCHEDULED} will not be started and keep in
* {@link RolloutGroupStatus#SCHEDULED} state until the rollout is * {@link RolloutGroupStatus#SCHEDULED} state until the rollout is
* {@link RolloutManagement#resumeRollout(Rollout)}. * {@link RolloutManagement#resumeRollout(long)}.
* * <p/>
* Switching the rollout status to {@link RolloutStatus#PAUSED} is * Switching the rollout status to {@link RolloutStatus#PAUSED} is sufficient.
* sufficient due the {@link #checkRunningRollouts(long)} will not check
* this rollout anymore.
* *
* @param rolloutId the rollout to be paused. * @param rolloutId the rollout to be paused.
* @throws EntityNotFoundException if rollout or group with given ID does not exist * @throws EntityNotFoundException if rollout or group with given ID does not exist
* @throws RolloutIllegalStateException if given rollout is not in {@link RolloutStatus#RUNNING}. * @throws RolloutIllegalStateException if given rollout is not in {@link RolloutStatus#RUNNING}. Only running rollouts can be paused.
* Only running rollouts can be paused.
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_HANDLE) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_HANDLE)
void pauseRollout(long rolloutId); void pauseRollout(long rolloutId);
/** /**
* Resumes a paused rollout. The rollout switches back to * Resumes a paused rollout. The rollout switches back to {@link RolloutStatus#RUNNING} state which is then picked up again executor.
* {@link RolloutStatus#RUNNING} state which is then picked up again by the
* {@link #checkRunningRollouts(long)}.
* *
* @param rolloutId the rollout to be resumed * @param rolloutId the rollout to be resumed
* @throws EntityNotFoundException if rollout with given ID does not exist * @throws EntityNotFoundException if rollout with given ID does not exist
* @throws RolloutIllegalStateException if given rollout is not in {@link RolloutStatus#PAUSED}. Only * @throws RolloutIllegalStateException if given rollout is not in {@link RolloutStatus#PAUSED}. Only paused rollouts can be resumed.
* paused rollouts can be resumed.
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_HANDLE) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_HANDLE)
void resumeRollout(long rolloutId); void resumeRollout(long rolloutId);
/** /**
* Approves or denies a created rollout being in state * Approves or denies a created rollout being in state {@link RolloutStatus#WAITING_FOR_APPROVAL}. If the rollout is approved,
* {@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}
* 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. * @param rolloutId the rollout to be approved or denied.
* @param decision decision whether a rollout is approved or denied. * @param decision decision whether a rollout is approved or denied.
* @return approved or denied rollout * @return approved or denied rollout
* @throws EntityNotFoundException if rollout with given ID does not exist * @throws EntityNotFoundException if rollout with given ID does not exist
* @throws RolloutIllegalStateException if given rollout is not in * @throws RolloutIllegalStateException if given rollout is not in {@link RolloutStatus#WAITING_FOR_APPROVAL}. Only rollouts
* {@link RolloutStatus#WAITING_FOR_APPROVAL}. Only rollouts
* waiting for approval can be acted upon. * waiting for approval can be acted upon.
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_APPROVE) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_APPROVE)
@@ -362,7 +343,7 @@ public interface RolloutManagement {
* reference * reference
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_UPDATE) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_UPDATE)
Rollout update(@NotNull @Valid RolloutUpdate update); Rollout update(@NotNull @Valid Update update);
/** /**
* Deletes a rollout. A rollout might be deleted asynchronously by * Deletes a rollout. A rollout might be deleted asynchronously by
@@ -394,4 +375,149 @@ public interface RolloutManagement {
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_UPDATE) @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_UPDATE)
void triggerNextGroup(long rolloutId); void triggerNextGroup(long rolloutId);
@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
final class Create extends UpdateCreate {
@ValidString
@Size(min = 1, max = TargetFilterQuery.QUERY_MAX_SIZE)
@NotNull
private String targetFilterQuery;
@NotNull
private DistributionSet distributionSet;
private boolean dynamic;
@Builder.Default
@NotNull
private Action.ActionType actionType = Action.ActionType.FORCED;
private Long forcedTime;
private Long startAt;
@Min(Action.WEIGHT_MIN)
@Max(Action.WEIGHT_MAX)
private Integer weight;
}
@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
final class Update extends UpdateCreate implements Identifiable<Long> {
@NotNull
private Long id;
}
@SuperBuilder
@Getter
class UpdateCreate {
@ValidString
@Size(min = 1, max = NamedEntity.NAME_MAX_SIZE)
@NotNull(groups = Create.class)
private String name;
@ValidString
@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE)
private String description;
}
@Getter
class GroupCreate {
@ValidString
@Size(min = 1, max = NamedEntity.NAME_MAX_SIZE)
@NotNull
private final String name;
@ValidString
@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE)
private final String description;
@ValidString
@Size(min = 1, max = TargetFilterQuery.QUERY_MAX_SIZE)
private final String targetFilterQuery;
private final Float targetPercentage;
private final boolean confirmationRequired;
// Conditions and actions for the rollout group
private final RolloutGroup.RolloutGroupSuccessCondition successCondition;
private final String successConditionExp;
private final RolloutGroup.RolloutGroupSuccessAction successAction;
private final String successActionExp;
private final RolloutGroup.RolloutGroupErrorCondition errorCondition;
private final String errorConditionExp;
private final RolloutGroup.RolloutGroupErrorAction errorAction;
private final String errorActionExp;
private GroupCreate(
final String name, final String description, final String targetFilterQuery, final Float targetPercentage,
final RolloutGroupConditions conditions, final boolean confirmationRequired) {
this.name = name;
this.description = description;
this.targetFilterQuery = targetFilterQuery;
this.targetPercentage = targetPercentage;
this.successCondition = conditions.getSuccessCondition();
this.successConditionExp = conditions.getSuccessConditionExp();
this.successAction = conditions.getSuccessAction();
this.successActionExp = conditions.getSuccessActionExp();
this.errorCondition = conditions.getErrorCondition();
this.errorConditionExp = conditions.getErrorConditionExp();
this.errorAction = conditions.getErrorAction();
this.errorActionExp = conditions.getErrorActionExp();
this.confirmationRequired = confirmationRequired;
}
public static GroupCreateBuilder builder() {
return new GroupCreateBuilder();
}
@Setter
@Accessors(fluent = true)
public static class GroupCreateBuilder {
private String name;
private String description;
private String targetFilterQuery;
private Float targetPercentage;
private RolloutGroupConditions conditions;
private boolean confirmationRequired;
public GroupCreate build() {
return new GroupCreate(
name, description, targetFilterQuery, targetPercentage,
conditions == null ? new RolloutGroupConditionBuilder().withDefaults().build() : conditions,
confirmationRequired);
}
}
}
/**
* Builder to create a new dynamic rollout group secret
*/
@Data
@Builder
class DynamicRolloutGroupTemplate {
/**
* The name suffix, by default "" is used.
*/
@NotNull
private String nameSuffix = "";
/**
* The count of matching Targets that should be assigned to this Group
*/
private long targetCount;
/**
* The group conditions
*/
private RolloutGroupConditions conditions;
/**
* If confirmation is required for this rollout group (considered with confirmation flow active)
*/
private boolean confirmationRequired;
}
} }

View File

@@ -1,25 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import org.eclipse.hawkbit.repository.model.ActionStatus;
/**
* Builder for {@link ActionStatus}.
*/
@FunctionalInterface
public interface ActionStatusBuilder {
/**
* @param actionId the status is for
* @return create builder
*/
ActionStatusCreate create(long actionId);
}

View File

@@ -1,57 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import java.util.Collection;
import jakarta.validation.constraints.NotNull;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.BaseEntity;
/**
* Builder to create a new {@link ActionStatus} entry. Defines all fields that
* can be set at creation time. Other fields are set by the repository
* automatically, e.g. {@link BaseEntity#getCreatedAt()}.
*/
public interface ActionStatusCreate {
/**
* @param status {@link ActionStatus#getStatus()}
* @return updated {@link ActionStatusCreate} object
*/
ActionStatusCreate status(@NotNull Status status);
/**
* @param occurredAt for {@link ActionStatus#getOccurredAt()}
* @return updated {@link ActionStatusCreate} object
*/
ActionStatusCreate occurredAt(long occurredAt);
ActionStatusCreate code(int code);
/**
* @param messages for {@link ActionStatus#getMessages()}
* @return updated {@link ActionStatusCreate} object
*/
ActionStatusCreate messages(Collection<String> messages);
/**
* @param message for {@link ActionStatus#getMessages()}
* @return updated {@link ActionStatusCreate} object
*/
ActionStatusCreate message(String message);
/**
* @return peek on current state of {@link ActionStatus} in the builder
*/
ActionStatus build();
}

View File

@@ -1,45 +0,0 @@
/**
* Copyright (c) 2024 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Data;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
/**
* Builder to create a new dynamic rollout group secret
*/
@Data
@Builder
public class DynamicRolloutGroupTemplate {
/**
* The name suffix, by default "" is used.
*/
@NotNull
private String nameSuffix = "";
/**
* The count of matching Targets that should be assigned to this Group
*/
private long targetCount;
/**
* The group conditions
*/
private RolloutGroupConditions conditions;
/**
* If confirmation is required for this rollout group (considered with confirmation flow active)
*/
private boolean confirmationRequired;
}

View File

@@ -1,29 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import org.eclipse.hawkbit.repository.model.Rollout;
/**
* Builder for {@link Rollout}.
*/
public interface RolloutBuilder {
/**
* @param id of the updatable entity
* @return builder instance
*/
RolloutUpdate update(long id);
/**
* @return builder instance
*/
RolloutCreate create();
}

View File

@@ -1,118 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import java.util.Optional;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
/**
* Builder to create a new {@link Rollout} entry. Defines all fields that can be
* set at creation time. Other fields are set by the repository automatically,
* e.g. {@link BaseEntity#getCreatedAt()}.
*/
public interface RolloutCreate {
/**
* Set name
*
* @param name for {@link Rollout#getName()}
* @return updated builder instance
*/
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
*/
RolloutCreate description(@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE) String description);
/**
* Set the {@link DistributionSet}
*
* @param set for {@link Rollout#getDistributionSet()}
* @return updated builder instance
*/
default RolloutCreate distributionSetId(final DistributionSet set) {
return distributionSetId(Optional.ofNullable(set).map(DistributionSet::getId).orElse(null));
}
/**
* Set the id of the {@link DistributionSet}
*
* @param distributionSetId for {@link Rollout#getDistributionSet()}
* @return updated builder instance
*/
RolloutCreate distributionSetId(long distributionSetId);
/**
* Set the {@link TargetFilterQuery}
*
* @param targetFilterQuery for {@link Rollout#getTargetFilterQuery()}
* @return updated builder instance
*/
RolloutCreate targetFilterQuery(
@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
*/
RolloutCreate actionType(@NotNull ActionType actionType);
/**
* Set the forcedTime of the resulting {@link org.eclipse.hawkbit.repository.model.Action}s
*
* @param forcedTime for {@link Rollout#getForcedTime()}
* @return updated builder instance
*/
RolloutCreate forcedTime(Long forcedTime);
/**
* Set the weight of the resulting {@link org.eclipse.hawkbit.repository.model.Action}s
*
* @param weight for {@link Rollout#getWeight()}
* @return updated builder instance
*/
RolloutCreate weight(Integer weight);
/**
* Set if the rollout shall be dynamic
*
* @param dynamic for {@link Rollout#isDynamic()}
* @return updated builder instance
*/
RolloutCreate dynamic(boolean dynamic);
/**
* Set start at
*
* @param startAt for {@link Rollout#getStartAt()}
* @return updated builder instance
*/
RolloutCreate startAt(Long startAt);
/**
* @return peek on current state of {@link Rollout} in the builder
*/
Rollout build();
}

View File

@@ -1,24 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import org.eclipse.hawkbit.repository.model.Rollout;
/**
* Builder for {@link Rollout}.
*/
@FunctionalInterface
public interface RolloutGroupBuilder {
/**
* @return builder instance
*/
RolloutGroupCreate create();
}

View File

@@ -1,72 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
/**
* Builder to create a new {@link RolloutGroup} entry. Defines all fields that
* can be set at creation time. Other fields are set by the repository
* automatically, e.g. {@link BaseEntity#getCreatedAt()}.
*/
public interface RolloutGroupCreate {
/**
* @param name for {@link Rollout#getName()}
* @return updated builder instance
*/
RolloutGroupCreate name(@Size(min = 1, max = NamedEntity.NAME_MAX_SIZE) @NotNull String name);
/**
* @param description for {@link Rollout#getDescription()}
* @return updated builder instance
*/
RolloutGroupCreate description(@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE) String description);
/**
* @param targetFilterQuery for {@link Rollout#getTargetFilterQuery()}
* @return updated builder instance
*/
RolloutGroupCreate targetFilterQuery(
@Size(min = 1, max = TargetFilterQuery.QUERY_MAX_SIZE) @NotNull String targetFilterQuery);
/**
* @param targetPercentage the percentage of matching Targets that should be assigned to this Group
* @return updated builder instance
*/
RolloutGroupCreate targetPercentage(Float targetPercentage);
/**
* @param conditions as created by {@link RolloutGroupConditionBuilder}.
* @return updated builder instance
*/
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
*/
RolloutGroup build();
}

View File

@@ -1,39 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.Rollout;
/**
* Builder to update an existing {@link Rollout} entry. Defines all fields that
* can be updated.
*/
public interface RolloutUpdate {
/**
* Set name of the {@link Rollout}
*
* @param name for {@link Rollout#getName()}
* @return updated builder instance
*/
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
*/
RolloutUpdate description(@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE) String description);
}

View File

@@ -10,10 +10,16 @@
package org.eclipse.hawkbit.repository.model; package org.eclipse.hawkbit.repository.model;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;
import org.eclipse.hawkbit.repository.ValidString;
/** /**
* Update operations to be executed by the target. * Update operations to be executed by the target.
@@ -338,4 +344,17 @@ public interface Action extends TenantAwareBaseEntity {
DOWNLOAD_ONLY DOWNLOAD_ONLY
} }
@Getter
@Builder
class ActionStatusCreate {
private long actionId;
@NotNull
private Status status;
private Integer code;
private Collection<@ValidString String> messages;
private Long occurredAt;
}
} }

View File

@@ -94,4 +94,4 @@ public class RolloutGroupConditionBuilder {
errorAction(RolloutGroupErrorAction.PAUSE, ""); errorAction(RolloutGroupErrorAction.PAUSE, "");
return this; return this;
} }
} }

View File

@@ -1,75 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.Getter;
import org.eclipse.hawkbit.repository.ValidString;
import org.eclipse.hawkbit.repository.model.Action.Status;
/**
* Create and update builder DTO.
*
* @param <T> update or create builder interface
*/
public abstract class AbstractActionStatusCreate<T> {
protected Status status;
protected Long occurredAt;
protected Integer code;
protected List<@ValidString String> messages;
@Getter
protected Long actionId;
public T status(final Status status) {
this.status = status;
return (T) this;
}
public T occurredAt(final long occurredAt) {
this.occurredAt = occurredAt;
return (T) this;
}
public T code(final int code) {
this.code = code;
return (T) this;
}
public T messages(final Collection<String> messages) {
if (this.messages == null) {
// create modifiable list
this.messages = messages.stream().filter(Objects::nonNull).map(String::strip).collect(Collectors.toCollection(ArrayList::new));
} else {
this.messages.addAll(messages.stream().filter(Objects::nonNull).map(String::strip).toList());
}
return (T) this;
}
public T message(final String message) {
if (message != null) {
if (this.messages == null) {
this.messages = new ArrayList<>();
}
this.messages.add(message.strip());
}
return (T) this;
}
public Optional<Long> getOccurredAt() {
return Optional.ofNullable(occurredAt);
}
}

View File

@@ -1,26 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import org.eclipse.hawkbit.repository.Identifiable;
public abstract class AbstractBaseEntityBuilder implements Identifiable<Long> {
protected Long id;
@Override
public Long getId() {
return id;
}
static String strip(final String value) {
return value == null ? null : value.strip();
}
}

View File

@@ -1,40 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import java.util.Optional;
import org.eclipse.hawkbit.repository.ValidString;
public abstract class AbstractNamedEntityBuilder<T> extends AbstractBaseEntityBuilder {
@ValidString
protected String name;
@ValidString
protected String description;
public T name(final String name) {
this.name = AbstractBaseEntityBuilder.strip(name);
return (T) this;
}
public T description(final String description) {
this.description = AbstractBaseEntityBuilder.strip(description);
return (T) this;
}
public Optional<String> getName() {
return Optional.ofNullable(name);
}
public Optional<String> getDescription() {
return Optional.ofNullable(description);
}
}

View File

@@ -1,47 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
import org.eclipse.hawkbit.repository.ValidString;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
/**
* Create builder DTO.
*
* @param <T> update or create builder interface
*/
public abstract class AbstractRolloutGroupCreate<T> extends AbstractNamedEntityBuilder<T> {
@ValidString
protected String targetFilterQuery;
protected Float targetPercentage;
protected RolloutGroupConditions conditions;
protected boolean confirmationRequired;
public T targetFilterQuery(final String targetFilterQuery) {
this.targetFilterQuery = AbstractBaseEntityBuilder.strip(targetFilterQuery);
return (T) this;
}
public T targetPercentage(final Float targetPercentage) {
this.targetPercentage = targetPercentage;
return (T) this;
}
public T conditions(final RolloutGroupConditions conditions) {
this.conditions = conditions;
return (T) this;
}
public T confirmationRequired(final boolean confirmationRequired) {
this.confirmationRequired = confirmationRequired;
return (T) this;
}
}

View File

@@ -1,20 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.builder;
/**
* Update implementation.
*/
public class GenericRolloutUpdate extends AbstractNamedEntityBuilder<RolloutUpdate> implements RolloutUpdate {
public GenericRolloutUpdate(final Long id) {
super.id = id;
}
}

View File

@@ -1,47 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.jpa;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutGroupBuilder;
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusBuilder;
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupBuilder;
import org.springframework.validation.annotation.Validated;
/**
* JPA Implementation of {@link EntityFactory}.
*/
@Validated
public class JpaEntityFactory implements EntityFactory {
private final RolloutBuilder rolloutBuilder;
@SuppressWarnings("java:S107")
public JpaEntityFactory(final RolloutBuilder rolloutBuilder) {
this.rolloutBuilder = rolloutBuilder;
}
@Override
public ActionStatusBuilder actionStatus() {
return new JpaActionStatusBuilder();
}
@Override
public RolloutGroupBuilder rolloutGroup() {
return new JpaRolloutGroupBuilder();
}
@Override
public RolloutBuilder rollout() {
return rolloutBuilder;
}
}

View File

@@ -21,8 +21,6 @@ import io.micrometer.core.instrument.MeterRegistry;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import org.eclipse.hawkbit.ContextAware; import org.eclipse.hawkbit.ContextAware;
import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.PropertiesQuotaManagement; import org.eclipse.hawkbit.repository.PropertiesQuotaManagement;
import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RepositoryConfiguration; import org.eclipse.hawkbit.repository.RepositoryConfiguration;
@@ -41,7 +39,6 @@ import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryption;
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionSecretsStore; import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionSecretsStore;
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService; import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService;
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor; import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
import org.eclipse.hawkbit.repository.event.ApplicationEventFilter; import org.eclipse.hawkbit.repository.event.ApplicationEventFilter;
import org.eclipse.hawkbit.repository.event.remote.EventEntityManager; import org.eclipse.hawkbit.repository.event.remote.EventEntityManager;
import org.eclipse.hawkbit.repository.event.remote.EventEntityManagerHolder; import org.eclipse.hawkbit.repository.event.remote.EventEntityManagerHolder;
@@ -53,7 +50,6 @@ import org.eclipse.hawkbit.repository.jpa.autoassign.AutoAssignScheduler;
import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoActionCleanup; import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoActionCleanup;
import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoCleanupScheduler; import org.eclipse.hawkbit.repository.jpa.autocleanup.AutoCleanupScheduler;
import org.eclipse.hawkbit.repository.jpa.autocleanup.CleanupTask; import org.eclipse.hawkbit.repository.jpa.autocleanup.CleanupTask;
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutBuilder;
import org.eclipse.hawkbit.repository.jpa.cluster.DistributedLockRepository; import org.eclipse.hawkbit.repository.jpa.cluster.DistributedLockRepository;
import org.eclipse.hawkbit.repository.jpa.cluster.LockProperties; import org.eclipse.hawkbit.repository.jpa.cluster.LockProperties;
import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager; import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
@@ -92,8 +88,6 @@ import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRollou
import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupErrorCondition; import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupErrorCondition;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupSuccessCondition; import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupSuccessCondition;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
@@ -297,15 +291,6 @@ public class JpaRepositoryConfiguration {
return e -> e instanceof TargetPollEvent && !repositoryProperties.isPublishTargetPollEvent(); return e -> e instanceof TargetPollEvent && !repositoryProperties.isPublishTargetPollEvent();
} }
/**
* @param distributionSetManagement for loading {@link Rollout#getDistributionSet()}
* @return RolloutBuilder bean
*/
@Bean
RolloutBuilder rolloutBuilder(final DistributionSetManagement<? extends DistributionSet> distributionSetManagement) {
return new JpaRolloutBuilder(distributionSetManagement);
}
/** /**
* @return the {@link SystemSecurityContext} singleton bean which make it * @return the {@link SystemSecurityContext} singleton bean which make it
* accessible in beans which cannot access the service directly, e.g. * accessible in beans which cannot access the service directly, e.g.
@@ -409,17 +394,6 @@ public class JpaRepositoryConfiguration {
return new DefaultRolloutApprovalStrategy(userAuthoritiesResolver, tenantConfigurationManagement, systemSecurityContext); return new DefaultRolloutApprovalStrategy(userAuthoritiesResolver, tenantConfigurationManagement, systemSecurityContext);
} }
/**
* {@link JpaEntityFactory} bean.
*
* @return a new {@link EntityFactory}
*/
@Bean
@ConditionalOnMissingBean
EntityFactory entityFactory(final RolloutBuilder rolloutBuilder) {
return new JpaEntityFactory(rolloutBuilder);
}
/** /**
* {@link EventEntityManagerHolder} bean. * {@link EventEntityManagerHolder} bean.
* *

View File

@@ -9,8 +9,6 @@
*/ */
package org.eclipse.hawkbit.repository.jpa; package org.eclipse.hawkbit.repository.jpa;
import static org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupCreate.addSuccessAndErrorConditionsAndActions;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Collection; import java.util.Collection;
@@ -719,7 +717,7 @@ public class JpaRolloutExecutor implements RolloutExecutor {
group.setTargetPercentage(lastGroup.isDynamic() ? lastGroup.getTargetPercentage() : lastGroup.getTotalTargets()); group.setTargetPercentage(lastGroup.isDynamic() ? lastGroup.getTargetPercentage() : lastGroup.getTotalTargets());
group.setTargetFilterQuery(lastGroup.getTargetFilterQuery()); group.setTargetFilterQuery(lastGroup.getTargetFilterQuery());
addSuccessAndErrorConditionsAndActions(group, lastGroup.getSuccessCondition(), JpaRolloutManagement.addSuccessAndErrorConditionsAndActions(group, lastGroup.getSuccessCondition(),
lastGroup.getSuccessConditionExp(), lastGroup.getSuccessAction(), lastGroup.getSuccessConditionExp(), lastGroup.getSuccessAction(),
lastGroup.getSuccessActionExp(), lastGroup.getErrorCondition(), lastGroup.getSuccessActionExp(), lastGroup.getErrorCondition(),
lastGroup.getErrorConditionExp(), lastGroup.getErrorAction(), lastGroup.getErrorConditionExp(), lastGroup.getErrorAction(),

View File

@@ -1,25 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.jpa.builder;
import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.ActionStatus;
/**
* Builder implementation for {@link ActionStatus}.
*/
public class JpaActionStatusBuilder implements ActionStatusBuilder {
@Override
public ActionStatusCreate create(final long actionId) {
return new JpaActionStatusCreate(actionId);
}
}

View File

@@ -1,36 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.jpa.builder;
import org.eclipse.hawkbit.repository.builder.AbstractActionStatusCreate;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
/**
* Create/build implementation.
*/
public class JpaActionStatusCreate extends AbstractActionStatusCreate<ActionStatusCreate> implements ActionStatusCreate {
JpaActionStatusCreate(final Long actionId) {
super.actionId = actionId;
}
@Override
public JpaActionStatus build() {
final JpaActionStatus result = new JpaActionStatus(status, getOccurredAt().orElse(System.currentTimeMillis()));
if (messages != null) {
messages.forEach(result::addMessage);
}
if (code != null) {
result.setCode(code);
}
return result;
}
}

View File

@@ -1,40 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.jpa.builder;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.builder.GenericRolloutUpdate;
import org.eclipse.hawkbit.repository.builder.RolloutBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
import org.eclipse.hawkbit.repository.builder.RolloutUpdate;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
/**
* Builder implementation for {@link Rollout}.
*/
public class JpaRolloutBuilder implements RolloutBuilder {
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
public JpaRolloutBuilder(final DistributionSetManagement<? extends DistributionSet> distributionSetManagement) {
this.distributionSetManagement = distributionSetManagement;
}
@Override
public RolloutUpdate update(final long id) {
return new GenericRolloutUpdate(id);
}
@Override
public RolloutCreate create() {
return new JpaRolloutCreate(distributionSetManagement);
}
}

View File

@@ -1,150 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.jpa.builder;
import java.util.Optional;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.ValidString;
import org.eclipse.hawkbit.repository.builder.AbstractNamedEntityBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
public class JpaRolloutCreate extends AbstractNamedEntityBuilder<RolloutCreate> implements RolloutCreate {
protected Long distributionSetId;
@ValidString
protected String targetFilterQuery;
protected Action.ActionType actionType;
protected Long forcedTime;
protected Long startAt;
@Min(Action.WEIGHT_MIN)
@Max(Action.WEIGHT_MAX)
protected Integer weight;
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
private boolean dynamic;
JpaRolloutCreate(final DistributionSetManagement<? extends DistributionSet> distributionSetManagement) {
this.distributionSetManagement = distributionSetManagement;
}
public RolloutCreate distributionSetId(final long distributionSetId) {
this.distributionSetId = distributionSetId;
return this;
}
/**
* Filter of the rollout
*
* @param targetFilterQuery query
* @return this builder
*/
public RolloutCreate targetFilterQuery(final String targetFilterQuery) {
this.targetFilterQuery = targetFilterQuery == null ? null : targetFilterQuery.strip();
return this;
}
/**
* {@link Action.ActionType} used for {@link Action}s
*
* @param actionType type
* @return this builder
*/
public RolloutCreate actionType(final Action.ActionType actionType) {
this.actionType = actionType;
return this;
}
/**
* forcedTime used for {@link Action}s
*
* @param forcedTime time
* @return this builder
*/
public RolloutCreate forcedTime(final Long forcedTime) {
this.forcedTime = forcedTime;
return this;
}
/**
* weight used for {@link Action}s
*
* @param weight weight
* @return this builder
*/
public RolloutCreate weight(final Integer weight) {
this.weight = weight;
return this;
}
public RolloutCreate dynamic(final boolean dynamic) {
this.dynamic = dynamic;
return this;
}
/**
* Set start of the Rollout
*
* @param startAt start time point
* @return this builder
*/
public RolloutCreate startAt(final Long startAt) {
this.startAt = startAt;
return this;
}
@Override
public JpaRollout build() {
final JpaRollout rollout = new JpaRollout();
rollout.setName(name);
rollout.setDescription(description);
rollout.setDistributionSet(distributionSetManagement.getValidAndComplete(distributionSetId));
rollout.setTargetFilterQuery(targetFilterQuery);
rollout.setStartAt(startAt);
rollout.setWeight(weight);
rollout.setDynamic(dynamic);
if (actionType != null) {
rollout.setActionType(actionType);
}
if (forcedTime != null) {
rollout.setForcedTime(forcedTime);
}
return rollout;
}
public Optional<Long> getDistributionSetId() {
return Optional.ofNullable(distributionSetId);
}
public Optional<Action.ActionType> getActionType() {
return Optional.ofNullable(actionType);
}
public Optional<Long> getForcedTime() {
return Optional.ofNullable(forcedTime);
}
public Optional<Integer> getWeight() {
return Optional.ofNullable(weight);
}
public Optional<Long> getStartAt() {
return Optional.ofNullable(startAt);
}
}

View File

@@ -1,25 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.jpa.builder;
import org.eclipse.hawkbit.repository.builder.RolloutGroupBuilder;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
/**
* Builder implementation for {@link RolloutGroup}.
*/
public class JpaRolloutGroupBuilder implements RolloutGroupBuilder {
@Override
public RolloutGroupCreate create() {
return new JpaRolloutGroupCreate();
}
}

View File

@@ -1,77 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.jpa.builder;
import org.eclipse.hawkbit.repository.builder.AbstractRolloutGroupCreate;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
public class JpaRolloutGroupCreate extends AbstractRolloutGroupCreate<RolloutGroupCreate> implements RolloutGroupCreate {
/**
* Set the Success And Error conditions for the rollout group
*
* @param group The Rollout group
* @param conditions The Rollout Success and Error Conditions
*/
public static void addSuccessAndErrorConditionsAndActions(final JpaRolloutGroup group,
final RolloutGroupConditions conditions) {
addSuccessAndErrorConditionsAndActions(group, conditions.getSuccessCondition(),
conditions.getSuccessConditionExp(), conditions.getSuccessAction(), conditions.getSuccessActionExp(),
conditions.getErrorCondition(), conditions.getErrorConditionExp(), conditions.getErrorAction(),
conditions.getErrorActionExp());
}
/**
* Set the Success And Error conditions for the rollout group
*/
@SuppressWarnings("java:S107")
public static void addSuccessAndErrorConditionsAndActions(final JpaRolloutGroup group,
final RolloutGroup.RolloutGroupSuccessCondition successCondition, final String successConditionExp,
final RolloutGroup.RolloutGroupSuccessAction successAction, final String successActionExp,
final RolloutGroup.RolloutGroupErrorCondition errorCondition, final String errorConditionExp,
final RolloutGroup.RolloutGroupErrorAction errorAction, final String errorActionExp) {
group.setSuccessCondition(successCondition);
group.setSuccessConditionExp(successConditionExp);
group.setSuccessAction(successAction);
group.setSuccessActionExp(successActionExp);
group.setErrorCondition(errorCondition);
group.setErrorConditionExp(errorConditionExp);
group.setErrorAction(errorAction);
group.setErrorActionExp(errorActionExp);
}
@Override
public JpaRolloutGroup build() {
final JpaRolloutGroup group = new JpaRolloutGroup();
group.setName(name);
group.setDescription(description);
group.setTargetFilterQuery(targetFilterQuery);
if (targetPercentage == null) {
targetPercentage = 100F;
}
group.setTargetPercentage(targetPercentage);
if (conditions != null) {
addSuccessAndErrorConditionsAndActions(group, conditions);
}
group.setConfirmationRequired(confirmationRequired);
return group;
}
}

View File

@@ -15,13 +15,13 @@ import static org.eclipse.hawkbit.repository.model.Action.Status.FINISHED;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RepositoryProperties; import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_; import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
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;
@@ -31,6 +31,7 @@ import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
@@ -64,22 +65,30 @@ public class JpaActionManagement {
return DOWNLOAD_ONLY == action.getActionType(); return DOWNLOAD_ONLY == action.getActionType();
} }
protected static JpaActionStatus buildJpaActionStatus(final ActionStatusCreate create) {
final JpaActionStatus actionStatus = new JpaActionStatus(
create.getStatus(),
Optional.ofNullable(create.getOccurredAt()).orElseGet(System::currentTimeMillis));
Optional.ofNullable(create.getMessages()).ifPresent(messages -> messages.forEach(actionStatus::addMessage));
actionStatus.setCode(create.getCode());
return actionStatus;
}
protected List<JpaAction> findActiveActionsHavingStatus(final String controllerId, final Action.Status status) { protected List<JpaAction> findActiveActionsHavingStatus(final String controllerId, final Action.Status status) {
return actionRepository.findAll(ActionSpecifications.byTargetControllerIdAndIsActiveAndStatus(controllerId, status)); return actionRepository.findAll(ActionSpecifications.byTargetControllerIdAndIsActiveAndStatus(controllerId, status));
} }
protected Action addActionStatus(final JpaActionStatusCreate statusCreate) { protected Action addActionStatus(final ActionStatusCreate create) {
final Long actionId = statusCreate.getActionId(); final Long actionId = create.getActionId();
final JpaActionStatus actionStatus = statusCreate.build();
final JpaAction action = getActionAndThrowExceptionIfNotFound(actionId); final JpaAction action = getActionAndThrowExceptionIfNotFound(actionId);
if (isUpdatingActionStatusAllowed(action, actionStatus)) { if (isUpdatingActionStatusAllowed(action, create)) {
return handleAddUpdateActionStatus(actionStatus, action); return handleAddUpdateActionStatus(create, action);
} }
log.debug( log.debug(
"Update of actionStatus {} for action {} not possible since action not active anymore and not allowed as an action terminating.", "Update of actionStatus {} for action {} not possible since action not active anymore and not allowed as an action terminating.",
actionStatus.getStatus(), action.getId()); create.getStatus(), action.getId());
return action; return action;
} }
@@ -91,7 +100,7 @@ public class JpaActionManagement {
// can be overwritten to intercept the persistence of the action status // can be overwritten to intercept the persistence of the action status
} }
protected void assertActionStatusQuota(final JpaActionStatus newActionStatus, final JpaAction action) { protected void assertActionStatusQuota(final ActionStatusCreate newActionStatus, final JpaAction action) {
if (isIntermediateStatus(newActionStatus)) {// check for quota only for intermediate statuses if (isIntermediateStatus(newActionStatus)) {// check for quota only for intermediate statuses
QuotaHelper.assertAssignmentQuota(action.getId(), 1, quotaManagement.getMaxStatusEntriesPerAction(), QuotaHelper.assertAssignmentQuota(action.getId(), 1, quotaManagement.getMaxStatusEntriesPerAction(),
ActionStatus.class, Action.class, actionStatusRepository::countByActionId); ActionStatus.class, Action.class, actionStatusRepository::countByActionId);
@@ -123,7 +132,7 @@ public class JpaActionManagement {
.toList(); .toList();
} }
private static boolean isIntermediateStatus(final JpaActionStatus actionStatus) { private static boolean isIntermediateStatus(final ActionStatusCreate actionStatus) {
return FINISHED != actionStatus.getStatus() && ERROR != actionStatus.getStatus(); return FINISHED != actionStatus.getStatus() && ERROR != actionStatus.getStatus();
} }
@@ -134,7 +143,7 @@ public class JpaActionManagement {
* Status.FINISHED are allowed. In the case of a DOWNLOAD_ONLY action, we accept * Status.FINISHED are allowed. In the case of a DOWNLOAD_ONLY action, we accept
* status updates only once. * status updates only once.
*/ */
private boolean isUpdatingActionStatusAllowed(final JpaAction action, final JpaActionStatus actionStatus) { private boolean isUpdatingActionStatusAllowed(final JpaAction action, final ActionStatusCreate actionStatus) {
if (action.isActive()) { if (action.isActive()) {
return true; return true;
} }
@@ -151,9 +160,11 @@ public class JpaActionManagement {
/** /**
* Sets {@link TargetUpdateStatus} based on given {@link ActionStatus}. * Sets {@link TargetUpdateStatus} based on given {@link ActionStatus}.
*/ */
private Action handleAddUpdateActionStatus(final JpaActionStatus actionStatus, final JpaAction action) { private Action handleAddUpdateActionStatus(final ActionStatusCreate create, final JpaAction action) {
// information status entry - check for a potential DOS attack // information status entry - check for a potential DOS attack
assertActionStatusQuota(actionStatus, action); assertActionStatusQuota(create, action);
final JpaActionStatus actionStatus = buildJpaActionStatus(create);
assertActionStatusMessageQuota(actionStatus); assertActionStatusMessageQuota(actionStatus);
actionStatus.setAction(action); actionStatus.setAction(action);

View File

@@ -9,26 +9,24 @@
*/ */
package org.eclipse.hawkbit.repository.jpa.management; package org.eclipse.hawkbit.repository.jpa.management;
import static org.eclipse.hawkbit.repository.RepositoryConstants.SERVER_MESSAGE_PREFIX;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.ConfirmationManagement; import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.RepositoryProperties; import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.exception.AutoConfirmationAlreadyActiveException; import org.eclipse.hawkbit.repository.exception.AutoConfirmationAlreadyActiveException;
import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException; import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException;
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper; import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate;
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;
@@ -39,6 +37,8 @@ import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository; import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate.ActionStatusCreateBuilder;
import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus; import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
@@ -62,18 +62,16 @@ import org.springframework.validation.annotation.Validated;
public class JpaConfirmationManagement extends JpaActionManagement implements ConfirmationManagement { public class JpaConfirmationManagement extends JpaActionManagement implements ConfirmationManagement {
private final EntityManager entityManager; private final EntityManager entityManager;
private final EntityFactory entityFactory;
private final TargetRepository targetRepository; private final TargetRepository targetRepository;
protected JpaConfirmationManagement( protected JpaConfirmationManagement(
final TargetRepository targetRepository, final TargetRepository targetRepository,
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository, final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
final RepositoryProperties repositoryProperties, final QuotaManagement quotaManagement, final RepositoryProperties repositoryProperties, final QuotaManagement quotaManagement,
final EntityManager entityManager, final EntityFactory entityFactory) { final EntityManager entityManager) {
super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties); super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties);
this.targetRepository = targetRepository; this.targetRepository = targetRepository;
this.entityManager = entityManager; this.entityManager = entityManager;
this.entityFactory = entityFactory;
} }
@Override @Override
@@ -116,11 +114,8 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
if (deviceMessages != null) { if (deviceMessages != null) {
messages.addAll(deviceMessages); messages.addAll(deviceMessages);
} }
messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target confirmed action." messages.add(SERVER_MESSAGE_PREFIX + "Target confirmed action. Therefore, it will be set to the running state to proceed with the deployment.");
+ " Therefore, it will be set to the running state to proceed with the deployment."); return addActionStatus(createConfirmationActionStatus(action.getId(), code, messages).status(Status.RUNNING).build());
final ActionStatusCreate statusCreate = createConfirmationActionStatus(action.getId(), code, messages)
.status(Status.RUNNING);
return addActionStatus((JpaActionStatusCreate) statusCreate);
} }
@Override @Override
@@ -135,10 +130,8 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
if (deviceMessages != null) { if (deviceMessages != null) {
messages.addAll(deviceMessages); messages.addAll(deviceMessages);
} }
messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target rejected action. Action will stay in confirmation pending state."); messages.add(SERVER_MESSAGE_PREFIX + "Target rejected action. Action will stay in confirmation pending state.");
final ActionStatusCreate statusCreate = createConfirmationActionStatus(action.getId(), code, messages) return addActionStatus(createConfirmationActionStatus(action.getId(), code, messages).status(Status.WAIT_FOR_CONFIRMATION).build());
.status(Status.WAIT_FOR_CONFIRMATION);
return addActionStatus((JpaActionStatusCreate) statusCreate);
} }
@Override @Override
@@ -186,14 +179,22 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
} }
} }
private ActionStatusCreate createConfirmationActionStatus(final long actionId, final Integer code, final Collection<String> messages) { private ActionStatusCreateBuilder createConfirmationActionStatus(
final ActionStatusCreate statusCreate = entityFactory.actionStatus().create(actionId); final long actionId, final Integer code, final Collection<String> messages) {
if (!CollectionUtils.isEmpty(messages)) { final ActionStatusCreateBuilder statusCreate = ActionStatusCreate.builder().actionId(actionId);
statusCreate.messages(messages); if (code == null) {
} if (!CollectionUtils.isEmpty(messages)) {
if (code != null) { statusCreate.messages(messages);
}
} else {
statusCreate.code(code); statusCreate.code(code);
statusCreate.message(String.format(CONFIRMATION_CODE_MSG_PREFIX, code)); if (CollectionUtils.isEmpty(messages)) {
statusCreate.messages(List.of(String.format(CONFIRMATION_CODE_MSG_PREFIX, code)));
} else {
final List<String> messagesWithCode = new ArrayList<>(messages);
messagesWithCode.add(String.format(CONFIRMATION_CODE_MSG_PREFIX, code));
statusCreate.messages(messagesWithCode);
}
} }
return statusCreate; return statusCreate;
} }
@@ -209,11 +210,8 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
log.debug("Auto-confirming action is not necessary, since action {} is in RUNNING state already.", action.getId()); log.debug("Auto-confirming action is not necessary, since action {} is in RUNNING state already.", action.getId());
return action; return action;
} }
final JpaActionStatus actionStatus = (JpaActionStatus) entityFactory.actionStatus() final JpaActionStatus actionStatus = new JpaActionStatus(Status.RUNNING, System.currentTimeMillis());
.create(action.getId()) actionStatus.addMessage(autoConfirmationStatus.constructActionMessage());
.status(Status.RUNNING)
.messages(Collections.singletonList(autoConfirmationStatus.constructActionMessage()))
.build();
log.debug( log.debug(
"Automatically confirm actionId '{}' due to active auto-confirmation initiated by '{}' and rollouts system user '{}'", "Automatically confirm actionId '{}' due to active auto-confirmation initiated by '{}' and rollouts system user '{}'",
action.getId(), autoConfirmationStatus.getInitiator(), autoConfirmationStatus.getCreatedBy()); action.getId(), autoConfirmationStatus.getInitiator(), autoConfirmationStatus.getCreatedBy());

View File

@@ -49,7 +49,6 @@ import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper; import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RepositoryConstants;
@@ -59,7 +58,6 @@ import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.TargetTypeManagement; import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.UpdateMode;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.event.EventPublisherHolder; import org.eclipse.hawkbit.repository.event.EventPublisherHolder;
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent; import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent; import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
@@ -70,7 +68,6 @@ 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.jpa.Jpa; import org.eclipse.hawkbit.repository.jpa.Jpa;
import org.eclipse.hawkbit.repository.jpa.acm.AccessController; import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants; import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_; import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
@@ -91,6 +88,7 @@ import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper; import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
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;
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus; import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
@@ -240,17 +238,13 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
@Transactional(isolation = Isolation.READ_COMMITTED) @Transactional(isolation = Isolation.READ_COMMITTED)
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY)) backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public Action addCancelActionStatus(final ActionStatusCreate c) { public Action addCancelActionStatus(final ActionStatusCreate create) {
final JpaActionStatusCreate create = (JpaActionStatusCreate) c;
final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId()); final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId());
if (!action.isCancelingOrCanceled()) { if (!action.isCancelingOrCanceled()) {
throw new CancelActionNotAllowedException("The action is not in canceling state."); throw new CancelActionNotAllowedException("The action is not in canceling state.");
} }
final JpaActionStatus actionStatus = create.build(); final JpaActionStatus actionStatus = buildJpaActionStatus(create);
switch (actionStatus.getStatus()) { switch (actionStatus.getStatus()) {
case CANCELED, FINISHED: { case CANCELED, FINISHED: {
handleFinishedCancelation(actionStatus, action); handleFinishedCancelation(actionStatus, action);
@@ -263,7 +257,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
} }
default: { default: {
// information status entry - check for a potential DOS attack // information status entry - check for a potential DOS attack
assertActionStatusQuota(actionStatus, action); assertActionStatusQuota(create, action);
assertActionStatusMessageQuota(actionStatus); assertActionStatusMessageQuota(actionStatus);
break; break;
} }
@@ -289,16 +283,15 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
@Transactional @Transactional
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY)) backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public ActionStatus addInformationalActionStatus(final ActionStatusCreate c) { public ActionStatus addInformationalActionStatus(final ActionStatusCreate create) {
final JpaActionStatusCreate create = (JpaActionStatusCreate) c;
final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId()); final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId());
final JpaActionStatus statusMessage = create.build(); assertActionStatusQuota(create, action);
statusMessage.setAction(action);
assertActionStatusQuota(statusMessage, action); final JpaActionStatus actionStatus = buildJpaActionStatus(create);
assertActionStatusMessageQuota(statusMessage); actionStatus.setAction(action);
assertActionStatusMessageQuota(actionStatus);
return actionStatusRepository.save(statusMessage); return actionStatusRepository.save(actionStatus);
} }
@Override @Override
@@ -306,7 +299,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY)) backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public Action addUpdateActionStatus(final ActionStatusCreate statusCreate) { public Action addUpdateActionStatus(final ActionStatusCreate statusCreate) {
return addActionStatus((JpaActionStatusCreate) statusCreate); return addActionStatus(statusCreate);
} }
@Override @Override

View File

@@ -9,16 +9,14 @@
*/ */
package org.eclipse.hawkbit.repository.jpa.management; package org.eclipse.hawkbit.repository.jpa.management;
import static org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupCreate.addSuccessAndErrorConditionsAndActions;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import jakarta.validation.ConstraintDeclarationException; import jakarta.validation.ConstraintDeclarationException;
@@ -40,19 +38,15 @@ import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.RolloutStatusCache; import org.eclipse.hawkbit.repository.RolloutStatusCache;
import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate;
import org.eclipse.hawkbit.repository.builder.GenericRolloutUpdate;
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
import org.eclipse.hawkbit.repository.builder.RolloutUpdate;
import org.eclipse.hawkbit.repository.event.EventPublisherHolder; import org.eclipse.hawkbit.repository.event.EventPublisherHolder;
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEvent;
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.IncompleteDistributionSetException;
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException; import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper; import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupCreate;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants; import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_; import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
@@ -80,6 +74,7 @@ import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.utils.ObjectCopyUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -89,7 +84,6 @@ import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -181,14 +175,15 @@ public class JpaRolloutManagement implements RolloutManagement {
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY)) backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public Rollout create( public Rollout create(
final RolloutCreate rollout, final int amountGroup, final boolean confirmationRequired, final Create rollout, final int amountGroup, final boolean confirmationRequired,
final RolloutGroupConditions conditions, final DynamicRolloutGroupTemplate dynamicRolloutGroupTemplate) { final RolloutGroupConditions conditions, final DynamicRolloutGroupTemplate dynamicRolloutGroupTemplate) {
return create0(rollout, amountGroup, confirmationRequired, conditions, dynamicRolloutGroupTemplate); return create0(rollout, amountGroup, confirmationRequired, conditions, dynamicRolloutGroupTemplate);
} }
private Rollout create0( private Rollout create0(
final RolloutCreate rollout, final int amountGroup, final boolean confirmationRequired, final Create rollout, final int amountGroup, final boolean confirmationRequired,
final RolloutGroupConditions conditions, final DynamicRolloutGroupTemplate dynamicRolloutGroupTemplate) { final RolloutGroupConditions conditions, final DynamicRolloutGroupTemplate dynamicRolloutGroupTemplate) {
validateDs(rollout);
if (amountGroup < 0) { if (amountGroup < 0) {
throw new ValidationException("The amount of groups cannot be lower than or equal to zero for static rollouts"); throw new ValidationException("The amount of groups cannot be lower than or equal to zero for static rollouts");
} else if (amountGroup == 0) { } else if (amountGroup == 0) {
@@ -200,7 +195,9 @@ public class JpaRolloutManagement implements RolloutManagement {
RolloutHelper.verifyRolloutGroupAmount(amountGroup, quotaManagement); RolloutHelper.verifyRolloutGroupAmount(amountGroup, quotaManagement);
} }
final JpaRollout rolloutRequest = (JpaRollout) rollout.build(); final JpaRollout rolloutRequest = new JpaRollout();
ObjectCopyUtil.copy(rollout, rolloutRequest, false, UnaryOperator.identity());
rolloutRequest.setDynamic(rollout.isDynamic()); // TODO - copy compares isDynamic == false and don't set it to false - remain null
// scheduled rollout, the creator shall have permissions to start rollout // scheduled rollout, the creator shall have permissions to start rollout
if (rolloutRequest.getStartAt() != null && rolloutRequest.getStartAt() != Long.MAX_VALUE && // if scheduled rollout if (rolloutRequest.getStartAt() != null && rolloutRequest.getStartAt() != Long.MAX_VALUE && // if scheduled rollout
!systemSecurityContext.hasPermission(SpPermission.HANDLE_ROLLOUT) && !systemSecurityContext.hasPermission(SpPermission.HANDLE_ROLLOUT) &&
@@ -220,7 +217,7 @@ public class JpaRolloutManagement implements RolloutManagement {
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY)) backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public Rollout create( public Rollout create(
@NotNull @Valid RolloutCreate create, int amountGroup, boolean confirmationRequired, @NotNull @Valid Create create, int amountGroup, boolean confirmationRequired,
@NotNull RolloutGroupConditions conditions) { @NotNull RolloutGroupConditions conditions) {
return create0(create, amountGroup, confirmationRequired, conditions, null); return create0(create, amountGroup, confirmationRequired, conditions, null);
} }
@@ -229,29 +226,16 @@ public class JpaRolloutManagement implements RolloutManagement {
@Transactional @Transactional
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY)) backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public Rollout create(final RolloutCreate rollout, final List<RolloutGroupCreate> groups, final RolloutGroupConditions conditions) { public Rollout create(final Create rollout, final List<GroupCreate> groups, final RolloutGroupConditions conditions) {
if (groups.isEmpty()) { if (groups.isEmpty()) {
throw new ValidationException("The amount of groups cannot be 0"); throw new ValidationException("The amount of groups cannot be 0");
} }
validateDs(rollout);
RolloutHelper.verifyRolloutGroupAmount(groups.size(), quotaManagement); RolloutHelper.verifyRolloutGroupAmount(groups.size(), quotaManagement);
return createRolloutGroups(groups, conditions, createRollout((JpaRollout) rollout.build(), false)); final JpaRollout rolloutRequest = new JpaRollout();
} ObjectCopyUtil.copy(rollout, rolloutRequest, false, UnaryOperator.identity());
rolloutRequest.setDynamic(rollout.isDynamic()); // TODO - copy compares isDynamic == false and don't set it to false - remain null
@Override return createRolloutGroups(groups, conditions, createRollout(rolloutRequest, false));
@Async
public CompletableFuture<RolloutGroupsValidation> validateTargetsInGroups(
final List<RolloutGroupCreate> groups, final String targetFilter, final Long createdAt, final Long dsTypeId) {
final TargetCount targets = calculateTargets(targetFilter, createdAt, dsTypeId);
long totalTargets = targets.total();
final String baseFilter = targets.filter();
if (totalTargets == 0) {
throw new ConstraintDeclarationException("Rollout target filter does not match any targets");
}
return CompletableFuture.completedFuture(
validateTargetsInGroups(groups.stream().map(RolloutGroupCreate::build).toList(), baseFilter, totalTargets, dsTypeId));
} }
@Override @Override
@@ -413,14 +397,11 @@ public class JpaRolloutManagement implements RolloutManagement {
@Transactional @Transactional
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY)) backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public Rollout update(final RolloutUpdate u) { public Rollout update(final Update update) {
final GenericRolloutUpdate update = (GenericRolloutUpdate) u;
final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(update.getId()); final JpaRollout rollout = getRolloutOrThrowExceptionIfNotFound(update.getId());
checkIfDeleted(update.getId(), rollout.getStatus()); checkIfDeleted(update.getId(), rollout.getStatus());
update.getName().ifPresent(rollout::setName); ObjectCopyUtil.copy(update, rollout, false, UnaryOperator.identity());
update.getDescription().ifPresent(rollout::setDescription);
return rolloutRepository.save(rollout); return rolloutRepository.save(rollout);
} }
@@ -492,15 +473,24 @@ public class JpaRolloutManagement implements RolloutManagement {
return rollouts; return rollouts;
} }
private static void validateDs(final Create rollout) {
if (!rollout.getDistributionSet().isValid()) {
throw new InvalidDistributionSetException("The distribution set is not valid");
}
if (!rollout.getDistributionSet().isComplete()) {
throw new IncompleteDistributionSetException("The distribution set is not complete");
}
}
/** /**
* In case the given group is missing conditions or actions, they will be set from the supplied default conditions. * In case the given group is missing conditions or actions, they will be set from the supplied default conditions.
* *
* @param create group to check * @param create group to check
* @param conditions default conditions and actions * @param conditions default conditions and actions
*/ */
private static JpaRolloutGroup prepareRolloutGroupWithDefaultConditions( private static JpaRolloutGroup prepareRolloutGroupWithDefaultConditions(final GroupCreate create, final RolloutGroupConditions conditions) {
final RolloutGroupCreate create, final RolloutGroupConditions conditions) { final JpaRolloutGroup group = new JpaRolloutGroup();
final JpaRolloutGroup group = ((JpaRolloutGroupCreate) create).build(); ObjectCopyUtil.copy(create, group, false, UnaryOperator.identity());
if (group.getSuccessCondition() == null) { if (group.getSuccessCondition() == null) {
group.setSuccessCondition(conditions.getSuccessCondition()); group.setSuccessCondition(conditions.getSuccessCondition());
@@ -554,8 +544,7 @@ public class JpaRolloutManagement implements RolloutManagement {
distributionSet.getType().getId()); distributionSet.getType().getId());
errMsg = "No failed targets in Rollout"; errMsg = "No failed targets in Rollout";
} else { } else {
totalTargets = targetManagement.countByRsqlAndCompatible(rollout.getTargetFilterQuery(), totalTargets = targetManagement.countByRsqlAndCompatible(rollout.getTargetFilterQuery(), distributionSet.getType().getId());
distributionSet.getType().getId());
errMsg = "Rollout does not match any existing targets"; errMsg = "Rollout does not match any existing targets";
} }
if (totalTargets == 0) { if (totalTargets == 0) {
@@ -575,6 +564,13 @@ public class JpaRolloutManagement implements RolloutManagement {
return rollout; return rollout;
} }
private static void addSuccessAndErrorConditionsAndActions(final JpaRolloutGroup group, final RolloutGroupConditions conditions) {
addSuccessAndErrorConditionsAndActions(group, conditions.getSuccessCondition(),
conditions.getSuccessConditionExp(), conditions.getSuccessAction(), conditions.getSuccessActionExp(),
conditions.getErrorCondition(), conditions.getErrorConditionExp(), conditions.getErrorAction(),
conditions.getErrorActionExp());
}
@SuppressWarnings("java:S2259") // java:S2259 - false positive, see the java:S2259 comment in code @SuppressWarnings("java:S2259") // java:S2259 - false positive, see the java:S2259 comment in code
private Rollout createRolloutGroups( private Rollout createRolloutGroups(
final int amountOfGroups, final RolloutGroupConditions conditions, final int amountOfGroups, final RolloutGroupConditions conditions,
@@ -649,7 +645,7 @@ public class JpaRolloutManagement implements RolloutManagement {
} }
private Rollout createRolloutGroups( private Rollout createRolloutGroups(
final List<RolloutGroupCreate> groupList, final RolloutGroupConditions conditions, final JpaRollout rollout) { final List<GroupCreate> groupList, final RolloutGroupConditions conditions, final JpaRollout rollout) {
RolloutHelper.verifyRolloutInStatus(rollout, RolloutStatus.CREATING); RolloutHelper.verifyRolloutInStatus(rollout, RolloutStatus.CREATING);
final DistributionSetType distributionSetType = rollout.getDistributionSet().getType(); final DistributionSetType distributionSetType = rollout.getDistributionSet().getType();
@@ -706,6 +702,24 @@ public class JpaRolloutManagement implements RolloutManagement {
return savedRollout; return savedRollout;
} }
public static void addSuccessAndErrorConditionsAndActions(final JpaRolloutGroup group,
final RolloutGroup.RolloutGroupSuccessCondition successCondition, final String successConditionExp,
final RolloutGroup.RolloutGroupSuccessAction successAction, final String successActionExp,
final RolloutGroup.RolloutGroupErrorCondition errorCondition, final String errorConditionExp,
final RolloutGroup.RolloutGroupErrorAction errorAction, final String errorActionExp) {
group.setSuccessCondition(successCondition);
group.setSuccessConditionExp(successConditionExp);
group.setSuccessAction(successAction);
group.setSuccessActionExp(successActionExp);
group.setErrorCondition(errorCondition);
group.setErrorConditionExp(errorConditionExp);
group.setErrorAction(errorAction);
group.setErrorActionExp(errorActionExp);
}
private JpaRollout getRolloutOrThrowExceptionIfNotFound(final Long rolloutId) { private JpaRollout getRolloutOrThrowExceptionIfNotFound(final Long rolloutId) {
return rolloutRepository.findById(rolloutId) return rolloutRepository.findById(rolloutId)
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId)); .orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));

View File

@@ -154,7 +154,7 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
private Boolean dynamic; private Boolean dynamic;
@Setter @Setter
@Column(name = "access_control_context", nullable = true) @Column(name = "access_control_context")
private String accessControlContext; private String accessControlContext;
@Setter @Setter

View File

@@ -45,6 +45,7 @@ public class JpaSoftwareModuleType extends AbstractJpaTypeEntity implements Soft
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Setter(value = lombok.AccessLevel.PRIVATE) // used via reflection
@Column(name = "max_ds_assignments", nullable = false) @Column(name = "max_ds_assignments", nullable = false)
@Min(1) @Min(1)
private int maxAssignments; private int maxAssignments;

View File

@@ -12,6 +12,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
import java.util.Set; import java.util.Set;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.RolloutManagement.Create;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
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;
@@ -52,7 +53,7 @@ class RolloutEventTest extends AbstractRemoteEntityEventTest<Rollout> {
.build()); .build());
return rolloutManagement.create( return rolloutManagement.create(
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").distributionSetId(ds), Create.builder().name("exampleRollout").targetFilterQuery("controllerId==*").distributionSet(ds).build(),
5, 5,
false, false,
new RolloutGroupConditionBuilder().withDefaults().successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10").build()); new RolloutGroupConditionBuilder().withDefaults().successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10").build());

View File

@@ -15,6 +15,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.RolloutManagement.Create;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
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;
@@ -93,7 +94,7 @@ class RolloutGroupEventTest extends AbstractRemoteEntityEventTest<RolloutGroup>
.build()); .build());
final Rollout entity = rolloutManagement.create( final Rollout entity = rolloutManagement.create(
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").distributionSetId(ds), Create.builder().name("exampleRollout").targetFilterQuery("controllerId==*").distributionSet(ds).build(),
5, 5,
false, false,
new RolloutGroupConditionBuilder().withDefaults().successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10").build()); new RolloutGroupConditionBuilder().withDefaults().successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10").build());

View File

@@ -57,6 +57,7 @@ import org.eclipse.hawkbit.repository.jpa.repository.TenantMetaDataRepository;
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetFilter; import org.eclipse.hawkbit.repository.model.DistributionSetFilter;
import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTag;
@@ -300,7 +301,8 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
} }
protected void finishAction(final Action action) { protected void finishAction(final Action action) {
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(Action.Status.FINISHED)); controllerManagement.addUpdateActionStatus(
ActionStatusCreate.builder().actionId(action.getId()).status(Action.Status.FINISHED).build());
} }
protected Set<TargetTag> getTargetTags(final String controllerId) { protected Set<TargetTag> getTargetTags(final String controllerId) {

View File

@@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.awaitility.Awaitility; import org.awaitility.Awaitility;
import org.eclipse.hawkbit.repository.RolloutManagement.Create;
import org.eclipse.hawkbit.repository.exception.StopRolloutException; import org.eclipse.hawkbit.repository.exception.StopRolloutException;
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup; import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository; import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
@@ -92,9 +93,10 @@ class ConcurrentDistributionSetInvalidationTest extends AbstractJpaIntegrationTe
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, "80") .errorCondition(RolloutGroupErrorCondition.THRESHOLD, "80")
.errorAction(RolloutGroupErrorAction.PAUSE, null).build(); .errorAction(RolloutGroupErrorAction.PAUSE, null).build();
return rolloutManagement.create(entityFactory.rollout().create() return rolloutManagement.create(Create.builder()
.name("verifyInvalidateDistributionSetWithLargeRolloutThrowsException").description("desc") .name("verifyInvalidateDistributionSetWithLargeRolloutThrowsException").description("desc")
.targetFilterQuery("name==*").distributionSetId(distributionSet).actionType(ActionType.FORCED), .targetFilterQuery("name==*").distributionSet(distributionSet).actionType(ActionType.FORCED)
.build(),
quotaManagement.getMaxRolloutGroupsPerRollout(), false, conditions); quotaManagement.getMaxRolloutGroupsPerRollout(), false, conditions);
} }

View File

@@ -19,6 +19,7 @@ import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
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;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
@@ -202,7 +203,7 @@ class AutoActionCleanupTest extends AbstractJpaIntegrationTest {
} }
private void setActionToFailed(final Long id) { private void setActionToFailed(final Long id) {
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(id).status(Status.ERROR)); controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(id).status(Status.ERROR).build());
} }
private void setupCleanupConfiguration(final boolean cleanupEnabled, final long expiry, final Status... status) { private void setupCleanupConfiguration(final boolean cleanupEnabled, final long expiry, final Status... status) {

View File

@@ -18,6 +18,7 @@ import org.awaitility.Awaitility;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
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;
@@ -91,7 +92,7 @@ class ActionTest extends AbstractJpaIntegrationTest {
void testActionsStatusStatusConvert() { void testActionsStatusStatusConvert() {
for (final Status status : Status.values()) { for (final Status status : Status.values()) {
final long id = createAction().getId(); final long id = createAction().getId();
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(id).status(status)); controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(id).status(status).build());
final List<ActionStatus> actionStatuses = actionRepository final List<ActionStatus> actionStatuses = actionRepository
.findById(id).orElseThrow(() -> new IllegalStateException("Action not found")) .findById(id).orElseThrow(() -> new IllegalStateException("Action not found"))
.getActionStatus(); .getActionStatus();

View File

@@ -18,6 +18,8 @@ import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@@ -33,7 +35,8 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest {
*/ */
@Test @Test
void addCancelActionStatusPermissionsCheck() { void addCancelActionStatusPermissionsCheck() {
assertPermissions(() -> controllerManagement.addCancelActionStatus(entityFactory.actionStatus().create(0L)), assertPermissions(() -> controllerManagement.addCancelActionStatus(
ActionStatusCreate.builder().actionId(0L).status(Action.Status.DOWNLOADED).build()),
List.of(SpringEvalExpressions.CONTROLLER_ROLE)); List.of(SpringEvalExpressions.CONTROLLER_ROLE));
} }
@@ -59,7 +62,8 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest {
*/ */
@Test @Test
void addInformationalActionStatusPermissionsCheck() { void addInformationalActionStatusPermissionsCheck() {
assertPermissions(() -> controllerManagement.addInformationalActionStatus(entityFactory.actionStatus().create(0L)), assertPermissions(() -> controllerManagement.addInformationalActionStatus(
ActionStatusCreate.builder().actionId(0L).status(Action.Status.DOWNLOADED).build()),
List.of(SpringEvalExpressions.CONTROLLER_ROLE)); List.of(SpringEvalExpressions.CONTROLLER_ROLE));
} }
@@ -68,7 +72,8 @@ class ControllerManagementSecurityTest extends AbstractJpaIntegrationTest {
*/ */
@Test @Test
void addUpdateActionStatusPermissionsCheck() { void addUpdateActionStatusPermissionsCheck() {
assertPermissions(() -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(0L)), assertPermissions(() -> controllerManagement.addUpdateActionStatus(
ActionStatusCreate.builder().actionId(0L).status(Action.Status.DOWNLOADED).build()),
List.of(SpringEvalExpressions.CONTROLLER_ROLE)); List.of(SpringEvalExpressions.CONTROLLER_ROLE));
} }

View File

@@ -25,7 +25,6 @@ import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -41,7 +40,6 @@ import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.RepositoryProperties; import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.TargetTypeManagement; import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.UpdateMode;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent; import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent; import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
@@ -67,6 +65,8 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate.ActionStatusCreateBuilder;
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;
import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.Artifact;
@@ -202,14 +202,14 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId = getFirstAssignedActionId(assignDistributionSet(testDs, testTarget)); final Long actionId = getFirstAssignedActionId(assignDistributionSet(testDs, testTarget));
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId) controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId)
.status(Action.Status.RUNNING).occurredAt(System.currentTimeMillis()) .status(Action.Status.RUNNING).occurredAt(System.currentTimeMillis()).messages(List.of("proceeding message 1"))
.messages(List.of("proceeding message 1"))); .build());
waitNextMillis(); waitNextMillis();
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId) controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId)
.status(Action.Status.RUNNING).occurredAt(System.currentTimeMillis()) .status(Action.Status.RUNNING).occurredAt(System.currentTimeMillis()).messages(List.of("proceeding message 2"))
.messages(List.of("proceeding message 2"))); .build());
final List<String> messages = controllerManagement.getActionHistoryMessages(actionId, 2); final List<String> messages = controllerManagement.getActionHistoryMessages(actionId, 2);
@@ -240,23 +240,23 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId1 = getFirstAssignedActionId(assignDistributionSet( final Long actionId1 = getFirstAssignedActionId(assignDistributionSet(
testdataFactory.createDistributionSet("ds1"), testdataFactory.createTargets(1, "t1"))); testdataFactory.createDistributionSet("ds1"), testdataFactory.createTargets(1, "t1")));
assertThat(actionId1).isNotNull(); assertThat(actionId1).isNotNull();
final ActionStatusCreate status = entityFactory.actionStatus().create(actionId1).status(Status.WARNING); final ActionStatusCreateBuilder status = ActionStatusCreate.builder().actionId(actionId1).status(Status.WARNING);
for (int i = 0; i < maxStatusEntries; ++i) { for (int i = 0; i < maxStatusEntries; ++i) {
controllerManagement.addInformationalActionStatus(status.message("Msg " + i).occurredAt(System.currentTimeMillis())); controllerManagement.addInformationalActionStatus(status.messages(List.of("Msg " + i)).occurredAt(System.currentTimeMillis()).build());
} }
assertThatExceptionOfType(AssignmentQuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> controllerManagement.addInformationalActionStatus(status)); .isThrownBy(() -> controllerManagement.addInformationalActionStatus(status.build()));
// test for update status (and mixed case) // test for update status (and mixed case)
final Long actionId2 = getFirstAssignedActionId(assignDistributionSet( final Long actionId2 = getFirstAssignedActionId(assignDistributionSet(
testdataFactory.createDistributionSet("ds2"), testdataFactory.createTargets(1, "t2"))); testdataFactory.createDistributionSet("ds2"), testdataFactory.createTargets(1, "t2")));
assertThat(actionId2).isNotEqualTo(actionId1); assertThat(actionId2).isNotEqualTo(actionId1);
final ActionStatusCreate statusWarning = entityFactory.actionStatus().create(actionId2).status(Status.WARNING); final ActionStatusCreateBuilder statusWarning = ActionStatusCreate.builder().actionId(actionId2).status(Status.WARNING);
for (int i = 0; i < maxStatusEntries; ++i) { for (int i = 0; i < maxStatusEntries; ++i) {
controllerManagement.addUpdateActionStatus(statusWarning.message("Msg " + i).occurredAt(System.currentTimeMillis())); controllerManagement.addUpdateActionStatus(statusWarning.messages(List.of("Msg " + i)).occurredAt(System.currentTimeMillis()).build());
} }
assertThatExceptionOfType(AssignmentQuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> controllerManagement.addInformationalActionStatus(statusWarning)); .isThrownBy(() -> controllerManagement.addInformationalActionStatus(statusWarning.build()));
} }
/** /**
@@ -283,10 +283,11 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
IntStream.range(0, maxMessages).forEach(i -> messages.add(i, "msg")); IntStream.range(0, maxMessages).forEach(i -> messages.add(i, "msg"));
assertThat(controllerManagement.addInformationalActionStatus( assertThat(controllerManagement.addInformationalActionStatus(
entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))).isNotNull(); ActionStatusCreate.builder().actionId(actionId).messages(messages).status(Status.WARNING).build())).isNotNull();
messages.add("msg"); messages.add("msg");
final ActionStatusCreate statusToManyMessages = entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING); final ActionStatusCreate statusToManyMessages = ActionStatusCreate.builder()
.actionId(actionId).messages(messages).status(Status.WARNING).build();
assertThatExceptionOfType(AssignmentQuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> controllerManagement.addInformationalActionStatus(statusToManyMessages)); .isThrownBy(() -> controllerManagement.addInformationalActionStatus(statusToManyMessages));
} }
@@ -308,8 +309,8 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
testdataFactory.createTarget(); testdataFactory.createTarget();
final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID);
assertThat(actionId).isNotNull(); assertThat(actionId).isNotNull();
controllerManagement controllerManagement.addUpdateActionStatus(
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOAD)); ActionStatusCreate.builder().actionId(actionId).status(Status.DOWNLOAD).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING,
Action.Status.DOWNLOAD, true); Action.Status.DOWNLOAD, true);
@@ -355,13 +356,13 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final SoftwareModule module = testdataFactory.createSoftwareModuleOs(); final SoftwareModule module = testdataFactory.createSoftwareModuleOs();
verifyThrownExceptionBy(() -> controllerManagement.addCancelActionStatus( verifyThrownExceptionBy(() -> controllerManagement.addCancelActionStatus(
entityFactory.actionStatus().create(NOT_EXIST_IDL).status(Action.Status.FINISHED)), "Action"); ActionStatusCreate.builder().actionId(NOT_EXIST_IDL).status(Action.Status.FINISHED).build()), "Action");
verifyThrownExceptionBy(() -> controllerManagement.addInformationalActionStatus( verifyThrownExceptionBy(() -> controllerManagement.addInformationalActionStatus(
entityFactory.actionStatus().create(NOT_EXIST_IDL).status(Action.Status.RUNNING)), "Action"); ActionStatusCreate.builder().actionId(NOT_EXIST_IDL).status(Action.Status.RUNNING).build()), "Action");
verifyThrownExceptionBy(() -> controllerManagement.addUpdateActionStatus( verifyThrownExceptionBy(() -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(NOT_EXIST_IDL).status(Action.Status.FINISHED)), "Action"); ActionStatusCreate.builder().actionId(NOT_EXIST_IDL).status(Action.Status.FINISHED).build()), "Action");
verifyThrownExceptionBy(() -> controllerManagement verifyThrownExceptionBy(() -> controllerManagement
.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), NOT_EXIST_IDL), .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), NOT_EXIST_IDL),
@@ -403,7 +404,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
simulateIntermediateStatusOnUpdate(actionId); simulateIntermediateStatusOnUpdate(actionId);
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.FINISHED).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.FINISHED, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.FINISHED,
Action.Status.FINISHED, false); Action.Status.FINISHED, false);
@@ -429,14 +430,8 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
simulateIntermediateStatusOnUpdate(actionId); simulateIntermediateStatusOnUpdate(actionId);
final ActionStatusCreate statusSingleMessage = entityFactory.actionStatus().create(actionId) final ActionStatusCreate statusMulipleMessages = ActionStatusCreate.builder().actionId(actionId)
.status(Status.FINISHED).message(INVALID_TEXT_HTML); .status(Status.FINISHED).messages(List.of("this is valid.", INVALID_TEXT_HTML)).build();
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set invalid description text should not be created")
.isThrownBy(() -> controllerManagement.addUpdateActionStatus(statusSingleMessage));
final ActionStatusCreate statusMulipleMessages = entityFactory.actionStatus().create(actionId)
.status(Status.FINISHED).messages(Arrays.asList("this is valid.", INVALID_TEXT_HTML));
assertThatExceptionOfType(ConstraintViolationException.class) assertThatExceptionOfType(ConstraintViolationException.class)
.as("set invalid description text should not be created") .as("set invalid description text should not be created")
.isThrownBy(() -> controllerManagement.addUpdateActionStatus(statusMulipleMessages)); .isThrownBy(() -> controllerManagement.addUpdateActionStatus(statusMulipleMessages));
@@ -467,7 +462,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
deploymentManagement.cancelAction(actionId); deploymentManagement.cancelAction(actionId);
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.FINISHED).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.FINISHED, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.FINISHED,
Action.Status.FINISHED, false); Action.Status.FINISHED, false);
@@ -491,7 +486,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
void cancellationFeedbackRejectedIfActionIsNotInCanceling() { void cancellationFeedbackRejectedIfActionIsNotInCanceling() {
final Long actionId = createTargetAndAssignDs(); final Long actionId = createTargetAndAssignDs();
final ActionStatusCreate status = entityFactory.actionStatus().create(actionId).status(Status.FINISHED); final ActionStatusCreate status = ActionStatusCreate.builder().actionId(actionId).status(Status.FINISHED).build();
assertThatExceptionOfType(CancelActionNotAllowedException.class) assertThatExceptionOfType(CancelActionNotAllowedException.class)
.as("Expected " + CancelActionNotAllowedException.class.getName()) .as("Expected " + CancelActionNotAllowedException.class.getName())
.isThrownBy(() -> controllerManagement.addCancelActionStatus(status)); .isThrownBy(() -> controllerManagement.addCancelActionStatus(status));
@@ -527,7 +522,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
simulateIntermediateStatusOnCancellation(actionId); simulateIntermediateStatusOnCancellation(actionId);
controllerManagement controllerManagement
.addCancelActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)); .addCancelActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.FINISHED).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.CANCELED, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.CANCELED,
Action.Status.FINISHED, false); Action.Status.FINISHED, false);
@@ -560,7 +555,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
simulateIntermediateStatusOnCancellation(actionId); simulateIntermediateStatusOnCancellation(actionId);
controllerManagement controllerManagement
.addCancelActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.CANCELED)); .addCancelActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.CANCELED).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.CANCELED, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.CANCELED,
Action.Status.CANCELED, false); Action.Status.CANCELED, false);
@@ -594,7 +589,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
simulateIntermediateStatusOnCancellation(actionId); simulateIntermediateStatusOnCancellation(actionId);
controllerManagement.addCancelActionStatus( controllerManagement.addCancelActionStatus(
entityFactory.actionStatus().create(actionId).status(Action.Status.CANCEL_REJECTED)); ActionStatusCreate.builder().actionId(actionId).status(Action.Status.CANCEL_REJECTED).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING,
Action.Status.CANCEL_REJECTED, true); Action.Status.CANCEL_REJECTED, true);
@@ -628,7 +623,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
simulateIntermediateStatusOnCancellation(actionId); simulateIntermediateStatusOnCancellation(actionId);
controllerManagement controllerManagement
.addCancelActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.ERROR)); .addCancelActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.ERROR).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING,
Action.Status.ERROR, true); Action.Status.ERROR, true);
@@ -1024,23 +1019,27 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId = createTargetAndAssignDs(); final Long actionId = createTargetAndAssignDs();
// test and verify // test and verify
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING)); controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.RUNNING).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, Action.Status.RUNNING, true); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, Action.Status.RUNNING, true);
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.ERROR)); controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.ERROR).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false);
// try with disabled late feedback // try with disabled late feedback
withRejectActionStatusForClosedAction(true, () -> withRejectActionStatusForClosedAction(
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED))); true,
() -> controllerManagement.addUpdateActionStatus(
ActionStatusCreate.builder().actionId(actionId).status(Action.Status.FINISHED).build()));
// test // test
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false);
// try with enabled late feedback - should not make a difference as it // try with enabled late feedback - should not make a difference as it
// only allows intermediate feedback and not multiple close // only allows intermediate feedback and not multiple close
withRejectActionStatusForClosedAction(false, withRejectActionStatusForClosedAction(
() -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED))); false,
() -> controllerManagement.addUpdateActionStatus(
ActionStatusCreate.builder().actionId(actionId).status(Action.Status.FINISHED).build()));
// test // test
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false);
@@ -1068,14 +1067,16 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId = prepareFinishedUpdate().getId(); final Long actionId = prepareFinishedUpdate().getId();
withRejectActionStatusForClosedAction(true, withRejectActionStatusForClosedAction(true,
() -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED))); () -> controllerManagement.addUpdateActionStatus(
ActionStatusCreate.builder().actionId(actionId).status(Action.Status.FINISHED).build()));
// test // test
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.FINISHED, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.FINISHED,
Action.Status.FINISHED, false); Action.Status.FINISHED, false);
withRejectActionStatusForClosedAction(false, withRejectActionStatusForClosedAction(false,
() -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED))); () -> controllerManagement.addUpdateActionStatus(
ActionStatusCreate.builder().actionId(actionId).status(Action.Status.FINISHED).build()));
// test // test
assertActionStatus( assertActionStatus(
@@ -1103,7 +1104,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Action action = prepareFinishedUpdate(); final Action action = prepareFinishedUpdate();
withRejectActionStatusForClosedAction(true, withRejectActionStatusForClosedAction(true,
() -> controllerManagement.addUpdateActionStatus( () -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(action.getId()).status(Action.Status.RUNNING))); ActionStatusCreate.builder().actionId(action.getId()).status(Action.Status.RUNNING).build()));
// nothing changed as "feedback after close" is disabled // nothing changed as "feedback after close" is disabled
assertThat(targetManagement.getByControllerId(DEFAULT_CONTROLLER_ID).get().getUpdateStatus()) assertThat(targetManagement.getByControllerId(DEFAULT_CONTROLLER_ID).get().getUpdateStatus())
@@ -1135,7 +1136,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
Action action = prepareFinishedUpdate(); Action action = prepareFinishedUpdate();
withRejectActionStatusForClosedAction(false, withRejectActionStatusForClosedAction(false,
() -> controllerManagement.addUpdateActionStatus( () -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(action.getId()).status(Action.Status.RUNNING))); ActionStatusCreate.builder().actionId(action.getId()).status(Action.Status.RUNNING).build()));
// nothing changed as "feedback after close" is disabled // nothing changed as "feedback after close" is disabled
assertThat(targetManagement.getByControllerId(DEFAULT_CONTROLLER_ID).get().getUpdateStatus()).isEqualTo(TargetUpdateStatus.IN_SYNC); assertThat(targetManagement.getByControllerId(DEFAULT_CONTROLLER_ID).get().getUpdateStatus()).isEqualTo(TargetUpdateStatus.IN_SYNC);
@@ -1215,7 +1216,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
testdataFactory.createTarget(); testdataFactory.createTarget();
final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID);
assertThat(actionId).isNotNull(); assertThat(actionId).isNotNull();
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)); controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Status.DOWNLOADED).build());
assertActionStatus( assertActionStatus(
actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.DOWNLOADED, Action.Status.DOWNLOADED, false); actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.DOWNLOADED, Action.Status.DOWNLOADED, false);
@@ -1273,7 +1274,7 @@ 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();
IntStream.range(0, 3).forEach(i -> controllerManagement IntStream.range(0, 3).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Status.DOWNLOADED).build()));
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Status.DOWNLOADED, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Status.DOWNLOADED,
Status.DOWNLOADED, false); Status.DOWNLOADED, false);
@@ -1306,7 +1307,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(actionId).isNotNull(); assertThat(actionId).isNotNull();
final IntConsumer op = i -> controllerManagement.addUpdateActionStatus( final IntConsumer op = i -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)); ActionStatusCreate.builder().actionId(actionId).status(Status.DOWNLOADED).build());
Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class) Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> forNTimes(maxMessages, op)); .isThrownBy(() -> forNTimes(maxMessages, op));
} }
@@ -1334,7 +1335,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
// assert that too many intermediate statuses will throw quota exception // assert that too many intermediate statuses will throw quota exception
final IntConsumer op = i -> controllerManagement.addUpdateActionStatus( final IntConsumer op = i -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)); ActionStatusCreate.builder().actionId(actionId).status(Status.DOWNLOADED).build());
assertThatExceptionOfType(AssignmentQuotaExceededException.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(() -> forNTimes(maxMessages, op)); .isThrownBy(() -> forNTimes(maxMessages, op));
@@ -1342,7 +1343,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
// assert that Final result is accepted even if quota is reached // assert that Final result is accepted even if quota is reached
assertThatNoException().isThrownBy(() -> { assertThatNoException().isThrownBy(() -> {
Action updatedAction = controllerManagement.addUpdateActionStatus( Action updatedAction = controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(actionId).status(Status.FINISHED)); ActionStatusCreate.builder().actionId(actionId).status(Status.FINISHED).build());
// check if action really finished // check if action really finished
assertThat(updatedAction.isActive()).isFalse(); assertThat(updatedAction.isActive()).isFalse();
// check if final status is updated accordingly // check if final status is updated accordingly
@@ -1352,7 +1353,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
// assert that additional final result is not accepted // assert that additional final result is not accepted
assertThatNoException().isThrownBy(() -> { assertThatNoException().isThrownBy(() -> {
Action updatedAction = controllerManagement Action updatedAction = controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Status.ERROR).build());
// check if action really finished // check if action really finished
assertThat(updatedAction.isActive()).isFalse(); assertThat(updatedAction.isActive()).isFalse();
// check if final status is not changed - e.g. ERROR is not updated because action has already finished // check if final status is not changed - e.g. ERROR is not updated because action has already finished
@@ -1382,7 +1383,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
// assert that too many intermediate statuses will throw quota exception // assert that too many intermediate statuses will throw quota exception
final IntConsumer op = i -> controllerManagement.addUpdateActionStatus( final IntConsumer op = i -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)); ActionStatusCreate.builder().actionId(actionId).status(Status.DOWNLOADED).build());
assertThatExceptionOfType(AssignmentQuotaExceededException.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(() -> forNTimes(maxMessages, op)); .isThrownBy(() -> forNTimes(maxMessages, op));
@@ -1390,7 +1391,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
// assert that Final result is accepted even if quota is reached // assert that Final result is accepted even if quota is reached
assertThatNoException().isThrownBy(() -> { assertThatNoException().isThrownBy(() -> {
Action updatedAction = controllerManagement Action updatedAction = controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Status.FINISHED).build());
// check if action really finished // check if action really finished
assertThat(updatedAction.isActive()).isFalse(); assertThat(updatedAction.isActive()).isFalse();
// check if final status is updated accordingly // check if final status is updated accordingly
@@ -1400,7 +1401,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
// assert that additional final result is not accepted // assert that additional final result is not accepted
assertThatNoException().isThrownBy(() -> { assertThatNoException().isThrownBy(() -> {
Action updatedAction = controllerManagement Action updatedAction = controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Status.ERROR).build());
// check if action really finished // check if action really finished
assertThat(updatedAction.isActive()).isFalse(); assertThat(updatedAction.isActive()).isFalse();
// check if final status is not changed - e.g. ERROR is not updated because action has already finished // check if final status is not changed - e.g. ERROR is not updated because action has already finished
@@ -1620,19 +1621,19 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId()) assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
.isEqualTo(actionWeightNull); .isEqualTo(actionWeightNull);
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeightNull).status(Status.FINISHED)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionWeightNull).status(Status.FINISHED).build());
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId()) assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
.isEqualTo(actionWeight1000); .isEqualTo(actionWeight1000);
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeight1000).status(Status.FINISHED)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionWeight1000).status(Status.FINISHED).build());
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId()) assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
.isEqualTo(actionWeight500old); .isEqualTo(actionWeight500old);
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeight500old).status(Status.FINISHED)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionWeight500old).status(Status.FINISHED).build());
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId()) assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId).get().getId())
.isEqualTo(actionWeight500new); .isEqualTo(actionWeight500new);
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionWeight500new).status(Status.FINISHED)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionWeight500new).status(Status.FINISHED).build());
assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId)).isEmpty(); assertThat(controllerManagement.findActiveActionWithHighestWeight(targetId)).isEmpty();
} }
@@ -1757,40 +1758,36 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
private void simulateIntermediateStatusOnCancellation(final Long actionId) { private void simulateIntermediateStatusOnCancellation(final Long actionId) {
controllerManagement controllerManagement
.addCancelActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING)); .addCancelActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.RUNNING).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING,
Action.Status.RUNNING, true); Action.Status.RUNNING, true);
controllerManagement controllerManagement
.addCancelActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.DOWNLOAD)); .addCancelActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.DOWNLOAD).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING,
Action.Status.DOWNLOAD, true); Action.Status.DOWNLOAD, true);
controllerManagement controllerManagement
.addCancelActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.DOWNLOADED)); .addCancelActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.DOWNLOADED).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING,
Action.Status.DOWNLOADED, true); Action.Status.DOWNLOADED, true);
controllerManagement controllerManagement
.addCancelActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.RETRIEVED)); .addCancelActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.RETRIEVED).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING,
Action.Status.RETRIEVED, true); Action.Status.RETRIEVED, true);
controllerManagement controllerManagement
.addCancelActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.WARNING)); .addCancelActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Action.Status.WARNING).build());
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING,
Action.Status.WARNING, true); Action.Status.WARNING, true);
} }
private void simulateIntermediateStatusOnUpdate(final Long actionId) { private void simulateIntermediateStatusOnUpdate(final Long actionId) {
addUpdateActionStatusAndAssert(actionId, Action.Status.RUNNING); addUpdateActionStatusAndAssert(actionId, Action.Status.RUNNING);
addUpdateActionStatusAndAssert(actionId, Action.Status.DOWNLOAD); addUpdateActionStatusAndAssert(actionId, Action.Status.DOWNLOAD);
addUpdateActionStatusAndAssert(actionId, Action.Status.DOWNLOADED); addUpdateActionStatusAndAssert(actionId, Action.Status.DOWNLOADED);
addUpdateActionStatusAndAssert(actionId, Action.Status.RETRIEVED); addUpdateActionStatusAndAssert(actionId, Action.Status.RETRIEVED);
addUpdateActionStatusAndAssert(actionId, Action.Status.WARNING); addUpdateActionStatusAndAssert(actionId, Action.Status.WARNING);
} }
@@ -1798,14 +1795,12 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
addUpdateActionStatusAndAssert(actionId, actionStatus, null); addUpdateActionStatusAndAssert(actionId, actionStatus, null);
} }
private void addUpdateActionStatusAndAssert(final Long actionId, final Action.Status actionStatus, private void addUpdateActionStatusAndAssert(final Long actionId, final Action.Status actionStatus, final Integer code) {
final Integer code) { final ActionStatusCreateBuilder status = ActionStatusCreate.builder().actionId(actionId).status(actionStatus);
final ActionStatusCreate status = entityFactory.actionStatus().create(actionId).status(actionStatus);
if (code != null) { if (code != null) {
status.code(code.intValue()); status.code(code);
} }
controllerManagement controllerManagement.addUpdateActionStatus(status.build());
.addUpdateActionStatus(status);
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING,
actionStatus, true); actionStatus, true);
} }
@@ -1938,21 +1933,21 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
private void writeStatus(final Long actionId, final int allowedStatusEntries) { private void writeStatus(final Long actionId, final int allowedStatusEntries) {
for (int i = 0; i < allowedStatusEntries; i++) { for (int i = 0; i < allowedStatusEntries; i++) {
controllerManagement.addInformationalActionStatus( controllerManagement.addInformationalActionStatus(
entityFactory.actionStatus().create(actionId).status(Status.RUNNING).message("test" + i)); ActionStatusCreate.builder().actionId(actionId).status(Status.RUNNING).messages(List.of("test" + i)).build());
} }
} }
private void finishDownloadOnlyUpdateAndSendUpdateActionStatus(final Long actionId, final Status status) { private void finishDownloadOnlyUpdateAndSendUpdateActionStatus(final Long actionId, final Status status) {
// finishing action // finishing action
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(Status.DOWNLOADED).build());
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(status)); controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(status).build());
assertThat(activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isFalse(); assertThat(activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isFalse();
} }
private void addUpdateActionStatus(final Long actionId, final String controllerId, final Status actionStatus) { private void addUpdateActionStatus(final Long actionId, final String controllerId, final Status actionStatus) {
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(actionStatus)); controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId).status(actionStatus).build());
assertActionStatus(actionId, controllerId, TargetUpdateStatus.IN_SYNC, actionStatus, actionStatus, false); assertActionStatus(actionId, controllerId, TargetUpdateStatus.IN_SYNC, actionStatus, actionStatus, false);
} }

View File

@@ -69,6 +69,7 @@ import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification;
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
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;
@@ -270,8 +271,8 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
// one action with one action status is generated // one action with one action status is generated
final Long actionId = getFirstAssignedActionId(assignDistributionSet(testDs, testTarget)); final Long actionId = getFirstAssignedActionId(assignDistributionSet(testDs, testTarget));
// create action-status entry with one message // create action-status entry with one message
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId) controllerManagement.addUpdateActionStatus(ActionStatusCreate.builder().actionId(actionId)
.status(Action.Status.FINISHED).messages(Collections.singletonList("finished message"))); .status(Action.Status.FINISHED).messages(List.of("finished message")).build());
final Page<ActionStatus> actionStates = deploymentManagement.findActionStatusByAction(actionId, PAGE); final Page<ActionStatus> actionStates = deploymentManagement.findActionStatusByAction(actionId, PAGE);
// find newly created action-status entry with message // find newly created action-status entry with message
@@ -365,7 +366,8 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
deploymentManagement.cancelAction(secondAction.getId()); deploymentManagement.cancelAction(secondAction.getId());
secondAction = (JpaAction) deploymentManagement.findActionWithDetails(secondAction.getId()).get(); secondAction = (JpaAction) deploymentManagement.findActionWithDetails(secondAction.getId()).get();
// confirm cancellation // confirm cancellation
controllerManagement.addCancelActionStatus(entityFactory.actionStatus().create(secondAction.getId()).status(Status.CANCELED)); controllerManagement.addCancelActionStatus(ActionStatusCreate.builder()
.actionId(secondAction.getId()).status(Status.CANCELED).build());
assertThat(actionStatusRepository.findAll()).as("wrong size of actions status").hasSize(7); assertThat(actionStatusRepository.findAll()).as("wrong size of actions status").hasSize(7);
assertThat(deploymentManagement.getAssignedDistributionSet("4712")).as("wrong ds").contains(dsFirst); assertThat(deploymentManagement.getAssignedDistributionSet("4712")).as("wrong ds").contains(dsFirst);
assertThat(targetManagement.getByControllerId("4712").get().getUpdateStatus()) assertThat(targetManagement.getByControllerId("4712").get().getUpdateStatus())
@@ -377,7 +379,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
firstAction = (JpaAction) deploymentManagement.findActionWithDetails(firstAction.getId()).get(); firstAction = (JpaAction) deploymentManagement.findActionWithDetails(firstAction.getId()).get();
// confirm cancellation // confirm cancellation
controllerManagement.addCancelActionStatus( controllerManagement.addCancelActionStatus(
entityFactory.actionStatus().create(firstAction.getId()).status(Status.CANCELED)); ActionStatusCreate.builder().actionId(firstAction.getId()).status(Status.CANCELED).build());
assertThat(actionStatusRepository.findAll()).as("wrong size of action status").hasSize(9); assertThat(actionStatusRepository.findAll()).as("wrong size of action status").hasSize(9);
assertThat(deploymentManagement.getAssignedDistributionSet("4712")).as("wrong assigned ds") assertThat(deploymentManagement.getAssignedDistributionSet("4712")).as("wrong assigned ds")
.contains(dsInstalled); .contains(dsInstalled);
@@ -414,7 +416,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
// confirm cancellation // confirm cancellation
firstAction = (JpaAction) deploymentManagement.findActionWithDetails(firstAction.getId()).get(); firstAction = (JpaAction) deploymentManagement.findActionWithDetails(firstAction.getId()).get();
controllerManagement.addCancelActionStatus( controllerManagement.addCancelActionStatus(
entityFactory.actionStatus().create(firstAction.getId()).status(Status.CANCELED)); ActionStatusCreate.builder().actionId(firstAction.getId()).status(Status.CANCELED).build());
assertThat(actionStatusRepository.findAll()).as("wrong size of action status").hasSize(7); assertThat(actionStatusRepository.findAll()).as("wrong size of action status").hasSize(7);
assertThat(deploymentManagement.getAssignedDistributionSet("4712")).as("wrong assigned ds").contains(dsSecond); assertThat(deploymentManagement.getAssignedDistributionSet("4712")).as("wrong assigned ds").contains(dsSecond);
assertThat(targetManagement.getByControllerId("4712").get().getUpdateStatus()).as("wrong target update status") assertThat(targetManagement.getByControllerId("4712").get().getUpdateStatus()).as("wrong target update status")
@@ -427,7 +429,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(deploymentManagement.getAssignedDistributionSet("4712")).as("wrong assigned ds").contains(dsSecond); assertThat(deploymentManagement.getAssignedDistributionSet("4712")).as("wrong assigned ds").contains(dsSecond);
// confirm cancellation // confirm cancellation
controllerManagement.addCancelActionStatus( controllerManagement.addCancelActionStatus(
entityFactory.actionStatus().create(secondAction.getId()).status(Status.CANCELED)); ActionStatusCreate.builder().actionId(secondAction.getId()).status(Status.CANCELED).build());
// cancelled success -> back to dsInstalled // cancelled success -> back to dsInstalled
assertThat(deploymentManagement.getAssignedDistributionSet("4712")) assertThat(deploymentManagement.getAssignedDistributionSet("4712"))
.as("wrong installed ds") .as("wrong installed ds")
@@ -1444,7 +1446,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final Slice<Action> updAct = findActionsByDistributionSet(PAGE, dsA.getId()); final Slice<Action> updAct = findActionsByDistributionSet(PAGE, dsA.getId());
controllerManagement.addUpdateActionStatus( controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(updAct.getContent().get(0).getId()).status(Status.FINISHED)); ActionStatusCreate.builder().actionId(updAct.getContent().get(0).getId()).status(Status.FINISHED).build());
targ = targetManagement.getByControllerId(targ.getControllerId()).get(); targ = targetManagement.getByControllerId(targ.getControllerId()).get();

View File

@@ -15,7 +15,7 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate; import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
@@ -217,7 +217,7 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
final Rollout rollout = testdataFactory.createRolloutByVariables(rolloutName, rolloutName, amountGroups, final Rollout rollout = testdataFactory.createRolloutByVariables(rolloutName, rolloutName, amountGroups,
"controllerid==" + targetPrefix + "*", distributionSet, "60", "30", "controllerid==" + targetPrefix + "*", distributionSet, "60", "30",
Action.ActionType.FORCED, 1000, false, true, Action.ActionType.FORCED, 1000, false, true,
DynamicRolloutGroupTemplate.builder().nameSuffix("-dyn").targetCount(6).build()); RolloutManagement.DynamicRolloutGroupTemplate.builder().nameSuffix("-dyn").targetCount(6).build());
// rollout is READY, amountGroups + 1 (dynamic) rollout groups and amountGroups * 3 targets in static groups // rollout is READY, amountGroups + 1 (dynamic) rollout groups and amountGroups * 3 targets in static groups
assertRollout(rollout, true, RolloutStatus.READY, amountGroups + 1, amountGroups * 3); assertRollout(rollout, true, RolloutStatus.READY, amountGroups + 1, amountGroups * 3);
@@ -314,7 +314,7 @@ class RolloutManagementFlowTest extends AbstractJpaIntegrationTest {
final Rollout rollout = testdataFactory.createRolloutByVariables(rolloutName, rolloutName, 0, final Rollout rollout = testdataFactory.createRolloutByVariables(rolloutName, rolloutName, 0,
"controllerid==" + targetPrefix + "*", distributionSet, "60", "30", "controllerid==" + targetPrefix + "*", distributionSet, "60", "30",
Action.ActionType.FORCED, 1000, false, true, Action.ActionType.FORCED, 1000, false, true,
DynamicRolloutGroupTemplate.builder().nameSuffix("-dyn").targetCount(6).build()); RolloutManagement.DynamicRolloutGroupTemplate.builder().nameSuffix("-dyn").targetCount(6).build());
// rollout is READY, amountGroups + 1 (dynamic) rollout groups and amountGroups * 3 targets in static groups // rollout is READY, amountGroups + 1 (dynamic) rollout groups and amountGroups * 3 targets in static groups
assertRollout(rollout, true, RolloutStatus.READY, 1, 0); assertRollout(rollout, true, RolloutStatus.READY, 1, 0);

View File

@@ -11,19 +11,22 @@ package org.eclipse.hawkbit.repository.jpa.management;
import java.util.List; import java.util.List;
import jakarta.validation.ConstraintDeclarationException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement; import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate; import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.RolloutManagement.Create;
import org.eclipse.hawkbit.repository.RolloutManagement.GroupCreate;
import org.eclipse.hawkbit.repository.RolloutManagement.Update;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
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;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
/** /**
* Feature: SecurityTests - RolloutManagement<br/> * Feature: SecurityTests - RolloutManagement<br/>
@@ -32,6 +35,9 @@ import org.junit.jupiter.api.Test;
@Slf4j @Slf4j
class RolloutManagementSecurityTest extends AbstractJpaIntegrationTest { class RolloutManagementSecurityTest extends AbstractJpaIntegrationTest {
@Autowired
private TestdataFactory testdataFactory;
/** /**
* Tests ManagementAPI PreAuthorized method with correct and insufficient permissions. * Tests ManagementAPI PreAuthorized method with correct and insufficient permissions.
*/ */
@@ -133,16 +139,22 @@ class RolloutManagementSecurityTest extends AbstractJpaIntegrationTest {
*/ */
@Test @Test
void createPermissionsCheck() { void createPermissionsCheck() {
assertPermissions(() -> rolloutManagement.create(entityFactory.rollout().create().distributionSetId(1L), 1, false, testdataFactory.createTarget(); // to have matching
new RolloutGroupConditionBuilder().withDefaults().build()), List.of(SpPermission.CREATE_ROLLOUT, SpPermission.READ_REPOSITORY)); final DistributionSet ds = testdataFactory.createDistributionSetLocked("createPermissionsCheck");
assertPermissions(() -> rolloutManagement.create(entityFactory.rollout().create().distributionSetId(1L), 1, false, final List<String> permissions = List.of(SpPermission.CREATE_ROLLOUT, SpPermission.READ_TARGET, SpPermission.READ_REPOSITORY);
new RolloutGroupConditionBuilder().withDefaults().build(), DynamicRolloutGroupTemplate.builder().build()), assertPermissions(() -> rolloutManagement.create(
List.of(SpPermission.CREATE_ROLLOUT, SpPermission.READ_REPOSITORY)); Create.builder().name("createPermissionsCheck").distributionSet(ds).targetFilterQuery("controllerid==*").build(),
1, false, new RolloutGroupConditionBuilder().withDefaults().build()),
permissions);
assertPermissions(() -> rolloutManagement.create(
Create.builder().name("createPermissionsCheck2").distributionSet(ds).targetFilterQuery("controllerid==*").dynamic(true).build(),
1, false, new RolloutGroupConditionBuilder().withDefaults().build(), RolloutManagement.DynamicRolloutGroupTemplate.builder().build()),
permissions);
assertPermissions( assertPermissions(
() -> rolloutManagement.create(entityFactory.rollout().create().distributionSetId(1L), () -> rolloutManagement.create(
List.of(entityFactory.rolloutGroup().create()), Create.builder().name("createPermissionsCheck3").distributionSet(ds).targetFilterQuery("controllerid==*").build(),
new RolloutGroupConditionBuilder().withDefaults().build()), List.of(GroupCreate.builder().name("group").build()), new RolloutGroupConditionBuilder().withDefaults().build()),
List.of(SpPermission.CREATE_ROLLOUT, SpPermission.READ_REPOSITORY)); permissions);
} }
/** /**
@@ -191,7 +203,7 @@ class RolloutManagementSecurityTest extends AbstractJpaIntegrationTest {
*/ */
@Test @Test
void updatePermissionsCheck() { void updatePermissionsCheck() {
assertPermissions(() -> rolloutManagement.update(entityFactory.rollout().update(1L)), List.of(SpPermission.UPDATE_ROLLOUT)); assertPermissions(() -> rolloutManagement.update(Update.builder().id(1L).build()), List.of(SpPermission.UPDATE_ROLLOUT));
} }
/** /**
@@ -216,25 +228,6 @@ class RolloutManagementSecurityTest extends AbstractJpaIntegrationTest {
}, List.of(SpPermission.UPDATE_ROLLOUT)); }, List.of(SpPermission.UPDATE_ROLLOUT));
} }
/**
* Tests ManagementAPI PreAuthorized method with correct and insufficient permissions.
*/
@Test// @WithUser(principal = "user", authorities = { SpPermission.CREATE_TARGET, SpPermission.CREATE_ROLLOUT, SpPermission.READ_ROLLOUT,
// SpPermission.READ_TARGET })
void validateTargetsInGroupsPermissionsCheck() {
try {
assertPermissions(
() -> rolloutManagement.validateTargetsInGroups(List.of(entityFactory.rolloutGroup().create()), "name==dummy", 1L, 1L),
List.of(SpPermission.READ_ROLLOUT, SpPermission.READ_TARGET));
} catch (Error e) {
if (e.getCause() instanceof ConstraintDeclarationException) {
log.info("ConstraintDeclarationException thrown expected");
} else {
throw e;
}
}
}
/** /**
* Tests ManagementAPI PreAuthorized method with correct and insufficient permissions. * Tests ManagementAPI PreAuthorized method with correct and insufficient permissions.
*/ */

View File

@@ -12,10 +12,8 @@ package org.eclipse.hawkbit.repository.jpa.management;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -23,7 +21,6 @@ import java.util.NoSuchElementException;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream; import java.util.stream.Stream;
import jakarta.validation.ConstraintViolationException; import jakarta.validation.ConstraintViolationException;
@@ -31,14 +28,13 @@ import jakarta.validation.ValidationException;
import org.assertj.core.api.Assertions; import org.assertj.core.api.Assertions;
import org.assertj.core.api.Condition; import org.assertj.core.api.Condition;
import org.awaitility.Awaitility;
import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpRole; import org.eclipse.hawkbit.im.authentication.SpRole;
import org.eclipse.hawkbit.repository.Identifiable; import org.eclipse.hawkbit.repository.Identifiable;
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.builder.RolloutCreate; import org.eclipse.hawkbit.repository.RolloutManagement.Create;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate; import org.eclipse.hawkbit.repository.RolloutManagement.GroupCreate;
import org.eclipse.hawkbit.repository.builder.RolloutUpdate; import org.eclipse.hawkbit.repository.RolloutManagement.Update;
import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent; import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.RolloutGroupDeletedEvent; import org.eclipse.hawkbit.repository.event.remote.RolloutGroupDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
@@ -65,6 +61,7 @@ import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
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;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
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;
@@ -109,8 +106,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
/** /**
* Tests static assignment aspects of the dynamic group assignment filters. * Tests static assignment aspects of the dynamic group assignment filters.
*/
/**
* Dynamic group doesn't override newer static group assignments * Dynamic group doesn't override newer static group assignments
*/ */
@Test @Test
@@ -183,16 +178,15 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
void rolloutShouldNotCancelRunningActionWithTheSameDistributionSet() { void rolloutShouldNotCancelRunningActionWithTheSameDistributionSet() {
// manually assign distribution set to target // manually assign distribution set to target
final String knownControllerId = "controller12345"; final String knownControllerId = "controller12345";
final DistributionSet knownDistributionSet = testdataFactory.createDistributionSet(); final DistributionSet knownDistributionSet = testdataFactory.createDistributionSetLocked("");
testdataFactory.createTarget(knownControllerId); testdataFactory.createTarget(knownControllerId);
final DistributionSetAssignmentResult assignmentResult = assignDistributionSet(knownDistributionSet.getId(), final DistributionSetAssignmentResult assignmentResult = assignDistributionSet(knownDistributionSet.getId(), knownControllerId);
knownControllerId);
final Long manuallyAssignedActionId = getFirstAssignedActionId(assignmentResult); final Long manuallyAssignedActionId = getFirstAssignedActionId(assignmentResult);
// create rollout with the same distribution set already assigned // create rollout with the same distribution set already assigned
// start rollout // start rollout
final Rollout rollout = testdataFactory.createRolloutByVariables("rolloutNotCancelRunningAction", "description", final Rollout rollout = testdataFactory.createRolloutByVariables(
1, "name==*", knownDistributionSet, "50", "5"); "rolloutNotCancelRunningAction", "description", 1, "name==*", knownDistributionSet, "50", "5");
rolloutManagement.start(rollout.getId()); rolloutManagement.start(rollout.getId());
rolloutHandler.handleAll(); rolloutHandler.handleAll();
@@ -325,8 +319,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
verifyThrownExceptionBy(() -> rolloutManagement.resumeRollout(NOT_EXIST_IDL), "Rollout"); verifyThrownExceptionBy(() -> rolloutManagement.resumeRollout(NOT_EXIST_IDL), "Rollout");
verifyThrownExceptionBy(() -> rolloutManagement.start(NOT_EXIST_IDL), "Rollout"); verifyThrownExceptionBy(() -> rolloutManagement.start(NOT_EXIST_IDL), "Rollout");
verifyThrownExceptionBy(() -> rolloutManagement.update(entityFactory.rollout().update(NOT_EXIST_IDL)), verifyThrownExceptionBy(() -> rolloutManagement.update(Update.builder().id(NOT_EXIST_IDL).build()), "Rollout");
"Rollout");
verifyThrownExceptionBy(() -> rolloutManagement.triggerNextGroup(NOT_EXIST_IDL), "Rollout"); verifyThrownExceptionBy(() -> rolloutManagement.triggerNextGroup(NOT_EXIST_IDL), "Rollout");
} }
@@ -378,8 +371,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
scheduledGroups.forEach(group -> assertThat(group.getStatus()) scheduledGroups.forEach(group -> assertThat(group.getStatus())
.as("group which should be in scheduled state is in " + group.getStatus() + " state") .as("group which should be in scheduled state is in " + group.getStatus() + " state")
.isEqualTo(RolloutGroupStatus.SCHEDULED)); .isEqualTo(RolloutGroupStatus.SCHEDULED));
// verify that the first group actions has been started and are in state // verify that the first group actions has been started and are in state running
// running
final List<Action> runningActions = findActionsByRolloutAndStatus(createdRollout, Status.RUNNING); final List<Action> runningActions = findActionsByRolloutAndStatus(createdRollout, Status.RUNNING);
assertThat(runningActions).hasSize(amountTargetsForRollout / amountGroups) assertThat(runningActions).hasSize(amountTargetsForRollout / amountGroups)
.as("Created actions are initiated by rollout creator") .as("Created actions are initiated by rollout creator")
@@ -408,7 +400,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// 50% // 50%
final JpaAction action = (JpaAction) runningActions.get(0); final JpaAction action = (JpaAction) runningActions.get(0);
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(Status.FINISHED)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(action.getId()).status(Status.FINISHED).build());
// check running rollouts again, now the finish condition should be hit // check running rollouts again, now the finish condition should be hit
// and should start the next group // and should start the next group
@@ -476,7 +468,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// finish actions with error // finish actions with error
for (final Action action : runningActions) { for (final Action action : runningActions) {
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(Status.ERROR)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(action.getId()).status(Status.ERROR).build());
} }
// check running rollouts again, now the error condition should be hit // check running rollouts again, now the error condition should be hit
@@ -521,7 +513,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// finish actions with error // finish actions with error
for (final Action action : runningActions) { for (final Action action : runningActions) {
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(Status.ERROR)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(action.getId()).status(Status.ERROR).build());
} }
// check running rollouts again, now the error condition should be hit // check running rollouts again, now the error condition should be hit
@@ -1371,8 +1363,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// Run here, because scheduler is disabled during tests // Run here, because scheduler is disabled during tests
rolloutHandler.handleAll(); rolloutHandler.handleAll();
awaitRunningState(myRolloutId);
myRollout = getRollout(myRolloutId); myRollout = getRollout(myRolloutId);
assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.RUNNING); assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.RUNNING);
final Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus = createInitStatusMap(); final Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus = createInitStatusMap();
@@ -1386,7 +1376,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
*/ */
@Test @Test
void createAndStartRollout() { void createAndStartRollout() {
final int amountTargetsForRollout = 50; final int amountTargetsForRollout = 50;
final int amountGroups = 5; final int amountGroups = 5;
final String successCondition = "50"; final String successCondition = "50";
@@ -1395,30 +1384,24 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName); final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
testdataFactory.createTargets(amountTargetsForRollout, rolloutName + "-", rolloutName); testdataFactory.createTargets(amountTargetsForRollout, rolloutName + "-", rolloutName);
Rollout myRollout = testdataFactory.createRolloutByVariables(rolloutName, "desc", amountGroups, Rollout myRollout = testdataFactory.createRolloutByVariables(
"controllerId==" + rolloutName + "-*", distributionSet, successCondition, errorCondition); rolloutName, "desc", amountGroups, "controllerId==" + rolloutName + "-*", distributionSet, successCondition, errorCondition);
assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.READY); assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.READY);
rolloutHandler.handleAll(); rolloutHandler.handleAll();
myRollout = getRollout(myRollout.getId());
final Long myRolloutId = myRollout.getId();
myRollout = getRollout(myRolloutId);
assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.READY); assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.READY);
rolloutManagement.start(myRolloutId); rolloutManagement.start(myRollout.getId());
// Run here, because scheduler is disabled during tests // Run here, because scheduler is disabled during tests
rolloutHandler.handleAll(); rolloutHandler.handleAll();
awaitRunningState(myRolloutId);
myRollout = reloadRollout(myRollout); myRollout = reloadRollout(myRollout);
assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.RUNNING); assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.RUNNING);
final Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus = createInitStatusMap(); final Map<TotalTargetCountStatus.Status, Long> expectedTargetCountStatus = createInitStatusMap();
expectedTargetCountStatus.put(TotalTargetCountStatus.Status.RUNNING, 10L); expectedTargetCountStatus.put(TotalTargetCountStatus.Status.RUNNING, 10L);
expectedTargetCountStatus.put(TotalTargetCountStatus.Status.SCHEDULED, 40L); expectedTargetCountStatus.put(TotalTargetCountStatus.Status.SCHEDULED, 40L);
validateRolloutActionStatus(myRolloutId, expectedTargetCountStatus); validateRolloutActionStatus(myRollout.getId(), expectedTargetCountStatus);
} }
/** /**
@@ -1465,17 +1448,18 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
() -> createRolloutWithStartAt(rolloutName + "_withLongMax", filter, distributionSet, Long.MAX_VALUE)); () -> createRolloutWithStartAt(rolloutName + "_withLongMax", filter, distributionSet, Long.MAX_VALUE));
} }
private Rollout createRolloutWithStartAt(final String rolloutName, final String filter, final DistributionSet distributionSet, private Rollout createRolloutWithStartAt(
final Long startAt) { final String rolloutName, final String filter, final DistributionSet distributionSet, final Long startAt) {
return rolloutManagement.create( return rolloutManagement.create(
entityFactory.rollout().create() Create.builder()
.name(rolloutName) .name(rolloutName)
.description("desc") .description("desc")
.targetFilterQuery(filter) .targetFilterQuery(filter)
.distributionSetId(distributionSet) .distributionSet(distributionSet)
.weight(1000) .weight(1000)
.startAt(startAt) .startAt(startAt)
.dynamic(false), .dynamic(false)
.build(),
5, false, new RolloutGroupConditionBuilder().withDefaults() 5, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "80") .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "80")
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, "50") .errorCondition(RolloutGroupErrorCondition.THRESHOLD, "50")
@@ -1504,8 +1488,10 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition)
.errorAction(RolloutGroupErrorAction.PAUSE, null).build(); .errorAction(RolloutGroupErrorAction.PAUSE, null).build();
final RolloutCreate rollout = entityFactory.rollout().create().name(rolloutName).description(rolloutName) final Create rollout = Create.builder()
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").distributionSetId(distributionSet); .name(rolloutName).description(rolloutName)
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").distributionSet(distributionSet)
.build();
assertThatExceptionOfType(AssignmentQuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> rolloutManagement.create(rollout, amountGroups, false, conditions)); .isThrownBy(() -> rolloutManagement.create(rollout, amountGroups, false, conditions));
@@ -1526,37 +1512,36 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
// create group definitions // create group definitions
final RolloutGroupCreate group1 = entityFactory.rolloutGroup().create().conditions(conditions).name("group1").targetPercentage(50.0F); final GroupCreate group1 = GroupCreate.builder().conditions(conditions).name("group1").targetPercentage(50.0F).build();
final RolloutGroupCreate group2 = entityFactory.rolloutGroup().create().conditions(conditions).name("group2").targetPercentage(50.0F); final GroupCreate group2 = GroupCreate.builder().conditions(conditions).name("group2").targetPercentage(50.0F).build();
// group1 exceeds the quota // group1 exceeds the quota
final RolloutCreate rolloutCreate = entityFactory.rollout().create() final Create rolloutCreate = Create.builder()
.name(rolloutName) .name(rolloutName)
.description(rolloutName) .description(rolloutName)
.targetFilterQuery("controllerId==" + rolloutName + "-*") .targetFilterQuery("controllerId==" + rolloutName + "-*")
.distributionSetId(distributionSet); .distributionSet(distributionSet)
final List<RolloutGroupCreate> groups = List.of(group1, group2); .build();
final List<GroupCreate> groups = List.of(group1, group2);
assertThatExceptionOfType(AssignmentQuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> rolloutManagement.create(rolloutCreate, groups, conditions)); .isThrownBy(() -> rolloutManagement.create(rolloutCreate, groups, conditions));
// create group definitions // create group definitions
final RolloutGroupCreate group3 = entityFactory.rolloutGroup().create().conditions(conditions).name("group3").targetPercentage(1.0F); final GroupCreate group3 = GroupCreate.builder().conditions(conditions).name("group3").targetPercentage(1.0F).build();
final RolloutGroupCreate group4 = entityFactory.rolloutGroup().create().conditions(conditions).name("group4").targetPercentage(100.0F); final GroupCreate group4 = GroupCreate.builder().conditions(conditions).name("group4").targetPercentage(100.0F).build();
// group4 exceeds the quota // group4 exceeds the quota
final List<RolloutGroupCreate> groups2 = List.of(group3, group4); final List<GroupCreate> groups2 = List.of(group3, group4);
assertThatExceptionOfType(AssignmentQuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> rolloutManagement.create(rolloutCreate, groups2, conditions)); .isThrownBy(() -> rolloutManagement.create(rolloutCreate, groups2, conditions));
// create group definitions // create group definitions
final RolloutGroupCreate group5 = entityFactory.rolloutGroup().create().conditions(conditions).name("group5").targetPercentage(33.3F); final GroupCreate group5 = GroupCreate.builder().conditions(conditions).name("group5").targetPercentage(33.3F).build();
final RolloutGroupCreate group6 = entityFactory.rolloutGroup().create().conditions(conditions).name("group6").targetPercentage(33.3F); final GroupCreate group6 = GroupCreate.builder().conditions(conditions).name("group6").targetPercentage(33.3F).build();
final RolloutGroupCreate group7 = entityFactory.rolloutGroup().create().conditions(conditions).name("group7").targetPercentage(33.3F); final GroupCreate group7 = GroupCreate.builder().conditions(conditions).name("group7").targetPercentage(33.3F).build();
// should work fine // should work fine
assertThat(rolloutManagement.create( assertThat(rolloutManagement.create(rolloutCreate, Arrays.asList(group5, group6, group7), conditions)).isNotNull();
rolloutCreate,
Arrays.asList(group5, group6, group7), conditions)).isNotNull();
} }
/** /**
@@ -1579,8 +1564,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
// schedule rollout auto start into the future // schedule rollout auto start into the future
final Long myRolloutId = myRollout.getId(); final Long myRolloutId = myRollout.getId();
rolloutManagement rolloutManagement.update(Update.builder().id(myRolloutId).name("newName").description("newDesc").build());
.update(entityFactory.rollout().update(myRolloutId).name("newName").description("newDesc"));
rolloutHandler.handleAll(); rolloutHandler.handleAll();
// rollout should not have been started // rollout should not have been started
@@ -1593,7 +1577,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
* Verify the creation of a rollout with a groups definition. * Verify the creation of a rollout with a groups definition.
*/ */
@Test @Test
void createRolloutWithGroupDefinition() throws Exception { void createRolloutWithGroupDefinition() {
final String rolloutName = "rolloutTest3"; final String rolloutName = "rolloutTest3";
final int amountTargetsInGroup1 = 10; final int amountTargetsInGroup1 = 10;
@@ -1609,12 +1593,12 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
// Generate Targets for group 2 and 3 and generate the Rollout // Generate Targets for group 2 and 3 and generate the Rollout
final RolloutCreate rolloutcreate = generateTargetsAndRollout(rolloutName, amountTargetsInGroup2and3); final Create rolloutcreate = generateTargetsAndRollout(rolloutName, amountTargetsInGroup2and3);
// Generate Targets for group 1 // Generate Targets for group 1
testdataFactory.createTargets(amountTargetsInGroup1, rolloutName + "-gr1-", rolloutName); testdataFactory.createTargets(amountTargetsInGroup1, rolloutName + "-gr1-", rolloutName);
final List<RolloutGroupCreate> rolloutGroups = new ArrayList<>(3); final List<GroupCreate> rolloutGroups = new ArrayList<>(3);
rolloutGroups.add(generateRolloutGroup(0, percentTargetsInGroup1, "id==" + rolloutName + "-gr1-*")); rolloutGroups.add(generateRolloutGroup(0, percentTargetsInGroup1, "id==" + rolloutName + "-gr1-*"));
rolloutGroups.add(generateRolloutGroup(1, percentTargetsInGroup2, null)); rolloutGroups.add(generateRolloutGroup(1, percentTargetsInGroup2, null));
rolloutGroups.add(generateRolloutGroup(2, percentTargetsInGroup3, null)); rolloutGroups.add(generateRolloutGroup(2, percentTargetsInGroup3, null));
@@ -1627,9 +1611,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
assertThat(group.getStatus()).isEqualTo(RolloutGroupStatus.CREATING); assertThat(group.getStatus()).isEqualTo(RolloutGroupStatus.CREATING);
} }
// Generate Targets that must not be addressed by the rollout, because // Generate Targets that must not be addressed by the rollout, because they were added after the rollout was created
// they were added after the rollout was created
TimeUnit.SECONDS.sleep(1);
testdataFactory.createTargets(10, rolloutName + "-notIn-", rolloutName); testdataFactory.createTargets(10, rolloutName + "-notIn-", rolloutName);
rolloutHandler.handleAll(); rolloutHandler.handleAll();
@@ -1648,7 +1630,6 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
assertThat(groups.get(2).getStatus()).isEqualTo(RolloutGroupStatus.READY); assertThat(groups.get(2).getStatus()).isEqualTo(RolloutGroupStatus.READY);
assertThat(groups.get(2).getTotalTargets()).isEqualTo(countTargetsInGroup3); assertThat(groups.get(2).getTotalTargets()).isEqualTo(countTargetsInGroup3);
} }
/** /**
@@ -1663,12 +1644,12 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
// Generate Targets for group 2 // Generate Targets for group 2
final RolloutCreate rolloutcreate = generateTargetsAndRollout(rolloutName, amountTargetsInGroup2); final Create rolloutcreate = generateTargetsAndRollout(rolloutName, amountTargetsInGroup2);
// Generate Targets for group 1 // Generate Targets for group 1
testdataFactory.createTargets(amountTargetsInGroup1, rolloutName + "-gr1-", rolloutName); testdataFactory.createTargets(amountTargetsInGroup1, rolloutName + "-gr1-", rolloutName);
final List<RolloutGroupCreate> rolloutGroups = new ArrayList<>(3); final List<GroupCreate> rolloutGroups = new ArrayList<>(3);
rolloutGroups.add(generateRolloutGroup(0, 100, "id==" + rolloutName + "-gr1-*", true)); rolloutGroups.add(generateRolloutGroup(0, 100, "id==" + rolloutName + "-gr1-*", true));
rolloutGroups.add(generateRolloutGroup(1, 100, null, false)); rolloutGroups.add(generateRolloutGroup(1, 100, null, false));
@@ -1740,9 +1721,9 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final int percentTargetsInGroup2 = 50; final int percentTargetsInGroup2 = 50;
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
final RolloutCreate myRollout = generateTargetsAndRollout(rolloutName, amountTargetsForRollout); final Create myRollout = generateTargetsAndRollout(rolloutName, amountTargetsForRollout);
final List<RolloutGroupCreate> rolloutGroups = new ArrayList<>(2); final List<GroupCreate> rolloutGroups = new ArrayList<>(2);
rolloutGroups.add(generateRolloutGroup(0, percentTargetsInGroup1, null)); rolloutGroups.add(generateRolloutGroup(0, percentTargetsInGroup1, null));
rolloutGroups.add(generateRolloutGroup(1, percentTargetsInGroup2, null)); rolloutGroups.add(generateRolloutGroup(1, percentTargetsInGroup2, null));
@@ -1763,9 +1744,9 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final int percentTargetsInGroup2 = 50; final int percentTargetsInGroup2 = 50;
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
final RolloutCreate myRollout = generateTargetsAndRollout(rolloutName, amountTargetsForRollout); final Create myRollout = generateTargetsAndRollout(rolloutName, amountTargetsForRollout);
final List<RolloutGroupCreate> rolloutGroups = Arrays.asList( final List<GroupCreate> rolloutGroups = Arrays.asList(
generateRolloutGroup(0, percentTargetsInGroup1, null), generateRolloutGroup(0, percentTargetsInGroup1, null),
generateRolloutGroup(1, percentTargetsInGroup2, null)); generateRolloutGroup(1, percentTargetsInGroup2, null));
@@ -1785,7 +1766,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final int maxGroups = quotaManagement.getMaxRolloutGroupsPerRollout(); final int maxGroups = quotaManagement.getMaxRolloutGroupsPerRollout();
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
final RolloutCreate rollout = generateTargetsAndRollout(rolloutName, targets); final Create rollout = generateTargetsAndRollout(rolloutName, targets);
assertThatExceptionOfType(AssignmentQuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> rolloutManagement.create(rollout, maxGroups + 1, false, conditions)) .isThrownBy(() -> rolloutManagement.create(rollout, maxGroups + 1, false, conditions))
@@ -1809,8 +1790,10 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition) .successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition)
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition)
.errorAction(RolloutGroupErrorAction.PAUSE, null).build(); .errorAction(RolloutGroupErrorAction.PAUSE, null).build();
final RolloutCreate rolloutToCreate = entityFactory.rollout().create().name(rolloutName) final Create rolloutToCreate = Create.builder()
.description("some description").targetFilterQuery("id==" + rolloutName + "-*").distributionSetId(distributionSet); .name(rolloutName).description("some description")
.targetFilterQuery("id==" + rolloutName + "-*").distributionSet(distributionSet)
.build();
Rollout myRollout = rolloutManagement.create(rolloutToCreate, amountGroups, false, conditions); Rollout myRollout = rolloutManagement.create(rolloutToCreate, amountGroups, false, conditions);
myRollout = getRollout(myRollout.getId()); myRollout = getRollout(myRollout.getId());
@@ -1964,7 +1947,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
assertThat(deletedRollout.getStatus()).isEqualTo(RolloutStatus.DELETED); assertThat(deletedRollout.getStatus()).isEqualTo(RolloutStatus.DELETED);
final RolloutUpdate rolloutUpdate = entityFactory.rollout().update(createdRollout.getId()).description("test"); final Update rolloutUpdate = Update.builder().id(createdRollout.getId()).description("test").build();
assertThatExceptionOfType(EntityReadOnlyException.class) assertThatExceptionOfType(EntityReadOnlyException.class)
.isThrownBy(() -> rolloutManagement.update(rolloutUpdate)) .isThrownBy(() -> rolloutManagement.update(rolloutUpdate))
.withMessageContaining("" + createdRollout.getId()); .withMessageContaining("" + createdRollout.getId());
@@ -1995,9 +1978,9 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
final String prefixRolloutRunning = randomString + "1"; final String prefixRolloutRunning = randomString + "1";
final RolloutCreate rolloutRunningCreate = entityFactory.rollout().create() final Create rolloutRunningCreate = Create.builder()
.name(prefixRolloutRunning + "-testRollout").targetFilterQuery("name==" + randomString + "*") .name(prefixRolloutRunning + "-testRollout").targetFilterQuery("name==" + randomString + "*").distributionSet(testDs)
.distributionSetId(testDs); .build();
Rollout rolloutRunning = rolloutManagement.create(rolloutRunningCreate, 1, false, conditions); Rollout rolloutRunning = rolloutManagement.create(rolloutRunningCreate, 1, false, conditions);
// Let the executor handle created Rollout // Let the executor handle created Rollout
@@ -2009,8 +1992,8 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
rolloutRunning = reloadRollout(rolloutRunning); rolloutRunning = reloadRollout(rolloutRunning);
final String prefixRolloutReady = randomString + "2"; final String prefixRolloutReady = randomString + "2";
final RolloutCreate rolloutReadyCreate = entityFactory.rollout().create() final Create rolloutReadyCreate = Create.builder()
.name(prefixRolloutReady + "-testRollout").targetFilterQuery("name==" + randomString + "*").distributionSetId(testDs); .name(prefixRolloutReady + "-testRollout").targetFilterQuery("name==" + randomString + "*").distributionSet(testDs).build();
Rollout rolloutReady = rolloutManagement.create(rolloutReadyCreate, 1, false, conditions); Rollout rolloutReady = rolloutManagement.create(rolloutReadyCreate, 1, false, conditions);
// Let the executor handle created Rollout // Let the executor handle created Rollout
rolloutHandler.handleAll(); rolloutHandler.handleAll();
@@ -2158,8 +2141,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
targets.addAll(targetsWithoutType); targets.addAll(targetsWithoutType);
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build(); final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
final RolloutCreate rolloutToCreate = entityFactory.rollout().create() final Create rolloutToCreate = Create.builder().name(rolloutName).targetFilterQuery("name==*").distributionSet(testDs).build();
.name(rolloutName).targetFilterQuery("name==*").distributionSetId(testDs);
final Rollout createdRollout = rolloutManagement.create(rolloutToCreate, 1, false, conditions); final Rollout createdRollout = rolloutManagement.create(rolloutToCreate, 1, false, conditions);
@@ -2415,26 +2397,26 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
}); });
} }
private RolloutGroupCreate generateRolloutGroup(final int index, final Integer percentage, private GroupCreate generateRolloutGroup(final int index, final Integer percentage, final String targetFilter) {
final String targetFilter) {
return generateRolloutGroup(index, percentage, targetFilter, false); return generateRolloutGroup(index, percentage, targetFilter, false);
} }
private RolloutGroupCreate generateRolloutGroup(final int index, final Integer percentage, private GroupCreate generateRolloutGroup(final int index, final Integer percentage,
final String targetFilter, final boolean confirmationRequired) { final String targetFilter, final boolean confirmationRequired) {
return entityFactory.rolloutGroup().create().name("Group" + index).description("Group" + index + "desc") return GroupCreate.builder().name("Group" + index).description("Group" + index + "desc")
.targetPercentage(Float.valueOf(percentage)).targetFilterQuery(targetFilter) .targetPercentage(Float.valueOf(percentage)).targetFilterQuery(targetFilter)
.confirmationRequired(confirmationRequired); .confirmationRequired(confirmationRequired).build();
} }
private RolloutCreate generateTargetsAndRollout(final String rolloutName, final int amountTargetsForRollout) { private Create generateTargetsAndRollout(final String rolloutName, final int amountTargetsForRollout) {
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName); final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
testdataFactory.createTargets(amountTargetsForRollout, rolloutName + "-", rolloutName); testdataFactory.createTargets(amountTargetsForRollout, rolloutName + "-", rolloutName);
return entityFactory.rollout().create().name(rolloutName) return Create.builder()
.description("This is a test description for the rollout") .name(rolloutName).description("This is a test description for the rollout")
.targetFilterQuery("controllerId==" + rolloutName + "-*").distributionSetId(distributionSet); .targetFilterQuery("controllerId==" + rolloutName + "-*").distributionSet(distributionSet)
.build();
} }
private void validateRolloutGroupActionStatus(final RolloutGroup rolloutGroup, private void validateRolloutGroupActionStatus(final RolloutGroup rolloutGroup,
@@ -2479,7 +2461,7 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
final List<Action> runningActions = findActionsByRolloutAndStatus(rollout, Status.RUNNING); final List<Action> runningActions = findActionsByRolloutAndStatus(rollout, Status.RUNNING);
for (final Action action : runningActions) { for (final Action action : runningActions) {
controllerManagement controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(status)); .addUpdateActionStatus(ActionStatusCreate.builder().actionId(action.getId()).status(status).build());
} }
return runningActions.size(); return runningActions.size();
} }
@@ -2490,18 +2472,8 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
assertThat(runningActions).hasSizeGreaterThanOrEqualTo(amountOfTargetsToGetChanged); assertThat(runningActions).hasSizeGreaterThanOrEqualTo(amountOfTargetsToGetChanged);
for (int i = 0; i < amountOfTargetsToGetChanged; i++) { for (int i = 0; i < amountOfTargetsToGetChanged; i++) {
controllerManagement.addUpdateActionStatus( controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(runningActions.get(i).getId()).status(status)); ActionStatusCreate.builder().actionId(runningActions.get(i).getId()).status(status).build());
} }
return runningActions.size(); return runningActions.size();
} }
}
private void awaitRunningState(final Long myRolloutId) {
Awaitility.await()
.pollInterval(Duration.ofMillis(500))
.atMost(Duration.ofSeconds(10))
.until(() -> SecurityContextSwitch
.callAsPrivileged(
() -> rolloutManagement.get(myRolloutId).orElseThrow(NoSuchElementException::new))
.getStatus().equals(RolloutStatus.RUNNING));
}
}

View File

@@ -18,6 +18,7 @@ import java.util.Set;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
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;
import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.DistributionSetType;
@@ -84,7 +85,8 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
// set on installed and assign another one // set on installed and assign another one
assignDistributionSet(installedSet, installedtargets).getAssignedEntity().forEach(action -> assignDistributionSet(installedSet, installedtargets).getAssignedEntity().forEach(action ->
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).status(Status.FINISHED))); controllerManagement.addUpdateActionStatus(
ActionStatusCreate.builder().actionId(action.getId()).status(Status.FINISHED).build()));
assignDistributionSet(assignedSet, installedtargets); assignDistributionSet(assignedSet, installedtargets);
// get final updated version of targets // get final updated version of targets

View File

@@ -70,6 +70,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
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;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult; import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
@@ -326,7 +327,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
implicitLock(testDs1); implicitLock(testDs1);
controllerManagement.addUpdateActionStatus( controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(getFirstAssignedActionId(result)).status(Status.FINISHED)); ActionStatusCreate.builder().actionId(getFirstAssignedActionId(result)).status(Status.FINISHED).build());
assignDistributionSet(testDs2.getId(), "4711"); assignDistributionSet(testDs2.getId(), "4711");
implicitLock(testDs2); implicitLock(testDs2);

View File

@@ -12,6 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import org.eclipse.hawkbit.repository.RolloutFields; import org.eclipse.hawkbit.repository.RolloutFields;
import org.eclipse.hawkbit.repository.RolloutManagement.Create;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
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;
@@ -58,8 +59,9 @@ class RsqlRolloutFieldTest extends AbstractJpaIntegrationTest {
private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId, final String targetFilterQuery) { private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId, final String targetFilterQuery) {
return rolloutManagement.create( return rolloutManagement.create(
entityFactory.rollout().create().distributionSetId( Create.builder()
distributionSetManagement.get(distributionSetId).get()).name(name).targetFilterQuery(targetFilterQuery), .distributionSet(distributionSetManagement.get(distributionSetId).get()).name(name).targetFilterQuery(targetFilterQuery)
.build(),
amountGroups, amountGroups,
false, false,
new RolloutGroupConditionBuilder().withDefaults().successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); new RolloutGroupConditionBuilder().withDefaults().successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());

View File

@@ -12,6 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import org.eclipse.hawkbit.repository.RolloutGroupFields; import org.eclipse.hawkbit.repository.RolloutGroupFields;
import org.eclipse.hawkbit.repository.RolloutManagement.Create;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
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;
@@ -100,8 +101,9 @@ class RsqlRolloutGroupFieldTest extends AbstractJpaIntegrationTest {
private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId, private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId,
final String targetFilterQuery) { final String targetFilterQuery) {
return rolloutManagement.create( return rolloutManagement.create(
entityFactory.rollout().create().distributionSetId(distributionSetManagement.get(distributionSetId).get()).name(name) Create.builder()
.targetFilterQuery(targetFilterQuery), .distributionSet(distributionSetManagement.get(distributionSetId).get()).name(name).targetFilterQuery(targetFilterQuery)
.build(),
amountGroups, false, new RolloutGroupConditionBuilder().withDefaults() amountGroups, false, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
} }

View File

@@ -39,7 +39,6 @@ import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement; import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement; import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RepositoryConstants; import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.RolloutGroupManagement; import org.eclipse.hawkbit.repository.RolloutGroupManagement;
@@ -57,6 +56,7 @@ import org.eclipse.hawkbit.repository.artifact.ArtifactRepository;
import org.eclipse.hawkbit.repository.artifact.exception.ArtifactStoreException; import org.eclipse.hawkbit.repository.artifact.exception.ArtifactStoreException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DeploymentRequest; import org.eclipse.hawkbit.repository.model.DeploymentRequest;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -129,8 +129,6 @@ public abstract class AbstractIntegrationTest {
*/ */
protected static final int DEFAULT_DS_TYPES = RepositoryConstants.DEFAULT_DS_TYPES_IN_TENANT + 1; protected static final int DEFAULT_DS_TYPES = RepositoryConstants.DEFAULT_DS_TYPES_IN_TENANT + 1;
@Autowired
protected EntityFactory entityFactory;
@Autowired @Autowired
protected SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement; protected SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement;
@Autowired @Autowired
@@ -457,9 +455,9 @@ public abstract class AbstractIntegrationTest {
} }
controllerManagement.addUpdateActionStatus( controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(savedAction.getId()).status(Action.Status.RUNNING)); ActionStatusCreate.builder().actionId(savedAction.getId()).status(Action.Status.RUNNING).build());
controllerManagement.addUpdateActionStatus( controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(savedAction.getId()).status(Action.Status.FINISHED)); ActionStatusCreate.builder().actionId(savedAction.getId()).status(Action.Status.FINISHED).build());
return controllerManagement.findActionWithDetails(savedAction.getId()) return controllerManagement.findActionWithDetails(savedAction.getId())
.orElseThrow(() -> new EntityNotFoundException(Action.class, savedAction.getId())); .orElseThrow(() -> new EntityNotFoundException(Action.class, savedAction.getId()));

View File

@@ -38,7 +38,6 @@ import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement; import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement; import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.QuotaManagement; import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RolloutHandler; import org.eclipse.hawkbit.repository.RolloutHandler;
import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.RolloutManagement;
@@ -49,8 +48,8 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.AutoAssignDist
import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTagManagement; import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.TargetTypeManagement; import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
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;
@@ -161,7 +160,6 @@ public class TestdataFactory {
private final RolloutManagement rolloutManagement; private final RolloutManagement rolloutManagement;
private final RolloutHandler rolloutHandler; private final RolloutHandler rolloutHandler;
private final QuotaManagement quotaManagement; private final QuotaManagement quotaManagement;
private final EntityFactory entityFactory;
private final TenantAware tenantAware; private final TenantAware tenantAware;
public TestdataFactory( public TestdataFactory(
@@ -178,8 +176,7 @@ public class TestdataFactory {
final TargetTagManagement<? extends TargetTag> targetTagManagement, final TargetTagManagement<? extends TargetTag> targetTagManagement,
final DeploymentManagement deploymentManagement, final DeploymentManagement deploymentManagement,
final RolloutManagement rolloutManagement, final RolloutHandler rolloutHandler, final RolloutManagement rolloutManagement, final RolloutHandler rolloutHandler,
final QuotaManagement quotaManagement, final QuotaManagement quotaManagement, final TenantAware tenantAware) {
final EntityFactory entityFactory, final TenantAware tenantAware) {
this.controllerManagement = controllerManagement; this.controllerManagement = controllerManagement;
this.softwareModuleManagement = softwareModuleManagement; this.softwareModuleManagement = softwareModuleManagement;
this.softwareModuleTypeManagement = softwareModuleTypeManagement; this.softwareModuleTypeManagement = softwareModuleTypeManagement;
@@ -192,7 +189,6 @@ public class TestdataFactory {
this.targetTypeManagement = targetTypeManagement; this.targetTypeManagement = targetTypeManagement;
this.targetTagManagement = targetTagManagement; this.targetTagManagement = targetTagManagement;
this.deploymentManagement = deploymentManagement; this.deploymentManagement = deploymentManagement;
this.entityFactory = entityFactory;
this.artifactManagement = artifactManagement; this.artifactManagement = artifactManagement;
this.rolloutManagement = rolloutManagement; this.rolloutManagement = rolloutManagement;
this.rolloutHandler = rolloutHandler; this.rolloutHandler = rolloutHandler;
@@ -229,6 +225,10 @@ public class TestdataFactory {
return createDistributionSet(prefix, DEFAULT_VERSION, false); return createDistributionSet(prefix, DEFAULT_VERSION, false);
} }
public DistributionSet createDistributionSetLocked(final String prefix) {
return distributionSetManagement.lock(createDistributionSet(prefix));
}
/** /**
* Creates {@link DistributionSet} in repository including three * Creates {@link DistributionSet} in repository including three
* {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} ,
@@ -241,6 +241,11 @@ public class TestdataFactory {
return createDistributionSet(UUID.randomUUID().toString(), DEFAULT_VERSION, false); return createDistributionSet(UUID.randomUUID().toString(), DEFAULT_VERSION, false);
} }
public DistributionSet createDistributionSetLocked() {
return distributionSetManagement.lock(createDistributionSet());
}
/** /**
* Creates {@link DistributionSet} in repository including three * Creates {@link DistributionSet} in repository including three
* {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} ,
@@ -1027,21 +1032,22 @@ public class TestdataFactory {
final int groupSize, final String filterQuery, final DistributionSet distributionSet, final int groupSize, final String filterQuery, final DistributionSet distributionSet,
final String successCondition, final String errorCondition, final Action.ActionType actionType, final String successCondition, final String errorCondition, final Action.ActionType actionType,
final Integer weight, final boolean confirmationRequired, final boolean dynamic, final Integer weight, final boolean confirmationRequired, final boolean dynamic,
final DynamicRolloutGroupTemplate dynamicRolloutGroupTemplate) { final RolloutManagement.DynamicRolloutGroupTemplate dynamicRolloutGroupTemplate) {
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults() final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition) .successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition)
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition)
.errorAction(RolloutGroupErrorAction.PAUSE, null).build(); .errorAction(RolloutGroupErrorAction.PAUSE, null).build();
final Rollout rollout = rolloutManagement.create( final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create() RolloutManagement.Create.builder()
.name(rolloutName) .name(rolloutName)
.description(rolloutDescription) .description(rolloutDescription)
.targetFilterQuery(filterQuery) .targetFilterQuery(filterQuery)
.distributionSetId(distributionSet) .distributionSet(distributionSet)
.actionType(actionType) .actionType(actionType == null ? Action.ActionType.FORCED : actionType)
.weight(weight) .weight(weight)
.dynamic(dynamic), .dynamic(dynamic)
.build(),
groupSize, confirmationRequired, conditions, dynamicRolloutGroupTemplate); groupSize, confirmationRequired, conditions, dynamicRolloutGroupTemplate);
// Run here, because Scheduler is disabled during tests // Run here, because Scheduler is disabled during tests
@@ -1259,7 +1265,8 @@ public class TestdataFactory {
} }
private Action sendUpdateActionStatusToTarget(final Status status, final Action updActA, final Collection<String> msgs) { private Action sendUpdateActionStatusToTarget(final Status status, final Action updActA, final Collection<String> msgs) {
return controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(updActA.getId()).status(status).messages(msgs)); return controllerManagement.addUpdateActionStatus(
ActionStatusCreate.builder().actionId(updActA.getId()).status(status).messages(msgs).build());
} }
private Rollout startAndReloadRollout(final Rollout rollout) { private Rollout startAndReloadRollout(final Rollout rollout) {