Skip to content

add --stdin-from-command flag to backup command#4410

Merged
MichaelEischer merged 17 commits intorestic:masterfrom
Enrico204:restic-stdin-command
Oct 27, 2023
Merged

add --stdin-from-command flag to backup command#4410
MichaelEischer merged 17 commits intorestic:masterfrom
Enrico204:restic-stdin-command

Conversation

@Enrico204
Copy link
Copy Markdown
Contributor

@Enrico204 Enrico204 commented Jul 17, 2023

What does this PR change? What problem does it solve?

This pull request is a continuation of #4254.

This fixes #4251 by providing the requested --stdin-from-command flag to the restic backup command. It skips snapshot creation in case the given commands fails as determined by exec.Cmd.Wait() and returns the stderr of the given command as an error message back to the user.

I have not written any tests, nor documentation because I wanted to get some feedback about the path taken here wrt. upstream inclusion first. I am seeing various test failures in existing tests but these seem to be unrelated and might just occur because I'm building/testing the project within a container. Using these changes locally does look promising though:

$ ./restic backup --stdin-from-command --repo ./backup -- pg_dump -h foobar
enter password for repository:
repository 55e7d5a0 opened (version 2, compression level auto)
using parent snapshot cc6e1dec
error: read /stdin: no data read
Fatal: unable to save snapshot: pg_dump: error: connection to database "root" failed: could not translate host name "foobar" to address: No address associated with hostname

Was the change previously discussed in an issue or on the forum?

Closes #4251

Checklist

@Enrico204
Copy link
Copy Markdown
Contributor Author

Enrico204 commented Jul 17, 2023

I rebased the code to the latest master, and in a few days I will proceed to fix it based on changes requested in the old PR 👍

@rawtaz
Copy link
Copy Markdown
Contributor

rawtaz commented Aug 12, 2023

Is there other software that has this option name (--stdin-from-command)? It's quite long, feels like --stdin-command is more concise without losing any semantics.

@Enrico204
Copy link
Copy Markdown
Contributor Author

Is there other software that has this option name (--stdin-from-command)? It's quite long, feels like --stdin-command is more concise without losing any semantics.

Actually, content-from-command may be better, that is also the name it has in Borg backup. See #4254 (comment)

@rawtaz
Copy link
Copy Markdown
Contributor

rawtaz commented Aug 12, 2023

Nah, there's already two --stdin-* options, no point in deviating from that prefix.

@Enrico204 Enrico204 force-pushed the restic-stdin-command branch from 7135980 to f8fe0c6 Compare August 27, 2023 07:57
@Enrico204
Copy link
Copy Markdown
Contributor Author

@MichaelEischer I've implemented your suggestions from the old pull request. I implemented a new io.ReadCloser instead of a new fs.FS, calling cmd.Wait() on io.ReadCloser.Close(). The archiver is back to the original code.

I'm testing the code now :-)

@meise
Copy link
Copy Markdown

meise commented Aug 27, 2023

Thank you for continuing with this feature. I tested your branch and it still creates snapshots when subcommand exists with non zero:

$ restic-stdin-command/restic backup --stdin-from-command -- pg_dump -h foobar  
repository 12ba8696 opened (version 2, compression level auto)
using parent snapshot 75e9f4c7
subprocess pg_dump: pg_dump: error: could not translate host name "foobar" to address: Name or service not known
error: read /stdin: no data read

Files:           0 new,     0 changed,     0 unmodified
Dirs:            0 new,     0 changed,     0 unmodified
Added to the repository: 0 B   (0 B   stored)

processed 0 files, 0 B in 0:00
snapshot d044b2eb saved
Warning: at least one source file could not be read

$ echo $?
3
$ pg_dump -h foobar; echo $?
pg_dump: error: could not translate host name "foobar" to address: Name or service not known
1

@Enrico204
Copy link
Copy Markdown
Contributor Author

Thank you for continuing with this feature. I tested your branch and it still creates snapshots when subcommand exists with non zero:

$ restic-stdin-command/restic backup --stdin-from-command -- pg_dump -h foobar  
repository 12ba8696 opened (version 2, compression level auto)
using parent snapshot 75e9f4c7
subprocess pg_dump: pg_dump: error: could not translate host name "foobar" to address: Name or service not known
error: read /stdin: no data read

Files:           0 new,     0 changed,     0 unmodified
Dirs:            0 new,     0 changed,     0 unmodified
Added to the repository: 0 B   (0 B   stored)

processed 0 files, 0 B in 0:00
snapshot d044b2eb saved
Warning: at least one source file could not be read

$ echo $?
3
$ pg_dump -h foobar; echo $?
pg_dump: error: could not translate host name "foobar" to address: Name or service not known
1

Uh, I was about to do the same test :-D

Thanks for your report, I'll investigate and fix 👍

@Enrico204
Copy link
Copy Markdown
Contributor Author

The problem was that the error returned in file reading or closing was logged, but the snapshot itself was continuing unaffected (because the logic assumed that an error while reading one file should not abort the snapshot).

The ReadCloserCommand now returns a "fatal" error, and the error is checked in the cmd_backup.go file: if it is "fatal", the snapshot is aborted. Otherwise, the behavior is the same as before: log the error, and exit with code 3 after completing the snapshot.

What do you think?

@meise
Copy link
Copy Markdown

meise commented Aug 28, 2023

What do you think?

