From b03fa5eec8fe8f5ee48fdc325b80ad9c14a396b9 Mon Sep 17 00:00:00 2001 From: Jonathan Philip Knoblauch Date: Thu, 31 Mar 2016 13:04:21 +0200 Subject: [PATCH] Verify all download URLs generated by SP-server (e.g. DDI and DMF API) - the get artifact request for the DDI API know contains https links - additional there where http links added - section for creating download urls based on patters was moved to hawkbit-core - tests where adapted and extended Signed-off-by: Jonathan Philip Knoblauch --- .../hawkbit/api}/ArtifactUrlHandler.java | 11 +- .../api}/ArtifactUrlHandlerProperties.java | 112 +----------------- .../api}/PropertyBasedArtifactUrlHandler.java | 28 ++--- .../org/eclipse/hawkbit/api/UrlProtocol.java | 11 ++ hawkbit-dmf-amqp/pom.xml | 5 + .../amqp/AmqpMessageDispatcherService.java | 13 +- .../AmqpMessageDispatcherServiceTest.java | 6 +- .../PropertyBasedArtifactUrlHandlerTest.java | 23 +++- hawkbit-rest-resource/pom.xml | 5 + .../controller/DataConversionHelper.java | 36 +++--- .../hawkbit/controller/RootController.java | 10 +- .../controller/DeploymentBaseTest.java | 74 ++++++++++-- 12 files changed, 167 insertions(+), 167 deletions(-) rename {hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util => hawkbit-core/src/main/java/org/eclipse/hawkbit/api}/ArtifactUrlHandler.java (73%) rename {hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util => hawkbit-core/src/main/java/org/eclipse/hawkbit/api}/ArtifactUrlHandlerProperties.java (75%) rename {hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util => hawkbit-core/src/main/java/org/eclipse/hawkbit/api}/PropertyBasedArtifactUrlHandler.java (79%) create mode 100644 hawkbit-core/src/main/java/org/eclipse/hawkbit/api/UrlProtocol.java diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util/ArtifactUrlHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java similarity index 73% rename from hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util/ArtifactUrlHandler.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java index f477da03a..a80551f9e 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util/ArtifactUrlHandler.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandler.java @@ -6,10 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.util; - -import org.eclipse.hawkbit.dmf.json.model.Artifact; -import org.eclipse.hawkbit.repository.model.LocalArtifact; +package org.eclipse.hawkbit.api; /** * Interface declaration of the {@link ArtifactUrlHandler} which generates the @@ -23,13 +20,13 @@ public interface ArtifactUrlHandler { * Returns a generated URL for a given artifact for a specific protocol. * * @param controllerId - * the authentifacted controller id + * the authenticated controller id * @param localArtifact * the artifact to retrieve a URL to * @param protocol * the protocol the URL should be generated * @return an URL for the given artifact in a given protocol */ - String getUrl(String controllerId, LocalArtifact localArtifact, final Artifact.UrlProtocol protocol); - + String getUrl(String controllerId, final Long softwareModuleId, final String filename, final String sha1Hash, + final UrlProtocol protocol); } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util/ArtifactUrlHandlerProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java similarity index 75% rename from hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util/ArtifactUrlHandlerProperties.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java index 91c385fae..33fe8651e 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util/ArtifactUrlHandlerProperties.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java @@ -6,13 +6,13 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.util; +package org.eclipse.hawkbit.api; import org.springframework.boot.context.properties.ConfigurationProperties; /** - * - * + * Artifact handler properties class for holding all supported protocols with + * host, ip, port and download pattern. */ @ConfigurationProperties("hawkbit.artifact.url") public class ArtifactUrlHandlerProperties { @@ -23,23 +23,14 @@ public class ArtifactUrlHandlerProperties { private final Https https = new Https(); private final Coap coap = new Coap(); - /** - * @return the http - */ public Http getHttp() { return http; } - /** - * @return the https - */ public Https getHttps() { return https; } - /** - * @return the coap - */ public Coap getCoap() { return coap; } @@ -66,9 +57,6 @@ public class ArtifactUrlHandlerProperties { /** * Interface for declaring common properties through all supported protocols * pattern. - * - * - * */ public interface ProtocolProperties { /** @@ -94,9 +82,6 @@ public class ArtifactUrlHandlerProperties { /** * Object to hold the properties for the HTTP protocol. - * - * - * */ public static class Http implements ProtocolProperties { private String hostname = LOCALHOST; @@ -108,66 +93,38 @@ public class ArtifactUrlHandlerProperties { */ private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; - /** - * @return the hostname - */ @Override public String getHostname() { return hostname; } - /** - * @param hostname - * the hostname to set - */ public void setHostname(final String hostname) { this.hostname = hostname; } - /** - * @return the ip - */ @Override public String getIp() { return ip; } - /** - * @param ip - * the ip to set - */ public void setIp(final String ip) { this.ip = ip; } - /** - * @return the urlPattern - */ @Override public String getPattern() { return pattern; } - /** - * @param urlPattern - * the urlPattern to set - */ public void setPattern(final String urlPattern) { this.pattern = urlPattern; } - /** - * @return the port - */ @Override public String getPort() { return port; } - /** - * @param port - * the port to set - */ public void setPort(final String port) { this.port = port; } @@ -175,9 +132,6 @@ public class ArtifactUrlHandlerProperties { /** * Object to hold the properties for the HTTP protocol. - * - * - * */ public static class Https implements ProtocolProperties { private String hostname = LOCALHOST; @@ -189,66 +143,38 @@ public class ArtifactUrlHandlerProperties { */ private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; - /** - * @return the hostname - */ @Override public String getHostname() { return hostname; } - /** - * @param hostname - * the hostname to set - */ public void setHostname(final String hostname) { this.hostname = hostname; } - /** - * @return the ip - */ @Override public String getIp() { return ip; } - /** - * @param ip - * the ip to set - */ public void setIp(final String ip) { this.ip = ip; } - /** - * @return the urlPattern - */ @Override public String getPattern() { return pattern; } - /** - * @param urlPattern - * the urlPattern to set - */ public void setPattern(final String urlPattern) { this.pattern = urlPattern; } - /** - * @return the port - */ @Override public String getPort() { return port; } - /** - * @param port - * the port to set - */ public void setPort(final String port) { this.port = port; } @@ -256,9 +182,6 @@ public class ArtifactUrlHandlerProperties { /** * Object to hold the properties for the HTTP protocol. - * - * - * */ public static class Coap implements ProtocolProperties { private String hostname = LOCALHOST; @@ -270,68 +193,41 @@ public class ArtifactUrlHandlerProperties { */ private String pattern = "{protocol}://{ip}:{port}/fw/{tenant}/{targetId}/sha1/{artifactSHA1}"; - /** - * @return the hostname - */ @Override public String getHostname() { return hostname; } - /** - * @param hostname - * the hostname to set - */ public void setHostname(final String hostname) { this.hostname = hostname; } - /** - * @return the ip - */ @Override public String getIp() { return ip; } - /** - * @param ip - * the ip to set - */ public void setIp(final String ip) { this.ip = ip; } - /** - * @return the urlPattern - */ @Override public String getPattern() { return pattern; } - /** - * @param urlPattern - * the urlPattern to set - */ public void setPattern(final String urlPattern) { this.pattern = urlPattern; } - /** - * @return the port - */ @Override public String getPort() { return port; } - /** - * @param port - * the port to set - */ public void setPort(final String port) { this.port = port; } } + } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java similarity index 79% rename from hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandler.java rename to hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java index 8d4cfbc28..174086613 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandler.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java @@ -6,17 +6,15 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.util; +package org.eclipse.hawkbit.api; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.eclipse.hawkbit.dmf.json.model.Artifact; -import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties.ProtocolProperties; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.util.ArtifactUrlHandlerProperties.ProtocolProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.stereotype.Component; @@ -24,8 +22,8 @@ import org.springframework.stereotype.Component; import com.google.common.base.Strings; /** - * - * + * Implementation for ArtifactUrlHandler for creating urls to download resource + * based on pattern. */ @Component @EnableConfigurationProperties(ArtifactUrlHandlerProperties.class) @@ -48,7 +46,9 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { private TenantAware tenantAware; @Override - public String getUrl(final String targetId, final LocalArtifact artifact, final Artifact.UrlProtocol protocol) { + public String getUrl(final String targetId, final Long softwareModuleId, final String filename, + final String sha1Hash, final UrlProtocol protocol) { + final String protocolString = protocol.name().toLowerCase(); final ProtocolProperties properties = urlHandlerProperties.getProperties(protocolString); if (properties == null || properties.getPattern() == null) { @@ -56,8 +56,8 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { } String urlPattern = properties.getPattern(); - final Set> entrySet = getReplaceMap(targetId, artifact, protocolString, properties) - .entrySet(); + final Set> entrySet = getReplaceMap(targetId, softwareModuleId, filename, sha1Hash, + protocolString, properties).entrySet(); for (final Entry entry : entrySet) { if (entry.getKey().equals(PORT_PLACEHOLDER)) { urlPattern = urlPattern.replace(":{" + entry.getKey() + "}", @@ -69,18 +69,18 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { return urlPattern; } - private Map getReplaceMap(final String targetId, final LocalArtifact artifact, - final String protocol, final ProtocolProperties properties) { + private Map getReplaceMap(final String targetId, final Long softwareModuleId, final String filename, + final String sha1Hash, final String protocol, final ProtocolProperties properties) { final Map replaceMap = new HashMap<>(); replaceMap.put(IP_PLACEHOLDER, properties.getIp()); replaceMap.put(HOSTNAME_PLACEHOLDER, properties.getHostname()); - replaceMap.put(ARTIFACT_FILENAME_PLACEHOLDER, artifact.getFilename()); - replaceMap.put(ARTIFACT_SHA1_PLACEHOLDER, artifact.getSha1Hash()); + replaceMap.put(ARTIFACT_FILENAME_PLACEHOLDER, filename); + replaceMap.put(ARTIFACT_SHA1_PLACEHOLDER, sha1Hash); replaceMap.put(PROTOCOL_PLACEHOLDER, protocol); replaceMap.put(PORT_PLACEHOLDER, properties.getPort()); replaceMap.put(TENANT_PLACEHOLDER, tenantAware.getCurrentTenant()); replaceMap.put(TARGET_ID_PLACEHOLDER, targetId); - replaceMap.put(SOFTWARE_MODULE_ID_PLACDEHOLDER, String.valueOf(artifact.getSoftwareModule().getId())); + replaceMap.put(SOFTWARE_MODULE_ID_PLACDEHOLDER, String.valueOf(softwareModuleId)); return replaceMap; } diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/UrlProtocol.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/UrlProtocol.java new file mode 100644 index 000000000..4dd84b7da --- /dev/null +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/UrlProtocol.java @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2011-2016 Bosch Software Innovations GmbH, Germany. All rights reserved. + */ +package org.eclipse.hawkbit.api; + +/** + * Represented the supported protocols for artifact url's. + */ +public enum UrlProtocol { + COAP, HTTP, HTTPS +} diff --git a/hawkbit-dmf-amqp/pom.xml b/hawkbit-dmf-amqp/pom.xml index 2fded8559..127103b91 100644 --- a/hawkbit-dmf-amqp/pom.xml +++ b/hawkbit-dmf-amqp/pom.xml @@ -25,6 +25,11 @@ org.eclipse.hawkbit hawkbit-repository ${project.version} + + + org.eclipse.hawkbit + hawkbit-core + ${project.version} org.eclipse.hawkbit diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java index b9e6fe9da..19e0cbadf 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java @@ -14,6 +14,8 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import org.eclipse.hawkbit.api.ArtifactUrlHandler; +import org.eclipse.hawkbit.api.UrlProtocol; import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey; import org.eclipse.hawkbit.dmf.amqp.api.MessageType; @@ -25,7 +27,6 @@ import org.eclipse.hawkbit.eventbus.EventSubscriber; import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent; import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.model.LocalArtifact; -import org.eclipse.hawkbit.util.ArtifactUrlHandler; import org.eclipse.hawkbit.util.IpUtil; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageProperties; @@ -152,12 +153,16 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { private Artifact convertArtifact(final String targetId, final LocalArtifact localArtifact) { final Artifact artifact = new Artifact(); + artifact.getUrls().put(Artifact.UrlProtocol.COAP, - artifactUrlHandler.getUrl(targetId, localArtifact, Artifact.UrlProtocol.COAP)); + artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), + localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.COAP)); artifact.getUrls().put(Artifact.UrlProtocol.HTTP, - artifactUrlHandler.getUrl(targetId, localArtifact, Artifact.UrlProtocol.HTTP)); + artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), + localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTP)); artifact.getUrls().put(Artifact.UrlProtocol.HTTPS, - artifactUrlHandler.getUrl(targetId, localArtifact, Artifact.UrlProtocol.HTTPS)); + artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(), + localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTPS)); artifact.setFilename(localArtifact.getFilename()); artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), null)); diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java index 46ddd35cc..f2c3d254c 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java @@ -13,6 +13,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; @@ -25,6 +26,7 @@ import java.util.List; import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; import org.eclipse.hawkbit.TestDataUtil; +import org.eclipse.hawkbit.api.ArtifactUrlHandler; import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey; @@ -36,7 +38,6 @@ import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.util.ArtifactUrlHandler; import org.eclipse.hawkbit.util.IpUtil; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -77,7 +78,8 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit amqpMessageDispatcherService.setAmqpSenderService(senderService); final ArtifactUrlHandler artifactUrlHandlerMock = Mockito.mock(ArtifactUrlHandler.class); - when(artifactUrlHandlerMock.getUrl(anyString(), any(), anyObject())).thenReturn("http://mockurl"); + when(artifactUrlHandlerMock.getUrl(anyString(), anyLong(), anyString(), anyString(), anyObject())) + .thenReturn("http://mockurl"); amqpMessageDispatcherService.setArtifactUrlHandler(artifactUrlHandlerMock); diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java index e7ba06d19..bfc560c38 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java @@ -15,7 +15,8 @@ import org.eclipse.hawkbit.AmqpTestConfiguration; import org.eclipse.hawkbit.RepositoryApplicationConfiguration; import org.eclipse.hawkbit.TestConfiguration; import org.eclipse.hawkbit.TestDataUtil; -import org.eclipse.hawkbit.dmf.json.model.Artifact; +import org.eclipse.hawkbit.api.ArtifactUrlHandler; +import org.eclipse.hawkbit.api.UrlProtocol; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; @@ -30,8 +31,7 @@ import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; /** - * - * + * Tests for creating urls to download artifacts. */ @Features("Component Tests - Artifact URL Handler") @Stories("Test to generate the artifact download URL") @@ -45,6 +45,9 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest private TenantAware tenantAware; private LocalArtifact localArtifact; private final String controllerId = "Test"; + private String fileName; + private Long softwareModuleId; + private String sha1Hash; @Before public void setup() { @@ -53,12 +56,18 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest final SoftwareModule module = dsA.getModules().iterator().next(); localArtifact = (LocalArtifact) TestDataUtil.generateArtifacts(artifactManagement, module.getId()).stream() .findAny().get(); + softwareModuleId = localArtifact.getSoftwareModule().getId(); + fileName = localArtifact.getFilename(); + sha1Hash = localArtifact.getSha1Hash(); + } @Test @Description("Tests the generation of http download url.") public void testHttpUrl() { - final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.HTTP); + + final String url = urlHandlerProperties.getUrl(controllerId, softwareModuleId, fileName, sha1Hash, + UrlProtocol.HTTP); assertEquals("http is build incorrect", "http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId + "/softwaremodules/" + localArtifact.getSoftwareModule().getId() + "/artifacts/" @@ -69,7 +78,8 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest @Test @Description("Tests the generation of https download url.") public void testHttpsUrl() { - final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.HTTPS); + final String url = urlHandlerProperties.getUrl(controllerId, softwareModuleId, fileName, sha1Hash, + UrlProtocol.HTTPS); assertEquals("https is build incorrect", "https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId + "/softwaremodules/" + localArtifact.getSoftwareModule().getId() + "/artifacts/" @@ -80,7 +90,8 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest @Test @Description("Tests the generation of coap download url.") public void testCoapUrl() { - final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.COAP); + final String url = urlHandlerProperties.getUrl(controllerId, softwareModuleId, fileName, sha1Hash, + UrlProtocol.COAP); assertEquals("coap is build incorrect", "coap://127.0.0.1:5683/fw/" + tenantAware.getCurrentTenant() + "/" + controllerId + "/sha1/" + localArtifact.getSha1Hash(), url); diff --git a/hawkbit-rest-resource/pom.xml b/hawkbit-rest-resource/pom.xml index 633a1f8cc..0be5d20f5 100644 --- a/hawkbit-rest-resource/pom.xml +++ b/hawkbit-rest-resource/pom.xml @@ -25,6 +25,11 @@ org.eclipse.hawkbit hawkbit-repository ${project.version} + + + org.eclipse.hawkbit + hawkbit-core + ${project.version} org.eclipse.hawkbit diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java index ef4468815..03623abdd 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/DataConversionHelper.java @@ -18,6 +18,8 @@ import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; +import org.eclipse.hawkbit.api.ArtifactUrlHandler; +import org.eclipse.hawkbit.api.UrlProtocol; import org.eclipse.hawkbit.controller.model.Artifact; import org.eclipse.hawkbit.controller.model.Chunk; import org.eclipse.hawkbit.controller.model.Config; @@ -29,27 +31,29 @@ import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactHash; import org.eclipse.hawkbit.tenancy.TenantAware; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.hateoas.Link; import com.google.common.base.Charsets; /** * Utility class for the Controller API. - * - * - * - * */ public final class DataConversionHelper { + @Autowired + ArtifactUrlHandler artifactUrlHandler; + // utility class, private constructor. private DataConversionHelper() { } - static List createChunks(final String targetid, final Action uAction, final TenantAware tenantAware) { - return uAction.getDistributionSet() - .getModules().stream().map(module -> new Chunk(mapChunkLegacyKeys(module.getType().getKey()), - module.getVersion(), module.getName(), createArtifacts(targetid, module, tenantAware))) + static List createChunks(final String targetid, final Action uAction, final TenantAware tenantAware, + final ArtifactUrlHandler artifactUrlHandler) { + return uAction.getDistributionSet().getModules().stream() + .map(module -> new Chunk(mapChunkLegacyKeys(module.getType().getKey()), module.getVersion(), + module.getName(), createArtifacts(targetid, module, tenantAware, artifactUrlHandler))) .collect(Collectors.toList()); } @@ -77,18 +81,22 @@ public final class DataConversionHelper { * @return a list of artifacts or a empty list. Cannot be . */ public static List createArtifacts(final String targetid, - final org.eclipse.hawkbit.repository.model.SoftwareModule module, final TenantAware tenantAware) { + final org.eclipse.hawkbit.repository.model.SoftwareModule module, final TenantAware tenantAware, + final ArtifactUrlHandler artifactUrlHandler) { final List files = new ArrayList<>(); module.getLocalArtifacts().forEach(artifact -> { final Artifact file = new Artifact(); file.setHashes(new ArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash())); file.setFilename(artifact.getFilename()); file.setSize(artifact.getSize()); - - file.add(linkTo(methodOn(RootController.class, tenantAware.getCurrentTenant()).downloadArtifact(targetid, - artifact.getSoftwareModule().getId(), artifact.getFilename(), null, null)).withRel("download")); - file.add(linkTo(methodOn(RootController.class, tenantAware.getCurrentTenant()).downloadArtifactMd5(targetid, - artifact.getSoftwareModule().getId(), artifact.getFilename(), null, null)).withRel("md5sum")); + final String linkHttp = artifactUrlHandler.getUrl(targetid, artifact.getSoftwareModule().getId(), + artifact.getFilename(), artifact.getSha1Hash(), UrlProtocol.HTTP); + final String linkHttps = artifactUrlHandler.getUrl(targetid, artifact.getSoftwareModule().getId(), + artifact.getFilename(), artifact.getSha1Hash(), UrlProtocol.HTTPS); + file.add(new Link(linkHttps).withRel("download")); + file.add(new Link(linkHttps + ".MD5SUM").withRel("md5sum")); + file.add(new Link(linkHttp).withRel("download-http")); + file.add(new Link(linkHttp + ".MD5SUM").withRel("md5sum-http")); files.add(file); }); diff --git a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java index ff1e26f8b..0a668338c 100644 --- a/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java +++ b/hawkbit-rest-resource/src/main/java/org/eclipse/hawkbit/controller/RootController.java @@ -15,6 +15,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import org.eclipse.hawkbit.api.ArtifactUrlHandler; import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; import org.eclipse.hawkbit.cache.CacheWriteNotify; import org.eclipse.hawkbit.controller.model.ActionFeedback; @@ -94,6 +95,9 @@ public class RootController { @Autowired private HawkbitSecurityProperties securityProperties; + @Autowired + private ArtifactUrlHandler artifactUrlHandler; + /** * Returns all artifacts of a given software module and target. * @@ -118,7 +122,8 @@ public class RootController { } - return new ResponseEntity<>(DataConversionHelper.createArtifacts(targetid, softwareModule, tenantAware), + return new ResponseEntity<>( + DataConversionHelper.createArtifacts(targetid, softwareModule, tenantAware, artifactUrlHandler), HttpStatus.OK); } @@ -307,7 +312,8 @@ public class RootController { if (!action.isCancelingOrCanceled()) { - final List chunks = DataConversionHelper.createChunks(targetid, action, tenantAware); + final List chunks = DataConversionHelper.createChunks(targetid, action, tenantAware, + artifactUrlHandler); final HandlingType handlingType = action.isForce() ? HandlingType.FORCED : HandlingType.ATTEMPT; diff --git a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/DeploymentBaseTest.java b/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/DeploymentBaseTest.java index 2b2b7e597..75e0f906a 100644 --- a/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/DeploymentBaseTest.java +++ b/hawkbit-rest-resource/src/test/java/org/eclipse/hawkbit/controller/DeploymentBaseTest.java @@ -170,15 +170,27 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1", equalTo(artifact.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href", + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/softwaremodules/" + + findDistributionSetByAction.findFirstModuleByType(osType).getId() + + "/artifacts/test1.MD5SUM"))) + + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download-http.href", + equalTo("http://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/softwaremodules/" + + findDistributionSetByAction.findFirstModuleByType(osType).getId() + + "/artifacts/test1"))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum-http.href", equalTo("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.MD5SUM"))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].size", equalTo(5 * 1024))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].filename", equalTo("test1.signature"))) @@ -188,11 +200,21 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1", equalTo(artifactSignature.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href", + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/softwaremodules/" + + findDistributionSetByAction.findFirstModuleByType(osType).getId() + + "/artifacts/test1.signature.MD5SUM"))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download-http.href", + equalTo("http://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/softwaremodules/" + + findDistributionSetByAction.findFirstModuleByType(osType).getId() + + "/artifacts/test1.signature"))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum-http.href", equalTo("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() @@ -293,12 +315,12 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1", equalTo(artifact.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.MD5SUM"))) @@ -311,11 +333,21 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1", equalTo(artifactSignature.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href", + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/softwaremodules/" + + findDistributionSetByAction.findFirstModuleByType(osType).getId() + + "/artifacts/test1.signature.MD5SUM"))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download-http.href", + equalTo("http://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/softwaremodules/" + + findDistributionSetByAction.findFirstModuleByType(osType).getId() + + "/artifacts/test1.signature"))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum-http.href", equalTo("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() @@ -409,15 +441,25 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].filename", equalTo("test1"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.md5", equalTo(artifact.getMd5Hash()))) - .andExpect( - jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1", - equalTo(artifact.getSha1Hash()))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1", + equalTo(artifact.getSha1Hash()))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href", + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/softwaremodules/" + + findDistributionSetByAction.findFirstModuleByType(osType).getId() + + "/artifacts/test1.MD5SUM"))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download-http.href", + equalTo("http://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/softwaremodules/" + + findDistributionSetByAction.findFirstModuleByType(osType).getId() + + "/artifacts/test1"))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum-http.href", equalTo("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() @@ -431,15 +473,27 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB { jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1", equalTo(artifactSignature.getSha1Hash()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href", - equalTo("http://localhost/" + tenantAware.getCurrentTenant() + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href", + equalTo("https://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/softwaremodules/" + + findDistributionSetByAction.findFirstModuleByType(osType).getId() + + "/artifacts/test1.signature.MD5SUM"))) + + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download-http.href", + equalTo("http://localhost/" + tenantAware.getCurrentTenant() + + "/controller/v1/4712/softwaremodules/" + + findDistributionSetByAction.findFirstModuleByType(osType).getId() + + "/artifacts/test1.signature"))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum-http.href", equalTo("http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/softwaremodules/" + findDistributionSetByAction.findFirstModuleByType(osType).getId() + "/artifacts/test1.signature.MD5SUM"))) + .andExpect(jsonPath("$deployment.chunks[?(@.part==bApp)][0].version", equalTo(ds.findFirstModuleByType(appType).getVersion()))) .andExpect(jsonPath("$deployment.chunks[?(@.part==bApp)][0].name",