Mini Shell
"""Handles automatic retries for Backup Authority API calls"""
from typing import Union, Any
import logging
import enum
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
import requests
DEFAULT_TIMEOUT = 20
DEFAULT_RETRIES = 2
logging.getLogger("urllib3.connectionpool").setLevel(logging.ERROR)
class Status(enum.Enum):
"""Backup Authority Error Codes"""
REQUEST_EXCEPTION = -1 # error contacting backup authority
OKAY = 0 # normal response
ERROR = 1 # general error
ARGS_MISSING = 2 # incorrect api usage, missing arguments
UNHANDLED_EXCEPTION = 3 # exception raised on bakauth server (a bug)
SQLALCHEMY_ERROR = 4 # SQL error raised. Possibly a MySQL timeout
AMP_DOWN = 5 # PowerPanel API is down
WRONG_SERVER_CLASS = 6 # Wrong API endpoint for registered server class
AUTH_FAILED = 7 # API login failed
INTERNAL_NO_QUOTA = 8 # requested quota on an internal server
PRODUCTION_ONLY = 9 # function does not work on testing bakauth server
VDED_AMP_MISSING = 10 # could not locate amp account for a v/ded server
LOOKUP_MISSING = 11 # requested data not found in bakauth database
AUTH_MIGRATED = 12 # ceph bucket was moved to a new server (dedi)
NO_REPLICANT = 13 # function does not work on the bakauth replicant
INTERNAL_VPS = 14 # access denied to S3 creds for an internal VPS (vznode)
class MdsState(enum.Enum):
"""Possible states for vznode MDS backups"""
OKAY = 0
WARN = 1
CRIT = 2
class LoggedRetry(Retry):
"""Logs on HTTP retries"""
def increment(
self,
method=None,
url=None,
response=None,
error=None,
_pool=None,
_stacktrace=None,
):
if error is not None:
logging.debug('bakauth::%s: %s', url, error)
return super().increment(
method, url, response, error, _pool, _stacktrace
)
class BakAuthSession(requests.Session):
"""Custom requests.Session for bakauth requests"""
def __init__(self, retries: int, log_retries: bool):
super().__init__()
retry_class = LoggedRetry if log_retries else Retry
self.mount(
'https://',
HTTPAdapter(
max_retries=retry_class(
total=retries,
read=retries,
connect=retries,
status=retries,
status_forcelist=[500],
backoff_factor=1.0,
)
),
)
def post(
*,
bakauth_host: str,
uri: str,
data: dict,
timeout: int,
retries: int,
auth: Union[tuple, None] = None,
log_retries: bool = True,
) -> tuple[Status, Any]:
"""Performs a Backup Authority API request
Args:
bakauth_host (str): bakauth server fqdn
uri (str): endpoint uri to use
data (dict): POST form data
timeout (int): seconds before raising BakAuthDown
retries (int): number of automatic retries
auth (tuple | None): HTTP auth info
Returns:
(Status, data): Status response (enum) and returned data
"""
try:
with BakAuthSession(retries, log_retries) as session:
raw = session.post(
url=f"https://{bakauth_host}:4002/{uri.lstrip('/')}",
auth=auth,
timeout=timeout,
data=data,
)
except requests.exceptions.RequestException as exc:
return Status.REQUEST_EXCEPTION, str(exc)
try:
ret = raw.json()
except ValueError:
return Status.REQUEST_EXCEPTION, f'Invalid JSON from auth server: {raw}'
try:
status = Status(ret['status'])
except ValueError:
status = Status.ERROR
return status, ret['data']
Zerion Mini Shell 1.0