Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add capability to register an embedded dataplane #3902

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2022 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Microsoft Corporation - initial API and implementation
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - improvements
* Mercedes-Benz Tech Innovation GmbH - publish public api context into dedicated swagger hub page
*
*/


plugins {
`java-library`
}

dependencies {
api(project(":spi:data-plane:data-plane-spi"))
implementation(project(":core:common:util"))
implementation(project(":spi:data-plane-selector:data-plane-selector-spi"))
implementation(project(":core:data-plane:data-plane-util"))

testImplementation(project(":core:common:junit"))
testImplementation(project(":spi:data-plane:data-plane-spi"))



implementation(libs.jakarta.rsApi)


}



Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2024 Zub4t (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Zub4t (BMW AG) - initial API and implementation
*
*/
package org.eclipse.edc.connector.dataplane.embedded.autoregistration;

public class EmbeddedDataPlaneConfig {
public static final String CONFIG_PREFIX = "edc.embedded.dataplane";
public static final String URL_SUFFIX = "url";
public static final String DESTINATION_TYPES_SUFFIX = "destinationtypes";
public static final String SOURCE_TYPES_SUFFIX = "sourcetypes";
public static final String PROPERTIES_SUFFIX = "properties";
public static final String PUBLIC_API_URL_PROPERTY = "publicApiUrl";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2024 Zub4t (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Zub4t (BMW AG) - initial API and implementation
*
*/
package org.eclipse.edc.connector.dataplane.embedded.autoregistration;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.edc.connector.dataplane.selector.spi.DataPlaneSelectorService;
import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance;
import org.eclipse.edc.connector.dataplane.spi.manager.DataPlaneManager;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.spi.system.configuration.Config;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static java.util.Objects.nonNull;

public class EmbeddedDataPlaneRegistration implements ServiceExtension {

private static final String NAME = "Embedded DataPlane Auto Registration";
private static final String COMMA = ",";
private static final String LOG_MISSING_CONFIGURATION = NAME + ": Missing configuration for " + EmbeddedDataPlaneConfig.CONFIG_PREFIX + ".%s.%s";
private static final String LOG_SKIP_BC_MISSING_CONFIGURATION = NAME + ": Configuration issues. Skip registering of Data Plane Instance '%s'";
private static final String LOG_REGISTERED = NAME + ": Registered Data Plane Instance. (id=%s, url=%s, sourceTypes=%s, destinationTypes=%s, properties=<omitted>)";
private Monitor monitor;
@Inject
private DataPlaneSelectorService selectorService;
@Override
public String name() {
return NAME;
}

@Override
public void initialize(ServiceExtensionContext context) {
this.monitor = context.getMonitor();
final Config config = context.getConfig(EmbeddedDataPlaneConfig.CONFIG_PREFIX);
context.getService(DataPlaneManager.class);
configureDataPlaneInstance(config);
}

public DataPlaneInstance createDataPlane(final Config config){

DataPlaneInstance dataPlaneInstance = null;
final String id = config.currentNode();
final String url = config.getString(EmbeddedDataPlaneConfig.URL_SUFFIX, "");
final List<String> sourceTypes =
Arrays.stream(config.getString(EmbeddedDataPlaneConfig.SOURCE_TYPES_SUFFIX, "").split(COMMA))
.map(String::trim)
.filter(Predicate.not(String::isEmpty))
.distinct()
.collect(Collectors.toList());
final List<String> destinationTypes =
Arrays.stream(config.getString(EmbeddedDataPlaneConfig.DESTINATION_TYPES_SUFFIX, "").split(COMMA))
.map(String::trim)
.filter(Predicate.not(String::isEmpty))
.distinct()
.collect(Collectors.toList());
final String propertiesJson = config.getString(EmbeddedDataPlaneConfig.PROPERTIES_SUFFIX, "{}");

if (url.isEmpty()) {
monitor.warning(String.format(LOG_MISSING_CONFIGURATION, id, EmbeddedDataPlaneConfig.URL_SUFFIX));
}

if (sourceTypes.isEmpty()) {
monitor.warning(String.format(LOG_MISSING_CONFIGURATION, id, EmbeddedDataPlaneConfig.SOURCE_TYPES_SUFFIX));
}

if (destinationTypes.isEmpty()) {
monitor.warning(String.format(LOG_MISSING_CONFIGURATION, id, EmbeddedDataPlaneConfig.DESTINATION_TYPES_SUFFIX));
}

final Map<String, String> properties;
try {
ObjectMapper mapper = new ObjectMapper();
properties = mapper.readValue(propertiesJson, new TypeReference<Map<String, String>>() {
});
} catch (JsonProcessingException e) {
throw new EdcException(e);
}

final boolean missingPublicApiProperty = !properties.containsKey(EmbeddedDataPlaneConfig.PUBLIC_API_URL_PROPERTY);
if (missingPublicApiProperty) {
monitor.warning(String.format(LOG_MISSING_CONFIGURATION, id, EmbeddedDataPlaneConfig.PROPERTIES_SUFFIX) + "." + EmbeddedDataPlaneConfig.PUBLIC_API_URL_PROPERTY);
}

final boolean invalidConfiguration =
url.isEmpty() || sourceTypes.isEmpty() || destinationTypes.isEmpty();
if (invalidConfiguration || missingPublicApiProperty) {
monitor.warning(String.format(LOG_SKIP_BC_MISSING_CONFIGURATION, id));
return null;
}
final DataPlaneInstance.Builder builder =
DataPlaneInstance.Builder.newInstance().id(id).url(url);

sourceTypes.forEach(builder::allowedSourceType);
destinationTypes.forEach(builder::allowedDestType);
properties.forEach(builder::property);

dataPlaneInstance = builder.build();

monitor.debug(
String.format(
LOG_REGISTERED,
id,
url,
String.join(", ", sourceTypes),
String.join(", ", destinationTypes)));
return dataPlaneInstance;
}
private void configureDataPlaneInstance(final Config config) {
var dataPlaneInstance = createDataPlane(config);
if(nonNull(dataPlaneInstance)){
selectorService.addInstance(dataPlaneInstance);
}


}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.eclipse.edc.connector.dataplane.embedded.autoregistration.EmbeddedDataPlaneRegistration
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2024 Zub4t (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Zub4t (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.connector.dataplane.embedded.autoregistration;


import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance;
import org.eclipse.edc.connector.dataplane.spi.manager.DataPlaneManager;
import org.eclipse.edc.junit.extensions.DependencyInjectionExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.spi.system.configuration.ConfigFactory;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;

@ExtendWith(DependencyInjectionExtension.class)
public class EmbeddedDataPlaneRegistrationTest {

@Test
void testName(EmbeddedDataPlaneRegistration extension) {
Assertions.assertNotNull(extension.name());
Assertions.assertEquals("Embedded DataPlane Auto Registration", extension.name());
}
@Test
void embeddedDataPlaneRegistration_shouldThrowEdcException(EmbeddedDataPlaneRegistration extension, ServiceExtensionContext context) {
assertThrows(org.eclipse.edc.spi.EdcException.class, () -> {
extension.initialize(context);
var dataPlaneInstance = extension.createDataPlane(ConfigFactory.fromMap(Collections.emptyMap()));

});
}
@Test
void embeddedDataPlaneRegistration_shouldNotAddDataPlane(EmbeddedDataPlaneRegistration extension, ServiceExtensionContext context) {
var dataPlaneManager = mock(DataPlaneManager.class);
context.registerService(DataPlaneManager.class,dataPlaneManager);
extension.initialize(context);
var dataPlaneInstance = extension.createDataPlane(ConfigFactory.fromMap(Collections.emptyMap()));
assertThat(dataPlaneInstance).isNull();
}
@Test
void embeddedDataPlaneRegistration_shouldAddDataPlane(EmbeddedDataPlaneRegistration extension, ServiceExtensionContext context) {
var dataPlaneManager = mock(DataPlaneManager.class);
context.registerService(DataPlaneManager.class,dataPlaneManager);

List<String> keys = List.of(
EmbeddedDataPlaneConfig.DESTINATION_TYPES_SUFFIX,
EmbeddedDataPlaneConfig.SOURCE_TYPES_SUFFIX,
EmbeddedDataPlaneConfig.URL_SUFFIX,
EmbeddedDataPlaneConfig.PROPERTIES_SUFFIX);

List<String> values = List.of("HttpProxy,HttpData","HttpData","http://localhost:19192/control/transfer","{\"publicApiUrl\": \"http://localhost:19291/public/\"}");
Map<String, String> map = IntStream.range(0, keys.size())
.boxed()
.collect(HashMap::new, (m, i) -> m.put(keys.get(i), values.get(i)), Map::putAll);

extension.initialize(context);
var dataPlaneInstance = extension.createDataPlane(ConfigFactory.fromMap(map));
assertThat(dataPlaneInstance).isInstanceOf(DataPlaneInstance.class);
}
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ version=0.5.2-SNAPSHOT
annotationProcessorVersion=0.5.2-SNAPSHOT
edcGradlePluginsVersion=0.5.2-SNAPSHOT
edcScmUrl=https://github.com/eclipse-edc/Connector.git
edcScmConnection=scm:git:[email protected]:eclipse-edc/Connector.git
edcScmConnection=scm:git:[email protected]:eclipse-edc/Connector.git
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ include(":extensions:data-plane:data-plane-http-oauth2-core")
include(":extensions:data-plane:data-plane-integration-tests")
include(":extensions:data-plane:store:sql:data-plane-store-sql")
include(":extensions:data-plane:data-plane-kafka")
include(":extensions:data-plane:embedded-data-plane-registration")

include(":extensions:data-plane-selector:data-plane-selector-api")
include(":extensions:data-plane-selector:data-plane-selector-client")
Expand Down