elaunira-airflow-provider-r2index 0.3.0__tar.gz → 0.3.2__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.
Files changed (18) hide show
  1. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/PKG-INFO +1 -1
  2. elaunira_airflow_provider_r2index-0.3.2/README.md +169 -0
  3. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/pyproject.toml +1 -1
  4. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/provider/r2index/hooks/r2index.py +10 -3
  5. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/provider/r2index/links/r2index.py +1 -1
  6. elaunira_airflow_provider_r2index-0.3.0/README.md +0 -75
  7. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/.gitignore +0 -0
  8. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/LICENSE +0 -0
  9. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/__init__.py +0 -0
  10. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/__init__.py +0 -0
  11. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/provider/__init__.py +0 -0
  12. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/provider/r2index/__init__.py +0 -0
  13. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/provider/r2index/decorators/__init__.py +0 -0
  14. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/provider/r2index/decorators/r2index.py +0 -0
  15. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/provider/r2index/hooks/__init__.py +0 -0
  16. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/provider/r2index/links/__init__.py +0 -0
  17. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/provider/r2index/operators/__init__.py +0 -0
  18. {elaunira_airflow_provider_r2index-0.3.0 → elaunira_airflow_provider_r2index-0.3.2}/src/elaunira/airflow/provider/r2index/operators/r2index.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elaunira-airflow-provider-r2index
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Airflow provider for Elaunira R2Index connections
5
5
  Project-URL: Repository, https://github.com/elaunira/elaunira-airflow-provider-r2index
6
6
  License-Expression: MIT
