hid_data_transfer_lib 0.3.10__tar.gz → 0.3.11__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 (20) hide show
  1. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/PKG-INFO +2 -2
  2. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/README.md +1 -1
  3. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/hid_dt_lib.py +51 -62
  4. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/nifi/nifi_client.py +98 -37
  5. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/nifi/nifi_rest.py +157 -16
  6. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/util/util.py +7 -3
  7. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/pyproject.toml +1 -1
  8. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/__init__.py +0 -0
  9. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/conf/__init__.py +0 -0
  10. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/conf/hid_dt.cfg +0 -0
  11. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/conf/hid_dt_configuration.py +0 -0
  12. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/conf/hid_dt_local.cfg +0 -0
  13. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/conf/hid_dt_psnc.cfg +0 -0
  14. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/exceptions/__init__.py +0 -0
  15. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/exceptions/hid_dt_exceptions.py +0 -0
  16. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/keycloak/__init__.py +0 -0
  17. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/keycloak/keycloak_rest.py +0 -0
  18. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/nifi/__init__.py +0 -0
  19. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/py.typed +0 -0
  20. {hid_data_transfer_lib-0.3.10 → hid_data_transfer_lib-0.3.11}/hid_data_transfer_lib/util/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hid_data_transfer_lib
3
- Version: 0.3.10
3
+ Version: 0.3.11
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
@@ -51,7 +51,7 @@ The Data Transfer Library sends requests to NIFI through its REST API.
51
51
  To use the Data Transfer library, it is required the following requirements:
52
52
  - **Python3** execution environment
53
53
  - **Poetry** python package management tool (optional)
54
- - **NIFI** instance, with a NIFI server SSH account (for keys transfer)
54
+ - **NIFI** instance, with a NIFI 2.X server SSH account (for keys transfer). Latest NIFI supported version: 2.8
55
55
  - **Keycloak** instance, with a KEYCLOAK user's account
56
56
  - **HDFS** instance, with an user's Kerberos principal account
57
57
  - **CKAN** instance, with an user APIKey
@@ -32,7 +32,7 @@ The Data Transfer Library sends requests to NIFI through its REST API.
32
32
  To use the Data Transfer library, it is required the following requirements:
33
33
  - **Python3** execution environment
34
34
  - **Poetry** python package management tool (optional)
35
- - **NIFI** instance, with a NIFI server SSH account (for keys transfer)
35
+ - **NIFI** instance, with a NIFI 2.X server SSH account (for keys transfer). Latest NIFI supported version: 2.8
36
36
  - **Keycloak** instance, with a KEYCLOAK user's account
37
37
  - **HDFS** instance, with an user's Kerberos principal account
38
38
  - **CKAN** instance, with an user APIKey
@@ -34,7 +34,6 @@ from hid_data_transfer_lib.nifi.nifi_client import (
34
34
  NIFIClient, ExecutionType, AccountingInfo
35
35
  )
36
36
 
37
- KERBEROS_PRINCIPAL = "kerberos.principal"
38
37
  HDFS_DATA_FOLDER = "hdfs.data_folder"
39
38
  HDFS_FILENAME = "hdfs.filename"
40
39
  HPC_TARGET_FOLDER = "hpc.target_folder"
@@ -158,9 +157,13 @@ class HIDDataTransfer:
158
157
  hpc_secret_key=hpc_secret_key_path,
159
158
  data_source=data_source,
160
159
  data_target=data_target,
160
+ recursive=recursive,
161
+ )
162
+
163
+ processors_with_kerberos = ["ListHDFS", "FetchHDFS"]
164
+ kerberos_account = SimpleNamespace(
161
165
  kerberos_principal=kerberos_principal,
162
166
  kerberos_password=kerberos_password,
163
- recursive=recursive,
164
167
  )
165
168
 
166
169
  self.__logger.info(
@@ -175,7 +178,7 @@ class HIDDataTransfer:
175
178
  "/".join(args.data_source.split("/")[:-1])
176
179
  arguments[HDFS_FILENAME] = \
177
180
  self.process_wildcards(args.data_source.split("/")[-1])
178
- arguments[KERBEROS_PRINCIPAL] = args.kerberos_principal
181
+
179
182
  arguments[RECURSIVE] = args.recursive
180
183
 
181
184
  execution_type = {
@@ -197,14 +200,6 @@ class HIDDataTransfer:
197
200
  args
198
201
  )
199
202
 
200
- processors_with_hdfs_sensitive_parameters = \
201
- ["ListHDFS", "FetchHDFS"]
202
- sensitive_parameters.update(
203
- self.__nifi_client.set_sensitive_hdfs_parameters(
204
- processors_with_hdfs_sensitive_parameters, args
205
- )
206
- )
207
-
208
203
  if not args.hpc_secret_key and not args.hpc_password:
209
204
  raise HidDataTransferException(HPC_ACCOUNT_MSG)
210
205
 
@@ -227,6 +222,8 @@ class HIDDataTransfer:
227
222
  accounting_target="PutSFTP",
228
223
  concurrent_tasks=concurrent_tasks_dict,
229
224
  ignore_bulletins_in_processors=["PutSFTP"],
225
+ processors_with_kerberos=processors_with_kerberos,
226
+ kerberos_account=kerberos_account,
230
227
  )
