ArtifactRepository tenant aware. (#539)

* ArtifactRepository tenant aware.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* No need to have this protected. Updated event to boot > 1.3

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Remove conditional.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Remove Debug log.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Cleanup

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Missing validation and readability.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix test after change.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix computation is DosFilter

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix session state on RESTful APIs.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Performance improvement controllermanagement

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Added cross tenant test.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Typos.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
Kai Zimmermann
2017-06-14 19:07:52 +02:00
committed by GitHub
parent 787042ce85
commit 8d17d21259
27 changed files with 340 additions and 160 deletions

View File

@@ -23,11 +23,11 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -118,13 +118,15 @@ public interface ControllerManagement {
/**
* Retrieves oldest {@link Action} that is active and assigned to a
* {@link Target}.
*
* For performance reasons this method does not throw
* {@link EntityNotFoundException} in case target with given controlelrId
* does not exist but will return an {@link Optional#empty()} instead.
*
* @param controllerId
* identifies the target to retrieve the actions from
* @return a list of actions assigned to given target which are active
*
* @throws EntityNotFoundException
* if target with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
Optional<Action> findOldestActiveActionByTarget(@NotNull String controllerId);

View File

@@ -116,6 +116,17 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
Optional<Action> findFirstByTargetControllerIdAndActive(final Sort sort, final String controllerId, boolean active);
/**
* Checks if an active action exists for given
* {@link Target#getControllerId()}.
*
* @param controllerId
* of target to check
* @return <code>true</code> if an active action for the target exists.
*/
@Query("SELECT CASE WHEN COUNT(a)>0 THEN 'true' ELSE 'false' END FROM JpaAction a JOIN a.target t WHERE t.controllerId=:controllerId AND a.active=1")
boolean activeActionExistsForControllerId(@Param("controllerId") String controllerId);
/**
* Retrieves latest {@link Action} for given target and
* {@link SoftwareModule}.

View File

@@ -28,9 +28,9 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -49,14 +49,22 @@ public class JpaArtifactManagement implements ArtifactManagement {
private static final Logger LOG = LoggerFactory.getLogger(JpaArtifactManagement.class);
@Autowired
private LocalArtifactRepository localArtifactRepository;
private final LocalArtifactRepository localArtifactRepository;
@Autowired
private SoftwareModuleRepository softwareModuleRepository;
private final SoftwareModuleRepository softwareModuleRepository;
@Autowired
private ArtifactRepository artifactRepository;
private final ArtifactRepository artifactRepository;
private final TenantAware tenantAware;
JpaArtifactManagement(final LocalArtifactRepository localArtifactRepository,
final SoftwareModuleRepository softwareModuleRepository, final ArtifactRepository artifactRepository,
final TenantAware tenantAware) {
this.localArtifactRepository = localArtifactRepository;
this.softwareModuleRepository = softwareModuleRepository;
this.artifactRepository = artifactRepository;
this.tenantAware = tenantAware;
}
private static Artifact checkForExistingArtifact(final String filename, final boolean overrideExisting,
final SoftwareModule softwareModule) {
@@ -87,7 +95,7 @@ public class JpaArtifactManagement implements ArtifactManagement {
final Artifact existing = checkForExistingArtifact(filename, overrideExisting, softwareModule);
try {
result = artifactRepository.store(stream, filename, contentType,
result = artifactRepository.store(tenantAware.getCurrentTenant(), stream, filename, contentType,
new DbArtifactHash(providedSha1Sum, providedMd5Sum));
} catch (final ArtifactStoreException e) {
throw new ArtifactUploadFailedException(e);
@@ -118,7 +126,7 @@ public class JpaArtifactManagement implements ArtifactManagement {
try {
LOG.debug("deleting artifact from repository {}", sha1Hash);
artifactRepository.deleteBySha1(sha1Hash);
artifactRepository.deleteBySha1(tenantAware.getCurrentTenant(), sha1Hash);
return true;
} catch (final ArtifactStoreException e) {
throw new ArtifactDeleteFailedException(e);
@@ -177,7 +185,7 @@ public class JpaArtifactManagement implements ArtifactManagement {
@Override
public Optional<DbArtifact> loadArtifactBinary(final String sha1Hash) {
return Optional.ofNullable(artifactRepository.getArtifactBySha1(sha1Hash));
return Optional.ofNullable(artifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), sha1Hash));
}
private Artifact storeArtifactMetadata(final SoftwareModule softwareModule, final String providedFilename,

View File

@@ -188,7 +188,9 @@ public class JpaControllerManagement implements ControllerManagement {
@Override
public Optional<Action> findOldestActiveActionByTarget(final String controllerId) {
throwExceptionIfTargetDoesNotExist(controllerId);
if (!actionRepository.activeActionExistsForControllerId(controllerId)) {
return Optional.empty();
}
// used in favorite to findFirstByTargetAndActiveOrderByIdAsc due to
// DATAJPA-841 issue.

View File

@@ -73,7 +73,6 @@ import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* JPA implementation of {@link SoftwareModuleManagement}.
@@ -591,7 +590,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
@Retryable(include = {
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public void deleteSoftwareModule(final Long moduleId) {
deleteSoftwareModules(Sets.newHashSet(moduleId));
deleteSoftwareModules(Arrays.asList(moduleId));
}
@Override

View File

@@ -16,6 +16,7 @@ import java.util.stream.Collectors;
import javax.persistence.EntityManager;
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
import org.eclipse.hawkbit.cache.TenancyCacheManager;
import org.eclipse.hawkbit.repository.RolloutStatusCache;
import org.eclipse.hawkbit.repository.SystemManagement;
@@ -116,6 +117,9 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
@Autowired
private RolloutStatusCache rolloutStatusCache;
@Autowired
private ArtifactRepository artifactRepository;
@Override
public SystemUsageReport getSystemUsageStatistics() {
@@ -236,6 +240,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
distributionSetRepository.deleteByTenant(tenant);
distributionSetTypeRepository.deleteByTenant(tenant);
softwareModuleRepository.deleteByTenant(tenant);
artifactRepository.deleteByTenant(tenant);
softwareModuleTypeRepository.deleteByTenant(tenant);
return null;
});

View File

@@ -13,6 +13,7 @@ import java.util.Map;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.DeploymentManagement;
@@ -502,16 +503,13 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
return new JpaControllerManagement();
}
/**
* {@link JpaArtifactManagement} bean.
*
* @return a new {@link ArtifactManagement}
*/
@Bean
@ConditionalOnMissingBean
ArtifactManagement artifactManagement() {
return new JpaArtifactManagement();
ArtifactManagement artifactManagement(final LocalArtifactRepository localArtifactRepository,
final SoftwareModuleRepository softwareModuleRepository, final ArtifactRepository artifactRepository,
final TenantAware tenantAware) {
return new JpaArtifactManagement(localArtifactRepository, softwareModuleRepository, artifactRepository,
tenantAware);
}
/**

View File

@@ -175,16 +175,21 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
assertThat(result2.getId()).isNotNull();
assertThat(((JpaArtifact) result).getSha1Hash()).isNotEqualTo(((JpaArtifact) result2).getSha1Hash());
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNotNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getSha1Hash())).isNotNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNotNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result2.getSha1Hash()))
.isNotNull();
artifactManagement.deleteArtifact(result.getId());
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getSha1Hash())).isNotNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result2.getSha1Hash()))
.isNotNull();
artifactManagement.deleteArtifact(result2.getId());
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getSha1Hash())).isNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result2.getSha1Hash()))
.isNull();
assertThat(artifactRepository.findAll()).hasSize(0);
}
@@ -211,12 +216,15 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
assertThat(result2.getId()).isNotNull();
assertThat(((JpaArtifact) result).getSha1Hash()).isEqualTo(((JpaArtifact) result2).getSha1Hash());
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNotNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNotNull();
artifactManagement.deleteArtifact(result.getId());
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNotNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNotNull();
artifactManagement.deleteArtifact(result2.getId());
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNull();
}
@Test

View File

@@ -78,6 +78,8 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(controllerManagement.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(),
module.getId())).isNotPresent();
assertThat(controllerManagement.findOldestActiveActionByTarget(NOT_EXIST_ID)).isNotPresent();
assertThat(controllerManagement.hasTargetArtifactAssigned(target.getControllerId(), "XXX")).isFalse();
assertThat(controllerManagement.hasTargetArtifactAssigned(target.getId(), "XXX")).isFalse();
}
@@ -100,8 +102,6 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
verifyThrownExceptionBy(() -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(NOT_EXIST_IDL).status(Action.Status.FINISHED)), "Action");
verifyThrownExceptionBy(() -> controllerManagement.findOldestActiveActionByTarget(NOT_EXIST_ID), "Target");
verifyThrownExceptionBy(() -> controllerManagement
.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), NOT_EXIST_IDL),
"SoftwareModule");

View File

@@ -22,7 +22,6 @@ import java.util.List;
import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
@@ -490,13 +489,15 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
assertThat(artifactRepository.findAll()).hasSize(results.length);
for (final Artifact result : results) {
assertThat(result.getId()).isNotNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNotNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNotNull();
}
}
private void assertArtfiactNull(final Artifact... results) {
for (final Artifact result : results) {
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNull();
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
.isNull();
}
}

View File

@@ -10,8 +10,9 @@
# Test utility properties for easier fault investigation - START
## Logging - START
logging.level.=INFO
logging.level.org.eclipse.persistence=ERROR
logging.level.org.eclipse.hawkbit.repository.test.matcher.EventVerifier=ERROR
logging.level.org.eclipse.persistence=ERROR
spring.datasource.eclipselink.logging.logger=JavaLogger
spring.jpa.properties.eclipselink.logging.level=FINE
spring.jpa.properties.eclipselink.logging.level.sql=FINE
spring.jpa.properties.eclipselink.logging.parameters=true