From ffe6dfc2ff3653012ea94c135dbf45d93144bcb9 Mon Sep 17 00:00:00 2001 From: "Riabokon Stanislav(EPAM)[GCP]" <stanislav_riabokon@epam.com> Date: Fri, 21 Feb 2025 15:29:16 +0000 Subject: [PATCH] Moved GC to CImpl (GONRG-10420) --- devops/gc/pipeline/override-stages.yml | 33 + provider/storage-gc/README.md | 28 +- .../cloudbuild/Dockerfile.cloudbuild | 15 +- provider/storage-gc/docs/anthos/README.md | 565 ------------------ .../storage-gc/docs/anthos/pics/client.png | Bin 92098 -> 0 bytes .../storage-gc/docs/anthos/pics/rabbit.PNG | Bin 9605 -> 0 bytes provider/storage-gc/docs/anthos/pics/sa.png | Bin 52971 -> 0 bytes provider/storage-gc/docs/gc/README.md | 42 +- provider/storage-gc/maven/settings.xml | 14 - provider/storage-gc/pom.xml | 99 +-- .../provider/gcp/StorageApplicationGCP.java | 4 +- .../formatter/GoogleJsonFormatter.java} | 27 +- .../MessagingCustomContextConfiguration.java | 68 --- .../LegalComplianceChangeServiceGcpImpl.java | 129 ---- .../jobs/LegalTagChangedProcessing.java | 49 -- .../messaging/jobs/OqmSubscriberManager.java | 185 ------ .../override/ScopeModifierPostProcessor.java | 47 -- .../scope/override/ThreadDpsHeaders.java | 53 -- .../gcp/messaging/thread/ThreadScope.java | 66 -- .../thread/ThreadScopeAttributes.java | 56 -- .../thread/ThreadScopeContextHolder.java | 48 -- .../provider/gcp/web/cache/CacheConfig.java | 84 --- .../web/cache/LegalTagMultiTenantCache.java | 60 -- .../gcp/web/config/GcpAppServiceConfig.java | 42 -- .../web/config/PartitionPropertyNames.java | 29 - .../WebAppMainContextConfiguration.java | 68 --- .../web/mappers/osm/OsmTypeMapperImpl.java | 80 --- .../web/middleware/GcpExceptionMapper.java | 49 -- .../provider/gcp/web/pubsub/OqmPubSub.java | 97 --- .../gcp/web/repository/ObmStorage.java | 439 -------------- .../web/repository/OsmQueryRepository.java | 112 ---- .../OsmRecordsMetadataRepository.java | 148 ----- .../web/repository/OsmSchemaRepository.java | 82 --- .../web/security/GSuiteSecurityConfig.java | 48 -- .../gcp/web/service/BatchServiceGcpImpl.java | 54 -- .../web/util/ServiceAccountJwtClientImpl.java | 42 -- .../resources/application-anthos.properties | 0 .../main/resources/application-gcp.properties | 0 .../resources/application-local.properties | 13 - .../src/main/resources/application.properties | 14 +- .../storage-gc/src/main/resources/logback.xml | 2 +- .../main/resources/type-mapper-config.json | 39 ++ ...hreadingLegalTagChangedProcessingTest.java | 251 -------- .../messaging/jobs/config/PullConfigStub.java | 71 --- .../messaging/jobs/stub/OqmPubSubStub.java | 58 -- .../middleware/GcpExceptionMapperTest.java | 42 -- .../gcp/web/repository/ObmStorageTest.java | 55 -- .../src/test/resources/test.properties | 2 +- 48 files changed, 143 insertions(+), 3366 deletions(-) delete mode 100644 provider/storage-gc/docs/anthos/README.md delete mode 100644 provider/storage-gc/docs/anthos/pics/client.png delete mode 100644 provider/storage-gc/docs/anthos/pics/rabbit.PNG delete mode 100644 provider/storage-gc/docs/anthos/pics/sa.png delete mode 100644 provider/storage-gc/maven/settings.xml rename provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/{messaging/config/MessagingConfigurationProperties.java => logging/formatter/GoogleJsonFormatter.java} (51%) delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/config/MessagingCustomContextConfiguration.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/LegalComplianceChangeServiceGcpImpl.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/LegalTagChangedProcessing.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/OqmSubscriberManager.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/scope/override/ScopeModifierPostProcessor.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/scope/override/ThreadDpsHeaders.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScope.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScopeAttributes.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScopeContextHolder.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/cache/CacheConfig.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/cache/LegalTagMultiTenantCache.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/GcpAppServiceConfig.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/PartitionPropertyNames.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/WebAppMainContextConfiguration.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/mappers/osm/OsmTypeMapperImpl.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/middleware/GcpExceptionMapper.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/pubsub/OqmPubSub.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/ObmStorage.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmQueryRepository.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmRecordsMetadataRepository.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmSchemaRepository.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/security/GSuiteSecurityConfig.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/service/BatchServiceGcpImpl.java delete mode 100644 provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/util/ServiceAccountJwtClientImpl.java delete mode 100644 provider/storage-gc/src/main/resources/application-anthos.properties delete mode 100644 provider/storage-gc/src/main/resources/application-gcp.properties delete mode 100644 provider/storage-gc/src/main/resources/application-local.properties create mode 100644 provider/storage-gc/src/main/resources/type-mapper-config.json delete mode 100644 provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/MultiThreadingLegalTagChangedProcessingTest.java delete mode 100644 provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/config/PullConfigStub.java delete mode 100644 provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/stub/OqmPubSubStub.java delete mode 100644 provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/web/middleware/GcpExceptionMapperTest.java delete mode 100644 provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/web/repository/ObmStorageTest.java diff --git a/devops/gc/pipeline/override-stages.yml b/devops/gc/pipeline/override-stages.yml index 8ddb79932..4cbb7fed6 100644 --- a/devops/gc/pipeline/override-stages.yml +++ b/devops/gc/pipeline/override-stages.yml @@ -12,3 +12,36 @@ gc-dev2-test: gc-test: variables: OPA_INTEGRATION_ENABLED: "true" + + +download_gc_plugins: + image: maven:3.8.3-openjdk-17-slim + stage: build + variables: + GC_OSM_PACKAGE_REGISTRY_URL: "https://community.opengroup.org/api/v4/projects/1476/packages/maven" + GC_OSM_VERSION: "0.27.2" + GC_OBM_PACKAGE_REGISTRY_URL: "https://community.opengroup.org/api/v4/projects/1475/packages/maven" + GC_OBM_VERSION: "0.27.2" + GC_OQM_PACKAGE_REGISRTY_URL: "https://community.opengroup.org/api/v4/projects/1477/packages/maven" + GC_OQM_VERSION: "0.27.2" + GC_APD_PACKAGE_REGISTRY_URL: "https://community.opengroup.org/api/v4/projects/1480/packages/maven" + GC_APD_VERSION: "0.27.2" + artifacts: + paths: + - ./tmp-gc/*.jar + when: always + expire_in: 1 days + script: + - mvn dependency:copy -DrepoUrl=$GC_OSM_PACKAGE_REGISTRY_URL -Dartifact="org.opengroup.osdu:gc-osm-datastore:$GC_OSM_VERSION:jar:plugin" -Dtransitive=false -DoutputDirectory="./tmp-gc" + - mvn dependency:copy -DrepoUrl=$GC_OBM_PACKAGE_REGISTRY_URL -Dartifact="org.opengroup.osdu:gc-obm-gs:$GC_OBM_VERSION:jar:plugin" -Dtransitive=false -DoutputDirectory="./tmp-gc" + - mvn dependency:copy -DrepoUrl=$GC_OQM_PACKAGE_REGISRTY_URL -Dartifact="org.opengroup.osdu:gc-oqm-pubsub:$GC_OQM_VERSION:jar:plugin" -Dtransitive=false -DoutputDirectory="./tmp-gc" + - mvn dependency:copy -DrepoUrl=$GC_APD_PACKAGE_REGISRTY_URL -Dartifact="org.opengroup.osdu:gc-apd-acc:$GC_APD_VERSION:jar:plugin" -Dtransitive=false -DoutputDirectory="./tmp-gc" + only: + variables: + - $GC == '1' + +gc-containerize-gitlab: + needs: ["gc-compile-and-unit-test", "download_gc_plugins"] + +gc-containerize-gcr: + needs: ["gc-compile-and-unit-test", "download_gc_plugins"] diff --git a/provider/storage-gc/README.md b/provider/storage-gc/README.md index d4e2f8951..330b61653 100644 --- a/provider/storage-gc/README.md +++ b/provider/storage-gc/README.md @@ -5,7 +5,6 @@ entire metadata life-cycle such as ingestion (persistence), modification, deleti ## Table of Contents <a name="TOC"></a> * [Getting started](#Getting-started) -* [Mappers](#Mappers) * [Settings and Configuration](#Settings-and-Configuration) * [Run service](#Run-service) * [Testing](#Testing) @@ -19,24 +18,6 @@ entire metadata life-cycle such as ingestion (persistence), modification, deleti These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system. -## Mappers - -This is a universal solution created using EPAM OSM, OBM and OQM mappers technology. It allows you to work with various -implementations of KV stores, Blob stores and message brokers. - -For more information about mappers: -- [OSM Readme](https://community.opengroup.org/osdu/platform/system/lib/cloud/gcp/osm/-/blob/main/README.md) -- [OBM Readme](https://community.opengroup.org/osdu/platform/system/lib/cloud/gcp/obm/-/blob/master/README.md) -- [OQM Readme](https://community.opengroup.org/osdu/platform/system/lib/cloud/gcp/oqm/-/blob/master/README.md) - -### Limitations of the current version - -In the current version, the mappers are equipped with several drivers to the stores and the message broker: - -- OSM (mapper for KV-data): Google Datastore; Postgres -- OBM (mapper to Blob stores): Google Cloud Storage (GCS); MinIO -- OQM (mapper to message brokers): Google PubSub; RabbitMQ - ## Settings and Configuration ### Requirements: @@ -48,8 +29,6 @@ In the current version, the mappers are equipped with several drivers to the sto 2. For Google Cloud only - GCloud SDK with java (latest version) -### Baremetal Service Configuration: -[Baremetal service configuration ](docs/baremetal/README.md) ### Google Cloud Service Configuration: [Google Cloud service configuration ](docs/gc/README.md) @@ -139,12 +118,9 @@ cd provider/storage-gc/ && mvn spring-boot:run This section describes how to run cloud OSDU E2E tests. -### Baremetal test configuration: -[Baremetal service configuration ](docs/baremetal/README.md) ### Google Cloud test configuration: [Google Cloud service configuration ](docs/gc/README.md) - ## Deployment Storage Service is compatible with App Engine Flexible Environment and Cloud Run. @@ -152,8 +128,8 @@ Storage Service is compatible with App Engine Flexible Environment and Cloud Run * To deploy into Cloud run, please, use this documentation: https://cloud.google.com/run/docs/quickstarts/build-and-deploy -* To deploy into App Engine, please, use this documentation: - https://cloud.google.com/appengine/docs/flexible/java/quickstart +* To deploy into GKE, please, use this documentation: + https://cloud.google.com/kubernetes-engine/docs/deploy-app-cluster ## Tutorial diff --git a/provider/storage-gc/cloudbuild/Dockerfile.cloudbuild b/provider/storage-gc/cloudbuild/Dockerfile.cloudbuild index a10c353c8..99b62633d 100644 --- a/provider/storage-gc/cloudbuild/Dockerfile.cloudbuild +++ b/provider/storage-gc/cloudbuild/Dockerfile.cloudbuild @@ -8,6 +8,13 @@ ENV PROVIDER_NAME $PROVIDER_NAME ARG PORT ENV PORT $PORT +ENV LOADER_PATH="gc/" + +COPY tmp-gc/gc-oqm-pubsub-*.jar gc/oqm-pubsub.jar +COPY tmp-gc/gc-obm-gs-*.jar gc/obm-gs.jar +COPY tmp-gc/gc-osm-datastore-*.jar gc/osm-datastore.jar +COPY tmp-gc/gc-apd-acc-*.jar gc/apd-acc.jar + # Copy the jar to the production image from the builder stage. COPY provider/storage-${PROVIDER_NAME}/target/storage-${PROVIDER_NAME}-*-spring-boot.jar storage-${PROVIDER_NAME}.jar @@ -18,4 +25,10 @@ RUN groupadd -g 10001 -r nonroot \ USER 10001:10001 # Run the web service on container startup. -CMD java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${PORT} -Dlog4j.formatMsgNoLookups=true -jar /app/storage-${PROVIDER_NAME}.jar +CMD java --add-opens java.base/java.lang=ALL-UNNAMED \ + --add-opens java.base/java.lang.reflect=ALL-UNNAMED \ + -Djava.security.egd=file:/dev/./urandom \ + -Dserver.port=${PORT} \ + -Dlog4j.formatMsgNoLookups=true \ + -Dloader.main=org.opengroup.osdu.storage.provider.gcp.StorageApplicationGCP \ + -jar /app/storage-${PROVIDER_NAME}.jar \ No newline at end of file diff --git a/provider/storage-gc/docs/anthos/README.md b/provider/storage-gc/docs/anthos/README.md deleted file mode 100644 index 3afb80340..000000000 --- a/provider/storage-gc/docs/anthos/README.md +++ /dev/null @@ -1,565 +0,0 @@ -# Service Configuration for Baremetal - -## Table of Contents <a name="TOC"></a> -* [Environment variables](#Environment-variables) - * [Common properties for all environments](#Common-properties-for-all-environments) - * [For Mappers to activate drivers](#For-Mappers-to-activate-drivers) -* [Requirements for requests](#Requirements-for-requests) -* [Configuring mappers Datasources](#Configuring-mappers-DataSources) - * [For OSM Postgres](#For-OSM-Postgres) - * [Postgres schema configuration](#Postgres-schema-configuration) - * [For OBM MinIO](#For-OBM-MinIO) - * [Object store configuration](#ObjectStoreConfig) - * [For OQM RabbitMQ](#For-OQM-RabbitMQ) - * [Exchanges and queues configuration](#Exchanges-and-queues-configuration) -* [Interaction with message brokers](#Interaction-with-message-brokers) -* [Keycloak configuration](#Keycloak-configuration) -* [Running E2E Tests](#Running-E2E-Tests) -* [Running locally](#Running-locally) -* [License](#License) - -## Environment variables - -### Common properties for all environments - -Define the following environment variables. - -Must have: - -| name | value | description | sensitive? | source | -|-------------------------------------------|--------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------| -| `SPRING_PROFILES_ACTIVE` | ex `anthos` | Spring profile that activate default configuration for Google Cloud environment | false | - | -| `OPENID_PROVIDER_CLIENT_ID` | `*****` | Client id that represents this service and serves to request tokens, example `workload-identity-legal` | yes | - | -| `OPENID_PROVIDER_CLIENT_SECRET` | `*****` | This client secret that serves to request tokens | yes | - | -| `OPENID_PROVIDER_URL` | `https://keycloack.com/auth/realms/master` | URL of OpenID Connect provider, it will be used as `<OpenID URL> + /.well-known/openid-configuration` to auto configure endpoint for token request | no | - | -| `<POSTGRES_PASSWORD_ENV_VARIABLE_NAME>` | ex `POSTGRES_PASS_OSDU` | Postgres password env name, name of that variable not defined at the service level, the name will be received through partition service. Each tenant can have it's own ENV name value, and it must be present in ENV of Storage service | yes | - | -| `<MINIO_SECRETKEY_ENV_VARIABLE_NAME>` | ex `MINIO_SECRET_OSDU` | Minio secret env name, name of that variable not defined at the service level, the name will be received through partition service. Each tenant can have it's own ENV name value, and it must be present in ENV of Storage service | yes | - | -| `<AMQP_PASSWORD_ENV_VARIABLE_NAME>` | ex `AMQP_PASS_OSDU` | Amqp password env name, name of that variable not defined at the service level, the name will be received through partition service. Each tenant can have it's own ENV name value, and it must be present in ENV of Storage service | yes | - | -| `<AMQP_ADMIN_PASSWORD_ENV_VARIABLE_NAME>` | ex `AMQP_ADMIN_PASS_OSDU` | Amqp admin password env name, name of that variable not defined at the service level, the name will be received through partition service. Each tenant can have it's own ENV name value, and it must be present in ENV of Storage service | yes | - | -| `STORAGE_SERVICE_ACCOUNT_EMAIL` | `workload-storage@keycloak.com` | Storage service account email, used during OQM events processing | no | - | - -| name | value | description | sensitive? | source | -|--------------------------------------------|-----------------------------------------------|---------------------------------------------------------------------------------------|------------|-------------------------------------| -| `LOG_PREFIX` | `storage` | Logging prefix | no | - | -| `SERVER_SERVLET_CONTEXPATH` | `/api/storage/v2/` | Servlet context path | no | - | -| `AUTHORIZE_API` | ex `https://entitlements.com/entitlements/v1` | Entitlements API endpoint | no | output of infrastructure deployment | -| `LEGALTAG_API` | ex `https://legal.com/api/legal/v1` | Legal API endpoint | no | output of infrastructure deployment | -| `PUBSUB_SEARCH_TOPIC` | ex `records-changed` | RabbitMQ topic name | no | | -| `REDIS_STORAGE_HOST` | ex `127.0.0.1` | Redis host for storage | no | | -| `REDIS_STORAGE_PASSWORD` | ex `*****` | Redis storage host password | yes | | -| `REDIS_STORAGE_WITH_SSL` | ex `true` or `false` | Redis storage host ssl config | no | | -| `REDIS_STORAGE_EXPIRATION` | ex `30` | Redis storage cache expiration in seconds | no | | -| `POLICY_API` | ex `http://localhost:8080/api/policy/v1/` | Police service endpoint | no | output of infrastructure deployment | -| `POLICY_ID` | ex `search` | policeId from ex `http://localhost:8080/api/policy/v1/policies`. Look at `POLICY_API` | no | - | -| `PARTITION_API` | ex `http://localhost:8081/api/partition/v1` | Partition service endpoint | no | - | -| `PARTITION_PROPERTIES_STORAGE_BUCKET_NAME` | ex `storage.bucket.name` | Name of partition property for storage bucket name value | yes | - | -| `SYSTEM_PARTITION_ID` | ex `system` | System partition ID | - -These variables define service behavior, and are used to switch between `Reference` or `Google Cloud` environments, their overriding and usage in mixed mode was not tested. -Usage of spring profiles is preferred. - -| name | value | description | sensitive? | source | -|--------------------------|----------------------|---------------------------------------------------------------------------------------------------------------------------|------------|--------| -| `PARTITION_AUTH_ENABLED` | ex `true` or `false` | Disable or enable auth token provisioning for requests to Partition service | no | - | -| `OSMDRIVER` | `postgres` | Osm driver mode that defines which KV storage will be used | no | - | -| `OBMDRIVER` | `minio` | Obm driver mode that defines which object storage will be used | no | - | -| `OQMDRIVER` | `rabbitmq` | Oqm driver mode that defines which message broker will be used | no | - | -| `SERVICE_TOKEN_PROVIDER` | `GCP` or `OPENID` | Service account token provider, `GCP` means use Google service account `OPEIND` means use OpenId provider like `Keycloak` | no | - | - -### Properties set in Partition service: - -Note that properties can be set in Partition as `sensitive` in that case in property `value` should be present **not value itself**, but **ENV variable name**. -This variable should be present in environment of service that need that variable. - -Example: -``` - "elasticsearch.port": { - "sensitive": false, <- value not sensitive - "value": "9243" <- will be used as is. - }, - "elasticsearch.password": { - "sensitive": true, <- value is sensitive - "value": "ELASTIC_SEARCH_PASSWORD_OSDU" <- service consumer should have env variable ELASTIC_SEARCH_PASSWORD_OSDU with elastic search password - } -``` - -### For Mappers to activate drivers - -| name | value | description | -|-----------|-----------|---------------------------------------------------------| -| OSMDRIVER | datastore | to activate **OSM** driver for **Google Datastore** | -| OSMDRIVER | postgres | to activate **OSM** driver for **PostgreSQL** | -| OBMDRIVER | gcs | to activate **OBM** driver for **Google Cloud Storage** | -| OBMDRIVER | minio | to activate **OBM** driver for **MinIO** | -| OQMDRIVER | pubsub | to activate **OQM** driver for **Google PubSub** | -| OQMDRIVER | rabbitmq | to activate **OQM** driver for **Rabbit MQ** | - -## Requirements for requests - -Record identifiers cannot contain a space character. At the same time, they may contain a % character, which, when -combined with subsequent numeric characters, may cause the application to misinterpret that combination. For example, -the "%20" combination will be interpreted as a space " " character. To correctly transfer such an identifier, you should -additionally perform the url-encode operation on it. This functionality can be built into the front-end application, or -you can use an online url-encoder tool ( eg.: https://www.urlencoder.org/). Thus, having ID "osdu: -work-product-component--WellboreMarkerSet:3D%20Kirchhoff%20DepthMigration" (with %20 combination) -you should url-encode it and request -"osdu%3Awork-product-component--WellboreMarkerSet%3A3D%2520Kirchhoff%2520DepthMigration" instead. - -## Configuring mappers DataSources - -When using non-Google-Cloud-native technologies, property sets must be defined on the Partition service as part of -PartitionInfo for each Tenant. - -They are specific to each storage technology: - -### For OSM Postgres - -**database structure** -OSM works with data logically organized as "partition"->"namespace"->"kind"->"record"->"columns". The above sequence -describes how it is named in Google Datastore, where "partition" maps to "Google Cloud project". - -For example, this is how **Datastore** OSM driver contains records for "RecordsChanged" data register: - -| hierarchy level | value | -|---------------------|----------------------------------| -| partition (opendes) | osdu-cicd-epam | -| namespace | opendes | -| kind | StorageRecord | -| record | `<multiple kind records>` | -| columns | acl; bucket; kind; legal; etc... | - -And this is how **Postgres** OSM driver does. Notice, the above hierarchy is kept, but Postgres uses alternative entities -for it. - -| Datastore hierarchy level | | Postgres alternative used | -|------------------------------------|-----|----------------------------| -| partition (Google Cloud project) | == | Postgres server URL | -| namespace | == | Schema | -| kind | == | Table | -| record | == | '<multiple table records>' | -| columns | == | id, data (jsonb) | - -As we can see in the above table, Postgres uses different approach in storing business data in records. Not like -Datastore, which segments data into multiple physical columns, Postgres organises them into the single JSONB "data" -column. It allows provisioning new data registers easily not taking care about specifics of certain registers structure. -In the current OSM version (as on December'21) the Postgres OSM driver is not able to create new tables in runtime. - -So this is a responsibility of DevOps / CI/CD to provision all required SQL tables (for all required data kinds) when on new -environment or tenant provisioning when using Postgres. Detailed instructions (with examples) for creating new tables is -in the **OSM module Postgres driver README.md** `org/opengroup/osdu/core/gcp/osm/translate/postgresql/README.md` - -As a quick shortcut, this example snippet can be used by DevOps DBA: -```postgres-psql ---CREATE SCHEMA "exampleschema"; -CREATE TABLE exampleschema."ExampleKind"( - id text COLLATE pg_catalog."default" NOT NULL, - pk bigint NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - data jsonb NOT NULL, - CONSTRAINT ExampleKind_id UNIQUE (id) -); -CREATE INDEX ExampleKind_datagin ON exampleschema."ExampleKind" USING GIN (data); -``` - -**prefix:** `osm.postgres` -It can be overridden by: - -- through the Spring Boot property `osm.postgres.partition-properties-prefix` -- environment variable `OSM_POSTGRES_PARTITION_PROPERTIES_PREFIX` - -**PropertySet:** - -| Property | Description | -|----------------------------------|-------------| -| osm.postgres.datasource.url | server URL | -| osm.postgres.datasource.username | username | -| osm.postgres.datasource.password | password | - -<details><summary>Example of a definition for a single tenant</summary> - -``` - -curl -L -X PATCH 'https://api/partition/v1/partitions/opendes' -H 'data-partition-id: opendes' -H 'Authorization: Bearer ...' -H 'Content-Type: application/json' --data-raw '{ - "properties": { - "osm.postgres.datasource.url": { - "sensitive": false, - "value": "jdbc:postgresql://127.0.0.1:5432/postgres" - }, - "osm.postgres.datasource.username": { - "sensitive": false, - "value": "postgres" - }, - "osm.postgres.datasource.password": { - "sensitive": true, - "value": "<POSTGRES_PASSWORD_ENV_VARIABLE_NAME>" <- (Not actual value, just name of env variable) - } - } -}' - -``` - -</details> - -#### Postgres schema configuration - -``` ---CREATE SCHEMA "opendes"; ---DROP TABLE opendes."StorageRecord"; -CREATE TABLE opendes."StorageRecord"( - id text COLLATE pg_catalog."default" NOT NULL, - pk bigint NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - data jsonb NOT NULL, - CONSTRAINT StorageRecord_id UNIQUE (id) -); -CREATE INDEX StorageRecord_datagin ON opendes."StorageRecord" USING GIN (data); ------------------ ---DROP TABLE opendes."StorageSchema"; -CREATE TABLE opendes."StorageSchema"( - id text COLLATE pg_catalog."default" NOT NULL, - pk bigint NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - data jsonb NOT NULL, - CONSTRAINT StorageSchema_id UNIQUE (id) -); -CREATE INDEX StorageSchema_datagin ON opendes."StorageSchema" USING GIN (data); - - -``` - -Example of filling tables - -``` - -INSERT INTO <partitionId>."StorageRecord"( -id, data) -VALUES ('726612843', '{ - "id": 726612843, - ... -}'); - -``` - -### For OBM MinIO - -**prefix:** `obm.minio` -It can be overridden by: - -- through the Spring Boot property `osm.postgres.partition-properties-prefix` -- environment variable `OBM_MINIO_PARTITION_PROPERTIES_PREFIX` - -**PropertySet:** - -| Property | Description | -|---------------------|------------------------| -| obm.minio.endpoint | server URL | -| obm.minio.accessKey | credentials access key | -| obm.minio.secretKey | credentials secret key | - -<details><summary>Example of a definition for a single tenant</summary> - -``` - -curl -L -X PATCH 'https:///api/partition/v1/partitions/opendes' -H 'data-partition-id: opendes' -H 'Authorization: Bearer ...' -H 'Content-Type: application/json' --data-raw '{ - "properties": { - "obm.minio.endpoint": { - "sensitive": false, - "value": "http://localhost:9000" - }, - "obm.minio.accessKey": { - "sensitive": false, - "value": "minioadmin" - }, - "obm.minio.secretKey": { - "sensitive": true, - "value": "<MINIO_SECRETKEY_ENV_VARIABLE_NAME>" <- (Not actual value, just name of env variable) - } - } -}' - -``` - -</details> - -### Object store configuration <a name="ObjectStoreConfig"></a> - -#### Used Technology - -MinIO (or any other supported by OBM) - -#### Per-tenant buckets configuration - -These buckets must be defined in tenants’ dedicated object store servers. -OBM connection properties of these servers (url, etc.) are defined as specific properties in tenants’ PartitionInfo registration objects at the Partition service as described in accordant sections of this document. - - -<table> - <tr> - <td>Bucket Naming template - </td> - <td>Permissions required - </td> - </tr> - <tr> - <td><PartitionInfo.projectId-PartitionInfo.name><strong>-records</strong> - </td> - <td>ListObjects, CRUDObject - </td> - </tr> -</table> - -or - -We can use Partition Service to get a bucket name: - -``` -curl -L -X PATCH 'https:///api/partition/v1/partitions/opendes' -H 'data-partition-id: opendes' -H 'Authorization: Bearer ...' -H 'Content-Type: application/json' --data-raw '{ - "properties": { - "partition.properties.storage.bucket.name": { - "sensitive": true, - "value": "PARTITION_PROPERTIES_STORAGE_BUCKET_NAME" - } - } -}' - -``` - -### For OQM RabbitMQ - -**prefix:** `oqm.rabbitmq` -It can be overridden by: - -- through the Spring Boot property `oqm.rabbitmq.partition-properties-prefix` -- environment variable `OQM_RABBITMQ_PARTITION_PROPERTIES_PREFIX`` - -**PropertySet** (for two types of connection: messaging and admin operations): - -| Property | Description | -|-----------------------------|--------------------------| -| oqm.rabbitmq.amqp.host | messaging hostname or IP | -| oqm.rabbitmq.amqp.port | - port | -| oqm.rabbitmq.amqp.path | - path | -| oqm.rabbitmq.amqp.username | - username | -| oqm.rabbitmq.amqp.password | - password | -| oqm.rabbitmq.admin.schema | admin host schema | -| oqm.rabbitmq.admin.host | - host name | -| oqm.rabbitmq.admin.port | - port | -| oqm.rabbitmq.admin.path | - path | -| oqm.rabbitmq.admin.username | - username | -| oqm.rabbitmq.admin.password | - password | - -<details><summary>Example of a single tenant definition</summary> - -``` - -curl -L -X PATCH 'https://api/partition/v1/partitions/opendes' -H 'data-partition-id: opendes' -H 'Authorization: Bearer ...' -H 'Content-Type: application/json' --data-raw '{ - "properties": { - "oqm.rabbitmq.amqp.host": { - "sensitive": false, - "value": "localhost" - }, - "oqm.rabbitmq.amqp.port": { - "sensitive": false, - "value": "5672" - }, - "oqm.rabbitmq.amqp.path": { - "sensitive": false, - "value": "" - }, - "oqm.rabbitmq.amqp.username": { - "sensitive": false, - "value": "guest" - }, - "oqm.rabbitmq.amqp.password": { - "sensitive": true, - "value": "<AMQP_PASSWORD_ENV_VARIABLE_NAME>" <- (Not actual value, just name of env variable) - }, - "oqm.rabbitmq.admin.schema": { - "sensitive": false, - "value": "http" - }, - "oqm.rabbitmq.admin.host": { - "sensitive": false, - "value": "localhost" - }, - "oqm.rabbitmq.admin.port": { - "sensitive": false, - "value": "9002" - }, - "oqm.rabbitmq.admin.path": { - "sensitive": false, - "value": "/api" - }, - "oqm.rabbitmq.admin.username": { - "sensitive": false, - "value": "guest" - }, - "oqm.rabbitmq.admin.password": { - "sensitive": true, - "value": "<AMQP_ADMIN_PASSWORD_ENV_VARIABLE_NAME>" <- (Not actual value, just name of env variable) - } - } -}' - -``` - -</details> - -## Exchanges and queues configuration - -At RabbitMq should be created set of exchanges and queues. - -| topic name | subscription name | description | sensitive? | env var to override | -|------------------------------------------|---------------------------------|------------------------------------------------------------|------------|-------------------------------------------------------------------------| -| `records-changed` | - | Search topic for pushing | yes | `PUBSUB_SEARCH_TOPIC` | -| `legaltags-changed` | `storage-oqm-legaltags-changed` | Legaltags topic for consuming | yes | `LEGAL_TAGS_CHANGED_TOPIC_NAME`, `LEGAL_TAGS_CHANGED_SUBSCRIPTION_NAME` | -| `storage-oqm-legaltags-changed-exchange` | - | Service topic for delaying failed legal tag changed events | - | - | - - - -## Interaction with message brokers - -### Specifics of work through PULL subscription - -To receive messages from brokers, this solution uses the PULL-subscriber mechanism to get 'record_changed' messages. -This is its cardinal difference from other implementations that use PUSH-subscribers (webhooks). This opens a wide -choice when choosing brokers. - -When using PULL-subscribers, there is a need to restore Storage service subscribers at the start of Storage service. -This magic happens in the `OqmSubscriberManager.java` class from `OQM` in the @PostConstruct method. - -## Keycloak configuration - -[Keycloak service accounts setup](https://www.keycloak.org/docs/latest/server_admin/#_service_accounts) - -Configure Clients. One Client per OSDU service. Set them “confidentialâ€. - - - -Each Client has embedded Service Account (SA) option. Enable SAs for Clients, make “Authorization enabledâ€: - - - -Add `partition-and-entitlements` scope to `Default Client Scopes` and generate Keys. - -Give `client-id` and `client-secret` to services, which should be authorized within the platform. - -## Running E2E Tests - -You will need to have the following environment variables defined. - -| name | value | description | sensitive? | source | -|------------------------------------------------|------------------------------------------------|------------------------------------------------------------------|---------------------------------------------------|--------| -| `DEPLOY_ENV` | `empty` | Required but not used, should be set up with string "empty" | no | - | -| `GROUP_ID` | ex`opendes-gc.projects.com` | OSDU R2 to run tests under | no | - | -| `LEGAL_URL` | ex`http://localhsot:8080/api/legal/v1/` | Legal API endpoint | no | - | -| `STORAGE_URL` | ex`http://localhost:8080/api/storage/v2/` | Endpoint of storage service | no | - | -| `TENANT_NAME` | ex `opendes` | OSDU tenant used for testing | no | -- | -| `TEST_OPENID_PROVIDER_CLIENT_ID` | `********` | Client Id for `$INTEGRATION_TESTER` | yes | -- | -| `TEST_OPENID_PROVIDER_CLIENT_SECRET` | `********` | | Client secret for `$INTEGRATION_TESTER` | -- | -| `TEST_NO_ACCESS_OPENID_PROVIDER_CLIENT_ID` | `********` | Client Id for `$NO_ACCESS_INTEGRATION_TESTER` | yes | -- | -| `TEST_NO_ACCESS_OPENID_PROVIDER_CLIENT_SECRET` | `********` | | Client secret for `$NO_ACCESS_INTEGRATION_TESTER` | -- | -| `TEST_OPENID_PROVIDER_URL` | `https://keycloak.com/auth/realms/osdu` | OpenID provider url | yes | -- | -| `OPA_INTEGRATION_ENABLED` | `true` OR `false` | Should be update if integration with OPA\Policy enabled\disabled | no | -- | -| `ENTITLEMENTS_URL` | ex`http://localhost:8080/api/entitlements/v2/` | Endpoint of entitlements service | no | - | -| `DATA_ROOT_OPENID_PROVIDER_CLIENT_ID` | `********` | Client Id for data root tester | yes | - | -| `DATA_ROOT_OPENID_PROVIDER_CLIENT_SECRET` | `********` | Client secret for data root tester | yes | - | - -**Entitlements configuration for integration accounts** - -| INTEGRATION_TESTER | NO_DATA_ACCESS_TESTER | DATA_ROOT_TESTER | -|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|-----------------------------------------------------------------------------------------| -| users<br/>service.entitlements.user<br/>service.storage.admin<br/>service.storage.creator<br/>service.storage.viewer<br/>service.legal.admin<br/>service.legal.editor<br/>data.test1<br/>data.integration.test | users<br/>service.entitlements.user<br/>service.storage.admin | users<br/>users.data.root<br/>service.entitlements.user<br/>service.storage.viewer<br/> | - -Execute following command to build code and run all the integration tests: - - ```bash - # Note: this assumes that the environment variables for integration tests as outlined - # above are already exported in your environment. - # build + install integration test core - $ (cd testing/storage-test-core/ && mvn clean install) - ``` - - ```bash - # build + run Google Cloud integration tests. - $ (cd testing/storage-test-baremetal/ && mvn clean test) - ``` - - -## Running locally -To run storage service locally connected with baremetal environment: -#### Specify mappers drivers property or run `SPRING_PROFILES_ACTIVE=anthos` -```properties -obmDriver=minio -osmDriver=postgres -oqmDriver=rabbitmq -``` -#### Specify osdu services urls: -```properties -HOST=https://osdu.ref.gcp.gnrg-osdu.projects.epam.com -AUTHORIZE_API=${HOST}/api/entitlements/v2 -CRS_API=${HOST}/api/crs/v2 -LEGALTAG_API=${HOST}/api/legal/v1 -PARTITION_API=${HOST}/api/partition/v1/ -``` -#### Auth variables: -```properties -opa.enabled=false; -partition-auth-enabled=false -service.token.provider=OPENID -OPENID_PROVIDER_CLIENT_ID=${CLIENT_ID}; -OPENID_PROVIDER_CLIENT_SECRET=${CLIENT_SECRET}; -OPENID_PROVIDER_URL=${OPENID_PROVIDER_URL}; -``` -#### Redis variables: -```properties -REDIS_STORAGE_HOST=127.0.0.1 -REDIS_GROUP_HOST=127.0.0.1 -``` -#### Partition service should contain non-production sensitive properties to override them with localhost and use through a custom prefixes. -##### OSM: -```properties -POSTGRES_DATASOURCE_URL_OSDU=jdbc:postgresql://localhost:5432/storage; -POSTGRES_DB_USERNAME_OSDU=${POSTGRES_USERNAME}; -POSTGRES_DB_PASSWORD_OSDU=${POSTGRES_PASSWORD}; -``` -##### OBM: -```properties -OBM_MINIO_PARTITION_PROPERTIES_PREFIX=obm.minio.localDebug; -MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}; -MINIO_SECRET_KEY=${MINIO_SECRET_KEY}; -``` -##### OQM: -```properties -OQM_RABBITMQ_PARTITION_PROPERTIES_PREFIX=oqm.rabbitmq.localDebug; -RABBIT_MQ_HOST=localhost; -RABBITMQ_ADMIN_HOST=localhost; -RABBITMQ_ADMIN_USERNAME=${RABBITMQ_ADMIN_USERNAME}; -RABBITMQ_ADMIN_PASSWORD=${RABBITMQ_ADMIN_PASSWORD}; -``` -#### To connect postgres or minio or rabbitmq port-forwarding should be used: -```shell -gcloud auth list -gcloud config set account <account_name> -gcloud config set project <project_name> -kubectl port-forward <rabbit_pod_name> 15672:15672 -kubectl port-forward <rabbit_pod_name> 5672:5672 -kubectl port-forward <minio_pod_name> 9000:9000 -gcloud components install cloud_sql_proxy -cloud_sql_proxy -instances=<instance_connection_string> -credential_file=<baremetal_service_account_json_file> -``` - -## License - -Copyright © Google LLC - -Copyright © EPAM Systems - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -[http://www.apache.org/licenses/LICENSE-2.0](http://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. \ No newline at end of file diff --git a/provider/storage-gc/docs/anthos/pics/client.png b/provider/storage-gc/docs/anthos/pics/client.png deleted file mode 100644 index 8a2014e672b65ddf644558e2c9e8cb8823f549dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92098 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 diff --git a/provider/storage-gc/docs/anthos/pics/rabbit.PNG b/provider/storage-gc/docs/anthos/pics/rabbit.PNG deleted file mode 100644 index e1c67734b91a536659fdf0b940a93208d749e3c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9605 zcmb_?dpy(q`~SK--5r%gA{CKsSRu;sPDzF^i{w-oIftB$?(Pn^^PM(AEHYV6*$Bhb zEo2)j#f+gaD|5I_o5LKw@2T$Z=kxe|KA+$B`*?i+@R;}Buh;8+UDxY+K3~u4dN0A| zg4vF(`?rEXpdIGt&musepRgd%I>nzi0pApdgXe&cb)g6|6Hs}l{1@P2gZF8x(;!e~ z+P0;u8-eRB*UvkKf<QZ)#eeJCf{HysAm#n$XHO#|T_*>uljP0vT4$m+^0!rv753y$ zh5j+N<NR+viy7C@FTBfdolChbap&d7-!AQ{BACv<z4kKfm~`(sQdPdhCfS1@S~riJ zp}9|oCUv-Zp7Zkb^z`yPx7<!$iOcYI#@=6bvNBA3*3~HmSh0&xiCp0tuO7a=%jD<7 zM^rIz;N$i#$pdiZwXYI(;?u=<ZlAq}Fc;r3DL6wovNrf#K2lPA=a0`5ZiFR)h2Uf7 zfiQ08dI6_meXF_b)L!xE9?X3Vb-Fu2LpObopfMuX07Dhri7^#VJAsnN^F<FDY`jh_ z43bi};6u=#Tz3O2dRl#Pfn?H9*JJxd{AF`j6>EM-6dxUS;OPyo%0wGxq_VK|8k6iZ zF)TnuJ=*NH;#)RXvdI6nv5B}Z#}8W3F5hG@R^euJy(f6j^LW3zHJ5}REd+ke!o^Fu z%%0#1lPN1MqiCT|><-abR@?3i^pC*U{soW3B#fdc*l4P=NPu=dm2tFXaYs<S%!m)f zlwLZWah4lp`;0FrOGi;1Y@aovo_VbH2&3b@R!#G@c}}8CzhY;L{nOQ_g4^m}!1B1< zaU+RZ9dUpr%r-SGPeRjGC<3_=%%Peqdr6T+M^3dA`Za_b<Pxu8zd#T>TAtbuKT7A8 zRxsvXCFtE}odUbJL^jXp&%tO^4}-U)xE_i@zswi4D50kQ4*a`_GJeAs?>#pH#9P6- zcNSfwNwz5pwzw^_e=cIHtGJ9rXXUmkYL_CV+vZ+7+c{!LHPNW37cSA3r1;R43nsz} zyGPz(t)%eyi5t#N+{Ueqx-Q20)~Z-w!8dWri%ELN?-11vQ#@OgYaedNpt>)+htt9E zK)pmep5@~NNABp^pb`t5YsQq)s#?Kn*|hdy5zHvFb})<D8MBv+e$P<({4K%~2^!e+ zt9LY0z<aSK4spR}WXcMD*OtmEpK))BVk?dqZiZGbpTZL(U2%ui@?=DR1u-Mb^#(*R zZ<F`j>Vh$rYo}SFE3-Omprm{<X{KD@G<86nT0%uXFt*tp&12F%ImeaTF<I`dC6acQ z<hB7RQRXP=Ub6+haAk*=xnpu^u%CTrW9RV0YVGMJio_6F;C~PSc^}|3eetDmz&NKo z#!Q@%=r=npl<UF?9R=dV_Jrgk(|5FLZ8OgoC%lU6{{|8^kS$^x&)?W@p)7`3B4P^& zbn_Yp4qTjlg8T^tI<y}z30%BW1!x2G`#Hh}5a<_exOi}ZEo2=qCFMU%*%KBVeEMhE zU7(l8Fw}(MmffGzhU7r|QW2+Y8&3YTJQK4X)NBhmnkZxT*f=f-bmb(Rb9QF<=dW$k zJ3!mb2#-`<<$qnd6&DnD%Ho0XCXkdWc8@7x!=m3x<ANQ*I}IDHb_bFEg4*_F*4ub= z1Ox)6N4d#6BxHAZ>CLvFDA$w1(Mwj;3Ux;g!)zL%KK6y-PC0+@)#nx3C07-^^G_fM zuw?h*@I&dxxf$e)k&5)QlUA@$JhR#uk0@->%t!V;By70(2^e*v6j_c;XB-*-;8n?I zsT&$OBz2o~yl-ovXpp#GqSoPYLrUm`0XDs-ZZ&n*qAWc`<aqhYgFLOU%%rF~G<j0d zJk2Bgu>~G|;KJ!Z{nZ;zju~nbVeDH2VQ3fQrtwH(0g_DihS<dxNrD<wu`h;Aha5Hu z{Wb-hCpfb<nxB7HnV29&B#xps;)ysK79Io7CsXjB<_p4#h#srCT&}!>%xeWaqQcGa z%Az;^GGu_;IF&XyNRIOsmGk^o7t9Y=x6R(_8(FOQ?J=-ve-$A6`22^3ut6;Ux;h-M zMZ5UgIYMtr`j5W2aZxcwr8#EFQq(^bAd)y`98+Z7#r58QtRz#RBBb#PE~k*O>@z^& zEsl#i)7?BKoo{>NnDRiX+<k)VvyA$%TJ04^=MNJE(#5IuQwHiq96kP@K|v$Z&&F3C zu~g=qe-gm3F8Fr4U%En}Ns0P<GD0lUKN-dq)gi+tn|MnGql23=pY<YSug71mk*Hk_ z;Bp&fFmRdgPbl;p<y7+RpH{PvLhmfpx-ucDKDNbD=F4nwv2a^`jM{Rn99~mDvxs<< zUE{!+><vNJJT7Fs=aplQJOM%$l1y#<JQy!p=x!6NG#>rz&}58|DhvI5ajW6n(=gHE zLOqkYGW#I3Y(=(wnYA8xs-g`fATZ%LY!S;*5Z1;`NIxm!hHQWO`Lj%Xgk!uwrmYl& z)hbZw=A{>O8RQM@(bCC;k$aCm+eVVLuDE*NkdcV!ogs<dAL}8<zl)2TWJ<RVm<9Xu z*i>UJ)@;G&>fHD@LYFz??&uV3Opc19r}3Ud)UUuc0RRbDG_8r<t>G2&i1X$5r-wKr z(Jm!YFN`WOHt3^l_j^HMsXn`X^JL|It;D&N65NJ%+CbI;Si+a(8&H#N>eyQK*MgY! zNIlWz2Ud+I?Y;gyce43}a5m|LfY*Nlz%l@}s%|*yS)>y&U%TjQ^4McURuC^^y$F{# zBM;jEOZ_E&X%O`CItHGjas2{;?hS?FtVl+yDg?TxPz|dH#dB6-hg6;-0}-=ryNI>% zD#tE<oA5sceS4D9;lg+js2Q;Q-*HOFpXKF)C7G}$+oYEG2QS|&r;7j)vzU*(fRR!H zn{&Cw__S5)#uziQ;+*+ZCR;ZVV5wyr$Wgc#yYSEgb&pRPTel8)$RT-rNCA<h6Yrxq zd0(V5CjkQ8egdq5QFObicr_njy|)s;2vuzG|M&k}7Mum8uwyv{$L!xmwyo+hkBO;M zY!mVlp~0qYvsPH`*OUMy*oRLOFZ7J&QYLl&VE{XfAm-R(dok2QQ0!>XZl;z)5-qlR z_ZJN;OAQruz|5Cmk=IDiYoTxZIAeR<KB}G_Er+%TCk6&<Gth0iyiyo(`l+>Xg?c7R zb4)|`yS>B;+MVpQs`Gt4ns$Vw0&q;!Cxh5`C+(%);-#!(N(r9f^6@+BBBm)CX$%}r znl@Ug_TYGoi~e`hgd7Z&*5cfeeo=U&2JYpn0eu)Ilb~_jQSzdT{*c-6DXE@cmBS+m z^sVkuMphf&M!SOVd(koUj7eXQoCHjpgwgyjjnRVKRD(b$MpArM0J|W1hBb)tW25tA z%o+nP(@VR+cS3dCR7qqFOwX*pTuEeLHPQ?9Jl3hc40M@+M=BT~xGiy$Fi^F>gIvGm zAZ6JKJ^#tdMMar^DPy7M#1B_t*6mO)6+3K}h1=m$%(<FB5-qA9&cW`NpT>9TkMtrz zWn3j30rSvZ7NM&A!@=&$Qn@C*wdIaIOB)Yy4+sV~Vd2ZC%z1ShNq|4<_j<N_<2~(H zSp~Br{hdZ-4EIz(ajxyFkONI5TNarfGdBoA>GR4*XR!fVSl;nsWKlcZ%{5RW?a^>A z67pU<PNbirk;UqLHS>fT&Y79W>KwQSp!pYL43*M=*TmBbw3;tD=|XWrZ#6$0K`Ikk zt+_2bm3g=nnO-DD!RLDjmV;gUds-Q+_vc1BeULNLP~oyHta;sMj1M{bBQ>oG_hrL) zQk$gz410`hz4QGM)z{|zkKjXs&H(52<AcDlXbvWm`7$b93Uxt067T~pbEtTB7T17J zs4|<%VH*R$6Q9fu4$}hv9H}E-YRzIGIq1+tMokX@*lfUu{8_lKJvj$+L{hrWO-dY* z|DX{#w`WXq1$SXHAkf=nU|mF9;m<SHTg#3vg`NR{s>Fz+KQrIL-+M&UAjFz8_!H<R z1h5pP<-6j3_O96!f$anW*_Z+<0Bl4-oE={CMQk93+Og*6fi;lkYy;T&rXDaer2<K@ zxku_BpKqA%oi`D?E*^drkD#(GJ4)p>(7ZAwvG+yE2-)$F{4rA9W#=)5i!k#2i27C- z);>!=zHn!kd(`#VPo*`f;!Su+T!v!Fg%`b<UZk^S{7)%g>~`k#47k6NM?#coPrk+} z5bzP~xIAN5FH`OQa~T)obvSfy%1Y&gu^g0EGJTSQF4e`w@+Abq$)IWuapJx8s-sij znr(sB7I-_leS*fpc9k4X7#JIsPfL7MF_FcMn$eFe>`V&C{hVc8|G0>Ekn*PWMpX42 zO2MsoWPQnXdtv1uyEgdDK*K^Nyb{w!v}~OSn-tqyoO6yKMZPqql|c!cK#k2PLZ5im z(^?GT1KlT;hE&Wa!b)WkLo3iUShsuNw0=iyJ_YNc7Z8c1e_+e^4mwEmgRxUDyz0=o zRy=QBcd8xqzGFN4wLhoCVdx7#a&BrU5fw4T?xuOtU70(@fhT{#P^$)&eazo2(`zo2 zea7E;>fx&e%?h`zrn<tZZk1_$EBXpDqYaZNenWn#@Ocg*D}Wd8)bBE+k<{}r?^TtB zPlgo+-p*n*eO;LzTCFDo#1yASi{)j1^T>uk_xh>X0`-gSdtNm?PNyUFuEC35tq0^c z;h2G4zgeJ$7)YH!UinDBgB^iQ?;o&=TKpO+CW_vgRG>fvfx?)PMO`%#45tqPc%l#P za9TigoxEA<wCuqvHiS~NsD80$c421nYn(RrwRUujpW_HurQ=~mgC34x85$RhH0<2O zUs@of2GMt{xy)P6qEe06HTia?EUmQMnG+qzqV+5_zx1gf%6VMNHW;>B(j_LxF|)~k z;^X}Niz^0rO)GnY+2sQYr+ArdU|NxED9(xZ0xf%Ovlz!Vx+w@pk+9~3U)FnEygxJ| z4<%qA`$iT@i%$J+IQX?U)b&o^iBSXYUPXW%4zEqAd5Z7KZs}@I!l}c2RN4y&pB*0s zjG3pGduLKZEZYKa3XO6Ucu#w3+9n;%8}qn&k0#I9LUd);;vsSXPDN_batHs?KY&Tf z0LM)}OJF;Twf+Y{m%|eo-Pk6n`=9Q|z<;0#<`(y)lM&CCR{AH@y0|nlwR{n`9#$r& zvCq_HvbO&vTGCh#0{w<KbrlikX>XOdD<O?-u@%^kI57tQO?mO?IU&~e9_$SWbSw@i z8PX+H?)VR_njc;P9|VDf>jA`jhFen~RuoTqj9wni27z9l1Pq1bux4ed(8<n8&U-+h zeMiNFw{8|oLa(LhOabzO6tHn1|2_DS%`5XGX|J{bWdsP+4>-Hd&2hVxsyHgWDsaxu zd8+$06LDelQpXk&@zO#1%pOST8m(ky9{`RdEUKn^rmk`Dq!_|i8j5ToFd1K?oRSvQ zN`n<HO!xKLj0WVO{pQW#3G7(H(&&Tu;+mlN65xo&#Vs=WLiUIsHge)QP);anIk!XN z6|ULc3ADq9oZ&jblAew$)#2=o^un0!lFzIO2Chbk&G%r>XqE&6>$b$%%hs%h;E}uJ zs96}+9h`>BN@nr;#0hcCwHeNVm~TU+OVjf1Bq0dhH22F8V?A|TQ(SRiM<C%|#bg-q z_V`7}`+`~n?K|%@u>8oPotX=Zv?o=U6bPsQ<7NJMcLdpBuu)Xw&dSw~5NOJhnAKw1 zz0$A=OTDORr)dse&FxR2IsBQ3%Je;6(b?KDwhdc0p1hZq(_RS`g`~#RJruPWa6h}% zOvXA1VS3bJCn?_jEZSrS+-0A@A5SVpDCVZi-Y1dbzr;kWt_*cI#>@#k9LJoPw}G?k zW#kT3EWalreWk*{^4Z4c)kwWGb@HLhLHK%x3;AueJkvN27y6ofj;B*_Rliw1G0@ex z0q<3#@Qj&PY13%Isoxe>YU~7X5;Zf@Ggkoc%KN7{E<U#Cps1(vn=6Z%@a3Kwf;Hk; z8GjUNCnS~!pMjC!mraFHop5gHMDwYmR$d3t+_&B?Pdsu!fwpS1mkk@R8Krkkz+1YT zkVWrESTm<Af_Bu(60%Kq?CzS~0uAg~S<n-{bfm{=f3QzJExA)b>hke=Iq`W`p`rX; zr4`7{5%Xp{r|e!uqlZd95YSi^;*!Y)dqs&<7;)xuJ3CN}yJUwZ1i`|-(Q<Fl#)!QX zv2A`i1poefK`QSwBiAgV5LH=dg5{H>C)NJzhgKB!uO(D>338kv*;6z^%&PaVTt4{# zo!_bvERb!a;0QO`1W}Hr6~ZjD;5r1<@uO5rPncY14O%X00{TQ*jDX_jh&s1#d1MGj z2?MUVF-tH83v_&5H#J?&K)EwnriH#xRPEI3OC);t;EtM?y}p?G<Uv}@R<{xI)Wa~> zfd2W^tFu^B^M08dmfs;HSS{FDu<-vv3cj@$AeKjB46pet1K=_ibzD2&m9lg$7q>d9 zeoeHmPP$G7pn(e*>VdzoEpKm=$<Y<w!ouXq*<}2qdgn7bvx`PedcX*s?<2k*R<`t- zEBs?JbacNe1_-5`81(<9b#XKqHV(8p0>tG5<`~#>>46CdbVUv*^p#05h}KxsfP+d* zMJB)!tqFjLVA1oM9{&^Pz_&iEcr+RM!+xM#0OseYV)Z|Y;+ytm+lWc-xz!Kj3jm1T z3@AWO-K<c%tMcD$wC44naL%@{lQ{&|E2S`3$8e_uxPD&Bno?;^Le%Zd+;#%j(LJmg zKltjO*rias=1Qv_B<y$&A?w1G(>%v99ThS%?^#-+AA|pnP=6uA1`X%T@bBxLjJ0*~ zf^(wu>>n|ssYMgKFYg(CG=M(pXjW@3Fl)UaqKwyIEH&){jazZ>nG?xr{F7fyu3COH zmRhB%Az^j3$^vhYM`%V-R`{ywXft2Oe(NT7eS}+P8<%07gaU+l`@_cawIg@r#1z6O z4<_ky(lQ;ZfCM@qmfn=}nO+()p?;+SxP;5q3P<e*aIZ;>BJR!_)gC3S%zkw&`PeuM z?(K*_tEa4`h)^(||F~WNaFQOsw#)|p%}fPAZoFho1}e9})Nk=?^BcbWbZsx)-!Mkb z8|TtC^9JtK9Hspz^OLlxZpFbt1j$LF+mCUnco5GYxTDvDE4u+laV!joozZYke@zoX z!nlDzD?F<}(;OnJh_|fO&)5qx8R7+-&8We`eQBQdBvj5@l#bz`YhX^TX(ioH@R$AN zK)J2>Bgj=m);Wf~LIA1=;hu;(pN|m>mVFfo8StnWvV!4mR<-q$7xdY1QMLu1ZZjA? z->2^-=?mx?Z$%nx)Ki)Nab8ib0!yF#Mj<W_vfvg>qZFzp!$>gy0gl@5B437*n-|W# z{kHJ326myeaM|{}t;iBz>rB9^eP(-ix{k>Xje0}+C4qx#%Hdm-BH?%qcdv7$b@VzK zWQZELB#dZ6`%Y;tx8#Pz&mJ*vV>&_lDUUrQ*BX8=e4Mqg%-jDWGyglOp-K5$ls8U{ zQ{6g+$3xWDLIot}dI}N9^}j{IKb^tf4%0Pd03b>j)r#nJDL<SOg~quZ08VK+IOn$c zmIo|Du%}4AZj)FUjQofGA~k_rTYKpC_Ve3^R(?Kw)khNx%MFCqFNHt>QP3B6dfj}> z%HUryo43FJTCc=8pV&oNosI0Lmaobh0dinwc+*!i!iMlCUn0!B1`3ZXY?bm!Woy+% z^q&*A8QC{iRIx7uwU?(nwE|a$&t@ylSxybSSnEydJ~oCcKbH%@cR6IAk5I*4lKU~- z2EsfDSMIqh^L+^L(%>E<q54zHj?Za`EfbsYA<Owl_khUY_2N3Iezya}t+<(G*)btc zdEOdWG7=ggr+=6?;r3(A*e2bkRYp8PKVm9!b~Jt#8?rRGu6a8QD>FWS1vsmP#Hu6W zx_E46!#0oes@OYN_-N36KtUMo{+lBxryFY5Eq@P%RxL8m7_ph8RQ)xDbBFZk6-K~M zuft3}LXjiK($dlrCwHd8sOa$#mWUmDb@^XN6?`SU%OtC?B}9LtzaJ2y;)S>%pd+di zbe*8xQu#3J#z-fU8XAGFK^BdSP0qr7I#MrYSVj!xw5Q1Fe(1=FCrDXDseLaOG=Xjc zTm{T&3a$S&3-RK-#nTlzlLESPQK{2P$LaJ;UAOzBOitPZPgj3vTZ1za*FRA?e3ErD zG|rK@g$dO4nY0^YNjC_rPLlI{r!fc?_)C0clkWE*Nk*LOQokR-7(l7>U?^c%-d@3^ z-*S{-T;D}udT`mPa-uW0KKi?0@&!bOt2C;WX#c#+_*iHEFnRRE-s5iIk`$*F+f>IG z*9?c%O8!i&8+MjdGnbo0agE8sF!+%x0puU4q*RWy2daa9NW8joWpAr%50QeQw#s&P zj7?0qk#pEhs}W(-gXrb&?TW2p(Sf}1X)6Q;jxik42^cA37`AmOKfmf$FnK9^;yvA~ zTte&-27X1i#}V?Ih5L{oLfg)V|Md%(YzZH&3_75Xp<<$V{lyI%2QT&|mn$-L1{V#W zH^=Vzn&Co+JY*LpiW5ZPqFv$?u!a0Ou+JI7(MoGEK8Sg$`9!sau@YWe@pB)I9UMXL z%hbr~hhozK<_?SX0Hg=`#zk881rF(6Ah=&(iN{Y@#+vkOd6^{l_8?xeH{}(cD2#$9 z80K6X+^I|R5R=o9*%5h#DB+1bXAy#6TyZJpU~hCxZT|HyurHVTQEr9DdEG;<os<vn zZNBQ|F^%lN8V<gk{>);v5?qq2Jqu^&j23PG`vITuA(=CKKg^6~XHqBn-&J48g1|jI zUQwyp3;oRo=3RnPSpCT$*wJl%##2W1c~6O5m#1L!Ib(~2>Ht?2Qo2)7h(zo^tcM0; zX=nVTtAs7N!JIw@vOEQIK0;?E`v*E(S1|Ax$>K#FQLhO>o|=_VwYudoFYyPKMF_|o z7y~a&S-K@@vUv1vQ2gybp3k2@4zy7+Rl4Nsyu}Q7ll`NI(vqNUHkHM$4-hv*ZrZMC z6?Wl~;~uO7b!H(IMA^Z)1sAr0SgGw(2b*c~R7?|Ym`!zSY{fqYX8hx8mUEM7#w+{e zK`(^>>nCReth@>I+z<n=63uQFOw4ErnsE!E4$PCg+5t7N9@MJ<=Tv`9(u-NTWN0K( zjvu^*NH{PH2qqBd#XUsSf#r}4X)3Ae(k9HScNi*je6%9|V*IjSK}HidY1h~s9xj|8 z6iYOq96Cd2xEpsWrqnYXu_B_s--KH5$ZA(ZsHeD$G-nN~o-)U=*oad_>8JRA>enF_ zf~rfG7Gg>>R>PU?KYg=9DF}_juR<jlA4a^5RqG{I7Me-pn%*izKLaZ7LDl^Eh4v7H z4;DjxRdflGxvGI%U8-Ijo{<^n;ehJoo5cg4YbYJwVEmQ7JI6$&D9)1%Y*+6I1+L)R zD^^DzY<RF%TG<f`tN=gMtw~75)`M&G9mh;9UXU!9M70;@?_L_TLAUn34W03E9b(JH zY^u4`6Jmgtcv24Qu0vB7ww;#tJJ>jF+OD1`ctckPRAP7vBC6wI4JC!@^pSGw8jQC; z%{?&%qav!jno)=9)X;F@J>=R$fHEF`yDsPz*LUPhXG?b@1$>`O&ysYIf|Dp0dqxeQ z%m-d?1YrSg1`I|w+O<BTJjRv-C=uiM<vY<!EzEIm#y-%M7*#AYLE~mOqu`5FkaxXS zCIRj<u|Mr2rqI2Ic+GHKOQC%gb=i~Tn>VbiXYq$>jrw~8M4!>JyDBc~(OJf#BmON3 zeOS1t_hJ>D<;lzOsOQZ!$^a@VW5E%<Y`Vy;$+rQLQ@ow$zH$#kr(Kf9o%$9nPWI?U z%av${r$}%zk_(EZCK>7`0(YeUh&htrFCV0V9pEDNHpB&Mbo&(#!7L^OVg7FVFGz7i zF`xKY(*(Lr+>C%Rczn-VW>%yacS|rHG0u!VGd&K?@{*oqv9h%Guud4=27@Wudv)jP z)O@qb-cv`ug0ZGxh|sS!#{xB1ck)(`F3!Sv+7iVTm}XE1=l=WzO%gYWlYu^7y*K=x zOM2o@sI8Bk*!0l)LyH+G{8MsT9G+;O=*!g~b#@-$<*=NW8|*(A^wYxHAN2BgeUyFE zmyN%=BLB|f*Qt&}Tf_I?1=~8Zf)g#DJv<EUd1t{Jx_RNjWS?80p2Y*T<6Om4r`p?S zlI&II*lcFS;5P38_j`GhC^g~YPcJH*<L`&CV*-7$fh2K|Rt|7`dwd<pUji@rGP>K# zc0}AISPSrmUF}-i>WWOjVjT~<ISEuy`%VD$)Q+`X2A%8p0a4|fwtr*t|MV5B_^m8( zTEs8Sm<d?kI0C>Omz2#-!lmj~`JsQ{HUk}!-l`001!a-ybp1`BlCcaxTgQFWu$oF^ zP;F27tF1tdlx*%nz|>quqwXdv@n?ZIF#D2P5$)cpZ3h+>fCnU-dJw+umDMa4|GyC* zk_Pm3j!9#vhC6}PFWErmP69VPP7~O`D_Br+OSlE+K~Q)7*HsF7SazGNTf_@=!wJBU zD{4J95bJI^*2fNlHy!vPMcLYu<`GfZ_Eg=VE_Yd*PF1Ym4)LOAGvNbZYtkx3But2C zcy@W1+&W;eAatSRsWLk<nrxr8kXhS(gD;SO$@mWcwHyX~B|8u_PQ)6Gd`7iRAb zE0?v!-ypy(>aY;U5~Ou$uuH}Ss*`?&Su3}?h`Rq_WTF4B?)03!bm9b_fii4tRCts5 z^xclP8c(}DHy%4E(Hqxmc+H3cXw{pQzeBNz$B8D&Egc%S1MgedfsrmFf$U|AyyBoC z7Hu@D?_C!PTQCN0(4&l0=bhPK|1~Ud`V_Z(rticz*9+jN9&ibxBuKYL>RG4Bm<lxC z$fc!9NA8;Bjh&9RWn0y-xgv>%qPuG${0l*#-8Zux+(hqMfM41@RGODl3Zg`f&@Ff7 z5&ZSqtU8f**CM(p6E2!fLKPmtlKi_k6JbP#Qik#~KXyt)>r6XAuY*~`AZYrHKgx{L z;DupL7?I(r`FNsee|<SYUA$?>pCiY#ZspZnD^Z3(LtE>0HDTVF&&y|`i3l%RPX)#> z*MG=rXr+g%V6&A38^jPp0Xe$jSH&PLWGA9^fb#f?+AyW~%;M1;ld`70#)rg<0-12* zQC8=;zppcJ*?J36*CyVKZE%jln$fD*7<q9}A0wxN#RCc|k#S2iZG(zuT6h1Qa7z;; zM#DcP<ibdraWrkatl21cEdf*Th*&|l!=TBTaJhv#V4-AlKZ2B|l1flDUzRp-ZmMZX z{$V~~qQ?hEpfCg7)DWN9|EBQ>4Evw|t^ru(U;PxqoUpq2oR!?~=kl7x+Xyl@y>PbN I<jSr80*{qvcK`qY diff --git a/provider/storage-gc/docs/anthos/pics/sa.png b/provider/storage-gc/docs/anthos/pics/sa.png deleted file mode 100644 index b9c8124047b5834a2cf79baecbf751dc106feeff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52971 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 K>nbasJO2PpLB22m diff --git a/provider/storage-gc/docs/gc/README.md b/provider/storage-gc/docs/gc/README.md index ff7a0fcfa..df4b84901 100644 --- a/provider/storage-gc/docs/gc/README.md +++ b/provider/storage-gc/docs/gc/README.md @@ -4,12 +4,14 @@ * [Environment variables](#Environment-variables) * [Common properties for all environments](#Common-properties-for-all-environments) -* [For Mappers to activate drivers](#For-Mappers-to-activate-drivers) * [Datastore configuration](#Datastore-configuration) -* [Pubsub configuration](#Pubsub-configuration) +* [Pub/Sub configuration](#Pubsub-configuration) * [Google Cloud service configuration](#ObjectStoreConfig) -* [Google loud service account configuration](#Google-cloud-service-account-configuration) +* [Google_Cloud service account configuration](#Google-cloud-service-account-configuration) +* [Run args](#run-args) +* [Running E2E Tests](#running-e2e-tests) * [License](#License) +* ## Environment variables Define the following environment variables. @@ -50,7 +52,6 @@ Defined in default application property file but possible to override: | `PARTITION_API` | ex `http://localhost:8081/api/partition/v1` | Partition service endpoint | no | - | | `GOOGLE_APPLICATION_CREDENTIALS` | ex `/path/to/directory/service-key.json` | Service account credentials, you only need this if running locally | yes | <https://console.cloud.google.com/iam-admin/serviceaccounts> | | `PARTITION_PROPERTIES_STORAGE_BUCKET_NAME` | ex `storage.bucket.name` | Name of partition property for storage bucket name value | yes | - | -| `SYSTEM_PARTITION_ID` | ex `system` | System partition ID | These variables define service behavior, and are used to switch between `Reference` or `Google Cloud` environments, their overriding and usage in mixed mode was not tested. Usage of spring profiles is preferred. @@ -58,22 +59,8 @@ Usage of spring profiles is preferred. | name | value | description | sensitive? | source | |--------------------------|---------------------------|---------------------------------------------------------------------------------------------------------------------------|------------|--------| | `PARTITION_AUTH_ENABLED` | ex `true` or `false` | Disable or enable auth token provisioning for requests to Partition service | no | - | -| `OQMDRIVER` | `rabbitmq` or `pubsub` | Oqm driver mode that defines which message broker will be used | no | - | -| `OSMDRIVER` | `datastore` or `postgres` | Osm driver mode that defines which KV storage will be used | no | - | -| `OBMDRIVER` | `gcs` or `minio` | Obm driver mode that defines which object storage will be used | no | - | | `SERVICE_TOKEN_PROVIDER` | `GCP` or `OPENID` | Service account token provider, `GCP` means use Google service account `OPEIND` means use OpenId provider like `Keycloak` | no | - | -### For Mappers to activate drivers - -| name | value | description | -|-----------|-----------|---------------------------------------------------------| -| OSMDRIVER | datastore | to activate **OSM** driver for **Google Datastore** | -| OSMDRIVER | postgres | to activate **OSM** driver for **PostgreSQL** | -| OBMDRIVER | gcs | to activate **OBM** driver for **Google Cloud Storage** | -| OBMDRIVER | minio | to activate **OBM** driver for **MinIO** | -| OQMDRIVER | pubsub | to activate **OQM** driver for **Google PubSub** | -| OQMDRIVER | rabbitmq | to activate **OQM** driver for **Rabbit MQ** | - ## Datastore configuration There must be a namespace for each tenant, which is the same as the tenant name. @@ -100,9 +87,9 @@ indexes: ``` -## PubSub configuration +## Pub/Sub configuration -At PubSub should be created set of topics and subscriptions. +At Pub/Sub should be created set of topics and subscriptions. | topic name | subscription name | description | sensitive? | env var to override | |------------------------------------|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|-------------------------------------------------------------------------| @@ -154,6 +141,21 @@ TBD |----------------| | - | +### Run args + +In order to run Legal with Java 17 additional run args must be provided: + +```bash +--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED +``` + +```bash +CMD java --add-opens java.base/java.lang=ALL-UNNAMED \ + --add-opens java.base/java.lang.reflect=ALL-UNNAMED \ + -Dloader.main=org.opengroup.osdu.storage.provider.gcp.StorageApplicationGCP \ + -jar /app/secret-${PROVIDER_NAME}.jar +``` + ### Running E2E Tests You will need to have the following environment variables defined. diff --git a/provider/storage-gc/maven/settings.xml b/provider/storage-gc/maven/settings.xml deleted file mode 100644 index b7a15a010..000000000 --- a/provider/storage-gc/maven/settings.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> - <servers> - <server> - <id>os-core</id> - <username>slb-des-ext-collaboration</username> - <!-- Treat this auth token like a password. Do not share it with anyone, including Microsoft support. --> - <!-- The generated token expires on or before 11/14/2019 --> - <password>${VSTS_FEED_TOKEN}</password> - </server> - </servers> -</settings> diff --git a/provider/storage-gc/pom.xml b/provider/storage-gc/pom.xml index cf1c0e8c3..2247071a0 100644 --- a/provider/storage-gc/pom.xml +++ b/provider/storage-gc/pom.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - ~ Copyright 2020-2023 Google LLC - ~ Copyright 2020-2023 EPAM Systems, Inc + ~ Copyright 2020-2025 Google LLC + ~ Copyright 2020-2025 EPAM Systems, Inc ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. @@ -16,8 +16,8 @@ ~ limitations under the License. --> <project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> @@ -28,7 +28,7 @@ </parent> <artifactId>storage-gc</artifactId> - <description>Google cloud related implementation staff.</description> + <description>Storage Service</description> <packaging>jar</packaging> <properties> @@ -58,79 +58,15 @@ <dependencies> <dependency> <groupId>org.opengroup.osdu</groupId> - <artifactId>core-lib-gc</artifactId> - <version>0.27.0-rc8</version> - </dependency> - <!-- Mappers --> - <dependency> - <groupId>org.opengroup.osdu</groupId> - <artifactId>osm</artifactId> - <version>0.27.0-rc3</version> - </dependency> - <dependency> - <groupId>org.opengroup.osdu</groupId> - <artifactId>oqm</artifactId> - <version>0.26.0</version> - </dependency> - <dependency> - <groupId>org.opengroup.osdu</groupId> - <artifactId>obm</artifactId> - <version>0.27.2</version> - </dependency> - <dependency> - <groupId>org.opengroup.osdu</groupId> - <artifactId>storage-core</artifactId> + <artifactId>storage-core-plus</artifactId> <version>0.28.0-SNAPSHOT</version> - <exclusions> - <exclusion> - <groupId>org.mockito</groupId> - <artifactId>mockito-all</artifactId> - </exclusion> - <exclusion> - <groupId>org.powermock</groupId> - <artifactId>powermock-api-mockito</artifactId> - </exclusion> - </exclusions> </dependency> + <dependency> <groupId>ch.qos.logback.contrib</groupId> - <artifactId>logback-json-classic</artifactId> + <artifactId>logback-jackson</artifactId> <version>0.1.5</version> </dependency> - <dependency> - <groupId>org.springframework.security</groupId> - <artifactId>spring-security-config</artifactId> - </dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-webmvc</artifactId> - <version>${spring-webmvc.version}</version> - </dependency> - - <dependency> - <groupId>jakarta.annotation</groupId> - <artifactId>jakarta.annotation-api</artifactId> - <version>2.1.1</version> - </dependency> - - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-test</artifactId> - <scope>test</scope> - </dependency> - <!-- Testing packages --> - <dependency> - <groupId>org.junit.vintage</groupId> - <artifactId>junit-vintage-engine</artifactId> - <version>5.10.2</version> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-actuator</artifactId> - </dependency> - </dependencies> <build> @@ -139,7 +75,7 @@ <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> - <version>3.0.0</version> + <version>3.2.2</version> <configuration> <profiles> <profile> @@ -151,12 +87,6 @@ <spring.profiles.active>local</spring.profiles.active> </properties> </profile> - <profile> - <id>dev</id> - <properties> - <spring.profiles.active>dev</spring.profiles.active> - </properties> - </profile> </profiles> </configuration> <executions> @@ -167,20 +97,13 @@ <configuration> <classifier>spring-boot</classifier> <mainClass> - org.opengroup.osdu.storage.provider.gcp.StorageApplicationGCP + org.springframework.boot.loader.launch.PropertiesLauncher </mainClass> </configuration> </execution> </executions> </plugin> - <plugin> - <artifactId>maven-war-plugin</artifactId> - <configuration> - <failOnMissingWebXml>false</failOnMissingWebXml> - </configuration> - </plugin> - <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> @@ -203,4 +126,4 @@ </plugins> </build> -</project> +</project> \ No newline at end of file diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/StorageApplicationGCP.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/StorageApplicationGCP.java index a3b482578..3d556cbaa 100644 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/StorageApplicationGCP.java +++ b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/StorageApplicationGCP.java @@ -1,6 +1,6 @@ /* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc + * Copyright 2020-2025 Google LLC + * Copyright 2020-2025 EPAM Systems, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/config/MessagingConfigurationProperties.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/logging/formatter/GoogleJsonFormatter.java similarity index 51% rename from provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/config/MessagingConfigurationProperties.java rename to provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/logging/formatter/GoogleJsonFormatter.java index 1c61908b4..d88fe08a9 100644 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/config/MessagingConfigurationProperties.java +++ b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/logging/formatter/GoogleJsonFormatter.java @@ -1,6 +1,6 @@ /* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc + * Copyright 2020-2025 Google LLC + * Copyright 2020-2025 EPAM Systems, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,19 +15,16 @@ * limitations under the License. */ -package org.opengroup.osdu.storage.provider.gcp.messaging.config; +package org.opengroup.osdu.storage.provider.gcp.logging.formatter; -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ConfigurationProperties -@Data -public class MessagingConfigurationProperties { - - private String legalTagsChangedTopicName; - private String legalTagsChangedSubscriptionName; - private String storageServiceAccountEmail; +import ch.qos.logback.contrib.jackson.JacksonJsonFormatter; +import java.io.IOException; +import java.util.Map; +public class GoogleJsonFormatter extends JacksonJsonFormatter { + @Override + public String toJsonString(Map map) throws IOException { + map.put("severity", map.remove("level")); + return super.toJsonString(map); + } } diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/config/MessagingCustomContextConfiguration.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/config/MessagingCustomContextConfiguration.java deleted file mode 100644 index 97bd8b11e..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/config/MessagingCustomContextConfiguration.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.config; - -import java.util.Arrays; -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.opengroup.osdu.storage.StorageApplication; -import org.opengroup.osdu.storage.provider.gcp.web.config.WebAppMainContextConfiguration; -import org.opengroup.osdu.storage.swagger.SwaggerConfiguration; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.FilterType; -import org.springframework.context.annotation.PropertySource; - -/** - * This context configuration serves for message receiving configuration not bounded to request scope. - * Also, configured context does not serve incoming requests. - */ -@Slf4j -@Configuration -@EnableConfigurationProperties -@PropertySource("classpath:application.properties") -@RequiredArgsConstructor -@ComponentScan(value = { - "org.opengroup.osdu" -}, - excludeFilters = { - @ComponentScan.Filter( - type = FilterType.ASSIGNABLE_TYPE, - value = { - StorageApplication.class, - WebAppMainContextConfiguration.class, - SwaggerConfiguration.class - } - ) - } -) -public class MessagingCustomContextConfiguration { - - private final ApplicationContext applicationContext; - - @PostConstruct - public void setUp() { - log.debug("Messaging context initialized with id: {}.", applicationContext.getId()); - log.debug("Messaging context status: {}.", applicationContext); - String[] allBeansNames = applicationContext.getBeanDefinitionNames(); - log.debug("Messaging context beans definitions: {}.", Arrays.toString(allBeansNames)); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/LegalComplianceChangeServiceGcpImpl.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/LegalComplianceChangeServiceGcpImpl.java deleted file mode 100644 index 9b6bfaa6b..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/LegalComplianceChangeServiceGcpImpl.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.jobs; - -import static java.util.Collections.singletonList; - -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import lombok.RequiredArgsConstructor; -import org.opengroup.osdu.core.common.cache.ICache; -import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; -import org.opengroup.osdu.core.common.model.http.DpsHeaders; -import org.opengroup.osdu.core.common.model.indexer.OperationType; -import org.opengroup.osdu.core.common.model.legal.LegalCompliance; -import org.opengroup.osdu.core.common.model.legal.jobs.ComplianceChangeInfo; -import org.opengroup.osdu.core.common.model.legal.jobs.ComplianceUpdateStoppedException; -import org.opengroup.osdu.core.common.model.legal.jobs.ILegalComplianceChangeService; -import org.opengroup.osdu.core.common.model.legal.jobs.LegalTagChanged; -import org.opengroup.osdu.core.common.model.legal.jobs.LegalTagChangedCollection; -import org.opengroup.osdu.core.common.model.storage.PubSubInfo; -import org.opengroup.osdu.core.common.model.storage.RecordMetadata; -import org.opengroup.osdu.core.common.model.storage.RecordState; -import org.opengroup.osdu.storage.logging.StorageAuditLogger; -import org.opengroup.osdu.storage.provider.interfaces.IMessageBus; -import org.opengroup.osdu.storage.provider.interfaces.IRecordsMetadataRepository; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class LegalComplianceChangeServiceGcpImpl implements ILegalComplianceChangeService { - - private final IRecordsMetadataRepository recordsRepo; - private final IMessageBus messageBus; - private final StorageAuditLogger auditLogger; - private final JaxRsDpsLog logger; - // not conventional field name due to bean qualifiers in a core module - private final ICache<String, String> LegalTagCache; - - private final long maxRunningTimeMills = 115000; - - @Override - public Map<String, LegalCompliance> updateComplianceOnRecords(LegalTagChangedCollection legalTagsChanged, - DpsHeaders headers) throws ComplianceUpdateStoppedException { - Map<String, LegalCompliance> output = new HashMap<>(); - long currentTimeMills; - long start = System.currentTimeMillis(); - - for (LegalTagChanged lt : legalTagsChanged.getStatusChangedTags()) { - - ComplianceChangeInfo complianceChangeInfo = this.getComplianceChangeInfo(lt); - if (complianceChangeInfo == null) { - continue; - } - AbstractMap.SimpleEntry<String, List<RecordMetadata>> results = this.recordsRepo - .queryByLegal(lt.getChangedTagName(), complianceChangeInfo.getCurrent(), 500); - - while (results.getValue() != null && !results.getValue().isEmpty()) { - currentTimeMills = System.currentTimeMillis() - start; - if (currentTimeMills >= maxRunningTimeMills) { - throw new ComplianceUpdateStoppedException(currentTimeMills / 1000); - } - List<RecordMetadata> recordsMetadata = results.getValue(); - PubSubInfo[] pubsubInfos = this.updateComplianceStatus(complianceChangeInfo, recordsMetadata, output); - StringBuilder recordsId = new StringBuilder(); - for (RecordMetadata recordMetadata : recordsMetadata) { - recordsId.append(", ").append(recordMetadata.getId()); - } - this.recordsRepo.createOrUpdate(recordsMetadata, Optional.empty()); - this.messageBus.publishMessage(headers, pubsubInfos); - this.auditLogger.updateRecordsComplianceStateSuccess( - singletonList("[" + recordsId.substring(2) + "]")); - results = this.recordsRepo.queryByLegal(lt.getChangedTagName(), complianceChangeInfo.getCurrent(), 500); - } - } - - return output; - } - - private PubSubInfo[] updateComplianceStatus(ComplianceChangeInfo complianceChangeInfo, - List<RecordMetadata> recordMetadata, Map<String, LegalCompliance> output) { - - PubSubInfo[] pubsubInfo = new PubSubInfo[recordMetadata.size()]; - - int i = 0; - for (RecordMetadata rm : recordMetadata) { - rm.getLegal().setStatus(complianceChangeInfo.getNewState()); - rm.setStatus(complianceChangeInfo.getNewRecordState()); - pubsubInfo[i] = new PubSubInfo(rm.getId(), rm.getKind(), complianceChangeInfo.getPubSubEvent()); - output.put(rm.getId(), complianceChangeInfo.getNewState()); - i++; - } - - return pubsubInfo; - } - - private ComplianceChangeInfo getComplianceChangeInfo(LegalTagChanged lt) { - ComplianceChangeInfo output = null; - - if (lt.getChangedTagStatus().equalsIgnoreCase("compliant")) { - output = new ComplianceChangeInfo(LegalCompliance.compliant, OperationType.update, RecordState.active); - } else if (lt.getChangedTagStatus().equalsIgnoreCase("incompliant")) { - this.LegalTagCache.delete(lt.getChangedTagName()); - output = new ComplianceChangeInfo(LegalCompliance.incompliant, OperationType.delete, RecordState.deleted); - } else { - this.logger.warning(String.format("Unknown LegalTag compliance status received %s %s", - lt.getChangedTagStatus(), lt.getChangedTagName())); - } - - return output; - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/LegalTagChangedProcessing.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/LegalTagChangedProcessing.java deleted file mode 100644 index d84c4cff2..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/LegalTagChangedProcessing.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.jobs; - -import com.google.gson.Gson; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.opengroup.osdu.core.common.model.legal.LegalCompliance; -import org.opengroup.osdu.core.common.model.legal.jobs.ComplianceUpdateStoppedException; -import org.opengroup.osdu.core.common.model.legal.jobs.LegalTagChangedCollection; -import org.opengroup.osdu.core.common.model.legal.jobs.LegalTagConsistencyValidator; -import org.opengroup.osdu.core.gcp.oqm.model.OqmMessage; -import org.opengroup.osdu.storage.provider.gcp.messaging.scope.override.ThreadDpsHeaders; - -@Slf4j -@RequiredArgsConstructor -public class LegalTagChangedProcessing { - - private final LegalTagConsistencyValidator legalTagConsistencyValidator; - private final LegalComplianceChangeServiceGcpImpl legalComplianceChangeServiceGcp; - private final ThreadDpsHeaders dpsHeaders; - - public void process(OqmMessage oqmMessage) throws ComplianceUpdateStoppedException { - String pubsubMessage = oqmMessage.getData(); - LegalTagChangedCollection dto = (new Gson()).fromJson(pubsubMessage, LegalTagChangedCollection.class); - - LegalTagChangedCollection validDto = this.legalTagConsistencyValidator.checkLegalTagStatusWithLegalService(dto); - log.debug("LegalTags changed status validation via Legal service: {}.", validDto); - Map<String, LegalCompliance> stringLegalComplianceMap = this.legalComplianceChangeServiceGcp.updateComplianceOnRecords(validDto, dpsHeaders); - log.debug("Updated compliance on records: {}.", stringLegalComplianceMap); - - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/OqmSubscriberManager.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/OqmSubscriberManager.java deleted file mode 100644 index ca331684c..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/OqmSubscriberManager.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.jobs; - -import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_SINGLETON; - -import java.util.Map; -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.opengroup.osdu.core.common.model.http.AppException; -import org.opengroup.osdu.core.common.model.legal.jobs.LegalTagConsistencyValidator; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory; -import org.opengroup.osdu.core.gcp.oqm.driver.OqmDriver; -import org.opengroup.osdu.core.gcp.oqm.model.OqmDestination; -import org.opengroup.osdu.core.gcp.oqm.model.OqmMessageReceiver; -import org.opengroup.osdu.core.gcp.oqm.model.OqmSubscriber; -import org.opengroup.osdu.core.gcp.oqm.model.OqmSubscription; -import org.opengroup.osdu.core.gcp.oqm.model.OqmSubscriptionQuery; -import org.opengroup.osdu.core.gcp.oqm.model.OqmTopic; -import org.opengroup.osdu.storage.provider.gcp.messaging.config.MessagingConfigurationProperties; -import org.opengroup.osdu.storage.provider.gcp.messaging.scope.override.ThreadDpsHeaders; -import org.opengroup.osdu.storage.provider.gcp.messaging.thread.ThreadScopeContextHolder; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Scope; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; - -/** - * Runs once on the service start. Fetches all tenants' oqm destinations for TOPIC existence. If exists - searches for pull SUBSCRIPTION existence. Creates - * SUBSCRIPTION if doesn't exist. Then subscribe itself on SUBSCRIPTION. - */ - -@Slf4j -@Component -@Scope(SCOPE_SINGLETON) -@ConditionalOnProperty(name = "oqmDriver") -@RequiredArgsConstructor -public class OqmSubscriberManager { - - private final MessagingConfigurationProperties configurationProperties; - - private final ITenantFactory tenantInfoFactory; - private final OqmDriver driver; - - private final LegalTagConsistencyValidator legalTagConsistencyValidator; - private final LegalComplianceChangeServiceGcpImpl legalComplianceChangeServiceGcp; - private final ThreadDpsHeaders dpsHeaders; - - @PostConstruct - void postConstruct() { - log.debug("OqmSubscriberManager bean constructed. Provisioning STARTED."); - - //Get all Tenant infos - for (TenantInfo tenantInfo : tenantInfoFactory.listTenantInfo()) { - String dataPartitionId = tenantInfo.getDataPartitionId(); - String tagsChangedTopicName = configurationProperties.getLegalTagsChangedTopicName(); - log.debug("* OqmSubscriberManager on provisioning tenant {}:", dataPartitionId); - - log.debug("* * OqmSubscriberManager on check for topic {} existence:", - tagsChangedTopicName); - OqmTopic topic = driver.getTopic(tagsChangedTopicName, getDestination(tenantInfo)).orElse(null); - if (topic == null) { - log.error("* * OqmSubscriberManager on check for topic {} existence: ABSENT.", - tagsChangedTopicName); - throw new AppException( - HttpStatus.INTERNAL_SERVER_ERROR.value(), - "Required topic not exists.", - String.format( - "Required topic not exists. Create topic: %s for tenant: %s and restart service.", - tagsChangedTopicName, dataPartitionId - ) - ); - } - - String legalTagsChangedSubscriptionName = configurationProperties.getLegalTagsChangedSubscriptionName(); - - log.debug("* * OqmSubscriberManager on check for subscription {} existence:", legalTagsChangedSubscriptionName); - - OqmSubscriptionQuery query = OqmSubscriptionQuery.builder() - .namePrefix(legalTagsChangedSubscriptionName) - .subscriberable(true) - .build(); - - OqmSubscription subscription = driver.listSubscriptions(topic, query, getDestination(tenantInfo)).stream().findAny().orElse(null); - - if (subscription == null) { - log.error("* * OqmSubscriberManager on check for subscription {} existence: ABSENT. Will create.", legalTagsChangedSubscriptionName); - throw new AppException( - HttpStatus.INTERNAL_SERVER_ERROR.value(), - "Required subscription not exists.", - String.format( - "Required subscription not exists. Create subscription: %s for tenant: %s and restart service.", - legalTagsChangedSubscriptionName, - dataPartitionId - ) - ); - } else { - log.debug("* * OqmSubscriberManager on check for subscription {} existence: PRESENT.", legalTagsChangedSubscriptionName); - } - - log.debug("* * OqmSubscriberManager on registering Subscriber for tenant {}, subscription {}", - dataPartitionId, - legalTagsChangedSubscriptionName); - registerSubscriber(tenantInfo, subscription); - log.debug("* * OqmSubscriberManager on provisioning for tenant {}, subscription {}: Subscriber REGISTERED.", - dataPartitionId, - subscription.getName()); - - log.debug("* OqmSubscriberManager on provisioning tenant {}: COMPLETED.", - dataPartitionId); - } - - log.debug("OqmSubscriberManager bean constructed. Provisioning COMPLETED."); - } - - private void registerSubscriber(TenantInfo tenantInfo, OqmSubscription subscription) { - OqmDestination destination = getDestination(tenantInfo); - - OqmMessageReceiver receiver = (oqmMessage, oqmAckReplier) -> { - - String pubsubMessage = oqmMessage.getData(); - Map<String, String> headerAttributes = oqmMessage.getAttributes(); - log.debug(pubsubMessage + " " + headerAttributes + " " + oqmMessage.getId()); - - boolean ackedNacked = false; - try { - dpsHeaders.setThreadContext(headerAttributes); - LegalTagChangedProcessing legalTagChangedProcessing = - new LegalTagChangedProcessing(legalTagConsistencyValidator, legalComplianceChangeServiceGcp, dpsHeaders); - legalTagChangedProcessing.process(oqmMessage); - log.debug("OQM message handling for tenant {} topic {} subscription {}. ACK. Message: -data: {}, attributes: {}.", - dpsHeaders.getPartitionId(), - configurationProperties.getLegalTagsChangedTopicName(), - configurationProperties.getLegalTagsChangedSubscriptionName(), - pubsubMessage, - StringUtils.join(headerAttributes) - ); - oqmAckReplier.ack(); - ackedNacked = true; - } catch (Exception e) { - log.error("OQM message handling error for tenant {} topic {} subscription {}. Message: -data: {}, attributes: {}, error: {}.", - dpsHeaders.getPartitionId(), - configurationProperties.getLegalTagsChangedTopicName(), - configurationProperties.getLegalTagsChangedSubscriptionName(), - pubsubMessage, - StringUtils.join(headerAttributes), - e - ); - } finally { - if (!ackedNacked) { - oqmAckReplier.nack(); - } - ThreadScopeContextHolder.currentThreadScopeAttributes().clear(); - } - }; - - OqmSubscriber subscriber = OqmSubscriber.builder().subscription(subscription).messageReceiver(receiver).build(); - driver.subscribe(subscriber, destination); - log.debug("Just subscribed at topic {} subscription {} for tenant {}.", - subscription.getTopics().get(0).getName(), subscription.getName(), tenantInfo.getDataPartitionId()); - } - - private OqmDestination getDestination(TenantInfo tenantInfo) { - return OqmDestination.builder().partitionId(tenantInfo.getDataPartitionId()).build(); - } - -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/scope/override/ScopeModifierPostProcessor.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/scope/override/ScopeModifierPostProcessor.java deleted file mode 100644 index 0c0656ae2..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/scope/override/ScopeModifierPostProcessor.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.scope.override; - -import java.util.Objects; -import lombok.extern.slf4j.Slf4j; -import org.opengroup.osdu.storage.provider.gcp.messaging.thread.ThreadScope; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -public class ScopeModifierPostProcessor implements BeanFactoryPostProcessor { - - public static final String SCOPE_THREAD = "scope_thread"; - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { - factory.registerScope(SCOPE_THREAD, new ThreadScope()); - - for (String beanName : factory.getBeanDefinitionNames()) { - BeanDefinition beanDef = factory.getBeanDefinition(beanName); - if (Objects.equals(beanDef.getScope(), "request")) { - beanDef.setScope(SCOPE_THREAD); - log.debug("Scope has been overridden for bean: {}", beanDef.getBeanClassName()); - } - } - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/scope/override/ThreadDpsHeaders.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/scope/override/ThreadDpsHeaders.java deleted file mode 100644 index ad212673e..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/scope/override/ThreadDpsHeaders.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.scope.override; - -import static org.springframework.context.annotation.ScopedProxyMode.TARGET_CLASS; - -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.opengroup.osdu.core.auth.TokenProvider; -import org.opengroup.osdu.core.common.model.http.DpsHeaders; -import org.opengroup.osdu.storage.provider.gcp.messaging.config.MessagingConfigurationProperties; -import org.springframework.context.annotation.Primary; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -/** - * Original class bean configuration bounded to request scope, extend purpose is to unbound it. Due to OQM specific, we cannot rely on events transferred via - * HTTP requests, only pull subscriptions works with OQM. But this bean is configured only for Messaging context, original bean keeps working as usual for the - * web app context. - */ - -@Slf4j -@Primary -@Component -@Scope(value = ScopeModifierPostProcessor.SCOPE_THREAD, proxyMode = TARGET_CLASS) -@RequiredArgsConstructor -public class ThreadDpsHeaders extends DpsHeaders { - - private final MessagingConfigurationProperties properties; - private final TokenProvider tokenProvider; - - public void setThreadContext(Map<String, String> headers) { - this.put(DpsHeaders.AUTHORIZATION, "Bearer " + tokenProvider.getIdToken()); - this.put(DpsHeaders.USER_EMAIL, properties.getStorageServiceAccountEmail()); - this.addFromMap(headers); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScope.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScope.java deleted file mode 100644 index 91c87ee7b..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScope.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.thread; - -import java.util.Map; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.ObjectFactory; -import org.springframework.beans.factory.config.Scope; - -@Slf4j -public class ThreadScope implements Scope { - - public Object get(String name, ObjectFactory<?> factory) { - log.trace("Get bean:{} with factory: {} current Thread: {}", name, factory, Thread.currentThread().getName()); - Object result = null; - Map<String, Object> hBeans = ThreadScopeContextHolder.currentThreadScopeAttributes().getBeanMap(); - if (!hBeans.containsKey(name)) { - result = factory.getObject(); - log.trace("No bean in context with name: {} factory provisioning result is: {} current Thread: {}", name, result, Thread.currentThread().getName()); - hBeans.put(name, result); - } else { - result = hBeans.get(name); - } - - return result; - } - - public Object remove(String name) { - log.trace("Removing bean : {} current Thread: {}", name, Thread.currentThread().getName()); - Object result = null; - Map<String, Object> hBeans = ThreadScopeContextHolder.currentThreadScopeAttributes().getBeanMap(); - if (hBeans.containsKey(name)) { - result = hBeans.get(name); - hBeans.remove(name); - } - - return result; - } - - public void registerDestructionCallback(String name, Runnable callback) { - ThreadScopeContextHolder.currentThreadScopeAttributes().registerRequestDestructionCallback(name, callback); - } - - public Object resolveContextualObject(String key) { - return null; - } - - public String getConversationId() { - return Thread.currentThread().getName(); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScopeAttributes.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScopeAttributes.java deleted file mode 100644 index 42b8ca4df..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScopeAttributes.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.thread; - -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.lang.NonNull; - -@Slf4j -@RequiredArgsConstructor -public class ThreadScopeAttributes { - - protected final Map<String, Object> hBeans = new HashMap(); - protected final Map<String, Runnable> hRequestDestructionCallbacks = new LinkedHashMap(); - - protected final Map<String, Object> getBeanMap() { - return this.hBeans; - } - - protected final void registerRequestDestructionCallback(@NonNull String name, @NonNull Runnable callback) { - log.trace("Registering callback for: {} on runnable: {}", name, callback); - this.hRequestDestructionCallbacks.put(name, callback); - } - - public final void clear() { - this.processDestructionCallbacks(); - this.hBeans.clear(); - } - - private void processDestructionCallbacks() { - for (Map.Entry<String, Runnable> mapEntry : this.hRequestDestructionCallbacks.entrySet()) { - Runnable callback = mapEntry.getValue(); - log.trace("Performing destruction callback for: {} on thread: {}", mapEntry.getKey(), Thread.currentThread().getName()); - callback.run(); - } - this.hRequestDestructionCallbacks.clear(); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScopeContextHolder.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScopeContextHolder.java deleted file mode 100644 index cd9016949..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/messaging/thread/ThreadScopeContextHolder.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.thread; - -public class ThreadScopeContextHolder { - - private static final ThreadLocal<ThreadScopeAttributes> threadScopeAttributesHolder = new InheritableThreadLocal<ThreadScopeAttributes>() { - @Override - protected ThreadScopeAttributes initialValue() { - return new ThreadScopeAttributes(); - } - }; - - private ThreadScopeContextHolder() { - } - - public static ThreadScopeAttributes getThreadScopeAttributes() { - return threadScopeAttributesHolder.get(); - } - - public static void setThreadScopeAttributes(ThreadScopeAttributes accessor) { - threadScopeAttributesHolder.set(accessor); - } - - public static ThreadScopeAttributes currentThreadScopeAttributes() throws IllegalStateException { - ThreadScopeAttributes accessor = threadScopeAttributesHolder.get(); - if (accessor == null) { - throw new IllegalStateException("No thread scoped attributes."); - } else { - return accessor; - } - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/cache/CacheConfig.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/cache/CacheConfig.java deleted file mode 100644 index 5115bbd5d..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/cache/CacheConfig.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.cache; - -import lombok.RequiredArgsConstructor; -import org.opengroup.osdu.core.common.cache.ICache; -import org.opengroup.osdu.core.common.cache.RedisCache; -import org.opengroup.osdu.core.common.cache.VmCache; -import org.opengroup.osdu.core.common.model.entitlements.Groups; -import org.opengroup.osdu.core.common.model.storage.Schema; -import org.opengroup.osdu.core.common.partition.PartitionInfo; -import org.opengroup.osdu.core.gcp.cache.RedisCacheBuilder; -import org.opengroup.osdu.storage.provider.gcp.web.config.GcpAppServiceConfig; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -@RequiredArgsConstructor -public class CacheConfig { - - private final RedisCacheBuilder<String, String> legalRedisCacheBuilder; - private final RedisCacheBuilder<String, Schema> schemaRedisCacheBuilder; - private final RedisCacheBuilder<String, Groups> groupsRedisCacheBuilder; - - @Bean("LegalTagCache") - public ICache<String, String> legalTagCache(GcpAppServiceConfig gcpAppServiceConfig) { - RedisCache<String, String> storageCache = legalRedisCacheBuilder.buildRedisCache( - gcpAppServiceConfig.getRedisStorageHost(), - gcpAppServiceConfig.getRedisStoragePort(), - gcpAppServiceConfig.getRedisStoragePassword(), - gcpAppServiceConfig.getRedisStorageExpiration(), - gcpAppServiceConfig.getRedisStorageWithSsl(), - String.class, - String.class - ); - return new LegalTagMultiTenantCache(storageCache); - } - - @Bean - public RedisCache<String, Schema> schemaCache(GcpAppServiceConfig gcpAppServiceConfig) { - return schemaRedisCacheBuilder.buildRedisCache( - gcpAppServiceConfig.getRedisStorageHost(), - gcpAppServiceConfig.getRedisStoragePort(), - gcpAppServiceConfig.getRedisStoragePassword(), - gcpAppServiceConfig.getRedisStorageExpiration(), - gcpAppServiceConfig.getRedisStorageWithSsl(), - String.class, - Schema.class - ); - } - - @Bean - public RedisCache<String, Groups> groupsCache(GcpAppServiceConfig gcpAppServiceConfig){ - return groupsRedisCacheBuilder.buildRedisCache( - gcpAppServiceConfig.getRedisGroupHost(), - gcpAppServiceConfig.getRedisGroupPort(), - gcpAppServiceConfig.getRedisGroupPassword(), - gcpAppServiceConfig.getRedisGroupExpiration(), - gcpAppServiceConfig.getRedisGroupWithSsl(), - String.class, - Groups.class - ); - } - - @Bean - public ICache<String, PartitionInfo> partitionInfoCache() { - return new VmCache<>(600, 2000); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/cache/LegalTagMultiTenantCache.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/cache/LegalTagMultiTenantCache.java deleted file mode 100644 index 961f41126..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/cache/LegalTagMultiTenantCache.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.cache; - -import org.opengroup.osdu.core.common.cache.ICache; -import org.opengroup.osdu.core.common.cache.MultiTenantCache; -import org.opengroup.osdu.core.common.cache.RedisCache; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.springframework.beans.factory.annotation.Autowired; - -public class LegalTagMultiTenantCache implements ICache<String, String> { - - @Autowired - private TenantInfo tenant; - - private final MultiTenantCache<String> caches; - - public LegalTagMultiTenantCache(RedisCache<String, String> redisCache) { - this.caches = new MultiTenantCache<>(redisCache); - } - - @Override - public void put(String key, String val) { - this.partitionCache().put(key, val); - } - - @Override - public String get(String key) { - return this.partitionCache().get(key); - } - - @Override - public void delete(String key) { - this.partitionCache().delete(key); - } - - @Override - public void clearAll() { - this.partitionCache().clearAll(); - } - - private ICache<String, String> partitionCache() { - return this.caches.get(String.format("%s:legalTag", this.tenant)); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/GcpAppServiceConfig.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/GcpAppServiceConfig.java deleted file mode 100644 index 40f80770e..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/GcpAppServiceConfig.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ConfigurationProperties -@Data -public class GcpAppServiceConfig { - - private String pubsubSearchTopic; - - private String redisStorageHost; - private Integer redisStoragePort; - private String redisStoragePassword; - private Integer redisStorageExpiration = 60 * 60; - private Boolean redisStorageWithSsl = false; - - private String redisGroupHost; - private Integer redisGroupPort; - private String redisGroupPassword; - private Integer redisGroupExpiration = 30; - private Boolean redisGroupWithSsl = false; -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/PartitionPropertyNames.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/PartitionPropertyNames.java deleted file mode 100644 index 3038ac7a7..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/PartitionPropertyNames.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License 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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Data -@Configuration -@ConfigurationProperties(prefix = "partition.properties") -public class PartitionPropertyNames { - private String storageBucketName; -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/WebAppMainContextConfiguration.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/WebAppMainContextConfiguration.java deleted file mode 100644 index 577f64ff0..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/config/WebAppMainContextConfiguration.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.config; - -import java.util.Arrays; -import jakarta.annotation.PostConstruct; -import lombok.extern.slf4j.Slf4j; -import org.opengroup.osdu.storage.StorageApplication; -import org.opengroup.osdu.storage.provider.gcp.messaging.config.MessagingCustomContextConfiguration; -import org.opengroup.osdu.storage.provider.gcp.messaging.jobs.OqmSubscriberManager; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.FilterType; -import org.springframework.context.annotation.PropertySource; - -/** - * This context configuration excludes pulling message receiving and thread scope configuration. - */ -@Slf4j -@Configuration -@EnableAutoConfiguration -@PropertySource("classpath:application.properties") -@ComponentScan( - value = {"org.opengroup.osdu"}, - excludeFilters = { - @ComponentScan.Filter( - type = FilterType.ASSIGNABLE_TYPE, - value = { - StorageApplication.class - } - ), - @ComponentScan.Filter( - type = FilterType.REGEX, - pattern = {"org\\.opengroup\\.osdu\\.storage\\.provider\\.gcp\\.messaging\\..*"} - ) - } -) -public class WebAppMainContextConfiguration { - - @Autowired - private ApplicationContext applicationContext; - - @PostConstruct - public void setUp() { - log.debug("Main web app context initialized with id: {}.", applicationContext.getId()); - log.debug("Main web app context status: {}.", applicationContext); - String[] allBeansNames = applicationContext.getBeanDefinitionNames(); - log.debug("Main web app context beans definitions: {}.", Arrays.toString(allBeansNames)); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/mappers/osm/OsmTypeMapperImpl.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/mappers/osm/OsmTypeMapperImpl.java deleted file mode 100644 index ca8527779..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/mappers/osm/OsmTypeMapperImpl.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ -package org.opengroup.osdu.storage.provider.gcp.web.mappers.osm; - -import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_SINGLETON; - -import com.google.cloud.Timestamp; -import com.google.cloud.datastore.Blob; -import com.google.cloud.datastore.Key; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import org.opengroup.osdu.core.common.model.storage.RecordMetadata; -import org.opengroup.osdu.core.common.model.storage.Schema; -import org.opengroup.osdu.core.gcp.osm.persistence.IdentityTranslator; -import org.opengroup.osdu.core.gcp.osm.translate.Instrumentation; -import org.opengroup.osdu.core.gcp.osm.translate.TypeMapper; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -/** - * All Entity classes used in translation should be registered here even if don't need custom settings. Each class is represented as Instrumentation object. At - * least class objects and rules for Identity translation should be provided.oi - */ -@Component -@Scope(SCOPE_SINGLETON) -@ConditionalOnProperty(name = "osmDriver") -public class OsmTypeMapperImpl extends TypeMapper { - - public OsmTypeMapperImpl() { - super(Arrays.asList( - new Instrumentation<>(RecordMetadata.class, - new HashMap<String, String>() {{ - put("user", "createUser"); - put("gcsVersionPaths", "bucket"); - }}, - new HashMap<String, Class<?>>() {{ - put("createTime", Timestamp.class); - put("modifyTime", Timestamp.class); - }}, - new IdentityTranslator<>( - RecordMetadata::getId, - (r, o) -> r.setId(((Key) o).getName()) - ), - Collections.singletonList("id") - ), - new Instrumentation<>(Schema.class, - new HashMap<String, String>() {{ - put("ext", "extension"); - }}, - new HashMap<String, Class<?>>() {{ - put("schema", Blob.class); - put("ext", Blob.class); - }}, - new IdentityTranslator<>( - Schema::getKind, - (r, o) -> r.setKind(((Key) o).getName()) - ), - Collections.singletonList("kind") - ) - )); - } - - -} \ No newline at end of file diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/middleware/GcpExceptionMapper.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/middleware/GcpExceptionMapper.java deleted file mode 100644 index 3b580843c..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/middleware/GcpExceptionMapper.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.middleware; - -import com.google.cloud.storage.StorageException; -import org.opengroup.osdu.core.common.model.http.AppException; -import org.opengroup.osdu.storage.util.GlobalExceptionMapper; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -@Order(Ordered.HIGHEST_PRECEDENCE + 1) -@ControllerAdvice -public class GcpExceptionMapper { - - public static final String ACCESS_DENIED_REASON = "Access denied"; - public static final String ACCESS_DENIED_MESSAGE = "The user is not authorized to perform this action"; - - private final GlobalExceptionMapper mapper; - - public GcpExceptionMapper(GlobalExceptionMapper mapper) { - this.mapper = mapper; - } - - @ExceptionHandler(StorageException.class) - protected ResponseEntity<Object> handleStorageException(StorageException e) { - return mapper.getErrorResponse( - new AppException(HttpStatus.FORBIDDEN.value(), ACCESS_DENIED_REASON, ACCESS_DENIED_MESSAGE, e)); - } - -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/pubsub/OqmPubSub.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/pubsub/OqmPubSub.java deleted file mode 100644 index 687d239fa..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/pubsub/OqmPubSub.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.pubsub; - -import com.google.gson.Gson; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.NotImplementedException; -import org.opengroup.osdu.core.common.model.http.CollaborationContext; -import org.opengroup.osdu.core.common.model.http.DpsHeaders; -import org.opengroup.osdu.core.common.model.storage.PubSubInfo; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.gcp.oqm.driver.OqmDriver; -import org.opengroup.osdu.core.gcp.oqm.model.OqmDestination; -import org.opengroup.osdu.core.gcp.oqm.model.OqmMessage; -import org.opengroup.osdu.core.gcp.oqm.model.OqmTopic; -import org.opengroup.osdu.storage.model.RecordChangedV2; -import org.opengroup.osdu.storage.provider.gcp.web.config.GcpAppServiceConfig; -import org.opengroup.osdu.storage.provider.interfaces.IMessageBus; -import org.springframework.stereotype.Repository; - -import jakarta.annotation.PostConstruct; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -@Repository -@RequiredArgsConstructor -public class OqmPubSub implements IMessageBus { - - private final GcpAppServiceConfig config; - private final OqmDriver driver; - private final TenantInfo tenant; - private final int BATCH_SIZE = 50; - - private OqmTopic oqmTopic = null; - - @PostConstruct - void postConstruct() { - oqmTopic = OqmTopic.builder().name(config.getPubsubSearchTopic()).build(); - } - - @Override - public void publishMessage(DpsHeaders headers, PubSubInfo... messages) { - - OqmDestination oqmDestination = OqmDestination.builder().partitionId(headers.getPartitionId()).build(); - - for (int i = 0; i < messages.length; i += BATCH_SIZE) { - - PubSubInfo[] batch = Arrays.copyOfRange(messages, i, Math.min(messages.length, i + BATCH_SIZE)); - - String json = new Gson().toJson(batch); - - Map<String, String> attributes = new HashMap<>(); - attributes.put(DpsHeaders.USER_EMAIL, headers.getUserEmail()); - attributes.put(DpsHeaders.ACCOUNT_ID, this.tenant.getName()); - attributes.put(DpsHeaders.DATA_PARTITION_ID, headers.getPartitionIdWithFallbackToAccountId()); - headers.addCorrelationIdIfMissing(); - attributes.put(DpsHeaders.CORRELATION_ID, headers.getCorrelationId()); - - OqmMessage oqmMessage = OqmMessage.builder().data(json).attributes(attributes).build(); - - driver.publish(oqmMessage, oqmTopic, oqmDestination); - } - } - - @Override - public void publishMessage(Optional<CollaborationContext> collaborationContext, DpsHeaders headers, RecordChangedV2... messages) { - throw new NotImplementedException(); - } - - @Override - public void publishMessage(DpsHeaders headers, Map<String, String> routingInfo, List<?> messageList) { - throw new NotImplementedException(); - } - - @Override - public void publishMessage(DpsHeaders headers, Map<String, String> routingInfo, PubSubInfo... messages) { - throw new NotImplementedException(); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/ObmStorage.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/ObmStorage.java deleted file mode 100644 index b664cf988..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/ObmStorage.java +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.repository; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.http.HttpStatus; -import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; -import org.opengroup.osdu.core.common.model.entitlements.Acl; -import org.opengroup.osdu.core.common.model.entitlements.GroupInfo; -import org.opengroup.osdu.core.common.model.http.AppException; -import org.opengroup.osdu.core.common.model.http.CollaborationContext; -import org.opengroup.osdu.core.common.model.http.DpsHeaders; -import org.opengroup.osdu.core.common.model.indexer.OperationType; -import org.opengroup.osdu.core.common.model.storage.RecordData; -import org.opengroup.osdu.core.common.model.storage.RecordMetadata; -import org.opengroup.osdu.core.common.model.storage.RecordProcessing; -import org.opengroup.osdu.core.common.model.storage.RecordState; -import org.opengroup.osdu.core.common.model.storage.TransferInfo; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.common.partition.PartitionPropertyResolver; -import org.opengroup.osdu.core.gcp.obm.driver.Driver; -import org.opengroup.osdu.core.gcp.obm.driver.ObmDriverRuntimeException; -import org.opengroup.osdu.core.gcp.obm.driver.S3CompatibleErrors; -import org.opengroup.osdu.core.gcp.obm.model.Blob; -import org.opengroup.osdu.core.gcp.obm.persistence.ObmDestination; -import org.opengroup.osdu.storage.provider.gcp.web.config.PartitionPropertyNames; -import org.opengroup.osdu.storage.provider.interfaces.ICloudStorage; -import org.opengroup.osdu.storage.provider.interfaces.IRecordsMetadataRepository; -import org.opengroup.osdu.storage.service.DataAuthorizationService; -import org.opengroup.osdu.storage.service.IEntitlementsExtensionService; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Repository; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.stream.Collectors; - -import static java.nio.charset.StandardCharsets.UTF_8; - -@Repository -@RequiredArgsConstructor -public class ObmStorage implements ICloudStorage { - - private static final String RECORD_WRITING_ERROR_REASON = "Error on writing record"; - private static final String RECORD_DOES_NOT_HAVE_VERSIONS_AVAILABLE_MSG = "Record %s does not have versions available"; - private static final String ERROR_ON_WRITING_THE_RECORD_HAS_OCCURRED_MSG = "An unexpected error on writing the record has occurred"; - - private final Driver storage; - private final DataAuthorizationService dataAuthorizationService; - private final DpsHeaders headers; - private final TenantInfo tenantInfo; - private final IRecordsMetadataRepository<?> recordRepository; - private final IEntitlementsExtensionService entitlementsService; - private final ExecutorService threadPool; - private final JaxRsDpsLog log; - - private final PartitionPropertyResolver partitionPropertyResolver; - - private final PartitionPropertyNames partitionPropertyNames; - - @Override - public void write(RecordProcessing... records) { - String bucket = getBucketName(this.tenantInfo); - String dataPartitionId = tenantInfo.getDataPartitionId(); - - ObjectMapper mapper = new ObjectMapper(); - - List<Callable<Boolean>> tasks = new ArrayList<>(); - - for (RecordProcessing record : records) { - - RecordMetadata metadata = record.getRecordMetadata(); - validateMetadata(metadata); - - tasks.add(() -> this.writeBlobThread(dataPartitionId, record, mapper, bucket)); - } - - try { - List<Future<Boolean>> results = this.threadPool.invokeAll(tasks); - - for (Future<Boolean> future : results) { - future.get(); - } - - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - if (e.getCause() instanceof AppException) { - throw (AppException) e.getCause(); - } else { - throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error during record ingestion", - ERROR_ON_WRITING_THE_RECORD_HAS_OCCURRED_MSG, e); - } - } - } - - @Override - public Map<String, Acl> updateObjectMetadata(List<RecordMetadata> recordsMetadata, List<String> recordsId, List<RecordMetadata> validMetadata, - List<String> lockedRecords, Map<String, String> recordsIdMap, Optional<CollaborationContext> collaborationContext) { - String bucket = getBucketName(this.tenantInfo); - Map<String, Acl> originalAcls = new HashMap<>(); - Map<String, RecordMetadata> currentRecords = this.recordRepository.get(recordsId, collaborationContext); - - for (RecordMetadata recordMetadata : recordsMetadata) { - String id = recordMetadata.getId(); - String idWithVersion = recordsIdMap.get(id); - - if (!id.equalsIgnoreCase(idWithVersion)) { - long previousVersion = Long.parseLong(idWithVersion.split(":")[3]); - long currentVersion = currentRecords.get(id).getLatestVersion(); - if (previousVersion != currentVersion) { - lockedRecords.add(idWithVersion); - continue; - } - } - validMetadata.add(recordMetadata); - storage.getBlob(bucket, recordMetadata.getVersionPath(recordMetadata.getLatestVersion()), getDestination()); - originalAcls.put(recordMetadata.getId(), currentRecords.get(id).getAcl()); - } - - return originalAcls; - } - - @Override - public void revertObjectMetadata(List<RecordMetadata> recordsMetadata, Map<String, Acl> originalAcls, Optional<CollaborationContext> collaborationContext) { - String bucket = getBucketName(this.tenantInfo); - - for (RecordMetadata recordMetadata : recordsMetadata) { - storage.getBlob(bucket, recordMetadata.getVersionPath(recordMetadata.getLatestVersion()), getDestination()); - } - } - - @Override - public boolean hasAccess(RecordMetadata... records) { - - if (ArrayUtils.isEmpty(records)) { - return true; - } - - String bucket = getBucketName(this.tenantInfo); - for (RecordMetadata record : records) { - - try { - validateMetadata(record); - } catch (AppException e) { - if (e.getError().getReason().equals(RECORD_WRITING_ERROR_REASON)) { - throw new AppException(HttpStatus.SC_FORBIDDEN, ACCESS_DENIED_ERROR_REASON, ACCESS_DENIED_ERROR_MSG); - } else { - throw e; - } - } - - if (!record.getStatus().equals(RecordState.active)) { - continue; - } - - if (!record.hasVersion()) { - this.log.warning(String.format(RECORD_DOES_NOT_HAVE_VERSIONS_AVAILABLE_MSG, record.getId())); - continue; - } - - try { - String path = record.getVersionPath(record.getLatestVersion()); - Blob blob = storage.getBlob(bucket, path, getDestination()); - if (blob == null) { - throw new ObmDriverRuntimeException(S3CompatibleErrors.NO_SUCH_KEY_CODE, new RuntimeException(String.format("'%s' not found", path))); - } - } catch (ObmDriverRuntimeException exception) { - throw new AppException(exception.getError().getHttpStatusCode(), exception.getCause().getMessage(), exception.getMessage(), exception); - } - } - - return true; - } - - @Override - public String read(RecordMetadata record, Long version, boolean checkDataInconsistency) { - - if (!this.dataAuthorizationService.validateViewerOrOwnerAccess(record, OperationType.view)) { - throw new AppException(HttpStatus.SC_FORBIDDEN, ACCESS_DENIED_ERROR_REASON, ACCESS_DENIED_ERROR_MSG); - } - - try { - String path = record.getVersionPath(version); - - byte[] blob = storage.getBlobContent(getBucketName(this.tenantInfo), path, getDestination()); - - return new String(blob, UTF_8); - - } catch (ObmDriverRuntimeException e) { - if (e.getError().getHttpStatusCode() == HttpStatus.SC_FORBIDDEN) { - //exception should be generic, logging can be informative - throw new AppException(HttpStatus.SC_FORBIDDEN, ACCESS_DENIED_ERROR_REASON, ACCESS_DENIED_ERROR_MSG, e); - } else if (e.getError().getHttpStatusCode() == HttpStatus.SC_NOT_FOUND) { - String msg = String.format("Record with id '%s' does not exist", record.getId()); - throw new AppException(HttpStatus.SC_UNPROCESSABLE_ENTITY, "Record not found", msg); - } else { - throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error during record retrieval", - "An unexpected error on retrieving the record has occurred", e); - } - } - } - - @Override - public Map<String, String> read(Map<String, String> objects, Optional<CollaborationContext> collaborationContext) { - - String bucketName = getBucketName(this.tenantInfo); - String dataPartitionId = tenantInfo.getDataPartitionId(); - - Map<String, String> map = new ConcurrentHashMap<>(); - - List<Callable<Boolean>> tasks = new ArrayList<>(); - - for (Map.Entry<String, String> object : objects.entrySet()) { - tasks.add(() -> this.readBlobThread(dataPartitionId, object.getValue(), bucketName, map)); - } - - try { - this.threadPool.invokeAll(tasks); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - return map; - } - - @Override - public Map<String, String> getHash(Collection<RecordMetadata> records) { - - String bucket = getBucketName(this.tenantInfo); - - String[] blobIds = records.stream().map(rm -> rm.getVersionPath(rm.getLatestVersion())).toArray(String[]::new); - Iterable<Blob> blobs = storage.listBlobsByName(bucket, getDestination(), blobIds); - - Map<String, String> hashes = new HashMap<>(); - - for (RecordMetadata rm : records) { - Blob blob = blobs.iterator().next(); - String hash = blob == null ? "" : blob.getChecksum(); - hashes.put(rm.getId(), hash); - } - - return hashes; - } - - @Override - public void delete(RecordMetadata record) { - if (!record.hasVersion()) { - this.log.warning(String.format(RECORD_DOES_NOT_HAVE_VERSIONS_AVAILABLE_MSG, record.getId())); - return; - } - - String bucket = getBucketName(this.tenantInfo); - try { - Blob blob = storage.getBlob(bucket, record.getVersionPath(record.getLatestVersion()), getDestination()); - - if (blob == null) { - String msg = String.format("Record with id '%s' does not exist", record.getId()); - throw new AppException(HttpStatus.SC_NOT_FOUND, "Record not found", msg); - } - - String[] versionFiles = record.getGcsVersionPaths().toArray(new String[0]); - - storage.deleteBlobs(bucket, getDestination(), versionFiles); - - } catch (ObmDriverRuntimeException e) { - throw new AppException(HttpStatus.SC_FORBIDDEN, ACCESS_DENIED_ERROR_REASON, ACCESS_DENIED_ERROR_MSG, e); - } - - } - - @Override - public void deleteVersion(RecordMetadata record, Long version) { - - String bucket = getBucketName(this.tenantInfo); - - try { - if (!record.hasVersion()) { - this.log.warning(String.format(RECORD_DOES_NOT_HAVE_VERSIONS_AVAILABLE_MSG, record.getId())); - } - - Blob blob = storage.getBlob(bucket, record.getVersionPath(version), getDestination()); - - if (blob == null) { - this.log.warning(String.format("Record with id '%s' does not exist, unable to purge version: %s", record.getId(), version)); - } - storage.deleteBlob(bucket, record.getVersionPath(version), getDestination()); - - } catch (ObmDriverRuntimeException e) { - throw new AppException(HttpStatus.SC_FORBIDDEN, ACCESS_DENIED_ERROR_REASON, ACCESS_DENIED_ERROR_MSG, e); - } - } - - @Override - public void deleteVersions(List<String> versionPaths) { - String bucket = getBucketName(this.tenantInfo); - versionPaths.stream().forEach(versionPath -> { - try { - storage.deleteBlob(bucket, versionPath, getDestination()); - } catch (ObmDriverRuntimeException e) { - throw new AppException(HttpStatus.SC_FORBIDDEN, ACCESS_DENIED_ERROR_REASON, ACCESS_DENIED_ERROR_MSG, e); - } - }); - } - - @Override - public boolean isDuplicateRecord(TransferInfo transfer, Map<String, String> hashMap, Map.Entry<RecordMetadata, RecordData> kv) { - Gson gson = new Gson(); - RecordMetadata updatedRecordMetadata = kv.getKey(); - RecordData recordData = kv.getValue(); - String recordHash = hashMap.get(updatedRecordMetadata.getId()); - - String newRecordStr = gson.toJson(recordData); - byte[] bytes = newRecordStr.getBytes(StandardCharsets.UTF_8); - String newHash = storage.getCalculatedChecksum(bytes); - - if (newHash.equals(recordHash)) { - transfer.getSkippedRecords().add(updatedRecordMetadata.getId()); - return true; - } else { - return false; - } - } - - private boolean writeBlobThread(String dataPartitionId, RecordProcessing processing, ObjectMapper mapper, String bucket) { - - RecordMetadata metadata = processing.getRecordMetadata(); - String objectPath = metadata.getVersionPath(metadata.getLatestVersion()); - - Blob blob = Blob.builder().bucket(bucket).name(objectPath).contentType(MediaType.APPLICATION_JSON_VALUE).build(); - - try { - String content = mapper.writeValueAsString(processing.getRecordData()); - storage.createAndGetBlob(blob, content.getBytes(UTF_8), getDestination(dataPartitionId)); - } catch (ObmDriverRuntimeException e) { - if (e.getError().getHttpStatusCode() == HttpStatus.SC_BAD_REQUEST) { - throw new AppException(HttpStatus.SC_BAD_REQUEST, RECORD_WRITING_ERROR_REASON, e.getMessage(), e); - } - - if (e.getError().getHttpStatusCode() == HttpStatus.SC_FORBIDDEN) { - throw new AppException(HttpStatus.SC_FORBIDDEN, RECORD_WRITING_ERROR_REASON, - "User does not have permission to write the records.", e); - } - - throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, RECORD_WRITING_ERROR_REASON, - "An unexpected error on writing the record has occurred", e); - } catch (JsonProcessingException e) { - throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, RECORD_WRITING_ERROR_REASON, - "An unexpected error on writing the record has occurred", e); - } - - return true; - } - - private void validateMetadata(RecordMetadata metadata) { - if (entitlementsService.isDataManager(headers)) { - return; - } - - List<String> aclGroups = new ArrayList<>(); - - Collections.addAll(aclGroups, metadata.getAcl().getViewers()); - Collections.addAll(aclGroups, metadata.getAcl().getOwners()); - - List<String> groups = entitlementsService.getGroups(headers) - .getGroups() - .stream() - .map(GroupInfo::getEmail) - .collect(Collectors.toList()); - - Optional<String> missingGroup = aclGroups.stream().filter((s) -> !groups.contains(s)).findFirst(); - - if (missingGroup.isPresent()) { - throw new AppException(HttpStatus.SC_BAD_REQUEST, - RECORD_WRITING_ERROR_REASON, - String.format("Could not find group \"%s\".", missingGroup.get())); - } - } - - private boolean readBlobThread(String dataPartitionId, String object, String bucket, Map<String, String> map) { - String[] tokens = object.split("/"); - String key = tokens[tokens.length - 2]; - - try { - String value = new String(storage.getBlobContent(bucket, object, getDestination(dataPartitionId)), UTF_8); - map.put(key, value); - } catch (ObmDriverRuntimeException e) { - map.put(key, null); - } - - return true; - } - - private String getBucketName(TenantInfo tenant) { - return partitionPropertyResolver - .getOptionalPropertyValue( - partitionPropertyNames.getStorageBucketName(), tenantInfo.getDataPartitionId()) - .orElseGet( - () -> String.format("%s-%s-records", tenant.getProjectId(), tenant.getName())); - } - - private ObmDestination getDestination() { - return getDestination(tenantInfo.getDataPartitionId()); - } - - private ObmDestination getDestination(String dataPartitionId) { - return ObmDestination.builder().partitionId(dataPartitionId).build(); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmQueryRepository.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmQueryRepository.java deleted file mode 100644 index ce427114e..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmQueryRepository.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.repository; - -import static org.opengroup.osdu.core.gcp.osm.model.where.condition.And.and; -import static org.opengroup.osdu.core.gcp.osm.model.where.predicate.Eq.eq; -import static org.opengroup.osdu.storage.provider.gcp.web.repository.OsmRecordsMetadataRepository.KIND; -import static org.opengroup.osdu.storage.provider.gcp.web.repository.OsmRecordsMetadataRepository.RECORD_KIND; -import static org.opengroup.osdu.storage.provider.gcp.web.repository.OsmRecordsMetadataRepository.STATUS; -import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_SINGLETON; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import lombok.extern.java.Log; -import org.apache.commons.lang3.NotImplementedException; -import org.opengroup.osdu.core.common.model.http.CollaborationContext; -import org.opengroup.osdu.core.common.model.storage.DatastoreQueryResult; -import org.opengroup.osdu.core.common.model.storage.RecordMetadata; -import org.opengroup.osdu.core.common.model.storage.RecordState; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.gcp.osm.model.Destination; -import org.opengroup.osdu.core.gcp.osm.model.Namespace; -import org.opengroup.osdu.core.gcp.osm.model.order.OrderBy; -import org.opengroup.osdu.core.gcp.osm.model.query.GetQuery; -import org.opengroup.osdu.core.gcp.osm.service.Context; -import org.opengroup.osdu.core.gcp.osm.translate.Outcome; -import org.opengroup.osdu.core.gcp.osm.translate.ViewResult; -import org.opengroup.osdu.storage.model.RecordId; -import org.opengroup.osdu.storage.model.RecordIdAndKind; -import org.opengroup.osdu.storage.model.RecordInfoQueryResult; -import org.opengroup.osdu.storage.provider.interfaces.IQueryRepository; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Repository; - -@Repository -@Scope(SCOPE_SINGLETON) -@Log -@RequiredArgsConstructor -public class OsmQueryRepository implements IQueryRepository { - - private final Context context; - private final TenantInfo tenantInfo; - - @Override - public DatastoreQueryResult getAllKinds(Integer limit, String cursor) { - - GetQuery<RecordMetadata> q = new GetQuery<>(RecordMetadata.class, getDestination(), - eq(STATUS, RecordState.active), OrderBy.builder().addAsc(KIND).build()); - Outcome<ViewResult> out = context.getViewResults(q, null, getLimitTuned(limit), Collections.singletonList(KIND), true, cursor).outcome(); - List<String> kinds = out.getList().stream().map(e -> (String) e.get(KIND)).collect(Collectors.toList()); - return new DatastoreQueryResult(out.getPointer(), kinds); - } - - @Override - public DatastoreQueryResult getAllRecordIdsFromKind(String kind, Integer limit, String cursor, Optional<CollaborationContext> collaborationContext) { - - GetQuery<RecordMetadata> q = new GetQuery<>(RecordMetadata.class, getDestination(), and(eq(KIND, kind), eq(STATUS, RecordState.active))); - Outcome<ViewResult> out = context.getViewResults(q, null, getLimitTuned(limit), Collections.singletonList("id"), false, cursor).outcome(); - return new DatastoreQueryResult(out.getPointer(), out.getList().stream().map(e -> (String) e.get("id")).collect(Collectors.toList())); - } - - @Override - public RecordInfoQueryResult<RecordIdAndKind> getAllRecordIdAndKind(Integer limit, String cursor) { - throw new NotImplementedException(); - } - - @Override - public RecordInfoQueryResult<RecordId> getAllRecordIdsFromKind(Integer limit, String cursor, String kind) { - throw new NotImplementedException(); - } - - @Override - public HashMap<String, Long> getActiveRecordsCount() { - throw new NotImplementedException(); - } - - @Override - public Map<String, Long> getActiveRecordsCountForKinds(List<String> kinds) { - throw new NotImplementedException(); - } - - private int getLimitTuned(Integer limit) { - return limit == null ? PAGE_SIZE : (limit > 0 ? limit : PAGE_SIZE); - } - - private Destination getDestination() { - return Destination.builder().partitionId(tenantInfo.getDataPartitionId()) - .namespace(new Namespace(tenantInfo.getName())) - .kind(RECORD_KIND) - .build(); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmRecordsMetadataRepository.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmRecordsMetadataRepository.java deleted file mode 100644 index 2cdd93645..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmRecordsMetadataRepository.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.repository; - -import com.github.fge.jsonpatch.JsonPatch; -import java.util.Map.Entry; -import lombok.RequiredArgsConstructor; -import lombok.extern.java.Log; -import org.opengroup.osdu.core.common.model.http.CollaborationContext; -import org.opengroup.osdu.core.common.model.legal.LegalCompliance; -import org.opengroup.osdu.core.common.model.storage.RecordMetadata; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.gcp.osm.model.Destination; -import org.opengroup.osdu.core.gcp.osm.model.Kind; -import org.opengroup.osdu.core.gcp.osm.model.Namespace; -import org.opengroup.osdu.core.gcp.osm.model.query.GetQuery; -import org.opengroup.osdu.core.gcp.osm.service.Context; -import org.opengroup.osdu.core.gcp.osm.translate.Outcome; -import org.opengroup.osdu.storage.provider.interfaces.IRecordsMetadataRepository; -import org.opengroup.osdu.storage.provider.interfaces.ISchemaRepository; -import org.opengroup.osdu.storage.util.JsonPatchUtil; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Repository; - -import java.util.*; -import java.util.stream.Collectors; - -import static org.opengroup.osdu.core.gcp.osm.model.where.condition.And.and; -import static org.opengroup.osdu.core.gcp.osm.model.where.predicate.Eq.eq; -import static org.opengroup.osdu.core.gcp.osm.model.where.predicate.In.in; -import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_SINGLETON; - -@Repository -@Scope(SCOPE_SINGLETON) -@Log -@RequiredArgsConstructor -public class OsmRecordsMetadataRepository implements IRecordsMetadataRepository<String> { - - private final Context context; - private final TenantInfo tenantInfo; - - public static final Kind RECORD_KIND = new Kind("StorageRecord"); - public static final Kind SCHEMA_KIND = new Kind(ISchemaRepository.SCHEMA_KIND); - - public static final String KIND = "kind"; - public static final String LEGAL_TAGS = "legal.legaltags"; - public static final String LEGAL_COMPLIANCE = "legal.status"; - public static final String STATUS = "status"; - - @Override - public List<RecordMetadata> createOrUpdate(List<RecordMetadata> recordsMetadata, - Optional<CollaborationContext> collaborationContext) { - if (recordsMetadata != null) { - RecordMetadata[] metadata = recordsMetadata.toArray(RecordMetadata[]::new); - context.upsert(getDestination(), metadata); - } - return recordsMetadata; - } - - @Override - public void delete(String id, Optional<CollaborationContext> collaborationContext) { - context.deleteById(RecordMetadata.class, getDestination(), id); - } - - @Override - public RecordMetadata get(String id, Optional<CollaborationContext> collaborationContext) { - GetQuery<RecordMetadata> osmQuery = new GetQuery<>(RecordMetadata.class, getDestination(), eq("id", id)); - return context.getResultsAsList(osmQuery).stream() - .filter(Objects::nonNull) - .findFirst() - .orElse(null); - } - - @Override - public AbstractMap.SimpleEntry<String, List<RecordMetadata>> queryByLegal(String legalTagName, LegalCompliance status, int limit) { - - GetQuery<RecordMetadata>.GetQueryBuilder<RecordMetadata> builder = new GetQuery<>(RecordMetadata.class, getDestination()).toBuilder(); - if (status == null) { - builder.where(eq(LEGAL_TAGS, legalTagName)); - } else { - builder.where(and(eq(LEGAL_TAGS, legalTagName), eq(LEGAL_COMPLIANCE, status.name()))); - } - - Outcome<RecordMetadata> out = context.getResults(builder.build(), null, limit, null).outcome(); - return new AbstractMap.SimpleEntry<>(out.getPointer(), out.getList()); - } - - @Override - public Map<String, RecordMetadata> get(List<String> ids, - Optional<CollaborationContext> collaborationContext) { - GetQuery<RecordMetadata> recordsMetadataInQuery = new GetQuery<>( - RecordMetadata.class, - getDestination(), - in("id", ids) - ); - return context.getResultsAsList(recordsMetadataInQuery).stream() - .filter(Objects::nonNull) - .collect(Collectors.toMap(RecordMetadata::getId, recordMetadata -> recordMetadata)); - } - - //TODO remove when other providers replace with new method queryByLegal - @Override - public AbstractMap.SimpleEntry<String, List<RecordMetadata>> queryByLegalTagName(String legalTagName, int limit, String cursor) { - return queryByLegal(legalTagName, null, limit); - } - - @Override - public AbstractMap.SimpleEntry<String, List<RecordMetadata>> queryByLegalTagName(String legalTagName[], int limit, String cursor) { - throw new UnsupportedOperationException("Method not implemented."); - } - - @Override - public Map<String, String> patch( - Map<RecordMetadata, JsonPatch> jsonPatchPerRecord, - Optional<CollaborationContext> collaborationContext) { - if (Objects.nonNull(jsonPatchPerRecord)) { - RecordMetadata[] newRecordMetadata = new RecordMetadata[jsonPatchPerRecord.size()]; - int count = 0; - for (Entry<RecordMetadata, JsonPatch> entry : jsonPatchPerRecord.entrySet()) { - JsonPatch jsonPatch = entry.getValue(); - newRecordMetadata[count] = JsonPatchUtil.applyPatch(jsonPatch, RecordMetadata.class, entry.getKey()); - count++; - } - context.upsert(getDestination(), newRecordMetadata); - } - return new HashMap<>(); - } - - private Destination getDestination() { - return Destination.builder().partitionId(tenantInfo.getDataPartitionId()) - .namespace(new Namespace(tenantInfo.getName())).kind(RECORD_KIND).build(); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmSchemaRepository.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmSchemaRepository.java deleted file mode 100644 index 4345d2d36..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/repository/OsmSchemaRepository.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.repository; - -import static org.opengroup.osdu.core.gcp.osm.model.where.predicate.Eq.eq; -import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_SINGLETON; - -import lombok.RequiredArgsConstructor; -import lombok.extern.java.Log; -import org.opengroup.osdu.core.common.model.storage.Schema; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.gcp.osm.model.Destination; -import org.opengroup.osdu.core.gcp.osm.model.Namespace; -import org.opengroup.osdu.core.gcp.osm.model.query.GetQuery; -import org.opengroup.osdu.core.gcp.osm.service.Context; -import org.opengroup.osdu.core.gcp.osm.service.Transaction; -import org.opengroup.osdu.storage.provider.interfaces.ISchemaRepository; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Repository; - -@Repository -@Scope(SCOPE_SINGLETON) -@Log -@RequiredArgsConstructor -public class OsmSchemaRepository implements ISchemaRepository { - - private final Context context; - private final TenantInfo tenantInfo; - - @Override - public void add(Schema schema, String user) { - GetQuery<Schema> q = new GetQuery<>(Schema.class, getDestination(), eq("kind", schema.getKind())); - Transaction txn = context.beginTransaction(getDestination()); - try { - if (context.findOne(q).isPresent()) { - txn.rollbackIfActive(); - throw new IllegalArgumentException("A schema for the specified kind has already been registered."); - } else { - context.create(getDestination(), schema); - txn.commitIfActive(); - } - } finally { - if (txn != null) { - txn.rollbackIfActive(); - } - } - } - - @Override - public Schema get(String kind) { - GetQuery<Schema> q = new GetQuery<>(Schema.class, getDestination(), eq("kind", kind)); - return context.getResultsAsList(q).stream().findFirst().orElse(null); - } - - @Override - public void delete(String kind) { - context.deleteById(Schema.class, getDestination(), kind); - } - - private Destination getDestination() { - return Destination.builder() - .partitionId(tenantInfo.getDataPartitionId()) - .namespace(new Namespace(tenantInfo.getName())) - .kind(OsmRecordsMetadataRepository.SCHEMA_KIND) - .build(); - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/security/GSuiteSecurityConfig.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/security/GSuiteSecurityConfig.java deleted file mode 100644 index 8b0a1e930..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/security/GSuiteSecurityConfig.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.security; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.web.SecurityFilterChain; - -import static org.springframework.security.config.Customizer.withDefaults; - -@Configuration -@EnableWebSecurity -@EnableMethodSecurity -public class GSuiteSecurityConfig { - - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http - .cors(AbstractHttpConfigurer::disable) - .csrf(AbstractHttpConfigurer::disable) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll()) - .httpBasic(withDefaults()); - return http.build(); - } - -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/service/BatchServiceGcpImpl.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/service/BatchServiceGcpImpl.java deleted file mode 100644 index 6124a6292..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/service/BatchServiceGcpImpl.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.service; - -import static java.util.Collections.singletonList; - -import lombok.RequiredArgsConstructor; -import org.opengroup.osdu.core.common.model.http.CollaborationContext; -import org.opengroup.osdu.core.common.model.storage.DatastoreQueryResult; -import org.opengroup.osdu.storage.logging.StorageAuditLogger; -import org.opengroup.osdu.storage.provider.interfaces.IQueryRepository; -import org.opengroup.osdu.storage.service.BatchServiceImpl; -import org.springframework.stereotype.Service; - -import java.util.Optional; - -@Service -@RequiredArgsConstructor -public class BatchServiceGcpImpl extends BatchServiceImpl { - - private final IQueryRepository queryRepository; - private final StorageAuditLogger auditLogger; - - @Override - public DatastoreQueryResult getAllKinds(String cursor, Integer limit) { - DatastoreQueryResult result = this.queryRepository.getAllKinds(limit, cursor); - this.auditLogger.readAllKindsSuccess(result.getResults()); - return result; - } - - @Override - public DatastoreQueryResult getAllRecords(String cursor, String kind, Integer limit, Optional<CollaborationContext> collaborationContext) { - DatastoreQueryResult result = this.queryRepository.getAllRecordIdsFromKind(kind, limit, cursor, collaborationContext); - if (!result.getResults().isEmpty()) { - this.auditLogger.readAllRecordsOfGivenKindSuccess(singletonList(kind)); - } - return result; - } -} diff --git a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/util/ServiceAccountJwtClientImpl.java b/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/util/ServiceAccountJwtClientImpl.java deleted file mode 100644 index 3989219a2..000000000 --- a/provider/storage-gc/src/main/java/org/opengroup/osdu/storage/provider/gcp/web/util/ServiceAccountJwtClientImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.web.util; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.opengroup.osdu.core.auth.TokenProvider; -import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; -import org.springframework.web.context.annotation.RequestScope; - -@Primary -@Component -@RequestScope -@Slf4j -@RequiredArgsConstructor -public class ServiceAccountJwtClientImpl implements IServiceAccountJwtClient { - - private final TokenProvider tokenProvider; - - @Override - public String getIdToken(String tenantName) { - log.debug("Tenant name received for auth token is: {}", tenantName); - return "Bearer " + tokenProvider.getIdToken(); - } -} \ No newline at end of file diff --git a/provider/storage-gc/src/main/resources/application-anthos.properties b/provider/storage-gc/src/main/resources/application-anthos.properties deleted file mode 100644 index e69de29bb..000000000 diff --git a/provider/storage-gc/src/main/resources/application-gcp.properties b/provider/storage-gc/src/main/resources/application-gcp.properties deleted file mode 100644 index e69de29bb..000000000 diff --git a/provider/storage-gc/src/main/resources/application-local.properties b/provider/storage-gc/src/main/resources/application-local.properties deleted file mode 100644 index 2fdec1f53..000000000 --- a/provider/storage-gc/src/main/resources/application-local.properties +++ /dev/null @@ -1,13 +0,0 @@ -osmDriver=datastore -obmDriver=gcs -oqmDriver=pubsub - -REDIS_GROUP_HOST=127.0.0.1 -REDIS_STORAGE_HOST=127.0.0.1 - -PARTITION_API=https://community.gcp.gnrg-osdu.projects.epam.com/api/partition/v1/ -AUTHORIZE_API=https://community.gcp.gnrg-osdu.projects.epam.com/entitlements/v2 -LEGALTAG_API=https://community.gcp.gnrg-osdu.projects.epam.com/api/legal/v1 -CRS_API=https://community.gcp.gnrg-osdu.projects.epam.com/api/crs/v2 - -DEFAULT_DATA_COUNTRY=US diff --git a/provider/storage-gc/src/main/resources/application.properties b/provider/storage-gc/src/main/resources/application.properties index 8306f6947..71eaa8444 100644 --- a/provider/storage-gc/src/main/resources/application.properties +++ b/provider/storage-gc/src/main/resources/application.properties @@ -15,7 +15,6 @@ osdu.spring.config.enableEncodedSpecialCharacters=true # Security config opa.opa-endpoint=${OPA_ENDPOINT:notused} -opa.enabled=true # OQM config legal-tags-changed-topic-name=legaltags-changed @@ -58,16 +57,15 @@ management.endpoints.web.base-path=${MANAGEMENT_ENDPOINTS_WEB_BASE:/} management.endpoints.web.exposure.include=health management.health.probes.enabled=true -featureFlag.strategy=systemPartition -featureFlag.opa.enabled=false -SYSTEM_PARTITION_ID=system +featureFlag.strategy=appProperty +featureFlag.opa.enabled=${OPA_ENABLED:false} + +destination.resolver=partition -# GCP specific properties -osmDriver=datastore -obmDriver=gcs -oqmDriver=pubsub service.token.provider=GCP partition-auth-enabled=true datastore-beta-enabled=false dead-lettering-required=true +googleAudiences=${GOOGLE_AUDIENCES:osdu} + diff --git a/provider/storage-gc/src/main/resources/logback.xml b/provider/storage-gc/src/main/resources/logback.xml index cdfa2e625..c32f3088e 100644 --- a/provider/storage-gc/src/main/resources/logback.xml +++ b/provider/storage-gc/src/main/resources/logback.xml @@ -22,7 +22,7 @@ <timestampFormatTimezoneId>Etc/UTC</timestampFormatTimezoneId> <appendLineSeparator>true</appendLineSeparator> - <jsonFormatter class="org.opengroup.osdu.core.gcp.logging.formatter.GoogleJsonFormatter"> + <jsonFormatter class="org.opengroup.osdu.storage.provider.gcp.logging.formatter.GoogleJsonFormatter"> <prettyPrint>false</prettyPrint> </jsonFormatter> </layout> diff --git a/provider/storage-gc/src/main/resources/type-mapper-config.json b/provider/storage-gc/src/main/resources/type-mapper-config.json new file mode 100644 index 000000000..d2d406fde --- /dev/null +++ b/provider/storage-gc/src/main/resources/type-mapper-config.json @@ -0,0 +1,39 @@ +{ + "instrumentations": [ + { + "entityType": "org.opengroup.osdu.core.common.model.storage.RecordMetadata", + "fieldNameCustomMapping": { + "user": "createUser", + "gcsVersionPaths": "bucket" + }, + "fieldTypeCustomMapping": { + "createTime": "shaded.osm.com.google.cloud.Timestamp", + "modifyTime": "shaded.osm.com.google.cloud.Timestamp" + }, + "identityTranslator": { + "getIdMethod": "getId", + "setIdMethod": "setId", + "keyClass": "java.lang.String" + }, + "keyFields": ["id"] + }, + + { + "entityType": "org.opengroup.osdu.core.common.model.storage.Schema", + "fieldNameCustomMapping": { + "ext": "extension", + "gcsVersionPaths": "bucket" + }, + "fieldTypeCustomMapping": { + "schema": "shaded.osm.com.google.cloud.datastore.Blob", + "ext": "shaded.osm.com.google.cloud.datastore.Blob" + }, + "identityTranslator": { + "getIdMethod": "getKind", + "setIdMethod": "setKind", + "keyClass": "java.lang.String" + }, + "keyFields": ["kind"] + } + ] +} \ No newline at end of file diff --git a/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/MultiThreadingLegalTagChangedProcessingTest.java b/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/MultiThreadingLegalTagChangedProcessingTest.java deleted file mode 100644 index a0316fb37..000000000 --- a/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/MultiThreadingLegalTagChangedProcessingTest.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.jobs; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.when; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import java.util.AbstractMap.SimpleEntry; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.opengroup.osdu.core.auth.TokenProvider; -import org.opengroup.osdu.core.common.cache.ICache; -import org.opengroup.osdu.core.common.logging.DefaultLogger; -import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; -import org.opengroup.osdu.core.common.model.entitlements.Groups; -import org.opengroup.osdu.core.common.model.http.DpsHeaders; -import org.opengroup.osdu.core.common.model.legal.InvalidTagWithReason; -import org.opengroup.osdu.core.common.model.legal.Legal; -import org.opengroup.osdu.core.common.model.legal.LegalCompliance; -import org.opengroup.osdu.core.common.model.legal.jobs.LegalTagConsistencyValidator; -import org.opengroup.osdu.core.common.model.storage.PubSubInfo; -import org.opengroup.osdu.core.common.model.storage.RecordMetadata; -import org.opengroup.osdu.core.common.model.storage.Schema; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory; -import org.opengroup.osdu.core.gcp.oqm.driver.OqmDriver; -import org.opengroup.osdu.core.gcp.oqm.model.OqmAckReplier; -import org.opengroup.osdu.core.gcp.oqm.model.OqmMessage; -import org.opengroup.osdu.storage.logging.StorageAuditLogger; -import org.opengroup.osdu.storage.provider.gcp.messaging.config.MessagingConfigurationProperties; -import org.opengroup.osdu.storage.provider.gcp.messaging.jobs.config.PullConfigStub; -import org.opengroup.osdu.storage.provider.gcp.messaging.jobs.stub.OqmPubSubStub; -import org.opengroup.osdu.storage.provider.gcp.messaging.scope.override.ThreadDpsHeaders; -import org.opengroup.osdu.storage.provider.gcp.messaging.thread.ThreadScopeContextHolder; -import org.opengroup.osdu.storage.provider.gcp.web.cache.LegalTagMultiTenantCache; -import org.opengroup.osdu.storage.provider.gcp.web.repository.OsmRecordsMetadataRepository; -import org.opengroup.osdu.storage.service.LegalServiceImpl; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = {PullConfigStub.class}, webEnvironment = WebEnvironment.NONE, properties = {"oqmDriver=any"}) -public class MultiThreadingLegalTagChangedProcessingTest { - - private static final String FIRST_TEST_TENANT = "test"; - private static final String FIRST_TEST_PROJECT = "test.project"; - private static final String SECOND_TEST_PROJECT = "test2.project"; - private static final String SECOND_TEST_TENANT = "test2"; - private static final String FIRST_TEST_LEGALTAG = "test-dataset-tag"; - private static final String SECOND_TEST_LEGALTAG = "test2-dataset-tag"; - private static final String REASON = "LegalTag not found"; - private static final String TEST_CORRELATION = "123"; - private static final int numberOfAllRuns = 500; - private static final int numberOfTenantRuns = numberOfAllRuns / 2; - private final CountDownLatch latch = new CountDownLatch(numberOfAllRuns); - - @MockBean - private ICache<String, Groups> groupCache; - - @MockBean(name = "LegalTagCache") - private LegalTagMultiTenantCache legalTagMultiTenantCache; - - @MockBean - private ICache<String, Schema> schemaCache; - - @MockBean - private TokenProvider tokenProvider; - - @MockBean - private ITenantFactory tenantInfoFactory; - - @MockBean - private OqmAckReplier oqmAckReplier; - - @MockBean - private LegalServiceImpl legalService; - - @MockBean - private OsmRecordsMetadataRepository recordsMetadataRepository; - - @MockBean - private OqmDriver oqmDriver; - - @MockBean - private DefaultLogger iLogger; - - @MockBean - private JaxRsDpsLog jaxRsDpsLog; - - @MockBean - private StorageAuditLogger auditLogger; - - @Autowired - private OqmPubSubStub pubSubStub; - - @Autowired - private PullConfigStub pullConfigStub; - - @Autowired - private LegalTagConsistencyValidator legalTagConsistencyValidator; - - @Autowired - private LegalComplianceChangeServiceGcpImpl complianceChangeServiceGcp; - - @Autowired - private ThreadDpsHeaders threadDpsHeaders; - - @Autowired - private MessagingConfigurationProperties configurationProperties; - - @Before - public void setUp() { - configurationProperties.setStorageServiceAccountEmail("storage"); - - setUpTenants(); - - for (int i = 0; i < numberOfAllRuns; i++) { - setUpLegalServiceGetInvalidLegalTags(FIRST_TEST_LEGALTAG + i); - setUpLegalServiceGetInvalidLegalTags(SECOND_TEST_LEGALTAG + i); - setStorageRepoQueryByLegal(FIRST_TEST_LEGALTAG + i); - setStorageRepoQueryByLegal(SECOND_TEST_LEGALTAG + i); - } - } - - @Test - public void testMultithreadingMessageProcessingWithDifferentTenants() throws InterruptedException { - ExecutorService service = Executors.newFixedThreadPool(numberOfTenantRuns); - for (int i = 0; i < numberOfTenantRuns; i++) { - int finalI = i; - service.execute(() -> messageRun(FIRST_TEST_LEGALTAG + finalI, FIRST_TEST_TENANT)); - service.execute(() -> messageRun(SECOND_TEST_LEGALTAG + finalI, SECOND_TEST_TENANT)); - } - latch.await(); - - List<Map<DpsHeaders, PubSubInfo[]>> collector = pubSubStub.getCollector(); - - assertEquals(numberOfAllRuns, collector.size()); - - long firstTenantEvents = collector.stream().flatMap(entry -> entry.keySet().stream()).map(DpsHeaders::getPartitionId) - .filter(partition -> partition.equals(FIRST_TEST_TENANT)).count(); - - long secondTenantEvents = collector.stream().flatMap(entry -> entry.keySet().stream()).map(DpsHeaders::getPartitionId) - .filter(partition -> partition.equals(SECOND_TEST_TENANT)).count(); - - assertEquals(numberOfTenantRuns, firstTenantEvents); - assertEquals(numberOfTenantRuns, secondTenantEvents); - } - - private void messageRun(String legalTagName, String tenantName) { - try { - OqmMessage firstOqmMessage = new OqmMessage("1", "{\n" - + " \"statusChangedTags\": [{\n" - + " \"changedTagName\": \"" + legalTagName + "\",\n" - + " \"changedTagStatus\": \"incompliant\"\n" - + " }\n" - + " ]\n" - + "}", - ImmutableMap.of( - DpsHeaders.ACCOUNT_ID, - tenantName, - DpsHeaders.CORRELATION_ID, - TEST_CORRELATION, - DpsHeaders.DATA_PARTITION_ID, - tenantName - ) - ); - - threadDpsHeaders.setThreadContext(firstOqmMessage.getAttributes()); - LegalTagChangedProcessing legalTagChangedProcessing = - new LegalTagChangedProcessing(legalTagConsistencyValidator, complianceChangeServiceGcp, threadDpsHeaders); - - legalTagChangedProcessing.process(firstOqmMessage); - } catch (Exception e) { - System.out.println(Arrays.toString(e.getStackTrace())); - } finally { - ThreadScopeContextHolder.currentThreadScopeAttributes().clear(); - latch.countDown(); - } - } - - - private void setUpLegalServiceGetInvalidLegalTags(String legalTagName) { - InvalidTagWithReason[] firstInvalidTagWithReasons = new InvalidTagWithReason[1]; - InvalidTagWithReason invalidTagWithReason = new InvalidTagWithReason(); - invalidTagWithReason.setName(legalTagName); - invalidTagWithReason.setReason(REASON); - firstInvalidTagWithReasons[0] = invalidTagWithReason; - - when(legalService.getInvalidLegalTags(Collections.singleton(legalTagName))).thenReturn(firstInvalidTagWithReasons); - - } - - private void setStorageRepoQueryByLegal(String legalTagName) { - Legal legal = new Legal(); - legal.setLegaltags(Collections.singleton(legalTagName)); - - RecordMetadata recordMetadata = new RecordMetadata(); - recordMetadata.setId("record-id" + legalTagName); - recordMetadata.setLegal(legal); - - SimpleEntry<String, List<RecordMetadata>> mapWithValues = new SimpleEntry<>("empty", Collections.singletonList(recordMetadata)); - SimpleEntry<String, List<RecordMetadata>> emptyMap = new SimpleEntry<>("empty", Collections.emptyList()); - - when(recordsMetadataRepository.queryByLegal(legalTagName, LegalCompliance.compliant, 500)) - .thenReturn(mapWithValues) - .thenReturn(emptyMap); - - } - - private void setUpTenants() { - TenantInfo testTenant = new TenantInfo(); - testTenant.setProjectId(FIRST_TEST_PROJECT); - testTenant.setDataPartitionId(FIRST_TEST_TENANT); - testTenant.setName(FIRST_TEST_TENANT); - - TenantInfo secondTestTenant = new TenantInfo(); - secondTestTenant.setProjectId(SECOND_TEST_PROJECT); - secondTestTenant.setDataPartitionId(SECOND_TEST_TENANT); - secondTestTenant.setName(SECOND_TEST_TENANT); - - when(tenantInfoFactory.listTenantInfo()).thenReturn(ImmutableList.of(testTenant, secondTestTenant)); - } -} diff --git a/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/config/PullConfigStub.java b/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/config/PullConfigStub.java deleted file mode 100644 index f3370b505..000000000 --- a/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/config/PullConfigStub.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2020-2023 Google LLC - * Copyright 2020-2023 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.jobs.config; - -import lombok.Getter; -import org.opengroup.osdu.core.common.legal.ILegalService; -import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; -import org.opengroup.osdu.core.common.model.legal.jobs.LegalTagConsistencyValidator; -import org.opengroup.osdu.storage.provider.gcp.messaging.config.MessagingCustomContextConfiguration; -import org.opengroup.osdu.storage.provider.gcp.messaging.jobs.stub.OqmPubSubStub; -import org.opengroup.osdu.storage.provider.gcp.messaging.scope.override.ScopeModifierPostProcessor; -import org.opengroup.osdu.storage.provider.interfaces.IMessageBus; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.FilterType; -import org.springframework.test.util.ReflectionTestUtils; - -@Getter -@Configuration -@EnableConfigurationProperties -@ComponentScan(value = { - "org.opengroup.osdu.storage.provider.gcp.messaging" -}, - excludeFilters = { - @ComponentScan.Filter( - type = FilterType.ASSIGNABLE_TYPE, - value = { - MessagingCustomContextConfiguration.class - } - ) - } -) -public class PullConfigStub { - - @Bean - public IMessageBus messageBusStub() { - return new OqmPubSubStub(); - } - - @Bean - public LegalTagConsistencyValidator legalTagConsistencyValidator(ILegalService legalService, - JaxRsDpsLog jaxRsDpsLog) { - LegalTagConsistencyValidator legalTagConsistencyValidator = new LegalTagConsistencyValidator(); - ReflectionTestUtils.setField(legalTagConsistencyValidator, "legalService", legalService); - ReflectionTestUtils.setField(legalTagConsistencyValidator, "logger", jaxRsDpsLog); - return legalTagConsistencyValidator; - } - - @Bean - public BeanFactoryPostProcessor beanFactoryPostProcessor() { - return new ScopeModifierPostProcessor(); - } -} diff --git a/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/stub/OqmPubSubStub.java b/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/stub/OqmPubSubStub.java deleted file mode 100644 index 40f3c8b8b..000000000 --- a/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/messaging/jobs/stub/OqmPubSubStub.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020-2022 Google LLC - * Copyright 2020-2022 EPAM Systems, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package org.opengroup.osdu.storage.provider.gcp.messaging.jobs.stub; - -import com.google.common.collect.ImmutableMap; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import lombok.Getter; -import org.apache.commons.lang3.NotImplementedException; -import org.opengroup.osdu.core.common.model.http.CollaborationContext; -import org.opengroup.osdu.core.common.model.http.DpsHeaders; -import org.opengroup.osdu.core.common.model.storage.PubSubInfo; -import org.opengroup.osdu.storage.model.RecordChangedV2; -import org.opengroup.osdu.storage.provider.interfaces.IMessageBus; - -@Getter -public class OqmPubSubStub implements IMessageBus { - - private final List<Map<DpsHeaders, PubSubInfo[]>> collector = new ArrayList<>(); - - @Override - public synchronized void publishMessage(DpsHeaders headers, PubSubInfo... messages) { - collector.add(ImmutableMap.of(DpsHeaders.createFromMap(headers.getHeaders()), messages)); - } - - @Override - public void publishMessage(Optional<CollaborationContext> collaborationContext, DpsHeaders headers, RecordChangedV2... messages) { - throw new NotImplementedException(); - } - - @Override - public void publishMessage(DpsHeaders headers, Map<String, String> routingInfo, List<?> messageList) { - throw new NotImplementedException(); - } - - @Override - public void publishMessage(DpsHeaders headers, Map<String, String> routingInfo, PubSubInfo... messages) { - throw new NotImplementedException(); - } -} diff --git a/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/web/middleware/GcpExceptionMapperTest.java b/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/web/middleware/GcpExceptionMapperTest.java deleted file mode 100644 index e54a7bd1a..000000000 --- a/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/web/middleware/GcpExceptionMapperTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.opengroup.osdu.storage.provider.gcp.web.middleware; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.when; -import static org.springframework.http.HttpStatus.FORBIDDEN; - -import com.google.cloud.storage.StorageException; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import org.opengroup.osdu.core.common.model.http.AppError; -import org.opengroup.osdu.storage.util.GlobalExceptionMapper; -import org.springframework.http.ResponseEntity; - -@RunWith(MockitoJUnitRunner.class) -public class GcpExceptionMapperTest { - - @InjectMocks - private GcpExceptionMapper sut; - - @Mock - private GlobalExceptionMapper mapper; - - @Test - public void handleStorageExceptionShouldReturnForbiddenResponseWhenCatchesStorageException() { - StorageException exception = new StorageException(403, "Access Denied"); - AppError expectedBody = new AppError(FORBIDDEN.value(), - "Access Denied", "The user is not authorized to perform this action"); - when(mapper.getErrorResponse(ArgumentMatchers .argThat( - e -> StorageException.class == e.getOriginalException().getClass()))) - .thenReturn(new ResponseEntity<>(expectedBody, FORBIDDEN)); - - ResponseEntity<Object> response = sut.handleStorageException(exception); - - assertThat(response.getStatusCodeValue(), is(FORBIDDEN.value())); - assertThat(response.getBody(), is(expectedBody)); - } -} diff --git a/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/web/repository/ObmStorageTest.java b/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/web/repository/ObmStorageTest.java deleted file mode 100644 index bd1930014..000000000 --- a/provider/storage-gc/src/test/java/org/opengroup/osdu/storage/provider/gcp/web/repository/ObmStorageTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.opengroup.osdu.storage.provider.gcp.web.repository; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.common.partition.PartitionPropertyResolver; -import org.opengroup.osdu.core.gcp.obm.driver.Driver; -import org.opengroup.osdu.storage.provider.gcp.web.config.PartitionPropertyNames; - -@ExtendWith(MockitoExtension.class) -class ObmStorageTest { - - private static final String PARTITION_ID = "dummyPartitionID"; - private static final String BUCKET_NAME = "dummy_bucket"; - private static final List<String> VERSION_PATHS = Arrays.asList("versionPath1", "versionPath2"); - - @InjectMocks - private ObmStorage storage; - - @Mock - private Driver storageDriver; - - @Mock - private PartitionPropertyNames partitionPropertyNames; - - @Mock - private TenantInfo tenantInfo; - - @Mock - private PartitionPropertyResolver partitionPropertyResolver; - - - @Test - void deleteSeveralVersions() { - when(partitionPropertyNames.getStorageBucketName()).thenReturn(BUCKET_NAME); - when(tenantInfo.getDataPartitionId()).thenReturn(PARTITION_ID); - - storage.deleteVersions(VERSION_PATHS); - - VERSION_PATHS.forEach(versionPath -> - verify(storageDriver, times(1)) - .deleteBlob(any() , eq(versionPath), any())); - } -} diff --git a/testing/storage-test-gc/src/test/resources/test.properties b/testing/storage-test-gc/src/test/resources/test.properties index 4e97497f4..4fd2b8175 100644 --- a/testing/storage-test-gc/src/test/resources/test.properties +++ b/testing/storage-test-gc/src/test/resources/test.properties @@ -1,2 +1,2 @@ enableEncodedSpecialCharactersInURL=true -opa.integration.enabled=true +opa.integration.enabled=false -- GitLab