231
228
 
232
229
  except Exception as ex:
@@ -387,6 +384,12 @@ class HIDDataTransfer:
387
384
  kerberos_password=kerberos_password,
388
385
  )
389
386
 
387
+ processors_with_kerberos = ["ListHDFS", "FetchHDFS"]
388
+ kerberos_account = SimpleNamespace(
389
+ kerberos_principal=kerberos_principal,
390
+ kerberos_password=kerberos_password,
391
+ )
392
+
390
393
  self.__logger.info(
391
394
  "executing hdfs2hpc_2fa command with args: %s",
392
395
  self.__nifi_client.format_args_to_string(args),
@@ -399,7 +402,6 @@ class HIDDataTransfer:
399
402
  "/".join(args.data_source.split("/")[:-1])
400
403
  arguments[HDFS_FILENAME] = \
401
404
  self.process_wildcards(args.data_source.split("/")[-1])
402
- arguments[KERBEROS_PRINCIPAL] = args.kerberos_principal
403
405
 
404
406
  # set local.data_folder to keep dataset retrieved from HDFS
405
407
  __uuid = uuid.uuid4()
@@ -422,16 +424,6 @@ class HIDDataTransfer:
422
424
  ],
423
425
  }
424
426
 
425
- sensitive_parameters = {}
426
-
427
- processors_with_hdfs_sensitive_parameters = \
428
- ["ListHDFS", "FetchHDFS"]
429
- sensitive_parameters.update(
430
- self.__nifi_client.set_sensitive_hdfs_parameters(
431
- processors_with_hdfs_sensitive_parameters, args
432
- )
433
- )
434
-
435
427
  if not args.hpc_secret_key:
436
428
  raise HidDataTransferException(HPC_ACCOUNT_MSG)
437
429
 
@@ -450,10 +442,12 @@ class HIDDataTransfer:
450
442
  execution_type,
451
443
  arguments,
452
444
  keys_arguments=keys_arguments,
453
- sensitive_parameters=sensitive_parameters,
445
+ sensitive_parameters=None,
454
446
  keycloak_token=self.__keycloak_token,
455
447
  accounting_target="PutFile",
456
448
  concurrent_tasks=concurrent_tasks_dict,
449
+ processors_with_kerberos=processors_with_kerberos,
450
+ kerberos_account=kerberos_account,
457
451
  )
458
452
  process_ids.append(process_id)
459
453
 
@@ -462,7 +456,7 @@ class HIDDataTransfer:
462
456
  execution_type,
463
457
  arguments,
464
458
  keys_arguments=keys_arguments,
465
- sensitive_parameters=sensitive_parameters,
459
+ sensitive_parameters=None,
466
460
  keycloak_token=self.__keycloak_token,
467
461
  processor_with_2fa="SftpTransferToHPCWithVPNCode",
468
462
  callback_2fa=callback_2fa,
@@ -536,6 +530,12 @@ class HIDDataTransfer:
536
530
  recursive=recursive,
537
531
  )
538
532
 
533
+ processors_with_kerberos = ["PutHDFS"]
534
+ kerberos_account = SimpleNamespace(
535
+ kerberos_principal=kerberos_principal,
536
+ kerberos_password=kerberos_password,
537
+ )
538
+
539
539
  self.__logger.info(
540
540
  "executing hpc2hdfs command with args: %s",
541
541
  self.__nifi_client.format_args_to_string(args),
@@ -549,7 +549,6 @@ class HIDDataTransfer:
549
549
  : args.data_source.rfind("/")
550
550
  ]
551
551
  arguments[HDFS_DATA_FOLDER] = args.data_target
552
- arguments[KERBEROS_PRINCIPAL] = args.kerberos_principal
553
552
  arguments[RECURSIVE] = args.recursive
554
553
 
555
554
  execution_type = {
@@ -572,14 +571,6 @@ class HIDDataTransfer:
572
571
  processors_with_hpc_sensitive_parameters, args
573
572
  )
574
573
 
575
- processors_with_hdfs_sensitive_parameters = \
576
- ["PutHDFS"]
577
- sensitive_parameters.update(
578
- self.__nifi_client.set_sensitive_hdfs_parameters(
579
- processors_with_hdfs_sensitive_parameters, args
580
- )
581
- )
582
-
583
574
  if not args.hpc_secret_key and not args.hpc_password:
584
575
  raise HidDataTransferException(HPC_ACCOUNT_MSG)
585
576
 
