Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0ba4a0f
Add MaxComputeHook and AlibabaBaseHook
jsjasonseba May 4, 2025
70d43aa
Remove unecessary init override
jsjasonseba May 4, 2025
da57a67
Fix word spelling
jsjasonseba May 5, 2025
09256cc
Add type hints and docstrings to MaxComputeHook and AlibabaBaseHook
jsjasonseba May 5, 2025
7e0eeb1
Set priority from hints if not explicitly provided
jsjasonseba May 5, 2025
21947f9
Add odps to spelling wordlist
jsjasonseba May 5, 2025
d891967
Add stop_instance method to MaxComputeHook
jsjasonseba May 10, 2025
83540fb
Add MaxComputeSQLOperator
jsjasonseba May 10, 2025
efe142e
Fix docstring
jsjasonseba May 10, 2025
4128d6a
Merge branch 'main' into alibaba-provider-maxcompute
jsjasonseba May 10, 2025
ca2e808
Add maxcompute to wordlist
jsjasonseba May 10, 2025
a43ed83
Add alibaba test_version_compat.py to overlooked test list
jsjasonseba May 10, 2025
313baa8
Add test for MaxComputeLogViewLink
jsjasonseba May 10, 2025
a35cd64
Simplify fallback logic
jsjasonseba May 21, 2025
ed6a7a3
Change error logging to use log.exception
jsjasonseba May 21, 2025
476165a
Simplify logics
jsjasonseba May 21, 2025
6e65471
Make arguments keyword-only
jsjasonseba May 21, 2025
31932ad
Create MaxComputeConfigurationException for configuration issues
jsjasonseba May 21, 2025
264ece6
Add test for MaxComputeConfigurationException
jsjasonseba May 21, 2025
09cfce1
Merge branch 'main' into alibaba-provider-maxcompute
jsjasonseba May 21, 2025
c996a98
Simplify code
jsjasonseba May 22, 2025
9b09cf7
Simplify code
jsjasonseba May 22, 2025
e89104e
Simplify code
jsjasonseba May 27, 2025
bdcc1b2
Adjust connection arg name for styling consistency with other hooks
jsjasonseba May 27, 2025
16e64df
Adjust connection arg name for styling consistency with other hooks
jsjasonseba May 27, 2025
cab01e0
Merge branch 'main' into alibaba-provider-maxcompute
jsjasonseba May 27, 2025
155f9ee
Refactor code
jsjasonseba May 29, 2025
082f69d
Refactor code
jsjasonseba May 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions airflow-core/tests/unit/always/test_project_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def test_providers_modules_should_have_tests(self):
# We should make sure that one goes to 0
# TODO(potiuk) - check if that test actually tests something
OVERLOOKED_TESTS = [
"providers/alibaba/tests/unit/alibaba/test_version_compat.py",
"providers/amazon/tests/unit/amazon/aws/auth_manager/datamodels/test_login.py",
"providers/amazon/tests/unit/amazon/aws/auth_manager/security_manager/test_aws_security_manager_override.py",
"providers/amazon/tests/unit/amazon/aws/executors/batch/test_batch_executor_config.py",
Expand Down
3 changes: 3 additions & 0 deletions docs/spelling_wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,8 @@ masterType
materializations
Matomo
matomo
MaxCompute
maxcompute
Maxime
MaxRuntimeInSeconds
mb
Expand Down Expand Up @@ -1220,6 +1222,7 @@ objectstorage
observability
od
odbc
odps
ok
Okta
okta
Expand Down
16 changes: 16 additions & 0 deletions providers/alibaba/provider.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ operators:
- integration-name: Alibaba Cloud AnalyticDB Spark
python-modules:
- airflow.providers.alibaba.cloud.operators.analyticdb_spark
- integration-name: Alibaba Cloud MaxCompute
python-modules:
- airflow.providers.alibaba.cloud.operators.maxcompute

sensors:
- integration-name: Alibaba Cloud OSS
Expand All @@ -94,13 +97,26 @@ hooks:
- integration-name: Alibaba Cloud AnalyticDB Spark
python-modules:
- airflow.providers.alibaba.cloud.hooks.analyticdb_spark
- integration-name: Alibaba Cloud
python-modules:
- airflow.providers.alibaba.cloud.hooks.base_alibaba
- integration-name: Alibaba Cloud MaxCompute
python-modules:
- airflow.providers.alibaba.cloud.hooks.maxcompute


connection-types:
- hook-class-name: airflow.providers.alibaba.cloud.hooks.oss.OSSHook
connection-type: oss
- hook-class-name: airflow.providers.alibaba.cloud.hooks.analyticdb_spark.AnalyticDBSparkHook
connection-type: adb_spark
- hook-class-name: airflow.providers.alibaba.cloud.hooks.base_alibaba.AlibabaBaseHook
connection-type: alibaba_cloud
- hook-class-name: airflow.providers.alibaba.cloud.hooks.maxcompute.MaxComputeHook
connection-type: maxcompute

logging:
- airflow.providers.alibaba.cloud.log.oss_task_handler.OSSTaskHandler

extra-links:
- airflow.providers.alibaba.cloud.links.maxcompute.MaxComputeLogViewLink
1 change: 1 addition & 0 deletions providers/alibaba/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ dependencies = [
"oss2>=2.14.0",
"alibabacloud_adb20211201>=1.0.0",
"alibabacloud_tea_openapi>=0.3.7",
"pyodps>=0.12.2.2",
]

[dependency-groups]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
from __future__ import annotations


class MaxComputeConfigurationException(Exception):
"""Raised when MaxCompute project or endpoint is not configured properly."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
from __future__ import annotations

from typing import Any, NamedTuple

from airflow.hooks.base import BaseHook


class AccessKeyCredentials(NamedTuple):
"""
A NamedTuple to store Alibaba Cloud Access Key credentials.

:param access_key_id: The Access Key ID for Alibaba Cloud authentication.
:param access_key_secret: The Access Key Secret for Alibaba Cloud authentication.
"""

access_key_id: str
access_key_secret: str


class AlibabaBaseHook(BaseHook):
"""
A base hook for Alibaba Cloud-related hooks.

This hook provides a common interface for authenticating using Alibaba Cloud credentials.

Supports Access Key-based authentication.

:param alibaba_cloud_conn_id: The connection ID to use when fetching connection info.
"""

conn_name_attr = "alibabacloud_conn_id"
default_conn_name = "alibabacloud_default"
conn_type = "alibaba_cloud"
hook_name = "Alibaba Cloud"

def __init__(
self,
alibabacloud_conn_id: str = "alibabacloud_default",
**kwargs,
) -> None:
super().__init__(**kwargs)
self.alibaba_cloud_conn_id = alibabacloud_conn_id
self.extras: dict = self.get_connection(self.alibaba_cloud_conn_id).extra_dejson

@classmethod
def get_connection_form_widgets(cls) -> dict[str, Any]:
"""Return connection widgets to add to connection form."""
from flask_appbuilder.fieldwidgets import BS3PasswordFieldWidget
from flask_babel import lazy_gettext
from wtforms import PasswordField

return {
"access_key_id": PasswordField(lazy_gettext("Access Key ID"), widget=BS3PasswordFieldWidget()),
"access_key_secret": PasswordField(
lazy_gettext("Access Key Secret"), widget=BS3PasswordFieldWidget()
),
}

@classmethod
def get_ui_field_behaviour(cls) -> dict[str, Any]:
"""Return custom field behaviour."""
return super().get_ui_field_behaviour()

def _get_field(self, field_name: str, default: Any = None) -> Any:
"""Fetch a field from extras, and returns it."""
value = self.extras.get(field_name)
return value if value is not None else default

def get_access_key_credential(self) -> AccessKeyCredentials:
"""
Fetch Access Key Credential for authentication.

:return: AccessKeyCredentials object containing access_key_id and access_key_secret.
"""
access_key_id = self._get_field("access_key_id", None)
access_key_secret = self._get_field("access_key_secret", None)
if not access_key_id:
raise ValueError("No access_key_id is specified.")

if not access_key_secret:
raise ValueError("No access_key_secret is specified.")

return AccessKeyCredentials(access_key_id, access_key_secret)
Loading
Loading