From 0759fd80b0f9200672ce8b8b9281a08b3f10a826 Mon Sep 17 00:00:00 2001 From: Shruthi Manavalli Ramanna Date: Fri, 2 Jun 2023 19:09:31 +0200 Subject: [PATCH] Added support for cdn download url for mgmt API and tests Signed-off-by: Shruthi Manavalli Ramanna --- .../hawkbit-artifactdl-defaults.properties | 9 +++++- .../java/org/eclipse/hawkbit/api/ApiType.java | 7 ++++- .../api/ArtifactUrlHandlerProperties.java | 4 +-- .../api/PropertyBasedArtifactUrlHandler.java | 8 +++-- .../rsql/RSQLTargetFilterQueryFieldsTest.java | 2 +- .../hawkbit-test-defaults.properties | 7 +++++ .../mgmt/rest/api/MgmtRestConstants.java | 6 ++++ .../rest/api/MgmtSoftwareModuleRestApi.java | 7 +++-- .../resource/MgmtSoftwareModuleMapper.java | 19 +++++++++++- .../resource/MgmtSoftwareModuleResource.java | 26 +++++++++++++--- .../MgmtSoftwareModuleResourceTest.java | 31 +++++++++++++++++++ .../application-cloudsandbox.properties | 5 +++ 12 files changed, 115 insertions(+), 16 deletions(-) diff --git a/hawkbit-autoconfigure/src/main/resources/hawkbit-artifactdl-defaults.properties b/hawkbit-autoconfigure/src/main/resources/hawkbit-artifactdl-defaults.properties index c2696d679..9c84f916d 100644 --- a/hawkbit-autoconfigure/src/main/resources/hawkbit-artifactdl-defaults.properties +++ b/hawkbit-autoconfigure/src/main/resources/hawkbit-artifactdl-defaults.properties @@ -21,4 +21,11 @@ hawkbit.artifact.url.protocols.md5sum-http.hostname=${hawkbit.artifact.url.proto hawkbit.artifact.url.protocols.md5sum-http.ip=${hawkbit.artifact.url.protocols.download-http.ip} hawkbit.artifact.url.protocols.md5sum-http.port=${hawkbit.artifact.url.protocols.download-http.port} hawkbit.artifact.url.protocols.md5sum-http.supports=DDI -hawkbit.artifact.url.protocols.md5sum-http.ref=${hawkbit.artifact.url.protocols.download-http.ref}.MD5SUM \ No newline at end of file +hawkbit.artifact.url.protocols.md5sum-http.ref=${hawkbit.artifact.url.protocols.download-http.ref}.MD5SUM +hawkbit.artifact.url.protocols.download-cdn-http.rel=cdndownload-http +hawkbit.artifact.url.protocols.download-cdn-http.hostname=localhost +hawkbit.artifact.url.protocols.download-cdn-http.ip=127.0.0.1 +hawkbit.artifact.url.protocols.download-cdn-http.protocol=http +hawkbit.artifact.url.protocols.download-cdn-http.port=8080 +hawkbit.artifact.url.protocols.download-cdn-http.supports=MGMT +hawkbit.artifact.url.protocols.download-cdn-http.ref={protocol}://{hostnameRequest}:{portRequest}/rest/v1/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName} \ No newline at end of file diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ApiType.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ApiType.java index e683b420b..017e3edb9 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ApiType.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ApiType.java @@ -22,5 +22,10 @@ public enum ApiType { /** * Support for Direct Device Integration API. */ - DDI + DDI, + + /** + * Support for Management API. + */ + MGMT } diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java index 4dec09e7b..115a86b22 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java @@ -54,7 +54,7 @@ public class ArtifactUrlHandlerProperties { * artifactFileName,artifactSHA1, * artifactIdBase62,artifactId,tenant,softwareModuleId, * softwareModuleIdBase62. - * + * * The update server itself supports */ private String ref = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; @@ -84,7 +84,7 @@ public class ArtifactUrlHandlerProperties { /** * Support for the following hawkBit API. */ - private List supports = Arrays.asList(ApiType.DDI, ApiType.DMF); + private List supports = Arrays.asList(ApiType.DDI, ApiType.DMF, ApiType.MGMT); public boolean isEnabled() { return enabled; diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java index 4b02c9efd..de9729954 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java @@ -104,7 +104,9 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { urlPattern = urlPattern.replace(":{" + entry.getKey() + "}", StringUtils.isEmpty(entry.getValue()) ? "" : (":" + entry.getValue())); } else { - urlPattern = urlPattern.replace("{" + entry.getKey() + "}", entry.getValue()); + if(entry.getValue() != null) { + urlPattern = urlPattern.replace("{" + entry.getKey() + "}", entry.getValue()); + } } } return urlPattern; @@ -135,7 +137,9 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { replaceMap.put(TENANT_ID_BASE62_PLACEHOLDER, Base62Util.fromBase10(placeholder.getTenantId())); replaceMap.put(CONTROLLER_ID_PLACEHOLDER, placeholder.getControllerId()); replaceMap.put(TARGET_ID_BASE10_PLACEHOLDER, String.valueOf(placeholder.getTargetId())); - replaceMap.put(TARGET_ID_BASE62_PLACEHOLDER, Base62Util.fromBase10(placeholder.getTargetId())); + if(placeholder.getTargetId() != null) { + replaceMap.put(TARGET_ID_BASE62_PLACEHOLDER, Base62Util.fromBase10(placeholder.getTargetId())); + } replaceMap.put(ARTIFACT_ID_BASE62_PLACEHOLDER, Base62Util.fromBase10(placeholder.getSoftwareData().getArtifactId())); replaceMap.put(ARTIFACT_ID_BASE10_PLACEHOLDER, String.valueOf(placeholder.getSoftwareData().getArtifactId())); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFilterQueryFieldsTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFilterQueryFieldsTest.java index f8c93920b..26ddbc8d4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFilterQueryFieldsTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFilterQueryFieldsTest.java @@ -34,7 +34,7 @@ public class RSQLTargetFilterQueryFieldsTest extends AbstractJpaIntegrationTest private TargetFilterQuery filter2; @BeforeEach - public void setupBeforeTest() throws InterruptedException { + public void setupBeforeTest() { final String filterName1 = "filter_a"; final String filterName2 = "filter_b"; final String filterName3 = "filter_c"; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/resources/hawkbit-test-defaults.properties b/hawkbit-repository/hawkbit-repository-test/src/main/resources/hawkbit-test-defaults.properties index 161e23204..c1a03b2e1 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/resources/hawkbit-test-defaults.properties +++ b/hawkbit-repository/hawkbit-repository-test/src/main/resources/hawkbit-test-defaults.properties @@ -51,6 +51,13 @@ hawkbit.artifact.url.protocols.md5sum-http.ip=${hawkbit.artifact.url.protocols.d hawkbit.artifact.url.protocols.md5sum-http.port=${hawkbit.artifact.url.protocols.download-http.port} hawkbit.artifact.url.protocols.md5sum-http.supports=DDI hawkbit.artifact.url.protocols.md5sum-http.ref=${hawkbit.artifact.url.protocols.download-http.ref}.MD5SUM +hawkbit.artifact.url.protocols.download-cdn-http.rel=cdndownload-http +hawkbit.artifact.url.protocols.download-cdn-http.hostname=localhost +hawkbit.artifact.url.protocols.download-cdn-http.ip=127.0.0.1 +hawkbit.artifact.url.protocols.download-cdn-http.protocol=http +hawkbit.artifact.url.protocols.download-cdn-http.port=8080 +hawkbit.artifact.url.protocols.download-cdn-http.supports=MGMT +hawkbit.artifact.url.protocols.download-cdn-http.ref={protocol}://{hostnameRequest}:{portRequest}/rest/v1/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName} ## Download URL Generation - END # Quota - START diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java index 009eb5b1d..83b26e132 100644 --- a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java @@ -271,6 +271,12 @@ public final class MgmtRestConstants { */ public static final String AUTH_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/userinfo"; + /** + * The artifact download URL type + */ + public static final String ARTIFACT_DOWNLOAD_URL_TYPE = "downloadurltype"; + + // constant class, private constructor. private MgmtRestConstants() { diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java index f6746474b..efc1f280d 100644 --- a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtSoftwareModuleRestApi.java @@ -98,9 +98,10 @@ public interface MgmtSoftwareModuleRestApi { @GetMapping(value = MgmtRestConstants.SOFTWAREMODULE_V1_REQUEST_MAPPING + "/{softwareModuleId}/artifacts/{artifactId}", produces = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }) - @ResponseBody - ResponseEntity getArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, - @PathVariable("artifactId") final Long artifactId); + @ResponseBody ResponseEntity getArtifact( + @PathVariable("softwareModuleId") final Long softwareModuleId, + @PathVariable("artifactId") final Long artifactId, + @RequestParam(value = MgmtRestConstants.ARTIFACT_DOWNLOAD_URL_TYPE, required = false) final String artifactDownloadUrlType); /** * Handles the DELETE request for a single SoftwareModule. diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java index 7b1903430..37f65d8a0 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java @@ -16,6 +16,10 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import org.eclipse.hawkbit.api.ApiType; +import org.eclipse.hawkbit.api.ArtifactUrl; +import org.eclipse.hawkbit.api.ArtifactUrlHandler; +import org.eclipse.hawkbit.api.URLPlaceholder; import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact; import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifactHash; import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule; @@ -25,12 +29,14 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi; import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi; import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate; import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; import org.eclipse.hawkbit.rest.data.ResponseList; +import org.springframework.hateoas.Link; /** * A mapper which maps repository model to RESTful model representation and @@ -143,7 +149,7 @@ public final class MgmtSoftwareModuleMapper { MgmtRestModelMapper.mapBaseToBase(artifactRest, artifact); artifactRest.add(linkTo(methodOn(MgmtSoftwareModuleRestApi.class) - .getArtifact(artifact.getSoftwareModule().getId(), artifact.getId())).withSelfRel().expand()); + .getArtifact(artifact.getSoftwareModule().getId(), artifact.getId(), null)).withSelfRel().expand()); return artifactRest; } @@ -155,6 +161,17 @@ public final class MgmtSoftwareModuleMapper { .expand()); } + static void addLinks(final Artifact artifact, final MgmtArtifact response, + final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement) { + + List urls = artifactUrlHandler.getUrls( + new URLPlaceholder(systemManagement.getTenantMetadata().getTenant(), + systemManagement.getTenantMetadata().getId(), null, null, + new URLPlaceholder.SoftwareData(artifact.getSoftwareModule().getId(), artifact.getFilename(), + artifact.getId(), artifact.getSha1Hash())), ApiType.MGMT, null); + response.add(Link.of(urls.get(0).getRef()).withRel("cdn-download").expand()); + } + static List artifactsToResponse(final Collection artifacts) { if (artifacts == null) { return Collections.emptyList(); diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java index d7b0682dd..55200ee23 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java @@ -15,6 +15,7 @@ import java.util.Collection; import java.util.List; import java.util.Optional; +import org.eclipse.hawkbit.api.ArtifactUrlHandler; import org.eclipse.hawkbit.mgmt.json.model.PagedList; import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact; import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule; @@ -29,6 +30,7 @@ import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; import org.eclipse.hawkbit.repository.SoftwareModuleManagement; import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement; +import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.ArtifactUpload; @@ -68,13 +70,21 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi { private final SoftwareModuleTypeManagement softwareModuleTypeManagement; + private final ArtifactUrlHandler artifactUrlHandler; + + private final SystemManagement systemManagement; + private final EntityFactory entityFactory; MgmtSoftwareModuleResource(final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareModuleManagement, - final SoftwareModuleTypeManagement softwareModuleTypeManagement, final EntityFactory entityFactory) { + final SoftwareModuleTypeManagement softwareModuleTypeManagement, + final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement, + final EntityFactory entityFactory) { this.artifactManagement = artifactManagement; this.softwareModuleManagement = softwareModuleManagement; this.softwareModuleTypeManagement = softwareModuleTypeManagement; + this.artifactUrlHandler = artifactUrlHandler; + this.systemManagement = systemManagement; this.entityFactory = entityFactory; } @@ -125,15 +135,21 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi { // subroutine @SuppressWarnings("squid:S3655") public ResponseEntity getArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, - @PathVariable("artifactId") final Long artifactId) { + @PathVariable("artifactId") final Long artifactId, + @RequestParam(value = MgmtRestConstants.ARTIFACT_DOWNLOAD_URL_TYPE, required = false) final String artifactDownloadUrlType) { final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId); - final MgmtArtifact reponse = MgmtSoftwareModuleMapper.toResponse(module.getArtifact(artifactId).get()); + final MgmtArtifact response = MgmtSoftwareModuleMapper.toResponse(module.getArtifact(artifactId).get()); if (!module.isDeleted()) { - MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), reponse); + if(artifactDownloadUrlType == null || artifactDownloadUrlType == "default") { + MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), response); + } else { + MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), response, artifactUrlHandler, + systemManagement); + } } - return ResponseEntity.ok(reponse); + return ResponseEntity.ok(response); } @Override diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java index a8f2a12c6..69cb7c34c 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java @@ -592,6 +592,37 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes "http://localhost/rest/v1/softwaremodules/" + sm.getId() + "/artifacts/" + artifact.getId()))); } + @Test + @Description("Verifies the listing of one defined artifact assigned to a given software module. That includes the artifact metadata and cdn download links.") + void getArtifactWithCdnDownloadUrl() throws Exception { + // prepare data for test + final SoftwareModule sm = testdataFactory.createSoftwareModuleOs(); + + final int artifactSize = 5 * 1024; + final byte random[] = randomBytes(artifactSize); + + final Artifact artifact = artifactManagement.create( + new ArtifactUpload(new ByteArrayInputStream(random), sm.getId(), "file1", false, artifactSize)); + + // perform test + mvc.perform(get("/rest/v1/softwaremodules/{smId}/artifacts/{artId}?downloadurltype=cdn", sm.getId(), artifact.getId()).accept( + MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultPrinter.print()) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.id", equalTo(artifact.getId().intValue()))) + .andExpect(jsonPath("$.size", equalTo(random.length))) + .andExpect(jsonPath("$.hashes.md5", equalTo(artifact.getMd5Hash()))) + .andExpect(jsonPath("$.hashes.sha1", equalTo(artifact.getSha1Hash()))) + .andExpect(jsonPath("$.hashes.sha256", equalTo(artifact.getSha256Hash()))) + .andExpect(jsonPath("$.providedFilename", equalTo("file1"))) + .andExpect(jsonPath("$._links.cdn-download.href", + equalTo("http://localhost:8080/rest/v1/softwaremodules/" + sm.getId() + "/artifacts/" + + artifact.getFilename()))) + .andExpect(jsonPath("$._links.self.href", equalTo( + "http://localhost/rest/v1/softwaremodules/" + sm.getId() + "/artifacts/" + artifact.getId()))); + } + @Test @Description("Verifies the listing of an artifact that belongs to a soft deleted software module.") void getArtifactSoftDeleted() throws Exception { diff --git a/hawkbit-runtime/hawkbit-update-server/src/main/resources/application-cloudsandbox.properties b/hawkbit-runtime/hawkbit-update-server/src/main/resources/application-cloudsandbox.properties index bf28ee36c..260d33add 100644 --- a/hawkbit-runtime/hawkbit-update-server/src/main/resources/application-cloudsandbox.properties +++ b/hawkbit-runtime/hawkbit-update-server/src/main/resources/application-cloudsandbox.properties @@ -19,6 +19,11 @@ hawkbit.artifact.url.protocols.download-http.protocol=https hawkbit.artifact.url.protocols.download-http.supports=DMF,DDI hawkbit.artifact.url.protocols.download-http.hostname=hawkbit.eclipse.org hawkbit.artifact.url.protocols.download-http.ref={protocol}://{hostname}/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName} +hawkbit.artifact.url.protocols.download-cdn-http.rel=cdndownload-http +hawkbit.artifact.url.protocols.download-cdn-http.protocol=https +hawkbit.artifact.url.protocols.download-cdn-http.supports=MGMT +hawkbit.artifact.url.protocols.download-cdn-http.hostname=hawkbit.eclipse.org +hawkbit.artifact.url.protocols.download-cdn-http.ref={protocol}://{hostnameRequest}:{portRequest}/rest/v1/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName} hawkbit.artifact.url.protocols.md5sum-http.rel=md5sum-http hawkbit.artifact.url.protocols.md5sum-http.protocol=${hawkbit.artifact.url.protocols.download-http.protocol} hawkbit.artifact.url.protocols.md5sum-http.supports=DDI