feat: allow a target to set offline assigned distribution set (#1620)

* feat: allow a target to set offline assigned distribution set

Signed-off-by: Florian Bezannier <florian.bezannier@hotmail.fr>

* refacto: apply @avgustinmm recommendation

* docs: Mark update offline API as experimental

---------

Signed-off-by: Florian Bezannier <florian.bezannier@hotmail.fr>
This commit is contained in:
Florian BEZANNIER
2024-08-01 10:51:31 +02:00
committed by GitHub
parent aa8ab69c1f
commit 0013750f78
10 changed files with 235 additions and 3 deletions

View File

@@ -527,4 +527,22 @@ public interface ControllerManagement {
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
void deactivateAutoConfirmation(@NotEmpty String controllerId);
/**
* Updates distributionSet installed version (experimental)
*
* @param distributionName
* installed
* @param version
* installed
*
* @return updated {@link Target}
*
* @throws EntityNotFoundException
* if target that has to be updated could not be found
* @throws java.util.NoSuchElementException
* if DistributionSetAssignmentResult list is empty
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
boolean updateOfflineAssignedVersion(@NotEmpty String controllerId, String distributionName, String version);
}

View File

@@ -165,6 +165,9 @@ public interface DeploymentManagement {
* target and multiassignment is disabled
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(Collection<Entry<String, Long>> assignments, String initiatedBy);
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(Collection<Entry<String, Long>> assignments);
/**

View File

@@ -13,6 +13,7 @@ import static org.eclipse.hawkbit.repository.model.Action.Status.DOWNLOADED;
import static org.eclipse.hawkbit.repository.model.Action.Status.FINISHED;
import static org.eclipse.hawkbit.repository.model.Target.CONTROLLER_ATTRIBUTE_KEY_SIZE;
import static org.eclipse.hawkbit.repository.model.Target.CONTROLLER_ATTRIBUTE_VALUE_SIZE;
import static org.eclipse.hawkbit.security.SecurityContextTenantAware.SYSTEM_USER;
import java.net.URI;
import java.time.Duration;
@@ -44,11 +45,14 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.UpdateMode;
@@ -85,6 +89,7 @@ import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.Target;
@@ -161,6 +166,12 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
@Autowired
private TargetTypeManagement targetTypeManagement;
@Autowired
private DeploymentManagement deploymentManagement;
@Autowired
private DistributionSetManagement distributionSetManagement;
public JpaControllerManagement(final ScheduledExecutorService executorService,
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
final QuotaManagement quotaManagement, final RepositoryProperties repositoryProperties) {
@@ -1095,6 +1106,22 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
confirmationManagement.deactivateAutoConfirmation(controllerId);
}
@Override
public boolean updateOfflineAssignedVersion(@NotEmpty String controllerId, String distributionName, String version){
List<DistributionSetAssignmentResult> distributionSetAssignmentResults =
systemSecurityContext.runAsSystem(() ->
distributionSetManagement.getByNameAndVersion(distributionName,version).map(
distributionSet -> deploymentManagement.offlineAssignedDistributionSets(
List.of(Map.entry(controllerId, distributionSet.getId())),controllerId))
.orElseThrow(() ->
new EntityNotFoundException(DistributionSet.class, Map.entry(distributionName, version)))
.stream().toList());
boolean notAlreadyAssigned = distributionSetAssignmentResults.stream().findFirst()
.map(result-> result.getAlreadyAssigned()==0)
.orElseThrow();
return notAlreadyAssigned;
}
private void cancelAssignDistributionSetEvent(final Action action) {
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
.publishEvent(new CancelTargetAssignmentEvent(action, eventPublisherHolder.getApplicationId())));

View File

@@ -185,6 +185,12 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
@Transactional(isolation = Isolation.READ_COMMITTED)
public List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(
final Collection<Entry<String, Long>> assignments) {
return offlineAssignedDistributionSets(assignments,tenantAware.getCurrentUsername());
}
@Override
public List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(
Collection<Entry<String, Long>> assignments, String initiatedBy) {
final Collection<Entry<String, Long>> distinctAssignments = assignments.stream().distinct().toList();
enforceMaxAssignmentsPerRequest(distinctAssignments.size());

View File

@@ -1564,6 +1564,36 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(foundAction).isPresent();
assertThat(foundAction.get().getId()).isEqualTo(actionId);
}
@Test
@Description("Verify that assigning version form target works")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3)}
)
void assignVersionToTarget() {
final DistributionSet knownDistributionSet = testdataFactory.createDistributionSet();
// GIVEN
testdataFactory.createTarget(DEFAULT_CONTROLLER_ID).getId();
// WHEN
boolean updated1 = controllerManagement.updateOfflineAssignedVersion(DEFAULT_CONTROLLER_ID,
knownDistributionSet.getName(),knownDistributionSet.getVersion());
// if target is already assigned to a distribution then it shouldn't reassign the distribution
boolean updated2 = controllerManagement.updateOfflineAssignedVersion(DEFAULT_CONTROLLER_ID,
knownDistributionSet.getName(),knownDistributionSet.getVersion());
// THEN
assertAssignedDistributionSetId(DEFAULT_CONTROLLER_ID, knownDistributionSet.getId());
assertInstalledDistributionSetId(DEFAULT_CONTROLLER_ID, knownDistributionSet.getId());
assertThat(updated1).isTrue();
assertThat(updated2).isFalse();
}
@Test
@Description("Verify that a null externalRef cannot be assigned to an action")