deltafi 2.0rc1720728217472__py3-none-any.whl → 2.0rc1722532930396__py3-none-any.whl
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.
- deltafi/action.py +25 -123
- deltafi/actiontype.py +2 -6
- deltafi/domain.py +66 -62
- deltafi/exception.py +0 -10
- deltafi/genericmodel.py +3 -1
- deltafi/input.py +1 -165
- deltafi/logger.py +2 -2
- deltafi/plugin.py +12 -18
- deltafi/result.py +32 -245
- deltafi/test_kit/framework.py +69 -66
- deltafi/test_kit/transform.py +41 -13
- {deltafi-2.0rc1720728217472.dist-info → deltafi-2.0rc1722532930396.dist-info}/METADATA +6 -6
- deltafi-2.0rc1722532930396.dist-info/RECORD +23 -0
- deltafi/test_kit/domain.py +0 -59
- deltafi/test_kit/enrich.py +0 -70
- deltafi/test_kit/format.py +0 -105
- deltafi/test_kit/load.py +0 -128
- deltafi/test_kit/validate.py +0 -54
- deltafi-2.0rc1720728217472.dist-info/RECORD +0 -28
- {deltafi-2.0rc1720728217472.dist-info → deltafi-2.0rc1722532930396.dist-info}/WHEEL +0 -0
deltafi/plugin.py
CHANGED
|
@@ -34,8 +34,7 @@ from importlib import metadata
|
|
|
34
34
|
import requests
|
|
35
35
|
from deltafi.actioneventqueue import ActionEventQueue
|
|
36
36
|
from deltafi.domain import Event, ActionExecution
|
|
37
|
-
from deltafi.exception import ExpectedContentException,
|
|
38
|
-
MissingMetadataException
|
|
37
|
+
from deltafi.exception import ExpectedContentException, MissingMetadataException
|
|
39
38
|
from deltafi.logger import get_logger
|
|
40
39
|
from deltafi.result import ErrorResult
|
|
41
40
|
from deltafi.storage import ContentService
|
|
@@ -47,9 +46,9 @@ def _coordinates():
|
|
|
47
46
|
|
|
48
47
|
|
|
49
48
|
def _setup_queue(max_connections):
|
|
50
|
-
|
|
51
|
-
password = os.getenv('
|
|
52
|
-
return ActionEventQueue(
|
|
49
|
+
url = os.getenv('VALKEY_URL', 'http://deltafi-valkey-master:6379')
|
|
50
|
+
password = os.getenv('VALKEY_PASSWORD')
|
|
51
|
+
return ActionEventQueue(url, max_connections, password)
|
|
53
52
|
|
|
54
53
|
|
|
55
54
|
def _setup_content_service():
|
|
@@ -165,8 +164,6 @@ class Plugin(object):
|
|
|
165
164
|
'name': self.action_name(action),
|
|
166
165
|
'description': action.description,
|
|
167
166
|
'type': action.action_type.name,
|
|
168
|
-
'requiresDomains': action.requires_domains,
|
|
169
|
-
'requiresEnrichments': action.requires_enrichments,
|
|
170
167
|
'schema': action.param_class().model_json_schema()
|
|
171
168
|
}
|
|
172
169
|
|
|
@@ -219,7 +216,8 @@ class Plugin(object):
|
|
|
219
216
|
for action in self.actions:
|
|
220
217
|
threading.Thread(target=self._do_action, args=(action,)).start()
|
|
221
218
|
|
|
222
|
-
threading.Thread(target=self._heartbeat)
|
|
219
|
+
hb_thread = threading.Thread(target=self._heartbeat)
|
|
220
|
+
hb_thread.start()
|
|
223
221
|
|
|
224
222
|
self.logger.info("All threads running")
|
|
225
223
|
|
|
@@ -227,6 +225,7 @@ class Plugin(object):
|
|
|
227
225
|
f.close()
|
|
228
226
|
|
|
229
227
|
self.logger.info("Application initialization complete")
|
|
228
|
+
hb_thread.join()
|
|
230
229
|
|
|
231
230
|
def _heartbeat(self):
|
|
232
231
|
long_running_actions = set()
|
|
@@ -263,7 +262,7 @@ class Plugin(object):
|
|
|
263
262
|
while True:
|
|
264
263
|
try:
|
|
265
264
|
event_string = self.queue.take(self.action_name(action))
|
|
266
|
-
event = Event.create(json.loads(event_string), self.
|
|
265
|
+
event = Event.create(json.loads(event_string), self.content_service, action_logger)
|
|
267
266
|
start_time = time.time()
|
|
268
267
|
action_logger.debug(f"Processing event for did {event.context.did}")
|
|
269
268
|
|
|
@@ -277,14 +276,6 @@ class Plugin(object):
|
|
|
277
276
|
f"Action attempted to look up element {e.index + 1} (index {e.index}) from "
|
|
278
277
|
f"content list of size {e.size}",
|
|
279
278
|
f"{str(e)}\n{traceback.format_exc()}")
|
|
280
|
-
except MissingDomainException as e:
|
|
281
|
-
result = ErrorResult(event.context,
|
|
282
|
-
f"Action attempted to access domain {e.name}, which does not exist",
|
|
283
|
-
f"{str(e)}\n{traceback.format_exc()}")
|
|
284
|
-
except MissingEnrichmentException as e:
|
|
285
|
-
result = ErrorResult(event.context,
|
|
286
|
-
f"Action attempted to access enrichment {e.name}, which does not exist",
|
|
287
|
-
f"{str(e)}\n{traceback.format_exc()}")
|
|
288
279
|
except MissingMetadataException as e:
|
|
289
280
|
result = ErrorResult(event.context,
|
|
290
281
|
f"Missing metadata with key {e.key}",
|
|
@@ -297,7 +288,10 @@ class Plugin(object):
|
|
|
297
288
|
|
|
298
289
|
response = {
|
|
299
290
|
'did': event.context.did,
|
|
300
|
-
'
|
|
291
|
+
'flowName': event.context.flow_name,
|
|
292
|
+
'flowId': event.context.flow_id,
|
|
293
|
+
'actionName': event.context.action_name,
|
|
294
|
+
'actionId': event.context.action_id,
|
|
301
295
|
'start': start_time,
|
|
302
296
|
'stop': time.time(),
|
|
303
297
|
'type': result.result_type,
|
deltafi/result.py
CHANGED
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
#
|
|
18
18
|
|
|
19
19
|
import abc
|
|
20
|
-
from enum import Enum
|
|
21
20
|
import uuid
|
|
22
|
-
from
|
|
21
|
+
from enum import Enum
|
|
22
|
+
from typing import NamedTuple
|
|
23
23
|
|
|
24
24
|
from deltafi.domain import Content, Context
|
|
25
25
|
from deltafi.metric import Metric
|
|
@@ -44,22 +44,8 @@ class Result:
|
|
|
44
44
|
|
|
45
45
|
def add_metric(self, metric: Metric):
|
|
46
46
|
self.metrics.append(metric)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class DomainResult(Result):
|
|
50
|
-
def __init__(self, context: Context):
|
|
51
|
-
super().__init__('domain', 'DOMAIN', context)
|
|
52
|
-
self.annotations = {}
|
|
53
|
-
|
|
54
|
-
def annotate(self, key: str, value: str):
|
|
55
|
-
self.annotations[key] = value
|
|
56
47
|
return self
|
|
57
48
|
|
|
58
|
-
def response(self):
|
|
59
|
-
return {
|
|
60
|
-
'annotations': self.annotations
|
|
61
|
-
}
|
|
62
|
-
|
|
63
49
|
|
|
64
50
|
class EgressResult(Result):
|
|
65
51
|
def __init__(self, context: Context, destination: str, bytes_egressed: int):
|
|
@@ -71,31 +57,6 @@ class EgressResult(Result):
|
|
|
71
57
|
return None
|
|
72
58
|
|
|
73
59
|
|
|
74
|
-
class EnrichResult(Result):
|
|
75
|
-
def __init__(self, context: Context):
|
|
76
|
-
super().__init__('enrich', 'ENRICH', context)
|
|
77
|
-
self.enrichments = []
|
|
78
|
-
self.annotations = {}
|
|
79
|
-
|
|
80
|
-
def enrich(self, name: str, value: str, media_type: str):
|
|
81
|
-
self.enrichments.append({
|
|
82
|
-
'name': name,
|
|
83
|
-
'value': value,
|
|
84
|
-
'mediaType': media_type
|
|
85
|
-
})
|
|
86
|
-
return self
|
|
87
|
-
|
|
88
|
-
def annotate(self, key: str, value: str):
|
|
89
|
-
self.annotations[key] = value
|
|
90
|
-
return self
|
|
91
|
-
|
|
92
|
-
def response(self):
|
|
93
|
-
return {
|
|
94
|
-
'enrichments': self.enrichments,
|
|
95
|
-
'annotations': self.annotations
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
60
|
class ErrorResult(Result):
|
|
100
61
|
def __init__(self, context: Context, error_cause: str, error_context: str):
|
|
101
62
|
super().__init__('error', 'ERROR', context)
|
|
@@ -116,7 +77,7 @@ class ErrorResult(Result):
|
|
|
116
77
|
|
|
117
78
|
|
|
118
79
|
class FilterResult(Result):
|
|
119
|
-
def __init__(self, context: Context, filtered_cause: str, filtered_context: str=None):
|
|
80
|
+
def __init__(self, context: Context, filtered_cause: str, filtered_context: str = None):
|
|
120
81
|
super().__init__('filter', 'FILTER', context)
|
|
121
82
|
self.filtered_cause = filtered_cause
|
|
122
83
|
self.filtered_context = filtered_context
|
|
@@ -134,87 +95,13 @@ class FilterResult(Result):
|
|
|
134
95
|
}
|
|
135
96
|
|
|
136
97
|
|
|
137
|
-
class FormatResult(Result):
|
|
138
|
-
def __init__(self, context: Context):
|
|
139
|
-
super().__init__('format', 'FORMAT', context)
|
|
140
|
-
self.content = None
|
|
141
|
-
self.delete_metadata_keys = []
|
|
142
|
-
self.metadata = {}
|
|
143
|
-
|
|
144
|
-
def set_metadata(self, metadata: dict):
|
|
145
|
-
self.metadata = metadata
|
|
146
|
-
return self
|
|
147
|
-
|
|
148
|
-
def add_metadata(self, key: str, value: str):
|
|
149
|
-
self.metadata[key] = value
|
|
150
|
-
return self
|
|
151
|
-
|
|
152
|
-
def delete_metadata_key(self, key: str):
|
|
153
|
-
self.delete_metadata_keys.append(key)
|
|
154
|
-
return self
|
|
155
|
-
|
|
156
|
-
def set_content(self, content: Content):
|
|
157
|
-
self.content = content
|
|
158
|
-
return self
|
|
159
|
-
|
|
160
|
-
def save_string_content(self, string_data: str, name: str, media_type: str):
|
|
161
|
-
segment = self.context.content_service.put_str(self.context.did, string_data)
|
|
162
|
-
self.content = Content(name=name, segments=[segment], media_type=media_type,
|
|
163
|
-
content_service=self.context.content_service)
|
|
164
|
-
return self
|
|
165
|
-
|
|
166
|
-
def save_byte_content(self, byte_data: bytes, name: str, media_type: str):
|
|
167
|
-
segment = self.context.content_service.put_bytes(self.context.did, byte_data)
|
|
168
|
-
self.content = Content(name=name, segments=[segment], media_type=media_type,
|
|
169
|
-
content_service=self.context.content_service)
|
|
170
|
-
return self
|
|
171
|
-
|
|
172
|
-
def response(self):
|
|
173
|
-
return {
|
|
174
|
-
'content': self.content.json(),
|
|
175
|
-
'metadata': self.metadata,
|
|
176
|
-
'deleteMetadataKeys': self.delete_metadata_keys
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
class ChildFormatResult:
|
|
181
|
-
def __init__(self, format_result: FormatResult = None):
|
|
182
|
-
self._did = str(uuid.uuid4())
|
|
183
|
-
self.format_result = format_result
|
|
184
|
-
|
|
185
|
-
@property
|
|
186
|
-
def did(self):
|
|
187
|
-
return self._did
|
|
188
|
-
|
|
189
|
-
def response(self):
|
|
190
|
-
res = self.format_result.response()
|
|
191
|
-
res["did"] = self._did
|
|
192
|
-
return res
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
class FormatManyResult(Result):
|
|
196
|
-
def __init__(self, context: Context):
|
|
197
|
-
super().__init__('formatMany', 'FORMAT_MANY', context)
|
|
198
|
-
self.format_results = []
|
|
199
|
-
|
|
200
|
-
def add_format_result(self, format_result):
|
|
201
|
-
if isinstance(format_result, ChildFormatResult):
|
|
202
|
-
self.format_results.append(format_result)
|
|
203
|
-
else:
|
|
204
|
-
self.format_results.append(ChildFormatResult(format_result))
|
|
205
|
-
return self
|
|
206
|
-
|
|
207
|
-
def response(self):
|
|
208
|
-
return [format_result.response() for format_result in self.format_results]
|
|
209
|
-
|
|
210
|
-
|
|
211
98
|
class IngressResultItem:
|
|
212
|
-
def __init__(self, context: Context,
|
|
99
|
+
def __init__(self, context: Context, delta_file_name: str):
|
|
213
100
|
self.context = context
|
|
214
|
-
self.filename = filename
|
|
215
101
|
self._did = str(uuid.uuid4())
|
|
216
102
|
self.content = []
|
|
217
103
|
self.metadata = {}
|
|
104
|
+
self.delta_file_name = delta_file_name
|
|
218
105
|
|
|
219
106
|
@property
|
|
220
107
|
def did(self):
|
|
@@ -253,7 +140,7 @@ class IngressResultItem:
|
|
|
253
140
|
def response(self):
|
|
254
141
|
return {
|
|
255
142
|
'did': self._did,
|
|
256
|
-
'
|
|
143
|
+
'deltaFileName': self.delta_file_name,
|
|
257
144
|
'metadata': self.metadata,
|
|
258
145
|
'content': [content.json() for content in self.content]
|
|
259
146
|
}
|
|
@@ -269,10 +156,10 @@ class IngressResult(Result):
|
|
|
269
156
|
def __init__(self, context: Context):
|
|
270
157
|
super().__init__('ingress', 'INGRESS', context)
|
|
271
158
|
self.memo = None
|
|
272
|
-
self.execute_immediate = False
|
|
273
159
|
self.ingress_result_items = []
|
|
160
|
+
self.execute_immediate = False
|
|
274
161
|
self.status = IngressStatusEnum.HEALTHY
|
|
275
|
-
self.
|
|
162
|
+
self.status_message = None
|
|
276
163
|
|
|
277
164
|
def add_item(self, ingress_result_item: IngressResultItem):
|
|
278
165
|
self.ingress_result_items.append(ingress_result_item)
|
|
@@ -284,17 +171,16 @@ class IngressResult(Result):
|
|
|
284
171
|
'executeImmediate': self.execute_immediate,
|
|
285
172
|
'ingressItems': [ingress_result_item.response() for ingress_result_item in self.ingress_result_items],
|
|
286
173
|
'status': self.status.value,
|
|
287
|
-
'statusMessage': self.
|
|
174
|
+
'statusMessage': self.status_message
|
|
288
175
|
}
|
|
289
176
|
|
|
290
177
|
|
|
291
|
-
class
|
|
178
|
+
class TransformResult(Result):
|
|
292
179
|
def __init__(self, context: Context):
|
|
293
|
-
super().__init__('
|
|
180
|
+
super().__init__('transform', 'TRANSFORM', context)
|
|
294
181
|
self.content = []
|
|
295
|
-
self.metadata = {}
|
|
296
|
-
self.domains = []
|
|
297
182
|
self.annotations = {}
|
|
183
|
+
self.metadata = {}
|
|
298
184
|
self.delete_metadata_keys = []
|
|
299
185
|
|
|
300
186
|
# content can be a single Content or a List[Content]
|
|
@@ -327,13 +213,6 @@ class LoadResult(Result):
|
|
|
327
213
|
self.metadata[key] = value
|
|
328
214
|
return self
|
|
329
215
|
|
|
330
|
-
def add_domain(self, name: str, value: str, media_type: str):
|
|
331
|
-
self.domains.append({
|
|
332
|
-
'name': name,
|
|
333
|
-
'value': value,
|
|
334
|
-
'mediaType': media_type})
|
|
335
|
-
return self
|
|
336
|
-
|
|
337
216
|
def annotate(self, key: str, value: str):
|
|
338
217
|
self.annotations[key] = value
|
|
339
218
|
return self
|
|
@@ -342,133 +221,41 @@ class LoadResult(Result):
|
|
|
342
221
|
self.delete_metadata_keys.append(key)
|
|
343
222
|
return self
|
|
344
223
|
|
|
345
|
-
def
|
|
224
|
+
def json(self):
|
|
346
225
|
return {
|
|
347
|
-
'domains': self.domains,
|
|
348
226
|
'content': [content.json() for content in self.content],
|
|
349
|
-
'metadata': self.metadata,
|
|
350
227
|
'annotations': self.annotations,
|
|
228
|
+
'metadata': self.metadata,
|
|
351
229
|
'deleteMetadataKeys': self.delete_metadata_keys
|
|
352
230
|
}
|
|
353
231
|
|
|
354
|
-
|
|
355
|
-
class ChildLoadResult:
|
|
356
|
-
def __init__(self, load_result: LoadResult = None):
|
|
357
|
-
self._did = str(uuid.uuid4())
|
|
358
|
-
self.load_result = load_result
|
|
359
|
-
|
|
360
|
-
@property
|
|
361
|
-
def did(self):
|
|
362
|
-
return self._did
|
|
363
|
-
|
|
364
|
-
def response(self):
|
|
365
|
-
res = self.load_result.response()
|
|
366
|
-
res["did"] = self._did
|
|
367
|
-
return res
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
class LoadManyResult(Result):
|
|
371
|
-
def __init__(self, context: Context):
|
|
372
|
-
super().__init__('loadMany', 'LOAD_MANY', context)
|
|
373
|
-
self.load_results = []
|
|
374
|
-
|
|
375
|
-
def add_load_result(self, load_result):
|
|
376
|
-
if isinstance(load_result, ChildLoadResult):
|
|
377
|
-
self.load_results.append(load_result)
|
|
378
|
-
else:
|
|
379
|
-
self.load_results.append(ChildLoadResult(load_result))
|
|
380
|
-
return self
|
|
381
|
-
|
|
382
232
|
def response(self):
|
|
383
|
-
return [
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
class ReinjectResult(Result):
|
|
387
|
-
class ReinjectChild:
|
|
388
|
-
def __init__(self, filename: str, flow: str, content: List[Content], metadata: Dict[str, str]):
|
|
389
|
-
self.filename = filename
|
|
390
|
-
self.flow = flow
|
|
391
|
-
self.content = content
|
|
392
|
-
self.metadata = metadata
|
|
233
|
+
return [self.json()]
|
|
393
234
|
|
|
394
|
-
def json(self):
|
|
395
|
-
return {
|
|
396
|
-
'filename': self.filename,
|
|
397
|
-
'flow': self.flow,
|
|
398
|
-
'metadata': self.metadata,
|
|
399
|
-
'content': [content.json() for content in self.content]
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
def __init__(self, context: Context):
|
|
403
|
-
super().__init__('reinject', 'REINJECT', context)
|
|
404
|
-
self.children = []
|
|
405
235
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
236
|
+
class NamedTransformResult(NamedTuple):
|
|
237
|
+
result: TransformResult
|
|
238
|
+
name: str
|
|
409
239
|
|
|
410
|
-
def
|
|
411
|
-
|
|
240
|
+
def json(self):
|
|
241
|
+
j = self.result.json()
|
|
242
|
+
if self.name is not None:
|
|
243
|
+
j['name'] = self.name
|
|
244
|
+
return j
|
|
412
245
|
|
|
413
246
|
|
|
414
|
-
class
|
|
247
|
+
class TransformResults(Result):
|
|
415
248
|
def __init__(self, context: Context):
|
|
416
249
|
super().__init__('transform', 'TRANSFORM', context)
|
|
417
|
-
self.
|
|
418
|
-
self.metadata = {}
|
|
419
|
-
self.annotations = {}
|
|
420
|
-
self.delete_metadata_keys = []
|
|
421
|
-
|
|
422
|
-
# content can be a single Content or a List[Content]
|
|
423
|
-
def add_content(self, content):
|
|
424
|
-
if content:
|
|
425
|
-
if type(content) == list:
|
|
426
|
-
self.content.extend(content)
|
|
427
|
-
else:
|
|
428
|
-
self.content.append(content)
|
|
250
|
+
self.named_results = []
|
|
429
251
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
def save_string_content(self, string_data: str, name: str, media_type: str):
|
|
433
|
-
segment = self.context.content_service.put_str(self.context.did, string_data)
|
|
434
|
-
self.content.append(
|
|
435
|
-
Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
|
|
436
|
-
return self
|
|
437
|
-
|
|
438
|
-
def save_byte_content(self, byte_data: bytes, name: str, media_type: str):
|
|
439
|
-
segment = self.context.content_service.put_bytes(self.context.did, byte_data)
|
|
440
|
-
self.content.append(
|
|
441
|
-
Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
|
|
442
|
-
return self
|
|
443
|
-
|
|
444
|
-
def set_metadata(self, metadata: dict):
|
|
445
|
-
self.metadata = metadata
|
|
446
|
-
return self
|
|
447
|
-
|
|
448
|
-
def add_metadata(self, key: str, value: str):
|
|
449
|
-
self.metadata[key] = value
|
|
450
|
-
return self
|
|
451
|
-
|
|
452
|
-
def annotate(self, key: str, value: str):
|
|
453
|
-
self.annotations[key] = value
|
|
454
|
-
return self
|
|
455
|
-
|
|
456
|
-
def delete_metadata_key(self, key: str):
|
|
457
|
-
self.delete_metadata_keys.append(key)
|
|
252
|
+
def add_result(self, result: TransformResult, name: str = None):
|
|
253
|
+
self.named_results.append(NamedTransformResult(result, name))
|
|
458
254
|
return self
|
|
459
255
|
|
|
460
256
|
def response(self):
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
class ValidateResult(Result):
|
|
470
|
-
def __init__(self, context: Context):
|
|
471
|
-
super().__init__(None, 'VALIDATE', context)
|
|
472
|
-
|
|
473
|
-
def response(self):
|
|
474
|
-
return None
|
|
257
|
+
transform_events = []
|
|
258
|
+
for named_result in self.named_results:
|
|
259
|
+
json_dict = named_result.json()
|
|
260
|
+
transform_events.append(json_dict)
|
|
261
|
+
return transform_events
|