PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/extras-3.10/restic/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/extras-3.10/restic/exc.py |
"""Restic Exception Classes""" from typing import Union import os import re import platform import logging from signal import Signals, SIGPIPE from subprocess import CalledProcessError, CompletedProcess LOCK_RE = re.compile(r'locked (?:exclusively )?by PID (\d+) on ([\w\.\-]+) by') class ResticError(Exception): """Base class for restic errors Args: proc (CalledProcessError | CompletedProcess): subprocess result """ __module__ = 'restic' def __init__(self, proc: Union[CalledProcessError, CompletedProcess]): super().__init__(proc.stderr) self.stderr = proc.stderr self.returncode = proc.returncode def __new__(cls, proc: Union[CalledProcessError, CompletedProcess]): if cls is not ResticError: return Exception.__new__(cls) stderr = proc.stderr.strip() if ( 'dial tcp' in stderr or 'TLS handshake timeout' in stderr or '502 Bad Gateway' in stderr ): return Exception.__new__(ResticConnError) if 'The access key ID you provided does not exist' in stderr: return Exception.__new__(ResticAccessError) if ( 'Stat: The specified key does not exist' in stderr or 'The specified bucket does not exist' in stderr ): return Exception.__new__(ResticInitError) if 'unable to create lock in backend' in stderr: return Exception.__new__(ResticLockedError) index_errs = ( 'repair index', 'rebuild-index', 'unable to load index', 'returned error, retrying after', 'Load(<index', 'Load(<lock', ) if any(x in stderr for x in index_errs) or ( stderr.startswith('Fatal:') and 'invalid data returned' in stderr ): return Exception.__new__(ResticBadIndexError) if proc.returncode < 0 and abs(proc.returncode) == SIGPIPE: # https://github.com/restic/restic/issues/1466 # https://github.com/restic/restic/pull/2546 return Exception.__new__(ResticConnError) return Exception.__new__(cls) @property def name(self) -> str: """Get the name of the class of the restic exception Returns: str: class name """ return type(self).__name__ def __str__(self): if self.returncode < 0: signum = abs(self.returncode) try: # https://github.com/PyCQA/pylint/issues/2804 sig = Signals(signum).name # pylint: disable=no-member except ValueError: sig = f'signal {signum}' if signum == SIGPIPE: # https://github.com/restic/restic/issues/1466 return f'Timeout: received SIGPIPE. {self.stderr}' return f'(killed with {sig}) {self.stderr}' return f'(return code {self.returncode}) {self.stderr}' class ResticBadIndexError(ResticError): """Raised when restic raises an index corruption error""" __module__ = 'restic' class ResticAccessError(ResticError): """Raised when S3 access/secret keys are incorrect for restic""" __module__ = 'restic' class ResticInitError(ResticError): """Raised when a restic repo connects but is not initialized""" __module__ = 'restic' class ResticConnError(ResticError): """Raised when a connection is refused or times out from ceph""" __module__ = 'restic' class ResticLockedError(ResticError): """Raised when an operation on a repo fails due to a lock held on it""" __module__ = 'restic' def __init__(self, proc: Union[CalledProcessError, CompletedProcess]): super().__init__(proc) if match := LOCK_RE.search(proc.stderr): self.pid = int(match.group(1)) self.host = match.group(2) else: logging.warning('failed to parse PID and host from %r', proc.stderr) self.pid = None self.host = None def unlock_ok(self) -> bool: """Check if a locked repo can be unlocked Returns: bool: true if restic unlock can be run safely """ if self.pid is None: return False if platform.node() != self.host: return False try: os.kill(self.pid, 0) except ProcessLookupError: return True return False def __str__(self): if self.pid: return f"repo is in use and locked by PID {self.pid} on {self.host}" return super().__str__()