From 48b39d878f9486c2744bdb4ffb92b18273b63511 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 28 Apr 2025 16:57:30 +0200 Subject: [PATCH] remove remainders of quota support Some features like repository quotas rely on a server-side component that enforces them (because that shall only be controllable server-side, not client-side). So, that can only work, if such a server-side component exists, which is the case for borg 1.x ssh: repositories (but not for borg 1.x non-ssh: repositories). For borg2, we currently have: - fs repos - sftp: repos - rclone: repos (enabling many different cloud providers) - s3/b3: repos - ssh: repos using client/server rpc code similar as in borg 1.x So, only for the last method we have a borg server-side process that could enforce some features, but not for any of the other repo types. For quotas the current idea is that this should not be done within borg, but enforced by a storage specific quota implementation (like fs quota, or quota of the cloud storage provider). borg could offer information about overall repo space used, but would not enforce quotas within borg. --- docs/deployment/hosting-repositories.rst | 13 ---- docs/internals/frontends.rst | 2 - docs/quickstart.rst | 2 +- scripts/shell_completions/fish/borg.fish | 2 - src/borg/archiver/__init__.py | 2 +- src/borg/archiver/_common.py | 21 +----- src/borg/archiver/repo_create_cmd.py | 12 ---- src/borg/archiver/repo_info_cmd.py | 11 +-- src/borg/archiver/serve_cmd.py | 17 +---- src/borg/helpers/__init__.py | 2 +- src/borg/helpers/parseformat.py | 7 -- src/borg/legacyremote.py | 3 - src/borg/legacyrepository.py | 68 +++---------------- src/borg/remote.py | 10 +-- src/borg/repository.py | 16 +---- .../testsuite/archiver/argparsing_test.py | 7 -- src/borg/testsuite/legacyrepository_test.py | 8 --- src/borg/testsuite/remote_test.py | 2 +- src/borg/testsuite/repository_test.py | 8 --- 19 files changed, 21 insertions(+), 192 deletions(-) diff --git a/docs/deployment/hosting-repositories.rst b/docs/deployment/hosting-repositories.rst index b0efbf696..3a50b0b95 100644 --- a/docs/deployment/hosting-repositories.rst +++ b/docs/deployment/hosting-repositories.rst @@ -6,7 +6,6 @@ Hosting repositories ==================== This sections shows how to provide repository storage securely for users. -Optionally, each user can have a storage quota. Repositories are accessed through SSH. Each user of the service should have her own login which is only able to access the user's files. @@ -56,18 +55,6 @@ multiple times to permit access to more than one repository. The repository may not exist yet; it can be initialized by the user, which allows for encryption. -**Storage quotas** can be enabled by adding the ``--storage-quota`` option -to the ``borg serve`` command line:: - - restrict,command="borg serve --storage-quota 20G ..." ... - -The storage quotas of repositories are completely independent. If a -client is able to access multiple repositories, each repository -can be filled to the specified quota. - -If storage quotas are used, ensure that all deployed Borg releases -support storage quotas. - **Specificities: Append-only repositories** Running ``borg init`` via a ``borg serve --append-only`` server will **not** diff --git a/docs/internals/frontends.rst b/docs/internals/frontends.rst index c29aa72cd..2e36426a9 100644 --- a/docs/internals/frontends.rst +++ b/docs/internals/frontends.rst @@ -610,8 +610,6 @@ Errors The parent path of the repo directory [{}] does not exist. Repository.PathAlreadyExists rc: 19 traceback: no There is already something at {}. - Repository.StorageQuotaExceeded rc: 20 traceback: no - The storage quota ({}) has been exceeded ({}). Try deleting some archives. Repository.PathPermissionDenied rc: 21 traceback: no Permission denied to {}. diff --git a/docs/quickstart.rst b/docs/quickstart.rst index c929012c2..667065fa8 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -47,7 +47,7 @@ Also helpful: does not have free space any more. - if you use LVM: use a LV + a filesystem that you can resize later and have some unallocated PEs you can add to the LV. -- consider using quotas +- consider using quotas (e.g. fs quota, quota settings of storage provider) - use `prune` and `compact` regularly diff --git a/scripts/shell_completions/fish/borg.fish b/scripts/shell_completions/fish/borg.fish index 75af73a51..ec0869cfd 100644 --- a/scripts/shell_completions/fish/borg.fish +++ b/scripts/shell_completions/fish/borg.fish @@ -89,7 +89,6 @@ complete -c borg -l 'rsh' -d 'Use COMMAND instead of s set -l encryption_modes "none keyfile keyfile-blake2 repokey repokey-blake2 authenticated authenticated-blake2" complete -c borg -f -s e -l 'encryption' -d 'Encryption key MODE' -a "$encryption_modes" -n "__fish_seen_subcommand_from init" complete -c borg -f -l 'append-only' -d 'Create an append-only mode repository' -n "__fish_seen_subcommand_from init" -complete -c borg -f -l 'storage-quota' -d 'Set storage QUOTA of the repository' -n "__fish_seen_subcommand_from init" complete -c borg -f -l 'make-parent-dirs' -d 'Create parent directories' -n "__fish_seen_subcommand_from init" # borg create options @@ -316,7 +315,6 @@ complete -c borg -f -l 'strip-components' -d 'Remove NUMBER of leading complete -c borg -l 'restrict-to-path' -d 'Restrict repository access to PATH' -n "__fish_seen_subcommand_from serve" complete -c borg -l 'restrict-to-repository' -d 'Restrict repository access at PATH' -n "__fish_seen_subcommand_from serve" complete -c borg -f -l 'append-only' -d 'Only allow appending to repository' -n "__fish_seen_subcommand_from serve" -complete -c borg -f -l 'storage-quota' -d 'Override storage QUOTA of the repository' -n "__fish_seen_subcommand_from serve" # borg config complete -c borg -f -s c -l 'cache' -d 'Get/set/list values in the repo cache' -n "__fish_seen_subcommand_from config" diff --git a/src/borg/archiver/__init__.py b/src/borg/archiver/__init__.py index 8b888b059..c3201a240 100644 --- a/src/borg/archiver/__init__.py +++ b/src/borg/archiver/__init__.py @@ -401,7 +401,7 @@ class Archiver( # client is allowed to specify the allowlisted options, # everything else comes from the forced "borg serve" command (or the defaults). # stuff from denylist must never be used from the client. - denylist = {"restrict_to_paths", "restrict_to_repositories", "append_only", "storage_quota", "umask"} + denylist = {"restrict_to_paths", "restrict_to_repositories", "append_only", "umask"} allowlist = {"debug_topics", "lock_wait", "log_level"} not_present = object() for attr_name in allowlist: diff --git a/src/borg/archiver/_common.py b/src/borg/archiver/_common.py index bdd4d0cd7..bf82f3970 100644 --- a/src/borg/archiver/_common.py +++ b/src/borg/archiver/_common.py @@ -30,7 +30,7 @@ from ..logger import create_logger logger = create_logger(__name__) -def get_repository(location, *, create, exclusive, lock_wait, lock, append_only, storage_quota, args, v1_or_v2): +def get_repository(location, *, create, exclusive, lock_wait, lock, append_only, args, v1_or_v2): if location.proto in ("ssh", "socket"): RemoteRepoCls = LegacyRemoteRepository if v1_or_v2 else RemoteRepository repository = RemoteRepoCls( @@ -45,25 +45,13 @@ def get_repository(location, *, create, exclusive, lock_wait, lock, append_only, elif location.proto in ("sftp", "file", "rclone") and not v1_or_v2: # stuff directly supported by borgstore repository = Repository( - location, - create=create, - exclusive=exclusive, - lock_wait=lock_wait, - lock=lock, - append_only=append_only, - storage_quota=storage_quota, + location, create=create, exclusive=exclusive, lock_wait=lock_wait, lock=lock, append_only=append_only ) else: RepoCls = LegacyRepository if v1_or_v2 else Repository repository = RepoCls( - location.path, - create=create, - exclusive=exclusive, - lock_wait=lock_wait, - lock=lock, - append_only=append_only, - storage_quota=storage_quota, + location.path, create=create, exclusive=exclusive, lock_wait=lock_wait, lock=lock, append_only=append_only ) return repository @@ -127,7 +115,6 @@ def with_repository( assert isinstance(exclusive, bool) lock = getattr(args, "lock", _lock) append_only = getattr(args, "append_only", False) - storage_quota = getattr(args, "storage_quota", None) repository = get_repository( location, @@ -136,7 +123,6 @@ def with_repository( lock_wait=self.lock_wait, lock=lock, append_only=append_only, - storage_quota=storage_quota, args=args, v1_or_v2=False, ) @@ -205,7 +191,6 @@ def with_other_repository(manifest=False, cache=False, compatibility=None): lock_wait=self.lock_wait, lock=True, append_only=False, - storage_quota=None, args=args, v1_or_v2=v1_or_v2, ) diff --git a/src/borg/archiver/repo_create_cmd.py b/src/borg/archiver/repo_create_cmd.py index e76939bbc..8149eecf0 100644 --- a/src/borg/archiver/repo_create_cmd.py +++ b/src/borg/archiver/repo_create_cmd.py @@ -6,7 +6,6 @@ from ..constants import * # NOQA from ..crypto.key import key_creator, key_argument_names from ..helpers import CancelledByUser, CommandError from ..helpers import location_validator, Location -from ..helpers import parse_storage_quota from ..manifest import Manifest from ..logger import create_logger @@ -19,8 +18,6 @@ class RepoCreateMixIn: @with_other_repository(manifest=True, compatibility=(Manifest.Operation.READ,)) def do_repo_create(self, args, repository, *, other_repository=None, other_manifest=None): """Create a new, empty repository""" - if args.storage_quota is not None: - raise CommandError("storage-quota is not supported (yet?)") if args.append_only: raise CommandError("append-only is not supported (yet?)") other_key = other_manifest.key if other_manifest is not None else None @@ -236,15 +233,6 @@ class RepoCreateMixIn: "or `prune` will still be allowed. See :ref:`append_only_mode` in " "Additional Notes for more details.", ) - subparser.add_argument( - "--storage-quota", - metavar="QUOTA", - dest="storage_quota", - default=None, - type=parse_storage_quota, - action=Highlander, - help="Set storage quota of the new repository (e.g. 5G, 1.5T). Default: no quota.", - ) subparser.add_argument( "--copy-crypt-key", dest="copy_crypt_key", diff --git a/src/borg/archiver/repo_info_cmd.py b/src/borg/archiver/repo_info_cmd.py index d756cb735..ae20c0729 100644 --- a/src/borg/archiver/repo_info_cmd.py +++ b/src/borg/archiver/repo_info_cmd.py @@ -3,7 +3,7 @@ import textwrap from ._common import with_repository from ..constants import * # NOQA -from ..helpers import bin_to_hex, json_print, basic_json_data, format_file_size +from ..helpers import bin_to_hex, json_print, basic_json_data from ..manifest import Manifest from ..logger import create_logger @@ -50,15 +50,6 @@ class RepoInfoMixIn: ) ) - response = repository.info() - storage_quota = response["storage_quota"] - used = format_file_size(response["storage_quota_use"], iec=args.iec) - - output += f"\nStorage quota: {used} used" - if storage_quota: - output += f" out of {format_file_size(storage_quota, iec=args.iec)}" - output += "\n" - if hasattr(info["cache"], "path"): output += "Cache: {cache.path}\n".format(**info) output += "Security dir: {security_dir}\n".format(**info) diff --git a/src/borg/archiver/serve_cmd.py b/src/borg/archiver/serve_cmd.py index d16949834..457695620 100644 --- a/src/borg/archiver/serve_cmd.py +++ b/src/borg/archiver/serve_cmd.py @@ -1,8 +1,7 @@ import argparse -from ._common import Highlander from ..constants import * # NOQA -from ..helpers import parse_storage_quota, CommandError +from ..helpers import CommandError from ..remote import RepositoryServer from ..logger import create_logger @@ -15,13 +14,10 @@ class ServeMixIn: """Start in server mode. This command is usually not used manually.""" if args.append_only: raise CommandError("append-only is not supported (yet?)") - if args.storage_quota is not None: - raise CommandError("storage-quota is not supported (yet?)") RepositoryServer( restrict_to_paths=args.restrict_to_paths, restrict_to_repositories=args.restrict_to_repositories, append_only=args.append_only, - storage_quota=args.storage_quota, use_socket=args.use_socket, ).serve() @@ -84,14 +80,3 @@ class ServeMixIn: "or `prune` will still be allowed. See :ref:`append_only_mode` in Additional " "Notes for more details.", ) - subparser.add_argument( - "--storage-quota", - metavar="QUOTA", - dest="storage_quota", - type=parse_storage_quota, - default=None, - action=Highlander, - help="Override storage quota of the repository (e.g. 5G, 1.5T). " - "When a new repository is initialized, sets the storage quota on the new " - "repository as well. Default: no quota.", - ) diff --git a/src/borg/helpers/__init__.py b/src/borg/helpers/__init__.py index 3d1bc74a1..b681101ec 100644 --- a/src/borg/helpers/__init__.py +++ b/src/borg/helpers/__init__.py @@ -30,7 +30,7 @@ from .parseformat import bin_to_hex, hex_to_bin, safe_encode, safe_decode from .parseformat import text_to_json, binary_to_json, remove_surrogates, join_cmd from .parseformat import eval_escapes, decode_dict, positive_int_validator, interval from .parseformat import PathSpec, SortBySpec, ChunkerParams, FilesCacheMode, partial_format, DatetimeWrapper -from .parseformat import format_file_size, parse_file_size, FileSize, parse_storage_quota +from .parseformat import format_file_size, parse_file_size, FileSize from .parseformat import sizeof_fmt, sizeof_fmt_iec, sizeof_fmt_decimal, Location, text_validator from .parseformat import format_line, replace_placeholders, PlaceholderError, relative_time_marker_validator from .parseformat import format_archive, parse_stringified_list, clean_lines diff --git a/src/borg/helpers/parseformat.py b/src/borg/helpers/parseformat.py index b23bc78ca..94a7eebb6 100644 --- a/src/borg/helpers/parseformat.py +++ b/src/borg/helpers/parseformat.py @@ -357,13 +357,6 @@ def parse_file_size(s): return int(float(s) * factor) -def parse_storage_quota(storage_quota): - parsed = parse_file_size(storage_quota) - if parsed < parse_file_size("10M"): - raise argparse.ArgumentTypeError("quota is too small (%s). At least 10M are required." % storage_quota) - return parsed - - def sizeof_fmt(num, suffix="B", units=None, power=None, sep="", precision=2, sign=False): sign = "+" if sign and num > 0 else "" fmt = "{0:{1}.{2}f}{3}{4}{5}" diff --git a/src/borg/legacyremote.py b/src/borg/legacyremote.py index 49018b52f..5dc143b58 100644 --- a/src/borg/legacyremote.py +++ b/src/borg/legacyremote.py @@ -409,9 +409,6 @@ class LegacyRemoteRepository: topic = "borg.debug." + topic if "repository" in topic: opts.append("--debug-topic=%s" % topic) - - if "storage_quota" in args and args.storage_quota: - opts.append("--storage-quota=%s" % args.storage_quota) env_vars = [] if testing: return env_vars + [sys.executable, "-m", "borg", "serve"] + opts + self.extra_test_args diff --git a/src/borg/legacyrepository.py b/src/borg/legacyrepository.py index 2b7f52102..f754e0b10 100644 --- a/src/borg/legacyrepository.py +++ b/src/borg/legacyrepository.py @@ -183,10 +183,7 @@ class LegacyRepository: exit_mcode = 19 - class StorageQuotaExceeded(Error): - """The storage quota ({}) has been exceeded ({}). Try deleting some archives.""" - - exit_mcode = 20 + # StorageQuotaExceeded was exit_mcode = 20 class PathPermissionDenied(Error): """Permission denied to {}.""" @@ -194,15 +191,7 @@ class LegacyRepository: exit_mcode = 21 def __init__( - self, - path, - create=False, - exclusive=False, - lock_wait=None, - lock=True, - append_only=False, - storage_quota=None, - send_log_cb=None, + self, path, create=False, exclusive=False, lock_wait=None, lock=True, append_only=False, send_log_cb=None ): self.path = os.path.abspath(path) self._location = Location("file://%s" % self.path) @@ -230,8 +219,6 @@ class LegacyRepository: self.created = False self.exclusive = exclusive self.append_only = append_only - self.storage_quota = storage_quota - self.storage_quota_use = 0 self.transaction_doomed = None # v2 is the default repo version for borg 2.0 # v1 repos must only be used in a read-only way, e.g. for @@ -290,13 +277,9 @@ class LegacyRepository: """ Raise an exception if a repository already exists at *path* or any parent directory. - Checking parent directories is done for two reasons: - (1) It's just a weird thing to do, and usually not intended. A Borg using the "parent" repository - may be confused, or we may accidentally put stuff into the "data/" or "data//" directories. - (2) When implementing repository quotas (which we currently don't), it's important to prohibit - folks from creating quota-free repositories. Since no one can create a repository within another - repository, user's can only use the quota'd repository, when their --restrict-to-path points - at the user's repository. + Checking parent directories is done because it's just a weird thing to do, and usually not intended. + A Borg using the "parent" repository may be confused, or we may accidentally put stuff into the "data/" or + "data//" directories. """ try: st = os.stat(path) @@ -345,10 +328,6 @@ class LegacyRepository: config.set("repository", "segments_per_dir", str(DEFAULT_SEGMENTS_PER_DIR)) config.set("repository", "max_segment_size", str(DEFAULT_MAX_SEGMENT_SIZE)) config.set("repository", "append_only", str(int(self.append_only))) - if self.storage_quota: - config.set("repository", "storage_quota", str(self.storage_quota)) - else: - config.set("repository", "storage_quota", "0") config.set("repository", "additional_free_space", "0") config.set("repository", "id", bin_to_hex(os.urandom(32))) self.save_config(path, config) @@ -492,9 +471,6 @@ class LegacyRepository: # append_only can be set in the constructor # it shouldn't be overridden (True -> False) here self.append_only = self.append_only or self.config.getboolean("repository", "append_only", fallback=False) - if self.storage_quota is None: - # self.storage_quota is None => no explicit storage_quota was specified, use repository setting. - self.storage_quota = parse_file_size(self.config.get("repository", "storage_quota", fallback=0)) self.id = hex_to_bin(self.config.get("repository", "id").strip(), length=32) self.io = LoggedIO(self.path, self.max_segment_size, self.segments_per_dir) @@ -504,15 +480,12 @@ class LegacyRepository: return hints = self._unpack_hints(transaction_id) self.version = hints["version"] - self.storage_quota_use = hints["storage_quota_use"] self.shadow_index = hints["shadow_index"] def info(self): """return some infos about the repo (must be opened first)""" info = dict(id=self.id, version=self.version, append_only=self.append_only) self._load_hints() - info["storage_quota"] = self.storage_quota - info["storage_quota_use"] = self.storage_quota_use return info def close(self): @@ -604,7 +577,6 @@ class LegacyRepository: if transaction_id is None: self.segments = {} # XXX bad name: usage_count_of_segment_x = self.segments[x] self.compact = FreeSpace() # XXX bad name: freeable_space_of_segment_x = self.compact[x] - self.storage_quota_use = 0 self.shadow_index.clear() else: if do_cleanup: @@ -626,7 +598,6 @@ class LegacyRepository: logger.debug("Upgrading from v1 hints.%d", transaction_id) self.segments = hints["segments"] self.compact = FreeSpace() - self.storage_quota_use = 0 self.shadow_index = {} for segment in sorted(hints["compact"]): logger.debug("Rebuilding sparse info for segment %d", segment) @@ -637,7 +608,6 @@ class LegacyRepository: else: self.segments = hints["segments"] self.compact = FreeSpace(hints["compact"]) - self.storage_quota_use = hints.get("storage_quota_use", 0) self.shadow_index = hints.get("shadow_index", {}) # Drop uncommitted segments in the shadow index for key, shadowed_segments in self.shadow_index.items(): @@ -653,13 +623,7 @@ class LegacyRepository: def rename_tmp(file): os.replace(file + ".tmp", file) - hints = { - "version": 2, - "segments": self.segments, - "compact": self.compact, - "storage_quota_use": self.storage_quota_use, - "shadow_index": self.shadow_index, - } + hints = {"version": 2, "segments": self.segments, "compact": self.compact, "shadow_index": self.shadow_index} integrity = { # Integrity version started at 2, the current hints version. # Thus, integrity version == hints version, for now. @@ -783,7 +747,6 @@ class LegacyRepository: if not self.compact: logger.debug("Nothing to do: compact empty") return - quota_use_before = self.storage_quota_use index_transaction_id = self.get_index_transaction_id() segments = self.segments unused = [] # list of segments, that are not used anymore @@ -855,9 +818,6 @@ class LegacyRepository: segments.setdefault(new_segment, 0) segments[new_segment] += 1 segments[segment] -= 1 - if tag == TAG_PUT: - # old tag is PUT, but new will be PUT2 and use a bit more storage - self.storage_quota_use += self.io.ENTRY_HASH_SIZE elif tag in (TAG_PUT2, TAG_PUT) and not is_index_object: # If this is a PUT shadowed by a later tag, then it will be gone when this segment is deleted after # this loop. Therefore it is removed from the shadow index. @@ -867,7 +827,6 @@ class LegacyRepository: # do not remove entry with empty shadowed_segments list here, # it is needed for shadowed_put_exists code (see below)! pass - self.storage_quota_use -= header_size(tag) + len(data) elif tag == TAG_DELETE and not in_index: # If the shadow index doesn't contain this key, then we can't say if there's a shadowed older tag, # therefore we do not drop the delete, but write it to a current segment. @@ -945,8 +904,6 @@ class LegacyRepository: self._send_log() complete_xfer(intermediate=False) self.io.clear_empty_dirs() - quota_use_after = self.storage_quota_use - logger.info("Compaction freed about %s repository space.", format_file_size(quota_use_before - quota_use_after)) logger.debug("Compaction completed.") def replay_segments(self, index_transaction_id, segments_transaction_id): @@ -990,7 +947,6 @@ class LegacyRepository: pass self.index[key] = NSIndex1Entry(segment, offset) self.segments[segment] += 1 - self.storage_quota_use += header_size(tag) + size elif tag == TAG_DELETE: try: # if the deleted PUT is not in the index, there is nothing to clean up @@ -1232,20 +1188,14 @@ class LegacyRepository: pass else: # this put call supersedes a previous put to same id. - # it is essential to do a delete first to get correct quota bookkeeping - # and also a correctly updated shadow_index, so that the compaction code - # does not wrongly resurrect an old PUT by dropping a DEL that is still needed. + # it is essential to do a delete first to get a correctly updated shadow_index, + # so that the compaction code does not wrongly resurrect an old PUT by + # dropping a DEL that is still needed. self._delete(id, in_index.segment, in_index.offset, 0) segment, offset = self.io.write_put(id, data) - self.storage_quota_use += header_size(TAG_PUT2) + len(data) self.segments.setdefault(segment, 0) self.segments[segment] += 1 self.index[id] = NSIndex1Entry(segment, offset) - if self.storage_quota and self.storage_quota_use > self.storage_quota: - self.transaction_doomed = self.StorageQuotaExceeded( - format_file_size(self.storage_quota), format_file_size(self.storage_quota_use) - ) - raise self.transaction_doomed def delete(self, id, wait=True): """delete a repo object diff --git a/src/borg/remote.py b/src/borg/remote.py index 84cfe0b94..6647ed028 100644 --- a/src/borg/remote.py +++ b/src/borg/remote.py @@ -183,7 +183,7 @@ class RepositoryServer: # pragma: no cover "store_move", ) - def __init__(self, restrict_to_paths, restrict_to_repositories, append_only, storage_quota, use_socket): + def __init__(self, restrict_to_paths, restrict_to_repositories, append_only, use_socket): self.repository = None self.RepoCls = None self.rpc_methods = ("open", "close", "negotiate") @@ -194,7 +194,6 @@ class RepositoryServer: # pragma: no cover # whatever the client wants, except when initializing a new repository # (see RepositoryServer.open below). self.append_only = append_only - self.storage_quota = storage_quota self.client_version = None # we update this after client sends version information if use_socket is False: self.socket_path = None @@ -276,7 +275,6 @@ class RepositoryServer: # pragma: no cover Repository.PathAlreadyExists, PathNotAllowed, Repository.InsufficientFreeSpaceError, - Repository.StorageQuotaExceeded, ) # logger.exception(e) ex_short = traceback.format_exception_only(e.__class__, e) @@ -407,7 +405,6 @@ class RepositoryServer: # pragma: no cover lock_wait=lock_wait, lock=lock, append_only=append_only, - storage_quota=self.storage_quota, exclusive=exclusive, send_log_cb=self.send_queued_log, ) @@ -735,9 +732,6 @@ class RemoteRepository: topic = "borg.debug." + topic if "repository" in topic: opts.append("--debug-topic=%s" % topic) - - if "storage_quota" in args and args.storage_quota: - opts.append("--storage-quota=%s" % args.storage_quota) env_vars = [] if testing: return env_vars + [sys.executable, "-m", "borg", "serve"] + opts + self.extra_test_args @@ -834,8 +828,6 @@ class RemoteRepository: raise Repository.InsufficientFreeSpaceError(args[0], args[1]) elif error == "InvalidRepositoryConfig": raise Repository.InvalidRepositoryConfig(self.location.processed, args[1]) - elif error == "StorageQuotaExceeded": - raise Repository.StorageQuotaExceeded(args[0], args[1]) else: raise self.RPCError(unpacked) diff --git a/src/borg/repository.py b/src/borg/repository.py index 1d98534b4..7a91eaf8d 100644 --- a/src/borg/repository.py +++ b/src/borg/repository.py @@ -86,10 +86,7 @@ class Repository: exit_mcode = 19 - class StorageQuotaExceeded(Error): - """The storage quota ({}) has been exceeded ({}). Try deleting some archives.""" - - exit_mcode = 20 + # StorageQuotaExceeded was exit_mcode = 20 class PathPermissionDenied(Error): """Permission denied to {}.""" @@ -104,7 +101,6 @@ class Repository: lock_wait=1.0, lock=True, append_only=False, - storage_quota=None, send_log_cb=None, ): if isinstance(path_or_location, Location): @@ -144,8 +140,6 @@ class Repository: self.acceptable_repo_versions = (3,) self.opened = False self.append_only = append_only # XXX not implemented / not implementable - self.storage_quota = storage_quota # XXX not implemented - self.storage_quota_use = 0 # XXX not implemented self.lock = None self.do_lock = lock self.lock_wait = lock_wait @@ -260,13 +254,7 @@ class Repository: """return some infos about the repo (must be opened first)""" # note: don't do anything expensive here or separate the lock refresh into a separate method. self._lock_refresh() # do not remove, see do_with_lock() - info = dict( - id=self.id, - version=self.version, - storage_quota_use=self.storage_quota_use, - storage_quota=self.storage_quota, - append_only=self.append_only, - ) + info = dict(id=self.id, version=self.version, append_only=self.append_only) return info def check(self, repair=False, max_duration=0): diff --git a/src/borg/testsuite/archiver/argparsing_test.py b/src/borg/testsuite/archiver/argparsing_test.py index b936158dc..5a53e2e52 100644 --- a/src/borg/testsuite/archiver/argparsing_test.py +++ b/src/borg/testsuite/archiver/argparsing_test.py @@ -1,7 +1,6 @@ import argparse import pytest -from ...helpers import parse_storage_quota from . import Archiver, RK_ENCRYPTION, cmd @@ -187,9 +186,3 @@ class TestCommonOptions: } assert parse_vars_from_line(*line) == result - - -def test_parse_storage_quota(): - assert parse_storage_quota("50M") == 50 * 1000**2 - with pytest.raises(argparse.ArgumentTypeError): - parse_storage_quota("5M") diff --git a/src/borg/testsuite/legacyrepository_test.py b/src/borg/testsuite/legacyrepository_test.py index fbf66fad1..3b3709798 100644 --- a/src/borg/testsuite/legacyrepository_test.py +++ b/src/borg/testsuite/legacyrepository_test.py @@ -1051,15 +1051,7 @@ def test_remote_borg_cmd(remote_repository): "--debug-topic=borg.debug.repository_compaction", ] args = _get_mock_args() - args.storage_quota = 0 assert remote_repository.borg_cmd(args, testing=False) == ["borg", "serve", "--info"] - args.storage_quota = 314159265 - assert remote_repository.borg_cmd(args, testing=False) == [ - "borg", - "serve", - "--info", - "--storage-quota=314159265", - ] args.rsh = "ssh -i foo" remote_repository._args = args assert remote_repository.ssh_cmd(Location("ssh://example.com/foo")) == ["ssh", "-i", "foo", "example.com"] diff --git a/src/borg/testsuite/remote_test.py b/src/borg/testsuite/remote_test.py index 1e64525e2..26b57e197 100644 --- a/src/borg/testsuite/remote_test.py +++ b/src/borg/testsuite/remote_test.py @@ -41,7 +41,7 @@ class TestSleepingBandwidthLimiter: now = 100 - it = SleepingBandwidthLimiter(100) + it = SleepingBandwidthLimiter(100) # bandwidth quota # all fits self.expect_write(5, b"test") diff --git a/src/borg/testsuite/repository_test.py b/src/borg/testsuite/repository_test.py index 7a142b26f..c22bdc36c 100644 --- a/src/borg/testsuite/repository_test.py +++ b/src/borg/testsuite/repository_test.py @@ -263,15 +263,7 @@ def test_remote_borg_cmd(remote_repository): "--debug-topic=borg.debug.repository_compaction", ] args = _get_mock_args() - args.storage_quota = 0 assert remote_repository.borg_cmd(args, testing=False) == ["borg", "serve", "--info"] - args.storage_quota = 314159265 - assert remote_repository.borg_cmd(args, testing=False) == [ - "borg", - "serve", - "--info", - "--storage-quota=314159265", - ] args.rsh = "ssh -i foo" remote_repository._args = args assert remote_repository.ssh_cmd(Location("ssh://example.com/foo")) == ["ssh", "-i", "foo", "example.com"]