Feature: Store all configs used to create an archive, inside the created archive. #697

Closed
opened 2023-05-14 09:53:08 +00:00 by diivi · 9 comments
Collaborator

What I'm trying to do and why

For Borgmatic to restore data from just a repository and nothing else, the user needs to have the config somewhere. Having it inside the archive will make things easier for the user as borgmatic can later use that config and restore the archive, with no external help.

Other notes / implementation ideas

  • Store configuration within the archive at the same path where it exists on the system being backed up.

For instance, let's say you have configuration at /etc/borgmatic/config.yaml and /etc/borgmatic.d/myapp.yaml. And you pass both of those to borgmatic either implicitly or explicitly. Then upon a "create" action, borgmatic can put those two configuration files into the archive at etc/borgmatic/config.yaml and etc/borgmatic.d/myapp.yaml just as it would with any other file (Borg doesn't store leading slashes in file paths). It already works kind of like this for the ~/.borgmatic/ directory.

  • witten

TODO: This should be as simple as adding the config being used to source_directories somehow?

  • Create a metadata/manifest file that tells borgmatic where these configs are, to list them and so that borgmatic knows what to extract.

The one thing missing though with an approach like this is some sort of metadata/manifest for borgmatic to programmatically retrieve the full list of configuration files within an archive, so that "bootstrap" knows what to extract. This could just be a JSON file shoved into ~/.borgmatic somewhere, for instance.

  • witten

TODO: Check how things get stored inside ~/.borgmatic (afair, every database has a folder in this folder) and then add one file with a pre-determined name (configs-list.json?) that contains info about all config files (just their path for now).

[
	"etc/borgmatic/config.yaml","etc/borgmatic.d/myapp.yaml"
]

This should complete "phase 1" of Borgmatic being able to restore an archive from nothing.

#### What I'm trying to do and why For Borgmatic to restore data from just a repository and nothing else, the user needs to have the config somewhere. Having it inside the archive will make things easier for the user as borgmatic can later use that config and restore the archive, with no external help. #### Other notes / implementation ideas * Store configuration within the archive at the same path where it exists on the system being backed up. > For instance, let's say you have configuration at /etc/borgmatic/config.yaml and /etc/borgmatic.d/myapp.yaml. And you pass both of those to borgmatic either implicitly or explicitly. Then upon a "create" action, borgmatic can put those two configuration files into the archive at etc/borgmatic/config.yaml and etc/borgmatic.d/myapp.yaml just as it would with any other file (Borg doesn't store leading slashes in file paths). It already works kind of like this for the ~/.borgmatic/ directory. - witten TODO: This should be as simple as adding the config being used to source_directories somehow? * Create a metadata/manifest file that tells borgmatic where these configs are, to list them and so that borgmatic knows what to extract. > The one thing missing though with an approach like this is some sort of metadata/manifest for borgmatic to programmatically retrieve the full list of configuration files within an archive, so that "bootstrap" knows what to extract. This could just be a JSON file shoved into ~/.borgmatic somewhere, for instance. - witten TODO: Check how things get stored inside ~/.borgmatic (afair, every database has a folder in this folder) and then add one file with a pre-determined name (configs-list.json?) that contains info about all config files (just their path for now). ```json [ "etc/borgmatic/config.yaml","etc/borgmatic.d/myapp.yaml" ] ``` This should complete "phase 1" of Borgmatic being able to restore an archive from nothing.
Owner

TODO: This should be as simple as adding the config being used to source_directories somehow?

I think so. This is where that happens now: https://projects.torsion.org/borgmatic-collective/borgmatic/src/branch/main/borgmatic/borg/create.py#L354

TODO: Check how things get stored inside ~/.borgmatic (afair, every database has a folder in this folder) and then add one file with a pre-determined name (configs-list.json?) that contains info about all config files (just their path for now).

Makes sense! Maybe ~/.borgmatic/bootstrap/configs-list.json or similar?

I like the idea of doing this in discrete, shippable phases so as to keep the work tractable.

