Merge branch 'master' into feature_ui_metadata
This commit is contained in:
@@ -31,7 +31,7 @@ public class DownloadIdCacheAutoConfiguration {
|
|||||||
private CacheManager cacheManager;
|
private CacheManager cacheManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean for the downlod id cache.
|
* Bean for the download id cache.
|
||||||
*
|
*
|
||||||
* @return the cache
|
* @return the cache
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -45,6 +45,12 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
<artifactId>hawkbit-repository-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ import static org.mockito.Mockito.verify;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent;
|
|
||||||
import org.eclipse.hawkbit.eventbus.event.EntityEvent;
|
import org.eclipse.hawkbit.eventbus.event.EntityEvent;
|
||||||
|
import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -56,7 +56,7 @@ public class EventDistributorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void distributeDistributedEventSendsToRedis() {
|
public void distributeDistributedEventSendsToRedis() {
|
||||||
|
|
||||||
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
|
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
|
||||||
underTest.distribute(event);
|
underTest.distribute(event);
|
||||||
|
|
||||||
// origin node ID should be set by distributing the event
|
// origin node ID should be set by distributing the event
|
||||||
@@ -67,7 +67,7 @@ public class EventDistributorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void dontDistributeDistributedEventIfSameNode() {
|
public void dontDistributeDistributedEventIfSameNode() {
|
||||||
final String knownNodeId = EventDistributor.getNodeId();
|
final String knownNodeId = EventDistributor.getNodeId();
|
||||||
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
|
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
|
||||||
event.setNodeId(knownNodeId);
|
event.setNodeId(knownNodeId);
|
||||||
|
|
||||||
// test
|
// test
|
||||||
@@ -79,7 +79,7 @@ public class EventDistributorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleDistributedMessageFromRedis() {
|
public void handleDistributedMessageFromRedis() {
|
||||||
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
|
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
|
||||||
final String knownChannel = "someChannel";
|
final String knownChannel = "someChannel";
|
||||||
|
|
||||||
underTest.handleMessage(event, knownChannel);
|
underTest.handleMessage(event, knownChannel);
|
||||||
@@ -90,7 +90,7 @@ public class EventDistributorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleDistributedMessageFilteredIfSameNodeId() {
|
public void handleDistributedMessageFilteredIfSameNodeId() {
|
||||||
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 10);
|
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
|
||||||
final String knownChannel = "someChannel";
|
final String knownChannel = "someChannel";
|
||||||
event.setOriginNodeId(EventDistributor.getNodeId());
|
event.setOriginNodeId(EventDistributor.getNodeId());
|
||||||
|
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
|
||||||
*
|
|
||||||
* All rights reserved. This program and the accompanying materials
|
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
|
||||||
* which accompanies this distribution, and is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
*/
|
|
||||||
package org.eclipse.hawkbit.eventbus.event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event that contains an updated download progress for a given Action.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class DownloadProgressEvent extends AbstractDistributedEvent {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private final Long statusId;
|
|
||||||
private final int progressPercent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*
|
|
||||||
* @param tenant
|
|
||||||
* the tenant for this event
|
|
||||||
* @param statusId
|
|
||||||
* of {@link UpdateActionStatus}
|
|
||||||
* @param progressPercent
|
|
||||||
* number (1-100)
|
|
||||||
*/
|
|
||||||
public DownloadProgressEvent(final String tenant, final Long statusId, final int progressPercent) {
|
|
||||||
// the revision of the DownloadProgressEvent is just equal the
|
|
||||||
// progressPercentage due the
|
|
||||||
// percentage is going from 0 to 100.
|
|
||||||
super(statusId, tenant);
|
|
||||||
this.statusId = statusId;
|
|
||||||
this.progressPercent = progressPercent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the statusId
|
|
||||||
*/
|
|
||||||
public Long getStatusId() {
|
|
||||||
return statusId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the progressPercent
|
|
||||||
*/
|
|
||||||
public int getProgressPercent() {
|
|
||||||
return progressPercent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -93,12 +93,12 @@ public class DdiArtifactStoreController implements DdiDlArtifactStoreControllerR
|
|||||||
// 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
|
||||||
if (targetid != null && !"anonymous".equals(targetid)) {
|
if (targetid != null && !"anonymous".equals(targetid)) {
|
||||||
final Action action = checkAndReportDownloadByTarget(
|
final ActionStatus actionStatus = checkAndReportDownloadByTarget(
|
||||||
requestResponseContextHolder.getHttpServletRequest(), targetid, artifact);
|
requestResponseContextHolder.getHttpServletRequest(), targetid, artifact);
|
||||||
result = RestResourceConversionHelper.writeFileResponse(artifact,
|
result = RestResourceConversionHelper.writeFileResponse(artifact,
|
||||||
requestResponseContextHolder.getHttpServletResponse(),
|
requestResponseContextHolder.getHttpServletResponse(),
|
||||||
requestResponseContextHolder.getHttpServletRequest(), file, controllerManagement,
|
requestResponseContextHolder.getHttpServletRequest(), file, controllerManagement,
|
||||||
action.getId());
|
actionStatus.getId());
|
||||||
} else {
|
} else {
|
||||||
result = RestResourceConversionHelper.writeFileResponse(artifact,
|
result = RestResourceConversionHelper.writeFileResponse(artifact,
|
||||||
requestResponseContextHolder.getHttpServletResponse(),
|
requestResponseContextHolder.getHttpServletResponse(),
|
||||||
@@ -131,7 +131,7 @@ public class DdiArtifactStoreController implements DdiDlArtifactStoreControllerR
|
|||||||
return new ResponseEntity<>(HttpStatus.OK);
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Action checkAndReportDownloadByTarget(final HttpServletRequest request, final String targetid,
|
private ActionStatus checkAndReportDownloadByTarget(final HttpServletRequest request, final String targetid,
|
||||||
final LocalArtifact artifact) {
|
final LocalArtifact artifact) {
|
||||||
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
||||||
IpUtil.getClientIpFromRequest(request, securityProperties));
|
IpUtil.getClientIpFromRequest(request, securityProperties));
|
||||||
@@ -152,8 +152,8 @@ public class DdiArtifactStoreController implements DdiDlArtifactStoreControllerR
|
|||||||
actionStatus.addMessage(
|
actionStatus.addMessage(
|
||||||
RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads: " + request.getRequestURI());
|
RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads: " + request.getRequestURI());
|
||||||
}
|
}
|
||||||
controllerManagement.addInformationalActionStatus(actionStatus);
|
|
||||||
return action;
|
return controllerManagement.addInformationalActionStatus(actionStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,8 +156,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
|
|||||||
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 Action action = checkAndLogDownload(requestResponseContextHolder.getHttpServletRequest(), target,
|
final ActionStatus action = checkAndLogDownload(requestResponseContextHolder.getHttpServletRequest(),
|
||||||
module);
|
target, module);
|
||||||
result = RestResourceConversionHelper.writeFileResponse(artifact,
|
result = RestResourceConversionHelper.writeFileResponse(artifact,
|
||||||
requestResponseContextHolder.getHttpServletResponse(),
|
requestResponseContextHolder.getHttpServletResponse(),
|
||||||
requestResponseContextHolder.getHttpServletRequest(), file, controllerManagement,
|
requestResponseContextHolder.getHttpServletRequest(), file, controllerManagement,
|
||||||
@@ -167,7 +167,7 @@ public class DdiRootController implements DdiRootControllerRestApi {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Action checkAndLogDownload(final HttpServletRequest request, final Target target,
|
private ActionStatus checkAndLogDownload(final HttpServletRequest request, final Target target,
|
||||||
final SoftwareModule module) {
|
final SoftwareModule module) {
|
||||||
final Action action = controllerManagement
|
final Action action = controllerManagement
|
||||||
.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), module);
|
.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), module);
|
||||||
@@ -185,8 +185,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
|
|||||||
statusMessage.addMessage(
|
statusMessage.addMessage(
|
||||||
RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads " + request.getRequestURI());
|
RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads " + request.getRequestURI());
|
||||||
}
|
}
|
||||||
controllerManagement.addInformationalActionStatus(statusMessage);
|
|
||||||
return action;
|
return controllerManagement.addInformationalActionStatus(statusMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkModule(final String fileName, final SoftwareModule module) {
|
private static boolean checkModule(final String fileName, final SoftwareModule module) {
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.RandomUtils;
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent;
|
import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
|
||||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
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.LocalArtifact;
|
import org.eclipse.hawkbit.repository.model.LocalArtifact;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
|
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
|
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -59,11 +59,15 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
|||||||
@Stories("Artifact Download Resource")
|
@Stories("Artifact Download Resource")
|
||||||
public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMongoDB {
|
public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMongoDB {
|
||||||
|
|
||||||
|
private static final int ARTIFACT_SIZE = 5 * 1024 * 1024;
|
||||||
|
|
||||||
public DdiArtifactDownloadTest() {
|
public DdiArtifactDownloadTest() {
|
||||||
LOG = LoggerFactory.getLogger(DdiArtifactDownloadTest.class);
|
LOG = LoggerFactory.getLogger(DdiArtifactDownloadTest.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private volatile int downLoadProgress = 0;
|
private volatile int downLoadProgress = 0;
|
||||||
|
private volatile long shippedBytes = 0;
|
||||||
|
private volatile long shippedBytesTotal = 0;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private EventBus eventBus;
|
private EventBus eventBus;
|
||||||
@@ -236,6 +240,8 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
|
|||||||
@Description("Tests valid downloads through the artifact resource by identifying the artifact not by ID but file name.")
|
@Description("Tests valid downloads through the artifact resource by identifying the artifact not by ID but file name.")
|
||||||
public void downloadArtifactThroughFileName() throws Exception {
|
public void downloadArtifactThroughFileName() throws Exception {
|
||||||
downLoadProgress = 1;
|
downLoadProgress = 1;
|
||||||
|
shippedBytes = 0;
|
||||||
|
shippedBytesTotal = 0;
|
||||||
eventBus.register(this);
|
eventBus.register(this);
|
||||||
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
|
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
|
||||||
|
|
||||||
@@ -249,7 +255,7 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
|
|||||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||||
|
|
||||||
// create artifact
|
// create artifact
|
||||||
final byte random[] = RandomUtils.nextBytes(5 * 1024 * 1024);
|
final byte random[] = RandomUtils.nextBytes(ARTIFACT_SIZE);
|
||||||
final LocalArtifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random),
|
final LocalArtifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random),
|
||||||
ds.findFirstModuleByType(osType).getId(), "file1", false);
|
ds.findFirstModuleByType(osType).getId(), "file1", false);
|
||||||
|
|
||||||
@@ -276,6 +282,7 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
|
|||||||
|
|
||||||
// download complete
|
// download complete
|
||||||
assertThat(downLoadProgress).isEqualTo(10);
|
assertThat(downLoadProgress).isEqualTo(10);
|
||||||
|
assertThat(shippedBytes).isEqualTo(shippedBytesTotal).isEqualTo(ARTIFACT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -313,35 +320,8 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
|
|||||||
+ "anonymous as authorization is notpossible, e.g. chekc if the controller has the artifact assigned.")
|
+ "anonymous as authorization is notpossible, e.g. chekc if the controller has the artifact assigned.")
|
||||||
public void downloadArtifactByNameFailsIfNotAuthenticated() throws Exception {
|
public void downloadArtifactByNameFailsIfNotAuthenticated() throws Exception {
|
||||||
downLoadProgress = 1;
|
downLoadProgress = 1;
|
||||||
eventBus.register(this);
|
shippedBytes = 0;
|
||||||
|
shippedBytesTotal = 0;
|
||||||
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
|
|
||||||
|
|
||||||
// create target
|
|
||||||
Target target = entityFactory.generateTarget("4712");
|
|
||||||
target = targetManagement.createTarget(target);
|
|
||||||
final List<Target> targets = new ArrayList();
|
|
||||||
targets.add(target);
|
|
||||||
|
|
||||||
// create ds
|
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
|
||||||
|
|
||||||
// create artifact
|
|
||||||
final byte random[] = RandomUtils.nextBytes(5 * 1024);
|
|
||||||
final Artifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random),
|
|
||||||
ds.findFirstModuleByType(osType).getId(), "file1.tar.bz2", false);
|
|
||||||
|
|
||||||
// download fails as artifact is not yet assigned to target
|
|
||||||
deploymentManagement.assignDistributionSet(ds, targets);
|
|
||||||
mvc.perform(get("/controller/artifacts/v1/filename/{filename}", "file1.tar.bz2"))
|
|
||||||
.andExpect(status().isNotFound());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@WithUser(principal = "4712", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
|
|
||||||
@Description("Ensures that an authenticated and named controller is permitted to download.")
|
|
||||||
public void downloadArtifactByNameByNamedController() throws Exception {
|
|
||||||
downLoadProgress = 1;
|
|
||||||
eventBus.register(this);
|
eventBus.register(this);
|
||||||
|
|
||||||
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
|
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
|
||||||
@@ -356,7 +336,41 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
|
|||||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||||
|
|
||||||
// create artifact
|
// create artifact
|
||||||
final byte random[] = RandomUtils.nextBytes(5 * 1024 * 1024);
|
final byte random[] = RandomUtils.nextBytes(ARTIFACT_SIZE);
|
||||||
|
artifactManagement.createLocalArtifact(new ByteArrayInputStream(random),
|
||||||
|
ds.findFirstModuleByType(osType).getId(), "file1.tar.bz2", false);
|
||||||
|
|
||||||
|
// download fails as artifact is not yet assigned to target
|
||||||
|
deploymentManagement.assignDistributionSet(ds, targets);
|
||||||
|
mvc.perform(get("/controller/artifacts/v1/filename/{filename}", "file1.tar.bz2"))
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
|
||||||
|
assertThat(downLoadProgress).isEqualTo(1);
|
||||||
|
assertThat(shippedBytes).isEqualTo(shippedBytesTotal).isEqualTo(0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUser(principal = "4712", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
|
||||||
|
@Description("Ensures that an authenticated and named controller is permitted to download.")
|
||||||
|
public void downloadArtifactByNameByNamedController() throws Exception {
|
||||||
|
downLoadProgress = 1;
|
||||||
|
shippedBytes = 0;
|
||||||
|
shippedBytesTotal = 0;
|
||||||
|
eventBus.register(this);
|
||||||
|
|
||||||
|
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
|
||||||
|
|
||||||
|
// create target
|
||||||
|
Target target = entityFactory.generateTarget("4712");
|
||||||
|
target = targetManagement.createTarget(target);
|
||||||
|
final List<Target> targets = new ArrayList<>();
|
||||||
|
targets.add(target);
|
||||||
|
|
||||||
|
// create ds
|
||||||
|
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||||
|
|
||||||
|
// create artifact
|
||||||
|
final byte random[] = RandomUtils.nextBytes(ARTIFACT_SIZE);
|
||||||
final Artifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random),
|
final Artifact artifact = artifactManagement.createLocalArtifact(new ByteArrayInputStream(random),
|
||||||
ds.findFirstModuleByType(osType).getId(), "file1", false);
|
ds.findFirstModuleByType(osType).getId(), "file1", false);
|
||||||
|
|
||||||
@@ -389,6 +403,7 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
|
|||||||
|
|
||||||
// download complete
|
// download complete
|
||||||
assertThat(downLoadProgress).isEqualTo(10);
|
assertThat(downLoadProgress).isEqualTo(10);
|
||||||
|
assertThat(shippedBytes).isEqualTo(shippedBytesTotal).isEqualTo(ARTIFACT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -550,5 +565,8 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void listen(final DownloadProgressEvent event) {
|
public void listen(final DownloadProgressEvent event) {
|
||||||
downLoadProgress++;
|
downLoadProgress++;
|
||||||
|
shippedBytes += event.getShippedBytesSinceLast();
|
||||||
|
shippedBytesTotal = event.getShippedBytesOverall();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ public class MgmtSystemTenantServiceUsage {
|
|||||||
* @param tenantName
|
* @param tenantName
|
||||||
*/
|
*/
|
||||||
public MgmtSystemTenantServiceUsage(final String tenantName) {
|
public MgmtSystemTenantServiceUsage(final String tenantName) {
|
||||||
super();
|
|
||||||
this.tenantName = tenantName;
|
this.tenantName = tenantName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent;
|
|
||||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||||
|
import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
|
||||||
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.ToManyAttributeEntriesException;
|
import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException;
|
||||||
@@ -58,16 +58,20 @@ public interface ControllerManagement {
|
|||||||
Action addCancelActionStatus(@NotNull ActionStatus actionStatus);
|
Action addCancelActionStatus(@NotNull ActionStatus actionStatus);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the download progress in percentage and notifies the
|
* Sends the download progress and notifies the {@link EventBus} with a
|
||||||
* {@link EventBus} with a {@link DownloadProgressEvent}.
|
* {@link DownloadProgressEvent}.
|
||||||
*
|
*
|
||||||
* @param statusId
|
* @param statusId
|
||||||
* the ID of the {@link ActionStatus}
|
* the ID of the {@link ActionStatus}
|
||||||
* @param progressPercent
|
* @param requestedBytes
|
||||||
* the progress in percentage which must be between 0-100
|
* requested bytes of the request
|
||||||
|
* @param shippedBytesSinceLast
|
||||||
|
* since the last report
|
||||||
|
* @param shippedBytesOverall
|
||||||
|
* for the {@link ActionStatus}
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||||
void downloadProgressPercent(long statusId, int progressPercent);
|
void downloadProgress(Long statusId, Long requestedBytes, Long shippedBytesSinceLast, Long shippedBytesOverall);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple addition of a new {@link ActionStatus} entry to the {@link Action}
|
* Simple addition of a new {@link ActionStatus} entry to the {@link Action}
|
||||||
@@ -75,9 +79,11 @@ public interface ControllerManagement {
|
|||||||
*
|
*
|
||||||
* @param statusMessage
|
* @param statusMessage
|
||||||
* to add to the action
|
* to add to the action
|
||||||
|
*
|
||||||
|
* @return create {@link ActionStatus} entity
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||||
void addInformationalActionStatus(@NotNull ActionStatus statusMessage);
|
ActionStatus addInformationalActionStatus(@NotNull ActionStatus statusMessage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an {@link ActionStatus} entry for an update {@link Action} including
|
* Adds an {@link ActionStatus} entry for an update {@link Action} including
|
||||||
|
|||||||
@@ -20,15 +20,14 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
|||||||
public interface TenantStatsManagement {
|
public interface TenantStatsManagement {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for stats of a single tenant. Opens a new transaction and as a
|
* Service for stats of the current tenant.
|
||||||
* result can an be used for multiple tenants, i.e. to allow in one session
|
|
||||||
* to collect data of all tenants in the system.
|
|
||||||
*
|
*
|
||||||
* @param tenant
|
|
||||||
* to collect for
|
|
||||||
* @return collected statistics
|
* @return collected statistics
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
|
||||||
TenantUsage getStatsOfTenant(String tenant);
|
+ SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
|
||||||
|
+ SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR
|
||||||
|
+ SpringEvalExpressions.IS_SYSTEM_CODE)
|
||||||
|
TenantUsage getStatsOfTenant();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.repository.eventbus.event;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event that contains an updated download progress for a given ActionStatus
|
||||||
|
* that was written for a download request.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DownloadProgressEvent extends AbstractDistributedEvent {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final Long statusId;
|
||||||
|
private final long requestedBytes;
|
||||||
|
private final long shippedBytesSinceLast;
|
||||||
|
private final long shippedBytesOverall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param tenant
|
||||||
|
* the tenant for this event
|
||||||
|
* @param statusId
|
||||||
|
* of ActionStatus that was written for the download request
|
||||||
|
* @param requestedBytes
|
||||||
|
* bytes requested
|
||||||
|
* @param shippedBytesSinceLast
|
||||||
|
* bytes since last event
|
||||||
|
* @param shippedBytesOverall
|
||||||
|
* on the download request
|
||||||
|
*/
|
||||||
|
public DownloadProgressEvent(final String tenant, final Long statusId, final Long requestedBytes,
|
||||||
|
final Long shippedBytesSinceLast, final Long shippedBytesOverall) {
|
||||||
|
// the revision of the DownloadProgressEvent is just equal the
|
||||||
|
// shippedBytesOverall as this is a growing number.
|
||||||
|
super(shippedBytesOverall, tenant);
|
||||||
|
this.statusId = statusId;
|
||||||
|
this.requestedBytes = requestedBytes;
|
||||||
|
this.shippedBytesSinceLast = shippedBytesSinceLast;
|
||||||
|
this.shippedBytesOverall = shippedBytesOverall;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getStatusId() {
|
||||||
|
return statusId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRequestedBytes() {
|
||||||
|
return requestedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getShippedBytesSinceLast() {
|
||||||
|
return shippedBytesSinceLast;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getShippedBytesOverall() {
|
||||||
|
return shippedBytesOverall;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,12 +39,6 @@ public interface Action extends TenantAwareBaseEntity {
|
|||||||
return Status.CANCELING.equals(getStatus()) || Status.CANCELED.equals(getStatus());
|
return Status.CANCELING.equals(getStatus()) || Status.CANCELED.equals(getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return current {@link Status#DOWNLOAD} progress if known by the update
|
|
||||||
* server.
|
|
||||||
*/
|
|
||||||
int getDownloadProgressPercent();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return current {@link Status} of the {@link Action}.
|
* @return current {@link Status} of the {@link Action}.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ public interface ActionStatus extends TenantAwareBaseEntity {
|
|||||||
*/
|
*/
|
||||||
void addMessage(String message);
|
void addMessage(String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return current {@link Status#DOWNLOAD} progress if known by the update
|
||||||
|
* server.
|
||||||
|
*/
|
||||||
|
int getDownloadProgressPercent();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return list of message entries that can be added to the
|
* @return list of message entries that can be added to the
|
||||||
* {@link ActionStatus}.
|
* {@link ActionStatus}.
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public class TenantUsage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() { // NOSONAR - as this is generated code
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + (int) (actions ^ (actions >>> 32));
|
result = prime * result + (int) (actions ^ (actions >>> 32));
|
||||||
@@ -118,15 +118,14 @@ public class TenantUsage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object obj) { // NOSONAR - as this is generated
|
public boolean equals(final Object obj) {
|
||||||
// code
|
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (getClass() != obj.getClass()) {
|
if (!(obj instanceof TenantUsage)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final TenantUsage other = (TenantUsage) obj;
|
final TenantUsage other = (TenantUsage) obj;
|
||||||
@@ -154,7 +153,7 @@ public class TenantUsage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SystemUsage [tenantName=" + tenantName + ", targets=" + targets + ", artifacts=" + artifacts
|
return "TenantUsage [tenantName=" + tenantName + ", targets=" + targets + ", artifacts=" + artifacts
|
||||||
+ ", actions=" + actions + ", overallArtifactVolumeInBytes=" + overallArtifactVolumeInBytes + "]";
|
+ ", actions=" + actions + ", overallArtifactVolumeInBytes=" + overallArtifactVolumeInBytes + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManage
|
|||||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
|
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
|
||||||
@@ -71,6 +72,8 @@ import org.springframework.transaction.PlatformTransactionManager;
|
|||||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General configuration for hawkBit's Repository.
|
* General configuration for hawkBit's Repository.
|
||||||
*
|
*
|
||||||
@@ -85,6 +88,9 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
|
|||||||
@EnableConfigurationProperties(RepositoryProperties.class)
|
@EnableConfigurationProperties(RepositoryProperties.class)
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||||
|
@Autowired
|
||||||
|
private EventBus eventBus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the {@link SystemSecurityContext} singleton bean which make it
|
* @return the {@link SystemSecurityContext} singleton bean which make it
|
||||||
* accessible in beans which cannot access the service directly,
|
* accessible in beans which cannot access the service directly,
|
||||||
@@ -249,7 +255,9 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public TenantStatsManagement tenantStatsManagement() {
|
public TenantStatsManagement tenantStatsManagement() {
|
||||||
return new JpaTenantStatsManagement();
|
final TenantStatsManagement mgmt = new JpaTenantStatsManagement();
|
||||||
|
eventBus.register(mgmt);
|
||||||
|
return mgmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -451,8 +451,8 @@ public class JpaControllerManagement implements ControllerManagement {
|
|||||||
@Override
|
@Override
|
||||||
@Modifying
|
@Modifying
|
||||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||||
public void addInformationalActionStatus(final ActionStatus statusMessage) {
|
public ActionStatus addInformationalActionStatus(final ActionStatus statusMessage) {
|
||||||
actionStatusRepository.save((JpaActionStatus) statusMessage);
|
return actionStatusRepository.save((JpaActionStatus) statusMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -469,8 +469,9 @@ public class JpaControllerManagement implements ControllerManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void downloadProgressPercent(final long statusId, final int progressPercent) {
|
public void downloadProgress(final Long statusId, final Long requestedBytes, final Long shippedBytesSinceLast,
|
||||||
cacheWriteNotify.downloadProgressPercent(statusId, progressPercent);
|
final Long shippedBytesOverall) {
|
||||||
|
cacheWriteNotify.downloadProgress(statusId, requestedBytes, shippedBytesSinceLast, shippedBytesOverall);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
|||||||
final List<String> tenants = findTenants();
|
final List<String> tenants = findTenants();
|
||||||
|
|
||||||
tenants.forEach(tenant -> tenantAware.runAsTenant(tenant, () -> {
|
tenants.forEach(tenant -> tenantAware.runAsTenant(tenant, () -> {
|
||||||
report.addTenantData(systemStatsManagement.getStatsOfTenant(tenant));
|
report.addTenantData(systemStatsManagement.getStatsOfTenant());
|
||||||
return null;
|
return null;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import java.util.Optional;
|
|||||||
|
|
||||||
import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
||||||
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
|
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
|
||||||
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Isolation;
|
import org.springframework.transaction.annotation.Isolation;
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -35,9 +35,14 @@ public class JpaTenantStatsManagement implements TenantStatsManagement {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ActionRepository actionRepository;
|
private ActionRepository actionRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TenantAware tenantAware;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_UNCOMMITTED)
|
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_UNCOMMITTED)
|
||||||
public TenantUsage getStatsOfTenant(final String tenant) {
|
public TenantUsage getStatsOfTenant() {
|
||||||
|
final String tenant = tenantAware.getCurrentTenant();
|
||||||
|
|
||||||
final TenantUsage result = new TenantUsage(tenant);
|
final TenantUsage result = new TenantUsage(tenant);
|
||||||
|
|
||||||
result.setTargets(targetRepository.count());
|
result.setTargets(targetRepository.count());
|
||||||
|
|||||||
@@ -8,9 +8,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.cache;
|
package org.eclipse.hawkbit.repository.jpa.cache;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent;
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
|
||||||
import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupCreatedEvent;
|
import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
|
||||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
@@ -20,6 +21,7 @@ import org.springframework.cache.CacheManager;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.google.common.eventbus.EventBus;
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.common.math.DoubleMath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An service which combines the functionality for functional use cases to write
|
* An service which combines the functionality for functional use cases to write
|
||||||
@@ -30,10 +32,6 @@ import com.google.common.eventbus.EventBus;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class CacheWriteNotify {
|
public class CacheWriteNotify {
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static final int DOWNLOAD_PROGRESS_MAX = 100;
|
private static final int DOWNLOAD_PROGRESS_MAX = 100;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -46,20 +44,29 @@ public class CacheWriteNotify {
|
|||||||
private TenantAware tenantAware;
|
private TenantAware tenantAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* writes the download progress in percentage into the cache
|
* writes the download progress into the cache
|
||||||
* {@link CacheKeys#DOWNLOAD_PROGRESS_PERCENT} and notifies the
|
* {@link CacheKeys#DOWNLOAD_PROGRESS_PERCENT} and notifies the
|
||||||
* {@link EventBus} with a {@link DownloadProgressEvent}.
|
* {@link EventBus} with a {@link DownloadProgressEvent}.
|
||||||
*
|
*
|
||||||
* @param statusId
|
* @param statusId
|
||||||
* the ID of the {@link ActionStatus}
|
* the ID of the {@link ActionStatus}
|
||||||
* @param progressPercent
|
* @param requestedBytes
|
||||||
* the progress in percentage which must be between 0-100
|
* requested bytes of the request
|
||||||
|
* @param shippedBytesSinceLast
|
||||||
|
* since last event
|
||||||
|
* @param shippedBytesOverall
|
||||||
|
* for the download request
|
||||||
*/
|
*/
|
||||||
public void downloadProgressPercent(final long statusId, final int progressPercent) {
|
public void downloadProgress(final Long statusId, final Long requestedBytes, final Long shippedBytesSinceLast,
|
||||||
|
final Long shippedBytesOverall) {
|
||||||
|
|
||||||
final Cache cache = cacheManager.getCache(Action.class.getName());
|
final Cache cache = cacheManager.getCache(ActionStatus.class.getName());
|
||||||
final String cacheKey = CacheKeys.entitySpecificCacheKey(String.valueOf(statusId),
|
final String cacheKey = CacheKeys.entitySpecificCacheKey(String.valueOf(statusId),
|
||||||
CacheKeys.DOWNLOAD_PROGRESS_PERCENT);
|
CacheKeys.DOWNLOAD_PROGRESS_PERCENT);
|
||||||
|
|
||||||
|
final int progressPercent = DoubleMath.roundToInt(shippedBytesOverall * 100.0 / requestedBytes,
|
||||||
|
RoundingMode.DOWN);
|
||||||
|
|
||||||
if (progressPercent < DOWNLOAD_PROGRESS_MAX) {
|
if (progressPercent < DOWNLOAD_PROGRESS_MAX) {
|
||||||
cache.put(cacheKey, progressPercent);
|
cache.put(cacheKey, progressPercent);
|
||||||
} else {
|
} else {
|
||||||
@@ -69,7 +76,8 @@ public class CacheWriteNotify {
|
|||||||
cache.evict(cacheKey);
|
cache.evict(cacheKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
eventBus.post(new DownloadProgressEvent(tenantAware.getCurrentTenant(), statusId, progressPercent));
|
eventBus.post(new DownloadProgressEvent(tenantAware.getCurrentTenant(), statusId, requestedBytes,
|
||||||
|
shippedBytesSinceLast, shippedBytesOverall));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,10 +27,7 @@ import javax.persistence.NamedEntityGraphs;
|
|||||||
import javax.persistence.NamedSubgraph;
|
import javax.persistence.NamedSubgraph;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.Transient;
|
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.cache.CacheField;
|
|
||||||
import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys;
|
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
@@ -89,13 +86,6 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
@JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout"))
|
@JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout"))
|
||||||
private JpaRollout rollout;
|
private JpaRollout rollout;
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: filled only in {@link Status#DOWNLOAD}.
|
|
||||||
*/
|
|
||||||
@Transient
|
|
||||||
@CacheField(key = CacheKeys.DOWNLOAD_PROGRESS_PERCENT)
|
|
||||||
private int downloadProgressPercent;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DistributionSet getDistributionSet() {
|
public DistributionSet getDistributionSet() {
|
||||||
return distributionSet;
|
return distributionSet;
|
||||||
@@ -120,15 +110,6 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getDownloadProgressPercent() {
|
|
||||||
return downloadProgressPercent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDownloadProgressPercent(final int downloadProgressPercent) {
|
|
||||||
this.downloadProgressPercent = downloadProgressPercent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isActive() {
|
public boolean isActive() {
|
||||||
return active;
|
return active;
|
||||||
|
|||||||
@@ -24,7 +24,10 @@ import javax.persistence.ManyToOne;
|
|||||||
import javax.persistence.NamedAttributeNode;
|
import javax.persistence.NamedAttributeNode;
|
||||||
import javax.persistence.NamedEntityGraph;
|
import javax.persistence.NamedEntityGraph;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.Transient;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.jpa.cache.CacheField;
|
||||||
|
import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||||
@@ -63,6 +66,13 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
|
|||||||
@Column(name = "detail_message", length = 512)
|
@Column(name = "detail_message", length = 512)
|
||||||
private final List<String> messages = new ArrayList<>();
|
private final List<String> messages = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: filled only in {@link Status#DOWNLOAD}.
|
||||||
|
*/
|
||||||
|
@Transient
|
||||||
|
@CacheField(key = CacheKeys.DOWNLOAD_PROGRESS_PERCENT)
|
||||||
|
private int downloadProgressPercent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link ActionStatus} object.
|
* Creates a new {@link ActionStatus} object.
|
||||||
*
|
*
|
||||||
@@ -105,6 +115,11 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
|
|||||||
// JPA default constructor.
|
// JPA default constructor.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDownloadProgressPercent() {
|
||||||
|
return downloadProgressPercent;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getOccurredAt() {
|
public Long getOccurredAt() {
|
||||||
return occurredAt;
|
return occurredAt;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import static org.mockito.Matchers.eq;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent;
|
import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -59,15 +59,14 @@ public class CacheWriteNotifyTest {
|
|||||||
@Test
|
@Test
|
||||||
public void downloadgProgressIsCachedAndEventSent() {
|
public void downloadgProgressIsCachedAndEventSent() {
|
||||||
final long knownStatusId = 1;
|
final long knownStatusId = 1;
|
||||||
final int knownPercentage = 23;
|
|
||||||
|
|
||||||
when(cacheManagerMock.getCache(Action.class.getName())).thenReturn(cacheMock);
|
when(cacheManagerMock.getCache(ActionStatus.class.getName())).thenReturn(cacheMock);
|
||||||
when(tenantAwareMock.getCurrentTenant()).thenReturn("default");
|
when(tenantAwareMock.getCurrentTenant()).thenReturn("default");
|
||||||
|
|
||||||
underTest.downloadProgressPercent(knownStatusId, knownPercentage);
|
underTest.downloadProgress(knownStatusId, 500L, 100L, 100L);
|
||||||
|
|
||||||
verify(cacheManagerMock).getCache(eq(Action.class.getName()));
|
verify(cacheManagerMock).getCache(eq(ActionStatus.class.getName()));
|
||||||
verify(cacheMock).put(knownStatusId + "." + CacheKeys.DOWNLOAD_PROGRESS_PERCENT, knownPercentage);
|
verify(cacheMock).put(knownStatusId + "." + CacheKeys.DOWNLOAD_PROGRESS_PERCENT, 20);
|
||||||
verify(eventBusMock).post(any(DownloadProgressEvent.class));
|
verify(eventBusMock).post(any(DownloadProgressEvent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
|
|
||||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||||
|
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.LocalArtifact;
|
import org.eclipse.hawkbit.repository.model.LocalArtifact;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -87,7 +88,7 @@ public final class RestResourceConversionHelper {
|
|||||||
* @param controllerManagement
|
* @param controllerManagement
|
||||||
* to write progress updates to
|
* to write progress updates to
|
||||||
* @param statusId
|
* @param statusId
|
||||||
* of the UpdateActionStatus
|
* of the {@link ActionStatus}
|
||||||
*
|
*
|
||||||
* @return http code
|
* @return http code
|
||||||
*
|
*
|
||||||
@@ -293,6 +294,7 @@ public final class RestResourceConversionHelper {
|
|||||||
|
|
||||||
long toRead = length;
|
long toRead = length;
|
||||||
boolean toContinue = true;
|
boolean toContinue = true;
|
||||||
|
long shippedSinceLastEvent = 0;
|
||||||
|
|
||||||
while (toContinue) {
|
while (toContinue) {
|
||||||
final int r = from.read(buf);
|
final int r = from.read(buf);
|
||||||
@@ -304,9 +306,11 @@ public final class RestResourceConversionHelper {
|
|||||||
if (toRead > 0) {
|
if (toRead > 0) {
|
||||||
to.write(buf, 0, r);
|
to.write(buf, 0, r);
|
||||||
total += r;
|
total += r;
|
||||||
|
shippedSinceLastEvent += r;
|
||||||
} else {
|
} else {
|
||||||
to.write(buf, 0, (int) toRead + r);
|
to.write(buf, 0, (int) toRead + r);
|
||||||
total += toRead + r;
|
total += toRead + r;
|
||||||
|
shippedSinceLastEvent += toRead + r;
|
||||||
toContinue = false;
|
toContinue = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +320,8 @@ public final class RestResourceConversionHelper {
|
|||||||
// every 10 percent an event
|
// every 10 percent an event
|
||||||
if (newPercent == 100 || newPercent > progressPercent + 10) {
|
if (newPercent == 100 || newPercent > progressPercent + 10) {
|
||||||
progressPercent = newPercent;
|
progressPercent = newPercent;
|
||||||
controllerManagement.downloadProgressPercent(statusId, progressPercent);
|
controllerManagement.downloadProgress(statusId, length, shippedSinceLastEvent, total);
|
||||||
|
shippedSinceLastEvent = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,10 +164,10 @@ public class CreateUpdateSoftwareTypeLayout extends CreateUpdateTypeLayout {
|
|||||||
if (null != selectedTypeTag) {
|
if (null != selectedTypeTag) {
|
||||||
tagDesc.setValue(selectedTypeTag.getDescription());
|
tagDesc.setValue(selectedTypeTag.getDescription());
|
||||||
typeKey.setValue(selectedTypeTag.getKey());
|
typeKey.setValue(selectedTypeTag.getKey());
|
||||||
if (selectedTypeTag.getMaxAssignments() == Integer.MAX_VALUE) {
|
if (selectedTypeTag.getMaxAssignments() == 1) {
|
||||||
assignOptiongroup.setValue(multiAssignStr);
|
|
||||||
} else {
|
|
||||||
assignOptiongroup.setValue(singleAssignStr);
|
assignOptiongroup.setValue(singleAssignStr);
|
||||||
|
} else {
|
||||||
|
assignOptiongroup.setValue(multiAssignStr);
|
||||||
}
|
}
|
||||||
setColorPickerComponentsColor(selectedTypeTag.getColour());
|
setColorPickerComponentsColor(selectedTypeTag.getColour());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user