@@ -602,6 +593,8 @@ class HIDDataTransfer:
602
593
  accounting_target="PutHDFS",
603
594
  concurrent_tasks=concurrent_tasks_dict,
604
595
  ignore_bulletins_in_processors=["FetchSFTP"],
596
+ processors_with_kerberos=processors_with_kerberos,
597
+ kerberos_account=kerberos_account,
605
598
  )
606
599
 
607
600
  except Exception as ex:
@@ -712,6 +705,12 @@ class HIDDataTransfer:
712
705
  kerberos_password=kerberos_password,
713
706
  )
714
707
 
708
+ processors_with_kerberos = ["PutHDFS"]
709
+ kerberos_account = SimpleNamespace(
710
+ kerberos_principal=kerberos_principal,
711
+ kerberos_password=kerberos_password,
712
+ )
713
+
715
714
  self.__logger.info(
716
715
  "executing hpc2hdfs_2fa command with args: %s",
717
716
  self.__nifi_client.format_args_to_string(args),
@@ -728,7 +727,6 @@ class HIDDataTransfer:
728
727
  : args.data_source.rfind("/")
729
728
  ]
730
729
  arguments[HDFS_DATA_FOLDER] = args.data_target
731
- arguments[KERBEROS_PRINCIPAL] = args.kerberos_principal
732
730
 
733
731
  # set local.data_folder to keep dataset retrieved from HPC
734
732
  __uuid = uuid.uuid4()
@@ -758,14 +756,6 @@ class HIDDataTransfer:
758
756
  processors_with_hpc_sensitive_parameters, args
759
757
  )
760
758
 
761
- processors_with_hdfs_sensitive_parameters = \
762
- ["PutHDFS"]
763
- sensitive_parameters.update(
764
- self.__nifi_client.set_sensitive_hdfs_parameters(
765
- processors_with_hdfs_sensitive_parameters, args
766
- )
767
- )
768
-
769
759
  if not args.hpc_secret_key and not args.hpc_password:
770
760
  raise HidDataTransferException(HPC_ACCOUNT_MSG)
771
761
 
@@ -788,7 +778,6 @@ class HIDDataTransfer:
788
778
  keycloak_token=self.__keycloak_token,
789
779
  processor_with_2fa="SftpTransferFromHPCWithVPNCode",
790
780
  callback_2fa=callback_2fa,
791
- accounting_target="PutHDFS",
792
781
  concurrent_tasks=concurrent_tasks_dict,
793
782
  )
794
783
  process_ids.append(process_id)
@@ -802,6 +791,8 @@ class HIDDataTransfer:
802
791
  keycloak_token=self.__keycloak_token,
803
792
  accounting_target="PutHDFS",
804
793
  concurrent_tasks=concurrent_tasks_dict,
794
+ processors_with_kerberos=processors_with_kerberos,
795
+ kerberos_account=kerberos_account,
805
796
  )
806
797
  process_ids.append(process_id)
807
798
 
@@ -913,6 +904,12 @@ class HIDDataTransfer:
913
904
  recursive=recursive,
914
905
  )
915
906
 
907
+ processors_with_kerberos = ["ListHDFS", "FetchHDFS"]
908
+ kerberos_account = SimpleNamespace(
909
+ kerberos_principal=kerberos_principal,
910
+ kerberos_password=kerberos_password,
911
+ )
912
+
916
913
  self.__logger.info(
917
914
  "executing hdfs2ckan command with args: %s",
918
915
  self.__nifi_client.format_args_to_string(args),
@@ -923,7 +920,6 @@ class HIDDataTransfer:
923
920
  "/".join(args.data_source.split("/")[:-1])
924
921
  arguments[HDFS_FILENAME] = \
925
922
  self.process_wildcards(args.data_source.split("/")[-1])
926
- arguments[KERBEROS_PRINCIPAL] = args.kerberos_principal
927
923
  self.__nifi_client.add_default_ckan_parameters(arguments, args)
928
924
  arguments[self.__nifi_client.CKAN_RESOURCE] = \
929
925
  self.generate_ckan_resource_name(args)
@@ -943,14 +939,6 @@ class HIDDataTransfer:
943
939
  processors_with_ckan_sensitive_parameters, args
944
940
  )
945
941
 
946
- processors_with_hdfs_sensitive_parameters = \
947
- ["ListHDFS", "FetchHDFS"]
948
- sensitive_parameters.update(
949
- self.__nifi_client.set_sensitive_hdfs_parameters(
950
- processors_with_hdfs_sensitive_parameters, args
951
- )
952
- )
953
-
954
942
  # Set the number of concurrent tasks
955
943
  # for parallel processors in the pipeline
956
944
  if concurrent_tasks is None:
@@ -982,6 +970,8 @@ class HIDDataTransfer:
982
970
  accounting_target="MergeContent",
983
971
  concurrent_tasks=concurrent_tasks_dict,
