-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
006c815
commit 67ba3ab
Showing
11 changed files
with
200 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
from pathlib import Path | ||
from typing import Annotated, Union | ||
from urllib.parse import urlparse | ||
|
||
from pydantic import BaseModel, Field | ||
|
||
from aproc.core.logger import Logger | ||
from extensions.aproc.proc.access.storages.file import FileStorage | ||
from extensions.aproc.proc.access.storages.gs import GoogleStorage | ||
from extensions.aproc.proc.access.storages.http import HttpStorage | ||
from extensions.aproc.proc.access.storages.https import HttpsStorage | ||
|
||
AnyStorage = Annotated[Union[FileStorage, GoogleStorage, HttpStorage, HttpsStorage], Field(discriminator="type")] | ||
|
||
|
||
class AccessManager(BaseModel): | ||
storage: AnyStorage | None = Field(None) | ||
logger = Logger.logger | ||
|
||
def __resolve_storage(self, href: str) -> AnyStorage: | ||
""" | ||
Based on the defined storages (TODO), returns the one matching the input href | ||
""" | ||
storage_type = urlparse(href).scheme | ||
netloc = urlparse(href).netloc | ||
|
||
if not storage_type or storage_type == "file": | ||
if self.storage.type is None: | ||
return self.storage | ||
return FileStorage() | ||
|
||
if storage_type == "gs": | ||
if self.storage.type == "gs" and netloc == self.storage.bucket: | ||
return self.storage | ||
return GoogleStorage(bucket=netloc) | ||
|
||
if storage_type == "http": | ||
if self.storage.type == "http" and netloc == self.storage.domain: | ||
return self.storage | ||
return HttpStorage(domain=netloc) | ||
|
||
if storage_type == "https": | ||
if self.storage.type == "https" and netloc == self.storage.domain: | ||
return self.storage | ||
return HttpsStorage(domain=netloc) | ||
|
||
raise NotImplementedError(f"Storage '{storage_type}' not compatible") | ||
|
||
def __get_storage_parameters(self, href: str): | ||
storage = self.__resolve_storage(href) | ||
|
||
if storage.type == "gs": | ||
from google.cloud.storage import Client | ||
from google.oauth2 import service_account | ||
|
||
if storage.api_key is None: | ||
self.logger.warning("No api_key is configured for this Google Storage. Using anonymous credentials") | ||
client = Client.create_anonymous_client() | ||
else: | ||
credentials = service_account.Credentials.from_service_account_info(storage.api_key) | ||
client = Client("APROC", credentials=credentials) | ||
|
||
return {"client": client} | ||
|
||
if storage.type == "http" or storage.type == "https": | ||
return {"headers": storage.headers} | ||
|
||
return {} | ||
|
||
def pull(self): | ||
""" | ||
Pulls a file from a storage to write it in the local storage. | ||
If the input storage is local, then it is a copy. Otherwise it is a download. | ||
""" | ||
... | ||
|
||
# Will return a yield | ||
def stream(self): | ||
""" | ||
Reads the content of a file in a storage without downloading it. | ||
""" | ||
... | ||
|
||
def exists(self, href: str) -> bool: | ||
""" | ||
Whether the file exists | ||
""" | ||
storage = self.__resolve_storage(href) | ||
|
||
if storage.type is None: | ||
return Path(href).exists() | ||
|
||
if storage.type == "gs": | ||
from google.cloud.storage import Client | ||
|
||
client: Client = self.__get_storage_parameters(href)["client"] | ||
bucket = client.get_bucket(storage.bucket) | ||
return bucket.blob(href).exists() | ||
|
||
if storage.type == "https" or storage.type == "http": | ||
import requests | ||
|
||
r = requests.head(href, headers=self.__get_storage_parameters(href), verify=False) | ||
return r.status_code < 400 | ||
|
||
raise ValueError("Href matches no storage that is configured") | ||
|
||
def is_download_required(self, href: str): | ||
return self.storage.type == "https" \ | ||
and urlparse(href).scheme == "https" \ | ||
and urlparse(href).netloc == self.storage.domain \ | ||
and self.storage.force_download |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from typing import Literal | ||
|
||
from pydantic import BaseModel | ||
|
||
|
||
class FileStorage(BaseModel): | ||
type: Literal[None] = None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
|
||
|
||
import enum | ||
from typing import Literal | ||
|
||
from pydantic import BaseModel, Field, computed_field | ||
|
||
|
||
class GoogleStorageConstants(str, enum.Enum): | ||
AUTH_URI = "https://accounts.google.com/o/oauth2/auth" | ||
TOKEN_URI = "https://oauth2.googleapis.com/token" | ||
AUTH_PROVIDER_CERT_URL = "https://www.googleapis.com/oauth2/v1/certs" | ||
|
||
|
||
class GoogleStorageApiKey(BaseModel): | ||
type: Literal["service_account"] = "service_account" | ||
project_id: str | ||
private_key_id: str | ||
private_key: str | ||
client_id: str | None = Field(None) | ||
auth_uri: Literal[GoogleStorageConstants.AUTH_URI] = GoogleStorageConstants.AUTH_URI.value | ||
token_uri: Literal[GoogleStorageConstants.TOKEN_URI] = GoogleStorageConstants.TOKEN_URI.value | ||
auth_provider_x509_cert_url: Literal[GoogleStorageConstants.AUTH_PROVIDER_CERT_URL] = GoogleStorageConstants.AUTH_PROVIDER_CERT_URL.value | ||
universe_domain: Literal["googleapis.com"] = "googleapis.com" | ||
|
||
@computed_field | ||
@property | ||
def client_x509_cert_url(self) -> str: | ||
return f"https://www.googleapis.com/robot/v1/metadata/x509/{self.project_id}%40appspot.gserviceaccount.com" | ||
|
||
@computed_field | ||
@property | ||
def client_email(self) -> str: | ||
return f"{self.project_id}@appspot.gserviceaccount.com" | ||
|
||
|
||
class GoogleStorage(BaseModel): | ||
type: Literal["gs"] = "gs" | ||
bucket: str | ||
api_key: GoogleStorageApiKey | None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from typing import Literal | ||
|
||
from pydantic import BaseModel, Field | ||
|
||
|
||
class HttpStorage(BaseModel): | ||
type: Literal["http"] = "http" | ||
headers: dict[str, str] | ||
domain: str | ||
force_download: bool = Field(default=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from typing import Literal | ||
|
||
from pydantic import BaseModel, Field | ||
|
||
|
||
class HttpsStorage(BaseModel): | ||
type: Literal["https"] = "https" | ||
headers: dict[str, str] | ||
domain: str | ||
force_download: bool = Field(default=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters