guardBean() {
+ if (!sslEnabled) {
+ throw new ServiceConfigurationError("HawkBit Configuration Manager only supports SECURE mode. Please set server.ssl.enabled to true in the application.properties file.");
+ }
+
+ return Optional.empty();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/Initialization.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/Initialization.java
new file mode 100644
index 000000000..9cd8e20f0
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/Initialization.java
@@ -0,0 +1,114 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr;
+
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.Base64;
+import java.util.Collections;
+
+import javax.annotation.PreDestroy;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import eu.arrowhead.core.hbconfmgr.arrowhead.ArrowheadServiceRegistryClient;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.request.ServiceRegistryRequestDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.request.SystemRequestDTO;
+import eu.arrowhead.core.hbconfmgr.hawkbit.HawkbitDmfConsumer;
+import eu.arrowhead.core.hbconfmgr.properties.SystemProperties;
+import lombok.extern.log4j.Log4j2;
+
+/**
+ * This class runs during the startup of the configuration system. It contains
+ * all logic for initialization, like the registration of the configuration
+ * system in Arrowhead.
+ */
+@Log4j2
+@Component
+public class Initialization implements ApplicationRunner {
+
+ private final HawkbitDmfConsumer hawkbitDmfConsumer;
+ private final ArrowheadServiceRegistryClient arrowheadServiceRegistryClient;
+ private final SystemProperties systemProperties;
+ private final PublicKey publicKey;
+
+ @Autowired
+ public Initialization(final ArrowheadServiceRegistryClient arrowheadServiceRegistryClient, final HawkbitDmfConsumer hawkbitDmfConsumer, final SystemProperties systemProperties, final PublicKey publicKey) {
+ this.arrowheadServiceRegistryClient = arrowheadServiceRegistryClient;
+ this.hawkbitDmfConsumer = hawkbitDmfConsumer;
+ this.systemProperties = systemProperties;
+ this.publicKey = publicKey;
+ }
+
+ @Override
+ public void run(final ApplicationArguments args) throws Exception {
+ registerOwnSystemInArrowhead();
+ connectToHawkBit();
+ log.info("Arrowhead HawkBit Configuration Manager initialization done.");
+ }
+
+ @PreDestroy
+ public void destroy() {
+ try {
+ this.arrowheadServiceRegistryClient.unregisterService(this.systemProperties.getProvidedServiceDefinition(), this.systemProperties.getName(), this.systemProperties.getAddress(), this.systemProperties.getPort(),
+ this.systemProperties.getProvidedServiceUri());
+ } catch (final WebClientResponseException e) {
+ log.error("Error during unregistration of own system in Arrowhead", e);
+ }
+ }
+
+ private void registerOwnSystemInArrowhead() {
+ final String publicKeyString = Base64.getEncoder().encodeToString(this.publicKey.getEncoded());
+
+ final ServiceRegistryRequestDTO requestDTO = ServiceRegistryRequestDTO.builder()
+ .serviceDefinition(this.systemProperties.getProvidedServiceDefinition())
+ .providerSystem(SystemRequestDTO.builder()
+ .systemName(this.systemProperties.getName())
+ .address(this.systemProperties.getAddress())
+ .port(this.systemProperties.getPort())
+ .authenticationInfo(publicKeyString)
+ .build())
+ .serviceUri(this.systemProperties.getProvidedServiceUri())
+ .secure(ServiceRegistryRequestDTO.SecurityLevel.TOKEN)
+ .version(this.systemProperties.getProvidedServiceVersion())
+ .interfaces(Collections.singletonList(this.systemProperties.getProvidedServiceInterface()))
+ .build();
+
+ try {
+ log.info("Registering own system in Arrowhead");
+ this.arrowheadServiceRegistryClient.registerService(requestDTO);
+ } catch (final WebClientResponseException e) {
+ if (HttpStatus.BAD_REQUEST.equals(e.getStatusCode())) {
+ log.warn("Own system is already registered in Arrowhead");
+ this.arrowheadServiceRegistryClient.unregisterService(this.systemProperties.getProvidedServiceDefinition(), this.systemProperties.getName(), this.systemProperties.getAddress(), this.systemProperties.getPort(),
+ this.systemProperties.getProvidedServiceUri());
+ this.arrowheadServiceRegistryClient.registerService(requestDTO);
+ } else {
+ log.error("Error during registration of own system in Arrowhead", e);
+ }
+ } catch (final Exception e) {
+ log.error("Error during registration of own system in Arrowhead", e);
+ }
+ }
+
+ private void connectToHawkBit() {
+ try {
+ this.hawkbitDmfConsumer.subscribeToDownloadEvents();
+ } catch (final IOException e) {
+ log.error("Could not subscribe to Hawkbit DMF API");
+ }
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/SSLProperties.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/SSLProperties.java
new file mode 100644
index 000000000..97c5fca9e
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/SSLProperties.java
@@ -0,0 +1,117 @@
+/********************************************************************************
+ * Copyright (c) 2021 AITIA
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * AITIA - implementation
+ * Arrowhead Consortia - conceptualization
+ ********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.stereotype.Component;
+
+@Component
+@DependsOn(Constants.GUARD_BEAN)
+public class SSLProperties {
+
+ //=================================================================================================
+ // members
+
+ @Value(Constants.SSL_ENABLED)
+ private boolean sslEnabled;
+
+ @Value(Constants.KEYSTORE_TYPE)
+ private String keyStoreType;
+
+ @Value(Constants.KEYSTORE_PATH)
+ private String keyStorePath;
+ private Resource keyStore;
+
+ @Value(Constants.KEYSTORE_PASSWORD)
+ private String keyStorePassword;
+
+ @Value(Constants.KEY_ALIAS)
+ private String keyAlias;
+
+ @Value(Constants.KEY_PASSWORD)
+ private String keyPassword;
+
+ @Value(Constants.TRUSTSTORE_PATH)
+ private String trustStorePath;
+ private Resource trustStore;
+
+ @Value(Constants.TRUSTSTORE_PASSWORD)
+ private String trustStorePassword;
+
+ @Autowired
+ private ResourceLoader resourceLoader;
+
+ //=================================================================================================
+ // methods
+
+ //-------------------------------------------------------------------------------------------------
+ public boolean isSslEnabled() { return sslEnabled; }
+ public String getKeyStoreType() { return keyStoreType; }
+ public Resource getKeyStore() { return keyStore; }
+ public String getKeyStorePassword() { return keyStorePassword; }
+ public String getKeyAlias() { return keyAlias; }
+ public String getKeyPassword() { return keyPassword; }
+ public Resource getTrustStore() { return trustStore; }
+ public String getTrustStorePassword() { return trustStorePassword; }
+
+ //-------------------------------------------------------------------------------------------------
+ @PostConstruct
+ private void validate() {
+ if (sslEnabled) {
+ if (isEmpty(keyStoreType)) {
+ throw new RuntimeException("keyStoreType is missing");
+ }
+
+ if (isEmpty(keyStorePath)) {
+ throw new RuntimeException("keyStorePath is missing");
+ } else {
+ keyStore = resourceLoader.getResource(keyStorePath);
+ }
+
+ if (isEmpty(keyStorePassword)) {
+ throw new RuntimeException("keyStorePassword is missing");
+ }
+
+ if (isEmpty(keyAlias)) {
+ throw new RuntimeException("keyAlias is missing");
+ }
+
+ if (isEmpty(keyPassword)) {
+ throw new RuntimeException("keyPassword is missing");
+ }
+
+ if (isEmpty(trustStorePath)) {
+ throw new RuntimeException("trustStorePath is missing");
+ } else {
+ trustStore = resourceLoader.getResource(trustStorePath);
+ }
+
+ if (isEmpty(trustStorePassword)) {
+ throw new RuntimeException("trustStorePassword is missing");
+ }
+ }
+ }
+
+ //-------------------------------------------------------------------------------------------------
+ private boolean isEmpty(final String str) {
+ return str == null || str.trim().isEmpty();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadAuthorizationSystemClient.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadAuthorizationSystemClient.java
new file mode 100644
index 000000000..8b73f8d37
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadAuthorizationSystemClient.java
@@ -0,0 +1,99 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead;
+
+import org.springframework.http.client.reactive.ReactorClientHttpConnector;
+import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.netty.handler.ssl.SslContext;
+import lombok.extern.log4j.Log4j2;
+import reactor.netty.http.client.HttpClient;
+
+
+/**
+ * Client class to directly interact with the arrowhead authorization system.
+ * Used solely to request its public key for JWT validation.
+ */
+@Log4j2
+public class ArrowheadAuthorizationSystemClient {
+
+ private static final String URI_PUBLIC_KEY = "/authorization/publickey";
+
+ private final WebClient webClient;
+ private final String baseUrl;
+
+ /**
+ * Initializes a new rest client to communicate with the Arrowhead Authorization System.
+ * Insecure (HTTP) and secure (HTTPS) communication is supported, depending on the baseUrl.
+ *
+ * @param baseUrl specifies the base url where arrowhead is available
+ */
+ public ArrowheadAuthorizationSystemClient(final String baseUrl) {
+ log.debug("Initialize ArrowheadAuthorizationSystemClient with baseUrl {}", baseUrl);
+
+ this.webClient = WebClient.create(baseUrl);
+ this.baseUrl = baseUrl;
+ }
+
+ /**
+ * Initializes a new rest client to communicate with the Arrowhead Authorization System with customized SSL
+ * handling. Insecure (HTTP) and secure (HTTPS) communication is supported, depending on the baseUrl.
+ *
+ * @param baseUrl specifies the base url where arrowhead is available
+ * @param sslContext specifies the ssl context the web client should use
+ */
+ public ArrowheadAuthorizationSystemClient(final String baseUrl, final SslContext sslContext) {
+ log.debug("Initialize ArrowheadAuthorizationSystemClient with baseUrl {} and customized sslContext", baseUrl);
+
+ final HttpClient httpClient = HttpClient.create()
+ .secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
+ this.webClient = WebClient.builder()
+ .baseUrl(baseUrl)
+ .clientConnector(new ReactorClientHttpConnector(httpClient))
+ .build();
+ this.baseUrl = baseUrl;
+ }
+
+ /**
+ * Returns the public key of the Authorization core service as a (Base64 encoded) text.
+ * This service is necessary for providers if they want to utilize the token based security.
+ * A more detailed description of this REST endpoint can be found in Github under the
+ * client endpoint description for
+ * getting the public key.
+ *
+ * @return a string containing the (Base64 encoded) public key
+ * @throws WebClientResponseException if the status code is 4xx or 5xx
+ */
+ public String getPublicKey() throws WebClientResponseException {
+ log.debug("Start HTTP GET request against {} on uri: {}", baseUrl, URI_PUBLIC_KEY);
+
+ final String key = this.webClient
+ .get()
+ .uri(URI_PUBLIC_KEY)
+ .retrieve()
+ .bodyToMono(String.class)
+ .doOnNext(response -> log.debug("Finished HTTP GET request with response: {}", response))
+ .block();
+
+ try {
+ final ObjectMapper mapper = new ObjectMapper();
+ return mapper.readValue(key, String.class);
+ } catch (final JsonProcessingException e) {
+ log.error("Invalid authorization public key", e);
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadServiceRegistryClient.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadServiceRegistryClient.java
new file mode 100644
index 000000000..18d01d13a
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadServiceRegistryClient.java
@@ -0,0 +1,180 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead;
+
+import java.util.Optional;
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.client.reactive.ReactorClientHttpConnector;
+import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.request.ServiceQueryFormDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.request.ServiceRegistryRequestDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.ServiceQueryResultDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.ServiceRegistryResponseDTO;
+import io.netty.handler.ssl.SslContext;
+import lombok.extern.log4j.Log4j2;
+import reactor.netty.http.client.HttpClient;
+
+
+/**
+ * Client class to establish a connection with the Arrowhead Service Registry REST API and transmit requests.
+ */
+@Log4j2
+public class ArrowheadServiceRegistryClient {
+
+ private static final String URI_REGISTER_SERVICE = "/serviceregistry/register";
+ private static final String URI_UNREGISTER_SERVICE = "/serviceregistry/unregister";
+ private static final String URI_QUERY_SERVICE = "/serviceregistry/query";
+
+ private static final String UNREGISTER_REQUEST_PARAM_SYSTEM_NAME = "system_name";
+ private static final String UNREGISTER_REQUEST_PARAM_ADDRESS = "address";
+ private static final String UNREGISTER_REQUEST_PARAM_PORT = "port";
+ private static final String UNREGISTER_REQUEST_PARAM_SERVICE_DEFINITION = "service_definition";
+ private static final String UNREGISTER_REQUEST_PARAM_SERVICE_URI = "service_uri";
+
+ private static final int SYSTEM_PORT_RANGE_MIN = 0;
+ private static final int SYSTEM_PORT_RANGE_MAX = 65535;
+
+ private final WebClient webClient;
+ private final String baseUrl;
+
+ /**
+ * Initializes a new rest client to communicate with the Arrowhead Service Registry.
+ * Insecure (HTTP) and secure (HTTPS) communication is supported, depending on the baseUrl.
+ *
+ * @param baseUrl specifies the base url where arrowhead is available
+ */
+ public ArrowheadServiceRegistryClient(final String baseUrl) {
+ log.debug("Initialize ArrowheadServiceRegistryClient with baseUrl {}", baseUrl);
+
+ this.webClient = WebClient.create(baseUrl);
+ this.baseUrl = baseUrl;
+ }
+
+ /**
+ * Initializes a new rest client to communicate with the Arrowhead Service Registry with customized SSL handling.
+ * Insecure (HTTP) and secure (HTTPS) communication is supported, depending on the baseUrl.
+ *
+ * @param baseUrl specifies the base url where arrowhead is available
+ * @param sslContext specifies the ssl context the web client should use
+ */
+ public ArrowheadServiceRegistryClient(final String baseUrl, final SslContext sslContext) {
+ log.debug("Initialize ArrowheadServiceRegistryClient with baseUrl {} and customized sslContext", baseUrl);
+
+ final HttpClient httpClient = HttpClient.create()
+ .secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
+ this.webClient = WebClient.builder()
+ .baseUrl(baseUrl)
+ .clientConnector(new ReactorClientHttpConnector(httpClient))
+ .build();
+ this.baseUrl = baseUrl;
+ }
+
+ /**
+ * Registers a service. A provider is allowed to register only its own services.
+ * It means that provider system name and certificate common name must match for successful registration.
+ * A more detailed description of this REST endpoint can be found in Github under the
+ * client endpoint description for
+ * registering a service.
+ *
+ * @param serviceRegistryRequestDTO contains the information about the service that should be registered
+ * @return a string containing the full response body
+ * @throws ConstraintViolationException if the serviceRegistryRequestDTO is not valid
+ * @throws WebClientResponseException if the status code is 4xx or 5xx
+ */
+ public ServiceRegistryResponseDTO registerService(final ServiceRegistryRequestDTO serviceRegistryRequestDTO) throws ConstraintViolationException, WebClientResponseException {
+ final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+ final Set> violations = validator.validate(serviceRegistryRequestDTO);
+ if (!violations.isEmpty()) {
+ throw new ConstraintViolationException(violations);
+ }
+
+ log.debug("Start HTTP POST request against {} on uri: {}", baseUrl, URI_REGISTER_SERVICE);
+
+ return this.webClient
+ .post()
+ .uri(URI_REGISTER_SERVICE)
+ .contentType(MediaType.APPLICATION_JSON)
+ .bodyValue(serviceRegistryRequestDTO)
+ .retrieve()
+ .bodyToMono(ServiceRegistryResponseDTO.class)
+ .doOnNext(response -> log.debug("Finished HTTP POST request with response: {}", response))
+ .block();
+ }
+
+ public void unregisterService(final String serviceDefinition, final String providerName, final String providerAddress, final int providerPort, final String serviceUri) {
+ if (isEmpty(serviceDefinition)) {
+ throw new RuntimeException("Service definition is blank");
+ }
+
+ if (isEmpty(providerName)) {
+ throw new RuntimeException("Name of the provider system is blank");
+ }
+
+ if (isEmpty(providerAddress)) {
+ throw new RuntimeException("Address of the provider system is blank");
+ }
+
+ if (providerPort < SYSTEM_PORT_RANGE_MIN || providerPort > SYSTEM_PORT_RANGE_MAX) {
+ throw new RuntimeException("Port must be between " + SYSTEM_PORT_RANGE_MIN + " and " + SYSTEM_PORT_RANGE_MAX + ".");
+ }
+
+ log.debug("Start HTTP DELETE request against {} on uri: {}", baseUrl, URI_UNREGISTER_SERVICE);
+
+ this.webClient
+ .delete()
+ .uri(uriBuilder -> uriBuilder
+ .path(URI_UNREGISTER_SERVICE)
+ .queryParam(UNREGISTER_REQUEST_PARAM_SERVICE_DEFINITION, serviceDefinition)
+ .queryParam(UNREGISTER_REQUEST_PARAM_SYSTEM_NAME, providerName)
+ .queryParam(UNREGISTER_REQUEST_PARAM_ADDRESS, providerAddress)
+ .queryParam(UNREGISTER_REQUEST_PARAM_PORT, providerPort)
+ .queryParamIfPresent(UNREGISTER_REQUEST_PARAM_SERVICE_URI, Optional.ofNullable(serviceUri))
+ .build())
+ .retrieve()
+ .bodyToMono(Void.class)
+ .doOnNext(response -> log.debug("Finished HTTP DELETE request with response: {}", response))
+ .block();
+ }
+
+ public ServiceQueryResultDTO queryService(final ServiceQueryFormDTO form) throws ConstraintViolationException {
+ final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+ final Set> violations = validator.validate(form);
+ if (!violations.isEmpty()) {
+ throw new ConstraintViolationException(violations);
+ }
+
+ log.debug("Start HTTP POST request against {} on uri: {}", baseUrl, URI_QUERY_SERVICE);
+
+ return this.webClient
+ .post()
+ .uri(URI_QUERY_SERVICE)
+ .contentType(MediaType.APPLICATION_JSON)
+ .bodyValue(form)
+ .retrieve()
+ .bodyToMono(ServiceQueryResultDTO.class)
+ .doOnNext(response -> log.debug("Finished HTTP POST request with response: {}", response))
+ .block();
+ }
+
+ //-------------------------------------------------------------------------------------------------
+ private boolean isEmpty(final String str) {
+ return str == null || str.trim().isEmpty();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/request/ServiceQueryFormDTO.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/request/ServiceQueryFormDTO.java
new file mode 100644
index 000000000..bc9dfac91
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/request/ServiceQueryFormDTO.java
@@ -0,0 +1,34 @@
+/********************************************************************************
+ * Copyright (c) 2021 AITIA
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * AITIA - implementation
+ * Arrowhead Consortia - conceptualization
+ ********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead.model.request;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class ServiceQueryFormDTO {
+
+ @NotNull
+ @NotEmpty
+ private String serviceDefinitionRequirement;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/request/ServiceRegistryRequestDTO.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/request/ServiceRegistryRequestDTO.java
new file mode 100644
index 000000000..e43ac0733
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/request/ServiceRegistryRequestDTO.java
@@ -0,0 +1,60 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead.model.request;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+/**
+ * DTO class for Service Registry requests. Carries Arrowhead-specific information,
+ * necessary for the registration of the configuration system wrapper in the Service Registry.
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class ServiceRegistryRequestDTO {
+
+ @NotNull
+ private String serviceDefinition;
+
+ @Valid
+ @NotNull
+ private SystemRequestDTO providerSystem;
+
+ @NotNull
+ private String serviceUri;
+
+ private String endOfValidity;
+
+ private Enum secure;
+
+ private Map metadata;
+
+ private Integer version;
+
+ @NotEmpty
+ private List interfaces;
+
+ public enum SecurityLevel {
+ NOT_SECURE, CERTIFICATE, TOKEN
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/request/SystemRequestDTO.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/request/SystemRequestDTO.java
new file mode 100644
index 000000000..7de588fb1
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/request/SystemRequestDTO.java
@@ -0,0 +1,41 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead.model.request;
+
+import java.util.Map;
+
+import javax.validation.constraints.NotNull;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class SystemRequestDTO {
+
+ @NotNull
+ private String systemName;
+
+ @NotNull
+ private String address;
+
+ @NotNull
+ private Integer port;
+
+ @NotNull
+ private String authenticationInfo;
+
+ private Map metadata;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceDefinitionResponseDTO.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceDefinitionResponseDTO.java
new file mode 100644
index 000000000..4a5c65632
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceDefinitionResponseDTO.java
@@ -0,0 +1,28 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead.model.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class ServiceDefinitionResponseDTO {
+
+ private long id;
+ private String serviceDefinition;
+ private String createdAt;
+ private String updatedAt;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceInterfaceResponseDTO.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceInterfaceResponseDTO.java
new file mode 100644
index 000000000..f027023e1
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceInterfaceResponseDTO.java
@@ -0,0 +1,28 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead.model.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class ServiceInterfaceResponseDTO {
+
+ private long id;
+ private String interfaceName;
+ private String createdAt;
+ private String updatedAt;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceQueryResultDTO.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceQueryResultDTO.java
new file mode 100644
index 000000000..bb6266691
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceQueryResultDTO.java
@@ -0,0 +1,32 @@
+/********************************************************************************
+ * Copyright (c) 2021 AITIA
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * AITIA - implementation
+ * Arrowhead Consortia - conceptualization
+ ********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead.model.response;
+
+import java.util.List;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class ServiceQueryResultDTO {
+
+ private List serviceQueryData;
+ private int unfilteredHits;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceRegistryResponseDTO.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceRegistryResponseDTO.java
new file mode 100644
index 000000000..43e185971
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/ServiceRegistryResponseDTO.java
@@ -0,0 +1,43 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead.model.response;
+
+import java.util.List;
+import java.util.Map;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+/**
+ * DTO class for the Service Registry responses. Carries necessary information about the successful registration
+ * of the configuration system in the Service Registry.
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class ServiceRegistryResponseDTO {
+
+ private long id;
+ private ServiceDefinitionResponseDTO serviceDefinition;
+ private SystemResponseDTO provider;
+ private String serviceUri;
+ private String endOfValidity;
+ private String secure;
+ private Map metadata;
+ private Integer version;
+ private List interfaces;
+ private String createdAt;
+ private String updatedAt;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/SystemResponseDTO.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/SystemResponseDTO.java
new file mode 100644
index 000000000..8cfe748b5
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/arrowhead/model/response/SystemResponseDTO.java
@@ -0,0 +1,34 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead.model.response;
+
+import java.util.Map;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class SystemResponseDTO {
+
+ private long id;
+ private String systemName;
+ private String address;
+ private Integer port;
+ private String authenticationInfo;
+ private Map metadata;
+ private String createdAt;
+ private String updatedAt;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/ArrowheadConfig.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/ArrowheadConfig.java
new file mode 100644
index 000000000..1ce242b95
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/ArrowheadConfig.java
@@ -0,0 +1,144 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import java.io.IOException;
+import java.util.ServiceConfigurationError;
+
+import javax.annotation.PostConstruct;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.TrustManagerFactory;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import eu.arrowhead.core.hbconfmgr.Constants;
+import eu.arrowhead.core.hbconfmgr.arrowhead.ArrowheadAuthorizationSystemClient;
+import eu.arrowhead.core.hbconfmgr.arrowhead.ArrowheadServiceRegistryClient;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.request.ServiceQueryFormDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.ServiceQueryResultDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.ServiceRegistryResponseDTO;
+import io.netty.handler.ssl.ClientAuth;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import lombok.extern.log4j.Log4j2;
+
+/**
+ * This class provides the clients for interaction with Arrowhead via beans managed by the Spring container.
+ */
+@Log4j2
+@Configuration
+public class ArrowheadConfig {
+
+ private static final int RETRIES = 3;
+ private static final int PERIOD = 5000;
+
+ @Value(Constants.SSL_ENABLED)
+ private boolean sslEnabled;
+
+ @Autowired
+ private KeyManagerFactory keyManagerFactory;
+
+ @Autowired
+ private TrustManagerFactory trustManagerFactory;
+
+ private final String authorizationSystemProtocol = Constants.HTTPS + "://";
+ private String authorizationSystemAddress;
+ private int authorizationSystemPort;
+
+ private final String serviceRegistryProtocol = Constants.HTTPS + "://";;
+
+ @Value(Constants.SERVICE_REGISTRY_ADDRESS)
+ private String serviceRegistryAddress;
+
+ @Value(Constants.SERVICE_REGISTRY_PORT)
+ private int serviceRegistryPort;
+
+ private SslContext sslContext;
+
+ @PostConstruct
+ public void init() throws IOException, InterruptedException {
+ final ArrowheadServiceRegistryClient srClient = arrowheadServiceRegistryClient();
+ for (int i = 0; i <= RETRIES; ++i) {
+ try {
+ final ServiceQueryFormDTO form = ServiceQueryFormDTO.builder()
+ .serviceDefinitionRequirement(Constants.CORE_SERVICE_AUTH_PUBLIC_KEY)
+ .build();
+
+ final ServiceQueryResultDTO response = srClient.queryService(form);
+
+ if (!response.getServiceQueryData().isEmpty()) {
+ final ServiceRegistryResponseDTO authResponse = response.getServiceQueryData().get(0);
+ this.authorizationSystemAddress = authResponse.getProvider().getAddress();
+ this.authorizationSystemPort = authResponse.getProvider().getPort();
+ return;
+ } else if (i >= RETRIES) {
+ log.error("Authorization system is not accessible.");
+ throw new ServiceConfigurationError("HawkBit Configuration Manager cannot work without the Authorization core system.");
+ } else {
+ log.info("Authorization system is unavailable at the moment, retrying in {} seconds...", PERIOD / 1000);
+ Thread.sleep(PERIOD);
+ }
+ } catch (final Exception e) {
+ if (i >= RETRIES) {
+ log.error("Service Registry is not accessible.", e);
+ throw e;
+ } else {
+ log.info("Service Registry is unavailable at the moment, retrying in {} seconds...", PERIOD / 1000);
+ Thread.sleep(PERIOD);
+ }
+ }
+ }
+ }
+
+ @Bean
+ public ArrowheadAuthorizationSystemClient arrowheadAuthorizationSystemClient() throws IOException {
+ final String baseUrl = this.authorizationSystemProtocol + this.authorizationSystemAddress + ":" + this.authorizationSystemPort;
+ log.debug("Registering bean for ArrowheadAuthorizationSystemClient with baseUrl {} and custom ssl context", baseUrl);
+
+ final SslContext sslContext = loadSslContext();
+ return new ArrowheadAuthorizationSystemClient(baseUrl, sslContext);
+ }
+
+ @Bean
+ public ArrowheadServiceRegistryClient arrowheadServiceRegistryClient() throws IOException {
+ final String baseUrl = this.serviceRegistryProtocol + this.serviceRegistryAddress + ":" + this.serviceRegistryPort;
+ log.debug("Registering bean for ArrowheadServiceRegistryClient with baseUrl {} and custom ssl context", baseUrl);
+
+ final SslContext sslContext = loadSslContext();
+ return new ArrowheadServiceRegistryClient(baseUrl, sslContext);
+ }
+
+ /**
+ * Load the ssl context with a defined client certificate and a defined server certificate.
+ * This allows to use self signed certificates.
+ *
+ * @param keyManagerFactory contains the client private and public certificates
+ * @param trustManagerFactory contains the server public certificate
+ * @return a ssl context for a {@link reactor.netty.http.client.HttpClient HttpClient}
+ * @throws SSLException if the ssl context could not be loaded correctly
+ */
+ private SslContext loadSslContext() throws IOException {
+ if (sslContext == null) {
+ sslContext = SslContextBuilder
+ .forClient()
+ .clientAuth(ClientAuth.REQUIRE)
+ .keyManager(keyManagerFactory)
+ .trustManager(trustManagerFactory)
+ .build();
+ }
+
+ return sslContext;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/HawkbitConfig.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/HawkbitConfig.java
new file mode 100644
index 000000000..bd872dd22
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/HawkbitConfig.java
@@ -0,0 +1,73 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import java.io.IOException;
+import java.util.concurrent.TimeoutException;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.context.annotation.Scope;
+
+import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.Connection;
+import com.rabbitmq.client.ConnectionFactory;
+
+import eu.arrowhead.core.hbconfmgr.Constants;
+
+/**
+ * This class provides the clients for interaction with hawkBit via beans managed by the Spring container.
+ */
+@Configuration
+public class HawkbitConfig {
+
+ @Value(Constants.HAWKBIT_HOST)
+ private String host;
+
+ @Value(Constants.HAWKBIT_PORT)
+ private int port;
+
+ @Value(Constants.HAWKBIT_USER)
+ private String username;
+
+ @Value(Constants.HAWKBIT_PASSWORD)
+ private String password;
+
+ @Bean
+ @DependsOn(Constants.GUARD_BEAN)
+ public ConnectionFactory connectionFactory() {
+ final ConnectionFactory connectionFactory = new ConnectionFactory();
+ connectionFactory.setHost(this.host);
+ connectionFactory.setPort(this.port);
+ connectionFactory.setUsername(this.username);
+ connectionFactory.setPassword(this.password);
+ connectionFactory.setAutomaticRecoveryEnabled(true);
+
+ return connectionFactory;
+ }
+
+ @Bean
+ @DependsOn(Constants.GUARD_BEAN)
+ public Connection getConnection(final ConnectionFactory connectionFactory) throws IOException, TimeoutException {
+ return connectionFactory.newConnection();
+ }
+
+ @Bean
+ @DependsOn(Constants.GUARD_BEAN)
+ @Scope("prototype")
+ @Autowired
+ public Channel createChannel(final Connection connection) throws IOException {
+ return connection.createChannel();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/KeyStoreConfig.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/KeyStoreConfig.java
new file mode 100644
index 000000000..787cfcc44
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/KeyStoreConfig.java
@@ -0,0 +1,77 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+
+import javax.net.ssl.KeyManagerFactory;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import eu.arrowhead.core.hbconfmgr.SSLProperties;
+
+/**
+ * This class provides the key store of the configuration system in different formats via beans managed by the Spring
+ * container. The key store contains the private and the public key of the configuration system itself.
+ */
+@Configuration
+public class KeyStoreConfig {
+
+ @Autowired
+ private SSLProperties sslProps;
+
+ private KeyStore keystore;
+
+ @Bean
+ public KeyManagerFactory hawkbitConfigurationSystemKeyManagerFactory() throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException, IOException, CertificateException {
+ final KeyStore keyStore = loadKeyStore();
+ final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ keyManagerFactory.init(keyStore, sslProps.getKeyStorePassword().toCharArray());
+
+ return keyManagerFactory;
+ }
+
+ @Bean
+ public PrivateKey hawkbitConfigurationSystemPrivateKey() throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException {
+ final KeyStore keyStore = loadKeyStore();
+
+ return (PrivateKey) keyStore.getKey(sslProps.getKeyAlias(), sslProps.getKeyPassword().toCharArray());
+ }
+
+ @Bean
+ public PublicKey hawkbitConfigurationSystemPublicKey() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
+ final KeyStore keyStore = loadKeyStore();
+
+ return keyStore.getCertificate(sslProps.getKeyAlias()).getPublicKey();
+ }
+
+ private KeyStore loadKeyStore() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
+ if (sslProps.isSslEnabled()) {
+ if (keystore == null) {
+ keystore = KeyStore.getInstance(sslProps.getKeyStoreType());
+ keystore.load(sslProps.getKeyStore().getInputStream(), sslProps.getKeyStorePassword().toCharArray());
+ }
+
+ return keystore;
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/PropertiesConfig.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/PropertiesConfig.java
new file mode 100644
index 000000000..4c858a8ea
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/PropertiesConfig.java
@@ -0,0 +1,41 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import eu.arrowhead.core.hbconfmgr.properties.SystemProperties;
+
+/**
+ * This class instantiates properties classes, populates them from Spring properties files (like application.yml)
+ * and provides them as beans managed by the Spring container.
+ */
+@Configuration
+public class PropertiesConfig {
+
+ private static final String SYSTEM = "system";
+
+ /**
+ * This makes use of Spring properties files (like application.yml), loads all properties under the
+ * prefix "system" into the newly instantiated class {@link SystemProperties} and provides it as a bean
+ * managed by the Spring container.
+ *
+ * @return a populated and validated instance of {@link SystemProperties}
+ */
+ @Bean
+ @ConfigurationProperties(prefix = SYSTEM)
+ public SystemProperties systemProperties() {
+ return new SystemProperties();
+ }
+
+}
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/TrustStoreConfig.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/TrustStoreConfig.java
new file mode 100644
index 000000000..a0ffab579
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/TrustStoreConfig.java
@@ -0,0 +1,60 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+
+import javax.net.ssl.TrustManagerFactory;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import eu.arrowhead.core.hbconfmgr.SSLProperties;
+
+/**
+ * This class provides the trust store of the configuration system in different formats via beans managed by the Spring
+ * container. The trust store contains the public keys that are trusted.
+ */
+@Configuration
+public class TrustStoreConfig {
+
+ @Autowired
+ private SSLProperties sslProps;
+
+ private KeyStore truststore;
+
+ @Bean
+ public TrustManagerFactory trustManagerFactory() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
+ final KeyStore trustStore = loadTrustStore();
+ final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(trustStore);
+
+ return trustManagerFactory;
+ }
+
+ private KeyStore loadTrustStore() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
+ if (sslProps.isSslEnabled()) {
+ if (truststore == null) {
+ truststore = KeyStore.getInstance(sslProps.getKeyStoreType());
+ truststore.load(sslProps.getTrustStore().getInputStream(), sslProps.getTrustStorePassword().toCharArray());
+ }
+
+ return truststore;
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/WebSocketConfig.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/WebSocketConfig.java
new file mode 100644
index 000000000..d1a625796
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/WebSocketConfig.java
@@ -0,0 +1,32 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.context.annotation.Scope;
+import org.springframework.web.socket.WebSocketSession;
+
+import eu.arrowhead.core.hbconfmgr.Constants;
+
+@Configuration
+public class WebSocketConfig {
+ @Bean
+ @DependsOn(Constants.GUARD_BEAN)
+ @Scope("singleton")
+ public Map getWebSocketSessionMap() {
+ return new ConcurrentHashMap<>();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/WebSocketSecurityConfig.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/WebSocketSecurityConfig.java
new file mode 100644
index 000000000..4e308879c
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/config/WebSocketSecurityConfig.java
@@ -0,0 +1,83 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import java.security.PrivateKey;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
+
+import eu.arrowhead.core.hbconfmgr.security.JwtAuthenticationFilter;
+import eu.arrowhead.core.hbconfmgr.service.ArrowheadService;
+import eu.arrowhead.core.hbconfmgr.websocket.WebSocketController;
+
+/**
+ * This is the configuration for web sockets.
+ * Web socket support can be enabled/disabled with the annotation {@link EnableWebSocket @EnableWebSocket}
+ * Web socket security can be enabled/disabled with the annotation {@link EnableWebSecurity @EnableWebSecurity}
+ */
+@Configuration
+@EnableWebSecurity
+@EnableWebSocket
+public class WebSocketSecurityConfig extends WebSecurityConfigurerAdapter implements WebSocketConfigurer {
+
+ private final ArrowheadService arrowheadService;
+ private final PrivateKey privateKey;
+ private final WebSocketController webSocketController;
+
+ @Autowired
+ public WebSocketSecurityConfig(final ArrowheadService arrowheadService, final PrivateKey privateKey, final WebSocketController webSocketController) {
+ this.arrowheadService = arrowheadService;
+ this.privateKey = privateKey;
+ this.webSocketController = webSocketController;
+ }
+
+ /**
+ * Registers the web socket controller as web socket handler.
+ */
+ @Override
+ public void registerWebSocketHandlers(final WebSocketHandlerRegistry registry) {
+ registry.addHandler(this.webSocketController, "/");
+ }
+
+ /**
+ * Configuration of the HTTP security for the whole configuration system, including web socket connections.
+ * Many default security settings are disabled as the clients are connecting non-interactive to the configuration
+ * system and don't support all default security settings.
+ */
+ @Override
+ protected void configure(final HttpSecurity http) throws Exception {
+ http
+ // Disable form login, as only non-interactive clients connect
+ .formLogin().disable()
+ // Disable HTTP basic authentication, as only JWT authentication is supported
+ .httpBasic().disable()
+ // CORS protection is not required, as only non-interactive clients connect
+ .cors().disable()
+ // CSRF protection is not required, as only non-interactive clients connect
+ .csrf(AbstractHttpConfigurer::disable)
+ // Register custom JWT authentication filter, so JWT authentication is supported
+ .addFilterBefore(new JwtAuthenticationFilter(this.arrowheadService, this.privateKey), BasicAuthenticationFilter.class)
+ // Disable Spring Sessions, as sessions should not be supported
+ .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+ // Require full authentication on every request
+ .authorizeRequests().anyRequest().fullyAuthenticated();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfConstants.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfConstants.java
new file mode 100644
index 000000000..996b1d0f3
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfConstants.java
@@ -0,0 +1,39 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit;
+
+public class HawkbitDmfConstants {
+
+ /**
+ * The exchange name for all messages sent to hawkBit. It is predefined from hawkBit and can not be changed.
+ */
+ public static final String SENDING_EXCHANGE = "dmf.exchange";
+
+ /**
+ * The routing key for all messages sent to hawkBit. It is predefined from hawkBit and can not be changed.
+ */
+ public static final String SENDING_ROUTING_KEY = "";
+
+ /**
+ * The exchange name for all messages sent from hawkBit to the configuration system. It can be modified.
+ */
+ public static final String RECEIVING_EXCHANGE = "configuration_system.direct.exchange";
+
+ /**
+ * The queue name for all messages sent from hawkBit to the configuration system. It can be modified.
+ */
+ public static final String RECEIVING_QUEUE = "configuration_system_direct_queue";
+
+ /**
+ * The routing key for all messages sent from hawkBit to the configuration system. It can be modified.
+ */
+ public static final String RECEIVING_ROUTING_KEY = "";
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfConsumer.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfConsumer.java
new file mode 100644
index 000000000..92a0b6c1f
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfConsumer.java
@@ -0,0 +1,331 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.rabbitmq.client.AMQP;
+import com.rabbitmq.client.BuiltinExchangeType;
+import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.DefaultConsumer;
+import com.rabbitmq.client.Envelope;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.EventType;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.MessageHeader;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.CancelDownloadInboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.DownloadRequestInboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.MessageTypeInbound;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.ThingDeletedInboundMessage;
+import eu.arrowhead.core.hbconfmgr.service.WebSocketService;
+import eu.arrowhead.core.hbconfmgr.websocket.DeviceNotConnectedException;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import lombok.extern.log4j.Log4j2;
+
+/**
+ * Handles incoming messages on the connected HawkBit (RabbitMQ) queue.
+ * Responsible for further message routing, depending on the message type and
+ * topic.
+ */
+@Log4j2
+@Component
+public class HawkbitDmfConsumer extends DefaultConsumer {
+
+ private final Channel channel;
+ private final ObjectMapper objectMapper;
+
+ private final WebSocketService wsService;
+
+ /**
+ * Initializes a new hawkBit consumer that operates on the hawkBit device
+ * management federation (DMF) API. It is used for downstream communication
+ * (receiving messages from hawkBit). Further information to the downstream DMF
+ * API can be found in the DMF API documentation
+ * under "Messages sent by hawkBit (hawkBit -> Client)"
+ *
+ * @param channel used for communication with hawkBit
+ */
+ @Autowired
+ public HawkbitDmfConsumer(final Channel channel, final WebSocketService wsService) {
+ super(channel);
+ this.channel = channel;
+ this.objectMapper = new ObjectMapper();
+ this.wsService = wsService;
+ }
+
+ /**
+ * Subscribe to download event messages from hawkBit.
+ *
+ * Important: The handler is responsible to acknowledge
+ * the successful retrieval and processing of the message via the method
+ * {@link #acknowledgeMessage(long)}.
+ *
+ * @throws IOException if there is a connection problem with hawkBit
+ */
+ public void subscribeToDownloadEvents() throws IOException {
+ this.initializeQueueOnHawkbit();
+ this.consumeFromQueueOnHawkbit();
+ }
+
+ /**
+ * Initialize the queue on hawkBit DMF API that is used from the configuration
+ * system to receive messages.
+ *
+ * @throws IOException if there is a connection problem with hawkBit
+ */
+ private void initializeQueueOnHawkbit() throws IOException {
+ this.channel.queueDeclare(HawkbitDmfConstants.RECEIVING_QUEUE, true, false, false, null);
+ this.channel.exchangeDeclare(HawkbitDmfConstants.RECEIVING_EXCHANGE, BuiltinExchangeType.DIRECT, true, false, null);
+ this.channel.queueBind(HawkbitDmfConstants.RECEIVING_QUEUE, HawkbitDmfConstants.RECEIVING_EXCHANGE, HawkbitDmfConstants.RECEIVING_ROUTING_KEY);
+ }
+
+ /**
+ * Start consuming from the configuration system queue on the hawkBit DMF API.
+ *
+ * @throws IOException if there is a connection problem with hawkBit
+ */
+ private void consumeFromQueueOnHawkbit() throws IOException {
+ this.channel.basicConsume(HawkbitDmfConstants.RECEIVING_QUEUE, false, this);
+ }
+
+ /**
+ * Overrides the method
+ * {@link DefaultConsumer#handleDelivery(String, Envelope, AMQP.BasicProperties, byte[])}
+ * with an implementation to handle hawkBit DMF API messages.
+ */
+ @Override
+ public void handleDelivery(final String consumerTag, final Envelope envelope, final AMQP.BasicProperties properties, final byte[] body) {
+ try {
+ log.debug("Received message");
+ handleMessage(envelope, properties, body);
+ } catch (final IOException e) {
+ log.atError().withThrowable(e).log(
+ "Handling of message delivery failed. Message has the following properties: {} and body: {}", properties, body);
+ }
+ }
+
+ /**
+ * Handle a hawkBit message.
+ *
+ * @param envelope envelope of the AMQP message
+ * @param properties properties (including the headers) of the AMQP message
+ * @param body body of the AMQP message
+ * @throws IOException if a problem occurs with the message itself, like a
+ * missing header or a malformed body
+ */
+ private void handleMessage(final Envelope envelope, final AMQP.BasicProperties properties, final byte[] body) throws IOException {
+ final Map headers = properties.getHeaders();
+ if (headers == null || !headers.containsKey(MessageHeader.TYPE.toString())) {
+ throw new IOException("Message doesn't contain header " + MessageHeader.TYPE.toString());
+ }
+
+ final MessageTypeInbound messageType = MessageTypeInbound.valueOf(String.valueOf(headers.get(MessageHeader.TYPE.toString())));
+ switch (messageType) {
+ case EVENT:
+ handleEvent(envelope, properties, body);
+ break;
+ case THING_DELETED:
+ handleThingDeleted(envelope, properties);
+ break;
+ case PING_RESPONSE:
+ default:
+ handleUnsupportedMessageType(envelope, messageType);
+ break;
+ }
+ }
+
+ /**
+ * Handle a hawkBit message from type {@link MessageTypeInbound#EVENT}.
+ *
+ * @param envelope envelope of the AMQP message
+ * @param properties properties (including the headers) of the AMQP message
+ * @param body body of the AMQP message
+ * @throws IOException if a problem occurs with the message itself, like a
+ * missing header or a malformed body
+ */
+ private void handleEvent(final Envelope envelope, final AMQP.BasicProperties properties, final byte[] body) throws IOException {
+ final Map headers = properties.getHeaders();
+ if (headers == null || !headers.containsKey(MessageHeader.TOPIC.toString())) {
+ throw new IOException("Message doesn't contain header " + MessageHeader.TOPIC.toString());
+ }
+
+ final EventType eventType = EventType.valueOf(String.valueOf(headers.get(MessageHeader.TOPIC.toString())));
+ switch (eventType) {
+ case DOWNLOAD:
+ case DOWNLOAD_AND_INSTALL:
+ handleEventWithTopicDownload(envelope, properties, body);
+ break;
+ case CANCEL_DOWNLOAD:
+ handleEventWithTopicCancelDownload(envelope, properties, body);
+ break;
+ case MULTI_ACTION:
+ case REQUEST_ATTRIBUTES_UPDATE:
+ default:
+ handleEventWithUnsupportedTopic(envelope, eventType);
+ break;
+ }
+ }
+
+ /**
+ * Handle a hawkBit download request message.
+ *
+ * @param envelope envelope of the AMQP message
+ * @param properties properties (including the headers) of the AMQP message
+ * @param body body of the AMQP message
+ * @throws IOException if a problem occurs during mapping the body to
+ * {@link DownloadRequestInboundMessage.Body} with a json
+ * object mapper
+ */
+ private void handleEventWithTopicDownload(final Envelope envelope, final AMQP.BasicProperties properties, final byte[] body) {
+ final Map headers = properties.getHeaders();
+
+ DownloadRequestInboundMessage message;
+ try {
+ message = DownloadRequestInboundMessage.builder()
+ .headers(DownloadRequestInboundMessage.Headers.builder()
+ .type(headers.get(MessageHeader.TYPE.toString()).toString())
+ .thingId(headers.get(MessageHeader.THING_ID.toString()).toString())
+ .topic(headers.get(MessageHeader.TOPIC.toString()).toString())
+ .tenant(headers.get(MessageHeader.TENANT.toString()).toString()).build())
+ .body(this.objectMapper.readValue(body, DownloadRequestInboundMessage.Body.class))
+ .deliveryTag(envelope.getDeliveryTag()).build();
+
+ wsService.sendDownloadEventMessage(message);
+
+ acknowledgeMessageDelivery(envelope.getDeliveryTag());
+ } catch (final JsonParseException e) {
+ log.error("Could not parse inbound message: {}", e);
+ } catch (final JsonMappingException e) {
+ log.error("Could not map inbound message: {}", e);
+ } catch (final IOException e) {
+ log.error("Could not send message to device {}, as it was not reachable.", headers.get(MessageHeader.THING_ID.toString()).toString());
+ } catch (final DeviceNotConnectedException e) {
+ log.error("Device {} is currently not connected to HawkBit.", headers.get(MessageHeader.THING_ID.toString()).toString());
+ }
+ }
+
+ /**
+ * Handle CANCEL_DOWNLOAD messages. Send ACK only if parsing of the message and further
+ * transport via WebSocket was successful.
+ *
+ * @param envelope AMQP envelope
+ * @param properties AMQP properties
+ * @param body the actual amqp message payload
+ */
+ private void handleEventWithTopicCancelDownload(final Envelope envelope, final AMQP.BasicProperties properties, final byte[] body) {
+ final Map headers = properties.getHeaders();
+
+ CancelDownloadInboundMessage message;
+ try {
+ message = CancelDownloadInboundMessage.builder()
+ .headers(
+ CancelDownloadInboundMessage.Headers.builder()
+ .type(headers.get(MessageHeader.TYPE.toString()).toString())
+ .thingId(headers.get(MessageHeader.THING_ID.toString()).toString())
+ .topic(headers.get(MessageHeader.TOPIC.toString()).toString())
+ .tenant(headers.get(MessageHeader.TENANT.toString()).toString())
+ .build()
+ )
+ .body(this.objectMapper.readValue(body, CancelDownloadInboundMessage.Body.class)).build();
+
+ this.wsService.sendCancelDownloadMessage(message);
+
+ acknowledgeMessageDelivery(envelope.getDeliveryTag());
+ } catch (final JsonParseException e) {
+ log.error("Could not parse inbound message: {}", e);
+ } catch (final JsonMappingException e) {
+ log.error("Could not map inbound message: {}", e);
+ } catch (final IOException e) {
+ log.error("Could not send message to device {}, as it was not reachable.", headers.get(MessageHeader.THING_ID.toString()).toString());
+ } catch (final DeviceNotConnectedException e) {
+ log.error("Device {} is currently not connected to HawkBit.", headers.get(MessageHeader.THING_ID.toString()).toString());
+ }
+ }
+
+ /**
+ * Handle THING_DELETED messages. Send ACK only if parsing of the message and further
+ * transport via Websocket was successful
+ *
+ * @param envelope AMQP envelope
+ * @param properties AMQP properties
+ * @param body the actual AMQP message payload
+ */
+ private void handleThingDeleted(final Envelope envelope, final AMQP.BasicProperties properties) {
+ final Map headers = properties.getHeaders();
+
+ ThingDeletedInboundMessage message;
+ try {
+ message = ThingDeletedInboundMessage.builder()
+ .headers(
+ ThingDeletedInboundMessage.Headers.builder()
+ .thingId(headers.get(MessageHeader.THING_ID.toString()).toString())
+ .build()
+ )
+ .build();
+
+ this.wsService.sendThingDeletedMessage(message);
+
+ acknowledgeMessageDelivery(envelope.getDeliveryTag());
+ } catch (final JsonParseException e) {
+ log.error("Could not parse inbound message: {}", e);
+ } catch (final JsonMappingException e) {
+ log.error("Could not map inbound message: {}", e);
+ } catch (final IOException e) {
+ log.error("Could not send message to device {}, as it was not reachable.", headers.get(MessageHeader.THING_ID.toString()).toString());
+ } catch (final DeviceNotConnectedException e) {
+ log.error("Device {} is currently not connected to HawkBit.", headers.get(MessageHeader.THING_ID.toString()).toString());
+ }
+ }
+
+
+ /**
+ * Handle a hawkBit message with unsupported message type. Send a negative acknowledgement to hawkBit for the
+ * message with no requeuing.
+ *
+ * @param envelope envelope of the AMQP message
+ * @param messageType message type of the AMQP message
+ * @throws IOException if there is a connection problem with hawkBit
+ */
+ private void handleUnsupportedMessageType(final Envelope envelope, final MessageTypeInbound messageType) throws IOException {
+ log.error("Message with unsupported message type {} was received, responding with negative acknowledgement and no requeuing", messageType.toString());
+
+ super.getChannel().basicNack(envelope.getDeliveryTag(), false, false);
+ }
+
+ /**
+ * Handle a hawkBit message from message type {@link MessageTypeInbound#EVENT} and with unsupported event type. Send a
+ * negative acknowledgement to hawkBit for the message with no requeuing.
+ *
+ * @param envelope envelope of the AMQP message
+ * @param eventType event type of the AMQP message
+ * @throws IOException if there is a connection problem with hawkBit
+ */
+ private void handleEventWithUnsupportedTopic(final Envelope envelope, final EventType eventType) throws IOException {
+ log.error("Message with message type {} and unsupported event topic {} was received, responding with negative acknowledgement and no requeuing", MessageTypeInbound.EVENT.toString(), eventType.toString());
+
+ super.getChannel().basicNack(envelope.getDeliveryTag(), false, false);
+ }
+
+ private void acknowledgeMessageDelivery(final Long deliveryTag) {
+ try {
+ super.getChannel().basicAck(deliveryTag, false);
+ } catch (final IOException e) {
+ log.error("Could not acknowledge message delivery to HawkBit.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfOutboundClient.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfOutboundClient.java
new file mode 100644
index 000000000..65de4b845
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfOutboundClient.java
@@ -0,0 +1,138 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.rabbitmq.client.AMQP;
+import com.rabbitmq.client.Channel;
+
+import eu.arrowhead.core.hbconfmgr.Constants;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound.ThingCreatedOutboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound.ThingRemovedOutboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound.UpdateActionStatusOutboundMessage;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import lombok.extern.log4j.Log4j2;
+
+
+/**
+ * Handles all outbound interaction with Eclipse HawkBit via its DMF API.
+ */
+@Log4j2
+@Component
+public class HawkbitDmfOutboundClient {
+
+ private final Channel channel;
+ private final ObjectMapper objectMapper;
+ private final Validator validator;
+
+ /**
+ * Initialize a new hawkBit client that operates on the hawkBit device management federation (DMF) API. It is
+ * used for upstream communication (sending messages to hawkBit). Further information to the upstream DMF API can
+ * be found in the DMF API documentation under
+ * "Messages sent to hawkBit (Client -> hawkBit)"
+ *
+ * @param channel used for communication with hawkBit
+ */
+ @Autowired
+ public HawkbitDmfOutboundClient(final Channel channel) {
+ this.channel = channel;
+ this.objectMapper = new ObjectMapper();
+ this.validator = Validation.buildDefaultValidatorFactory().getValidator();
+ }
+
+ /**
+ * Send a message to hawkBit on the device management federation (DMF) API to create a new thing. A description of
+ * this API can be found in the DMF API documentation
+ * under "Messages sent to hawkBit (Client -> hawkBit)" -> "THING_CREATED".
+ *
+ * @param message the message to publish with body and headers
+ * @throws ConstraintViolationException if message is not valid
+ * @throws IOException if there is a connection problem with hawkBit
+ */
+ public void createThing(final ThingCreatedOutboundMessage message) throws ConstraintViolationException, IOException {
+ log.debug("Validating ThingCreatedOutboundMessage");
+
+ final Set> violations = validator.validate(message);
+ if (!violations.isEmpty()) {
+ throw new ConstraintViolationException(violations);
+ }
+
+ final byte[] byteBody = this.objectMapper.writeValueAsBytes(message.getBody());
+ final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
+ .contentType(Constants.APPLICATION_JSON)
+ .headers(message.getHeaders().asMap())
+ .replyTo(HawkbitDmfConstants.RECEIVING_EXCHANGE)
+ .build();
+
+ log.debug("Sending ThingCreatedOutboundMessage to exchange {}", HawkbitDmfConstants.SENDING_EXCHANGE);
+ this.channel.basicPublish(HawkbitDmfConstants.SENDING_EXCHANGE, HawkbitDmfConstants.SENDING_ROUTING_KEY, properties, byteBody);
+ }
+
+ /**
+ * Send a message to hawkBit on the device management federation (DMF) API to create a new thing. A description of
+ * this API can be found in the DMF API documentation
+ * under "Messages sent to hawkBit (Client -> hawkBit)" -> "UPDATE_ACTION_STATUS".
+ *
+ * @param message the message to publish with body and headers
+ * @throws ConstraintViolationException if message is not valid
+ * @throws IOException if there is a connection problem with hawkBit
+ */
+ public void updateActionStatus(final UpdateActionStatusOutboundMessage message) throws IOException {
+ log.debug("Validating UpdateActionStatusOutboundMessage");
+
+ final Set> violations = validator.validate(message);
+ if (!violations.isEmpty()) {
+ throw new ConstraintViolationException(violations);
+ }
+
+ final byte[] byteBody = this.objectMapper.writeValueAsBytes(message.getBody());
+ final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
+ .contentType(Constants.APPLICATION_JSON)
+ .headers(message.getHeaders().asMap())
+ .build();
+
+ log.debug("Sending UpdateActionStatusOutboundMessage to exchange {}", HawkbitDmfConstants.SENDING_EXCHANGE);
+ this.channel.basicPublish(HawkbitDmfConstants.SENDING_EXCHANGE, HawkbitDmfConstants.SENDING_ROUTING_KEY, properties, byteBody);
+ }
+
+ /**
+ * Send a message to hawkBit via the device management federation (DMF) API to remove a thing. A description of
+ * this API can be found in the DMF API documentation
+ * under "Messages sent to hawkBit (Client -> hawkBit)" -> "THING_REMOVED".
+ * @param message the actual message to be published
+ * @throws IOException
+ */
+ public void removeThing(final ThingRemovedOutboundMessage message) throws IOException {
+ final Set> violations = validator.validate(message);
+ if (!violations.isEmpty()) {
+ throw new ConstraintViolationException(violations);
+ }
+
+ final byte[] byteBody = "".getBytes();
+ final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
+ .contentType(Constants.APPLICATION_JSON)
+ .headers(message.getHeaders().asMap())
+ .build();
+
+ this.channel.basicPublish(HawkbitDmfConstants.SENDING_EXCHANGE, HawkbitDmfConstants.SENDING_ROUTING_KEY, properties, byteBody);
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/ActionStatus.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/ActionStatus.java
new file mode 100644
index 000000000..e1f25e5df
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/ActionStatus.java
@@ -0,0 +1,38 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model;
+
+
+/**
+ * Enum for outbound UPDATE_ACTION_STATUS type classification.
+ */
+public enum ActionStatus {
+ DOWNLOAD("DOWNLOAD"),
+ RETRIEVED("RETRIEVED"),
+ RUNNING("RUNNING"),
+ FINISHED("FINISHED"),
+ ERROR("ERROR"),
+ WARNING("WARNING"),
+ CANCELED("CANCELED"),
+ CANCEL_REJECTED("CANCEL_REJECTED"),
+ DOWNLOADED("DOWNLOADED");
+
+ private final String stringValue;
+
+ private ActionStatus(final String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ @Override
+ public String toString() {
+ return this.stringValue;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/EventType.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/EventType.java
new file mode 100644
index 000000000..acc8b066a
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/EventType.java
@@ -0,0 +1,31 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model;
+
+public enum EventType {
+ CANCEL_DOWNLOAD("CANCEL_DOWNLOAD"),
+ DOWNLOAD("DOWNLOAD"),
+ DOWNLOAD_AND_INSTALL("DOWNLOAD_AND_INSTALL"),
+ MULTI_ACTION("MULTI_ACTION"),
+ REQUEST_ATTRIBUTES_UPDATE("REQUEST_ATTRIBUTES_UPDATE"),
+ UPDATE_ACTION_STATUS("UPDATE_ACTION_STATUS");
+
+ private final String stringValue;
+
+ private EventType(final String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ @Override
+ public String toString() {
+ return this.stringValue;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/MessageHeader.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/MessageHeader.java
new file mode 100644
index 000000000..a84a2a845
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/MessageHeader.java
@@ -0,0 +1,34 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model;
+
+
+/**
+ * Enum for outbound header type classification.
+ */
+public enum MessageHeader {
+ SENDER("sender"),
+ TENANT("tenant"),
+ THING_ID("thingId"),
+ TOPIC("topic"),
+ TYPE("type");
+
+ private final String stringValue;
+
+ private MessageHeader(final String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ @Override
+ public String toString() {
+ return this.stringValue;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/CancelDownloadInboundMessage.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/CancelDownloadInboundMessage.java
new file mode 100644
index 000000000..6cbe35f0b
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/CancelDownloadInboundMessage.java
@@ -0,0 +1,45 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+/**
+ * Transfer object, encapsulating Cancel Download requests, received by the HawkBit consumer.
+ */
+@Builder
+@Data
+public class CancelDownloadInboundMessage implements InboundMessage {
+
+ private Headers headers;
+ private Body body;
+
+ @Builder
+ @Data
+ public static class Headers {
+ private String type;
+ private String thingId;
+ private String topic;
+ private String tenant;
+ }
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Builder
+ @Data
+ public static class Body {
+ private Long actionId;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/DownloadRequestInboundMessage.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/DownloadRequestInboundMessage.java
new file mode 100644
index 000000000..fdac5fcda
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/DownloadRequestInboundMessage.java
@@ -0,0 +1,112 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound;
+
+import java.util.Date;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+/**
+ * Transfer object, encapsulating Download Requests, received by the HawkBit consumer.
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class DownloadRequestInboundMessage implements InboundMessage {
+
+ private Body body;
+ private Headers headers;
+ private Long deliveryTag;
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class Body {
+ private Long actionId;
+ private String targetSecurityToken;
+ private List softwareModules;
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class SoftwareModule {
+ private Long moduleId;
+ private String moduleType;
+ private String moduleVersion;
+ private List artifacts;
+ private List metadata;
+ }
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class Artifact {
+ private String filename;
+ private Urls urls;
+ private Hashes hashes;
+ private Long size;
+ private Date lastModified;
+ }
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class Urls {
+ @JsonProperty("COAP")
+ private String COAP;
+ @JsonProperty("HTTP")
+ private String HTTP;
+ @JsonProperty("HTTPS")
+ private String HTTPS;
+ }
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class Hashes {
+ private String md5;
+ private String sha1;
+ }
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class Metadata {
+ private String key;
+ private String value;
+ }
+ }
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class Headers {
+ private String type;
+ private String thingId;
+ private String topic;
+ private String tenant;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/InboundMessage.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/InboundMessage.java
new file mode 100644
index 000000000..cb3080877
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/InboundMessage.java
@@ -0,0 +1,17 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound;
+
+
+/**
+ * Interface for all incoming AMQP message types.
+ */
+public interface InboundMessage {}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/MessageTypeInbound.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/MessageTypeInbound.java
new file mode 100644
index 000000000..8c6fd5a5d
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/MessageTypeInbound.java
@@ -0,0 +1,32 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound;
+
+
+/**
+ * Enum for inbound message type classification.
+ */
+public enum MessageTypeInbound {
+ EVENT("EVENT"),
+ THING_DELETED("THING_DELETED"),
+ PING_RESPONSE("PING_RESPONSE");
+
+ private final String stringValue;
+
+ private MessageTypeInbound(final String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ @Override
+ public String toString() {
+ return this.stringValue;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/ThingDeletedInboundMessage.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/ThingDeletedInboundMessage.java
new file mode 100644
index 000000000..39897c8bc
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/inbound/ThingDeletedInboundMessage.java
@@ -0,0 +1,29 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * Transfer object, encapsulating Thing Deleted messages, received by the HawkBit consumer.
+ */
+@Builder
+@Data
+public class ThingDeletedInboundMessage implements InboundMessage {
+ private Headers headers;
+
+ @Builder
+ @Data
+ public static class Headers {
+ private String thingId;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/MessageTypeOutbound.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/MessageTypeOutbound.java
new file mode 100644
index 000000000..d4881fbbb
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/MessageTypeOutbound.java
@@ -0,0 +1,32 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound;
+
+
+/**
+ * Enum for outbound message type classification.
+ */
+public enum MessageTypeOutbound {
+ EVENT("EVENT"),
+ THING_CREATED("THING_CREATED"),
+ THING_REMOVED("THING_REMOVED");
+
+ private final String stringValue;
+
+ private MessageTypeOutbound(final String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ @Override
+ public String toString() {
+ return this.stringValue;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/ThingCreatedOutboundMessage.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/ThingCreatedOutboundMessage.java
new file mode 100644
index 000000000..e5d21e4b8
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/ThingCreatedOutboundMessage.java
@@ -0,0 +1,84 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.MessageHeader;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+/**
+ * Transfer object, encapsulating THING_CREATED requests, sent by the HawkBit client.
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class ThingCreatedOutboundMessage {
+
+ @Valid
+ @NotNull
+ private Body body;
+
+ @Valid
+ @NotNull
+ private Headers headers;
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class Body {
+ private String name;
+ }
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class Headers {
+ @NotNull
+ private final String type = MessageTypeOutbound.THING_CREATED.toString();
+
+ @NotNull
+ private String thingId;
+
+ private String sender;
+
+ private String tenant;
+
+ public Map asMap() {
+ final HashMap headers = new HashMap<>();
+ if (this.type != null) {
+ headers.put(MessageHeader.TYPE.toString(), this.type);
+ }
+ if (this.thingId != null) {
+ headers.put(MessageHeader.THING_ID.toString(), this.thingId);
+ }
+ if (this.sender != null) {
+ headers.put(MessageHeader.SENDER.toString(), this.sender);
+ }
+ if (this.tenant != null) {
+ headers.put(MessageHeader.TENANT.toString(), this.tenant);
+ }
+
+ return headers;
+ }
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/ThingRemovedOutboundMessage.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/ThingRemovedOutboundMessage.java
new file mode 100644
index 000000000..84018aeff
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/ThingRemovedOutboundMessage.java
@@ -0,0 +1,55 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.validation.constraints.NotNull;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.MessageHeader;
+import lombok.Builder;
+import lombok.Data;
+
+
+/**
+ * Transfer object, encapsulating THING_REMOVED requests, sent by the HawkBit client.
+ */
+@Builder
+@Data
+public class ThingRemovedOutboundMessage {
+
+ @NotNull
+ private Headers headers;
+
+ @Builder
+ @Data
+ public static class Headers {
+ private final String type = MessageTypeOutbound.THING_REMOVED.toString();
+ private String thingId;
+ private String tenant;
+
+ public Map asMap() {
+ final HashMap headers = new HashMap<>();
+ if (this.type != null) {
+ headers.put(MessageHeader.TYPE.toString(), this.type);
+ }
+ if (this.thingId != null) {
+ headers.put(MessageHeader.THING_ID.toString(), this.thingId);
+ }
+ if (this.tenant != null) {
+ headers.put(MessageHeader.TENANT.toString(), this.tenant);
+ }
+
+ return headers;
+ }
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/UpdateActionStatusOutboundMessage.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/UpdateActionStatusOutboundMessage.java
new file mode 100644
index 000000000..0320d8a12
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/hawkbit/model/outbound/UpdateActionStatusOutboundMessage.java
@@ -0,0 +1,91 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.validation.ConstraintViolationException;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.ActionStatus;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.EventType;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.MessageHeader;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+/**
+ * Transfer object, encapsulating UPDATE_ACTION_STATUS requests, sent by the HawkBit client.
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class UpdateActionStatusOutboundMessage {
+
+ @Valid
+ @NotNull
+ private UpdateActionStatusOutboundMessageBody body;
+
+ @Valid
+ @NotNull
+ private UpdateActionStatusOutboundMessageHeaders headers;
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class UpdateActionStatusOutboundMessageBody {
+ @NotNull
+ private Long actionId;
+
+ @NotNull
+ private ActionStatus actionStatus;
+
+ private Long softwareModuleId;
+
+ private List message;
+ }
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ @Builder
+ public static class UpdateActionStatusOutboundMessageHeaders {
+ @NotNull
+ private final String type = MessageTypeOutbound.EVENT.toString();
+
+ @NotNull
+ private final String topic = EventType.UPDATE_ACTION_STATUS.toString();
+
+ private String tenant;
+
+ public Map asMap() throws ConstraintViolationException {
+ final HashMap headers = new HashMap<>();
+ if (this.type != null) {
+ headers.put(MessageHeader.TYPE.toString(), this.type);
+ }
+ if (this.topic != null) {
+ headers.put(MessageHeader.TOPIC.toString(), this.topic);
+ }
+ if (this.tenant != null) {
+ headers.put(MessageHeader.TENANT.toString(), this.tenant);
+ }
+
+ return headers;
+ }
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/model/HawkbitActionUpdateStatus.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/model/HawkbitActionUpdateStatus.java
new file mode 100644
index 000000000..4f176dafe
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/model/HawkbitActionUpdateStatus.java
@@ -0,0 +1,34 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.model;
+
+import java.util.List;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.ActionStatus;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * Internal model for representation of the update of a status of an action in hawkBit.
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class HawkbitActionUpdateStatus {
+
+ private Long actionId;
+ private Long softwareModuleId;
+ private ActionStatus actionStatus;
+ private List message;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/properties/SystemProperties.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/properties/SystemProperties.java
new file mode 100644
index 000000000..a2283d194
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/properties/SystemProperties.java
@@ -0,0 +1,74 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.properties;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import lombok.Data;
+
+/**
+ * This class provides all properties of the configuration system itself.
+ */
+@Data
+public class SystemProperties {
+
+ /**
+ * This is the address of the configuration system itself, e.g. "192.168.1.1" or
+ * "subdomain.domain.tld".
+ * It must be not blank (validated with {@link NotBlank @NotBlank}).
+ */
+ @NotBlank
+ private String address;
+
+ /**
+ * This is the port of the configuration system itself, e.g. 8447.
+ *
It must be not null (validated with {@link NotNull @NotNull}).
+ */
+ @NotNull
+ private Integer port;
+
+ /**
+ * This is the name of the configuration system itself, e.g. "HAWKBITCONFIGURATIONSYSTEM".
+ *
In the context of Arrowhead the system (provider) name and certificate common name must match.
+ *
It must be not blank (validated with {@link NotBlank @NotBlank}).
+ */
+ @NotBlank
+ private String name;
+
+ /**
+ * This is the protocol of the provided service from the configuration system itself, e.g. "HTTP-SECURE-JSON".
+ *
It must be not blank (validated with {@link NotBlank @NotBlank}).
+ */
+ @NotBlank
+ private String providedServiceInterface;
+
+ /**
+ * This is the definition of the provided service from the configuration system itself, e.g. "definition5".
+ *
It must be not blank (validated with {@link NotBlank @NotBlank}).
+ */
+ @NotBlank
+ private String providedServiceDefinition;
+
+ /**
+ * This is the uri of the provided service from the configuration system itself, e.g "/".
+ *
It must be not blank (validated with {@link NotBlank @NotBlank}).
+ */
+ @NotBlank
+ private String providedServiceUri;
+
+ /**
+ * This is the version of the provided service from the configuration system itself, e.g. 2.
+ *
It must be not null (validated with {@link NotNull @NotNull}).
+ */
+ @NotNull
+ private Integer providedServiceVersion;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/security/CidValidator.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/security/CidValidator.java
new file mode 100644
index 000000000..8e17f31f1
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/security/CidValidator.java
@@ -0,0 +1,33 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.security;
+
+import org.jose4j.jwt.JwtClaims;
+import org.jose4j.jwt.consumer.ErrorCodeValidator;
+import org.jose4j.jwt.consumer.ErrorCodes;
+import org.jose4j.jwt.consumer.JwtContext;
+
+/**
+ * The cid validator checks that the claim "cid" is available in a JWT.
+ */
+public class CidValidator implements ErrorCodeValidator {
+
+ @Override
+ public Error validate(final JwtContext jwtContext) {
+ final JwtClaims jwtClaims = jwtContext.getJwtClaims();
+ final Object clientIdentifier = jwtClaims.getClaimValue(JwtAuthenticationToken.CLIENT_IDENTIFIER_CLAIM);
+ if (clientIdentifier == null ) {
+ return new Error(ErrorCodes.MISCELLANEOUS, "No client identifier (cid) claim is present.");
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/security/JwtAuthenticationFilter.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/security/JwtAuthenticationFilter.java
new file mode 100644
index 000000000..b698ad82e
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/security/JwtAuthenticationFilter.java
@@ -0,0 +1,147 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.security;
+
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jose4j.jwa.AlgorithmConstraints;
+import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers;
+import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers;
+import org.jose4j.jws.AlgorithmIdentifiers;
+import org.jose4j.jwt.JwtClaims;
+import org.jose4j.jwt.consumer.InvalidJwtException;
+import org.jose4j.jwt.consumer.JwtConsumer;
+import org.jose4j.jwt.consumer.JwtConsumerBuilder;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import eu.arrowhead.core.hbconfmgr.service.ArrowheadService;
+import lombok.extern.log4j.Log4j2;
+
+/**
+ * Implementation of JWT authentication filter for Spring Security. It supports bearer tokens (JWT) in the standard
+ * HTTP authentication header "Authorization". A subject is authenticated if it provides a valid JWT with all required
+ * claims according to {@link #validateJwtAndRetrieveClaims(String, PublicKey, PrivateKey)}.
+ */
+@Log4j2
+public class JwtAuthenticationFilter extends OncePerRequestFilter {
+
+ private static final String RSA = "RSA";
+
+ /**
+ * The value of the header "Authorization" must start with "Bearer " according to
+ * RFC6750.
+ */
+ private static final String AUTHENTICATION_SCHEME_BEARER = "Bearer ";
+
+ private final ArrowheadService arrowheadService;
+ private final PrivateKey hawkbitConfigurationSystemPrivateKey;
+ private PublicKey authorizationSystemPublicKey;
+
+ /**
+ * A filter for validation JWT.
+ *
+ * @param arrowheadService required to receive the public key for JWT validation
+ * @param configurationSystemPrivateKey the private key for JWT encryption
+ */
+ public JwtAuthenticationFilter(final ArrowheadService arrowheadService, final PrivateKey configurationSystemPrivateKey) {
+ this.arrowheadService = arrowheadService;
+ this.hawkbitConfigurationSystemPrivateKey = configurationSystemPrivateKey;
+ init();
+ }
+
+ private void init() {
+ try {
+ final String authorizationSystemPublicKeyString = arrowheadService.receiveAuthorizationSystemPublicKey();
+ this.authorizationSystemPublicKey = loadPublicKeyFromString(authorizationSystemPublicKeyString);
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ log.error("Public key from JWT provider couldn't be loaded", e);
+ }
+ }
+
+ @Override
+ protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws IOException, ServletException {
+ final String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
+
+ if (this.authorizationSystemPublicKey == null || authorizationHeader == null || !authorizationHeader.startsWith(AUTHENTICATION_SCHEME_BEARER)) {
+ log.debug("No bearer token found");
+ chain.doFilter(request, response);
+ return;
+ }
+ final String clientJwtString = authorizationHeader.replaceFirst(AUTHENTICATION_SCHEME_BEARER, "");
+
+ try {
+
+ final SecurityContext context = SecurityContextHolder.createEmptyContext();
+ final JwtClaims clientJwtClaims = validateJwtAndRetrieveClaims(clientJwtString, this.authorizationSystemPublicKey, this.hawkbitConfigurationSystemPrivateKey);
+ final JwtAuthenticationToken authentication = new JwtAuthenticationToken(clientJwtClaims, true);
+ context.setAuthentication(authentication);
+
+ SecurityContextHolder.setContext(context);
+ } catch (final InvalidJwtException e) {
+ log.error("The provided JWT is not valid", e);
+ } finally {
+ chain.doFilter(request, response);
+ }
+ }
+
+ /**
+ * Validates a JWT and retrieves it claims.
+ *
+ * @param clientJwt the JWT that should be validated
+ * @param publicKey the public key for verification of the JWT
+ * @param privateKey the private key for encryption of the JWT
+ * @return on success: all claims of the JWT
+ * @throws InvalidJwtException if the JWT is not valid
+ */
+ private JwtClaims validateJwtAndRetrieveClaims(final String clientJwt, final PublicKey publicKey, final PrivateKey privateKey) throws InvalidJwtException {
+ final JwtConsumer jwtConsumer = new JwtConsumerBuilder()
+ .registerValidator(new CidValidator())
+ .setRequireJwtId()
+ .setRequireNotBefore()
+ .setEnableRequireEncryption()
+ .setEnableRequireIntegrity()
+ .setDecryptionKey(privateKey)
+ .setVerificationKey(publicKey)
+ .setJwsAlgorithmConstraints(new AlgorithmConstraints(
+ AlgorithmConstraints.ConstraintType.WHITELIST,
+ AlgorithmIdentifiers.RSA_USING_SHA512))
+ .setJweAlgorithmConstraints(new AlgorithmConstraints(
+ AlgorithmConstraints.ConstraintType.WHITELIST,
+ KeyManagementAlgorithmIdentifiers.RSA_OAEP_256))
+ .setJweContentEncryptionAlgorithmConstraints(new AlgorithmConstraints(
+ AlgorithmConstraints.ConstraintType.WHITELIST,
+ ContentEncryptionAlgorithmIdentifiers.AES_256_CBC_HMAC_SHA_512))
+ .build();
+
+ return jwtConsumer.processToClaims(clientJwt);
+ }
+
+ private PublicKey loadPublicKeyFromString(final String publicKeyString) throws NoSuchAlgorithmException, InvalidKeySpecException {
+ final KeyFactory kf = KeyFactory.getInstance(RSA);
+ final byte[] keyBytes = Base64.getDecoder().decode(publicKeyString);
+ return kf.generatePublic(new X509EncodedKeySpec(keyBytes));
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/security/JwtAuthenticationToken.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/security/JwtAuthenticationToken.java
new file mode 100644
index 000000000..1e86612e4
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/security/JwtAuthenticationToken.java
@@ -0,0 +1,55 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.security;
+
+import org.jose4j.jwt.JwtClaims;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+
+public class JwtAuthenticationToken extends AbstractAuthenticationToken {
+ private static final long serialVersionUID = 1L;
+
+ public static final String CLIENT_IDENTIFIER_CLAIM = "cid";
+
+ private final String clientIdentifier;
+ private final JwtClaims jwtClaims;
+
+ /**
+ * Creates a JWT (JSON Web Token) authentication token that can be used in the context of Spring Security.
+ *
+ * @param jwtClaims the claims of the JWT itself
+ * @param authenticated if the JWT is already validated and therefore authenticated
+ */
+ public JwtAuthenticationToken(final JwtClaims jwtClaims, final boolean authenticated) {
+ super(null);
+ this.jwtClaims = jwtClaims;
+ this.clientIdentifier = String.valueOf(jwtClaims.getClaimValue(CLIENT_IDENTIFIER_CLAIM));
+ super.setAuthenticated(authenticated);
+ }
+
+ /**
+ *
+ * @return the client identifier (cid claim) of the JWT
+ */
+ @Override
+ public String getName() {
+ return this.clientIdentifier;
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return this.jwtClaims;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return this.jwtClaims.toString();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/service/ArrowheadService.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/service/ArrowheadService.java
new file mode 100644
index 000000000..1010f538d
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/service/ArrowheadService.java
@@ -0,0 +1,42 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import eu.arrowhead.core.hbconfmgr.arrowhead.ArrowheadAuthorizationSystemClient;
+
+/**
+ * This is the Arrowhead service that implements business logic specifically for the configuration system.
+ */
+@Service
+public class ArrowheadService {
+
+ private final ArrowheadAuthorizationSystemClient authorizationSystemClient;
+
+ @Autowired
+ public ArrowheadService(final ArrowheadAuthorizationSystemClient arrowheadAuthorizationSystemClient) {
+ this.authorizationSystemClient = arrowheadAuthorizationSystemClient;
+ }
+
+ /**
+ * Returns the public key of the Arrowhead authorization system. The public key is used for validating JWT issued
+ * by the authorization system itself.
+ *
+ * The result of this method is cached, the configuration for caching can be found in resources/ehcache.xml.
+ *
+ * @return public key of Arrowhead authorization system
+ */
+ public String receiveAuthorizationSystemPublicKey() {
+ return this.authorizationSystemClient.getPublicKey();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/service/HawkbitService.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/service/HawkbitService.java
new file mode 100644
index 000000000..4124a9c29
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/service/HawkbitService.java
@@ -0,0 +1,111 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.service;
+
+import java.io.IOException;
+
+import javax.validation.ConstraintViolationException;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import eu.arrowhead.core.hbconfmgr.Constants;
+import eu.arrowhead.core.hbconfmgr.hawkbit.HawkbitDmfOutboundClient;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound.ThingCreatedOutboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound.ThingRemovedOutboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound.UpdateActionStatusOutboundMessage;
+import eu.arrowhead.core.hbconfmgr.model.HawkbitActionUpdateStatus;
+import lombok.extern.log4j.Log4j2;
+
+/**
+ * This is the hawkBit service that implements business logic specifically for
+ * the configuration system.
+ */
+@Log4j2
+@Service
+public class HawkbitService {
+
+ private final HawkbitDmfOutboundClient hawkbitDmfClient;
+ private final String hawkbitTenant;
+
+ @Autowired
+ public HawkbitService(@Value(Constants.HAWKBIT_TENANT) final String hawkbitTenant, final HawkbitDmfOutboundClient hawkbitDmfClient) {
+ this.hawkbitDmfClient = hawkbitDmfClient;
+ this.hawkbitTenant = hawkbitTenant;
+ }
+
+ /**
+ * Create a new device in HawkBit.
+ *
+ * @param deviceId the id of the device that should be create
+ */
+ public void createDevice(final String deviceId) {
+ try {
+ final ThingCreatedOutboundMessage message = ThingCreatedOutboundMessage.builder()
+ .body(
+ ThingCreatedOutboundMessage.Body.builder()
+ .name(deviceId)
+ .build()
+ )
+ .headers(
+ ThingCreatedOutboundMessage.Headers.builder()
+ .thingId(deviceId)
+ .tenant(hawkbitTenant)
+ .build()
+ )
+ .build();
+ this.hawkbitDmfClient.createThing(message);
+ } catch (final IOException e) {
+ log.error("Creating new device was not possible", e);
+ }
+ }
+
+ public void removeDevice(final String deviceId) {
+ final ThingRemovedOutboundMessage message = ThingRemovedOutboundMessage.builder()
+ .headers(
+ ThingRemovedOutboundMessage.Headers.builder()
+ .thingId(deviceId)
+ .tenant(hawkbitTenant)
+ .build()
+ )
+ .build();
+
+ try {
+ this.hawkbitDmfClient.removeThing(message);
+ } catch (final IOException e) {
+ log.error("Deleting the device was not possible", e);
+ }
+ }
+
+ /**
+ * Update the status of an action in hawkBit.
+ *
+ * @param actionUpdateStatus contains the information for the new status of an
+ * action
+ * @throws ConstraintViolationException if a specification for sending a message
+ * to hawkBit is not adhered
+ * @throws IOException if there is a connection problem with
+ * hawkBit
+ */
+ public void updateActionStatus(final HawkbitActionUpdateStatus actionUpdateStatus) throws ConstraintViolationException, IOException {
+ final UpdateActionStatusOutboundMessage message = UpdateActionStatusOutboundMessage.builder()
+ .body(UpdateActionStatusOutboundMessage.UpdateActionStatusOutboundMessageBody.builder()
+ .actionId(actionUpdateStatus.getActionId())
+ .actionStatus(actionUpdateStatus.getActionStatus())
+ .softwareModuleId(actionUpdateStatus.getSoftwareModuleId())
+ .message(actionUpdateStatus.getMessage()).build())
+ .headers(UpdateActionStatusOutboundMessage.UpdateActionStatusOutboundMessageHeaders.builder()
+ .tenant(hawkbitTenant).build())
+ .build();
+ this.hawkbitDmfClient.updateActionStatus(message);
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/service/WebSocketService.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/service/WebSocketService.java
new file mode 100644
index 000000000..41081f3d8
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/service/WebSocketService.java
@@ -0,0 +1,80 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.service;
+
+import java.io.IOException;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.CancelDownloadInboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.DownloadRequestInboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.MessageTypeInbound;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.ThingDeletedInboundMessage;
+import eu.arrowhead.core.hbconfmgr.websocket.DeviceNotConnectedException;
+import eu.arrowhead.core.hbconfmgr.websocket.WebSocketSender;
+import eu.arrowhead.core.hbconfmgr.websocket.model.DeviceMessage;
+import lombok.extern.log4j.Log4j2;
+
+/**
+ * This is the web socket service that implements business logic specifically
+ * for the configuration system.
+ */
+@Log4j2
+@Service
+public class WebSocketService {
+
+ private final WebSocketSender wsSender;
+
+ @Autowired
+ public WebSocketService(final WebSocketSender wsSender) throws IOException {
+ this.wsSender = wsSender;
+ }
+
+ public void sendDownloadEventMessage(final DownloadRequestInboundMessage message) throws IOException, DeviceNotConnectedException {
+ log.debug("Message {}", message);
+
+ final String clientId = message.getHeaders().getThingId();
+
+ final DeviceMessage deviceMessage = DeviceMessage.builder()
+ .type(MessageTypeInbound.EVENT.toString())
+ .message(message)
+ .build();
+
+ this.wsSender.sendMessage(clientId, deviceMessage);
+ }
+
+ public void sendThingDeletedMessage(final ThingDeletedInboundMessage message) throws IOException, DeviceNotConnectedException {
+ log.debug("Message {}", message);
+
+ final String clientId = message.getHeaders().getThingId();
+
+ final DeviceMessage deviceMessage = DeviceMessage.builder()
+ .type(MessageTypeInbound.THING_DELETED.toString())
+ .message(message)
+ .build();
+
+ this.wsSender.sendMessage(clientId, deviceMessage);
+ }
+
+ public void sendCancelDownloadMessage(final CancelDownloadInboundMessage message) throws IOException, DeviceNotConnectedException {
+ log.debug("Message {}", message);
+
+ final String clientId = message.getHeaders().getThingId();
+
+ final DeviceMessage deviceMessage = DeviceMessage.builder()
+ .type(MessageTypeInbound.EVENT.toString())
+ .message(message)
+ .build();
+
+ this.wsSender.sendMessage(clientId, deviceMessage);
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/DeviceNotConnectedException.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/DeviceNotConnectedException.java
new file mode 100644
index 000000000..cc44aac99
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/DeviceNotConnectedException.java
@@ -0,0 +1,30 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.websocket;
+
+public class DeviceNotConnectedException extends Exception {
+ private static final long serialVersionUID = 7329483234L;
+
+ public DeviceNotConnectedException() { super(); }
+ public DeviceNotConnectedException(final String message) { super(message); }
+ public DeviceNotConnectedException(final String message, final Throwable cause) { super(message, cause); }
+ public DeviceNotConnectedException(final Throwable cause) { super(cause); }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketController.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketController.java
new file mode 100644
index 000000000..a91ec010e
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketController.java
@@ -0,0 +1,73 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.websocket;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import eu.arrowhead.core.hbconfmgr.service.HawkbitService;
+import eu.arrowhead.core.hbconfmgr.websocket.model.ActionUpdateStatusMapper;
+import eu.arrowhead.core.hbconfmgr.websocket.model.UpdateActionRequestDTO;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.handler.AbstractWebSocketHandler;
+
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+@Controller
+public class WebSocketController extends AbstractWebSocketHandler {
+
+ private final HawkbitService hawkbitService;
+ private final ObjectMapper objectMapper;
+ private final Map webSocketSessionMap;
+
+ @Autowired
+ public WebSocketController(final HawkbitService hawkbitService, final Map webSocketSessionMap) {
+ this.objectMapper = new ObjectMapper();
+ this.hawkbitService = hawkbitService;
+ this.webSocketSessionMap = webSocketSessionMap;
+ }
+
+ @Override
+ public void afterConnectionEstablished(final WebSocketSession session) throws IOException {
+ if (session.getPrincipal() != null) {
+ final String clientId = session.getPrincipal().getName();
+ this.hawkbitService.createDevice(clientId);
+ this.webSocketSessionMap.put(clientId, session);
+ } else {
+ session.close();
+ }
+ }
+
+ @Override
+ public void afterConnectionClosed(final WebSocketSession session, final CloseStatus status) {
+ if (session.getPrincipal() != null) {
+ this.webSocketSessionMap.remove(session.getPrincipal().getName());
+ }
+ }
+
+ @Override
+ protected void handleTextMessage(final WebSocketSession session, final TextMessage message) {
+ try {
+ final UpdateActionRequestDTO request = objectMapper.readValue(message.getPayload(), UpdateActionRequestDTO.class);
+ this.hawkbitService.updateActionStatus(ActionUpdateStatusMapper.mapToActionUpdateStatus(request));
+ } catch (final Exception e) {
+ log.error("Web socket text message could not be handled", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketSender.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketSender.java
new file mode 100644
index 000000000..1802fa924
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketSender.java
@@ -0,0 +1,51 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.websocket;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import eu.arrowhead.core.hbconfmgr.Constants;
+import eu.arrowhead.core.hbconfmgr.websocket.model.DeviceMessage;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+
+@DependsOn(Constants.GUARD_BEAN)
+@Component
+public class WebSocketSender {
+
+ private final Map webSocketSessionMap;
+ private final ObjectMapper objectMapper;
+
+ @Autowired
+ public WebSocketSender(final Map webSocketSessionMap) {
+ this.webSocketSessionMap = webSocketSessionMap;
+ this.objectMapper = new ObjectMapper();
+ }
+
+ public void sendMessage(final String thingId, final DeviceMessage message) throws IOException, DeviceNotConnectedException {
+ if (this.webSocketSessionMap.containsKey(thingId)) {
+ final String body = this.objectMapper.writeValueAsString(message);
+ final TextMessage wsMessage = new TextMessage(body);
+
+ final WebSocketSession session = this.webSocketSessionMap.get(thingId);
+ session.sendMessage(wsMessage);
+ } else {
+ throw new DeviceNotConnectedException("The device " + thingId + " is currently not connected.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/model/ActionUpdateStatusMapper.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/model/ActionUpdateStatusMapper.java
new file mode 100644
index 000000000..d3c586ac0
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/model/ActionUpdateStatusMapper.java
@@ -0,0 +1,30 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.websocket.model;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.ActionStatus;
+import eu.arrowhead.core.hbconfmgr.model.HawkbitActionUpdateStatus;
+
+public class ActionUpdateStatusMapper {
+
+ private ActionUpdateStatusMapper() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static HawkbitActionUpdateStatus mapToActionUpdateStatus(final UpdateActionRequestDTO input) throws IllegalArgumentException {
+ return HawkbitActionUpdateStatus.builder()
+ .actionId(input.getActionId())
+ .actionStatus(ActionStatus.valueOf(input.getActionStatus()))
+ .message(input.getMessage())
+ .softwareModuleId(input.getSoftwareModuleId())
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/model/DeviceMessage.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/model/DeviceMessage.java
new file mode 100644
index 000000000..d5f304ce5
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/model/DeviceMessage.java
@@ -0,0 +1,23 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.websocket.model;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.InboundMessage;
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+public class DeviceMessage {
+
+ private final String type;
+ private InboundMessage message;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/model/UpdateActionRequestDTO.java b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/model/UpdateActionRequestDTO.java
new file mode 100644
index 000000000..ad46d1051
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/java/eu/arrowhead/core/hbconfmgr/websocket/model/UpdateActionRequestDTO.java
@@ -0,0 +1,30 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.websocket.model;
+
+import java.util.List;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class UpdateActionRequestDTO {
+
+ private Long actionId;
+ private Long softwareModuleId;
+ private String actionStatus;
+ private List message;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/hawkbit-configuration-manager/src/main/resources/META-INF/additional-spring-configuration-metadata.json
new file mode 100644
index 000000000..3167764e8
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -0,0 +1,72 @@
+{"properties": [
+ {
+ "name": "system.name",
+ "type": "java.lang.String",
+ "description": "A description for 'system.name'"
+ },
+ {
+ "name": "system.port",
+ "type": "java.lang.Integer",
+ "description": "A description for 'system.port'"
+ },
+ {
+ "name": "system.providedServiceInterface",
+ "type": "java.lang.String",
+ "description": "A description for 'system.providedServiceInterface'"
+ },
+ {
+ "name": "system.providedServiceDefinition",
+ "type": "java.lang.String",
+ "description": "A description for 'system.providedServiceDefinition'"
+ },
+ {
+ "name": "system.providedServiceVersion",
+ "type": "java.lang.Integer",
+ "description": "A description for 'system.providedServiceVersion'"
+ },
+ {
+ "name": "system.providedServiceUri",
+ "type": "java.lang.String",
+ "description": "A description for 'system.providedServiceUri'"
+ },
+ {
+ "name": "sr_address",
+ "type": "java.lang.String",
+ "description": "A description for 'sr_address'"
+ },
+ {
+ "name": "sr_port",
+ "type": "java.lang.Integer",
+ "description": "A description for 'sr_port'"
+ },
+ {
+ "name": "hawkbit.host",
+ "type": "java.lang.String",
+ "description": "A description for 'hawkbit.host'"
+ },
+ {
+ "name": "hawkbit.port",
+ "type": "java.lang.Integer",
+ "description": "A description for 'hawkbit.port'"
+ },
+ {
+ "name": "hawkbit.username",
+ "type": "java.lang.String",
+ "description": "A description for 'hawkbit.username'"
+ },
+ {
+ "name": "hawkbit.password",
+ "type": "java.lang.String",
+ "description": "A description for 'hawkbit.password'"
+ },
+ {
+ "name": "hawkbit.tenant",
+ "type": "java.lang.String",
+ "description": "A description for 'hawkbit.tenant'"
+ },
+ {
+ "name": "system.address",
+ "type": "java.lang.String",
+ "description": "A description for 'system.address'"
+ }
+]}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/resources/application.properties b/hawkbit-configuration-manager/src/main/resources/application.properties
new file mode 100644
index 000000000..0409c7ace
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/resources/application.properties
@@ -0,0 +1,56 @@
+############################################
+### APPLICATION PARAMETERS ###
+############################################
+
+# Hawkbit Configuration Manager web-server parameters
+server.address=0.0.0.0
+server.port=8447
+
+############################################
+### CUSTOM PARAMETERS ###
+############################################
+
+# These are the properties of the configuration system itself
+# The properties are loaded into the class eu.arrowhead.core.hbconfmgr.properties.SystemProperties
+system.name=HAWKBITCONFIGURATIONMANAGER
+system.address=127.0.0.1
+system.port=8447
+# This is the protocol of the provided service from the configuration system itself, e.g. "HTTP-SECURE-JSON"
+system.providedServiceInterface=HTTP-SECURE-JSON
+# This is the definition of the provided service from the configuration system itself, e.g. "definition5"
+system.providedServiceDefinition=definition1
+# This is the uri of the provided service from the configuration system itself, e.g "/"
+system.providedServiceUri=/
+# This is the version of the provided service from the configuration system itself, e.g. 2
+system.providedServiceVersion=1
+
+# Service Registry web-server parameters
+sr_address=127.0.0.1
+sr_port=8443
+
+# These are the connection parameters for the hawkBit DMF API
+hawkbit.host=localhost
+hawkbit.port=5672
+hawkbit.username=guest
+hawkbit.password=guest
+# This is the tenant in hawkBit itself
+hawkbit.tenant=DEFAULT
+
+##########################################
+### SECURE MODE ###
+############################################
+
+# configure secure mode
+
+# This system works only in secure mode. Do not modify this property.
+server.ssl.enabled=true
+
+server.ssl.key-store-type=PKCS12
+server.ssl.key-store=classpath:certificates/hawkbitconfigurationmanager.p12
+server.ssl.key-store-password=123456
+server.ssl.key-alias=hawkbitconfigurationmanager
+server.ssl.key-password=123456
+server.ssl.client-auth=need
+server.ssl.trust-store-type=PKCS12
+server.ssl.trust-store=classpath:certificates/truststore.p12
+server.ssl.trust-store-password=123456
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/main/resources/certificates/hawkbitconfigurationmanager.p12 b/hawkbit-configuration-manager/src/main/resources/certificates/hawkbitconfigurationmanager.p12
new file mode 100644
index 000000000..d7560b726
Binary files /dev/null and b/hawkbit-configuration-manager/src/main/resources/certificates/hawkbitconfigurationmanager.p12 differ
diff --git a/hawkbit-configuration-manager/src/main/resources/certificates/truststore.p12 b/hawkbit-configuration-manager/src/main/resources/certificates/truststore.p12
new file mode 100644
index 000000000..567814b1e
Binary files /dev/null and b/hawkbit-configuration-manager/src/main/resources/certificates/truststore.p12 differ
diff --git a/hawkbit-configuration-manager/src/main/resources/log4j2.xml b/hawkbit-configuration-manager/src/main/resources/log4j2.xml
new file mode 100644
index 000000000..692f06f1c
--- /dev/null
+++ b/hawkbit-configuration-manager/src/main/resources/log4j2.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex
+
+ INFO
+ .
+
+
+
+
+
+
+
+ ${LOG_PATTERN}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadAuthorizationSystemClientTest.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadAuthorizationSystemClientTest.java
new file mode 100644
index 000000000..5101802a5
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadAuthorizationSystemClientTest.java
@@ -0,0 +1,48 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.Test;
+
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
+
+public class ArrowheadAuthorizationSystemClientTest {
+
+ @Test
+ public void givenPublicKeyIsAvailable_whenGetPublicKey_thenPublicKeyReceived() throws Exception {
+ final MockWebServer mockWebServer = new MockWebServer();
+ mockWebServer.enqueue(new MockResponse()
+ .setResponseCode(200)
+ .addHeader("Content-Type", "application/json")
+ .setBody("\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvmaFymz4cSB+LP3pixhhgrczq8G2rWTMyyajMQNSXOuvGDBhB7S32rl/+B8VUvTrYBx7ab8AM/TxrDwWAzsQ3p3oo0+5NNibHpZ8QucWIXqbpQqFobiNWx+ogoBLV4UfJekxXYH54QrTdwkvlOFXxjkL11uwBKEsZ0TzKgGaRs+iR80sjDeicnpPlMm0RbpXjx10OzmjqfC1Wrusyl2gjsW9ySfwJ1461n6cPndn8csvC37IHdHpkKTRlcDDPG6/GN3+vfUeznA7zGFWv2IOTzsuruehXaOuDNgekvREK3Xh4BpvGTZ6oEFVmr5853U3PS6ExKlvwR8NwFiPXI9LAQIDAQAB\""));
+ mockWebServer.start();
+
+ final String baseUrl = mockWebServer.url("").toString();
+ final ArrowheadAuthorizationSystemClient client = new ArrowheadAuthorizationSystemClient(baseUrl);
+
+ final String publicKey = client.getPublicKey();
+
+ final RecordedRequest recordedRequest = mockWebServer.takeRequest(10, TimeUnit.SECONDS);
+ assertThat(recordedRequest).isNotNull();
+ assertThat(recordedRequest.getMethod()).isEqualTo("GET");
+ assertThat(recordedRequest.getPath()).isEqualTo("/authorization/publickey");
+
+ assertThat(publicKey).isEqualTo("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvmaFymz4cSB+LP3pixhhgrczq8G2rWTMyyajMQNSXOuvGDBhB7S32rl/+B8VUvTrYBx7ab8AM/TxrDwWAzsQ3p3oo0+5NNibHpZ8QucWIXqbpQqFobiNWx+ogoBLV4UfJekxXYH54QrTdwkvlOFXxjkL11uwBKEsZ0TzKgGaRs+iR80sjDeicnpPlMm0RbpXjx10OzmjqfC1Wrusyl2gjsW9ySfwJ1461n6cPndn8csvC37IHdHpkKTRlcDDPG6/GN3+vfUeznA7zGFWv2IOTzsuruehXaOuDNgekvREK3Xh4BpvGTZ6oEFVmr5853U3PS6ExKlvwR8NwFiPXI9LAQIDAQAB");
+
+ mockWebServer.close();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadServiceRegistryClientTest.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadServiceRegistryClientTest.java
new file mode 100644
index 000000000..d6c6cfc6a
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/ArrowheadServiceRegistryClientTest.java
@@ -0,0 +1,248 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.catchThrowableOfType;
+
+import java.util.Collections;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
+import javax.validation.ConstraintViolationException;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.skyscreamer.jsonassert.JSONCompareMode;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.request.ServiceRegistryRequestDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.request.SystemRequestDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.ServiceDefinitionResponseDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.ServiceInterfaceResponseDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.ServiceRegistryResponseDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.SystemResponseDTO;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
+
+public class ArrowheadServiceRegistryClientTest {
+
+ private static Locale defaultLocale;
+
+ @BeforeAll
+ public static void setUp() {
+ defaultLocale = Locale.getDefault();
+ Locale.setDefault(Locale.UK);
+ }
+
+ @AfterAll
+ public static void tearDown() {
+ Locale.setDefault(defaultLocale);
+ }
+
+ @Test
+ public void givenServiceIsNotRegistered_whenRegisterService_thenServiceIsRegistered() throws Exception {
+ final MockWebServer mockWebServer = new MockWebServer();
+ mockWebServer.enqueue(new MockResponse()
+ .setResponseCode(201)
+ .addHeader("Content-Type", "application/json")
+ .setBody("{\n" +
+ " \"id\": 22,\n" +
+ " \"serviceDefinition\": {\n" +
+ " \"id\": 7,\n" +
+ " \"serviceDefinition\": \"definition3\",\n" +
+ " \"createdAt\": \"2020-04-21T11:27:39Z\",\n" +
+ " \"updatedAt\": \"2020-04-21T11:27:39Z\"\n" +
+ " },\n" +
+ " \"provider\": {\n" +
+ " \"id\": 9,\n" +
+ " \"systemName\": \"conf-system\",\n" +
+ " \"address\": \"192.168.1.1\",\n" +
+ " \"port\": 1234,\n" +
+ " \"authenticationInfo\": \"test\",\n" +
+ " \"createdAt\": \"2020-05-05T06:37:19Z\",\n" +
+ " \"updatedAt\": \"2020-05-05T06:37:19Z\"\n" +
+ " },\n" +
+ " \"serviceUri\": \"/\",\n" +
+ " \"secure\": \"TOKEN\",\n" +
+ " \"version\": 1,\n" +
+ " \"interfaces\": [{\n" +
+ " \"id\": 3,\n" +
+ " \"interfaceName\": \"HTTP-SECURE-JSON\",\n" +
+ " \"createdAt\": \"2020-04-21T11:27:39Z\",\n" +
+ " \"updatedAt\": \"2020-04-21T11:27:39Z\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"createdAt\": \"2020-05-05T06:37:19Z\",\n" +
+ " \"updatedAt\": \"2020-05-05T06:37:19Z\"\n" +
+ "}"));
+ mockWebServer.start();
+
+ final String baseUrl = mockWebServer.url("").toString();
+ final ArrowheadServiceRegistryClient client = new ArrowheadServiceRegistryClient(baseUrl);
+ final ServiceRegistryRequestDTO requestDTO = ServiceRegistryRequestDTO.builder()
+ .serviceDefinition("definition3")
+ .providerSystem(SystemRequestDTO.builder()
+ .systemName("conf-system")
+ .address("192.168.1.1")
+ .port(1234)
+ .authenticationInfo("test")
+ .build())
+ .serviceUri("/")
+ .secure(ServiceRegistryRequestDTO.SecurityLevel.TOKEN)
+ .version(1)
+ .interfaces(Collections.singletonList("HTTP-SECURE-JSON"))
+ .build();
+ final ServiceRegistryResponseDTO responseDTO = client.registerService(requestDTO);
+
+ final RecordedRequest recordedRequest = mockWebServer.takeRequest(10, TimeUnit.SECONDS);
+ assertThat(recordedRequest).isNotNull();
+ assertThat(recordedRequest.getMethod()).isEqualTo("POST");
+ assertThat(recordedRequest.getPath()).isEqualTo("/serviceregistry/register");
+ JSONAssert.assertEquals("{\n" +
+ " \"serviceDefinition\": \"definition3\",\n" +
+ " \"providerSystem\": {\n" +
+ " \"systemName\": \"conf-system\",\n" +
+ " \"address\": \"192.168.1.1\",\n" +
+ " \"port\": 1234,\n" +
+ " \"authenticationInfo\": \"test\",\n" +
+ " \"metadata\": null\n" +
+ " },\n" +
+ " \"serviceUri\": \"/\",\n" +
+ " \"endOfValidity\": null,\n" +
+ " \"secure\": \"TOKEN\",\n" +
+ " \"metadata\": null,\n" +
+ " \"version\": 1,\n" +
+ " \"interfaces\": [\"HTTP-SECURE-JSON\"]\n" +
+ "}", recordedRequest.getBody().readUtf8(), JSONCompareMode.NON_EXTENSIBLE);
+
+ assertThat(responseDTO).isEqualTo(ServiceRegistryResponseDTO.builder()
+ .id(22L)
+ .serviceDefinition(ServiceDefinitionResponseDTO.builder()
+ .id(7L)
+ .serviceDefinition("definition3")
+ .createdAt("2020-04-21T11:27:39Z")
+ .updatedAt("2020-04-21T11:27:39Z")
+ .build())
+ .provider(SystemResponseDTO.builder()
+ .id(9L)
+ .systemName("conf-system")
+ .address("192.168.1.1")
+ .port(1234)
+ .authenticationInfo("test")
+ .createdAt("2020-05-05T06:37:19Z")
+ .updatedAt("2020-05-05T06:37:19Z")
+ .build())
+ .serviceUri("/")
+ .secure("TOKEN")
+ .version(1)
+ .interfaces(Collections.singletonList(ServiceInterfaceResponseDTO.builder()
+ .id(3L)
+ .interfaceName("HTTP-SECURE-JSON")
+ .createdAt("2020-04-21T11:27:39Z")
+ .updatedAt("2020-04-21T11:27:39Z")
+ .build()))
+ .createdAt("2020-05-05T06:37:19Z")
+ .updatedAt("2020-05-05T06:37:19Z")
+ .build());
+ mockWebServer.close();
+ }
+
+ @Test
+ public void givenServiceIsAlreadyRegistered_whenRegisterService_thenWebClientResponseExceptionIsThrown() throws Exception {
+ final MockWebServer mockWebServer = new MockWebServer();
+ mockWebServer.enqueue(new MockResponse()
+ .setResponseCode(400)
+ .addHeader("Content-Type", "application/json")
+ .setBody("{\n" +
+ " \"errorMessage\": \"Service Registry entry with provider: (conf-system, 192.168.1.1:1234) and service definition: definition3 already exists.\",\n" +
+ " \"errorCode\": 400,\n" +
+ " \"exceptionType\": \"INVALID_PARAMETER\"\n" +
+ "}"));
+ mockWebServer.start();
+
+ final String baseUrl = mockWebServer.url("").toString();
+ final ArrowheadServiceRegistryClient client = new ArrowheadServiceRegistryClient(baseUrl);
+ final ServiceRegistryRequestDTO requestDTO = ServiceRegistryRequestDTO.builder()
+ .serviceDefinition("definition3")
+ .providerSystem(SystemRequestDTO.builder()
+ .systemName("conf-system")
+ .address("192.168.1.1")
+ .port(1234)
+ .authenticationInfo("test")
+ .build())
+ .serviceUri("/")
+ .secure(ServiceRegistryRequestDTO.SecurityLevel.TOKEN)
+ .version(1)
+ .interfaces(Collections.singletonList("HTTP-SECURE-JSON"))
+ .build();
+
+ final WebClientResponseException exception = catchThrowableOfType(() ->
+ client.registerService(requestDTO), WebClientResponseException.class);
+
+ assertThat(exception).hasMessageContaining("400 Bad Request from POST");
+ assertThat(exception.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
+
+ mockWebServer.close();
+ }
+
+ @Test
+ public void givenServiceRegistryRequestDTOIsInvalid_whenRegisterService_thenConstraintViolationExceptionIsThrown() throws Exception {
+ final MockWebServer mockWebServer = new MockWebServer();
+ mockWebServer.start();
+
+ final String baseUrl = mockWebServer.url("").toString();
+ final ArrowheadServiceRegistryClient client = new ArrowheadServiceRegistryClient(baseUrl);
+ final ServiceRegistryRequestDTO requestDTO = ServiceRegistryRequestDTO.builder().build();
+
+ assertThatThrownBy(() -> client.registerService(requestDTO))
+ .isInstanceOf(ConstraintViolationException.class)
+ .hasMessageContaining("providerSystem: must not be null")
+ .hasMessageContaining("serviceDefinition: must not be null")
+ .hasMessageContaining("interfaces: must not be empty")
+ .hasMessageContaining("serviceUri: must not be null");
+ assertThat(mockWebServer.getRequestCount()).isZero();
+
+ mockWebServer.close();
+ }
+
+ @Test
+ public void givenSystemRequestDTOIsInvalid_whenRegisterService_thenConstraintViolationExceptionIsThrown() throws Exception {
+ final MockWebServer mockWebServer = new MockWebServer();
+ mockWebServer.start();
+
+ final String baseUrl = mockWebServer.url("").toString();
+ final ArrowheadServiceRegistryClient client = new ArrowheadServiceRegistryClient(baseUrl);
+ final ServiceRegistryRequestDTO requestDTO = ServiceRegistryRequestDTO.builder()
+ .serviceDefinition("definition3")
+ .providerSystem(SystemRequestDTO.builder().build())
+ .serviceUri("/")
+ .secure(ServiceRegistryRequestDTO.SecurityLevel.TOKEN)
+ .version(1)
+ .interfaces(Collections.singletonList("HTTP-SECURE-JSON"))
+ .build();
+
+ assertThatThrownBy(() -> client.registerService(requestDTO))
+ .isInstanceOf(ConstraintViolationException.class)
+ .hasMessageContaining("providerSystem.authenticationInfo: must not be null")
+ .hasMessageContaining("providerSystem.address: must not be null")
+ .hasMessageContaining("providerSystem.port: must not be null")
+ .hasMessageContaining("providerSystem.systemName: must not be null");
+ assertThat(mockWebServer.getRequestCount()).isZero();
+
+ mockWebServer.close();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/CertificateCheckFailureIT.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/CertificateCheckFailureIT.java
new file mode 100644
index 000000000..88a54951c
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/CertificateCheckFailureIT.java
@@ -0,0 +1,56 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.nio.channels.ClosedChannelException;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import eu.arrowhead.core.hbconfmgr.config.ArrowheadConfig;
+import eu.arrowhead.core.hbconfmgr.config.InitArrowheadMockServers;
+
+
+@ActiveProfiles("test")
+public class CertificateCheckFailureIT {
+ private static InitArrowheadMockServers initMockServer;
+
+
+ @BeforeAll
+ public static void beforeAll() throws JsonProcessingException {
+ CertificateCheckFailureIT.initMockServer = new InitArrowheadMockServers();
+ CertificateCheckFailureIT.initMockServer.setUp(false);
+ }
+
+ @Test
+ public void testMissingServerCertificatesServiceRegistry() {
+ try {
+ ArrowheadConfig config = new ArrowheadConfig();
+ ReflectionTestUtils.setField(config, "serviceRegistryAddress", "localhost");
+ ReflectionTestUtils.setField(config, "serviceRegistryPort", 8443);
+ config.init();
+ } catch (final Exception e) {
+ assertEquals(ClosedChannelException.class, e.getCause().getClass());
+ }
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ CertificateCheckFailureIT.initMockServer.shutDown();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/CoreSystemsFailure.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/CoreSystemsFailure.java
new file mode 100644
index 000000000..2015a0ce7
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/arrowhead/CoreSystemsFailure.java
@@ -0,0 +1,61 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.arrowhead;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.net.ConnectException;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.request.ServiceRegistryRequestDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.request.SystemRequestDTO;
+
+
+public class CoreSystemsFailure {
+ @Test
+ public void testServiceRegistryFailure() {
+ final ArrowheadServiceRegistryClient srClient = new ArrowheadServiceRegistryClient("https://localhost:8443");
+
+ final ServiceRegistryRequestDTO requestDTO = ServiceRegistryRequestDTO.builder()
+ .serviceDefinition("definition3")
+ .providerSystem(SystemRequestDTO.builder()
+ .systemName("conf-system")
+ .address("192.168.1.1")
+ .port(1234)
+ .authenticationInfo("test")
+ .build())
+ .serviceUri("/")
+ .secure(ServiceRegistryRequestDTO.SecurityLevel.TOKEN)
+ .version(1)
+ .interfaces(Collections.singletonList("HTTP-SECURE-JSON"))
+ .build();
+
+ final Exception exception = assertThrows(Exception.class, () -> {
+ srClient.registerService(requestDTO);
+ });
+
+ assertEquals(ConnectException.class, exception.getCause().getCause().getClass());
+ }
+
+ @Test
+ public void testAuthorizationSystemFailure() {
+ final ArrowheadAuthorizationSystemClient authClient = new ArrowheadAuthorizationSystemClient("https://localhost:8443");
+
+ final Exception exception = assertThrows(Exception.class, () -> {
+ authClient.getPublicKey();
+ });
+
+ assertEquals(ConnectException.class, exception.getCause().getCause().getClass());
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/InitArrowheadMockServers.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/InitArrowheadMockServers.java
new file mode 100644
index 000000000..0a889fb1a
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/InitArrowheadMockServers.java
@@ -0,0 +1,119 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import static org.mockserver.model.HttpRequest.request;
+import static org.mockserver.model.HttpResponse.response;
+
+import java.util.List;
+
+import org.mockserver.configuration.ConfigurationProperties;
+import org.mockserver.integration.ClientAndServer;
+import org.mockserver.model.MediaType;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.ServiceQueryResultDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.ServiceRegistryResponseDTO;
+import eu.arrowhead.core.hbconfmgr.arrowhead.model.response.SystemResponseDTO;
+
+
+public class InitArrowheadMockServers {
+
+ private ClientAndServer serviceRegistryMockServer;
+ private ClientAndServer authorizationSystemMockServer;
+
+ public void setUp() throws JsonProcessingException {
+ startServiceRegistryMockServer(true);
+ startAuthorizationSystemMockServer(true);
+ }
+
+ public void setUp(final Boolean useCertificates) throws JsonProcessingException {
+ startServiceRegistryMockServer(useCertificates);
+ startAuthorizationSystemMockServer(useCertificates);
+ }
+
+ private void startServiceRegistryMockServer(final Boolean useCertificates) throws JsonProcessingException {
+ if (useCertificates) {
+ final String certificateAuthorityKeyPath = PropertiesExtractor.getProperty("mockserver.certificateAuthorityPrivateKey");
+ final String certificateAuthorityCertificatePath = PropertiesExtractor.getProperty("mockserver.certificateAuthorityCertificate");
+ final String serviceRegistryKeyPath = PropertiesExtractor.getProperty("mockserver.sreg.privateKeyPath");
+ final String serviceRegistryCertPath = PropertiesExtractor.getProperty("mockserver.sreg.x509CertificatePath");
+
+ ConfigurationProperties.certificateAuthorityPrivateKey(certificateAuthorityKeyPath);
+ ConfigurationProperties.certificateAuthorityCertificate(certificateAuthorityCertificatePath);
+ ConfigurationProperties.privateKeyPath(serviceRegistryKeyPath);
+ ConfigurationProperties.x509CertificatePath(serviceRegistryCertPath);
+ } else {
+ ConfigurationProperties.certificateAuthorityPrivateKey("");
+ ConfigurationProperties.certificateAuthorityCertificate("");
+ ConfigurationProperties.privateKeyPath("");
+ ConfigurationProperties.x509CertificatePath("");
+ }
+
+ serviceRegistryMockServer = ClientAndServer.startClientAndServer(8443);
+
+ serviceRegistryMockServer.when(request().withPath("/serviceregistry/register"))
+ .respond(response().withStatusCode(201));
+ serviceRegistryMockServer.when(request().withPath("/serviceregistry/unregister"))
+ .respond(response().withStatusCode(200));
+ final ServiceRegistryResponseDTO response = ServiceRegistryResponseDTO.builder()
+ .provider(SystemResponseDTO.builder()
+ .address("127.0.0.1")
+ .port(8445)
+ .build())
+ .build();
+ final ServiceQueryResultDTO result = ServiceQueryResultDTO.builder()
+ .unfilteredHits(1)
+ .serviceQueryData(List.of(response))
+ .build();
+ final ObjectMapper mapper = new ObjectMapper();
+ serviceRegistryMockServer.when(request().withPath("/serviceregistry/query"))
+ .respond(response().withStatusCode(200)
+ .withContentType(MediaType.APPLICATION_JSON_UTF_8)
+ .withBody(mapper.writeValueAsString(result)));
+
+ }
+
+ private void startAuthorizationSystemMockServer(final Boolean useCertificates) {
+ if (useCertificates) {
+ final String certificateAuthorityKeyPath = PropertiesExtractor.getProperty("mockserver.certificateAuthorityPrivateKey");
+ final String certificateAuthorityCertificatePath = PropertiesExtractor.getProperty("mockserver.certificateAuthorityCertificate");
+ final String authorizationSystemKeyPath = PropertiesExtractor.getProperty("mockserver.auth.privateKeyPath");
+ final String authorizationSystemCertPath = PropertiesExtractor.getProperty("mockserver.auth.x509CertificatePath");
+
+ ConfigurationProperties.certificateAuthorityPrivateKey(certificateAuthorityKeyPath);
+ ConfigurationProperties.certificateAuthorityCertificate(certificateAuthorityCertificatePath);
+ ConfigurationProperties.privateKeyPath(authorizationSystemKeyPath);
+ ConfigurationProperties.x509CertificatePath(authorizationSystemCertPath);
+ }
+
+ final String authorizationSystemPubKey = PropertiesExtractor.getProperty("mockserver.auth.pubKeyResponse");
+
+ authorizationSystemMockServer = ClientAndServer.startClientAndServer(8445);
+
+ authorizationSystemMockServer.when(
+ request()
+ .withPath("/authorization/publickey")
+ )
+ .respond(
+ response()
+ .withBody("\"" + authorizationSystemPubKey + "\"")
+ );
+ }
+
+ public void shutDown() {
+ serviceRegistryMockServer.stop();
+ authorizationSystemMockServer.stop();
+ }
+
+}
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/PropertiesExtractor.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/PropertiesExtractor.java
new file mode 100644
index 000000000..c72651bf9
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/PropertiesExtractor.java
@@ -0,0 +1,33 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+
+public class PropertiesExtractor {
+ private static Properties properties;
+ static {
+ properties = new Properties();
+ final URL url = PropertiesExtractor.class.getClassLoader().getResource("mockserver.properties");
+ try{
+ properties.load(new FileInputStream(url.getPath()));
+ } catch (final IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static String getProperty(final String key){
+ return properties.getProperty(key);
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/TestConfig.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/TestConfig.java
new file mode 100644
index 000000000..c616e4118
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/TestConfig.java
@@ -0,0 +1,79 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import java.net.Socket;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509ExtendedTrustManager;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+import lombok.extern.log4j.Log4j2;
+
+
+@Log4j2
+@Configuration
+@Profile("test")
+public class TestConfig {
+ /**
+ * This Bean returns a mocked TrustManager implementation to test
+ * whether the correct certificate is used during TLS handshake
+ * @return mocked TrustManager object
+ */
+ @Bean
+ public TrustManager[] getTestTrustManager() {
+ final TrustManager[] tm = {
+ new X509ExtendedTrustManager(){
+ @Override
+ public void checkClientTrusted(final X509Certificate[] chain, final String authType, final Socket socket) {
+ }
+
+ @Override
+ public void checkServerTrusted(final X509Certificate[] chain, final String authType, final Socket socket) {
+ log.info("Server authentication with the following certificate:");
+ log.error(chain[0]);
+ }
+
+ @Override
+ public void checkClientTrusted(final X509Certificate[] chain, final String authType, final SSLEngine engine) {
+ }
+
+ @Override
+ public void checkServerTrusted(final X509Certificate[] chain, final String authType, final SSLEngine engine) {
+ log.info("Server authentication with the following certificate:");
+ log.error(chain[0]);
+ }
+
+ @Override
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ @Override
+ public void checkClientTrusted(final X509Certificate[] certs, final String authType) {
+ }
+
+ @Override
+ public void checkServerTrusted(final X509Certificate[] certs, final String authType) {
+ log.info("Server authentication with the following certificate:");
+ log.error(certs[0]);
+ }
+ }
+ };
+
+ return tm;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/TestHawkbitConfig.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/TestHawkbitConfig.java
new file mode 100644
index 000000000..db5487779
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/config/TestHawkbitConfig.java
@@ -0,0 +1,35 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.config;
+
+import com.github.fridujo.rabbitmq.mock.MockConnectionFactory;
+import com.rabbitmq.client.ConnectionFactory;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.context.annotation.Profile;
+
+/**
+ * This class provides the clients for interaction with hawkBit via beans managed by the Spring container.
+ */
+@Configuration
+@Profile("test")
+public class TestHawkbitConfig {
+ @Primary
+ @Bean
+ public ConnectionFactory hawkbitConnectionFactory() {
+ final MockConnectionFactory mockConnectionFactory = new MockConnectionFactory();
+ mockConnectionFactory.setAutomaticRecoveryEnabled(true);
+
+ return mockConnectionFactory;
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfConsumerTest.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfConsumerTest.java
new file mode 100644
index 000000000..a2b539586
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfConsumerTest.java
@@ -0,0 +1,150 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.github.fridujo.rabbitmq.mock.MockConnection;
+import com.github.fridujo.rabbitmq.mock.MockConnectionFactory;
+import com.rabbitmq.client.AMQP;
+import com.rabbitmq.client.Envelope;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.CancelDownloadInboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.DownloadRequestInboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.ThingDeletedInboundMessage;
+import eu.arrowhead.core.hbconfmgr.service.WebSocketService;
+import eu.arrowhead.core.hbconfmgr.websocket.DeviceNotConnectedException;
+
+public class HawkbitDmfConsumerTest {
+
+ private HawkbitDmfConsumer consumer;
+ private MockConnection mockConnection;
+ private WebSocketService mock_wsService;
+
+ @BeforeEach
+ public void init() {
+ mockConnection = new MockConnectionFactory().newConnection();
+
+ mock_wsService = mock(WebSocketService.class);
+ consumer = new HawkbitDmfConsumer(mockConnection.createChannel(), mock_wsService);
+ }
+
+ @Test
+ public void testDownloadRequestInboundGeneration() throws IOException, DeviceNotConnectedException {
+ final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().contentType("application/json")
+ .headers(Map.ofEntries(Map.entry("type", "EVENT"), Map.entry("thingId", "device7"),
+ Map.entry("topic", "DOWNLOAD_AND_INSTALL"), Map.entry("tenant", "tenant1")))
+ .build();
+
+ final String body = "{\n" + " \"actionId\": 8,\n" + " \"targetSecurityToken\": \"aslkhju4kjasdz9uas\",\n"
+ + " \"softwareModules\": [{\n" + " \"moduleId\": 1,\n"
+ + " \"moduleType\": \"OS\",\n" + " \"moduleVersion\": \"1.0\",\n"
+ + " \"artifacts\": [{\n" + " \"filename\": \"os.zip\",\n"
+ + " \"urls\": {\n"
+ + " \"COAP\": \"coap://coap.local/os.zip\",\n"
+ + " \"HTTP\": \"http://localhost/os.zip\",\n"
+ + " \"HTTPS\": \"https://localhost/os.zip\"\n" + " },\n"
+ + " \"hashes\": {\n"
+ + " \"md5\": \"8c9693121361daf0d992df4eeb714ebb\",\n"
+ + " \"sha1\": \"e5ee90a0f8d0570b8bbdcaa23aa9a6b737c0c826\"\n"
+ + " },\n" + " \"size\": 539475\n" + " }\n"
+ + " ],\n" + " \"metadata\": [{\n"
+ + " \"key\": \"Description\",\n"
+ + " \"value\": \"This is the new operating system\"\n" + " }\n"
+ + " ]\n" + " }\n" + " ]\n" + "}";
+
+ final DownloadRequestInboundMessage.Body assertBody = DownloadRequestInboundMessage.Body.builder().actionId(8L)
+ .targetSecurityToken("aslkhju4kjasdz9uas")
+ .softwareModules(Collections.singletonList(DownloadRequestInboundMessage.Body.SoftwareModule.builder()
+ .moduleId(1L).moduleType("OS").moduleVersion("1.0")
+ .artifacts(Collections.singletonList(DownloadRequestInboundMessage.Body.Artifact.builder()
+ .filename("os.zip")
+ .urls(DownloadRequestInboundMessage.Body.Urls.builder().COAP("coap://coap.local/os.zip")
+ .HTTP("http://localhost/os.zip").HTTPS("https://localhost/os.zip").build())
+ .hashes(DownloadRequestInboundMessage.Body.Hashes.builder()
+ .md5("8c9693121361daf0d992df4eeb714ebb")
+ .sha1("e5ee90a0f8d0570b8bbdcaa23aa9a6b737c0c826").build())
+ .size(539475L).build()))
+ .metadata(Collections.singletonList(DownloadRequestInboundMessage.Body.Metadata.builder()
+ .key("Description").value("This is the new operating system").build()))
+ .build()))
+ .build();
+
+ final DownloadRequestInboundMessage.Headers assertHeaders = DownloadRequestInboundMessage.Headers.builder().type("EVENT")
+ .thingId("device7").topic("DOWNLOAD_AND_INSTALL").tenant("tenant1").build();
+
+ final DownloadRequestInboundMessage assertMessage = DownloadRequestInboundMessage.builder().body(assertBody).deliveryTag(1l).headers(assertHeaders).build();
+
+ consumer.handleDelivery("tag", new Envelope(1L, false, "exchange", "routingKey"), properties, body.getBytes());
+
+ verify(mock_wsService).sendDownloadEventMessage(assertMessage);
+ }
+
+ @Test
+ public void testCancelDownload() throws IOException, DeviceNotConnectedException {
+ final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().contentType("application/json")
+ .headers(Map.ofEntries(Map.entry("type", "EVENT"), Map.entry("thingId", "device7"),
+ Map.entry("topic", "CANCEL_DOWNLOAD"), Map.entry("tenant", "tenant1")))
+ .build();
+
+ final String rawMessage = "{"
+ + "\"actionId\": 16"
+ + "}";
+
+ final CancelDownloadInboundMessage cancelDownloadInboundMessage = CancelDownloadInboundMessage.builder()
+ .body(
+ CancelDownloadInboundMessage.Body.builder()
+ .actionId(16L)
+ .build()
+ )
+ .headers(
+ CancelDownloadInboundMessage.Headers.builder()
+ .type("EVENT")
+ .tenant("tenant1")
+ .thingId("device7")
+ .topic("CANCEL_DOWNLOAD")
+ .build()
+ )
+ .build();
+
+ consumer.handleDelivery("tag", new Envelope(1L, false, "exchange", "routingKey"), properties, rawMessage.getBytes());
+
+ verify(mock_wsService).sendCancelDownloadMessage(cancelDownloadInboundMessage);
+ }
+
+ @Test
+ public void testThingDeleted() throws IOException, DeviceNotConnectedException {
+ final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().contentType("application/json")
+ .headers(Map.ofEntries(Map.entry("type", "THING_DELETED"), Map.entry("thingId", "device7"),
+ Map.entry("topic", "THING_DELETED"), Map.entry("tenant", "tenant1")))
+ .build();
+
+ final ThingDeletedInboundMessage thingDeletedInboundMessage = ThingDeletedInboundMessage.builder()
+ .headers(
+ ThingDeletedInboundMessage.Headers.builder()
+ .thingId("device7")
+ .build()
+ )
+ .build();
+
+ consumer.handleDelivery("tag", new Envelope(1L, false, "exchange", "routingKey"), properties, null);
+
+ verify(mock_wsService).sendThingDeletedMessage(thingDeletedInboundMessage);
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfOutboundClientTest.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfOutboundClientTest.java
new file mode 100644
index 000000000..1adf73a06
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitDmfOutboundClientTest.java
@@ -0,0 +1,110 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+
+import org.json.JSONException;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.skyscreamer.jsonassert.JSONCompareMode;
+
+import com.github.fridujo.rabbitmq.mock.MockConnection;
+import com.github.fridujo.rabbitmq.mock.MockConnectionFactory;
+import com.rabbitmq.client.AMQP;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.ActionStatus;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound.ThingCreatedOutboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound.UpdateActionStatusOutboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.util.HawkbitDmfMockServer;
+import eu.arrowhead.core.hbconfmgr.hawkbit.util.Message;
+
+public class HawkbitDmfOutboundClientTest {
+
+ @Test
+ public void givenCorrectMessage_whenCreateThing_thenThingIsCreated() throws IOException, JSONException {
+ final MockConnection mockConnection = new MockConnectionFactory().newConnection();
+ final HawkbitDmfMockServer mockServer = new HawkbitDmfMockServer(mockConnection.createChannel());
+ final HawkbitDmfOutboundClient client = new HawkbitDmfOutboundClient(mockConnection.createChannel());
+
+ final ThingCreatedOutboundMessage message = ThingCreatedOutboundMessage.builder()
+ .body(ThingCreatedOutboundMessage.Body.builder()
+ .name("device3")
+ .build())
+ .headers(ThingCreatedOutboundMessage.Headers.builder()
+ .tenant("tenant1")
+ .thingId("device3")
+ .sender("testSender")
+ .build())
+ .build();
+
+ client.createThing(message);
+
+ await().until(() -> mockServer.getMessages().size() == 1);
+ final Message receivedMessage = mockServer.getMessages().get(0);
+ assertThat(receivedMessage).isNotNull();
+ assertThat(receivedMessage.getProperties()).isEqualTo(new AMQP.BasicProperties.Builder()
+ .headers(Map.ofEntries(
+ Map.entry("type", "THING_CREATED"),
+ Map.entry("thingId", "device3"),
+ Map.entry("sender", "testSender"),
+ Map.entry("tenant", "tenant1")))
+ .contentType("application/json")
+ .replyTo("configuration_system.direct.exchange")
+ .build());
+ JSONAssert.assertEquals("{\n" +
+ " \"name\": \"device3\"\n" +
+ "}", receivedMessage.getBody(), JSONCompareMode.NON_EXTENSIBLE);
+ }
+
+ @Test
+ public void givenCorrectMessage_whenUpdateActionStatus_thenActionIsUpdated() throws IOException, JSONException {
+ final MockConnection mockConnection = new MockConnectionFactory().newConnection();
+ final HawkbitDmfMockServer mockServer = new HawkbitDmfMockServer(mockConnection.createChannel());
+ final HawkbitDmfOutboundClient client = new HawkbitDmfOutboundClient(mockConnection.createChannel());
+
+ final UpdateActionStatusOutboundMessage message = UpdateActionStatusOutboundMessage.builder()
+ .body(UpdateActionStatusOutboundMessage.UpdateActionStatusOutboundMessageBody.builder()
+ .actionId(7L)
+ .actionStatus(ActionStatus.FINISHED)
+ .message(Collections.singletonList("Successfully applied update on device"))
+ .softwareModuleId(3L)
+ .build())
+ .headers(UpdateActionStatusOutboundMessage.UpdateActionStatusOutboundMessageHeaders.builder()
+ .tenant("tenant1")
+ .build())
+ .build();
+
+ client.updateActionStatus(message);
+
+ await().until(() -> mockServer.getMessages().size() == 1);
+ final Message receivedMessage = mockServer.getMessages().get(0);
+ assertThat(receivedMessage).isNotNull();
+ assertThat(receivedMessage.getProperties()).isEqualTo(new AMQP.BasicProperties.Builder()
+ .headers(Map.ofEntries(
+ Map.entry("type", "EVENT"),
+ Map.entry("topic", "UPDATE_ACTION_STATUS"),
+ Map.entry("tenant", "tenant1")))
+ .contentType("application/json")
+ .build());
+ JSONAssert.assertEquals("{\n" +
+ " \"actionId\": 7,\n" +
+ " \"softwareModuleId\": 3,\n" +
+ " \"actionStatus\": \"FINISHED\",\n" +
+ " \"message\": [\"Successfully applied update on device\"]\n" +
+ "}", receivedMessage.getBody(), JSONCompareMode.NON_EXTENSIBLE);
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitFailureTest.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitFailureTest.java
new file mode 100644
index 000000000..71272dbd5
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/HawkbitFailureTest.java
@@ -0,0 +1,61 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit;
+
+import static org.junit.Assert.assertThrows;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.Test;
+
+import com.github.fridujo.rabbitmq.mock.MockConnection;
+import com.github.fridujo.rabbitmq.mock.MockConnectionFactory;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound.ThingCreatedOutboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.util.HawkbitDmfMockServer;
+
+
+public class HawkbitFailureTest {
+
+ private HawkbitDmfMockServer dmfMockServer;
+
+ @Test
+ public void testMissingExchange() throws IOException {
+ final MockConnection mockConnection = new MockConnectionFactory().newConnection();
+
+ final HawkbitDmfOutboundClient hawkbitClient = new HawkbitDmfOutboundClient(mockConnection.createChannel());
+
+ dmfMockServer = new HawkbitDmfMockServer(mockConnection.createChannel());
+
+ final ThingCreatedOutboundMessage message = ThingCreatedOutboundMessage.builder()
+ .body(
+ ThingCreatedOutboundMessage.Body.builder()
+ .name("some.device")
+ .build()
+ )
+ .headers(
+ ThingCreatedOutboundMessage.Headers.builder()
+ .sender("sender")
+ .tenant("tenant")
+ .thingId("thingId")
+ .build()
+ )
+ .build();
+
+ hawkbitClient.createThing(message);
+
+ dmfMockServer.stageFailure();
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ hawkbitClient.createThing(message);
+ });
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/RabbitMQAPITest.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/RabbitMQAPITest.java
new file mode 100644
index 000000000..597c93562
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/RabbitMQAPITest.java
@@ -0,0 +1,120 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.github.fridujo.rabbitmq.mock.MockConnectionFactory;
+import com.rabbitmq.client.AMQP;
+import com.rabbitmq.client.Connection;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.DownloadRequestInboundMessage;
+import eu.arrowhead.core.hbconfmgr.hawkbit.util.HawkbitDmfMockServer;
+import eu.arrowhead.core.hbconfmgr.service.WebSocketService;
+import eu.arrowhead.core.hbconfmgr.websocket.DeviceNotConnectedException;
+
+public class RabbitMQAPITest {
+
+ private HawkbitDmfConsumer consumer;
+ private WebSocketService mock_wsService;
+ private HawkbitDmfMockServer mockServer;
+ private Connection mockConnection;
+
+ @BeforeEach
+ public void init() throws IOException {
+ mock_wsService = mock(WebSocketService.class);
+
+ mockConnection = new MockConnectionFactory().newConnection();
+
+ mockServer = new HawkbitDmfMockServer(mockConnection.createChannel());
+ consumer = new HawkbitDmfConsumer(mockConnection.createChannel(), mock_wsService);
+ }
+
+ @Test
+ public void testAMQPInterface() throws IOException, DeviceNotConnectedException {
+
+ consumer.subscribeToDownloadEvents();
+
+ final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
+ .contentType("application/json")
+ .headers(Map.ofEntries(
+ Map.entry("type", "EVENT"),
+ Map.entry("thingId", "device7"),
+ Map.entry("topic", "DOWNLOAD_AND_INSTALL"),
+ Map.entry("tenant", "tenant1")
+ ))
+ .build();
+ final String body = "{\n" +
+ " \"actionId\": 8,\n" +
+ " \"targetSecurityToken\": \"aslkhju4kjasdz9uas\",\n" +
+ " \"softwareModules\": [{\n" +
+ " \"moduleId\": 1,\n" +
+ " \"moduleType\": \"OS\",\n" +
+ " \"moduleVersion\": \"1.0\",\n" +
+ " \"artifacts\": [{\n" +
+ " \"filename\": \"os.zip\",\n" +
+ " \"urls\": {\n" +
+ " \"COAP\": \"coap://coap.local/os.zip\",\n" +
+ " \"HTTP\": \"http://localhost/os.zip\",\n" +
+ " \"HTTPS\": \"https://localhost/os.zip\"\n" +
+ " },\n" +
+ " \"hashes\": {\n" +
+ " \"md5\": \"8c9693121361daf0d992df4eeb714ebb\",\n" +
+ " \"sha1\": \"e5ee90a0f8d0570b8bbdcaa23aa9a6b737c0c826\"\n" +
+ " },\n" +
+ " \"size\": 539475\n" +
+ " }\n" +
+ " ],\n" +
+ " \"metadata\": [{\n" +
+ " \"key\": \"Description\",\n" +
+ " \"value\": \"This is the new operating system\"\n" +
+ " }\n" +
+ " ]\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+ mockServer.publish(properties, body);
+
+ final DownloadRequestInboundMessage.Body assertBody = DownloadRequestInboundMessage.Body.builder().actionId(8L)
+ .targetSecurityToken("aslkhju4kjasdz9uas")
+ .softwareModules(Collections.singletonList(DownloadRequestInboundMessage.Body.SoftwareModule.builder()
+ .moduleId(1L).moduleType("OS").moduleVersion("1.0")
+ .artifacts(Collections.singletonList(DownloadRequestInboundMessage.Body.Artifact.builder()
+ .filename("os.zip")
+ .urls(DownloadRequestInboundMessage.Body.Urls.builder().COAP("coap://coap.local/os.zip")
+ .HTTP("http://localhost/os.zip").HTTPS("https://localhost/os.zip").build())
+ .hashes(DownloadRequestInboundMessage.Body.Hashes.builder()
+ .md5("8c9693121361daf0d992df4eeb714ebb")
+ .sha1("e5ee90a0f8d0570b8bbdcaa23aa9a6b737c0c826")
+ .build())
+ .size(539475L).build()))
+ .metadata(Collections.singletonList(DownloadRequestInboundMessage.Body.Metadata.builder()
+ .key("Description").value("This is the new operating system").build()))
+ .build()))
+ .build();
+
+ final DownloadRequestInboundMessage.Headers assertHeaders = DownloadRequestInboundMessage.Headers.builder().type("EVENT")
+ .thingId("device7").topic("DOWNLOAD_AND_INSTALL").tenant("tenant1").build();
+
+ final DownloadRequestInboundMessage assertMessage = DownloadRequestInboundMessage.builder().body(assertBody).deliveryTag(1l).headers(assertHeaders).build();
+
+ verify(mock_wsService, timeout(1000)).sendDownloadEventMessage(assertMessage);
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/util/HawkbitDmfMockServer.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/util/HawkbitDmfMockServer.java
new file mode 100644
index 000000000..4dafccde8
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/util/HawkbitDmfMockServer.java
@@ -0,0 +1,69 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.util;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.rabbitmq.client.AMQP;
+import com.rabbitmq.client.BuiltinExchangeType;
+import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.DefaultConsumer;
+import com.rabbitmq.client.Envelope;
+
+import lombok.Getter;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+public class HawkbitDmfMockServer {
+
+ @Getter
+ private final Channel channel;
+
+ @Getter
+ private final List messages;
+
+ public HawkbitDmfMockServer(final Channel channel) throws IOException {
+ this.channel = channel;
+ this.messages = new ArrayList<>();
+ this.initializeMockServer();
+ }
+
+ public void clearMessages() {
+ messages.clear();
+ }
+
+ public void publish(final AMQP.BasicProperties properties, final String body) throws IOException {
+ final byte[] byteBody = body.getBytes(StandardCharsets.UTF_8);
+ this.channel.basicPublish("configuration_system.direct.exchange", "", properties, byteBody);
+ }
+
+ private void initializeMockServer() throws IOException {
+ final String queueName = this.channel.queueDeclare().getQueue();
+ this.channel.exchangeDeclare("dmf.exchange", BuiltinExchangeType.DIRECT);
+ this.channel.queueBind(queueName, "dmf.exchange", "");
+ this.channel.basicConsume(queueName, new DefaultConsumer(this.channel) {
+ @Override
+ public void handleDelivery(final String consumerTag, final Envelope envelope, final AMQP.BasicProperties properties, final byte[] body) {
+ final String bodyString = new String(body, StandardCharsets.UTF_8);
+ log.debug("Received amqp message: consumerTag {}, envelope {}, properties {}, body {}",
+ consumerTag, envelope, properties, bodyString);
+ messages.add(new Message(envelope, properties, bodyString));
+ }
+ });
+ }
+
+ public void stageFailure() throws IOException {
+ this.channel.exchangeDelete("dmf.exchange", false);
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/util/Message.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/util/Message.java
new file mode 100644
index 000000000..fc743bcde
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/hawkbit/util/Message.java
@@ -0,0 +1,30 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.hawkbit.util;
+
+import com.rabbitmq.client.AMQP;
+import com.rabbitmq.client.Envelope;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+@Builder
+public class Message {
+
+ private Envelope envelope;
+ private AMQP.BasicProperties properties;
+ private String body;
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/service/HawbitServiceTest.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/service/HawbitServiceTest.java
new file mode 100644
index 000000000..98050f781
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/service/HawbitServiceTest.java
@@ -0,0 +1,74 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.service;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import javax.validation.ConstraintViolationException;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.HawkbitDmfOutboundClient;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.ActionStatus;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.outbound.UpdateActionStatusOutboundMessage;
+import eu.arrowhead.core.hbconfmgr.model.HawkbitActionUpdateStatus;
+
+public class HawbitServiceTest {
+
+ private HawkbitService hawkbitService;
+ private HawkbitDmfOutboundClient mock_hawkbitDmfClient;
+
+ @BeforeEach
+ public void init() {
+ mock_hawkbitDmfClient = mock(HawkbitDmfOutboundClient.class);
+
+ hawkbitService = new HawkbitService("testTenant", mock_hawkbitDmfClient);
+ }
+
+ @Test
+ public void testUpdateActionStatus() throws ConstraintViolationException, IOException {
+ final ArrayList messageList = new ArrayList();
+ messageList.add("test");
+
+ final HawkbitActionUpdateStatus hActionUpdateStatus = HawkbitActionUpdateStatus
+ .builder()
+ .actionId(123456789L)
+ .actionStatus(ActionStatus.CANCELED)
+ .softwareModuleId(987654321L)
+ .message(messageList)
+ .build();
+
+ final UpdateActionStatusOutboundMessage message = UpdateActionStatusOutboundMessage.builder()
+ .body(
+ UpdateActionStatusOutboundMessage.UpdateActionStatusOutboundMessageBody.builder()
+ .actionId(123456789L)
+ .actionStatus(ActionStatus.CANCELED)
+ .softwareModuleId(987654321L)
+ .message(messageList).build()
+ )
+ .headers(
+ UpdateActionStatusOutboundMessage.UpdateActionStatusOutboundMessageHeaders.builder()
+ .tenant("testTenant")
+ .build()
+ )
+ .build();
+
+
+ hawkbitService.updateActionStatus(hActionUpdateStatus);
+
+ verify(mock_hawkbitDmfClient).updateActionStatus(message);
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketControllerIT.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketControllerIT.java
new file mode 100644
index 000000000..ac9ad05c4
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketControllerIT.java
@@ -0,0 +1,180 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.websocket;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URI;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import javax.net.ssl.SSLContext;
+import javax.websocket.DeploymentException;
+
+import org.apache.http.ssl.SSLContexts;
+import org.apache.http.ssl.TrustStrategy;
+import org.apache.tomcat.websocket.Constants;
+import org.awaitility.Awaitility;
+import org.json.JSONException;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketHttpHeaders;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.client.standard.StandardWebSocketClient;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.base.Throwables;
+import com.rabbitmq.client.Connection;
+
+import eu.arrowhead.core.hbconfmgr.SSLProperties;
+import eu.arrowhead.core.hbconfmgr.config.InitArrowheadMockServers;
+import eu.arrowhead.core.hbconfmgr.hawkbit.util.HawkbitDmfMockServer;
+import eu.arrowhead.core.hbconfmgr.hawkbit.util.Message;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles("test")
+public class WebSocketControllerIT {
+
+ @Value("${testParameters.token}")
+ private String testToken;
+
+ @Value("${testParameters.incorrectToken}")
+ private String incorrectTestToken;
+
+ @Autowired
+ private Connection mockConnection;
+
+// @Autowired
+// private TrustManager[] tm;
+
+ @Autowired
+ private SSLProperties sslProps;
+
+ @LocalServerPort
+ private Integer port;
+
+ private HawkbitDmfMockServer hawkbitMockServer;
+ private StandardWebSocketClient wsClient;
+
+ private static InitArrowheadMockServers initMockServer;
+
+ @BeforeAll
+ public static void beforeAll() throws JsonProcessingException {
+ WebSocketControllerIT.initMockServer = new InitArrowheadMockServers();
+ WebSocketControllerIT.initMockServer.setUp();
+ }
+
+ @BeforeEach
+ public void init() throws NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException,
+ KeyStoreException, UnrecoverableKeyException, KeyManagementException {
+ wsClient = new StandardWebSocketClient();
+ final Map userProperties = new HashMap<>();
+ final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(new TrustStrategy() {
+ @Override
+ public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
+ log.error(chain);
+ return true;
+ }
+ }).loadKeyMaterial(sslProps.getKeyStore().getURL(), sslProps.getKeyStorePassword().toCharArray(), sslProps.getKeyPassword().toCharArray())
+ .build();
+
+
+// sslContext.init(null, tm, new java.security.SecureRandom());
+ userProperties.put(Constants.SSL_CONTEXT_PROPERTY, sslContext);
+
+ wsClient.setUserProperties(userProperties);
+
+ // Mock the HawkBit DMF API (RabbitMQ)
+ hawkbitMockServer = new HawkbitDmfMockServer(mockConnection.createChannel());
+ }
+
+ @Test
+ public void testWebsocketWithCorrectTokenAndCorrectPayload()
+ throws InterruptedException, ExecutionException, IOException, JSONException {
+ final WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
+ headers.setBearerAuth(testToken);
+
+ final WebSocketSession session = wsClient.doHandshake(new TextWebSocketHandler() {
+
+ }, headers, URI.create("wss://localhost:" + port)).get();
+
+ final String message = "{"
+ + "\"actionId\": 11,"
+ + "\"softwareModuleId\": 12,"
+ + "\"actionStatus\": \"DOWNLOAD\","
+ + "\"message\": ["
+ + "\"value\""
+ + "]"
+ + "}";
+
+ session.sendMessage(new TextMessage(message));
+
+ // Mock server should contain two messages up to this point:
+ // 1. the device creation message resulting from the call of doHandshake()
+ // 2. the action update status message
+
+ Awaitility.await().atMost(Duration.ofMillis(500)).until(() -> {
+ if (hawkbitMockServer.getMessages().size() == 2) {
+ return true;
+ } else {
+ return false;
+ }
+ });
+
+ final List receivedMessages = hawkbitMockServer.getMessages();
+ final Message receivedUpdateActionStatus = receivedMessages.get(1);
+ final String receivedUpdateActionStatusBody = receivedUpdateActionStatus.getBody();
+
+ JSONAssert.assertEquals(message, receivedUpdateActionStatusBody, true);
+ }
+
+ @Test
+ public void testWebsocketWithIncorrectToken() throws IOException, InterruptedException, ExecutionException {
+ final WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
+ headers.setBearerAuth(incorrectTestToken);
+
+
+ final Exception e = assertThrows(ExecutionException.class, () -> {
+ wsClient.doHandshake(new TextWebSocketHandler(), headers, URI.create("wss://localhost:" + port)).get();
+ });
+
+ assertEquals(DeploymentException.class, Throwables.getRootCause(e).getClass());
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ WebSocketControllerIT.initMockServer.shutDown();
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketSenderTest.java b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketSenderTest.java
new file mode 100644
index 000000000..effd7871f
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/java/eu/arrowhead/core/hbconfmgr/websocket/WebSocketSenderTest.java
@@ -0,0 +1,95 @@
+/********************************************************************************
+* Copyright (c) 2021 Bosch.IO GmbH[ and others]
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/
+
+package eu.arrowhead.core.hbconfmgr.websocket;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.MessageTypeInbound;
+import eu.arrowhead.core.hbconfmgr.hawkbit.model.inbound.ThingDeletedInboundMessage;
+import eu.arrowhead.core.hbconfmgr.websocket.model.DeviceMessage;
+
+public class WebSocketSenderTest {
+
+ private WebSocketSender wsSender;
+ private WebSocketSession wsSession;
+
+ @BeforeEach
+ public void init() {
+ final ConcurrentHashMap webSocketSessionMap = new ConcurrentHashMap<>();
+
+ wsSession = mock(WebSocketSession.class);
+ webSocketSessionMap.put("testIdX", wsSession);
+
+ wsSender = new WebSocketSender(webSocketSessionMap);
+ }
+
+ @Test
+ public void testSendMessageWithMissingSessionWebSocketSessionMap() throws IOException {
+ final DeviceMessage deviceMessage = DeviceMessage.builder()
+ .type(MessageTypeInbound.EVENT.toString())
+ .message(
+ ThingDeletedInboundMessage.builder()
+ .headers(
+ ThingDeletedInboundMessage.Headers.builder()
+ .thingId("testIdY")
+ .build()
+ )
+ .build()
+ )
+ .build();
+
+ assertThrows(DeviceNotConnectedException.class, () -> {
+ wsSender.sendMessage("testIdY", deviceMessage);
+ });
+ }
+
+ @Test
+ public void testSendMessageWithExistingSession() throws IOException,
+ DeviceNotConnectedException {
+ final DeviceMessage deviceMessage = DeviceMessage.builder()
+ .type(MessageTypeInbound.EVENT.toString())
+ .message(
+ ThingDeletedInboundMessage.builder()
+ .headers(
+ ThingDeletedInboundMessage.Headers.builder()
+ .thingId("testIdX")
+ .build()
+ )
+ .build()
+ )
+ .build();
+
+ final String expectedBody = "{"
+ + "\"type\":\"EVENT\","
+ + "\"message\":{"
+ + "\"headers\":{"
+ + "\"thingId\":\"testIdX\""
+ + "}"
+ + "}"
+ + "}";
+
+ final TextMessage expectedWSMessage = new TextMessage(expectedBody);
+
+ wsSender.sendMessage("testIdX", deviceMessage);
+
+ verify(wsSession).sendMessage(expectedWSMessage);
+ }
+}
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/resources/application-test.properties b/hawkbit-configuration-manager/src/test/resources/application-test.properties
new file mode 100644
index 000000000..41fbd8344
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/resources/application-test.properties
@@ -0,0 +1,70 @@
+############################################
+### APPLICATION PARAMETERS ###
+############################################
+
+# Hawkbit Configuration Manager web-server parameters
+server.address=0.0.0.0
+server.port=8447
+
+############################################
+### CUSTOM PARAMETERS ###
+############################################
+
+# These are the properties of the configuration system itself
+# The properties are loaded into the class eu.arrowhead.core.hbconfmgr.properties.SystemProperties
+system.name=confsys
+system.address=127.0.0.1
+system.port=8447
+# This is the protocol of the provided service from the configuration system itself, e.g. "HTTP-SECURE-JSON"
+system.providedServiceInterface=HTTP-SECURE-JSON
+# This is the definition of the provided service from the configuration system itself, e.g. "definition5"
+system.providedServiceDefinition=definition1
+# This is the uri of the provided service from the configuration system itself, e.g "/"
+system.providedServiceUri=/
+# This is the version of the provided service from the configuration system itself, e.g. 2
+system.providedServiceVersion=1
+
+# Service Registry web-server parameters
+sr_address=127.0.0.1
+sr_port=8443
+
+# These are the connection parameters for the hawkBit DMF API
+hawkbit.host=127.0.0.1
+hawkbit.port=5672
+hawkbit.username=hawkbit
+hawkbit.password=hawkbit
+# This is the tenant in hawkBit itself
+hawkbit.tenant=DEFAULT
+
+##########################################
+### SECURE MODE ###
+############################################
+
+# configure secure mode
+
+# This system works only in secure mode. Do not modify this property.
+server.ssl.enabled=true
+
+server.ssl.key-store-type=PKCS12
+server.ssl.key-store=classpath:test-certificates/test-conf-system.p12
+server.ssl.key-store-password=confsys-test-pw
+server.ssl.key-alias=confsys.example.corp.arrowhead.eu
+server.ssl.key-password=confsys-test-pw
+server.ssl.client-auth=need
+server.ssl.trust-store-type=PKCS12
+server.ssl.trust-store=classpath:test-certificates/test-cloud.truststore.p12
+server.ssl.trust-store-password=test-cloud-trust-store-pw
+
+
+testParameters.authorization.cert.path=./src/test/resources/test-certificates/test-auth-system.cert.pem
+testParameters.authorization.key.path=./src/test/resources/test-certificates/test-auth-system.key.pem
+testParameters.authorization.pubKey=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvmaFymz4cSB+LP3pixhhgrczq8G2rWTMyyajMQNSXOuvGDBhB7S32rl/+B8VUvTrYBx7ab8AM/TxrDwWAzsQ3p3oo0+5NNibHpZ8QucWIXqbpQqFobiNWx+ogoBLV4UfJekxXYH54QrTdwkvlOFXxjkL11uwBKEsZ0TzKgGaRs+iR80sjDeicnpPlMm0RbpXjx10OzmjqfC1Wrusyl2gjsW9ySfwJ1461n6cPndn8csvC37IHdHpkKTRlcDDPG6/GN3+vfUeznA7zGFWv2IOTzsuruehXaOuDNgekvREK3Xh4BpvGTZ6oEFVmr5853U3PS6ExKlvwR8NwFiPXI9LAQIDAQAB
+
+testParameters.serviceRegistry.cert.path=./src/test/resources/test-certificates/test-sreg.cert.pem
+testParameters.serviceRegistry.key.path=./src/test/resources/test-certificates/test-sreg.key.pem
+
+testParameters.cloud.cert.path=./src/test/resources/test-certificates/test-cloud.cert.pem
+testParameters.cloud.key.path=./src/test/resources/test-certificates/test-cloud.key.pem
+
+testParameters.token=eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiY3R5IjoiSldUIn0.LgLfAMnAvIKBhSThP6hhY9q5sVH9krMhXlb6UvVC5Bmvm-ph_ThOKlqd4iIoXws6kDaKJx--sWKKZhjbnRabLAZUHMwkmQHTbHl9FfUinCXBf95rwVxlL6hUS7tPvzp4awh5QqVMi_Focb6FboXx0ScXNUlaqsP3AreSFPiS_w2wPyBvsfKHF2xFkCmsSRb2Cxoh2P7_MFxtXK-eY4IiDlCOaBv9VijeDVV2hJ251R10k0w2yjG-b8--cdgDLsjQ3vjpDoIDqRHR8_7VzfnQZKVsU_4YNsAJMPx0OdwGBXKsUhx5yEqHtaglq3ym4P7qm3zXcYWgG9u8wD3KHvnPiw.4d8ObjIomnHzKdilPBGOQg.yhdv2DSpw4N_sQtalwVBnHhIXPRkm8G82KF11tHAJZ-iw3NKGjMI57_xOGPkL04yF3-HPsr52lxNLn883nynIJRcj2g8rri1D08mQ6hil4B2HpL3O4OvyM-CLgLNQ8ZODFMbTQ8rZgw4B1-gT61H0RYq4XMKyubf3_QrLKDkz4CLzuZR_F4EsXYZZ682zX1_Ym3sM6rDA2YI7wVZRSIAf0FOnV2IOu5WfABNcRYJtuSE60Tx20rz86nLdvC7LVo6xzFRAzsW3YQLSCQrZeanxzVU0lSN3p6AxifuD38CZzNMDqFIEuNJA3PpEU6-hwrKVYksrngbUSdJ1cjaSrGuXR5zI4LwsJOXMoCUDvGhO1Wz4qzWAdLJNZ2qOz_FC_6rN2hrU7YgWJ4-vDNLTJVyqCYURUiv1b3UDjEBUgSBPBp0gpX7-xBwv3EW0DB8c-r5_93lS8c0DIJ_bwr5p2q9o2nFSVbjWOPBzz0i8heGq_ZgkzE-x2672NhxoCQRGEfC9EhZH5pUtjhqIKedZn90XtbeXgytDtpRJ8sgCdMejjnzZpFIdyQru549e14t9bjoyE7mNs4INd6gNB8qQyFaTV07pLDsTdWrfvVRcp6BZx_0wWkXQOpUF5jmrSIGdpHOhFmNlrKJCapivyTwVs_IPmqzFrIdexTKA3Gx7w3fT1-4ckrTtsVR115xPbh_b0ZPPRH9mI9OLlf_TR1r9ZAI3KOAA4yCwDYZWVi0x87BPmnt0O1RWtQRfmDrXapLCHxdEz1KuCv8_KPWjKSm1lnyzg._lX83lJYfL2lf8Mq5t8N3r9-Qa9045Odx3bg9yL6deY
+testParameters.incorrectToken=eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiY3R5IjoiSldUIn0.U5PblBD4SRwVIYjZbG-OwA83pZeU63mj9VlOWxSgcRdskU24KDRA1utE3Ubl6zLtSgUuTtVtGgWNJWi-AHHQBRY1XLSfr4f7-5fUp3bUes1QtF3Sj8cUknA04_H4nyIzoHwxb_b80upS5wpps6gcASmBuWtVlwyCxiv-mR5mNvHro3ueZo1Lrxk0y4MSIXQA6FQlnTkamSdGGA9WDI1Q6pm4YVkPF4Z7OOobvwhqQJR3r4HUQyglf8jhdIBfxxzD6RRGqXTk7PVQgq2D018UAAgJfNmpD37_A9EPFsWDFNMj_7Prf_to48QnwVX5qHrVcHTclHPjgZb4TD8sEzKjTg.qxBxIfX41UfQbSOhLhRWoQ.bFqcOHyl8A6ujQR2oXToQIfbxvpKLchZwuz7KJ-y5jvOqEaOo0hzLX0G-ueeLZVbQFsuLFJSaJKPmEe1odPaRCjH4H1Seo2eUWMDIMGj7ub6v5dvn2Y7p5jpYKG2mHsFC0bA7nvMx6RyT4wMwPsX8GTDHDPwFFMRVoWzT0ENRuV358IjNp5wEWuKEHTB2_VKuUYKFGmP7rSsXlgSWYz6anJC41bVkzfv4OnJyYTV7DJ5yXtESkE9b1UZNDXpBezbeCAshpFgjKrACi_m46zRJR5kJP9Fkn_lJPPNvKd11Q3ij6OLPjLnoHm1vENnsP7BhWvLJhoTiGjMROe5hLL1AzajNYegSYHwKONPk2w_Zf9UZP8A2hq_s5olkDmopKPEiWJ_Ml8PN61Q9dfMtio7UvLIu9MP-12pU0hvCK1BMs_F8jqqm-SpxqSDa0sM-DJaeYjbxrCVzCiiJg04bq1y_2BrGP1sGi3pl6W-ezpmksyn0m_UjwCFl9nYi8caYHr4fNvBt4mRRY1ZoH-ihGWM0befFPyG-QjHqMTfdcwU17NyBHEqoq5Yxq4maOeULg7MM0MPP0I5g_s9P8ByrwJ0arTkmZIh4crjhhjXycsOMFNKJRd8CogmHHQPJ3VrT78bmLjVQ-2EyK7X3R-qs-JiUwY6HnQR9EpNcw_LeFRSPuqCWZBeyEDIS8T_Fc8fcHUj4nz0pdSN1GS5uSbdy8OwO87zF8y6g1pEo__yL_D1GwrLr1r6tfJbAAhIJC6vu4MwoJ1lhdGN3HODA2Kt87-1ww.onky0el9l6HXWQOIs2ZrWDHNl1jI06dxmQeJUJ_UwcA
diff --git a/hawkbit-configuration-manager/src/test/resources/banner.txt b/hawkbit-configuration-manager/src/test/resources/banner.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/hawkbit-configuration-manager/src/test/resources/log4j2.xml b/hawkbit-configuration-manager/src/test/resources/log4j2.xml
new file mode 100644
index 000000000..26c26f8dd
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/resources/log4j2.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex
+
+ OFF
+ .
+
+
+
+
+
+
+
+ ${LOG_PATTERN}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/resources/mockserver.properties b/hawkbit-configuration-manager/src/test/resources/mockserver.properties
new file mode 100644
index 000000000..2249ee4e4
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/resources/mockserver.properties
@@ -0,0 +1,7 @@
+mockserver.certificateAuthorityPrivateKey=./src/test/resources/test-certificates/test-cloud.key.pem
+mockserver.certificateAuthorityCertificate=./src/test/resources/test-certificates/test-cloud.cert.pem
+mockserver.sreg.privateKeyPath=./src/test/resources/test-certificates/test-sreg.key.pem
+mockserver.sreg.x509CertificatePath=./src/test/resources/test-certificates/test-sreg.cert.pem
+mockserver.auth.privateKeyPath=./src/test/resources/test-certificates/test-auth-system.key.pem
+mockserver.auth.x509CertificatePath=./src/test/resources/test-certificates/test-auth-system.cert.pem
+mockserver.auth.pubKeyResponse=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqIZpQa/yCE8JBYtLz+XkoXpHYUsTFHuntQIPV6pPgcX07OagpFWW+LIRWD4jXPc+ndXOVD7XmimnkAOXGYD+1GF+glBSCKVcjOM55S5LLoJbV9J77H1B/NhKQX6kZDxP94jRPql7YmMlo8ge3NHjc/isNh2mX8yS4LnjjXXdhv2Ggn0fcItgAAYd2CLpds/obrsue6hWD4G1T/TUTjgoYR3JiPh+XTOOQJXWTDMA5ay81/TGTLJ+PAc8Fp2GP+AED2QVmPO+PPuk4RjTCxS7L63aH0HW2o1ibf4kndKbsg5XwOEP56+IwEutGqctzQw4y3luLHXOBSxsfWcnyoMeDwIDAQAB
\ No newline at end of file
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/master.p12 b/hawkbit-configuration-manager/src/test/resources/test-certificates/master.p12
new file mode 100644
index 000000000..c6bc2c6ea
Binary files /dev/null and b/hawkbit-configuration-manager/src/test/resources/test-certificates/master.p12 differ
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-auth-system.cert.pem b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-auth-system.cert.pem
new file mode 100644
index 000000000..446256a20
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-auth-system.cert.pem
@@ -0,0 +1,80 @@
+Bag Attributes
+ friendlyName: authorization.example.corp.arrowhead.eu
+ localKeyID: 54 69 6D 65 20 31 36 30 34 36 36 32 30 32 37 30 39 34
+subject=CN = authorization.example.corp.arrowhead.eu
+
+issuer=C = DE, ST = Berlin, L = Berlin, O = AHT, OU = arrowhead.eu, CN = example.corp.arrowhead.eu
+
+-----BEGIN CERTIFICATE-----
+MIIDqjCCApKgAwIBAgIEX6UyfTANBgkqhkiG9w0BAQsFADB4MQswCQYDVQQGEwJE
+RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xDDAKBgNVBAoMA0FI
+VDEVMBMGA1UECwwMYXJyb3doZWFkLmV1MSIwIAYDVQQDDBlleGFtcGxlLmNvcnAu
+YXJyb3doZWFkLmV1MB4XDTIwMTEwNjExMjQ0NVoXDTMwMTEwNjExMjQ0NVowMjEw
+MC4GA1UEAwwnYXV0aG9yaXphdGlvbi5leGFtcGxlLmNvcnAuYXJyb3doZWFkLmV1
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqIZpQa/yCE8JBYtLz+Xk
+oXpHYUsTFHuntQIPV6pPgcX07OagpFWW+LIRWD4jXPc+ndXOVD7XmimnkAOXGYD+
+1GF+glBSCKVcjOM55S5LLoJbV9J77H1B/NhKQX6kZDxP94jRPql7YmMlo8ge3NHj
+c/isNh2mX8yS4LnjjXXdhv2Ggn0fcItgAAYd2CLpds/obrsue6hWD4G1T/TUTjgo
+YR3JiPh+XTOOQJXWTDMA5ay81/TGTLJ+PAc8Fp2GP+AED2QVmPO+PPuk4RjTCxS7
+L63aH0HW2o1ibf4kndKbsg5XwOEP56+IwEutGqctzQw4y3luLHXOBSxsfWcnyoMe
+DwIDAQABo4GBMH8wGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMEIGA1UdIwQ7
+MDmAFBOMBYikgCvo8FXUYauQwlW8VZvqoRukGTAXMRUwEwYDVQQDDAxhcnJvd2hl
+YWQuZXWCBF+kKMowHQYDVR0OBBYEFKAIzWSlATK8//WtDrPAzVbefzZUMA0GCSqG
+SIb3DQEBCwUAA4IBAQCKlv6loenAlJPgAzNkm9HVKU72Qk+Atn7J/lM3ub8SxTO2
+0tD8B9Jm+0kpn5Tl14KOPtCnjSu2hFRzp+q6x4N2P63SXezaBCuxIOfS3CSdEWPA
+sF9oTbhBaaz528lx2xjkI4yagDRdmNcnSvmoOJd4AfJpD8C1aWOm2EgDsC/MgB3w
+rMEBs67hFpzS0rxxNM1J6myc2Bhq2lzgwKE5tQxquSUBSjJtRyh0p3lZWLWp72jN
+YfwHg8T5l7Xvf/4l2kDiAOLZRRo/88SQpxxgIb3v54JfvRJmazapikgISMyv1U9s
+ukfQtyNSPeCX4+//LYda1D7EvuRIq5ljK0UdzEUn
+-----END CERTIFICATE-----
+Bag Attributes
+ friendlyName: CN=example.corp.arrowhead.eu,OU=arrowhead.eu,O=AHT,L=Berlin,ST=Berlin,C=DE
+subject=C = DE, ST = Berlin, L = Berlin, O = AHT, OU = arrowhead.eu, CN = example.corp.arrowhead.eu
+
+issuer=CN = arrowhead.eu
+
+-----BEGIN CERTIFICATE-----
+MIIDgzCCAmugAwIBAgIEX6QoyjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxh
+cnJvd2hlYWQuZXUwHhcNMjAxMTA1MTYzMTA2WhcNMzAxMTA1MTYzMTA2WjB4MQsw
+CQYDVQQGEwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xDDAK
+BgNVBAoMA0FIVDEVMBMGA1UECwwMYXJyb3doZWFkLmV1MSIwIAYDVQQDDBlleGFt
+cGxlLmNvcnAuYXJyb3doZWFkLmV1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAmrcvpwqTKaGgpQLuqXMi6TrH5KxkpFH8lH5vq2aozu7QnZexM0Qyf1TY
+kvpiy3sDTu6mzGysT96Qv8K8CI8g24oIVRKnJUEs23NgS+KUK6Nz2eIjRaaMVRh4
+cFBcRkr3oFbk+ujGySn+BR8v4eRjq5+qzFX8fswcoeBmlkU+M92kg/Bcy65Pg2v5
+1ORuGhbnmqsEuoyOsSjucL43zTOQtwAva5rvdERVPh7978I+UGFUXaSQnYpP8oyw
+CRRIYrPTBHHBA0Q/7sDb2lCA1yLPSwD/H5QvFOxmN3cYAnzvgQZO8+spCiy1T7Kx
+FBAnutVn8Sj6BeFNGZvszmlDCs54AwIDAQABo3YwdDAPBgNVHRMECDAGAQH/AgEC
+MEIGA1UdIwQ7MDmAFJqKmR4xTB6y5i22mu3HHjHK3Tv+oRukGTAXMRUwEwYDVQQD
+DAxhcnJvd2hlYWQuZXWCBFzVPq0wHQYDVR0OBBYEFBOMBYikgCvo8FXUYauQwlW8
+VZvqMA0GCSqGSIb3DQEBCwUAA4IBAQAEhHykqvmRnl3S0aVv4tSoA+tGxwBMaRoY
+OvxEDC321CFY/QkWaQfUpVg/eGgsLLFweUp9OFXxkgK4H/rUvQ/twt7oUIDUdJd+
+sGn04mIaym3M9IWhCTxqYf+X3/SHWmI5GnT3dQu9ayJKitD28/6FMLMqEdPiON/9
+VMzkoD2ndN6VSJWOWSg3xmOJ93u+xGbTkweIFildnhf79QwgColJGBytIWBhggvV
+DVccNfLqmq9NNaxvPx/y2Oe1ngNhLcqqTUSiwKH42pdupKWZD/EcNlMXttRrkiOt
+S3sXv18pDV/094abPB38ulgeeY7Kt2lz12qK7irxjZsVPahyW1Z0
+-----END CERTIFICATE-----
+Bag Attributes
+ friendlyName: CN=arrowhead.eu
+subject=CN = arrowhead.eu
+
+issuer=CN = arrowhead.eu
+
+-----BEGIN CERTIFICATE-----
+MIIC3jCCAcagAwIBAgIEXNU+rTANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxh
+cnJvd2hlYWQuZXUwHhcNMTkwNTEwMDkwNDQ1WhcNMjkwNTEwMDkwNDQ1WjAXMRUw
+EwYDVQQDDAxhcnJvd2hlYWQuZXUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCuB4z+wchXDKdfy9YFZha2U0khBAWuHYerBlBLM0Oqvr4c/YYcZpNwTWY2
+tk6UXPUTQ8gI9V6Ob7DRXoAfLDhCRGKySN0BlGnjUJkItP25Sj0RfiTL3b8fFEIT
+Z8pg+6pAfeFQgV0yz+ziyL+0uu69VZPv+RAEf1GKgshGGLJw3sOlcIdKuZaEAaA2
+b0nDUn229VpKXb9cg47Ae1Yb0sJcTkyIBuhkQKln3uhG2xct9nDfVal05+229AJQ
+Ly1f0UfEofvD/OLjFG3umF857T1Vr5azj8zFOvNi503gV458lH3wKC+9UHUf46sg
+Hc8Tyrz1q8VAIamJe7BLUeRFwGvBAgMBAAGjMjAwMA8GA1UdEwQIMAYBAf8CAQMw
+HQYDVR0OBBYEFJqKmR4xTB6y5i22mu3HHjHK3Tv+MA0GCSqGSIb3DQEBCwUAA4IB
+AQCkFsqyeAjztDBkTQrPxAB0Vvx6KPINApHGIHkJj/9crKXZEQcNJcJr35hfLcgv
+hSsmLMdeRFCeaG5QLmUKI6GFYIbX+6nawMLGzIPUTOGetNeuMauDXkq09Hu/UmjN
+AOgoD5vWdtyTbItv21enJnUelClAJ7VXti2QpyRM2puPHpZMNi4FWgLGPo6hq5ka
+d7KomzW8JLh2Vd67v/6mXGpST4EzyRe+Yb2FJZUmhxVWt68/MFaflPQ2toPIsIpW
+5m4OS+rT7t+uxPKWU/ogCK7BOUfE/qf3Al/osWkNKnFQDtO/7x7InEmRoP9EUv07
+JY4vK/+k5fJUZHpJzpuKxbBo
+-----END CERTIFICATE-----
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-auth-system.key.pem b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-auth-system.key.pem
new file mode 100644
index 000000000..cde3c39ae
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-auth-system.key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCohmlBr/IITwkF
+i0vP5eShekdhSxMUe6e1Ag9Xqk+BxfTs5qCkVZb4shFYPiNc9z6d1c5UPteaKaeQ
+A5cZgP7UYX6CUFIIpVyM4znlLksugltX0nvsfUH82EpBfqRkPE/3iNE+qXtiYyWj
+yB7c0eNz+Kw2HaZfzJLgueONdd2G/YaCfR9wi2AABh3YIul2z+huuy57qFYPgbVP
+9NROOChhHcmI+H5dM45AldZMMwDlrLzX9MZMsn48BzwWnYY/4AQPZBWY8748+6Th
+GNMLFLsvrdofQdbajWJt/iSd0puyDlfA4Q/nr4jAS60apy3NDDjLeW4sdc4FLGx9
+ZyfKgx4PAgMBAAECggEAB5o8sFpsHETYftgIXQIdfM1j3/c/jpp/d9J2d7l2qb+Q
+64kB8TftPh3mW2k+NijvObaV/sXw+wLrDLukuuFPXaxiRSWzdbFkCfUMPRMIEDqQ
+PVeBAKur6Oim/OpmJyFzaBLTgbSqnMclQQy7m7GaRbaPqkdPJJ45eArawZxyGG9P
+nB1Iwnv1J7KilklJuWkzFSrlk2VE+UUzAiUiRN2TPtGQ0HOnTz+piuovSEIDco3v
+EUCpr6sppUTHKRCyN6h6UZlMeFAfyjiTDWXhx8N5pN00m8QXdL7g2EILBnB8/m1r
+sUUiVlAznSQ+C5oVEuc17NpuABA94yfCSRA8XUvVXQKBgQDqVjjfZnXMJsi7N4gO
+DTuuWrpPBV03RVOBHtcrW0zGcyxGkz4B/E9pm0A7q2PSfVR0YaunetLFjMpm/GOC
+AD7Bys19NtejKnrgOFwcDxYnj5spvu5huMpkIdmr0sSMaQ8CoaCm3R16GOUEUax+
+6s7HfBoJedWSmrOT/V9n+DyfjQKBgQC4GrK/mteRXgq/2NrukxrfhIcFcwQ3Hige
+V3ZgsMdwROUeKz5AYX/vQdL3t1cQkmTfBiIS+MPxRrtCIaR0AQ10IvA1ch7eIIrJ
+8YVTZQEurTRJrzDuwpJSlHQyGEqBKCTx6wKesAnb+D6CWmTpl5569Yya/VTGLvkL
+sISo9YsPCwKBgQCUaRsH0XpVW1LRzy+pxpO/rtJD7Z/Fu3BRXFjlqqMLJDIsWGBz
+HXql5Z9eqwNDcgCk3J68KTuHxc0CQGI9GS6lyW0vGiajvemoS8l6M8vSLk8Ut0l+
+Nmxn0lBrU8cLLhZFkluOkodypoWUoK1gjBF9oYlT6wdqG/QTi+p6jGrImQKBgQCq
+7HaZtzt+Bc57EO0p5D9l11e38nGubnwWt2L7IAT5saz6FnHEOgEZ84XXYEsf4ppu
+CPanoHfiUKXYHv3ciYGhGjLjm+EWnyXbmTUMGNFBMaNC6bjHYrOQoa1DORQq10d9
+po+XHp74r3/xa9UWniKPy9tPpfUHzmJ/vNFdQCJrwwKBgAyVj1mgcmvT4ISfgwtm
+nBLJ7a0fDvRRphCC6LUyYMntAHRzAJspYMmgdBb32PClF4WmJ01APtToYFWroUYL
+JG6lQAZE92qyhxaR/Juth30zsTVVczsL0zQ16cAEMneNf9LCjZG2f78driNMsX6h
+ystjmZOkSuYTKgNc7nfDnNZE
+-----END PRIVATE KEY-----
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-auth-system.p12 b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-auth-system.p12
new file mode 100644
index 000000000..5f54d7f3e
Binary files /dev/null and b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-auth-system.p12 differ
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.cert.pem b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.cert.pem
new file mode 100644
index 000000000..128567567
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.cert.pem
@@ -0,0 +1,52 @@
+Bag Attributes
+ friendlyName: example.corp.arrowhead.eu
+ localKeyID: 54 69 6D 65 20 31 36 30 34 35 39 34 31 32 36 38 31 36
+subject=C = DE, ST = Berlin, L = Berlin, O = AHT, OU = arrowhead.eu, CN = example.corp.arrowhead.eu
+
+issuer=CN = arrowhead.eu
+
+-----BEGIN CERTIFICATE-----
+MIIDgzCCAmugAwIBAgIEX6QoyjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxh
+cnJvd2hlYWQuZXUwHhcNMjAxMTA1MTYzMTA2WhcNMzAxMTA1MTYzMTA2WjB4MQsw
+CQYDVQQGEwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xDDAK
+BgNVBAoMA0FIVDEVMBMGA1UECwwMYXJyb3doZWFkLmV1MSIwIAYDVQQDDBlleGFt
+cGxlLmNvcnAuYXJyb3doZWFkLmV1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAmrcvpwqTKaGgpQLuqXMi6TrH5KxkpFH8lH5vq2aozu7QnZexM0Qyf1TY
+kvpiy3sDTu6mzGysT96Qv8K8CI8g24oIVRKnJUEs23NgS+KUK6Nz2eIjRaaMVRh4
+cFBcRkr3oFbk+ujGySn+BR8v4eRjq5+qzFX8fswcoeBmlkU+M92kg/Bcy65Pg2v5
+1ORuGhbnmqsEuoyOsSjucL43zTOQtwAva5rvdERVPh7978I+UGFUXaSQnYpP8oyw
+CRRIYrPTBHHBA0Q/7sDb2lCA1yLPSwD/H5QvFOxmN3cYAnzvgQZO8+spCiy1T7Kx
+FBAnutVn8Sj6BeFNGZvszmlDCs54AwIDAQABo3YwdDAPBgNVHRMECDAGAQH/AgEC
+MEIGA1UdIwQ7MDmAFJqKmR4xTB6y5i22mu3HHjHK3Tv+oRukGTAXMRUwEwYDVQQD
+DAxhcnJvd2hlYWQuZXWCBFzVPq0wHQYDVR0OBBYEFBOMBYikgCvo8FXUYauQwlW8
+VZvqMA0GCSqGSIb3DQEBCwUAA4IBAQAEhHykqvmRnl3S0aVv4tSoA+tGxwBMaRoY
+OvxEDC321CFY/QkWaQfUpVg/eGgsLLFweUp9OFXxkgK4H/rUvQ/twt7oUIDUdJd+
+sGn04mIaym3M9IWhCTxqYf+X3/SHWmI5GnT3dQu9ayJKitD28/6FMLMqEdPiON/9
+VMzkoD2ndN6VSJWOWSg3xmOJ93u+xGbTkweIFildnhf79QwgColJGBytIWBhggvV
+DVccNfLqmq9NNaxvPx/y2Oe1ngNhLcqqTUSiwKH42pdupKWZD/EcNlMXttRrkiOt
+S3sXv18pDV/094abPB38ulgeeY7Kt2lz12qK7irxjZsVPahyW1Z0
+-----END CERTIFICATE-----
+Bag Attributes
+ friendlyName: CN=arrowhead.eu
+subject=CN = arrowhead.eu
+
+issuer=CN = arrowhead.eu
+
+-----BEGIN CERTIFICATE-----
+MIIC3jCCAcagAwIBAgIEXNU+rTANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxh
+cnJvd2hlYWQuZXUwHhcNMTkwNTEwMDkwNDQ1WhcNMjkwNTEwMDkwNDQ1WjAXMRUw
+EwYDVQQDDAxhcnJvd2hlYWQuZXUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCuB4z+wchXDKdfy9YFZha2U0khBAWuHYerBlBLM0Oqvr4c/YYcZpNwTWY2
+tk6UXPUTQ8gI9V6Ob7DRXoAfLDhCRGKySN0BlGnjUJkItP25Sj0RfiTL3b8fFEIT
+Z8pg+6pAfeFQgV0yz+ziyL+0uu69VZPv+RAEf1GKgshGGLJw3sOlcIdKuZaEAaA2
+b0nDUn229VpKXb9cg47Ae1Yb0sJcTkyIBuhkQKln3uhG2xct9nDfVal05+229AJQ
+Ly1f0UfEofvD/OLjFG3umF857T1Vr5azj8zFOvNi503gV458lH3wKC+9UHUf46sg
+Hc8Tyrz1q8VAIamJe7BLUeRFwGvBAgMBAAGjMjAwMA8GA1UdEwQIMAYBAf8CAQMw
+HQYDVR0OBBYEFJqKmR4xTB6y5i22mu3HHjHK3Tv+MA0GCSqGSIb3DQEBCwUAA4IB
+AQCkFsqyeAjztDBkTQrPxAB0Vvx6KPINApHGIHkJj/9crKXZEQcNJcJr35hfLcgv
+hSsmLMdeRFCeaG5QLmUKI6GFYIbX+6nawMLGzIPUTOGetNeuMauDXkq09Hu/UmjN
+AOgoD5vWdtyTbItv21enJnUelClAJ7VXti2QpyRM2puPHpZMNi4FWgLGPo6hq5ka
+d7KomzW8JLh2Vd67v/6mXGpST4EzyRe+Yb2FJZUmhxVWt68/MFaflPQ2toPIsIpW
+5m4OS+rT7t+uxPKWU/ogCK7BOUfE/qf3Al/osWkNKnFQDtO/7x7InEmRoP9EUv07
+JY4vK/+k5fJUZHpJzpuKxbBo
+-----END CERTIFICATE-----
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.key.pem b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.key.pem
new file mode 100644
index 000000000..5c201123b
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCaty+nCpMpoaCl
+Au6pcyLpOsfkrGSkUfyUfm+rZqjO7tCdl7EzRDJ/VNiS+mLLewNO7qbMbKxP3pC/
+wrwIjyDbighVEqclQSzbc2BL4pQro3PZ4iNFpoxVGHhwUFxGSvegVuT66MbJKf4F
+Hy/h5GOrn6rMVfx+zByh4GaWRT4z3aSD8FzLrk+Da/nU5G4aFueaqwS6jI6xKO5w
+vjfNM5C3AC9rmu90RFU+Hv3vwj5QYVRdpJCdik/yjLAJFEhis9MEccEDRD/uwNva
+UIDXIs9LAP8flC8U7GY3dxgCfO+BBk7z6ykKLLVPsrEUECe61WfxKPoF4U0Zm+zO
+aUMKzngDAgMBAAECggEADZysXp/5jqIfxiTZ5qKwoaCAUcgxGpv0AwSUwpnHpF0y
+kYr1FjOb1cQbQeMxqgFqqxkoJ7gv+N72EUkKzh35oBcm4IVBm29+iNg/0q1ep/A7
+kyHoRIqAskPy5L7NP4n8+2hpwQGV68D8DmtOBSvY8RKdLlkqW+WNZ1ic7f+tl1Z3
+vi3o0SfID6FvVTUXhWMopR2eLDOn5oX9MQE1uXqZyBDk8/6DxcMqjleDnVMmJWMz
+HPlhPK2TFcW8UPxYuCe2z1s1OMR+sdOKZ0g87wD/GEm95SR8gTzbN6OJkvWVxYIl
+RPTk4ukK5gyhJDKAh+/jQXEkzdmwAySBR/x6to2dwQKBgQDSW9XloxjpcvkpkaPe
+rXsR+FY/TCBLSfFrtXnKxSmqLxSZBBWHNlyhMO7zdJRa6m9EnPZizIv0Kl/RkHzH
+GMc4GYiJEJ9p0kiyB2iDXuxurw2BrCyowNWJOvQ1i8EMULv39DIYGHtTNxHXRPqx
+mkPtAed2mi+BWieCtoRJto2JUQKBgQC8SLUEB/f/Wll2ujhyi01WSbNe9+MoOTmn
+ibN6Uf3bZtul0MS6uKs4Bljjo9BovyBNXqCVcG+VngyhyoV+Ed/dSjBRnG9nol0o
+uMWHDIFn7BjdfT5tekzUy40K2BeU6RRRLZ+Wrh87mVC0H18hTqKQoXPZmQwyXBGQ
+sq1bOccXEwKBgQCvRCz3Y+jBuTW4WMw8IDbGRi82FetiT32CzHVpaNTKIuf6hdia
+C8Up2Gd/GMby6RlEBbOTpfGFwjiLluMfz5lNOJj1+o+Xz8kZ6+o8ar57igaq4BVl
+lSVVbXVDl+mEpU+3zBJg2SUHtH586dAmYe3ubwO3Ycfq8n6w/flCoYNTwQKBgQCb
+9eXrVuZ4IFDm5c4II5eGGDp6Of9xvCUjwA5pDi2nZYYfzdSHjpxVJfzPY0wo19hb
+/jwqTR5A4tA33FfDW+8BkIiBsYEeaQGdz5/fA97VRF48aZgieyHVSl6kUucFtCPe
+Mlp1J/o7Ff4hlbLpFgfWocYiwoG13Um3gCnU3QEq/QKBgQCpXFRfz3CKM2Qs1ThV
+Rs7qxcmpReQTRy0uMQ5C/VTMSI+S9LAreVn/juZV4DY+ukV6gXFENpXRzU+K71cN
+nducNnGJ0LoiNdtiPuCiCVLNkuYU87HlIPIc07g3MSUJ6ZVs38mI8yFnGhXsMpfB
+9WU9YlS49UkHvw9ma7U8+MldoQ==
+-----END PRIVATE KEY-----
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.p12 b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.p12
new file mode 100644
index 000000000..ac088c1cb
Binary files /dev/null and b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.p12 differ
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.truststore.p12 b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.truststore.p12
new file mode 100644
index 000000000..434905c9a
Binary files /dev/null and b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-cloud.truststore.p12 differ
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-conf-system.p12 b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-conf-system.p12
new file mode 100644
index 000000000..0c7e3633e
Binary files /dev/null and b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-conf-system.p12 differ
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-hdevice.p12 b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-hdevice.p12
new file mode 100644
index 000000000..c7eb364e2
Binary files /dev/null and b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-hdevice.p12 differ
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-orch.p12 b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-orch.p12
new file mode 100644
index 000000000..119baf27a
Binary files /dev/null and b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-orch.p12 differ
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sreg.cert.pem b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sreg.cert.pem
new file mode 100644
index 000000000..72e8d632a
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sreg.cert.pem
@@ -0,0 +1,80 @@
+Bag Attributes
+ friendlyName: service_registry.example.corp.arrowhead.eu
+ localKeyID: 54 69 6D 65 20 31 36 30 34 36 36 32 37 30 37 31 37 34
+subject=CN = service_registry.example.corp.arrowhead.eu
+
+issuer=C = DE, ST = Berlin, L = Berlin, O = AHT, OU = arrowhead.eu, CN = example.corp.arrowhead.eu
+
+-----BEGIN CERTIFICATE-----
+MIIDrTCCApWgAwIBAgIEX6UzaTANBgkqhkiG9w0BAQsFADB4MQswCQYDVQQGEwJE
+RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xDDAKBgNVBAoMA0FI
+VDEVMBMGA1UECwwMYXJyb3doZWFkLmV1MSIwIAYDVQQDDBlleGFtcGxlLmNvcnAu
+YXJyb3doZWFkLmV1MB4XDTIwMTEwNjExMjg0MVoXDTMwMTEwNjExMjg0MVowNTEz
+MDEGA1UEAwwqc2VydmljZV9yZWdpc3RyeS5leGFtcGxlLmNvcnAuYXJyb3doZWFk
+LmV1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxRAbGzhXa/9qmsVs
+tavu72oQaPxaqkinE4NOxlqv309nKrtV24ETW0xilD9L6UUkdHOMXDuCi9vSivHD
+9LT+lSIgy+O1+7mpH4ykN9Fv6KSXoDCt37+nCV8ysp7syy1cVh9sMGbGZcbqenOn
+S7aNZ0YlLMsvgbB4rG2CdRRFtOUaVWre3lKd3U6DW69jTk+ObtbLymfrlDqTugmj
+FWbBLbEq5MCtnDR1sZ5aupHW8KTxnqMOz4Q0Xg7NYUAad1hGkzkM304Y8BO99RNp
+Of96B54R8zB30nvsCBR7vp4/pzgqtf4b2qY25eU1Sn530LHpp2TrEumUpyyTbh8P
+xGssiwIDAQABo4GBMH8wGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMEIGA1Ud
+IwQ7MDmAFBOMBYikgCvo8FXUYauQwlW8VZvqoRukGTAXMRUwEwYDVQQDDAxhcnJv
+d2hlYWQuZXWCBF+kKMowHQYDVR0OBBYEFMRvboBK5sZoOK6kt5PUmkNnWrTtMA0G
+CSqGSIb3DQEBCwUAA4IBAQA2yW1neYa+FCfiBQApV17RJDA8CbdU0jgcJNwwg1OG
+AHhtDZ5zy/v/mfI1fYF3aiB/UgIfaNzqRtTLNLdpSgV3TNCsP5O7EYgyElQkNcIH
+LJAFbqUnObFgrhuU6Sdv7qtHy3s0sKePDvpxa4G6jD6RdJqxCd5ziIjh57tFE3bt
+0KMFdMKL9YahBElPrwqqA6wEKWHQBJSg841Up4noYg1HI32hJQP2pzeXl5zU0grR
+Cp5y37gEa0KPosQp7u9e6D1O1/WyYuEZ5p81fCgdzNsJc77Pi147AT5UQLxgv3FZ
+mchn0yB3mDBE/qmPSeoq5L8lwkpjHuDHbTZA8LSg8CbO
+-----END CERTIFICATE-----
+Bag Attributes
+ friendlyName: CN=example.corp.arrowhead.eu,OU=arrowhead.eu,O=AHT,L=Berlin,ST=Berlin,C=DE
+subject=C = DE, ST = Berlin, L = Berlin, O = AHT, OU = arrowhead.eu, CN = example.corp.arrowhead.eu
+
+issuer=CN = arrowhead.eu
+
+-----BEGIN CERTIFICATE-----
+MIIDgzCCAmugAwIBAgIEX6QoyjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxh
+cnJvd2hlYWQuZXUwHhcNMjAxMTA1MTYzMTA2WhcNMzAxMTA1MTYzMTA2WjB4MQsw
+CQYDVQQGEwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xDDAK
+BgNVBAoMA0FIVDEVMBMGA1UECwwMYXJyb3doZWFkLmV1MSIwIAYDVQQDDBlleGFt
+cGxlLmNvcnAuYXJyb3doZWFkLmV1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAmrcvpwqTKaGgpQLuqXMi6TrH5KxkpFH8lH5vq2aozu7QnZexM0Qyf1TY
+kvpiy3sDTu6mzGysT96Qv8K8CI8g24oIVRKnJUEs23NgS+KUK6Nz2eIjRaaMVRh4
+cFBcRkr3oFbk+ujGySn+BR8v4eRjq5+qzFX8fswcoeBmlkU+M92kg/Bcy65Pg2v5
+1ORuGhbnmqsEuoyOsSjucL43zTOQtwAva5rvdERVPh7978I+UGFUXaSQnYpP8oyw
+CRRIYrPTBHHBA0Q/7sDb2lCA1yLPSwD/H5QvFOxmN3cYAnzvgQZO8+spCiy1T7Kx
+FBAnutVn8Sj6BeFNGZvszmlDCs54AwIDAQABo3YwdDAPBgNVHRMECDAGAQH/AgEC
+MEIGA1UdIwQ7MDmAFJqKmR4xTB6y5i22mu3HHjHK3Tv+oRukGTAXMRUwEwYDVQQD
+DAxhcnJvd2hlYWQuZXWCBFzVPq0wHQYDVR0OBBYEFBOMBYikgCvo8FXUYauQwlW8
+VZvqMA0GCSqGSIb3DQEBCwUAA4IBAQAEhHykqvmRnl3S0aVv4tSoA+tGxwBMaRoY
+OvxEDC321CFY/QkWaQfUpVg/eGgsLLFweUp9OFXxkgK4H/rUvQ/twt7oUIDUdJd+
+sGn04mIaym3M9IWhCTxqYf+X3/SHWmI5GnT3dQu9ayJKitD28/6FMLMqEdPiON/9
+VMzkoD2ndN6VSJWOWSg3xmOJ93u+xGbTkweIFildnhf79QwgColJGBytIWBhggvV
+DVccNfLqmq9NNaxvPx/y2Oe1ngNhLcqqTUSiwKH42pdupKWZD/EcNlMXttRrkiOt
+S3sXv18pDV/094abPB38ulgeeY7Kt2lz12qK7irxjZsVPahyW1Z0
+-----END CERTIFICATE-----
+Bag Attributes
+ friendlyName: CN=arrowhead.eu
+subject=CN = arrowhead.eu
+
+issuer=CN = arrowhead.eu
+
+-----BEGIN CERTIFICATE-----
+MIIC3jCCAcagAwIBAgIEXNU+rTANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxh
+cnJvd2hlYWQuZXUwHhcNMTkwNTEwMDkwNDQ1WhcNMjkwNTEwMDkwNDQ1WjAXMRUw
+EwYDVQQDDAxhcnJvd2hlYWQuZXUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCuB4z+wchXDKdfy9YFZha2U0khBAWuHYerBlBLM0Oqvr4c/YYcZpNwTWY2
+tk6UXPUTQ8gI9V6Ob7DRXoAfLDhCRGKySN0BlGnjUJkItP25Sj0RfiTL3b8fFEIT
+Z8pg+6pAfeFQgV0yz+ziyL+0uu69VZPv+RAEf1GKgshGGLJw3sOlcIdKuZaEAaA2
+b0nDUn229VpKXb9cg47Ae1Yb0sJcTkyIBuhkQKln3uhG2xct9nDfVal05+229AJQ
+Ly1f0UfEofvD/OLjFG3umF857T1Vr5azj8zFOvNi503gV458lH3wKC+9UHUf46sg
+Hc8Tyrz1q8VAIamJe7BLUeRFwGvBAgMBAAGjMjAwMA8GA1UdEwQIMAYBAf8CAQMw
+HQYDVR0OBBYEFJqKmR4xTB6y5i22mu3HHjHK3Tv+MA0GCSqGSIb3DQEBCwUAA4IB
+AQCkFsqyeAjztDBkTQrPxAB0Vvx6KPINApHGIHkJj/9crKXZEQcNJcJr35hfLcgv
+hSsmLMdeRFCeaG5QLmUKI6GFYIbX+6nawMLGzIPUTOGetNeuMauDXkq09Hu/UmjN
+AOgoD5vWdtyTbItv21enJnUelClAJ7VXti2QpyRM2puPHpZMNi4FWgLGPo6hq5ka
+d7KomzW8JLh2Vd67v/6mXGpST4EzyRe+Yb2FJZUmhxVWt68/MFaflPQ2toPIsIpW
+5m4OS+rT7t+uxPKWU/ogCK7BOUfE/qf3Al/osWkNKnFQDtO/7x7InEmRoP9EUv07
+JY4vK/+k5fJUZHpJzpuKxbBo
+-----END CERTIFICATE-----
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sreg.key.pem b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sreg.key.pem
new file mode 100644
index 000000000..0d24c2281
--- /dev/null
+++ b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sreg.key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDFEBsbOFdr/2qa
+xWy1q+7vahBo/FqqSKcTg07GWq/fT2cqu1XbgRNbTGKUP0vpRSR0c4xcO4KL29KK
+8cP0tP6VIiDL47X7uakfjKQ30W/opJegMK3fv6cJXzKynuzLLVxWH2wwZsZlxup6
+c6dLto1nRiUsyy+BsHisbYJ1FEW05RpVat7eUp3dToNbr2NOT45u1svKZ+uUOpO6
+CaMVZsEtsSrkwK2cNHWxnlq6kdbwpPGeow7PhDReDs1hQBp3WEaTOQzfThjwE731
+E2k5/3oHnhHzMHfSe+wIFHu+nj+nOCq1/hvapjbl5TVKfnfQsemnZOsS6ZSnLJNu
+Hw/EayyLAgMBAAECggEAEK4k/TrZpi8/1iCb67dv9B1QN51qDJE1wzW8Iey53Pca
++Rz+Ts7a1UGJSUR0/SZ4ctBNCImTqpmiyqwINYW/KYnH/jokxKKZ1C0oFqlzBYgu
+ZXAkEj+7YymxtY405kXNU7o5LXz653vc4RyPrp2h089g2i0gtPjmXgIEUZCzuHSo
+privjmUQtX/8MSj68gDQ5555/EUtWhMjEBrl0nOBWcsg3vNhPtHTWJCnKMMlA/hr
+hqItoygjjYMMXujxX/laPke1yjPiXA7NP/YM1gAZUicB7TPaf9ltJ3bMyhnuUWab
+k5iprSGMlxYaJIjoHDYtzRYe6DAZ998YMfjJD3MosQKBgQDpXp8vBi819Ucw4viQ
+N5Fh1GOgq7QaUlMdobZDe6AUKC2ngdlvt3linmbGsLjivxwcgmBBqT+5vdAN4ND4
+JURvobAiLNE+1pUEdNBUJ62RrorIEqHH/Egrgb9azW5GT+WRk3TPWL78WIC/PBfI
+laJetx32KlVc+vVYcJH9yk8IzQKBgQDYLCx2Ysz3H+XFa5Wvar5owrhBXBZoWclR
+8yHIYyrjaqYQIo+cy8Lhneh+KQ97DITTTuJHAv1gvMxtwnU2ZiJCNYdgEl4+vH+t
+9aJTjdTI5NvYb1mxDOA9JUT3DzZK1s2VnkOmA43eIlPCog7ZkvHKt/rX0iKX2NaX
+wsY/GWNqtwKBgQCaBNYAXg+IiBHtJM8xt0rfCyKZptjdylmKo/C7xvqWcxH2jI9p
+2Ohm+u4P0hCjrceq1S0cCMzDFJAcqLSiIU5ycn7hfzy2QT7mSwY3lFxMWqrDcvCN
+IWasOByHnC9cflyf4HbmZcbemraV/94ehws7gZVnovblv8dvEBR6MCxLPQKBgBH1
+0Zfga5EYqFl3r88MOlev3ekoQoBW/V/+qE7i1lxgrv1mMbJgR4fBO+DHfo7Fon9/
+7VLjD7Qq230/C8gCQlRn6CB2RjhGJwGIB/2TKhuq0A0yayxHmpXZ89nm/KbJI/mL
+VamEYBQVnAnutvciu04RbRjjT5Z4IJQpTZlOfbEPAoGAO6RBn7kHsSh4F6QEVS4U
+nL5X8uG0I6xSdLDT9xNbyjwHs5r0EBkjo+QXG5vC/ofgVp52DEPoicSCue5l/C3e
+h2kq/H55iHkcJC/EVEwOAiGZPOznFMzwfWCT8sW9uIloe+vLAJiqezltKK+oDA2P
+/rpiixiWCPNlHvre5ugcPw0=
+-----END PRIVATE KEY-----
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sreg.p12 b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sreg.p12
new file mode 100644
index 000000000..caf350bff
Binary files /dev/null and b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sreg.p12 differ
diff --git a/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sysop.p12 b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sysop.p12
new file mode 100644
index 000000000..7668c04a2
Binary files /dev/null and b/hawkbit-configuration-manager/src/test/resources/test-certificates/test-sysop.p12 differ
diff --git a/kubernetes/README.md b/kubernetes/README.md
new file mode 100644
index 000000000..4584cd26c
--- /dev/null
+++ b/kubernetes/README.md
@@ -0,0 +1,50 @@
+# Arrowhead Core Systems Helm chart
+
+## Introduction
+
+This Helm chart enables you to quickly setup the Arrowhead core systems on your Kubernetes cluster.
+Currently, the three mandatory core systems (service registry, authorization system and orchestrator) are supported.
+
+Supported core systems:
+
+| core system | included |
+| ----------------- | :--------: |
+| Service Registry | ☑ |
+| Authorization System | ☑ |
+| Orchestrator | ☑ |
+| event handler | |
+| Gatekeeper | |
+| Gateway | |
+| Gateway | |
+| Certificate Authority | |
+| QoS Monitor | |
+| Onboarding Controller | |
+| Device Registry | |
+| System Registry | |
+| Choreographer | |
+
+## Ingress
+This deployment uses the [Ambassador Emissary Ingress implementation](https://www.getambassador.io/products/api-gateway/) to route traffic to each core system.
+You will need to provision a static and public IP address beforehand.
+The required steps for that strongly depend on the cloud provider or (in case you are hosting the cluster by yourself) Kubernetes distribution you are using.
+
+To let Ambassador know, on what IP address it should listen on, modify the `emissary-ingress.service.loadBalancerIP` property in the `values.yaml`.
+In case you do not have a domain name yet, you need to set the `domain` property for each service to the same public IP address.
+Also, set the ports your core systems are listening on.
+By default the port range starts at `3000` for the service registry and continues with `3001` for the authorization system, etc.
+These ports also need to map to the exposed Ambassador ports.
+
+## Setup
+To configure the core system properties, modify the `values.yaml` accordingly.
+Remember to set the datasource credentials which is used to setup a connection with the database.
+Furthermore, you need to generate your cloud and core system certificates as keystores (PKCS12) and place them under `static/certificates`.
+Now, modify the properties `keystore`, `keystorePassword`, `keyAlias`, `keyPassword`, `truststore` and `truststorePassword` in the `values.yaml` for each core system.
+
+## Deployment
+Load the necessary dependencies: `helm dep up arrowhead/`
+
+Apply the Ambassador CRDs: `kubectl apply -f https://app.getambassador.io/yaml/emissary/2.1.0/emissary-crds.yaml`
+
+Now, we have to create a new namespace in your cluster: `kubectl create namespace arrowhead`
+
+Finally, you can start the actual deployment by running `helm install arrowhead arrowhead/ -n arrowhead`
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/.gitignore b/kubernetes/arrowhead-helm/.gitignore
new file mode 100644
index 000000000..ee27b40cf
--- /dev/null
+++ b/kubernetes/arrowhead-helm/.gitignore
@@ -0,0 +1,2 @@
+*.tgz
+.DS_Store
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/.helmignore b/kubernetes/arrowhead-helm/.helmignore
new file mode 100644
index 000000000..0e8a0eb36
--- /dev/null
+++ b/kubernetes/arrowhead-helm/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/kubernetes/arrowhead-helm/Chart.lock b/kubernetes/arrowhead-helm/Chart.lock
new file mode 100644
index 000000000..05f55d90e
--- /dev/null
+++ b/kubernetes/arrowhead-helm/Chart.lock
@@ -0,0 +1,6 @@
+dependencies:
+- name: emissary-ingress
+ repository: https://app.getambassador.io
+ version: 7.2.0
+digest: sha256:69f5374b042286ae53e60729065a58181b47d8bafa8b1cfdf8a9809c93834451
+generated: "2022-01-04T18:44:09.734379+01:00"
diff --git a/kubernetes/arrowhead-helm/Chart.yaml b/kubernetes/arrowhead-helm/Chart.yaml
new file mode 100644
index 000000000..e34f603d5
--- /dev/null
+++ b/kubernetes/arrowhead-helm/Chart.yaml
@@ -0,0 +1,14 @@
+apiVersion: v2
+name: arrowhead
+description: A Helm chart for the Arrowhead core systems
+
+type: application
+
+version: 1.0.0
+
+appVersion: 4.4.0
+
+dependencies:
+ - name: emissary-ingress
+ version: 7.2.0
+ repository: https://app.getambassador.io
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/charts/.gitignore b/kubernetes/arrowhead-helm/charts/.gitignore
new file mode 100644
index 000000000..9e30eb9b7
--- /dev/null
+++ b/kubernetes/arrowhead-helm/charts/.gitignore
@@ -0,0 +1 @@
+*.tgz
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/certificates/test-auth-system.p12 b/kubernetes/arrowhead-helm/static/certificates/test-auth-system.p12
new file mode 100644
index 000000000..5f3c83526
Binary files /dev/null and b/kubernetes/arrowhead-helm/static/certificates/test-auth-system.p12 differ
diff --git a/kubernetes/arrowhead-helm/static/certificates/test-cloud.truststore.p12 b/kubernetes/arrowhead-helm/static/certificates/test-cloud.truststore.p12
new file mode 100644
index 000000000..2d45b8ba5
Binary files /dev/null and b/kubernetes/arrowhead-helm/static/certificates/test-cloud.truststore.p12 differ
diff --git a/kubernetes/arrowhead-helm/static/certificates/test-orch.p12 b/kubernetes/arrowhead-helm/static/certificates/test-orch.p12
new file mode 100644
index 000000000..ef0072d66
Binary files /dev/null and b/kubernetes/arrowhead-helm/static/certificates/test-orch.p12 differ
diff --git a/kubernetes/arrowhead-helm/static/certificates/test-sreg.p12 b/kubernetes/arrowhead-helm/static/certificates/test-sreg.p12
new file mode 100644
index 000000000..ef80d8ea1
Binary files /dev/null and b/kubernetes/arrowhead-helm/static/certificates/test-sreg.p12 differ
diff --git a/kubernetes/arrowhead-helm/static/certificates/testcloud2.aitia.arrowhead.eu.p12 b/kubernetes/arrowhead-helm/static/certificates/testcloud2.aitia.arrowhead.eu.p12
new file mode 100644
index 000000000..071c456b1
Binary files /dev/null and b/kubernetes/arrowhead-helm/static/certificates/testcloud2.aitia.arrowhead.eu.p12 differ
diff --git a/kubernetes/arrowhead-helm/static/db-init/authorization_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/authorization_privileges.sql
new file mode 100644
index 000000000..0484c30a3
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/authorization_privileges.sql
@@ -0,0 +1,33 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'authorization'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'authorization'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'authorization'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'authorization'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'authorization'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'authorization'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/certificate_authority_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/certificate_authority_privileges.sql
new file mode 100644
index 000000000..413aa5090
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/certificate_authority_privileges.sql
@@ -0,0 +1,13 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'certificate_authority'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'certificate_authority'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`ca_certificate` TO 'certificate_authority'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`ca_trusted_key` TO 'certificate_authority'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'certificate_authority'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'certificate_authority'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`ca_certificate` TO 'certificate_authority'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`ca_trusted_key` TO 'certificate_authority'@'%';
+
+FLUSH PRIVILEGES;
diff --git a/kubernetes/arrowhead-helm/static/db-init/choreographer_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/choreographer_privileges.sql
new file mode 100644
index 000000000..b022267bc
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/choreographer_privileges.sql
@@ -0,0 +1,27 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'choreographer'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_plan` TO 'choreographer'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action` TO 'choreographer'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_step` TO 'choreographer'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_step_service_definition_connection` TO 'choreographer'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_step_next_step_connection` TO 'choreographer'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_session` TO 'choreographer'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_running_step` TO 'choreographer'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_worklog` TO 'choreographer'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'choreographer'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'choreographer'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_plan` TO 'choreographer'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action` TO 'choreographer'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_step` TO 'choreographer'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_step_service_definition_connection` TO 'choreographer'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_step_next_step_connection` TO 'choreographer'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_session` TO 'choreographer'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_running_step` TO 'choreographer'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_worklog` TO 'choreographer'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'choreographer'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/configuration_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/configuration_privileges.sql
new file mode 100644
index 000000000..fd9ad9956
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/configuration_privileges.sql
@@ -0,0 +1,11 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'configuration'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`configuration_data` TO 'configuration'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'configuration'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`configuration_data` TO 'configuration'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'configuration'@'%';
+
+FLUSH PRIVILEGES;
diff --git a/kubernetes/arrowhead-helm/static/db-init/create_arrowhead_tables.sql b/kubernetes/arrowhead-helm/static/db-init/create_arrowhead_tables.sql
new file mode 100644
index 000000000..dfac3666f
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/create_arrowhead_tables.sql
@@ -0,0 +1,731 @@
+CREATE DATABASE IF NOT EXISTS `arrowhead`;
+USE `arrowhead`;
+
+-- Common
+
+CREATE TABLE IF NOT EXISTS `cloud` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `operator` varchar(255) NOT NULL,
+ `name` varchar(255) NOT NULL,
+ `secure` int(1) NOT NULL DEFAULT 0 COMMENT 'Is secure?',
+ `neighbor` int(1) NOT NULL DEFAULT 0 COMMENT 'Is neighbor cloud?',
+ `own_cloud` int(1) NOT NULL DEFAULT 0 COMMENT 'Is own cloud?',
+ `authentication_info` varchar(2047) DEFAULT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `cloud` (`operator`,`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `relay` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `address` varchar(255) NOT NULL,
+ `port` int(11) NOT NULL,
+ `secure` int(1) NOT NULL DEFAULT 0,
+ `exclusive` int(1) NOT NULL DEFAULT 0,
+ `type` varchar(255) NOT NULL DEFAULT 'GENERAL_RELAY',
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `pair` (`address`, `port`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `cloud_gatekeeper_relay` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `cloud_id` bigint(20) NOT NULL,
+ `relay_id` bigint(20) NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `pair` (`cloud_id`,`relay_id`),
+ CONSTRAINT `gk_cloud_constr` FOREIGN KEY (`cloud_id`) REFERENCES `cloud` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `gk_relay_constr` FOREIGN KEY (`relay_id`) REFERENCES `relay` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `cloud_gateway_relay` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `cloud_id` bigint(20) NOT NULL,
+ `relay_id` bigint(20) NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `pair` (`cloud_id`,`relay_id`),
+ CONSTRAINT `gw_cloud_constr` FOREIGN KEY (`cloud_id`) REFERENCES `cloud` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `gw_relay_constr` FOREIGN KEY (`relay_id`) REFERENCES `relay` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `system_` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `system_name` varchar(255) NOT NULL,
+ `address` varchar(255) NOT NULL,
+ `port` int(11) NOT NULL,
+ `authentication_info` varchar(2047) DEFAULT NULL,
+ `metadata` mediumtext NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `triple` (`system_name`,`address`,`port`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `device` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `device_name` varchar(255) NOT NULL,
+ `address` varchar(255) NOT NULL,
+ `mac_address` varchar(255) NOT NULL,
+ `authentication_info` varchar(2047) DEFAULT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `double` (`device_name`,`mac_address`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `service_definition` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `service_definition` varchar(255) NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `service_definition` (`service_definition`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `service_interface` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `interface_name` varchar(255) DEFAULT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `interface` (`interface_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+INSERT IGNORE INTO `service_interface` (interface_name) VALUES ('HTTP-SECURE-JSON');
+INSERT IGNORE INTO `service_interface` (interface_name) VALUES ('HTTP-INSECURE-JSON');
+
+-- Device Registry
+
+CREATE TABLE IF NOT EXISTS `device_registry` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `device_id` bigint(20) NOT NULL,
+ `end_of_validity` timestamp NULL DEFAULT NULL,
+ `metadata` text,
+ `version` int(11) DEFAULT 1,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `device_registry_device` (`device_id`),
+ CONSTRAINT `device_registry_device` FOREIGN KEY (`device_id`) REFERENCES `device` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- System Registry
+
+CREATE TABLE IF NOT EXISTS `system_registry` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `system_id` bigint(20) NOT NULL,
+ `device_id` bigint(20) NOT NULL,
+ `end_of_validity` timestamp NULL DEFAULT NULL,
+ `metadata` text,
+ `version` int(11) DEFAULT 1,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `system_registry_pair` (`system_id`,`device_id`),
+ KEY `system_registry_device` (`device_id`),
+ CONSTRAINT `system_registry_system` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `system_registry_device` FOREIGN KEY (`device_id`) REFERENCES `device` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Service Registry
+
+CREATE TABLE IF NOT EXISTS `service_registry` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `service_id` bigint(20) NOT NULL,
+ `system_id` bigint(20) NOT NULL,
+ `service_uri` varchar(255) NOT NULL DEFAULT '',
+ `end_of_validity` timestamp NULL DEFAULT NULL,
+ `secure` varchar(255) NOT NULL DEFAULT 'NOT_SECURE',
+ `metadata` mediumtext,
+ `version` int(11) DEFAULT 1,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `service_registry_triplet` (`service_id`,`system_id`, `service_uri`),
+ KEY `service_registry_system` (`system_id`),
+ CONSTRAINT `service_registry_service` FOREIGN KEY (`service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `service_registry_system` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `service_registry_interface_connection` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `service_registry_id` bigint(20) NOT NULL,
+ `interface_id` bigint(20) NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `pair` (`service_registry_id`,`interface_id`),
+ KEY `interface_sr` (`interface_id`),
+ CONSTRAINT `interface_sr` FOREIGN KEY (`interface_id`) REFERENCES `service_interface` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `service_registry` FOREIGN KEY (`service_registry_id`) REFERENCES `service_registry` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Authorization
+
+CREATE TABLE IF NOT EXISTS `authorization_intra_cloud` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `consumer_system_id` bigint(20) NOT NULL,
+ `provider_system_id` bigint(20) NOT NULL,
+ `service_id` bigint(20) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `rule` (`consumer_system_id`,`provider_system_id`,`service_id`),
+ KEY `provider` (`provider_system_id`),
+ KEY `service_intra_auth` (`service_id`),
+ CONSTRAINT `service_intra_auth` FOREIGN KEY (`service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `provider` FOREIGN KEY (`provider_system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `consumer` FOREIGN KEY (`consumer_system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `authorization_inter_cloud` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `consumer_cloud_id` bigint(20) NOT NULL,
+ `provider_system_id` bigint(20) NOT NULL,
+ `service_id` bigint(20) NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `rule` (`consumer_cloud_id`, `provider_system_id`, `service_id`),
+ KEY `service_inter_auth` (`service_id`),
+ CONSTRAINT `cloud` FOREIGN KEY (`consumer_cloud_id`) REFERENCES `cloud` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `service_inter_auth` FOREIGN KEY (`service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `provider_inter_auth` FOREIGN KEY (`provider_system_id`) REFERENCES `system_` (id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `authorization_inter_cloud_interface_connection` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `authorization_inter_cloud_id` bigint(20) NOT NULL,
+ `interface_id` bigint(20) NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `pair` (`authorization_inter_cloud_id`,`interface_id`),
+ KEY `interface_inter` (`interface_id`),
+ CONSTRAINT `auth_inter_interface` FOREIGN KEY (`interface_id`) REFERENCES `service_interface` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `auth_inter_cloud` FOREIGN KEY (`authorization_inter_cloud_id`) REFERENCES `authorization_inter_cloud` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `authorization_intra_cloud_interface_connection` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `authorization_intra_cloud_id` bigint(20) NOT NULL,
+ `interface_id` bigint(20) NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `pair` (`authorization_intra_cloud_id`,`interface_id`),
+ KEY `interface_intra` (`interface_id`),
+ CONSTRAINT `auth_intra_interface` FOREIGN KEY (`interface_id`) REFERENCES `service_interface` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `auth_intra_cloud` FOREIGN KEY (`authorization_intra_cloud_id`) REFERENCES `authorization_intra_cloud` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Orchestrator
+
+CREATE TABLE IF NOT EXISTS `orchestrator_store` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `consumer_system_id` bigint(20) NOT NULL,
+ `provider_system_id` bigint(20) NOT NULL,
+ `foreign_` int(1) NOT NULL DEFAULT 0,
+ `service_id` bigint(20) NOT NULL,
+ `service_interface_id` bigint(20) NOT NULL,
+ `priority` int(11) NOT NULL,
+ `attribute` text,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `priority_rule` (`service_id`, `service_interface_id`, `consumer_system_id`,`priority`),
+ UNIQUE KEY `duplication_rule` (`service_id`, `service_interface_id`, `consumer_system_id`,`provider_system_id`, `foreign_`),
+ CONSTRAINT `consumer_orch` FOREIGN KEY (`consumer_system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `service_orch` FOREIGN KEY (`service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `service_intf_orch` FOREIGN KEY (`service_interface_id`) REFERENCES `service_interface` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `foreign_system` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `provider_cloud_id` bigint(20) NOT NULL,
+ `system_name` varchar(255) NOT NULL,
+ `address` varchar(255) NOT NULL,
+ `port` int(11) NOT NULL,
+ `authentication_info` varchar(2047) DEFAULT NULL,
+ `metadata` mediumtext,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `triple` (`system_name`,`address`,`port`),
+ CONSTRAINT `foreign_cloud` FOREIGN KEY (`provider_cloud_id`) REFERENCES `cloud` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `orchestrator_store_flexible` (
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`consumer_system_name` varchar(255),
+`provider_system_name` varchar(255),
+`consumer_system_metadata` mediumtext,
+`provider_system_metadata` mediumtext,
+`service_metadata` mediumtext,
+`service_interface_name` varchar(255),
+`service_definition_name` varchar(255) NOT NULL,
+`priority` int(11) NOT NULL DEFAULT 2147483647,
+`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Logs
+
+CREATE TABLE IF NOT EXISTS `logs` (
+ `log_id` varchar(100) NOT NULL,
+ `entry_date` timestamp NULL DEFAULT NULL,
+ `logger` varchar(100) DEFAULT NULL,
+ `log_level` varchar(100) DEFAULT NULL,
+ `message` text,
+ `exception` text,
+ PRIMARY KEY (`log_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Event Handler
+
+CREATE TABLE IF NOT EXISTS `event_type` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `event_type_name` varchar(255) NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `eventtype` (`event_type_name`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `subscription` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `system_id` bigint(20) NOT NULL,
+ `event_type_id` bigint(20) NOT NULL,
+ `filter_meta_data` mediumtext,
+ `match_meta_data` int(1) NOT NULL DEFAULT 0,
+ `only_predefined_publishers` int(1) NOT NULL DEFAULT 0,
+ `notify_uri` text NOT NULL,
+ `start_date` timestamp NULL DEFAULT NULL,
+ `end_date` timestamp NULL DEFAULT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `pair` (`event_type_id`,`system_id`),
+ CONSTRAINT `subscriber_system` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `event_type` FOREIGN KEY (`event_type_id`) REFERENCES `event_type` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `subscription_publisher_connection` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `subscription_id` bigint(20) NOT NULL,
+ `system_id` bigint(20) NOT NULL,
+ `authorized` int(1) NOT NULL DEFAULT 0,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `pair` (`subscription_id`,`system_id`),
+ CONSTRAINT `subscription_constraint` FOREIGN KEY (`subscription_id`) REFERENCES `subscription` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `system_constraint` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- DataManager
+
+CREATE TABLE IF NOT EXISTS `dmhist_services` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `system_name` varchar(255) NOT NULL,
+ `service_name` varchar(255) NOT NULL,
+ `service_type` varchar(255),
+ last_update timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `dmhist_messages` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `sid` bigint(20) NOT NULL,
+ `bt` double NOT NULL,
+ `mint` double NOT NULL,
+ `maxt` double NOT NULL,
+ `msg` BLOB NOT NULL,
+ `datastored` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `service_id_constr` FOREIGN KEY (`sid`) REFERENCES `dmhist_services` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `dmhist_entries` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `sid` bigint(20) NOT NULL,
+ `mid` bigint(20) NOT NULL,
+ `n` varchar(128) NOT NULL,
+ `t` double NOT NULL,
+ `u` varchar(64),
+ `v` double,
+ `vs` BLOB,
+ `vb` BOOLEAN,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `service_id_fk` FOREIGN KEY(`sid`) REFERENCES `dmhist_services`(`id`) ON DELETE CASCADE,
+ CONSTRAINT `message_id_fk` FOREIGN KEY(`mid`) REFERENCES `dmhist_messages`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- TimeManager
+
+-- Choreographer
+
+CREATE TABLE IF NOT EXISTS `choreographer_plan` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `name` varchar(255) NOT NULL,
+ `first_action_id` bigint(20),
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `choreographer_action` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `name` varchar(255) NOT NULL,
+ `plan_id` bigint(20) NOT NULL,
+ `next_action_id` bigint(20) DEFAULT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name_plan_id_unique_key` (`name`,`plan_id`),
+ CONSTRAINT `next_action` FOREIGN KEY (`next_action_id`) REFERENCES `choreographer_action` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `plan` FOREIGN KEY (`plan_id`) REFERENCES `choreographer_plan` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
+
+ALTER TABLE `choreographer_plan` ADD FOREIGN KEY (`first_action_id`) references `choreographer_action`(`id`);
+
+CREATE TABLE IF NOT EXISTS `choreographer_step` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `name` varchar(255) NOT NULL,
+ `action_first_step_id` bigint(20),
+ `action_id` bigint(20) NOT NULL,
+ `service_name` varchar(255) NOT NULL,
+ `metadata` text,
+ `parameters` text,
+ `quantity` int(20) NOT NULL DEFAULT 1,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name_action_id_unique_key` (`name`, `action_id`),
+ CONSTRAINT `action_first_step` FOREIGN KEY (`action_first_step_id`) REFERENCES `choreographer_action` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `action` FOREIGN KEY (`action_id`) REFERENCES `choreographer_action` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `choreographer_step_next_step_connection` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `step_id` bigint(20) NOT NULL,
+ `next_step_id` bigint(20) NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `current_step` FOREIGN KEY (`step_id`) REFERENCES choreographer_step (`id`) ON DELETE CASCADE,
+ CONSTRAINT `next_step` FOREIGN KEY (`step_id`) REFERENCES choreographer_step (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `choreographer_session` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `plan_id` bigint(20) NOT NULL,
+ `started_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `status` varchar(255) NOT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `session_plan` FOREIGN KEY (`plan_id`) REFERENCES `choreographer_plan` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `choreographer_running_step` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `step_id` bigint(20) NOT NULL,
+ `session_id` bigint(20) NOT NULL,
+ `status` varchar(255) NOT NULL,
+ `message` text,
+ `started_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `running_step` FOREIGN KEY (`step_id`) REFERENCES `choreographer_step` (`id`),
+ CONSTRAINT `running_step_session` FOREIGN KEY (`session_id`) REFERENCES `choreographer_session`(`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `choreographer_worklog` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `entry_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `message` text,
+ `exception` text,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Configuration
+CREATE TABLE IF NOT EXISTS `configuration_data` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `systemName` varchar(255) NOT NULL UNIQUE,
+ `fileName` varchar(255) NOT NULL,
+ `contentType` varchar(255) NOT NULL,
+ `data` blob NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
+
+-- QoS Monitor
+-- Intra
+
+CREATE TABLE IF NOT EXISTS `qos_intra_measurement` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `system_id` bigint(20) NOT NULL,
+ `measurement_type` varchar(255) NOT NULL,
+ `last_measurement_at` timestamp NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT `fk_system` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `unique_system_id_measurement_type` (`system_id`, `measurement_type`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `qos_intra_ping_measurement` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `measurement_id` bigint(20) NOT NULL,
+ `available` int(1) NOT NULL DEFAULT 0,
+ `last_access_at` timestamp NULL DEFAULT NULL,
+ `min_response_time` int(11) DEFAULT NULL,
+ `max_response_time` int(11) DEFAULT NULL,
+ `mean_response_time_with_timeout` int(11) NULL DEFAULT NULL,
+ `mean_response_time_without_timeout` int(11) NULL DEFAULT NULL,
+ `jitter_with_timeout` int(11) NULL DEFAULT NULL,
+ `jitter_without_timeout` int(11) NULL DEFAULT NULL,
+ `lost_per_measurement_percent` int(3) NOT NULL DEFAULT 0,
+ `sent` bigint(20) NOT NULL DEFAULT 0,
+ `received` bigint(20) NOT NULL DEFAULT 0,
+ `count_started_at` timestamp NULL,
+ `sent_all` bigint(20) NOT NULL DEFAULT 0,
+ `received_all` bigint(20) NOT NULL DEFAULT 0,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT `fk_intra_measurement` FOREIGN KEY (`measurement_id`) REFERENCES `qos_intra_measurement` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `unique_intra_measurement` (`measurement_id`)
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `qos_intra_ping_measurement_log` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `measured_system_address` varchar(255) NOT NULL,
+ `available` int(1) NOT NULL DEFAULT 0,
+ `min_response_time` int(11) DEFAULT NULL,
+ `max_response_time` int(11) DEFAULT NULL,
+ `mean_response_time_with_timeout` int(11) NULL DEFAULT NULL,
+ `mean_response_time_without_timeout` int(11) NULL DEFAULT NULL,
+ `jitter_with_timeout` int(11) NULL DEFAULT NULL,
+ `jitter_without_timeout` int(11) NULL DEFAULT NULL,
+ `lost_per_measurement_percent` int(3) NOT NULL DEFAULT 0,
+ `sent` bigint(20) NOT NULL DEFAULT 0,
+ `received` bigint(20) NOT NULL DEFAULT 0,
+ `measured_at` timestamp NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `qos_intra_ping_measurement_log_details` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `measurement_log_id` bigint(20) NOT NULL,
+ `measurement_sequenece_number` int(3) NOT NULL,
+ `success_flag` int(1) NOT NULL DEFAULT 0,
+ `timeout_flag` int(1) NOT NULL DEFAULT 0,
+ `error_message` varchar(255) NULL DEFAULT NULL,
+ `throwable` varchar(255) NULL DEFAULT NULL,
+ `size_` int(11) NULL DEFAULT NULL,
+ `rtt` int(11) NULL DEFAULT NULL,
+ `ttl` int(3) NULL DEFAULT NULL,
+ `duration` int(5) NULL DEFAULT NULL,
+ `measured_at` timestamp NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT `fk_intra_measurement_log` FOREIGN KEY (`measurement_log_id`) REFERENCES `qos_intra_ping_measurement_log` (`id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- QoS Monitor
+-- Inter
+
+CREATE TABLE IF NOT EXISTS `qos_inter_direct_measurement` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `cloud_id` bigint(20) NOT NULL,
+ `address` varchar(255) NOT NULL,
+ `measurement_type` varchar(255) NOT NULL,
+ `last_measurement_at` timestamp NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT `fk_cloud_inter_direct` FOREIGN KEY (`cloud_id`) REFERENCES `cloud` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `unique_cloud_id_address_measurement_type` (`cloud_id`, `address`, `measurement_type`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `qos_inter_direct_ping_measurement` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `measurement_id` bigint(20) NOT NULL,
+ `available` int(1) NOT NULL DEFAULT 0,
+ `last_access_at` timestamp NULL DEFAULT NULL,
+ `min_response_time` int(11) DEFAULT NULL,
+ `max_response_time` int(11) DEFAULT NULL,
+ `mean_response_time_with_timeout` int(11) NULL DEFAULT NULL,
+ `mean_response_time_without_timeout` int(11) NULL DEFAULT NULL,
+ `jitter_with_timeout` int(11) NULL DEFAULT NULL,
+ `jitter_without_timeout` int(11) NULL DEFAULT NULL,
+ `lost_per_measurement_percent` int(3) NOT NULL DEFAULT 0,
+ `sent` bigint(20) NOT NULL DEFAULT 0,
+ `received` bigint(20) NOT NULL DEFAULT 0,
+ `count_started_at` timestamp NULL,
+ `sent_all` bigint(20) NOT NULL DEFAULT 0,
+ `received_all` bigint(20) NOT NULL DEFAULT 0,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT `fk_inter_direct_measurement` FOREIGN KEY (`measurement_id`) REFERENCES `qos_inter_direct_measurement` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `unique_measurement` (`measurement_id`)
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `qos_inter_direct_ping_measurement_log` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `measured_system_address` varchar(255) NOT NULL,
+ `available` int(1) NOT NULL DEFAULT 0,
+ `min_response_time` int(11) DEFAULT NULL,
+ `max_response_time` int(11) DEFAULT NULL,
+ `mean_response_time_with_timeout` int(11) NULL DEFAULT NULL,
+ `mean_response_time_without_timeout` int(11) NULL DEFAULT NULL,
+ `jitter_with_timeout` int(11) NULL DEFAULT NULL,
+ `jitter_without_timeout` int(11) NULL DEFAULT NULL,
+ `lost_per_measurement_percent` int(3) NOT NULL DEFAULT 0,
+ `sent` bigint(20) NOT NULL DEFAULT 0,
+ `received` bigint(20) NOT NULL DEFAULT 0,
+ `measured_at` timestamp NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `qos_inter_direct_ping_measurement_log_details` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `measurement_log_id` bigint(20) NOT NULL,
+ `measurement_sequenece_number` int(3) NOT NULL,
+ `success_flag` int(1) NOT NULL DEFAULT 0,
+ `timeout_flag` int(1) NOT NULL DEFAULT 0,
+ `error_message` varchar(255) NULL DEFAULT NULL,
+ `throwable` varchar(255) NULL DEFAULT NULL,
+ `size_` int(11) NULL DEFAULT NULL,
+ `rtt` int(11) NULL DEFAULT NULL,
+ `ttl` int(3) NULL DEFAULT NULL,
+ `duration` int(5) NULL DEFAULT NULL,
+ `measured_at` timestamp NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT `fk_inter_direct_ping_measurement_log` FOREIGN KEY (`measurement_log_id`) REFERENCES `qos_inter_direct_ping_measurement_log` (`id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `qos_inter_relay_measurement` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `cloud_id` bigint(20) NOT NULL,
+ `relay_id` bigint(20) NOT NULL,
+ `measurement_type` varchar(255) NOT NULL,
+ `status` varchar(255) NOT NULL,
+ `last_measurement_at` timestamp NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT `fk_cloud_inter_relay` FOREIGN KEY (`cloud_id`) REFERENCES `cloud` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `fk_relay_inter_relay` FOREIGN KEY (`relay_id`) REFERENCES `relay` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `unique_cloud_relay_measurement_type` (`cloud_id`, `relay_id`, `measurement_type`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `qos_inter_relay_echo_measurement` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `measurement_id` bigint(20) NOT NULL,
+ `last_access_at` timestamp NULL DEFAULT NULL,
+ `min_response_time` int(11) DEFAULT NULL,
+ `max_response_time` int(11) DEFAULT NULL,
+ `mean_response_time_with_timeout` int(11) NULL DEFAULT NULL,
+ `mean_response_time_without_timeout` int(11) NULL DEFAULT NULL,
+ `jitter_with_timeout` int(11) NULL DEFAULT NULL,
+ `jitter_without_timeout` int(11) NULL DEFAULT NULL,
+ `lost_per_measurement_percent` int(3) NOT NULL DEFAULT 0,
+ `sent` bigint(20) NOT NULL DEFAULT 0,
+ `received` bigint(20) NOT NULL DEFAULT 0,
+ `count_started_at` timestamp NULL,
+ `sent_all` bigint(20) NOT NULL DEFAULT 0,
+ `received_all` bigint(20) NOT NULL DEFAULT 0,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT `fk_inter_relay_measurement` FOREIGN KEY (`measurement_id`) REFERENCES `qos_inter_relay_measurement` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `unique_inter_relay_echo_measurement` (`measurement_id`)
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `qos_inter_relay_echo_measurement_log` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `measurement_id` bigint(20) NOT NULL,
+ `measurement_sequenece_number` int(3) NOT NULL,
+ `timeout_flag` int(1) NOT NULL DEFAULT 0,
+ `error_message` varchar(255) NULL DEFAULT NULL,
+ `throwable` varchar(255) NULL DEFAULT NULL,
+ `size_` int(11) NULL DEFAULT NULL,
+ `duration` int(5) NULL DEFAULT NULL,
+ `measured_at` timestamp NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT `fk_inter_relay_echo_measurement_log` FOREIGN KEY (`measurement_id`) REFERENCES `qos_inter_relay_measurement` (`id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- QoS Manager
+
+CREATE TABLE IF NOT EXISTS `qos_reservation` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `reserved_provider_id` bigint(20) NOT NULL,
+ `reserved_service_id` bigint(20) NOT NULL,
+ `consumer_system_name` varchar(255) NOT NULL,
+ `consumer_address` varchar(255) NOT NULL,
+ `consumer_port` int(11) NOT NULL,
+ `reserved_to` timestamp NOT NULL,
+ `temporary_lock` int(1) NOT NULL DEFAULT 0,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT `fk_reserved_provider` FOREIGN KEY (`reserved_provider_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `fk_reserved_service` FOREIGN KEY (`reserved_service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE,
+ UNIQUE KEY `unique_reserved_provider_and_service` (`reserved_provider_id`, `reserved_service_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Certificate Authority
+
+CREATE TABLE IF NOT EXISTS `ca_certificate` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `common_name` varchar(255) NOT NULL,
+ `serial` bigint(20) NOT NULL,
+ `created_by` varchar(255) NOT NULL,
+ `valid_after` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `valid_before` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `revoked_at` timestamp NULL,
+ UNIQUE KEY `unique_certificate_serial` (`serial`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8;
+
+CREATE TABLE IF NOT EXISTS `ca_trusted_key` (
+ `id` bigint(20) PRIMARY KEY AUTO_INCREMENT,
+ `public_key` text NOT NULL,
+ `hash` varchar(255) NOT NULL,
+ `description` varchar(255) NOT NULL,
+ `valid_after` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `valid_before` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ UNIQUE KEY `unique_hash` (`hash`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8;
+
+-- Plant Description Engine
+
+CREATE TABLE IF NOT EXISTS `pde_rule` (
+ `id` bigint(20) PRIMARY KEY,
+ `plant_description_id` bigint(20) NOT NULL
+) ENGINE = InnoDB DEFAULT CHARSET = utf8;
+
+CREATE TABLE IF NOT EXISTS `plant_description` (
+ `id` bigint(20) PRIMARY KEY,
+ `plant_description` mediumtext NOT NULL
+) ENGINE = InnoDB DEFAULT CHARSET = utf8;
diff --git a/kubernetes/arrowhead-helm/static/db-init/create_empty_arrowhead_db.sql b/kubernetes/arrowhead-helm/static/db-init/create_empty_arrowhead_db.sql
new file mode 100644
index 000000000..fae500eba
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/create_empty_arrowhead_db.sql
@@ -0,0 +1,93 @@
+DROP DATABASE IF EXISTS `arrowhead`;
+CREATE DATABASE `arrowhead`;
+USE `arrowhead`;
+
+-- create tables
+source docker-entrypoint-initdb.d/privileges/create_arrowhead_tables.sql
+
+-- Set up privileges
+
+-- Service Registry
+CREATE USER IF NOT EXISTS 'service_registry'@'localhost' IDENTIFIED BY 'ZzNNpxrbZGVvfJ8';
+CREATE USER IF NOT EXISTS 'service_registry'@'%' IDENTIFIED BY 'ZzNNpxrbZGVvfJ8';
+source docker-entrypoint-initdb.d/privileges/service_registry_privileges.sql
+
+-- System Registry
+CREATE USER IF NOT EXISTS 'system_registry'@'localhost' IDENTIFIED BY 'Kh12Hhgaxzo7haf';
+CREATE USER IF NOT EXISTS 'system_registry'@'%' IDENTIFIED BY 'Kh12Hhgaxzo7haf';
+source docker-entrypoint-initdb.d/privileges/system_registry_privileges.sql
+
+-- Device Registry
+CREATE USER IF NOT EXISTS 'device_registry'@'localhost' IDENTIFIED BY 'iooHU87hNGUalht';
+CREATE USER IF NOT EXISTS 'device_registry'@'%' IDENTIFIED BY 'iooHU87hNGUalht';
+source docker-entrypoint-initdb.d/privileges/device_registry_privileges.sql
+
+-- Onboarding controller
+CREATE USER IF NOT EXISTS 'onboarding_controller'@'localhost' IDENTIFIED BY 'JKgh1as5f6oi7aV';
+CREATE USER IF NOT EXISTS 'onboarding_controller'@'%' IDENTIFIED BY 'JKgh1as5f6oi7aV';
+source docker-entrypoint-initdb.d/privileges/onboarding_controller_privileges.sql
+
+-- Authorization
+CREATE USER IF NOT EXISTS 'authorization'@'localhost' IDENTIFIED BY 'hqZFUkuHxhekio3';
+CREATE USER IF NOT EXISTS 'authorization'@'%' IDENTIFIED BY 'hqZFUkuHxhekio3';
+source docker-entrypoint-initdb.d/privileges/authorization_privileges.sql
+
+-- Orchestrator
+CREATE USER IF NOT EXISTS 'orchestrator'@'localhost' IDENTIFIED BY 'KbgD2mTr8DQ4vtc';
+CREATE USER IF NOT EXISTS 'orchestrator'@'%' IDENTIFIED BY 'KbgD2mTr8DQ4vtc';
+source docker-entrypoint-initdb.d/privileges/orchestrator_privileges.sql
+
+-- Event Handler
+CREATE USER IF NOT EXISTS 'event_handler'@'localhost' IDENTIFIED BY 'gRLjXbqu9YwYhfK';
+CREATE USER IF NOT EXISTS 'event_handler'@'%' IDENTIFIED BY 'gRLjXbqu9YwYhfK';
+source docker-entrypoint-initdb.d/privileges/event_handler_privileges.sql
+
+-- DataManager
+CREATE USER IF NOT EXISTS 'datamanager'@'localhost' IDENTIFIED BY 'gRLjXbqu0YwYhfK';
+CREATE USER IF NOT EXISTS 'datamanager'@'%' IDENTIFIED BY 'gRLjXbqu0YwYhfK';
+source docker-entrypoint-initdb.d/privileges/datamanager_privileges.sql
+
+-- TimeManager
+CREATE USER IF NOT EXISTS 'timemanager'@'localhost' IDENTIFIED BY 'xyp2XEAu5Tbc41g';
+CREATE USER IF NOT EXISTS 'timemanager'@'%' IDENTIFIED BY 'xyp2XEAu5Tbc41g';
+source docker-entrypoint-initdb.d/privileges/timemanager_privileges.sql
+
+-- Choreographer
+CREATE USER IF NOT EXISTS 'choreographer'@'localhost' IDENTIFIED BY 'Qa5yx4oBp4Y9RLX';
+CREATE USER IF NOT EXISTS 'choreographer'@'%' IDENTIFIED BY 'Qa5yx4oBp4Y9RLX';
+source docker-entrypoint-initdb.d/privileges/choreographer_privileges.sql
+
+-- Configuration
+CREATE USER IF NOT EXISTS 'configuration'@'localhost' IDENTIFIED BY 'yRLjX2qA0YwYhzU';
+CREATE USER IF NOT EXISTS 'configuration'@'%' IDENTIFIED BY 'yRLjX2qA0YwYhzU';
+source docker-entrypoint-initdb.d/privileges/configuration_privileges.sql
+
+-- Gatekeeper
+CREATE USER IF NOT EXISTS 'gatekeeper'@'localhost' IDENTIFIED BY 'fbJKYzKhU5t8QtT';
+CREATE USER IF NOT EXISTS 'gatekeeper'@'%' IDENTIFIED BY 'fbJKYzKhU5t8QtT';
+source docker-entrypoint-initdb.d/privileges/gatekeeper_privileges.sql
+
+-- Gateway
+CREATE USER IF NOT EXISTS 'gateway'@'localhost' IDENTIFIED BY 'LfiSM9DpGfDEP5g';
+CREATE USER IF NOT EXISTS 'gateway'@'%' IDENTIFIED BY 'LfiSM9DpGfDEP5g';
+source docker-entrypoint-initdb.d/privileges/gateway_privileges.sql
+
+-- Certificate Authority
+CREATE USER IF NOT EXISTS 'certificate_authority'@'localhost' IDENTIFIED BY 'FsdG6Kgf9QpPfv2';
+CREATE USER IF NOT EXISTS 'certificate_authority'@'%' IDENTIFIED BY 'FsdG6Kgf9QpPfv2';
+source docker-entrypoint-initdb.d/privileges/certificate_authority_privileges.sql
+
+-- QoS Monitor
+CREATE USER IF NOT EXISTS 'qos_monitor'@'localhost' IDENTIFIED BY 'RLY3UEx6nx4kSXy';
+CREATE USER IF NOT EXISTS 'qos_monitor'@'%' IDENTIFIED BY 'RLY3UEx6nx4kSXy';
+source docker-entrypoint-initdb.d/privileges/qos_monitor_privileges.sql
+
+-- Translator
+CREATE USER IF NOT EXISTS 'translator'@'localhost' IDENTIFIED BY 'wozYpV58G0HUkbL';
+CREATE USER IF NOT EXISTS 'translator'@'%' IDENTIFIED BY 'wozYpV58G0HUkbL';
+source docker-entrypoint-initdb.d/privileges/translator_privileges.sql
+
+-- Plant Description Engine
+CREATE USER IF NOT EXISTS 'plant_description_engine'@'localhost' IDENTIFIED BY 'ivJ2y9qWCpTmzr0';
+CREATE USER IF NOT EXISTS 'plant_description_engine'@'%' IDENTIFIED BY 'ivJ2y9qWCpTmzr0';
+source docker-entrypoint-initdb.d/privileges/plant_description_engine_privileges.sql
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/datamanager_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/datamanager_privileges.sql
new file mode 100644
index 000000000..e35de51f8
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/datamanager_privileges.sql
@@ -0,0 +1,17 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'datamanager'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`dmhist_services` TO 'datamanager'@'localhost';
+#GRANT ALL PRIVILEGES ON `arrowhead`.`dmhist_files` TO 'datamanager'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`dmhist_messages` TO 'datamanager'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`dmhist_entries` TO 'datamanager'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'datamanager'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`dmhist_services` TO 'datamanager'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`dmhist_files` TO 'datamanager'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`dmhist_messages` TO 'datamanager'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`dmhist_entries` TO 'datamanager'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'datamanager'@'%';
+
+FLUSH PRIVILEGES;
diff --git a/kubernetes/arrowhead-helm/static/db-init/device_registry_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/device_registry_privileges.sql
new file mode 100644
index 000000000..eaa1e60ce
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/device_registry_privileges.sql
@@ -0,0 +1,33 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'device_registry'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`device` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`device_registry` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'device_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'device_registry'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'device_registry'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`device` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`device_registry` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'device_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'device_registry'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/event_handler_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/event_handler_privileges.sql
new file mode 100644
index 000000000..59183f487
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/event_handler_privileges.sql
@@ -0,0 +1,19 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'event_handler'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`event_type` TO 'event_handler'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`subscription` TO 'event_handler'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`subscription_publisher_connection` TO 'event_handler'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'event_handler'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'event_handler'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'event_handler'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`event_type` TO 'event_handler'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`subscription` TO 'event_handler'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`subscription_publisher_connection` TO 'event_handler'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'event_handler'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'event_handler'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/gatekeeper_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/gatekeeper_privileges.sql
new file mode 100644
index 000000000..944fe7cb1
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/gatekeeper_privileges.sql
@@ -0,0 +1,29 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'gatekeeper'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'gatekeeper'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'gatekeeper'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'gatekeeper'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'gatekeeper'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'gatekeeper'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'gatekeeper'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'gatekeeper'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'gatekeeper'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`foreign_system` TO 'gatekeeper'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'gatekeeper'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'gatekeeper'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'gatekeeper'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'gatekeeper'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'gatekeeper'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'gatekeeper'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'gatekeeper'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'gatekeeper'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'gatekeeper'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'gatekeeper'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`foreign_system` TO 'gatekeeper'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'gatekeeper'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/gateway_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/gateway_privileges.sql
new file mode 100644
index 000000000..0158ed405
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/gateway_privileges.sql
@@ -0,0 +1,9 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'gateway'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'gateway'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'gateway'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'gateway'@'%';
+
+FLUSH PRIVILEGES;
diff --git a/kubernetes/arrowhead-helm/static/db-init/onboarding_controller_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/onboarding_controller_privileges.sql
new file mode 100644
index 000000000..b619e2097
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/onboarding_controller_privileges.sql
@@ -0,0 +1,11 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'onboarding_controller'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'onboarding_controller'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'onboarding_controller'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'onboarding_controller'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/orchestrator_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/orchestrator_privileges.sql
new file mode 100644
index 000000000..6f8563117
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/orchestrator_privileges.sql
@@ -0,0 +1,33 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'orchestrator'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`orchestrator_store` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`foreign_system` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`orchestrator_store_flexible` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_reservation` TO 'orchestrator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'orchestrator'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'orchestrator'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`orchestrator_store` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`foreign_system` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`orchestrator_store_flexible` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_reservation` TO 'orchestrator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'orchestrator'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/plant_description_engine_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/plant_description_engine_privileges.sql
new file mode 100644
index 000000000..bbf87d38c
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/plant_description_engine_privileges.sql
@@ -0,0 +1,15 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'plant_description_engine'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`pde_rule` TO 'plant_description_engine'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`plant_description` TO 'plant_description_engine'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'plant_description_engine'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'plant_description_engine'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`pde_rule` TO 'plant_description_engine'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`plant_description` TO 'plant_description_engine'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'plant_description_engine'@'%';
+
+FLUSH PRIVILEGES;
diff --git a/kubernetes/arrowhead-helm/static/db-init/qos_monitor_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/qos_monitor_privileges.sql
new file mode 100644
index 000000000..c8a9d1d5f
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/qos_monitor_privileges.sql
@@ -0,0 +1,47 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'qos_monitor'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_measurement` TO 'qos_monitor'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement` TO 'qos_monitor'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement_log` TO 'qos_monitor'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement_log_details` TO 'qos_monitor'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_direct_measurement` TO 'qos_monitor'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_direct_ping_measurement` TO 'qos_monitor'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_direct_ping_measurement_log` TO 'qos_monitor'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_direct_ping_measurement_log_details` TO 'qos_monitor'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_relay_measurement` TO 'qos_monitor'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_relay_echo_measurement` TO 'qos_monitor'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_relay_echo_measurement_log` TO 'qos_monitor'@'localhost';
+
+GRANT SELECT ON `arrowhead`.`system_` TO 'qos_monitor'@'localhost';
+GRANT SELECT ON `arrowhead`.`cloud` TO 'qos_monitor'@'localhost';
+GRANT SELECT ON `arrowhead`.`relay` TO 'qos_monitor'@'localhost';
+GRANT SELECT ON `arrowhead`.`cloud_gatekeeper_relay` TO 'qos_monitor'@'localhost';
+GRANT SELECT ON `arrowhead`.`cloud_gateway_relay` TO 'qos_monitor'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'qos_monitor'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'qos_monitor'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_measurement` TO 'qos_monitor'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement` TO 'qos_monitor'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement_log` TO 'qos_monitor'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement_log_details` TO 'qos_monitor'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_direct_measurement` TO 'qos_monitor'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_direct_ping_measurement` TO 'qos_monitor'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_direct_ping_measurement_log` TO 'qos_monitor'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_direct_ping_measurement_log_details` TO 'qos_monitor'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_relay_measurement` TO 'qos_monitor'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_relay_echo_measurement` TO 'qos_monitor'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`qos_inter_relay_echo_measurement_log` TO 'qos_monitor'@'%';
+
+GRANT SELECT ON `arrowhead`.`system_` TO 'qos_monitor'@'%';
+GRANT SELECT ON `arrowhead`.`cloud` TO 'qos_monitor'@'%';
+GRANT SELECT ON `arrowhead`.`relay` TO 'qos_monitor'@'%';
+GRANT SELECT ON `arrowhead`.`cloud_gatekeeper_relay` TO 'qos_monitor'@'%';
+GRANT SELECT ON `arrowhead`.`cloud_gateway_relay` TO 'qos_monitor'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'qos_monitor'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/service_registry_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/service_registry_privileges.sql
new file mode 100644
index 000000000..072ae3572
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/service_registry_privileges.sql
@@ -0,0 +1,57 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'service_registry'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`orchestrator_store` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`subscription` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`subscription_publisher_connection` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_plan` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_step` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_plan_action_connection` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_action_step_connection` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_step_service_definition_connection` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_next_action_step` TO 'service_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'service_registry'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'service_registry'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`orchestrator_store` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`subscription` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`subscription_publisher_connection` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_plan` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_step` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_plan_action_connection` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_action_step_connection` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_step_service_definition_connection` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_next_action_step` TO 'service_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'service_registry'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/system_registry_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/system_registry_privileges.sql
new file mode 100644
index 000000000..37ea8a6e0
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/system_registry_privileges.sql
@@ -0,0 +1,33 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'system_registry'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`device` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_registry` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'system_registry'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'system_registry'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'system_registry'@'%';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`device` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`system_registry` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'system_registry'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'system_registry'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/static/db-init/timemanager_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/timemanager_privileges.sql
new file mode 100644
index 000000000..aadf90563
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/timemanager_privileges.sql
@@ -0,0 +1,9 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'timemanager'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'timemanager'@'localhost';
+
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'timemanager'@'%';
+
+FLUSH PRIVILEGES;
diff --git a/kubernetes/arrowhead-helm/static/db-init/translator_privileges.sql b/kubernetes/arrowhead-helm/static/db-init/translator_privileges.sql
new file mode 100644
index 000000000..1245851d1
--- /dev/null
+++ b/kubernetes/arrowhead-helm/static/db-init/translator_privileges.sql
@@ -0,0 +1,9 @@
+USE `arrowhead`;
+
+REVOKE ALL, GRANT OPTION FROM 'translator'@'localhost';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'translator'@'localhost';
+
+REVOKE ALL, GRANT OPTION FROM 'translator'@'%';
+GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'translator'@'%';
+
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/_helpers.tpl b/kubernetes/arrowhead-helm/templates/_helpers.tpl
new file mode 100644
index 000000000..dfd8f5c6a
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/_helpers.tpl
@@ -0,0 +1,47 @@
+{{- define "loadDBConnectionDetails" -}}
+spring:
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ password: {{ .component.datasourcePassword }}
+ username: {{ .component.datasourceUsername }}
+ url: {{ printf "jdbc:mysql://%s:%v/arrowhead?serverTimezone=Europe/Budapest" .dot.Values.mysql.address .dot.Values.mysql.port | indent 2 }}
+{{- end -}}
+
+{{- define "loadCertificateDetails" -}}
+server:
+ ssl:
+ key-store-password: {{ .component.keystorePassword }}
+ trust-store-type: {{ .component.truststoreType }}
+ key-store: {{ printf "file:%s/keystore/keystore.p12" .mountpath }}
+ key-password: {{ .component.keyPassword }}
+ trust-store: {{ printf "file:%s/truststore/truststore.p12" .mountpath }}
+ key-store-type: {{ .component.keystoreType }}
+ key-alias: {{ .component.keyAlias }}
+ client-auth: need
+ enabled: {{ .component.sslEnabled }}
+ trust-store-password: {{ .component.truststorePassword }}
+{{- end -}}
+
+{{- define "loadSRDetails" -}}
+sr_address: {{ .Values.serviceRegistry.address }}
+sr_port: {{ .Values.serviceRegistry.port }}
+{{- end -}}
+
+{{- define "flattenYaml" -}}
+{{- $map := first . -}}
+{{- $concatenatedKeys := last . -}}
+{{- range $key, $value := $map -}}
+ {{ $addKey := "" }}
+ {{- if not (eq $concatenatedKeys "") -}}
+ {{ $addKey = printf "%s.%s" $concatenatedKeys $key}}
+ {{- else -}}
+ {{- $addKey = $key -}}
+ {{- end -}}
+ {{- if kindOf $value | eq "map" -}}
+ {{- include "flattenYaml" (list $value $addKey) -}}
+ {{- else -}}
+{{ printf "%s=%v" $addKey $value }}
+{{ printf ""}}
+ {{- end -}}
+{{- end -}}
+{{- end -}}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/ambassador/authorization-mapping.yaml b/kubernetes/arrowhead-helm/templates/ambassador/authorization-mapping.yaml
new file mode 100644
index 000000000..0a0967f36
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/ambassador/authorization-mapping.yaml
@@ -0,0 +1,7 @@
+apiVersion: getambassador.io/v3alpha1
+kind: TCPMapping
+metadata:
+ name: authorization-mapping
+spec:
+ port: 3001
+ service: {{ printf "%s:%v" .Values.authorization.address .Values.authorization.port }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/ambassador/orchestrator-mapping.yaml b/kubernetes/arrowhead-helm/templates/ambassador/orchestrator-mapping.yaml
new file mode 100644
index 000000000..aa39a19f2
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/ambassador/orchestrator-mapping.yaml
@@ -0,0 +1,7 @@
+apiVersion: getambassador.io/v3alpha1
+kind: TCPMapping
+metadata:
+ name: orchestrator-mapping
+spec:
+ port: 3002
+ service: {{ printf "%s:%v" .Values.orchestrator.address .Values.orchestrator.port }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/ambassador/service-registry-mapping.yaml b/kubernetes/arrowhead-helm/templates/ambassador/service-registry-mapping.yaml
new file mode 100644
index 000000000..30fcce6b1
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/ambassador/service-registry-mapping.yaml
@@ -0,0 +1,7 @@
+apiVersion: getambassador.io/v3alpha1
+kind: TCPMapping
+metadata:
+ name: service-registry-mapping
+spec:
+ port: 3000
+ service: {{ printf "%s:%v" .Values.serviceRegistry.address .Values.serviceRegistry.port }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/authorization/authorization-deployment.yaml b/kubernetes/arrowhead-helm/templates/authorization/authorization-deployment.yaml
new file mode 100644
index 000000000..553a5da6a
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/authorization/authorization-deployment.yaml
@@ -0,0 +1,55 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: authorization
+ name: {{ .Release.Name }}-authorization-deployment
+spec:
+ replicas: {{ .Values.replicaCount }}
+ selector:
+ matchLabels:
+ app: authorization
+ strategy:
+ type: Recreate
+ template:
+ metadata:
+ labels:
+ app: authorization
+ spec:
+ containers:
+ - image: {{ .Values.authorization.image }}
+ name: authorization
+ ports:
+ - containerPort: {{ .Values.authorization.port }}
+ resources: {}
+ volumeMounts:
+ - name: {{ .Values.authorization.address }}-properties-volume
+ mountPath: /authorization/application.properties
+ subPath: application.properties
+ - name: {{ .Values.authorization.address }}-keystore-volume
+ mountPath: /authorization/keystore
+ - name: {{ .Values.authorization.address }}-truststore-volume
+ mountPath: /authorization/truststore
+ initContainers:
+ - image: busybox:1.28
+ name: wait-for-db
+ volumeMounts:
+ - name: wait-for-db
+ mountPath: /init
+ command:
+ - /bin/sh
+ - /init/wait-for-db.sh
+ volumes:
+ - name: {{ .Values.authorization.address }}-properties-volume
+ secret:
+ secretName: {{ .Release.Name }}-authorization-properties
+ - name: wait-for-db
+ configMap:
+ name: {{ .Release.Name }}-wait-for-db
+ - name: {{ .Values.authorization.address }}-keystore-volume
+ configMap:
+ name: {{ .Release.Name }}-authorization-keystore
+ - name: {{ .Values.authorization.address }}-truststore-volume
+ configMap:
+ name: {{ .Release.Name }}-authorization-truststore
+ restartPolicy: Always
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/authorization/authorization-keystore.yaml b/kubernetes/arrowhead-helm/templates/authorization/authorization-keystore.yaml
new file mode 100644
index 000000000..3f15fd391
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/authorization/authorization-keystore.yaml
@@ -0,0 +1,6 @@
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: {{ .Release.Name }}-authorization-keystore
+binaryData:
+ keystore.p12: {{ printf "static/certificates/%s" .Values.authorization.keystore | .Files.Get | b64enc }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/authorization/authorization-properties.yaml b/kubernetes/arrowhead-helm/templates/authorization/authorization-properties.yaml
new file mode 100644
index 000000000..8effddd78
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/authorization/authorization-properties.yaml
@@ -0,0 +1,7 @@
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ .Release.Name }}-authorization-properties
+stringData:
+ application.properties: |-
+{{ list (merge .Values.authorization.properties (fromYaml (include "loadDBConnectionDetails" (dict "dot" . "component" .Values.serviceRegistry))) (fromYaml (include "loadCertificateDetails" (dict "component" .Values.authorization "mountpath" "/authorization"))) (fromYaml (include "loadSRDetails" .))) "" | include "flattenYaml" | indent 4 }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/authorization/authorization-service.yaml b/kubernetes/arrowhead-helm/templates/authorization/authorization-service.yaml
new file mode 100644
index 000000000..fdb45a890
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/authorization/authorization-service.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Values.authorization.address }}
+spec:
+ selector:
+ app: authorization
+ ports:
+ - port: {{ .Values.authorization.port }}
+ targetPort: {{ .Values.authorization.port }}
+ type: ClusterIP
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/authorization/authorization-truststore.yaml b/kubernetes/arrowhead-helm/templates/authorization/authorization-truststore.yaml
new file mode 100644
index 000000000..34e25d86f
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/authorization/authorization-truststore.yaml
@@ -0,0 +1,6 @@
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: {{ .Release.Name }}-authorization-truststore
+binaryData:
+ truststore.p12: {{ printf "static/certificates/%s" .Values.authorization.truststore | .Files.Get | b64enc }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/mysql/mysql-conf.yaml b/kubernetes/arrowhead-helm/templates/mysql/mysql-conf.yaml
new file mode 100644
index 000000000..60110b257
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/mysql/mysql-conf.yaml
@@ -0,0 +1,22 @@
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: mysql-conf
+data:
+{{- range $path, $bytes := .Files.Glob "static/db-init/*" }}
+ {{ base $path }}: |-
+{{ $.Files.Get $path | indent 4 }}
+{{- end }}
+ updateUsers.sql: |-
+{{ printf "RENAME USER 'service_registry'@'localhost' TO '%s'@'localhost';" .Values.serviceRegistry.datasourceUsername | indent 4 }}
+{{ printf "RENAME USER 'service_registry'@'%%' TO '%s'@'%%';" .Values.serviceRegistry.datasourceUsername | indent 4 }}
+{{ printf "ALTER USER '%s'@'localhost' IDENTIFIED BY '%s';" .Values.serviceRegistry.datasourceUsername .Values.serviceRegistry.datasourcePassword | indent 4 }}
+{{ printf "ALTER USER '%s'@'%%' IDENTIFIED BY '%s';" .Values.serviceRegistry.datasourceUsername .Values.serviceRegistry.datasourcePassword | indent 4 }}
+{{ printf "RENAME USER 'authorization'@'localhost' TO '%s'@'localhost';" .Values.authorization.datasourceUsername | indent 4 }}
+{{ printf "RENAME USER 'authorization'@'%%' TO '%s'@'%%';" .Values.authorization.datasourceUsername | indent 4 }}
+{{ printf "ALTER USER '%s'@'localhost' IDENTIFIED BY '%s';" .Values.authorization.datasourceUsername .Values.authorization.datasourcePassword | indent 4 }}
+{{ printf "ALTER USER '%s'@'%%' IDENTIFIED BY '%s';" .Values.authorization.datasourceUsername .Values.authorization.datasourcePassword | indent 4 }}
+{{ printf "RENAME USER 'orchestrator'@'localhost' TO '%s'@'localhost';" .Values.orchestrator.datasourceUsername | indent 4 }}
+{{ printf "RENAME USER 'orchestrator'@'%%' TO '%s'@'%%';" .Values.orchestrator.datasourceUsername | indent 4 }}
+{{ printf "ALTER USER '%s'@'localhost' IDENTIFIED BY '%s';" .Values.orchestrator.datasourceUsername .Values.orchestrator.datasourcePassword | indent 4 }}
+{{ printf "ALTER USER '%s'@'%%' IDENTIFIED BY '%s';" .Values.orchestrator.datasourceUsername .Values.orchestrator.datasourcePassword | indent 4 }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/mysql/mysql-deployment.yaml b/kubernetes/arrowhead-helm/templates/mysql/mysql-deployment.yaml
new file mode 100644
index 000000000..6839ee2f7
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/mysql/mysql-deployment.yaml
@@ -0,0 +1,43 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: mysql
+spec:
+ selector:
+ matchLabels:
+ app: mysql
+ strategy:
+ type: Recreate
+ template:
+ metadata:
+ labels:
+ app: mysql
+ spec:
+ containers:
+ - image: {{ .Values.mysql.image }}
+ name: mysql
+ env:
+ - name: MYSQL_ROOT_PASSWORD
+ value: {{ .Values.mysql.rootPassword }}
+ ports:
+ - containerPort: 3306
+ name: mysql
+ volumeMounts:
+ - name: mysql-persistent-storage
+ mountPath: /var/lib/mysql/
+ subPath: data
+ - name: mysql-conf
+ mountPath: /docker-entrypoint-initdb.d/privileges
+ - name: mysql-conf
+ mountPath: /docker-entrypoint-initdb.d/updateUsers.sql
+ subPath: updateUsers.sql
+ - name: mysql-conf
+ mountPath: /docker-entrypoint-initdb.d/create_empty_arrowhead_db.sql
+ subPath: create_empty_arrowhead_db.sql
+ volumes:
+ - name: mysql-persistent-storage
+ persistentVolumeClaim:
+ claimName: mysql-pv-claim
+ - name: mysql-conf
+ configMap:
+ name: mysql-conf
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/mysql/mysql-service.yaml b/kubernetes/arrowhead-helm/templates/mysql/mysql-service.yaml
new file mode 100644
index 000000000..c355e3649
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/mysql/mysql-service.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Values.mysql.address }}
+spec:
+ ports:
+ - port: 3306
+ selector:
+ app: mysql
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/mysql/mysql-volume-claim.yaml b/kubernetes/arrowhead-helm/templates/mysql/mysql-volume-claim.yaml
new file mode 100644
index 000000000..8d3627463
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/mysql/mysql-volume-claim.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: mysql-pv-claim
+spec:
+ storageClassName: managed-premium
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-deployment.yaml b/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-deployment.yaml
new file mode 100644
index 000000000..196e56410
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-deployment.yaml
@@ -0,0 +1,55 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: orchestrator
+ name: {{ .Release.Name }}-orchestrator-deployment
+spec:
+ replicas: {{ .Values.replicaCount }}
+ selector:
+ matchLabels:
+ app: orchestrator
+ strategy:
+ type: Recreate
+ template:
+ metadata:
+ labels:
+ app: orchestrator
+ spec:
+ containers:
+ - image: {{ .Values.orchestrator.image }}
+ name: orchestrator
+ ports:
+ - containerPort: {{ .Values.orchestrator.port }}
+ resources: {}
+ volumeMounts:
+ - name: {{ .Values.orchestrator.address }}-properties-volume
+ mountPath: /orchestrator/application.properties
+ subPath: application.properties
+ - name: {{ .Values.orchestrator.address }}-keystore-volume
+ mountPath: /orchestrator/keystore
+ - name: {{ .Values.orchestrator.address }}-truststore-volume
+ mountPath: /orchestrator/truststore
+ initContainers:
+ - image: busybox:1.28
+ name: wait-for-db
+ volumeMounts:
+ - name: wait-for-db
+ mountPath: /init
+ command:
+ - /bin/sh
+ - /init/wait-for-db.sh
+ volumes:
+ - name: {{ .Values.orchestrator.address }}-properties-volume
+ secret:
+ secretName: {{ .Release.Name }}-orchestrator-properties
+ - name: wait-for-db
+ configMap:
+ name: {{ .Release.Name }}-wait-for-db
+ - name: {{ .Values.orchestrator.address }}-keystore-volume
+ configMap:
+ name: {{ .Release.Name }}-orchestrator-keystore
+ - name: {{ .Values.orchestrator.address }}-truststore-volume
+ configMap:
+ name: {{ .Release.Name }}-orchestrator-truststore
+ restartPolicy: Always
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-keystore.yaml b/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-keystore.yaml
new file mode 100644
index 000000000..a0ff4a26d
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-keystore.yaml
@@ -0,0 +1,6 @@
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: {{ .Release.Name }}-orchestrator-keystore
+binaryData:
+ keystore.p12: {{ printf "static/certificates/%s" .Values.orchestrator.keystore | .Files.Get | b64enc }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-properties.yaml b/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-properties.yaml
new file mode 100644
index 000000000..ef89152b6
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-properties.yaml
@@ -0,0 +1,7 @@
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ .Release.Name }}-orchestrator-properties
+stringData:
+ application.properties: |-
+{{ list (merge .Values.orchestrator.properties (fromYaml (include "loadDBConnectionDetails" (dict "dot" . "component" .Values.serviceRegistry))) (fromYaml (include "loadCertificateDetails" (dict "component" .Values.orchestrator "mountpath" "/orchestrator"))) (fromYaml (include "loadSRDetails" .))) "" | include "flattenYaml" | indent 4 }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-service.yaml b/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-service.yaml
new file mode 100644
index 000000000..172c83e03
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-service.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Values.orchestrator.address }}
+spec:
+ selector:
+ app: orchestrator
+ ports:
+ - port: {{ .Values.orchestrator.port }}
+ targetPort: {{ .Values.orchestrator.port }}
+ type: ClusterIP
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-truststore.yaml b/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-truststore.yaml
new file mode 100644
index 000000000..39d3fc804
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/orchestrator/orchestrator-truststore.yaml
@@ -0,0 +1,6 @@
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: {{ .Release.Name }}-orchestrator-truststore
+binaryData:
+ truststore.p12: {{ printf "static/certificates/%s" .Values.orchestrator.truststore | .Files.Get | b64enc }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/service-registry/service-registry-deployment.yaml b/kubernetes/arrowhead-helm/templates/service-registry/service-registry-deployment.yaml
new file mode 100644
index 000000000..8d8c6e51f
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/service-registry/service-registry-deployment.yaml
@@ -0,0 +1,55 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: service-registry
+ name: {{ .Release.Name }}-service-registry-deployment
+spec:
+ replicas: {{ .Values.replicaCount }}
+ selector:
+ matchLabels:
+ app: service-registry
+ strategy:
+ type: Recreate
+ template:
+ metadata:
+ labels:
+ app: service-registry
+ spec:
+ containers:
+ - image: {{ .Values.serviceRegistry.image }}
+ name: serviceregistry
+ ports:
+ - containerPort: {{ .Values.serviceRegistry.port }}
+ resources: {}
+ volumeMounts:
+ - name: {{ .Values.serviceRegistry.address }}-properties-volume
+ mountPath: /serviceregistry/application.properties
+ subPath: application.properties
+ - name: {{ .Values.serviceRegistry.address }}-keystore-volume
+ mountPath: /serviceregistry/keystore
+ - name: {{ .Values.serviceRegistry.address }}-truststore-volume
+ mountPath: /serviceregistry/truststore
+ initContainers:
+ - image: busybox:1.28
+ name: wait-for-db
+ volumeMounts:
+ - name: wait-for-db
+ mountPath: /init
+ command:
+ - /bin/sh
+ - /init/wait-for-db.sh
+ volumes:
+ - name: {{ .Values.serviceRegistry.address }}-properties-volume
+ secret:
+ secretName: {{ .Release.Name }}-service-registry-properties
+ - name: wait-for-db
+ configMap:
+ name: {{ .Release.Name }}-wait-for-db
+ - name: {{ .Values.serviceRegistry.address }}-keystore-volume
+ configMap:
+ name: {{ .Release.Name }}-service-registry-keystore
+ - name: {{ .Values.serviceRegistry.address }}-truststore-volume
+ configMap:
+ name: {{ .Release.Name }}-service-registry-truststore
+ restartPolicy: Always
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/service-registry/service-registry-keystore.yaml b/kubernetes/arrowhead-helm/templates/service-registry/service-registry-keystore.yaml
new file mode 100644
index 000000000..08b72ca1b
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/service-registry/service-registry-keystore.yaml
@@ -0,0 +1,6 @@
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: {{ .Release.Name }}-service-registry-keystore
+binaryData:
+ keystore.p12: {{ printf "static/certificates/%s" .Values.serviceRegistry.keystore | .Files.Get | b64enc }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/service-registry/service-registry-properties.yaml b/kubernetes/arrowhead-helm/templates/service-registry/service-registry-properties.yaml
new file mode 100644
index 000000000..96ed4c2fb
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/service-registry/service-registry-properties.yaml
@@ -0,0 +1,7 @@
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ .Release.Name }}-service-registry-properties
+stringData:
+ application.properties: |-
+{{ list (merge .Values.serviceRegistry.properties (fromYaml (include "loadDBConnectionDetails" (dict "dot" . "component" .Values.serviceRegistry))) (fromYaml (include "loadCertificateDetails" (dict "component" .Values.serviceRegistry "mountpath" "/serviceregistry")))) "" | include "flattenYaml" | indent 4 }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/service-registry/service-registry-service.yaml b/kubernetes/arrowhead-helm/templates/service-registry/service-registry-service.yaml
new file mode 100644
index 000000000..95ccd5273
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/service-registry/service-registry-service.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Values.serviceRegistry.address }}
+spec:
+ selector:
+ app: service-registry
+ ports:
+ - port: {{ .Values.serviceRegistry.port }}
+ targetPort: {{ .Values.serviceRegistry.port }}
+ type: ClusterIP
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/service-registry/service-registry-truststore.yaml b/kubernetes/arrowhead-helm/templates/service-registry/service-registry-truststore.yaml
new file mode 100644
index 000000000..543ad60b3
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/service-registry/service-registry-truststore.yaml
@@ -0,0 +1,6 @@
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: {{ .Release.Name }}-service-registry-truststore
+binaryData:
+ truststore.p12: {{ printf "static/certificates/%s" .Values.serviceRegistry.truststore | .Files.Get | b64enc }}
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/templates/wait-for-db-configmap.yaml b/kubernetes/arrowhead-helm/templates/wait-for-db-configmap.yaml
new file mode 100644
index 000000000..b12d85938
--- /dev/null
+++ b/kubernetes/arrowhead-helm/templates/wait-for-db-configmap.yaml
@@ -0,0 +1,12 @@
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: {{ .Release.Name }}-wait-for-db
+data:
+ wait-for-db.sh: |
+ #!/bin/sh
+ {{ printf "until nc -z -v -w30 %s %v" .Values.mysql.address .Values.mysql.port }}
+ do
+ echo "Waiting for database connection..."
+ sleep 5
+ done
\ No newline at end of file
diff --git a/kubernetes/arrowhead-helm/values.yaml b/kubernetes/arrowhead-helm/values.yaml
new file mode 100644
index 000000000..0e356b3dc
--- /dev/null
+++ b/kubernetes/arrowhead-helm/values.yaml
@@ -0,0 +1,153 @@
+replicaCount: 1
+
+namespace: arrowhead
+
+restartPolicy: Always
+
+emissary-ingress:
+ replicaCount: 1
+ service:
+ ports:
+ - name: sreg
+ port: 3000
+ targetPort: 3000
+ - name: auth
+ port: 3001
+ targetPort: 3001
+ - name: orch
+ port: 3002
+ targetPort: 3002
+ loadBalancerIP:
+
+mysql:
+ image: mysql:8.0
+ port: 3306
+ address: mysql
+ rootPassword: tvYiBMhznmcVOeng
+
+serviceRegistry:
+ image: arrowheadcr.azurecr.io/serviceregistry:4.4.0
+ port: 80
+ address: arrowhead-serviceregistry
+ sslEnabled: true
+ datasourceUsername: s_reg
+ datasourcePassword: 3RgoBkD5mqER68js
+ keystore: test-sreg.p12
+ keystorePassword: SgK0QHHX7ge1vtGs
+ keystoreType: PKCS12
+ keyAlias: service_registry.testcloud2.aitia.arrowhead.eu
+ keyPassword: SgK0QHHX7ge1vtGs
+ truststore: test-cloud.truststore.p12
+ truststorePassword: "123456"
+ truststoreType: PKCS12
+ properties:
+ log_all_request_and_response: false
+ server:
+ address: 0.0.0.0
+ port: 80
+ use_strict_service_definition_verifier: true
+ disable:
+ hostname:
+ verifier: false
+ ping_timeout: 5000
+ spring:
+ jpa:
+ hibernate:
+ ddl-auto: none
+ database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
+ properties:
+ hibernate:
+ format_sql: true
+ show-sql: false
+ ping_interval: 60
+ use_network_address_detector: false
+ ttl_scheduled: false
+ allow_non_routable_addressing: true
+ use_strict_service_intf_name_verifier: false
+ domain:
+ port: 3000
+ name:
+ allow_self_addressing: true
+ ping_scheduled: false
+ ttl_interval: 10
+
+authorization:
+ image: arrowheadcr.azurecr.io/authorization:4.4.0
+ port: 80
+ address: arrowhead-authorization
+ sslEnabled: true
+ datasourceUsername: auth
+ datasourcePassword: CDif68aDUWTvHWaN
+ keystore: test-auth-system.p12
+ keystorePassword: 3Irx3m9D8RfkEoyP
+ keystoreType: PKCS12
+ keyAlias: authorization.testcloud2.aitia.arrowhead.eu
+ keyPassword: 3Irx3m9D8RfkEoyP
+ truststore: test-cloud.truststore.p12
+ truststorePassword: "123456"
+ truststoreType: PKCS12
+ properties:
+ log_all_request_and_response: false
+ server:
+ address: 0.0.0.0
+ port: 80
+ use_strict_service_definition_verifier: true
+ disable:
+ hostname:
+ verifier: false
+ ping_timeout: 5000
+ spring:
+ jpa:
+ hibernate:
+ ddl-auto: none
+ database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
+ properties:
+ hibernate:
+ format_sql: true
+ show-sql: false
+ use_strict_service_intf_name_verifier: false
+ domain:
+ port: 3001
+ name:
+
+orchestrator:
+ image: arrowheadcr.azurecr.io/orchestrator:4.4.0
+ port: 80
+ address: arrowhead-orchestration
+ sslEnabled: true
+ datasourceUsername: orch
+ datasourcePassword: 6zXzDAQ8vkgyJipI
+ keystore: test-orch.p12
+ keystorePassword: C40HciVwR6V6Adbf
+ keystoreType: PKCS12
+ keyAlias: orchestrator.testcloud2.aitia.arrowhead.eu
+ keyPassword: C40HciVwR6V6Adbf
+ truststore: test-cloud.truststore.p12
+ truststorePassword: "123456"
+ truststoreType: PKCS12
+ logging: false
+ domain:
+ exposedPort: 3002
+ properties:
+ log_all_request_and_response: false
+ server:
+ address: 0.0.0.0
+ port: 80
+ use_strict_service_definition_verifier: true
+ disable:
+ hostname:
+ verifier: false
+ ping_timeout: 5000
+ spring:
+ jpa:
+ hibernate:
+ ddl-auto: none
+ database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
+ properties:
+ hibernate:
+ format_sql: true
+ show-sql: false
+ use_strict_service_intf_name_verifier: false
+ domain:
+ port: 3002
+ name:
\ No newline at end of file
diff --git a/onboarding/.project b/onboarding/.project
index eb567f148..bbe5978bb 100644
--- a/onboarding/.project
+++ b/onboarding/.project
@@ -15,6 +15,11 @@