apache-airflow-providers-microsoft-azure 8.1.0__tar.gz → 8.2.0rc1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {apache-airflow-providers-microsoft-azure-8.1.0/apache_airflow_providers_microsoft_azure.egg-info → apache-airflow-providers-microsoft-azure-8.2.0rc1}/PKG-INFO +7 -9
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/README.rst +4 -6
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/__init__.py +1 -1
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/get_provider_info.py +1 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/adx.py +12 -2
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/asb.py +31 -6
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/base_azure.py +11 -2
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/batch.py +20 -10
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/container_instance.py +7 -1
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/container_registry.py +14 -3
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/container_volume.py +25 -17
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/cosmos.py +15 -4
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/data_factory.py +18 -2
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/data_lake.py +30 -14
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/fileshare.py +37 -21
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/synapse.py +17 -3
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/wasb.py +22 -4
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/operators/container_instances.py +5 -6
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/secrets/key_vault.py +22 -3
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/utils.py +80 -4
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1/apache_airflow_providers_microsoft_azure.egg-info}/PKG-INFO +7 -9
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/apache_airflow_providers_microsoft_azure.egg-info/requires.txt +1 -1
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/pyproject.toml +4 -6
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/setup.cfg +4 -4
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/setup.py +1 -1
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/LICENSE +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/MANIFEST.in +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/NOTICE +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/fs/__init__.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/fs/adls.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/hooks/__init__.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/log/__init__.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/log/wasb_task_handler.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/operators/__init__.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/operators/adls.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/operators/adx.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/operators/asb.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/operators/batch.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/operators/cosmos.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/operators/data_factory.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/operators/synapse.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/operators/wasb_delete_blob.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/secrets/__init__.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/sensors/__init__.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/sensors/cosmos.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/sensors/data_factory.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/sensors/wasb.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/transfers/__init__.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/transfers/azure_blob_to_gcs.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/transfers/local_to_adls.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/transfers/local_to_wasb.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/transfers/oracle_to_azure_data_lake.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/transfers/sftp_to_wasb.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/triggers/__init__.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/triggers/data_factory.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/airflow/providers/microsoft/azure/triggers/wasb.py +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/apache_airflow_providers_microsoft_azure.egg-info/SOURCES.txt +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/apache_airflow_providers_microsoft_azure.egg-info/dependency_links.txt +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/apache_airflow_providers_microsoft_azure.egg-info/entry_points.txt +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/apache_airflow_providers_microsoft_azure.egg-info/not-zip-safe +0 -0
- {apache-airflow-providers-microsoft-azure-8.1.0 → apache-airflow-providers-microsoft-azure-8.2.0rc1}/apache_airflow_providers_microsoft_azure.egg-info/top_level.txt +0 -0
@@ -1,14 +1,14 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: apache-airflow-providers-microsoft-azure
|
3
|
-
Version: 8.
|
3
|
+
Version: 8.2.0rc1
|
4
4
|
Summary: Provider for Apache Airflow. Implements apache-airflow-providers-microsoft-azure package
|
5
5
|
Home-page: https://airflow.apache.org/
|
6
6
|
Download-URL: https://archive.apache.org/dist/airflow/providers
|
7
7
|
Author: Apache Software Foundation
|
8
8
|
Author-email: dev@airflow.apache.org
|
9
9
|
License: Apache License 2.0
|
10
|
-
Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.
|
11
|
-
Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.
|
10
|
+
Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.2.0/
|
11
|
+
Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.2.0/changelog.html
|
12
12
|
Project-URL: Bug Tracker, https://github.com/apache/airflow/issues
|
13
13
|
Project-URL: Source Code, https://github.com/apache/airflow
|
14
14
|
Project-URL: Slack Chat, https://s.apache.org/airflow-slack
|
@@ -52,8 +52,7 @@ License-File: NOTICE
|
|
52
52
|
KIND, either express or implied. See the License for the
|
53
53
|
specific language governing permissions and limitations
|
54
54
|
under the License.
|
55
|
-
|
56
|
-
.. Licensed to the Apache Software Foundation (ASF) under one
|
55
|
+
.. Licensed to the Apache Software Foundation (ASF) under one
|
57
56
|
or more contributor license agreements. See the NOTICE file
|
58
57
|
distributed with this work for additional information
|
59
58
|
regarding copyright ownership. The ASF licenses this file
|
@@ -73,7 +72,7 @@ License-File: NOTICE
|
|
73
72
|
|
74
73
|
Package ``apache-airflow-providers-microsoft-azure``
|
75
74
|
|
76
|
-
Release: ``8.
|
75
|
+
Release: ``8.2.0rc1``
|
77
76
|
|
78
77
|
|
79
78
|
`Microsoft Azure <https://azure.microsoft.com/>`__
|
@@ -86,8 +85,7 @@ This is a provider package for ``microsoft.azure`` provider. All classes for thi
|
|
86
85
|
are in ``airflow.providers.microsoft.azure`` python package.
|
87
86
|
|
88
87
|
You can find package information and changelog for the provider
|
89
|
-
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.
|
90
|
-
|
88
|
+
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.2.0/>`_.
|
91
89
|
|
92
90
|
Installation
|
93
91
|
------------
|
@@ -149,4 +147,4 @@ Dependent package
|
|
149
147
|
==================================================================================================== ==========
|
150
148
|
|
151
149
|
The changelog for the provider package can be found in the
|
152
|
-
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.
|
150
|
+
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.2.0/changelog.html>`_.
|
@@ -15,8 +15,7 @@
|
|
15
15
|
KIND, either express or implied. See the License for the
|
16
16
|
specific language governing permissions and limitations
|
17
17
|
under the License.
|
18
|
-
|
19
|
-
.. Licensed to the Apache Software Foundation (ASF) under one
|
18
|
+
.. Licensed to the Apache Software Foundation (ASF) under one
|
20
19
|
or more contributor license agreements. See the NOTICE file
|
21
20
|
distributed with this work for additional information
|
22
21
|
regarding copyright ownership. The ASF licenses this file
|
@@ -36,7 +35,7 @@
|
|
36
35
|
|
37
36
|
Package ``apache-airflow-providers-microsoft-azure``
|
38
37
|
|
39
|
-
Release: ``8.
|
38
|
+
Release: ``8.2.0rc1``
|
40
39
|
|
41
40
|
|
42
41
|
`Microsoft Azure <https://azure.microsoft.com/>`__
|
@@ -49,8 +48,7 @@ This is a provider package for ``microsoft.azure`` provider. All classes for thi
|
|
49
48
|
are in ``airflow.providers.microsoft.azure`` python package.
|
50
49
|
|
51
50
|
You can find package information and changelog for the provider
|
52
|
-
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.
|
53
|
-
|
51
|
+
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.2.0/>`_.
|
54
52
|
|
55
53
|
Installation
|
56
54
|
------------
|
@@ -112,4 +110,4 @@ Dependent package
|
|
112
110
|
==================================================================================================== ==========
|
113
111
|
|
114
112
|
The changelog for the provider package can be found in the
|
115
|
-
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.
|
113
|
+
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-microsoft-azure/8.2.0/changelog.html>`_.
|
@@ -29,12 +29,15 @@ import warnings
|
|
29
29
|
from functools import cached_property
|
30
30
|
from typing import TYPE_CHECKING, Any
|
31
31
|
|
32
|
-
from azure.identity import DefaultAzureCredential
|
33
32
|
from azure.kusto.data import ClientRequestProperties, KustoClient, KustoConnectionStringBuilder
|
34
33
|
from azure.kusto.data.exceptions import KustoServiceError
|
35
34
|
|
36
35
|
from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
|
37
36
|
from airflow.hooks.base import BaseHook
|
37
|
+
from airflow.providers.microsoft.azure.utils import (
|
38
|
+
add_managed_identity_connection_widgets,
|
39
|
+
get_sync_default_azure_credential,
|
40
|
+
)
|
38
41
|
|
39
42
|
if TYPE_CHECKING:
|
40
43
|
from azure.kusto.data.response import KustoResponseDataSetV2
|
@@ -80,6 +83,7 @@ class AzureDataExplorerHook(BaseHook):
|
|
80
83
|
hook_name = "Azure Data Explorer"
|
81
84
|
|
82
85
|
@classmethod
|
86
|
+
@add_managed_identity_connection_widgets
|
83
87
|
def get_connection_form_widgets(cls) -> dict[str, Any]:
|
84
88
|
"""Returns connection widgets to add to connection form."""
|
85
89
|
from flask_appbuilder.fieldwidgets import BS3PasswordFieldWidget, BS3TextFieldWidget
|
@@ -192,9 +196,15 @@ class AzureDataExplorerHook(BaseHook):
|
|
192
196
|
elif auth_method == "AAD_DEVICE":
|
193
197
|
kcsb = KustoConnectionStringBuilder.with_aad_device_authentication(cluster)
|
194
198
|
elif auth_method == "AZURE_TOKEN_CRED":
|
199
|
+
managed_identity_client_id = conn.extra_dejson.get("managed_identity_client_id")
|
200
|
+
workload_identity_tenant_id = conn.extra_dejson.get("workload_identity_tenant_id")
|
201
|
+
credential = get_sync_default_azure_credential(
|
202
|
+
managed_identity_client_id=managed_identity_client_id,
|
203
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
204
|
+
)
|
195
205
|
kcsb = KustoConnectionStringBuilder.with_azure_token_credential(
|
196
206
|
connection_string=cluster,
|
197
|
-
credential=
|
207
|
+
credential=credential,
|
198
208
|
)
|
199
209
|
else:
|
200
210
|
raise AirflowException(f"Unknown authentication method: {auth_method}")
|
@@ -16,14 +16,20 @@
|
|
16
16
|
# under the License.
|
17
17
|
from __future__ import annotations
|
18
18
|
|
19
|
-
from typing import Any
|
19
|
+
from typing import TYPE_CHECKING, Any
|
20
20
|
|
21
|
-
from azure.identity import DefaultAzureCredential
|
22
21
|
from azure.servicebus import ServiceBusClient, ServiceBusMessage, ServiceBusSender
|
23
22
|
from azure.servicebus.management import QueueProperties, ServiceBusAdministrationClient
|
24
23
|
|
25
24
|
from airflow.hooks.base import BaseHook
|
26
|
-
from airflow.providers.microsoft.azure.utils import
|
25
|
+
from airflow.providers.microsoft.azure.utils import (
|
26
|
+
add_managed_identity_connection_widgets,
|
27
|
+
get_field,
|
28
|
+
get_sync_default_azure_credential,
|
29
|
+
)
|
30
|
+
|
31
|
+
if TYPE_CHECKING:
|
32
|
+
from azure.identity import DefaultAzureCredential
|
27
33
|
|
28
34
|
|
29
35
|
class BaseAzureServiceBusHook(BaseHook):
|
@@ -40,6 +46,7 @@ class BaseAzureServiceBusHook(BaseHook):
|
|
40
46
|
hook_name = "Azure Service Bus"
|
41
47
|
|
42
48
|
@staticmethod
|
49
|
+
@add_managed_identity_connection_widgets
|
43
50
|
def get_connection_form_widgets() -> dict[str, Any]:
|
44
51
|
"""Returns connection widgets to add to connection form."""
|
45
52
|
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
|
@@ -64,7 +71,7 @@ class BaseAzureServiceBusHook(BaseHook):
|
|
64
71
|
"<Resource group>.servicebus.windows.net (for Azure AD authenticaltion)"
|
65
72
|
),
|
66
73
|
"credential": "credential",
|
67
|
-
"schema": "Endpoint=sb://<Resource group>.servicebus.windows.net/;SharedAccessKeyName=<AccessKeyName>;SharedAccessKey=<SharedAccessKey>",
|
74
|
+
"schema": "Endpoint=sb://<Resource group>.servicebus.windows.net/;SharedAccessKeyName=<AccessKeyName>;SharedAccessKey=<SharedAccessKey>",
|
68
75
|
},
|
69
76
|
}
|
70
77
|
|
@@ -106,7 +113,16 @@ class AdminClientHook(BaseAzureServiceBusHook):
|
|
106
113
|
credential: str | DefaultAzureCredential = self._get_field(extras=extras, field_name="credential")
|
107
114
|
fully_qualified_namespace = self._get_field(extras=extras, field_name="fully_qualified_namespace")
|
108
115
|
if not credential:
|
109
|
-
|
116
|
+
managed_identity_client_id = self._get_field(
|
117
|
+
extras=extras, field_name="managed_identity_client_id"
|
118
|
+
)
|
119
|
+
workload_identity_tenant_id = self._get_field(
|
120
|
+
extras=extras, field_name="workload_identity_tenant_id"
|
121
|
+
)
|
122
|
+
credential = get_sync_default_azure_credential(
|
123
|
+
managed_identity_client_id=managed_identity_client_id,
|
124
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
125
|
+
)
|
110
126
|
client = ServiceBusAdministrationClient(
|
111
127
|
fully_qualified_namespace=fully_qualified_namespace,
|
112
128
|
credential=credential, # type: ignore[arg-type]
|
@@ -190,7 +206,16 @@ class MessageHook(BaseAzureServiceBusHook):
|
|
190
206
|
credential: str | DefaultAzureCredential = self._get_field(extras=extras, field_name="credential")
|
191
207
|
fully_qualified_namespace = self._get_field(extras=extras, field_name="fully_qualified_namespace")
|
192
208
|
if not credential:
|
193
|
-
|
209
|
+
managed_identity_client_id = self._get_field(
|
210
|
+
extras=extras, field_name="managed_identity_client_id"
|
211
|
+
)
|
212
|
+
workload_identity_tenant_id = self._get_field(
|
213
|
+
extras=extras, field_name="workload_identity_tenant_id"
|
214
|
+
)
|
215
|
+
credential = get_sync_default_azure_credential(
|
216
|
+
managed_identity_client_id=managed_identity_client_id,
|
217
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
218
|
+
)
|
194
219
|
client = ServiceBusClient(
|
195
220
|
fully_qualified_namespace=fully_qualified_namespace,
|
196
221
|
credential=credential, # type: ignore[arg-type]
|
@@ -24,7 +24,10 @@ from azure.common.credentials import ServicePrincipalCredentials
|
|
24
24
|
|
25
25
|
from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
|
26
26
|
from airflow.hooks.base import BaseHook
|
27
|
-
from airflow.providers.microsoft.azure.utils import
|
27
|
+
from airflow.providers.microsoft.azure.utils import (
|
28
|
+
AzureIdentityCredentialAdapter,
|
29
|
+
add_managed_identity_connection_widgets,
|
30
|
+
)
|
28
31
|
|
29
32
|
|
30
33
|
class AzureBaseHook(BaseHook):
|
@@ -45,6 +48,7 @@ class AzureBaseHook(BaseHook):
|
|
45
48
|
hook_name = "Azure"
|
46
49
|
|
47
50
|
@staticmethod
|
51
|
+
@add_managed_identity_connection_widgets
|
48
52
|
def get_connection_form_widgets() -> dict[str, Any]:
|
49
53
|
"""Returns connection widgets to add to connection form."""
|
50
54
|
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
|
@@ -133,7 +137,12 @@ class AzureBaseHook(BaseHook):
|
|
133
137
|
)
|
134
138
|
else:
|
135
139
|
self.log.info("Using DefaultAzureCredential as credential")
|
136
|
-
|
140
|
+
managed_identity_client_id = conn.extra_dejson.get("managed_identity_client_id")
|
141
|
+
workload_identity_tenant_id = conn.extra_dejson.get("workload_identity_tenant_id")
|
142
|
+
credentials = AzureIdentityCredentialAdapter(
|
143
|
+
managed_identity_client_id=managed_identity_client_id,
|
144
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
145
|
+
)
|
137
146
|
|
138
147
|
return self.sdk_client(
|
139
148
|
credentials=credentials,
|
@@ -26,7 +26,11 @@ from azure.batch import BatchServiceClient, batch_auth, models as batch_models
|
|
26
26
|
|
27
27
|
from airflow.exceptions import AirflowException
|
28
28
|
from airflow.hooks.base import BaseHook
|
29
|
-
from airflow.providers.microsoft.azure.utils import
|
29
|
+
from airflow.providers.microsoft.azure.utils import (
|
30
|
+
AzureIdentityCredentialAdapter,
|
31
|
+
add_managed_identity_connection_widgets,
|
32
|
+
get_field,
|
33
|
+
)
|
30
34
|
from airflow.utils import timezone
|
31
35
|
|
32
36
|
if TYPE_CHECKING:
|
@@ -46,15 +50,8 @@ class AzureBatchHook(BaseHook):
|
|
46
50
|
conn_type = "azure_batch"
|
47
51
|
hook_name = "Azure Batch Service"
|
48
52
|
|
49
|
-
def _get_field(self, extras, name):
|
50
|
-
return get_field(
|
51
|
-
conn_id=self.conn_id,
|
52
|
-
conn_type=self.conn_type,
|
53
|
-
extras=extras,
|
54
|
-
field_name=name,
|
55
|
-
)
|
56
|
-
|
57
53
|
@classmethod
|
54
|
+
@add_managed_identity_connection_widgets
|
58
55
|
def get_connection_form_widgets(cls) -> dict[str, Any]:
|
59
56
|
"""Returns connection widgets to add to connection form."""
|
60
57
|
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
|
@@ -80,6 +77,14 @@ class AzureBatchHook(BaseHook):
|
|
80
77
|
super().__init__()
|
81
78
|
self.conn_id = azure_batch_conn_id
|
82
79
|
|
80
|
+
def _get_field(self, extras, name):
|
81
|
+
return get_field(
|
82
|
+
conn_id=self.conn_id,
|
83
|
+
conn_type=self.conn_type,
|
84
|
+
extras=extras,
|
85
|
+
field_name=name,
|
86
|
+
)
|
87
|
+
|
83
88
|
@cached_property
|
84
89
|
def connection(self) -> BatchServiceClient:
|
85
90
|
"""Get the Batch client connection (cached)."""
|
@@ -101,8 +106,13 @@ class AzureBatchHook(BaseHook):
|
|
101
106
|
if all([conn.login, conn.password]):
|
102
107
|
credentials = batch_auth.SharedKeyCredentials(conn.login, conn.password)
|
103
108
|
else:
|
109
|
+
managed_identity_client_id = conn.extra_dejson.get("managed_identity_client_id")
|
110
|
+
workload_identity_tenant_id = conn.extra_dejson.get("workload_identity_tenant_id")
|
104
111
|
credentials = AzureIdentityCredentialAdapter(
|
105
|
-
None,
|
112
|
+
None,
|
113
|
+
resource_id="https://batch.core.windows.net/.default",
|
114
|
+
managed_identity_client_id=managed_identity_client_id,
|
115
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
106
116
|
)
|
107
117
|
|
108
118
|
batch_client = BatchServiceClient(credentials, batch_url=batch_account_url)
|
@@ -27,6 +27,7 @@ from azure.mgmt.containerinstance import ContainerInstanceManagementClient
|
|
27
27
|
|
28
28
|
from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
|
29
29
|
from airflow.providers.microsoft.azure.hooks.base_azure import AzureBaseHook
|
30
|
+
from airflow.providers.microsoft.azure.utils import get_sync_default_azure_credential
|
30
31
|
|
31
32
|
if TYPE_CHECKING:
|
32
33
|
from azure.mgmt.containerinstance.models import (
|
@@ -92,7 +93,12 @@ class AzureContainerInstanceHook(AzureBaseHook):
|
|
92
93
|
)
|
93
94
|
else:
|
94
95
|
self.log.info("Using DefaultAzureCredential as credential")
|
95
|
-
|
96
|
+
managed_identity_client_id = conn.extra_dejson.get("managed_identity_client_id")
|
97
|
+
workload_identity_tenant_id = conn.extra_dejson.get("workload_identity_tenant_id")
|
98
|
+
credential = get_sync_default_azure_credential(
|
99
|
+
managed_identity_client_id=managed_identity_client_id,
|
100
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
101
|
+
)
|
96
102
|
|
97
103
|
subscription_id = cast(str, conn.extra_dejson.get("subscriptionId"))
|
98
104
|
return ContainerInstanceManagementClient(
|
@@ -21,12 +21,15 @@ from __future__ import annotations
|
|
21
21
|
from functools import cached_property
|
22
22
|
from typing import Any
|
23
23
|
|
24
|
-
from azure.identity import DefaultAzureCredential
|
25
24
|
from azure.mgmt.containerinstance.models import ImageRegistryCredential
|
26
25
|
from azure.mgmt.containerregistry import ContainerRegistryManagementClient
|
27
26
|
|
28
27
|
from airflow.hooks.base import BaseHook
|
29
|
-
from airflow.providers.microsoft.azure.utils import
|
28
|
+
from airflow.providers.microsoft.azure.utils import (
|
29
|
+
add_managed_identity_connection_widgets,
|
30
|
+
get_field,
|
31
|
+
get_sync_default_azure_credential,
|
32
|
+
)
|
30
33
|
|
31
34
|
|
32
35
|
class AzureContainerRegistryHook(BaseHook):
|
@@ -44,6 +47,7 @@ class AzureContainerRegistryHook(BaseHook):
|
|
44
47
|
hook_name = "Azure Container Registry"
|
45
48
|
|
46
49
|
@staticmethod
|
50
|
+
@add_managed_identity_connection_widgets
|
47
51
|
def get_connection_form_widgets() -> dict[str, Any]:
|
48
52
|
"""Returns connection widgets to add to connection form."""
|
49
53
|
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
|
@@ -103,8 +107,15 @@ class AzureContainerRegistryHook(BaseHook):
|
|
103
107
|
extras = conn.extra_dejson
|
104
108
|
subscription_id = self._get_field(extras, "subscription_id")
|
105
109
|
resource_group = self._get_field(extras, "resource_group")
|
110
|
+
managed_identity_client_id = self._get_field(extras, "managed_identity_client_id")
|
111
|
+
workload_identity_tenant_id = self._get_field(extras, "workload_identity_tenant_id")
|
112
|
+
credential = get_sync_default_azure_credential(
|
113
|
+
managed_identity_client_id=managed_identity_client_id,
|
114
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
115
|
+
)
|
106
116
|
client = ContainerRegistryManagementClient(
|
107
|
-
credential=
|
117
|
+
credential=credential,
|
118
|
+
subscription_id=subscription_id,
|
108
119
|
)
|
109
120
|
credentials = client.registries.list_credentials(resource_group, conn.login).as_dict()
|
110
121
|
password = credentials["passwords"][0]["value"]
|
@@ -1,4 +1,3 @@
|
|
1
|
-
#
|
2
1
|
# Licensed to the Apache Software Foundation (ASF) under one
|
3
2
|
# or more contributor license agreements. See the NOTICE file
|
4
3
|
# distributed with this work for additional information
|
@@ -19,12 +18,15 @@ from __future__ import annotations
|
|
19
18
|
|
20
19
|
from typing import Any
|
21
20
|
|
22
|
-
from azure.identity import DefaultAzureCredential
|
23
21
|
from azure.mgmt.containerinstance.models import AzureFileVolume, Volume
|
24
22
|
from azure.mgmt.storage import StorageManagementClient
|
25
23
|
|
26
24
|
from airflow.hooks.base import BaseHook
|
27
|
-
from airflow.providers.microsoft.azure.utils import
|
25
|
+
from airflow.providers.microsoft.azure.utils import (
|
26
|
+
add_managed_identity_connection_widgets,
|
27
|
+
get_field,
|
28
|
+
get_sync_default_azure_credential,
|
29
|
+
)
|
28
30
|
|
29
31
|
|
30
32
|
class AzureContainerVolumeHook(BaseHook):
|
@@ -41,19 +43,8 @@ class AzureContainerVolumeHook(BaseHook):
|
|
41
43
|
conn_type = "azure_container_volume"
|
42
44
|
hook_name = "Azure Container Volume"
|
43
45
|
|
44
|
-
def __init__(self, azure_container_volume_conn_id: str = "azure_container_volume_default") -> None:
|
45
|
-
super().__init__()
|
46
|
-
self.conn_id = azure_container_volume_conn_id
|
47
|
-
|
48
|
-
def _get_field(self, extras, name):
|
49
|
-
return get_field(
|
50
|
-
conn_id=self.conn_id,
|
51
|
-
conn_type=self.conn_type,
|
52
|
-
extras=extras,
|
53
|
-
field_name=name,
|
54
|
-
)
|
55
|
-
|
56
46
|
@staticmethod
|
47
|
+
@add_managed_identity_connection_widgets
|
57
48
|
def get_connection_form_widgets() -> dict[str, Any]:
|
58
49
|
"""Returns connection widgets to add to connection form."""
|
59
50
|
from flask_appbuilder.fieldwidgets import BS3PasswordFieldWidget, BS3TextFieldWidget
|
@@ -92,6 +83,18 @@ class AzureContainerVolumeHook(BaseHook):
|
|
92
83
|
},
|
93
84
|
}
|
94
85
|
|
86
|
+
def __init__(self, azure_container_volume_conn_id: str = "azure_container_volume_default") -> None:
|
87
|
+
super().__init__()
|
88
|
+
self.conn_id = azure_container_volume_conn_id
|
89
|
+
|
90
|
+
def _get_field(self, extras, name):
|
91
|
+
return get_field(
|
92
|
+
conn_id=self.conn_id,
|
93
|
+
conn_type=self.conn_type,
|
94
|
+
extras=extras,
|
95
|
+
field_name=name,
|
96
|
+
)
|
97
|
+
|
95
98
|
def get_storagekey(self, *, storage_account_name: str | None = None) -> str:
|
96
99
|
"""Get Azure File Volume storage key."""
|
97
100
|
conn = self.get_connection(self.conn_id)
|
@@ -106,8 +109,13 @@ class AzureContainerVolumeHook(BaseHook):
|
|
106
109
|
subscription_id = self._get_field(extras, "subscription_id")
|
107
110
|
resource_group = self._get_field(extras, "resource_group")
|
108
111
|
if subscription_id and storage_account_name and resource_group:
|
109
|
-
|
110
|
-
|
112
|
+
managed_identity_client_id = self._get_field(extras, "managed_identity_client_id")
|
113
|
+
workload_identity_tenant_id = self._get_field(extras, "workload_identity_tenant_id")
|
114
|
+
credential = get_sync_default_azure_credential(
|
115
|
+
managed_identity_client_id=managed_identity_client_id,
|
116
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
117
|
+
)
|
118
|
+
storage_client = StorageManagementClient(credential, subscription_id)
|
111
119
|
storage_account_list_keys_result = storage_client.storage_accounts.list_keys(
|
112
120
|
resource_group, storage_account_name
|
113
121
|
)
|
@@ -31,12 +31,15 @@ from urllib.parse import urlparse
|
|
31
31
|
|
32
32
|
from azure.cosmos.cosmos_client import CosmosClient
|
33
33
|
from azure.cosmos.exceptions import CosmosHttpResponseError
|
34
|
-
from azure.identity import DefaultAzureCredential
|
35
34
|
from azure.mgmt.cosmosdb import CosmosDBManagementClient
|
36
35
|
|
37
36
|
from airflow.exceptions import AirflowBadRequest, AirflowException
|
38
37
|
from airflow.hooks.base import BaseHook
|
39
|
-
from airflow.providers.microsoft.azure.utils import
|
38
|
+
from airflow.providers.microsoft.azure.utils import (
|
39
|
+
add_managed_identity_connection_widgets,
|
40
|
+
get_field,
|
41
|
+
get_sync_default_azure_credential,
|
42
|
+
)
|
40
43
|
|
41
44
|
|
42
45
|
class AzureCosmosDBHook(BaseHook):
|
@@ -57,6 +60,7 @@ class AzureCosmosDBHook(BaseHook):
|
|
57
60
|
hook_name = "Azure CosmosDB"
|
58
61
|
|
59
62
|
@staticmethod
|
63
|
+
@add_managed_identity_connection_widgets
|
60
64
|
def get_connection_form_widgets() -> dict[str, Any]:
|
61
65
|
"""Returns connection widgets to add to connection form."""
|
62
66
|
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
|
@@ -126,9 +130,16 @@ class AzureCosmosDBHook(BaseHook):
|
|
126
130
|
if conn.password:
|
127
131
|
master_key = conn.password
|
128
132
|
elif resource_group_name:
|
133
|
+
managed_identity_client_id = self._get_field(extras, "managed_identity_client_id")
|
134
|
+
workload_identity_tenant_id = self._get_field(extras, "workload_identity_tenant_id")
|
135
|
+
subscritption_id = self._get_field(extras, "subscription_id")
|
136
|
+
credential = get_sync_default_azure_credential(
|
137
|
+
managed_identity_client_id=managed_identity_client_id,
|
138
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
139
|
+
)
|
129
140
|
management_client = CosmosDBManagementClient(
|
130
|
-
credential=
|
131
|
-
subscription_id=
|
141
|
+
credential=credential,
|
142
|
+
subscription_id=subscritption_id,
|
132
143
|
)
|
133
144
|
|
134
145
|
database_account = urlparse(conn.login).netloc.split(".")[0]
|
@@ -48,6 +48,11 @@ from azure.mgmt.datafactory.aio import DataFactoryManagementClient as AsyncDataF
|
|
48
48
|
|
49
49
|
from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
|
50
50
|
from airflow.hooks.base import BaseHook
|
51
|
+
from airflow.providers.microsoft.azure.utils import (
|
52
|
+
add_managed_identity_connection_widgets,
|
53
|
+
get_async_default_azure_credential,
|
54
|
+
get_sync_default_azure_credential,
|
55
|
+
)
|
51
56
|
|
52
57
|
if TYPE_CHECKING:
|
53
58
|
from azure.core.polling import LROPoller
|
@@ -152,6 +157,7 @@ class AzureDataFactoryHook(BaseHook):
|
|
152
157
|
hook_name: str = "Azure Data Factory"
|
153
158
|
|
154
159
|
@staticmethod
|
160
|
+
@add_managed_identity_connection_widgets
|
155
161
|
def get_connection_form_widgets() -> dict[str, Any]:
|
156
162
|
"""Returns connection widgets to add to connection form."""
|
157
163
|
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
|
@@ -205,7 +211,12 @@ class AzureDataFactoryHook(BaseHook):
|
|
205
211
|
client_id=conn.login, client_secret=conn.password, tenant_id=tenant
|
206
212
|
)
|
207
213
|
else:
|
208
|
-
|
214
|
+
managed_identity_client_id = get_field(extras, "managed_identity_client_id")
|
215
|
+
workload_identity_tenant_id = get_field(extras, "workload_identity_tenant_id")
|
216
|
+
credential = get_sync_default_azure_credential(
|
217
|
+
managed_identity_client_id=managed_identity_client_id,
|
218
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
219
|
+
)
|
209
220
|
self._conn = self._create_client(credential, subscription_id)
|
210
221
|
|
211
222
|
return self._conn
|
@@ -1140,7 +1151,12 @@ class AzureDataFactoryAsyncHook(AzureDataFactoryHook):
|
|
1140
1151
|
client_id=conn.login, client_secret=conn.password, tenant_id=tenant
|
1141
1152
|
)
|
1142
1153
|
else:
|
1143
|
-
|
1154
|
+
managed_identity_client_id = get_field(extras, "managed_identity_client_id")
|
1155
|
+
workload_identity_tenant_id = get_field(extras, "workload_identity_tenant_id")
|
1156
|
+
credential = get_async_default_azure_credential(
|
1157
|
+
managed_identity_client_id=managed_identity_client_id,
|
1158
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
1159
|
+
)
|
1144
1160
|
|
1145
1161
|
self._async_conn = AsyncDataFactoryManagementClient(
|
1146
1162
|
credential=credential,
|
@@ -34,7 +34,11 @@ from azure.storage.filedatalake import (
|
|
34
34
|
|
35
35
|
from airflow.exceptions import AirflowException
|
36
36
|
from airflow.hooks.base import BaseHook
|
37
|
-
from airflow.providers.microsoft.azure.utils import
|
37
|
+
from airflow.providers.microsoft.azure.utils import (
|
38
|
+
AzureIdentityCredentialAdapter,
|
39
|
+
add_managed_identity_connection_widgets,
|
40
|
+
get_field,
|
41
|
+
)
|
38
42
|
|
39
43
|
Credentials = Union[ClientSecretCredential, AzureIdentityCredentialAdapter]
|
40
44
|
|
@@ -62,6 +66,7 @@ class AzureDataLakeHook(BaseHook):
|
|
62
66
|
hook_name = "Azure Data Lake"
|
63
67
|
|
64
68
|
@staticmethod
|
69
|
+
@add_managed_identity_connection_widgets
|
65
70
|
def get_connection_form_widgets() -> dict[str, Any]:
|
66
71
|
"""Returns connection widgets to add to connection form."""
|
67
72
|
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
|
@@ -118,7 +123,12 @@ class AzureDataLakeHook(BaseHook):
|
|
118
123
|
if tenant:
|
119
124
|
credential = lib.auth(tenant_id=tenant, client_secret=conn.password, client_id=conn.login)
|
120
125
|
else:
|
121
|
-
|
126
|
+
managed_identity_client_id = self._get_field(extras, "managed_identity_client_id")
|
127
|
+
workload_identity_tenant_id = self._get_field(extras, "workload_identity_tenant_id")
|
128
|
+
credential = AzureIdentityCredentialAdapter(
|
129
|
+
managed_identity_client_id=managed_identity_client_id,
|
130
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
131
|
+
)
|
122
132
|
self._conn = core.AzureDLFileSystem(credential, store_name=self.account_name)
|
123
133
|
self._conn.connect()
|
124
134
|
return self._conn
|
@@ -265,6 +275,7 @@ class AzureDataLakeStorageV2Hook(BaseHook):
|
|
265
275
|
hook_name = "Azure Date Lake Storage V2"
|
266
276
|
|
267
277
|
@classmethod
|
278
|
+
@add_managed_identity_connection_widgets
|
268
279
|
def get_connection_form_widgets(cls) -> dict[str, Any]:
|
269
280
|
"""Returns connection widgets to add to connection form."""
|
270
281
|
from flask_appbuilder.fieldwidgets import BS3PasswordFieldWidget, BS3TextFieldWidget
|
@@ -305,6 +316,17 @@ class AzureDataLakeStorageV2Hook(BaseHook):
|
|
305
316
|
self.conn_id = adls_conn_id
|
306
317
|
self.public_read = public_read
|
307
318
|
|
319
|
+
def _get_field(self, extra_dict, field_name):
|
320
|
+
prefix = "extra__adls__"
|
321
|
+
if field_name.startswith("extra__"):
|
322
|
+
raise ValueError(
|
323
|
+
f"Got prefixed name {field_name}; please remove the '{prefix}' prefix "
|
324
|
+
f"when using this method."
|
325
|
+
)
|
326
|
+
if field_name in extra_dict:
|
327
|
+
return extra_dict[field_name] or None
|
328
|
+
return extra_dict.get(f"{prefix}{field_name}") or None
|
329
|
+
|
308
330
|
@cached_property
|
309
331
|
def service_client(self) -> DataLakeServiceClient:
|
310
332
|
"""Return the DataLakeServiceClient object (cached)."""
|
@@ -330,7 +352,12 @@ class AzureDataLakeStorageV2Hook(BaseHook):
|
|
330
352
|
elif conn.password:
|
331
353
|
credential = conn.password
|
332
354
|
else:
|
333
|
-
|
355
|
+
managed_identity_client_id = self._get_field(extra, "managed_identity_client_id")
|
356
|
+
workload_identity_tenant_id = self._get_field(extra, "workload_identity_tenant_id")
|
357
|
+
credential = AzureIdentityCredentialAdapter(
|
358
|
+
managed_identity_client_id=managed_identity_client_id,
|
359
|
+
workload_identity_tenant_id=workload_identity_tenant_id,
|
360
|
+
)
|
334
361
|
|
335
362
|
return DataLakeServiceClient(
|
336
363
|
account_url=f"https://{conn.host}.dfs.core.windows.net",
|
@@ -338,17 +365,6 @@ class AzureDataLakeStorageV2Hook(BaseHook):
|
|
338
365
|
**extra,
|
339
366
|
)
|
340
367
|
|
341
|
-
def _get_field(self, extra_dict, field_name):
|
342
|
-
prefix = "extra__adls__"
|
343
|
-
if field_name.startswith("extra__"):
|
344
|
-
raise ValueError(
|
345
|
-
f"Got prefixed name {field_name}; please remove the '{prefix}' prefix "
|
346
|
-
f"when using this method."
|
347
|
-
)
|
348
|
-
if field_name in extra_dict:
|
349
|
-
return extra_dict[field_name] or None
|
350
|
-
return extra_dict.get(f"{prefix}{field_name}") or None
|
351
|
-
|
352
368
|
def create_file_system(self, file_system_name: str) -> None:
|
353
369
|
"""Create a new file system under the specified account.
|
354
370
|
|