> TODO: This should be as simple as adding the config being used to source_directories somehow? I think so. This is where that happens now: https://projects.torsion.org/borgmatic-collective/borgmatic/src/branch/main/borgmatic/borg/create.py#L354 > TODO: Check how things get stored inside ~/.borgmatic (afair, every database has a folder in this folder) and then add one file with a pre-determined name (configs-list.json?) that contains info about all config files (just their path for now). Makes sense! Maybe `~/.borgmatic/bootstrap/configs-list.json` or similar? I like the idea of doing this in discrete, shippable phases so as to keep the work tractable.
witten added this to the bootstrap from nothing milestone 2023-05-14 21:15:07 +00:00
Author
Collaborator

I was trying to back up all configs with:

    location_config['source_directories'] = location_config.get('source_directories', []) + global_arguments.config_paths

Out of the default config_paths (used without the -c arg) that Borgmatic uses, the ones that start with /root raised an error, here's the log for clarity:

Creating archive at "/home/divyansh/Desktop/bkt2::divi-2023-05-15T20:54:29.396008"
/etc/borgmatic.d: [Errno 2] No such file or directory: 'borgmatic.d'
- /etc/borgmatic/config.yaml
- /home/divyansh/Desktop/os/os-ass4/q2.c
- /home/divyansh/Desktop/os/os-ass4/q1.c
- /home/divyansh/Desktop/os/os-ass4/q3.c
- /home/divyansh/Desktop/os/os-ass4/q4.c
- /home/divyansh/Desktop/os/os-ass4/a.out
- /home/divyansh/Desktop/os/2110110680.tar.gz
- /home/divyansh/Desktop/os/a.out
- /home/divyansh/Desktop/os/file.txt
- /home/divyansh/Desktop/os/hello.txt
- /home/divyansh/Desktop/os/wow.txt
- /home/divyansh/Desktop/os/meh.txt
- /home/divyansh/Desktop/os/yo.txt
- /home/divyansh/Desktop/os/.vscode/settings.json
- /home/divyansh/Desktop/os/rr.c
- /home/divyansh/Desktop/os/sjf.c
- /home/divyansh/Desktop/os/os-ass5/a.out
- /home/divyansh/Desktop/os/os-ass5/q1.c
- /home/divyansh/Desktop/os/os-ass5/q2.c
- /home/divyansh/Desktop/os/xyz/x.txt
- /home/divyansh/Desktop/os/ass2/addtrans.c
- /home/divyansh/Desktop/os/ass2/a.out
- /home/divyansh/Desktop/os/helll/hello.sql
/home/divyansh/Desktop/xyz: [Errno 2] No such file or directory: 'xyz'
/root/.config/borgmatic.d: [Errno 2] No such file or directory: 'borgmatic.d'
Local Exception
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/borg/archive.py", line 264, in OsOpen
    fd = os_open(path=path, parent_fd=parent_fd, name=name, flags=flags, noatime=noatime)
  File "/usr/lib/python3/dist-packages/borg/helpers/fs.py", line 290, in os_open
    fd = os.open(fname, _flags_noatime, dir_fd=parent_fd)
FileNotFoundError: [Errno 2] No such file or directory: '/root/.config/borgmatic'

Borg raised this error:

borg.archive.BackupOSError: open_root: [Errno 2] No such file or directory: '/root/.config/borgmatic'

which was not handled by Borgmatic (I even set source_directories_must_exist to false).

Why wasn't this handled by https://github.com/borgmatic-collective/borgmatic/pull/56? Also, how should I go about backing up the configs in the /root folder?

