-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat: Add Prefect Cloud pipeline connector #27607
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 9 commits
d48526d
f3cf785
b0de1c0
bc53164
5e7ac14
c0a6fee
5d18b7b
425f7ea
cccf02d
5ae07b8
8331e35
59e9def
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| # Empty init file for Prefect connector package |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| # Copyright 2025 Collate | ||
| # Licensed under the Collate Community License, Version 1.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # https://github.com/open-metadata/OpenMetadata/blob/main/ingestion/LICENSE | ||
| # 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. | ||
|
|
||
| """ | ||
| Connection handler for Prefect | ||
| """ | ||
| import httpx | ||
|
|
||
| from metadata.generated.schema.entity.automations.workflow import ( | ||
| Workflow as AutomationWorkflow, | ||
| ) | ||
| from metadata.generated.schema.entity.services.connections.pipeline.prefectConnection import ( | ||
| PrefectConnection, | ||
| ) | ||
| from metadata.ingestion.connections.test_connections import test_connection_steps | ||
| from metadata.ingestion.ometa.ometa_api import OpenMetadata | ||
| from metadata.utils.ssl_registry import get_verify_ssl_fn | ||
|
|
||
|
|
||
| def _build_base_url(connection: PrefectConnection) -> str: | ||
| """ | ||
| Build the Prefect API base URL based on connection mode. | ||
|
|
||
| Returns: | ||
| Base URL for Prefect API (Cloud or self-hosted) | ||
| """ | ||
| if connection.accountId and connection.workspaceId: | ||
| # Prefect Cloud mode | ||
| host = getattr(connection, "hostPort", None) or "https://api.prefect.cloud" | ||
| return ( | ||
| f"{host}/api/accounts" | ||
| f"/{connection.accountId}" | ||
| f"/workspaces/{connection.workspaceId}" | ||
| ) | ||
| else: | ||
| # Self-hosted Prefect Server mode | ||
| host = getattr(connection, "hostPort", None) or "http://localhost:4200" | ||
| return f"{host}/api" | ||
|
|
||
|
|
||
| def get_connection(connection: PrefectConnection) -> httpx.Client: | ||
| """ | ||
| Create an HTTP client for Prefect Cloud or self-hosted Prefect Server. | ||
| """ | ||
| # Validate accountId/workspaceId consistency | ||
| has_account = bool(connection.accountId) | ||
| has_workspace = bool(connection.workspaceId) | ||
| if has_account != has_workspace: | ||
| raise ValueError( | ||
| "Both accountId and workspaceId must be provided for " | ||
| "Prefect Cloud, or both must be empty for self-hosted mode." | ||
| ) | ||
|
|
||
| # Handle both SecretStr and plain string for apiKey | ||
| api_key = connection.apiKey | ||
| if hasattr(api_key, "get_secret_value"): | ||
| api_key_str = api_key.get_secret_value() | ||
| else: | ||
| api_key_str = str(api_key) | ||
|
|
||
| # Build base URL using shared helper | ||
| base_url = _build_base_url(connection) | ||
|
|
||
| headers = { | ||
| "Authorization": f"Bearer {api_key_str}", | ||
| "Content-Type": "application/json", | ||
| "User-Agent": "OpenMetadata/Prefect-Connector", | ||
| } | ||
|
|
||
| # Handle SSL verification (required for enterprise deployments) | ||
| verify_ssl = True # Default to verifying SSL for security | ||
| if connection.verifySSL: | ||
| verify_ssl_fn = get_verify_ssl_fn(connection.verifySSL) | ||
| ssl_result = verify_ssl_fn(connection.sslConfig) | ||
| # None (no-ssl) and False (ignore) both mean disable verification | ||
| verify_ssl = ssl_result if ssl_result is not None else False | ||
|
|
||
| return httpx.Client( | ||
| base_url=base_url, headers=headers, timeout=30, verify=verify_ssl | ||
| ) | ||
|
Comment on lines
+49
to
+88
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please use the BaseConnection? We are moving away from these module level functions and using the BaseConnection to handle it |
||
|
|
||
|
|
||
| def test_connection( | ||
| metadata: OpenMetadata, | ||
| client: httpx.Client, | ||
| service_connection: PrefectConnection, | ||
| base_url: str = None, | ||
| headers: dict = None, | ||
| automation_workflow: AutomationWorkflow = None, | ||
| ) -> None: | ||
| """ | ||
| Test connection to Prefect Cloud by fetching flows. | ||
| """ | ||
|
|
||
| def custom_test_connection(client: httpx.Client) -> None: | ||
| # Test using POST /flows/filter as per Prefect 3.x API | ||
| # Use provided base_url and headers if available (from metadata.py) | ||
| # Otherwise construct them (when called from get_connection) | ||
| if base_url and headers: | ||
| url = f"{base_url}/flows/filter" | ||
| response = client.post(url, headers=headers, json={"limit": 1, "offset": 0}) | ||
| else: | ||
| # Fallback: client already has base_url and headers configured | ||
| response = client.post("/flows/filter", json={"limit": 1, "offset": 0}) | ||
| response.raise_for_status() | ||
|
|
||
| test_fn = {"GetFlows": custom_test_connection} | ||
| test_connection_steps( | ||
| metadata=metadata, | ||
| service_type="Prefect", | ||
| test_fn=test_fn, | ||
| automation_workflow=automation_workflow, | ||
| ) | ||
|
Comment on lines
+91
to
+121
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While changing to BaseConnection, could you also migrate to the new TestConnection that provides diagnostics on different errors? You can check an example here: #29767 |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason for using httpx here while the rest of the code uses requests?