airbyte-source-azure-blob-storage 0.4.4__tar.gz → 0.5.0__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.
Potentially problematic release.
This version of airbyte-source-azure-blob-storage might be problematic. Click here for more details.
- {airbyte_source_azure_blob_storage-0.4.4 → airbyte_source_azure_blob_storage-0.5.0}/PKG-INFO +1 -1
- {airbyte_source_azure_blob_storage-0.4.4 → airbyte_source_azure_blob_storage-0.5.0}/pyproject.toml +1 -1
- {airbyte_source_azure_blob_storage-0.4.4 → airbyte_source_azure_blob_storage-0.5.0}/source_azure_blob_storage/config_migrations.py +3 -4
- {airbyte_source_azure_blob_storage-0.4.4 → airbyte_source_azure_blob_storage-0.5.0}/source_azure_blob_storage/spec.py +22 -2
- {airbyte_source_azure_blob_storage-0.4.4 → airbyte_source_azure_blob_storage-0.5.0}/source_azure_blob_storage/stream_reader.py +55 -8
- {airbyte_source_azure_blob_storage-0.4.4 → airbyte_source_azure_blob_storage-0.5.0}/README.md +0 -0
- {airbyte_source_azure_blob_storage-0.4.4 → airbyte_source_azure_blob_storage-0.5.0}/source_azure_blob_storage/__init__.py +0 -0
- {airbyte_source_azure_blob_storage-0.4.4 → airbyte_source_azure_blob_storage-0.5.0}/source_azure_blob_storage/run.py +0 -0
- {airbyte_source_azure_blob_storage-0.4.4 → airbyte_source_azure_blob_storage-0.5.0}/source_azure_blob_storage/source.py +0 -0
|
@@ -9,19 +9,18 @@ from typing import Any, List, Mapping
|
|
|
9
9
|
|
|
10
10
|
from airbyte_cdk import AirbyteEntrypoint, Source, create_connector_config_control_message
|
|
11
11
|
|
|
12
|
+
|
|
12
13
|
logger = logging.getLogger("airbyte_logger")
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class MigrateConfig(ABC):
|
|
16
17
|
@classmethod
|
|
17
18
|
@abstractmethod
|
|
18
|
-
def should_migrate(cls, config: Mapping[str, Any]) -> bool:
|
|
19
|
-
...
|
|
19
|
+
def should_migrate(cls, config: Mapping[str, Any]) -> bool: ...
|
|
20
20
|
|
|
21
21
|
@classmethod
|
|
22
22
|
@abstractmethod
|
|
23
|
-
def migrate_config(cls, config: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
24
|
-
...
|
|
23
|
+
def migrate_config(cls, config: Mapping[str, Any]) -> Mapping[str, Any]: ...
|
|
25
24
|
|
|
26
25
|
@classmethod
|
|
27
26
|
def modify_and_save(cls, config_path: str, source: Source, config: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
from typing import Any, Dict, Literal, Optional, Union
|
|
7
7
|
|
|
8
8
|
import dpath.util
|
|
9
|
+
from pydantic import AnyUrl, BaseModel, Field
|
|
10
|
+
|
|
9
11
|
from airbyte_cdk import OneOfOptionConfig
|
|
10
12
|
from airbyte_cdk.sources.file_based.config.abstract_file_based_spec import AbstractFileBasedSpec
|
|
11
|
-
from pydantic import AnyUrl, BaseModel, Field
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class Oauth2(BaseModel):
|
|
@@ -35,6 +36,25 @@ class Oauth2(BaseModel):
|
|
|
35
36
|
)
|
|
36
37
|
|
|
37
38
|
|
|
39
|
+
class ClientCredentials(BaseModel):
|
|
40
|
+
class Config(OneOfOptionConfig):
|
|
41
|
+
title = "Authenticate via Client Credentials"
|
|
42
|
+
discriminator = "auth_type"
|
|
43
|
+
|
|
44
|
+
auth_type: Literal["client_credentials"] = Field("client_credentials", const=True)
|
|
45
|
+
app_tenant_id: str = Field(title="Tenant ID", description="Tenant ID of the Microsoft Azure Application", airbyte_secret=True)
|
|
46
|
+
app_client_id: str = Field(
|
|
47
|
+
title="Client ID",
|
|
48
|
+
description="Client ID of your Microsoft developer application",
|
|
49
|
+
airbyte_secret=True,
|
|
50
|
+
)
|
|
51
|
+
app_client_secret: str = Field(
|
|
52
|
+
title="Client Secret",
|
|
53
|
+
description="Client Secret of your Microsoft developer application",
|
|
54
|
+
airbyte_secret=True,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
38
58
|
class StorageAccountKey(BaseModel):
|
|
39
59
|
class Config(OneOfOptionConfig):
|
|
40
60
|
title = "Authenticate via Storage Account Key"
|
|
@@ -60,7 +80,7 @@ class SourceAzureBlobStorageSpec(AbstractFileBasedSpec):
|
|
|
60
80
|
def documentation_url(cls) -> AnyUrl:
|
|
61
81
|
return AnyUrl("https://docs.airbyte.com/integrations/sources/azure-blob-storage", scheme="https")
|
|
62
82
|
|
|
63
|
-
credentials: Union[Oauth2, StorageAccountKey] = Field(
|
|
83
|
+
credentials: Union[Oauth2, ClientCredentials, StorageAccountKey] = Field(
|
|
64
84
|
title="Authentication",
|
|
65
85
|
description="Credentials for connecting to the Azure Blob Storage",
|
|
66
86
|
discriminator="auth_type",
|
|
@@ -3,22 +3,62 @@
|
|
|
3
3
|
|
|
4
4
|
import logging
|
|
5
5
|
from io import IOBase
|
|
6
|
-
from typing import Iterable, List, Optional, Union
|
|
6
|
+
from typing import Any, Iterable, List, Mapping, MutableMapping, Optional, Union
|
|
7
7
|
|
|
8
8
|
import pytz
|
|
9
|
+
from azure.core.credentials import AccessToken, TokenCredential
|
|
10
|
+
from azure.core.exceptions import ResourceNotFoundError
|
|
11
|
+
from azure.storage.blob import BlobServiceClient, ContainerClient
|
|
12
|
+
from smart_open import open
|
|
13
|
+
|
|
9
14
|
from airbyte_cdk import AirbyteTracedException, FailureType
|
|
10
15
|
from airbyte_cdk.sources.file_based.file_based_stream_reader import AbstractFileBasedStreamReader, FileReadMode
|
|
11
16
|
from airbyte_cdk.sources.file_based.remote_file import RemoteFile
|
|
12
17
|
from airbyte_cdk.sources.streams.http.requests_native_auth import Oauth2Authenticator
|
|
13
|
-
from azure.core.credentials import AccessToken
|
|
14
|
-
from azure.core.exceptions import ResourceNotFoundError
|
|
15
|
-
from azure.storage.blob import BlobServiceClient, ContainerClient
|
|
16
|
-
from smart_open import open
|
|
17
18
|
|
|
18
19
|
from .spec import SourceAzureBlobStorageSpec
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
class
|
|
22
|
+
class AzureClientCredentialsAuthenticator(Oauth2Authenticator, TokenCredential):
|
|
23
|
+
def __init__(self, tenant_id: str, client_id: str, client_secret: str, **kwargs):
|
|
24
|
+
super().__init__(
|
|
25
|
+
token_refresh_endpoint=f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token",
|
|
26
|
+
client_id=client_id,
|
|
27
|
+
client_secret=client_secret,
|
|
28
|
+
grant_type="client_credentials",
|
|
29
|
+
scopes=["https://storage.azure.com/.default"],
|
|
30
|
+
refresh_token=None,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def build_refresh_request_body(self) -> Mapping[str, Any]:
|
|
34
|
+
"""
|
|
35
|
+
Returns the request body to set on the refresh request
|
|
36
|
+
|
|
37
|
+
Override to define additional parameters
|
|
38
|
+
"""
|
|
39
|
+
payload: MutableMapping[str, Any] = {
|
|
40
|
+
"grant_type": self.get_grant_type(),
|
|
41
|
+
"client_id": self.get_client_id(),
|
|
42
|
+
"client_secret": self.get_client_secret(),
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if self.get_scopes():
|
|
46
|
+
payload["scope"] = " ".join(self.get_scopes())
|
|
47
|
+
|
|
48
|
+
if self.get_refresh_request_body():
|
|
49
|
+
for key, val in self.get_refresh_request_body().items():
|
|
50
|
+
# We defer to existing oauth constructs over custom configured fields
|
|
51
|
+
if key not in payload:
|
|
52
|
+
payload[key] = val
|
|
53
|
+
|
|
54
|
+
return payload
|
|
55
|
+
|
|
56
|
+
def get_token(self, *args, **kwargs) -> AccessToken:
|
|
57
|
+
"""Parent class handles Oauth Refresh token logic."""
|
|
58
|
+
return AccessToken(token=self.get_access_token(), expires_on=int(self.get_token_expiry_date().timestamp()))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class AzureOauth2Authenticator(Oauth2Authenticator, TokenCredential):
|
|
22
62
|
"""
|
|
23
63
|
Authenticator for Azure Blob Storage SDK to align with azure.core.credentials.TokenCredential protocol
|
|
24
64
|
"""
|
|
@@ -62,17 +102,24 @@ class SourceAzureBlobStorageStreamReader(AbstractFileBasedStreamReader):
|
|
|
62
102
|
return BlobServiceClient(self.account_url, credential=self._credentials)
|
|
63
103
|
|
|
64
104
|
@property
|
|
65
|
-
def azure_credentials(self) -> Union[str, AzureOauth2Authenticator]:
|
|
105
|
+
def azure_credentials(self) -> Union[str, AzureOauth2Authenticator, AzureClientCredentialsAuthenticator]:
|
|
66
106
|
if not self._credentials:
|
|
67
107
|
if self.config.credentials.auth_type == "storage_account_key":
|
|
68
108
|
self._credentials = self.config.credentials.azure_blob_storage_account_key
|
|
69
|
-
|
|
109
|
+
elif self.config.credentials.auth_type == "oauth2":
|
|
70
110
|
self._credentials = AzureOauth2Authenticator(
|
|
71
111
|
token_refresh_endpoint=f"https://login.microsoftonline.com/{self.config.credentials.tenant_id}/oauth2/v2.0/token",
|
|
72
112
|
client_id=self.config.credentials.client_id,
|
|
73
113
|
client_secret=self.config.credentials.client_secret,
|
|
74
114
|
refresh_token=self.config.credentials.refresh_token,
|
|
75
115
|
)
|
|
116
|
+
elif self.config.credentials.auth_type == "client_credentials":
|
|
117
|
+
self._credentials = AzureClientCredentialsAuthenticator(
|
|
118
|
+
tenant_id=self.config.credentials.app_tenant_id,
|
|
119
|
+
client_id=self.config.credentials.app_client_id,
|
|
120
|
+
client_secret=self.config.credentials.app_client_secret,
|
|
121
|
+
)
|
|
122
|
+
|
|
76
123
|
return self._credentials
|
|
77
124
|
|
|
78
125
|
def get_matching_files(
|
{airbyte_source_azure_blob_storage-0.4.4 → airbyte_source_azure_blob_storage-0.5.0}/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|