@@ -0,0 +1,169 @@
1
+ # Elaunira Airflow Provider for R2Index
2
+
3
+ Airflow provider package for R2Index, providing connection type, operators, and TaskFlow decorators.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install elaunira-airflow-provider-r2index
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **R2Index** connection type in Airflow UI
14
+ - `R2IndexUploadOperator` and `R2IndexDownloadOperator` for file transfers
15
+ - `@task.r2index_upload` and `@task.r2index_download` TaskFlow decorators
16
+
17
+ ## Connection Configuration
18
+
19
+ After installation, the **R2Index** connection type will be available in Airflow's connection UI.
20
+
21
+ ### Vault/OpenBao Mode (Recommended)
22
+
23
+ Fetches credentials dynamically from HashiCorp Vault or OpenBao:
24
+
25
+ | Field | Description |
26
+ |-------|-------------|
27
+ | Vault Connection ID | Airflow Vault connection ID (e.g., `openbao-elaunira`) |
28
+ | Vault Namespace | OpenBao namespace (e.g., `elaunira/production`) |
29
+ | Vault Secrets Mapping | JSON mapping of config keys to secret paths |
30
+
31
+ Example Vault Secrets Mapping:
32
+ ```json
33
+ {
34
+ "r2index_api_url": "cloudflare/r2index#api-url",
35
+ "r2index_api_token": "cloudflare/r2index#api-token",
36
+ "r2_access_key_id": "cloudflare/r2/e2e-tests#access-key-id",
37
+ "r2_secret_access_key": "cloudflare/r2/e2e-tests#secret-access-key",
38
+ "r2_endpoint_url": "cloudflare/r2/e2e-tests#endpoint-url"
39
+ }
40
+ ```
41
+
42
+ Secret path format: `path#key` (e.g., `cloudflare/r2index#api-url`)
43
+
44
+ ### Direct Mode
45
+
46
+ Store credentials directly in the connection:
47
+
48
+ | Field | Description |
49
+ |-------|-------------|
50
+ | R2Index API URL | API endpoint URL |
51
+ | R2Index API Token | API authentication token |
52
+ | R2 Access Key ID | Cloudflare R2 access key |
53
+ | R2 Secret Access Key | Cloudflare R2 secret key |
54
+ | R2 Endpoint URL | Cloudflare R2 endpoint |
55
+
56
+ ### Environment Variables Fallback
57
+
58
+ If no connection is configured, the hook falls back to environment variables:
59
+
60
+ - `R2INDEX_API_URL`
61
+ - `R2INDEX_API_TOKEN`
62
+ - `R2_ACCESS_KEY_ID`
63
+ - `R2_SECRET_ACCESS_KEY`
64
+ - `R2_ENDPOINT_URL`
65
+
66
+ ## Operators
67
+
68
+ ### R2IndexUploadOperator
69
+
70
+ Upload files to R2Index:
71
+
72
+ ```python
73
+ from elaunira.airflow.provider.r2index.operators import R2IndexUploadOperator, UploadItem
74
+
75
+ upload = R2IndexUploadOperator(
76
+ task_id="upload_file",
77
+ bucket="my-bucket",
78
+ r2index_conn_id="my_r2index_connection",
79
+ items=UploadItem(
80
+ source="/tmp/data.csv",
81
+ category="example",
82
+ entity="sample-data",
83
+ extension="csv",
84
+ media_type="text/csv",
85
+ destination_path="example/data",
86
+ destination_filename="data.csv",
87
+ destination_version="{{ ds }}",
88
+ ),
89
+ )
90
+ ```
91
+
92
+ ### R2IndexDownloadOperator
93
+
94
+ Download files from R2Index:
95
+
96
+ ```python
97
+ from elaunira.airflow.provider.r2index.operators import R2IndexDownloadOperator, DownloadItem
98
+
99
+ download = R2IndexDownloadOperator(
100
+ task_id="download_file",
101
+ bucket="my-bucket",
102
+ r2index_conn_id="my_r2index_connection",
103
+ items=DownloadItem(
104
+ source_path="example/data",
105
+ source_filename="data.csv",
106
+ source_version="{{ ds }}",
107
+ destination="/tmp/downloaded.csv",
108
+ ),
109
+ )
110
+ ```
111
+
112
+ ## TaskFlow Decorators
113
+
114
+ ### @task.r2index_upload
115
+
116
+ ```python
117
+ from airflow.sdk import dag, task
118
+ from elaunira.airflow.provider.r2index.operators import UploadItem
119
+
120
+ @dag(schedule=None)
121
+ def my_dag():
122
+ @task.r2index_upload(bucket="my-bucket", r2index_conn_id="my_connection")
123
+ def prepare_upload() -> UploadItem:
124
+ return UploadItem(
125
+ source="/tmp/data.csv",
126
+ category="example",
127
+ entity="sample-data",
128
+ extension="csv",
129
+ media_type="text/csv",
130
+ destination_path="example/data",
131
+ destination_filename="data.csv",
132
+ destination_version="2024-01-01",
133
+ )
134
+
135
+ prepare_upload()
136
+ ```
137
+
138
+ ### @task.r2index_download
139
+
140
+ ```python
141
+ from airflow.sdk import dag, task
142
+ from elaunira.airflow.provider.r2index.operators import DownloadItem
143
+
144
+ @dag(schedule=None)
145
+ def my_dag():
146
+ @task.r2index_download(bucket="my-bucket", r2index_conn_id="my_connection")
147
+ def prepare_download() -> DownloadItem:
148
+ return DownloadItem(
149
+ source_path="example/data",
150
+ source_filename="data.csv",
151
+ source_version="2024-01-01",
152
+ destination="/tmp/downloaded.csv",
153
+ )
154
+
155
+ prepare_download()
156
+ ```
157
+
158
+ ## Hook Usage
159
+
160
+ ```python
161
+ from elaunira.airflow.provider.r2index.hooks import R2IndexHook
162
+
163
+ hook = R2IndexHook(r2index_conn_id="my_r2index_connection")
164
+ client = hook.get_conn()
165
+ ```
166
+
167
+ ## License
168
+
169
+ MIT
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "elaunira-airflow-provider-r2index"
7
- version = "0.3.0"
7
+ version = "0.3.2"
8
8
  description = "Airflow provider for Elaunira R2Index connections"
9
9
  requires-python = ">=3.12"
10
10
  license = "MIT"
@@ -191,14 +191,20 @@ class R2IndexHook(BaseHook):
191
191
 
192
192
  return secret_cache[path].get(key)
193
193
 
