Skip to content

Latest commit

 

History

History
1158 lines (782 loc) · 65.6 KB

eclipse-edc.rst

File metadata and controls

1158 lines (782 loc) · 65.6 KB

eclipse-edc

  • #1832 で多少整理された感がある。

  • どのモジュールがどのSPIを実装してるのかは、モジュールの依存関係から見るのが早いのかな..?:

    $ find . -name build.gradle.kts | xargs grep 'api(project(":spi:'
    ./core/data-plane-selector/data-plane-selector-core/build.gradle.kts:    api(project(":spi:data-plane-selector:data-plane-selector-spi"))
    ./core/data-plane/data-plane-framework/build.gradle.kts:    api(project(":spi:common:core-spi"))
    ./core/data-plane/data-plane-framework/build.gradle.kts:    api(project(":spi:data-plane:data-plane-spi"))
    ./core/data-plane/data-plane-framework/build.gradle.kts:    api(project(":spi:control-plane:control-plane-api-client-spi"))
    ./core/data-plane/data-plane-util/build.gradle.kts:    api(project(":spi:data-plane:data-plane-spi"))
    ...
    
  • web.http.{context}.path and web.http.{context}.port のような設定プロパティの組で、ポートとpathの組を指定する。

  • 上記のcontext aliasとしてはcontrol、management、protocol、publicがある。

    • https://github.com/eclipse-edc/Connector/blob/9adb0e4a09f4b0518a903e61890f94229ebda69e/docs/developer/decision-records/2022-11-09-api-refactoring/renaming.md
    • controlはコネクタが内部的に使うもの。 という理解だったが、コネクタ間のやりとりでDataspace Protocol以外のものだと、少ないように見える。 transferのsample実行時に/controlというcontext pathにregisterされたcontrollerは以下。
      • TransferProcessControlApiController
      • ConsumerPullTransferTokenValidationApiController
      • DataPlaneControlApiController
    • managementはコネクタのクライアントが呼び出すもの。
    • protocolはDataspace Protocol用のもので、Dataspace Protocolへの移行前はidsだった。
    • publicはdata planeがデータを送るときに使うもの。
  • どのAPIがどのport/contextに対応してるいるのか、コードを静的に眺めて判断するのが以外と難しい。 JerseyRestService#start にブレークポイントを仕掛けて、contextとcontrolerとの対応付けをデバッガで見るとわかりやすいか。 Samples/transferのコネクタ でやると、以下のような感じ。:

    $ java \
       -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=18888 \
       -Dedc.keystore=transfer/transfer-00-prerequisites/resources/certs/cert.pfx \
       -Dedc.keystore.password=123456 \
       -Dedc.vault=transfer/transfer-00-prerequisites/resources/configuration/provider-vault.properties \
       -Dedc.fs.config=transfer/transfer-00-prerequisites/resources/configuration/provider-configuration.properties \
       -jar \
       transfer/transfer-00-prerequisites/connector/build/libs/connector.jar
    
  • web.http.path and web.http.port は、defaultコンテキストに対応づけられる。 controlとmanagementは固有の指定( web.http.control.path や web.http.management.path )がない場合、defaultを使う。 ( useDefaultContext(true) されている。)

  • Swaggerのアノテーションを利用して、.yamlなどを生成している。

  • OpenAPIで生成したドキュメントはSwagger Hubでホストされることになり、 ソースツリー内のdocs/swaggeruiは削除された。 generateSwaggerUiタスクによるローカルにドキュメント閲覧もできなくなった。

  • Swagger UIのドキュメント上、management-apiとcontrol-apiの2つのくくりに分かれている。 v0.1.0で見た時の分類は以下。 context aliasとの対応で見ると、managementはmanagement-apiで、 残りのcontrol、protocol、publicはcontrol-apiなのかしら。:

    $ find . -name build.gradle.kts | xargs grep management-api | grep apiGroup
    ./extensions/data-plane-selector/data-plane-selector-api/build.gradle.kts:        apiGroup.set("management-api")
    ./extensions/control-plane/provision/provision-http/build.gradle.kts:        apiGroup.set("management-api")
    ./extensions/control-plane/api/management-api/policy-definition-api/build.gradle.kts:        apiGroup.set("management-api")
    ./extensions/control-plane/api/management-api/contract-definition-api/build.gradle.kts:        apiGroup.set("management-api")
    ./extensions/control-plane/api/management-api/contract-negotiation-api/build.gradle.kts:        apiGroup.set("management-api")
    ./extensions/control-plane/api/management-api/transfer-process-api/build.gradle.kts:        apiGroup.set("management-api")
    ./extensions/control-plane/api/management-api/catalog-api/build.gradle.kts:        apiGroup.set("management-api")
    ./extensions/control-plane/api/management-api/asset-api/build.gradle.kts:        apiGroup.set("management-api")
    ./extensions/control-plane/api/management-api/contract-agreement-api/build.gradle.kts:        apiGroup.set("management-api")
    ./extensions/common/api/api-observability/build.gradle.kts:        apiGroup.set("management-api")
    ./extensions/common/api/management-api-configuration/build.gradle.kts:        apiGroup.set("management-api")
    
    $ find . -name build.gradle.kts | xargs grep control-api | grep apiGroup
    ./extensions/data-plane/data-plane-api/build.gradle.kts:        apiGroup.set("control-api")
    ./extensions/control-plane/transfer/transfer-data-plane/build.gradle.kts:        apiGroup.set("control-api")
    ./extensions/control-plane/api/control-plane-api/build.gradle.kts:        apiGroup.set("control-api")
    
  • -PverboseTest を指定すると、出力されるログが増える。:

    $ ./gradlew test -PverboseTest
    
  • 特定のテストだけを実行したい場合は以下の要領。

    $ ./gradlew extensions:api:data-management:transferprocess:test --tests '*TransferProcessEventDispatchTest'
    
  • 特定のディレクトリ下のサブモジュールのテストすべてを実行したい場合は、 -p でディレクトリを指定する。:

    $ ./gradlew test -p extensions/api/data-management/transferprocess --tests '*TransferProcessEventDispatchTest'
    
  • @EndToEntTest アノテーションがついたテストを実行するためには、以下の要領。:

    $ ./gradlew test -DincludeTags="EndToEndTest"
    
  • 特定のテストメソッドだけ実行する例:

    $ ./gradlew clean test -p system-tests/e2e-transfer-test/runner -PverboseTest -DincludeTags="EndToEndTest" --tests "*EndToEndTransferInMemoryTest.httpPull_dataTransfer" 2>&1 | tee /tmp/test.log
    
  • @PostgresqlDbIntegrationTest アノテーションが付いたテストを実行する場合、下記の要領。:

    $ ./gradlew clean test -p system-tests/e2e-transfer-test/runner -DincludeTags=PostgresqlIntegrationTest
    $ ./gradlew clean test -p system-tests/e2e-transfer-test/runner -DincludeTags=PostgresqlIntegrationTest --tests '*TransferPullEndToEndTest*pullFromHttp' -PverboseTest
    
  • JUnitのテストケース内でServiceExtension実装をテストするための枠組みが、 core/common/junit下に定義されている。

    • EdcExtensionは、各テストメソッドの前後でbootしてshutdownするようなBaseRuntimeの拡張。 テストクラスに @ExtendWith(EdcExtension.class) して利用する。
    • EdcExtensionはParameterResolverを実装しているので、 テストメソッドの引数としてregister済みのサービス(mock)を指定できる。
    • EdcExtension#registerServiceMock はテスト用のserviceをregisterする。 ServiceExtensionContext#registerService で既にregister済みのserviceでもオーバーライドできる。
    • EdcExtension#registerSystemExtension はテスト用にextensionをregisterする。 @Inject なフィールドに @Provider なメソッドで生成したインスタンスをセットする処理は、 ExtensionLoader#bootServiceExtensions で実行される。 そのため、 @BetoreEach なメソッドの中など、bootされるタイミングより前で、 呼び出しておかなければならない。
  • コネクタによるデータ転送の一連の流れを実行するテストコードが定義されている。

  • AbstractEndToEndTransferがベースクラスで、データの永続化先によって3種類の派生がある。 各派生には @EndToEndTest のようなアノテーションがついていて、それに応じて -DincludeTags=EndToEndTest のような指定をしないと、テストが実行されない。

  • EndToEndTransferInMemoryTestはデータをメモリ上に持ち、永続化しないパターンで、それ単体で実行できる。:

    $ ./gradlew clean test -p system-tests/e2e-transfer-test/runner -DincludeTags=EndToEndTest --tests '*EndToEndTransferInMemoryTest' -PverboseTest
    
  • EndToEndTransferPostgresqlTestはPostgreSQLにデータを永続化する。 これも、コンテナを利用してPostgreSQLのサーバを建てることで、簡単に実行できる。:

    $ docker run --rm --name edc-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres
    $ ./gradlew clean test -p system-tests/e2e-transfer-test/runner -DincludeTags=PostgresqlIntegrationTest --tests '*EndToEndTransferPostgresqlTest' -PverboseTest
    
    • テスト実行後に、データベース内のデータを見てみるのも、理解を深めるのに役立つかもしれない。 concsumerとproducerというデータベースができている。:

      $ psql -U postgres -W -h localhost -l
      psql: warning: extra command-line argument "postgres" ignored
      Password:
                                       List of databases
         Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges
      -----------+----------+----------+------------+------------+-----------------------
       consumer  | postgres | UTF8     | en_US.utf8 | en_US.utf8 |
       postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 |
       provider  | postgres | UTF8     | en_US.utf8 | en_US.utf8 |
       template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
                 |          |          |            |            | postgres=CTc/postgres
       template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
                 |          |          |            |            | postgres=CTc/postgres
      (5 rows)
      
      $ psql -U postgres -W -h localhost -c 'SELECT * FROM edc_policydefinitions LIMIT 1;' provider
                        policy_id               |  created_at   |                                                                                           permissions                                                                                           | prohibitions | duties | extensible_properties | inherits_from | assigner | assignee | target |      policy_type
      --------------------------------------+---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+--------+-----------------------+---------------+----------+----------+--------+-----------------------
       f5ed763c-7ec1-427d-a47d-3099236b61bd | 1682079999930 | [{"edctype":"dataspaceconnector:permission","uid":null,"target":null,"action":{"type":"USE","includedIn":null,"constraint":null},"assignee":null,"assigner":null,"constraints":[],"duties":[]}] | []           | []     | {}                    |               |          |          |        | {"@policytype":"set"}
      (1 row)
      
    • PostgreSQLの設定を変えたい場合、 dockerhubのドキュメント にあるように、 postgresql.confを置き換えればよい。 コンテナはpostgresプロセスがPID 1で起動してくるので、 pg_ctl reload はできるが、 pg_ctl restart はできない。:

      $ docker run -i --rm postgres cat /usr/share/postgresql/postgresql.conf.sample > my-postgres.conf
      $ vi my-postgres.conf
      $ docker run --rm --name edc-postgres -v "$PWD/my-postgres.conf":/etc/postgresql/postgresql.conf -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres -c 'config_file=/etc/postgresql/postgresql.conf'
      
    • log_statement = 'all' , log_destination = 'stderr' , log_directory = '/var/log/postgresql' という設定で、クエリログを出力するのも、内部動作を確認する上でよい。

  • ドキュメント自動生成用のモジュールやアノテーションの定義は、 #2001で、 GradlePlugins 配下に移動された。
  • データの永続化のための仕組み/抽象化は独自実装で、外部ライブラリの依存性が増えることを避ける方針に見える。
    • 永続化が必要なサブモジュールは、それぞれ org.eclipse.edc.spi.persistence.*.*Store のような名前の、インターフェースを定義する。 この定義はサブモジュールごとに行っていて、意外と共通化されていない。
    • デフォルト実装として、データを永続化しない InMemory*Store があり、ユニットテストやサンプルの実行に利用される。 こちらも、あまり共通化する余地なし。
    • RDBMSを利用してデータを永続化する実装として Sql*Store がある。 これらの実装は、 common/sql/sql-core下の org.eclipse.edc.sql.store.AbstractSqlStore を、 ベースロジックとしてモジュール横断的に利用されているようだ。
      • Sql*Store では、 *Statements のような名前のクラスを使い、 SQLステートメントを組み上げてJDBCドライバで実行する。
      • *Statements*DialectStatements のようなクラスをベースにしている。 このDialectを切り替えることで、複数RDBMSに対応できるようにする方針。 デフォルトで用意されているのは PostgresDialectStatements でPostgreSQLが前提。
  • ログの出力はMonitorというインターフェースで抽象化されている。 明示的にMonitor実装がregisterされていない場合、 ConsoleMonitorという単純な実装が使われる。 ロギングライブラリは使用せずに、コンソールにDEBUGレベルを含むすべてのログを出力する。
  • MonitorExtension実装をロードすることで、monitorの切りかえ/追加ができる。
  • LoggerMonitorExtensionは、java.util.loggingでログ出力するLoggerMonitorを提供するもの。
  • BaseRuntimeは MonitorProvider というSLF4JServiceProvider実装をロードし、SLF4J APIで出力されたログを、Monitor側に送る仕組みを用意している。 結果として、ほかのSLF4J bindingを使うことができない。

