Merge in RR/mini_queue from add-storage-handle to master
Squashed commit of the following:
commit 03e542d2a65802c28735873fae184209f0c83553
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Wed Feb 16 11:55:34 2022 +0100
Quickfix typo
commit b4d538e9445187435d87c5cf8ce1f4e448021129
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Wed Feb 16 11:41:42 2022 +0100
added prefetch count and make channel function
commit d46d1375e387d36641c06b062a8ccc54f114ef4c
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Wed Feb 16 11:20:39 2022 +0100
black on M.s request
commit bc47b20312a978f19b08531804bf42b00f0a88f0
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Wed Feb 16 11:19:57 2022 +0100
changed response
commit 9a475ecd8df9ca007e5f7fe146483b6403eccc3b
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Wed Feb 16 10:15:08 2022 +0100
.
commit 108bc3ea90d867575db8c1b1503c9df859222485
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Wed Feb 16 09:56:56 2022 +0100
quickrestore
commit ae04d17d8d041f612d86117e8e96c96ddffcbde3
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Wed Feb 16 09:37:30 2022 +0100
refactor
commit 68051a72eb93868eba8adba234258b9e5373ecaa
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Wed Feb 16 08:50:59 2022 +0100
added answer file template for rancher
commit 09ef45ead51c07732a20133acad0b8b2ae7d0a61
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Wed Feb 16 08:26:05 2022 +0100
Quickfix inconsistency
commit d925b0f3f91f29403c88fb6149566ec966af2973
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Wed Feb 16 08:20:40 2022 +0100
Quick refactor
commit 48795455cde8d97ed98e58c3004a87a26f331352
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Tue Feb 15 17:46:45 2022 +0100
bluckckck
commit 80e58efab0269dc513990f83b14ceb36b3e4dd8e
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Tue Feb 15 17:45:49 2022 +0100
Quick restatus setting
commit 83f276ee13348a678b7da84e25ca844dd348b4c9
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Tue Feb 15 17:30:16 2022 +0100
Quickreset to working status
commit d44cdcf922250639a6832cc3e16d0d967d9853fb
Author: Julius Unverfehrt <Julius.Unverfehrt@iqser.com>
Date: Tue Feb 15 14:44:26 2022 +0100
added storage handle for minio WIP
180 lines
5.7 KiB
Python
180 lines
5.7 KiB
Python
import abc
|
|
import gzip
|
|
import logging
|
|
import os
|
|
from itertools import repeat
|
|
from operator import attrgetter
|
|
from typing import Iterable
|
|
|
|
from mini_queue.utils.file import path_to_compressed_storage_pdf_object_name, provide_directory
|
|
from mini_queue.utils.meta import NoAttemptsLeft, max_attempts
|
|
|
|
|
|
class StorageHandle:
|
|
"""Storage API base"""
|
|
|
|
def __init__(self):
|
|
self.default_container_name = None
|
|
|
|
@abc.abstractmethod
|
|
def __provide_container(self, container_name):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def __add_file(self, path, filename, container_name=None):
|
|
pass
|
|
|
|
@max_attempts(n_attempts=10, max_timeout=60)
|
|
def add_file(self, path: str, folder: str = None, container_name: str = None) -> None:
|
|
"""Adds a file to the store.
|
|
|
|
Args:
|
|
path: Path to file to add to store.
|
|
folder: Folder to hold file.
|
|
container_name: container to hold file.
|
|
"""
|
|
storage_path = self.__storage_path(path, folder=folder)
|
|
self.__add_file(path, storage_path, container_name)
|
|
|
|
@max_attempts()
|
|
def _list_files(self, object_name_attr="object_name", container_name=None) -> Iterable[str]:
|
|
"""List all files in a container.
|
|
|
|
Args:
|
|
container_name: container to list files from.
|
|
|
|
Returns:
|
|
Iterable of filenames.
|
|
"""
|
|
if container_name is None:
|
|
container_name = self.default_container_name
|
|
return map(attrgetter(object_name_attr), self.get_objects(container_name))
|
|
|
|
@abc.abstractmethod
|
|
def list_files(self, container_name=None) -> Iterable[str]:
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def get_objects(self, container_name=None):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def __list_containers(self):
|
|
pass
|
|
|
|
@max_attempts()
|
|
def get_all_objects(self) -> Iterable:
|
|
"""Gets all objects in the store
|
|
|
|
Returns:
|
|
Iterable over all objects in the store.
|
|
"""
|
|
for container in self.__list_containers():
|
|
yield from zip(repeat(container), self.get_objects(container.name))
|
|
|
|
@abc.abstractmethod
|
|
def __purge(self) -> None:
|
|
pass
|
|
|
|
@max_attempts()
|
|
def purge(self) -> None:
|
|
self.__purge()
|
|
|
|
def list_files_by_type(self, container_name=None, extension=".pdf.gz"):
|
|
return filter(lambda p: p.endswith(extension), self.list_files(container_name))
|
|
|
|
@abc.abstractmethod
|
|
def __fget_object(self, *args, **kwargs):
|
|
pass
|
|
|
|
@staticmethod
|
|
def __storage_path(path, folder: str = None):
|
|
def path_to_filename(path):
|
|
return os.path.basename(path)
|
|
|
|
storage_path = path_to_filename(path)
|
|
if folder is not None:
|
|
storage_path = os.path.join(folder, storage_path)
|
|
|
|
return storage_path
|
|
|
|
@max_attempts()
|
|
def list_folders_and_files(self, container_name: str = None) -> Iterable[str]:
|
|
"""Lists pairs of folder name (dossier-IDs) and file name (file-IDs) of items in a container.
|
|
|
|
Args:
|
|
container_name: container to list items for.
|
|
|
|
Returns:
|
|
Iterable of pairs folder name (dossier-ID) and file names (file-ID)
|
|
"""
|
|
return map(lambda p: p.split("/"), self.list_files_by_type(container_name))
|
|
|
|
@abc.abstractmethod
|
|
def __remove_file(self, folder: str, filename: str, container_name: str = None) -> None:
|
|
pass
|
|
|
|
@max_attempts()
|
|
def remove_file(self, folder: str, filename: str, container_name: str = None) -> None:
|
|
self.__remove_file(folder, filename, container_name)
|
|
|
|
def add_file_compressed(self, path, folder: str = None, container_name: str = None) -> None:
|
|
"""Adds a file as a .gz archive to the store.
|
|
|
|
Args:
|
|
path: Path to file to add to store.
|
|
folder: Folder to hold file.
|
|
container_name: container to hold file.
|
|
"""
|
|
|
|
def compress(path_in: str, path_out: str):
|
|
with open(path_in, "rb") as f_in, gzip.open(path_out, "wb") as f_out:
|
|
f_out.writelines(f_in)
|
|
|
|
path_gz = path_to_compressed_storage_pdf_object_name(path)
|
|
compress(path, path_gz)
|
|
|
|
self.add_file(path_gz, folder, container_name)
|
|
os.unlink(path_gz)
|
|
|
|
@max_attempts()
|
|
def download_file(self, object_names: str, target_root_dir: str, container_name: str = None) -> str:
|
|
"""Downloads a file from the store.
|
|
|
|
Args:
|
|
object_names: Complete object name (folder and file).
|
|
target_root_dir: Root directory to download file into (including its folder).
|
|
container_name: container to load file from.
|
|
|
|
Returns:
|
|
str: Path to downloaded file.
|
|
"""
|
|
|
|
@max_attempts(5, exceptions=(FileNotFoundError,))
|
|
def download(object_name: str) -> str:
|
|
|
|
path, basename = os.path.split(object_name)
|
|
target_dir = os.path.join(target_root_dir, path)
|
|
provide_directory(target_dir)
|
|
target_path = os.path.join(target_dir, basename)
|
|
|
|
logging.log(msg=f"Downloading {object_name}...", level=logging.DEBUG)
|
|
try:
|
|
self.__fget_object(container_name, object_name, target_path)
|
|
logging.log(msg=f"Downloaded {object_name}.", level=logging.DEBUG)
|
|
except Exception as err:
|
|
logging.log(msg=f"Downloading {object_name} failed.", level=logging.ERROR)
|
|
raise err
|
|
return target_path
|
|
|
|
if container_name is None:
|
|
container_name = self.default_container_name
|
|
|
|
try:
|
|
target_path = download(object_names)
|
|
except NoAttemptsLeft as err:
|
|
logging.log(msg=f"{err}", level=logging.ERROR)
|
|
raise err
|
|
|
|
return target_path
|