Merge remote-tracking branch 'eclipse/master' into
fix-set-db-read-uncommited Fixed small typo Signed-off-by: Kai Zimmermann <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -11,9 +11,6 @@ package org.eclipse.hawkbit;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.transaction.Transaction;
|
||||
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -38,38 +35,12 @@ public class MultiTenantJpaTransactionManager extends JpaTransactionManager {
|
||||
protected void doBegin(final Object transaction, final TransactionDefinition definition) {
|
||||
super.doBegin(transaction, definition);
|
||||
|
||||
final EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager
|
||||
.getResource(getEntityManagerFactory());
|
||||
final EntityManager em = emHolder.getEntityManager();
|
||||
|
||||
if (notTenantManagement(definition) && notCurrentTenantKeyGenerator(definition)
|
||||
&& notRolloutScheduler(definition) && notGetOrCreateTenantMetadata(definition)) {
|
||||
|
||||
final String currentTenant = tenantAware.getCurrentTenant();
|
||||
if (currentTenant == null) {
|
||||
throw new TenantNotExistException("Tenant Unknown. Canceling transaction.");
|
||||
}
|
||||
|
||||
final String currentTenant = tenantAware.getCurrentTenant();
|
||||
if (currentTenant != null) {
|
||||
final EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager
|
||||
.getResource(getEntityManagerFactory());
|
||||
final EntityManager em = emHolder.getEntityManager();
|
||||
em.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, currentTenant.toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean notGetOrCreateTenantMetadata(final TransactionDefinition definition) {
|
||||
return !definition.getName()
|
||||
.startsWith(SystemManagement.class.getCanonicalName() + ".getOrCreateTenantMetadata");
|
||||
}
|
||||
|
||||
private boolean notRolloutScheduler(final TransactionDefinition definition) {
|
||||
return !definition.getName().startsWith(RolloutManagement.class.getCanonicalName() + ".rolloutScheduler");
|
||||
}
|
||||
|
||||
private boolean notCurrentTenantKeyGenerator(final TransactionDefinition definition) {
|
||||
return !definition.getName()
|
||||
.startsWith(SystemManagement.class.getCanonicalName() + ".currentTenantKeyGenerator");
|
||||
}
|
||||
|
||||
private boolean notTenantManagement(final TransactionDefinition definition) {
|
||||
return !definition.getName().startsWith(SystemManagement.class.getCanonicalName() + ".deleteTenant")
|
||||
&& !definition.getName().startsWith(SystemManagement.class.getCanonicalName() + ".findTenants");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,10 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
>>>>>>> eclipse/master
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
@@ -135,7 +139,7 @@ public class RolloutManagement {
|
||||
|
||||
/**
|
||||
* Retrieves all rollouts.
|
||||
*
|
||||
*
|
||||
* @param page
|
||||
* the page request to sort and limit the result
|
||||
* @return a page of found rollouts
|
||||
@@ -147,7 +151,7 @@ public class RolloutManagement {
|
||||
|
||||
/**
|
||||
* Retrieves all rollouts found by the given specification.
|
||||
*
|
||||
*
|
||||
* @param specification
|
||||
* the specification to filter rollouts
|
||||
* @param page
|
||||
@@ -164,7 +168,7 @@ public class RolloutManagement {
|
||||
|
||||
/**
|
||||
* Retrieves a specific rollout by its ID.
|
||||
*
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout to retrieve
|
||||
* @return the founded rollout or {@code null} if rollout with given ID does
|
||||
@@ -181,13 +185,13 @@ public class RolloutManagement {
|
||||
* which are effected by this rollout to create. The targets will then be
|
||||
* split up into groups. The size of the groups can be defined in the
|
||||
* {@code groupSize} parameter.
|
||||
*
|
||||
*
|
||||
* The rollout is not started. Only the preparation of the rollout is done,
|
||||
* persisting and creating all the necessary groups. The Rollout and the
|
||||
* groups are persisted in {@link RolloutStatus#READY} and
|
||||
* {@link RolloutGroupStatus#READY} so they can be started
|
||||
* {@link #startRollout(Rollout)}.
|
||||
*
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout entity to create
|
||||
* @param amountGroup
|
||||
@@ -196,7 +200,7 @@ public class RolloutManagement {
|
||||
* the rolloutgroup conditions and actions which should be
|
||||
* applied for each {@link RolloutGroup}
|
||||
* @return the persisted rollout.
|
||||
*
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* in case the given groupSize is zero or lower.
|
||||
*/
|
||||
@@ -216,22 +220,22 @@ public class RolloutManagement {
|
||||
* will be done synchronously and will be returned. The targets will then be
|
||||
* split up into groups. The size of the groups can be defined in the
|
||||
* {@code groupSize} parameter.
|
||||
*
|
||||
*
|
||||
* The creation of the rollout groups is executed asynchronously due it
|
||||
* might take some time to split up the targets into groups. The creation of
|
||||
* the {@link RolloutGroup} is published as event
|
||||
* {@link RolloutGroupCreatedEvent}.
|
||||
*
|
||||
*
|
||||
* The rollout is in status {@link RolloutStatus#CREATING} until all rollout
|
||||
* groups has been created and the targets are split up, then the rollout
|
||||
* will change the status to {@link RolloutStatus#READY}.
|
||||
*
|
||||
*
|
||||
* The rollout is not started. Only the preparation of the rollout is done,
|
||||
* persisting and creating all the necessary groups. The Rollout and the
|
||||
* groups are persisted in {@link RolloutStatus#READY} and
|
||||
* {@link RolloutGroupStatus#READY} so they can be started
|
||||
* {@link #startRollout(Rollout)}.
|
||||
*
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout to be created
|
||||
* @param amountGroup
|
||||
@@ -260,13 +264,7 @@ public class RolloutManagement {
|
||||
entityManager.flush();
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
final DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||
def.setName("creatingRollout");
|
||||
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
new TransactionTemplate(txManager, def).execute(status -> {
|
||||
createRolloutGroups(amountGroup, conditions, savedRollout);
|
||||
return null;
|
||||
});
|
||||
createRolloutGroupsInNewTransaction(amountGroup, conditions, savedRollout);
|
||||
} finally {
|
||||
creatingRollouts.remove(savedRollout.getName());
|
||||
}
|
||||
@@ -289,13 +287,22 @@ public class RolloutManagement {
|
||||
}
|
||||
}
|
||||
|
||||
private Rollout createRolloutGroupsInNewTransaction(final int amountOfGroups, final RolloutGroupConditions conditions,
|
||||
final Rollout savedRollout) {
|
||||
final DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||
def.setName("creatingRollout");
|
||||
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
return new TransactionTemplate(txManager, def)
|
||||
.execute(status -> createRolloutGroups(amountOfGroups, conditions, savedRollout));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for creating rollout groups and calculating group sizes. Group
|
||||
* sizes are calculated by dividing the total count of targets through the
|
||||
* amount of given groups. In same cases this will lead to less rollout
|
||||
* groups than given by client.
|
||||
*
|
||||
* @param amountGroup
|
||||
*
|
||||
* @param amountOfGroups
|
||||
* the amount of groups
|
||||
* @param conditions
|
||||
* the rollout group conditions
|
||||
@@ -303,17 +310,17 @@ public class RolloutManagement {
|
||||
* the rollout
|
||||
* @return the rollout with created groups
|
||||
*/
|
||||
private Rollout createRolloutGroups(final int amountGroup, final RolloutGroupConditions conditions,
|
||||
private Rollout createRolloutGroups(final int amountOfGroups, final RolloutGroupConditions conditions,
|
||||
final Rollout savedRollout) {
|
||||
int pageIndex = 0;
|
||||
int groupIndex = 0;
|
||||
final Long totalCount = savedRollout.getTotalTargets();
|
||||
final int groupSize = (int) Math.ceil((double) totalCount / (double) amountGroup);
|
||||
final int groupSize = (int) Math.ceil((double) totalCount / (double) amountOfGroups);
|
||||
// validate if the amount of groups that will be created are the amount
|
||||
// of groups that the client what's to have created.
|
||||
int amountGroupValidated = amountGroup;
|
||||
int amountGroupValidated = amountOfGroups;
|
||||
final int amountGroupCreation = (int) (Math.ceil((double) totalCount / (double) groupSize));
|
||||
if (amountGroupCreation == (amountGroup - 1)) {
|
||||
if (amountGroupCreation == (amountOfGroups - 1)) {
|
||||
amountGroupValidated--;
|
||||
}
|
||||
RolloutGroup lastSavedGroup = null;
|
||||
@@ -357,14 +364,14 @@ public class RolloutManagement {
|
||||
* for each affected target in the rollout. The actions of the first group
|
||||
* will be started immediately {@link RolloutGroupStatus#RUNNING} as the
|
||||
* other groups will be {@link RolloutGroupStatus#SCHEDULED} state.
|
||||
*
|
||||
*
|
||||
* The rollout itself will be then also in {@link RolloutStatus#RUNNING}.
|
||||
*
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout to be started
|
||||
*
|
||||
*
|
||||
* @return started rollout
|
||||
*
|
||||
*
|
||||
* @throws RolloutIllegalStateException
|
||||
* if given rollout is not in {@link RolloutStatus#READY}. Only
|
||||
* ready rollouts can be started.
|
||||
@@ -386,14 +393,14 @@ public class RolloutManagement {
|
||||
* actions of the first group will be started immediately
|
||||
* {@link RolloutGroupStatus#RUNNING} as the other groups will be
|
||||
* {@link RolloutGroupStatus#SCHEDULED} state.
|
||||
*
|
||||
*
|
||||
* The rollout itself will be then also in {@link RolloutStatus#RUNNING}.
|
||||
*
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout to be started
|
||||
*
|
||||
*
|
||||
* @return the started rollout
|
||||
*
|
||||
*
|
||||
* @throws RolloutIllegalStateException
|
||||
* if given rollout is not in {@link RolloutStatus#READY}. Only
|
||||
* ready rollouts can be started.
|
||||
@@ -461,14 +468,14 @@ public class RolloutManagement {
|
||||
* {@link RolloutGroupStatus#SCHEDULED} will not be started and keep in
|
||||
* {@link RolloutGroupStatus#SCHEDULED} state until the rollout is
|
||||
* {@link RolloutManagement#resumeRollout(Rollout)}.
|
||||
*
|
||||
*
|
||||
* Switching the rollout status to {@link RolloutStatus#PAUSED} is
|
||||
* sufficient due the {@link #checkRunningRollouts(long)} will not check
|
||||
* this rollout anymore.
|
||||
*
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout to be paused.
|
||||
*
|
||||
*
|
||||
* @throws RolloutIllegalStateException
|
||||
* if given rollout is not in {@link RolloutStatus#RUNNING}.
|
||||
* Only running rollouts can be paused.
|
||||
@@ -496,7 +503,7 @@ public class RolloutManagement {
|
||||
* Resumes a paused rollout. The rollout switches back to
|
||||
* {@link RolloutStatus#RUNNING} state which is then picked up again by the
|
||||
* {@link #checkRunningRollouts(long)}.
|
||||
*
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout to be resumed
|
||||
* @throws RolloutIllegalStateException
|
||||
@@ -521,7 +528,7 @@ public class RolloutManagement {
|
||||
* Checking running rollouts. Rollouts which are checked updating the
|
||||
* {@link Rollout#setLastCheck(long)} to indicate that the current instance
|
||||
* is handling the specific rollout. This code should run as system-code.
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* SystemSecurityContext.runAsSystem(new Callable<Void>() {
|
||||
@@ -531,21 +538,21 @@ public class RolloutManagement {
|
||||
* });
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* This method is attend to be called by a scheduler.
|
||||
* {@link RolloutScheduler}. And must be running in an transaction so it's
|
||||
* splitted from the scheduler.
|
||||
*
|
||||
*
|
||||
* Rollouts which are currently running are investigated, by means the
|
||||
* error- and finish condition of running groups in this rollout are
|
||||
* evaluated.
|
||||
*
|
||||
*
|
||||
* @param delayBetweenChecks
|
||||
* the time in milliseconds of the delay between the further and
|
||||
* this check. This check is only applied if the last check is
|
||||
* less than (lastcheck-delay).
|
||||
*/
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_UNCOMMITTED)
|
||||
@Modifying
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_SYSTEM_CODE)
|
||||
@@ -728,7 +735,7 @@ public class RolloutManagement {
|
||||
|
||||
/**
|
||||
* Count rollouts by specified filter text.
|
||||
*
|
||||
*
|
||||
* @param searchText
|
||||
* name or description
|
||||
* @return total count rollouts for specified filter text.
|
||||
@@ -750,7 +757,7 @@ public class RolloutManagement {
|
||||
|
||||
/**
|
||||
* * Retrieves a specific rollout by its ID.
|
||||
*
|
||||
*
|
||||
* @param pageable
|
||||
* the page request to sort and limit the result
|
||||
* @param searchText
|
||||
@@ -768,7 +775,7 @@ public class RolloutManagement {
|
||||
|
||||
/**
|
||||
* Retrieves a specific rollout by its name.
|
||||
*
|
||||
*
|
||||
* @param rolloutName
|
||||
* the name of the rollout to retrieve
|
||||
* @return the founded rollout or {@code null} if rollout with given name
|
||||
@@ -781,10 +788,10 @@ public class RolloutManagement {
|
||||
|
||||
/**
|
||||
* Update rollout details.
|
||||
*
|
||||
*
|
||||
* @param rollout
|
||||
* rollout to be updated
|
||||
*
|
||||
*
|
||||
* @return Rollout updated rollout
|
||||
*/
|
||||
@NotNull
|
||||
@@ -798,7 +805,7 @@ public class RolloutManagement {
|
||||
|
||||
/**
|
||||
* Get count of targets in different status in rollout.
|
||||
*
|
||||
*
|
||||
* @param page
|
||||
* the page request to sort and limit the result
|
||||
* @return a list of rollouts with details of targets count for different
|
||||
@@ -860,7 +867,7 @@ public class RolloutManagement {
|
||||
/***
|
||||
* Get finished percentage details for a specified group which is in running
|
||||
* state.
|
||||
*
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the {@link Rollout}
|
||||
* @param rolloutGroup
|
||||
|
||||
@@ -165,6 +165,7 @@ public class SystemManagement {
|
||||
* @return the {@link CurrentTenantKeyGenerator}
|
||||
*/
|
||||
@Bean
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public CurrentTenantKeyGenerator currentTenantKeyGenerator() {
|
||||
return new CurrentTenantKeyGenerator();
|
||||
}
|
||||
@@ -207,7 +208,6 @@ public class SystemManagement {
|
||||
@NotNull
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_SYSTEM_CODE)
|
||||
// tenant independent
|
||||
public List<String> findTenants() {
|
||||
return tenantMetaDataRepository.findAll().stream().map(md -> md.getTenant()).collect(Collectors.toList());
|
||||
}
|
||||
@@ -222,7 +222,6 @@ public class SystemManagement {
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
@Modifying
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
||||
// tenant independent
|
||||
public void deleteTenant(@NotNull final String tenant) {
|
||||
cacheManager.evictCaches(tenant);
|
||||
cacheManager.getCache("currentTenant").evict(currentTenantKeyGenerator().generate(null, null));
|
||||
|
||||
@@ -24,13 +24,18 @@ import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.eclipse.persistence.annotations.ExistenceChecking;
|
||||
import org.eclipse.persistence.annotations.ExistenceType;
|
||||
|
||||
/**
|
||||
* @author Michael Hirsch
|
||||
*
|
||||
* Entity with JPA annotation to store the information which {@link Target} is
|
||||
* in a specific {@link RolloutGroup}.
|
||||
*
|
||||
*/
|
||||
@IdClass(RolloutTargetGroupId.class)
|
||||
@Entity
|
||||
@Table(name = "sp_rollouttargetgroup")
|
||||
@ExistenceChecking(ExistenceType.ASSUME_NON_EXISTENCE)
|
||||
public class RolloutTargetGroup implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -78,6 +78,22 @@ public class MultiTenancyEntityTest extends AbstractIntegrationTest {
|
||||
assertThat(findTargetsForTenant).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description(value = "Ensures that tenant with proper permissions can read and delete other tenants.")
|
||||
@WithUser(tenantId = "mytenant", allSpPermissions = true)
|
||||
public void deleteAnotherTenantPossible() throws Exception {
|
||||
// create target for another tenant
|
||||
final String anotherTenant = "anotherTenant";
|
||||
final String controllerAnotherTenant = "anotherController";
|
||||
createTargetForTenant(controllerAnotherTenant, anotherTenant);
|
||||
|
||||
assertThat(systemManagement.findTenants()).as("Expected number if tenants before deletion is").hasSize(3);
|
||||
|
||||
systemManagement.deleteTenant(anotherTenant);
|
||||
|
||||
assertThat(systemManagement.findTenants()).as("Expected number if tenants after deletion is").hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description(value = "Ensures that tenant metadata is retrieved for the current tenant.")
|
||||
@WithUser(tenantId = "mytenant", autoCreateTenant = false, allSpPermissions = true)
|
||||
|
||||
Reference in New Issue
Block a user