I was trying to back up all configs with: ```python location_config['source_directories'] = location_config.get('source_directories', []) + global_arguments.config_paths ``` Out of the default config_paths (used without the -c arg) that Borgmatic uses, the ones that start with /root raised an error, here's the log for clarity: ```bash Creating archive at "/home/divyansh/Desktop/bkt2::divi-2023-05-15T20:54:29.396008" /etc/borgmatic.d: [Errno 2] No such file or directory: 'borgmatic.d' - /etc/borgmatic/config.yaml - /home/divyansh/Desktop/os/os-ass4/q2.c - /home/divyansh/Desktop/os/os-ass4/q1.c - /home/divyansh/Desktop/os/os-ass4/q3.c - /home/divyansh/Desktop/os/os-ass4/q4.c - /home/divyansh/Desktop/os/os-ass4/a.out - /home/divyansh/Desktop/os/2110110680.tar.gz - /home/divyansh/Desktop/os/a.out - /home/divyansh/Desktop/os/file.txt - /home/divyansh/Desktop/os/hello.txt - /home/divyansh/Desktop/os/wow.txt - /home/divyansh/Desktop/os/meh.txt - /home/divyansh/Desktop/os/yo.txt - /home/divyansh/Desktop/os/.vscode/settings.json - /home/divyansh/Desktop/os/rr.c - /home/divyansh/Desktop/os/sjf.c - /home/divyansh/Desktop/os/os-ass5/a.out - /home/divyansh/Desktop/os/os-ass5/q1.c - /home/divyansh/Desktop/os/os-ass5/q2.c - /home/divyansh/Desktop/os/xyz/x.txt - /home/divyansh/Desktop/os/ass2/addtrans.c - /home/divyansh/Desktop/os/ass2/a.out - /home/divyansh/Desktop/os/helll/hello.sql /home/divyansh/Desktop/xyz: [Errno 2] No such file or directory: 'xyz' /root/.config/borgmatic.d: [Errno 2] No such file or directory: 'borgmatic.d' Local Exception Traceback (most recent call last): File "/usr/lib/python3/dist-packages/borg/archive.py", line 264, in OsOpen fd = os_open(path=path, parent_fd=parent_fd, name=name, flags=flags, noatime=noatime) File "/usr/lib/python3/dist-packages/borg/helpers/fs.py", line 290, in os_open fd = os.open(fname, _flags_noatime, dir_fd=parent_fd) FileNotFoundError: [Errno 2] No such file or directory: '/root/.config/borgmatic' ``` Borg raised this error: ```bash borg.archive.BackupOSError: open_root: [Errno 2] No such file or directory: '/root/.config/borgmatic' ``` which was not handled by Borgmatic (I even set source_directories_must_exist to false). Why wasn't this handled by https://github.com/borgmatic-collective/borgmatic/pull/56? Also, how should I go about backing up the configs in the /root folder?
Owner

Where exactly did you put this line?

  location_config['source_directories'] = location_config.get('source_directories', []) + global_arguments.config_paths

If, for instance, it came before the call to check_all_source_directories_exist() in create_archive(), I would expect that feature to raise when it can't find those paths. If it came after, then I would not expect borgmatic to catch that, and it would be consistent with your observed behavior. In any case, I don't think this approach will quite work....

Also, how should I go about backing up the configs in the /root folder?

Here's how I think you should go about backing up configs in any folder: I think you might need to probe for existence before adding them to location_config['source_directories']. And not to raise when they don't exist like the check_all_source_directories_exist() feature, but instead just to omit them if they don't exist. The reason I say that is because unlike standard source directories, it's okay if the default config paths don't exist. They just need to be probed for one at a time and config loaded if it's present there.

The good news is this is already done for you, and I think you might be able to switch out the value you add to location_config['source_directories'] (with some annoying plumbing work). Instead of global_arguments.config_paths, which is the raw, unprocessed set of config paths that may or may not exist, you need the output of borgmatic/config/collect.py:collect_config_filenames() ...

  • Which is currently called in borgmatic/commands/borgmatic.py:main().
  • That calls collect_configuration_run_summary_logs() with configs (a map from processed config filename to loaded config).
  • That calls run_configuration() on a single config file.
  • That calls run_actions().
  • That calls borgmatic/actions/create.py:run_create().
  • That calls borgmatic/borg/create.py:create_archive(), which is where you presumably need the full list of configs so you can add them to source directories.

