hid_data_transfer_lib 0.4.1__tar.gz → 0.5.1__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.
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/PKG-INFO +46 -22
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/README.md +44 -21
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/hid_dt_lib.py +438 -12
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/nifi/nifi_client.py +14 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/pyproject.toml +3 -2
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/__init__.py +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/conf/__init__.py +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/conf/hid_dt.cfg +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/conf/hid_dt_configuration.py +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/conf/hid_dt_local.cfg +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/conf/hid_dt_psnc.cfg +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/exceptions/__init__.py +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/exceptions/hid_dt_exceptions.py +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/keycloak/__init__.py +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/keycloak/keycloak_rest.py +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/nifi/__init__.py +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/nifi/nifi_rest.py +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/py.typed +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/util/__init__.py +0 -0
- {hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/util/util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hid_data_transfer_lib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: HiDALGO Data Transfer library provides methods to transfer data between different data providers and consumers using NIFI pipelines
|
|
5
5
|
License: APL-2.0
|
|
6
6
|
Author: Jesús Gorroñogoitia
|
|
@@ -12,16 +12,20 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
15
16
|
Requires-Dist: paramiko (>=3.3.1)
|
|
16
17
|
Requires-Dist: requests (>=2.31.0)
|
|
17
18
|
Requires-Dist: setuptools (>=79.0.0,<80.0.0)
|
|
18
19
|
Description-Content-Type: text/markdown
|
|
19
20
|
|
|
20
21
|
# Hidalgo2 Data Transfer Lib
|
|
22
|
+
|
|
21
23
|
This repository contains the implementation of the Hidalgo2 data transfer library. It uses [Apache NIFI](https://nifi.apache.org/) to transfer data from different data sources to specified targets
|
|
22
24
|
|
|
23
25
|
## Features
|
|
26
|
+
|
|
24
27
|
This library is planning to support the following features:
|
|
28
|
+
|
|
25
29
|
- transfer datasets from Cloud Providers to HDFS
|
|
26
30
|
- transfer datasets from Cloud Providers to CKAN
|
|
27
31
|
- transfer datasets from/to Hadoop HDFS to/from HPC
|
|
@@ -31,39 +35,47 @@ This library is planning to support the following features:
|
|
|
31
35
|
- transfer datasets from/to local filesystem to/from CKAN
|
|
32
36
|
|
|
33
37
|
## Current version
|
|
38
|
+
|
|
34
39
|
Current version of the library supports the following features:
|
|
40
|
+
|
|
41
|
+
- transfer datasets from Cloud Providers (ECMWF and Meteofrance) to HDFS
|
|
42
|
+
- transfer datasets from Cloud Providers (ECMWF and Meteofrance) to CKAN
|
|
35
43
|
- transfer datasets from/to Hadoop HDFS to/from HPC
|
|
36
44
|
- transfer datasets from/to Hadoop HDFS to/from CKAN
|
|
37
45
|
- transfer datasets from/to a CKAN to/from HPC
|
|
38
46
|
- transfer datasets from/to local filesystem to/from CKAN
|
|
39
47
|
|
|
40
|
-
|
|
41
48
|
## Implementation
|
|
49
|
+
|
|
42
50
|
This is a Python library that offers specialized API methods to transfer data from data sources to targets.
|
|
43
|
-
Each API method launches a NIFI pipeline, by instantiating a NIFI process group out of its workflow definition registered in the NIFI registry.
|
|
44
|
-
It uses the parameters given within the library method invocation to populate a NIFI parameter context that is asociated to the process group.
|
|
51
|
+
Each API method launches a NIFI pipeline, by instantiating a NIFI process group out of its workflow definition registered in the NIFI registry.
|
|
52
|
+
It uses the parameters given within the library method invocation to populate a NIFI parameter context that is asociated to the process group.
|
|
45
53
|
Then, processors in the process group are executed once (or forever until the incomining processor's flowfile queue gets empty), one after another, following the group sequence flow, until the flow is completed.
|
|
46
|
-
A processor is executed after the previous one has terminated. To check the status of the transfer command, the library offers another check-status command.
|
|
47
|
-
Upon termination, the NIFI environment is cleaned up, by removing the created entities (i.e. the process group and its paramenter context).
|
|
48
|
-
The Data Transfer Library sends requests to NIFI through its REST API.
|
|
54
|
+
A processor is executed after the previous one has terminated. To check the status of the transfer command, the library offers another check-status command.
|
|
55
|
+
Upon termination, the NIFI environment is cleaned up, by removing the created entities (i.e. the process group and its paramenter context).
|
|
56
|
+
The Data Transfer Library sends requests to NIFI through its REST API.
|
|
49
57
|
|
|
50
58
|
## Requirements
|
|
59
|
+
|
|
51
60
|
To use the Data Transfer library, it is required the following requirements:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
|
|
62
|
+
- **Python3** execution environment
|
|
63
|
+
- **Poetry** python package management tool (optional)
|
|
64
|
+
- **NIFI** instance, with a NIFI 2.X server SSH account (for keys transfer). Latest NIFI supported version: 2.8
|
|
65
|
+
- **Keycloak** instance, with a KEYCLOAK user's account
|
|
66
|
+
- **HDFS** instance, with an user's Kerberos principal account
|
|
67
|
+
- **CKAN** instance, with an user APIKey
|
|
58
68
|
|
|
59
69
|
Python3 should be installed in the computer where Data Transfer CLI will be used.
|
|
60
70
|
To install Poetry, follows [this instructions](https://python-poetry.org/docs/#installing-with-the-official-installer)
|
|
61
71
|
|
|
62
72
|
## Data Transfer lib configuration
|
|
73
|
+
|
|
63
74
|
### Configuration file
|
|
75
|
+
|
|
64
76
|
Before using the Data Transfer library, you should configure it to point at the target NIFI and Keycloak services. The default configuration file is located, by default, at the *data_transfer_cli/conf/hid_dt.cfg* file. However, this default configuration should be complemented (and optionally overriden) with user's specific settings, placed in a configuration file whose location should be also specified (e.g., *~/.dtcli/dtcli.cfg*). Settings in this latter user's configuration will override those in the former default library configuration. The user should not modify the default library configuration, but the the user's specific one, including therein any additional required settings (see below) or modifications to the default ones. The location of this user's specific configuration file is passed as parameter to the library when setting it programmatically.
|
|
65
77
|
|
|
66
|
-
```
|
|
78
|
+
```script
|
|
67
79
|
[Nifi]
|
|
68
80
|
nifi_endpoint=https://nifi.hidalgo2.eu:9443
|
|
69
81
|
nifi_upload_folder=/opt/nifi/data/upload
|
|
@@ -82,7 +94,8 @@ logging_level=INFO
|
|
|
82
94
|
check_status_sleep_lapse=5
|
|
83
95
|
```
|
|
84
96
|
|
|
85
|
-
Under the NIFI section,
|
|
97
|
+
Under the NIFI section,
|
|
98
|
+
|
|
86
99
|
- We define the url of the NIFI service (*nifi_endpoint*),
|
|
87
100
|
- We also specify a folder (*nifi_upload_folder*) in NIFI server where to upload files
|
|
88
101
|
- And another folder (*nifi_download_folder*) where from to download files. These folder must be accessible by the NIFI service (ask NIFI administrator for details).
|
|
@@ -91,6 +104,7 @@ Under the NIFI section,
|
|
|
91
104
|
These default library settings works with the HiDALGO2 NIFI, so not additional modifications are required.
|
|
92
105
|
|
|
93
106
|
Under the Keycloak section, you can configure the Keycloak integrated with NIFI, specifying:
|
|
107
|
+
|
|
94
108
|
- The Keycloak service endpoint (*keycloak_endpoint*)
|
|
95
109
|
- The NIFI client in Keycloak (*keycloak_client*)
|
|
96
110
|
- The NIFI secret in Keycloak (*keycloak_client_secret*). This setting must be set in the user's configuration (e.g., *~/.dtcli/dtcli.cfg*).
|
|
@@ -113,7 +127,7 @@ HiDALGO2 developers can contact the Keycloak administrator for the *keycloak_cli
|
|
|
113
127
|
|
|
114
128
|
Additional user's accounts are specified in the user's specific configuration file (e.g., *~/.dtcli/dtcli.cfg*):
|
|
115
129
|
|
|
116
|
-
```
|
|
130
|
+
```script
|
|
117
131
|
[Nifi]
|
|
118
132
|
nifi_server_username=<user_name>
|
|
119
133
|
nifi_server_private_key=<path/to/private/key>
|
|
@@ -129,16 +143,19 @@ Under the Keycloak section, you must specify your Keycloak account (username and
|
|
|
129
143
|
|
|
130
144
|
For HiDALGO2 developers, NIFI (Service, Server) and Keycloak accounts are provided by the HiDALGO2 administrator.
|
|
131
145
|
|
|
132
|
-
|
|
133
146
|
## Usage
|
|
147
|
+
|
|
134
148
|
The data transfer library can be invoked following two procedures:
|
|
135
149
|
|
|
136
150
|
### Using user's configuration (e.g., ~/.dtcli/dtcli.cfg)
|
|
151
|
+
|
|
137
152
|
In this case, user's configuration will be read from a give file, such as *~/.dtcli/dtcli.cfg*, whose location is programmatically passed as a parameter upon the setup of the library (see procedure below).
|
|
138
153
|
|
|
139
154
|
### Providing configuration in a dictionary
|
|
155
|
+
|
|
140
156
|
In this case, the user's configuration is provided in a dictionary, with this structure:
|
|
141
|
-
|
|
157
|
+
|
|
158
|
+
```script
|
|
142
159
|
{
|
|
143
160
|
'Nifi':
|
|
144
161
|
{
|
|
@@ -158,6 +175,7 @@ In this case, the user's configuration is provided in a dictionary, with this st
|
|
|
158
175
|
}
|
|
159
176
|
}
|
|
160
177
|
```
|
|
178
|
+
|
|
161
179
|
In this settings' dictionary you should add the user's specific accounts for Nifi and Keycloak, and optionally, other settings, as shown for the logging level or the sleep lapse time for checking the processors status on the Nifi pipeline. This dictionary is programmatically passed as parameter to the library upon its setup (see procedure below).
|
|
162
180
|
|
|
163
181
|
The remaining procedure goes as follows:
|
|
@@ -168,7 +186,7 @@ The remaining procedure goes as follows:
|
|
|
168
186
|
|
|
169
187
|
Example with user's configuration file
|
|
170
188
|
|
|
171
|
-
```
|
|
189
|
+
```script
|
|
172
190
|
from hid_data_transfer_lib.hid_dt_lib import HIDDataTransfer
|
|
173
191
|
from hid_data_transfer_lib.conf.hid_dt_configuration import (
|
|
174
192
|
HidDataTransferConfiguration
|
|
@@ -207,7 +225,8 @@ dt_client = HIDDataTransfer(
|
|
|
207
225
|
```
|
|
208
226
|
|
|
209
227
|
Example with user's configuration dictionary:
|
|
210
|
-
|
|
228
|
+
|
|
229
|
+
```script
|
|
211
230
|
user_config_dict = {...} # See example of dictionary given above
|
|
212
231
|
config = HidDataTransferConfiguration().configure(
|
|
213
232
|
user_config_dict=user_config_dict,
|
|
@@ -215,9 +234,9 @@ config = HidDataTransferConfiguration().configure(
|
|
|
215
234
|
dt_client = HIDDataTransfer(conf=config, secure=True)
|
|
216
235
|
```
|
|
217
236
|
|
|
218
|
-
|
|
219
237
|
- Invoke any data transfer library method using the created object to tranfer data
|
|
220
|
-
|
|
238
|
+
|
|
239
|
+
```script
|
|
221
240
|
pipeline_id, accounting = dt_client.hpc2ckan(
|
|
222
241
|
hpc_host=<hpc_endpoint>,
|
|
223
242
|
hpc_username=<hpc_username>,
|
|
@@ -232,17 +251,22 @@ pipeline_id, accounting = dt_client.hpc2ckan(
|
|
|
232
251
|
recursive=False,
|
|
233
252
|
)
|
|
234
253
|
```
|
|
254
|
+
|
|
235
255
|
This method returns the id of the data transfer pipeline that NIFI executed and an AccountingInfo object that contains statistics of data transfer, including the *pipeline_timespan* (or total transfer time) and the flowfiles_sizes, a dictionary whose keys are the names of the transferred files and the values are their lengths.
|
|
236
256
|
|
|
237
257
|
## Data Transfer optimization
|
|
258
|
+
|
|
238
259
|
You can improve the data transfer rate by setting the optional parameter concurrent_tasks (*integer*) to the number of concurrent tasks that will be used in the NIFI pipeline (default is 1). The maximum number of tasks that improve the transfer throughput depends on the physical resources of the NIFI server (consult its administrator). The parallel transfer is currently supported to/from HPC and HDFS data servers, but not to/from CKAN (under development)
|
|
239
260
|
|
|
240
261
|
## Support for HPC clusters that require a 2FA token
|
|
262
|
+
|
|
241
263
|
This library includes methods (suffixed as _2fa) to transfer data to/from HPC clusters that require a 2FA token. These methods offer an optional parameter *callback_2fa* that points to a method that should return (as str) the 2FA token when invoked by the library. If not set by the method caller, these methods call a default implementation that prompts the user (in the standard input) for the token.
|
|
242
264
|
|
|
243
265
|
## Data transfer process with NIFI
|
|
266
|
+
|
|
244
267
|
The following UML Sequence Diagram describes the data transfer process for each command, for instance *ckan2hpc*, leveraging the associated NIFI pipeline.
|
|
245
268
|
The Data Transfer (DT) Consumer (a client of this library) invokes a *ckan2hpc* command by following these steps:
|
|
269
|
+
|
|
246
270
|
- Creates an instance of HidDataTransferConfiguration, which reads the file and environment configuration (see [Installation Instructions](#data-transfer-lib-configuration)).
|
|
247
271
|
- Creates an instance of HIDDataTransfer with that configuration object, with secure mode activated, and by passing a dictionary with Keycloak token details. A renewable Keycloak token is required to invoke the remote NIFI REST APIs.
|
|
248
272
|
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# Hidalgo2 Data Transfer Lib
|
|
2
|
+
|
|
2
3
|
This repository contains the implementation of the Hidalgo2 data transfer library. It uses [Apache NIFI](https://nifi.apache.org/) to transfer data from different data sources to specified targets
|
|
3
4
|
|
|
4
5
|
## Features
|
|
6
|
+
|
|
5
7
|
This library is planning to support the following features:
|
|
8
|
+
|
|
6
9
|
- transfer datasets from Cloud Providers to HDFS
|
|
7
10
|
- transfer datasets from Cloud Providers to CKAN
|
|
8
11
|
- transfer datasets from/to Hadoop HDFS to/from HPC
|
|
@@ -12,39 +15,47 @@ This library is planning to support the following features:
|
|
|
12
15
|
- transfer datasets from/to local filesystem to/from CKAN
|
|
13
16
|
|
|
14
17
|
## Current version
|
|
18
|
+
|
|
15
19
|
Current version of the library supports the following features:
|
|
20
|
+
|
|
21
|
+
- transfer datasets from Cloud Providers (ECMWF and Meteofrance) to HDFS
|
|
22
|
+
- transfer datasets from Cloud Providers (ECMWF and Meteofrance) to CKAN
|
|
16
23
|
- transfer datasets from/to Hadoop HDFS to/from HPC
|
|
17
24
|
- transfer datasets from/to Hadoop HDFS to/from CKAN
|
|
18
25
|
- transfer datasets from/to a CKAN to/from HPC
|
|
19
26
|
- transfer datasets from/to local filesystem to/from CKAN
|
|
20
27
|
|
|
21
|
-
|
|
22
28
|
## Implementation
|
|
29
|
+
|
|
23
30
|
This is a Python library that offers specialized API methods to transfer data from data sources to targets.
|
|
24
|
-
Each API method launches a NIFI pipeline, by instantiating a NIFI process group out of its workflow definition registered in the NIFI registry.
|
|
25
|
-
It uses the parameters given within the library method invocation to populate a NIFI parameter context that is asociated to the process group.
|
|
31
|
+
Each API method launches a NIFI pipeline, by instantiating a NIFI process group out of its workflow definition registered in the NIFI registry.
|
|
32
|
+
It uses the parameters given within the library method invocation to populate a NIFI parameter context that is asociated to the process group.
|
|
26
33
|
Then, processors in the process group are executed once (or forever until the incomining processor's flowfile queue gets empty), one after another, following the group sequence flow, until the flow is completed.
|
|
27
|
-
A processor is executed after the previous one has terminated. To check the status of the transfer command, the library offers another check-status command.
|
|
28
|
-
Upon termination, the NIFI environment is cleaned up, by removing the created entities (i.e. the process group and its paramenter context).
|
|
29
|
-
The Data Transfer Library sends requests to NIFI through its REST API.
|
|
34
|
+
A processor is executed after the previous one has terminated. To check the status of the transfer command, the library offers another check-status command.
|
|
35
|
+
Upon termination, the NIFI environment is cleaned up, by removing the created entities (i.e. the process group and its paramenter context).
|
|
36
|
+
The Data Transfer Library sends requests to NIFI through its REST API.
|
|
30
37
|
|
|
31
38
|
## Requirements
|
|
39
|
+
|
|
32
40
|
To use the Data Transfer library, it is required the following requirements:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
|
|
42
|
+
- **Python3** execution environment
|
|
43
|
+
- **Poetry** python package management tool (optional)
|
|
44
|
+
- **NIFI** instance, with a NIFI 2.X server SSH account (for keys transfer). Latest NIFI supported version: 2.8
|
|
45
|
+
- **Keycloak** instance, with a KEYCLOAK user's account
|
|
46
|
+
- **HDFS** instance, with an user's Kerberos principal account
|
|
47
|
+
- **CKAN** instance, with an user APIKey
|
|
39
48
|
|
|
40
49
|
Python3 should be installed in the computer where Data Transfer CLI will be used.
|
|
41
50
|
To install Poetry, follows [this instructions](https://python-poetry.org/docs/#installing-with-the-official-installer)
|
|
42
51
|
|
|
43
52
|
## Data Transfer lib configuration
|
|
53
|
+
|
|
44
54
|
### Configuration file
|
|
55
|
+
|
|
45
56
|
Before using the Data Transfer library, you should configure it to point at the target NIFI and Keycloak services. The default configuration file is located, by default, at the *data_transfer_cli/conf/hid_dt.cfg* file. However, this default configuration should be complemented (and optionally overriden) with user's specific settings, placed in a configuration file whose location should be also specified (e.g., *~/.dtcli/dtcli.cfg*). Settings in this latter user's configuration will override those in the former default library configuration. The user should not modify the default library configuration, but the the user's specific one, including therein any additional required settings (see below) or modifications to the default ones. The location of this user's specific configuration file is passed as parameter to the library when setting it programmatically.
|
|
46
57
|
|
|
47
|
-
```
|
|
58
|
+
```script
|
|
48
59
|
[Nifi]
|
|
49
60
|
nifi_endpoint=https://nifi.hidalgo2.eu:9443
|
|
50
61
|
nifi_upload_folder=/opt/nifi/data/upload
|
|
@@ -63,7 +74,8 @@ logging_level=INFO
|
|
|
63
74
|
check_status_sleep_lapse=5
|
|
64
75
|
```
|
|
65
76
|
|
|
66
|
-
Under the NIFI section,
|
|
77
|
+
Under the NIFI section,
|
|
78
|
+
|
|
67
79
|
- We define the url of the NIFI service (*nifi_endpoint*),
|
|
68
80
|
- We also specify a folder (*nifi_upload_folder*) in NIFI server where to upload files
|
|
69
81
|
- And another folder (*nifi_download_folder*) where from to download files. These folder must be accessible by the NIFI service (ask NIFI administrator for details).
|
|
@@ -72,6 +84,7 @@ Under the NIFI section,
|
|
|
72
84
|
These default library settings works with the HiDALGO2 NIFI, so not additional modifications are required.
|
|
73
85
|
|
|
74
86
|
Under the Keycloak section, you can configure the Keycloak integrated with NIFI, specifying:
|
|
87
|
+
|
|
75
88
|
- The Keycloak service endpoint (*keycloak_endpoint*)
|
|
76
89
|
- The NIFI client in Keycloak (*keycloak_client*)
|
|
77
90
|
- The NIFI secret in Keycloak (*keycloak_client_secret*). This setting must be set in the user's configuration (e.g., *~/.dtcli/dtcli.cfg*).
|
|
@@ -94,7 +107,7 @@ HiDALGO2 developers can contact the Keycloak administrator for the *keycloak_cli
|
|
|
94
107
|
|
|
95
108
|
Additional user's accounts are specified in the user's specific configuration file (e.g., *~/.dtcli/dtcli.cfg*):
|
|
96
109
|
|
|
97
|
-
```
|
|
110
|
+
```script
|
|
98
111
|
[Nifi]
|
|
99
112
|
nifi_server_username=<user_name>
|
|
100
113
|
nifi_server_private_key=<path/to/private/key>
|
|
@@ -110,16 +123,19 @@ Under the Keycloak section, you must specify your Keycloak account (username and
|
|
|
110
123
|
|
|
111
124
|
For HiDALGO2 developers, NIFI (Service, Server) and Keycloak accounts are provided by the HiDALGO2 administrator.
|
|
112
125
|
|
|
113
|
-
|
|
114
126
|
## Usage
|
|
127
|
+
|
|
115
128
|
The data transfer library can be invoked following two procedures:
|
|
116
129
|
|
|
117
130
|
### Using user's configuration (e.g., ~/.dtcli/dtcli.cfg)
|
|
131
|
+
|
|
118
132
|
In this case, user's configuration will be read from a give file, such as *~/.dtcli/dtcli.cfg*, whose location is programmatically passed as a parameter upon the setup of the library (see procedure below).
|
|
119
133
|
|
|
120
134
|
### Providing configuration in a dictionary
|
|
135
|
+
|
|
121
136
|
In this case, the user's configuration is provided in a dictionary, with this structure:
|
|
122
|
-
|
|
137
|
+
|
|
138
|
+
```script
|
|
123
139
|
{
|
|
124
140
|
'Nifi':
|
|
125
141
|
{
|
|
@@ -139,6 +155,7 @@ In this case, the user's configuration is provided in a dictionary, with this st
|
|
|
139
155
|
}
|
|
140
156
|
}
|
|
141
157
|
```
|
|
158
|
+
|
|
142
159
|
In this settings' dictionary you should add the user's specific accounts for Nifi and Keycloak, and optionally, other settings, as shown for the logging level or the sleep lapse time for checking the processors status on the Nifi pipeline. This dictionary is programmatically passed as parameter to the library upon its setup (see procedure below).
|
|
143
160
|
|
|
144
161
|
The remaining procedure goes as follows:
|
|
@@ -149,7 +166,7 @@ The remaining procedure goes as follows:
|
|
|
149
166
|
|
|
150
167
|
Example with user's configuration file
|
|
151
168
|
|
|
152
|
-
```
|
|
169
|
+
```script
|
|
153
170
|
from hid_data_transfer_lib.hid_dt_lib import HIDDataTransfer
|
|
154
171
|
from hid_data_transfer_lib.conf.hid_dt_configuration import (
|
|
155
172
|
HidDataTransferConfiguration
|
|
@@ -188,7 +205,8 @@ dt_client = HIDDataTransfer(
|
|
|
188
205
|
```
|
|
189
206
|
|
|
190
207
|
Example with user's configuration dictionary:
|
|
191
|
-
|
|
208
|
+
|
|
209
|
+
```script
|
|
192
210
|
user_config_dict = {...} # See example of dictionary given above
|
|
193
211
|
config = HidDataTransferConfiguration().configure(
|
|
194
212
|
user_config_dict=user_config_dict,
|
|
@@ -196,9 +214,9 @@ config = HidDataTransferConfiguration().configure(
|
|
|
196
214
|
dt_client = HIDDataTransfer(conf=config, secure=True)
|
|
197
215
|
```
|
|
198
216
|
|
|
199
|
-
|
|
200
217
|
- Invoke any data transfer library method using the created object to tranfer data
|
|
201
|
-
|
|
218
|
+
|
|
219
|
+
```script
|
|
202
220
|
pipeline_id, accounting = dt_client.hpc2ckan(
|
|
203
221
|
hpc_host=<hpc_endpoint>,
|
|
204
222
|
hpc_username=<hpc_username>,
|
|
@@ -213,17 +231,22 @@ pipeline_id, accounting = dt_client.hpc2ckan(
|
|
|
213
231
|
recursive=False,
|
|
214
232
|
)
|
|
215
233
|
```
|
|
234
|
+
|
|
216
235
|
This method returns the id of the data transfer pipeline that NIFI executed and an AccountingInfo object that contains statistics of data transfer, including the *pipeline_timespan* (or total transfer time) and the flowfiles_sizes, a dictionary whose keys are the names of the transferred files and the values are their lengths.
|
|
217
236
|
|
|
218
237
|
## Data Transfer optimization
|
|
238
|
+
|
|
219
239
|
You can improve the data transfer rate by setting the optional parameter concurrent_tasks (*integer*) to the number of concurrent tasks that will be used in the NIFI pipeline (default is 1). The maximum number of tasks that improve the transfer throughput depends on the physical resources of the NIFI server (consult its administrator). The parallel transfer is currently supported to/from HPC and HDFS data servers, but not to/from CKAN (under development)
|
|
220
240
|
|
|
221
241
|
## Support for HPC clusters that require a 2FA token
|
|
242
|
+
|
|
222
243
|
This library includes methods (suffixed as _2fa) to transfer data to/from HPC clusters that require a 2FA token. These methods offer an optional parameter *callback_2fa* that points to a method that should return (as str) the 2FA token when invoked by the library. If not set by the method caller, these methods call a default implementation that prompts the user (in the standard input) for the token.
|
|
223
244
|
|
|
224
245
|
## Data transfer process with NIFI
|
|
246
|
+
|
|
225
247
|
The following UML Sequence Diagram describes the data transfer process for each command, for instance *ckan2hpc*, leveraging the associated NIFI pipeline.
|
|
226
248
|
The Data Transfer (DT) Consumer (a client of this library) invokes a *ckan2hpc* command by following these steps:
|
|
249
|
+
|
|
227
250
|
- Creates an instance of HidDataTransferConfiguration, which reads the file and environment configuration (see [Installation Instructions](#data-transfer-lib-configuration)).
|
|
228
251
|
- Creates an instance of HIDDataTransfer with that configuration object, with secure mode activated, and by passing a dictionary with Keycloak token details. A renewable Keycloak token is required to invoke the remote NIFI REST APIs.
|
|
229
252
|
|
{hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/hid_dt_lib.py
RENAMED
|
@@ -22,7 +22,9 @@ import sys
|
|
|
22
22
|
from typing import Any, Dict, Optional, Callable
|
|
23
23
|
import uuid
|
|
24
24
|
import os
|
|
25
|
+
import json
|
|
25
26
|
from types import SimpleNamespace
|
|
27
|
+
from pathlib import Path
|
|
26
28
|
|
|
27
29
|
from hid_data_transfer_lib.conf.hid_dt_configuration import (
|
|
28
30
|
HidDataTransferConfiguration
|
|
@@ -46,6 +48,8 @@ HPC_2FA = "hpc.2fa"
|
|
|
46
48
|
NIFI_DOWNLOAD_FOLDER = "nifi.download_folder"
|
|
47
49
|
RECURSIVE = "recursive"
|
|
48
50
|
|
|
51
|
+
PYTHON_PATH_ECMWF = "/opt/nifi/data/scripts/ecmwf/nenv/bin/python"
|
|
52
|
+
|
|
49
53
|
HPC_ACCOUNT_MSG = "Either hpc_password or hpc_secret_key must be provided"
|
|
50
54
|
|
|
51
55
|
|
|
@@ -70,7 +74,7 @@ class HIDDataTransfer:
|
|
|
70
74
|
"""
|
|
71
75
|
self.__conf = conf
|
|
72
76
|
self.__secure = secure
|
|
73
|
-
self.use_keycloak_account =
|
|
77
|
+
self.use_keycloak_account = keycloak_token is None
|
|
74
78
|
self.__nifi_client = NIFIClient().configure(
|
|
75
79
|
conf, secure, use_keycloak_account=self.use_keycloak_account)
|
|
76
80
|
self.__logger = self.__conf.logger("hid_data_transfer_lib")
|
|
@@ -93,21 +97,31 @@ class HIDDataTransfer:
|
|
|
93
97
|
name = name.replace("?", ".")
|
|
94
98
|
return name
|
|
95
99
|
|
|
96
|
-
def generate_ckan_resource_name(self, args):
|
|
100
|
+
def generate_ckan_resource_name(self, args, prefix_zip:bool = True):
|
|
97
101
|
'''computes the ckan resource name'''
|
|
98
102
|
ckan_resource = args.ckan_resource
|
|
99
103
|
if ckan_resource:
|
|
100
|
-
|
|
104
|
+
# Process wildcards
|
|
105
|
+
ckan_resource = ckan_resource.replace("*", ".*")
|
|
106
|
+
ckan_resource = ckan_resource.replace("?", ".")
|
|
107
|
+
|
|
108
|
+
if prefix_zip and not ckan_resource.endswith(".zip"):
|
|
109
|
+
ckan_resource = ckan_resource + ".zip" \
|
|
101
110
|
if not ckan_resource.endswith(".zip") \
|
|
102
111
|
else ckan_resource
|
|
103
112
|
else:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
if not hasattr(args, "data_source"):
|
|
114
|
+
ckan_resource = ".*"
|
|
115
|
+
else:
|
|
116
|
+
start_idx = 1 if args.data_source.startswith("/") else 0
|
|
117
|
+
ends_with_slash = args.data_source.endswith("/")
|
|
118
|
+
ckan_resource = (
|
|
119
|
+
args.data_source[start_idx:].replace("/", "_")[0:]
|
|
120
|
+
if not ends_with_slash
|
|
121
|
+
else args.data_source[start_idx:-1].replace("/", "_")
|
|
108
122
|
)
|
|
109
|
-
|
|
110
|
-
|
|
123
|
+
if prefix_zip and not ckan_resource.endswith(".zip"):
|
|
124
|
+
ckan_resource += ".zip"
|
|
111
125
|
return ckan_resource
|
|
112
126
|
|
|
113
127
|
# MAIN API methods
|
|
@@ -561,6 +575,7 @@ class HIDDataTransfer:
|
|
|
561
575
|
)
|
|
562
576
|
try:
|
|
563
577
|
hpc_filename = args.data_source[args.data_source.rfind("/") + 1 :]
|
|
578
|
+
hpc_filename = self.process_wildcards(hpc_filename)
|
|
564
579
|
arguments: Dict[str, Any] = {}
|
|
565
580
|
self.__nifi_client.add_default_hpc_parameters(arguments, args)
|
|
566
581
|
arguments[HPC_FILENAME] = hpc_filename if hpc_filename else ".*"
|
|
@@ -1070,7 +1085,7 @@ class HIDDataTransfer:
|
|
|
1070
1085
|
arguments: Dict[str, Any] = {}
|
|
1071
1086
|
self.__nifi_client.add_default_ckan_parameters(arguments, args)
|
|
1072
1087
|
arguments[self.__nifi_client.CKAN_RESOURCE] = \
|
|
1073
|
-
self.
|
|
1088
|
+
self.generate_ckan_resource_name(args, prefix_zip=False)
|
|
1074
1089
|
|
|
1075
1090
|
# If multiple ckan resource files are selected, data_target represents a folder
|
|
1076
1091
|
# Else If data_target ends with / represents a folder, otherwise a file
|
|
@@ -1206,7 +1221,7 @@ class HIDDataTransfer:
|
|
|
1206
1221
|
self.__nifi_client.add_default_hpc_parameters(arguments, args)
|
|
1207
1222
|
self.__nifi_client.add_default_ckan_parameters(arguments, args)
|
|
1208
1223
|
arguments[self.__nifi_client.CKAN_RESOURCE] = \
|
|
1209
|
-
self.
|
|
1224
|
+
self.generate_ckan_resource_name(args, prefix_zip=False)
|
|
1210
1225
|
|
|
1211
1226
|
# If multiple ckan resource files are selected, data_target represents a folder
|
|
1212
1227
|
# Else If data_target ends with / represents a folder, otherwise a file
|
|
@@ -1405,7 +1420,7 @@ class HIDDataTransfer:
|
|
|
1405
1420
|
arguments[HPC_TARGET_FOLDER] = args.data_target
|
|
1406
1421
|
self.__nifi_client.add_default_ckan_parameters(arguments, args)
|
|
1407
1422
|
arguments[self.__nifi_client.CKAN_RESOURCE] = \
|
|
1408
|
-
self.
|
|
1423
|
+
self.generate_ckan_resource_name(args, prefix_zip=False)
|
|
1409
1424
|
|
|
1410
1425
|
keys_arguments = {
|
|
1411
1426
|
self.__nifi_client.HPC_SECRET_KEY_PATH: arguments[
|
|
@@ -2247,6 +2262,417 @@ class HIDDataTransfer:
|
|
|
2247
2262
|
if download_folder is not None:
|
|
2248
2263
|
self.__nifi_client.remove_download_folder(download_folder)
|
|
2249
2264
|
|
|
2265
|
+
def aggregate(self, accountings: list[AccountingInfo]) -> AccountingInfo:
|
|
2266
|
+
"""Aggregate the accounting information from multiple process groups"""
|
|
2267
|
+
aggregated_accounting = AccountingInfo(
|
|
2268
|
+
pipeline_timespan = 0,
|
|
2269
|
+
flowfiles_sizes = {}
|
|
2270
|
+
)
|
|
2271
|
+
for accounting in accountings:
|
|
2272
|
+
aggregated_accounting.pipeline_timespan += accounting.pipeline_timespan
|
|
2273
|
+
aggregated_accounting.flowfiles_sizes.update(accounting.flowfiles_sizes)
|
|
2274
|
+
|
|
2275
|
+
return aggregated_accounting
|
|
2276
|
+
|
|
2277
|
+
|
|
2278
|
+
def meteofrance2ckan(
|
|
2279
|
+
self,
|
|
2280
|
+
meteofrance_config,
|
|
2281
|
+
meteofrance_apikey,
|
|
2282
|
+
ckan_host,
|
|
2283
|
+
ckan_api_key,
|
|
2284
|
+
ckan_organization,
|
|
2285
|
+
ckan_dataset
|
|
2286
|
+
) -> tuple[str, AccountingInfo]:
|
|
2287
|
+
"""
|
|
2288
|
+
transfer data from MeteoFrance service to CKAN
|
|
2289
|
+
|
|
2290
|
+
Args:
|
|
2291
|
+
ckan_host (str): The CKAN host URL.
|
|
2292
|
+
ckan_organization (str): The CKAN organization name.
|
|
2293
|
+
ckan_dataset (str): The CKAN dataset name.
|
|
2294
|
+
# ckan_resource (str): The name of the CKAN resource
|
|
2295
|
+
# to be created with the data.
|
|
2296
|
+
meteofrance_config (str): path to json file with request configuration
|
|
2297
|
+
meteofrance_apikey (str): The apikey for MeteoFrance
|
|
2298
|
+
|
|
2299
|
+
Returns:
|
|
2300
|
+
tuple[str, AccountingInfo]: The result of the process group execution.
|
|
2301
|
+
|
|
2302
|
+
Raises:
|
|
2303
|
+
HidDataTransferException: If an error occurs during
|
|
2304
|
+
the data transfer process.
|
|
2305
|
+
|
|
2306
|
+
"""
|
|
2307
|
+
|
|
2308
|
+
args = SimpleNamespace(
|
|
2309
|
+
ckan_host=ckan_host,
|
|
2310
|
+
ckan_api_key=ckan_api_key,
|
|
2311
|
+
ckan_organization=ckan_organization,
|
|
2312
|
+
ckan_dataset=ckan_dataset,
|
|
2313
|
+
meteofrance_config=meteofrance_config,
|
|
2314
|
+
meteofrance_apikey=meteofrance_apikey,
|
|
2315
|
+
)
|
|
2316
|
+
|
|
2317
|
+
self.__logger.info(
|
|
2318
|
+
"executing meteofrance2ckan command with args: %s",
|
|
2319
|
+
self.__nifi_client.format_args_to_string(args),
|
|
2320
|
+
)
|
|
2321
|
+
try:
|
|
2322
|
+
arguments: Dict[str, Any] = {}
|
|
2323
|
+
|
|
2324
|
+
with open(meteofrance_config, encoding="utf-8") as config:
|
|
2325
|
+
mtf_config = json.load(config)
|
|
2326
|
+
|
|
2327
|
+
arguments['meteofrance.url'] = mtf_config['url']
|
|
2328
|
+
coverages = mtf_config['coverages']
|
|
2329
|
+
process_ids = []
|
|
2330
|
+
accountings = []
|
|
2331
|
+
for entry in coverages:
|
|
2332
|
+
arguments['meteofrance.coverageid'] = '&coverageid=' + entry['coverageid']
|
|
2333
|
+
arguments['meteofrance.subsets'] = \
|
|
2334
|
+
''.join(['&subset=' + i for i in entry['subsets']])
|
|
2335
|
+
time = [i for i in entry['subsets'] if 'time' in i][0].strip('time(').strip(')')
|
|
2336
|
+
|
|
2337
|
+
args.ckan_resource = entry['coverageid'] + '_' + time + '.tif'
|
|
2338
|
+
self.__nifi_client.add_default_ckan_parameters(arguments, args)
|
|
2339
|
+
arguments[self.__nifi_client.CKAN_RESOURCE] = \
|
|
2340
|
+
self.generate_ckan_resource_name(args, False)
|
|
2341
|
+
|
|
2342
|
+
keys_arguments: Dict[str, Any] = {}
|
|
2343
|
+
|
|
2344
|
+
processors_with_meteofrance_sensitive_parameters = ["InvokeHTTP"]
|
|
2345
|
+
sensitive_parameters = \
|
|
2346
|
+
self.__nifi_client.set_sensitive_meteofrance_parameters(
|
|
2347
|
+
processors_with_meteofrance_sensitive_parameters, args
|
|
2348
|
+
)
|
|
2349
|
+
|
|
2350
|
+
processors_with_ckan_sensitive_parameters = ["CKANFileUploader"]
|
|
2351
|
+
sensitive_parameters.update(
|
|
2352
|
+
self.__nifi_client.set_sensitive_ckan_parameters(
|
|
2353
|
+
processors_with_ckan_sensitive_parameters, args
|
|
2354
|
+
)
|
|
2355
|
+
)
|
|
2356
|
+
|
|
2357
|
+
execution_type = {
|
|
2358
|
+
"InvokeHTTP": ExecutionType.ONCE,
|
|
2359
|
+
"UpdateAttribute": ExecutionType.ONCE,
|
|
2360
|
+
"CKANFileUploader": ExecutionType.ONCE,
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
process_id, accounting = self.__nifi_client.run_process_group(
|
|
2364
|
+
"meteofrance2ckan",
|
|
2365
|
+
execution_type,
|
|
2366
|
+
arguments,
|
|
2367
|
+
keys_arguments,
|
|
2368
|
+
sensitive_parameters,
|
|
2369
|
+
keycloak_token=self.__keycloak_token,
|
|
2370
|
+
accounting_target="CKANFileUploader",
|
|
2371
|
+
)
|
|
2372
|
+
process_ids.append(process_id)
|
|
2373
|
+
accountings.append(accounting)
|
|
2374
|
+
|
|
2375
|
+
return '|'.join(process_ids), self.aggregate(accountings)
|
|
2376
|
+
|
|
2377
|
+
except Exception as ex:
|
|
2378
|
+
raise HidDataTransferException(ex) from ex
|
|
2379
|
+
|
|
2380
|
+
def meteofrance2hdfs(
|
|
2381
|
+
self,
|
|
2382
|
+
meteofrance_config,
|
|
2383
|
+
meteofrance_apikey,
|
|
2384
|
+
data_target,
|
|
2385
|
+
kerberos_principal=None,
|
|
2386
|
+
kerberos_password=None
|
|
2387
|
+
) -> tuple[str, AccountingInfo]:
|
|
2388
|
+
"""
|
|
2389
|
+
transfer data from MeteoFrance service to CKAN
|
|
2390
|
+
|
|
2391
|
+
Args:
|
|
2392
|
+
kerberos_principal (str): The kerberos principal.
|
|
2393
|
+
kerberos_password (str): The kerberos password.
|
|
2394
|
+
data_target (str): The target path in HDFS.
|
|
2395
|
+
data_source (str): The filename in HDFS.
|
|
2396
|
+
meteofrance_config (str): path to json file with request configuration
|
|
2397
|
+
meteofrance_apikey (str): The apikey for MeteoFrance
|
|
2398
|
+
|
|
2399
|
+
Returns:
|
|
2400
|
+
tuple[str, AccountingInfo]: The result of the process group execution.
|
|
2401
|
+
|
|
2402
|
+
Raises:
|
|
2403
|
+
HidDataTransferException: If an error occurs during
|
|
2404
|
+
the data transfer process.
|
|
2405
|
+
|
|
2406
|
+
"""
|
|
2407
|
+
|
|
2408
|
+
args = SimpleNamespace(
|
|
2409
|
+
meteofrance_config=meteofrance_config,
|
|
2410
|
+
meteofrance_apikey=meteofrance_apikey,
|
|
2411
|
+
data_target=data_target,
|
|
2412
|
+
kerberos_principal=kerberos_principal,
|
|
2413
|
+
kerberos_password=kerberos_password,
|
|
2414
|
+
)
|
|
2415
|
+
|
|
2416
|
+
processors_with_kerberos = ["PutHDFS"]
|
|
2417
|
+
kerberos_account = SimpleNamespace(
|
|
2418
|
+
kerberos_principal=kerberos_principal,
|
|
2419
|
+
kerberos_password=kerberos_password,
|
|
2420
|
+
)
|
|
2421
|
+
|
|
2422
|
+
self.__logger.info(
|
|
2423
|
+
"executing meteofrance2hdfs command with args: %s",
|
|
2424
|
+
self.__nifi_client.format_args_to_string(args),
|
|
2425
|
+
)
|
|
2426
|
+
try:
|
|
2427
|
+
arguments: Dict[str, Any] = {}
|
|
2428
|
+
arguments[HDFS_DATA_FOLDER] = args.data_target
|
|
2429
|
+
|
|
2430
|
+
with open(meteofrance_config, encoding="utf-8") as config:
|
|
2431
|
+
mtf_config = json.load(config)
|
|
2432
|
+
|
|
2433
|
+
arguments['meteofrance.url'] = mtf_config['url']
|
|
2434
|
+
coverages = mtf_config['coverages']
|
|
2435
|
+
process_ids = []
|
|
2436
|
+
accountings = []
|
|
2437
|
+
for entry in coverages:
|
|
2438
|
+
arguments['meteofrance.coverageid'] = '&coverageid=' + entry['coverageid']
|
|
2439
|
+
arguments['meteofrance.subsets'] = \
|
|
2440
|
+
''.join(['&subset=' + i for i in entry['subsets']])
|
|
2441
|
+
time = [i for i in entry['subsets'] if 'time' in i][0].strip('time(').strip(')')
|
|
2442
|
+
filename = entry['coverageid'] + '_' + time + '.tif'
|
|
2443
|
+
arguments[HDFS_FILENAME] = filename.replace(':', '_')
|
|
2444
|
+
|
|
2445
|
+
keys_arguments: Dict[str, Any] = {}
|
|
2446
|
+
|
|
2447
|
+
processors_with_meteofrance_sensitive_parameters = ["InvokeHTTP"]
|
|
2448
|
+
sensitive_parameters = \
|
|
2449
|
+
self.__nifi_client.set_sensitive_meteofrance_parameters(
|
|
2450
|
+
processors_with_meteofrance_sensitive_parameters, args
|
|
2451
|
+
)
|
|
2452
|
+
|
|
2453
|
+
|
|
2454
|
+
execution_type = {
|
|
2455
|
+
"InvokeHTTP": ExecutionType.ONCE,
|
|
2456
|
+
"UpdateAttribute": ExecutionType.ONCE,
|
|
2457
|
+
"PutHDFS": ExecutionType.FOREVER,
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
process_id, accounting = self.__nifi_client.run_process_group(
|
|
2461
|
+
"meteofrance2hdfs",
|
|
2462
|
+
execution_type,
|
|
2463
|
+
arguments,
|
|
2464
|
+
keys_arguments,
|
|
2465
|
+
sensitive_parameters,
|
|
2466
|
+
keycloak_token=self.__keycloak_token,
|
|
2467
|
+
processors_with_kerberos=processors_with_kerberos,
|
|
2468
|
+
kerberos_account=kerberos_account,
|
|
2469
|
+
accounting_target="PutHDFS",
|
|
2470
|
+
)
|
|
2471
|
+
process_ids.append(process_id)
|
|
2472
|
+
accountings.append(accounting)
|
|
2473
|
+
|
|
2474
|
+
return '|'.join(process_ids), self.aggregate(accountings)
|
|
2475
|
+
|
|
2476
|
+
except Exception as ex:
|
|
2477
|
+
raise HidDataTransferException(ex) from ex
|
|
2478
|
+
|
|
2479
|
+
def ecmwf2ckan(
|
|
2480
|
+
self,
|
|
2481
|
+
data_script,
|
|
2482
|
+
ckan_host,
|
|
2483
|
+
ckan_api_key,
|
|
2484
|
+
ckan_organization,
|
|
2485
|
+
ckan_dataset,
|
|
2486
|
+
ckan_resource
|
|
2487
|
+
) -> tuple[str, AccountingInfo]:
|
|
2488
|
+
"""
|
|
2489
|
+
transfer data from ECMWF open data service to CKAN
|
|
2490
|
+
|
|
2491
|
+
Args:
|
|
2492
|
+
data_script (str): Path to the python script.
|
|
2493
|
+
ckan_host (str): The CKAN host URL.
|
|
2494
|
+
ckan_organization (str): The CKAN organization name.
|
|
2495
|
+
ckan_dataset (str): The CKAN dataset name.
|
|
2496
|
+
ckan_resource (str): The name of the CKAN resource
|
|
2497
|
+
to be created with the data.
|
|
2498
|
+
|
|
2499
|
+
Returns:
|
|
2500
|
+
tuple[str, AccountingInfo]: The result of the process group execution.
|
|
2501
|
+
|
|
2502
|
+
Raises:
|
|
2503
|
+
HidDataTransferException: If an error occurs during
|
|
2504
|
+
the data transfer process.
|
|
2505
|
+
|
|
2506
|
+
"""
|
|
2507
|
+
|
|
2508
|
+
args = SimpleNamespace(
|
|
2509
|
+
ckan_host=ckan_host,
|
|
2510
|
+
ckan_api_key=ckan_api_key,
|
|
2511
|
+
ckan_organization=ckan_organization,
|
|
2512
|
+
ckan_dataset=ckan_dataset,
|
|
2513
|
+
data_script=data_script,
|
|
2514
|
+
)
|
|
2515
|
+
|
|
2516
|
+
self.__logger.info(
|
|
2517
|
+
"executing ecmwf2ckan command with args: %s",
|
|
2518
|
+
self.__nifi_client.format_args_to_string(args),
|
|
2519
|
+
)
|
|
2520
|
+
|
|
2521
|
+
upload_folder = None
|
|
2522
|
+
try:
|
|
2523
|
+
arguments: Dict[str, Any] = {}
|
|
2524
|
+
|
|
2525
|
+
local_regexp = \
|
|
2526
|
+
args.data_script[args.data_script.rfind("/") + 1 :]
|
|
2527
|
+
local_folder = args.data_script[: args.data_script.rfind("/")]
|
|
2528
|
+
|
|
2529
|
+
# Transfer files from data source to NIFI upload subfolder
|
|
2530
|
+
# (within user folder)
|
|
2531
|
+
upload_folder, num_files = self.__nifi_client.upload_files(
|
|
2532
|
+
local_folder, local_regexp
|
|
2533
|
+
)
|
|
2534
|
+
if num_files == 0:
|
|
2535
|
+
raise HidDataTransferException(
|
|
2536
|
+
f"File not found in {local_folder}"
|
|
2537
|
+
)
|
|
2538
|
+
arguments["local.folder"] = upload_folder
|
|
2539
|
+
# arguments["local.numfiles"] = num_files
|
|
2540
|
+
|
|
2541
|
+
arguments['nifi.download_folder'] = upload_folder
|
|
2542
|
+
arguments['python.path'] = PYTHON_PATH_ECMWF
|
|
2543
|
+
arguments['python.command'] = str(Path(upload_folder, local_regexp))
|
|
2544
|
+
|
|
2545
|
+
args.ckan_resource = ckan_resource
|
|
2546
|
+
self.__nifi_client.add_default_ckan_parameters(arguments, args)
|
|
2547
|
+
arguments[self.__nifi_client.CKAN_RESOURCE] = \
|
|
2548
|
+
self.generate_ckan_resource_name(args, False)
|
|
2549
|
+
|
|
2550
|
+
keys_arguments: Dict[str, Any] = {}
|
|
2551
|
+
|
|
2552
|
+
processors_with_ckan_sensitive_parameters = ["CKANFileUploader"]
|
|
2553
|
+
sensitive_parameters = \
|
|
2554
|
+
self.__nifi_client.set_sensitive_ckan_parameters(
|
|
2555
|
+
processors_with_ckan_sensitive_parameters, args
|
|
2556
|
+
)
|
|
2557
|
+
|
|
2558
|
+
execution_type = {
|
|
2559
|
+
"GenerateFlowFile": ExecutionType.ONCE,
|
|
2560
|
+
"ExecuteStreamCommand": ExecutionType.ONCE,
|
|
2561
|
+
"FetchFile": ExecutionType.ONCE,
|
|
2562
|
+
"UpdateAttribute": ExecutionType.ONCE,
|
|
2563
|
+
"CKANFileUploader": ExecutionType.ONCE,
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
return self.__nifi_client.run_process_group(
|
|
2567
|
+
"ecmwf2ckan_v1.0",
|
|
2568
|
+
execution_type,
|
|
2569
|
+
arguments,
|
|
2570
|
+
keys_arguments,
|
|
2571
|
+
sensitive_parameters,
|
|
2572
|
+
keycloak_token=self.__keycloak_token,
|
|
2573
|
+
accounting_target="CKANFileUploader",
|
|
2574
|
+
)
|
|
2575
|
+
|
|
2576
|
+
except Exception as ex:
|
|
2577
|
+
raise HidDataTransferException(ex) from ex
|
|
2578
|
+
|
|
2579
|
+
def ecmwf2hdfs(
|
|
2580
|
+
self,
|
|
2581
|
+
data_script,
|
|
2582
|
+
data_target,
|
|
2583
|
+
data_source,
|
|
2584
|
+
kerberos_principal=None,
|
|
2585
|
+
kerberos_password=None
|
|
2586
|
+
) -> tuple[str, AccountingInfo]:
|
|
2587
|
+
"""
|
|
2588
|
+
transfer data from ECMWF open data service to HDFS
|
|
2589
|
+
|
|
2590
|
+
Args:
|
|
2591
|
+
data_target (str): The target path in HDFS.
|
|
2592
|
+
data_source (str): The filename in script.
|
|
2593
|
+
data_script (str): Path to the python script.
|
|
2594
|
+
kerberos_principal (str): The kerberos principal.
|
|
2595
|
+
kerberos_password (str): The kerberos password.
|
|
2596
|
+
|
|
2597
|
+
Returns:
|
|
2598
|
+
tuple[str, AccountingInfo]: The result of the process group execution.
|
|
2599
|
+
|
|
2600
|
+
Raises:
|
|
2601
|
+
HidDataTransferException: If an error occurs during
|
|
2602
|
+
the data transfer process.
|
|
2603
|
+
|
|
2604
|
+
"""
|
|
2605
|
+
|
|
2606
|
+
args = SimpleNamespace(
|
|
2607
|
+
data_source=data_source,
|
|
2608
|
+
data_target=data_target,
|
|
2609
|
+
data_script=data_script,
|
|
2610
|
+
kerberos_principal=kerberos_principal,
|
|
2611
|
+
kerberos_password=kerberos_password,
|
|
2612
|
+
)
|
|
2613
|
+
|
|
2614
|
+
processors_with_kerberos = ["PutHDFS"]
|
|
2615
|
+
kerberos_account = SimpleNamespace(
|
|
2616
|
+
kerberos_principal=kerberos_principal,
|
|
2617
|
+
kerberos_password=kerberos_password,
|
|
2618
|
+
)
|
|
2619
|
+
|
|
2620
|
+
self.__logger.info(
|
|
2621
|
+
"executing ecmwf2hdfs command with args: %s",
|
|
2622
|
+
self.__nifi_client.format_args_to_string(args),
|
|
2623
|
+
)
|
|
2624
|
+
|
|
2625
|
+
upload_folder = None
|
|
2626
|
+
try:
|
|
2627
|
+
arguments: Dict[str, Any] = {}
|
|
2628
|
+
arguments[HDFS_DATA_FOLDER] = args.data_target
|
|
2629
|
+
arguments[HDFS_FILENAME] = args.data_source
|
|
2630
|
+
|
|
2631
|
+
local_regexp = \
|
|
2632
|
+
args.data_script[args.data_script.rfind("/") + 1 :]
|
|
2633
|
+
local_folder = args.data_script[: args.data_script.rfind("/")]
|
|
2634
|
+
|
|
2635
|
+
# Transfer script file to NIFI upload subfolder
|
|
2636
|
+
# (within user folder)
|
|
2637
|
+
upload_folder, num_files = self.__nifi_client.upload_files(
|
|
2638
|
+
local_folder, local_regexp
|
|
2639
|
+
)
|
|
2640
|
+
if num_files == 0:
|
|
2641
|
+
raise HidDataTransferException(
|
|
2642
|
+
f"File not found in {local_folder}"
|
|
2643
|
+
)
|
|
2644
|
+
arguments["local.folder"] = upload_folder
|
|
2645
|
+
# arguments["local.numfiles"] = num_files
|
|
2646
|
+
|
|
2647
|
+
arguments['nifi.download_folder'] = upload_folder
|
|
2648
|
+
arguments['python.path'] = PYTHON_PATH_ECMWF
|
|
2649
|
+
arguments['python.command'] = str(Path(upload_folder, local_regexp))
|
|
2650
|
+
|
|
2651
|
+
keys_arguments: Dict[str, Any] = {}
|
|
2652
|
+
|
|
2653
|
+
execution_type = {
|
|
2654
|
+
"GenerateFlowFile": ExecutionType.ONCE,
|
|
2655
|
+
"ExecuteStreamCommand": ExecutionType.ONCE,
|
|
2656
|
+
"FetchFile": ExecutionType.ONCE,
|
|
2657
|
+
"UpdateAttribute": ExecutionType.ONCE,
|
|
2658
|
+
"PutHDFS": ExecutionType.FOREVER,
|
|
2659
|
+
}
|
|
2660
|
+
|
|
2661
|
+
return self.__nifi_client.run_process_group(
|
|
2662
|
+
"ecmwf2hdfs",
|
|
2663
|
+
execution_type,
|
|
2664
|
+
arguments,
|
|
2665
|
+
keys_arguments,
|
|
2666
|
+
keycloak_token=self.__keycloak_token,
|
|
2667
|
+
processors_with_kerberos=processors_with_kerberos,
|
|
2668
|
+
kerberos_account=kerberos_account,
|
|
2669
|
+
accounting_target="PutHDFS",
|
|
2670
|
+
)
|
|
2671
|
+
|
|
2672
|
+
except Exception as ex:
|
|
2673
|
+
raise HidDataTransferException(ex) from ex
|
|
2674
|
+
|
|
2675
|
+
|
|
2250
2676
|
def check_command_status(self, command_id):
|
|
2251
2677
|
"""
|
|
2252
2678
|
Checks the status of a NIFI pipeline (process group) by ID
|
|
@@ -125,6 +125,7 @@ class NIFIClient:
|
|
|
125
125
|
CKAN_RESOURCE = "ckan.resource"
|
|
126
126
|
CKAN_CONCURRENT_TASKS = "ckan.concurrent_tasks"
|
|
127
127
|
KERBEROS_PASSWORD = "Kerberos Password"
|
|
128
|
+
APIKEY = "apikey" #Meteofrance APIKEY
|
|
128
129
|
|
|
129
130
|
def __init__(self):
|
|
130
131
|
"""Constructor method"""
|
|
@@ -1775,6 +1776,19 @@ class NIFIClient:
|
|
|
1775
1776
|
)
|
|
1776
1777
|
return sensitive_parameters
|
|
1777
1778
|
|
|
1779
|
+
def set_sensitive_meteofrance_parameters(
|
|
1780
|
+
self, processors_with_meteofrance_sensitive_parameters, args):
|
|
1781
|
+
"""Set sensitive parameters for METEOFRANCE connection"""
|
|
1782
|
+
sensitive_parameters = {}
|
|
1783
|
+
for processor in processors_with_meteofrance_sensitive_parameters:
|
|
1784
|
+
inner_sensitive_parameters = {}
|
|
1785
|
+
sensitive_parameters[processor] = inner_sensitive_parameters
|
|
1786
|
+
if args.meteofrance_apikey:
|
|
1787
|
+
inner_sensitive_parameters[self.APIKEY] = (
|
|
1788
|
+
args.meteofrance_apikey
|
|
1789
|
+
)
|
|
1790
|
+
return sensitive_parameters
|
|
1791
|
+
|
|
1778
1792
|
def set_kerberos_configuration(self, process_group_id,
|
|
1779
1793
|
kerberos_account, processors_with_kerberos):
|
|
1780
1794
|
"""Set Kerberos configuration for processors"""
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "hid_data_transfer_lib"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.1"
|
|
4
4
|
description = "HiDALGO Data Transfer library provides methods to transfer data between different data providers and consumers using NIFI pipelines"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Jesús Gorroñogoitia", email = "jesus.gorronogoitia@eviden.com" },
|
|
7
|
+
{ name = "Angela Rivera", email = "angela@meteogrid.com" },
|
|
7
8
|
]
|
|
8
9
|
license = "APL-2.0"
|
|
9
10
|
readme = "README.md"
|
|
@@ -41,7 +42,7 @@ pytest = "^8.3.5"
|
|
|
41
42
|
pytest-cov = "^6.1.0"
|
|
42
43
|
pytest-env = "^1.1.5"
|
|
43
44
|
numpy = "^2.3.4"
|
|
44
|
-
python-dotenv = "^1.2.
|
|
45
|
+
python-dotenv = "^1.2.4"
|
|
45
46
|
|
|
46
47
|
[build-system]
|
|
47
48
|
requires = ["poetry-core"]
|
{hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/__init__.py
RENAMED
|
File without changes
|
{hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/conf/__init__.py
RENAMED
|
File without changes
|
{hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/conf/hid_dt.cfg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/nifi/__init__.py
RENAMED
|
File without changes
|
{hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/nifi/nifi_rest.py
RENAMED
|
File without changes
|
|
File without changes
|
{hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/util/__init__.py
RENAMED
|
File without changes
|
{hid_data_transfer_lib-0.4.1 → hid_data_transfer_lib-0.5.1}/hid_data_transfer_lib/util/util.py
RENAMED
|
File without changes
|