Fix EntityMatcher when for Identifiable.getId (#2724)
* Fix EntityMatcher to process properly filters of type targetType.id - to resolve correctly the getter return type Long not T * Add AutoAsssignTest access control test * Simplify rest of the ACM tests Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2025 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.jpa.acm;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.eclipse.hawkbit.repository.TargetTagFields;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
|
||||
|
||||
// utility class to validate authorities when ACM is enabled
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class AuthorityChecker {
|
||||
|
||||
private static final Set<String> ALL_AUTHORITIES = SpPermission.getAllTenantAuthorities();
|
||||
|
||||
public static String[] validateAuthorities(final String... authorities) {
|
||||
for (final String authority : authorities) {
|
||||
validateAuthority(authority);
|
||||
}
|
||||
return authorities;
|
||||
}
|
||||
|
||||
public static void validateAuthority(final String authority) {
|
||||
final int index = authority.indexOf('/');
|
||||
final String unscopedPermission = index > 0 ? authority.substring(0, index) : authority;
|
||||
if (index > 0) {
|
||||
validateScope(group(unscopedPermission), authority.substring(index + 1), authority);
|
||||
}
|
||||
if (!ALL_AUTHORITIES.contains(unscopedPermission)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown permission: " + unscopedPermission + (index > 0 ? " (unscoped of " + authority + ")" : ""));
|
||||
}
|
||||
}
|
||||
|
||||
private static String group(final String unscopedPermission) {
|
||||
if (unscopedPermission.startsWith(SpPermission.CREATE_PREFIX)) {
|
||||
return unscopedPermission.substring(SpPermission.CREATE_PREFIX.length());
|
||||
} else if (unscopedPermission.startsWith(SpPermission.READ_PREFIX)) {
|
||||
return unscopedPermission.substring(SpPermission.READ_PREFIX.length());
|
||||
} else if (unscopedPermission.startsWith(SpPermission.UPDATE_PREFIX)) {
|
||||
return unscopedPermission.substring(SpPermission.UPDATE_PREFIX.length());
|
||||
} else if (unscopedPermission.startsWith(SpPermission.DELETE_PREFIX)) {
|
||||
return unscopedPermission.substring(SpPermission.DELETE_PREFIX.length());
|
||||
} else {
|
||||
throw new IllegalArgumentException(unscopedPermission + " doesn't support targetTypeScope");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private static void validateScope(final String permission, final String rsql, final String authority) {
|
||||
// validate RSQL
|
||||
final Class<?> rsqlQueryFieldType;
|
||||
final Class<?> jpaType;
|
||||
switch (permission) {
|
||||
case SpPermission.TARGET -> {
|
||||
rsqlQueryFieldType = TargetFields.class;
|
||||
jpaType = JpaTarget.class;
|
||||
}
|
||||
case SpPermission.TARGET_TYPE -> {
|
||||
rsqlQueryFieldType = TargetTagFields.class;
|
||||
jpaType = JpaTarget.class;
|
||||
}
|
||||
case SpPermission.SOFTWARE_MODULE -> {
|
||||
rsqlQueryFieldType = SoftwareModuleFields.class;
|
||||
jpaType = JpaSoftwareModule.class;
|
||||
}
|
||||
case SpPermission.SOFTWARE_MODULE_TYPE -> {
|
||||
rsqlQueryFieldType = SoftwareModuleTypeFields.class;
|
||||
jpaType = JpaSoftwareModuleType.class;
|
||||
}
|
||||
case SpPermission.DISTRIBUTION_SET -> {
|
||||
rsqlQueryFieldType = DistributionSetFields.class;
|
||||
jpaType = JpaDistributionSet.class;
|
||||
}
|
||||
case SpPermission.DISTRIBUTION_SET_TYPE -> {
|
||||
rsqlQueryFieldType = DistributionSetTypeFields.class;
|
||||
jpaType = JpaTarget.class;
|
||||
}
|
||||
default -> throw new IllegalArgumentException(permission + " doesn't support targetTypeScope");
|
||||
}
|
||||
try {
|
||||
QLSupport.getInstance().validate(rsql, (Class) rsqlQueryFieldType, jpaType);
|
||||
} catch (final RuntimeException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Scope of " + authority + " is not a valid RSQL for " + permission + ": " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO 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.autoassign;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstract implementation of an AutoAssignExecutor
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
||||
|
||||
/**
|
||||
* The message which is added to the action status when a distribution set is
|
||||
* assigned to an target. First %s is the name of the target filter.
|
||||
*/
|
||||
private static final String ACTION_MESSAGE = "Auto assignment by target filter: %s";
|
||||
|
||||
/**
|
||||
* Maximum for target filter queries with auto assign DS activated.
|
||||
*/
|
||||
private static final int PAGE_SIZE = 1000;
|
||||
|
||||
private final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement;
|
||||
private final DeploymentManagement deploymentManagement;
|
||||
private final PlatformTransactionManager transactionManager;
|
||||
private final ContextAware contextAware;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param targetFilterQueryManagement to get all target filter queries
|
||||
* @param deploymentManagement to assign distribution sets to targets
|
||||
* @param transactionManager to run transactions
|
||||
* @param contextAware to handle the context
|
||||
*/
|
||||
protected AbstractAutoAssignExecutor(
|
||||
final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement,
|
||||
final DeploymentManagement deploymentManagement,
|
||||
final PlatformTransactionManager transactionManager, final ContextAware contextAware) {
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.transactionManager = transactionManager;
|
||||
this.contextAware = contextAware;
|
||||
}
|
||||
|
||||
protected static String getAutoAssignmentInitiatedBy(final TargetFilterQuery targetFilterQuery) {
|
||||
return StringUtils.hasText(targetFilterQuery.getAutoAssignInitiatedBy())
|
||||
? targetFilterQuery.getAutoAssignInitiatedBy()
|
||||
: targetFilterQuery.getCreatedBy();
|
||||
}
|
||||
|
||||
protected DeploymentManagement getDeploymentManagement() {
|
||||
return deploymentManagement;
|
||||
}
|
||||
|
||||
protected PlatformTransactionManager getTransactionManager() {
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
protected TenantAware getContextAware() {
|
||||
return contextAware;
|
||||
}
|
||||
|
||||
// run in the context the auto assignment is made in, i.e. if there is access control context it runs in it
|
||||
// otherwise in the tenant & user context built by createdBy
|
||||
// Note! It must be called in a tenant context, i.e. contextAware.getCurrentTenant() returns the tenant
|
||||
protected void forEachFilterWithAutoAssignDS(final Consumer<TargetFilterQuery> consumer) {
|
||||
Slice<TargetFilterQuery> filterQueries;
|
||||
Pageable query = PageRequest.of(0, PAGE_SIZE);
|
||||
|
||||
do {
|
||||
filterQueries = targetFilterQueryManagement.findWithAutoAssignDS(query);
|
||||
|
||||
filterQueries.forEach(filterQuery -> {
|
||||
try {
|
||||
filterQuery.getAccessControlContext().ifPresentOrElse(
|
||||
context -> // has stored context - executes it with it
|
||||
contextAware.runInContext(
|
||||
context,
|
||||
() -> consumer.accept(filterQuery)),
|
||||
() -> // has no stored context - executes it in the tenant & user scope
|
||||
contextAware.runAsTenantAsUser(
|
||||
contextAware.getCurrentTenant(),
|
||||
getAutoAssignmentInitiatedBy(filterQuery), () -> {
|
||||
consumer.accept(filterQuery);
|
||||
return null;
|
||||
})
|
||||
);
|
||||
} catch (final RuntimeException ex) {
|
||||
log.debug(
|
||||
"Exception on forEachFilterWithAutoAssignDS execution for tenant {} with filter id {}. Continue with next filter query.",
|
||||
filterQuery.getTenant(), filterQuery.getId(), ex);
|
||||
log.error(
|
||||
"Exception on forEachFilterWithAutoAssignDS execution for tenant {} with filter id {} and error message [{}]. "
|
||||
+ "Continue with next filter query.",
|
||||
filterQuery.getTenant(), filterQuery.getId(), ex.getMessage());
|
||||
}
|
||||
});
|
||||
} while ((query = filterQueries.nextPageable()) != Pageable.unpaged());
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs target assignments within a dedicated transaction for a given list of
|
||||
* controllerIDs
|
||||
*
|
||||
* @param targetFilterQuery the target filter query
|
||||
* @param controllerIds the controllerIDs
|
||||
* @return count of targets
|
||||
*/
|
||||
protected int runTransactionalAssignment(final TargetFilterQuery targetFilterQuery,
|
||||
final List<String> controllerIds) {
|
||||
final String actionMessage = String.format(ACTION_MESSAGE, targetFilterQuery.getName());
|
||||
|
||||
return DeploymentHelper.runInNewTransaction(getTransactionManager(), "autoAssignDSToTargets",
|
||||
Isolation.READ_COMMITTED.value(), status -> {
|
||||
|
||||
final List<DeploymentRequest> deploymentRequests = mapToDeploymentRequests(controllerIds,
|
||||
targetFilterQuery);
|
||||
|
||||
final int count = deploymentRequests.size();
|
||||
if (count > 0) {
|
||||
getDeploymentManagement().assignDistributionSets(
|
||||
getAutoAssignmentInitiatedBy(targetFilterQuery), deploymentRequests, actionMessage);
|
||||
}
|
||||
return count;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of {@link DeploymentRequest} for given list of controllerIds
|
||||
* and {@link TargetFilterQuery}
|
||||
*
|
||||
* @param controllerIds list of controllerIds
|
||||
* @param filterQuery the query the targets have to match
|
||||
* @return list of deployment request
|
||||
*/
|
||||
protected List<DeploymentRequest> mapToDeploymentRequests(final List<String> controllerIds,
|
||||
final TargetFilterQuery filterQuery) {
|
||||
// the action type is set to FORCED per default (when not explicitly
|
||||
// specified)
|
||||
final Action.ActionType autoAssignActionType = filterQuery.getAutoAssignActionType() == null
|
||||
? Action.ActionType.FORCED
|
||||
: filterQuery.getAutoAssignActionType();
|
||||
|
||||
return controllerIds.stream()
|
||||
.map(controllerId -> DeploymentRequest
|
||||
.builder(controllerId, filterQuery.getAutoAssignDistributionSet().getId())
|
||||
.actionType(autoAssignActionType).weight(filterQuery.getAutoAssignWeight().orElse(null))
|
||||
.confirmationRequired(filterQuery.isConfirmationRequired()).build())
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.autoassign;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import jakarta.persistence.PersistenceException;
|
||||
|
||||
@@ -20,109 +21,195 @@ import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Checks if targets need a new distribution set (DS) based on the target filter
|
||||
* queries and assigns the new DS when necessary. First all target filter
|
||||
* queries are listed. For every target filter query (TFQ) the auto assign DS is
|
||||
* retrieved. All targets get listed per target filter query, that match the TFQ
|
||||
* and that don't have the auto assign DS in their action history.
|
||||
* Checks if targets need a new distribution set (DS) based on the target filter queries and assigns the new DS when necessary. First all target
|
||||
* filter queries are listed. For every target filter query (TFQ) the auto assign DS is retrieved. All targets get listed per target filter
|
||||
* query, that match the TFQ and that don't have the auto assign DS in their action history.
|
||||
*/
|
||||
@Slf4j
|
||||
public class AutoAssignChecker extends AbstractAutoAssignExecutor {
|
||||
|
||||
private final TargetManagement<? extends Target> targetManagement;
|
||||
public class AutoAssignChecker implements AutoAssignExecutor {
|
||||
|
||||
/**
|
||||
* Instantiates a new auto assign checker
|
||||
*
|
||||
* @param targetFilterQueryManagement to get all target filter queries
|
||||
* @param targetManagement to get targets
|
||||
* @param deploymentManagement to assign distribution sets to targets
|
||||
* @param transactionManager to run transactions
|
||||
* @param contextAware to handle the context
|
||||
* The message which is added to the action status when a distribution set is assigned to a target.
|
||||
* First %s is the name of the target filter.
|
||||
*/
|
||||
private static final String ACTION_MESSAGE = "Auto assignment by target filter: %s";
|
||||
|
||||
/**
|
||||
* Maximum for target filter queries with auto assign DS activated.
|
||||
*/
|
||||
private static final int PAGE_SIZE = 1000;
|
||||
|
||||
private final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement;
|
||||
private final TargetManagement<? extends Target> targetManagement;
|
||||
private final DeploymentManagement deploymentManagement;
|
||||
private final PlatformTransactionManager transactionManager;
|
||||
private final ContextAware contextAware;
|
||||
|
||||
public AutoAssignChecker(
|
||||
final TargetFilterQueryManagement<? extends TargetFilterQuery> targetFilterQueryManagement,
|
||||
final TargetManagement<? extends Target> targetManagement, final DeploymentManagement deploymentManagement,
|
||||
final PlatformTransactionManager transactionManager, final ContextAware contextAware) {
|
||||
super(targetFilterQueryManagement, deploymentManagement, transactionManager, contextAware);
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.targetManagement = targetManagement;
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.transactionManager = transactionManager;
|
||||
this.contextAware = contextAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public void checkAllTargets() {
|
||||
log.debug("Auto assign check call for tenant {} started", getContextAware().getCurrentTenant());
|
||||
log.debug("Auto assign check call started");
|
||||
forEachFilterWithAutoAssignDS(this::checkByTargetFilterQueryAndAssignDS);
|
||||
log.debug("Auto assign check call for tenant {} finished", getContextAware().getCurrentTenant());
|
||||
log.debug("Auto assign check call finished");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkSingleTarget(String controllerId) {
|
||||
log.debug("Auto assign check call for tenant {} and device {} started", getContextAware().getCurrentTenant(), controllerId);
|
||||
log.debug("Auto assign check call for device {} started", controllerId);
|
||||
forEachFilterWithAutoAssignDS(filter -> checkForDevice(controllerId, filter));
|
||||
log.debug("Auto assign check call for tenant {} and device {} finished", getContextAware().getCurrentTenant(), controllerId);
|
||||
log.debug("Auto assign check call for device {} finished", controllerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the distribution set, gets all controllerIds and assigns the DS to
|
||||
* them. Catches PersistenceException and own exceptions derived from
|
||||
* AbstractServerRtException
|
||||
* Fetches the distribution set, gets all controllerIds and assigns the DS to them. Catches PersistenceException and own exceptions derived
|
||||
* from AbstractServerRtException
|
||||
*
|
||||
* @param targetFilterQuery the target filter query
|
||||
*/
|
||||
private void checkByTargetFilterQueryAndAssignDS(final TargetFilterQuery targetFilterQuery) {
|
||||
log.debug("Auto assign check call for tenant {} and target filter query id {} started",
|
||||
getContextAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
log.debug("Auto assign check call for target filter query id {} started", targetFilterQuery.getId());
|
||||
try {
|
||||
int count;
|
||||
do {
|
||||
final List<String> controllerIds = targetManagement
|
||||
.findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(
|
||||
targetFilterQuery.getAutoAssignDistributionSet().getId(), targetFilterQuery.getQuery(),
|
||||
PageRequest.of(0, Constants.MAX_ENTRIES_IN_STATEMENT)
|
||||
)
|
||||
PageRequest.of(0, Constants.MAX_ENTRIES_IN_STATEMENT))
|
||||
.getContent().stream().map(Target::getControllerId).toList();
|
||||
log.debug(
|
||||
"Retrieved {} auto assign targets for tenant {} and target filter query id {}, starting with assignment",
|
||||
controllerIds.size(), getContextAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
log.debug("Retrieved {} auto assign targets for target filter query id {}, starting with assignment",
|
||||
controllerIds.size(), targetFilterQuery.getId());
|
||||
|
||||
count = runTransactionalAssignment(targetFilterQuery, controllerIds);
|
||||
log.debug(
|
||||
"Assignment for {} auto assign targets for tenant {} and target filter query id {} finished",
|
||||
controllerIds.size(), getContextAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
log.debug("Assignment for {} auto assign targets for target filter query id {} finished",
|
||||
controllerIds.size(), targetFilterQuery.getId());
|
||||
} while (count == Constants.MAX_ENTRIES_IN_STATEMENT);
|
||||
} catch (final PersistenceException | AbstractServerRtException e) {
|
||||
log.error("Error during auto assign check of target filter query id {}", targetFilterQuery.getId(), e);
|
||||
}
|
||||
log.debug("Auto assign check call for tenant {} and target filter query id {} finished",
|
||||
getContextAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
log.debug("Auto assign check call for target filter query id {} finished", targetFilterQuery.getId());
|
||||
}
|
||||
|
||||
private static String getAutoAssignmentInitiatedBy(final TargetFilterQuery targetFilterQuery) {
|
||||
return StringUtils.hasText(targetFilterQuery.getAutoAssignInitiatedBy())
|
||||
? targetFilterQuery.getAutoAssignInitiatedBy()
|
||||
: targetFilterQuery.getCreatedBy();
|
||||
}
|
||||
|
||||
// run in the context the auto assignment is made in, i.e. if there is access control context it runs in it
|
||||
// otherwise in the tenant & user context built by createdBy
|
||||
// Note: It must be called in a tenant context, i.e. contextAware.getCurrentTenant() returns the tenant
|
||||
private void forEachFilterWithAutoAssignDS(final Consumer<TargetFilterQuery> consumer) {
|
||||
Slice<TargetFilterQuery> filterQueries;
|
||||
Pageable query = PageRequest.of(0, PAGE_SIZE);
|
||||
do {
|
||||
filterQueries = targetFilterQueryManagement.findWithAutoAssignDS(query);
|
||||
|
||||
filterQueries.forEach(filterQuery -> {
|
||||
try {
|
||||
filterQuery.getAccessControlContext().ifPresentOrElse(
|
||||
context -> // has stored context - executes it with it
|
||||
contextAware.runInContext(
|
||||
context,
|
||||
() -> consumer.accept(filterQuery)),
|
||||
() -> // has no stored context - executes it in the tenant & user scope
|
||||
contextAware.runAsTenantAsUser(
|
||||
contextAware.getCurrentTenant(),
|
||||
getAutoAssignmentInitiatedBy(filterQuery), () -> {
|
||||
consumer.accept(filterQuery);
|
||||
return null;
|
||||
})
|
||||
);
|
||||
} catch (final RuntimeException ex) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Exception on forEachFilterWithAutoAssignDS execution for filter id {}. Continue with next filter query.",
|
||||
filterQuery.getId(), ex);
|
||||
} else {
|
||||
log.error(
|
||||
"Exception on forEachFilterWithAutoAssignDS execution for filter id {} and error message [{}]. Continue with next filter query.",
|
||||
filterQuery.getId(), ex.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
} while (filterQueries.hasNext() && (query = filterQueries.nextPageable()) != Pageable.unpaged());
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs target assignments within a dedicated transaction for a given list of controllerIDs
|
||||
*
|
||||
* @param targetFilterQuery the target filter query
|
||||
* @param controllerIds the controllerIDs
|
||||
* @return count of targets
|
||||
*/
|
||||
private int runTransactionalAssignment(final TargetFilterQuery targetFilterQuery, final List<String> controllerIds) {
|
||||
final String actionMessage = String.format(ACTION_MESSAGE, targetFilterQuery.getName());
|
||||
return DeploymentHelper.runInNewTransaction(transactionManager, "autoAssignDSToTargets", Isolation.READ_COMMITTED.value(), status -> {
|
||||
final List<DeploymentRequest> deploymentRequests = mapToDeploymentRequests(controllerIds, targetFilterQuery);
|
||||
final int count = deploymentRequests.size();
|
||||
if (count > 0) {
|
||||
deploymentManagement.assignDistributionSets(getAutoAssignmentInitiatedBy(targetFilterQuery), deploymentRequests, actionMessage);
|
||||
}
|
||||
return count;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of {@link DeploymentRequest} for given list of controllerIds and {@link TargetFilterQuery}
|
||||
*
|
||||
* @param controllerIds list of controllerIds
|
||||
* @param filterQuery the query the targets have to match
|
||||
* @return list of deployment request
|
||||
*/
|
||||
private List<DeploymentRequest> mapToDeploymentRequests(final List<String> controllerIds, final TargetFilterQuery filterQuery) {
|
||||
// the action type is set to FORCED per default (when not explicitly specified)
|
||||
final Action.ActionType autoAssignActionType = filterQuery.getAutoAssignActionType() == null
|
||||
? Action.ActionType.FORCED
|
||||
: filterQuery.getAutoAssignActionType();
|
||||
return controllerIds.stream()
|
||||
.map(controllerId -> DeploymentRequest
|
||||
.builder(controllerId, filterQuery.getAutoAssignDistributionSet().getId())
|
||||
.actionType(autoAssignActionType).weight(filterQuery.getAutoAssignWeight().orElse(null))
|
||||
.confirmationRequired(filterQuery.isConfirmationRequired()).build())
|
||||
.toList();
|
||||
}
|
||||
|
||||
private void checkForDevice(final String controllerId, final TargetFilterQuery targetFilterQuery) {
|
||||
log.debug("Auto assign check call for tenant {} and target filter query id {} for device {} started",
|
||||
getContextAware().getCurrentTenant(), targetFilterQuery.getId(), controllerId);
|
||||
log.debug("Auto assign check call for target filter query id {} for device {} started", targetFilterQuery.getId(), controllerId);
|
||||
try {
|
||||
final boolean controllerIdMatches = targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(
|
||||
controllerId, targetFilterQuery.getAutoAssignDistributionSet().getId(),
|
||||
targetFilterQuery.getQuery());
|
||||
|
||||
if (controllerIdMatches) {
|
||||
if (targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(
|
||||
controllerId, targetFilterQuery.getAutoAssignDistributionSet().getId(), targetFilterQuery.getQuery())) {
|
||||
runTransactionalAssignment(targetFilterQuery, Collections.singletonList(controllerId));
|
||||
}
|
||||
|
||||
} catch (final PersistenceException | AbstractServerRtException e) {
|
||||
log.error("Error during auto assign check of target filter query id {}", targetFilterQuery.getId(), e);
|
||||
}
|
||||
log.debug("Auto assign check call for tenant {} and target filter query id {} for device {} finished",
|
||||
getContextAware().getCurrentTenant(), targetFilterQuery.getId(), controllerId);
|
||||
log.debug("Auto assign check call for target filter query id {} for device {} finished", targetFilterQuery.getId(), controllerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user