diff --git a/README.md b/README.md index 4fef6bf0..5bf2e2d0 100644 --- a/README.md +++ b/README.md @@ -59,15 +59,15 @@ The credentials can be found/configured in one of the following: It is required to configure those parameters: -| Parameter name | Description | Mandatory | -|--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------| -| `edc.ionos.access.key` | IONOS Access Key Id to access S3 | Yes if the context is accessing file | -| `edc.ionos.secret.access.key` | IONOS Secret Access Key to access S3 | Yes if the context is accessing file | -| `edc.ionos.token` | IONOS token to allow S3 provisioning | Yes if the context is provisioning access for others | -| `edc.ionos.endpoint` | IONOS S3 endpoint address. Refer to [docs](https://docs.ionos.com/cloud/managed-services/s3-object-storage/endpoints) for further information. | Yes, if the context is accessing file | No, the default value is | -| `edc.ionos.max.files` | Maximum number of files retrieved by list files function. | No, the default value is 5,000 files | -| `edc.ionos.key.validation.attempts` | Maximum number of attemps to validate a temporary key after its creation. | No, the default values is 10 attempts | -| `edc.ionos.key.validation.delay` | Time to wait (in milisseconds) before each key validation attempt. In each new attempt the delay is multiplied by the attempt number. | No, the default value is 3,000 (3 seconds) | +| Parameter name | Description | Mandatory | +|-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------| +| `edc.ionos.access.key` | IONOS Access Key Id to access S3 | Yes if the context is accessing file | +| `edc.ionos.secret.access.key` | IONOS Secret Access Key to access S3 | Yes if the context is accessing file | +| `edc.ionos.token` | IONOS token to allow S3 provisioning | Yes if the context is provisioning access for others | +| `edc.ionos.endpoint.region` | IONOS S3 endpoint region. Refer to [docs](https://docs.ionos.com/cloud/managed-services/s3-object-storage/endpoints) for further information. | No, the default value is de | +| `edc.ionos.max.files` | Maximum number of files retrieved by list files function. | No, the default value is 5,000 files | +| `edc.ionos.key.validation.attempts` | Maximum number of attemps to validate a temporary key after its creation. | No, the default values is 10 attempts | +| `edc.ionos.key.validation.delay` | Time to wait (in milisseconds) before each key validation attempt. In each new attempt the delay is multiplied by the attempt number. | No, the default value is 3,000 (3 seconds) | To create the token please take a look at the following [documentation](./ionos_token.md). diff --git a/assets.md b/assets.md index ec0fc54d..69494c8f 100644 --- a/assets.md +++ b/assets.md @@ -9,13 +9,13 @@ The asset registration aims to specify which file/folder we want to share. We ca ### Requirements -| Parameter | Description | Mandatory | -|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------| -| `storage` | IONOS S3 endpoint address. Refer to [docs](https://docs.ionos.com/cloud/managed-services/s3-object-storage/s3-endpoints) for further information. | yes | -| `bucketName` | IONOS S3 bucket name. Refer to [docs](https://docs.ionos.com/cloud/managed-services/s3-object-storage/concepts/buckets) for further information. | yes | -| `blobName` | File name or path to folder | yes | -| `filterIncludes` | `filterIncludes` use regular expression that will be used to select the file name pattern from the asset's blobName that will be copied during the transfer
* do not consider the blobName in the expression, but the path from it. example: blobName = folder1, filterIncludes=file1.csv, the file foloder1/file1.csv will be copied | no | -| `filterExcludes` | `filterExcludes` use regular expression that will be used to select the file name pattern from the asset's blobName that will NOT be copied during the transfer
| no | +| Parameter | Description | Mandatory | +|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------| +| `region` | IONOS S3 endpoint region. Refer to [docs](https://docs.ionos.com/cloud/managed-services/s3-object-storage/s3-endpoints) for further information. | no, default value = de | +| `bucketName` | IONOS S3 bucket name. Refer to [docs](https://docs.ionos.com/cloud/managed-services/s3-object-storage/concepts/buckets) for further information. | yes | +| `blobName` | File name or path to folder | yes | +| `filterIncludes` | `filterIncludes` use regular expression that will be used to select the file name pattern from the asset's blobName that will be copied during the transfer
* do not consider the blobName in the expression, but the path from it. example: blobName = folder1, filterIncludes=file1.csv, the file foloder1/file1.csv will be copied | no | +| `filterExcludes` | `filterExcludes` use regular expression that will be used to select the file name pattern from the asset's blobName that will NOT be copied during the transfer
| no | Note: if `filterIncludes` and `filterExcludes` parameters are satisfied, the files to be copied will be selected using the `filterIncludes` and after that selected list, the files that have the pattern defined in the `filterExcludes` will be ignored. @@ -23,9 +23,9 @@ Note: if `filterIncludes` and `filterExcludes` parameters are satisfied, the f ## Example ```json -"dataAddress":{ +"dataAddress": { "type": "IonosS3", //from EDC - "storage": "s3-eu-central-1.ionoscloud.com", + "region": "de, "bucketName": "mybucket", "blobName": "folder1/", "filterIncludes": "file1.csv", @@ -40,19 +40,19 @@ The transfer of assets aims to transfer the files/folders from one connector to ### Requirements -| Parameter | Description | Mandatory | -|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|-----------| -| `storage` | IONOS S3 endpoint address. Refer to [docs](https://docs.ionos.com/cloud/managed-services/s3-object-storage/s3-endpoints) for further information. | yes | -| `bucketName` | IONOS S3 bucket name. Refer to [docs](https://docs.ionos.com/cloud/managed-services/s3-object-storage/concepts/buckets) for further information. | yes | -| `path` | Path of destination where the file/folder will be placed.
*if the path not filled, the file will be placed in the root of the bucket. | no | +| Parameter | Description | Mandatory | +|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------|------------------------| +| `region` | IONOS S3 endpoint region. Refer to [docs](https://docs.ionos.com/cloud/managed-services/s3-object-storage/s3-endpoints) for further information. | no, default value = de | +| `bucketName` | IONOS S3 bucket name. Refer to [docs](https://docs.ionos.com/cloud/managed-services/s3-object-storage/concepts/buckets) for further information. | yes | +| `path` | Path of destination where the file/folder will be placed.
*if the path not filled, the file will be placed in the root of the bucket. | no | ## Example ```json -"dataDestination":{ +"dataDestination": { "type": "IonosS3", //from EDC - "storage": "s3-eu-central-1.ionoscloud.com", + "region": "de", "bucketName": "mybucket", "path": "folder2/", "keyName": "mykey" //from EDC diff --git a/deployment/README.md b/deployment/README.md index 2aaa79cf..d3d5ada6 100644 --- a/deployment/README.md +++ b/deployment/README.md @@ -48,7 +48,7 @@ export TF_VAR_persistence_type='PostgreSQLaaS' # 'PostgreSQLaaS', 'PostgreSQL' o export TF_VAR_vaultname='vault' # optional if only 1 connector per cluster export TF_VAR_s3_access_key='' # S3 access key export TF_VAR_s3_secret_key='' # S3 secret key -export TF_VAR_s3_endpoint='' # s3 endpoint (e.g. s3-eu-central-1.ionoscloud.com) +export TF_VAR_s3_endpoint_region='' # s3 endpoint region (e.g. de) export TF_VAR_ionos_token='' # IONOS Cloud token, for further information: https://docs.ionos.com/cloud/managed-services/s3-object-storage/endpoints # Required only if persistence_type is PostgreSQLaaS @@ -86,7 +86,7 @@ In case you want to configure this Connector without Hashicorp Vault, you need t ```yaml ionos: - endpoint: + region: accessKey: secretKey: token: diff --git a/deployment/helm/README.md b/deployment/helm/README.md index 86fb89ec..1ab673f1 100644 --- a/deployment/helm/README.md +++ b/deployment/helm/README.md @@ -35,7 +35,7 @@ The IONOS S3 Extension can be deployed to a Kubernetes cluster using the Helm ch # Add secrets to Vault kubectl exec --namespace edc-ionos-s3 -it vault-0 -- vault kv put secret/edc.ionos.access.key content= kubectl exec --namespace edc-ionos-s3 -it vault-0 -- vault kv put secret/edc.ionos.secret.key content= - kubectl exec --namespace edc-ionos-s3 -it vault-0 -- vault kv put secret/edc.ionos.endpoint content= + kubectl exec --namespace edc-ionos-s3 -it vault-0 -- vault kv put secret/edc.ionos.endpoint.region content= kubectl exec --namespace edc-ionos-s3 -it vault-0 -- vault kv put secret/edc.ionos.token content= ``` diff --git a/deployment/helm/edc-ionos-s3/templates/configmap.yaml b/deployment/helm/edc-ionos-s3/templates/configmap.yaml index af030c9b..aa81e0af 100644 --- a/deployment/helm/edc-ionos-s3/templates/configmap.yaml +++ b/deployment/helm/edc-ionos-s3/templates/configmap.yaml @@ -18,7 +18,7 @@ data: edc.participant.id={{ .Values.edc.participant.id }} edc.ionos.access.key={{ .Values.edc.ionos.accessKey }} edc.ionos.secret.key={{ .Values.edc.ionos.secretKey }} - edc.ionos.endpoint={{ .Values.edc.ionos.endpoint }} + edc.ionos.endpoint.region={{ .Values.edc.ionos.endpoint.region }} edc.ionos.token={{ .Values.edc.ionos.token }} edc.vault.hashicorp.url={{ .Values.edc.vault.hashicorp.url }} edc.vault.hashicorp.token={{ .Values.edc.vault.hashicorp.token }} diff --git a/deployment/kind/README.md b/deployment/kind/README.md index 43b31cd6..4b9db821 100644 --- a/deployment/kind/README.md +++ b/deployment/kind/README.md @@ -26,7 +26,7 @@ Set environment variables export KUBECONFIG=path/to/kubeconfig export S3_ACCESS_KEY='' export S3_SECRET_KEY='' -export S3_ENDPOINT='' +export S3_ENDPOINT_REGION='' export IONOS_TOKEN='' ``` diff --git a/deployment/kind/scripts/deploy.sh b/deployment/kind/scripts/deploy.sh index b04c954c..4ad48976 100755 --- a/deployment/kind/scripts/deploy.sh +++ b/deployment/kind/scripts/deploy.sh @@ -34,8 +34,8 @@ if [ -z `printenv S3_SECRET_KEY` ]; then echo "Stopping because S3_SECRET_KEY is undefined" exit 1 fi -if [ -z `printenv S3_ENDPOINT` ]; then - echo "Stopping because S3_ENDPOINT is undefined" +if [ -z `printenv S3_ENDPOINT_REGION` ]; then + echo "Stopping because S3_ENDPOINT_REGION is undefined" exit 1 fi if [ -z `printenv IONOS_TOKEN` ]; then @@ -72,7 +72,7 @@ helm install -n edc-ionos-s3 --wait vault hashicorp/vault \ export TF_VAR_kubeconfig=$KUBECONFIG export TF_VAR_s3_access_key=$S3_ACCESS_KEY export TF_VAR_s3_secret_key=$S3_SECRET_KEY -export TF_VAR_s3_endpoint=$S3_ENDPOINT +export TF_VAR_s3_endpoint_region=$S3_ENDPOINT_REGION export TF_VAR_ionos_token=$IONOS_TOKEN ../terraform/vault-init/vault-init.sh diff --git a/deployment/terraform/deploy-services.sh b/deployment/terraform/deploy-services.sh index b858286f..1b6e3a0d 100755 --- a/deployment/terraform/deploy-services.sh +++ b/deployment/terraform/deploy-services.sh @@ -19,8 +19,8 @@ if [[ -z `printenv TF_VAR_s3_secret_key` ]]; then exit 1 fi -if [[ -z `printenv TF_VAR_s3_endpoint` ]]; then - echo "Stopping because TF_VAR_s3_endpoint is undefined" +if [[ -z `printenv TF_VAR_s3_endpoint_region` ]]; then + echo "Stopping because TF_VAR_s3_endpoint_region is undefined" exit 1 fi diff --git a/deployment/terraform/ionos-s3-deploy/main.tf b/deployment/terraform/ionos-s3-deploy/main.tf index f568798c..8f74f22c 100644 --- a/deployment/terraform/ionos-s3-deploy/main.tf +++ b/deployment/terraform/ionos-s3-deploy/main.tf @@ -56,9 +56,6 @@ variable "pg_password" { default = "postgres" } -variable "s3_access_key" {} -variable "s3_secret_key" {} -variable "s3_endpoint" {} variable "ionos_token" {} variable "vaultname" { @@ -98,8 +95,8 @@ resource "helm_release" "edc-ionos-s3" { } set { - name = "edc.ionos.endpoint" - value = var.s3_endpoint + name = "edc.ionos.endpoint.region" + value = var.s3_endpoint_region } set { diff --git a/deployment/terraform/vault-init/vault-init.sh b/deployment/terraform/vault-init/vault-init.sh index 73a7d0ec..18da804b 100755 --- a/deployment/terraform/vault-init/vault-init.sh +++ b/deployment/terraform/vault-init/vault-init.sh @@ -39,5 +39,5 @@ fi # Add secrets to Vault kubectl --kubeconfig=$TF_VAR_kubeconfig exec --namespace $NAMESPACE -it "$TF_VAR_vaultname-0" -- vault kv put secret/edc.ionos.access.key content=$TF_VAR_s3_access_key kubectl --kubeconfig=$TF_VAR_kubeconfig exec --namespace $NAMESPACE -it "$TF_VAR_vaultname-0" -- vault kv put secret/edc.ionos.secret.key content=$TF_VAR_s3_secret_key -kubectl --kubeconfig=$TF_VAR_kubeconfig exec --namespace $NAMESPACE -it "$TF_VAR_vaultname-0" -- vault kv put secret/edc.ionos.endpoint content=$TF_VAR_s3_endpoint +kubectl --kubeconfig=$TF_VAR_kubeconfig exec --namespace $NAMESPACE -it "$TF_VAR_vaultname-0" -- vault kv put secret/edc.ionos.endpoint.region content=$TF_VAR_s3_endpoint_region kubectl --kubeconfig=$TF_VAR_kubeconfig exec --namespace $NAMESPACE -it "$TF_VAR_vaultname-0" -- vault kv put secret/edc.ionos.token content=$TF_VAR_ionos_token diff --git a/extensions/core-ionos-s3/build.gradle.kts b/extensions/core-ionos-s3/build.gradle.kts index 3051ff77..13d735e3 100644 --- a/extensions/core-ionos-s3/build.gradle.kts +++ b/extensions/core-ionos-s3/build.gradle.kts @@ -9,7 +9,6 @@ val metaModelVersion: String by project val minIOVersion: String by project val extensionsGroup: String by project val extensionsVersion: String by project -val junitVersion: String by project val gitHubPkgsName: String by project val gitHubPkgsUrl: String by project @@ -21,9 +20,6 @@ dependencies { implementation("${edcGroup}:transfer-spi:${edcVersion}") implementation("io.minio:minio:${minIOVersion}") - - testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}") - testImplementation("org.junit.jupiter:junit-jupiter-engine:${junitVersion}") } java { @@ -31,10 +27,6 @@ java { withSourcesJar() } -tasks.test { - useJUnitPlatform() -} - publishing { publications { create("maven") { diff --git a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/api/S3ConnectorApi.java b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/api/S3ConnectorApi.java index 9b7d3674..6307e128 100644 --- a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/api/S3ConnectorApi.java +++ b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/api/S3ConnectorApi.java @@ -41,4 +41,5 @@ public interface S3ConnectorApi { void deleteAccessKey(String keyID); + S3ConnectorApi clone(String region, String accessKey, String secretKey); } diff --git a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/api/S3ConnectorApiImpl.java b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/api/S3ConnectorApiImpl.java index 4f45c7c7..b6491b6b 100644 --- a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/api/S3ConnectorApiImpl.java +++ b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/api/S3ConnectorApiImpl.java @@ -18,6 +18,7 @@ import com.ionos.edc.extension.s3.connector.ionosapi.S3AccessKey; import com.ionos.edc.extension.s3.connector.ionosapi.S3ApiConnector; +import com.ionos.edc.extension.s3.connector.ionosapi.S3Region; import io.minio.BucketExistsArgs; import io.minio.GetObjectArgs; import io.minio.ListObjectsArgs; @@ -25,32 +26,34 @@ import io.minio.MinioClient; import io.minio.PutObjectArgs; import org.eclipse.edc.spi.EdcException; +import org.jetbrains.annotations.NotNull; import java.io.ByteArrayInputStream; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import static com.ionos.edc.extension.s3.schema.IonosBucketSchema.REGION_ID_DEFAULT; + public class S3ConnectorApiImpl implements S3ConnectorApi { MinioConnector miniConnector = new MinioConnector(); S3ApiConnector ionoss3Api = new S3ApiConnector(); private final MinioClient minioClient; - private final String region; - private String token; + private final String regionId; + private final String token; private final Integer maxFiles; - public S3ConnectorApiImpl(String endpoint, String accessKey, String secretKey, int maxFiles) { - this.minioClient = miniConnector.connect(endpoint, accessKey, secretKey); - this.region = getRegion(endpoint); - this.token = ""; + public S3ConnectorApiImpl(String regionId, @NotNull String accessKey, @NotNull String secretKey, @NotNull String token, int maxFiles) { + this.token = token; this.maxFiles = maxFiles; - } - public S3ConnectorApiImpl(String endpoint, String accessKey, String secretKey, String token, int maxFiles) { - this(endpoint, accessKey, secretKey, maxFiles); - this.token = token; + this.regionId = Objects.requireNonNullElse(regionId, REGION_ID_DEFAULT); + var endpoint = getEndpoint( this.regionId , token); + + this.minioClient = miniConnector.connect(endpoint, accessKey, secretKey); } @Override @@ -59,7 +62,7 @@ public void createBucket(String bucketName) { try { minioClient.makeBucket(MakeBucketArgs.builder() .bucket(bucketName.toLowerCase()) - .region(region) + .region(regionId) .build()); } catch (Exception e) { throw new EdcException("Creating bucket: " + e.getMessage()); @@ -72,7 +75,7 @@ public boolean bucketExists(String bucketName) { try { return minioClient.bucketExists(BucketExistsArgs.builder() .bucket(bucketName.toLowerCase()) - .region(region) + .region(regionId) .build()); } catch (Exception e) { throw new EdcException("Verifying if bucket exists - " + e.getMessage()); @@ -88,7 +91,7 @@ public void uploadObject(String bucketName, String objectName, ByteArrayInputStr try { minioClient.putObject(PutObjectArgs.builder() .bucket(bucketName.toLowerCase()) - .region(region) + .region(regionId) .object(objectName) .stream(stream, stream.available(), -1) .build()); @@ -105,7 +108,7 @@ public ByteArrayInputStream getObject(String bucketName, String objectName) { var request = GetObjectArgs.builder() .bucket(bucketName.toLowerCase()) - .region(region) + .region(regionId) .object(objectName) .build(); @@ -124,7 +127,7 @@ public ByteArrayInputStream getObject(String bucketName, String objectName, long var request = GetObjectArgs.builder() .bucket(bucketName.toLowerCase()) - .region(region) + .region(regionId) .object(objectName) .offset(offset) .length(length) @@ -142,7 +145,7 @@ public List listObjects(String bucketName, String objectName) { var objects = minioClient.listObjects(ListObjectsArgs.builder() .bucket(bucketName.toLowerCase()) - .region(region) + .region(regionId) .prefix(objectName) .recursive(true) .maxKeys(maxFiles) @@ -187,24 +190,20 @@ public void deleteAccessKey(String keyID) { } } - static String getRegion(String endpoint) { - - switch (endpoint) { - case "https://s3-eu-central-1.ionoscloud.com": - return "de"; - case "s3-eu-central-1.ionoscloud.com": - return "de"; - case "https://s3-eu-central-2.ionoscloud.com": - return "eu-central-2"; - case "s3-eu-central-2.ionoscloud.com": - return "eu-central-2"; - case "https://s3-eu-south-2.ionoscloud.com": - return "eu-south-2"; - case "s3-eu-south-2.ionoscloud.com": - return "eu-south-2"; - default: - throw new EdcException("Invalid endpoint: " + endpoint); + private String getEndpoint(String regionId, String token) { + var regions = ionoss3Api.retrieveRegions(token); + + for (S3Region region: regions.getItems()) { + if (region.getId().equals(regionId)) { + return "https://" + region.getProperties().getEndpoint(); + } } + throw new EdcException("Invalid region: " + regionId); + } + + @Override + public S3ConnectorApi clone(String region, String accessKey, String secretKey) { + return new S3ConnectorApiImpl(region, accessKey, secretKey, this.token, this.maxFiles); } } diff --git a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/configuration/S3CoreExtension.java b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/configuration/S3CoreExtension.java index be4140e0..8947fcd8 100644 --- a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/configuration/S3CoreExtension.java +++ b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/configuration/S3CoreExtension.java @@ -26,7 +26,7 @@ import static com.ionos.edc.extension.s3.schema.IonosSettingsSchema.IONOS_ACCESS_KEY; import static com.ionos.edc.extension.s3.schema.IonosSettingsSchema.IONOS_SECRET_KEY; -import static com.ionos.edc.extension.s3.schema.IonosSettingsSchema.IONOS_ENDPOINT; +import static com.ionos.edc.extension.s3.schema.IonosSettingsSchema.IONOS_REGION; import static com.ionos.edc.extension.s3.schema.IonosSettingsSchema.IONOS_TOKEN; import static com.ionos.edc.extension.s3.schema.IonosSettingsSchema.IONOS_MAX_FILES; import static com.ionos.edc.extension.s3.schema.IonosSettingsSchema.IONOS_MAX_FILES_DEFAULT; @@ -53,20 +53,20 @@ public void initialize(ServiceExtensionContext context) { var accessKey = vault.resolveSecret(IONOS_ACCESS_KEY); var secretKey = vault.resolveSecret(IONOS_SECRET_KEY); - var endPoint = vault.resolveSecret(IONOS_ENDPOINT); + var region = vault.resolveSecret(IONOS_REGION); var token = vault.resolveSecret(IONOS_TOKEN); - if(accessKey == null || secretKey == null || endPoint ==null) { + if(accessKey == null || secretKey == null || region == null || token == null) { monitor.warning("Couldn't connect or the vault didn't return values, falling back to ConfigMap Configuration"); accessKey = context.getSetting(IONOS_ACCESS_KEY, IONOS_ACCESS_KEY); secretKey = context.getSetting(IONOS_SECRET_KEY, IONOS_SECRET_KEY); - endPoint = context.getSetting(IONOS_ENDPOINT, IONOS_ENDPOINT); + region = context.getSetting(IONOS_REGION, IONOS_REGION); token = context.getSetting(IONOS_TOKEN, IONOS_TOKEN); } var maxFiles = context.getSetting(IONOS_MAX_FILES, IONOS_MAX_FILES_DEFAULT); - var s3Api = new S3ConnectorApiImpl(endPoint, accessKey, secretKey, token, maxFiles); + var s3Api = new S3ConnectorApiImpl(region, accessKey, secretKey, token, maxFiles); context.registerService(S3ConnectorApi.class, s3Api); } } diff --git a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/connector/ionosapi/S3ApiConnector.java b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/connector/ionosapi/S3ApiConnector.java index d5bfc2e4..dad960b8 100644 --- a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/connector/ionosapi/S3ApiConnector.java +++ b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/connector/ionosapi/S3ApiConnector.java @@ -2,6 +2,7 @@ import java.io.IOException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; @@ -20,6 +21,26 @@ public S3ApiConnector() { .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } + public S3Regions retrieveRegions(String token) { + String url = BASE_URL + "/regions"; + + Request request = new Request.Builder().url(url) + .addHeader("Authorization", "Bearer " + token) + .get() + .build(); + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new EdcException("Unexpected code [" + response.code() + "] retrieving S3 regions"); + } + if (response.body() == null) + throw new IOException("Empty response body retrieving S3 regions"); + else + return objectMapper.readValue(response.body().string(), new TypeReference() {}); + } catch (IOException e) { + throw new EdcException("Error retrieving S3 accesskey", e); + } + } + public S3AccessKey createAccessKey(String token) { String url = BASE_URL + "/accesskeys"; diff --git a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/connector/ionosapi/S3Region.java b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/connector/ionosapi/S3Region.java new file mode 100644 index 00000000..507c731e --- /dev/null +++ b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/connector/ionosapi/S3Region.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 IONOS + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * IONOS + * + */ +package com.ionos.edc.extension.s3.connector.ionosapi; + +public class S3Region { + + private String id; + + private Properties properties; + + public String getId() { + return id; + } + + public Properties getProperties() { + return properties; + } + + public static class Properties { + + private String endpoint; + + public String getEndpoint() { + return endpoint; + } + } +} \ No newline at end of file diff --git a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/connector/ionosapi/S3Regions.java b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/connector/ionosapi/S3Regions.java new file mode 100644 index 00000000..5ebfebfa --- /dev/null +++ b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/connector/ionosapi/S3Regions.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 IONOS + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * IONOS + * + */ +package com.ionos.edc.extension.s3.connector.ionosapi; + +import java.util.List; + +public class S3Regions { + + private List items; + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } +} \ No newline at end of file diff --git a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/schema/IonosBucketSchema.java b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/schema/IonosBucketSchema.java index 9b3460e2..65921a56 100644 --- a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/schema/IonosBucketSchema.java +++ b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/schema/IonosBucketSchema.java @@ -18,7 +18,7 @@ public interface IonosBucketSchema { String TYPE = "IonosS3"; - String STORAGE_NAME = EDC_NAMESPACE + "storage"; + String REGION_ID = EDC_NAMESPACE + "region"; String BUCKET_NAME = EDC_NAMESPACE + "bucketName"; String BLOB_NAME = EDC_NAMESPACE + "blobName"; String PATH = EDC_NAMESPACE + "path"; @@ -27,5 +27,5 @@ public interface IonosBucketSchema { String ACCESS_KEY_ID = EDC_NAMESPACE + "accessKey"; String SECRET_ACCESS_KEY = EDC_NAMESPACE + "secretKey"; - String STORAGE_NAME_DEFAULT = "https://s3-eu-central-1.ionoscloud.com"; + String REGION_ID_DEFAULT = "de"; } diff --git a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/schema/IonosSettingsSchema.java b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/schema/IonosSettingsSchema.java index 456ed58a..3bef6158 100644 --- a/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/schema/IonosSettingsSchema.java +++ b/extensions/core-ionos-s3/src/main/java/com/ionos/edc/extension/s3/schema/IonosSettingsSchema.java @@ -17,7 +17,7 @@ public interface IonosSettingsSchema { String IONOS_ACCESS_KEY = "edc.ionos.access.key"; String IONOS_SECRET_KEY = "edc.ionos.secret.key"; - String IONOS_ENDPOINT = "edc.ionos.endpoint"; + String IONOS_REGION = "edc.ionos.endpoint.region"; String IONOS_TOKEN = "edc.ionos.token"; String IONOS_KEY_VALIDATION_ATTEMPTS = "edc.ionos.key.validation.attempts"; String IONOS_KEY_VALIDATION_DELAY = "edc.ionos.key.validation.delay"; diff --git a/extensions/core-ionos-s3/src/test/java/com/ionos/edc/extension/s3/api/S3ConnectorApiImplTest.java b/extensions/core-ionos-s3/src/test/java/com/ionos/edc/extension/s3/api/S3ConnectorApiImplTest.java deleted file mode 100644 index 2b48ff35..00000000 --- a/extensions/core-ionos-s3/src/test/java/com/ionos/edc/extension/s3/api/S3ConnectorApiImplTest.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.ionos.edc.extension.s3.api; - -import org.eclipse.edc.spi.EdcException; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class S3ConnectorApiImplTest { - - @Test - public void getRegion_Frankfurt_Full() { - var endpoint = "https://s3-eu-central-1.ionoscloud.com"; - var region = S3ConnectorApiImpl.getRegion(endpoint); - - assertEquals("de", region); - } - - @Test - public void getRegion_Frankfurt_Short() { - var endpoint = "s3-eu-central-1.ionoscloud.com"; - var region = S3ConnectorApiImpl.getRegion(endpoint); - - assertEquals("de", region); - } - - @Test - public void getRegion_Berlin_Full() { - var endpoint = "https://s3-eu-central-2.ionoscloud.com"; - var region = S3ConnectorApiImpl.getRegion(endpoint); - - assertEquals("eu-central-2", region); - } - - @Test - public void getRegion_Berlin_Short() { - var endpoint = "s3-eu-central-2.ionoscloud.com"; - var region = S3ConnectorApiImpl.getRegion(endpoint); - - assertEquals("eu-central-2", region); - } - - @Test - public void getRegion_Logrono_Full() { - var endpoint = "https://s3-eu-south-2.ionoscloud.com"; - var region = S3ConnectorApiImpl.getRegion(endpoint); - - assertEquals("eu-south-2", region); - } - - @Test - public void getRegion_Logrono_Short() { - var endpoint = "s3-eu-south-2.ionoscloud.com"; - var region = S3ConnectorApiImpl.getRegion(endpoint); - - assertEquals("eu-south-2", region); - } - - @Test - public void getRegion_Invalid_Full() { - var endpoint = "https://s3-de-central.profitbricks.com"; - - Exception exception = assertThrows(EdcException.class, () -> { - S3ConnectorApiImpl.getRegion(endpoint); - }); - - assertNotNull(exception); - } - - public void getRegion_Invalid_Short() { - var endpoint = "s3-de-central.profitbricks.com"; - - Exception exception = assertThrows(EdcException.class, () -> { - S3ConnectorApiImpl.getRegion(endpoint); - }); - - assertNotNull(exception); - } -} diff --git a/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/DataPlaneIonosS3Extension.java b/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/DataPlaneIonosS3Extension.java index a8d2cfcf..29ec30b1 100644 --- a/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/DataPlaneIonosS3Extension.java +++ b/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/DataPlaneIonosS3Extension.java @@ -24,9 +24,6 @@ import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.eclipse.edc.spi.types.TypeManager; -import static com.ionos.edc.extension.s3.schema.IonosSettingsSchema.IONOS_MAX_FILES; -import static com.ionos.edc.extension.s3.schema.IonosSettingsSchema.IONOS_MAX_FILES_DEFAULT; - @Extension(value = DataPlaneIonosS3Extension.NAME) public class DataPlaneIonosS3Extension implements ServiceExtension { @@ -55,12 +52,10 @@ public String name() { public void initialize(ServiceExtensionContext context) { var monitor = context.getMonitor(); - var maxFiles = context.getSetting(IONOS_MAX_FILES, IONOS_MAX_FILES_DEFAULT); - var sourceFactory = new IonosDataSourceFactory(s3Api, monitor); pipelineService.registerFactory(sourceFactory); - var sinkFactory = new IonosDataSinkFactory(s3Api, executorContainer.getExecutorService(), monitor, vault, typeManager, maxFiles); + var sinkFactory = new IonosDataSinkFactory(s3Api, executorContainer.getExecutorService(), monitor, vault, typeManager); pipelineService.registerFactory(sinkFactory); context.getMonitor().info("File Transfer Extension initialized!"); } diff --git a/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/IonosDataSinkFactory.java b/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/IonosDataSinkFactory.java index 1b968dce..8bb1f057 100644 --- a/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/IonosDataSinkFactory.java +++ b/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/IonosDataSinkFactory.java @@ -16,7 +16,6 @@ import com.ionos.edc.dataplane.ionos.s3.validation.IonosSinkDataAddressValidationRule; import com.ionos.edc.extension.s3.api.S3ConnectorApi; -import com.ionos.edc.extension.s3.api.S3ConnectorApiImpl; import com.ionos.edc.extension.s3.configuration.IonosToken; import com.ionos.edc.extension.s3.schema.IonosBucketSchema; import org.eclipse.edc.connector.dataplane.spi.pipeline.DataSink; @@ -34,8 +33,6 @@ import java.util.concurrent.ExecutorService; -import static com.ionos.edc.extension.s3.schema.IonosBucketSchema.STORAGE_NAME_DEFAULT; - public class IonosDataSinkFactory implements DataSinkFactory { private final ExecutorService executorService; @@ -43,17 +40,15 @@ public class IonosDataSinkFactory implements DataSinkFactory { private final S3ConnectorApi s3Api; private final Vault vault; private final TypeManager typeManager; - private final int maxFiles; private final Validator validator = new IonosSinkDataAddressValidationRule(); - public IonosDataSinkFactory(S3ConnectorApi s3Api, ExecutorService executorService, Monitor monitor, Vault vault, TypeManager typeManager, int maxFiles) { + public IonosDataSinkFactory(S3ConnectorApi s3Api, ExecutorService executorService, Monitor monitor, Vault vault, TypeManager typeManager) { this.s3Api = s3Api; this.executorService = executorService; this.monitor = monitor; this.vault = vault; this.typeManager = typeManager; - this.maxFiles = maxFiles; } @Override @@ -77,45 +72,23 @@ public DataSink createSink(DataFlowRequest request) { var destination = request.getDestinationDataAddress(); - var secret = vault.resolveSecret(destination.getKeyName()); - if (secret != null) { - var token = typeManager.readValue(secret, IonosToken.class); - - if (destination.getStringProperty(IonosBucketSchema.STORAGE_NAME) != null) { - var s3ApiTemp = new S3ConnectorApiImpl(destination.getStringProperty(IonosBucketSchema.STORAGE_NAME), - token.getAccessKey(), - token.getSecretKey(), - maxFiles); - return IonosDataSink.Builder.newInstance() - .bucketName(destination.getStringProperty(IonosBucketSchema.BUCKET_NAME)) - .path(destination.getStringProperty(IonosBucketSchema.PATH)) - .requestId(request.getId()) - .executorService(executorService) - .monitor(monitor) - .s3Api(s3ApiTemp) - .build(); - } else { - var s3ApiTemp = new S3ConnectorApiImpl(STORAGE_NAME_DEFAULT, - token.getAccessKey(), - token.getSecretKey(), - maxFiles); - return IonosDataSink.Builder.newInstance() - .bucketName(destination.getStringProperty(IonosBucketSchema.BUCKET_NAME)) - .path(destination.getStringProperty(IonosBucketSchema.PATH)) - .requestId(request.getId()) - .executorService(executorService) - .monitor(monitor) - .s3Api(s3ApiTemp) - .build(); - } + var secret = vault.resolveSecret(request.getDestinationDataAddress().getKeyName()); + if (secret == null) { + throw new EdcException("Missing destination temporary token"); } + var token = typeManager.readValue(secret, IonosToken.class); + + var region = destination.getStringProperty(IonosBucketSchema.REGION_ID); + + var s3ApiTemp = s3Api.clone(region, token.getAccessKey(), token.getSecretKey()); return IonosDataSink.Builder.newInstance() .bucketName(destination.getStringProperty(IonosBucketSchema.BUCKET_NAME)) .path(destination.getStringProperty(IonosBucketSchema.PATH)) - .requestId(request.getId()).executorService(executorService) + .requestId(request.getId()) + .executorService(executorService) .monitor(monitor) - .s3Api(s3Api) + .s3Api(s3ApiTemp) .build(); } } diff --git a/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/validation/IonosSourceDataAddressValidationRule.java b/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/validation/IonosSourceDataAddressValidationRule.java index c9691b10..02e7042a 100644 --- a/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/validation/IonosSourceDataAddressValidationRule.java +++ b/extensions/data-plane-ionos-s3/src/main/java/com/ionos/edc/dataplane/ionos/s3/validation/IonosSourceDataAddressValidationRule.java @@ -28,7 +28,7 @@ public class IonosSourceDataAddressValidationRule implements Validator { var value = dataAddress.getStringProperty(it); if (value == null || value.isBlank()) { diff --git a/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ConsumerResourceDefinitionGenerator.java b/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ConsumerResourceDefinitionGenerator.java index 9c27e1e3..c27a02c3 100644 --- a/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ConsumerResourceDefinitionGenerator.java +++ b/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ConsumerResourceDefinitionGenerator.java @@ -42,7 +42,7 @@ public ResourceDefinition generate(DataRequest dataRequest, Policy policy) { var id = randomUUID().toString(); var keyName = destination.getKeyName(); - var storage = destination.getStringProperty(IonosBucketSchema.STORAGE_NAME); + var regionId = destination.getStringProperty(IonosBucketSchema.REGION_ID); var bucketName = destination.getStringProperty(IonosBucketSchema.BUCKET_NAME); var accessKey = destination.getStringProperty(IonosBucketSchema.ACCESS_KEY_ID); var secretKey = destination.getStringProperty(IonosBucketSchema.SECRET_ACCESS_KEY); @@ -50,7 +50,7 @@ public ResourceDefinition generate(DataRequest dataRequest, Policy policy) { return IonosS3ResourceDefinition.Builder.newInstance() .id(id) .keyName(keyName) - .storage(storage) + .regionId(regionId) .bucketName(bucketName) .path(path) .accessKey(accessKey) diff --git a/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ProvisionedResource.java b/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ProvisionedResource.java index 9117ddcb..8b31a33f 100644 --- a/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ProvisionedResource.java +++ b/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ProvisionedResource.java @@ -50,8 +50,8 @@ public static Builder newInstance() { return new Builder(); } - public Builder storage(String storage) { - dataAddressBuilder.property(STORAGE_NAME, storage); + public Builder regionId(String regionId) { + dataAddressBuilder.property(REGION_ID, regionId); return this; } diff --git a/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3Provisioner.java b/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3Provisioner.java index 2663305c..c2f803db 100644 --- a/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3Provisioner.java +++ b/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3Provisioner.java @@ -80,8 +80,8 @@ public CompletableFuture> provision(IonosS3Resou .accessKeyID(temporaryKey.getId()) .transferProcessId(resourceDefinition.getTransferProcessId()) .hasToken(true); - if (resourceDefinition.getStorage() != null) { - resourceBuilder = resourceBuilder.storage(resourceDefinition.getStorage()); + if (resourceDefinition.getRegionId() != null) { + resourceBuilder = resourceBuilder.regionId(resourceDefinition.getRegionId()); } if (resourceDefinition.getPath() != null) { resourceBuilder = resourceBuilder.path(resourceDefinition.getPath()); diff --git a/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ResourceDefinition.java b/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ResourceDefinition.java index 4d407d8a..66a3a99c 100644 --- a/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ResourceDefinition.java +++ b/extensions/provision-ionos-s3/src/main/java/com/ionos/edc/provision/s3/bucket/IonosS3ResourceDefinition.java @@ -23,7 +23,7 @@ @JsonDeserialize(as=IonosS3ResourceDefinition.class) public class IonosS3ResourceDefinition extends ResourceDefinition { private String keyName; - private String storage; + private String regionId; private String bucketName; private String path; private String accessKey; @@ -35,8 +35,8 @@ public IonosS3ResourceDefinition() { public String getKeyName() { return keyName; } - public String getStorage() { - return storage; + public String getRegionId() { + return regionId; } public String getBucketName() { return bucketName; @@ -49,7 +49,7 @@ public String getPath() { public Builder toBuilder() { return initializeBuilder(new Builder()) .keyName(keyName) - .storage(storage) + .regionId(regionId) .bucketName(bucketName) .path(path) .accessKey(accessKey) @@ -70,8 +70,8 @@ public Builder keyName(String keyName) { resourceDefinition.keyName = keyName; return this; } - public Builder storage(String storage) { - resourceDefinition.storage = storage; + public Builder regionId(String regionId) { + resourceDefinition.regionId = regionId; return this; } public Builder bucketName(String bucketName) { diff --git a/hashicorp/README.md b/hashicorp/README.md index f54ecaff..2de75207 100644 --- a/hashicorp/README.md +++ b/hashicorp/README.md @@ -64,7 +64,7 @@ vault login token= vault kv put secret/edc.ionos.access.key content= vault kv put secret/edc.ionos.secret.key content= vault kv put secret/edc.ionos.token content= -vault kv put secret/edc.ionos.endpoint content= +vault kv put secret/edc.ionos.endpoint.region content= ``` Note: @@ -76,7 +76,7 @@ Note: ```console kubectl exec -it vault-0 -- vault kv put secret/edc.ionos.access.key content= kubectl exec -it vault-0 -- vault kv put secret/edc.ionos.secret.key content= -kubectl exec -it vault-0 -- vault kv put secret/edc.ionos.endpoint content= +kubectl exec -it vault-0 -- vault kv put secret/edc.ionos.endpoint.region content= kubectl exec -it vault-0 -- vault kv put secret/edc.ionos.token content= ``` diff --git a/launchers/dev/connector-consumer/resources/config.properties b/launchers/dev/connector-consumer/resources/config.properties index e6246173..63d85447 100644 --- a/launchers/dev/connector-consumer/resources/config.properties +++ b/launchers/dev/connector-consumer/resources/config.properties @@ -18,5 +18,5 @@ edc.vault.hashicorp.timeout.seconds=30 edc.ionos.access.key= edc.ionos.secret.key= -edc.ionos.endpoint=https://s3-eu-central-1.ionoscloud.com -edc.ionos.token= \ No newline at end of file +edc.ionos.endpoint.region= +edc.ionos.token= \ No newline at end of file diff --git a/launchers/dev/connector-provider/resources/config.properties b/launchers/dev/connector-provider/resources/config.properties index e83e681b..3717bddc 100644 --- a/launchers/dev/connector-provider/resources/config.properties +++ b/launchers/dev/connector-provider/resources/config.properties @@ -18,4 +18,5 @@ edc.vault.hashicorp.timeout.seconds=30 edc.ionos.access.key= edc.ionos.secret.key= -edc.ionos.endpoint=https://s3-eu-central-1.ionoscloud.com +edc.ionos.endpoint.region= +edc.ionos.token= \ No newline at end of file diff --git a/launchers/prod/connector-persistence/resources/config.properties b/launchers/prod/connector-persistence/resources/config.properties index f626f02a..36d759a6 100644 --- a/launchers/prod/connector-persistence/resources/config.properties +++ b/launchers/prod/connector-persistence/resources/config.properties @@ -20,8 +20,8 @@ edc.vault.hashicorp.timeout.seconds=30 edc.ionos.access.key= edc.ionos.secret.key= -edc.ionos.endpoint= -edc.ionos.token= +edc.ionos.endpoint.region= +edc.ionos.token= edc.datasource.asset.name=asset edc.datasource.asset.user= diff --git a/launchers/prod/connector/resources/config.properties b/launchers/prod/connector/resources/config.properties index 5586509e..7c848bc8 100644 --- a/launchers/prod/connector/resources/config.properties +++ b/launchers/prod/connector/resources/config.properties @@ -20,5 +20,5 @@ edc.vault.hashicorp.timeout.seconds=30 edc.ionos.access.key= edc.ionos.secret.key= -edc.ionos.endpoint= -edc.ionos.token= +edc.ionos.endpoint.region= +edc.ionos.token=