diff --git a/.github/workflows/cypress-integration-tests-postgresql.yml b/.github/workflows/cypress-integration-tests-postgresql.yml
index 5ad614d01369..408488cf1ddf 100644
--- a/.github/workflows/cypress-integration-tests-postgresql.yml
+++ b/.github/workflows/cypress-integration-tests-postgresql.yml
@@ -32,10 +32,6 @@ concurrency:
jobs:
cypress-ci-postgresql:
runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- matrix:
- job: [0, 1, 2]
environment: test
steps:
- name: Free Disk Space (Ubuntu)
diff --git a/.github/workflows/openmetadata-airflow-apis.yml b/.github/workflows/openmetadata-airflow-apis.yml
index 13f887d984fc..f87348ce8bb3 100644
--- a/.github/workflows/openmetadata-airflow-apis.yml
+++ b/.github/workflows/openmetadata-airflow-apis.yml
@@ -34,6 +34,6 @@ jobs:
run: |
make install_dev install_apis
cd openmetadata-airflow-apis; \
- python setup.py build sdist bdist_wheel; \
+ python -m build; \
twine check dist/*; \
twine upload dist/* --verbose
diff --git a/.github/workflows/py-cli-e2e-tests.yml b/.github/workflows/py-cli-e2e-tests.yml
index ea13b84bcaff..e9eca681bca3 100644
--- a/.github/workflows/py-cli-e2e-tests.yml
+++ b/.github/workflows/py-cli-e2e-tests.yml
@@ -25,7 +25,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- e2e-test: ['bigquery', 'dbt_redshift', 'metabase', 'mssql', 'mysql', 'redash', 'snowflake', 'tableau', 'powerbi', 'vertica', 'python', 'redshift', 'hive', 'quicksight', 'datalake_s3', 'postgres', 'oracle', 'athena', 'bigquery_multiple_project']
+ e2e-test: ['bigquery', 'dbt_redshift', 'metabase', 'mssql', 'mysql', 'redash', 'snowflake', 'tableau', 'powerbi', 'vertica', 'python', 'redshift', 'quicksight', 'datalake_s3', 'postgres', 'oracle', 'athena', 'bigquery_multiple_project']
environment: test
steps:
diff --git a/.github/workflows/py-ingestion-core-publish.yml b/.github/workflows/py-ingestion-core-publish.yml
deleted file mode 100644
index 9f840e5161f8..000000000000
--- a/.github/workflows/py-ingestion-core-publish.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright 2021 Collate
-# 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.
-
-# When a new push happens to the main branch that
-# modifies the JSON Schemas, we are going to
-# generate the updated pydantic models and
-# publish a new version of openmetadata-core
-
-name: Publish openmetadata-ingestion-core packages
-
-on:
- workflow_dispatch:
-
-concurrency:
- group: py-ingestion-core-publish-${{ github.head_ref || github.run_id }}
- cancel-in-progress: true
-jobs:
- py-core-build-and-push:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - name: Set up Python 3.9
- uses: actions/setup-python@v4
- with:
- python-version: 3.9
- - name: Install Ubuntu related dependencies
- run: |
- sudo apt-get update && sudo apt-get install -y libsasl2-dev unixodbc-dev python3-venv
- - name: Install, Generate and Publish Test PyPi packages
- env:
- TWINE_USERNAME: ${{ secrets.TWINE_USERNAME_TEST }}
- TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD_TEST }}
- run: |
- python3 -m venv env
- source env/bin/activate
- sudo make install_antlr_cli
- make install_dev generate install
- cd ingestion-core; \
- python setup.py build sdist bdist_wheel; \
- twine check dist/*; \
- twine upload dist/* --verbose
diff --git a/.github/workflows/py-ingestion-publish.yml b/.github/workflows/py-ingestion-publish.yml
index dd4567460881..7838e25c20b8 100644
--- a/.github/workflows/py-ingestion-publish.yml
+++ b/.github/workflows/py-ingestion-publish.yml
@@ -37,6 +37,6 @@ jobs:
sudo make install_antlr_cli
make install_dev generate install
cd ingestion; \
- python setup.py build sdist bdist_wheel; \
+ python -m build; \
twine check dist/*; \
twine upload dist/* --verbose
diff --git a/Makefile b/Makefile
index 3bf028852878..9c16def705eb 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ include ingestion/Makefile
.PHONY: help
help:
- @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[35m%-30s\033[0m %s\n", $$1, $$2}'
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":"}; {printf "\033[35m%-35s\033[0m %s\n", $$2, $$3}'
.PHONY: install_e2e_tests
install_e2e_tests: ## Install the ingestion module with e2e test dependencies (playwright)
@@ -24,40 +24,6 @@ yarn_install_cache: ## Use Yarn to install UI dependencies
yarn_start_dev_ui: ## Run the UI locally with Yarn
cd openmetadata-ui/src/main/resources/ui && yarn start
-## Ingestion Core
-.PHONY: core_install_dev
-core_install_dev: ## Prepare a venv for the ingestion-core module
- cd ingestion-core; \
- rm -rf venv; \
- python3 -m venv venv; \
- . venv/bin/activate; \
- python3 -m pip install ".[dev]"
-
-.PHONY: core_clean
-core_clean: ## Clean the ingestion-core generated files
- rm -rf ingestion-core/src/metadata/generated
- rm -rf ingestion-core/build
- rm -rf ingestion-core/dist
-
-.PHONY: core_generate
-core_generate: ## Generate the pydantic models from the JSON Schemas to the ingestion-core module
- $(MAKE) core_install_dev
- mkdir -p ingestion-core/src/metadata/generated; \
- . ingestion-core/venv/bin/activate; \
- datamodel-codegen --input openmetadata-spec/src/main/resources/json/schema --input-file-type jsonschema --output ingestion-core/src/metadata/generated/schema
- $(MAKE) core_py_antlr
-
-.PHONY: core_bump_version_dev
-core_bump_version_dev: ## Bump a `dev` version to the ingestion-core module. To be used when schemas are updated
- $(MAKE) core_install_dev
- cd ingestion-core; \
- . venv/bin/activate; \
- python -m incremental.update metadata --dev
-
-.PHONY: core_py_antlr
-core_py_antlr: ## Generate the Python core code for parsing FQNs under ingestion-core
- antlr4 -Dlanguage=Python3 -o ingestion-core/src/metadata/generated/antlr ${PWD}/openmetadata-spec/src/main/antlr4/org/openmetadata/schema/*.g4
-
.PHONY: py_antlr
py_antlr: ## Generate the Python code for parsing FQNs
antlr4 -Dlanguage=Python3 -o ingestion/src/metadata/generated/antlr ${PWD}/openmetadata-spec/src/main/antlr4/org/openmetadata/schema/*.g4
@@ -103,8 +69,8 @@ SNYK_ARGS := --severity-threshold=high
.PHONY: snyk-ingestion-report
snyk-ingestion-report: ## Uses Snyk CLI to validate the ingestion code and container. Don't stop the execution
@echo "Validating Ingestion container..."
- docker build -t openmetadata-ingestion:scan -f ingestion/Dockerfile .
- snyk container test openmetadata-ingestion:scan --file=ingestion/Dockerfile $(SNYK_ARGS) --json > security-report/ingestion-docker-scan.json | true;
+ docker build -t openmetadata-ingestion:scan -f ingestion/Dockerfile.ci .
+ snyk container test openmetadata-ingestion:scan --file=ingestion/Dockerfile.ci $(SNYK_ARGS) --json > security-report/ingestion-docker-scan.json | true;
@echo "Validating ALL ingestion dependencies. Make sure the venv is activated."
cd ingestion; \
pip freeze > scan-requirements.txt; \
@@ -171,7 +137,7 @@ generate-schema-docs: ## Generates markdown files for documenting the JSON Sche
#Upgrade release automation scripts below
.PHONY: update_all
-update_all: ## To update all the release related files run make update_all RELEASE_VERSION=2.2.2 PY_RELEASE_VERSION=2.2.2.2
+update_all: ## To update all the release related files run make update_all RELEASE_VERSION=2.2.2 PY_RELEASE_VERSION=2.2.2.2
@echo "The release version is: $(RELEASE_VERSION)" ; \
echo "The python metadata release version: $(PY_RELEASE_VERSION)" ; \
$(MAKE) update_maven ; \
@@ -184,7 +150,7 @@ update_all: ## To update all the release related files run make update_all RELEA
#make update_all RELEASE_VERSION=2.2.2 PY_RELEASE_VERSION=2.2.2.2
.PHONY: update_maven
-update_maven: ## To update the common and pom.xml maven version
+update_maven: ## To update the common and pom.xml maven version
@echo "Updating Maven projects to version $(RELEASE_VERSION)..."; \
mvn versions:set -DnewVersion=$(RELEASE_VERSION)
#remove comment and use the below section when want to use this sub module "update_maven" independently to update github actions
@@ -192,7 +158,7 @@ update_maven: ## To update the common and pom.xml maven version
.PHONY: update_github_action_paths
-update_github_action_paths: ## To update the github action ci docker files
+update_github_action_paths: ## To update the github action ci docker files
@echo "Updating docker github action release version to $(RELEASE_VERSION)... "; \
file_paths="docker/docker-compose-quickstart/Dockerfile \
.github/workflows/docker-openmetadata-db.yml \
@@ -212,7 +178,7 @@ update_github_action_paths: ## To update the github action ci docker files
#make update_github_action_paths RELEASE_VERSION=2.2.2
.PHONY: update_python_release_paths
-update_python_release_paths: ## To update the setup.py files
+update_python_release_paths: ## To update the setup.py files
file_paths="ingestion/setup.py \
openmetadata-airflow-apis/setup.py"; \
echo "Updating Python setup file versions to $(PY_RELEASE_VERSION)... "; \
@@ -223,7 +189,7 @@ update_python_release_paths: ## To update the setup.py files
#make update_python_release_paths PY_RELEASE_VERSION=2.2.2.2
.PHONY: update_dockerfile_version
-update_dockerfile_version: ## To update the dockerfiles version
+update_dockerfile_version: ## To update the dockerfiles version
@file_paths="docker/docker-compose-ingestion/docker-compose-ingestion.yml \
docker/docker-compose-openmetadata/docker-compose-openmetadata.yml \
docker/docker-compose-quickstart/docker-compose-postgres.yml \
@@ -236,7 +202,7 @@ update_dockerfile_version: ## To update the dockerfiles version
#make update_dockerfile_version RELEASE_VERSION=2.2.2
.PHONY: update_ingestion_dockerfile_version
-update_ingestion_dockerfile_version: ## To update the ingestion dockerfiles version
+update_ingestion_dockerfile_version: ## To update the ingestion dockerfiles version
@file_paths="ingestion/Dockerfile \
ingestion/operators/docker/Dockerfile"; \
echo "Updating ingestion dockerfile release version to $(PY_RELEASE_VERSION)... "; \
diff --git a/bootstrap/sql/migrations/native/1.2.3/mysql/postDataMigrationSQLScript.sql b/bootstrap/sql/migrations/native/1.2.3/mysql/postDataMigrationSQLScript.sql
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/bootstrap/sql/migrations/native/1.2.3/mysql/schemaChanges.sql b/bootstrap/sql/migrations/native/1.2.3/mysql/schemaChanges.sql
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/bootstrap/sql/migrations/native/1.2.3/postgres/postDataMigrationSQLScript.sql b/bootstrap/sql/migrations/native/1.2.3/postgres/postDataMigrationSQLScript.sql
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/bootstrap/sql/migrations/native/1.2.3/postgres/schemaChanges.sql b/bootstrap/sql/migrations/native/1.2.3/postgres/schemaChanges.sql
new file mode 100644
index 000000000000..399e5d62f61d
--- /dev/null
+++ b/bootstrap/sql/migrations/native/1.2.3/postgres/schemaChanges.sql
@@ -0,0 +1,12 @@
+
+-- fixed Query for updating viewParsingTimeoutLimit
+UPDATE ingestion_pipeline_entity
+SET json = jsonb_set(
+ json::jsonb #- '{sourceConfig,config,viewParsingTimeoutLimit}',
+ '{sourceConfig,config,queryParsingTimeoutLimit}',
+ (json #> '{sourceConfig,config,viewParsingTimeoutLimit}')::jsonb,
+ true
+)
+WHERE json #>> '{pipelineType}' = 'metadata'
+AND json #>> '{sourceConfig,config,type}' = 'DatabaseMetadata'
+AND json #>> '{sourceConfig,config,viewParsingTimeoutLimit}' is not null;
diff --git a/bootstrap/sql/migrations/native/1.3.0/mysql/postDataMigrationSQLScript.sql b/bootstrap/sql/migrations/native/1.3.0/mysql/postDataMigrationSQLScript.sql
new file mode 100644
index 000000000000..e66612d8f5fa
--- /dev/null
+++ b/bootstrap/sql/migrations/native/1.3.0/mysql/postDataMigrationSQLScript.sql
@@ -0,0 +1,8 @@
+-- Rename customMetricsProfile to customMetrics
+UPDATE profiler_data_time_series
+SET json = REPLACE(json, '"customMetricsProfile"', '"customMetrics"');
+
+-- Delete customMetricsProfile from entity_extension
+-- This was not supported on the processing side before 1.3.
+DELETE FROM openmetadata_db.entity_extension ee
+where extension like '%customMetrics';
\ No newline at end of file
diff --git a/bootstrap/sql/migrations/native/1.3.0/postgres/postDataMigrationSQLScript.sql b/bootstrap/sql/migrations/native/1.3.0/postgres/postDataMigrationSQLScript.sql
new file mode 100644
index 000000000000..6d65e5f77057
--- /dev/null
+++ b/bootstrap/sql/migrations/native/1.3.0/postgres/postDataMigrationSQLScript.sql
@@ -0,0 +1,8 @@
+-- Rename customMetricsProfile to customMetrics
+UPDATE profiler_data_time_series
+SET json = REPLACE(json::text, '"customMetricsProfile"', '"customMetrics"')::jsonb;
+
+-- Delete customMetricsProfile from entity_extension
+-- This was not supported on the processing side before 1.3.
+DELETE FROM entity_extension ee
+where extension like '%customMetrics';
\ No newline at end of file
diff --git a/conf/openmetadata.yaml b/conf/openmetadata.yaml
index 2fa33e0991d4..839d362906e2 100644
--- a/conf/openmetadata.yaml
+++ b/conf/openmetadata.yaml
@@ -144,6 +144,8 @@ authorizerConfiguration:
authenticationConfiguration:
provider: ${AUTHENTICATION_PROVIDER:-basic}
+ # This is used by auth provider provide response as either id_token or code
+ responseType: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
# This will only be valid when provider type specified is customOidc
providerName: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
publicKeyUrls: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
diff --git a/docker/development/docker-compose-postgres.yml b/docker/development/docker-compose-postgres.yml
index ded3943fc559..cb3cab7a02d2 100644
--- a/docker/development/docker-compose-postgres.yml
+++ b/docker/development/docker-compose-postgres.yml
@@ -85,6 +85,7 @@ services:
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-basic}
+ AUTHENTICATION_RESPONSE_TYPE: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
@@ -230,6 +231,7 @@ services:
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-basic}
+ AUTHENTICATION_RESPONSE_TYPE: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
diff --git a/docker/development/docker-compose.yml b/docker/development/docker-compose.yml
index 42840e2ba9f0..d398a774bd78 100644
--- a/docker/development/docker-compose.yml
+++ b/docker/development/docker-compose.yml
@@ -84,6 +84,7 @@ services:
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-basic}
+ AUTHENTICATION_RESPONSE_TYPE: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
@@ -231,6 +232,7 @@ services:
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-basic}
+ AUTHENTICATION_RESPONSE_TYPE: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
diff --git a/docker/docker-compose-openmetadata/docker-compose-openmetadata.yml b/docker/docker-compose-openmetadata/docker-compose-openmetadata.yml
index 7c93ef4230a9..2b6858cc126a 100644
--- a/docker/docker-compose-openmetadata/docker-compose-openmetadata.yml
+++ b/docker/docker-compose-openmetadata/docker-compose-openmetadata.yml
@@ -34,6 +34,7 @@ services:
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-basic}
+ AUTHENTICATION_RESPONSE_TYPE: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
@@ -175,6 +176,7 @@ services:
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-basic}
+ AUTHENTICATION_RESPONSE_TYPE: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
diff --git a/docker/docker-compose-openmetadata/env-mysql b/docker/docker-compose-openmetadata/env-mysql
index e7524f9bebb2..82daf618565c 100644
--- a/docker/docker-compose-openmetadata/env-mysql
+++ b/docker/docker-compose-openmetadata/env-mysql
@@ -16,6 +16,7 @@ AUTHORIZER_PRINCIPAL_DOMAIN="openmetadata.org"
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN="false"
AUTHORIZER_ENABLE_SECURE_SOCKET="false"
AUTHENTICATION_PROVIDER="basic"
+AUTHENTICATION_RESPONSE_TYPE="id_token"
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME=""
AUTHENTICATION_PUBLIC_KEYS=[http://localhost:8585/api/v1/system/config/jwks]
AUTHENTICATION_AUTHORITY="https://accounts.google.com"
diff --git a/docker/docker-compose-openmetadata/env-postgres b/docker/docker-compose-openmetadata/env-postgres
index 1ca2d5c3d723..db9df1a9a67a 100644
--- a/docker/docker-compose-openmetadata/env-postgres
+++ b/docker/docker-compose-openmetadata/env-postgres
@@ -16,6 +16,7 @@ AUTHORIZER_PRINCIPAL_DOMAIN="openmetadata.org"
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN="false"
AUTHORIZER_ENABLE_SECURE_SOCKET="false"
AUTHENTICATION_PROVIDER="basic"
+AUTHENTICATION_RESPONSE_TYPE:"id_token"
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME=""
AUTHENTICATION_PUBLIC_KEYS=[http://localhost:8585/api/v1/system/config/jwks]
AUTHENTICATION_AUTHORITY="https://accounts.google.com"
diff --git a/docker/docker-compose-quickstart/docker-compose-postgres.yml b/docker/docker-compose-quickstart/docker-compose-postgres.yml
index 6e5c76fa6b85..97da1f7632f5 100644
--- a/docker/docker-compose-quickstart/docker-compose-postgres.yml
+++ b/docker/docker-compose-quickstart/docker-compose-postgres.yml
@@ -77,6 +77,7 @@ services:
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-basic}
+ AUTHENTICATION_RESPONSE_TYPE: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
@@ -219,6 +220,7 @@ services:
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-basic}
+ AUTHENTICATION_RESPONSE_TYPE: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
diff --git a/docker/docker-compose-quickstart/docker-compose.yml b/docker/docker-compose-quickstart/docker-compose.yml
index 1c6ebc413062..8fa6c340f895 100644
--- a/docker/docker-compose-quickstart/docker-compose.yml
+++ b/docker/docker-compose-quickstart/docker-compose.yml
@@ -75,6 +75,7 @@ services:
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-basic}
+ AUTHENTICATION_RESPONSE_TYPE: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
@@ -217,6 +218,7 @@ services:
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-basic}
+ AUTHENTICATION_RESPONSE_TYPE: ${AUTHENTICATION_RESPONSE_TYPE:-id_token}
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEYS:-[http://localhost:8585/api/v1/system/config/jwks]}
AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
diff --git a/ingestion-core/README.md b/ingestion-core/README.md
deleted file mode 100644
index 9080a188d0c1..000000000000
--- a/ingestion-core/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-This guide will help you set up OpenMetadata Core Models
----
-
-
-
-These models are `pydantic` models automatically generated from the
-central JSON Schemas that define our APIs and Entities.
-
-**Prerequisites**
-
-- Python >= 3.8.x
-
-### Docs
-
-Please refer to the documentation here https://docs.open-metadata.org/openmetadata/connectors
-
-### Contribution
-
-In order to contribute to this package:
-
-```bash
-cd ingestion-core
-python -m virtualenv venv
-source venv/bin/activate
-python -m pip install ".[dev]"
-```
-
-> OBS: During development we might need to treat this in a different
- virtual environment if we are yet to update the reference to the core
- package in `openmetadata-ingestion`.
diff --git a/ingestion-core/setup.py b/ingestion-core/setup.py
deleted file mode 100644
index c8e5dab39be7..000000000000
--- a/ingestion-core/setup.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright 2021 Collate
-# 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.
-import os
-
-from setuptools import find_namespace_packages, setup
-
-
-def get_long_description():
- root = os.path.dirname(__file__)
- with open(os.path.join(root, "README.md")) as f:
- description = f.read()
- return description
-
-
-dev = {
- "datamodel-code-generator==0.13.0",
- "black==21.12b0",
- "incremental",
- "twine",
- "twisted",
- "wheel",
- "click",
- "pydantic[email]==1.9.0",
-}
-
-setup(
- name="openmetadata-ingestion-core",
- url="https://open-metadata.org/",
- author="OpenMetadata Committers",
- license="Apache License 2.0",
- description="These are the generated Python classes from JSON Schema",
- long_description=get_long_description(),
- long_description_content_type="text/markdown",
- python_requires=">=3.7",
- package_dir={"": "src"},
- zip_safe=False,
- use_incremental=True,
- setup_requires=["incremental"],
- install_requires=["incremental"],
- project_urls={
- "Documentation": "https://docs.open-metadata.org/",
- "Source": "https://github.com/open-metadata/OpenMetadata",
- },
- packages=find_namespace_packages(where="./src", exclude=["tests*"]),
- extras_require={
- "dev": list(dev),
- },
-)
diff --git a/ingestion-core/src/metadata/_version.py b/ingestion-core/src/metadata/_version.py
deleted file mode 100644
index 140659dbc491..000000000000
--- a/ingestion-core/src/metadata/_version.py
+++ /dev/null
@@ -1,11 +0,0 @@
-"""
-Provides metadata version information.
-"""
-
-# This file is auto-generated! Do not edit!
-# Use `python -m incremental.update metadata` to change this file.
-
-from incremental import Version
-
-__version__ = Version("metadata", 0, 12, 0, dev=20)
-__all__ = ["__version__"]
diff --git a/ingestion/.coveragerc b/ingestion/.coveragerc
deleted file mode 100644
index 0d6a5c99fdf2..000000000000
--- a/ingestion/.coveragerc
+++ /dev/null
@@ -1,11 +0,0 @@
-[run]
-source = env/lib/python3.9/site-packages/metadata
-relative_files = True
-branch = True
-[report]
-omit =
- *__init__*
- */generated/*
- tests/*
- ingestion/src/*
- */src/metadata/ingestion/source/database/sample_*
\ No newline at end of file
diff --git a/ingestion/Makefile b/ingestion/Makefile
index 6d57e471f3b8..41f181406229 100644
--- a/ingestion/Makefile
+++ b/ingestion/Makefile
@@ -30,8 +30,8 @@ install_apis: ## Install the REST APIs module to the current environment
python -m pip install $(ROOT_DIR)/openmetadata-airflow-apis/
.PHONY: lint
-lint: ## Run pylint on the Python sources to analyze the codebase
- PYTHONPATH="${PYTHONPATH}:$(INGESTION_DIR)/plugins" find $(PY_SOURCE) -path $(PY_SOURCE)/metadata/generated -prune -false -o -type f -name "*.py" | xargs pylint
+lint: ## Run pylint on the Python sources to analyze the codebase
+ PYTHONPATH="${PYTHONPATH}:$(INGESTION_DIR)/plugins" find $(PY_SOURCE) -path $(PY_SOURCE)/metadata/generated -prune -false -o -type f -name "*.py" | xargs pylint --rcfile=$(INGESTION_DIR)/pyproject.toml
.PHONY: precommit_install
precommit_install: ## Install the project's precommit hooks from .pre-commit-config.yaml
@@ -41,32 +41,32 @@ precommit_install: ## Install the project's precommit hooks from .pre-commit-co
.PHONY: py_format
py_format: ## Run black and isort to format the Python codebase
- pycln $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --extend-exclude $(PY_SOURCE)/metadata/generated --all
- isort $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --skip $(PY_SOURCE)/metadata/generated --skip $(INGESTION_DIR)/env --skip $(INGESTION_DIR)/build --skip $(ROOT_DIR)/openmetadata-airflow-apis/build --profile black --multi-line 3
- black $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --extend-exclude $(PY_SOURCE)/metadata/generated
+ pycln $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --config $(INGESTION_DIR)/pyproject.toml
+ isort $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --settings-file $(INGESTION_DIR)/pyproject.toml
+ black $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --config $(INGESTION_DIR)/pyproject.toml
.PHONY: py_format_check
py_format_check: ## Check if Python sources are correctly formatted
- pycln $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --diff --extend-exclude $(PY_SOURCE)/metadata/generated --all
- isort --check-only $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --skip $(PY_SOURCE)/metadata/generated --skip $(INGESTION_DIR)/build --skip $(ROOT_DIR)/openmetadata-airflow-apis/build --profile black --multi-line 3
- black --check --diff $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --extend-exclude $(PY_SOURCE)/metadata/generated
- PYTHONPATH="${PYTHONPATH}:$(INGESTION_DIR)/plugins" pylint --fail-under=10 $(PY_SOURCE)/metadata --ignore-paths $(PY_SOURCE)/metadata/generated || (echo "PyLint error code $$?"; exit 1)
+ pycln $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --diff --config $(INGESTION_DIR)/pyproject.toml
+ isort --check-only $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --settings-file $(INGESTION_DIR)/pyproject.toml
+ black --check --diff $(INGESTION_DIR)/ $(ROOT_DIR)/openmetadata-airflow-apis/ --config $(INGESTION_DIR)/pyproject.toml
+ PYTHONPATH="${PYTHONPATH}:$(INGESTION_DIR)/plugins" pylint --rcfile=$(INGESTION_DIR)/pyproject.toml --fail-under=10 $(PY_SOURCE)/metadata --ignore-paths $(PY_SOURCE)/metadata/generated || (echo "PyLint error code $$?"; exit 1)
.PHONY: unit_ingestion
unit_ingestion: ## Run Python unit tests
- coverage run --rcfile $(INGESTION_DIR)/.coveragerc -a --branch -m pytest -c $(INGESTION_DIR)/setup.cfg --junitxml=$(INGESTION_DIR)/junit/test-results-unit.xml --ignore=$(INGESTION_DIR)/tests/unit/source $(INGESTION_DIR)/tests/unit
+ coverage run --rcfile $(INGESTION_DIR)/pyproject.toml -a --branch -m pytest -c $(INGESTION_DIR)/pyproject.toml --junitxml=$(INGESTION_DIR)/junit/test-results-unit.xml --ignore=$(INGESTION_DIR)/tests/unit/source $(INGESTION_DIR)/tests/unit
## Ingestion tests & QA
.PHONY: run_ometa_integration_tests
run_ometa_integration_tests: ## Run Python integration tests
- coverage run --rcfile $(INGESTION_DIR)/.coveragerc -a --branch -m pytest -c $(INGESTION_DIR)/setup.cfg --junitxml=$(INGESTION_DIR)/junit/test-results-integration.xml $(INGESTION_DIR)/tests/integration/ometa $(INGESTION_DIR)/tests/integration/orm_profiler $(INGESTION_DIR)/tests/integration/test_suite $(INGESTION_DIR)/tests/integration/data_insight $(INGESTION_DIR)/tests/integration/lineage
+ coverage run --rcfile $(INGESTION_DIR)/pyproject.toml -a --branch -m pytest -c $(INGESTION_DIR)/pyproject.toml --junitxml=$(INGESTION_DIR)/junit/test-results-integration.xml $(INGESTION_DIR)/tests/integration/ometa $(INGESTION_DIR)/tests/integration/orm_profiler $(INGESTION_DIR)/tests/integration/test_suite $(INGESTION_DIR)/tests/integration/data_insight $(INGESTION_DIR)/tests/integration/lineage
.PHONY: run_python_tests
run_python_tests: ## Run all Python tests with coverage
coverage erase
$(MAKE) unit_ingestion
$(MAKE) run_ometa_integration_tests
- coverage report --rcfile $(INGESTION_DIR)/.coveragerc || true
+ coverage report --rcfile $(INGESTION_DIR)/pyproject.toml || true
.PHONY: sonar_ingestion
sonar_ingestion: ## Run the Sonar analysis based on the tests results and push it to SonarCloud
@@ -82,20 +82,17 @@ sonar_ingestion: ## Run the Sonar analysis based on the tests results and push
.PHONY: run_apis_tests
run_apis_tests: ## Run the openmetadata airflow apis tests
coverage erase
- coverage run --rcfile $(ROOT_DIR)/openmetadata-airflow-apis/.coveragerc -a --branch -m pytest --junitxml=$(ROOT_DIR)/openmetadata-airflow-apis/junit/test-results.xml $(ROOT_DIR)/openmetadata-airflow-apis/tests
- coverage report --rcfile $(ROOT_DIR)/openmetadata-airflow-apis/.coveragerc
-
+ coverage run --rcfile $(ROOT_DIR)/openmetadata-airflow-apis/pyproject.toml -a --branch -m pytest -c $(INGESTION_DIR)/pyproject.toml --junitxml=$(ROOT_DIR)/openmetadata-airflow-apis/junit/test-results.xml $(ROOT_DIR)/openmetadata-airflow-apis/tests
+ coverage report --rcfile $(ROOT_DIR)/openmetadata-airflow-apis/pyproject.toml
.PHONY: coverage_apis
coverage_apis: ## Run the python tests on openmetadata-airflow-apis
$(MAKE) run_apis_tests
- coverage xml --rcfile $(ROOT_DIR)/openmetadata-airflow-apis/.coveragerc -o $(ROOT_DIR)/openmetadata-airflow-apis/coverage.xml
+ coverage xml --rcfile $(ROOT_DIR)/openmetadata-airflow-apis/pyproject.toml -o $(ROOT_DIR)/openmetadata-airflow-apis/coverage.xml
sed -e "s/$(shell python -c "import site; import os; from pathlib import Path; print(os.path.relpath(site.getsitepackages()[0], str(Path.cwd())).replace('/','\/'))")\///g" $(ROOT_DIR)/openmetadata-airflow-apis/coverage.xml >> $(ROOT_DIR)/openmetadata-airflow-apis/ci-coverage.xml
-
-
.PHONY: coverage
coverage: ## Run all Python tests and generate the coverage XML report
$(MAKE) run_python_tests
- coverage xml --rcfile $(INGESTION_DIR)/.coveragerc -o $(INGESTION_DIR)/coverage.xml || true
+ coverage xml --rcfile $(INGESTION_DIR)/pyproject.toml -o $(INGESTION_DIR)/coverage.xml || true
sed -e "s/$(shell python -c "import site; import os; from pathlib import Path; print(os.path.relpath(site.getsitepackages()[0], str(Path.cwd())).replace('/','\/'))")/src/g" $(INGESTION_DIR)/coverage.xml >> $(INGESTION_DIR)/ci-coverage.xml
diff --git a/ingestion/examples/sample_data/datasets/tables.json b/ingestion/examples/sample_data/datasets/tables.json
index acddd81788c7..98cfcbc216bd 100644
--- a/ingestion/examples/sample_data/datasets/tables.json
+++ b/ingestion/examples/sample_data/datasets/tables.json
@@ -95,7 +95,19 @@
"dataTypeDisplay": "varchar",
"description": "The ZIP or postal code. For example, 90210.",
"tags": [],
- "ordinalPosition": 10
+ "ordinalPosition": 10,
+ "customMetrics": [
+ {
+ "name": "CountOfLAZipCode",
+ "columnName": "zip",
+ "expression": "SELECT COUNT(zip) FROM dim_address WHERE zip LIKE '900%'"
+ },
+ {
+ "name": "CountOfOrangeCountyZipCode",
+ "columnName": "zip",
+ "expression": "SELECT COUNT(zip) FROM dim_address WHERE zip LIKE '92%'"
+ }
+ ]
},
{
"name": "country",
@@ -113,7 +125,14 @@
"dataTypeDisplay": "varchar",
"description": "The phone number of the customer.",
"tags": [],
- "ordinalPosition": 12
+ "ordinalPosition": 12,
+ "customMetrics": [
+ {
+ "name": "CountOfNonUsPhoneNumbers",
+ "columnName": "zip",
+ "expression": "SELECT COUNT(phone) FROM dim_address WHERE phone NOT LIKE '1%'"
+ }
+ ]
}
],
"tableConstraints": [
@@ -581,6 +600,16 @@
"timestamp": 1634366539,
"columnCount": 12,
"rowCount": 725,
+ "customMetrics": [
+ {
+ "name": "CountOfUSAddress",
+ "value": 15467
+ },
+ {
+ "name": "CountOfFRAddress",
+ "value": 1467
+ }
+ ],
"columnProfile": [
{
"name": "address_id",
@@ -650,7 +679,17 @@
"uniqueCount": 11,
"uniqueProportion": 0.1383472,
"distinctCount": 0,
- "distinctProportion": 0
+ "distinctProportion": 0,
+ "customMetrics": [
+ {
+ "name": "CountOfLAZipCode",
+ "value": 3456
+ },
+ {
+ "name": "CountOfOrangeCountyZipCode",
+ "value": 2345
+ }
+ ]
},
{
"name": "country",
@@ -674,7 +713,17 @@
"name": "sample_data.ecommerce_db.shopify",
"description": "This **mock** Schema contains tables related to shopify sales and orders with related dimension tables.",
"href": "http://localhost:8585/api/v1/databaseSchemas/d7be1e2c-b3dc-11ec-b909-0242ac120002"
- }
+ },
+ "customMetrics": [
+ {
+ "name": "CountOfUSAddress",
+ "expression": "SELECT COUNT(address_id) FROM dim_address WHERE country = 'US'"
+ },
+ {
+ "name": "CountOfFRAddress",
+ "expression": "SELECT COUNT(address_id) FROM dim_address WHERE country = 'FR'"
+ }
+ ]
},
{
"id": "1cda9ecb-f4c6-4ed4-8506-abe965b64c87",
diff --git a/ingestion/examples/sample_data/profiler/tableProfile.json b/ingestion/examples/sample_data/profiler/tableProfile.json
index b9e38d1e7358..0dea2772e7b3 100644
--- a/ingestion/examples/sample_data/profiler/tableProfile.json
+++ b/ingestion/examples/sample_data/profiler/tableProfile.json
@@ -8,6 +8,16 @@
"rowCount": 14567.0,
"sizeInByte": 16890,
"createDateTime": "2023-07-24T07:00:48.000750Z",
+ "customMetrics": [
+ {
+ "name": "CountOfUSAddress",
+ "value": 15467
+ },
+ {
+ "name": "CountOfFRAddress",
+ "value": 1467
+ }
+ ],
"columnProfile": [
{
"name": "shop_id",
@@ -151,7 +161,17 @@
"distinctProportion": 0.10,
"minLength": 6.0,
"maxLength": 156.0,
- "mean": 98.0
+ "mean": 98.0,
+ "customMetrics": [
+ {
+ "name": "CountOfLAZipCode",
+ "value": 3041
+ },
+ {
+ "name": "CountOfOrangeCountyZipCode",
+ "value": 2076
+ }
+ ]
},
{
"name": "country",
@@ -208,6 +228,16 @@
"rowCount": 13256.0,
"sizeInByte": 163290,
"createDateTime": "2023-07-24T07:00:48.000750Z",
+ "customMetrics": [
+ {
+ "name": "CountOfUSAddress",
+ "value": 15098
+ },
+ {
+ "name": "CountOfFRAddress",
+ "value": 1402
+ }
+ ],
"columnProfile": [
{
"name": "shop_id",
@@ -351,7 +381,17 @@
"distinctProportion": 0.10,
"minLength": 6.0,
"maxLength": 156.0,
- "mean": 98.0
+ "mean": 98.0,
+ "customMetrics": [
+ {
+ "name": "CountOfLAZipCode",
+ "value": 2987
+ },
+ {
+ "name": "CountOfOrangeCountyZipCode",
+ "value": 2005
+ }
+ ]
},
{
"name": "country",
@@ -408,6 +448,16 @@
"rowCount": 10256.0,
"sizeInByte": 16890,
"createDateTime": "2023-07-24T07:00:48.000750Z",
+ "customMetrics": [
+ {
+ "name": "CountOfUSAddress",
+ "value": 14998
+ },
+ {
+ "name": "CountOfFRAddress",
+ "value": 1387
+ }
+ ],
"columnProfile": [
{
"name": "shop_id",
@@ -551,7 +601,17 @@
"distinctProportion": 0.10,
"minLength": 6.0,
"maxLength": 156.0,
- "mean": 98.0
+ "mean": 98.0,
+ "customMetrics": [
+ {
+ "name": "CountOfLAZipCode",
+ "value": 3109
+ },
+ {
+ "name": "CountOfOrangeCountyZipCode",
+ "value": 2178
+ }
+ ]
},
{
"name": "country",
@@ -600,6 +660,16 @@
"rowCount": 8945.0,
"sizeInByte": 16890521,
"createDateTime": "2023-07-24T07:00:48.000750Z",
+ "customMetrics": [
+ {
+ "name": "CountOfUSAddress",
+ "value": 13458
+ },
+ {
+ "name": "CountOfFRAddress",
+ "value": 1278
+ }
+ ],
"columnProfile": [
{
"name": "shop_id",
@@ -743,7 +813,17 @@
"distinctProportion": 0.10,
"minLength": 6.0,
"maxLength": 156.0,
- "mean": 98.0
+ "mean": 98.0,
+ "customMetrics": [
+ {
+ "name": "CountOfLAZipCode",
+ "value": 3389
+ },
+ {
+ "name": "CountOfOrangeCountyZipCode",
+ "value": 2165
+ }
+ ]
},
{
"name": "country",
@@ -788,6 +868,16 @@
"rowCount": 5461.0,
"sizeInByte": 1572301627719.68,
"createDateTime": "2023-07-24T07:00:48.000750Z",
+ "customMetrics": [
+ {
+ "name": "CountOfUSAddress",
+ "value": 13092
+ },
+ {
+ "name": "CountOfFRAddress",
+ "value": 1293
+ }
+ ],
"columnProfile": [
{
"name": "shop_id",
@@ -931,7 +1021,17 @@
"distinctProportion": 0.10,
"minLength": 6.0,
"maxLength": 156.0,
- "mean": 98.0
+ "mean": 98.0,
+ "customMetrics": [
+ {
+ "name": "CountOfLAZipCode",
+ "value": 3456
+ },
+ {
+ "name": "CountOfOrangeCountyZipCode",
+ "value": 2345
+ }
+ ]
},
{
"name": "country",
diff --git a/ingestion/pyproject.toml b/ingestion/pyproject.toml
new file mode 100644
index 000000000000..37f603ea256b
--- /dev/null
+++ b/ingestion/pyproject.toml
@@ -0,0 +1,125 @@
+[build-system]
+requires = ["setuptools==69.0.2"]
+build-backend = "setuptools.build_meta"
+
+# We will keep handling dependencies in setup.py
+# since it helps us organize and isolate version management
+[project]
+name = "openmetadata-ingestion"
+version = "1.3.0.0.dev0"
+dynamic = ["readme", "dependencies", "optional-dependencies"]
+authors = [
+ {name = "OpenMetadata Committers"}
+]
+license = {file = "LICENSE"}
+description = "Ingestion Framework for OpenMetadata"
+requires-python = ">=3.8"
+
+[project.urls]
+Homepage = "https://open-metadata.org/"
+Documentation = "https://docs.open-metadata.org/"
+Source = "https://github.com/open-metadata/OpenMetadata"
+
+[tool.setuptools.dynamic]
+readme = {file = ["README.md"]}
+
+[tool.setuptools.packages.find]
+where = ["./src"]
+exclude = ["tests*"]
+namespaces = true
+
+[tool.setuptools.package-data]
+"metadata.examples" = ["workflows/*.yaml"]
+
+[project.scripts]
+metadata = "metadata.cmd:metadata"
+
+[project.entry-points.apache_airflow_provider]
+provider_info = "airflow_provider_openmetadata:get_provider_config"
+
+[tool.coverage.run]
+source = [
+ "env/lib/python3.9/site-packages/metadata"
+]
+relative_files = true
+branch = true
+
+[tool.coverage.report]
+omit = [
+ "*__init__*",
+ "*/generated/*",
+ "tests/*",
+ "ingestion/src/*",
+ "*/src/metadata/ingestion/source/database/sample_*"
+]
+
+[tool.mypy]
+mypy_path = "src"
+plugins = [
+ "sqlalchemy.ext.mypy.plugin",
+ "pydantic.mypy"
+]
+ignore_missing_imports = true
+namespace_packages = true
+strict_optional = true
+check_untyped_defs = true
+# eventually we'd like to enable these
+disallow_untyped_defs = false
+disallow_incomplete_defs = false
+
+[tool.pytest.ini_options]
+markers = [
+ "slow: marks tests as slow (deselect with '-m \"not slow\"')"
+]
+
+[tool.pylint.BASIC]
+# W1203: logging-fstring-interpolation - f-string brings better readability and unifies style
+# W1202: logging-format-interpolation - lazy formatting in logging functions
+# R0903: too-few-public-methods - False negatives in pydantic classes
+# W0707: raise-missing-from - Tends to be a false positive as exception are closely encapsulated
+# R0901: too-many-ancestors - We are already inheriting from SQA classes with a bunch of ancestors
+# W0703: broad-except - We are dealing with many different source systems, but we want to make sure workflows run until the end
+# W0511: fixme - These are internal notes and guides
+# W1518: method-cache-max-size-none - allow us to use LRU Cache with maxsize `None` to speed up certain calls
+disable = "W1203,W1202,R0903,W0707,R0901,W1201,W0703,W0511,W1518"
+
+docstring-min-length = 20
+max-args = 7
+max-attributes = 12
+
+# usual typevar naming
+good-names = "T,C,fn,db,df,i"
+module-rgx = "(([a-z_][a-z0-9_]*)|([a-zA-Z0-9]+))$"
+
+[tool.pylint.MASTER]
+fail-under = 6.0
+init-hook = "from pylint.config import find_default_config_files; import os, sys; sys.path.append(os.path.dirname(next(find_default_config_files())))"
+extension-pkg-allow-list = "pydantic"
+load-plugins = "ingestion.plugins.print_checker"
+max-public-methods = 25
+
+[tool.pylint."MESSAGES CONTROL"]
+disable = "no-name-in-module,import-error,duplicate-code"
+enable = "useless-suppression"
+
+[tool.pylint.FORMAT]
+# We all have big monitors now
+max-line-length = 120
+
+[tool.black]
+extend-exclude = "src/metadata/generated"
+
+[tool.pycln]
+all = true
+extend-exclude = "src/metadata/generated"
+
+[tool.isort]
+skip_glob = [
+ "src/metadata/generated/*",
+ "build/*",
+ "env/*",
+ "../openmetadata-airflow-apis/build/*"
+]
+profile = "black"
+indent = " "
+multi_line_output = 3
diff --git a/ingestion/setup.cfg b/ingestion/setup.cfg
deleted file mode 100644
index 34ec910e7ce6..000000000000
--- a/ingestion/setup.cfg
+++ /dev/null
@@ -1,52 +0,0 @@
-[flake8]
-# We ignore the line length issues here, since black will take care of them.
-max-line-length = 150
-max-complexity = 15
-ignore =
- # Ignore: 1 blank line required before class docstring.
- D203,
- W503
-exclude =
- .git,
- __pycache__
-per-file-ignores =
- # imported but unused
- __init__.py: F401
-[metadata]
-license_files = LICENSE
-[mypy]
-mypy_path = src
-plugins =
- sqlalchemy.ext.mypy.plugin,
- pydantic.mypy
-ignore_missing_imports = yes
-namespace_packages = true
-strict_optional = yes
-check_untyped_defs = yes
-# eventually we'd like to enable these
-disallow_untyped_defs = no
-disallow_incomplete_defs = no
-
-[isort]
-profile = black
-indent=' '
-sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
-
-[tool:pytest]
-markers =
- slow: marks tests as slow (deselect with '-m "not slow"')
-testpaths =
- tests/unit
-
-[options]
-packages = find:
-package_dir =
- =src
-
-[options.packages.find]
-where = src
-include = *
-
-[options.package_data]
-metadata.examples =
- workflows/*.yaml
diff --git a/ingestion/setup.py b/ingestion/setup.py
index c7aab12cdb14..e169ad8d180e 100644
--- a/ingestion/setup.py
+++ b/ingestion/setup.py
@@ -13,18 +13,9 @@
Python Dependencies
"""
-import os
from typing import Dict, Set
-from setuptools import find_namespace_packages, setup
-
-
-def get_long_description():
- root = os.path.dirname(__file__)
- with open(os.path.join(root, "README.md"), encoding="UTF-8") as file:
- description = file.read()
- return description
-
+from setuptools import setup
# Add here versions required for multiple plugins
VERSIONS = {
@@ -123,7 +114,6 @@ def get_long_description():
"sqlalchemy>=1.4.0,<2",
"collate-sqllineage>=1.0.4",
"tabulate==0.9.0",
- "typing-compat~=0.1.0", # compatibility requirements for 3.7
"typing_extensions<=4.5.0", # We need to have this fixed due to a yanked release 4.6.0
"typing-inspect",
"wheel~=0.38.4",
@@ -260,13 +250,14 @@ def get_long_description():
dev = {
"black==22.3.0",
- "datamodel-code-generator==0.22.0",
- "docker",
+ "datamodel-code-generator==0.24.2",
"isort",
"pre-commit",
"pycln",
"pylint~=3.0.0",
+ # For publishing
"twine",
+ "build",
}
test = {
@@ -306,34 +297,7 @@ def get_long_description():
"pytest-base-url",
}
-build_options = {"includes": ["_cffi_backend"]}
setup(
- name="openmetadata-ingestion",
- version="1.3.0.0.dev0",
- url="https://open-metadata.org/",
- author="OpenMetadata Committers",
- license="Apache License 2.0",
- description="Ingestion Framework for OpenMetadata",
- long_description=get_long_description(),
- long_description_content_type="text/markdown",
- python_requires=">=3.8",
- options={"build_exe": build_options},
- package_dir={"": "src"},
- package_data={"metadata.examples": ["workflows/*.yaml"]},
- zip_safe=False,
- dependency_links=[],
- project_urls={
- "Documentation": "https://docs.open-metadata.org/",
- "Source": "https://github.com/open-metadata/OpenMetadata",
- },
- packages=find_namespace_packages(where="./src", exclude=["tests*"]),
- namespace_package=["metadata"],
- entry_points={
- "console_scripts": ["metadata = metadata.cmd:metadata"],
- "apache_airflow_provider": [
- "provider_info = airflow_provider_openmetadata:get_provider_config"
- ],
- },
install_requires=list(base_requirements),
extras_require={
"base": list(base_requirements),
diff --git a/ingestion/src/metadata/ingestion/source/database/athena/models.py b/ingestion/src/metadata/ingestion/source/database/athena/models.py
index d833893846de..51c9403e46ae 100644
--- a/ingestion/src/metadata/ingestion/source/database/athena/models.py
+++ b/ingestion/src/metadata/ingestion/source/database/athena/models.py
@@ -39,3 +39,13 @@ class AthenaQueryExecution(BaseModel):
class AthenaQueryExecutionList(BaseModel):
QueryExecutions: Optional[List[AthenaQueryExecution]]
+
+
+class WorkGroup(BaseModel):
+ Name: Optional[str]
+ State: Optional[str]
+
+
+class WorkGroupsList(BaseModel):
+ WorkGroups: Optional[List[WorkGroup]] = []
+ NextToken: Optional[str]
diff --git a/ingestion/src/metadata/ingestion/source/database/athena/query_parser.py b/ingestion/src/metadata/ingestion/source/database/athena/query_parser.py
index a9e2bb1beaa4..725af32ca0eb 100644
--- a/ingestion/src/metadata/ingestion/source/database/athena/query_parser.py
+++ b/ingestion/src/metadata/ingestion/source/database/athena/query_parser.py
@@ -12,6 +12,7 @@
Athena Query parser module
"""
+import traceback
from abc import ABC
from math import ceil
@@ -27,6 +28,7 @@
from metadata.ingestion.source.database.athena.models import (
AthenaQueryExecutionList,
QueryExecutionIdsResponse,
+ WorkGroupsList,
)
from metadata.ingestion.source.database.query_parser_source import QueryParserSource
from metadata.utils.constants import QUERY_WITH_DBT, QUERY_WITH_OM_VERSION
@@ -36,6 +38,8 @@
ATHENA_QUERY_PAGINATOR_LIMIT = 50
+ATHENA_ENABLED_WORK_GROUP_STATE = "ENABLED"
+
class AthenaQueryParserSource(QueryParserSource, ABC):
"""
@@ -59,23 +63,67 @@ def create(cls, config_dict, metadata: OpenMetadata):
)
return cls(config, metadata)
- def get_queries(self):
- query_limit = ceil(
- self.source_config.resultLimit / ATHENA_QUERY_PAGINATOR_LIMIT
- )
- paginator = self.client.get_paginator("list_query_executions")
- paginator_response = paginator.paginate()
- for response in paginator_response:
- response_obj = QueryExecutionIdsResponse(**response)
- if response_obj.QueryExecutionIds:
- query_details_response = self.client.batch_get_query_execution(
- QueryExecutionIds=response_obj.QueryExecutionIds
+ def _get_work_group_response(self, next_token: str, is_first_call: bool = False):
+ if is_first_call:
+ return self.client.list_work_groups()
+ return self.client.list_work_groups(NextToken=next_token)
+
+ def get_work_groups(self) -> str:
+ """
+ Method to get list of names of athena work groups
+ """
+ next_token = None
+ is_first_call = True
+ try:
+ while True:
+ work_group_list = self._get_work_group_response(
+ next_token, is_first_call
)
- query_details_list = AthenaQueryExecutionList(**query_details_response)
- yield query_details_list
- query_limit -= 1
- if not query_limit:
- break
+ response_obj = WorkGroupsList(**work_group_list)
+ for work_group in response_obj.WorkGroups:
+ if (
+ work_group.State
+ and work_group.State.upper() == ATHENA_ENABLED_WORK_GROUP_STATE
+ ):
+ yield work_group.Name
+ next_token = response_obj.NextToken
+ is_first_call = False
+ if next_token is None:
+ break
+ except Exception as exc:
+ logger.debug(f"Failed to fetch work groups due to: {exc}")
+ logger.debug(traceback.format_exc())
+ if is_first_call:
+ # if it fails for the first api call, most likely due to insufficient
+ # permissions then still fetch the queries with default workgroup
+ yield None
+
+ def get_queries(self):
+ """
+ Method to fetch queries from all work groups
+ """
+ for work_group in self.get_work_groups():
+ query_limit = ceil(
+ self.source_config.resultLimit / ATHENA_QUERY_PAGINATOR_LIMIT
+ )
+ paginator = self.client.get_paginator("list_query_executions")
+ if work_group:
+ paginator_response = paginator.paginate(WorkGroup=work_group)
+ else:
+ paginator_response = paginator.paginate()
+ for response in paginator_response:
+ response_obj = QueryExecutionIdsResponse(**response)
+ if response_obj.QueryExecutionIds:
+ query_details_response = self.client.batch_get_query_execution(
+ QueryExecutionIds=response_obj.QueryExecutionIds
+ )
+ query_details_list = AthenaQueryExecutionList(
+ **query_details_response
+ )
+ yield query_details_list
+ query_limit -= 1
+ if not query_limit:
+ break
def is_not_dbt_or_om_query(self, query_text: str) -> bool:
return not (
diff --git a/ingestion/src/metadata/ingestion/source/database/athena/usage.py b/ingestion/src/metadata/ingestion/source/database/athena/usage.py
index bfeb9401b41c..edc63f28917a 100644
--- a/ingestion/src/metadata/ingestion/source/database/athena/usage.py
+++ b/ingestion/src/metadata/ingestion/source/database/athena/usage.py
@@ -11,7 +11,7 @@
"""
Athena usage module
"""
-from typing import Iterable, Optional
+from typing import Iterable
from metadata.generated.schema.type.tableQuery import TableQueries, TableQuery
from metadata.ingestion.source.database.athena.query_parser import (
@@ -32,7 +32,7 @@ class AthenaUsageSource(AthenaQueryParserSource, UsageSource):
Athena Usage Source
"""
- def yield_table_queries(self) -> Optional[Iterable[TableQuery]]:
+ def yield_table_queries(self) -> Iterable[TableQueries]:
"""
Method to yield TableQueries
"""
diff --git a/ingestion/src/metadata/ingestion/source/database/databricks/connection.py b/ingestion/src/metadata/ingestion/source/database/databricks/connection.py
index 1953e1876827..02f90c19caa0 100644
--- a/ingestion/src/metadata/ingestion/source/database/databricks/connection.py
+++ b/ingestion/src/metadata/ingestion/source/database/databricks/connection.py
@@ -17,6 +17,7 @@
from databricks.sdk import WorkspaceClient
from sqlalchemy.engine import Engine
+from sqlalchemy.exc import DatabaseError
from sqlalchemy.inspection import inspect
from metadata.generated.schema.entity.automations.workflow import (
@@ -33,7 +34,6 @@
from metadata.ingestion.connections.test_connections import (
test_connection_engine_step,
test_connection_steps,
- test_query,
)
from metadata.ingestion.ometa.ometa_api import OpenMetadata
from metadata.ingestion.source.database.databricks.client import DatabricksClient
@@ -42,6 +42,9 @@
DATABRICKS_GET_CATALOGS,
)
from metadata.utils.db_utils import get_host_from_host_port
+from metadata.utils.logger import ingestion_logger
+
+logger = ingestion_logger()
def get_connection_url(connection: DatabricksConnection) -> str:
@@ -84,6 +87,18 @@ def test_connection(
"""
client = DatabricksClient(service_connection)
+ def test_database_query(engine: Engine, statement: str):
+ """
+ Method used to execute the given query and fetch a result
+ to test if user has access to the tables specified
+ in the sql statement
+ """
+ try:
+ connection = engine.connect()
+ connection.execute(statement).fetchone()
+ except DatabaseError as soe:
+ logger.debug(f"Failed to fetch catalogs due to: {soe}")
+
if service_connection.useUnityCatalog:
table_obj = DatabricksTable()
@@ -121,7 +136,7 @@ def get_tables(connection: WorkspaceClient, table_obj: DatabricksTable):
"GetTables": inspector.get_table_names,
"GetViews": inspector.get_view_names,
"GetDatabases": partial(
- test_query,
+ test_database_query,
engine=connection,
statement=DATABRICKS_GET_CATALOGS,
),
diff --git a/ingestion/src/metadata/ingestion/source/database/databricks/legacy/metadata.py b/ingestion/src/metadata/ingestion/source/database/databricks/legacy/metadata.py
index 682de21ca40a..6d50bc9a5b71 100644
--- a/ingestion/src/metadata/ingestion/source/database/databricks/legacy/metadata.py
+++ b/ingestion/src/metadata/ingestion/source/database/databricks/legacy/metadata.py
@@ -13,11 +13,12 @@
import re
import traceback
from copy import deepcopy
-from typing import Iterable
+from typing import Iterable, Optional
from pyhive.sqlalchemy_hive import _type_map
from sqlalchemy import types, util
from sqlalchemy.engine import reflection
+from sqlalchemy.exc import DatabaseError
from sqlalchemy.inspection import inspect
from sqlalchemy.sql.sqltypes import String
from sqlalchemy_databricks._dialect import DatabricksDialect
@@ -35,10 +36,13 @@
from metadata.ingestion.source.database.column_type_parser import create_sqlalchemy_type
from metadata.ingestion.source.database.common_db_source import CommonDbSourceService
from metadata.ingestion.source.database.databricks.queries import (
+ DATABRICKS_GET_CATALOGS,
DATABRICKS_GET_TABLE_COMMENTS,
DATABRICKS_VIEW_DEFINITIONS,
)
+from metadata.ingestion.source.database.multi_db_source import MultiDBSource
from metadata.utils import fqn
+from metadata.utils.constants import DEFAULT_DATABASE
from metadata.utils.filters import filter_by_database
from metadata.utils.logger import ingestion_logger
from metadata.utils.sqlalchemy_utils import (
@@ -158,7 +162,7 @@ def get_columns(self, connection, table_name, schema=None, **kw):
@reflection.cache
def get_schema_names(self, connection, **kw): # pylint: disable=unused-argument
# Equivalent to SHOW DATABASES
- if kw.get("database"):
+ if kw.get("database") and kw.get("is_old_version") is not True:
connection.execute(f"USE CATALOG '{kw.get('database')}'")
return [row[0] for row in connection.execute("SHOW SCHEMAS")]
@@ -238,13 +242,26 @@ def get_view_definition(
reflection.Inspector.get_schema_names = get_schema_names_reflection
-class DatabricksLegacySource(CommonDbSourceService):
+class DatabricksLegacySource(CommonDbSourceService, MultiDBSource):
"""
Implements the necessary methods to extract
Database metadata from Databricks Source using
the legacy hive metastore method
"""
+ def __init__(self, config: WorkflowSource, metadata: OpenMetadata):
+ super().__init__(config, metadata)
+ self.is_older_version = False
+ self._init_version()
+
+ def _init_version(self):
+ try:
+ self.connection.execute(DATABRICKS_GET_CATALOGS).fetchone()
+ self.is_older_version = False
+ except DatabaseError as soe:
+ logger.debug(f"Failed to fetch catalogs due to: {soe}")
+ self.is_older_version = True
+
@classmethod
def create(cls, config_dict, metadata: OpenMetadata):
config: WorkflowSource = WorkflowSource.parse_obj(config_dict)
@@ -268,44 +285,55 @@ def set_inspector(self, database_name: str) -> None:
self.engine = get_connection(new_service_connection)
self.inspector = inspect(self.engine)
+ def get_configured_database(self) -> Optional[str]:
+ return self.service_connection.catalog
+
+ def get_database_names_raw(self) -> Iterable[str]:
+ if not self.is_older_version:
+ results = self.connection.execute(DATABRICKS_GET_CATALOGS)
+ for res in results:
+ if res:
+ row = list(res)
+ yield row[0]
+ else:
+ yield DEFAULT_DATABASE
+
def get_database_names(self) -> Iterable[str]:
- configured_catalog = self.service_connection.__dict__.get("catalog")
+ configured_catalog = self.service_connection.catalog
if configured_catalog:
self.set_inspector(database_name=configured_catalog)
yield configured_catalog
else:
- results = self.connection.execute("SHOW CATALOGS")
- for res in results:
- if res:
- new_catalog = res[0]
- database_fqn = fqn.build(
- self.metadata,
- entity_type=Database,
- service_name=self.context.database_service.name.__root__,
- database_name=new_catalog,
+ for new_catalog in self.get_database_names_raw():
+ database_fqn = fqn.build(
+ self.metadata,
+ entity_type=Database,
+ service_name=self.context.database_service.name.__root__,
+ database_name=new_catalog,
+ )
+ if filter_by_database(
+ self.source_config.databaseFilterPattern,
+ database_fqn
+ if self.source_config.useFqnForFiltering
+ else new_catalog,
+ ):
+ self.status.filter(database_fqn, "Database Filtered Out")
+ continue
+ try:
+ self.set_inspector(database_name=new_catalog)
+ yield new_catalog
+ except Exception as exc:
+ logger.error(traceback.format_exc())
+ logger.warning(
+ f"Error trying to process database {new_catalog}: {exc}"
)
- if filter_by_database(
- self.source_config.databaseFilterPattern,
- database_fqn
- if self.source_config.useFqnForFiltering
- else new_catalog,
- ):
- self.status.filter(database_fqn, "Database Filtered Out")
- continue
- try:
- self.set_inspector(database_name=new_catalog)
- yield new_catalog
- except Exception as exc:
- logger.error(traceback.format_exc())
- logger.warning(
- f"Error trying to process database {new_catalog}: {exc}"
- )
def get_raw_database_schema_names(self) -> Iterable[str]:
if self.service_connection.__dict__.get("databaseSchema"):
yield self.service_connection.databaseSchema
else:
for schema_name in self.inspector.get_schema_names(
- database=self.context.database.name.__root__
+ database=self.context.database.name.__root__,
+ is_old_version=self.is_older_version,
):
yield schema_name
diff --git a/ingestion/src/metadata/ingestion/source/database/databricks/unity_catalog/metadata.py b/ingestion/src/metadata/ingestion/source/database/databricks/unity_catalog/metadata.py
index 898fe2ec9ba2..fa8d010a95be 100644
--- a/ingestion/src/metadata/ingestion/source/database/databricks/unity_catalog/metadata.py
+++ b/ingestion/src/metadata/ingestion/source/database/databricks/unity_catalog/metadata.py
@@ -61,6 +61,7 @@
ForeignConstrains,
Type,
)
+from metadata.ingestion.source.database.multi_db_source import MultiDBSource
from metadata.ingestion.source.database.stored_procedures_mixin import QueryByProcedure
from metadata.ingestion.source.models import TableView
from metadata.utils import fqn
@@ -84,7 +85,7 @@ def from_dict(cls, dct: Dict[str, Any]) -> "TableConstraintList":
TableConstraintList.from_dict = from_dict
-class DatabricksUnityCatalogSource(DatabaseServiceSource):
+class DatabricksUnityCatalogSource(DatabaseServiceSource, MultiDBSource):
"""
Implements the necessary methods to extract
Database metadata from Databricks Source using
@@ -107,6 +108,13 @@ def __init__(self, config: WorkflowSource, metadata: OpenMetadata):
self.table_constraints = []
self.test_connection()
+ def get_configured_database(self) -> Optional[str]:
+ return self.service_connection.catalog
+
+ def get_database_names_raw(self) -> Iterable[str]:
+ for catalog in self.client.catalogs.list():
+ yield catalog.name
+
@classmethod
def create(cls, config_dict, metadata: OpenMetadata):
config: WorkflowSource = WorkflowSource.parse_obj(config_dict)
@@ -131,31 +139,31 @@ def get_database_names(self) -> Iterable[str]:
if self.service_connection.catalog:
yield self.service_connection.catalog
else:
- for catalog in self.client.catalogs.list():
+ for catalog_name in self.get_database_names_raw():
try:
database_fqn = fqn.build(
self.metadata,
entity_type=Database,
service_name=self.context.database_service.name.__root__,
- database_name=catalog.name,
+ database_name=catalog_name,
)
if filter_by_database(
self.config.sourceConfig.config.databaseFilterPattern,
database_fqn
if self.config.sourceConfig.config.useFqnForFiltering
- else catalog.name,
+ else catalog_name,
):
self.status.filter(
database_fqn,
"Database (Catalog ID) Filtered Out",
)
continue
- yield catalog.name
+ yield catalog_name
except Exception as exc:
self.status.failed(
StackTraceError(
- name=catalog.name,
- error=f"Unexpected exception to get database name [{catalog.name}]: {exc}",
+ name=catalog_name,
+ error=f"Unexpected exception to get database name [{catalog_name}]: {exc}",
stack_trace=traceback.format_exc(),
)
)
diff --git a/ingestion/src/metadata/ingestion/source/database/sample_data.py b/ingestion/src/metadata/ingestion/source/database/sample_data.py
index a4742295a6b6..26c0147c4c6e 100644
--- a/ingestion/src/metadata/ingestion/source/database/sample_data.py
+++ b/ingestion/src/metadata/ingestion/source/database/sample_data.py
@@ -1292,6 +1292,7 @@ def ingest_profiles(self) -> Iterable[Either[OMetaTableProfileSampleData]]:
rowCount=profile["rowCount"],
createDateTime=profile.get("createDateTime"),
sizeInByte=profile.get("sizeInByte"),
+ customMetrics=profile.get("customMetrics"),
timestamp=int(
(
datetime.now(tz=timezone.utc) - timedelta(days=days)
diff --git a/ingestion/tests/cli_e2e/dashboard/tableau/tableau.yaml b/ingestion/tests/cli_e2e/dashboard/tableau/tableau.yaml
index 53695e367c89..77d089b56995 100644
--- a/ingestion/tests/cli_e2e/dashboard/tableau/tableau.yaml
+++ b/ingestion/tests/cli_e2e/dashboard/tableau/tableau.yaml
@@ -11,7 +11,7 @@ source:
hostPort: $E2E_TABLEAU_HOST_PORT
siteName: $E2E_TABLEAU_SITE
siteUrl: $E2E_TABLEAU_SITE
- apiVersion: 3.19
+ apiVersion: 3.21
sourceConfig:
config:
type: DashboardMetadata
diff --git a/ingestion/tests/cli_e2e/test_cli_athena.py b/ingestion/tests/cli_e2e/test_cli_athena.py
index becd6a37a58f..037854e95f3a 100644
--- a/ingestion/tests/cli_e2e/test_cli_athena.py
+++ b/ingestion/tests/cli_e2e/test_cli_athena.py
@@ -87,7 +87,7 @@ def get_excludes_tables() -> List[str]:
@staticmethod
def expected_filtered_schema_includes() -> int:
- return 3
+ return 4
@staticmethod
def expected_filtered_schema_excludes() -> int:
@@ -95,15 +95,15 @@ def expected_filtered_schema_excludes() -> int:
@staticmethod
def expected_filtered_table_includes() -> int:
- return 26
+ return 29
@staticmethod
def expected_filtered_table_excludes() -> int:
- return 1
+ return 2
@staticmethod
def expected_filtered_mix() -> int:
- return 4
+ return 6
def retrieve_lineage(self, entity_fqn: str) -> dict:
pass
diff --git a/ingestion/tests/cli_e2e/test_cli_tableau.py b/ingestion/tests/cli_e2e/test_cli_tableau.py
index 6c8b4544ae1c..cfbc8e6b1793 100644
--- a/ingestion/tests/cli_e2e/test_cli_tableau.py
+++ b/ingestion/tests/cli_e2e/test_cli_tableau.py
@@ -54,22 +54,22 @@ def get_excludes_datamodels(self) -> List[str]:
return ["Random.*"]
def expected_dashboards_and_charts(self) -> int:
- return 20
+ return 22
def expected_lineage(self) -> int:
- return 0
+ return 1
def expected_tags(self) -> int:
return 1
def expected_datamodel_lineage(self) -> int:
- return 11
+ return 5
def expected_datamodels(self) -> int:
- return 10
+ return 5
def expected_filtered_mix(self) -> int:
- return 12
+ return 2
def expected_filtered_sink_mix(self) -> int:
- return 10
+ return 9
diff --git a/ingestion/tests/unit/topology/database/test_databricks.py b/ingestion/tests/unit/topology/database/test_databricks.py
index 412937912889..fb5be497ac57 100644
--- a/ingestion/tests/unit/topology/database/test_databricks.py
+++ b/ingestion/tests/unit/topology/database/test_databricks.py
@@ -1,3 +1,18 @@
+# Copyright 2021 Collate
+# 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.
+
+"""
+Test databricks using the topology
+"""
+
from unittest import TestCase
from unittest.mock import patch
@@ -20,6 +35,7 @@
from metadata.generated.schema.type.entityReference import EntityReference
from metadata.ingestion.source.database.databricks.metadata import DatabricksSource
+# pylint: disable=line-too-long
mock_databricks_config = {
"source": {
"type": "databricks",
@@ -230,12 +246,20 @@
class DatabricksUnitTest(TestCase):
+ """
+ Databricks unit tests
+ """
+
@patch(
"metadata.ingestion.source.database.common_db_source.CommonDbSourceService.test_connection"
)
- def __init__(self, methodName, test_connection) -> None:
+ @patch(
+ "metadata.ingestion.source.database.databricks.legacy.metadata.DatabricksLegacySource._init_version"
+ )
+ def __init__(self, methodName, test_connection, db_init_version) -> None:
super().__init__(methodName)
test_connection.return_value = False
+ db_init_version.return_value = None
self.config = OpenMetadataWorkflowConfig.parse_obj(mock_databricks_config)
self.databricks_source = DatabricksSource.create(
diff --git a/openmetadata-airflow-apis/.coveragerc b/openmetadata-airflow-apis/.coveragerc
deleted file mode 100644
index 64a3eb0c3c5a..000000000000
--- a/openmetadata-airflow-apis/.coveragerc
+++ /dev/null
@@ -1,10 +0,0 @@
-[run]
-source = env/lib/python3.9/site-packages/openmetadata_managed_apis
-relative_files = True
-branch = True
-[report]
-omit =
- *__init__*
- tests/*
- views/**
- plugin.py
diff --git a/openmetadata-airflow-apis/LICENSE b/openmetadata-airflow-apis/LICENSE
new file mode 100644
index 000000000000..f49a4e16e68b
--- /dev/null
+++ b/openmetadata-airflow-apis/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
\ No newline at end of file
diff --git a/openmetadata-airflow-apis/pyproject.toml b/openmetadata-airflow-apis/pyproject.toml
new file mode 100644
index 000000000000..8e5eafcdc556
--- /dev/null
+++ b/openmetadata-airflow-apis/pyproject.toml
@@ -0,0 +1,65 @@
+[build-system]
+requires = ["setuptools"]
+build-backend = "setuptools.build_meta"
+
+# We will keep handling dependencies in setup.py
+# since it helps us organize and isolate version management
+[project]
+name = "openmetadata_managed_apis"
+version = "1.3.0.0.dev0"
+dynamic = ["readme"]
+authors = [
+ {name = "OpenMetadata Committers"}
+]
+license = {file = "LICENSE"}
+description = "Airflow REST APIs to create and manage DAGS"
+requires-python = ">=3.8"
+dependencies = [
+ "pendulum~=2.1.2",
+ "apache-airflow>=2.2.2",
+ "Flask>=1.1.4",
+ "Flask-Admin==1.6.0",
+]
+
+[project.optional-dependencies]
+dev = [
+ "black==22.3.0",
+ "pytest",
+ "pylint",
+ "pytest-cov",
+ "isort",
+ "pycln",
+]
+
+[project.urls]
+Homepage = "https://open-metadata.org/"
+Documentation = "https://docs.open-metadata.org/"
+Source = "https://github.com/open-metadata/OpenMetadata"
+
+[tool.setuptools.dynamic]
+readme = {file = ["README.md"]}
+
+[tool.setuptools.packages.find]
+include = ["openmetadata_managed_apis.*", "openmetadata_managed_apis"]
+
+[tool.setuptools.package-data]
+"openmetadata_managed_apis" = ["views/templates/rest_api/index.html", "resources/dag_runner.j2"]
+
+[project.entry-points."airflow.plugins"]
+openmetadata_managed_apis = "openmetadata_managed_apis.plugin:RestApiPlugin"
+
+
+[tool.coverage.run]
+source = [
+ "env/lib/python3.9/site-packages/openmetadata_managed_apis"
+]
+relative_files = true
+branch = true
+
+[tool.coverage.report]
+omit = [
+ "*__init__*",
+ "tests/*",
+ "views/**",
+ "plugin.py"
+]
\ No newline at end of file
diff --git a/openmetadata-airflow-apis/setup.py b/openmetadata-airflow-apis/setup.py
deleted file mode 100644
index 33a3925c94ea..000000000000
--- a/openmetadata-airflow-apis/setup.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# Copyright 2021 Collate
-# 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.
-import glob
-import os
-import pathlib
-from itertools import chain
-
-from setuptools import find_packages, setup
-
-PLUGIN_NAME = "openmetadata_managed_apis"
-PLUGIN_ROOT_FILE = "plugin"
-PLUGIN_ENTRY_POINT = "RestApiPlugin"
-HOME = pathlib.Path(__file__).parent
-README = (HOME / "README.md").read_text()
-CONFIG = HOME / PLUGIN_NAME / "config.py"
-
-
-def get_package_data():
- """
- Add templates and html files to the built
- package for easier deployments
- """
- extensions = ["html", "j2"]
-
- files = list(
- chain(
- *[
- glob.glob(f"{PLUGIN_NAME}/**/*.%s" % x, recursive=True)
- for x in extensions
- ]
- )
- )
- return [x.split(os.sep, 1)[1] for x in files]
-
-
-def get_long_description():
- root = os.path.dirname(__file__)
- with open(os.path.join(root, "README.md")) as f:
- description = f.read()
- return description
-
-
-base_requirements = {
- "pendulum~=2.1.2",
- "apache-airflow>=2.2.2",
- "Flask>=1.1.4",
- "Flask-Admin==1.6.0",
-}
-
-dev_requirements = {
- "black==22.3.0",
- "pytest",
- "pylint",
- "pytest-cov",
- "isort",
- "pycln",
-}
-
-setup(
- name=PLUGIN_NAME,
- packages=find_packages(include=[f"{PLUGIN_NAME}.*", PLUGIN_NAME]),
- include_package_data=True,
- package_data={PLUGIN_NAME: get_package_data()},
- version="1.3.0.0.dev0",
- url="https://open-metadata.org/",
- author="OpenMetadata Committers",
- license="Apache License 2.0",
- description="Airflow REST APIs to create and manage DAGS",
- long_description=get_long_description(),
- long_description_content_type="text/markdown",
- entry_points={
- "airflow.plugins": [
- f"{PLUGIN_NAME} = {PLUGIN_NAME}.{PLUGIN_ROOT_FILE}:{PLUGIN_ENTRY_POINT}"
- ]
- },
- python_requires=">=3.8",
- zip_safe=False,
- dependency_links=[],
- project_urls={
- "Documentation": "https://docs.open-metadata.org/",
- "Source": "https://github.com/open-metadata/OpenMetadata",
- },
- install_requires=list(base_requirements),
- extras_require={
- "base": list(base_requirements),
- "dev": list(dev_requirements),
- },
-)
diff --git a/openmetadata-clients/openmetadata-java-client/pom.xml b/openmetadata-clients/openmetadata-java-client/pom.xml
index bd7fbae1d76b..d9b4f6828044 100644
--- a/openmetadata-clients/openmetadata-java-client/pom.xml
+++ b/openmetadata-clients/openmetadata-java-client/pom.xml
@@ -15,7 +15,7 @@
${java.version}${java.version}2.7.0
- 13.0
+ 13.10.2.68.3.32.1.18
diff --git a/openmetadata-docs/content/v1.2.x/connectors/database/athena/index.md b/openmetadata-docs/content/v1.2.x/connectors/database/athena/index.md
index 361ad0f75661..5a4692db6e0a 100644
--- a/openmetadata-docs/content/v1.2.x/connectors/database/athena/index.md
+++ b/openmetadata-docs/content/v1.2.x/connectors/database/athena/index.md
@@ -74,6 +74,7 @@ And is defined as:
"athena:ListQueryExecutions",
"athena:StartQueryExecution",
"athena:GetQueryExecution",
+ "athena:ListWorkGroups",
"athena:GetQueryResults",
"athena:BatchGetQueryExecution"
],
diff --git a/openmetadata-docs/content/v1.2.x/deployment/docker/index.md b/openmetadata-docs/content/v1.2.x/deployment/docker/index.md
index d20155597f25..7d6151b44d38 100644
--- a/openmetadata-docs/content/v1.2.x/deployment/docker/index.md
+++ b/openmetadata-docs/content/v1.2.x/deployment/docker/index.md
@@ -102,7 +102,7 @@ This docker compose file contains only the docker compose services for OpenMetad
You can also run the below command to fetch the docker compose file directly from the terminal -
```bash
-wget https://github.com/open-metadata/OpenMetadata/releases/download/1.2.0-release/docker-compose-openmetadata.yml
+wget https://github.com/open-metadata/OpenMetadata/releases/download/1.2.2-release/docker-compose-openmetadata.yml
```
### 3. Update Environment Variables required for OpenMetadata Dependencies
@@ -191,7 +191,7 @@ You can validate that all containers are up by running with command `docker ps`.
```commandline
❯ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-470cc8149826 openmetadata/server:1.2.0 "./openmetadata-star…" 45 seconds ago Up 43 seconds 3306/tcp, 9200/tcp, 9300/tcp, 0.0.0.0:8585-8586->8585-8586/tcp openmetadata_server
+470cc8149826 openmetadata/server:1.2.2 "./openmetadata-star…" 45 seconds ago Up 43 seconds 3306/tcp, 9200/tcp, 9300/tcp, 0.0.0.0:8585-8586->8585-8586/tcp openmetadata_server
```
In a few seconds, you should be able to access the OpenMetadata UI at [http://localhost:8585](http://localhost:8585)
diff --git a/openmetadata-docs/content/v1.2.x/deployment/ingestion/mwaa.md b/openmetadata-docs/content/v1.2.x/deployment/ingestion/mwaa.md
index f1f5fcd8e20f..cb8ec536c1c0 100644
--- a/openmetadata-docs/content/v1.2.x/deployment/ingestion/mwaa.md
+++ b/openmetadata-docs/content/v1.2.x/deployment/ingestion/mwaa.md
@@ -32,9 +32,9 @@ To install the package, we need to update the `requirements.txt` file from the M
openmetadata-ingestion[]==x.y.z
```
-Where `x.y.z` is the version of the OpenMetadata ingestion package. Note that the version needs to match the server version. If we are using the server at 1.2.0, then the ingestion package needs to also be 1.2.0.
+Where `x.y.z` is the version of the OpenMetadata ingestion package. Note that the version needs to match the server version. If we are using the server at 1.2.2, then the ingestion package needs to also be 1.2.2.
-The plugin parameter is a list of the sources that we want to ingest. An example would look like this `openmetadata-ingestion[mysql,snowflake,s3]==1.2.0`.
+The plugin parameter is a list of the sources that we want to ingest. An example would look like this `openmetadata-ingestion[mysql,snowflake,s3]==1.2.2`.
A DAG deployed using a Python Operator would then look like follows
@@ -106,7 +106,7 @@ We will now describe the steps, following the official AWS documentation.
- The cluster needs a task to run in `FARGATE` mode.
- The required image is `docker.getcollate.io/openmetadata/ingestion-base:x.y.z`
- - The same logic as above applies. The `x.y.z` version needs to match the server version. For example, `docker.getcollate.io/openmetadata/ingestion-base:1.2.0`
+ - The same logic as above applies. The `x.y.z` version needs to match the server version. For example, `docker.getcollate.io/openmetadata/ingestion-base:1.2.2`
We have tested this process with a Task Memory of 512MB and Task CPU (unit) of 256. This can be tuned depending on the amount of metadata that needs to be ingested.
diff --git a/openmetadata-docs/content/v1.2.x/deployment/kubernetes/faqs.md b/openmetadata-docs/content/v1.2.x/deployment/kubernetes/faqs.md
index 02ff65bfee57..492cd23b9b91 100644
--- a/openmetadata-docs/content/v1.2.x/deployment/kubernetes/faqs.md
+++ b/openmetadata-docs/content/v1.2.x/deployment/kubernetes/faqs.md
@@ -48,7 +48,7 @@ WORKDIR /home/
COPY .
RUN update-ca-certificates
```
-where `docker.getcollate.io/openmetadata/server:x.y.z` needs to point to the same version of the OpenMetadata server, for example `docker.getcollate.io/openmetadata/server:1.2.0`.
+where `docker.getcollate.io/openmetadata/server:x.y.z` needs to point to the same version of the OpenMetadata server, for example `docker.getcollate.io/openmetadata/server:1.2.2`.
This image needs to be built and published to the container registry of your choice.
### 2. Update your openmetadata helm values yaml
@@ -95,7 +95,7 @@ COPY setup.py .
RUN pip install --no-deps .
```
-where `docker.getcollate.io/openmetadata/ingestion:x.y.z` needs to point to the same version of the OpenMetadata server, for example `docker.getcollate.io/openmetadata/ingestion:1.2.0`.
+where `docker.getcollate.io/openmetadata/ingestion:x.y.z` needs to point to the same version of the OpenMetadata server, for example `docker.getcollate.io/openmetadata/ingestion:1.2.2`.
This image needs to be built and published to the container registry of your choice.
### 2. Update the airflow in openmetadata dependencies values YAML
diff --git a/openmetadata-docs/content/v1.2.x/deployment/upgrade/kubernetes.md b/openmetadata-docs/content/v1.2.x/deployment/upgrade/kubernetes.md
index c8a30c62049c..ba72e6960c9b 100644
--- a/openmetadata-docs/content/v1.2.x/deployment/upgrade/kubernetes.md
+++ b/openmetadata-docs/content/v1.2.x/deployment/upgrade/kubernetes.md
@@ -45,12 +45,12 @@ Verify with the below command to see the latest release available locally.
```commandline
helm search repo open-metadata --versions
> NAME CHART VERSION APP VERSION DESCRIPTION
-open-metadata/openmetadata 1.2.1 1.2.0 A Helm chart for OpenMetadata on Kubernetes
-open-metadata/openmetadata 1.2.0 1.2.0 A Helm chart for OpenMetadata on Kubernetes
+open-metadata/openmetadata 1.2.4 1.2.2 A Helm chart for OpenMetadata on Kubernetes
+open-metadata/openmetadata 1.2.3 1.2.2 A Helm chart for OpenMetadata on Kubernetes
...
-open-metadata/openmetadata-dependencies 1.2.1 1.2.0 Helm Dependencies for OpenMetadata
-open-metadata/openmetadata-dependencies 1.2.0 1.2.0 Helm Dependencies for OpenMetadata
+open-metadata/openmetadata-dependencies 1.2.4 1.2.2 Helm Dependencies for OpenMetadata
+open-metadata/openmetadata-dependencies 1.2.3 1.2.2 Helm Dependencies for OpenMetadata
...
```
diff --git a/openmetadata-docs/content/v1.2.x/quick-start/local-docker-deployment.md b/openmetadata-docs/content/v1.2.x/quick-start/local-docker-deployment.md
index 7d809d8e84ac..05b3d87ea3f4 100644
--- a/openmetadata-docs/content/v1.2.x/quick-start/local-docker-deployment.md
+++ b/openmetadata-docs/content/v1.2.x/quick-start/local-docker-deployment.md
@@ -119,15 +119,15 @@ The latest version is at the top of the page
You can use the curl or wget command as well to fetch the docker compose files from your terminal -
```commandline
-curl -sL -o docker-compose.yml https://github.com/open-metadata/OpenMetadata/releases/download/1.2.0-release/docker-compose.yml
+curl -sL -o docker-compose.yml https://github.com/open-metadata/OpenMetadata/releases/download/1.2.2-release/docker-compose.yml
-curl -sL -o docker-compose-postgres.yml https://github.com/open-metadata/OpenMetadata/releases/download/1.2.0-release/docker-compose-postgres.yml
+curl -sL -o docker-compose-postgres.yml https://github.com/open-metadata/OpenMetadata/releases/download/1.2.2-release/docker-compose-postgres.yml
```
```commandline
-wget -O https://github.com/open-metadata/OpenMetadata/releases/download/1.2.0-release/docker-compose.yml
+wget -O https://github.com/open-metadata/OpenMetadata/releases/download/1.2.2-release/docker-compose.yml
-wget -O https://github.com/open-metadata/OpenMetadata/releases/download/1.2.0-release/docker-compose-postgres.yml
+wget -O https://github.com/open-metadata/OpenMetadata/releases/download/1.2.2-release/docker-compose-postgres.yml
```
### 3. Start the Docker Compose Services
@@ -166,10 +166,10 @@ You can validate that all containers are up by running with command `docker ps`.
```commandline
❯ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-470cc8149826 openmetadata/server:1.2.0 "./openmetadata-star…" 45 seconds ago Up 43 seconds 3306/tcp, 9200/tcp, 9300/tcp, 0.0.0.0:8585-8586->8585-8586/tcp openmetadata_server
-63578aacbff5 openmetadata/ingestion:1.2.0 "./ingestion_depende…" 45 seconds ago Up 43 seconds 0.0.0.0:8080->8080/tcp openmetadata_ingestion
+470cc8149826 openmetadata/server:1.2.2 "./openmetadata-star…" 45 seconds ago Up 43 seconds 3306/tcp, 9200/tcp, 9300/tcp, 0.0.0.0:8585-8586->8585-8586/tcp openmetadata_server
+63578aacbff5 openmetadata/ingestion:1.2.2 "./ingestion_depende…" 45 seconds ago Up 43 seconds 0.0.0.0:8080->8080/tcp openmetadata_ingestion
9f5ee8334f4b docker.elastic.co/elasticsearch/elasticsearch:7.16.3 "/tini -- /usr/local…" 45 seconds ago Up 44 seconds 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp openmetadata_elasticsearch
-08947ab3424b openmetadata/db:1.2.0 "/entrypoint.sh mysq…" 45 seconds ago Up 44 seconds (healthy) 3306/tcp, 33060-33061/tcp openmetadata_mysql
+08947ab3424b openmetadata/db:1.2.2 "/entrypoint.sh mysq…" 45 seconds ago Up 44 seconds (healthy) 3306/tcp, 33060-33061/tcp openmetadata_mysql
```
In a few seconds, you should be able to access the OpenMetadata UI at [http://localhost:8585](http://localhost:8585)
diff --git a/openmetadata-service/pom.xml b/openmetadata-service/pom.xml
index e67f8f6899e5..6bf772e80e49 100644
--- a/openmetadata-service/pom.xml
+++ b/openmetadata-service/pom.xml
@@ -15,8 +15,8 @@
${project.basedir}/target/surefire-reports${project.basedir}/target/site/jacoco-aggregate/jacoco.xml${project.basedir}/src/test/java
- 1.19.1
- 2.21.16
+ 1.19.2
+ 2.21.260.5.112.9.02.2.6
@@ -471,7 +471,7 @@
com.cronutilscron-utils
- 9.2.0
+ 9.2.1com.google.guava
diff --git a/openmetadata-service/src/main/java/org/openmetadata/csv/CsvUtil.java b/openmetadata-service/src/main/java/org/openmetadata/csv/CsvUtil.java
index c0985873337f..4de4fcd9ad38 100644
--- a/openmetadata-service/src/main/java/org/openmetadata/csv/CsvUtil.java
+++ b/openmetadata-service/src/main/java/org/openmetadata/csv/CsvUtil.java
@@ -95,9 +95,8 @@ public static String quoteField(List field) {
: field.stream().map(CsvUtil::quoteCsvField).collect(Collectors.joining(FIELD_SEPARATOR));
}
- public static List addField(List csvRecord, Boolean field) {
+ public static void addField(List csvRecord, Boolean field) {
csvRecord.add(field == null ? "" : field.toString());
- return csvRecord;
}
public static List addField(List csvRecord, String field) {
@@ -129,14 +128,12 @@ public static List addTagLabels(List csvRecord, List t
return csvRecord;
}
- public static List addOwner(List csvRecord, EntityReference owner) {
+ public static void addOwner(List csvRecord, EntityReference owner) {
csvRecord.add(nullOrEmpty(owner) ? null : owner.getType() + FIELD_SEPARATOR + owner.getName());
- return csvRecord;
}
- public static List addUserOwner(List csvRecord, EntityReference owner) {
+ public static void addUserOwner(List csvRecord, EntityReference owner) {
csvRecord.add(nullOrEmpty(owner) ? null : owner.getName());
- return csvRecord;
}
private static String quoteCsvField(String str) {
diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/ResourceRegistry.java b/openmetadata-service/src/main/java/org/openmetadata/service/ResourceRegistry.java
index 86872657f2cd..86bf260b87e9 100644
--- a/openmetadata-service/src/main/java/org/openmetadata/service/ResourceRegistry.java
+++ b/openmetadata-service/src/main/java/org/openmetadata/service/ResourceRegistry.java
@@ -65,13 +65,13 @@ public static void addResource(
ResourceDescriptor resourceDescriptor =
new ResourceDescriptor()
.withName(resourceName)
- .withOperations(getOperations(resourceName, entitySpecificOperations, new ArrayList<>(entityFields)));
+ .withOperations(getOperations(entitySpecificOperations, new ArrayList<>(entityFields)));
RESOURCE_DESCRIPTORS.sort(Comparator.comparing(ResourceDescriptor::getName));
RESOURCE_DESCRIPTORS.add(resourceDescriptor);
}
private static List getOperations(
- String resourceName, List entitySpecificOperations, List entityFields) {
+ List entitySpecificOperations, List entityFields) {
Set operations = new TreeSet<>(COMMON_OPERATIONS);
if (!nullOrEmpty(entitySpecificOperations)) {
operations.addAll(entitySpecificOperations);
diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/apps/AbstractNativeApplication.java b/openmetadata-service/src/main/java/org/openmetadata/service/apps/AbstractNativeApplication.java
index 5ce5659c84d1..4c744a7e794d 100644
--- a/openmetadata-service/src/main/java/org/openmetadata/service/apps/AbstractNativeApplication.java
+++ b/openmetadata-service/src/main/java/org/openmetadata/service/apps/AbstractNativeApplication.java
@@ -197,11 +197,11 @@ public static AppRuntime getAppRuntime(App app) {
return JsonUtils.convertValue(app.getRuntime(), ScheduledExecutionContext.class);
}
- protected IngestionPipeline getIngestionPipeline(CreateIngestionPipeline create, String botname, String user) {
+ protected IngestionPipeline getIngestionPipeline(CreateIngestionPipeline create, String botName, String user) {
IngestionPipelineRepository ingestionPipelineRepository =
(IngestionPipelineRepository) Entity.getEntityRepository(Entity.INGESTION_PIPELINE);
OpenMetadataConnection openMetadataServerConnection =
- new OpenMetadataConnectionBuilder(ingestionPipelineRepository.getOpenMetadataApplicationConfig(), botname)
+ new OpenMetadataConnectionBuilder(ingestionPipelineRepository.getOpenMetadataApplicationConfig(), botName)
.build();
return ingestionPipelineRepository
.copy(new IngestionPipeline(), create, user)
@@ -224,8 +224,8 @@ protected AppRunRecord getJobRecord(JobExecutionContext jobExecutionContext) {
}
@SneakyThrows
- protected void pushAppStausUpdates(JobExecutionContext jobExecutionContext, AppRunRecord record, boolean update) {
+ protected void pushAppStatusUpdates(JobExecutionContext jobExecutionContext, AppRunRecord appRecord, boolean update) {
OmAppJobListener listener = getJobListener(jobExecutionContext);
- listener.pushApplicationStatusUpdates(jobExecutionContext, record, update);
+ listener.pushApplicationStatusUpdates(jobExecutionContext, appRecord, update);
}
}
diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/searchIndex/SearchIndexApp.java b/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/searchIndex/SearchIndexApp.java
index 4280c34191b1..bd78b640ef85 100644
--- a/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/searchIndex/SearchIndexApp.java
+++ b/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/searchIndex/SearchIndexApp.java
@@ -151,7 +151,7 @@ public void updateRecordToDb(JobExecutionContext jobExecutionContext) {
appRecord.setSuccessContext(new SuccessContext().withAdditionalProperty("stats", jobData.getStats()));
}
- pushAppStausUpdates(jobExecutionContext, appRecord, true);
+ pushAppStatusUpdates(jobExecutionContext, appRecord, true);
}
private void entitiesReIndex() {
diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/apps/scheduler/AbstractOmAppJobListener.java b/openmetadata-service/src/main/java/org/openmetadata/service/apps/scheduler/AbstractOmAppJobListener.java
index e89b765ab17a..d96bfd7a621f 100644
--- a/openmetadata-service/src/main/java/org/openmetadata/service/apps/scheduler/AbstractOmAppJobListener.java
+++ b/openmetadata-service/src/main/java/org/openmetadata/service/apps/scheduler/AbstractOmAppJobListener.java
@@ -109,13 +109,13 @@ public void pushApplicationStatusUpdates(JobExecutionContext context, AppRunReco
}
}
- private void updateStatus(UUID appId, AppRunRecord record, boolean update) {
+ private void updateStatus(UUID appId, AppRunRecord appRunRecord, boolean update) {
if (update) {
collectionDAO
.appExtensionTimeSeriesDao()
- .update(appId.toString(), JsonUtils.pojoToJson(record), record.getTimestamp());
+ .update(appId.toString(), JsonUtils.pojoToJson(appRunRecord), appRunRecord.getTimestamp());
} else {
- collectionDAO.appExtensionTimeSeriesDao().insert(JsonUtils.pojoToJson(record));
+ collectionDAO.appExtensionTimeSeriesDao().insert(JsonUtils.pojoToJson(appRunRecord));
}
}
diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/config/OMWebBundle.java b/openmetadata-service/src/main/java/org/openmetadata/service/config/OMWebBundle.java
index 3eb22bfc4daa..107a964e5ad7 100644
--- a/openmetadata-service/src/main/java/org/openmetadata/service/config/OMWebBundle.java
+++ b/openmetadata-service/src/main/java/org/openmetadata/service/config/OMWebBundle.java
@@ -75,7 +75,7 @@ protected void configureHeaderFilter(
}
private String deriveUrlPattern(String uri) {
- return uri.endsWith("/") ? uri + "*" : uri + "/" + "*";
+ return uri.endsWith("/") ? uri + "*" : uri + "/*";
}
public abstract OMWebConfiguration getWebConfiguration(T var1);
diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUnusedAssetsCountAggregator.java b/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUnusedAssetsCountAggregator.java
index 6ed6bb87127f..64e7d584df67 100644
--- a/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUnusedAssetsCountAggregator.java
+++ b/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUnusedAssetsCountAggregator.java
@@ -9,7 +9,7 @@
public abstract class AggregatedUnusedAssetsCountAggregator implements DataInsightAggregatorInterface {
private final A aggregations;
- public AggregatedUnusedAssetsCountAggregator(A aggregations) {
+ protected AggregatedUnusedAssetsCountAggregator(A aggregations) {
this.aggregations = aggregations;
}
diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUnusedAssetsSizeAggregator.java b/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUnusedAssetsSizeAggregator.java
index 43dcd0ea1888..cd0bfcd4658e 100644
--- a/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUnusedAssetsSizeAggregator.java
+++ b/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUnusedAssetsSizeAggregator.java
@@ -9,7 +9,7 @@
public abstract class AggregatedUnusedAssetsSizeAggregator implements DataInsightAggregatorInterface {
private final A aggregations;
- public AggregatedUnusedAssetsSizeAggregator(A aggregations) {
+ protected AggregatedUnusedAssetsSizeAggregator(A aggregations) {
this.aggregations = aggregations;
}
diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUsedvsUnusedAssetsCountAggregator.java b/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUsedvsUnusedAssetsCountAggregator.java
index 55da7c43ff35..903fc223a408 100644
--- a/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUsedvsUnusedAssetsCountAggregator.java
+++ b/openmetadata-service/src/main/java/org/openmetadata/service/dataInsight/AggregatedUsedvsUnusedAssetsCountAggregator.java
@@ -10,7 +10,7 @@ public abstract class AggregatedUsedvsUnusedAssetsCountAggregator
implements DataInsightAggregatorInterface {
private final A aggregations;
- public AggregatedUsedvsUnusedAssetsCountAggregator(A aggregations) {
+ protected AggregatedUsedvsUnusedAssetsCountAggregator(A aggregations) {
this.aggregations = aggregations;
}
@@ -26,8 +26,8 @@ public List