[feature request] label/tag a repo #635

Open
opened 2023-02-06 20:32:35 +00:00 by eoli3n · 11 comments

What I'm trying to do and why

Label a repo, to be able to use --repository label1 instead of the full path copypasted from borgmatic list. Useful when using multiple config files with /etc/borgmatic.d, or multiple repositories in the same file.

Syntax could be

location:
  repositories:
    - path: borgbase.com/stuff
      label: borgbase
    - path: rsync.net/stuff
      label: rsyncnet

Problem is that it uses a dict instead of the current list, and it breaks compatibility.

If a label is set, it could be used in borgmatic list --short

$ borgmatic list --short
borgbase: Listing archives
host1-2022-10-02T11:34:27
rsyncnet: Listing archives
host1-2022-10-02T11:34:27

Mount a backup

borgmatic mount --archive host1-2022-10-02T11:34:27 --repository borgbase --mount-point /mnt
#### What I'm trying to do and why Label a repo, to be able to use ``--repository label1`` instead of the full path copypasted from ``borgmatic list``. Useful when using multiple config files with ``/etc/borgmatic.d``, or multiple repositories in the same file. Syntax could be ``` location: repositories: - path: borgbase.com/stuff label: borgbase - path: rsync.net/stuff label: rsyncnet ``` Problem is that it uses a dict instead of the current list, and it breaks compatibility. If a label is set, it could be used in ``borgmatic list --short`` ``` $ borgmatic list --short borgbase: Listing archives host1-2022-10-02T11:34:27 rsyncnet: Listing archives host1-2022-10-02T11:34:27 ``` Mount a backup ``` borgmatic mount --archive host1-2022-10-02T11:34:27 --repository borgbase --mount-point /mnt ```
Owner

This is a great idea! I think the string vs. dict thing could be sidestepped by auto-converting any list of strings into a list of dicts internally.. There is precedent for doing that with other configuration options in borgmatic.

This is a great idea! I think the string vs. dict thing could be sidestepped by auto-converting any list of strings into a list of dicts internally.. There is precedent for doing that with other configuration options in borgmatic.
witten added the
design finalized
good first issue
labels 2023-02-06 21:12:56 +00:00
Collaborator

This is a problem that I face too, I would like to work on the solution!
Will explore the code a little, anything you have to sugget @witten ?

This is a problem that I face too, I would like to work on the solution! Will explore the code a little, anything you have to sugget @witten ?
Owner

Sure! The auto-converting of lists to dicts internally I mentioned in the last comment could be done in the existing borgmatic/config/normalize.py:normalize(). That way, "old-style" configuration files would continue to work. (Which suggests repository labels should be optional.) There are also a number of places throughout the borgmatic source that expect repositories to be a list of strings instead of list of dicts, so those would have to be updated as well.

Additionally, the code that resolves repository names (matching a repository specified on the command-line to a repository specified in configuration) is at borgmatic/config/validate.py:repositories_match(). That could be enhanced to support matching repositories by label and not just path, although the relevant configuration would have to get passed in for that to work.

Lastly, code that looks like this throughout the borgmatic source would probably need updating to use repository labels (if set):

logger.answer(f'{repository}: Listing archive {archive}')
Sure! The auto-converting of lists to dicts internally I mentioned in the last comment could be done in the existing `borgmatic/config/normalize.py:normalize()`. That way, "old-style" configuration files would continue to work. (Which suggests repository labels should be optional.) There are also a number of places throughout the borgmatic source that expect `repositories` to be a list of strings instead of list of dicts, so those would have to be updated as well. Additionally, the code that resolves repository names (matching a repository specified on the command-line to a repository specified in configuration) is at `borgmatic/config/validate.py:repositories_match()`. That could be enhanced to support matching repositories by label and not just path, although the relevant configuration would have to get passed in for that to work. Lastly, code that looks like this throughout the borgmatic source would probably need updating to use repository labels (if set): ```python logger.answer(f'{repository}: Listing archive {archive}') ```
Collaborator

That way, "old-style" configuration files would continue to work. (Which suggests repository labels should be optional.)

I checked the current schema.yaml and did this:

repositories:
                type: array
                items:
                    type: object
                    required:
                        - path
                    additionalProperties: false
                    properties:
                        path:
                            type: string
                            description: |
                                Path to local or remote repository (required). 
                                are expanded. Multiple repositories are backed up to
                                in sequence. Borg placeholders can be used. See the
                                output of "borg help placeholders" for details. See
                                ssh_command for SSH options like identity file or
                                port. If systemd service is used, then add local
                                repository paths in the systemd service file to the
                                ReadWritePaths list.                                
                            example:
                                - ssh://user@backupserver/./sourcehostname.borg
                                - ssh://user@backupserver/./{fqdn}
                                - /var/local/backups/local.borg
                        label:
                            type: string
                            description: |
                                Optional label for the repository.                                
                            example: backupserver

But this expects the repositories to be an array of objects instead of an array of strings.
I couldn't understand your discussion about "lists to dicts", here I should be getting a list of dicts like this right?

[{
	path: "x/y/z",
    	label: "some repo
}]

What should I convert this data structure to? Assuming earlier it used to be

["x/y/z"]

If the label does not need to be handled in normalize.py, I can convert the list of dicts(1) back to the list of strings(2), effectively ignoring it here and only handling it in the places where you mentioned matching/handling of a repository name takes place