194
- return {
194
+ config = {
195
195
  "index_api_url": get_secret_value("r2index_api_url"),
196
196
  "index_api_token": get_secret_value("r2index_api_token"),
197
197
  "r2_access_key_id": get_secret_value("r2_access_key_id"),
198
198
  "r2_secret_access_key": get_secret_value("r2_secret_access_key"),
199
199
  "r2_endpoint_url": get_secret_value("r2_endpoint_url"),
200
200
  }
201
- except Exception:
201
+ # Log which values are missing
202
+ missing = [k for k, v in config.items() if v is None]
203
+ if missing:
204
+ self.log.warning("Missing Vault secrets: %s", missing)
205
+ return config
206
+ except Exception as e:
207
+ self.log.error("Failed to get config from Vault: %s", e)
202
208
  return None
203
209
 
204
210
  def _get_config_from_connection(self) -> dict[str, str | None] | None:
@@ -233,7 +239,8 @@ class R2IndexHook(BaseHook):
233
239
  "r2_secret_access_key": extra.get("r2_secret_access_key"),
234
240
  "r2_endpoint_url": extra.get("r2_endpoint_url"),
235
241
  }
236
- except Exception:
242
+ except Exception as e:
243
+ self.log.error("Failed to get config from connection: %s", e)
237
244
  return None
238
245
 
239
246
  def get_conn(self) -> R2IndexClient:
@@ -29,7 +29,7 @@ class R2IndexFileLink(BaseOperatorLink):
29
29
  """Get the link to the R2Index file."""
30
30
  from airflow.models import XCom
31
31
 
32
- result = XCom.get_value(ti_key=ti_key)
32
+ result = XCom.get_value(ti_key=ti_key, key="return_value")
33
33
  if result and isinstance(result, dict):
34
34
  file_id = result.get("id") or result.get("file_record", {}).get("id")
35
35
  if file_id:
@@ -1,75 +0,0 @@
1
- # Elaunira Airflow Provider for R2Index
2
-
3
- Airflow provider package that adds the **Elaunira R2Index** connection type for managing R2Index credentials.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- pip install elaunira-airflow-provider-r2index
9
- ```
10
-
11
- ## Usage
12
-
13
- After installation, a new connection type **Elaunira R2Index** will be available in Airflow's connection UI.
14
-
15
- ### Connection Configuration
16
-
17
- The connection supports two modes:
18
-
19
- #### 1. Vault/OpenBao Mode (Recommended)
20
-
21
- Fetches credentials dynamically from HashiCorp Vault or OpenBao:
22
-
23
- | Field | Description |
24
- |-------|-------------|
25
- | Vault Connection ID | Airflow Vault connection ID (e.g., `openbao-ipregistry`) |
26
- | Vault Namespace | OpenBao namespace (e.g., `ipregistry/production`) |
27
- | Vault Secrets (JSON) | JSON mapping of config keys to secret paths |
28
-
29
- Example Vault Secrets JSON:
30
- ```json
31
- {
32
- "r2index_api_url": "cloudflare/r2index#api-url",
33
- "r2index_api_token": "cloudflare/r2index#api-token",
34
- "r2_access_key_id": "cloudflare/r2/airflow#access-key-id",
35
- "r2_secret_access_key": "cloudflare/r2/airflow#secret-access-key",
36
- "r2_endpoint_url": "cloudflare/r2/airflow#endpoint-url"
37
- }
38
- ```
39
-
40
- Secret path format: `path#key` (e.g., `cloudflare/r2index#api-url`)
41
-
42
- #### 2. Direct Mode
43
-
44
- Store credentials directly in the connection:
45
-
46
- | Field | Description |
47
- |-------|-------------|
48
- | R2Index API URL | API endpoint URL |
49
- | R2Index API Token | API authentication token |
50
- | R2 Access Key ID | Cloudflare R2 access key |
51
- | R2 Secret Access Key | Cloudflare R2 secret key |
52
- | R2 Endpoint URL | Cloudflare R2 endpoint |
53
-
54
- ### Environment Variables Fallback
55
-
56
- If no connection is configured, the hook falls back to environment variables:
57
-
58
- - `R2INDEX_API_URL`
59
- - `R2INDEX_API_TOKEN`
60
- - `R2_ACCESS_KEY_ID`
61
- - `R2_SECRET_ACCESS_KEY`
62
- - `R2_ENDPOINT_URL`
63
-
64
- ## Hook Usage
65
-
66
- ```python
67
- from elaunira.airflow.provider.r2index.hooks import R2IndexHook
68
-
69
- hook = R2IndexHook(r2index_conn_id="my_r2index_connection")
70
- client = hook.get_conn()
71
- ```
72
-
73
- ## License
74
-
75
- MIT