コネクタ内のHTTPリクエストは、okhttp3で実行されている。 logging-interceptorを仕込むと、リクエストの内容をログ出力できる。:

$ git diff
diff --git a/core/common/connector-core/src/main/java/org/eclipse/edc/connector/core/base/OkHttpClientFactory.java b/core/common/connector-core/src/main/java/org/eclipse/edc/connector/core/base/OkHttpClientFactory.java
index 10dc4d5d2..1c7bc3eab 100644
--- a/core/common/connector-core/src/main/java/org/eclipse/edc/connector/core/base/OkHttpClientFactory.java
+++ b/core/common/connector-core/src/main/java/org/eclipse/edc/connector/core/base/OkHttpClientFactory.java
@@ -77,6 +77,9 @@ public class OkHttpClientFactory {
             context.getMonitor().info("HTTPS enforcement it not enabled, please enable it in a production environment");
         }

+        var logging = new okhttp3.logging.HttpLoggingInterceptor();
+        logging.setLevel(okhttp3.logging.HttpLoggingInterceptor.Level.BODY);
+        builder.addInterceptor(logging);
         return builder.build();
     }

diff --git a/gradle.properties b/gradle.properties
index 9bd583ee1..e86600c1b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,9 +1,9 @@
 group=org.eclipse.edc