I'm not sure about the command terminated with no output fatal error. The current behaviour in stdin mode is to log no data read and exit with status code 3 when reading no data.

I like your current implementation more, because having a snapshot with no data makes no sense for me. But it might be behaving differently than we have in existing implementations.

@Enrico204
Copy link
Copy Markdown
Contributor Author

What do you think?

I'm not sure about the command terminated with no output fatal error. The current behaviour in stdin mode is to log no data read and exit with status code 3 when reading no data.

I like your current implementation more, because having a snapshot with no data makes no sense for me. But it might be behaving differently than we have in existing implementations.

You are right, it is a different behavior. I assumed that this is expected, given that we are explicitly asking for monitoring the command.

On second thought, the best way is to check the command exit code also in ReadCloserCommand.Read(), and return a fatal error only when there is an EOF and the exit code is non-zero. By doing so, if the command exits with 0 and there is no output, the snapshot is created with a warning (which is the current behavior for files and stdin), while the snapshot is not created if the exit code is non-zero (which is expected).

I'll modify the code asap :-)

@Enrico204
Copy link
Copy Markdown
Contributor Author

Ok, now the code should stop the snapshot creation by looking only at the exit code. If there is no output, the snapshot is still created with a warning (and exit code 3), which is the same behavior that other snapshot options have (--stdin, but also normal file backup). Let me know if there is something we can improve :-)

@meise
Copy link
Copy Markdown

meise commented Aug 29, 2023

Works for me. Very good!

I think there should now be some feedback on the code itself.

@Enrico204 Enrico204 marked this pull request as ready for review August 29, 2023 12:00
@Enrico204
Copy link
Copy Markdown
Contributor Author

Works for me. Very good!

I think there should now be some feedback on the code itself.

Agreed, thanks for feedbacks and tests :-)

@Enrico204
Copy link
Copy Markdown
Contributor Author

I rebased the branch to the latest master :-)

@MichaelEischer MichaelEischer force-pushed the restic-stdin-command branch 2 times, most recently from 87bae0d to a7c1cae Compare October 1, 2023 14:58
@MichaelEischer
Copy link
Copy Markdown
Member

@Enrico204 Thanks for finishing the PR, and sorry for the late feedback. I've somehow missed that the review comments have been addressed in the meantime.

I've reworked the code a bit: the command startup is now handled by fs.CommandReader (that's the new name for the helper in fs). Instead of using canceling the backup indirectly using a context, arch.Error now just returns an error if it is Fatal. This also allows for a nicer error message.

@Enrico204
Copy link
Copy Markdown
Contributor Author

No problem at all :-)

I will compile this branch and I will test it as soon as possible!

@Enrico204 Enrico204 force-pushed the restic-stdin-command branch 2 times, most recently from a7c1cae to 2053832 Compare October 16, 2023 07:38
@Enrico204
Copy link
Copy Markdown
Contributor Author

I am testing the code since a few weeks: so far, no issues :-)

This new flag is added to the backup subcommand in order to allow restic to control the execution of a command and determine whether to save a snapshot if the given command succeeds.

Signed-off-by: Sebastian Hoß <seb@xn--ho-hia.de>
In order to run with --stdin-from-command we need to short-circuit some functions similar to how it is handled for the --stdin flag. The only difference here is that --stdin-from-command actually expects that len(args) should be greater 0 whereas --stdin does not expect any args at all.

Signed-off-by: Sebastian Hoß <seb@xn--ho-hia.de>
It acts similar to --stdin but reads its data from the stdout of the given command instead of os.Stdin.

Signed-off-by: Sebastian Hoß <seb@xn--ho-hia.de>
sebhoss and others added 14 commits October 27, 2023 23:58
In order to determine whether to save a snapshot, we need to capture the exit code returned by a command. In order to provide a nice error message, we supply stderr as well.

Signed-off-by: Sebastian Hoß <seb@xn--ho-hia.de>
Return with an error containing the stderr of the given command in case it fails. No new snapshot will be created and future prune operations on the repository will remove the unreferenced data.

Signed-off-by: Sebastian Hoß <seb@xn--ho-hia.de>
The code has been refactored so that the archiver is back to the original code, and the stderr is handled using a go routine to avoid deadlock.
…de 0 from command

The behavior of the new option should reflect the behavior of normal backups: when the command exit code is zero and there is no output in the stdout, emit a warning but create the snapshot. This commit fixes the integration tests and the ReadCloserCommand struct.
Copy link
Copy Markdown
Member

@MichaelEischer MichaelEischer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for your work on the PR!

I've rebased the commits one more time before merging it.

@MichaelEischer MichaelEischer added this pull request to the merge queue Oct 27, 2023
Merged via the queue into restic:master with commit 42ab3ea Oct 27, 2023
mushrowan added a commit to mushrowan/nixpkgs that referenced this pull request Aug 21, 2025
Add module support for --stdin-from-command flag, which was added to
restic in restic/restic#4410. I also made a few
very small changes here and there in the nix code to make it look a
little neater in my opinion.

I could potentially add support for the --stdin flag too, but this would
require prepending the restic command with an external command and a
pipe, which seems a bit messy - and the restic documentation says to
prefer --stdin-from-command over --stdin anyway.

I could add an option for --stdin-filename, but I feel that this would
be better for users to do in extraBackupArgs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Backup flag to execute commands with restic, read content from standard input and consider return status

5 participants