So maybe the thing to do is to pass the config filename list into run_configuration() and all the way down to create_archive()? If you can think of a better approach, that's fine too.

Where exactly did you put this line? ```python location_config['source_directories'] = location_config.get('source_directories', []) + global_arguments.config_paths ``` If, for instance, it came *before* the call to `check_all_source_directories_exist()` in `create_archive()`, I would expect that feature to raise when it can't find those paths. If it came *after*, then I would not expect borgmatic to catch that, and it would be consistent with your observed behavior. In any case, I don't think this approach will quite work.... > Also, how should I go about backing up the configs in the /root folder? Here's how I think you should go about backing up configs in *any* folder: I think you might need to probe for existence before adding them to `location_config['source_directories']`. And not to raise when they don't exist like the `check_all_source_directories_exist()` feature, but instead just to omit them if they don't exist. The reason I say that is because unlike standard source directories, it's okay if the default config paths don't exist. They just need to be probed for one at a time and config loaded if it's present there. The good news is this is already done for you, and I think you might be able to switch out the value you add to `location_config['source_directories']` (with some annoying plumbing work). Instead of `global_arguments.config_paths`, which is the raw, unprocessed set of config paths that may or may not exist, you need the output of `borgmatic/config/collect.py:collect_config_filenames()` ... * Which is currently called in `borgmatic/commands/borgmatic.py:main()`. * That calls `collect_configuration_run_summary_logs()` with `configs` (a map from processed config filename to loaded config). * That calls `run_configuration()` on a single config file. * That calls `run_actions()`. * That calls `borgmatic/actions/create.py:run_create()`. * That calls `borgmatic/borg/create.py:create_archive()`, which is where you presumably need the full list of configs so you can add them to source directories. So maybe the thing to do is to pass the config filename list into `run_configuration()` and all the way down to `create_archive()`? If you can think of a better approach, that's fine too.
Owner

@diivi It occurs to me that borgmatic bootstrap could be renamed to borgmatic config bootstrap, especially if all it's doing is extracting config. Related ticket: #529.

@diivi It occurs to me that `borgmatic bootstrap` _could_ be renamed to `borgmatic config bootstrap`, especially if all it's doing is extracting config. Related ticket: #529.
Owner

For the record: The bulk of this was implemented in: https://github.com/borgmatic-collective/borgmatic/pull/71

For the record: The bulk of this was implemented in: https://github.com/borgmatic-collective/borgmatic/pull/71
Owner

I tried this feature and it works great! However one thing that occurs to me is that it's not storing absolute paths for config files that are specified as relative paths. Which means that when you go to bootstrap, if you don't happen to be in the same directory where the backup was taken, then the config file won't get extracted into the right place. So do you think it makes sense to abspath() all config files before storing them?

I tried this feature and it works great! However one thing that occurs to me is that it's not storing absolute paths for config files that are specified as relative paths. Which means that when you go to bootstrap, if you don't happen to be in the same directory where the backup was taken, then the config file won't get extracted into the right place. So do you think it makes sense to `abspath()` all config files before storing them?
Owner

FYI: bbc7f0596c ... I haven't done this for Fish shell though, because honestly I don't understand how its completions work.

FYI: https://projects.torsion.org/borgmatic-collective/borgmatic/commit/bbc7f0596c13b79e6930ffa1a2b4381e8d2df766 ... I haven't done this for Fish shell though, because honestly I don't understand how its completions work.
Owner

Just released in borgmatic 1.7.15. I'm leaving the ticket open for now pending documentation.

Just released in borgmatic 1.7.15. I'm leaving the ticket open for now pending documentation.
witten added the
new feature area
label 2023-06-28 18:37:04 +00:00
Owner
Docs are complete, courtesy of @diivi! https://torsion.org/borgmatic/docs/how-to/extract-a-backup/#extract-the-configuration-files-used-to-create-an-archive
Sign in to join this conversation.
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: borgmatic-collective/borgmatic#697
No description provided.