-version=0.3.1-SNAPSHOT
+version=0.3.1
 # for now, we're using the same version for the autodoc plugin, the processor and the runtime-metamodel lib, but that could
 # change in the future
-annotationProcessorVersion=0.3.1-SNAPSHOT
-edcGradlePluginsVersion=0.3.1-SNAPSHOT
-metaModelVersion=0.3.1-SNAPSHOT
+annotationProcessorVersion=0.3.1
+edcGradlePluginsVersion=0.3.1
+metaModelVersion=0.3.1
 edcScmUrl=https://github.com/eclipse-edc/Connector.git
 edcScmConnection=scm:git:[email protected]:eclipse-edc/Connector.git
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 97672f052..12b80c690 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -79,6 +79,7 @@ mockserver-client = { module = "org.mock-server:mockserver-client-java", version
 mockserver-netty = { module = "org.mock-server:mockserver-netty", version.ref = "httpMockServer" }
 nimbus-jwt = { module = "com.nimbusds:nimbus-jose-jwt", version.ref = "nimbus" }
 okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
+okhttp-logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
 opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api", version.ref = "opentelemetry" }
 opentelemetry-instrumentation-annotations = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations", version.ref = "opentelemetry" }
 opentelemetry-proto = { module = "io.opentelemetry.proto:opentelemetry-proto", version.ref = "opentelemetry-proto" }
diff --git a/spi/common/http-spi/build.gradle.kts b/spi/common/http-spi/build.gradle.kts
index 9aaf288b5..d9fa0bfa7 100644
--- a/spi/common/http-spi/build.gradle.kts
+++ b/spi/common/http-spi/build.gradle.kts
@@ -21,6 +21,7 @@ dependencies {
     api(project(":spi:common:core-spi"))

     api(libs.okhttp)
+    api(libs.okhttp.logging.interceptor)
     api(libs.failsafe.okhttp)
 }

okhttp3のロギングはjava.util.loggingを使っているので、 -Djava.util.logging.config.file=/tmp/logging.properties のようにシステムプロパティ経由で設定ファイルを指定できる。:

$ cat >/tmp/logging.properties <<EOF
handlers = java.util.logging.ConsoleHandler
.level = INFO
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format = %1\$tF %1\$tT %4\$s : %5\$s %n
EOF

指定したファイルのpathが誤っているなどすると、単にログが出なくなるため、原因を見つけにくい。

  • StatefulEntityは、StateMachineManagerのsingle threadedなExecutorによって状態遷移される。

  • StateMachineManagerが使われるのは3か所。

    • ContractServiceExtensionで初期化される ProviderContractNegotiationManagerと、ConsumerContractNegotiationManager。
    • CoreTransferExtensionで初期化されるTransferProcessManager。
  • 基本的にはWaitStrategyはExponentialWaitStrategy(1000)が使われる。 なんらかのprosessが実行された場合はスリープなし、 そうでなければ1000ミリ秒後に次回、という感じ。

  • テスト用にWaitStrategyを差し込み可能になっている。 see NegotiationWaitStrategy and TransferWaitStrategy

  • StateMachineManager#loop 一回につき、 登録されたprocessor のすべてが実行される。 バックエンドのstoreがRDBの場合、以下のようなクエリが、 各stateを処理する各processorによって繰り返し実行される。:

    SELECT * FROM edc_transfer_process WHERE state = $1 AND pending = $2 AND (lease_id IS NULL OR lease_id IN (SELECT lease_id FROM edc_lease WHERE ($3 > (leased_at + lease_duration)))) LIMIT $4 OFFSET $5
    
  • /v2/transferprocesses は、consumer connectorが、データ転送のためのリクエストを受けるAPI。

    • sourceは、ContractAgreementに含まれるassetIdで指定される。
    • destinationは、dataDestinationで具体的にtypeとその他propertyで指定される。 例えばAzure Blobだと、typeはAzureStorageで、 accountでストレージアカウント名、containerはcontainer名を指す。
  • データ転送の処理それ自体は、transfer-data-plane側にコードがある。 https://github.com/eclipse-edc/Connector/blob/65479dc186ad0517565c77047672d1783a2188d7/extensions/control-plane/transfer/transfer-data-plane/README.md

  • リクエストが呼ばれると、TransferProcessインスタンスが作成され、 状態(state)を含む情報がTransferProcessStoreに保存される。 StateMachineManagerのスレッドがprocess*を順次呼び出すことで、 TransferProcessの状態は遷移していく。

    • processInitialで、destinationのtypeに応じて必要なら、 登録されたConsumerResourceManifestGeneratorにが、ResourceDefinitionを作成する。 現状destinationがAzure Blob/Amazon S3/GCSのオブジェクトの場合に、この処理が入る。

    • processProvisioningで、上記のResourceDefinitionに応じて、 ProvisionManagerが登録されたProvisioner実装を利用して、resourceを作成する。 destinationがAzure Blog/Amazon S3/GCSのオブジェクトの場合に、 container/bucketを(無ければ)作成し、provider connecterに書き込みを許可するための、 tokenを作成する。

    • processRequestingで、provider connectorにDataRequestを送る。 リクエストはRemoteMessageDispatcherを利用して送信される。

      • DataRequestメッセージを受信したprovider connector側では、 ArtifactRequestHandlerがリクエストを処理する。 ここでも、consumer側と同じようにTransferProcessManagerImplが使われ、 TransferProcessが作られる。 consumer側のTransferProcessとは独立だが、同じDataRequestのidに紐づくので、 consumerとproducerでTransferProcessStoreは独立になっていないとダメ。

        • (provider側の)processProvisioningの段階で、initiateDataTransferが呼ばれ、 DataFlowManagerを介して、data-planeの処理が呼ばれる。
          • DataFlowManagerは、DataFlowControllerを切り替える。 destinationがHttpProxyだとConsumerPullTransferDataFlowControllerが、 それ以外だとProviderPushTransferDataFlwoControllerが使われる。
        • DataPlaneSelectorで、接続先を選択する。 DataPlaneSelectorも、個別に建ててREST APIでアクセスする方式を取れる。
        • 接続先を示すDataplaneInstanceは、 data-plane-selector-apiの提供するREST API(/instances)で、事前に追加(定義)する。
        • DataPlaneClientで、DataFlowRequestをdata-planeに送る。 DataPlaneManagerが同居しているどうかで、クラスが違う。 EmbeddedDataPlaneTransferClientとRemotDataPlaneTransferClientがある。
    • processInprogressで、StatusChecker実装が、transferが終わったか確認する。 例えばAzure Blobだと、container内に、名前のsuffixが".complete"なblobがあるかを見る。

    • provider pushの場合、 provider側でsink.transfer(source)という形で、データコピーが実行される。 sinkはconsumer側に属するリソースなので、書き込み権限をどうやって与えるかがポイントになる。 例えば、sinkがAzure Blobなら、consumer側のコネクタが、自身のstorage accountで、 コンテナと、書き込みのにを許すSASトークンを作成し、それをvault経由でprovider側が読めるようにする。

  • eclipse-edc/Connector#463
  • DataPlaneFrameWorkExtensionが本体。 サンプル類はdata-plane-coreにdependencyを付けてロードしている。
  • PipelineServiceImpl#transferがデータコピー処理の本体。 sink.transfer(source) する。 PipelineServiceImpl implements PipelineService extends TransferService みたいな階層で、 インターフェースが切られているが、その理由は?
  • (data-plane-apiモジュールの)DataPlaneApiExtensionが、REST APIを提供する。 controlとpublicという2種類のcontextを使い分ける。 そのため、web.http.control.*とweb.http.public.*の2種類の設定(port mapping)が必要。 DataFlowRequestを受け取る/transferはcontrolの範疇。
  • DataPlanePublicApiControllerは、transferされたデータをByteArrayOutputStreamで受け取って、 クライアントにtoStringして渡すので、大きなデータを受け渡せるわけではない。
  • consumerがHTTPレスポンスのbodyとしてデータを受け取るパターンは、e2e-transfer-testの方に例が追加された。
  • providerは、 asset typeをcanHandleなSourceから、 dataDestination typeをcanHandleなSinkに、 transferする。
  • assetのtypeを増やす場合、DataSourceFactoryとDataSinkFactoryの実装をつくり、 PipelineService#registerFactory する。
  • 元々あったprovider pushは、provider connector側でデータ送信の処理( sink.transfer(source) )が呼ばれるのでわかりやすい。 それに対して、後から追加されたデータ転送方式であるところのconsumer pullはちょっとわかりにくい。
    • 現状consumer pullになるのは、destinationのtypeがHttpProxyの場合のみ。
    • consumer pullの場合は、TransferStartMessageのペイロードとして、データの在処を示すEndpointDataReference(EDR)をconsumer connectorに渡す。 consumer connectorは、受け取ったEDRをbackendにPOSTする。
    • consumer clientは(backendから取り出した)EDRに入っているendpointのURLに対して、authCodeに入っているトークンをAuthorizationヘッダに入れて、GETする。 このendpointのURLはコネクタのdata-plane APIを指すもの。 コネクタは、authCodeに含まれている真のデータの在処を示すURLからデータを取得し、clientに渡す。つまり、プロキシサーバとして振る舞う。 authCodeに含まれる情報で認証を行うために、クライアントは直接データの在処にアクセスしない。

#1645 で、 chunked transferが問題となる場合の対策として、 HttpAddressのpropertyで、nonChunkedTransferをtrueにすることで、 chunked transferをオフにできるようになった。:

"dataDestination": {
  "type": "HttpData",
  "baseUrl": "http://localhost:4000/api/consumer/store",
  "nonChunkedTransfer": "true"
}
  • IDE(IntelliJ)で開くと、Gradleデーモンがメモリ不足で落ちる場合がある。 落ちない場合もある。 ヒープサイズはgradle.propertiesに以下を追加することで増やせるが..。:

    org.gradle.jvmargs=-Xmx4g
    
  • https://github.com/eclipse-edc/docs

  • 複数のリポジトリのドキュメントをまとめて一つに見せる仕組み。 もともとはConnectorにあったドキュメントを移動し、拡張したもの。

  • eclipse-edc.github.io でサイトがserveされている。

  • docsify というツールが使われていて、 docsify serve コマンドでローカルで確認可能。

  • git submodule で、 各種リポジトリ

    を取得し、そのdocsをまとめてserveする。:

    $ git clone https://github.com/eclipse-edc/docs
    $ cd docs
    $ git submodule update --init --remote
    $ docsify serve docs
    
  • submoduleは、GitHubのworkflowで、 週一回更新 されていく。

  • docsも自身のsubmodule になっている。 docs/documentation/配下のmarkdownを編集すると、 docsifyでserveされてるサイトに即時反映されるので便利だが、 その修正をpull requestにするためには、 submoduleではない本体側に変更を反映する必要がある。

  • samplesの内容は、個別のソースツリーに移動された。

  • transferのサンプルが雰囲気をつかむのによい。

    • client(curlコマンド)はconsumerにREST APIでmanagemnent APIのリクエストを送る。 consumerは受付情報的な内容をすぐにレスポンスとして返す。
    • consumerはclientリクエストを受けて、providerにDataspace Protocolのリクエストを送る。
  • 手でcurlコマンドを叩く代わりに、一連の処理をtestタスクで実行することもできる。:

    $ ./gradlew clean test -p system-tests -DincludeTags=EndToEndTest --tests Transfer03providerPushTest -PverboseTest
    
    • 最近は、testcontainersを使って、backendなどをDockerで起動するようになった様子。
  • EDCのモジュール構造を記述するためのアノテーションを定義している。
  • フィールドのinjectionなどの、 DependencyGraph内の処理に関する順序 としては、 BaseExtension > CoreExtension > その他
  • ExtensionPointは、 GradlePlugins で定義された、モジュール定義のドキュメントを自動生成する仕組みの中で利用される。 単に、実装すべきInterfaceであることを示すという感じ。
  • いくつかのプラグインを定義している。
    • モジュール定義のドキュメントを自動生成。
      • 各サブモジュールをビルドしたときにできる build/edc.json がそれ。
      • 対象となるのはextensionかspi 。 spiモジュールについては、 @Spi なインターフェースがただ一つあるという前提のようだ。
    • EDCのGradleモジュールの convention を定義。
    • サブモジュール名の重複がないかどうかを確認。
    • OpenAPIの定義をマージ。
    • テストのサマリを出力。
  • org.eclipse.edc.edc-build (のベースとなるedc-build-base)により、 上記のプラグイン一式が組み込まれる
  • Connectorのbuild.gradle.kts を見ると使い方がなんとなく分かる。

Docker Composeを利用して、ローカルノードで動作確認できる。

  • https://github.com/eclipse-edc/MinimumViableDataspace/blob/659505e2a3dee432341d3e91d6f22509dfcff6ec/system-tests/README.md#test-execution-using-embedded-services

  • -DuseFsVault="true" をつけてビルドしないと、(azuriteではなく)Azure前提のVaultが使われて、エラーになる。

  • MVD_UI_PATHをexportして、DataDashboardのUIを動かす場合も、上記の仕込みは必要。

  • MVDはAxure BlobのみをAssetのデータ置き場としてサポートしているため、azuriteのコンテナがいる。

  • WebDidResolverがDIDを取得するために、nginxのコンテナがいる。

  • 上記をまとめてると、以下の要領でコマンドを実行することになる。:

    $ cd /home/iwasakims/srcs
    $ git clone https://github.com/eclipse-edc/MinimumViableDataspace
    $ git clone https://github.com/eclipse-edc/DataDashBoard
    $ cd MinimumViableDataspace
    

    $ ./gradlew -DuseFsVault="true" :launchers:connector:shadowJar $ ./gradlew -DuseFsVault="true" :launchers:registrationservice:shadowJar $ export MVD_UI_PATH=/home/iwasakims/srcs/eclipse-edc/DataDashboard $ docker compose --profile ui -f system-tests/docker-compose.yml up --build

  • cli-toolsというコンテナの、 entrypoint.sh のなかで、participantのenrollmentを実行。

    • identity-hub-cliでverifiable credentialを登録
    • registry-service-cliでparticipantを登録
  • did-serverというnginxのコンテナが、 DID document の置き場。

MVDはAxure BlobのみをAssetのデータ置き場としてサポートしているため、 試すには現物のAzureを使うか、Azuriteのコンテナをローカル実行する必要がある。

テスト用にAzure Blogのcontainerやblobを作る上では、 Azure CLIのazコマンドを使うのが楽。 Ubuntu環境であれば、 LinuxにAzure CLIをインストールする 手順にあるように、aptでインストールできる。:

$ sudo apt-get update
$ sudo apt-get install ca-certificates curl apt-transport-https lsb-release gnupg
$ curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/keyrings/microsoft.gpg > /dev/null
$ sudo chmod go+r /etc/apt/keyrings/microsoft.gpg
$ AZ_DIST=$(lsb_release -cs)
$ echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $AZ_DIST main" | sudo tee /etc/apt/sources.list.d/azure-cli.list
$ sudo apt-get update
$ sudo apt-get install azure-cli
$ az version

azuriteを使う場合、ストレージアカウント名とキーは、 docker-compose.ymlのAZURITE_ACCOUNTS で設定されている。 それに合わせて、接続文字列を設定して使う。:

$ az config set storage.connection_string="DefaultEndpointsProtocol=http;AccountName=company1assets;AccountKey=key1;BlobEndpoint=http://localhost:10000/company1assets"
$ az storage container list
$ az storage container create --name src-container
$ az storage blob upload --container-name src-container --file ./deployment/azure/terraform/modules/participant/sample-data/text-document.txt

Azure CLIでblobを操作する方法は、 Azure Blob Storage documentation 等に説明がある。

  • https://github.com/eclipse-edc/FederatedCatalog

  • /federatedcatalogというpathに対応したAPIをserveする。 指定された条件を満たすContractOfferを返す。

  • (test用ではない)extensionとしては4つ。:

    40 FederatedCatalog/core/federated-catalog-core/src/main/java/org/eclipse/edc/catalog/cache/FederatedCatalogCacheExtension.java public class FederatedCatalogCacheExtension implements ServiceExtension {
    37 FederatedCatalog/core/federated-catalog-core/src/main/java/org/eclipse/edc/catalog/cache/FederatedCatalogDefaultServicesExtension.java public class FederatedCatalogDefaultServicesExtension implements ServiceExtension {
    28 FederatedCatalog/extensions/api/federated-catalog-api/src/main/java/org/eclipse/edc/catalog/api/query/FederatedCatalogCacheQueryApiExtension.java public class FederatedCatalogCacheQueryApiExtension implements ServiceExtension {
    35 FederatedCatalog/extensions/store/fcc-node-directory-cosmos/src/main/java/org/eclipse/edc/catalog/node/directory/azure/CosmosFederatedCacheNodeDirectoryExtension.java public class CosmosFederatedCacheNodeDirectoryExtension implements ServiceExtension {