diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 0b7c7371..00000000
--- a/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# Copyright (c) 2024 Contributors to the Eclipse Foundation
-#
-# See the NOTICE file(s) distributed with this work for additional
-# information regarding copyright ownership.
-#
-# 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
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-
-name: "CodeQL"
-
-on:
- push:
- branches:
- - main
- paths-ignore:
- - 'docs/**'
- - '**.md'
- pull_request:
- paths-ignore:
- - 'docs/**'
- - '**.md'
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: true
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
-
- strategy:
- fail-fast: false
- matrix:
- language: [ 'java' ]
-
- steps:
- - uses: actions/checkout@v4
- - uses: ./.github/actions/gradle-setup
-
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v3
- with:
- languages: ${{ matrix.language }}
- queries: +security-and-quality
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
- # queries: ./path/to/local/query, your-org/your-repo/queries@main
-
- # Compiles production Java source (without tests)
- - name: Build
- run: ./gradlew compileJava --no-daemon
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v3
diff --git a/.github/workflows/run-terraform.yml b/.github/workflows/run-terraform.yml
index 4fbec458..2701a432 100644
--- a/.github/workflows/run-terraform.yml
+++ b/.github/workflows/run-terraform.yml
@@ -61,7 +61,7 @@ jobs:
cluster_name: dcp-demo
- name: "Load runtime images into KinD"
- run: kind load docker-image connector:latest identity-hub:latest catalog-server:latest -n dcp-demo
+ run: kind load docker-image controlplane:latest identity-hub:latest catalog-server:latest -n dcp-demo
- name: "Install nginx ingress controller"
run: |-
diff --git a/.run/Connector Consumer Corp.run.xml b/.run/Connector Consumer Corp.run.xml
index 31b4e342..de6d2bb7 100644
--- a/.run/Connector Consumer Corp.run.xml
+++ b/.run/Connector Consumer Corp.run.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/README.md b/README.md
index b6f4f60a..61934708 100644
--- a/README.md
+++ b/README.md
@@ -124,7 +124,7 @@ All commands are executed from the **repository's root folder** unless stated ot
./gradlew dockerize -Ppersistence=true
```
-this builds the runtime images and creates the following docker images: `connector:latest`, `catalog-server:latest`
+this builds the runtime images and creates the following docker images: `controlplane:latest`, `catalog-server:latest`
and `identity-hub:latest` in the local docker image cache. Note the `-Ppersistence` flag which puts the HashiCorp Vault
module and PostgreSQL persistence modules on the classpath. These obviously require additional configuration, which is
handled by the Terraform scripts.
@@ -136,7 +136,7 @@ Next, we bring up and configure the Kubernetes Cluster
kind create cluster -n dcp-demo --config deployment/kind.config.yaml
# Load docker images into KinD
-kind load docker-image connector:latest identity-hub:latest catalog-server:latest -n dcp-demo
+kind load docker-image controlplane:latest identity-hub:latest catalog-server:latest -n dcp-demo
# Deploy an NGINX ingress
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
diff --git a/deployment/consumer.tf b/deployment/consumer.tf
index 73fea6ce..7568b71a 100644
--- a/deployment/consumer.tf
+++ b/deployment/consumer.tf
@@ -19,14 +19,13 @@ module "consumer-connector" {
source = "./modules/connector"
humanReadableName = "consumer"
participantId = var.consumer-did
- participant-did = var.consumer-did
database = {
user = "consumer"
password = "consumer"
url = "jdbc:postgresql://${module.consumer-postgres.database-url}/consumer"
}
- namespace = kubernetes_namespace.ns.metadata.0.name
vault-url = "http://consumer-vault:8200"
+ namespace = kubernetes_namespace.ns.metadata.0.name
}
# consumer identity hub
@@ -43,12 +42,14 @@ module "consumer-identityhub" {
password = "consumer"
url = "jdbc:postgresql://${module.consumer-postgres.database-url}/consumer"
}
+ namespace = kubernetes_namespace.ns.metadata.0.name
}
# consumer vault
module "consumer-vault" {
source = "./modules/vault"
humanReadableName = "consumer-vault"
+ namespace = kubernetes_namespace.ns.metadata.0.name
}
# Postgres database for the consumer
diff --git a/deployment/modules/catalog-server/catalog-server.tf b/deployment/modules/catalog-server/catalog-server.tf
index effafcb5..58a79f38 100644
--- a/deployment/modules/catalog-server/catalog-server.tf
+++ b/deployment/modules/catalog-server/catalog-server.tf
@@ -68,7 +68,25 @@ resource "kubernetes_deployment" "connector" {
liveness_probe {
exec {
- command = ["curl", "-X POST", "http://localhost:8080/api/check/health"]
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/liveness"]
+ }
+ failure_threshold = 10
+ period_seconds = 5
+ timeout_seconds = 30
+ }
+
+ readiness_probe {
+ exec {
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/readiness"]
+ }
+ failure_threshold = 10
+ period_seconds = 5
+ timeout_seconds = 30
+ }
+
+ startup_probe {
+ exec {
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/startup"]
}
failure_threshold = 10
period_seconds = 5
diff --git a/deployment/modules/catalog-server/variables.tf b/deployment/modules/catalog-server/variables.tf
index 524c0b6a..7eaf52ef 100644
--- a/deployment/modules/catalog-server/variables.tf
+++ b/deployment/modules/catalog-server/variables.tf
@@ -43,8 +43,7 @@ variable "participant-did" {
}
variable "namespace" {
- type = string
- default = "mvd"
+ type = string
}
variable "ports" {
diff --git a/deployment/modules/connector/connector.tf b/deployment/modules/connector/controlplane.tf
similarity index 80%
rename from deployment/modules/connector/connector.tf
rename to deployment/modules/connector/controlplane.tf
index 7bb3d07e..74cc2e07 100644
--- a/deployment/modules/connector/connector.tf
+++ b/deployment/modules/connector/controlplane.tf
@@ -17,12 +17,12 @@
# SPDX-License-Identifier: Apache-2.0
#
-resource "kubernetes_deployment" "connector" {
+resource "kubernetes_deployment" "controlplane" {
metadata {
- name = "${lower(var.humanReadableName)}-connector"
+ name = "${lower(var.humanReadableName)}-controlplane"
namespace = var.namespace
labels = {
- App = "${lower(var.humanReadableName)}-connector"
+ App = "${lower(var.humanReadableName)}-controlplane"
}
}
@@ -30,21 +30,21 @@ resource "kubernetes_deployment" "connector" {
replicas = 1
selector {
match_labels = {
- App = "${lower(var.humanReadableName)}-connector"
+ App = "${lower(var.humanReadableName)}-controlplane"
}
}
template {
metadata {
labels = {
- App = "${lower(var.humanReadableName)}-connector"
+ App = "${lower(var.humanReadableName)}-controlplane"
}
}
spec {
container {
name = "connector-${lower(var.humanReadableName)}"
- image = "connector:latest"
+ image = "controlplane:latest"
image_pull_policy = "Never"
env_from {
@@ -68,7 +68,25 @@ resource "kubernetes_deployment" "connector" {
liveness_probe {
exec {
- command = ["curl", "-X POST", "http://localhost:8080/api/check/health"]
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/liveness"]
+ }
+ failure_threshold = 10
+ period_seconds = 5
+ timeout_seconds = 30
+ }
+
+ readiness_probe {
+ exec {
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/readiness"]
+ }
+ failure_threshold = 10
+ period_seconds = 5
+ timeout_seconds = 30
+ }
+
+ startup_probe {
+ exec {
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/startup"]
}
failure_threshold = 10
period_seconds = 5
@@ -118,17 +136,18 @@ resource "kubernetes_config_map" "participants-map" {
resource "kubernetes_config_map" "connector-config" {
metadata {
- name = "${lower(var.humanReadableName)}-connector-config"
+ name = "${lower(var.humanReadableName)}-controlplane-config"
namespace = var.namespace
}
## Create databases for keycloak and MIW, create users and assign privileges
data = {
+ EDC_PARTICIPANT_ID = var.participantId
EDC_API_AUTH_KEY = "password"
- EDC_IAM_ISSUER_ID = var.participant-did
+ EDC_IAM_ISSUER_ID = var.participantId
EDC_IAM_DID_WEB_USE_HTTPS = false
WEB_HTTP_PORT = var.ports.web
- WEB_HTTP_PATH = "/"
+ WEB_HTTP_PATH = "/api"
WEB_HTTP_MANAGEMENT_PORT = var.ports.management
WEB_HTTP_MANAGEMENT_PATH = "/api/management"
WEB_HTTP_CONTROL_PORT = var.ports.control
@@ -140,10 +159,9 @@ resource "kubernetes_config_map" "connector-config" {
EDC_API_AUTH_KEY = "password"
EDC_DSP_CALLBACK_ADDRESS = "http://${local.controlplane-service-name}:${var.ports.protocol}/api/dsp"
EDC_IAM_STS_PRIVATEKEY_ALIAS = var.aliases.sts-private-key
- EDC_IAM_STS_PUBLICKEY_ID = "${var.participant-did}#${var.aliases.sts-public-key-id}"
+ EDC_IAM_STS_PUBLICKEY_ID = "${var.participantId}#${var.aliases.sts-public-key-id}"
JAVA_TOOL_OPTIONS = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${var.ports.debug}"
EDC_IH_AUDIENCE_REGISTRY_PATH = "/etc/registry/registry.json"
- EDC_PARTICIPANT_ID = var.participantId
EDC_VAULT_HASHICORP_URL = var.vault-url
EDC_VAULT_HASHICORP_TOKEN = var.vault-token
EDC_MVD_PARTICIPANTS_LIST_FILE = "/etc/participants/participants.json"
diff --git a/deployment/modules/connector/dataplane.tf b/deployment/modules/connector/dataplane.tf
new file mode 100644
index 00000000..f0c0fe23
--- /dev/null
+++ b/deployment/modules/connector/dataplane.tf
@@ -0,0 +1,123 @@
+#
+# Copyright (c) 2023 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# 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
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+resource "kubernetes_deployment" "dataplane" {
+ # needs a hard dependency, otherwise the dataplane registration fails, and it is not retried
+ depends_on = [kubernetes_deployment.controlplane]
+ metadata {
+ name = "${lower(var.humanReadableName)}-dataplane"
+ namespace = var.namespace
+ labels = {
+ App = "${lower(var.humanReadableName)}-dataplane"
+ }
+ }
+
+ spec {
+ replicas = 1
+ selector {
+ match_labels = {
+ App = "${lower(var.humanReadableName)}-dataplane"
+ }
+ }
+
+ template {
+ metadata {
+ labels = {
+ App = "${lower(var.humanReadableName)}-dataplane"
+ }
+ }
+
+ spec {
+ container {
+ name = "dataplane-${lower(var.humanReadableName)}"
+ image = "dataplane:latest"
+ image_pull_policy = "Never"
+
+ env_from {
+ config_map_ref {
+ name = kubernetes_config_map.dataplane-config.metadata[0].name
+ }
+ }
+
+ port {
+ container_port = var.ports.public
+ name = "public-port"
+ }
+
+ port {
+ container_port = var.ports.debug
+ name = "debug-port"
+ }
+
+ liveness_probe {
+ exec {
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/liveness"]
+ }
+ failure_threshold = 10
+ period_seconds = 5
+ timeout_seconds = 30
+ }
+
+ readiness_probe {
+ exec {
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/readiness"]
+ }
+ failure_threshold = 10
+ period_seconds = 5
+ timeout_seconds = 30
+ }
+
+ startup_probe {
+ exec {
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/startup"]
+ }
+ failure_threshold = 10
+ period_seconds = 5
+ timeout_seconds = 30
+ }
+ }
+ }
+ }
+ }
+}
+
+resource "kubernetes_config_map" "dataplane-config" {
+ metadata {
+ name = "${lower(var.humanReadableName)}-dataplane-config"
+ namespace = var.namespace
+ }
+
+ ## Create databases for keycloak and MIW, create users and assign privileges
+ data = {
+ # hostname is "localhost" by default, but must be the service name at which the dataplane is reachable. URL scheme and port are appended by the application
+ EDC_HOSTNAME = local.dataplane-service-name
+ EDC_RUNTIME_ID = "${var.humanReadableName}-dataplane"
+ EDC_PARTICIPANT_ID = var.participantId
+ EDC_TRANSFER_PROXY_TOKEN_VERIFIER_PUBLICKEY_ALIAS = "${var.participantId}#${var.aliases.sts-public-key-id}"
+ EDC_TRANSFER_PROXY_TOKEN_SIGNER_PRIVATEKEY_ALIAS = var.aliases.sts-private-key
+ EDC_DPF_SELECTOR_URL = "http://${local.controlplane-service-name}:${var.ports.control}/api/control/v1/dataplanes"
+ WEB_HTTP_PORT = var.ports.web
+ WEB_HTTP_PATH = "/api"
+ WEB_HTTP_CONTROL_PORT = var.ports.control
+ WEB_HTTP_CONTROL_PATH = "/api/control"
+ WEB_HTTP_PUBLIC_PORT = var.ports.public
+ WEB_HTTP_PUBLIC_PATH = "/api/public"
+ JAVA_TOOL_OPTIONS = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${var.ports.debug}"
+ }
+}
diff --git a/deployment/modules/connector/ingress.tf b/deployment/modules/connector/ingress.tf
index 90d8a8a9..8c4b5d3a 100644
--- a/deployment/modules/connector/ingress.tf
+++ b/deployment/modules/connector/ingress.tf
@@ -54,6 +54,18 @@ resource "kubernetes_ingress_v1" "api-ingress" {
}
}
+ path {
+ path = "/${var.humanReadableName}/public(/|$)(.*)"
+ backend {
+ service {
+ name = kubernetes_service.dataplane-service.metadata.0.name
+ port {
+ number = var.ports.public
+ }
+ }
+ }
+ }
+
path {
path = "/${var.humanReadableName}/fc(/|$)(.*)"
backend {
diff --git a/deployment/modules/connector/outputs.tf b/deployment/modules/connector/outputs.tf
index 5c4ff129..81a5e9c5 100644
--- a/deployment/modules/connector/outputs.tf
+++ b/deployment/modules/connector/outputs.tf
@@ -33,6 +33,6 @@ output "ports" {
output "audience-mapping" {
value = {
# dspAudience = "http://${local.connector-cluster-ip}:${var.ports.protocol}/api/dsp"
- dcpAudience = var.participant-did
+ dcpAudience = var.participantId
}
}
diff --git a/deployment/modules/connector/services.tf b/deployment/modules/connector/services.tf
index cd1cdaba..972e1cd2 100644
--- a/deployment/modules/connector/services.tf
+++ b/deployment/modules/connector/services.tf
@@ -25,7 +25,7 @@ resource "kubernetes_service" "controlplane-service" {
spec {
type = "NodePort"
selector = {
- App = kubernetes_deployment.connector.spec.0.template.0.metadata[0].labels.App
+ App = kubernetes_deployment.controlplane.spec.0.template.0.metadata[0].labels.App
}
port {
name = "health"
@@ -47,5 +47,30 @@ resource "kubernetes_service" "controlplane-service" {
name = "debug"
port = var.ports.debug
}
+ port {
+ name = "control"
+ port = var.ports.control
+ }
+ }
+}
+
+resource "kubernetes_service" "dataplane-service" {
+ metadata {
+ name = local.dataplane-service-name
+ namespace = var.namespace
+ }
+ spec {
+ type = "NodePort"
+ selector = {
+ App = kubernetes_deployment.dataplane.spec.0.template.0.metadata[0].labels.App
+ }
+ port {
+ name = "control"
+ port = var.ports.control
+ }
+ port {
+ name = "public"
+ port = var.ports.public
+ }
}
}
\ No newline at end of file
diff --git a/deployment/modules/connector/variables.tf b/deployment/modules/connector/variables.tf
index 32746dc3..ce4fbe6f 100644
--- a/deployment/modules/connector/variables.tf
+++ b/deployment/modules/connector/variables.tf
@@ -34,17 +34,11 @@ variable "humanReadableName" {
variable "participantId" {
type = string
- description = "Participant ID of the connector. In Catena-X, this MUST be the BPN"
-}
-
-variable "participant-did" {
- type = string
- description = "DID:WEB identifier of the participant"
+ description = "DID:WEB identifier of the participant, will be used as runtime participantId"
}
variable "namespace" {
- type = string
- default = "mvd"
+ type = string
}
variable "ports" {
@@ -55,6 +49,7 @@ variable "ports" {
control = number
catalog = number
debug = number
+ public = number
})
default = {
web = 8080
@@ -63,6 +58,7 @@ variable "ports" {
control = 8083
catalog = 8084
debug = 1044
+ public = 11002
}
}
@@ -104,4 +100,5 @@ variable "aliases" {
locals {
name = lower(var.humanReadableName)
controlplane-service-name = "${var.humanReadableName}-controlplane"
+ dataplane-service-name = "${var.humanReadableName}-dataplane"
}
diff --git a/deployment/modules/identity-hub/identityhub.tf b/deployment/modules/identity-hub/identityhub.tf
index 15684243..3e295f26 100644
--- a/deployment/modules/identity-hub/identityhub.tf
+++ b/deployment/modules/identity-hub/identityhub.tf
@@ -63,11 +63,42 @@ resource "kubernetes_deployment" "identityhub" {
container_port = var.ports.ih-did
name = "did"
}
+ port {
+ container_port = var.ports.web
+ name = "default-port"
+ }
volume_mount {
mount_path = "/etc/credentials"
name = "credentials-volume"
}
+
+ liveness_probe {
+ exec {
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/liveness"]
+ }
+ failure_threshold = 10
+ period_seconds = 5
+ timeout_seconds = 30
+ }
+
+ readiness_probe {
+ exec {
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/readiness"]
+ }
+ failure_threshold = 10
+ period_seconds = 5
+ timeout_seconds = 30
+ }
+
+ startup_probe {
+ exec {
+ command = ["curl", "-X GET", "http://localhost:${var.ports.web}/api/check/startup"]
+ }
+ failure_threshold = 10
+ period_seconds = 5
+ timeout_seconds = 30
+ }
}
volume {
@@ -107,7 +138,7 @@ resource "kubernetes_config_map" "identityhub-config" {
EDC_IAM_DID_WEB_USE_HTTPS = false
EDC_IH_IAM_PUBLICKEY_ALIAS = local.public-key-alias
EDC_IH_API_SUPERUSER_KEY = var.ih_superuser_apikey
- WEB_HTTP_PORT = var.ports.ih-default
+ WEB_HTTP_PORT = var.ports.web
WEB_HTTP_PATH = "/api"
WEB_HTTP_IDENTITY_PORT = var.ports.ih-identity-api
WEB_HTTP_IDENTITY_PATH = "/api/identity"
diff --git a/deployment/modules/identity-hub/variables.tf b/deployment/modules/identity-hub/variables.tf
index b9f5b7f4..5ad82961 100644
--- a/deployment/modules/identity-hub/variables.tf
+++ b/deployment/modules/identity-hub/variables.tf
@@ -32,24 +32,21 @@ variable "participantId" {
}
variable "namespace" {
- type = string
- default = "mvd"
+ type = string
}
variable "ports" {
type = object({
web = number
debug = number
- ih-default = number
ih-debug = number
ih-did = number
ih-identity-api = number
resolution-api = number
})
default = {
- web = 8080
+ web = 7080
debug = 1044
- ih-default = 7080
ih-debug = 1045
ih-did = 7083
ih-identity-api = 7081
diff --git a/deployment/modules/vault/variables.tf b/deployment/modules/vault/variables.tf
index 822306fc..1ad67483 100644
--- a/deployment/modules/vault/variables.tf
+++ b/deployment/modules/vault/variables.tf
@@ -23,8 +23,7 @@ variable "humanReadableName" {
}
variable "namespace" {
- type = string
- default = "mvd"
+ type = string
}
variable "vault-token" {
diff --git a/deployment/provider.tf b/deployment/provider.tf
index 5155c7a9..3a509ce2 100644
--- a/deployment/provider.tf
+++ b/deployment/provider.tf
@@ -20,7 +20,6 @@ module "provider-qna-connector" {
source = "./modules/connector"
humanReadableName = "provider-qna"
participantId = var.provider-did
- participant-did = var.provider-did
database = {
user = "qna"
password = "provider-qna"
@@ -35,7 +34,6 @@ module "provider-manufacturing-connector" {
source = "./modules/connector"
humanReadableName = "provider-manufacturing"
participantId = var.provider-did
- participant-did = var.provider-did
database = {
user = "manufacturing"
password = "provider-manufacturing"
@@ -53,6 +51,8 @@ module "provider-identityhub" {
participantId = var.provider-did
vault-url = "http://provider-vault:8200"
service-name = "provider"
+ namespace = kubernetes_namespace.ns.metadata.0.name
+
database = {
user = "identityhub"
password = "identityhub"
@@ -78,6 +78,7 @@ module "provider-catalog-server" {
module "provider-vault" {
source = "./modules/vault"
humanReadableName = "provider-vault"
+ namespace = kubernetes_namespace.ns.metadata.0.name
}
# Postgres database for the consumer
diff --git a/extensions/superuser-seed/src/main/java/org/eclipse/edc/identityhub/seed/ParticipantContextSeedExtension.java b/extensions/superuser-seed/src/main/java/org/eclipse/edc/identityhub/seed/ParticipantContextSeedExtension.java
index aa82fe40..448e0319 100644
--- a/extensions/superuser-seed/src/main/java/org/eclipse/edc/identityhub/seed/ParticipantContextSeedExtension.java
+++ b/extensions/superuser-seed/src/main/java/org/eclipse/edc/identityhub/seed/ParticipantContextSeedExtension.java
@@ -43,18 +43,16 @@ public class ParticipantContextSeedExtension implements ServiceExtension {
private String superUserParticipantId;
private String superUserApiKey;
private Monitor monitor;
+ @Inject
+ private ParticipantContextService participantContextService;
+ @Inject
+ private Vault vault;
@Override
public String name() {
return NAME;
}
- @Inject
- private ParticipantContextService participantContextService;
-
- @Inject
- private Vault vault;
-
@Override
public void initialize(ServiceExtensionContext context) {
superUserParticipantId = context.getSetting(SUPERUSER_PARTICIPANT_ID_PROPERTY, DEFAULT_SUPER_USER_PARTICIPANT_ID);
@@ -65,7 +63,10 @@ public void initialize(ServiceExtensionContext context) {
@Override
public void start() {
// create super-user
-
+ if (participantContextService.getParticipantContext(superUserParticipantId).succeeded()) { // already exists
+ monitor.debug("super-user already exists with ID '%s', will not re-create".formatted(superUserParticipantId));
+ return;
+ }
participantContextService.createParticipantContext(ParticipantManifest.Builder.newInstance()
.participantId(superUserParticipantId)
.did("did:web:%s".formatted(superUserParticipantId)) // doesn't matter, not intended for resolution
diff --git a/extensions/superuser-seed/src/test/java/org/eclipse/edc/identityhub/seed/ParticipantContextSeedExtensionTest.java b/extensions/superuser-seed/src/test/java/org/eclipse/edc/identityhub/seed/ParticipantContextSeedExtensionTest.java
index b578c10a..6635bacd 100644
--- a/extensions/superuser-seed/src/test/java/org/eclipse/edc/identityhub/seed/ParticipantContextSeedExtensionTest.java
+++ b/extensions/superuser-seed/src/test/java/org/eclipse/edc/identityhub/seed/ParticipantContextSeedExtensionTest.java
@@ -32,6 +32,7 @@
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -39,6 +40,7 @@
@ExtendWith(DependencyInjectionExtension.class)
class ParticipantContextSeedExtensionTest {
+ public static final String SUPER_USER = "super-user";
private final ParticipantContextService participantContextService = mock();
private final Vault vault = mock();
private final Monitor monitor = mock();
@@ -48,6 +50,7 @@ void setup(ServiceExtensionContext context) {
context.registerService(ParticipantContextService.class, participantContextService);
context.registerService(Vault.class, vault);
context.registerService(Monitor.class, monitor);
+ when(participantContextService.getParticipantContext(eq(SUPER_USER))).thenReturn(ServiceResult.notFound("foobar"));
}
@Test
@@ -58,6 +61,7 @@ void start_verifySuperUser(ParticipantContextSeedExtension ext,
ext.initialize(context);
ext.start();
+ verify(participantContextService).getParticipantContext(eq(SUPER_USER));
verify(participantContextService).createParticipantContext(any());
verifyNoMoreInteractions(participantContextService);
}
@@ -69,6 +73,8 @@ void start_failsToCreate(ParticipantContextSeedExtension ext, ServiceExtensionCo
.thenReturn(ServiceResult.badRequest("test-message"));
ext.initialize(context);
assertThatThrownBy(ext::start).isInstanceOf(EdcException.class);
+
+ verify(participantContextService).getParticipantContext(eq(SUPER_USER));
verify(participantContextService).createParticipantContext(any());
verifyNoMoreInteractions(participantContextService);
}
@@ -86,13 +92,14 @@ void start_withApiKeyOverride(ParticipantContextSeedExtension ext,
when(participantContextService.createParticipantContext(any()))
.thenReturn(ServiceResult.success("generated-api-key"));
- when(participantContextService.getParticipantContext(eq("super-user")))
+ when(participantContextService.getParticipantContext(eq(SUPER_USER)))
+ .thenReturn(ServiceResult.notFound("foobar"))
.thenReturn(ServiceResult.success(superUserContext().build()));
ext.initialize(context);
ext.start();
+ verify(participantContextService, times(2)).getParticipantContext(eq(SUPER_USER));
verify(participantContextService).createParticipantContext(any());
- verify(participantContextService).getParticipantContext(eq("super-user"));
verify(vault).storeSecret(eq("super-user-apikey"), eq(apiKeyOverride));
verifyNoMoreInteractions(participantContextService, vault);
}
@@ -108,13 +115,14 @@ void start_withInvalidKeyOverride(ParticipantContextSeedExtension ext,
when(participantContextService.createParticipantContext(any()))
.thenReturn(ServiceResult.success("generated-api-key"));
- when(participantContextService.getParticipantContext(eq("super-user")))
+ when(participantContextService.getParticipantContext(eq(SUPER_USER)))
+ .thenReturn(ServiceResult.notFound("foobar"))
.thenReturn(ServiceResult.success(superUserContext().build()));
ext.initialize(context);
ext.start();
verify(participantContextService).createParticipantContext(any());
- verify(participantContextService).getParticipantContext(eq("super-user"));
+ verify(participantContextService, times(2)).getParticipantContext(eq(SUPER_USER));
verify(vault).storeSecret(eq("super-user-apikey"), eq(apiKeyOverride));
verify(monitor).warning(contains("this key appears to have an invalid format"));
verifyNoMoreInteractions(participantContextService, vault);
@@ -131,13 +139,14 @@ void start_whenVaultReturnsFailure(ParticipantContextSeedExtension ext,
when(participantContextService.createParticipantContext(any()))
.thenReturn(ServiceResult.success("generated-api-key"));
- when(participantContextService.getParticipantContext(eq("super-user")))
+ when(participantContextService.getParticipantContext(eq(SUPER_USER)))
+ .thenReturn(ServiceResult.notFound("foobar"))
.thenReturn(ServiceResult.success(superUserContext().build()));
ext.initialize(context);
ext.start();
+ verify(participantContextService, times(2)).getParticipantContext(eq(SUPER_USER));
verify(participantContextService).createParticipantContext(any());
- verify(participantContextService).getParticipantContext(eq("super-user"));
verify(vault).storeSecret(eq("super-user-apikey"), eq(apiKeyOverride));
verify(monitor).warning(eq("Error storing API key in vault: test-failure"));
verifyNoMoreInteractions(participantContextService, vault);
@@ -145,7 +154,7 @@ void start_whenVaultReturnsFailure(ParticipantContextSeedExtension ext,
private ParticipantContext.Builder superUserContext() {
return ParticipantContext.Builder.newInstance()
- .participantId("super-user")
+ .participantId(SUPER_USER)
.apiTokenAlias("super-user-apikey");
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 8d20781a..52834e52 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -4,7 +4,7 @@ format.version = "1.1"
[versions]
assertj = "3.24.2"
awaitility = "4.2.0"
-edc = "0.7.2-SNAPSHOT"
+edc = "0.8.0"
failsafe = "3.3.2"
jackson = "2.14.2"
jupiter = "5.10.1"
@@ -64,11 +64,25 @@ edc-lib-transform = { module = "org.eclipse.edc:transform-lib", version.ref = "e
edc-lib-crypto = { module = "org.eclipse.edc:crypto-common-lib", version.ref = "edc" }
edc-lib-keys = { module = "org.eclipse.edc:keys-lib", version.ref = "edc" }
-# EDC DPF dependencies
+# EDC dataplane client modules (used in controlplane)
edc-dpf-transfer = { module = "org.eclipse.edc:transfer-data-plane", version.ref = "edc" }
edc-dpf-selector-client = { module = "org.eclipse.edc:data-plane-selector-client", version.ref = "edc" }
edc-spi-dataplane-selector = { module = "org.eclipse.edc:data-plane-selector-spi", version.ref = "edc" }
edc-dpf-selector-core = { module = "org.eclipse.edc:data-plane-selector-core", version.ref = "edc" }
+edc-dpf-selector-control-api = { module = "org.eclipse.edc:data-plane-selector-control-api", version.ref = "edc" }
+edc-dpf-signaling-client = { module = "org.eclipse.edc:data-plane-signaling-client", version.ref = "edc" }
+
+# EDC dataplane modules
+edc-dataplane-core = { module = "org.eclipse.edc:data-plane-core", version.ref = "edc" }
+edc-dataplane-api-control-config = { module = "org.eclipse.edc:control-api-configuration", version.ref = "edc" }
+edc-dataplane-api-control-client = { module = "org.eclipse.edc:control-plane-api-client", version.ref = "edc" }
+edc-dataplane-selfregistration = { module = "org.eclipse.edc:data-plane-self-registration", version.ref = "edc" }
+edc-dataplane-http = { module = "org.eclipse.edc:data-plane-http", version.ref = "edc" }
+edc-dataplane-http-oauth2 = { module = "org.eclipse.edc:data-plane-http-oauth2", version.ref = "edc" }
+edc-dataplane-api-control = { module = "org.eclipse.edc:data-plane-control-api", version.ref = "edc" }
+edc-dataplane-api-public = { module = "org.eclipse.edc:data-plane-public-api-v2", version.ref = "edc" }
+edc-dataplane-api-signaling = { module = "org.eclipse.edc:data-plane-signaling-api", version.ref = "edc" }
+
# EDC Postgres modules
edc-sql-assetindex = { module = "org.eclipse.edc:asset-index-sql", version.ref = "edc" }
@@ -126,7 +140,7 @@ postgres = { module = "org.postgresql:postgresql", version.ref = "postgres" }
[bundles]
-dpf = ["edc-dpf-transfer", "edc-dpf-selector-core", "edc-spi-dataplane-selector"]
+dpf = ["edc-dpf-selector-core", "edc-spi-dataplane-selector", "edc-dpf-selector-control-api", "edc-dpf-signaling-client"]
connector = ["edc-boot", "edc-core-connector", "edc-ext-http", "edc-ext-observability", "edc-ext-jsonld"]
@@ -146,7 +160,7 @@ dcp = ["edc-dcp", "edc-did-core", "edc-did-web", "edc-oauth2-client", "edc-dcp-c
sql-edc = ["edc-sql-assetindex", "edc-sql-contractdef", "edc-sql-contractneg", "edc-sql-policydef", "edc-sql-transferprocess", "edc-sql-core", "edc-sql-lease", "edc-sql-pool", "edc-sql-transactionlocal", "postgres"]
-sql-ih = ["edc-sql-ih-credstore-sql", "edc-sql-ih-didstore-sql","edc-sql-ih-keypairstore-sql","edc-sql-ih-pcstore-sql","edc-sql-core", "edc-sql-pool", "edc-sql-transactionlocal", "postgres"]
+sql-ih = ["edc-sql-ih-credstore-sql", "edc-sql-ih-didstore-sql", "edc-sql-ih-keypairstore-sql", "edc-sql-ih-pcstore-sql", "edc-sql-core", "edc-sql-pool", "edc-sql-transactionlocal", "postgres"]
[plugins]
shadow = { id = "com.github.johnrengelman.shadow", version = "8.1.1" }
diff --git a/launchers/connector/build.gradle.kts b/launchers/controlplane/build.gradle.kts
similarity index 99%
rename from launchers/connector/build.gradle.kts
rename to launchers/controlplane/build.gradle.kts
index 74465fa5..d8fce1f3 100644
--- a/launchers/connector/build.gradle.kts
+++ b/launchers/controlplane/build.gradle.kts
@@ -34,6 +34,7 @@ dependencies {
}
runtimeOnly(libs.bundles.dpf)
runtimeOnly(libs.edc.api.version)
+
}
tasks.withType {
diff --git a/launchers/connector/src/main/docker/Dockerfile b/launchers/controlplane/src/main/docker/Dockerfile
similarity index 100%
rename from launchers/connector/src/main/docker/Dockerfile
rename to launchers/controlplane/src/main/docker/Dockerfile
diff --git a/launchers/dataplane/build.gradle.kts b/launchers/dataplane/build.gradle.kts
new file mode 100644
index 00000000..b52fddca
--- /dev/null
+++ b/launchers/dataplane/build.gradle.kts
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (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:
+* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - Initial API and Implementation
+*
+*/
+
+plugins {
+ `java-library`
+ id("application")
+ alias(libs.plugins.shadow)
+}
+
+dependencies {
+ runtimeOnly(libs.edc.ext.observability)
+ runtimeOnly(libs.edc.dataplane.core)
+ runtimeOnly(libs.edc.dataplane.api.control.config)
+ runtimeOnly(libs.edc.dataplane.api.control.client)
+ runtimeOnly(libs.edc.dataplane.selfregistration)
+ runtimeOnly(libs.edc.dataplane.http)
+ runtimeOnly(libs.edc.dataplane.http.oauth2)
+ runtimeOnly(libs.edc.dataplane.api.control)
+ runtimeOnly(libs.edc.dataplane.api.public)
+ runtimeOnly(libs.edc.dataplane.api.signaling)
+ runtimeOnly(libs.edc.ext.jsonld) // needed by the DataPlaneSignalingApi
+ runtimeOnly(libs.edc.dpf.selector.client) // for the selector service -> self registration
+
+}
+
+tasks.withType {
+ exclude("**/pom.properties", "**/pom.xm")
+ mergeServiceFiles()
+ archiveFileName.set("${project.name}.jar")
+}
+
+application {
+ mainClass.set("org.eclipse.edc.boot.system.runtime.BaseRuntime")
+}
+
+edcBuild {
+ publish.set(false)
+}
\ No newline at end of file
diff --git a/launchers/dataplane/src/main/docker/Dockerfile b/launchers/dataplane/src/main/docker/Dockerfile
new file mode 100644
index 00000000..824c56f4
--- /dev/null
+++ b/launchers/dataplane/src/main/docker/Dockerfile
@@ -0,0 +1,27 @@
+# -buster is required to have apt available
+FROM eclipse-temurin:21.0.2_13-jre-alpine
+
+# Optional JVM arguments, such as memory settings
+ARG JVM_ARGS=""
+ARG JAR
+
+RUN apk --no-cache add curl
+
+WORKDIR /app
+
+
+COPY ${JAR} edc-dataplane.jar
+
+EXPOSE 8080
+
+ENV WEB_HTTP_PORT="8080"
+ENV WEB_HTTP_PATH="/"
+
+HEALTHCHECK --interval=5s --timeout=5s --retries=10 CMD curl --fail http://localhost:8080/api/check/health
+
+# Use "exec" for graceful termination (SIGINT) to reach JVM.
+# ARG can not be used in ENTRYPOINT so storing value in an ENV variable
+ENV ENV_JVM_ARGS=$JVM_ARGS
+# need the sh -c syntax so that the SECRETS variable gets expanded
+# use the "exec" syntax so that SIGINT reaches the JVM -> graceful termination
+CMD ["sh", "-c", "exec java -Dedc.fs.config=/app/configuration.properties -Dedc.vault.secrets=\"${SECRETS}\" -Djava.util.logging.config.file=/app/logging.properties -Djava.security.egd=file:/dev/urandom -jar edc-dataplane.jar"]
diff --git a/launchers/identity-hub/build.gradle.kts b/launchers/identity-hub/build.gradle.kts
index 09970369..0289918a 100644
--- a/launchers/identity-hub/build.gradle.kts
+++ b/launchers/identity-hub/build.gradle.kts
@@ -20,6 +20,7 @@ plugins {
dependencies {
runtimeOnly(libs.bundles.identityhub)
+ runtimeOnly(libs.edc.api.observability)
if (project.properties.getOrDefault("persistence", "false") == "true") {
runtimeOnly(libs.edc.vault.hashicorp)
runtimeOnly(libs.bundles.sql.ih)
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 9cf43add..aadf8ad3 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -36,12 +36,15 @@ dependencyResolutionManagement {
}
rootProject.name = "mvd"
-include(":launchers:identity-hub")
-include(":launchers:connector")
-include(":launchers:catalog-server")
include(":extensions:did-example-resolver")
include(":extensions:catalog-node-resolver")
include(":extensions:dcp-impl")
include(":extensions:superuser-seed")
//include(":tests:performance")
include(":tests:system-tests")
+
+// launcher modules
+include(":launchers:identity-hub")
+include(":launchers:controlplane")
+include(":launchers:dataplane")
+include(":launchers:catalog-server")