From bcb04e817274e827eff59de7a73603479829f597 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Tue, 14 May 2024 22:38:51 -0700 Subject: [PATCH 01/21] chore(Tractusx-Edc): bump version to 0.7.1 --- local/tractus-x-edc/docker-compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/local/tractus-x-edc/docker-compose.yaml b/local/tractus-x-edc/docker-compose.yaml index afb927c3..9f95a37a 100644 --- a/local/tractus-x-edc/docker-compose.yaml +++ b/local/tractus-x-edc/docker-compose.yaml @@ -21,13 +21,13 @@ version: "3" services: control-plane: - image: tractusx/edc-controlplane-postgresql-hashicorp-vault:0.7.0 + image: tractusx/edc-controlplane-postgresql-hashicorp-vault:0.7.1 volumes: - ./config/default/opentelemetry.properties:/app/opentelemetry.properties - ./config/default/logging.properties:/app/logging.properties data-plane: - image: tractusx/edc-dataplane-hashicorp-vault:0.7.0 + image: tractusx/edc-dataplane-hashicorp-vault:0.7.1 volumes: - ./config/default/opentelemetry.properties:/app/opentelemetry.properties - ./config/default/logging.properties:/app/logging.properties From d3dd47cb311d6632d7cc561328c44c136ec18157 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Mon, 6 May 2024 10:31:59 -0700 Subject: [PATCH 02/21] chore(edc-0.7.0): migrated backend to version 0.7.0 --- DEPENDENCIES_BACKEND | 2 + backend/DEPENDENCIES | 2 + backend/pom.xml | 360 +++++++++--------- .../common/edc/controller/EdcController.java | 4 +- .../EndpointDataReferenceReceiver.java | 7 +- .../backend/common/edc/logic/dto/EdrDto.java | 19 +- .../edc/logic/dto/PolicyConstraintDto.java | 34 ++ .../edc/logic/service/EdcAdapterService.java | 210 +++++++--- .../service/EndpointDataReferenceService.java | 31 +- .../edc/logic/util/EdcRequestBodyBuilder.java | 188 +++++---- 10 files changed, 512 insertions(+), 345 deletions(-) create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/PolicyConstraintDto.java diff --git a/DEPENDENCIES_BACKEND b/DEPENDENCIES_BACKEND index d5be54a6..329d42f5 100644 --- a/DEPENDENCIES_BACKEND +++ b/DEPENDENCIES_BACKEND @@ -8,7 +8,9 @@ maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/2.15.3, maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.15.3, Apache-2.0, approved, #7930 maven/mavencentral/com.fasterxml.jackson.module/jackson-module-parameter-names/2.15.3, Apache-2.0, approved, #8803 maven/mavencentral/com.fasterxml/classmate/1.6.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/com.github.stephenc.jcip/jcip-annotations/1.0-1, Apache-2.0, approved, CQ21949 maven/mavencentral/com.jayway.jsonpath/json-path/2.8.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.37.3, Apache-2.0, approved, #11701 maven/mavencentral/com.squareup.okhttp3/okhttp/4.12.0, Apache-2.0, approved, #11156 maven/mavencentral/com.squareup.okio/okio-jvm/3.6.0, Apache-2.0, approved, #11158 maven/mavencentral/com.squareup.okio/okio/3.6.0, Apache-2.0, approved, #11155 diff --git a/backend/DEPENDENCIES b/backend/DEPENDENCIES index d5be54a6..329d42f5 100644 --- a/backend/DEPENDENCIES +++ b/backend/DEPENDENCIES @@ -8,7 +8,9 @@ maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/2.15.3, maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.15.3, Apache-2.0, approved, #7930 maven/mavencentral/com.fasterxml.jackson.module/jackson-module-parameter-names/2.15.3, Apache-2.0, approved, #8803 maven/mavencentral/com.fasterxml/classmate/1.6.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/com.github.stephenc.jcip/jcip-annotations/1.0-1, Apache-2.0, approved, CQ21949 maven/mavencentral/com.jayway.jsonpath/json-path/2.8.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.37.3, Apache-2.0, approved, #11701 maven/mavencentral/com.squareup.okhttp3/okhttp/4.12.0, Apache-2.0, approved, #11156 maven/mavencentral/com.squareup.okio/okio-jvm/3.6.0, Apache-2.0, approved, #11158 maven/mavencentral/com.squareup.okio/okio/3.6.0, Apache-2.0, approved, #11155 diff --git a/backend/pom.xml b/backend/pom.xml index 695aab26..68987a8f 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -24,182 +24,190 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.2.2 - - - org.eclipse.tractusx.puris - puris-backend - 1.0.0 - puris-backend - PURIS Backend - - 17 - 2.3.0 - 8.0.1.Final - 2.2 - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.session - spring-session-core - - - org.hsqldb - hsqldb - 2.7.1 - runtime - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.postgresql - postgresql - 42.7.2 - runtime - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.security - spring-security-test - test - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - ${springdoc.version} - - - com.squareup.okhttp3 - okhttp - 4.12.0 - - - - org.hibernate.validator - hibernate-validator - ${hibernate-validator.version} - - - - org.modelmapper - modelmapper - 3.2.0 - - + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.2 + + + org.eclipse.tractusx.puris + puris-backend + 1.0.0 + puris-backend + PURIS Backend + + 17 + 2.3.0 + 8.0.1.Final + 2.2 + 9.37.3 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.session + spring-session-core + + + org.hsqldb + hsqldb + 2.7.1 + runtime + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.postgresql + postgresql + 42.7.2 + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + + + org.hibernate.validator + hibernate-validator + ${hibernate-validator.version} + + + + org.modelmapper + modelmapper + 3.2.0 + + + + com.nimbusds + nimbus-jose-jwt + ${nimbus.version} + - - - dash-licenses - https://repo.eclipse.org/content/repositories/dash-licenses - - + - - - - org.eclipse.dash - license-tool-plugin - 1.0.2 - - automotive.tractusx - - DEPENDENCIES - - test - - - - license-check - - license-check - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - org.hsqldb - hsqldb - - - - - - com.mycila - license-maven-plugin - 4.2 - - - -
scripts/license/header.txt
- - **/README - src/test/resources/** - src/main/resources/** - -
-
-
-
-
- - - - ${project.basedir}/src/main/resources - - application.properties - - BOOT-INF/classes/ - - - - ${project.basedir}/ - - README.md - LICENSE - NOTICE.md - DEPENDENCIES - SECURITY.md - - META-INF - - -
+ + + dash-licenses + https://repo.eclipse.org/content/repositories/dash-licenses + + + + + + + org.eclipse.dash + license-tool-plugin + 1.0.2 + + automotive.tractusx + + DEPENDENCIES + + test + + + + license-check + + license-check + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + org.hsqldb + hsqldb + + + + + + com.mycila + license-maven-plugin + 4.2 + + + +
scripts/license/header.txt
+ + **/README + src/test/resources/** + src/main/resources/** + +
+
+
+
+
+ + + + ${project.basedir}/src/main/resources + + application.properties + + BOOT-INF/classes/ + + + + ${project.basedir}/ + + README.md + LICENSE + NOTICE.md + DEPENDENCIES + SECURITY.md + + META-INF + + +
diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EdcController.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EdcController.java index e4baf04d..948b8809 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EdcController.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EdcController.java @@ -68,7 +68,9 @@ public ResponseEntity getCatalog(@RequestParam String dspUrl) { if (!PatternStore.URL_PATTERN.matcher(dspUrl).matches()) { return ResponseEntity.badRequest().build(); } - var catalogResponse = edcAdapter.getCatalogResponse(dspUrl); + // TODO implement bpnl resolver or update frontend to use bpnl / partner + String partnerBpnl = "not yet implemented"; + var catalogResponse = edcAdapter.getCatalogResponse(dspUrl, partnerBpnl, null); if (catalogResponse != null && catalogResponse.isSuccessful()) { var responseString = catalogResponse.body().string(); catalogResponse.body().close(); diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EndpointDataReferenceReceiver.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EndpointDataReferenceReceiver.java index 5f8a59ec..08b029eb 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EndpointDataReferenceReceiver.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EndpointDataReferenceReceiver.java @@ -27,9 +27,9 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.extern.slf4j.Slf4j; -import org.eclipse.tractusx.puris.backend.common.util.PatternStore; import org.eclipse.tractusx.puris.backend.common.edc.logic.dto.EdrDto; import org.eclipse.tractusx.puris.backend.common.edc.logic.service.EndpointDataReferenceService; +import org.eclipse.tractusx.puris.backend.common.util.PatternStore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; @@ -37,6 +37,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import java.util.Date; import java.util.regex.Pattern; /** @@ -57,7 +58,7 @@ public class EndpointDataReferenceReceiver { * This endpoint awaits incoming EDR Tokens from external * partners during a consumer pull transfer. * - * @param body + * @param body received from edc containing access information * @return Status code 200 if request body was found, otherwise 400 */ @PostMapping("/edrendpoint") @@ -88,7 +89,7 @@ private ResponseEntity authCodeReceivingEndpoint(@RequestBody JsonNode b return ResponseEntity.status(400).build(); } - edrService.save(transferId, new EdrDto(authKey, authCode, endpoint)); + edrService.save(transferId, new EdrDto(authKey, authCode, endpoint, new Date())); log.debug("EDR endpoint stored authCode for " + transferId); return ResponseEntity.status(200).build(); } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/EdrDto.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/EdrDto.java index 0efc4908..b8ccdb56 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/EdrDto.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/EdrDto.java @@ -23,17 +23,20 @@ import org.eclipse.tractusx.puris.backend.common.edc.logic.service.EndpointDataReferenceService; +import java.util.Date; + /** * An internal, immutable Dto class used by the {@link EndpointDataReferenceService} * It contains an authKey, authCode and endpoint. * - * @param authKey This defines the key, under which the - * authCode is to be sent to the data plane. - * For example: "Authorization" - * @param authCode This is the secret key to be sent - * to the data plane. - * @param endpoint The address of the data plane that has - * to handle the consumer pull. + * @param authKey This defines the key, under which the + * authCode is to be sent to the data plane. + * For example: "Authorization" + * @param authCode This is the secret key to be sent + * to the data plane. + * @param endpoint The address of the data plane that has + * to handle the consumer pull. + * @param expiresAt The expiry data in ms till data */ -public record EdrDto(String authKey, String authCode, String endpoint) { +public record EdrDto(String authKey, String authCode, String endpoint, Date expiresAt) { } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/PolicyConstraintDto.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/PolicyConstraintDto.java new file mode 100644 index 00000000..8b7b8d53 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/PolicyConstraintDto.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Volkswagen AG + * 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 + */ + +package org.eclipse.tractusx.puris.backend.common.edc.logic.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class PolicyConstraintDto { + + private String leftOperand; + private String operator; + private String rightOperand; + +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index 1c5c9a78..1017caa7 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -22,7 +22,10 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.Optional; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.JWTParser; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import org.eclipse.tractusx.puris.backend.common.edc.domain.model.SubmodelType; @@ -38,8 +41,8 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.List; +import java.text.ParseException; +import java.util.*; import java.util.regex.Pattern; /** @@ -52,7 +55,7 @@ public class EdcAdapterService { private static final OkHttpClient CLIENT = new OkHttpClient(); @Autowired private VariablesService variablesService; - private ObjectMapper objectMapper; + private final ObjectMapper objectMapper; @Autowired private EdcRequestBodyBuilder edcRequestBodyBuilder; @Autowired @@ -61,7 +64,7 @@ public class EdcAdapterService { @Autowired private EdcContractMappingService edcContractMappingService; - private Pattern urlPattern = PatternStore.URL_PATTERN; + private final Pattern urlPattern = PatternStore.URL_PATTERN; public EdcAdapterService(ObjectMapper objectMapper) { this.objectMapper = objectMapper; @@ -73,14 +76,18 @@ public EdcAdapterService(ObjectMapper objectMapper) { * the returned Response object after using it. * * @param pathSegments The path segments + * @param queryParams The query parameters to use * @return The response * @throws IOException If the connection to your control plane fails */ - public Response sendGetRequest(List pathSegments) throws IOException { + public Response sendGetRequest(List pathSegments, Map queryParams) throws IOException { HttpUrl.Builder urlBuilder = HttpUrl.parse(variablesService.getEdcManagementUrl()).newBuilder(); for (var pathSegment : pathSegments) { urlBuilder.addPathSegment(pathSegment); } + for (Map.Entry entry : queryParams.entrySet()) { + urlBuilder.addQueryParameter(entry.getKey(), entry.getValue()); + } var request = new Request.Builder() .get() .url(urlBuilder.build()) @@ -89,13 +96,26 @@ public Response sendGetRequest(List pathSegments) throws IOException { return CLIENT.newCall(request).execute(); } + /** + * Util method for issuing a GET request to the management api of your control plane. + * Any caller of this method has the responsibility to close + * the returned Response object after using it. + * + * @param pathSegments The path segments + * @return The response + * @throws IOException If the connection to your control plane fails + */ + public Response sendGetRequest(List pathSegments) throws IOException { + return sendGetRequest(pathSegments, new HashMap<>()); + } + /** * Util method for issuing a POST request to the management api of your control plane. * Any caller of this method has the responsibility to close * the returned Response object after using it. * * @param requestBody The request body - * @param pathSegments The path segments + * @param pathSegments The path se&gments * @return The response from your control plane * @throws IOException If the connection to your control plane fails */ @@ -133,16 +153,19 @@ public boolean registerAssetsInitially() { variablesService.getItemStockSubmodelEndpoint(), SubmodelType.ITEM_STOCK.URN_SEMANTIC_ID ))); + result &= assetRegistration; log.info("Registration of Planned Production 2.0.0 submodel successful {}", (assetRegistration = registerSubmodelAsset( variablesService.getProductionSubmodelApiAssetId(), variablesService.getProductionSubmodelEndpoint(), SubmodelType.PRODUCTION.URN_SEMANTIC_ID ))); + result &= assetRegistration; log.info("Registration of Short Term Material Demand 1.0.0 submodel successful {}", (assetRegistration = registerSubmodelAsset( variablesService.getDemandSubmodelApiAssetId(), variablesService.getDemandSubmodelEndpoint(), SubmodelType.DEMAND.URN_SEMANTIC_ID ))); + result &= assetRegistration; log.info("Registration of Delivery Information 2.0.0 submodel successful {}", (assetRegistration = registerSubmodelAsset( variablesService.getDeliverySubmodelApiAssetId(), variablesService.getDeliverySubmodelEndpoint(), @@ -307,23 +330,28 @@ private boolean registerSubmodelAsset(String assetId, String endpoint, String se * Retrieve the response to an unfiltered catalog request from the partner * with the given dspUrl * - * @param dspUrl The dspUrl of your partner + * @param dspUrl The dspUrl of your partner + * @param partnerBpnl The bpnl of your partner + * @param filter Map of key (leftOperand) and values (rightOperand) to use as filterExpression with equal operand * @return The response containing the full catalog, if successful */ - public Response getCatalogResponse(String dspUrl) throws IOException { - return sendPostRequest(edcRequestBodyBuilder.buildBasicCatalogRequestBody(dspUrl, null), List.of("v2", "catalog", "request")); + public Response getCatalogResponse(String dspUrl, String partnerBpnl, Map filter) throws IOException { + // TODO check if we need the method here + return sendPostRequest(edcRequestBodyBuilder.buildBasicCatalogRequestBody(dspUrl, partnerBpnl, filter), List.of("v2", "catalog", "request")); } /** * Retrieve an (unfiltered) catalog from the partner with the * given dspUrl * - * @param dspUrl The dspUrl of your partner + * @param dspUrl The dspUrl of your partner + * @param partnerBpnl The bpnl of your partner + * @param filter Map of key (leftOperand) and values (rightOperand) to use as filterExpression with equal operand * @return The full catalog * @throws IOException If the connection to the partners control plane fails */ - public JsonNode getCatalog(String dspUrl) throws IOException { - try (var response = getCatalogResponse(dspUrl)) { + public JsonNode getCatalog(String dspUrl, String partnerBpnl, Map filter) throws IOException { // TODO: use partner to get the catalog + try (var response = getCatalogResponse(dspUrl, partnerBpnl, filter)) { String stringData = response.body().string(); return objectMapper.readTree(stringData); } @@ -343,6 +371,7 @@ private JsonNode initiateNegotiation(Partner partner, JsonNode catalogItem) thro var requestBody = edcRequestBodyBuilder.buildAssetNegotiationBody(partner, catalogItem); try (var response = sendPostRequest(requestBody, List.of("v2", "contractnegotiations"))) { String responseString = response.body().string(); + log.debug("Result from negotiation" + responseString); return objectMapper.readTree(responseString); } } @@ -389,7 +418,9 @@ public JsonNode initiateProxyPullTransfer(Partner partner, String contractId, St var body = edcRequestBodyBuilder.buildProxyPullRequestBody(partner, contractId, assetId, partnerEdcUrl); try (var response = sendPostRequest(body, List.of("v2", "transferprocesses"))) { String data = response.body().string(); - return objectMapper.readTree(data); + JsonNode result = objectMapper.readTree(data); + log.debug("Got response from Proxy pull transfer init: {}", result.toPrettyString()); + return result; } } @@ -518,11 +549,12 @@ private JsonNode getSubmodelFromPartner(MaterialPartnerRelation mpr, SubmodelTyp } // Request EdrToken var transferResp = initiateProxyPullTransfer(partner, submodelContractId, assetId, partnerDspUrl); + log.debug("Transfer Request {}", transferResp.toPrettyString()); String transferId = transferResp.get("@id").asText(); for (int i = 0; i < 100; i++) { Thread.sleep(100); transferResp = getTransferState(transferId); - if ("STARTED".equals(transferResp.get("edc:state").asText())) { + if ("STARTED".equals(transferResp.get("state").asText())) { break; } } @@ -530,7 +562,7 @@ private JsonNode getSubmodelFromPartner(MaterialPartnerRelation mpr, SubmodelTyp // Await arrival of edr for (int i = 0; i < 100; i++) { Thread.sleep(100); - edrDto = edrService.findByTransferId(transferId); + edrDto = getEdrForTransferProcessId(transferId); //edrService.findByTransferId(transferId); if (edrDto != null) { log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); break; @@ -576,7 +608,13 @@ public JsonNode doSubmodelRequest(SubmodelType type, MaterialPartnerRelation mpr private boolean negotiateForPartnerDtr(Partner partner) { try { - var responseNode = getCatalog(partner.getEdcUrl()); + Map equalFilters = new HashMap<>(); + equalFilters.put(EdcRequestBodyBuilder.CX_COMMON_NAMESPACE + "version", "3.0"); + equalFilters.put( + "'" + EdcRequestBodyBuilder.DCT_NAMESPACE + "type'.'@id'", + EdcRequestBodyBuilder.CX_TAXO_NAMESPACE + "DigitalTwinRegistry" + ); + var responseNode = getCatalog(partner.getEdcUrl(), partner.getBpnl(), equalFilters); var catalogArray = responseNode.get("dcat:dataset"); // If there is exactly one asset, the catalogContent will be a JSON object. // In all other cases catalogContent will be a JSON array. @@ -584,36 +622,28 @@ private boolean negotiateForPartnerDtr(Partner partner) { if (catalogArray.isObject()) { catalogArray = objectMapper.createArrayNode().add(catalogArray); } - JsonNode targetCatalogEntry = null; - for (var entry : catalogArray) { - var dctTypeObject = entry.get("dct:type"); - if (dctTypeObject != null) { - if (("https://w3id.org/catenax/taxonomy#DigitalTwinRegistry").equals(dctTypeObject.get("@id").asText())) { - if ("3.0".equals(entry.get("https://w3id.org/catenax/ontology/common#version").asText())) { - if (targetCatalogEntry == null) { - targetCatalogEntry = entry; - } else { - log.warn("Ambiguous catalog entries found! \n" + catalogArray.toPrettyString()); - } - } - } - } + if (catalogArray.size() > 1) { + log.warn("Ambiguous catalog entries found! Will take the first\n" + catalogArray.toPrettyString()); + // TODO constraint check } + JsonNode targetCatalogEntry = catalogArray.get(0); if (targetCatalogEntry == null) { log.error("Could not find asset for DigitalTwinRegistry at partner " + partner.getBpnl() + "'s catalog"); - log.warn("CATALOG CONTENT \n" + catalogArray.toPrettyString()); return false; } String assetId = targetCatalogEntry.get("@id").asText(); + log.debug("Found contract offer for asset {}", assetId); JsonNode negotiationResponse = initiateNegotiation(partner, targetCatalogEntry); String negotiationId = negotiationResponse.get("@id").asText(); + log.info("Started negotiation with id {}", negotiationId); // Await confirmation of contract and contractId String contractId = null; for (int i = 0; i < 100; i++) { Thread.sleep(100); var responseObject = getNegotiationState(negotiationId); - if ("FINALIZED".equals(responseObject.get("edc:state").asText())) { - contractId = responseObject.get("edc:contractAgreementId").asText(); + if ("FINALIZED".equals(responseObject.get("state").asText())) { + contractId = responseObject.get("contractAgreementId").asText(); + log.info("Contracted DTR with contractAgreementId {}", contractId); break; } } @@ -706,14 +736,15 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man for (int i = 0; i < 100; i++) { Thread.sleep(100); transferResp = getTransferState(transferId); - if ("STARTED".equals(transferResp.get("edc:state").asText())) { + if ("STARTED".equals(transferResp.get("state").asText())) { break; } } EdrDto edrDto = null; // Await arrival of edr for (int i = 0; i < 100; i++) { - edrDto = edrService.findByTransferId(transferId); + // TODO use external EDR Service provided by EDC + edrDto = getEdrForTransferProcessId(transferId);//edrService.findByTransferId(transferId); if (edrDto != null) { log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); break; @@ -777,6 +808,66 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man return getAasSubmodelDescriptors(manufacturerPartId, manufacturerId, mpr, --retries); } + /** + * Requests an EDR for the communication from edc + *

+ * The edc already handles the expiry as configured in the provider data plane and refreshs the token before + * answering. + * + * @param transferProcessId to get the EDR for + * @return unpersisted EdrDto. + */ + private EdrDto getEdrForTransferProcessId(String transferProcessId) { + + // Note: If we decode the auth token, we could add the exp as expiresAt so that I can store the EDR and lookup + // again + EdrDto storedEdr = edrService.findByTransferId(transferProcessId); + log.debug("storedEdr: {}", storedEdr); + + // got a stored edr that has an auth token that will not expire within 5 seconds + // Notes: + // - this might cause an issue if there are different time zones between EDC and us + // - we could also implement an ProxyRequestInterceptor that gets a fresh token for a TransferProcessId + if (storedEdr != null && storedEdr.expiresAt().before(new Date(System.currentTimeMillis() + 5000))) { + log.info("Reuse EDR directly as it will not expire within 5 seconds"); + return storedEdr; + } + + if (storedEdr != null) { + log.debug("Expiry edr: {} VS expiry within 5 sec {}", storedEdr.expiresAt(), new Date(System.currentTimeMillis() + 5000)); + } else { + log.debug("No EDR token found"); + } + + try (Response response = sendGetRequest( + List.of("v2", "edrs", transferProcessId, "dataaddress"), + Map.of("auto_refresh", "true")) + ) { + ObjectNode responseObject = (ObjectNode) objectMapper.readTree(response.body().string()); + + // TODO pattern check dataPlaneEndpoint + String dataPlaneEndpoint = responseObject.get("endpoint").asText(); + String authToken = responseObject.get("authorization").asText(); + + JWT jwt = JWTParser.parse(authToken); + JWTClaimsSet claims = jwt.getJWTClaimsSet(); + Date expirationTime = claims.getExpirationTime(); + + storedEdr = new EdrDto("Authorization", authToken, dataPlaneEndpoint, expirationTime); + edrService.save(transferProcessId, storedEdr); + log.debug("Requested EDR successfully: {}", storedEdr); + + return storedEdr; + + } catch (ParseException e) { + log.error("EDR token could not be parsed: {}", e); + } catch (IOException e) { + log.error("EDR token for transfer process with ID {} could not be obtained", transferProcessId); + } + + return null; + } + /** * Tries to negotiate for a partner's Submodel API.

* If successful, the contractId as well as the assetId @@ -801,7 +892,15 @@ private boolean negotiateForSubmodel(MaterialPartnerRelation mpr, SubmodelType t case PART_TYPE_INFORMATION -> fetchPartTypeSubmodelData(mpr); }; try { - var responseNode = getCatalog(submodelData.dspUrl()); + // TODO: why is semantics not expanded? + Map equalFilters = new HashMap<>(); + equalFilters.put(EdcRequestBodyBuilder.CX_COMMON_NAMESPACE + "version", "3.0"); + equalFilters.put( + "'" + EdcRequestBodyBuilder.DCT_NAMESPACE + "type'.'@id'", + EdcRequestBodyBuilder.CX_TAXO_NAMESPACE + "Submodel" + ); + equalFilters.put("'" + EdcRequestBodyBuilder.AAS_SEMANTICS_NAMESPACE + "semanticId'.'@id'", type.URN_SEMANTIC_ID); + var responseNode = getCatalog(submodelData.dspUrl(), partner.getBpnl(), equalFilters); var catalogArray = responseNode.get("dcat:dataset"); // If there is exactly one asset, the catalogContent will be a JSON object. // In all other cases catalogContent will be a JSON array. @@ -810,31 +909,18 @@ private boolean negotiateForSubmodel(MaterialPartnerRelation mpr, SubmodelType t catalogArray = objectMapper.createArrayNode().add(catalogArray); } JsonNode targetCatalogEntry = null; - for (var entry : catalogArray) { - var semanticId = entry.get("aas-semantics:semanticId"); - if (semanticId == null) { - continue; - } - String idString = semanticId.get("@id").asText(); - if (idString == null) { - continue; - } - if (type.URN_SEMANTIC_ID.equals(idString) && submodelData.assetId.equals(entry.get("edc:id").asText())) { - if (targetCatalogEntry == null) { - if (testContractPolicyConstraints(entry)) { - targetCatalogEntry = entry; - } else { - log.error("Contract Negotiation for " + type + " Submodel asset with partner " + partner.getBpnl() + " has " + - "been aborted. This partner's contract policy does not match the policy " + - "supported by this application. \n Supported Policy: " + variablesService.getPurisFrameworkAgreement() + - "\n Received offer from Partner: \n" + entry.toPrettyString()); - break; - } - } else { - log.warn("Ambiguous catalog entries found! \n" + catalogArray.toPrettyString()); + if (catalogArray.size() > 1) { + log.debug("Ambiguous catalog entries found! Will take the first with supported policy \n" + catalogArray.toPrettyString()); + for (JsonNode entry : catalogArray) { + if (testContractPolicyConstraints(entry)) { + targetCatalogEntry = entry; + break; } } + } else { + targetCatalogEntry = catalogArray.get(0); } + if (targetCatalogEntry == null) { log.error("Could not find asset for " + type + " Submodel at partner " + partner.getBpnl() + "'s catalog"); log.warn("CATALOG CONTENT \n" + catalogArray.toPrettyString()); @@ -847,8 +933,8 @@ private boolean negotiateForSubmodel(MaterialPartnerRelation mpr, SubmodelType t for (int i = 0; i < 100; i++) { Thread.sleep(100); var responseObject = getNegotiationState(negotiationId); - if ("FINALIZED".equals(responseObject.get("edc:state").asText())) { - contractId = responseObject.get("edc:contractAgreementId").asText(); + if ("FINALIZED".equals(responseObject.get("state").asText())) { + contractId = responseObject.get("contractAgreementId").asText(); break; } } @@ -879,7 +965,7 @@ private boolean negotiateForSubmodel(MaterialPartnerRelation mpr, SubmodelType t * @return the partner's CXid for that material */ public String getCxIdFromPartTypeInformation(MaterialPartnerRelation mpr) { - var data = getSubmodelFromPartner(mpr, SubmodelType.PART_TYPE_INFORMATION, null, 1); + var data = getSubmodelFromPartner(mpr, SubmodelType.PART_TYPE_INFORMATION, null, 1); return data.get("catenaXId").asText(); } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EndpointDataReferenceService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EndpointDataReferenceService.java index ff74ed94..f3ac2a99 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EndpointDataReferenceService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EndpointDataReferenceService.java @@ -21,8 +21,8 @@ package org.eclipse.tractusx.puris.backend.common.edc.logic.service; import lombok.extern.slf4j.Slf4j; -import org.eclipse.tractusx.puris.backend.common.util.VariablesService; import org.eclipse.tractusx.puris.backend.common.edc.logic.dto.EdrDto; +import org.eclipse.tractusx.puris.backend.common.util.VariablesService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -30,19 +30,20 @@ import java.util.concurrent.ExecutorService; /** - * This class stores authCodes which are generated in the course of + * This class stores authCodes which are generated in the course of * the contracting for the request or response api. Since authCodes - * expire after a very short period, all stored items will be deleted - * after a number of minutes specified in the parameter own.authcodes.deletiontimer. + * expire after a very short period, all stored items will be deleted + * after a number of minutes specified in the parameter own.authcodes.deletiontimer. */ @Service @Slf4j public class EndpointDataReferenceService { - /** AuthCodes expire after a very short period and the data is quite voluminous, - * therefore it's not really useful to persist them in the database. - * The key is the transferId, the value is the authCode - */ + /** + * AuthCodes expire after a very short period and the data is quite voluminous, + * therefore it's not really useful to persist them in the database. + * The key is the transferId, the value is the authCode + */ final private HashMap nonpersistantRepository = new HashMap<>(); @Autowired private VariablesService variablesService; @@ -50,17 +51,18 @@ public class EndpointDataReferenceService { private ExecutorService executorService; /** - * Stores transferId and authCode as a key/value-pair. + * Stores transferId and authCode as a key/value-pair. * Please note that any data will only be stored for a period of 5 - * minutes. - * @param transferId - * @param edr_Dto + * minutes. + * + * @param transferId to store the edr associated to + * @param edr_Dto to store providing the access */ public void save(String transferId, EdrDto edr_Dto) { nonpersistantRepository.put(transferId, edr_Dto); final long timer = variablesService.getEdrTokenDeletionTimer() * 60 * 1000; // Start timer for deletion - executorService.submit(()-> { + executorService.submit(() -> { try { Thread.sleep(timer); } catch (InterruptedException e) { @@ -72,12 +74,11 @@ public void save(String transferId, EdrDto edr_Dto) { } /** - * * @param transferId The key under which the Dto is supposed to be stored * @return the Dto or null, if there is no authCode recorded under the given parameter */ public EdrDto findByTransferId(String transferId) { return nonpersistantRepository.get(transferId); } - + } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java index b516d6b6..63b3450f 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java @@ -23,15 +23,17 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; - import lombok.extern.slf4j.Slf4j; - +import org.eclipse.tractusx.puris.backend.common.edc.logic.dto.PolicyConstraintDto; import org.eclipse.tractusx.puris.backend.common.util.VariablesService; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -45,13 +47,14 @@ public class EdcRequestBodyBuilder { private VariablesService variablesService; @Autowired private ObjectMapper MAPPER; - private final String EDC_NAMESPACE = "https://w3id.org/edc/v0.0.1/ns/"; - private final String VOCAB_KEY = "@vocab"; - private final String ODRL_NAMESPACE = "http://www.w3.org/ns/odrl/2/"; - private final String CX_TAXO_NAMESPACE = "https://w3id.org/catenax/taxonomy#"; - private final String CX_COMMON_NAMESPACE = "https://w3id.org/catenax/ontology/common#"; - private final String DCT_NAMESPACE = "https://purl.org/dc/terms/"; - private final String CONTRACT_POLICY_ID = "Contract_Policy"; + public static final String EDC_NAMESPACE = "https://w3id.org/edc/v0.0.1/ns/"; + public static final String VOCAB_KEY = "@vocab"; + public static final String ODRL_NAMESPACE = "http://www.w3.org/ns/odrl/2/"; + public static final String CX_TAXO_NAMESPACE = "https://w3id.org/catenax/taxonomy#"; + public static final String CX_COMMON_NAMESPACE = "https://w3id.org/catenax/ontology/common#"; + public static final String DCT_NAMESPACE = "https://purl.org/dc/terms/"; + public static final String AAS_SEMANTICS_NAMESPACE = "https://admin-shell.io/aas/3/0/HasSemantics/"; + public static final String CONTRACT_POLICY_ID = "Contract_Policy"; /** * Creates a request body for requesting a catalog in DSP protocol. @@ -60,50 +63,55 @@ public class EdcRequestBodyBuilder { * for the filter criteria programmatically. * * @param counterPartyDspUrl The protocol url of the other party + * @param counterPartyBpnl The bpnl of the other party * @param filter Key-value-pairs, may be empty or null * @return The request body */ - public ObjectNode buildBasicCatalogRequestBody(String counterPartyDspUrl, Map filter) { + public ObjectNode buildBasicCatalogRequestBody(String counterPartyDspUrl, String counterPartyBpnl, Map filter) { var objectNode = getEdcContextObject(); objectNode.put("protocol", "dataspace-protocol-http"); objectNode.put("@type", "CatalogRequest"); objectNode.put("counterPartyAddress", counterPartyDspUrl); + objectNode.put("counterPartyId", counterPartyBpnl); if (filter != null && !filter.isEmpty()) { - var querySpecNode = MAPPER.createObjectNode(); - objectNode.set("querySpec", querySpecNode); + ObjectNode querySpecObject = MAPPER.createObjectNode(); + ArrayNode filterExpressionsArray = MAPPER.createArrayNode(); + querySpecObject.set("filterExpression", filterExpressionsArray); for (var entry : filter.entrySet()) { - querySpecNode.put(entry.getKey(), entry.getValue()); + ObjectNode filterExpressionObject = MAPPER.createObjectNode(); + filterExpressionObject.put("operandLeft", entry.getKey()); + filterExpressionObject.put("operator", "="); + filterExpressionObject.put("operandRight", entry.getValue()); + filterExpressionsArray.add(filterExpressionObject); } + objectNode.set("querySpec", querySpecObject); } + log.debug("Built Catalog Request: \n" + objectNode.toPrettyString()); return objectNode; } - /** - * Creates a request body that demands all of the following conditions: - * 1. The BPNL of the requesting connector is equal to the BPNL of the partner - * 2. There's a valid CX membership credential present - * - * @param partner the partner to create the policy for - * @return the request body as a {@link JsonNode} - */ - public JsonNode buildBpnAndMembershipRestrictedPolicy(Partner partner) { + private JsonNode buildPolicy(String policyId, List constraints) { var body = MAPPER.createObjectNode(); var context = MAPPER.createObjectNode(); context.put("odrl", ODRL_NAMESPACE); body.set("@context", context); body.put("@type", "PolicyDefinitionRequestDto"); - body.put("@id", getBpnPolicyId(partner)); + body.put("@id", policyId); var policy = MAPPER.createObjectNode(); body.set("policy", policy); - policy.put("@type", "Policy"); + policy.put("@type", "odrl:Set"); + + // TODO profile etc. var permissionsArray = MAPPER.createArrayNode(); policy.set("odrl:permission", permissionsArray); var permissionsObject = MAPPER.createObjectNode(); permissionsArray.add(permissionsObject); - permissionsObject.put("odrl:action", "USE"); + var useActionObject = MAPPER.createObjectNode(); + useActionObject.put("@id", "odrl:use"); + permissionsObject.set("odrl:action", useActionObject); var constraintObject = MAPPER.createObjectNode(); permissionsObject.set("odrl:constraint", constraintObject); @@ -112,29 +120,50 @@ public JsonNode buildBpnAndMembershipRestrictedPolicy(Partner partner) { var andArray = MAPPER.createArrayNode(); constraintObject.set("odrl:and", andArray); - var bpnlpConstraint = MAPPER.createObjectNode(); - andArray.add(bpnlpConstraint); - bpnlpConstraint.put("@type", "Constraint"); - bpnlpConstraint.put("odrl:leftOperand", "BusinessPartnerNumber"); + for (PolicyConstraintDto policyConstraintDto : constraints) { + ObjectNode constraint = MAPPER.createObjectNode(); + constraint.put("@type", "LogicalConstraint"); + constraint.put("odrl:leftOperand", policyConstraintDto.getLeftOperand()); - var bpnlOperator = MAPPER.createObjectNode(); - bpnlpConstraint.set("odrl:operator", bpnlOperator); - bpnlOperator.put("@id", "odrl:eq"); + ObjectNode operatorObject = MAPPER.createObjectNode(); + operatorObject.put("@id", policyConstraintDto.getOperator()); + constraint.set("odrl:operator", operatorObject); - bpnlpConstraint.put("odrl:rightOperand", partner.getBpnl()); + constraint.put("odrl:rightOperand", policyConstraintDto.getRightOperand()); + andArray.add(constraint); + } - var membershipConstraint = MAPPER.createObjectNode(); - andArray.add(membershipConstraint); - membershipConstraint.put("@type", "Constraint"); - membershipConstraint.put("odrl:leftOperand", "Membership"); + return body; + } - var membershipOperator = MAPPER.createObjectNode(); - membershipConstraint.set("odrl:operator", membershipOperator); - membershipOperator.put("@id", "odrl:eq"); + /** + * Creates a request body that demands all of the following conditions: + * 1. The BPNL of the requesting connector is equal to the BPNL of the partner + * 2. There's a valid CX membership credential present + * + * @param partner the partner to create the policy for + * @return the request body as a {@link JsonNode} + */ + public JsonNode buildBpnAndMembershipRestrictedPolicy(Partner partner) { - membershipConstraint.put("odrl:rightOperand", "active"); + List constraints = new ArrayList<>(); - return body; + constraints.add(new PolicyConstraintDto( + "BusinessPartnerNumber", + "odrl:eq", + partner.getBpnl() + )); + + constraints.add(new PolicyConstraintDto( + "Membership", + "odrl:eq", + "active" + )); + + return buildPolicy( + getBpnPolicyId(partner), + constraints + ); } /** @@ -144,35 +173,20 @@ public JsonNode buildBpnAndMembershipRestrictedPolicy(Partner partner) { * @return the request body */ public JsonNode buildFrameworkPolicy() { - var body = MAPPER.createObjectNode(); - var context = MAPPER.createObjectNode(); - context.put("odrl", ODRL_NAMESPACE); - body.set("@context", context); - body.put("@type", "PolicyDefinitionRequestDto"); - body.put("@id", CONTRACT_POLICY_ID); - - var policy = MAPPER.createObjectNode(); - body.set("policy", policy); - policy.put("@type", "Policy"); - - var permissionsArray = MAPPER.createArrayNode(); - policy.set("odrl:permission", permissionsArray); - - var permissionObject = MAPPER.createObjectNode(); - permissionsArray.add(permissionObject); - permissionObject.put("odrl:action", "USE"); - var constraintObject = MAPPER.createObjectNode(); - permissionObject.set("odrl:constraint", constraintObject); - constraintObject.put("@type", "LogicalConstraint"); - constraintObject.put("odrl:leftOperand", variablesService.getPurisFrameworkAgreement()); + List constraints = new ArrayList<>(); - var operatorObject = MAPPER.createObjectNode(); - constraintObject.set("odrl:operator", operatorObject); - operatorObject.put("@id", "odrl:eq"); - constraintObject.put("odrl:rightOperand", "active"); + // TODO add version and migrate to new version + constraints.add(new PolicyConstraintDto( + variablesService.getPurisFrameworkAgreement(), + "odrl:eq", + "active" + )); - return body; + return buildPolicy( + CONTRACT_POLICY_ID, + constraints + ); } public JsonNode buildSubmodelContractDefinitionWithBpnRestrictedPolicy(String assetId, Partner partner) { @@ -191,7 +205,7 @@ public JsonNode buildSubmodelContractDefinitionWithBpnRestrictedPolicy(String as public JsonNode buildDtrContractDefinitionForPartner(Partner partner) { var body = getEdcContextObject(); - body.put("@id", partner.getBpnl() +"_contractdefinition_for_dtr"); + body.put("@id", partner.getBpnl() + "_contractdefinition_for_dtr"); body.put("accessPolicyId", getBpnPolicyId(partner)); body.put("contractPolicyId", getBpnPolicyId(partner)); var assetsSelector = MAPPER.createObjectNode(); @@ -205,7 +219,7 @@ public JsonNode buildDtrContractDefinitionForPartner(Partner partner) { public JsonNode buildPartTypeInfoContractDefinitionForPartner(Partner partner) { var body = getEdcContextObject(); - body.put("@id", partner.getBpnl() +"_contractdefinition_for_PartTypeInfoAsset"); + body.put("@id", partner.getBpnl() + "_contractdefinition_for_PartTypeInfoAsset"); body.put("accessPolicyId", getBpnPolicyId(partner)); body.put("contractPolicyId", CONTRACT_POLICY_ID); var assetsSelector = MAPPER.createObjectNode(); @@ -238,25 +252,35 @@ private String getBpnPolicyId(Partner partner) { * @return The request body */ public JsonNode buildAssetNegotiationBody(Partner partner, JsonNode dcatCatalogItem) { - var body = MAPPER.createObjectNode(); - var contextNode = MAPPER.createObjectNode(); + ObjectNode body = MAPPER.createObjectNode(); + ObjectNode contextNode = MAPPER.createObjectNode(); contextNode.put(VOCAB_KEY, EDC_NAMESPACE); contextNode.put("odrl", ODRL_NAMESPACE); body.set("@context", contextNode); - body.put("@type", "NegotiationInitiateRequestDto"); - body.put("connectorId", partner.getBpnl()); - body.put("connectorAddress", partner.getEdcUrl()); - body.put("consumerId", variablesService.getOwnBpnl()); - body.put("providerId", partner.getBpnl()); + body.put("@type", "ContractRequest"); + body.put("counterPartyAddress", partner.getEdcUrl()); // TODO this might result in a bug body.put("protocol", "dataspace-protocol-http"); + + // extract policy and information from offer + // framework agreement and co has been checked during catalog request String assetId = dcatCatalogItem.get("@id").asText(); var policyNode = dcatCatalogItem.get("odrl:hasPolicy"); + + ObjectNode targetIdObject = MAPPER.createObjectNode(); + targetIdObject.put("@id", assetId); + ((ObjectNode) policyNode).put("@context", "http://www.w3.org/ns/odrl.jsonld"); + ((ObjectNode) policyNode).set("odrl:target", targetIdObject); + ((ObjectNode) policyNode).put("assigner", partner.getBpnl()); + var offerNode = MAPPER.createObjectNode(); String offerId = policyNode.get("@id").asText(); offerNode.put("offerId", offerId); offerNode.put("assetId", assetId); offerNode.set("policy", policyNode); - body.set("offer", offerNode); + //TODO + body.set("policy", policyNode); + + log.debug("Created asset negotiation body:\n" + body.toPrettyString()); return body; } @@ -271,21 +295,24 @@ public JsonNode buildAssetNegotiationBody(Partner partner, JsonNode dcatCatalogI */ public JsonNode buildProxyPullRequestBody(Partner partner, String contractID, String assetId, String partnerEdcUrl) { var body = getEdcContextObject(); - body.put("@type", "TransferRequestDto"); body.put("connectorId", partner.getBpnl()); - body.put("connectorAddress", partnerEdcUrl); + body.put("counterPartyAddress", partnerEdcUrl); body.put("contractId", contractID); body.put("assetId", assetId); body.put("protocol", "dataspace-protocol-http"); body.put("managedResources", false); + body.put("transferType", "HttpData-PULL"); var dataDestination = MAPPER.createObjectNode(); dataDestination.put("type", "HttpProxy"); body.set("dataDestination", dataDestination); + // TODO replace by callbackAddress or use EDR api var privateProperties = MAPPER.createObjectNode(); privateProperties.put("receiverHttpEndpoint", variablesService.getEdrEndpoint()); body.set("privateProperties", privateProperties); + + log.debug("Built Proxy Pull Request:\n{}", body.toPrettyString()); return body; } @@ -413,6 +440,7 @@ private ObjectNode getAssetRegistrationContext() { context.put("cx-taxo", CX_TAXO_NAMESPACE); context.put("cx-common", CX_COMMON_NAMESPACE); context.put("dct", DCT_NAMESPACE); + context.put("aas-semantics", AAS_SEMANTICS_NAMESPACE); body.set("@context", context); body.put("@type", "Asset"); return body; From 857587347ac864ce40b2f3a077cebf21bf84e0de Mon Sep 17 00:00:00 2001 From: --show-origin Date: Mon, 6 May 2024 23:46:49 -0700 Subject: [PATCH 03/21] feat(EdcAdapterService): terminate transfers --- .../edc/logic/service/EdcAdapterService.java | 242 +++++++++++------- .../edc/logic/util/EdcRequestBodyBuilder.java | 15 ++ 2 files changed, 164 insertions(+), 93 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index 1017caa7..96278611 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -114,8 +114,8 @@ public Response sendGetRequest(List pathSegments) throws IOException { * Any caller of this method has the responsibility to close * the returned Response object after using it. * - * @param requestBody The request body - * @param pathSegments The path se&gments + * @param requestBody The request body; null if no body is needed + * @param pathSegments The path segments * @return The response from your control plane * @throws IOException If the connection to your control plane fails */ @@ -124,7 +124,11 @@ private Response sendPostRequest(JsonNode requestBody, List pathSegments for (var pathSegment : pathSegments) { urlBuilder.addPathSegment(pathSegment); } - RequestBody body = RequestBody.create(requestBody.toString(), MediaType.parse("application/json")); + RequestBody body = null; + + if (requestBody != null) { + body = RequestBody.create(requestBody.toString(), MediaType.parse("application/json")); + } var request = new Request.Builder() .post(body) @@ -132,6 +136,7 @@ private Response sendPostRequest(JsonNode requestBody, List pathSegments .header("X-Api-Key", variablesService.getEdcApiKey()) .header("Content-Type", "application/json") .build(); + return CLIENT.newCall(request).execute(); } @@ -336,7 +341,6 @@ private boolean registerSubmodelAsset(String assetId, String endpoint, String se * @return The response containing the full catalog, if successful */ public Response getCatalogResponse(String dspUrl, String partnerBpnl, Map filter) throws IOException { - // TODO check if we need the method here return sendPostRequest(edcRequestBodyBuilder.buildBasicCatalogRequestBody(dspUrl, partnerBpnl, filter), List.of("v2", "catalog", "request")); } @@ -551,37 +555,44 @@ private JsonNode getSubmodelFromPartner(MaterialPartnerRelation mpr, SubmodelTyp var transferResp = initiateProxyPullTransfer(partner, submodelContractId, assetId, partnerDspUrl); log.debug("Transfer Request {}", transferResp.toPrettyString()); String transferId = transferResp.get("@id").asText(); - for (int i = 0; i < 100; i++) { - Thread.sleep(100); - transferResp = getTransferState(transferId); - if ("STARTED".equals(transferResp.get("state").asText())) { - break; + // try proxy pull and terminate request + try { + for (int i = 0; i < 100; i++) { + Thread.sleep(100); + transferResp = getTransferState(transferId); + if ("STARTED".equals(transferResp.get("state").asText())) { + break; + } } - } - EdrDto edrDto = null; - // Await arrival of edr - for (int i = 0; i < 100; i++) { - Thread.sleep(100); - edrDto = getEdrForTransferProcessId(transferId); //edrService.findByTransferId(transferId); - if (edrDto != null) { - log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); - break; + EdrDto edrDto = null; + // Await arrival of edr + for (int i = 0; i < 100; i++) { + Thread.sleep(100); + edrDto = getEdrForTransferProcessId(transferId); //edrService.findByTransferId(transferId); + if (edrDto != null) { + log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); + break; + } } - } - if (edrDto == null) { - log.error("Failed to obtain EDR data for " + assetId + " with " + partner.getEdcUrl()); - return doSubmodelRequest(type, mpr, direction, --retries); - } - if (!submodelData.href().startsWith(edrDto.endpoint())) { - log.warn("Diverging URLs in ItemStock Submodel request"); - log.warn("href: " + submodelData.href()); - log.warn("Data plane base URL from EDR: " + edrDto.endpoint()); - } - try (var response = getProxyPullRequest(submodelData.href, edrDto.authKey(), edrDto.authCode(), new String[]{type.REPRESENTATION})) { - if (response.isSuccessful()) { - String responseString = response.body().string(); - failed = false; - return objectMapper.readTree(responseString); + if (edrDto == null) { + log.error("Failed to obtain EDR data for " + assetId + " with " + partner.getEdcUrl()); + return doSubmodelRequest(type, mpr, direction, --retries); + } + if (!submodelData.href().startsWith(edrDto.endpoint())) { + log.warn("Diverging URLs in ItemStock Submodel request"); + log.warn("href: " + submodelData.href()); + log.warn("Data plane base URL from EDR: " + edrDto.endpoint()); + } + try (var response = getProxyPullRequest(submodelData.href, edrDto.authKey(), edrDto.authCode(), new String[]{type.REPRESENTATION})) { + if (response.isSuccessful()) { + String responseString = response.body().string(); + failed = false; + return objectMapper.readTree(responseString); + } + } + } finally { + if (transferId != null) { + terminateTransfer(transferId); } } } catch (Exception e) { @@ -712,6 +723,17 @@ private SubmodelData fetchSubmodelData(MaterialPartnerRelation mpr, String seman return null; } + /** + * quries the dtr of a pratner for the given mpr / material and returns submodel descriptors + *

+ * Method assumes that the query at dtr only finds one shell (else take first entry) + * + * @param manufacturerPartId material number of the supplier party + * @param manufacturerId bpnl of the supplier party + * @param mpr containing the mapping between material and partner to lookup at dtr + * @param retries number of times to retry in case the shell could not (yet) been found + * @return array of submodelDescriptors of the found shell + */ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String manufacturerId, MaterialPartnerRelation mpr, int retries) { if (retries < 0) { log.error("AasSubmodelDescriptors Request failed for " + manufacturerPartId + " and " + manufacturerId); @@ -733,68 +755,74 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man } var transferResp = initiateProxyPullTransfer(partner, contractId, assetId); String transferId = transferResp.get("@id").asText(); - for (int i = 0; i < 100; i++) { - Thread.sleep(100); - transferResp = getTransferState(transferId); - if ("STARTED".equals(transferResp.get("state").asText())) { - break; + try { + for (int i = 0; i < 100; i++) { + Thread.sleep(100); + transferResp = getTransferState(transferId); + if ("STARTED".equals(transferResp.get("state").asText())) { + break; + } } - } - EdrDto edrDto = null; - // Await arrival of edr - for (int i = 0; i < 100; i++) { - // TODO use external EDR Service provided by EDC - edrDto = getEdrForTransferProcessId(transferId);//edrService.findByTransferId(transferId); - if (edrDto != null) { - log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); - break; + EdrDto edrDto = null; + // Await arrival of edr + for (int i = 0; i < 100; i++) { + edrDto = getEdrForTransferProcessId(transferId);//edrService.findByTransferId(transferId); + if (edrDto != null) { + log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); + break; + } + Thread.sleep(100); } - Thread.sleep(100); - } - if (edrDto == null) { - log.error("Failed to obtain EDR data for " + assetId + " with " + partner.getEdcUrl()); - return getAasSubmodelDescriptors(manufacturerPartId, manufacturerId, mpr, --retries); - } - HttpUrl.Builder urlBuilder = HttpUrl.parse(edrDto.endpoint()).newBuilder() - .addPathSegment("api") - .addPathSegment("v3.0") - .addPathSegment("lookup") - .addPathSegment("shells"); - String query = "{\"name\":\"manufacturerPartId\",\"value\":\"" + manufacturerPartId + "\"}"; - query += ",{\"name\":\"digitalTwinType\",\"value\":\"PartType\"}"; - query += ",{\"name\":\"manufacturerId\",\"value\":\"" + manufacturerId + "\"}"; - urlBuilder.addQueryParameter("assetIds", Base64.getEncoder().encodeToString(query.getBytes(StandardCharsets.UTF_8))); - var request = new Request.Builder() - .get() - .header(edrDto.authKey(), edrDto.authCode()) - .url(urlBuilder.build()) - .build(); - try (var response = CLIENT.newCall(request).execute()) { - var bodyString = response.body().string(); - var jsonResponse = objectMapper.readTree(bodyString); - var resultArray = jsonResponse.get("result"); - if (resultArray.isArray()) { - String aasId = resultArray.get(0).asText(); - urlBuilder = HttpUrl.parse(edrDto.endpoint()).newBuilder() - .addPathSegment("api") - .addPathSegment("v3.0") - .addPathSegment("shell-descriptors"); - String base64AasId = Base64.getEncoder().encodeToString(aasId.getBytes(StandardCharsets.UTF_8)); - urlBuilder.addQueryParameter("aasIdentifier", base64AasId); - request = new Request.Builder() - .get() - .header(edrDto.authKey(), edrDto.authCode()) - .url(urlBuilder.build()) - .build(); - try (var response2 = CLIENT.newCall(request).execute()) { - var body2String = response2.body().string(); - var aasJson = objectMapper.readTree(body2String); - var resultObject = aasJson.get("result").get(0); - var submodelDescriptors = resultObject.get("submodelDescriptors"); - failed = false; - return submodelDescriptors; + if (edrDto == null) { + log.error("Failed to obtain EDR data for " + assetId + " with " + partner.getEdcUrl()); + return getAasSubmodelDescriptors(manufacturerPartId, manufacturerId, mpr, --retries); + } + HttpUrl.Builder urlBuilder = HttpUrl.parse(edrDto.endpoint()).newBuilder() + .addPathSegment("api") + .addPathSegment("v3.0") + .addPathSegment("lookup") + .addPathSegment("shells"); + String query = "{\"name\":\"manufacturerPartId\",\"value\":\"" + manufacturerPartId + "\"}"; + query += ",{\"name\":\"digitalTwinType\",\"value\":\"PartType\"}"; + query += ",{\"name\":\"manufacturerId\",\"value\":\"" + manufacturerId + "\"}"; + urlBuilder.addQueryParameter("assetIds", Base64.getEncoder().encodeToString(query.getBytes(StandardCharsets.UTF_8))); + var request = new Request.Builder() + .get() + .header(edrDto.authKey(), edrDto.authCode()) + .url(urlBuilder.build()) + .build(); + try (var response = CLIENT.newCall(request).execute()) { + var bodyString = response.body().string(); + var jsonResponse = objectMapper.readTree(bodyString); + var resultArray = jsonResponse.get("result"); + if (resultArray.isArray()) { + String aasId = resultArray.get(0).asText(); + urlBuilder = HttpUrl.parse(edrDto.endpoint()).newBuilder() + .addPathSegment("api") + .addPathSegment("v3.0") + .addPathSegment("shell-descriptors"); + String base64AasId = Base64.getEncoder().encodeToString(aasId.getBytes(StandardCharsets.UTF_8)); + urlBuilder.addQueryParameter("aasIdentifier", base64AasId); + request = new Request.Builder() + .get() + .header(edrDto.authKey(), edrDto.authCode()) + .url(urlBuilder.build()) + .build(); + try (var response2 = CLIENT.newCall(request).execute()) { + var body2String = response2.body().string(); + var aasJson = objectMapper.readTree(body2String); + var resultObject = aasJson.get("result").get(0); + var submodelDescriptors = resultObject.get("submodelDescriptors"); + failed = false; + return submodelDescriptors; + } } } + + } finally { + if (transferId != null) { + terminateTransfer(transferId); + } } } catch (Exception e) { log.error("Error in AasSubmodelDescriptor Request for " + mpr + " and manufacturerPartId " + manufacturerPartId, e); @@ -845,7 +873,6 @@ private EdrDto getEdrForTransferProcessId(String transferProcessId) { ) { ObjectNode responseObject = (ObjectNode) objectMapper.readTree(response.body().string()); - // TODO pattern check dataPlaneEndpoint String dataPlaneEndpoint = responseObject.get("endpoint").asText(); String authToken = responseObject.get("authorization").asText(); @@ -868,6 +895,36 @@ private EdrDto getEdrForTransferProcessId(String transferProcessId) { return null; } + /** + * terminate the transfer with reason "Transfer done." + *

+ * Edr in {@link EndpointDataReferenceService} is not removed because it is removed automatically by a job after + * time period x. + * + * @param transferProcessId to terminate + */ + private void terminateTransfer(String transferProcessId) { + + JsonNode body = edcRequestBodyBuilder.buildTransferProcessTerminationBody("Transfer done."); + + try (Response response = sendPostRequest(body, List.of("v2", "transferprocesses", transferProcessId, "terminate"))) { + + JsonNode resultNode = objectMapper.readTree(response.body().string()); + if (!response.isSuccessful()) { + log.error( + "Transfer process with id {} could not be termianted; status code {}, reason: {}", + transferProcessId, + response.code(), + resultNode.get("message").asText("MESSAGE NOT FOUND") + ); + } else { + log.info("Terminated transfer process with id {}.", transferProcessId); + } + } catch (IOException e) { + log.error("Error while trying to terminate transfer: {}", e); + } + } + /** * Tries to negotiate for a partner's Submodel API.

* If successful, the contractId as well as the assetId @@ -892,7 +949,6 @@ private boolean negotiateForSubmodel(MaterialPartnerRelation mpr, SubmodelType t case PART_TYPE_INFORMATION -> fetchPartTypeSubmodelData(mpr); }; try { - // TODO: why is semantics not expanded? Map equalFilters = new HashMap<>(); equalFilters.put(EdcRequestBodyBuilder.CX_COMMON_NAMESPACE + "version", "3.0"); equalFilters.put( diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java index 63b3450f..c2c34f19 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java @@ -462,4 +462,19 @@ private ObjectNode getEdcContextObject() { } + /** + * builds a body to terminate the transfer process + * + * @param reason why transfer is terminated + * @return transfer process termination request body + */ + public JsonNode buildTransferProcessTerminationBody(String reason) { + + ObjectNode body = getEdcContextObject(); + + body.put("@type", "TerminateTransfer"); + body.put("reason", reason); + + return body; + } } From 411435cce46b37fa77144eaf9f56dc838ccfe7ee Mon Sep 17 00:00:00 2001 From: --show-origin Date: Tue, 7 May 2024 05:00:45 -0700 Subject: [PATCH 04/21] feat: updated edc request and frontend to edc 0.7.0 --- .../common/edc/controller/EdcController.java | 15 ++- .../edc/logic/service/EdcAdapterService.java | 6 +- frontend/.env | 2 +- frontend/.env.dockerbuild | 2 +- frontend/src/config.json | 6 +- .../src/features/edc/hooks/usePartners.ts | 34 +++++++ .../src/features/stock-view/hooks/useSites.ts | 12 ++- frontend/src/hooks/edc/useCatalog.ts | 33 ++++--- frontend/src/models/constants/config.ts | 2 +- frontend/src/models/types/edc/catalog.ts | 30 +++--- frontend/src/models/types/edc/negotiation.ts | 14 +-- frontend/src/models/types/edc/transfer.ts | 16 ++-- frontend/src/views/CatalogView.tsx | 96 ++++++++++++------- frontend/src/views/NegotiationView.tsx | 27 +++--- frontend/src/views/TransferView.tsx | 29 +++--- local/docker-compose.yaml | 8 +- 16 files changed, 199 insertions(+), 133 deletions(-) create mode 100644 frontend/src/features/edc/hooks/usePartners.ts diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EdcController.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EdcController.java index 948b8809..0d929c0e 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EdcController.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EdcController.java @@ -59,17 +59,16 @@ public class EdcController { /** * Get the catalog from an EDC. * - * @param dspUrl url of the edc to get catalog from. + * @param dspUrl url of the edc to get catalog from. + * @param partnerBpnl bpnl of the partner to get the catalog from. * @return catalog of the requested edc. */ @GetMapping(CATALOG) - public ResponseEntity getCatalog(@RequestParam String dspUrl) { + public ResponseEntity getCatalog(@RequestParam String dspUrl, @RequestParam String partnerBpnl) { try { if (!PatternStore.URL_PATTERN.matcher(dspUrl).matches()) { return ResponseEntity.badRequest().build(); } - // TODO implement bpnl resolver or update frontend to use bpnl / partner - String partnerBpnl = "not yet implemented"; var catalogResponse = edcAdapter.getCatalogResponse(dspUrl, partnerBpnl, null); if (catalogResponse != null && catalogResponse.isSuccessful()) { var responseString = catalogResponse.body().string(); @@ -177,12 +176,12 @@ public ResponseEntity getTransfers() { // in a transfer. Because we want to show the other party's // BPNL in the frontend in any case, we retrieve the BPNL via // the contractAgreement and insert it into the JSON data. - String myRole = item.get("edc:type").asText(); + String myRole = item.get("type").asText(); if ("PROVIDER".equals(myRole)) { - String contractId = item.get("edc:contractId").asText(); + String contractId = item.get("contractId").asText(); var contractObject = objectMapper.readTree(edcAdapter.getContractAgreement(contractId)); - String partnerBpnl = contractObject.get("edc:consumerId").asText(); - ((ObjectNode) item).put("edc:connectorId", partnerBpnl); + String partnerBpnl = contractObject.get("consumerId").asText(); + ((ObjectNode) item).put("connectorId", partnerBpnl); } } return ResponseEntity.ok(responseObject); diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index 96278611..eaaea3de 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -356,8 +356,9 @@ public Response getCatalogResponse(String dspUrl, String partnerBpnl, Map filter) throws IOException { // TODO: use partner to get the catalog try (var response = getCatalogResponse(dspUrl, partnerBpnl, filter)) { - String stringData = response.body().string(); - return objectMapper.readTree(stringData); + JsonNode responseNode = objectMapper.readTree(response.body().string()); + log.debug("Got Catalog response {}", responseNode.toPrettyString()); + return responseNode; } } @@ -457,6 +458,7 @@ public JsonNode getTransferState(String transferId) throws IOException { */ public Response getAllTransfers() throws IOException { var requestBody = edcRequestBodyBuilder.buildTransfersRequestBody(); + log.debug("GetAllTransfers Request: {}", requestBody.toPrettyString()); return sendPostRequest(requestBody, List.of("v2", "transferprocesses", "request")); } diff --git a/frontend/.env b/frontend/.env index ea5ee400..87f55c5a 100644 --- a/frontend/.env +++ b/frontend/.env @@ -12,7 +12,7 @@ VITE_ENDPOINT_REPORTED_MATERIAL_STOCKS=stockView/reported-material-stocks?ownMat VITE_ENDPOINT_REPORTED_PRODUCT_STOCKS=stockView/reported-product-stocks?ownMaterialNumber= VITE_ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS=stockView/update-reported-material-stocks?ownMaterialNumber= VITE_ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS=stockView/update-reported-product-stocks?ownMaterialNumber= -VITE_ENDPOINT_PARTNER_OWNSITES=partners/ownSites +VITE_ENDPOINT_PARTNER=partners VITE_ENDPOINT_DEMAND=demand VITE_ENDPOINT_PRODUCTION=production VITE_ENDPOINT_PRODUCTION_RANGE=production/range diff --git a/frontend/.env.dockerbuild b/frontend/.env.dockerbuild index 77bcbb7d..c6bb2f8a 100644 --- a/frontend/.env.dockerbuild +++ b/frontend/.env.dockerbuild @@ -11,7 +11,7 @@ VITE_ENDPOINT_REPORTED_MATERIAL_STOCKS=\$ENDPOINT_REPORTED_MATERIAL_STOCKS VITE_ENDPOINT_REPORTED_PRODUCT_STOCKS=\$ENDPOINT_REPORTED_PRODUCT_STOCKS VITE_ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS=\$ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS VITE_ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS=\$ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS -VITE_ENDPOINT_PARTNER_OWNSITES=\$ENDPOINT_PARTNER_OWNSITES +VITE_ENDPOINT_PARTNER=\$ENDPOINT_PARTNER VITE_ENDPOINT_DEMAND=\$ENDPOINT_DEMAND VITE_ENDPOINT_PRODUCTION=\$ENDPOINT_PRODUCTION VITE_ENDPOINT_PRODUCTION_RANGE=\$ENDPOINT_PRODUCTION_RANGE diff --git a/frontend/src/config.json b/frontend/src/config.json index 3b765b5b..f0e6a6e4 100644 --- a/frontend/src/config.json +++ b/frontend/src/config.json @@ -10,9 +10,9 @@ "ENDPOINT_SUPPLIER": "$ENDPOINT_SUPPLIER", "ENDPOINT_REPORTED_MATERIAL_STOCKS": "$ENDPOINT_REPORTED_MATERIAL_STOCKS", "ENDPOINT_REPORTED_PRODUCT_STOCKS": "$ENDPOINT_REPORTED_PRODUCT_STOCKS", - "ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS":"$ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS", - "ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS":"$ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS", - "ENDPOINT_PARTNER_OWNSITES": "$ENDPOINT_PARTNER_OWNSITES", + "ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS": "$ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS", + "ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS": "$ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS", + "ENDPOINT_PARTNER": "$ENDPOINT_PARTNER", "IDP_DISABLE": "$IDP_DISABLE", "IDP_URL": "$IDP_URL", "IDP_REALM": "$IDP_REALM", diff --git a/frontend/src/features/edc/hooks/usePartners.ts b/frontend/src/features/edc/hooks/usePartners.ts new file mode 100644 index 00000000..34cee21c --- /dev/null +++ b/frontend/src/features/edc/hooks/usePartners.ts @@ -0,0 +1,34 @@ +/* +Copyright (c) 2024 Volkswagen AG +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 +*/ + +import {useFetch} from '@hooks/useFetch'; +import {config} from '@models/constants/config'; +import {Partner} from '@models/types/edc/partner'; + +export const usePartners = () => { + const endpoint = config.app.ENDPOINT_PARTNER + "/all"; + const {data: partners, isLoading: isLoadingPartners} = useFetch( + `${config.app.BACKEND_BASE_URL}${endpoint}` + ); + return { + partners, + isLoadingPartners, + }; +} diff --git a/frontend/src/features/stock-view/hooks/useSites.ts b/frontend/src/features/stock-view/hooks/useSites.ts index 1369c559..66ecb30c 100644 --- a/frontend/src/features/stock-view/hooks/useSites.ts +++ b/frontend/src/features/stock-view/hooks/useSites.ts @@ -18,12 +18,16 @@ under the License. SPDX-License-Identifier: Apache-2.0 */ -import { config } from '@models/constants/config'; -import { Site } from '@models/types/edc/site'; -import { useFetch } from '@hooks/useFetch'; +import {config} from '@models/constants/config'; +import {Site} from '@models/types/edc/site'; +import {useFetch} from '@hooks/useFetch'; export const useSites = () => { - const { data: sites, error: sitesError, isLoading: isLoadingSites, } = useFetch(config.app.BACKEND_BASE_URL + config.app.ENDPOINT_PARTNER_OWNSITES); + const { + data: sites, + error: sitesError, + isLoading: isLoadingSites, + } = useFetch(config.app.BACKEND_BASE_URL + config.app.ENDPOINT_PARTNER + "/ownSites"); return { sites, sitesError, diff --git a/frontend/src/hooks/edc/useCatalog.ts b/frontend/src/hooks/edc/useCatalog.ts index 59092671..758ce811 100644 --- a/frontend/src/hooks/edc/useCatalog.ts +++ b/frontend/src/hooks/edc/useCatalog.ts @@ -18,28 +18,31 @@ under the License. SPDX-License-Identifier: Apache-2.0 */ -import { config } from '@models/constants/config'; -import { RawCatalogData } from '@models/types/edc/catalog'; -import { useFetch } from '../useFetch'; -import { isErrorResponse } from '@util/helpers'; +import {config} from '@models/constants/config'; +import {RawCatalogData} from '@models/types/edc/catalog'; +import {useFetch} from '../useFetch'; +import {isErrorResponse} from '@util/helpers'; +import {Partner} from '@models/types/edc/partner'; -export const useCatalog = (edcUrl: string | null) => { +export const useCatalog = (partner: Partner | null) => { const { data, error, isLoading: isLoadingCatalog, - } = useFetch(edcUrl ? config.app.BACKEND_BASE_URL + 'edc/catalog?dspUrl=' + encodeURIComponent(edcUrl) : undefined); + } = useFetch(partner ? config.app.BACKEND_BASE_URL + + 'edc/catalog?dspUrl=' + encodeURIComponent(partner.edcUrl) + + '&partnerBpnl=' + encodeURIComponent(partner.bpnl) : undefined); const catalog = data && !isErrorResponse(data) ? (data['dcat:dataset']?.map((item) => { - return { - assetId: item['@id'], - assetType: item['dct:type']['@id'], - assetVersion: item['https://w3id.org/catenax/ontology/common#version'], - permission: item['odrl:hasPolicy'] && item['odrl:hasPolicy']['odrl:permission'], - prohibitions: item['odrl:hasPolicy'] && item['odrl:hasPolicy']['odrl:prohibition'], - obligations: item['odrl:hasPolicy'] && item['odrl:hasPolicy']['odrl:obligation'], - }; - }) ?? null) + return { + assetId: item['@id'], + assetType: item['https://purl.org/dc/terms/type']['@id'], + assetVersion: item['https://w3id.org/catenax/ontology/common#version'], + permission: item['odrl:hasPolicy'] && item['odrl:hasPolicy']['odrl:permission'], + prohibitions: item['odrl:hasPolicy'] && item['odrl:hasPolicy']['odrl:prohibition'], + obligations: item['odrl:hasPolicy'] && item['odrl:hasPolicy']['odrl:obligation'], + }; + }) ?? null) : null; const catalogError = error ?? (data && isErrorResponse(data) ? data : null); return { diff --git a/frontend/src/models/constants/config.ts b/frontend/src/models/constants/config.ts index b5a391d0..0bff9b25 100644 --- a/frontend/src/models/constants/config.ts +++ b/frontend/src/models/constants/config.ts @@ -32,7 +32,7 @@ const app = { ENDPOINT_REPORTED_PRODUCT_STOCKS: import.meta.env.VITE_ENDPOINT_REPORTED_PRODUCT_STOCKS.trim() as string, ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS: import.meta.env.VITE_ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS.trim() as string, ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS: import.meta.env.VITE_ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS.trim() as string, - ENDPOINT_PARTNER_OWNSITES: import.meta.env.VITE_ENDPOINT_PARTNER_OWNSITES.trim() as string, + ENDPOINT_PARTNER: import.meta.env.VITE_ENDPOINT_PARTNER.trim() as string, ENDPOINT_DEMAND: import.meta.env.VITE_ENDPOINT_DEMAND.trim() as string, ENDPOINT_PRODUCTION: import.meta.env.VITE_ENDPOINT_PRODUCTION.trim() as string, ENDPOINT_PRODUCTION_RANGE: import.meta.env.VITE_ENDPOINT_PRODUCTION_RANGE.trim() as string, diff --git a/frontend/src/models/types/edc/catalog.ts b/frontend/src/models/types/edc/catalog.ts index 9e2cff14..e9fe28c4 100644 --- a/frontend/src/models/types/edc/catalog.ts +++ b/frontend/src/models/types/edc/catalog.ts @@ -19,13 +19,13 @@ SPDX-License-Identifier: Apache-2.0 */ export type CatalogOperation = { - 'odrl:constraint': { - 'odrl:leftOperand': string; - 'odrl:operator': { - '@id': string; - }; - 'odrl:rightOperand': string; - }; + 'odrl:constraint': { + 'odrl:leftOperand': string; + 'odrl:operator': { + '@id': string; + }; + 'odrl:rightOperand': string; + }; }; export type CatalogPermission = { @@ -34,28 +34,28 @@ export type CatalogPermission = { 'odrl:type': string; } 'odrl:constraint': { - 'odrl:leftOperand': string; - 'odrl:operator': { - '@id': string; - }; - 'odrl:rightOperand': string; + 'odrl:leftOperand': string; + 'odrl:operator': { + '@id': string; + }; + 'odrl:rightOperand': string; } | { '@type': string, 'odrl:and': { - '@type': string, + '@type': string, 'odrl:leftOperand': string; 'odrl:operator': { '@id': string; }; 'odrl:rightOperand': string; }[] - }; + }; }; export type RawCatalogData = { 'dcat:dataset': { '@id': string; - 'dct:type': { + 'https://purl.org/dc/terms/type': { '@id': string; } 'https://w3id.org/catenax/ontology/common#version': string; diff --git a/frontend/src/models/types/edc/negotiation.ts b/frontend/src/models/types/edc/negotiation.ts index 38acd3b0..9bb56ac5 100644 --- a/frontend/src/models/types/edc/negotiation.ts +++ b/frontend/src/models/types/edc/negotiation.ts @@ -19,11 +19,11 @@ SPDX-License-Identifier: Apache-2.0 */ export type Negotiation = { - '@id': string; - 'edc:contractAgreementId'?: string; - 'edc:type': string; - 'edc:state': string; - 'edc:counterPartyId': string; - 'edc:counterPartyAddress': string; - 'edc:createdAt': string; + '@id': string; + 'contractAgreementId'?: string; + 'type': string; + 'state': string; + 'counterPartyId': string; + 'counterPartyAddress': string; + 'createdAt': string; }; diff --git a/frontend/src/models/types/edc/transfer.ts b/frontend/src/models/types/edc/transfer.ts index 833c5f9d..7e57ed8c 100644 --- a/frontend/src/models/types/edc/transfer.ts +++ b/frontend/src/models/types/edc/transfer.ts @@ -19,12 +19,12 @@ SPDX-License-Identifier: Apache-2.0 */ export type Transfer = { - '@id': string; - 'edc:correlationId': string; - 'edc:state': string; - 'edc:stateTimestamp': string; - 'edc:type': string; - 'edc:assetId': string; - 'edc:contractId': string; - 'edc:connectorId': string; + '@id': string; + 'correlationId': string; + 'state': string; + 'stateTimestamp': string; + 'type': string; + 'assetId': string; + 'contractId': string; + 'connectorId': string; }; diff --git a/frontend/src/views/CatalogView.tsx b/frontend/src/views/CatalogView.tsx index b7ae5ea9..0d28b5dc 100644 --- a/frontend/src/views/CatalogView.tsx +++ b/frontend/src/views/CatalogView.tsx @@ -19,19 +19,21 @@ under the License. SPDX-License-Identifier: Apache-2.0 */ -import { Input, LoadingButton } from '@catena-x/portal-shared-components'; -import { useCatalog } from '@hooks/edc/useCatalog'; -import { useRef, useState } from 'react'; -import { CatalogOperation } from '@models/types/edc/catalog'; -import { Card } from '@mui/material'; -import { getCatalogOperator } from '@util/helpers'; +import {Input, LoadingButton} from '@catena-x/portal-shared-components'; +import {useCatalog} from '@hooks/edc/useCatalog'; +import {useRef, useState} from 'react'; +import {CatalogOperation} from '@models/types/edc/catalog'; +import {Autocomplete, Card} from '@mui/material'; +import {getCatalogOperator} from '@util/helpers'; +import {Partner} from '@models/types/edc/partner'; +import {usePartners} from "@features/edc/hooks/usePartners.ts"; type OperationListProps = { title: string; operations: CatalogOperation[]; }; -const OperationList = ({ title, operations }: OperationListProps) => { +const OperationList = ({title, operations}: OperationListProps) => { return ( <> {title} @@ -53,27 +55,37 @@ const OperationList = ({ title, operations }: OperationListProps) => { }; export const CatalogView = () => { - const [edcUrl, setEdcUrl] = useState(null); - const { catalog, catalogError, isLoadingCatalog } = useCatalog(edcUrl); - const urlRef = useRef(null); + const {partners} = usePartners(); + const [partner, setPartner] = useState(null); + const {catalog, catalogError, isLoadingCatalog} = useCatalog(partner); + const partnerRef = useRef(null); return (

View EDC Catalog

-
- (urlRef.current = event.target.value)} +
+ option?.name ?? ''} + renderInput={(params) => ( + + )} + onChange={(event, newValue) => (partnerRef.current = newValue)} + isOptionEqualToValue={(option, value) => option?.uuid === value?.uuid} + className="flex-grow" />
setEdcUrl(urlRef?.current)} + onButtonClick={() => setPartner(partnerRef?.current)} />
@@ -81,7 +93,7 @@ export const CatalogView = () => {
    {catalog.map((item, index) => ( -
  • +
  • Catalog Item

    @@ -98,28 +110,37 @@ export const CatalogView = () => {

    Asset condition(s):

    - {'odrl:and' in item.permission['odrl:constraint'] ? - (item.permission['odrl:constraint']['odrl:and'].map(constraint => ( + {'odrl:and' in item.permission['odrl:constraint'] ? ( + Array.isArray(item.permission['odrl:constraint']['odrl:and']) ? ( + item.permission['odrl:constraint']['odrl:and'].map(constraint => ( +
    + {constraint['odrl:leftOperand'] + ' '} + {getCatalogOperator(constraint['odrl:operator']['@id']) + ' '} + {constraint['odrl:rightOperand']} +
    + )) + ) : (
    - {constraint['odrl:leftOperand'] + ' '} - {getCatalogOperator(constraint['odrl:operator']['@id']) + ' '} - {constraint['odrl:rightOperand']} -
    - ))) : - ( -
    - {item.permission['odrl:constraint']['odrl:leftOperand'] + ' '} - {getCatalogOperator(item.permission['odrl:constraint']['odrl:operator']['@id']) + ' '} - {item.permission['odrl:constraint']['odrl:rightOperand']} + {item.permission['odrl:constraint']['odrl:and']['odrl:leftOperand'] + ' '} + {getCatalogOperator(item.permission['odrl:constraint']['odrl:and']['odrl:operator']['@id']) + ' '} + {item.permission['odrl:constraint']['odrl:and']['odrl:rightOperand']}
    ) - } + ) : ( +
    + {item.permission['odrl:constraint']['odrl:leftOperand'] + ' '} + {getCatalogOperator(item.permission['odrl:constraint']['odrl:operator']['@id']) + ' '} + {item.permission['odrl:constraint']['odrl:rightOperand']} +
    + )}
    - - + +
  • @@ -127,9 +148,10 @@ export const CatalogView = () => { ))}
) : catalogError != null ? ( -
There was an error retrieving the Catalog from {edcUrl}
+
There was an error retrieving the Catalog + from {partner?.edcUrl}
) : ( -
{`No Catalog available for ${edcUrl}`}
+
{`No Catalog available for ${partner?.edcUrl}`}
)}
); diff --git a/frontend/src/views/NegotiationView.tsx b/frontend/src/views/NegotiationView.tsx index 8716265d..b31ab3d8 100644 --- a/frontend/src/views/NegotiationView.tsx +++ b/frontend/src/views/NegotiationView.tsx @@ -21,14 +21,14 @@ SPDX-License-Identifier: Apache-2.0 import Card from '@mui/material/Card'; -import { useNegotiations } from '@hooks/edc/useNegotiations'; -import { Negotiation } from '@models/types/edc/negotiation'; +import {useNegotiations} from '@hooks/edc/useNegotiations'; +import {Negotiation} from '@models/types/edc/negotiation'; type NegotiationCardProps = { negotiation: Negotiation; }; -const NegotiationCard = ({negotiation }: NegotiationCardProps) => { +const NegotiationCard = ({negotiation}: NegotiationCardProps) => { return (

Negotiation

@@ -40,27 +40,27 @@ const NegotiationCard = ({negotiation }: NegotiationCardProps) => {
Aggreement Id: - {negotiation['edc:contractAgreementId']} + {negotiation['contractAgreementId']}
Type: - {negotiation['edc:type']} + {negotiation['type']}
State: - {negotiation['edc:state']} + {negotiation['state']}
CounterParty: - {negotiation['edc:counterPartyId']} + {negotiation['counterPartyId']}
Counterparty EDC URL: - {negotiation['edc:counterPartyAddress']} + {negotiation['counterPartyAddress']}
Timestamp: - {new Date(negotiation['edc:createdAt']).toLocaleString()} + {new Date(negotiation['createdAt']).toLocaleString()}
@@ -69,19 +69,20 @@ const NegotiationCard = ({negotiation }: NegotiationCardProps) => { }; export const NegotiationView = () => { - const { negotiations } = useNegotiations(); + const {negotiations} = useNegotiations(); return (

Negotiation

    {negotiations && negotiations.length > 0 ? ( negotiations.map((negotiation) => ( -
  • - +
  • +
  • )) ) : ( -

    No negotiations found. This list will be updated when Negotiations happen.

    +

    No negotiations found. This list will be updated when Negotiations + happen.

    )}
diff --git a/frontend/src/views/TransferView.tsx b/frontend/src/views/TransferView.tsx index 4cae9b86..be97a27d 100644 --- a/frontend/src/views/TransferView.tsx +++ b/frontend/src/views/TransferView.tsx @@ -21,14 +21,14 @@ SPDX-License-Identifier: Apache-2.0 import Card from '@mui/material/Card'; -import { useTransfers } from '@hooks/edc/useTransfers'; -import { Transfer } from '@models/types/edc/transfer'; +import {useTransfers} from '@hooks/edc/useTransfers'; +import {Transfer} from '@models/types/edc/transfer'; type TransferCardProps = { transfer: Transfer; }; -const TransferCard = ({ transfer }: TransferCardProps) => { +const TransferCard = ({transfer}: TransferCardProps) => { return (

Transfer

@@ -40,31 +40,31 @@ const TransferCard = ({ transfer }: TransferCardProps) => {
Correlation Id: - {transfer['edc:correlationId']} + {transfer['correlationId']}
State: - {transfer['edc:state']} + {transfer['state']}
State Timestamp: - {new Date(transfer['edc:stateTimestamp']).toLocaleString()} + {new Date(transfer['stateTimestamp']).toLocaleString()}
Type: - {transfer['edc:type']} + {transfer['type']}
Asset Id: - {transfer['edc:assetId']} + {transfer['assetId']}
Contract Id: - {transfer['edc:contractId']} + {transfer['contractId']}
Connector Id: - {transfer['edc:connectorId']} + {transfer['connectorId']}
@@ -73,19 +73,20 @@ const TransferCard = ({ transfer }: TransferCardProps) => { }; export const TransferView = () => { - const { transfers } = useTransfers(); + const {transfers} = useTransfers(); return (

Transfers

    {transfers && transfers.length > 0 ? ( transfers.map((transfer) => ( -
  • - +
  • +
  • )) ) : ( -

    No transfers found. This Page will be updated as soon as there are transfers.

    +

    No transfers found. This Page will be updated as soon as there are + transfers.

    )}
diff --git a/local/docker-compose.yaml b/local/docker-compose.yaml index ee5be31a..3bfff7d8 100644 --- a/local/docker-compose.yaml +++ b/local/docker-compose.yaml @@ -40,7 +40,7 @@ services: - ENDPOINT_REPORTED_PRODUCT_STOCKS=stockView/reported-product-stocks?ownMaterialNumber= - ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS=stockView/update-reported-material-stocks?ownMaterialNumber= - ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS=stockView/update-reported-product-stocks?ownMaterialNumber= - - ENDPOINT_PARTNER_OWNSITES=partners/ownSites + - ENDPOINT_PARTNER=partners - ENDPOINT_DEMAND=demand - ENDPOINT_PRODUCTION=production - ENDPOINT_PRODUCTION_RANGE=production/range @@ -86,7 +86,7 @@ services: test: ["CMD", "wget", "-q", "--spider", "http://localhost:4243/api/v3.0/shell-descriptors"] interval: 4s timeout: 3s - retries: 15 + retries: 20 ports: - "127.0.0.1:4243:4243" environment: @@ -189,7 +189,7 @@ services: - ENDPOINT_REPORTED_PRODUCT_STOCKS=stockView/reported-product-stocks?ownMaterialNumber= - ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS=stockView/update-reported-material-stocks?ownMaterialNumber= - ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS=stockView/update-reported-product-stocks?ownMaterialNumber= - - ENDPOINT_PARTNER_OWNSITES=partners/ownSites + - ENDPOINT_PARTNER=partners - ENDPOINT_DEMAND=demand - ENDPOINT_PRODUCTION=production - ENDPOINT_PRODUCTION_RANGE=production/range @@ -235,7 +235,7 @@ services: test: ["CMD", "wget", "-q", "--spider", "http://localhost:4243/api/v3.0/shell-descriptors"] interval: 4s timeout: 3s - retries: 15 + retries: 20 ports: - "127.0.0.1:4244:4243" environment: From d1c0b5238d0c4be09e23ac09ab09fcfd6f0c2445 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Tue, 7 May 2024 23:19:32 -0700 Subject: [PATCH 05/21] feat(EdcRequestBodyBuilder): adjust context for policy creation and add odrl-profile --- .../edc/logic/util/EdcRequestBodyBuilder.java | 89 +++++++++++++------ 1 file changed, 61 insertions(+), 28 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java index c2c34f19..f1f133fa 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java @@ -50,8 +50,10 @@ public class EdcRequestBodyBuilder { public static final String EDC_NAMESPACE = "https://w3id.org/edc/v0.0.1/ns/"; public static final String VOCAB_KEY = "@vocab"; public static final String ODRL_NAMESPACE = "http://www.w3.org/ns/odrl/2/"; + public static final String ODRL_REMOTE_CONTEXT = "http://www.w3.org/ns/odrl.jsonld"; public static final String CX_TAXO_NAMESPACE = "https://w3id.org/catenax/taxonomy#"; public static final String CX_COMMON_NAMESPACE = "https://w3id.org/catenax/ontology/common#"; + public static final String CX_POLICY_NAMESPACE = "https://w3id.org/catenax/policy/"; public static final String DCT_NAMESPACE = "https://purl.org/dc/terms/"; public static final String AAS_SEMANTICS_NAMESPACE = "https://admin-shell.io/aas/3/0/HasSemantics/"; public static final String CONTRACT_POLICY_ID = "Contract_Policy"; @@ -90,46 +92,49 @@ public ObjectNode buildBasicCatalogRequestBody(String counterPartyDspUrl, String return objectNode; } - private JsonNode buildPolicy(String policyId, List constraints) { - var body = MAPPER.createObjectNode(); - var context = MAPPER.createObjectNode(); - context.put("odrl", ODRL_NAMESPACE); - body.set("@context", context); + /** + * create a policy for given constraints + * + * @param policyId to use as for identification (must be unique) + * @param constraints list of constraints that are assembled via odrl:and (note: also if just one is given, and will be put) + * @param policyProfile profile to use for odrl:policy, may be null (should only be used for contract policies) + * @return body to use for policy request + */ + private JsonNode buildPolicy(String policyId, List constraints, String policyProfile) { + ObjectNode body = getPolicyContextObject(); body.put("@type", "PolicyDefinitionRequestDto"); body.put("@id", policyId); var policy = MAPPER.createObjectNode(); - body.set("policy", policy); - policy.put("@type", "odrl:Set"); + body.set("edc:policy", policy); + policy.put("@type", "Set"); - // TODO profile etc. + if (policyProfile != null && !policyProfile.isEmpty()) { + policy.put("profile", policyProfile); + } var permissionsArray = MAPPER.createArrayNode(); - policy.set("odrl:permission", permissionsArray); + policy.set("permission", permissionsArray); var permissionsObject = MAPPER.createObjectNode(); permissionsArray.add(permissionsObject); - var useActionObject = MAPPER.createObjectNode(); - useActionObject.put("@id", "odrl:use"); - permissionsObject.set("odrl:action", useActionObject); + permissionsObject.put("action", "use"); var constraintObject = MAPPER.createObjectNode(); - permissionsObject.set("odrl:constraint", constraintObject); + permissionsObject.set("constraint", constraintObject); constraintObject.put("@type", "LogicalConstraint"); var andArray = MAPPER.createArrayNode(); - constraintObject.set("odrl:and", andArray); + constraintObject.set("and", andArray); for (PolicyConstraintDto policyConstraintDto : constraints) { ObjectNode constraint = MAPPER.createObjectNode(); constraint.put("@type", "LogicalConstraint"); - constraint.put("odrl:leftOperand", policyConstraintDto.getLeftOperand()); + constraint.put("leftOperand", policyConstraintDto.getLeftOperand()); - ObjectNode operatorObject = MAPPER.createObjectNode(); - operatorObject.put("@id", policyConstraintDto.getOperator()); - constraint.set("odrl:operator", operatorObject); + constraint.put("operator", policyConstraintDto.getOperator()); - constraint.put("odrl:rightOperand", policyConstraintDto.getRightOperand()); + constraint.put("rightOperand", policyConstraintDto.getRightOperand()); andArray.add(constraint); } @@ -137,7 +142,7 @@ private JsonNode buildPolicy(String policyId, List constrai } /** - * Creates a request body that demands all of the following conditions: + * Creates a request body that demands all of the following conditions as access policy: * 1. The BPNL of the requesting connector is equal to the BPNL of the partner * 2. There's a valid CX membership credential present * @@ -150,24 +155,28 @@ public JsonNode buildBpnAndMembershipRestrictedPolicy(Partner partner) { constraints.add(new PolicyConstraintDto( "BusinessPartnerNumber", - "odrl:eq", + "eq", partner.getBpnl() )); constraints.add(new PolicyConstraintDto( "Membership", - "odrl:eq", + "eq", "active" )); - return buildPolicy( + JsonNode body = buildPolicy( getBpnPolicyId(partner), - constraints + constraints, + null ); + log.debug("Built bpn and membership access policy:\n{}", body.toPrettyString()); + + return body; } /** - * Creates a request body in order to register a policy that + * Creates a request body in order to register a contract policy that * allows only participants of the framework agreement. * * @return the request body @@ -179,14 +188,18 @@ public JsonNode buildFrameworkPolicy() { // TODO add version and migrate to new version constraints.add(new PolicyConstraintDto( variablesService.getPurisFrameworkAgreement(), - "odrl:eq", + "eq", "active" )); - return buildPolicy( + JsonNode body = buildPolicy( CONTRACT_POLICY_ID, - constraints + constraints, + "cx-policy:profile2405" ); + log.debug("Built framework agreement contract policy:\n{}", body.toPrettyString()); + + return body; } public JsonNode buildSubmodelContractDefinitionWithBpnRestrictedPolicy(String assetId, Partner partner) { @@ -461,6 +474,26 @@ private ObjectNode getEdcContextObject() { return node; } + /** + * A helper method returning a basic request object meant for policy interactions to be used to build other + * specific request bodies. + * + * @return A request body stub + */ + private ObjectNode getPolicyContextObject() { + ObjectNode node = MAPPER.createObjectNode(); + ArrayNode contextArray = MAPPER.createArrayNode(); + contextArray.add(ODRL_REMOTE_CONTEXT); + + ObjectNode contextObject = MAPPER.createObjectNode(); + contextObject.put("edc", EDC_NAMESPACE); + contextObject.put("cx-policy", CX_POLICY_NAMESPACE); + contextArray.add(contextObject); + + node.set("@context", contextArray); + return node; + } + /** * builds a body to terminate the transfer process From 50b346ca84885ca1356c40af667fed24c52ef0fd Mon Sep 17 00:00:00 2001 From: --show-origin Date: Wed, 8 May 2024 00:56:50 -0700 Subject: [PATCH 06/21] fix(EdcAdapterService): use dspUrl of the SubmodelDescriptor for negotiation --- .../edc/logic/service/EdcAdapterService.java | 30 +++++++++++++++---- .../edc/logic/util/EdcRequestBodyBuilder.java | 14 +++++---- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index eaaea3de..2e49f133 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -366,6 +366,8 @@ public JsonNode getCatalog(String dspUrl, String partnerBpnl, Map + * Uses the dspUrl of the partner. * * @param partner The Partner to negotiate with * @param catalogItem An excerpt from a catalog. @@ -373,11 +375,27 @@ public JsonNode getCatalog(String dspUrl, String partnerBpnl, Map Date: Wed, 8 May 2024 01:18:44 -0700 Subject: [PATCH 07/21] fix(EdcAdapterService): check constraints for >=1 submodel offers and take the first fulfilled --- .../backend/common/edc/logic/service/EdcAdapterService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index 2e49f133..75b28622 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -985,7 +985,7 @@ private boolean negotiateForSubmodel(MaterialPartnerRelation mpr, SubmodelType t catalogArray = objectMapper.createArrayNode().add(catalogArray); } JsonNode targetCatalogEntry = null; - if (catalogArray.size() > 1) { + if (catalogArray.size() >= 1) { log.debug("Ambiguous catalog entries found! Will take the first with supported policy \n" + catalogArray.toPrettyString()); for (JsonNode entry : catalogArray) { if (testContractPolicyConstraints(entry)) { @@ -993,8 +993,6 @@ private boolean negotiateForSubmodel(MaterialPartnerRelation mpr, SubmodelType t break; } } - } else { - targetCatalogEntry = catalogArray.get(0); } if (targetCatalogEntry == null) { @@ -1053,6 +1051,7 @@ public String getCxIdFromPartTypeInformation(MaterialPartnerRelation mpr) { * @return true, if the policy matches yours, otherwise false */ private boolean testContractPolicyConstraints(JsonNode catalogEntry) { + log.debug("Testing constraints in the following catalogEntry: {}", catalogEntry.toPrettyString()); var constraint = Optional.ofNullable(catalogEntry.get("odrl:hasPolicy")) .map(policy -> policy.get("odrl:permission")) .map(permission -> permission.get("odrl:constraint")); @@ -1069,6 +1068,7 @@ private boolean testContractPolicyConstraints(JsonNode catalogEntry) { .filter(operand -> "active".equals(operand.asText())); if (leftOperand.isEmpty() || operator.isEmpty() || rightOperand.isEmpty()) return false; + log.info("Contract Offer constraints can be fulfilled by PURIS FOSS application (passed)."); return true; } From 7b2aed1f15879b68b3d23c67121815a9146f369d Mon Sep 17 00:00:00 2001 From: --show-origin Date: Wed, 8 May 2024 02:32:48 -0700 Subject: [PATCH 08/21] feat(EdcRequestBodyBuilder): introduced cx-policy framework agreement definition --- .../edc/logic/service/EdcAdapterService.java | 35 +- .../edc/logic/util/EdcRequestBodyBuilder.java | 5 +- .../backend/common/util/VariablesService.java | 10 + .../src/main/resources/application.properties | 11 +- .../src/test/resources/application.properties | 3 +- charts/puris/README.md | 326 +++++++++--------- .../puris/templates/backend-deployment.yaml | 2 + charts/puris/values.yaml | 4 +- .../config/customer/puris-backend.properties | 3 +- .../config/supplier/puris-backend.properties | 3 +- 10 files changed, 221 insertions(+), 181 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index 75b28622..32fa4b36 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -985,7 +985,7 @@ private boolean negotiateForSubmodel(MaterialPartnerRelation mpr, SubmodelType t catalogArray = objectMapper.createArrayNode().add(catalogArray); } JsonNode targetCatalogEntry = null; - if (catalogArray.size() >= 1) { + if (!catalogArray.isEmpty()) { log.debug("Ambiguous catalog entries found! Will take the first with supported policy \n" + catalogArray.toPrettyString()); for (JsonNode entry : catalogArray) { if (testContractPolicyConstraints(entry)) { @@ -1055,19 +1055,42 @@ private boolean testContractPolicyConstraints(JsonNode catalogEntry) { var constraint = Optional.ofNullable(catalogEntry.get("odrl:hasPolicy")) .map(policy -> policy.get("odrl:permission")) .map(permission -> permission.get("odrl:constraint")); - if (constraint.isEmpty()) return false; + if (constraint.isEmpty()) { + log.debug("Constraint mismatch: we expect to have a constraint in permission node."); + return false; + } + + if (constraint.map(con -> con.get("odrl:and")).isPresent()) { + log.debug("constraint uses ordl:and"); + constraint = constraint.map(con -> con.get("odrl:and")); + } var leftOperand = constraint.map(cons -> cons.get("odrl:leftOperand")) - .filter(operand -> variablesService.getPurisFrameworkAgreement().equals(operand.asText())); + .filter( + operand -> (EdcRequestBodyBuilder.CX_POLICY_NAMESPACE + "FrameworkAgreement").equals(operand.asText()) + ); var operator = constraint.map(cons -> cons.get("odrl:operator")) .map(op -> op.get("@id")) .filter(operand -> "odrl:eq".equals(operand.asText())); var rightOperand = constraint.map(cons -> cons.get("odrl:rightOperand")) - .filter(operand -> "active".equals(operand.asText())); - - if (leftOperand.isEmpty() || operator.isEmpty() || rightOperand.isEmpty()) return false; + .filter(operand -> variablesService.getPurisFrameworkAgreementWithVersion().equals(operand.asText())); + + if (leftOperand.isEmpty() || operator.isEmpty() || rightOperand.isEmpty()) { + log.debug( + "Did not found leftOperand {}, operator {}, rightOperand {}", + leftOperand.isEmpty(), + operator.isEmpty(), + rightOperand.isEmpty() + ); + log.info( + "Framework Agreement Policy (cx-policy:FrameworkAgreement) not fulfilled. Application supports {}:{}", + variablesService.getPurisFrameworkAgreement(), + variablesService.getPurisFrameworkAgreementVersion() + ); + return false; + } log.info("Contract Offer constraints can be fulfilled by PURIS FOSS application (passed)."); return true; diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java index e0c9c3b5..5cc66b89 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java @@ -185,11 +185,10 @@ public JsonNode buildFrameworkPolicy() { List constraints = new ArrayList<>(); - // TODO add version and migrate to new version constraints.add(new PolicyConstraintDto( - variablesService.getPurisFrameworkAgreement(), + CX_POLICY_NAMESPACE + ":FrameworkAgreement", "eq", - "active" + variablesService.getPurisFrameworkAgreementWithVersion() )); JsonNode body = buildPolicy( diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java index 7fbb25e7..06413e2d 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java @@ -125,6 +125,12 @@ public class VariablesService { */ private String purisFrameworkAgreement; + @Value("${puris.frameworkagreement.version}") + /** + * The version of the framework agreement to be used. + */ + private String purisFrameworkAgreementVersion; + @Value("${puris.api.key}") /** * The key for accessing the api. @@ -241,4 +247,8 @@ public String getDeliverySubmodelApiAssetId() { public String getPartTypeSubmodelApiAssetId() { return "PartTypeInformationSubmodelApi@" + getOwnBpnl(); } + + public String getPurisFrameworkAgreementWithVersion() { + return getPurisFrameworkAgreement() + ":" + getPurisFrameworkAgreementVersion(); + } } diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index afec35e0..31da282c 100755 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -11,7 +11,8 @@ puris.productionsubmodel.apiassetid=${PURIS_PRODUCTIONSUBMODEL_APIASSETID:produc puris.demandsubmodel.apiassetid=${PURIS_DEMANDSUBMODEL_APIASSETID:demandsubmodel-api-asset} puris.deliverysubmodel.apiassetid=${PURIS_DELIVERYSUBMODEL_APIASSETID:deliverysubmodel-api-asset} puris.frameworkagreement.use=${PURIS_FRAMEWORKAGREEMENT_USE:false} -puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:FrameworkAgreement.traceability} +puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:puris} +puris.frameworkagreement.version=${PURIS_FRAMEWORKAGREEMENT_VERSION:1.0} puris.api.key=${PURIS_API_KEY:test} puris.dtr.url=${PURIS_DTR_URL:http://localhost:4243} @@ -23,7 +24,6 @@ puris.dtr.url=${PURIS_DTR_URL:http://localhost:4243} # In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that # Material entity. puris.generatematerialcatenaxid=${PURIS_GENERATEMATERIALCATENAXID:true} - # DB Configuration spring.datasource.driver-class-name=${DATASOURCE_DRIVERCLASSNAME:org.postgresql.Driver} spring.datasource.url=${DATASOURCE_URL:jdbc:postgresql://localhost:5432/puris-db} @@ -38,31 +38,25 @@ edc.controlplane.key=${EDC_CONTROLPLANE_KEY:password} edc.controlplane.management.url=${EDC_CONTROLPLANE_MANAGEMENT_URL:http://customer-control-plane:8181/management} edc.controlplane.protocol.url=${EDC_CONTROLPLANE_PROTOCOL_URL:http://customer-control-plane:8184/api/v1/dsp} edc.dataplane.public.url=${EDC_DATAPLANE_PUBLIC_URL:http://customer-data-plane:8285/api/public/} - # Jackson (JSON) #spring.jackson.default-property-inclusion=non_empty #logging.level.org.hibernate.SQL=DEBUG #logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true - # Own BPNL own.bpnl=${OWN_BPNL:BPNL4444444444XX} - # Own name (self-description) own.name=${OWN_NAME:Control Unit Creator Inc.} - # Own BPNS (optional: if this is set, then set own.site.name as well) own.bpns=${OWN_BPNS:BPNS4444444444XX} # Name of Site (see above) own.site.name=${OWN_SITE:Control Unit Creator Production Site} - # If a BPNS is set, then this BPNA will be attached to it. # Otherwise, it will be attached immediately to the BPNL (see above) own.bpna=${OWN_BPNA:BPNA4444444444AA} own.streetandnumber=${OWN_STREETANDNUMBER:13th Street 47} own.zipcodeandcity=${OWN_ZIPCODEANDCITY:10011 New York} own.country=${OWN_COUNTRY:USA} - server.ssl.enabled=false #server.port=8443 #server.ssl.bundle=server @@ -70,6 +64,5 @@ server.ssl.enabled=false #spring.ssl.bundle.jks.server.keystore.location=file:ssl-certificates/application.p12 #spring.ssl.bundle.jks.server.keystore.password=testtest #spring.ssl.bundle.jks.server.keystore.type=PKCS12 - # run with: # ./mvnw spring-boot:run -Dspring-boot.run.arguments=--spring.config.location="./src/main/resources/application.properties" diff --git a/backend/src/test/resources/application.properties b/backend/src/test/resources/application.properties index 91252480..6d941266 100755 --- a/backend/src/test/resources/application.properties +++ b/backend/src/test/resources/application.properties @@ -8,7 +8,8 @@ puris.productionsubmodel.apiassetid=${PURIS_PRODUCTIONSUBMODEL_APIASSETID:produc puris.demandsubmodel.apiassetid=${PURIS_DEMANDSUBMODEL_APIASSETID:demandsubmodel-api-asset} puris.deliverysubmodel.apiassetid=${PURIS_DELIVERYSUBMODEL_APIASSETID:deliverysubmodel-api-asset} puris.frameworkagreement.use=${PURIS_FRAMEWORKAGREEMENT_USE:false} -puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:FrameworkAgreement.traceability} +puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:puris} +puris.frameworkagreement.version=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:1.0} puris.api.key=${PURIS_API_KEY:test} puris.dtr.url=${PURIS_DTR_URL:http://localhost:4243} puris.generatematerialcatenaxid=${PURIS_GENERATEMATERIALCATENAXID:true} diff --git a/charts/puris/README.md b/charts/puris/README.md index 1f6bb1d9..8eacc699 100644 --- a/charts/puris/README.md +++ b/charts/puris/README.md @@ -7,10 +7,12 @@ A helm chart for Kubernetes deployment of PURIS **Homepage:** ## Prerequisites + - Kubernetes 1.19+ - Helm 3.2.0+ ## TL;DR + ```shell $ helm install puris --namespace puris --create-namespace . ``` @@ -21,167 +23,173 @@ $ helm install puris --namespace puris --create-namespace . ## Requirements -| Repository | Name | Version | -|------------|------|---------| +| Repository | Name | Version | +|------------------------------------|------------|---------| | https://charts.bitnami.com/bitnami | postgresql | 12.12.x | ## Values -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | -| backend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | -| backend.env | object | `{}` | Extra environment variables that will be passed onto the backend deployment pods | -| backend.fullnameOverride | string | `"backend"` | Possibility to override the fullname | -| backend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | -| backend.image.repository | string | `"tractusx/app-puris-backend"` | Repository of the docker image | -| backend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | -| backend.imagePullSecrets | list | `[]` | List of used secrets | -| backend.ingress.annotations | object | `{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/backend-protocol":"HTTP","nginx.ingress.kubernetes.io/force-ssl-redirect":"true","nginx.ingress.kubernetes.io/ssl-passthrough":"true"}` | Annotations for the Ingress controller | -| backend.ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | Kubernetes Ingress class annotation for direct bindings | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/backend-protocol" | string | `"HTTP"` | The backend protocol type (e.g. HTTP) | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/force-ssl-redirect" | string | `"true"` | Force redirects from HTTP to HTTPS | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/ssl-passthrough" | string | `"true"` | Pass SSL traffic to the backend ports | -| backend.ingress.enabled | bool | `false` | Enable the Ingress | -| backend.ingress.hosts | list | `[{"host":"your-backend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | -| backend.ingress.tls | list | `[{"hosts":["your-backend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | -| backend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | -| backend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | -| backend.livenessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial liveness probe is checked | -| backend.livenessProbe.periodSeconds | int | `25` | Wait time in seconds between liveness probes | -| backend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | -| backend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | -| backend.nameOverride | string | `""` | Possibility to override the name | -| backend.nodeSelector | object | `{}` | Constrains for the node selector | -| backend.podAnnotations | object | `{}` | Annotations added to a running pod | -| backend.podSecurityContext | object | `{}` | Added security contexts for a pod | -| backend.puris.api.key | string | `"test"` | The API key of the PURIS application | -| backend.puris.api.rootDir | string | `"/catena"` | The root directory of the API | -| backend.puris.baseurl | string | `"your-backend-host-address.com"` | Base url of the PURIS backend | -| backend.puris.datasource.driverClassName | string | `"org.postgresql.Driver"` | Driver class name of the database | -| backend.puris.datasource.password | string | `nil` | Password for the database user. Ignored if postgres.enabled is true. | -| backend.puris.datasource.url | string | `"jdbc:postgresql://postgresql-name:5432/puris-database"` | URL of the database. Ignored if postgres.enabled is true. | -| backend.puris.datasource.username | string | `"db-user"` | Username of the database. Ignored if postgres.enabled is true. | -| backend.puris.demonstrator.role | string | `nil` | Current role of the PURIS demonstrator. Default value should be empty. Can be set to "customer" or "supplier" to enable demonstration setup | -| backend.puris.dtr.url | string | `"http://localhost:4243"` | Endpoint for DTR | -| backend.puris.edc.controlplane.host | string | `"172.17.0.2"` | | -| backend.puris.edc.controlplane.key | string | `"password"` | Key for the EDC control plane | -| backend.puris.edc.controlplane.management.url | string | `"https:/your-edc-address:8181/management"` | Url to the EDC controlplane management of the edc | -| backend.puris.edc.controlplane.protocol.url | string | `"https://your-edc-address:8184/api/v1/dsp"` | Url to the EDC controlplane protocol API of the edc | -| backend.puris.edc.dataplane.public.url | string | `"https://your-data-plane:8285/api/public/"` | Url of one of your data plane's public api | -| backend.puris.edr.deletiontimer | int | `2` | Number of minutes before received authentication data of a consumer pull is removed from memory | -| backend.puris.existingSecret | string | `"secret-backend-puris"` | Secret for backend passwords. For more information look into 'backend-secrets.yaml' file. | -| backend.puris.frameworkagreement.credential | string | `"FrameworkAgreement.traceability"` | The name of the framework agreement | -| backend.puris.generatematerialcatenaxid | bool | `true` | Flag that decides whether the auto-generation feature of the puris backend is enabled. Since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing CatenaX-Id via the materials-API of the backend, when you are inserting a new Material entity to the backend's database. If a CatenaX-Id was not assigned to your Material so far, then this feature can auto-generate one randomly. In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. | -| backend.puris.itemstocksubmodel.apiassetid | string | `"itemstocksubmodel-api-asset"` | Asset ID for ItemStockSubmodel API | -| backend.puris.jpa.hibernate.ddl-auto | string | `"create"` | Initialises SQL database with Hibernate property "create" to allow Hibernate to first drop all tables and then create new ones | -| backend.puris.jpa.properties.hibernate.enable_lazy_load_no_trans | bool | `true` | Enables "Lazy load no trans" property to fetch of each lazy entity to open a temporary session and run inside a separate transaction | -| backend.puris.own.bpna | string | `"BPNA4444444444ZZ"` | Own BPNA of the EDC | -| backend.puris.own.bpnl | string | `"BPNL4444444444XX"` | Own BPNL of the EDC | -| backend.puris.own.bpns | string | `"BPNS4444444444XX"` | Own BPNS of the EDC | -| backend.puris.own.country | string | `"Germany"` | Own country | -| backend.puris.own.name | string | `"YOUR-COMPANY-NAME"` | Own name (self-description) | -| backend.puris.own.site.name | string | `"YOUR-SITE-NAME"` | Own site name | -| backend.puris.own.streetnumber | string | `"Musterstraße 110A"` | Own street and number | -| backend.puris.own.zipcodeandcity | string | `"12345 Musterhausen"` | Own zipcode and city | -| backend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | -| backend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | -| backend.readinessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial readiness probe is checked | -| backend.readinessProbe.periodSeconds | int | `25` | Wait time in seconds between readiness probes | -| backend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | -| backend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | -| backend.replicaCount | int | `1` | Number of replicas of the Kubernetes deployment | -| backend.resources.limits | object | `{"cpu":"3000m","memory":"2048Mi"}` | Maximum resource limits of CPU und memory | -| backend.resources.requests | object | `{"cpu":"1000m","memory":"2048Mi"}` | Minimum requested resources for CPU und memory | -| backend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":8877}` | Security configurations | -| backend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | -| backend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | -| backend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | -| backend.securityContext.runAsUser | int | `8877` | Configures the user id for a run | -| backend.service.port | int | `8081` | The port of the service | -| backend.service.type | string | `"ClusterIP"` | Type of the service | -| backend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | -| backend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | -| backend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | -| backend.tolerations | list | `[]` | Constrains for tolerations | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | -| frontend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | -| frontend.autoscaling.maxReplicas | int | `100` | Number of maximum replica pods for autoscaling | -| frontend.autoscaling.minReplicas | int | `1` | Number of minimum replica pods for autoscaling | -| frontend.autoscaling.targetCPUUtilizationPercentage | int | `80` | Value of CPU usage in percentage for autoscaling decisions | -| frontend.env | object | `{}` | Extra environment variables that will be passed onto the frontend deployment pods | -| frontend.fullnameOverride | string | `"frontend"` | Possibility to override the fullname | -| frontend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | -| frontend.image.repository | string | `"tractusx/app-puris-frontend"` | Repository of the docker image | -| frontend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | -| frontend.imagePullSecrets | list | `[]` | List of used secrets | -| frontend.ingress.annotations | object | `{}` | Annotations for the Ingress controller | -| frontend.ingress.className | string | `"nginx"` | Class name for the Ingress controller | -| frontend.ingress.enabled | bool | `false` | Enable the Ingress | -| frontend.ingress.hosts | list | `[{"host":"your-frontend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | -| frontend.ingress.tls | list | `[{"hosts":["your-frontend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | -| frontend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | -| frontend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | -| frontend.livenessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial liveness probe is checked | -| frontend.livenessProbe.periodSeconds | int | `10` | Wait time in seconds between liveness probes | -| frontend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | -| frontend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | -| frontend.nameOverride | string | `""` | Possibility to override the name | -| frontend.nodeSelector | object | `{}` | Constrains for the node selector | -| frontend.podAnnotations | object | `{}` | Annotations added to a running pod | -| frontend.podSecurityContext | object | `{}` | Added security contexts for a pod | -| frontend.puris.appName | string | `"PURIS"` | The name of the app displayed in the frontend | -| frontend.puris.baseUrl | string | `"your-backend-host-address.com"` | The base URL for the backend base URL without further endpoints | -| frontend.puris.endpointCustomer | string | `"stockView/customer?ownMaterialNumber="` | The endpoint for the customers who buy a material identified via the own material number for the stock view | -| frontend.puris.endpointMaterialStocks | string | `"stockView/material-stocks"` | The endpoint for material stocks for the stock view | -| frontend.puris.endpointMaterials | string | `"stockView/materials"` | The endpoint for materials for the stock view | -| frontend.puris.endpointPartnerOwnSites | string | `"partners/ownSites"` | The endpoint for the partners BPNS | -| frontend.puris.endpointProductStocks | string | `"stockView/product-stocks"` | The endpoint for product stocks for the stock view | -| frontend.puris.endpointProducts | string | `"stockView/products"` | The endpoint for products for the stock view | -| frontend.puris.endpointReportedMaterialStocks | string | `"stockView/reported-material-stocks?ownMaterialNumber="` | The endpoint for the partners' (supplier) material stocks that they potentially will deliver to me | -| frontend.puris.endpointReportedProductStocks | string | `"stockView/reported-product-stocks?ownMaterialNumber="` | The endpoint for the partners' (customer) product stocks that they received from me | -| frontend.puris.endpointSupplier | string | `"stockView/supplier?ownMaterialNumber="` | The endpoint for the suppliers who buy a material identified via the own material number for the stock view | -| frontend.puris.endpointUpdateReportedMaterialStocks | string | `"stockView/update-reported-material-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your material stocks on your partners side | -| frontend.puris.endpointUpdateReportedProductStocks | string | `"stockView/update-reported-product-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your product stocks on your partners side | -| frontend.puris.keycloak.clientId | string | `"appXYZ"` | Name of the client which is used for the application. | -| frontend.puris.keycloak.disabled | bool | `true` | Disable the Keycloak integration. | -| frontend.puris.keycloak.realm | string | `"Catena-X"` | Name of the Realm of the keycloak instance. | -| frontend.puris.keycloak.redirectUrlFrontend | string | `"https://your-frontend-url.com"` | URL to use as keycloak redirect url. | -| frontend.puris.keycloak.url | string | `"https://idp.com/auth"` | The URL to the IDP that should be used. | -| frontend.puris.rateLimiting.burst | int | `30` | Burst rate limiting for nginx. | -| frontend.puris.rateLimiting.limit | string | `"10m"` | Bucket zone limit for rate limiting in nginx. | -| frontend.puris.rateLimiting.rate | string | `"10r/s"` | Allowed rates per second for nginx rate limiting. | -| frontend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | -| frontend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | -| frontend.readinessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial readiness probe is checked | -| frontend.readinessProbe.periodSeconds | int | `10` | Wait time in seconds between readiness probes | -| frontend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | -| frontend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | -| frontend.replicaCount | int | `1` | | -| frontend.resources.limits | object | `{"cpu":"600m","memory":"128Mi"}` | Maximum resource limits of CPU und memory | -| frontend.resources.requests | object | `{"cpu":"200m","memory":"128Mi"}` | Minimum requested resources for CPU und memory | -| frontend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":101}` | Security configurations | -| frontend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | -| frontend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | -| frontend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | -| frontend.securityContext.runAsUser | int | `101` | Configures the user id for a run | -| frontend.service.port | int | `8080` | The port of the service | -| frontend.service.type | string | `"ClusterIP"` | Type of the service | -| frontend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | -| frontend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | -| frontend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | -| frontend.tolerations | list | `[]` | Constrains for tolerations | -| global.domain.backend.ingress | string | `"your-backend-host-address.com"` | | -| postgresql.auth.database | string | `"postgres"` | Name of the database. | -| postgresql.auth.existingSecret | string | `"secret-postgres-init"` | Secret containing the password. For more information look into 'backend-secrets-postgres.yaml' file. | -| postgresql.auth.password | string | `""` | Password for the custom database user. Secret-key 'password' | -| postgresql.auth.passwordPostgres | string | `""` | Password for the database. Secret-key 'postgres-password'. | -| postgresql.auth.username | string | `"puris"` | Username for the custom database user. | -| postgresql.enabled | bool | `true` | Enable postgres by default, set to false to use existing postgres. Make sure to set backend.puris.jpa.hibernate.ddl-auto accordingly (by default database is created using hibernate ddl from backend). | -| postgresql.fullnameOverride | string | `"backend-postgresql"` | Possibility to override the fullname | -| postgresql.service.ports.postgresql | int | `5432` | Port of postgres database. | +| Key | Type | Default | Description | +|-------------------------------------------------------------------------------------------------------------------------------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | +| backend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | +| backend.env | object | `{}` | Extra environment variables that will be passed onto the backend deployment pods | +| backend.fullnameOverride | string | `"backend"` | Possibility to override the fullname | +| backend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | +| backend.image.repository | string | `"tractusx/app-puris-backend"` | Repository of the docker image | +| backend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| backend.imagePullSecrets | list | `[]` | List of used secrets | +| backend.ingress.annotations | object | `{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/backend-protocol":"HTTP","nginx.ingress.kubernetes.io/force-ssl-redirect":"true","nginx.ingress.kubernetes.io/ssl-passthrough":"true"}` | Annotations for the Ingress controller | +| backend.ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | Kubernetes Ingress class annotation for direct bindings | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/backend-protocol" | string | `"HTTP"` | The backend protocol type (e.g. HTTP) | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/force-ssl-redirect" | string | `"true"` | Force redirects from HTTP to HTTPS | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/ssl-passthrough" | string | `"true"` | Pass SSL traffic to the backend ports | +| backend.ingress.enabled | bool | `false` | Enable the Ingress | +| backend.ingress.hosts | list | `[{"host":"your-backend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | +| backend.ingress.tls | list | `[{"hosts":["your-backend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | +| backend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | +| backend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | +| backend.livenessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial liveness probe is checked | +| backend.livenessProbe.periodSeconds | int | `25` | Wait time in seconds between liveness probes | +| backend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | +| backend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | +| backend.nameOverride | string | `""` | Possibility to override the name | +| backend.nodeSelector | object | `{}` | Constrains for the node selector | +| backend.podAnnotations | object | `{}` | Annotations added to a running pod | +| backend.podSecurityContext | object | `{}` | Added security contexts for a pod | +| backend.puris.api.key | string | `"test"` | The API key of the PURIS application | +| backend.puris.api.rootDir | string | `"/catena"` | The root directory of the API | +| backend.puris.baseurl | string | `"your-backend-host-address.com"` | Base url of the PURIS backend | +| backend.puris.datasource.driverClassName | string | `"org.postgresql.Driver"` | Driver class name of the database | +| backend.puris.datasource.password | string | `nil` | Password for the database user. Ignored if postgres.enabled is true. | +| backend.puris.datasource.url | string | `"jdbc:postgresql://postgresql-name:5432/puris-database"` | URL of the database. Ignored if postgres.enabled is true. | +| backend.puris.datasource.username | string | `"db-user"` | Username of the database. Ignored if postgres.enabled is true. | +| backend.puris.deliverysubmodel.apiassetid | string | `"deliverysubmodel-api-asset"` | Asset ID for DeliverySubmodel API | +| backend.puris.demandsubmodel.apiassetid | string | `"demandsubmodel-api-asset"` | Asset ID for DemandSubmodel API | +| backend.puris.demonstrator.role | string | `nil` | Current role of the PURIS demonstrator. Default value should be empty. Can be set to "customer" or "supplier" to enable demonstration setup | +| backend.puris.dtr.url | string | `"http://localhost:4243"` | Endpoint for DTR | +| backend.puris.edc.controlplane.host | string | `"172.17.0.2"` | | +| backend.puris.edc.controlplane.key | string | `"password"` | Key for the EDC control plane | +| backend.puris.edc.controlplane.management.url | string | `"https:/your-edc-address:8181/management"` | Url to the EDC controlplane management of the edc | +| backend.puris.edc.controlplane.protocol.url | string | `"https://your-edc-address:8184/api/v1/dsp"` | Url to the EDC controlplane protocol API of the edc | +| backend.puris.edc.dataplane.public.url | string | `"https://your-data-plane:8285/api/public/"` | Url of one of your data plane's public api | +| backend.puris.edr.deletiontimer | int | `2` | Number of minutes before received authentication data of a consumer pull is removed from memory | +| backend.puris.existingSecret | string | `"secret-backend-puris"` | Secret for backend passwords. For more information look into 'backend-secrets.yaml' file. | +| backend.puris.frameworkagreement.credential | string | `"puris"` | The name of the framework agreement | +| backend.puris.frameworkagreement.version | string | `"1.0"` | The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! | +| backend.puris.generatematerialcatenaxid | bool | `true` | Flag that decides whether the auto-generation feature of the puris backend is enabled. Since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing CatenaX-Id via the materials-API of the backend, when you are inserting a new Material entity to the backend's database. If a CatenaX-Id was not assigned to your Material so far, then this feature can auto-generate one randomly. In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. | +| backend.puris.itemstocksubmodel.apiassetid | string | `"itemstocksubmodel-api-asset"` | Asset ID for ItemStockSubmodel API | +| backend.puris.jpa.hibernate.ddl-auto | string | `"create"` | Initialises SQL database with Hibernate property "create" to allow Hibernate to first drop all tables and then create new ones | +| backend.puris.jpa.properties.hibernate.enable_lazy_load_no_trans | bool | `true` | Enables "Lazy load no trans" property to fetch of each lazy entity to open a temporary session and run inside a separate transaction | +| backend.puris.own.bpna | string | `"BPNA4444444444ZZ"` | Own BPNA of the EDC | +| backend.puris.own.bpnl | string | `"BPNL4444444444XX"` | Own BPNL of the EDC | +| backend.puris.own.bpns | string | `"BPNS4444444444XX"` | Own BPNS of the EDC | +| backend.puris.own.country | string | `"Germany"` | Own country | +| backend.puris.own.name | string | `"YOUR-COMPANY-NAME"` | Own name (self-description) | +| backend.puris.own.site.name | string | `"YOUR-SITE-NAME"` | Own site name | +| backend.puris.own.streetnumber | string | `"Musterstraße 110A"` | Own street and number | +| backend.puris.own.zipcodeandcity | string | `"12345 Musterhausen"` | Own zipcode and city | +| backend.puris.productionsubmodel.apiassetid | string | `"productionsubmodel-api-asset"` | Asset ID for ProductionSubmodel API | +| backend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | +| backend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | +| backend.readinessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial readiness probe is checked | +| backend.readinessProbe.periodSeconds | int | `25` | Wait time in seconds between readiness probes | +| backend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | +| backend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | +| backend.replicaCount | int | `1` | Number of replicas of the Kubernetes deployment | +| backend.resources.limits | object | `{"cpu":"3000m","memory":"2048Mi"}` | Maximum resource limits of CPU und memory | +| backend.resources.requests | object | `{"cpu":"1000m","memory":"2048Mi"}` | Minimum requested resources for CPU und memory | +| backend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":8877}` | Security configurations | +| backend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | +| backend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | +| backend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | +| backend.securityContext.runAsUser | int | `8877` | Configures the user id for a run | +| backend.service.port | int | `8081` | The port of the service | +| backend.service.type | string | `"ClusterIP"` | Type of the service | +| backend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| backend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| backend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| backend.tolerations | list | `[]` | Constrains for tolerations | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | +| frontend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | +| frontend.autoscaling.maxReplicas | int | `100` | Number of maximum replica pods for autoscaling | +| frontend.autoscaling.minReplicas | int | `1` | Number of minimum replica pods for autoscaling | +| frontend.autoscaling.targetCPUUtilizationPercentage | int | `80` | Value of CPU usage in percentage for autoscaling decisions | +| frontend.env | object | `{}` | Extra environment variables that will be passed onto the frontend deployment pods | +| frontend.fullnameOverride | string | `"frontend"` | Possibility to override the fullname | +| frontend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | +| frontend.image.repository | string | `"tractusx/app-puris-frontend"` | Repository of the docker image | +| frontend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| frontend.imagePullSecrets | list | `[]` | List of used secrets | +| frontend.ingress.annotations | object | `{}` | Annotations for the Ingress controller | +| frontend.ingress.className | string | `"nginx"` | Class name for the Ingress controller | +| frontend.ingress.enabled | bool | `false` | Enable the Ingress | +| frontend.ingress.hosts | list | `[{"host":"your-frontend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | +| frontend.ingress.tls | list | `[{"hosts":["your-frontend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | +| frontend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | +| frontend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | +| frontend.livenessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial liveness probe is checked | +| frontend.livenessProbe.periodSeconds | int | `10` | Wait time in seconds between liveness probes | +| frontend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | +| frontend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | +| frontend.nameOverride | string | `""` | Possibility to override the name | +| frontend.nodeSelector | object | `{}` | Constrains for the node selector | +| frontend.podAnnotations | object | `{}` | Annotations added to a running pod | +| frontend.podSecurityContext | object | `{}` | Added security contexts for a pod | +| frontend.puris.appName | string | `"PURIS"` | The name of the app displayed in the frontend | +| frontend.puris.baseUrl | string | `"your-backend-host-address.com"` | The base URL for the backend base URL without further endpoints | +| frontend.puris.endpointCustomer | string | `"stockView/customer?ownMaterialNumber="` | The endpoint for the customers who buy a material identified via the own material number for the stock view | +| frontend.puris.endpointMaterialStocks | string | `"stockView/material-stocks"` | The endpoint for material stocks for the stock view | +| frontend.puris.endpointMaterials | string | `"stockView/materials"` | The endpoint for materials for the stock view | +| frontend.puris.endpointPartnerOwnSites | string | `"partners/ownSites"` | The endpoint for the partners BPNS | +| frontend.puris.endpointProductStocks | string | `"stockView/product-stocks"` | The endpoint for product stocks for the stock view | +| frontend.puris.endpointProducts | string | `"stockView/products"` | The endpoint for products for the stock view | +| frontend.puris.endpointReportedMaterialStocks | string | `"stockView/reported-material-stocks?ownMaterialNumber="` | The endpoint for the partners' (supplier) material stocks that they potentially will deliver to me | +| frontend.puris.endpointReportedProductStocks | string | `"stockView/reported-product-stocks?ownMaterialNumber="` | The endpoint for the partners' (customer) product stocks that they received from me | +| frontend.puris.endpointSupplier | string | `"stockView/supplier?ownMaterialNumber="` | The endpoint for the suppliers who buy a material identified via the own material number for the stock view | +| frontend.puris.endpointUpdateReportedMaterialStocks | string | `"stockView/update-reported-material-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your material stocks on your partners side | +| frontend.puris.endpointUpdateReportedProductStocks | string | `"stockView/update-reported-product-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your product stocks on your partners side | +| frontend.puris.keycloak.clientId | string | `"appXYZ"` | Name of the client which is used for the application. | +| frontend.puris.keycloak.disabled | bool | `true` | Disable the Keycloak integration. | +| frontend.puris.keycloak.realm | string | `"Catena-X"` | Name of the Realm of the keycloak instance. | +| frontend.puris.keycloak.redirectUrlFrontend | string | `"https://your-frontend-url.com"` | URL to use as keycloak redirect url. | +| frontend.puris.keycloak.url | string | `"https://idp.com/auth"` | The URL to the IDP that should be used. | +| frontend.puris.rateLimiting.burst | int | `30` | Burst rate limiting for nginx. | +| frontend.puris.rateLimiting.limit | string | `"10m"` | Bucket zone limit for rate limiting in nginx. | +| frontend.puris.rateLimiting.rate | string | `"10r/s"` | Allowed rates per second for nginx rate limiting. | +| frontend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | +| frontend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | +| frontend.readinessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial readiness probe is checked | +| frontend.readinessProbe.periodSeconds | int | `10` | Wait time in seconds between readiness probes | +| frontend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | +| frontend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | +| frontend.replicaCount | int | `1` | | +| frontend.resources.limits | object | `{"cpu":"600m","memory":"128Mi"}` | Maximum resource limits of CPU und memory | +| frontend.resources.requests | object | `{"cpu":"200m","memory":"128Mi"}` | Minimum requested resources for CPU und memory | +| frontend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":101}` | Security configurations | +| frontend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | +| frontend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | +| frontend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | +| frontend.securityContext.runAsUser | int | `101` | Configures the user id for a run | +| frontend.service.port | int | `8080` | The port of the service | +| frontend.service.type | string | `"ClusterIP"` | Type of the service | +| frontend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| frontend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| frontend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| frontend.tolerations | list | `[]` | Constrains for tolerations | +| global.domain.backend.ingress | string | `"your-backend-host-address.com"` | | +| postgresql.auth.database | string | `"postgres"` | Name of the database. | +| postgresql.auth.existingSecret | string | `"secret-postgres-init"` | Secret containing the password. For more information look into 'backend-secrets-postgres.yaml' file. | +| postgresql.auth.password | string | `""` | Password for the custom database user. Secret-key 'password' | +| postgresql.auth.passwordPostgres | string | `""` | Password for the database. Secret-key 'postgres-password'. | +| postgresql.auth.username | string | `"puris"` | Username for the custom database user. | +| postgresql.enabled | bool | `true` | Enable postgres by default, set to false to use existing postgres. Make sure to set backend.puris.jpa.hibernate.ddl-auto accordingly (by default database is created using hibernate ddl from backend). | +| postgresql.fullnameOverride | string | `"backend-postgresql"` | Possibility to override the fullname | +| postgresql.service.ports.postgresql | int | `5432` | Port of postgres database. | +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.3](https://github.com/norwoodj/helm-docs/releases/v1.11.3) diff --git a/charts/puris/templates/backend-deployment.yaml b/charts/puris/templates/backend-deployment.yaml index 4fe0bfb2..876a3a32 100644 --- a/charts/puris/templates/backend-deployment.yaml +++ b/charts/puris/templates/backend-deployment.yaml @@ -149,6 +149,8 @@ spec: value: "{{ .Values.backend.puris.frameworkagreement.use }}" - name: PURIS_FRAMEWORKAGREEMENT_CREDENTIAL value: "{{ .Values.backend.puris.frameworkagreement.credential }}" + - name: PURIS_FRAMEWORKAGREEMENT_VERSION + value: "{{ .Values.backend.puris.frameworkagreement.version }}" - name: PURIS_DTR_URL value: "{{ .Values.backend.puris.dtr.url }}" - name: PURIS_GENERATEMATERIALCATENAXID diff --git a/charts/puris/values.yaml b/charts/puris/values.yaml index 0785491f..7bbfeca1 100644 --- a/charts/puris/values.yaml +++ b/charts/puris/values.yaml @@ -425,7 +425,9 @@ backend: apiassetid: deliverysubmodel-api-asset frameworkagreement: # -- The name of the framework agreement - credential: FrameworkAgreement.traceability + credential: puris + # -- The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! + version: "1.0" edr: # -- Number of minutes before received authentication data of a consumer pull is removed from memory deletiontimer: 2 diff --git a/local/tractus-x-edc/config/customer/puris-backend.properties b/local/tractus-x-edc/config/customer/puris-backend.properties index 8ed2802c..ddba89bc 100644 --- a/local/tractus-x-edc/config/customer/puris-backend.properties +++ b/local/tractus-x-edc/config/customer/puris-backend.properties @@ -7,7 +7,8 @@ puris.itemstocksubmodel.apiassetid=itemstocksubmodel-api-asset puris.productionsubmodel.apiassetid=productionsubmodel-api-asset puris.demandsubmodel.apiassetid=demandsubmodel-api-asset puris.deliverysubmodel.apiassetid=deliverysubmodel-api-asset -puris.frameworkagreement.credential=FrameworkAgreement.traceability +puris.frameworkagreement.credential=puris +puris.frameworkagreement.version=1.0 puris.api.key=${CUSTOMER_BACKEND_API_KEY} puris.dtr.url=http://dtr-customer:4243 puris.generatematerialcatenaxid=true diff --git a/local/tractus-x-edc/config/supplier/puris-backend.properties b/local/tractus-x-edc/config/supplier/puris-backend.properties index 4c704874..3336ed2f 100644 --- a/local/tractus-x-edc/config/supplier/puris-backend.properties +++ b/local/tractus-x-edc/config/supplier/puris-backend.properties @@ -7,7 +7,8 @@ puris.itemstocksubmodel.apiassetid=itemstocksubmodel-api-asset puris.productionsubmodel.apiassetid=productionsubmodel-api-asset puris.demandsubmodel.apiassetid=demandsubmodel-api-asset puris.deliverysubmodel.apiassetid=deliverysubmodel-api-asset -puris.frameworkagreement.credential=FrameworkAgreement.traceability +puris.frameworkagreement.credential=puris +puris.frameworkagreement.version=1.0 puris.api.key=${SUPPLIER_BACKEND_API_KEY} puris.dtr.url=http://dtr-supplier:4243 puris.generatematerialcatenaxid=true From 4e36df92424b657536c77b55e520502de2242660 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Wed, 8 May 2024 02:52:50 -0700 Subject: [PATCH 09/21] chore(chart): increased chart version --- charts/puris/Chart.yaml | 2 +- charts/puris/README.md | 330 ++++++++++++++++++++-------------------- 2 files changed, 165 insertions(+), 167 deletions(-) diff --git a/charts/puris/Chart.yaml b/charts/puris/Chart.yaml index a6ada138..06142577 100644 --- a/charts/puris/Chart.yaml +++ b/charts/puris/Chart.yaml @@ -35,7 +35,7 @@ dependencies: # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 2.2.0 +version: 2.3.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/puris/README.md b/charts/puris/README.md index 8eacc699..d34a4ff6 100644 --- a/charts/puris/README.md +++ b/charts/puris/README.md @@ -1,18 +1,16 @@ # puris -![Version: 2.0.1](https://img.shields.io/badge/Version-2.0.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) +![Version: 2.3.0](https://img.shields.io/badge/Version-2.3.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) A helm chart for Kubernetes deployment of PURIS **Homepage:** ## Prerequisites - - Kubernetes 1.19+ - Helm 3.2.0+ ## TL;DR - ```shell $ helm install puris --namespace puris --create-namespace . ``` @@ -23,173 +21,173 @@ $ helm install puris --namespace puris --create-namespace . ## Requirements -| Repository | Name | Version | -|------------------------------------|------------|---------| +| Repository | Name | Version | +|------------|------|---------| | https://charts.bitnami.com/bitnami | postgresql | 12.12.x | ## Values -| Key | Type | Default | Description | -|-------------------------------------------------------------------------------------------------------------------------------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | -| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | -| backend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | -| backend.env | object | `{}` | Extra environment variables that will be passed onto the backend deployment pods | -| backend.fullnameOverride | string | `"backend"` | Possibility to override the fullname | -| backend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | -| backend.image.repository | string | `"tractusx/app-puris-backend"` | Repository of the docker image | -| backend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | -| backend.imagePullSecrets | list | `[]` | List of used secrets | -| backend.ingress.annotations | object | `{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/backend-protocol":"HTTP","nginx.ingress.kubernetes.io/force-ssl-redirect":"true","nginx.ingress.kubernetes.io/ssl-passthrough":"true"}` | Annotations for the Ingress controller | -| backend.ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | Kubernetes Ingress class annotation for direct bindings | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/backend-protocol" | string | `"HTTP"` | The backend protocol type (e.g. HTTP) | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/force-ssl-redirect" | string | `"true"` | Force redirects from HTTP to HTTPS | -| backend.ingress.annotations."nginx.ingress.kubernetes.io/ssl-passthrough" | string | `"true"` | Pass SSL traffic to the backend ports | -| backend.ingress.enabled | bool | `false` | Enable the Ingress | -| backend.ingress.hosts | list | `[{"host":"your-backend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | -| backend.ingress.tls | list | `[{"hosts":["your-backend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | -| backend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | -| backend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | -| backend.livenessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial liveness probe is checked | -| backend.livenessProbe.periodSeconds | int | `25` | Wait time in seconds between liveness probes | -| backend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | -| backend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | -| backend.nameOverride | string | `""` | Possibility to override the name | -| backend.nodeSelector | object | `{}` | Constrains for the node selector | -| backend.podAnnotations | object | `{}` | Annotations added to a running pod | -| backend.podSecurityContext | object | `{}` | Added security contexts for a pod | -| backend.puris.api.key | string | `"test"` | The API key of the PURIS application | -| backend.puris.api.rootDir | string | `"/catena"` | The root directory of the API | -| backend.puris.baseurl | string | `"your-backend-host-address.com"` | Base url of the PURIS backend | -| backend.puris.datasource.driverClassName | string | `"org.postgresql.Driver"` | Driver class name of the database | -| backend.puris.datasource.password | string | `nil` | Password for the database user. Ignored if postgres.enabled is true. | -| backend.puris.datasource.url | string | `"jdbc:postgresql://postgresql-name:5432/puris-database"` | URL of the database. Ignored if postgres.enabled is true. | -| backend.puris.datasource.username | string | `"db-user"` | Username of the database. Ignored if postgres.enabled is true. | -| backend.puris.deliverysubmodel.apiassetid | string | `"deliverysubmodel-api-asset"` | Asset ID for DeliverySubmodel API | -| backend.puris.demandsubmodel.apiassetid | string | `"demandsubmodel-api-asset"` | Asset ID for DemandSubmodel API | -| backend.puris.demonstrator.role | string | `nil` | Current role of the PURIS demonstrator. Default value should be empty. Can be set to "customer" or "supplier" to enable demonstration setup | -| backend.puris.dtr.url | string | `"http://localhost:4243"` | Endpoint for DTR | -| backend.puris.edc.controlplane.host | string | `"172.17.0.2"` | | -| backend.puris.edc.controlplane.key | string | `"password"` | Key for the EDC control plane | -| backend.puris.edc.controlplane.management.url | string | `"https:/your-edc-address:8181/management"` | Url to the EDC controlplane management of the edc | -| backend.puris.edc.controlplane.protocol.url | string | `"https://your-edc-address:8184/api/v1/dsp"` | Url to the EDC controlplane protocol API of the edc | -| backend.puris.edc.dataplane.public.url | string | `"https://your-data-plane:8285/api/public/"` | Url of one of your data plane's public api | -| backend.puris.edr.deletiontimer | int | `2` | Number of minutes before received authentication data of a consumer pull is removed from memory | -| backend.puris.existingSecret | string | `"secret-backend-puris"` | Secret for backend passwords. For more information look into 'backend-secrets.yaml' file. | -| backend.puris.frameworkagreement.credential | string | `"puris"` | The name of the framework agreement | -| backend.puris.frameworkagreement.version | string | `"1.0"` | The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! | -| backend.puris.generatematerialcatenaxid | bool | `true` | Flag that decides whether the auto-generation feature of the puris backend is enabled. Since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing CatenaX-Id via the materials-API of the backend, when you are inserting a new Material entity to the backend's database. If a CatenaX-Id was not assigned to your Material so far, then this feature can auto-generate one randomly. In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. | -| backend.puris.itemstocksubmodel.apiassetid | string | `"itemstocksubmodel-api-asset"` | Asset ID for ItemStockSubmodel API | -| backend.puris.jpa.hibernate.ddl-auto | string | `"create"` | Initialises SQL database with Hibernate property "create" to allow Hibernate to first drop all tables and then create new ones | -| backend.puris.jpa.properties.hibernate.enable_lazy_load_no_trans | bool | `true` | Enables "Lazy load no trans" property to fetch of each lazy entity to open a temporary session and run inside a separate transaction | -| backend.puris.own.bpna | string | `"BPNA4444444444ZZ"` | Own BPNA of the EDC | -| backend.puris.own.bpnl | string | `"BPNL4444444444XX"` | Own BPNL of the EDC | -| backend.puris.own.bpns | string | `"BPNS4444444444XX"` | Own BPNS of the EDC | -| backend.puris.own.country | string | `"Germany"` | Own country | -| backend.puris.own.name | string | `"YOUR-COMPANY-NAME"` | Own name (self-description) | -| backend.puris.own.site.name | string | `"YOUR-SITE-NAME"` | Own site name | -| backend.puris.own.streetnumber | string | `"Musterstraße 110A"` | Own street and number | -| backend.puris.own.zipcodeandcity | string | `"12345 Musterhausen"` | Own zipcode and city | -| backend.puris.productionsubmodel.apiassetid | string | `"productionsubmodel-api-asset"` | Asset ID for ProductionSubmodel API | -| backend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | -| backend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | -| backend.readinessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial readiness probe is checked | -| backend.readinessProbe.periodSeconds | int | `25` | Wait time in seconds between readiness probes | -| backend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | -| backend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | -| backend.replicaCount | int | `1` | Number of replicas of the Kubernetes deployment | -| backend.resources.limits | object | `{"cpu":"3000m","memory":"2048Mi"}` | Maximum resource limits of CPU und memory | -| backend.resources.requests | object | `{"cpu":"1000m","memory":"2048Mi"}` | Minimum requested resources for CPU und memory | -| backend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":8877}` | Security configurations | -| backend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | -| backend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | -| backend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | -| backend.securityContext.runAsUser | int | `8877` | Configures the user id for a run | -| backend.service.port | int | `8081` | The port of the service | -| backend.service.type | string | `"ClusterIP"` | Type of the service | -| backend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | -| backend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | -| backend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | -| backend.tolerations | list | `[]` | Constrains for tolerations | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | -| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | -| frontend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | -| frontend.autoscaling.maxReplicas | int | `100` | Number of maximum replica pods for autoscaling | -| frontend.autoscaling.minReplicas | int | `1` | Number of minimum replica pods for autoscaling | -| frontend.autoscaling.targetCPUUtilizationPercentage | int | `80` | Value of CPU usage in percentage for autoscaling decisions | -| frontend.env | object | `{}` | Extra environment variables that will be passed onto the frontend deployment pods | -| frontend.fullnameOverride | string | `"frontend"` | Possibility to override the fullname | -| frontend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | -| frontend.image.repository | string | `"tractusx/app-puris-frontend"` | Repository of the docker image | -| frontend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | -| frontend.imagePullSecrets | list | `[]` | List of used secrets | -| frontend.ingress.annotations | object | `{}` | Annotations for the Ingress controller | -| frontend.ingress.className | string | `"nginx"` | Class name for the Ingress controller | -| frontend.ingress.enabled | bool | `false` | Enable the Ingress | -| frontend.ingress.hosts | list | `[{"host":"your-frontend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | -| frontend.ingress.tls | list | `[{"hosts":["your-frontend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | -| frontend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | -| frontend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | -| frontend.livenessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial liveness probe is checked | -| frontend.livenessProbe.periodSeconds | int | `10` | Wait time in seconds between liveness probes | -| frontend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | -| frontend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | -| frontend.nameOverride | string | `""` | Possibility to override the name | -| frontend.nodeSelector | object | `{}` | Constrains for the node selector | -| frontend.podAnnotations | object | `{}` | Annotations added to a running pod | -| frontend.podSecurityContext | object | `{}` | Added security contexts for a pod | -| frontend.puris.appName | string | `"PURIS"` | The name of the app displayed in the frontend | -| frontend.puris.baseUrl | string | `"your-backend-host-address.com"` | The base URL for the backend base URL without further endpoints | -| frontend.puris.endpointCustomer | string | `"stockView/customer?ownMaterialNumber="` | The endpoint for the customers who buy a material identified via the own material number for the stock view | -| frontend.puris.endpointMaterialStocks | string | `"stockView/material-stocks"` | The endpoint for material stocks for the stock view | -| frontend.puris.endpointMaterials | string | `"stockView/materials"` | The endpoint for materials for the stock view | -| frontend.puris.endpointPartnerOwnSites | string | `"partners/ownSites"` | The endpoint for the partners BPNS | -| frontend.puris.endpointProductStocks | string | `"stockView/product-stocks"` | The endpoint for product stocks for the stock view | -| frontend.puris.endpointProducts | string | `"stockView/products"` | The endpoint for products for the stock view | -| frontend.puris.endpointReportedMaterialStocks | string | `"stockView/reported-material-stocks?ownMaterialNumber="` | The endpoint for the partners' (supplier) material stocks that they potentially will deliver to me | -| frontend.puris.endpointReportedProductStocks | string | `"stockView/reported-product-stocks?ownMaterialNumber="` | The endpoint for the partners' (customer) product stocks that they received from me | -| frontend.puris.endpointSupplier | string | `"stockView/supplier?ownMaterialNumber="` | The endpoint for the suppliers who buy a material identified via the own material number for the stock view | -| frontend.puris.endpointUpdateReportedMaterialStocks | string | `"stockView/update-reported-material-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your material stocks on your partners side | -| frontend.puris.endpointUpdateReportedProductStocks | string | `"stockView/update-reported-product-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your product stocks on your partners side | -| frontend.puris.keycloak.clientId | string | `"appXYZ"` | Name of the client which is used for the application. | -| frontend.puris.keycloak.disabled | bool | `true` | Disable the Keycloak integration. | -| frontend.puris.keycloak.realm | string | `"Catena-X"` | Name of the Realm of the keycloak instance. | -| frontend.puris.keycloak.redirectUrlFrontend | string | `"https://your-frontend-url.com"` | URL to use as keycloak redirect url. | -| frontend.puris.keycloak.url | string | `"https://idp.com/auth"` | The URL to the IDP that should be used. | -| frontend.puris.rateLimiting.burst | int | `30` | Burst rate limiting for nginx. | -| frontend.puris.rateLimiting.limit | string | `"10m"` | Bucket zone limit for rate limiting in nginx. | -| frontend.puris.rateLimiting.rate | string | `"10r/s"` | Allowed rates per second for nginx rate limiting. | -| frontend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | -| frontend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | -| frontend.readinessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial readiness probe is checked | -| frontend.readinessProbe.periodSeconds | int | `10` | Wait time in seconds between readiness probes | -| frontend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | -| frontend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | -| frontend.replicaCount | int | `1` | | -| frontend.resources.limits | object | `{"cpu":"600m","memory":"128Mi"}` | Maximum resource limits of CPU und memory | -| frontend.resources.requests | object | `{"cpu":"200m","memory":"128Mi"}` | Minimum requested resources for CPU und memory | -| frontend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":101}` | Security configurations | -| frontend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | -| frontend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | -| frontend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | -| frontend.securityContext.runAsUser | int | `101` | Configures the user id for a run | -| frontend.service.port | int | `8080` | The port of the service | -| frontend.service.type | string | `"ClusterIP"` | Type of the service | -| frontend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | -| frontend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | -| frontend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | -| frontend.tolerations | list | `[]` | Constrains for tolerations | -| global.domain.backend.ingress | string | `"your-backend-host-address.com"` | | -| postgresql.auth.database | string | `"postgres"` | Name of the database. | -| postgresql.auth.existingSecret | string | `"secret-postgres-init"` | Secret containing the password. For more information look into 'backend-secrets-postgres.yaml' file. | -| postgresql.auth.password | string | `""` | Password for the custom database user. Secret-key 'password' | -| postgresql.auth.passwordPostgres | string | `""` | Password for the database. Secret-key 'postgres-password'. | -| postgresql.auth.username | string | `"puris"` | Username for the custom database user. | -| postgresql.enabled | bool | `true` | Enable postgres by default, set to false to use existing postgres. Make sure to set backend.puris.jpa.hibernate.ddl-auto accordingly (by default database is created using hibernate ddl from backend). | -| postgresql.fullnameOverride | string | `"backend-postgresql"` | Possibility to override the fullname | -| postgresql.service.ports.postgresql | int | `5432` | Port of postgres database. | +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | +| backend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | +| backend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | +| backend.env | object | `{}` | Extra environment variables that will be passed onto the backend deployment pods | +| backend.fullnameOverride | string | `"backend"` | Possibility to override the fullname | +| backend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | +| backend.image.repository | string | `"tractusx/app-puris-backend"` | Repository of the docker image | +| backend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| backend.imagePullSecrets | list | `[]` | List of used secrets | +| backend.ingress.annotations | object | `{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/backend-protocol":"HTTP","nginx.ingress.kubernetes.io/force-ssl-redirect":"true","nginx.ingress.kubernetes.io/ssl-passthrough":"true"}` | Annotations for the Ingress controller | +| backend.ingress.annotations."kubernetes.io/ingress.class" | string | `"nginx"` | Kubernetes Ingress class annotation for direct bindings | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/backend-protocol" | string | `"HTTP"` | The backend protocol type (e.g. HTTP) | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/force-ssl-redirect" | string | `"true"` | Force redirects from HTTP to HTTPS | +| backend.ingress.annotations."nginx.ingress.kubernetes.io/ssl-passthrough" | string | `"true"` | Pass SSL traffic to the backend ports | +| backend.ingress.enabled | bool | `false` | Enable the Ingress | +| backend.ingress.hosts | list | `[{"host":"your-backend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | +| backend.ingress.tls | list | `[{"hosts":["your-backend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | +| backend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | +| backend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | +| backend.livenessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial liveness probe is checked | +| backend.livenessProbe.periodSeconds | int | `25` | Wait time in seconds between liveness probes | +| backend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | +| backend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | +| backend.nameOverride | string | `""` | Possibility to override the name | +| backend.nodeSelector | object | `{}` | Constrains for the node selector | +| backend.podAnnotations | object | `{}` | Annotations added to a running pod | +| backend.podSecurityContext | object | `{}` | Added security contexts for a pod | +| backend.puris.api.key | string | `"test"` | The API key of the PURIS application | +| backend.puris.api.rootDir | string | `"/catena"` | The root directory of the API | +| backend.puris.baseurl | string | `"your-backend-host-address.com"` | Base url of the PURIS backend | +| backend.puris.datasource.driverClassName | string | `"org.postgresql.Driver"` | Driver class name of the database | +| backend.puris.datasource.password | string | `nil` | Password for the database user. Ignored if postgres.enabled is true. | +| backend.puris.datasource.url | string | `"jdbc:postgresql://postgresql-name:5432/puris-database"` | URL of the database. Ignored if postgres.enabled is true. | +| backend.puris.datasource.username | string | `"db-user"` | Username of the database. Ignored if postgres.enabled is true. | +| backend.puris.deliverysubmodel.apiassetid | string | `"deliverysubmodel-api-asset"` | Asset ID for DeliverySubmodel API | +| backend.puris.demandsubmodel.apiassetid | string | `"demandsubmodel-api-asset"` | Asset ID for DemandSubmodel API | +| backend.puris.demonstrator.role | string | `nil` | Current role of the PURIS demonstrator. Default value should be empty. Can be set to "customer" or "supplier" to enable demonstration setup | +| backend.puris.dtr.url | string | `"http://localhost:4243"` | Endpoint for DTR | +| backend.puris.edc.controlplane.host | string | `"172.17.0.2"` | | +| backend.puris.edc.controlplane.key | string | `"password"` | Key for the EDC control plane | +| backend.puris.edc.controlplane.management.url | string | `"https:/your-edc-address:8181/management"` | Url to the EDC controlplane management of the edc | +| backend.puris.edc.controlplane.protocol.url | string | `"https://your-edc-address:8184/api/v1/dsp"` | Url to the EDC controlplane protocol API of the edc | +| backend.puris.edc.dataplane.public.url | string | `"https://your-data-plane:8285/api/public/"` | Url of one of your data plane's public api | +| backend.puris.edr.deletiontimer | int | `2` | Number of minutes before received authentication data of a consumer pull is removed from memory | +| backend.puris.existingSecret | string | `"secret-backend-puris"` | Secret for backend passwords. For more information look into 'backend-secrets.yaml' file. | +| backend.puris.frameworkagreement.credential | string | `"puris"` | The name of the framework agreement | +| backend.puris.frameworkagreement.version | string | `"1.0"` | The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! | +| backend.puris.generatematerialcatenaxid | bool | `true` | Flag that decides whether the auto-generation feature of the puris backend is enabled. Since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing CatenaX-Id via the materials-API of the backend, when you are inserting a new Material entity to the backend's database. If a CatenaX-Id was not assigned to your Material so far, then this feature can auto-generate one randomly. In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. | +| backend.puris.itemstocksubmodel.apiassetid | string | `"itemstocksubmodel-api-asset"` | Asset ID for ItemStockSubmodel API | +| backend.puris.jpa.hibernate.ddl-auto | string | `"create"` | Initialises SQL database with Hibernate property "create" to allow Hibernate to first drop all tables and then create new ones | +| backend.puris.jpa.properties.hibernate.enable_lazy_load_no_trans | bool | `true` | Enables "Lazy load no trans" property to fetch of each lazy entity to open a temporary session and run inside a separate transaction | +| backend.puris.own.bpna | string | `"BPNA4444444444ZZ"` | Own BPNA of the EDC | +| backend.puris.own.bpnl | string | `"BPNL4444444444XX"` | Own BPNL of the EDC | +| backend.puris.own.bpns | string | `"BPNS4444444444XX"` | Own BPNS of the EDC | +| backend.puris.own.country | string | `"Germany"` | Own country | +| backend.puris.own.name | string | `"YOUR-COMPANY-NAME"` | Own name (self-description) | +| backend.puris.own.site.name | string | `"YOUR-SITE-NAME"` | Own site name | +| backend.puris.own.streetnumber | string | `"Musterstraße 110A"` | Own street and number | +| backend.puris.own.zipcodeandcity | string | `"12345 Musterhausen"` | Own zipcode and city | +| backend.puris.productionsubmodel.apiassetid | string | `"productionsubmodel-api-asset"` | Asset ID for ProductionSubmodel API | +| backend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | +| backend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | +| backend.readinessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial readiness probe is checked | +| backend.readinessProbe.periodSeconds | int | `25` | Wait time in seconds between readiness probes | +| backend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | +| backend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | +| backend.replicaCount | int | `1` | Number of replicas of the Kubernetes deployment | +| backend.resources.limits | object | `{"cpu":"3000m","memory":"2048Mi"}` | Maximum resource limits of CPU und memory | +| backend.resources.requests | object | `{"cpu":"1000m","memory":"2048Mi"}` | Minimum requested resources for CPU und memory | +| backend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":8877}` | Security configurations | +| backend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | +| backend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | +| backend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | +| backend.securityContext.runAsUser | int | `8877` | Configures the user id for a run | +| backend.service.port | int | `8081` | The port of the service | +| backend.service.type | string | `"ClusterIP"` | Type of the service | +| backend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| backend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| backend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| backend.tolerations | list | `[]` | Constrains for tolerations | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | list | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Rules for the scheduler to find a pod | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions | list | `[{"key":"app.kubernetes.io/name","operator":"DoesNotExist"}]` | Matching Expressions as key and operators for the pod affinity | +| frontend.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Topology key of the Kubernetes cluster | +| frontend.autoscaling.enabled | bool | `false` | Enable or disable the autoscaling of pods | +| frontend.autoscaling.maxReplicas | int | `100` | Number of maximum replica pods for autoscaling | +| frontend.autoscaling.minReplicas | int | `1` | Number of minimum replica pods for autoscaling | +| frontend.autoscaling.targetCPUUtilizationPercentage | int | `80` | Value of CPU usage in percentage for autoscaling decisions | +| frontend.env | object | `{}` | Extra environment variables that will be passed onto the frontend deployment pods | +| frontend.fullnameOverride | string | `"frontend"` | Possibility to override the fullname | +| frontend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process | +| frontend.image.repository | string | `"tractusx/app-puris-frontend"` | Repository of the docker image | +| frontend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| frontend.imagePullSecrets | list | `[]` | List of used secrets | +| frontend.ingress.annotations | object | `{}` | Annotations for the Ingress controller | +| frontend.ingress.className | string | `"nginx"` | Class name for the Ingress controller | +| frontend.ingress.enabled | bool | `false` | Enable the Ingress | +| frontend.ingress.hosts | list | `[{"host":"your-frontend-host-address.com","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}]` | Hosts for the Ingress controller | +| frontend.ingress.tls | list | `[{"hosts":["your-frontend-host-address.com"],"secretName":"tls-secret"}]` | TLS certificates for the Ingress controller | +| frontend.livenessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks whether a pod is alive or not | +| frontend.livenessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a liveness probe | +| frontend.livenessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial liveness probe is checked | +| frontend.livenessProbe.periodSeconds | int | `10` | Wait time in seconds between liveness probes | +| frontend.livenessProbe.successThreshold | int | `1` | Number of trys until a pod is marked alive | +| frontend.livenessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the liveness probe | +| frontend.nameOverride | string | `""` | Possibility to override the name | +| frontend.nodeSelector | object | `{}` | Constrains for the node selector | +| frontend.podAnnotations | object | `{}` | Annotations added to a running pod | +| frontend.podSecurityContext | object | `{}` | Added security contexts for a pod | +| frontend.puris.appName | string | `"PURIS"` | The name of the app displayed in the frontend | +| frontend.puris.baseUrl | string | `"your-backend-host-address.com"` | The base URL for the backend base URL without further endpoints | +| frontend.puris.endpointCustomer | string | `"stockView/customer?ownMaterialNumber="` | The endpoint for the customers who buy a material identified via the own material number for the stock view | +| frontend.puris.endpointMaterialStocks | string | `"stockView/material-stocks"` | The endpoint for material stocks for the stock view | +| frontend.puris.endpointMaterials | string | `"stockView/materials"` | The endpoint for materials for the stock view | +| frontend.puris.endpointPartnerOwnSites | string | `"partners/ownSites"` | The endpoint for the partners BPNS | +| frontend.puris.endpointProductStocks | string | `"stockView/product-stocks"` | The endpoint for product stocks for the stock view | +| frontend.puris.endpointProducts | string | `"stockView/products"` | The endpoint for products for the stock view | +| frontend.puris.endpointReportedMaterialStocks | string | `"stockView/reported-material-stocks?ownMaterialNumber="` | The endpoint for the partners' (supplier) material stocks that they potentially will deliver to me | +| frontend.puris.endpointReportedProductStocks | string | `"stockView/reported-product-stocks?ownMaterialNumber="` | The endpoint for the partners' (customer) product stocks that they received from me | +| frontend.puris.endpointSupplier | string | `"stockView/supplier?ownMaterialNumber="` | The endpoint for the suppliers who buy a material identified via the own material number for the stock view | +| frontend.puris.endpointUpdateReportedMaterialStocks | string | `"stockView/update-reported-material-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your material stocks on your partners side | +| frontend.puris.endpointUpdateReportedProductStocks | string | `"stockView/update-reported-product-stocks?ownMaterialNumber="` | The endpoint for triggering an update of your product stocks on your partners side | +| frontend.puris.keycloak.clientId | string | `"appXYZ"` | Name of the client which is used for the application. | +| frontend.puris.keycloak.disabled | bool | `true` | Disable the Keycloak integration. | +| frontend.puris.keycloak.realm | string | `"Catena-X"` | Name of the Realm of the keycloak instance. | +| frontend.puris.keycloak.redirectUrlFrontend | string | `"https://your-frontend-url.com"` | URL to use as keycloak redirect url. | +| frontend.puris.keycloak.url | string | `"https://idp.com/auth"` | The URL to the IDP that should be used. | +| frontend.puris.rateLimiting.burst | int | `30` | Burst rate limiting for nginx. | +| frontend.puris.rateLimiting.limit | string | `"10m"` | Bucket zone limit for rate limiting in nginx. | +| frontend.puris.rateLimiting.rate | string | `"10r/s"` | Allowed rates per second for nginx rate limiting. | +| frontend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | +| frontend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | +| frontend.readinessProbe.initialDelaySeconds | int | `10` | Delay in seconds after which an initial readiness probe is checked | +| frontend.readinessProbe.periodSeconds | int | `10` | Wait time in seconds between readiness probes | +| frontend.readinessProbe.successThreshold | int | `1` | Number of trys until a pod is marked ready | +| frontend.readinessProbe.timeoutSeconds | int | `1` | Timeout in seconds of the readiness probe | +| frontend.replicaCount | int | `1` | | +| frontend.resources.limits | object | `{"cpu":"600m","memory":"128Mi"}` | Maximum resource limits of CPU und memory | +| frontend.resources.requests | object | `{"cpu":"200m","memory":"128Mi"}` | Minimum requested resources for CPU und memory | +| frontend.securityContext | object | `{"allowPrivilegeEscalation":false,"runAsGroup":3000,"runAsNonRoot":true,"runAsUser":101}` | Security configurations | +| frontend.securityContext.allowPrivilegeEscalation | bool | `false` | Get more privileges than the parent process | +| frontend.securityContext.runAsGroup | int | `3000` | Configures the group id of a user for a run | +| frontend.securityContext.runAsNonRoot | bool | `true` | Configures the non-root privileges for a run | +| frontend.securityContext.runAsUser | int | `101` | Configures the user id for a run | +| frontend.service.port | int | `8080` | The port of the service | +| frontend.service.type | string | `"ClusterIP"` | Type of the service | +| frontend.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| frontend.serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| frontend.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| frontend.tolerations | list | `[]` | Constrains for tolerations | +| global.domain.backend.ingress | string | `"your-backend-host-address.com"` | | +| postgresql.auth.database | string | `"postgres"` | Name of the database. | +| postgresql.auth.existingSecret | string | `"secret-postgres-init"` | Secret containing the password. For more information look into 'backend-secrets-postgres.yaml' file. | +| postgresql.auth.password | string | `""` | Password for the custom database user. Secret-key 'password' | +| postgresql.auth.passwordPostgres | string | `""` | Password for the database. Secret-key 'postgres-password'. | +| postgresql.auth.username | string | `"puris"` | Username for the custom database user. | +| postgresql.enabled | bool | `true` | Enable postgres by default, set to false to use existing postgres. Make sure to set backend.puris.jpa.hibernate.ddl-auto accordingly (by default database is created using hibernate ddl from backend). | +| postgresql.fullnameOverride | string | `"backend-postgresql"` | Possibility to override the fullname | +| postgresql.service.ports.postgresql | int | `5432` | Port of postgres database. | ---------------------------------------------- Autogenerated from chart metadata using [helm-docs v1.11.3](https://github.com/norwoodj/helm-docs/releases/v1.11.3) From 76719e2d71da66c268749ac71c67a4b0443c1026 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Fri, 10 May 2024 02:28:47 -0700 Subject: [PATCH 10/21] feat(EdcAdapterService): introduced cx-policy usage purpose policy --- .../edc/logic/service/EdcAdapterService.java | 91 ++++++++++++++----- .../edc/logic/util/EdcRequestBodyBuilder.java | 8 +- .../backend/common/util/VariablesService.java | 16 ++++ .../src/main/resources/application.properties | 2 + .../src/test/resources/application.properties | 2 + .../puris/templates/backend-deployment.yaml | 4 + charts/puris/values.yaml | 5 + .../config/customer/puris-backend.properties | 3 + .../config/supplier/puris-backend.properties | 3 + 9 files changed, 108 insertions(+), 26 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index 32fa4b36..2e0f509e 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -1054,43 +1054,84 @@ private boolean testContractPolicyConstraints(JsonNode catalogEntry) { log.debug("Testing constraints in the following catalogEntry: {}", catalogEntry.toPrettyString()); var constraint = Optional.ofNullable(catalogEntry.get("odrl:hasPolicy")) .map(policy -> policy.get("odrl:permission")) - .map(permission -> permission.get("odrl:constraint")); + .map(permission -> permission.get("odrl:constraint")) + .map(con -> con.get("odrl:and")); if (constraint.isEmpty()) { log.debug("Constraint mismatch: we expect to have a constraint in permission node."); return false; } + boolean result = true; - if (constraint.map(con -> con.get("odrl:and")).isPresent()) { - log.debug("constraint uses ordl:and"); - constraint = constraint.map(con -> con.get("odrl:and")); - } - - var leftOperand = constraint.map(cons -> cons.get("odrl:leftOperand")) - .filter( - operand -> (EdcRequestBodyBuilder.CX_POLICY_NAMESPACE + "FrameworkAgreement").equals(operand.asText()) - ); + if (constraint.isPresent() && constraint.get().isArray() && constraint.get().size() == 2) { + Optional frameworkAgreementConstraint = Optional.empty(); + Optional purposeConstraint = Optional.empty(); - var operator = constraint.map(cons -> cons.get("odrl:operator")) - .map(op -> op.get("@id")) - .filter(operand -> "odrl:eq".equals(operand.asText())); + for (JsonNode con : constraint.get()) { // Iterate over array elements and find the nodes + JsonNode leftOperandNode = con.get("odrl:leftOperand"); + if (leftOperandNode != null && (EdcRequestBodyBuilder.CX_POLICY_NAMESPACE + "FrameworkAgreement").equals(leftOperandNode.asText())) { + frameworkAgreementConstraint = Optional.of(con); + } + if (leftOperandNode != null && (EdcRequestBodyBuilder.CX_POLICY_NAMESPACE + "UsagePurpose").equals(leftOperandNode.asText())) { + purposeConstraint = Optional.of(con); + } + } - var rightOperand = constraint.map(cons -> cons.get("odrl:rightOperand")) - .filter(operand -> variablesService.getPurisFrameworkAgreementWithVersion().equals(operand.asText())); + if (frameworkAgreementConstraint.isPresent()) { + result = result && testSingleConstraint( + frameworkAgreementConstraint, + EdcRequestBodyBuilder.CX_POLICY_NAMESPACE + "FrameworkAgreement", + "odrl:eq", + variablesService.getPurisFrameworkAgreementWithVersion() + ); + } else { + log.debug("FrameworkAgreement Policy not found."); + } - if (leftOperand.isEmpty() || operator.isEmpty() || rightOperand.isEmpty()) { - log.debug( - "Did not found leftOperand {}, operator {}, rightOperand {}", - leftOperand.isEmpty(), - operator.isEmpty(), - rightOperand.isEmpty() - ); + if (purposeConstraint.isPresent()) { + result = result && testSingleConstraint( + purposeConstraint, + EdcRequestBodyBuilder.CX_POLICY_NAMESPACE + "UsagePurpose", + "odrl:eq", + variablesService.getPurisPuposeWithVersion() + ); + } else { + log.debug("Usage Purpose Policy not found."); + } + } else { log.info( - "Framework Agreement Policy (cx-policy:FrameworkAgreement) not fulfilled. Application supports {}:{}", - variablesService.getPurisFrameworkAgreement(), - variablesService.getPurisFrameworkAgreementVersion() + "2 Constraints (Framework Agreement, Purpose) are expected but got {} constraints.", + constraint.get().size() ); return false; } + + return result; + } + + private boolean testSingleConstraint(Optional constraintToTest, String targetLeftOperand, String targetOperator, String targetRightOperand) { + + if (!constraintToTest.isPresent()) return false; + + JsonNode con = constraintToTest.get(); + + JsonNode leftOperandNode = con.get("odrl:leftOperand"); + if (leftOperandNode == null || !targetLeftOperand.equals(leftOperandNode.asText())) { + log.debug("Left operand {} odes not equal expected value {}.", leftOperandNode.asText(), targetLeftOperand); + return false; + } + + JsonNode operatorNode = con.get("odrl:operator").get("@id"); + if (operatorNode == null || !targetOperator.equals(operatorNode.asText())) { + log.debug("Operator {} does not equal expected value {}.", operatorNode.asText(), targetOperator); + return false; + } + + JsonNode rightOperandNode = con.get("odrl:rightOperand"); + if (operatorNode == null || !targetRightOperand.equals(rightOperandNode.asText())) { + log.debug("Right operand {} odes not equal expected value {}.", rightOperandNode.asText(), targetRightOperand); + return false; + } + log.info("Contract Offer constraints can be fulfilled by PURIS FOSS application (passed)."); return true; diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java index 5cc66b89..1a6476e4 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java @@ -186,11 +186,17 @@ public JsonNode buildFrameworkPolicy() { List constraints = new ArrayList<>(); constraints.add(new PolicyConstraintDto( - CX_POLICY_NAMESPACE + ":FrameworkAgreement", + CX_POLICY_NAMESPACE + "FrameworkAgreement", "eq", variablesService.getPurisFrameworkAgreementWithVersion() )); + constraints.add(new PolicyConstraintDto( + CX_POLICY_NAMESPACE + "UsagePurpose", + "eq", + variablesService.getPurisPuposeWithVersion() + )); + JsonNode body = buildPolicy( CONTRACT_POLICY_ID, constraints, diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java index 06413e2d..9c19600c 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/util/VariablesService.java @@ -131,6 +131,18 @@ public class VariablesService { */ private String purisFrameworkAgreementVersion; + @Value("${puris.purpose.name}") + /** + * The name of the purpose to be used for submodel contract policies. + */ + private String purisPurposeName; + + @Value("${puris.purpose.version}") + /** + * The version of the purpse to be used for submodel contract policies. + */ + private String purisPurposeVersion; + @Value("${puris.api.key}") /** * The key for accessing the api. @@ -251,4 +263,8 @@ public String getPartTypeSubmodelApiAssetId() { public String getPurisFrameworkAgreementWithVersion() { return getPurisFrameworkAgreement() + ":" + getPurisFrameworkAgreementVersion(); } + + public String getPurisPuposeWithVersion() { + return getPurisPurposeName() + ":" + getPurisPurposeVersion(); + } } diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 31da282c..0497bca0 100755 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -13,6 +13,8 @@ puris.deliverysubmodel.apiassetid=${PURIS_DELIVERYSUBMODEL_APIASSETID:deliverysu puris.frameworkagreement.use=${PURIS_FRAMEWORKAGREEMENT_USE:false} puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:puris} puris.frameworkagreement.version=${PURIS_FRAMEWORKAGREEMENT_VERSION:1.0} +puris.purpose.name=${PURIS_PURPOSE_NAME:cx.puris.base} +puris.purpose.version=${PURIS_PURPOSE_VERSION:1} puris.api.key=${PURIS_API_KEY:test} puris.dtr.url=${PURIS_DTR_URL:http://localhost:4243} diff --git a/backend/src/test/resources/application.properties b/backend/src/test/resources/application.properties index 6d941266..5a96ce78 100755 --- a/backend/src/test/resources/application.properties +++ b/backend/src/test/resources/application.properties @@ -10,6 +10,8 @@ puris.deliverysubmodel.apiassetid=${PURIS_DELIVERYSUBMODEL_APIASSETID:deliverysu puris.frameworkagreement.use=${PURIS_FRAMEWORKAGREEMENT_USE:false} puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:puris} puris.frameworkagreement.version=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:1.0} +puris.purpose.name=${PURIS_PURPOSE_NAME:cx.puris.base} +puris.purpose.version=${PURIS_PURPOSE_VERSION:1} puris.api.key=${PURIS_API_KEY:test} puris.dtr.url=${PURIS_DTR_URL:http://localhost:4243} puris.generatematerialcatenaxid=${PURIS_GENERATEMATERIALCATENAXID:true} diff --git a/charts/puris/templates/backend-deployment.yaml b/charts/puris/templates/backend-deployment.yaml index 876a3a32..1b91a08b 100644 --- a/charts/puris/templates/backend-deployment.yaml +++ b/charts/puris/templates/backend-deployment.yaml @@ -151,6 +151,10 @@ spec: value: "{{ .Values.backend.puris.frameworkagreement.credential }}" - name: PURIS_FRAMEWORKAGREEMENT_VERSION value: "{{ .Values.backend.puris.frameworkagreement.version }}" + - name: PURIS_PURPOSE_NAME + value: "{{ .Values.backend.puris.purpose.name }}" + - name: PURIS_PURPOSE_VERSION + value: "{{ .Values.backend.puris.purpose.version }}" - name: PURIS_DTR_URL value: "{{ .Values.backend.puris.dtr.url }}" - name: PURIS_GENERATEMATERIALCATENAXID diff --git a/charts/puris/values.yaml b/charts/puris/values.yaml index 7bbfeca1..fa56b8c5 100644 --- a/charts/puris/values.yaml +++ b/charts/puris/values.yaml @@ -428,6 +428,11 @@ backend: credential: puris # -- The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! version: "1.0" + purpose: + # -- The name of the purpose to use for submodel contracts + name: "cx.puris.base" + # -- The version of the purpose to use for submodel contracts. NEEDS TO BE PUT AS "STRING"! + version: "1" edr: # -- Number of minutes before received authentication data of a consumer pull is removed from memory deletiontimer: 2 diff --git a/local/tractus-x-edc/config/customer/puris-backend.properties b/local/tractus-x-edc/config/customer/puris-backend.properties index ddba89bc..0a795e30 100644 --- a/local/tractus-x-edc/config/customer/puris-backend.properties +++ b/local/tractus-x-edc/config/customer/puris-backend.properties @@ -9,6 +9,9 @@ puris.demandsubmodel.apiassetid=demandsubmodel-api-asset puris.deliverysubmodel.apiassetid=deliverysubmodel-api-asset puris.frameworkagreement.credential=puris puris.frameworkagreement.version=1.0 +puris.purpose.name=cx.puris.base +puris.purpose.version=1 +logging.level.org.eclipse.tractusx.puris.backend=DEBUG puris.api.key=${CUSTOMER_BACKEND_API_KEY} puris.dtr.url=http://dtr-customer:4243 puris.generatematerialcatenaxid=true diff --git a/local/tractus-x-edc/config/supplier/puris-backend.properties b/local/tractus-x-edc/config/supplier/puris-backend.properties index 3336ed2f..035a70a5 100644 --- a/local/tractus-x-edc/config/supplier/puris-backend.properties +++ b/local/tractus-x-edc/config/supplier/puris-backend.properties @@ -9,6 +9,9 @@ puris.demandsubmodel.apiassetid=demandsubmodel-api-asset puris.deliverysubmodel.apiassetid=deliverysubmodel-api-asset puris.frameworkagreement.credential=puris puris.frameworkagreement.version=1.0 +puris.purpose.name=cx.puris.base +puris.purpose.version=1 +logging.level.org.eclipse.tractusx.puris.backend=DEBUG puris.api.key=${SUPPLIER_BACKEND_API_KEY} puris.dtr.url=http://dtr-supplier:4243 puris.generatematerialcatenaxid=true From cd17779350f2edaf07d899810f2ff7ca0189a401 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Tue, 14 May 2024 05:27:03 -0700 Subject: [PATCH 11/21] refactor(EdcRequestBodyBuilder): make PolicyConstraintDto a private record --- .../edc/logic/dto/PolicyConstraintDto.java | 34 ------------------- .../edc/logic/util/EdcRequestBodyBuilder.java | 29 +++++++++------- 2 files changed, 17 insertions(+), 46 deletions(-) delete mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/PolicyConstraintDto.java diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/PolicyConstraintDto.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/PolicyConstraintDto.java deleted file mode 100644 index 8b7b8d53..00000000 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/PolicyConstraintDto.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2024 Volkswagen AG - * 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 - */ - -package org.eclipse.tractusx.puris.backend.common.edc.logic.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -@AllArgsConstructor -@Getter -public class PolicyConstraintDto { - - private String leftOperand; - private String operator; - private String rightOperand; - -} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java index 1a6476e4..59f8f7ca 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/util/EdcRequestBodyBuilder.java @@ -26,7 +26,6 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; -import org.eclipse.tractusx.puris.backend.common.edc.logic.dto.PolicyConstraintDto; import org.eclipse.tractusx.puris.backend.common.util.VariablesService; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; import org.springframework.beans.factory.annotation.Autowired; @@ -58,6 +57,12 @@ public class EdcRequestBodyBuilder { public static final String AAS_SEMANTICS_NAMESPACE = "https://admin-shell.io/aas/3/0/HasSemantics/"; public static final String CONTRACT_POLICY_ID = "Contract_Policy"; + /** + * helper class to encapsulate PolicyConstraint + **/ + private record PolicyConstraint(String leftOperand, String operator, String rightOperand) { + } + /** * Creates a request body for requesting a catalog in DSP protocol. * You can add filter criteria. However, at the moment there are issues @@ -100,7 +105,7 @@ public ObjectNode buildBasicCatalogRequestBody(String counterPartyDspUrl, String * @param policyProfile profile to use for odrl:policy, may be null (should only be used for contract policies) * @return body to use for policy request */ - private JsonNode buildPolicy(String policyId, List constraints, String policyProfile) { + private JsonNode buildPolicy(String policyId, List constraints, String policyProfile) { ObjectNode body = getPolicyContextObject(); body.put("@type", "PolicyDefinitionRequestDto"); body.put("@id", policyId); @@ -127,14 +132,14 @@ private JsonNode buildPolicy(String policyId, List constrai var andArray = MAPPER.createArrayNode(); constraintObject.set("and", andArray); - for (PolicyConstraintDto policyConstraintDto : constraints) { + for (PolicyConstraint policyConstraint : constraints) { ObjectNode constraint = MAPPER.createObjectNode(); constraint.put("@type", "LogicalConstraint"); - constraint.put("leftOperand", policyConstraintDto.getLeftOperand()); + constraint.put("leftOperand", policyConstraint.leftOperand); - constraint.put("operator", policyConstraintDto.getOperator()); + constraint.put("operator", policyConstraint.operator); - constraint.put("rightOperand", policyConstraintDto.getRightOperand()); + constraint.put("rightOperand", policyConstraint.rightOperand); andArray.add(constraint); } @@ -151,15 +156,15 @@ private JsonNode buildPolicy(String policyId, List constrai */ public JsonNode buildBpnAndMembershipRestrictedPolicy(Partner partner) { - List constraints = new ArrayList<>(); + List constraints = new ArrayList<>(); - constraints.add(new PolicyConstraintDto( + constraints.add(new PolicyConstraint( "BusinessPartnerNumber", "eq", partner.getBpnl() )); - constraints.add(new PolicyConstraintDto( + constraints.add(new PolicyConstraint( "Membership", "eq", "active" @@ -183,15 +188,15 @@ public JsonNode buildBpnAndMembershipRestrictedPolicy(Partner partner) { */ public JsonNode buildFrameworkPolicy() { - List constraints = new ArrayList<>(); + List constraints = new ArrayList<>(); - constraints.add(new PolicyConstraintDto( + constraints.add(new PolicyConstraint( CX_POLICY_NAMESPACE + "FrameworkAgreement", "eq", variablesService.getPurisFrameworkAgreementWithVersion() )); - constraints.add(new PolicyConstraintDto( + constraints.add(new PolicyConstraint( CX_POLICY_NAMESPACE + "UsagePurpose", "eq", variablesService.getPurisPuposeWithVersion() From 517a2c7caab68a305fd4d26b60e11a0cc663c153 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Tue, 14 May 2024 05:37:12 -0700 Subject: [PATCH 12/21] refactor(EdcAdapterService): improved null value handling --- .../edc/logic/service/EdcAdapterService.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index 2e0f509e..31238abe 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -114,7 +114,7 @@ public Response sendGetRequest(List pathSegments) throws IOException { * Any caller of this method has the responsibility to close * the returned Response object after using it. * - * @param requestBody The request body; null if no body is needed + * @param requestBody The request body, not null * @param pathSegments The path segments * @return The response from your control plane * @throws IOException If the connection to your control plane fails @@ -124,11 +124,7 @@ private Response sendPostRequest(JsonNode requestBody, List pathSegments for (var pathSegment : pathSegments) { urlBuilder.addPathSegment(pathSegment); } - RequestBody body = null; - - if (requestBody != null) { - body = RequestBody.create(requestBody.toString(), MediaType.parse("application/json")); - } + RequestBody body = RequestBody.create(requestBody.toString(), MediaType.parse("application/json")); var request = new Request.Builder() .post(body) @@ -1116,19 +1112,23 @@ private boolean testSingleConstraint(Optional constraintToTest, String JsonNode leftOperandNode = con.get("odrl:leftOperand"); if (leftOperandNode == null || !targetLeftOperand.equals(leftOperandNode.asText())) { - log.debug("Left operand {} odes not equal expected value {}.", leftOperandNode.asText(), targetLeftOperand); + String leftOperand = leftOperandNode == null ? "null" : leftOperandNode.asText(); + log.debug("Left operand '{}' does not equal expected value '{}'.", leftOperand, targetLeftOperand); return false; } - JsonNode operatorNode = con.get("odrl:operator").get("@id"); + JsonNode operatorNode = con.get("odrl:operator"); + operatorNode = operatorNode == null ? null : operatorNode.get("@id"); if (operatorNode == null || !targetOperator.equals(operatorNode.asText())) { - log.debug("Operator {} does not equal expected value {}.", operatorNode.asText(), targetOperator); + String operator = operatorNode == null ? "null" : operatorNode.asText(); + log.debug("Operator '{}' does not equal expected value '{}'.", operator, targetOperator); return false; } JsonNode rightOperandNode = con.get("odrl:rightOperand"); if (operatorNode == null || !targetRightOperand.equals(rightOperandNode.asText())) { - log.debug("Right operand {} odes not equal expected value {}.", rightOperandNode.asText(), targetRightOperand); + String rightOperand = rightOperandNode == null ? "null" : rightOperandNode.asText(); + log.debug("Right operand '{}' odes not equal expected value '{}'.", rightOperand, targetRightOperand); return false; } From 65178bc45aaea2e6942d8a630a71477003d57d21 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Tue, 14 May 2024 22:37:03 -0700 Subject: [PATCH 13/21] refactor(EdcAdapterService): remove storing of edr and expiry check --- DEPENDENCIES_BACKEND | 2 - backend/DEPENDENCIES | 2 - backend/pom.xml | 13 +-- .../EndpointDataReferenceReceiver.java | 3 +- .../backend/common/edc/logic/dto/EdrDto.java | 19 ++-- .../edc/logic/service/EdcAdapterService.java | 93 +++++++------------ .../config/customer/puris-backend.properties | 4 +- .../config/supplier/puris-backend.properties | 4 +- 8 files changed, 47 insertions(+), 93 deletions(-) diff --git a/DEPENDENCIES_BACKEND b/DEPENDENCIES_BACKEND index 329d42f5..d5be54a6 100644 --- a/DEPENDENCIES_BACKEND +++ b/DEPENDENCIES_BACKEND @@ -8,9 +8,7 @@ maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/2.15.3, maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.15.3, Apache-2.0, approved, #7930 maven/mavencentral/com.fasterxml.jackson.module/jackson-module-parameter-names/2.15.3, Apache-2.0, approved, #8803 maven/mavencentral/com.fasterxml/classmate/1.6.0, Apache-2.0, approved, clearlydefined -maven/mavencentral/com.github.stephenc.jcip/jcip-annotations/1.0-1, Apache-2.0, approved, CQ21949 maven/mavencentral/com.jayway.jsonpath/json-path/2.8.0, Apache-2.0, approved, clearlydefined -maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.37.3, Apache-2.0, approved, #11701 maven/mavencentral/com.squareup.okhttp3/okhttp/4.12.0, Apache-2.0, approved, #11156 maven/mavencentral/com.squareup.okio/okio-jvm/3.6.0, Apache-2.0, approved, #11158 maven/mavencentral/com.squareup.okio/okio/3.6.0, Apache-2.0, approved, #11155 diff --git a/backend/DEPENDENCIES b/backend/DEPENDENCIES index 329d42f5..d5be54a6 100644 --- a/backend/DEPENDENCIES +++ b/backend/DEPENDENCIES @@ -8,9 +8,7 @@ maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/2.15.3, maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.15.3, Apache-2.0, approved, #7930 maven/mavencentral/com.fasterxml.jackson.module/jackson-module-parameter-names/2.15.3, Apache-2.0, approved, #8803 maven/mavencentral/com.fasterxml/classmate/1.6.0, Apache-2.0, approved, clearlydefined -maven/mavencentral/com.github.stephenc.jcip/jcip-annotations/1.0-1, Apache-2.0, approved, CQ21949 maven/mavencentral/com.jayway.jsonpath/json-path/2.8.0, Apache-2.0, approved, clearlydefined -maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.37.3, Apache-2.0, approved, #11701 maven/mavencentral/com.squareup.okhttp3/okhttp/4.12.0, Apache-2.0, approved, #11156 maven/mavencentral/com.squareup.okio/okio-jvm/3.6.0, Apache-2.0, approved, #11158 maven/mavencentral/com.squareup.okio/okio/3.6.0, Apache-2.0, approved, #11155 diff --git a/backend/pom.xml b/backend/pom.xml index 68987a8f..e79e5871 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -1,9 +1,9 @@ - - com.nimbusds - nimbus-jose-jwt - ${nimbus.version} - diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EndpointDataReferenceReceiver.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EndpointDataReferenceReceiver.java index 08b029eb..20bd59e6 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EndpointDataReferenceReceiver.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/controller/EndpointDataReferenceReceiver.java @@ -37,7 +37,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import java.util.Date; import java.util.regex.Pattern; /** @@ -89,7 +88,7 @@ private ResponseEntity authCodeReceivingEndpoint(@RequestBody JsonNode b return ResponseEntity.status(400).build(); } - edrService.save(transferId, new EdrDto(authKey, authCode, endpoint, new Date())); + edrService.save(transferId, new EdrDto(authKey, authCode, endpoint)); log.debug("EDR endpoint stored authCode for " + transferId); return ResponseEntity.status(200).build(); } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/EdrDto.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/EdrDto.java index b8ccdb56..0efc4908 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/EdrDto.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/dto/EdrDto.java @@ -23,20 +23,17 @@ import org.eclipse.tractusx.puris.backend.common.edc.logic.service.EndpointDataReferenceService; -import java.util.Date; - /** * An internal, immutable Dto class used by the {@link EndpointDataReferenceService} * It contains an authKey, authCode and endpoint. * - * @param authKey This defines the key, under which the - * authCode is to be sent to the data plane. - * For example: "Authorization" - * @param authCode This is the secret key to be sent - * to the data plane. - * @param endpoint The address of the data plane that has - * to handle the consumer pull. - * @param expiresAt The expiry data in ms till data + * @param authKey This defines the key, under which the + * authCode is to be sent to the data plane. + * For example: "Authorization" + * @param authCode This is the secret key to be sent + * to the data plane. + * @param endpoint The address of the data plane that has + * to handle the consumer pull. */ -public record EdrDto(String authKey, String authCode, String endpoint, Date expiresAt) { +public record EdrDto(String authKey, String authCode, String endpoint) { } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index 31238abe..a7df0baa 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -23,9 +23,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.nimbusds.jwt.JWT; -import com.nimbusds.jwt.JWTClaimsSet; -import com.nimbusds.jwt.JWTParser; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import org.eclipse.tractusx.puris.backend.common.edc.domain.model.SubmodelType; @@ -36,12 +33,12 @@ import org.eclipse.tractusx.puris.backend.masterdata.domain.model.MaterialPartnerRelation; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; import org.eclipse.tractusx.puris.backend.stock.logic.dto.itemstocksamm.DirectionCharacteristic; +import org.jetbrains.annotations.Nullable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.text.ParseException; import java.util.*; import java.util.regex.Pattern; @@ -58,8 +55,6 @@ public class EdcAdapterService { private final ObjectMapper objectMapper; @Autowired private EdcRequestBodyBuilder edcRequestBodyBuilder; - @Autowired - private EndpointDataReferenceService edrService; @Autowired private EdcContractMappingService edcContractMappingService; @@ -580,16 +575,8 @@ private JsonNode getSubmodelFromPartner(MaterialPartnerRelation mpr, SubmodelTyp break; } } - EdrDto edrDto = null; - // Await arrival of edr - for (int i = 0; i < 100; i++) { - Thread.sleep(100); - edrDto = getEdrForTransferProcessId(transferId); //edrService.findByTransferId(transferId); - if (edrDto != null) { - log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); - break; - } - } + EdrDto edrDto = getAndAwaitEdrDto(transferId); + log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); if (edrDto == null) { log.error("Failed to obtain EDR data for " + assetId + " with " + partner.getEdcUrl()); return doSubmodelRequest(type, mpr, direction, --retries); @@ -622,6 +609,26 @@ private JsonNode getSubmodelFromPartner(MaterialPartnerRelation mpr, SubmodelTyp return getSubmodelFromPartner(mpr, type, direction, --retries); } + /** + * get the EDR via edr api and retry multiple times in case the EDR has not yet been available + * + * @param transferProcessId to get the EDR for, not null + * @return edr received, or null if not yet available + * @throws InterruptedException if thread was not able to sleep + */ + private @Nullable EdrDto getAndAwaitEdrDto(String transferProcessId) throws InterruptedException { + EdrDto edrDto = null; + // retry, if Data Space Protocol / Data Plane Provisioning communication needs time to prepare + for (int i = 0; i < 100; i++) { + edrDto = getEdrForTransferProcessId(transferProcessId); + if (edrDto != null) { + break; + } + Thread.sleep(100); + } + return edrDto; + } + public JsonNode doSubmodelRequest(SubmodelType type, MaterialPartnerRelation mpr, DirectionCharacteristic direction, int retries) { if (retries < 0) { return null; @@ -779,19 +786,12 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man break; } } - EdrDto edrDto = null; - // Await arrival of edr - for (int i = 0; i < 100; i++) { - edrDto = getEdrForTransferProcessId(transferId);//edrService.findByTransferId(transferId); - if (edrDto != null) { - log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); - break; - } - Thread.sleep(100); - } + EdrDto edrDto = getAndAwaitEdrDto(transferId); if (edrDto == null) { log.error("Failed to obtain EDR data for " + assetId + " with " + partner.getEdcUrl()); return getAasSubmodelDescriptors(manufacturerPartId, manufacturerId, mpr, --retries); + } else { + log.info("Received EDR data for " + assetId + " with " + partner.getEdcUrl()); } HttpUrl.Builder urlBuilder = HttpUrl.parse(edrDto.endpoint()).newBuilder() .addPathSegment("api") @@ -863,26 +863,6 @@ private JsonNode getAasSubmodelDescriptors(String manufacturerPartId, String man */ private EdrDto getEdrForTransferProcessId(String transferProcessId) { - // Note: If we decode the auth token, we could add the exp as expiresAt so that I can store the EDR and lookup - // again - EdrDto storedEdr = edrService.findByTransferId(transferProcessId); - log.debug("storedEdr: {}", storedEdr); - - // got a stored edr that has an auth token that will not expire within 5 seconds - // Notes: - // - this might cause an issue if there are different time zones between EDC and us - // - we could also implement an ProxyRequestInterceptor that gets a fresh token for a TransferProcessId - if (storedEdr != null && storedEdr.expiresAt().before(new Date(System.currentTimeMillis() + 5000))) { - log.info("Reuse EDR directly as it will not expire within 5 seconds"); - return storedEdr; - } - - if (storedEdr != null) { - log.debug("Expiry edr: {} VS expiry within 5 sec {}", storedEdr.expiresAt(), new Date(System.currentTimeMillis() + 5000)); - } else { - log.debug("No EDR token found"); - } - try (Response response = sendGetRequest( List.of("v2", "edrs", transferProcessId, "dataaddress"), Map.of("auto_refresh", "true")) @@ -892,18 +872,11 @@ private EdrDto getEdrForTransferProcessId(String transferProcessId) { String dataPlaneEndpoint = responseObject.get("endpoint").asText(); String authToken = responseObject.get("authorization").asText(); - JWT jwt = JWTParser.parse(authToken); - JWTClaimsSet claims = jwt.getJWTClaimsSet(); - Date expirationTime = claims.getExpirationTime(); - - storedEdr = new EdrDto("Authorization", authToken, dataPlaneEndpoint, expirationTime); - edrService.save(transferProcessId, storedEdr); - log.debug("Requested EDR successfully: {}", storedEdr); + EdrDto edr = new EdrDto("Authorization", authToken, dataPlaneEndpoint); + log.debug("Requested EDR successfully: {}", edr); - return storedEdr; + return edr; - } catch (ParseException e) { - log.error("EDR token could not be parsed: {}", e); } catch (IOException e) { log.error("EDR token for transfer process with ID {} could not be obtained", transferProcessId); } @@ -937,7 +910,7 @@ private void terminateTransfer(String transferProcessId) { log.info("Terminated transfer process with id {}.", transferProcessId); } } catch (IOException e) { - log.error("Error while trying to terminate transfer: {}", e); + log.error("Error while trying to terminate transfer: ", e); } } @@ -1058,7 +1031,7 @@ private boolean testContractPolicyConstraints(JsonNode catalogEntry) { } boolean result = true; - if (constraint.isPresent() && constraint.get().isArray() && constraint.get().size() == 2) { + if (constraint.get().isArray() && constraint.get().size() == 2) { Optional frameworkAgreementConstraint = Optional.empty(); Optional purposeConstraint = Optional.empty(); @@ -1106,7 +1079,7 @@ private boolean testContractPolicyConstraints(JsonNode catalogEntry) { private boolean testSingleConstraint(Optional constraintToTest, String targetLeftOperand, String targetOperator, String targetRightOperand) { - if (!constraintToTest.isPresent()) return false; + if (constraintToTest.isEmpty()) return false; JsonNode con = constraintToTest.get(); @@ -1126,7 +1099,7 @@ private boolean testSingleConstraint(Optional constraintToTest, String } JsonNode rightOperandNode = con.get("odrl:rightOperand"); - if (operatorNode == null || !targetRightOperand.equals(rightOperandNode.asText())) { + if (rightOperandNode == null || !targetRightOperand.equals(rightOperandNode.asText())) { String rightOperand = rightOperandNode == null ? "null" : rightOperandNode.asText(); log.debug("Right operand '{}' odes not equal expected value '{}'.", rightOperand, targetRightOperand); return false; diff --git a/local/tractus-x-edc/config/customer/puris-backend.properties b/local/tractus-x-edc/config/customer/puris-backend.properties index 0a795e30..e4a5673d 100644 --- a/local/tractus-x-edc/config/customer/puris-backend.properties +++ b/local/tractus-x-edc/config/customer/puris-backend.properties @@ -11,16 +11,14 @@ puris.frameworkagreement.credential=puris puris.frameworkagreement.version=1.0 puris.purpose.name=cx.puris.base puris.purpose.version=1 -logging.level.org.eclipse.tractusx.puris.backend=DEBUG +logging.level.org.eclipse.tractusx.puris.backend=INFO puris.api.key=${CUSTOMER_BACKEND_API_KEY} puris.dtr.url=http://dtr-customer:4243 puris.generatematerialcatenaxid=true - edc.controlplane.key=${EDC_API_PW} edc.controlplane.management.url=http://customer-control-plane:8181/management edc.controlplane.protocol.url=http://customer-control-plane:8184/api/v1/dsp edc.dataplane.public.url=http://customer-data-plane:8285/api/public/ - own.bpnl=BPNL4444444444XX own.name=Control Unit Creator Inc. own.bpns=BPNS4444444444XX diff --git a/local/tractus-x-edc/config/supplier/puris-backend.properties b/local/tractus-x-edc/config/supplier/puris-backend.properties index 035a70a5..3277e983 100644 --- a/local/tractus-x-edc/config/supplier/puris-backend.properties +++ b/local/tractus-x-edc/config/supplier/puris-backend.properties @@ -11,16 +11,14 @@ puris.frameworkagreement.credential=puris puris.frameworkagreement.version=1.0 puris.purpose.name=cx.puris.base puris.purpose.version=1 -logging.level.org.eclipse.tractusx.puris.backend=DEBUG +logging.level.org.eclipse.tractusx.puris.backend=INFO puris.api.key=${SUPPLIER_BACKEND_API_KEY} puris.dtr.url=http://dtr-supplier:4243 puris.generatematerialcatenaxid=true - edc.controlplane.key=${EDC_API_PW} edc.controlplane.management.url=http://supplier-control-plane:9181/management edc.controlplane.protocol.url=http://supplier-control-plane:9184/api/v1/dsp edc.dataplane.public.url=http://supplier-data-plane:9285/api/public/ - own.bpnl=BPNL1234567890ZZ own.name=Semiconductor Supplier Inc. own.bpns=BPNS1234567890ZZ From fbf0831db559b2e66cbbbb32caf684b111a5e8cc Mon Sep 17 00:00:00 2001 From: --show-origin Date: Wed, 15 May 2024 06:26:37 -0700 Subject: [PATCH 14/21] Revert "chore(Tractusx-Edc): bump version to 0.7.1" This reverts commit bcb04e817274e827eff59de7a73603479829f597. --- local/tractus-x-edc/docker-compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/local/tractus-x-edc/docker-compose.yaml b/local/tractus-x-edc/docker-compose.yaml index 9f95a37a..afb927c3 100644 --- a/local/tractus-x-edc/docker-compose.yaml +++ b/local/tractus-x-edc/docker-compose.yaml @@ -21,13 +21,13 @@ version: "3" services: control-plane: - image: tractusx/edc-controlplane-postgresql-hashicorp-vault:0.7.1 + image: tractusx/edc-controlplane-postgresql-hashicorp-vault:0.7.0 volumes: - ./config/default/opentelemetry.properties:/app/opentelemetry.properties - ./config/default/logging.properties:/app/logging.properties data-plane: - image: tractusx/edc-dataplane-hashicorp-vault:0.7.1 + image: tractusx/edc-dataplane-hashicorp-vault:0.7.0 volumes: - ./config/default/opentelemetry.properties:/app/opentelemetry.properties - ./config/default/logging.properties:/app/logging.properties From 3a71a7032dbc75d15e8906e711e57fac69f1933a Mon Sep 17 00:00:00 2001 From: --show-origin Date: Wed, 15 May 2024 06:59:43 -0700 Subject: [PATCH 15/21] chore: updated frontend dependencies --- DEPENDENCIES_FRONTEND | 2 +- frontend/DEPENDENCIES | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPENDENCIES_FRONTEND b/DEPENDENCIES_FRONTEND index 09e994b8..cc86c023 100644 --- a/DEPENDENCIES_FRONTEND +++ b/DEPENDENCIES_FRONTEND @@ -172,7 +172,7 @@ npm/npmjs/-/path-key/3.1.1, MIT, approved, clearlydefined npm/npmjs/-/path-parse/1.0.7, MIT, approved, clearlydefined npm/npmjs/-/path-scurry/1.10.1, BlueOak-1.0.0, approved, #9370 npm/npmjs/-/path-type/4.0.0, MIT, approved, clearlydefined -npm/npmjs/-/picocolors/1.0.0, ISC, approved, clearlydefined +npm/npmjs/-/picocolors/1.0.0, ISC, approved, #14718 npm/npmjs/-/picomatch/2.3.1, MIT, approved, clearlydefined npm/npmjs/-/pify/2.3.0, MIT, approved, clearlydefined npm/npmjs/-/pirates/4.0.6, MIT, approved, #680 diff --git a/frontend/DEPENDENCIES b/frontend/DEPENDENCIES index 09e994b8..cc86c023 100644 --- a/frontend/DEPENDENCIES +++ b/frontend/DEPENDENCIES @@ -172,7 +172,7 @@ npm/npmjs/-/path-key/3.1.1, MIT, approved, clearlydefined npm/npmjs/-/path-parse/1.0.7, MIT, approved, clearlydefined npm/npmjs/-/path-scurry/1.10.1, BlueOak-1.0.0, approved, #9370 npm/npmjs/-/path-type/4.0.0, MIT, approved, clearlydefined -npm/npmjs/-/picocolors/1.0.0, ISC, approved, clearlydefined +npm/npmjs/-/picocolors/1.0.0, ISC, approved, #14718 npm/npmjs/-/picomatch/2.3.1, MIT, approved, clearlydefined npm/npmjs/-/pify/2.3.0, MIT, approved, clearlydefined npm/npmjs/-/pirates/4.0.6, MIT, approved, #680 From 22407abb68e3c97076869867f0d6a3947064cb63 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Wed, 15 May 2024 23:41:29 -0700 Subject: [PATCH 16/21] fix(FrameworkAgreementCredential): made the config uppercase --- backend/src/main/resources/application.properties | 2 +- backend/src/test/resources/application.properties | 2 +- charts/puris/README.md | 4 +++- charts/puris/values.yaml | 4 ++-- local/tractus-x-edc/config/customer/puris-backend.properties | 2 +- local/tractus-x-edc/config/supplier/puris-backend.properties | 2 +- 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 0497bca0..ec851ede 100755 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -11,7 +11,7 @@ puris.productionsubmodel.apiassetid=${PURIS_PRODUCTIONSUBMODEL_APIASSETID:produc puris.demandsubmodel.apiassetid=${PURIS_DEMANDSUBMODEL_APIASSETID:demandsubmodel-api-asset} puris.deliverysubmodel.apiassetid=${PURIS_DELIVERYSUBMODEL_APIASSETID:deliverysubmodel-api-asset} puris.frameworkagreement.use=${PURIS_FRAMEWORKAGREEMENT_USE:false} -puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:puris} +puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:Puris} puris.frameworkagreement.version=${PURIS_FRAMEWORKAGREEMENT_VERSION:1.0} puris.purpose.name=${PURIS_PURPOSE_NAME:cx.puris.base} puris.purpose.version=${PURIS_PURPOSE_VERSION:1} diff --git a/backend/src/test/resources/application.properties b/backend/src/test/resources/application.properties index 5a96ce78..57d1390c 100755 --- a/backend/src/test/resources/application.properties +++ b/backend/src/test/resources/application.properties @@ -8,7 +8,7 @@ puris.productionsubmodel.apiassetid=${PURIS_PRODUCTIONSUBMODEL_APIASSETID:produc puris.demandsubmodel.apiassetid=${PURIS_DEMANDSUBMODEL_APIASSETID:demandsubmodel-api-asset} puris.deliverysubmodel.apiassetid=${PURIS_DELIVERYSUBMODEL_APIASSETID:deliverysubmodel-api-asset} puris.frameworkagreement.use=${PURIS_FRAMEWORKAGREEMENT_USE:false} -puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:puris} +puris.frameworkagreement.credential=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:Puris} puris.frameworkagreement.version=${PURIS_FRAMEWORKAGREEMENT_CREDENTIAL:1.0} puris.purpose.name=${PURIS_PURPOSE_NAME:cx.puris.base} puris.purpose.version=${PURIS_PURPOSE_VERSION:1} diff --git a/charts/puris/README.md b/charts/puris/README.md index d34a4ff6..85fe6d82 100644 --- a/charts/puris/README.md +++ b/charts/puris/README.md @@ -75,7 +75,7 @@ $ helm install puris --namespace puris --create-namespace . | backend.puris.edc.dataplane.public.url | string | `"https://your-data-plane:8285/api/public/"` | Url of one of your data plane's public api | | backend.puris.edr.deletiontimer | int | `2` | Number of minutes before received authentication data of a consumer pull is removed from memory | | backend.puris.existingSecret | string | `"secret-backend-puris"` | Secret for backend passwords. For more information look into 'backend-secrets.yaml' file. | -| backend.puris.frameworkagreement.credential | string | `"puris"` | The name of the framework agreement | +| backend.puris.frameworkagreement.credential | string | `"Puris"` | The name of the framework agreement. Starting with Uppercase and using CamelCase. | | backend.puris.frameworkagreement.version | string | `"1.0"` | The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! | | backend.puris.generatematerialcatenaxid | bool | `true` | Flag that decides whether the auto-generation feature of the puris backend is enabled. Since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing CatenaX-Id via the materials-API of the backend, when you are inserting a new Material entity to the backend's database. If a CatenaX-Id was not assigned to your Material so far, then this feature can auto-generate one randomly. In a real-world-scenario, you must then use this randomly generated CatenaX-Id for the lifetime of that Material entity. | | backend.puris.itemstocksubmodel.apiassetid | string | `"itemstocksubmodel-api-asset"` | Asset ID for ItemStockSubmodel API | @@ -90,6 +90,8 @@ $ helm install puris --namespace puris --create-namespace . | backend.puris.own.streetnumber | string | `"Musterstraße 110A"` | Own street and number | | backend.puris.own.zipcodeandcity | string | `"12345 Musterhausen"` | Own zipcode and city | | backend.puris.productionsubmodel.apiassetid | string | `"productionsubmodel-api-asset"` | Asset ID for ProductionSubmodel API | +| backend.puris.purpose.name | string | `"cx.puris.base"` | The name of the purpose to use for submodel contracts | +| backend.puris.purpose.version | string | `"1"` | The version of the purpose to use for submodel contracts. NEEDS TO BE PUT AS "STRING"! | | backend.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":120,"periodSeconds":25,"successThreshold":1,"timeoutSeconds":1}` | Checks if the pod is fully ready to operate | | backend.readinessProbe.failureThreshold | int | `3` | Number of failures (threshold) for a readiness probe | | backend.readinessProbe.initialDelaySeconds | int | `120` | Delay in seconds after which an initial readiness probe is checked | diff --git a/charts/puris/values.yaml b/charts/puris/values.yaml index fa56b8c5..b56d49b0 100644 --- a/charts/puris/values.yaml +++ b/charts/puris/values.yaml @@ -424,8 +424,8 @@ backend: # -- Asset ID for DeliverySubmodel API apiassetid: deliverysubmodel-api-asset frameworkagreement: - # -- The name of the framework agreement - credential: puris + # -- The name of the framework agreement. Starting with Uppercase and using CamelCase. + credential: Puris # -- The version of the framework agreement, NEEDS TO BE PUT AS "STRING"! version: "1.0" purpose: diff --git a/local/tractus-x-edc/config/customer/puris-backend.properties b/local/tractus-x-edc/config/customer/puris-backend.properties index e4a5673d..30a91ebd 100644 --- a/local/tractus-x-edc/config/customer/puris-backend.properties +++ b/local/tractus-x-edc/config/customer/puris-backend.properties @@ -7,7 +7,7 @@ puris.itemstocksubmodel.apiassetid=itemstocksubmodel-api-asset puris.productionsubmodel.apiassetid=productionsubmodel-api-asset puris.demandsubmodel.apiassetid=demandsubmodel-api-asset puris.deliverysubmodel.apiassetid=deliverysubmodel-api-asset -puris.frameworkagreement.credential=puris +puris.frameworkagreement.credential=Puris puris.frameworkagreement.version=1.0 puris.purpose.name=cx.puris.base puris.purpose.version=1 diff --git a/local/tractus-x-edc/config/supplier/puris-backend.properties b/local/tractus-x-edc/config/supplier/puris-backend.properties index 3277e983..cfa2a826 100644 --- a/local/tractus-x-edc/config/supplier/puris-backend.properties +++ b/local/tractus-x-edc/config/supplier/puris-backend.properties @@ -7,7 +7,7 @@ puris.itemstocksubmodel.apiassetid=itemstocksubmodel-api-asset puris.productionsubmodel.apiassetid=productionsubmodel-api-asset puris.demandsubmodel.apiassetid=demandsubmodel-api-asset puris.deliverysubmodel.apiassetid=deliverysubmodel-api-asset -puris.frameworkagreement.credential=puris +puris.frameworkagreement.credential=Puris puris.frameworkagreement.version=1.0 puris.purpose.name=cx.puris.base puris.purpose.version=1 From 169923e7255e888bb9e2caf34492724c33c23598 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Thu, 16 May 2024 00:40:56 -0700 Subject: [PATCH 17/21] chore(docker-compose-infrastructure.yaml): outcomment unused MIW --- local/INSTALL.md | 2 ++ local/docker-compose-infrastructure.yaml | 21 ++++++++++--------- .../config/customer/control-plane.properties | 14 ++++++------- .../config/supplier/control-plane.properties | 14 ++++++------- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/local/INSTALL.md b/local/INSTALL.md index 0a0386f4..58a65631 100644 --- a/local/INSTALL.md +++ b/local/INSTALL.md @@ -54,6 +54,7 @@ First start the infrastructure by navigating your shell to the local folder and docker compose -f docker-compose-infrastructure.yaml up ``` + After starting the central infrastructure, initialize the bdrs-service. To do so, just run the script `seed-bdrs.sh` created during the run of script `generate-keys.sh`. diff --git a/local/docker-compose-infrastructure.yaml b/local/docker-compose-infrastructure.yaml index 5a1766f5..e131347f 100644 --- a/local/docker-compose-infrastructure.yaml +++ b/local/docker-compose-infrastructure.yaml @@ -20,16 +20,17 @@ version: "3" services: - miw: - image: tractusx/managed-identity-wallet:0.4.0 - container_name: miw - env_file: - - ./miw/infrastructure.properties - ports: - - "127.0.0.1:8000:80" - - "127.0.0.1:8090:8090" - networks: - - miw-net + # Outcommented as not updated for R24.05 but scheduled for R24.08 + # miw: + # image: tractusx/managed-identity-wallet:0.4.0 + # container_name: miw + # env_file: + # - ./miw/infrastructure.properties + # ports: + # - "127.0.0.1:8000:80" + # - "127.0.0.1:8090:8090" + # networks: + # - miw-net postgres: image: postgres:15.4-alpine diff --git a/local/tractus-x-edc/config/customer/control-plane.properties b/local/tractus-x-edc/config/customer/control-plane.properties index d62e7a03..da7ef02e 100644 --- a/local/tractus-x-edc/config/customer/control-plane.properties +++ b/local/tractus-x-edc/config/customer/control-plane.properties @@ -29,13 +29,13 @@ edc.iam.trusted-issuer.portal.id=did:web:mock-util-service/trusted-issuer tx.iam.iatp.credentialservice.url=http://mock-util-service:80 # don't use https during did resolving edc.iam.did.web.use.https=false -# old MIW config, can be ignored TODO remove -tx.ssi.oauth.token.url=http://keycloak:8080/realms/miw_test/protocol/openid-connect/token -tx.ssi.oauth.client.id=${CUSTOMER_OAUTH_CLIENT_ID} -tx.ssi.oauth.client.secret.alias=${CUSTOMER_OAUTH_SECRET_ALIAS} -tx.ssi.miw.url=http://miw -tx.ssi.miw.authority.id=BPNL000000000000 -tx.ssi.endpoint.audience=http://customer-control-plane:8184/api/v1/dsp +# old MIW config (<0.7.0), can be ignored till MIW is back +#tx.ssi.oauth.token.url=http://keycloak:8080/realms/miw_test/protocol/openid-connect/token +#tx.ssi.oauth.client.id=${CUSTOMER_OAUTH_CLIENT_ID} +#tx.ssi.oauth.client.secret.alias=${CUSTOMER_OAUTH_SECRET_ALIAS} +#tx.ssi.miw.url=http://miw +#tx.ssi.miw.authority.id=BPNL000000000000 +#tx.ssi.endpoint.audience=http://customer-control-plane:8184/api/v1/dsp # HashiCorp vault related configuration edc.vault.hashicorp.url=http://vault:8200 edc.vault.hashicorp.health.check.enabled=false diff --git a/local/tractus-x-edc/config/supplier/control-plane.properties b/local/tractus-x-edc/config/supplier/control-plane.properties index d8f54d67..ac0b8f2b 100644 --- a/local/tractus-x-edc/config/supplier/control-plane.properties +++ b/local/tractus-x-edc/config/supplier/control-plane.properties @@ -30,13 +30,13 @@ edc.iam.trusted-issuer.portal.id=did:web:mock-util-service/trusted-issuer tx.iam.iatp.credentialservice.url=http://mock-util-service:80 # don't use https during did resolving edc.iam.did.web.use.https=false -# old MIW config, can be ignored TODO remove -tx.ssi.oauth.token.url=http://keycloak:8080/realms/miw_test/protocol/openid-connect/token -tx.ssi.oauth.client.id=${SUPPLIER_OAUTH_CLIENT_ID} -tx.ssi.oauth.client.secret.alias=${SUPPLIER_OAUTH_SECRET_ALIAS} -tx.ssi.miw.url=http://miw -tx.ssi.miw.authority.id=BPNL000000000000 -tx.ssi.endpoint.audience=http://supplier-control-plane:9184/api/v1/dsp +# old MIW config (<0.7.0), can be ignored till MIW is back +#tx.ssi.oauth.token.url=http://keycloak:8080/realms/miw_test/protocol/openid-connect/token +#tx.ssi.oauth.client.id=${SUPPLIER_OAUTH_CLIENT_ID} +#tx.ssi.oauth.client.secret.alias=${SUPPLIER_OAUTH_SECRET_ALIAS} +#tx.ssi.miw.url=http://miw +#tx.ssi.miw.authority.id=BPNL000000000000 +#tx.ssi.endpoint.audience=http://supplier-control-plane:9184/api/v1/dsp # HashiCorp vault related configuration edc.vault.hashicorp.url=http://vault:8200 edc.vault.hashicorp.health.check.enabled=false From a6468554c58bdf68a701280896871c039a91ee29 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Thu, 16 May 2024 01:35:41 -0700 Subject: [PATCH 18/21] chore: removed solved todos --- .../backend/common/edc/logic/service/EdcAdapterService.java | 4 ++-- local/tractus-x-edc/config/supplier/data-plane.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java index 0a041c1f..d80ff8d5 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/edc/logic/service/EdcAdapterService.java @@ -345,7 +345,7 @@ public Response getCatalogResponse(String dspUrl, String partnerBpnl, Map filter) throws IOException { // TODO: use partner to get the catalog + public JsonNode getCatalog(String dspUrl, String partnerBpnl, Map filter) throws IOException { try (var response = getCatalogResponse(dspUrl, partnerBpnl, filter)) { JsonNode responseNode = objectMapper.readTree(response.body().string()); log.debug("Got Catalog response {}", responseNode.toPrettyString()); @@ -658,7 +658,7 @@ private boolean negotiateForPartnerDtr(Partner partner) { } if (catalogArray.size() > 1) { log.warn("Ambiguous catalog entries found! Will take the first\n" + catalogArray.toPrettyString()); - // TODO constraint check + // potential constraint check in future } JsonNode targetCatalogEntry = catalogArray.get(0); if (targetCatalogEntry == null) { diff --git a/local/tractus-x-edc/config/supplier/data-plane.properties b/local/tractus-x-edc/config/supplier/data-plane.properties index ac8be2ff..95e01a79 100644 --- a/local/tractus-x-edc/config/supplier/data-plane.properties +++ b/local/tractus-x-edc/config/supplier/data-plane.properties @@ -7,7 +7,7 @@ web.http.public.path=/api/public # new in 0.7.0 data plane signalling, replaced control web.http.signaling.port=9283 web.http.signaling.path=/api/signaling -# new in 0.3.3 - why do we need the management in a data plane? TODO removed? +# new in 0.3.3 - why do we need the management in a data plane? web.http.management.port=9293 web.http.management.path=/api/v1/data # Validation endpoint of controlplane From fda877efa7dfef1b25b1380d921adbaa03cbbc8a Mon Sep 17 00:00:00 2001 From: --show-origin Date: Thu, 16 May 2024 04:39:59 -0700 Subject: [PATCH 19/21] docs(local/INSTALL.md): fixed bdrs typo --- local/INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local/INSTALL.md b/local/INSTALL.md index 58a65631..7d0034d4 100644 --- a/local/INSTALL.md +++ b/local/INSTALL.md @@ -68,7 +68,7 @@ After starting the central infrastructure, initialize the bdrs-service. To do so created during the run of script `generate-keys.sh`. ```shell -sh seed-brds.sh +sh seed-bdrs.sh ``` Then start the PURIS demonstrator containers via: From 886393a86d20b8c810a3b381da93fe22957c8927 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Fri, 17 May 2024 07:26:04 -0700 Subject: [PATCH 20/21] chore: bump chart version to 2.4.0 --- charts/puris/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/puris/Chart.yaml b/charts/puris/Chart.yaml index 06142577..694945f8 100644 --- a/charts/puris/Chart.yaml +++ b/charts/puris/Chart.yaml @@ -35,7 +35,7 @@ dependencies: # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 2.3.0 +version: 2.4.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to From 8b608a5be3ba15ed937d9ab00d54b33df7cbf6f0 Mon Sep 17 00:00:00 2001 From: --show-origin Date: Sun, 19 May 2024 01:22:37 -0700 Subject: [PATCH 21/21] fix(helm): updated partner ownSites endpoint to partner endpoint --- charts/puris/README.md | 2 +- charts/puris/templates/frontend-deployment.yaml | 4 ++-- charts/puris/values.yaml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/charts/puris/README.md b/charts/puris/README.md index fa2a3e8d..3f774f13 100644 --- a/charts/puris/README.md +++ b/charts/puris/README.md @@ -147,7 +147,7 @@ $ helm install puris --namespace puris --create-namespace . | frontend.puris.endpointDemand | string | `"demand"` | The endpoint for the demand submodel | | frontend.puris.endpointMaterialStocks | string | `"stockView/material-stocks"` | The endpoint for material stocks for the stock view | | frontend.puris.endpointMaterials | string | `"stockView/materials"` | The endpoint for materials for the stock view | -| frontend.puris.endpointPartnerOwnSites | string | `"partners/ownSites"` | The endpoint for the partners BPNS | +| frontend.puris.endpointPartner | string | `"partner"` | The endpoint for the partners BPNS | | frontend.puris.endpointProductStocks | string | `"stockView/product-stocks"` | The endpoint for product stocks for the stock view | | frontend.puris.endpointProduction | string | `"production"` | The endpoint for the production submodel | | frontend.puris.endpointProductionRange | string | `"production/range"` | The endpoint for the production range of the production submodel | diff --git a/charts/puris/templates/frontend-deployment.yaml b/charts/puris/templates/frontend-deployment.yaml index af53a91a..38c0d5de 100644 --- a/charts/puris/templates/frontend-deployment.yaml +++ b/charts/puris/templates/frontend-deployment.yaml @@ -79,8 +79,8 @@ spec: value: "{{ .Values.frontend.puris.endpointUpdateReportedMaterialStocks }}" - name: ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS value: "{{ .Values.frontend.puris.endpointUpdateReportedProductStocks }}" - - name: ENDPOINT_PARTNER_OWNSITES - value: "{{ .Values.frontend.puris.endpointPartnerOwnSites }}" + - name: ENDPOINT_PARTNER + value: "{{ .Values.frontend.puris.endpointPartner }}" - name: ENDPOINT_DEMAND value: "{{ .Values.frontend.puris.endpointDemand }}" - name: ENDPOINT_PRODUCTION diff --git a/charts/puris/values.yaml b/charts/puris/values.yaml index c7b91809..908424fc 100644 --- a/charts/puris/values.yaml +++ b/charts/puris/values.yaml @@ -185,8 +185,8 @@ frontend: endpointUpdateReportedMaterialStocks: stockView/update-reported-material-stocks?ownMaterialNumber= # -- The endpoint for triggering an update of your product stocks on your partners side endpointUpdateReportedProductStocks: stockView/update-reported-product-stocks?ownMaterialNumber= - # -- The endpoint for the partners BPNS - endpointPartnerOwnSites: partners/ownSites + # -- The endpoint for partner information + endpointPartner: partner # -- The endpoint for the demand submodel endpointDemand: demand # -- The endpoint for the production submodel