Removed deprecated GridFS column from repository (#419)
* Merged artifact sha1 hash and gridfs column. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Renamed exception to get rid of old GridFS name. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Added test description. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Fix typo. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -89,7 +89,7 @@ public class DdiArtifactStoreController implements DdiDlArtifactStoreControllerR
|
|||||||
if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) {
|
if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) {
|
||||||
result = new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED);
|
result = new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED);
|
||||||
} else {
|
} else {
|
||||||
final DbArtifact file = artifactManagement.loadArtifactBinary(artifact.getId());
|
final DbArtifact file = artifactManagement.loadArtifactBinary(artifact.getSha1Hash());
|
||||||
|
|
||||||
// we set a download status only if we are aware of the
|
// we set a download status only if we are aware of the
|
||||||
// targetid, i.e. authenticated and not anonymous
|
// targetid, i.e. authenticated and not anonymous
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
|
|||||||
@SuppressWarnings("squid:S3655")
|
@SuppressWarnings("squid:S3655")
|
||||||
final Artifact artifact = module.getArtifactByFilename(fileName).get();
|
final Artifact artifact = module.getArtifactByFilename(fileName).get();
|
||||||
|
|
||||||
final DbArtifact file = artifactManagement.loadArtifactBinary(artifact.getId());
|
final DbArtifact file = artifactManagement.loadArtifactBinary(artifact.getSha1Hash());
|
||||||
|
|
||||||
final String ifMatch = requestResponseContextHolder.getHttpServletRequest().getHeader("If-Match");
|
final String ifMatch = requestResponseContextHolder.getHttpServletRequest().getHeader("If-Match");
|
||||||
if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) {
|
if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
package org.eclipse.hawkbit.amqp;
|
package org.eclipse.hawkbit.amqp;
|
||||||
|
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.api.HostnameResolver;
|
import org.eclipse.hawkbit.api.HostnameResolver;
|
||||||
@@ -116,60 +117,60 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService {
|
|||||||
*
|
*
|
||||||
* @param secruityToken
|
* @param secruityToken
|
||||||
* the security token which holds the target ID to check on
|
* the security token which holds the target ID to check on
|
||||||
* @param artifactId
|
* @param sha1Hash
|
||||||
* the artifact to verify if the given target is allowed to
|
* of the artifact to verify if the given target is allowed to
|
||||||
* download it
|
* download it
|
||||||
*/
|
*/
|
||||||
private void checkIfArtifactIsAssignedToTarget(final TenantSecurityToken secruityToken, final Long artifactId) {
|
private void checkIfArtifactIsAssignedToTarget(final TenantSecurityToken secruityToken, final String sha1Hash) {
|
||||||
|
|
||||||
if (secruityToken.getControllerId() != null) {
|
if (secruityToken.getControllerId() != null) {
|
||||||
checkByControllerId(artifactId, secruityToken.getControllerId());
|
checkByControllerId(sha1Hash, secruityToken.getControllerId());
|
||||||
} else if (secruityToken.getTargetId() != null) {
|
} else if (secruityToken.getTargetId() != null) {
|
||||||
checkByTargetId(artifactId, secruityToken.getTargetId());
|
checkByTargetId(sha1Hash, secruityToken.getTargetId());
|
||||||
} else {
|
} else {
|
||||||
LOG.info("anonymous download no authentication check for artifact {}", artifactId);
|
LOG.info("anonymous download no authentication check for artifact {}", sha1Hash);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkByTargetId(final Long artifactId, final Long targetId) {
|
private void checkByTargetId(final String sha1Hash, final Long targetId) {
|
||||||
LOG.debug("no anonymous download request, doing authentication check for target {} and artifact {}", targetId,
|
LOG.debug("no anonymous download request, doing authentication check for target {} and artifact {}", targetId,
|
||||||
artifactId);
|
sha1Hash);
|
||||||
if (!controllerManagement.hasTargetArtifactAssigned(targetId, artifactId)) {
|
if (!controllerManagement.hasTargetArtifactAssigned(targetId, sha1Hash)) {
|
||||||
LOG.info("target {} tried to download artifact {} which is not assigned to the target", targetId,
|
LOG.info("target {} tried to download artifact {} which is not assigned to the target", targetId, sha1Hash);
|
||||||
artifactId);
|
|
||||||
throw new EntityNotFoundException();
|
throw new EntityNotFoundException();
|
||||||
}
|
}
|
||||||
LOG.info("download security check for target {} and artifact {} granted", targetId, artifactId);
|
LOG.info("download security check for target {} and artifact {} granted", targetId, sha1Hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkByControllerId(final Long artifactId, final String controllerId) {
|
private void checkByControllerId(final String sha1Hash, final String controllerId) {
|
||||||
LOG.debug("no anonymous download request, doing authentication check for target {} and artifact {}",
|
LOG.debug("no anonymous download request, doing authentication check for target {} and artifact {}",
|
||||||
controllerId, artifactId);
|
controllerId, sha1Hash);
|
||||||
if (!controllerManagement.hasTargetArtifactAssigned(controllerId, artifactId)) {
|
if (!controllerManagement.hasTargetArtifactAssigned(controllerId, sha1Hash)) {
|
||||||
LOG.info("target {} tried to download artifact {} which is not assigned to the target", controllerId,
|
LOG.info("target {} tried to download artifact {} which is not assigned to the target", controllerId,
|
||||||
artifactId);
|
sha1Hash);
|
||||||
throw new EntityNotFoundException();
|
throw new EntityNotFoundException();
|
||||||
}
|
}
|
||||||
LOG.info("download security check for target {} and artifact {} granted", controllerId, artifactId);
|
LOG.info("download security check for target {} and artifact {} granted", controllerId, sha1Hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
private org.eclipse.hawkbit.repository.model.Artifact findArtifactByFileResource(final FileResource fileResource) {
|
private Optional<String> findArtifactByFileResource(final FileResource fileResource) {
|
||||||
if (fileResource.getSha1() != null) {
|
if (fileResource.getSha1() != null) {
|
||||||
return artifactManagement.findFirstArtifactBySHA1(fileResource.getSha1());
|
return Optional.ofNullable(fileResource.getSha1());
|
||||||
} else if (fileResource.getFilename() != null) {
|
} else if (fileResource.getFilename() != null) {
|
||||||
return artifactManagement.findArtifactByFilename(fileResource.getFilename()).stream().findFirst()
|
return artifactManagement.findArtifactByFilename(fileResource.getFilename()).stream().findFirst()
|
||||||
.orElse(null);
|
.map(org.eclipse.hawkbit.repository.model.Artifact::getSha1Hash);
|
||||||
} else if (fileResource.getArtifactId() != null) {
|
} else if (fileResource.getArtifactId() != null) {
|
||||||
return artifactManagement.findArtifact(fileResource.getArtifactId());
|
return Optional.ofNullable(artifactManagement.findArtifact(fileResource.getArtifactId()))
|
||||||
|
.map(org.eclipse.hawkbit.repository.model.Artifact::getSha1Hash);
|
||||||
} else if (fileResource.getSoftwareModuleFilenameResource() != null) {
|
} else if (fileResource.getSoftwareModuleFilenameResource() != null) {
|
||||||
return artifactManagement
|
return artifactManagement
|
||||||
.findByFilenameAndSoftwareModule(fileResource.getSoftwareModuleFilenameResource().getFilename(),
|
.findByFilenameAndSoftwareModule(fileResource.getSoftwareModuleFilenameResource().getFilename(),
|
||||||
fileResource.getSoftwareModuleFilenameResource().getSoftwareModuleId())
|
fileResource.getSoftwareModuleFilenameResource().getSoftwareModuleId())
|
||||||
.stream().findFirst().orElse(null);
|
.stream().findFirst().map(org.eclipse.hawkbit.repository.model.Artifact::getSha1Hash);
|
||||||
}
|
}
|
||||||
return null;
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Artifact convertDbArtifact(final DbArtifact dbArtifact) {
|
private static Artifact convertDbArtifact(final DbArtifact dbArtifact) {
|
||||||
@@ -189,26 +190,24 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService {
|
|||||||
try {
|
try {
|
||||||
SecurityContextHolder.getContext().setAuthentication(authenticationManager.doAuthenticate(secruityToken));
|
SecurityContextHolder.getContext().setAuthentication(authenticationManager.doAuthenticate(secruityToken));
|
||||||
|
|
||||||
final org.eclipse.hawkbit.repository.model.Artifact localArtifact = findArtifactByFileResource(
|
final Optional<String> sha1Hash = findArtifactByFileResource(fileResource);
|
||||||
fileResource);
|
|
||||||
|
|
||||||
if (localArtifact == null) {
|
if (!sha1Hash.isPresent()) {
|
||||||
LOG.info("target {} requested file resource {} which does not exists to download",
|
LOG.info("target {} requested file resource {} which does not exists to download",
|
||||||
secruityToken.getControllerId(), fileResource);
|
secruityToken.getControllerId(), fileResource);
|
||||||
throw new EntityNotFoundException();
|
throw new EntityNotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
checkIfArtifactIsAssignedToTarget(secruityToken, localArtifact.getId());
|
checkIfArtifactIsAssignedToTarget(secruityToken, sha1Hash.get());
|
||||||
|
|
||||||
final Artifact artifact = convertDbArtifact(artifactManagement.loadArtifactBinary(localArtifact.getId()));
|
final Artifact artifact = convertDbArtifact(artifactManagement.loadArtifactBinary(sha1Hash.get()));
|
||||||
if (artifact == null) {
|
if (artifact == null) {
|
||||||
throw new EntityNotFoundException();
|
throw new EntityNotFoundException();
|
||||||
}
|
}
|
||||||
authentificationResponse.setArtifact(artifact);
|
authentificationResponse.setArtifact(artifact);
|
||||||
final String downloadId = UUID.randomUUID().toString();
|
final String downloadId = UUID.randomUUID().toString();
|
||||||
// SHA1 key is set, download by SHA1
|
// SHA1 key is set, download by SHA1
|
||||||
final DownloadArtifactCache downloadCache = new DownloadArtifactCache(DownloadType.BY_SHA1,
|
final DownloadArtifactCache downloadCache = new DownloadArtifactCache(DownloadType.BY_SHA1, sha1Hash.get());
|
||||||
localArtifact.getSha1Hash());
|
|
||||||
cache.put(downloadId, downloadCache);
|
cache.put(downloadId, downloadCache);
|
||||||
authentificationResponse
|
authentificationResponse
|
||||||
.setDownloadUrl(UriComponentsBuilder.fromUri(hostnameResolver.resolveHostname().toURI())
|
.setDownloadUrl(UriComponentsBuilder.fromUri(hostnameResolver.resolveHostname().toURI())
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ public class AmqpControllerAuthenticationTest {
|
|||||||
|
|
||||||
authenticationManager.postConstruct();
|
authenticationManager.postConstruct();
|
||||||
|
|
||||||
final JpaArtifact testArtifact = new JpaArtifact("afilename", "afilename", new JpaSoftwareModule(
|
final JpaArtifact testArtifact = new JpaArtifact(SHA1, "afilename", new JpaSoftwareModule(
|
||||||
new JpaSoftwareModuleType("a key", "a name", null, 1), "a name", null, null, null));
|
new JpaSoftwareModuleType("a key", "a name", null, 1), "a name", null, null, null));
|
||||||
testArtifact.setId(1L);
|
testArtifact.setId(1L);
|
||||||
|
|
||||||
@@ -161,8 +161,8 @@ public class AmqpControllerAuthenticationTest {
|
|||||||
|
|
||||||
final DbArtifact artifact = new DbArtifact();
|
final DbArtifact artifact = new DbArtifact();
|
||||||
artifact.setSize(ARTIFACT_SIZE);
|
artifact.setSize(ARTIFACT_SIZE);
|
||||||
artifact.setHashes(new DbArtifactHash("sha1 test", "md5 test"));
|
artifact.setHashes(new DbArtifactHash(SHA1, "md5 test"));
|
||||||
when(artifactManagementMock.loadArtifactBinary(1L)).thenReturn(artifact);
|
when(artifactManagementMock.loadArtifactBinary(SHA1)).thenReturn(artifact);
|
||||||
|
|
||||||
amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate,
|
amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate,
|
||||||
mock(AmqpMessageDispatcherService.class), controllerManagementMock, new JpaEntityFactory());
|
mock(AmqpMessageDispatcherService.class), controllerManagementMock, new JpaEntityFactory());
|
||||||
@@ -173,8 +173,8 @@ public class AmqpControllerAuthenticationTest {
|
|||||||
|
|
||||||
when(hostnameResolverMock.resolveHostname()).thenReturn(new URL("http://localhost"));
|
when(hostnameResolverMock.resolveHostname()).thenReturn(new URL("http://localhost"));
|
||||||
|
|
||||||
when(controllerManagementMock.hasTargetArtifactAssigned(TARGET_ID, 1L)).thenReturn(true);
|
when(controllerManagementMock.hasTargetArtifactAssigned(TARGET_ID, SHA1)).thenReturn(true);
|
||||||
when(controllerManagementMock.hasTargetArtifactAssigned(CONTROLLER_ID, 1L)).thenReturn(true);
|
when(controllerManagementMock.hasTargetArtifactAssigned(CONTROLLER_ID, SHA1)).thenReturn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ package org.eclipse.hawkbit.amqp;
|
|||||||
|
|
||||||
import static org.fest.assertions.api.Assertions.assertThat;
|
import static org.fest.assertions.api.Assertions.assertThat;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Matchers.anyLong;
|
|
||||||
import static org.mockito.Matchers.anyObject;
|
import static org.mockito.Matchers.anyObject;
|
||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Matchers.anyString;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
@@ -79,9 +78,10 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
|||||||
@Stories("AmqpMessage Handler Service Test")
|
@Stories("AmqpMessage Handler Service Test")
|
||||||
public class AmqpMessageHandlerServiceTest {
|
public class AmqpMessageHandlerServiceTest {
|
||||||
|
|
||||||
|
private static final String SHA1 = "12345";
|
||||||
private static final String TENANT = "DEFAULT";
|
private static final String TENANT = "DEFAULT";
|
||||||
private static final Long TENANT_ID = 123L;
|
private static final Long TENANT_ID = 123L;
|
||||||
private static String CONTROLLLER_ID = "123";
|
private static final String CONTROLLLER_ID = "123";
|
||||||
private static final Long TARGET_ID = 123L;
|
private static final Long TARGET_ID = 123L;
|
||||||
|
|
||||||
private AmqpMessageHandlerService amqpMessageHandlerService;
|
private AmqpMessageHandlerService amqpMessageHandlerService;
|
||||||
@@ -362,17 +362,16 @@ public class AmqpMessageHandlerServiceTest {
|
|||||||
|
|
||||||
// mock
|
// mock
|
||||||
final Artifact localArtifactMock = mock(Artifact.class);
|
final Artifact localArtifactMock = mock(Artifact.class);
|
||||||
final Long mockedArtifactId = 1L;
|
when(localArtifactMock.getSha1Hash()).thenReturn(SHA1);
|
||||||
when(localArtifactMock.getId()).thenReturn(mockedArtifactId);
|
|
||||||
|
|
||||||
final DbArtifact dbArtifactMock = mock(DbArtifact.class);
|
final DbArtifact dbArtifactMock = mock(DbArtifact.class);
|
||||||
when(artifactManagementMock.findFirstArtifactBySHA1(anyString())).thenReturn(localArtifactMock);
|
when(artifactManagementMock.findFirstArtifactBySHA1(SHA1)).thenReturn(localArtifactMock);
|
||||||
when(controllerManagementMock.hasTargetArtifactAssigned(securityToken.getControllerId(), mockedArtifactId))
|
when(controllerManagementMock.hasTargetArtifactAssigned(securityToken.getControllerId(), SHA1))
|
||||||
.thenReturn(true);
|
.thenReturn(true);
|
||||||
when(artifactManagementMock.loadArtifactBinary(anyLong())).thenReturn(dbArtifactMock);
|
when(artifactManagementMock.loadArtifactBinary(anyString())).thenReturn(dbArtifactMock);
|
||||||
when(dbArtifactMock.getArtifactId()).thenReturn("artifactId");
|
when(dbArtifactMock.getArtifactId()).thenReturn("artifactId");
|
||||||
when(dbArtifactMock.getSize()).thenReturn(1L);
|
when(dbArtifactMock.getSize()).thenReturn(1L);
|
||||||
when(dbArtifactMock.getHashes()).thenReturn(new DbArtifactHash("sha1", "md5"));
|
when(dbArtifactMock.getHashes()).thenReturn(new DbArtifactHash(SHA1, "md5"));
|
||||||
when(hostnameResolverMock.resolveHostname()).thenReturn(new URL("http://localhost"));
|
when(hostnameResolverMock.resolveHostname()).thenReturn(new URL("http://localhost"));
|
||||||
|
|
||||||
// test
|
// test
|
||||||
@@ -384,7 +383,7 @@ public class AmqpMessageHandlerServiceTest {
|
|||||||
assertThat(downloadResponse.getResponseCode()).as("Message body response code is wrong")
|
assertThat(downloadResponse.getResponseCode()).as("Message body response code is wrong")
|
||||||
.isEqualTo(HttpStatus.OK.value());
|
.isEqualTo(HttpStatus.OK.value());
|
||||||
assertThat(downloadResponse.getArtifact().getSize()).as("Wrong artifact size in message body").isEqualTo(1L);
|
assertThat(downloadResponse.getArtifact().getSize()).as("Wrong artifact size in message body").isEqualTo(1L);
|
||||||
assertThat(downloadResponse.getArtifact().getHashes().getSha1()).as("Wrong sha1 hash").isEqualTo("sha1");
|
assertThat(downloadResponse.getArtifact().getHashes().getSha1()).as("Wrong sha1 hash").isEqualTo(SHA1);
|
||||||
assertThat(downloadResponse.getArtifact().getHashes().getMd5()).as("Wrong md5 hash").isEqualTo("md5");
|
assertThat(downloadResponse.getArtifact().getHashes().getMd5()).as("Wrong md5 hash").isEqualTo("md5");
|
||||||
assertThat(downloadResponse.getDownloadUrl()).as("download url is wrong")
|
assertThat(downloadResponse.getDownloadUrl()).as("download url is wrong")
|
||||||
.startsWith("http://localhost/api/v1/downloadserver/downloadId/");
|
.startsWith("http://localhost/api/v1/downloadserver/downloadId/");
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public class MgmtDownloadArtifactResource implements MgmtDownloadArtifactRestApi
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Artifact artifact = module.getArtifact(artifactId).get();
|
final Artifact artifact = module.getArtifact(artifactId).get();
|
||||||
final DbArtifact file = artifactManagement.loadArtifactBinary(artifact.getId());
|
final DbArtifact file = artifactManagement.loadArtifactBinary(artifact.getSha1Hash());
|
||||||
final HttpServletRequest request = requestResponseContextHolder.getHttpServletRequest();
|
final HttpServletRequest request = requestResponseContextHolder.getHttpServletRequest();
|
||||||
final String ifMatch = request.getHeader("If-Match");
|
final String ifMatch = request.getHeader("If-Match");
|
||||||
if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) {
|
if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) {
|
||||||
|
|||||||
@@ -163,7 +163,8 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra
|
|||||||
|
|
||||||
// binary
|
// binary
|
||||||
try (InputStream fileInputStream = artifactManagement
|
try (InputStream fileInputStream = artifactManagement
|
||||||
.loadArtifactBinary(softwareManagement.findSoftwareModuleById(sm.getId()).getArtifacts().get(0).getId())
|
.loadArtifactBinary(
|
||||||
|
softwareManagement.findSoftwareModuleById(sm.getId()).getArtifacts().get(0).getSha1Hash())
|
||||||
.getFileInputStream()) {
|
.getFileInputStream()) {
|
||||||
assertTrue("Wrong artifact content",
|
assertTrue("Wrong artifact content",
|
||||||
IOUtils.contentEquals(new ByteArrayInputStream(random), fileInputStream));
|
IOUtils.contentEquals(new ByteArrayInputStream(random), fileInputStream));
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import org.eclipse.hawkbit.repository.exception.ArtifactDeleteFailedException;
|
|||||||
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
|
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||||
import org.eclipse.hawkbit.repository.exception.GridFSDBFileNotFoundException;
|
import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNotFoundException;
|
||||||
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
||||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
||||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||||
@@ -186,18 +186,15 @@ public interface ArtifactManagement {
|
|||||||
/**
|
/**
|
||||||
* Loads {@link DbArtifact} from store for given {@link Artifact}.
|
* Loads {@link DbArtifact} from store for given {@link Artifact}.
|
||||||
*
|
*
|
||||||
* @param artifactId
|
* @param sha1Hash
|
||||||
* to search for
|
* to search for
|
||||||
* @return loaded {@link DbArtifact}
|
* @return loaded {@link DbArtifact}
|
||||||
*
|
*
|
||||||
* @throws GridFSDBFileNotFoundException
|
* @throws ArtifactBinaryNotFoundException
|
||||||
* if file could not be found in store
|
* if file could not be found in store
|
||||||
*
|
|
||||||
* @throws EntityNotFoundException
|
|
||||||
* is artifact with given ID does not exist
|
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DOWNLOAD_ARTIFACT + SpringEvalExpressions.HAS_AUTH_OR
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DOWNLOAD_ARTIFACT + SpringEvalExpressions.HAS_AUTH_OR
|
||||||
+ SpringEvalExpressions.HAS_CONTROLLER_DOWNLOAD)
|
+ SpringEvalExpressions.HAS_CONTROLLER_DOWNLOAD)
|
||||||
DbArtifact loadArtifactBinary(@NotNull Long artifactId);
|
DbArtifact loadArtifactBinary(@NotEmpty String sha1Hash);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,15 +178,15 @@ public interface ControllerManagement {
|
|||||||
*
|
*
|
||||||
* @param controllerId
|
* @param controllerId
|
||||||
* the ID of the target to check
|
* the ID of the target to check
|
||||||
* @param artifactId
|
* @param sha1Hash
|
||||||
* the artifact to verify if the given target had even been
|
* of the artifact to verify if the given target had even been
|
||||||
* assigned to
|
* assigned to
|
||||||
* @return {@code true} if the given target has currently or had ever a
|
* @return {@code true} if the given target has currently or had ever a
|
||||||
* relation to the given artifact through the action history,
|
* relation to the given artifact through the action history,
|
||||||
* otherwise {@code false}
|
* otherwise {@code false}
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||||
boolean hasTargetArtifactAssigned(@NotNull String controllerId, @NotNull Long artifactId);
|
boolean hasTargetArtifactAssigned(@NotEmpty String controllerId, @NotEmpty String sha1Hash);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a given target has currently or has even been assigned to the
|
* Checks if a given target has currently or has even been assigned to the
|
||||||
@@ -197,15 +197,15 @@ public interface ControllerManagement {
|
|||||||
*
|
*
|
||||||
* @param targetId
|
* @param targetId
|
||||||
* the ID of the target to check
|
* the ID of the target to check
|
||||||
* @param artifactId
|
* @param sha1Hash
|
||||||
* the artifact to verify if the given target had even been
|
* of the artifact to verify if the given target had even been
|
||||||
* assigned to
|
* assigned to
|
||||||
* @return {@code true} if the given target has currently or had ever a
|
* @return {@code true} if the given target has currently or had ever a
|
||||||
* relation to the given artifact through the action history,
|
* relation to the given artifact through the action history,
|
||||||
* otherwise {@code false}
|
* otherwise {@code false}
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||||
boolean hasTargetArtifactAssigned(@NotNull Long targetId, @NotNull Long artifactId);
|
boolean hasTargetArtifactAssigned(@NotNull Long targetId, @NotEmpty String sha1Hash);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers retrieved status for given {@link Target} and {@link Action} if
|
* Registers retrieved status for given {@link Target} and {@link Action} if
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import org.eclipse.hawkbit.exception.SpServerError;
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final class GridFSDBFileNotFoundException extends AbstractServerRtException {
|
public final class ArtifactBinaryNotFoundException extends AbstractServerRtException {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -27,7 +27,7 @@ public final class GridFSDBFileNotFoundException extends AbstractServerRtExcepti
|
|||||||
* Creates a new FileUploadFailedException with
|
* Creates a new FileUploadFailedException with
|
||||||
* {@link SpServerError#SP_REST_BODY_NOT_READABLE} error.
|
* {@link SpServerError#SP_REST_BODY_NOT_READABLE} error.
|
||||||
*/
|
*/
|
||||||
public GridFSDBFileNotFoundException() {
|
public ArtifactBinaryNotFoundException() {
|
||||||
super(SpServerError.SP_ARTIFACT_LOAD_FAILED);
|
super(SpServerError.SP_ARTIFACT_LOAD_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ public final class GridFSDBFileNotFoundException extends AbstractServerRtExcepti
|
|||||||
* @param cause
|
* @param cause
|
||||||
* for the exception
|
* for the exception
|
||||||
*/
|
*/
|
||||||
public GridFSDBFileNotFoundException(final Throwable cause) {
|
public ArtifactBinaryNotFoundException(final Throwable cause) {
|
||||||
super(SpServerError.SP_ARTIFACT_LOAD_FAILED, cause);
|
super(SpServerError.SP_ARTIFACT_LOAD_FAILED, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ public final class GridFSDBFileNotFoundException extends AbstractServerRtExcepti
|
|||||||
* @param message
|
* @param message
|
||||||
* of the error
|
* of the error
|
||||||
*/
|
*/
|
||||||
public GridFSDBFileNotFoundException(final String message) {
|
public ArtifactBinaryNotFoundException(final String message) {
|
||||||
super(message, SpServerError.SP_ARTIFACT_LOAD_FAILED);
|
super(message, SpServerError.SP_ARTIFACT_LOAD_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.model;
|
package org.eclipse.hawkbit.repository.model;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||||
|
|
||||||
import com.google.common.io.BaseEncoding;
|
import com.google.common.io.BaseEncoding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,7 +36,7 @@ public interface Artifact extends TenantAwareBaseEntity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return SHA-1 hash of the artifact in {@link BaseEncoding#base16()}
|
* @return SHA-1 hash of the artifact in {@link BaseEncoding#base16()}
|
||||||
* format.
|
* format that identifies the {@link DbArtifact} in the system.
|
||||||
*/
|
*/
|
||||||
String getSha1Hash();
|
String getSha1Hash();
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ import org.eclipse.hawkbit.artifact.repository.HashNotMatchException;
|
|||||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
|
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
|
||||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||||
|
import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNotFoundException;
|
||||||
import org.eclipse.hawkbit.repository.exception.ArtifactDeleteFailedException;
|
import org.eclipse.hawkbit.repository.exception.ArtifactDeleteFailedException;
|
||||||
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
|
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||||
import org.eclipse.hawkbit.repository.exception.GridFSDBFileNotFoundException;
|
|
||||||
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
||||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||||
@@ -112,7 +112,7 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
|
|
||||||
private boolean clearArtifactBinary(final JpaArtifact existing) {
|
private boolean clearArtifactBinary(final JpaArtifact existing) {
|
||||||
|
|
||||||
for (final Artifact lArtifact : localArtifactRepository.findByGridFsFileName(existing.getGridFsFileName())) {
|
for (final Artifact lArtifact : localArtifactRepository.findBySha1Hash(existing.getSha1Hash())) {
|
||||||
if (!lArtifact.getSoftwareModule().isDeleted()
|
if (!lArtifact.getSoftwareModule().isDeleted()
|
||||||
&& Long.compare(lArtifact.getSoftwareModule().getId(), existing.getSoftwareModule().getId()) != 0) {
|
&& Long.compare(lArtifact.getSoftwareModule().getId(), existing.getSoftwareModule().getId()) != 0) {
|
||||||
return false;
|
return false;
|
||||||
@@ -120,8 +120,8 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LOG.debug("deleting artifact from repository {}", existing.getGridFsFileName());
|
LOG.debug("deleting artifact from repository {}", existing.getSha1Hash());
|
||||||
artifactRepository.deleteBySha1(existing.getGridFsFileName());
|
artifactRepository.deleteBySha1(existing.getSha1Hash());
|
||||||
return true;
|
return true;
|
||||||
} catch (final ArtifactStoreException e) {
|
} catch (final ArtifactStoreException e) {
|
||||||
throw new ArtifactDeleteFailedException(e);
|
throw new ArtifactDeleteFailedException(e);
|
||||||
@@ -156,8 +156,8 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Artifact findFirstArtifactBySHA1(final String sha1) {
|
public Artifact findFirstArtifactBySHA1(final String sha1Hash) {
|
||||||
return localArtifactRepository.findFirstByGridFsFileName(sha1);
|
return localArtifactRepository.findFirstBySha1Hash(sha1Hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -171,16 +171,9 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DbArtifact loadArtifactBinary(final Long artifactId) {
|
public DbArtifact loadArtifactBinary(final String sha1Hash) {
|
||||||
final JpaArtifact artifact = Optional.ofNullable(localArtifactRepository.findOne(artifactId))
|
return Optional.ofNullable(artifactRepository.getArtifactBySha1(sha1Hash))
|
||||||
.orElseThrow(() -> new EntityNotFoundException("Artifact with given id " + artifactId + " not found."));
|
.orElseThrow(() -> new ArtifactBinaryNotFoundException(sha1Hash));
|
||||||
|
|
||||||
final DbArtifact result = artifactRepository.getArtifactBySha1(artifact.getGridFsFileName());
|
|
||||||
if (result == null) {
|
|
||||||
throw new GridFSDBFileNotFoundException(artifact.getGridFsFileName());
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Artifact storeArtifactMetadata(final SoftwareModule softwareModule, final String providedFilename,
|
private Artifact storeArtifactMetadata(final SoftwareModule softwareModule, final String providedFilename,
|
||||||
|
|||||||
@@ -156,21 +156,21 @@ public class JpaControllerManagement implements ControllerManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasTargetArtifactAssigned(final String controllerId, final Long localArtifact) {
|
public boolean hasTargetArtifactAssigned(final String controllerId, final String sha1Hash) {
|
||||||
final Target target = targetRepository.findByControllerId(controllerId);
|
final Target target = targetRepository.findByControllerId(controllerId);
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(target, localArtifact)) > 0;
|
return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(target, sha1Hash)) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasTargetArtifactAssigned(final Long targetId, final Long localArtifact) {
|
public boolean hasTargetArtifactAssigned(final Long targetId, final String sha1Hash) {
|
||||||
final Target target = targetRepository.findOne(targetId);
|
final Target target = targetRepository.findOne(targetId);
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(target, localArtifact)) > 0;
|
return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(target, sha1Hash)) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -48,20 +48,20 @@ public interface LocalArtifactRepository extends BaseEntityRepository<JpaArtifac
|
|||||||
/**
|
/**
|
||||||
* Searches for a {@link Artifact} based on given gridFsFileName.
|
* Searches for a {@link Artifact} based on given gridFsFileName.
|
||||||
*
|
*
|
||||||
* @param gridFsFileName
|
* @param sha1Hash
|
||||||
* to search
|
* to search
|
||||||
* @return list of {@link Artifact}s.
|
* @return list of {@link Artifact}s.
|
||||||
*/
|
*/
|
||||||
List<Artifact> findByGridFsFileName(String gridFsFileName);
|
List<Artifact> findBySha1Hash(String sha1Hash);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for a {@link Artifact} based on given gridFsFileName.
|
* Searches for a {@link Artifact} based on given gridFsFileName.
|
||||||
*
|
*
|
||||||
* @param gridFsFileName
|
* @param sha1Hash
|
||||||
* to search
|
* to search
|
||||||
* @return {@link Artifact} the first in the result list
|
* @return {@link Artifact} the first in the result list
|
||||||
*/
|
*/
|
||||||
JpaArtifact findFirstByGridFsFileName(String gridFsFileName);
|
JpaArtifact findFirstBySha1Hash(String sha1Hash);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for a {@link Artifact} based user provided filename at upload.
|
* Searches for a {@link Artifact} based user provided filename at upload.
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.hibernate.validator.constraints.NotEmpty;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Table(name = "sp_artifact", indexes = { @Index(name = "sp_idx_artifact_01", columnList = "tenant,software_module"),
|
@Table(name = "sp_artifact", indexes = { @Index(name = "sp_idx_artifact_01", columnList = "tenant,software_module"),
|
||||||
|
@Index(name = "sp_idx_artifact_02", columnList = "tenant,sha1_hash"),
|
||||||
@Index(name = "sp_idx_artifact_prim", columnList = "tenant,id") })
|
@Index(name = "sp_idx_artifact_prim", columnList = "tenant,id") })
|
||||||
@Entity
|
@Entity
|
||||||
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
||||||
@@ -38,10 +39,10 @@ import org.hibernate.validator.constraints.NotEmpty;
|
|||||||
public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Artifact {
|
public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Artifact {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Column(name = "gridfs_file_name", length = 40)
|
@Column(name = "sha1_hash", length = 40, nullable = false, updatable = false)
|
||||||
@Size(max = 40)
|
@Size(max = 40)
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
private String gridFsFileName;
|
private String sha1Hash;
|
||||||
|
|
||||||
@Column(name = "provided_file_name", length = 256)
|
@Column(name = "provided_file_name", length = 256)
|
||||||
@Size(max = 256)
|
@Size(max = 256)
|
||||||
@@ -52,9 +53,6 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
|||||||
@JoinColumn(name = "software_module", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_assigned_sm"))
|
@JoinColumn(name = "software_module", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_assigned_sm"))
|
||||||
private JpaSoftwareModule softwareModule;
|
private JpaSoftwareModule softwareModule;
|
||||||
|
|
||||||
@Column(name = "sha1_hash", length = 40, nullable = true)
|
|
||||||
private String sha1Hash;
|
|
||||||
|
|
||||||
@Column(name = "md5_hash", length = 32, nullable = true)
|
@Column(name = "md5_hash", length = 32, nullable = true)
|
||||||
private String md5Hash;
|
private String md5Hash;
|
||||||
|
|
||||||
@@ -71,17 +69,17 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
|||||||
/**
|
/**
|
||||||
* Constructs artifact.
|
* Constructs artifact.
|
||||||
*
|
*
|
||||||
* @param gridFsFileName
|
* @param sha1Hash
|
||||||
* that is the link to the {@link DbArtifact} entity.
|
* that is the link to the {@link DbArtifact} entity.
|
||||||
* @param filename
|
* @param filename
|
||||||
* that is used by {@link DbArtifact} store.
|
* that is used by {@link DbArtifact} store.
|
||||||
* @param softwareModule
|
* @param softwareModule
|
||||||
* of this artifact
|
* of this artifact
|
||||||
*/
|
*/
|
||||||
public JpaArtifact(@NotNull final String gridFsFileName, @NotNull final String filename,
|
public JpaArtifact(@NotEmpty final String sha1Hash, @NotNull final String filename,
|
||||||
final SoftwareModule softwareModule) {
|
final SoftwareModule softwareModule) {
|
||||||
setSoftwareModule(softwareModule);
|
setSoftwareModule(softwareModule);
|
||||||
this.gridFsFileName = gridFsFileName;
|
this.sha1Hash = sha1Hash;
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,10 +120,6 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
|||||||
this.softwareModule.addArtifact(this);
|
this.softwareModule.addArtifact(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGridFsFileName() {
|
|
||||||
return gridFsFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFilename() {
|
public String getFilename() {
|
||||||
return filename;
|
return filename;
|
||||||
|
|||||||
@@ -43,18 +43,18 @@ public final class ActionSpecifications {
|
|||||||
* @param target
|
* @param target
|
||||||
* the target to verfiy if the given artifact is currently
|
* the target to verfiy if the given artifact is currently
|
||||||
* assigned or had been assigned
|
* assigned or had been assigned
|
||||||
* @param localArtifact
|
* @param sha1Hash
|
||||||
* the local artifact to check wherever the target had ever been
|
* of the local artifact to check wherever the target had ever
|
||||||
* assigned
|
* been assigned
|
||||||
* @return a specification to use with spring JPA
|
* @return a specification to use with spring JPA
|
||||||
*/
|
*/
|
||||||
public static Specification<JpaAction> hasTargetAssignedArtifact(final Target target, final Long localArtifact) {
|
public static Specification<JpaAction> hasTargetAssignedArtifact(final Target target, final String sha1Hash) {
|
||||||
return (actionRoot, query, criteriaBuilder) -> {
|
return (actionRoot, query, criteriaBuilder) -> {
|
||||||
final Join<JpaAction, JpaDistributionSet> dsJoin = actionRoot.join(JpaAction_.distributionSet);
|
final Join<JpaAction, JpaDistributionSet> dsJoin = actionRoot.join(JpaAction_.distributionSet);
|
||||||
final SetJoin<JpaDistributionSet, JpaSoftwareModule> modulesJoin = dsJoin.join(JpaDistributionSet_.modules);
|
final SetJoin<JpaDistributionSet, JpaSoftwareModule> modulesJoin = dsJoin.join(JpaDistributionSet_.modules);
|
||||||
final ListJoin<JpaSoftwareModule, JpaArtifact> artifactsJoin = modulesJoin
|
final ListJoin<JpaSoftwareModule, JpaArtifact> artifactsJoin = modulesJoin
|
||||||
.join(JpaSoftwareModule_.artifacts);
|
.join(JpaSoftwareModule_.artifacts);
|
||||||
return criteriaBuilder.and(criteriaBuilder.equal(artifactsJoin.get(JpaArtifact_.id), localArtifact),
|
return criteriaBuilder.and(criteriaBuilder.equal(artifactsJoin.get(JpaArtifact_.sha1Hash), sha1Hash),
|
||||||
criteriaBuilder.equal(actionRoot.get(JpaAction_.target), target));
|
criteriaBuilder.equal(actionRoot.get(JpaAction_.target), target));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE sp_artifact DROP COLUMN sha1_hash;
|
||||||
|
ALTER TABLE sp_artifact CHANGE gridfs_file_name sha1_hash varchar(40) not null;
|
||||||
|
CREATE INDEX sp_idx_artifact_02 ON sp_artifact (tenant, sha1_hash);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE sp_artifact DROP COLUMN sha1_hash;
|
||||||
|
ALTER TABLE sp_artifact CHANGE gridfs_file_name sha1_hash varchar(40) not null;
|
||||||
|
CREATE INDEX sp_idx_artifact_02 ON sp_artifact (tenant, sha1_hash);
|
||||||
@@ -87,9 +87,9 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
assertThat(result.getSoftwareModule().getId()).isEqualTo(sm.getId());
|
assertThat(result.getSoftwareModule().getId()).isEqualTo(sm.getId());
|
||||||
assertThat(result2.getSoftwareModule().getId()).isEqualTo(sm2.getId());
|
assertThat(result2.getSoftwareModule().getId()).isEqualTo(sm2.getId());
|
||||||
assertThat(((JpaArtifact) result).getFilename()).isEqualTo("file1");
|
assertThat(((JpaArtifact) result).getFilename()).isEqualTo("file1");
|
||||||
assertThat(((JpaArtifact) result).getGridFsFileName()).isNotNull();
|
assertThat(((JpaArtifact) result).getSha1Hash()).isNotNull();
|
||||||
assertThat(result).isNotEqualTo(result2);
|
assertThat(result).isNotEqualTo(result2);
|
||||||
assertThat(((JpaArtifact) result).getGridFsFileName()).isEqualTo(((JpaArtifact) result2).getGridFsFileName());
|
assertThat(((JpaArtifact) result).getSha1Hash()).isEqualTo(((JpaArtifact) result2).getSha1Hash());
|
||||||
|
|
||||||
assertThat(artifactManagement.findArtifactByFilename("file1").get(0).getSha1Hash())
|
assertThat(artifactManagement.findArtifactByFilename("file1").get(0).getSha1Hash())
|
||||||
.isEqualTo(HashGeneratorUtils.generateSHA1(random));
|
.isEqualTo(HashGeneratorUtils.generateSHA1(random));
|
||||||
@@ -148,19 +148,18 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
|
|
||||||
assertThat(result.getId()).isNotNull();
|
assertThat(result.getId()).isNotNull();
|
||||||
assertThat(result2.getId()).isNotNull();
|
assertThat(result2.getId()).isNotNull();
|
||||||
assertThat(((JpaArtifact) result).getGridFsFileName())
|
assertThat(((JpaArtifact) result).getSha1Hash()).isNotEqualTo(((JpaArtifact) result2).getSha1Hash());
|
||||||
.isNotEqualTo(((JpaArtifact) result2).getGridFsFileName());
|
|
||||||
|
|
||||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNotNull();
|
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNotNull();
|
||||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getGridFsFileName())).isNotNull();
|
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getSha1Hash())).isNotNull();
|
||||||
|
|
||||||
artifactManagement.deleteArtifact(result.getId());
|
artifactManagement.deleteArtifact(result.getId());
|
||||||
|
|
||||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNull();
|
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNull();
|
||||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getGridFsFileName())).isNotNull();
|
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getSha1Hash())).isNotNull();
|
||||||
|
|
||||||
artifactManagement.deleteArtifact(result2.getId());
|
artifactManagement.deleteArtifact(result2.getId());
|
||||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getGridFsFileName())).isNull();
|
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result2).getSha1Hash())).isNull();
|
||||||
|
|
||||||
assertThat(artifactRepository.findAll()).hasSize(0);
|
assertThat(artifactRepository.findAll()).hasSize(0);
|
||||||
}
|
}
|
||||||
@@ -187,14 +186,14 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
assertThat(artifactRepository.findAll()).hasSize(2);
|
assertThat(artifactRepository.findAll()).hasSize(2);
|
||||||
assertThat(result.getId()).isNotNull();
|
assertThat(result.getId()).isNotNull();
|
||||||
assertThat(result2.getId()).isNotNull();
|
assertThat(result2.getId()).isNotNull();
|
||||||
assertThat(((JpaArtifact) result).getGridFsFileName()).isEqualTo(((JpaArtifact) result2).getGridFsFileName());
|
assertThat(((JpaArtifact) result).getSha1Hash()).isEqualTo(((JpaArtifact) result2).getSha1Hash());
|
||||||
|
|
||||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNotNull();
|
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNotNull();
|
||||||
artifactManagement.deleteArtifact(result.getId());
|
artifactManagement.deleteArtifact(result.getId());
|
||||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNotNull();
|
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNotNull();
|
||||||
|
|
||||||
artifactManagement.deleteArtifact(result2.getId());
|
artifactManagement.deleteArtifact(result2.getId());
|
||||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNull();
|
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -214,7 +213,8 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
final Artifact result = artifactManagement.createArtifact(new ByteArrayInputStream(random),
|
final Artifact result = artifactManagement.createArtifact(new ByteArrayInputStream(random),
|
||||||
testdataFactory.createSoftwareModuleOs().getId(), "file1", false);
|
testdataFactory.createSoftwareModuleOs().getId(), "file1", false);
|
||||||
|
|
||||||
try (InputStream fileInputStream = artifactManagement.loadArtifactBinary(result.getId()).getFileInputStream()) {
|
try (InputStream fileInputStream = artifactManagement.loadArtifactBinary(result.getSha1Hash())
|
||||||
|
.getFileInputStream()) {
|
||||||
assertTrue("The stored binary matches the given binary",
|
assertTrue("The stored binary matches the given binary",
|
||||||
IOUtils.contentEquals(new ByteArrayInputStream(random), fileInputStream));
|
IOUtils.contentEquals(new ByteArrayInputStream(random), fileInputStream));
|
||||||
}
|
}
|
||||||
@@ -225,7 +225,7 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
@Description("Trys and fails to load an artifact without required permission. Checks if expected InsufficientPermissionException is thrown.")
|
@Description("Trys and fails to load an artifact without required permission. Checks if expected InsufficientPermissionException is thrown.")
|
||||||
public void loadArtifactBinaryWithoutDownloadArtifactThrowsPermissionDenied() {
|
public void loadArtifactBinaryWithoutDownloadArtifactThrowsPermissionDenied() {
|
||||||
try {
|
try {
|
||||||
artifactManagement.loadArtifactBinary(1L);
|
artifactManagement.loadArtifactBinary("123");
|
||||||
fail("Should not have worked with missing permission.");
|
fail("Should not have worked with missing permission.");
|
||||||
} catch (final InsufficientPermissionException e) {
|
} catch (final InsufficientPermissionException e) {
|
||||||
|
|
||||||
|
|||||||
@@ -11,18 +11,23 @@ package org.eclipse.hawkbit.repository.jpa;
|
|||||||
import static org.fest.assertions.api.Assertions.assertThat;
|
import static org.fest.assertions.api.Assertions.assertThat;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
|
||||||
import javax.validation.ConstraintViolationException;
|
import javax.validation.ConstraintViolationException;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||||
@@ -80,6 +85,42 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
.isEqualTo(3);
|
.isEqualTo(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verifies that assignement verification works based on SHA1 hash. By design it is not important which artifact "
|
||||||
|
+ "is actually used for the check as long as they have an identical binary, i.e. same SHA1 hash. ")
|
||||||
|
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||||
|
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
||||||
|
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1),
|
||||||
|
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
|
||||||
|
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
|
||||||
|
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 2) })
|
||||||
|
public void hasTargetArtifactAssignedIsTrueWithMultipleArtifacts() {
|
||||||
|
final byte[] random = RandomUtils.nextBytes(5 * 1024);
|
||||||
|
|
||||||
|
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||||
|
final DistributionSet ds2 = testdataFactory.createDistributionSet("2");
|
||||||
|
Target savedTarget = testdataFactory.createTarget();
|
||||||
|
|
||||||
|
// create two artifacts with identical SHA1 hash
|
||||||
|
final Artifact artifact = artifactManagement.createArtifact(new ByteArrayInputStream(random),
|
||||||
|
ds.findFirstModuleByType(osType).getId(), "file1", false);
|
||||||
|
final Artifact artifact2 = artifactManagement.createArtifact(new ByteArrayInputStream(random),
|
||||||
|
ds2.findFirstModuleByType(osType).getId(), "file1", false);
|
||||||
|
assertThat(artifact.getSha1Hash()).isEqualTo(artifact2.getSha1Hash());
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
controllerManagament.hasTargetArtifactAssigned(savedTarget.getControllerId(), artifact.getSha1Hash()))
|
||||||
|
.isFalse();
|
||||||
|
savedTarget = assignDistributionSet(ds.getId(), savedTarget.getControllerId()).getAssignedEntity().iterator()
|
||||||
|
.next();
|
||||||
|
assertThat(
|
||||||
|
controllerManagament.hasTargetArtifactAssigned(savedTarget.getControllerId(), artifact.getSha1Hash()))
|
||||||
|
.isTrue();
|
||||||
|
assertThat(
|
||||||
|
controllerManagament.hasTargetArtifactAssigned(savedTarget.getControllerId(), artifact2.getSha1Hash()))
|
||||||
|
.isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Register a controller which does not exist")
|
@Description("Register a controller which does not exist")
|
||||||
public void testfindOrRegisterTargetIfItDoesNotexist() {
|
public void testfindOrRegisterTargetIfItDoesNotexist() {
|
||||||
|
|||||||
@@ -501,14 +501,13 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
assertThat(artifactRepository.findAll()).hasSize(results.length);
|
assertThat(artifactRepository.findAll()).hasSize(results.length);
|
||||||
for (final Artifact result : results) {
|
for (final Artifact result : results) {
|
||||||
assertThat(result.getId()).isNotNull();
|
assertThat(result.getId()).isNotNull();
|
||||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName()))
|
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNotNull();
|
||||||
.isNotNull();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertArtfiactNull(final Artifact... results) {
|
private void assertArtfiactNull(final Artifact... results) {
|
||||||
for (final Artifact result : results) {
|
for (final Artifact result : results) {
|
||||||
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getGridFsFileName())).isNull();
|
assertThat(binaryArtifactRepository.getArtifactBySha1(((JpaArtifact) result).getSha1Hash())).isNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user