> That way, "old-style" configuration files would continue to work. (Which suggests repository labels should be optional.) I checked the current `schema.yaml` and did this: ```yaml repositories: type: array items: type: object required: - path additionalProperties: false properties: path: type: string description: | Path to local or remote repository (required). are expanded. Multiple repositories are backed up to in sequence. Borg placeholders can be used. See the output of "borg help placeholders" for details. See ssh_command for SSH options like identity file or port. If systemd service is used, then add local repository paths in the systemd service file to the ReadWritePaths list. example: - ssh://user@backupserver/./sourcehostname.borg - ssh://user@backupserver/./{fqdn} - /var/local/backups/local.borg label: type: string description: | Optional label for the repository. example: backupserver ``` But this expects the repositories to be an array of objects instead of an array of strings. I couldn't understand your discussion about "lists to dicts", here I should be getting a list of dicts like this right? ```python [{ path: "x/y/z", label: "some repo }] ``` What should I convert this data structure to? Assuming earlier it used to be ```python ["x/y/z"] ``` If the label does not need to be handled in `normalize.py`, I can convert the list of dicts(1) back to the list of strings(2), effectively ignoring it here and only handling it in the places where you mentioned matching/handling of a repository name takes place
Owner

Your new schema and resulting list of dicts looks completely correct to me. I'm assuming that will be the new standard data structure for repositories going forward. So what I meant by converting "lists to dicts" is that if the old data structure, e.g. ["x/y/z"] (a list of strings), happens to be present in a configuration file, it needs to get converted to the new data structure (a list of dicts) before the schema is applied. That way all the borgmatic code can get updated to expect the new structure and can forget all about the old structure (outside of normalize.py).

To summarize, the general order of events is:

  1. Load configuration file into a data structure.
  2. Normalize it with normalize.py.
  3. Validate the normalized data structure with the configuration schema.
  4. Actually use the data structure!

This is all already in place today, and my suggested change is just to update normalize.py. And also of course the schema changes you've already made!

Please let me know if any of this doesn't make sense.

Your new schema and resulting list of dicts looks completely correct to me. I'm assuming that will be the new standard data structure for `repositories` going forward. So what I meant by converting "lists to dicts" is that if the *old* data structure, e.g. `["x/y/z"]` (a list of strings), happens to be present in a configuration file, it needs to get converted to the new data structure (a list of dicts) before the schema is applied. That way all the borgmatic code can get updated to expect the new structure and can forget all about the old structure (outside of `normalize.py`). To summarize, the general order of events is: 1. Load configuration file into a data structure. 2. Normalize it with `normalize.py`. 3. Validate the normalized data structure with the configuration schema. 4. Actually use the data structure! This is all already in place today, and my suggested change is just to update `normalize.py`. And also of course the schema changes you've already made! Please let me know if any of this doesn't make sense.
Owner

Released in borgmatic 1.7.10! Thanks to @diivi for doing this work!

Released in borgmatic 1.7.10! Thanks to @diivi for doing this work!
Author

I just tested this, and notice that a little part is missing.
Maybe not important, but --short doesn't use the label, it still uses the full path.

➜ sudo borgmatic list --short --repository vps
ssh://vps/data/zfs/backups/osz: Listing archives
osz-2023-03-31T09:43:25
osz-2023-04-02T09:18:42
osz-2023-04-07T20:56:28

But It should return

➜ sudo borgmatic list --short --repository vps
vps: Listing archives
osz-2023-03-31T09:43:25
osz-2023-04-02T09:18:42
osz-2023-04-07T20:56:28

That's the cherry at the top of that feature :P

I just tested this, and notice that a little part is missing. Maybe not important, but ``--short`` doesn't use the label, it still uses the full path. ``` ➜ sudo borgmatic list --short --repository vps ssh://vps/data/zfs/backups/osz: Listing archives osz-2023-03-31T09:43:25 osz-2023-04-02T09:18:42 osz-2023-04-07T20:56:28 ``` But It should return ``` ➜ sudo borgmatic list --short --repository vps vps: Listing archives osz-2023-03-31T09:43:25 osz-2023-04-02T09:18:42 osz-2023-04-07T20:56:28 ``` That's the cherry at the top of that feature :P
eoli3n reopened this issue 2023-05-15 19:03:21 +00:00
Owner

Makes sense! Thanks for bringing this to our attention.

Makes sense! Thanks for bringing this to our attention.
Owner

I did part of this for some of the high-level functions, but more work will be needed to change the log statements for the remainder of the code base.

I did part of this for some of the high-level functions, but more work will be needed to change the log statements for the remainder of the code base.
witten removed the
good first issue
label 2023-06-28 18:39:36 +00:00
diivi was assigned by witten 2023-08-24 21:57:46 +00:00
Collaborator

hey @witten, did you end up solving this? Sorry for the late response, my exam just ended.

Looks like

repository.get("label", repository["path"]) throughout the codebase is done to implement this?

hey @witten, did you end up solving this? Sorry for the late response, my exam just ended. Looks like `repository.get("label", repository["path"])` throughout the codebase is done to implement this?
Owner

Hey @diivi! Glad to hear you've gotten through your exams. You are correct, what you propose is most of the work remaining on this ticket. The other 90% though is passing through the full repository dict to everywhere in the code that needs it for this!

Hey @diivi! Glad to hear you've gotten through your exams. You are correct, what you propose is most of the work remaining on this ticket. The other 90% though is passing through the full `repository` dict to everywhere in the code that needs it for this!
Sign in to join this conversation.
No Milestone
No Assignees
3 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#635
No description provided.