assemblyline-core 4.7.5.dev89__tar.gz → 4.7.5.dev94__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.
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/PKG-INFO +1 -1
- assemblyline_core-4.7.5.dev94/assemblyline_core/VERSION +1 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/expiry/run_expiry.py +144 -60
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core.egg-info/PKG-INFO +1 -1
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_expiry.py +9 -1
- assemblyline_core-4.7.5.dev89/assemblyline_core/VERSION +0 -1
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/LICENCE.md +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/README.md +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/alerter/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/alerter/processing.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/alerter/run_alerter.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/archiver/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/archiver/run_archiver.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/badlist_client.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/dispatching/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/dispatching/client.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/dispatching/dispatcher.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/dispatching/schedules.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/expiry/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/ingester/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/ingester/constants.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/ingester/ingester.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/metrics/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/metrics/es_metrics.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/metrics/heartbeat_formatter.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/metrics/helper.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/metrics/metrics_server.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/metrics/run_heartbeat_manager.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/metrics/run_metrics_aggregator.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/metrics/run_statistics_aggregator.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/client.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/creator/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/creator/run.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/creator/run_worker.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/loader/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/loader/run.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/loader/run_worker.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/replay.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/safelist_client.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/base.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/collection.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/controllers/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/controllers/docker_ctl.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/controllers/interface.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/controllers/kubernetes.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/controllers/kubernetes_ctl.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/run_scaler.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/scaler_server.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler_hpa/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler_hpa/kubernetes.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler_hpa/run_scaler.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler_hpa/scaler_server.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/server_base.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/signature_client.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/submission_client.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/updater/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/updater/helper.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/updater/run_updater.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/vacuum/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/vacuum/crawler.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/vacuum/department_map.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/vacuum/safelist.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/vacuum/stream_map.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/vacuum/worker.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/workflow/__init__.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/workflow/run_workflow.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core.egg-info/SOURCES.txt +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core.egg-info/dependency_links.txt +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core.egg-info/requires.txt +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core.egg-info/top_level.txt +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/setup.cfg +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/setup.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_alerter.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_badlist_client.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_replay.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_safelist_client.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_scaler.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_scheduler.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_signature_client.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_updater_helper.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_vacuum.py +0 -0
- {assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_workflow.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4.7.5.dev94
|
|
@@ -15,7 +15,7 @@ from datemath import dm
|
|
|
15
15
|
from assemblyline_core.server_base import ServerBase
|
|
16
16
|
from assemblyline_core.dispatching.dispatcher import BAD_SID_HASH
|
|
17
17
|
from assemblyline.common import forge, chunk
|
|
18
|
-
from assemblyline.common.isotime import epoch_to_iso, now_as_iso
|
|
18
|
+
from assemblyline.common.isotime import epoch_to_iso, now_as_iso, now
|
|
19
19
|
from assemblyline.common.metrics import MetricsFactory
|
|
20
20
|
from assemblyline.filestore import FileStore
|
|
21
21
|
from assemblyline.odm.messages.expiry_heartbeat import Metrics
|
|
@@ -26,6 +26,9 @@ from assemblyline.remote.datatypes.set import Set
|
|
|
26
26
|
if TYPE_CHECKING:
|
|
27
27
|
from assemblyline.datastore.collection import ESCollection
|
|
28
28
|
|
|
29
|
+
QUERY_DELETE_SIZE = 100_000
|
|
30
|
+
QUERY_WORKER_CHECK_VOLUME = 5_000_000
|
|
31
|
+
|
|
29
32
|
|
|
30
33
|
def file_delete_worker(logger, filestore_urls, file_batch: list[tuple[str, bool]],
|
|
31
34
|
archive_filestore_urls=None) -> list[tuple[str, bool]]:
|
|
@@ -215,12 +218,6 @@ class ExpiryManager(ServerBase):
|
|
|
215
218
|
if not hot_file_list and not archive_file_list:
|
|
216
219
|
self.log.warning(f'[{collection.name}] Expiry unable to clean up any of the files in filestore.')
|
|
217
220
|
|
|
218
|
-
def _simple_delete(self, collection: ESCollection, delete_query, number_to_delete):
|
|
219
|
-
self.heartbeat()
|
|
220
|
-
collection.delete_by_query(delete_query, index_type=self.index_type)
|
|
221
|
-
self.counter.increment(f'{collection.name}', increment_by=number_to_delete)
|
|
222
|
-
self.log.info(f"[{collection.name}] Deleted {number_to_delete} items from the datastore...")
|
|
223
|
-
|
|
224
221
|
def _cleanup_canceled_submission(self, sid):
|
|
225
222
|
# Allowing us at minimum 5 minutes to cleanup the submission
|
|
226
223
|
self.heartbeat(int(time.time() + 5 * 60))
|
|
@@ -246,53 +243,47 @@ class ExpiryManager(ServerBase):
|
|
|
246
243
|
# blob would be deleted anyway, leaving a file record with no filestore object
|
|
247
244
|
delete_query = f"expiry_ts:{{{start} TO {end}]"
|
|
248
245
|
|
|
249
|
-
#
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
f"removed from the {'cachestore' if 'cache' in collection.name else 'filestore'}")
|
|
291
|
-
self._finish_delete(collection, delete_tasks, expire_only)
|
|
292
|
-
|
|
293
|
-
else:
|
|
294
|
-
# Proceed with deletion
|
|
295
|
-
self._simple_delete(collection, delete_query, number_to_delete)
|
|
246
|
+
# Delete associated files
|
|
247
|
+
delete_objects: list[tuple[str, bool]] = []
|
|
248
|
+
for item in collection.stream_search(
|
|
249
|
+
delete_query, fl='id,from_archive', as_obj=False, index_type=self.index_type):
|
|
250
|
+
self.heartbeat()
|
|
251
|
+
delete_objects.append((item['id'], item.get('from_archive', False)))
|
|
252
|
+
|
|
253
|
+
# Filter archived documents if archive filestore is the same as the filestore
|
|
254
|
+
expire_only: list[tuple[str, bool]] = []
|
|
255
|
+
if self.same_storage and self.archive_access and collection.name == 'file':
|
|
256
|
+
# Separate hot and archive files
|
|
257
|
+
delete_from_archive = [i[0] for i in delete_objects if i[1]]
|
|
258
|
+
delete_from_hot = [i[0] for i in delete_objects if not i[1]]
|
|
259
|
+
|
|
260
|
+
# Check for overlap
|
|
261
|
+
overlap = set(delete_from_archive).intersection(set(delete_from_hot))
|
|
262
|
+
delete_from_archive = list(set(delete_from_archive)-overlap)
|
|
263
|
+
delete_from_hot = list(set(delete_from_hot)-overlap)
|
|
264
|
+
|
|
265
|
+
# Create the original delete_object form the overlap
|
|
266
|
+
delete_objects = [(k, False) for k in overlap]
|
|
267
|
+
delete_objects.extend([(k, True) for k in overlap])
|
|
268
|
+
|
|
269
|
+
if delete_from_hot:
|
|
270
|
+
# Check hot objects to delete if they are in archive
|
|
271
|
+
archived_files = self.datastore.file.multiexists(delete_from_hot, index_type=Index.ARCHIVE)
|
|
272
|
+
delete_objects.extend([(k, False) for k, v in archived_files.items() if not v])
|
|
273
|
+
expire_only.extend([(k, False) for k, v in archived_files.items() if v])
|
|
274
|
+
|
|
275
|
+
if delete_from_archive:
|
|
276
|
+
# Check hot objects to delete if they are in archive
|
|
277
|
+
hot_files = self.datastore.file.multiexists(delete_from_archive, index_type=Index.HOT)
|
|
278
|
+
delete_objects.extend([(k, True) for k, v in hot_files.items() if not v])
|
|
279
|
+
expire_only.extend([(k, True) for k, v in hot_files.items() if v])
|
|
280
|
+
|
|
281
|
+
delete_tasks = self.fs_hashmap[collection.name](delete_objects, final_date)
|
|
282
|
+
|
|
283
|
+
# Proceed with deletion, but only after all the scheduled deletes for this
|
|
284
|
+
self.log.info(f"[{collection.name}] Scheduled {len(delete_objects)}/{number_to_delete} files to be "
|
|
285
|
+
f"removed from the {'cachestore' if 'cache' in collection.name else 'filestore'}")
|
|
286
|
+
self._finish_delete(collection, delete_tasks, expire_only)
|
|
296
287
|
|
|
297
288
|
def feed_expiry_jobs(self, collection, start, jobs: list[concurrent.futures.Future],
|
|
298
289
|
pool: ThreadPoolExecutor) -> tuple[str, bool]:
|
|
@@ -329,11 +320,11 @@ class ExpiryManager(ServerBase):
|
|
|
329
320
|
return start, number_to_delete < self.expiry_size
|
|
330
321
|
|
|
331
322
|
def _get_final_date(self):
|
|
332
|
-
|
|
323
|
+
_now = now_as_iso()
|
|
333
324
|
if self.config.core.expiry.batch_delete:
|
|
334
|
-
final_date = dm(f"{
|
|
325
|
+
final_date = dm(f"{_now}||-{self.config.core.expiry.delay}h/d").float_timestamp
|
|
335
326
|
else:
|
|
336
|
-
final_date = dm(f"{
|
|
327
|
+
final_date = dm(f"{_now}||-{self.config.core.expiry.delay}h").float_timestamp
|
|
337
328
|
return epoch_to_iso(final_date)
|
|
338
329
|
|
|
339
330
|
def _get_next_chunk(self, collection: ESCollection, start, final_date):
|
|
@@ -357,7 +348,11 @@ class ExpiryManager(ServerBase):
|
|
|
357
348
|
|
|
358
349
|
# Launch threads that expire data from each collection of data
|
|
359
350
|
for collection in self.expirable_collections:
|
|
360
|
-
|
|
351
|
+
# check if we are dealing with an index that needs file cleanup
|
|
352
|
+
if self.config.core.expiry.delete_storage and collection.name in self.fs_hashmap:
|
|
353
|
+
thread = threading.Thread(target=self.run_file_collection, args=[pool, collection])
|
|
354
|
+
else:
|
|
355
|
+
thread = threading.Thread(target=self.run_collection, args=[collection])
|
|
361
356
|
thread.start()
|
|
362
357
|
main_threads.append(thread)
|
|
363
358
|
|
|
@@ -376,8 +371,13 @@ class ExpiryManager(ServerBase):
|
|
|
376
371
|
pool.submit(self.log_errors(self._cleanup_canceled_submission), submission.sid)
|
|
377
372
|
self.sleep_with_heartbeat(self.config.core.expiry.sleep_time)
|
|
378
373
|
|
|
379
|
-
def
|
|
380
|
-
"""
|
|
374
|
+
def run_file_collection(self, pool: concurrent.futures.ThreadPoolExecutor, collection):
|
|
375
|
+
"""
|
|
376
|
+
Feed batches of jobs to delete to the thread pool for the given collection.
|
|
377
|
+
|
|
378
|
+
The files must be cleaned up for this collection so we operate by
|
|
379
|
+
batching rather than delete by query.
|
|
380
|
+
"""
|
|
381
381
|
start = "*"
|
|
382
382
|
jobs: list[concurrent.futures.Future] = []
|
|
383
383
|
|
|
@@ -412,6 +412,90 @@ class ExpiryManager(ServerBase):
|
|
|
412
412
|
self.log.error("File delete worker pool crashed.")
|
|
413
413
|
self.file_delete_worker = ProcessPoolExecutor(self.config.core.expiry.delete_workers)
|
|
414
414
|
|
|
415
|
+
def run_collection(self, collection):
|
|
416
|
+
"""
|
|
417
|
+
For collections where no file cleanup is needed we can simply run delete by query.
|
|
418
|
+
|
|
419
|
+
In cases where there are large quantities of records expiring (or a large backlog) multiple
|
|
420
|
+
delete by query calls running on non-overlapping sections of the data can be needed to catch
|
|
421
|
+
up.
|
|
422
|
+
|
|
423
|
+
The metric we use here is that every day gets its own delete query. When the expiry daemon
|
|
424
|
+
starts we will probe to see how many days of historical data we need to clean up and
|
|
425
|
+
start that many query workers.
|
|
426
|
+
|
|
427
|
+
Perodically a workers will terminate and this calculation will be redone.
|
|
428
|
+
"""
|
|
429
|
+
while self.running:
|
|
430
|
+
# Calculate how many queries we want to run
|
|
431
|
+
queries = self.day_chunks(collection)
|
|
432
|
+
|
|
433
|
+
# prepare a thread pool suitable for that operation
|
|
434
|
+
with ThreadPoolExecutor(len(queries)) as pool:
|
|
435
|
+
# Prepare a signal so we can stop all the workers as desired
|
|
436
|
+
stop = threading.Event()
|
|
437
|
+
|
|
438
|
+
# dispatch each of these queries
|
|
439
|
+
futures = [pool.submit(self.run_collection_query, collection, stop, query) for query in queries]
|
|
440
|
+
|
|
441
|
+
# wait for one of them to finish
|
|
442
|
+
for future in as_completed(futures):
|
|
443
|
+
stop.set()
|
|
444
|
+
future.result()
|
|
445
|
+
|
|
446
|
+
def day_chunks(self, collection):
|
|
447
|
+
# Figure out the range of time we want to build queries for
|
|
448
|
+
earliest = self.get_earliest_expiring(collection)
|
|
449
|
+
if not earliest:
|
|
450
|
+
return []
|
|
451
|
+
days = int((now() - earliest)/(60 * 60 * 24)) + 1
|
|
452
|
+
|
|
453
|
+
# Base no settings we will truncade expiry ranges by the day
|
|
454
|
+
if self.config.core.expiry.batch_delete:
|
|
455
|
+
suffix = f"-{self.config.core.expiry.delay}h/d"
|
|
456
|
+
else:
|
|
457
|
+
suffix = f"-{self.config.core.expiry.delay}h"
|
|
458
|
+
|
|
459
|
+
# construct the ranges that build queries covering all of those days, bounded by
|
|
460
|
+
# the appropirately modifide NOW on the high end, and modfied to be open on the low end
|
|
461
|
+
ranges = [(f"now-1d{suffix}", f"now{suffix}")]
|
|
462
|
+
for days in range(1, days):
|
|
463
|
+
ranges.append((f"now-{days + 1}d{suffix}", f"now-{days}d{suffix}"))
|
|
464
|
+
ranges[-1] = ("*", ranges[-1][1])
|
|
465
|
+
|
|
466
|
+
# Convert those ranges to queries, each inclusive on the low end and exclusive on the high end
|
|
467
|
+
queries = [f"expiry_ts: [{s} TO {e}}}" for s, e in ranges]
|
|
468
|
+
return queries
|
|
469
|
+
|
|
470
|
+
def get_earliest_expiring(self, collection) -> None | float:
|
|
471
|
+
final = self._get_final_date()
|
|
472
|
+
rows = collection.search(f"expiry_ts: [* TO {final}]", rows=1, fl='expiry_ts', sort="expiry_ts asc")
|
|
473
|
+
if rows['items']:
|
|
474
|
+
return rows['items'][0]['expiry_ts'].timestamp()
|
|
475
|
+
return None
|
|
476
|
+
|
|
477
|
+
def run_collection_query(self, collection, stop, query):
|
|
478
|
+
total_deleted = 0
|
|
479
|
+
while self.running or stop.is_set():
|
|
480
|
+
self.heartbeat()
|
|
481
|
+
deleted = 0
|
|
482
|
+
|
|
483
|
+
try:
|
|
484
|
+
deleted = collection.simple_delete_by_query(query, sort='expiry_ts asc', max_docs=QUERY_DELETE_SIZE)
|
|
485
|
+
total_deleted += deleted
|
|
486
|
+
self.counter.increment(f'{collection.name}', increment_by=deleted)
|
|
487
|
+
self.log.info(f"[{collection.name}] Deleted {deleted} items from the datastore...")
|
|
488
|
+
|
|
489
|
+
except Exception as e:
|
|
490
|
+
self.log.exception(str(e))
|
|
491
|
+
|
|
492
|
+
if total_deleted >= QUERY_WORKER_CHECK_VOLUME:
|
|
493
|
+
return
|
|
494
|
+
|
|
495
|
+
# If the number deleted is small wait before running the delete command again
|
|
496
|
+
if deleted < QUERY_DELETE_SIZE * 0.9:
|
|
497
|
+
self.sleep_with_heartbeat(self.config.core.expiry.sleep_time)
|
|
498
|
+
|
|
415
499
|
|
|
416
500
|
if __name__ == "__main__":
|
|
417
501
|
with ExpiryManager() as em:
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
import pytest
|
|
3
3
|
import random
|
|
4
|
+
import threading
|
|
4
5
|
import concurrent.futures
|
|
5
6
|
|
|
6
7
|
from assemblyline.common.isotime import now_as_iso
|
|
7
8
|
from assemblyline.datastore.helper import AssemblylineDatastore
|
|
8
9
|
from assemblyline.odm.randomizer import random_model_obj
|
|
9
10
|
|
|
11
|
+
import assemblyline_core.expiry.run_expiry
|
|
10
12
|
from assemblyline_core.expiry.run_expiry import ExpiryManager
|
|
11
13
|
|
|
12
14
|
MAX_OBJECTS = 10
|
|
@@ -60,9 +62,15 @@ def test_expire_all(config, ds_expiry, filestore):
|
|
|
60
62
|
expiry = ExpiryManager(config=config, datastore=ds_expiry, filestore=filestore)
|
|
61
63
|
expiry.running = True
|
|
62
64
|
expiry.counter = FakeCounter()
|
|
65
|
+
|
|
66
|
+
assemblyline_core.expiry.run_expiry.QUERY_WORKER_CHECK_VOLUME = 0
|
|
67
|
+
|
|
63
68
|
with concurrent.futures.ThreadPoolExecutor(5) as pool:
|
|
64
69
|
for collection in expiry.expirable_collections:
|
|
65
|
-
|
|
70
|
+
if collection.name in expiry.fs_hashmap:
|
|
71
|
+
expiry.feed_expiry_jobs(collection=collection, pool=pool, start='*', jobs=[])
|
|
72
|
+
else:
|
|
73
|
+
pool.submit(expiry.run_collection, collection)
|
|
66
74
|
|
|
67
75
|
for k, v in expiry_collections_len.items():
|
|
68
76
|
assert v == expiry.counter.get(k)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
4.7.5.dev89
|
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/badlist_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/expiry/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/metrics/helper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/__init__.py
RENAMED
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/replay/replay.py
RENAMED
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/safelist_client.py
RENAMED
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/__init__.py
RENAMED
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/scaler/base.py
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/server_base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/updater/helper.py
RENAMED
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/vacuum/__init__.py
RENAMED
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/vacuum/crawler.py
RENAMED
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/vacuum/safelist.py
RENAMED
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/assemblyline_core/vacuum/worker.py
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_safelist_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline_core-4.7.5.dev89 → assemblyline_core-4.7.5.dev94}/test/test_signature_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|