984
972
  synchronization_processor_name="MergeContent",
973
+ processors_with_kerberos=processors_with_kerberos,
974
+ kerberos_account=kerberos_account,
985
975
  )
986
976
 
987
977
  except Exception as ex:
@@ -1033,6 +1023,12 @@ class HIDDataTransfer:
1033
1023
  kerberos_password=kerberos_password,
1034
1024
  )
1035
1025
 
1026
+ processors_with_kerberos = ["PutHDFS"]
1027
+ kerberos_account = SimpleNamespace(
1028
+ kerberos_principal=kerberos_principal,
1029
+ kerberos_password=kerberos_password,
1030
+ )
1031
+
1036
1032
  self.__logger.info(
1037
1033
  "executing ckan2hdfs command with args: %s",
1038
1034
  self.__nifi_client.format_args_to_string(args),
@@ -1043,7 +1039,6 @@ class HIDDataTransfer:
1043
1039
  arguments[self.__nifi_client.CKAN_RESOURCE] = \
1044
1040
  self.process_wildcards(args.ckan_resource)
1045
1041
  arguments[HDFS_DATA_FOLDER] = args.data_target
1046
- arguments[KERBEROS_PRINCIPAL] = args.kerberos_principal
1047
1042
 
1048
1043
  execution_type = {
1049
1044
  "CKANFileDownloader": ExecutionType.ONCE,
@@ -1056,14 +1051,6 @@ class HIDDataTransfer:
1056
1051
  processors_with_ckan_sensitive_parameters, args
1057
1052
  )
1058
1053
 
1059
- processors_with_hdfs_sensitive_parameters = \
1060
- ["PutHDFS"]
1061
- sensitive_parameters.update(
1062
- self.__nifi_client.set_sensitive_hdfs_parameters(
1063
- processors_with_hdfs_sensitive_parameters, args
1064
- )
1065
- )
1066
-
1067
1054
  # Set the number of concurrent tasks
1068
1055
  # for parallel processors in the pipeline
1069
1056
  if concurrent_tasks is None:
@@ -1095,7 +1082,9 @@ class HIDDataTransfer:
1095
1082
  sensitive_parameters,
1096
1083
  keycloak_token=self.__keycloak_token,
1097
1084
  accounting_target="PutHDFS",
1098
- concurrent_tasks=concurrent_tasks_dict
1085
+ concurrent_tasks=concurrent_tasks_dict,
1086
+ processors_with_kerberos=processors_with_kerberos,
1087
+ kerberos_account=kerberos_account,
1099
1088
  )
1100
1089
 
1101
1090
  except Exception as ex:
@@ -192,13 +192,13 @@ class NIFIClient:
192
192
  def get_process_group_processors(self, group_id) -> dict:
193
193
  """gets the processors of a process group identified by id"""
194
194
  return self.nifi_rest_client.process_group_get_request(
195
- group_id, self.token(), "processors"
195
+ group_id, self.token(), entity="processors"
196
196
  )
197
197
 
198
198
  def get_process_group_connections(self, group_id) -> dict:
199
199
  """gets the connetions of a process group identified by id"""
200
200
  return self.nifi_rest_client.process_group_get_request(
201
- group_id, self.token(), "connections"
201
+ group_id, self.token(), entity="connections"
202
202
  )
203
203
 
204
204
  def get_processors_sequence(self, group_id) -> list:
@@ -324,6 +324,22 @@ class NIFIClient:
324
324
  processor["component"]["config"][configuration_name] = \
325
325
  configuration_value
326
326
 
327
+ def update_kpus_kerberos_account(
328
+ self, kpus, kerberos_account,
329
+ ):
330
+ """updates the Kerberos account of a kpus"""
331
+ kpus["component"]["properties"]['Kerberos Principal'] = \
332
+ kerberos_account.kerberos_principal
333
+ kpus["component"]["properties"]['Kerberos Password'] = \
334
+ kerberos_account.kerberos_password
335
+
336
+ def update_processor_kus(
337
+ self, processor, kus_id,
338
+ ):
339
+ """updates the KUs of a processor"""
340
+ processor["component"]['config']["properties"]['Kerberos User Service'] = \
341
+ kus_id
342
+
327
343
  # DELETE requests
328
344
 
329
345
  # MULTI-REQUESTS methods
@@ -890,6 +906,8 @@ class NIFIClient:
890
906
  accounting_target: Optional[str] = None,
891
907
  concurrent_tasks: Optional[dict] = None,
892
908
  ignore_bulletins_in_processors=None,
909
+ processors_with_kerberos=None,
910
+ kerberos_account=None,
893
911
  ) -> tuple[str, AccountingInfo]:
