Bladeren bron

transfer: fix upgrades from borg 1.x by adding a --from-borg1 option

borg transfer is primarily a general purpose archive transfer function
from borg2 to related borg2 repos.

but for upgrades from borg 1.x, we also need to support:
- rcreate with a borg 1.x "other repo"
- transfer with a borg 1.x "other repo"
Thomas Waldmann 10 maanden geleden
bovenliggende
commit
c740fd718b

+ 7 - 3
src/borg/archiver/_common.py

@@ -190,6 +190,8 @@ def with_other_repository(manifest=False, cache=False, compatibility=None):
             if not location.valid:  # nothing to do
                 return method(self, args, **kwargs)
 
+            v1_or_v2 = getattr(args, "v1_or_v2", False)
+
             repository = get_repository(
                 location,
                 create=False,
@@ -200,12 +202,14 @@ def with_other_repository(manifest=False, cache=False, compatibility=None):
                 make_parent_dirs=False,
                 storage_quota=None,
                 args=args,
-                v1_or_v2=True
+                v1_or_v2=v1_or_v2,
             )
 
             with repository:
-                if repository.version not in (1, 2):
-                    raise Error("This borg version only accepts version 1 or 2 repos for --other-repo.")
+                acceptable_versions = (1, 2) if v1_or_v2 else (3,)
+                if repository.version not in acceptable_versions:
+                    raise Error(
+                        f"This borg version only accepts version {' or '.join(acceptable_versions)} repos for --other-repo.")
                 kwargs["other_repository"] = repository
                 if manifest or cache:
                     manifest_ = Manifest.load(

+ 11 - 0
src/borg/archiver/rcreate_cmd.py

@@ -172,6 +172,14 @@ class RCreateMixIn:
         keys to manage.
 
         Creating related repositories is useful e.g. if you want to use ``borg transfer`` later.
+
+        Creating a related repository for data migration from borg 1.2 or 1.4
+        +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+        You can use ``borg rcreate --other-repo ORIG_REPO --from-borg1 ...`` to create a related
+        repository that uses the same secret key material as the given other/original repository.
+
+        Then use ``borg transfer --other-repo ORIG_REPO --from-borg1 ...`` to transfer the archives.
         """
         )
         subparser = subparsers.add_parser(
@@ -193,6 +201,9 @@ class RCreateMixIn:
             action=Highlander,
             help="reuse the key material from the other repository",
         )
+        subparser.add_argument(
+            "--from-borg1", dest="v1_or_v2", action="store_true", help="other repository is borg 1.x"
+        )
         subparser.add_argument(
             "-e",
             "--encryption",

+ 32 - 15
src/borg/archiver/transfer_cmd.py

@@ -61,10 +61,15 @@ class TransferMixIn:
 
         from .. import upgrade as upgrade_mod
 
+        v1_or_v2 = getattr(args, "v1_or_v2", False)
+        upgrader = args.upgrader
+        if upgrader == "NoOp" and v1_or_v2:
+            upgrader = "From12To20"
+
         try:
-            UpgraderCls = getattr(upgrade_mod, f"Upgrader{args.upgrader}")
+            UpgraderCls = getattr(upgrade_mod, f"Upgrader{upgrader}")
         except AttributeError:
-            raise Error(f"No such upgrader: {args.upgrader}")
+            raise Error(f"No such upgrader: {upgrader}")
 
         if UpgraderCls is not upgrade_mod.UpgraderFrom12To20 and other_manifest.repository.version == 1:
             raise Error("To transfer from a borg 1.x repo, you need to use: --upgrader=From12To20")
@@ -188,32 +193,41 @@ class TransferMixIn:
         If you want to globally change compression while transferring archives to the DST_REPO,
         give ``--compress=WANTED_COMPRESSION --recompress=always``.
 
-        Suggested use for general purpose archive transfer (not repo upgrades)::
+        The default is to transfer all archives, including checkpoint archives.
+
+        You could use the misc. archive filter options to limit which archives it will
+        transfer, e.g. using the ``-a`` option. This is recommended for big
+        repositories with multiple data sets to keep the runtime per invocation lower.
+
+        General purpose archive transfer
+        ++++++++++++++++++++++++++++++++
+
+        Transfer borg2 archives into a related other borg2 repository::
 
             # create a related DST_REPO (reusing key material from SRC_REPO), so that
             # chunking and chunk id generation will work in the same way as before.
-            borg --repo=DST_REPO rcreate --other-repo=SRC_REPO --encryption=DST_ENC
+            borg --repo=DST_REPO rcreate --encryption=DST_ENC --other-repo=SRC_REPO
 
             # transfer archives from SRC_REPO to DST_REPO
             borg --repo=DST_REPO transfer --other-repo=SRC_REPO --dry-run  # check what it would do
             borg --repo=DST_REPO transfer --other-repo=SRC_REPO            # do it!
             borg --repo=DST_REPO transfer --other-repo=SRC_REPO --dry-run  # check! anything left?
 
-        The default is to transfer all archives, including checkpoint archives.
 
-        You could use the misc. archive filter options to limit which archives it will
-        transfer, e.g. using the ``-a`` option. This is recommended for big
-        repositories with multiple data sets to keep the runtime per invocation lower.
+        Data migration / upgrade from borg 1.x
+        ++++++++++++++++++++++++++++++++++++++
 
-        For repository upgrades (e.g. from a borg 1.2 repo to a related borg 2.0 repo), usage is
-        quite similar to the above::
+        To migrate your borg 1.x archives into a related, new borg2 repository, usage is quite similar
+        to the above, but you need the ``--from-borg1`` option::
 
-            # fast: compress metadata with zstd,3, but keep data chunks compressed as they are:
-            borg --repo=DST_REPO transfer --other-repo=SRC_REPO --upgrader=From12To20 \\
-                 --compress=zstd,3 --recompress=never
+            borg --repo=DST_REPO rcreate --encryption=DST_ENC --other-repo=SRC_REPO --from-borg1
 
-            # compress metadata and recompress data with zstd,3
-            borg --repo=DST_REPO transfer --other-repo=SRC_REPO --upgrader=From12To20 \\
+            # to continue using lz4 compression as you did in SRC_REPO:
+            borg --repo=DST_REPO transfer --other-repo=SRC_REPO --from-borg1 \\
+                 --compress=lz4 --recompress=never
+
+            # alternatively, to recompress everything to zstd,3:
+            borg --repo=DST_REPO transfer --other-repo=SRC_REPO --from-borg1 \\
                  --compress=zstd,3 --recompress=always
 
 
@@ -241,6 +255,9 @@ class TransferMixIn:
             action=Highlander,
             help="transfer archives from the other repository",
         )
+        subparser.add_argument(
+            "--from-borg1", dest="v1_or_v2", action="store_true", help="other repository is borg 1.x"
+        )
         subparser.add_argument(
             "--upgrader",
             metavar="UPGRADER",

+ 2 - 2
src/borg/testsuite/archiver/transfer_cmd.py

@@ -75,8 +75,8 @@ def test_transfer_upgrade(archivers, request):
     assert os.environ.get("BORG_PASSPHRASE") == "waytooeasyonlyfortests"
     os.environ["BORG_TESTONLY_WEAKEN_KDF"] = "0"  # must use the strong kdf here or it can't decrypt the key
 
-    cmd(archiver, "rcreate", RK_ENCRYPTION, other_repo1)
-    cmd(archiver, "transfer", other_repo1, "--upgrader=From12To20")
+    cmd(archiver, "rcreate", RK_ENCRYPTION, other_repo1, "--from-borg1")
+    cmd(archiver, "transfer", other_repo1, "--from-borg1")
     cmd(archiver, "check")
 
     # check list of archives / manifest