jfaustin's picture
add dockerfile and folding studio cli
44459bb
raw
history blame
3.4 kB
"""Helper methods for GCP."""
import logging
import shutil
import subprocess
import time
import zipfile
from pathlib import Path
import requests
from folding_studio.config import REQUEST_TIMEOUT
TOKEN_EXPIRY_SECONDS = 15 * 60 # 15 Minutes
class TokenManager:
"""Class to handle token updating."""
def __init__(self) -> None:
"""Initialize TokenManager class.
Args:
host_url: the url to obtain the token for.
"""
self.access_token = None
self.token_generation_time = 0
def get_token(self) -> str:
"""Get the token (self updating every 15 mins).
Return:
The updated token
"""
current_time = time.time()
# Check if the token is expired
if (
self.access_token is None
or current_time - self.token_generation_time >= TOKEN_EXPIRY_SECONDS
):
self.access_token = get_id_token()
return self.access_token
def get_id_token() -> str:
"""Get the user's gcp token id.
Returns:
str: The user's gcp token id.
"""
cmd_output = subprocess.run(
["gcloud", "auth", "print-identity-token"],
capture_output=True,
text=True,
check=False,
)
return cmd_output.stdout.strip()
def download_file_from_signed_url(
signed_url: str,
output_path: Path,
force: bool = False,
unzip: bool = False,
unzip_dir: str | None = None,
) -> None:
"""Download a file from a signed url.
Args:
signed_url (str): GCP signed url.
output_path (Path): Output file path.
force (bool, optional): Force file writing if it already exists.Defaults to False.
unzip (bool, optional): Unzip the zip file after downloading. Defaults to False.
unzip_dir (str | None, optional): Directory where to extract all members of the archive.
Defaults to None.
Raises:
ValueError: If output file path exists but force set to false.
ValueError: If unzip but the output path is not a zip file.
Exception: If an error occurs during the download.
ValueError: If unzip but the downloaded file is not a valid zip archive.
"""
if output_path.exists() and not force:
msg = f"The file '{output_path}' already exists. Use the --force flag to overwrite it."
raise ValueError(msg)
if unzip and not output_path.suffix == ".zip":
msg = "The output path must be a zip file."
raise ValueError(msg)
unzip_dir = unzip_dir or output_path.with_suffix("")
try:
response = requests.get(signed_url, stream=True, timeout=REQUEST_TIMEOUT)
response.raise_for_status()
output_path.parent.mkdir(parents=True, exist_ok=True)
with output_path.open("wb") as f:
shutil.copyfileobj(response.raw, f)
except Exception as e:
msg = f"Error downloading from signed url: {e}"
raise Exception(msg) from e
if unzip:
unzip_dir.mkdir(parents=True, exist_ok=True)
try:
with zipfile.ZipFile(output_path, "r") as zip_ref:
zip_ref.extractall(unzip_dir)
except zipfile.BadZipFile:
msg = f"File {output_path} is not a valid zip archive."
raise ValueError(msg)
logging.info(f"Extracted all files of {output_path} to {unzip_dir}.")