894
912
  """MAIN method to run a processor from a template identify by name
895
913
  The procedure is as follows:
@@ -946,6 +964,11 @@ class NIFIClient:
946
964
  self.__logger.info(
947
965
  "Process group %s created\n", process_group["id"])
948
966
 
967
+ # Set Kerberos configuration
968
+ if kerberos_account and processors_with_kerberos:
969
+ self.set_kerberos_configuration(
970
+ process_group["id"], kerberos_account, processors_with_kerberos)
971
+
949
972
  # Get ordered list of all processors in the process group
950
973
  processors = self.get_ordered_processors_in_group(
951
974
  process_group["id"])
@@ -1102,6 +1125,8 @@ class NIFIClient:
1102
1125
  concurrent_tasks: Optional[dict] = None,
1103
1126
  synchronization_processor_name=None,
1104
1127
  ignore_bulletins_in_processors=None,
1128
+ processors_with_kerberos=None,
1129
+ kerberos_account=None,
1105
1130
  ) -> tuple[str, AccountingInfo]:
1106
1131
  """MAIN method to run a processor from a template identify by name
1107
1132
  The procedure is as follows:
@@ -1127,6 +1152,11 @@ class NIFIClient:
1127
1152
  self.__logger.info(
1128
1153
  "Process group %s created\n", process_group["id"])
1129
1154
 
1155
+ # Set Kerberos configuration
1156
+ if kerberos_account and processors_with_kerberos:
1157
+ self.set_kerberos_configuration(
1158
+ process_group["id"], kerberos_account, processors_with_kerberos)
1159
+
1130
1160
  # Accounting initialization
1131
1161
  pipeline_start_time = time.time()
1132
1162
 
@@ -1156,7 +1186,8 @@ class NIFIClient:
1156
1186
  accounting_target,
1157
1187
  parameter_context,
1158
1188
  synchronization_processor_name=synchronization_processor_name,
1159
- first_processor_expected_outgoing_flowfiles=first_processor_expected_outgoing_flowfiles,
1189
+ first_processor_expected_outgoing_flowfiles=
1190
+ first_processor_expected_outgoing_flowfiles,
1160
1191
  ignore_bulletins_in_processors=ignore_bulletins_in_processors,
1161
1192
  )
1162
1193
 
@@ -1338,21 +1369,21 @@ class NIFIClient:
1338
1369
 
1339
1370
  ok, response = self.start_process_group(process_group)
1340
1371
 
1341
- # Wait for first processor to find source files
1342
- if not self.has_processor_executed_once_and_produce_outgoing_flowfiles(
1343
- processors[0]):
1344
- raise HidDataTransferException("Source files not found")
1345
-
1346
- # manage the synchronization point if required
1347
- if synchronization_processor_name:
1348
- self.synchronize_processor_execution(
1349
- process_group['id'],
1350
- synchronization_processor_name,
1351
- execution_type,
1352
- first_processor_expected_outgoing_flowfiles,
1353
- ignore_bulletins_in_processors)
1354
-
1355
1372
  if ok:
1373
+ # Wait for first processor to find source files
1374
+ if not self.has_processor_executed_once_and_produce_outgoing_flowfiles(
1375
+ processors[0]):
1376
+ raise HidDataTransferException("Source files not found")
1377
+
1378
+ # manage the synchronization point if required
1379
+ if synchronization_processor_name:
1380
+ self.synchronize_processor_execution(
1381
+ process_group['id'],
1382
+ synchronization_processor_name,
1383
+ execution_type,
1384
+ first_processor_expected_outgoing_flowfiles,
1385
+ ignore_bulletins_in_processors)
1386
+
1356
1387
  self.wait_for_process_group_completion(
1357
1388
  process_group['id'], processors,
1358
1389
  ignore_bulletins_in_processors)
@@ -1401,6 +1432,30 @@ class NIFIClient:
1401
1432
  processor, self.token())
1402
1433
  return processor
1403
1434
 
1435
+ def set_kpus_kerberos_account(
1436
+ self, kpus, kerberos_account):
1437
+ """Set the Kerberos account of a kpus instance"""
1438
+
1439
+ self.update_kpus_kerberos_account(
1440
+ kpus,
1441
+ kerberos_account,
1442
+ )
1443
+ kpus = self.nifi_rest_client.update_kpus(
1444
+ kpus, self.token())
1445
+ return kpus
1446
+
1447
+ def set_processor_kus(
1448
+ self, processor, kus_id):
1449
+ """Set the Kerberos User Service of a processor instance"""
1450
+
1451
+ self.update_processor_kus(
1452
+ processor,
1453
+ kus_id,
1454
+ )
1455
+ processor = self.nifi_rest_client.update_processor(
1456
+ processor, self.token())
1457
+ return processor
1458
+
1404
1459
  def set_2fa_token(self, processor, parameter_context,
1405
1460
  processor_with_2fa, callback_2fa):
