@@ -1,66 +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;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.hawkbit.repository.artifact.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.repository.artifact.model.DbArtifactHash;
|
||||
|
||||
/**
|
||||
* {@link DbArtifact} implementation that decrypts the underlying artifact
|
||||
* binary input stream.
|
||||
*/
|
||||
public class EncryptionAwareDbArtifact implements DbArtifact {
|
||||
|
||||
private final DbArtifact encryptedDbArtifact;
|
||||
private final UnaryOperator<InputStream> decryptionFunction;
|
||||
private final int encryptionOverhead;
|
||||
|
||||
public EncryptionAwareDbArtifact(final DbArtifact encryptedDbArtifact,
|
||||
final UnaryOperator<InputStream> decryptionFunction) {
|
||||
this.encryptedDbArtifact = encryptedDbArtifact;
|
||||
this.decryptionFunction = decryptionFunction;
|
||||
this.encryptionOverhead = 0;
|
||||
}
|
||||
|
||||
public EncryptionAwareDbArtifact(final DbArtifact encryptedDbArtifact,
|
||||
final UnaryOperator<InputStream> decryptionFunction, final int encryptionOverhead) {
|
||||
this.encryptedDbArtifact = encryptedDbArtifact;
|
||||
this.decryptionFunction = decryptionFunction;
|
||||
this.encryptionOverhead = encryptionOverhead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArtifactId() {
|
||||
return encryptedDbArtifact.getArtifactId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbArtifactHash getHashes() {
|
||||
return encryptedDbArtifact.getHashes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return encryptedDbArtifact.getSize() - encryptionOverhead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return encryptedDbArtifact.getContentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getFileInputStream() {
|
||||
return decryptionFunction.apply(encryptedDbArtifact.getFileInputStream());
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,9 @@ import jakarta.validation.Validation;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.artifact.encryption.ArtifactEncryption;
|
||||
import org.eclipse.hawkbit.artifact.encryption.ArtifactEncryptionSecretsStorage;
|
||||
import org.eclipse.hawkbit.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.PropertiesQuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
@@ -31,13 +34,11 @@ import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutHandler;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||
import org.eclipse.hawkbit.repository.SecurityTokenGeneratorHolder;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryption;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionSecretsStore;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
|
||||
import org.eclipse.hawkbit.repository.event.ApplicationEventFilter;
|
||||
import org.eclipse.hawkbit.repository.event.remote.EventEntityManager;
|
||||
@@ -55,7 +56,6 @@ import org.eclipse.hawkbit.repository.jpa.cluster.LockProperties;
|
||||
import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitDefaultServiceExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
@@ -66,7 +66,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder;
|
||||
import org.eclipse.hawkbit.repository.SecurityTokenGeneratorHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
@@ -88,6 +87,7 @@ 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.ThresholdRolloutGroupSuccessCondition;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
@@ -525,7 +525,7 @@ public class JpaRepositoryConfiguration {
|
||||
|
||||
/**
|
||||
* Default artifact encryption service bean that internally uses {@link ArtifactEncryption} and
|
||||
* {@link ArtifactEncryptionSecretsStore} beans for {@link SoftwareModule} artifacts encryption/decryption
|
||||
* {@link ArtifactEncryptionSecretsStorage} beans for {@link SoftwareModule} artifacts encryption/decryption
|
||||
*
|
||||
* @return a {@link ArtifactEncryptionService} bean
|
||||
*/
|
||||
|
||||
@@ -16,23 +16,22 @@ import java.util.Optional;
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.artifact.ArtifactStorage;
|
||||
import org.eclipse.hawkbit.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.artifact.exception.ArtifactBinaryNotFoundException;
|
||||
import org.eclipse.hawkbit.artifact.exception.ArtifactDeleteFailedException;
|
||||
import org.eclipse.hawkbit.artifact.exception.ArtifactStoreException;
|
||||
import org.eclipse.hawkbit.artifact.exception.ArtifactUploadFailedException;
|
||||
import org.eclipse.hawkbit.artifact.exception.HashNotMatchException;
|
||||
import org.eclipse.hawkbit.artifact.model.ArtifactHashes;
|
||||
import org.eclipse.hawkbit.artifact.model.ArtifactStream;
|
||||
import org.eclipse.hawkbit.artifact.model.StoredArtifactInfo;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.artifact.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.artifact.exception.ArtifactBinaryNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.artifact.exception.ArtifactDeleteFailedException;
|
||||
import org.eclipse.hawkbit.repository.artifact.exception.ArtifactStoreException;
|
||||
import org.eclipse.hawkbit.repository.artifact.exception.ArtifactUploadFailedException;
|
||||
import org.eclipse.hawkbit.repository.artifact.exception.HashNotMatchException;
|
||||
import org.eclipse.hawkbit.repository.artifact.model.AbstractDbArtifact;
|
||||
import org.eclipse.hawkbit.repository.artifact.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.repository.artifact.model.DbArtifactHash;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA256HashException;
|
||||
import org.eclipse.hawkbit.repository.jpa.EncryptionAwareDbArtifact;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidMd5HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSha1HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSha256HashException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
@@ -69,7 +68,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
public class JpaArtifactManagement implements ArtifactManagement {
|
||||
|
||||
private final LocalArtifactRepository localArtifactRepository;
|
||||
private final ArtifactRepository artifactRepository;
|
||||
private final ArtifactStorage artifactRepository;
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
private final EntityManager entityManager;
|
||||
private final PlatformTransactionManager txManager;
|
||||
@@ -78,7 +77,7 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
|
||||
protected JpaArtifactManagement(
|
||||
final LocalArtifactRepository localArtifactRepository,
|
||||
final Optional<ArtifactRepository> artifactRepository,
|
||||
final Optional<ArtifactStorage> artifactRepository,
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final EntityManager entityManager,
|
||||
final PlatformTransactionManager txManager,
|
||||
@@ -102,42 +101,40 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
final long moduleId = artifactUpload.getModuleId();
|
||||
final long moduleId = artifactUpload.moduleId();
|
||||
QuotaHelper.assertAssignmentQuota(
|
||||
moduleId, 1, quotaManagement.getMaxArtifactsPerSoftwareModule(),
|
||||
Artifact.class, SoftwareModule.class,
|
||||
// get all artifacts without user context
|
||||
softwareModuleId -> localArtifactRepository
|
||||
.count(null, ArtifactSpecifications.bySoftwareModuleId(softwareModuleId)));
|
||||
softwareModuleId -> localArtifactRepository.count(null, ArtifactSpecifications.bySoftwareModuleId(softwareModuleId)));
|
||||
|
||||
final JpaSoftwareModule softwareModule = softwareModuleRepository.getById(moduleId);
|
||||
|
||||
final String filename = artifactUpload.getFilename();
|
||||
final String filename = artifactUpload.filename();
|
||||
final Artifact existing = softwareModule.getArtifactByFilename(filename).orElse(null);
|
||||
if (existing != null) {
|
||||
if (artifactUpload.isOverrideExisting()) {
|
||||
if (artifactUpload.overrideExisting()) {
|
||||
log.debug("overriding existing artifact with new filename {}", filename);
|
||||
} else {
|
||||
throw new EntityAlreadyExistsException("File with that name already exists in the Software Module");
|
||||
}
|
||||
}
|
||||
|
||||
// touch it to update the lock revision because we are modifying the
|
||||
// DS indirectly, it will, also check UPDATE access
|
||||
// touch it to update the lock revision because we are modifying the DS indirectly, it will, also check UPDATE access
|
||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository, softwareModule);
|
||||
|
||||
final AbstractDbArtifact artifact = storeArtifact(artifactUpload, softwareModule.isEncrypted());
|
||||
final StoredArtifactInfo artifact = storeArtifact(artifactUpload, softwareModule.isEncrypted());
|
||||
try {
|
||||
return storeArtifactMetadata(softwareModule, filename, artifact, existing);
|
||||
return storeArtifactMetadata(softwareModule, filename, artifact.getHashes(), artifact.getSize(), existing);
|
||||
} catch (final Exception e) {
|
||||
artifactRepository.deleteBySha1(tenantAware.getCurrentTenant(), artifact.getHashes().getSha1());
|
||||
artifactRepository.deleteBySha1(tenantAware.getCurrentTenant(), artifact.getHashes().sha1());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("java:S2201") // java:S2201 - the idea is to just check if the artifact exists
|
||||
@Override
|
||||
public DbArtifact loadArtifactBinary(final String sha1Hash, final long softwareModuleId, final boolean isEncrypted) {
|
||||
public ArtifactStream getArtifactStream(final String sha1Hash, final long softwareModuleId, final boolean isEncrypted) {
|
||||
if (artifactRepository == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@@ -146,8 +143,15 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
// check access to the software module and if artifact belongs to it
|
||||
for (final Artifact artifact : softwareModuleRepository.getById(softwareModuleId).getArtifacts()) {
|
||||
if (artifact.getSha1Hash().equals(sha1Hash)) {
|
||||
final DbArtifact dbArtifact = artifactRepository.getBySha1(tenant, sha1Hash);
|
||||
return isEncrypted ? wrapInEncryptionAwareDbArtifact(softwareModuleId, dbArtifact) : dbArtifact;
|
||||
if (isEncrypted) {
|
||||
final ArtifactEncryptionService encryptionService = ArtifactEncryptionService.getInstance();
|
||||
return new ArtifactStream(
|
||||
encryptionService.decryptArtifact(softwareModuleId, artifactRepository.getBySha1(tenant, sha1Hash)),
|
||||
artifact.getSize() - encryptionService.encryptionSizeOverhead(),
|
||||
artifact.getSha1Hash());
|
||||
} else {
|
||||
return new ArtifactStream(artifactRepository.getBySha1(tenant, sha1Hash), artifact.getSize(), artifact.getSha1Hash());
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new ArtifactBinaryNotFoundException(sha1Hash);
|
||||
@@ -208,27 +212,23 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
});
|
||||
}
|
||||
|
||||
private AbstractDbArtifact storeArtifact(final ArtifactUpload artifactUpload, final boolean isSmEncrypted) {
|
||||
final InputStream stream = artifactUpload.getInputStream();
|
||||
private StoredArtifactInfo storeArtifact(final ArtifactUpload artifactUpload, final boolean isSmEncrypted) {
|
||||
final InputStream stream = artifactUpload.inputStream();
|
||||
try (final InputStream wrappedStream = wrapInQuotaStream(
|
||||
isSmEncrypted
|
||||
? wrapInEncryptionStream(artifactUpload.getModuleId(), stream)
|
||||
: stream)) {
|
||||
isSmEncrypted ? wrapInEncryptionStream(artifactUpload.moduleId(), stream) : stream)) {
|
||||
return artifactRepository.store(
|
||||
tenantAware.getCurrentTenant(), wrappedStream, artifactUpload.getFilename(), artifactUpload.getContentType(),
|
||||
new DbArtifactHash(
|
||||
artifactUpload.getProvidedSha1Sum(),
|
||||
artifactUpload.getProvidedMd5Sum(),
|
||||
artifactUpload.getProvidedSha256Sum()));
|
||||
tenantAware.getCurrentTenant(),
|
||||
wrappedStream, artifactUpload.filename(),
|
||||
artifactUpload.contentType(), artifactUpload.hash());
|
||||
} catch (final ArtifactStoreException | IOException e) {
|
||||
throw new ArtifactUploadFailedException(e);
|
||||
} catch (final HashNotMatchException e) {
|
||||
if (e.getHashFunction().equals(HashNotMatchException.SHA1)) {
|
||||
throw new InvalidSHA1HashException(e.getMessage(), e);
|
||||
throw new InvalidSha1HashException(e.getMessage(), e);
|
||||
} else if (e.getHashFunction().equals(HashNotMatchException.SHA256)) {
|
||||
throw new InvalidSHA256HashException(e.getMessage(), e);
|
||||
throw new InvalidSha256HashException(e.getMessage(), e);
|
||||
} else {
|
||||
throw new InvalidMD5HashException(e.getMessage(), e);
|
||||
throw new InvalidMd5HashException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,33 +243,23 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
final long currentlyUsed = localArtifactRepository.sumOfNonDeletedArtifactSize().orElse(0L);
|
||||
final long maxArtifactSizeTotal = quotaManagement.getMaxArtifactStorage();
|
||||
|
||||
return new FileSizeAndStorageQuotaCheckingInputStream(in, maxArtifactSize,
|
||||
maxArtifactSizeTotal - currentlyUsed);
|
||||
}
|
||||
|
||||
private DbArtifact wrapInEncryptionAwareDbArtifact(final long softwareModuleId, final DbArtifact dbArtifact) {
|
||||
if (dbArtifact == null) {
|
||||
return null;
|
||||
}
|
||||
final ArtifactEncryptionService encryptionService = ArtifactEncryptionService.getInstance();
|
||||
return new EncryptionAwareDbArtifact(dbArtifact,
|
||||
stream -> encryptionService.decryptArtifact(softwareModuleId, stream),
|
||||
encryptionService.encryptionSizeOverhead());
|
||||
return new FileSizeAndStorageQuotaCheckingInputStream(in, maxArtifactSize, maxArtifactSizeTotal - currentlyUsed);
|
||||
}
|
||||
|
||||
private Artifact storeArtifactMetadata(
|
||||
final SoftwareModule softwareModule, final String providedFilename, final AbstractDbArtifact result,
|
||||
final SoftwareModule softwareModule, final String providedFilename,
|
||||
final ArtifactHashes hash, final long fileSize,
|
||||
final Artifact existing) {
|
||||
final JpaArtifact artifact;
|
||||
if (existing == null) {
|
||||
artifact = new JpaArtifact(result.getHashes().getSha1(), providedFilename, softwareModule);
|
||||
artifact = new JpaArtifact(hash.sha1(), providedFilename, softwareModule);
|
||||
} else {
|
||||
artifact = (JpaArtifact) existing;
|
||||
artifact.setSha1Hash(result.getHashes().getSha1());
|
||||
artifact.setSha1Hash(hash.sha1());
|
||||
}
|
||||
artifact.setMd5Hash(result.getHashes().getMd5());
|
||||
artifact.setSha256Hash(result.getHashes().getSha256());
|
||||
artifact.setFileSize(result.getSize());
|
||||
artifact.setMd5Hash(hash.md5());
|
||||
artifact.setSha256Hash(hash.sha256());
|
||||
artifact.setFileSize(fileSize);
|
||||
|
||||
log.debug("storing new artifact into repository {}", artifact);
|
||||
return localArtifactRepository.save(AccessController.Operation.CREATE, artifact);
|
||||
|
||||
@@ -146,7 +146,7 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<AutoConfirmationStatus> getStatus(final String controllerId) {
|
||||
public Optional<AutoConfirmationStatus> findStatus(final String controllerId) {
|
||||
return Optional.of(targetRepository.getWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_AUTO_CONFIRMATION_STATUS))
|
||||
.map(JpaTarget::getAutoConfirmationStatus);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.SecurityTokenGeneratorHolder;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.UpdateMode;
|
||||
import org.eclipse.hawkbit.repository.event.EventPublisherHolder;
|
||||
@@ -66,6 +65,7 @@ import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
|
||||
import org.eclipse.hawkbit.repository.exception.SoftwareModuleNotAssignedToTargetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.Jpa;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
@@ -83,8 +83,10 @@ import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
@@ -138,7 +140,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
|
||||
// TODO - make it final
|
||||
private TargetRepository targetRepository;
|
||||
private final TargetTypeManagement<? extends TargetType> targetTypeManagement;
|
||||
private final TargetTypeRepository targetTypeRepository;
|
||||
private final DeploymentManagement deploymentManagement;
|
||||
private final ConfirmationManagement confirmationManagement;
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
@@ -158,7 +160,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
protected JpaControllerManagement(
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository, final QuotaManagement quotaManagement,
|
||||
final RepositoryProperties repositoryProperties,
|
||||
final TargetRepository targetRepository, final TargetTypeManagement<? extends TargetType> targetTypeManagement,
|
||||
final TargetRepository targetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final DeploymentManagement deploymentManagement, final ConfirmationManagement confirmationManagement,
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement,
|
||||
@@ -171,7 +173,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties);
|
||||
|
||||
this.targetRepository = targetRepository;
|
||||
this.targetTypeManagement = targetTypeManagement;
|
||||
this.targetTypeRepository = targetTypeRepository;
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.confirmationManagement = confirmationManagement;
|
||||
this.softwareModuleRepository = softwareModuleRepository;
|
||||
@@ -270,8 +272,9 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SoftwareModule> getSoftwareModule(final long id) {
|
||||
return softwareModuleRepository.findById(id).map(SoftwareModule.class::cast);
|
||||
public SoftwareModule getSoftwareModule(final long id) {
|
||||
return softwareModuleRepository.findById(id).map(SoftwareModule.class::cast)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -360,7 +363,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Action> getActionForDownloadByTargetAndSoftwareModule(final String controllerId, final long moduleId) {
|
||||
public Action getActionForDownloadByTargetAndSoftwareModule(final String controllerId, final long moduleId) {
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(moduleId);
|
||||
|
||||
@@ -376,7 +379,8 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
.stream()
|
||||
.anyMatch(module -> module.getId() == moduleId))
|
||||
.map(Action.class::cast)
|
||||
.findFirst();
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new SoftwareModuleNotAssignedToTargetException(moduleId, controllerId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -542,11 +546,6 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
actionRepository.updateExternalRef(actionId, externalRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Action> getActionByExternalRef(@NotEmpty final String externalRef) {
|
||||
return actionRepository.findByExternalRef(externalRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteExistingTarget(@NotEmpty final String controllerId) {
|
||||
final JpaTarget target = targetRepository.getByControllerId(controllerId);
|
||||
@@ -555,7 +554,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Action> getInstalledActionByTarget(final Target target) {
|
||||
public Optional<Action> findInstalledActionByTarget(final Target target) {
|
||||
final JpaTarget jpaTarget = (JpaTarget) target;
|
||||
return Optional.ofNullable(jpaTarget.getInstalledDistributionSet())
|
||||
.flatMap(installedDistributionSet -> actionRepository.findFirstByTargetIdAndDistributionSetIdAndStatusOrderByIdDesc(
|
||||
@@ -575,12 +574,9 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
@Override
|
||||
public boolean updateOfflineAssignedVersion(@NotEmpty final String controllerId, final String distributionName, final String version) {
|
||||
List<DistributionSetAssignmentResult> distributionSetAssignmentResults =
|
||||
systemSecurityContext.runAsSystem(() ->
|
||||
distributionSetManagement.findByNameAndVersion(distributionName, version)
|
||||
.map(distributionSet -> deploymentManagement.offlineAssignedDistributionSets(
|
||||
controllerId, List.of(Map.entry(controllerId, distributionSet.getId()))))
|
||||
.orElseThrow(() ->
|
||||
new EntityNotFoundException(DistributionSet.class, Map.entry(distributionName, version))));
|
||||
systemSecurityContext.runAsSystem(() -> deploymentManagement.offlineAssignedDistributionSets(
|
||||
controllerId,
|
||||
List.of(Map.entry(controllerId, distributionSetManagement.findByNameAndVersion(distributionName, version).getId()))));
|
||||
|
||||
return distributionSetAssignmentResults.stream()
|
||||
.findFirst()
|
||||
@@ -588,8 +584,8 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
Optional<TargetType> getTargetType(String targetTypeName) {
|
||||
return systemSecurityContext.runAsSystem(() -> targetTypeManagement.getByName(targetTypeName));
|
||||
private Optional<TargetType> findTargetType(String targetTypeName) {
|
||||
return targetTypeRepository.findOne(TargetTypeSpecification.hasName(targetTypeName)).map(TargetType.class::cast);
|
||||
}
|
||||
|
||||
// for testing
|
||||
@@ -668,7 +664,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
jpaTarget.setAddress(Optional.ofNullable(address).map(URI::toString).orElse(null));
|
||||
|
||||
if (StringUtils.hasText(type)) {
|
||||
var targetTypeOptional = getTargetType(type);
|
||||
final Optional<TargetType> targetTypeOptional = findTargetType(type);
|
||||
if (targetTypeOptional.isPresent()) {
|
||||
log.debug("Setting target type for thing ID \"{}\" to \"{}\".", controllerId, type);
|
||||
jpaTarget.setTargetType(targetTypeOptional.get());
|
||||
@@ -772,7 +768,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
|
||||
if (isTypeChanged(toUpdate.getTargetType(), type)) {
|
||||
if (StringUtils.hasText(type)) {
|
||||
final Optional<TargetType> targetTypeOptional = getTargetType(type);
|
||||
final Optional<TargetType> targetTypeOptional = findTargetType(type);
|
||||
if (targetTypeOptional.isPresent()) {
|
||||
log.debug("Updating target type for thing ID \"{}\" to \"{}\".", toUpdate.getControllerId(), type);
|
||||
toUpdate.setTargetType(targetTypeOptional.get());
|
||||
|
||||
@@ -464,13 +464,13 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> getAssignedDistributionSet(final String controllerId) {
|
||||
public Optional<DistributionSet> findAssignedDistributionSet(final String controllerId) {
|
||||
return targetRepository.findWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_ASSIGNED_DISTRIBUTION_SET)
|
||||
.map(JpaTarget::getAssignedDistributionSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> getInstalledDistributionSet(final String controllerId) {
|
||||
public Optional<DistributionSet> findInstalledDistributionSet(final String controllerId) {
|
||||
return targetRepository.findWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_INSTALLED_DISTRIBUTION_SET)
|
||||
.map(JpaTarget::getInstalledDistributionSet);
|
||||
}
|
||||
|
||||
@@ -154,8 +154,9 @@ public class JpaDistributionSetManagement
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<JpaDistributionSet> getWithDetails(final long id) {
|
||||
return jpaRepository.findOne(jpaRepository.byIdSpec(id), JpaDistributionSet_.GRAPH_DISTRIBUTION_SET_DETAIL);
|
||||
public JpaDistributionSet getWithDetails(final long id) {
|
||||
return jpaRepository.findOne(jpaRepository.byIdSpec(id), JpaDistributionSet_.GRAPH_DISTRIBUTION_SET_DETAIL)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, id));
|
||||
}
|
||||
|
||||
// implicitly lock a distribution set if not already locked and implicit lock is enabled and not to skip
|
||||
@@ -290,8 +291,9 @@ public class JpaDistributionSetManagement
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<JpaDistributionSet> findByNameAndVersion(final String distributionName, final String version) {
|
||||
return jpaRepository.findOne(DistributionSetSpecification.equalsNameAndVersionIgnoreCase(distributionName, version));
|
||||
public JpaDistributionSet findByNameAndVersion(final String distributionName, final String version) {
|
||||
return jpaRepository.findOne(DistributionSetSpecification.equalsNameAndVersionIgnoreCase(distributionName, version))
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, Map.entry(distributionName, version)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -94,11 +94,6 @@ public class JpaDistributionSetTypeManagement
|
||||
return jpaRepository.findOne(DistributionSetTypeSpecification.byKey(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<JpaDistributionSetType> findByName(final String name) {
|
||||
return jpaRepository.findOne(DistributionSetTypeSpecification.byName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = TX_RT_MAX, backoff = @Backoff(delay = TX_RT_DELAY))
|
||||
|
||||
@@ -109,8 +109,26 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<RolloutGroup> get(final long rolloutGroupId) {
|
||||
return rolloutGroupRepository.findById(rolloutGroupId).map(RolloutGroup.class::cast);
|
||||
public RolloutGroup get(final long rolloutGroupId) {
|
||||
return rolloutGroupRepository.findById(rolloutGroupId).map(RolloutGroup.class::cast)
|
||||
.orElseThrow(() -> new EntityNotFoundException(RolloutGroup.class, rolloutGroupId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RolloutGroup getWithDetailedStatus(final long rolloutGroupId) {
|
||||
final JpaRolloutGroup jpaRolloutGroup = (JpaRolloutGroup) rolloutGroupRepository.findById(rolloutGroupId).map(RolloutGroup.class::cast)
|
||||
.orElseThrow(() -> new EntityNotFoundException(RolloutGroup.class, rolloutGroupId));
|
||||
|
||||
List<TotalTargetCountActionStatus> rolloutStatusCountItems = rolloutStatusCache.getRolloutGroupStatus(rolloutGroupId);
|
||||
if (CollectionUtils.isEmpty(rolloutStatusCountItems)) {
|
||||
rolloutStatusCountItems = actionRepository.getStatusCountByRolloutGroupId(rolloutGroupId);
|
||||
rolloutStatusCache.putRolloutGroupStatus(rolloutGroupId, rolloutStatusCountItems);
|
||||
}
|
||||
|
||||
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(
|
||||
rolloutStatusCountItems, (long) jpaRolloutGroup.getTotalTargets(), jpaRolloutGroup.getRollout().getActionType());
|
||||
jpaRolloutGroup.setTotalTargetCountStatus(totalTargetCountStatus);
|
||||
return jpaRolloutGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,30 +203,6 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, specList, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<RolloutGroup> getWithDetailedStatus(final long rolloutGroupId) {
|
||||
final Optional<RolloutGroup> rolloutGroup = get(rolloutGroupId);
|
||||
if (rolloutGroup.isEmpty()) {
|
||||
return rolloutGroup;
|
||||
}
|
||||
|
||||
final JpaRolloutGroup jpaRolloutGroup = (JpaRolloutGroup) rolloutGroup.get();
|
||||
|
||||
List<TotalTargetCountActionStatus> rolloutStatusCountItems = rolloutStatusCache
|
||||
.getRolloutGroupStatus(rolloutGroupId);
|
||||
|
||||
if (CollectionUtils.isEmpty(rolloutStatusCountItems)) {
|
||||
rolloutStatusCountItems = actionRepository.getStatusCountByRolloutGroupId(rolloutGroupId);
|
||||
rolloutStatusCache.putRolloutGroupStatus(rolloutGroupId, rolloutStatusCountItems);
|
||||
}
|
||||
|
||||
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(
|
||||
rolloutStatusCountItems, (long) jpaRolloutGroup.getTotalTargets(), jpaRolloutGroup.getRollout().getActionType());
|
||||
jpaRolloutGroup.setTotalTargetCountStatus(totalTargetCountStatus);
|
||||
return rolloutGroup;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countTargetsOfRolloutsGroup(final long rolloutGroupId) {
|
||||
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);
|
||||
|
||||
@@ -304,22 +304,21 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
return rolloutRepository.findByStatusIn(ACTIVE_ROLLOUTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rollout get(final long rolloutId) {
|
||||
return rolloutRepository.findById(rolloutId).map(Rollout.class::cast)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Rollout> find(final long rolloutId) {
|
||||
return rolloutRepository.findById(rolloutId).map(Rollout.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Rollout> getByName(final String rolloutName) {
|
||||
return rolloutRepository.findByName(rolloutName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Rollout> getWithDetailedStatus(final long rolloutId) {
|
||||
final Optional<Rollout> rollout = find(rolloutId);
|
||||
if (rollout.isEmpty()) {
|
||||
return rollout;
|
||||
}
|
||||
public Rollout getWithDetailedStatus(final long rolloutId) {
|
||||
final Rollout rollout = rolloutRepository.findById(rolloutId).map(Rollout.class::cast)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
||||
|
||||
List<TotalTargetCountActionStatus> rolloutStatusCountItems = rolloutStatusCache.getRolloutStatus(rolloutId);
|
||||
|
||||
@@ -329,8 +328,8 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
}
|
||||
|
||||
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(
|
||||
rolloutStatusCountItems, rollout.get().getTotalTargets(), rollout.get().getActionType());
|
||||
((JpaRollout) rollout.get()).setTotalTargetCountStatus(totalTargetCountStatus);
|
||||
rolloutStatusCountItems, rollout.getTotalTargets(), rollout.getActionType());
|
||||
((JpaRollout) rollout).setTotalTargetCountStatus(totalTargetCountStatus);
|
||||
return rollout;
|
||||
}
|
||||
|
||||
@@ -831,7 +830,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
if (quotaManagement.getMaxTargetsPerRolloutGroup() > 0) {
|
||||
validateTargetsInGroups(
|
||||
srcGroups, rollout.getTargetFilterQuery(), rollout.getCreatedAt(),
|
||||
distributionSetType.getId()).getTargetsPerGroup().forEach(this::assertTargetsPerRolloutGroupQuota);
|
||||
distributionSetType.getId()).targetsPerGroup().forEach(this::assertTargetsPerRolloutGroupQuota);
|
||||
}
|
||||
|
||||
// create and persist the groups (w/o filling them with targets)
|
||||
|
||||
@@ -22,11 +22,11 @@ import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.artifact.encryption.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.LockedException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
@@ -53,19 +53,17 @@ import org.springframework.util.ObjectUtils;
|
||||
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "software-module-management" }, matchIfMissing = true)
|
||||
public class JpaSoftwareModuleManagement
|
||||
extends AbstractJpaRepositoryWithMetadataManagement<JpaSoftwareModule, SoftwareModuleManagement.Create, SoftwareModuleManagement.Update, SoftwareModuleRepository, SoftwareModuleFields, MetadataValue, JpaSoftwareModule.JpaMetadataValue>
|
||||
public class JpaSoftwareModuleManagement extends
|
||||
AbstractJpaRepositoryWithMetadataManagement<JpaSoftwareModule, SoftwareModuleManagement.Create, SoftwareModuleManagement.Update, SoftwareModuleRepository, SoftwareModuleFields, MetadataValue, JpaSoftwareModule.JpaMetadataValue>
|
||||
implements SoftwareModuleManagement<JpaSoftwareModule> {
|
||||
|
||||
private final DistributionSetRepository distributionSetRepository;
|
||||
private final ArtifactManagement artifactManagement;
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
protected JpaSoftwareModuleManagement(
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final EntityManager entityManager,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement) {
|
||||
protected JpaSoftwareModuleManagement(final SoftwareModuleRepository softwareModuleRepository, final EntityManager entityManager,
|
||||
final DistributionSetRepository distributionSetRepository, final ArtifactManagement artifactManagement,
|
||||
final QuotaManagement quotaManagement) {
|
||||
super(softwareModuleRepository, entityManager);
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
this.artifactManagement = artifactManagement;
|
||||
@@ -79,9 +77,7 @@ public class JpaSoftwareModuleManagement
|
||||
if (createdModules.stream().anyMatch(SoftwareModule::isEncrypted)) {
|
||||
// flush sm creation in order to get ids
|
||||
entityManager.flush();
|
||||
createdModules.stream()
|
||||
.filter(SoftwareModule::isEncrypted)
|
||||
.map(SoftwareModule::getId)
|
||||
createdModules.stream().filter(SoftwareModule::isEncrypted).map(SoftwareModule::getId)
|
||||
.forEach(encryptedModuleId -> ArtifactEncryptionService.getInstance().addEncryptionSecrets(encryptedModuleId));
|
||||
}
|
||||
|
||||
@@ -103,48 +99,39 @@ public class JpaSoftwareModuleManagement
|
||||
|
||||
@Override
|
||||
protected List<JpaSoftwareModule> softDelete(final Collection<JpaSoftwareModule> toDelete) {
|
||||
return toDelete.stream()
|
||||
.filter(swModule -> {
|
||||
final List<DistributionSet> assignedTo = swModule.getAssignedTo();
|
||||
if (assignedTo != null) {
|
||||
final List<DistributionSet> lockedDS = assignedTo.stream()
|
||||
.filter(DistributionSet::isLocked)
|
||||
.filter(ds -> !ds.isDeleted())
|
||||
.toList();
|
||||
if (!lockedDS.isEmpty()) {
|
||||
final StringBuilder sb = new StringBuilder("Part of ");
|
||||
if (lockedDS.size() == 1) {
|
||||
sb.append("a locked distribution set: ");
|
||||
} else {
|
||||
sb.append(lockedDS.size()).append(" locked distribution sets: ");
|
||||
}
|
||||
for (final DistributionSet ds : lockedDS) {
|
||||
sb.append(ds.getName()).append(":").append(ds.getVersion()).append(" (").append(ds.getId()).append("), ");
|
||||
}
|
||||
sb.delete(sb.length() - 2, sb.length());
|
||||
throw new LockedException(JpaSoftwareModule.class, swModule.getId(), "DELETE", sb.toString());
|
||||
}
|
||||
return toDelete.stream().filter(swModule -> {
|
||||
final List<DistributionSet> assignedTo = swModule.getAssignedTo();
|
||||
if (assignedTo != null) {
|
||||
final List<DistributionSet> lockedDS = assignedTo.stream().filter(DistributionSet::isLocked).filter(ds -> !ds.isDeleted())
|
||||
.toList();
|
||||
if (!lockedDS.isEmpty()) {
|
||||
final StringBuilder sb = new StringBuilder("Part of ");
|
||||
if (lockedDS.size() == 1) {
|
||||
sb.append("a locked distribution set: ");
|
||||
} else {
|
||||
sb.append(lockedDS.size()).append(" locked distribution sets: ");
|
||||
}
|
||||
final boolean isAssigned = !ObjectUtils.isEmpty(assignedTo);
|
||||
// schedule delete binary data of artifacts for every soft or not soft deleted module
|
||||
deleteGridFsArtifacts(swModule);
|
||||
return isAssigned;
|
||||
})
|
||||
.toList();
|
||||
for (final DistributionSet ds : lockedDS) {
|
||||
sb.append(ds.getName()).append(":").append(ds.getVersion()).append(" (").append(ds.getId()).append("), ");
|
||||
}
|
||||
sb.delete(sb.length() - 2, sb.length());
|
||||
throw new LockedException(JpaSoftwareModule.class, swModule.getId(), "DELETE", sb.toString());
|
||||
}
|
||||
}
|
||||
final boolean isAssigned = !ObjectUtils.isEmpty(assignedTo);
|
||||
// schedule delete binary data of artifacts for every soft or not soft deleted module
|
||||
deleteGridFsArtifacts(swModule);
|
||||
return isAssigned;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// called only with 'system code' access, so no need to check access control
|
||||
@Override
|
||||
public Map<Long, Map<String, String>> findMetaDataBySoftwareModuleIdsAndTargetVisible(final Collection<Long> ids) {
|
||||
return jpaRepository.findVisibleMetadataByModuleIds(ids)
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
entry -> (Long) entry[0],
|
||||
Collectors.toMap(
|
||||
entry -> (String) entry[1],
|
||||
entry -> (String) entry[2],
|
||||
(existing, replacement) -> existing, // in case of duplicates, keep the first one
|
||||
HashMap::new)));
|
||||
return jpaRepository.findVisibleMetadataByModuleIds(ids).stream().collect(Collectors.groupingBy(entry -> (Long) entry[0],
|
||||
Collectors.toMap(entry -> (String) entry[1], entry -> (String) entry[2], (existing, replacement) -> existing,
|
||||
// in case of duplicates, keep the first one
|
||||
HashMap::new)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,10 +164,8 @@ public class JpaSoftwareModuleManagement
|
||||
public Page<JpaSoftwareModule> findByAssignedTo(final long distributionSetId, final Pageable pageable) {
|
||||
assertDistributionSetExists(distributionSetId);
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(
|
||||
jpaRepository,
|
||||
Collections.singletonList(SoftwareModuleSpecification.byAssignedToDs(distributionSetId)),
|
||||
pageable);
|
||||
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository,
|
||||
Collections.singletonList(SoftwareModuleSpecification.byAssignedToDs(distributionSetId)), pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,11 +188,11 @@ public class JpaSoftwareModuleManagement
|
||||
}
|
||||
|
||||
private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) {
|
||||
jpaRepository.getAccessController().ifPresent(accessController ->
|
||||
accessController.assertOperationAllowed(AccessController.Operation.DELETE, swModule));
|
||||
jpaRepository.getAccessController()
|
||||
.ifPresent(accessController -> accessController.assertOperationAllowed(AccessController.Operation.DELETE, swModule));
|
||||
final Set<String> sha1Hashes = swModule.getArtifacts().stream().map(Artifact::getSha1Hash).collect(Collectors.toSet());
|
||||
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() ->
|
||||
sha1Hashes.forEach(((JpaArtifactManagement) artifactManagement)::clearArtifactBinary));
|
||||
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit()
|
||||
.afterCommit(() -> sha1Hashes.forEach(((JpaArtifactManagement) artifactManagement)::clearArtifactBinary));
|
||||
}
|
||||
|
||||
private void assertDistributionSetExists(final long distributionSetId) {
|
||||
|
||||
@@ -47,11 +47,6 @@ public class JpaSoftwareModuleTypeManagement
|
||||
return jpaRepository.findByKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<JpaSoftwareModuleType> findByName(final String name) {
|
||||
return jpaRepository.findByName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<JpaSoftwareModuleType> softDelete(final Collection<JpaSoftwareModuleType> toDelete) {
|
||||
return toDelete.stream().filter(smt ->
|
||||
|
||||
@@ -15,12 +15,12 @@ import java.util.function.Consumer;
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.cache.TenancyCacheManager;
|
||||
import org.eclipse.hawkbit.artifact.ArtifactStorage;
|
||||
import org.eclipse.hawkbit.tenancy.cache.TenantCacheManager;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
||||
import org.eclipse.hawkbit.repository.artifact.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.CurrentTenantCacheKeyGenerator;
|
||||
import org.eclipse.hawkbit.repository.jpa.SystemManagementCacheKeyGenerator;
|
||||
@@ -44,8 +44,8 @@ import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.TenantMetaData;
|
||||
import org.eclipse.hawkbit.repository.report.model.SystemUsageReport;
|
||||
import org.eclipse.hawkbit.repository.report.model.SystemUsageReportWithTenants;
|
||||
import org.eclipse.hawkbit.repository.model.report.SystemUsageReport;
|
||||
import org.eclipse.hawkbit.repository.model.report.SystemUsageReportWithTenants;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -98,13 +98,13 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
private final TenantAware tenantAware;
|
||||
private final PlatformTransactionManager txManager;
|
||||
private final TenancyCacheManager cacheManager;
|
||||
private final TenantCacheManager cacheManager;
|
||||
private final RolloutStatusCache rolloutStatusCache;
|
||||
private final EntityManager entityManager;
|
||||
private final RepositoryProperties repositoryProperties;
|
||||
|
||||
@Nullable
|
||||
private ArtifactRepository artifactRepository;
|
||||
private ArtifactStorage artifactRepository;
|
||||
|
||||
@SuppressWarnings("squid:S00107")
|
||||
protected JpaSystemManagement(
|
||||
@@ -116,7 +116,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
final TenantConfigurationRepository tenantConfigurationRepository, final TenantMetaDataRepository tenantMetaDataRepository,
|
||||
final TenantStatsManagement systemStatsManagement, final SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final PlatformTransactionManager txManager,
|
||||
final TenancyCacheManager cacheManager, final RolloutStatusCache rolloutStatusCache,
|
||||
final TenantCacheManager cacheManager, final RolloutStatusCache rolloutStatusCache,
|
||||
final EntityManager entityManager, final RepositoryProperties repositoryProperties,
|
||||
final JpaProperties properties) {
|
||||
this.targetRepository = targetRepository;
|
||||
@@ -147,7 +147,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
}
|
||||
|
||||
@Autowired(required = false) // it's not required on dmf/ddi only instances
|
||||
public void setArtifactRepository(ArtifactRepository artifactRepository) {
|
||||
public void setArtifactRepository(ArtifactStorage artifactRepository) {
|
||||
this.artifactRepository = artifactRepository;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,27 @@ public class JpaTargetManagement
|
||||
return jpaRepository.exists(AccessController.Operation.UPDATE, combinedSpecification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Target getByControllerId(final String controllerId) {
|
||||
return jpaRepository.findByControllerId(controllerId).map(Target.class::cast)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Target> findByControllerId(final String controllerId) {
|
||||
return jpaRepository.findByControllerId(controllerId).map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Target> findByControllerId(final Collection<String> controllerIDs) {
|
||||
return Collections.unmodifiableList(jpaRepository.findAll(TargetSpecifications.byControllerIdWithAssignedDsInJoin(controllerIDs)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Target getWithDetails(final String controllerId, final String detailsKey) {
|
||||
return jpaRepository.getWithDetailsByControllerId(controllerId, "Target." + detailsKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(
|
||||
final long distributionSetId, final String rsql, final Pageable pageable) {
|
||||
@@ -143,21 +164,6 @@ public class JpaTargetManagement
|
||||
.map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Target> getByControllerId(final Collection<String> controllerIDs) {
|
||||
return Collections.unmodifiableList(jpaRepository.findAll(TargetSpecifications.byControllerIdWithAssignedDsInJoin(controllerIDs)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Target> getByControllerId(final String controllerId) {
|
||||
return jpaRepository.findByControllerId(controllerId).map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Target getWithDetails(final String controllerId, final String detailsKey) {
|
||||
return jpaRepository.getWithDetailsByControllerId(controllerId, "Target." + detailsKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(
|
||||
final Collection<Long> groups, final String rsql, final DistributionSetType dsType, final Pageable pageable) {
|
||||
|
||||
@@ -76,26 +76,21 @@ public class JpaTargetTypeManagement
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TargetType> getByKey(final String key) {
|
||||
public Optional<TargetType> findByKey(final String key) {
|
||||
return jpaRepository.findOne(TargetTypeSpecification.hasKey(key)).map(TargetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TargetType> getByName(final String name) {
|
||||
return jpaRepository.findOne(TargetTypeSpecification.hasName(name)).map(TargetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public TargetType assignCompatibleDistributionSetTypes(final long id,
|
||||
final Collection<Long> distributionSetTypeIds) {
|
||||
final Collection<JpaDistributionSetType> dsTypes = distributionSetTypeRepository
|
||||
.findAllById(distributionSetTypeIds);
|
||||
final Collection<JpaDistributionSetType> dsTypes = distributionSetTypeRepository.findAllById(distributionSetTypeIds);
|
||||
|
||||
if (dsTypes.size() < distributionSetTypeIds.size()) {
|
||||
throw new EntityNotFoundException(DistributionSetType.class, distributionSetTypeIds,
|
||||
throw new EntityNotFoundException(
|
||||
DistributionSetType.class, distributionSetTypeIds,
|
||||
dsTypes.stream().map(DistributionSetType::getId).toList());
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
|
||||
import org.eclipse.hawkbit.repository.model.report.TenantUsage;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -28,7 +28,6 @@ import jakarta.validation.constraints.Size;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.eclipse.hawkbit.repository.artifact.model.AbstractDbArtifact;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
|
||||
@@ -76,13 +75,6 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
||||
@Column(name = "file_size", updatable = false)
|
||||
private long fileSize;
|
||||
|
||||
/**
|
||||
* Constructs artifact.
|
||||
*
|
||||
* @param sha1Hash that is the link to the {@link AbstractDbArtifact} entity.
|
||||
* @param filename that is used by {@link AbstractDbArtifact} store.
|
||||
* @param softwareModule of this artifact
|
||||
*/
|
||||
public JpaArtifact(@NotEmpty final String sha1Hash, @NotNull final String filename, final SoftwareModule softwareModule) {
|
||||
this.sha1Hash = sha1Hash;
|
||||
this.filename = filename;
|
||||
|
||||
@@ -56,8 +56,7 @@ public class PauseRolloutGroupAction implements RolloutGroupActionEvaluator<Roll
|
||||
and this one tries to pause the rollout too but throws an exception
|
||||
and rollbacks rollout processing transaction
|
||||
*/
|
||||
final Rollout refreshedRollout = rolloutManagement.find(rollout.getId())
|
||||
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rollout.getId()));
|
||||
final Rollout refreshedRollout = rolloutManagement.get(rollout.getId());
|
||||
if (Rollout.RolloutStatus.PAUSED != refreshedRollout.getStatus()) {
|
||||
// if only the latest state is != paused then pause
|
||||
rolloutManagement.pauseRollout(rollout.getId());
|
||||
|
||||
@@ -25,18 +25,6 @@ import org.springframework.data.jpa.domain.Specification;
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class DistributionSetTypeSpecification {
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSetType} with
|
||||
* given {@link DistributionSetType#getName()} including fetching the
|
||||
* elements list.
|
||||
*
|
||||
* @param name to search
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSetType> byName(final String name) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(AbstractJpaNamedEntity_.name), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSetType} with
|
||||
* given {@link DistributionSetType#getKey()} including fetching the
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import jakarta.persistence.criteria.SetJoin;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
|
||||
@@ -13,11 +13,11 @@ import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.FileSizeQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.StorageQuotaExceededException;
|
||||
import org.eclipse.hawkbit.artifact.exception.FileSizeQuotaExceededException;
|
||||
import org.eclipse.hawkbit.artifact.exception.StorageQuotaExceededException;
|
||||
|
||||
/**
|
||||
* A FilterInputStream that ensures file size and storage quotas are enforced. It check during read operations if the
|
||||
* A FilterInputStream that ensures file size and storage quotas are enforced. It checks during read operations if the
|
||||
* quota will be exceeded and throws an QuotaExceededException if this happens.
|
||||
*/
|
||||
public class FileSizeAndStorageQuotaCheckingInputStream extends FilterInputStream {
|
||||
|
||||
Reference in New Issue
Block a user