1406
1461
  '''Set the 2FA token in context parameter
@@ -1707,19 +1762,25 @@ class NIFIClient:
1707
1762
  )
1708
1763
  return sensitive_parameters
1709
1764
 
1710
- def set_sensitive_hdfs_parameters(
1711
- self, processors_with_hdfs_sensitive_parameters, args
1712
- ):
1713
- """Set sensitive parameters for HDFS connection"""
1714
- sensitive_parameters = {}
1715
- for processor in processors_with_hdfs_sensitive_parameters:
1716
- inner_sensitive_parameters = {}
1717
- sensitive_parameters[processor] = inner_sensitive_parameters
1718
- if args.kerberos_password:
1719
- inner_sensitive_parameters[self.KERBEROS_PASSWORD] = (
1720
- args.kerberos_password
1721
- )
1722
- return sensitive_parameters
1765
+ def set_kerberos_configuration(self, process_group_id,
1766
+ kerberos_account, processors_with_kerberos):
1767
+ """Set Kerberos configuration for processors"""
1768
+ # Implementation to configure Kerberos for specified processors
1769
+ processors = self.get_ordered_processors_in_group(process_group_id)
1770
+
1771
+ # Create a Kerberos Password User Service (KPUS) associated to a process group
1772
+ kpus = self.nifi_rest_client.instantiate_kpus(process_group_id, self.token())
1773
+ # Set principal and password in KPUS
1774
+ kpus = self.set_kpus_kerberos_account(kpus, kerberos_account)
1775
+ # Enable KUPS
1776
+ kpus = self.nifi_rest_client.enable_kpus(kpus, self.token())
1777
+
1778
+ for processor_name in processors_with_kerberos:
1779
+ # Get processor by name
1780
+ processor = self.find_processor_by_name(processors, processor_name)
1781
+
1782
+ # Save changes in processor
1783
+ self.set_processor_kus(processor, kpus['id'])
1723
1784
 
1724
1785
  def clean_process_group_up(self, process_group_id, retry=True):
1725
1786
  """Clean up the process group and associated parameter context"""
@@ -1729,13 +1790,17 @@ class NIFIClient:
1729
1790
  try:
1730
1791
  # Remove transferred keys
1731
1792
  self.__logger.debug("Removing uploaded keys\n")
1732
- self.remove_uploaded_keys(process_group["id"])
1793
+ self.remove_uploaded_keys(process_group_id)
1733
1794
 
1734
1795
  # Stop process_group and wait for all processosr to be stopped
1735
- self.stop_process_group(process_group["id"])
1796
+ self.stop_process_group(process_group_id)
1797
+
1798
+ # Disable controller services
1799
+ self.nifi_rest_client.disable_controller_services(
1800
+ process_group_id, self.token())
1736
1801
 
1737
1802
  # Empty process group queues
1738
- self.empty_process_group_queues(process_group["id"])
1803
+ self.empty_process_group_queues(process_group_id)
1739
1804
 
1740
1805
  # Get parameter context
1741
1806
  if "parameterContext" in process_group["component"]:
@@ -1759,10 +1824,6 @@ class NIFIClient:
1759
1824
  except HidDataTransferException:
1760
1825
  # If case of exception try clean up again
1761
1826
  if retry:
1762
- # self.stop_process_group(
1763
- # process_group["id"])
1764
- # self.empty_process_group_queues(
1765
- # process_group["id"])
1766
1827
  self.clean_process_group_up(
1767
1828
  process_group["id"], retry=False)
1768
1829
 
@@ -126,14 +126,16 @@ class NIFIRESTClient:
126
126
  url = self.build_url("nifi-api", "flow", "process-groups", "root")
127
127
  return self._get_entity(url, token)
128
128
 
129
- def process_group_get_request(self, group_id, token, entity=None) -> dict:
129
+ def process_group_get_request(
130
+ self, group_id, token, process_group_flow=False, entity=None) -> dict:
130
131
  """helper method to process a get request for a process group
131
132
  identified by id"""
132
- url = (
133
- self.build_url("nifi-api", "process-groups", group_id, entity)
134
- if entity
135
- else self.build_url("nifi-api", "process-groups", group_id)
136
- )
133
+ if entity:
134
+ url = self.build_url("nifi-api", "process-groups", group_id, entity)
135
+ elif process_group_flow:
136
+ url = self.build_url("nifi-api", "flow", "process-groups", group_id)
137
+ else:
138
+ url = self.build_url("nifi-api", "process-groups", group_id)
137
139
  return self._get_entity(url, token)
138
140
 
139
141
  def get_templates(self, token) -> dict:
@@ -318,8 +320,8 @@ class NIFIRESTClient:
318
320
  "Content-Type": self.__JSON_CONTENT_TYPE,
319
321
  "Authorization": f"Bearer {token}",
320
322
  }
321
- x = random.uniform(0, 3)
322
- y = random.uniform(0, 3)
323
+ x = random.uniform(0, 1000)
324
+ y = random.uniform(0, 1000)
323
325
  payload = {
324
326
  "revision": {"version": 0},
325
327
  "disconnectedNodeAcknowledged": False,
@@ -353,10 +355,11 @@ class NIFIRESTClient:
353
355
  if response.ok:
354
356
  response_json = response.content.decode()
355
357
  process_group = json.loads(response_json)
358
+
356
359
  # Rename process_group as flow_definition_name + process_group_id
357
360
  process_group_name = process_group["component"]["name"]
358
361
  process_group = self.rename_process_group(
359
- process_group, process_group_name, token
362
+ process_group["id"], process_group_name, token
360
363
  )
361
364
  return process_group
362
365
  else:
@@ -365,18 +368,34 @@ class NIFIRESTClient:
365
368
  f"{response.content.decode()}"
366
369
  )
367
370
 
368
- def rename_process_group(self, process_group, name, token) -> str:
369
- """creates a process group from a given template"""
371
+ def rename_process_group(self, process_group_id, name, token) -> str:
372
+ # TODO Send only what is required to modify the name
373
+ """rename a process group name"""
374
+
375
+ # Reload process_group
376
+ process_group = self.process_group_get_request(
377
+ process_group_id, token, process_group_flow=True)
378
+
370
379
  headers = {
371
380
  "Content-Type": self.__JSON_CONTENT_TYPE,
372
381
  "Authorization": f"Bearer {token}",
373
382
  }
374
- process_group_id = process_group["id"]
375
- process_group["component"]["name"] = name + "_" + process_group_id
376
- payload = json.dumps(process_group)
383
+ process_group_id = process_group["processGroupFlow"]["id"]
384
+
385
+ payload = {
386
+ "component": {
387
+ "id": process_group_id,
388
+ "name": name + "_" + process_group_id
389
+ },
390
+ "revision": {"version": process_group["revision"]["version"]},
391
+ }
392
+
393
+ # payload = json.dumps(process_group)
394
+ payload_json = json.dumps(payload)
395
+
377
396
  response = requests.put(
378
397
  url=self.build_url("nifi-api", "process-groups", process_group_id),
379
- data=payload,
398
+ data=payload_json,
380
399
  verify=self.__conf.nifi_secure_connection(),
381
400
  headers=headers,
382
401
  timeout=self.__REQUEST_TIMEOUT,
@@ -472,6 +491,51 @@ class NIFIRESTClient:
472
491
  f"{response.content.decode()}"
473
492
  )
474
493
 
494
+ def instantiate_kpus(
495
+ self, process_group_id, token
496
+ ) -> dict:
497
+ """creates a Kerberos Password User Service"""
498
+ headers = {
499
+ "Content-Type": self.__JSON_CONTENT_TYPE,
500
+ "Authorization": f"Bearer {token}",
501
+ }
502
+
503
+ payload = {
504
+ "revision": {"version": 0},
505
+ "disconnectedNodeAcknowledged": False,
506
+ "component": {
507
+ "bundle": {
508
+ "group": "org.apache.nifi",
509
+ "artifact": "nifi-kerberos-user-service-nar",
510
+ "version": "2.8.0"
511
+ },
512
+ "type": "org.apache.nifi.kerberos.KerberosPasswordUserService"
513
+ }
514
+ } # /nifi-api/process-groups/e2dde1d0-019c-1000-b433-43f8611cef38/controller-services
515
+ payload_json = json.dumps(payload)
516
+ response = requests.post(
517
+ url=self.build_url(
518
+ "nifi-api",
519
+ "process-groups",
520
+ process_group_id,
521
+ "controller-services",
522
+ ),
523
+ data=payload_json,
524
+ verify=self.__conf.nifi_secure_connection(),
525
+ headers=headers,
526
+ timeout=self.__REQUEST_TIMEOUT,
527
+ )
528
+ if response.ok:
529
+ response_json = response.content.decode()
530
+ kpus = json.loads(response_json)
531
+ return kpus
532
+ else:
533
+ raise HidDataTransferException(
534
+ "Instantiate kpus exception: "
535
+ f"{response.content.decode()}"
536
+ )
537
+
538
+
475
539
  # PUT requests
476
540
 
477
541
  def associate_parameter_context_to_group(
@@ -486,7 +550,6 @@ class NIFIRESTClient:
486
550
  payload = {
487
551
  "revision": {
488
552
  "version": process_group["revision"]["version"],
489
- # "clientId": parameter_context['revision']['clientId']
490
553
  },
491
554
  "disconnectedNodeAcknowledged": False,
492
555
  "component": {
@@ -541,6 +604,84 @@ class NIFIRESTClient:
541
604
  f"Processor exception: {response.content.decode()}"
542
605
  )
543
606
 
607
+ def update_kpus(self, kpus, token) -> dict:
608
+ """updates a kpus identified by id"""
609
+ headers = {
610
+ "Content-Type": self.__JSON_CONTENT_TYPE,
611
+ "Authorization": f"Bearer {token}",
612
+ }
613
+ response = requests.put(
614
+ url=self.build_url("nifi-api", "controller-services", kpus["id"]),
615
+ verify=self.__conf.nifi_secure_connection(),
616
+ data=json.dumps(kpus),
617
+ headers=headers,
618
+ timeout=self.__REQUEST_TIMEOUT,
619
+ )
620
+ if response.ok:
621
+ response_json = response.content.decode()
622
+ return json.loads(response_json)
623
+ else:
624
+ raise HidDataTransferException(
625
+ f"Controller service exception: {response.content.decode()}"
626
+ )
627
+
628
+ def enable_kpus(self, kpus, token) -> dict:
629
+ """updates a kpus identified by id"""
630
+ headers = {
631
+ "Content-Type": self.__JSON_CONTENT_TYPE,
632
+ "Authorization": f"Bearer {token}",
633
+ }
634
+
635
+ payload = {
636
+ "revision":{"version":kpus["revision"]["version"]},
637
+ "state":"ENABLED"
638
+ }
639
+ payload_json = json.dumps(payload)
640
+
641
+ response = requests.put(
642
+ url=self.build_url("nifi-api", "controller-services", kpus['id'], "run-status"),
643
+ verify=self.__conf.nifi_secure_connection(),
644
+ data=payload_json,
645
+ headers=headers,
646
+ timeout=self.__REQUEST_TIMEOUT,
647
+ )
648
+ if response.ok:
649
+ response_json = response.content.decode()
650
+ return json.loads(response_json)
651
+ else:
652
+ raise HidDataTransferException(
653
+ f"Controller service exception: {response.content.decode()}"
654
+ )
655
+
656
+ def disable_controller_services(self, process_group_id, token):
657
+ ''' disable the controller services'''
658
+ headers = {
659
+ "Content-Type": self.__JSON_CONTENT_TYPE,
660
+ "Authorization": f"Bearer {token}",
661
+ }
662
+
663
+ payload = {
664
+ "id": process_group_id,
665
+ "state":"DISABLED"
666
+ }
667
+ payload_json = json.dumps(payload)
668
+
669
+ response = requests.put(
670
+ url=self.build_url(
671
+ "nifi-api", "flow", "process-groups", process_group_id, "controller-services"),
672
+ verify=self.__conf.nifi_secure_connection(),
673
+ data=payload_json,
674
+ headers=headers,
675
+ timeout=self.__REQUEST_TIMEOUT,
676
+ )
677
+ if response.ok:
678
+ response_json = response.content.decode()
679
+ return json.loads(response_json)
680
+ else:
681
+ raise HidDataTransferException(
682
+ f"Process group exception: {response.content.decode()}"
683
+ )
684
+
544
685
  # DELETE requests
545
686
  def delete_update_request(self, entity_name,
546
687
  entity_id, request_id, token) -> bool:
@@ -127,10 +127,12 @@ def sftp_put(
127
127
  sftp.put(source, target)
128
128
  if target_permissions:
129
129
  command = f"chmod {target_permissions} {target}"
130
- ssh.exec_command(command)
130
+ _, stdout, _ = ssh.exec_command(command)
131
+ stdout.channel.recv_exit_status() # Block until done, drains buffers
131
132
  if target_ownership:
132
133
  command = f"chown {target_ownership} {target}"
133
- ssh.exec_command(command)
134
+ _, stdout, _ = ssh.exec_command(command)
135
+ stdout.channel.recv_exit_status() # Block until done, drains buffers
134
136
  except Exception as ex:
135
137
  msg = "Exception transferring keys with SFTP"
136
138
  raise HidDataTransferException(msg) from ex
@@ -189,8 +191,9 @@ def __ssh_execute_command(server, username, command, private_key=None):
189
191
  ssh.connect(server, username=username)
190
192
  else:
191
193
  ssh.connect(server, username=username, key_filename=private_key)
192
- _, _, stderr = ssh.exec_command(command)
194
+ _, stdout, stderr = ssh.exec_command(command)
193
195
  error = stderr.read().decode("utf-8")
196
+ stdout.channel.recv_exit_status() # Block until done, drains buffers
194
197
  if error:
195
198
  raise HidDataTransferException(
196
199
  f"Error '{error}' executing command '{command}'"
@@ -217,6 +220,7 @@ def ssh_list(path, server, username, private_key=None, prefix=None) -> list:
217
220
  else:
218
221
  command = f'find {path} -maxdepth 1 -type f -printf "%p\n"'
219
222
  _, stdout, _ = ssh.exec_command(command)
223
+ stdout.channel.recv_exit_status() # Block until done, drains buffers
220
224
 
221
225
  # read lines from stdout in a list
222
226
  files = []
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hid_data_transfer_lib"
3
- version = "0.3.10"
3
+ version = "0.3.11"
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" },