diff --git a/NEWS b/NEWS
index ba42cac28..12c271826 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
1.5.10.dev0
+ * #350: Fix traceback when a configuration directory is non-readable due to directory permissions.
* Clarify documentation on configuration overrides, specifically the portion about list syntax:
- http://localhost:8080/docs/how-to/make-per-application-backups/#configuration-overrides
+ http://torsion.org/borgmatic/docs/how-to/make-per-application-backups/#configuration-overrides
+ * Clarify documentation overview of monitoring options:
+ http://torsion.org/borgmatic/docs/how-to/monitor-your-backups/
1.5.9
* #300: Add "borgmatic export-tar" action to export an archive to a tar-formatted file or stream.
diff --git a/README.md b/README.md
index 18028d18a..1f7c3a93e 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ location:
# Paths of local or remote repositories to backup to.
repositories:
- - 1234@usw-s001.rsync.net:backups.borg
- k8pDxu32@k8pDxu32.repo.borgbase.com:repo
+ - 1234@usw-s001.rsync.net:backups.borg
- /var/lib/backups/local.borg
retention:
@@ -66,9 +66,9 @@ borgmatic is powered by [Borg Backup](https://www.borgbackup.org/).
-
-
+
+
## How-to guides
@@ -101,8 +101,8 @@ services helps support borgmatic development and hosting. (These are referral
links, but without any tracking scripts or cookies.)
- - rsync.net: Cloud Storage provider with full support for borg and any other SSH/SFTP tool
- BorgBase: Borg hosting service with support for monitoring, 2FA, and append-only repos
+ - rsync.net: Cloud Storage provider with full support for borg and any other SSH/SFTP tool
## Support and contributing
diff --git a/borgmatic/config/collect.py b/borgmatic/config/collect.py
index 97c941062..a13472ee4 100644
--- a/borgmatic/config/collect.py
+++ b/borgmatic/config/collect.py
@@ -44,6 +44,9 @@ def collect_config_filenames(config_paths):
yield path
continue
+ if not os.access(path, os.R_OK):
+ continue
+
for filename in sorted(os.listdir(path)):
full_filename = os.path.join(path, filename)
matching_filetype = full_filename.endswith('.yaml') or full_filename.endswith('.yml')
diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml
index 8637153a6..9e1670437 100644
--- a/borgmatic/config/schema.yaml
+++ b/borgmatic/config/schema.yaml
@@ -123,7 +123,7 @@ map:
patterns" for more details.
example:
- '*.pyc'
- - ~/*/.cache
+ - /home/*/.cache
- /etc/ssl
exclude_from:
seq:
@@ -522,6 +522,26 @@ map:
"check" action or an associated before/after hook.
example:
- echo "Error during prune/create/check."
+ before_everything:
+ seq:
+ - type: str
+ desc: |
+ List of one or more shell commands or scripts to execute
+ before running all actions (if one of them is "create").
+ These are collected from all configuration files and then
+ run once before all of them (prior to all actions).
+ example:
+ - echo "Starting actions."
+ after_everything:
+ seq:
+ - type: str
+ desc: |
+ List of one or more shell commands or scripts to execute
+ after running all actions (if one of them is "create").
+ These are collected from all configuration files and then
+ run once after all of them (after any action).
+ example:
+ - echo "Completed actions."
postgresql_databases:
seq:
- map:
@@ -709,26 +729,6 @@ map:
documentation for details.
example:
https://cronhub.io/start/1f5e3410-254c-11e8-b61d-55875966d01
- before_everything:
- seq:
- - type: str
- desc: |
- List of one or more shell commands or scripts to execute
- before running all actions (if one of them is "create").
- These are collected from all configuration files and then
- run once before all of them (prior to all actions).
- example:
- - echo "Starting actions."
- after_everything:
- seq:
- - type: str
- desc: |
- List of one or more shell commands or scripts to execute
- after running all actions (if one of them is "create").
- These are collected from all configuration files and then
- run once before all of them (prior to all actions).
- example:
- - echo "Completed actions."
umask:
type: scalar
desc: |
diff --git a/docs/how-to/make-backups-redundant.md b/docs/how-to/make-backups-redundant.md
index cb7551344..b001e32da 100644
--- a/docs/how-to/make-backups-redundant.md
+++ b/docs/how-to/make-backups-redundant.md
@@ -16,8 +16,8 @@ location:
# Paths of local or remote repositories to backup to.
repositories:
- - 1234@usw-s001.rsync.net:backups.borg
- k8pDxu32@k8pDxu32.repo.borgbase.com:repo
+ - 1234@usw-s001.rsync.net:backups.borg
- /var/lib/backups/local.borg
```
@@ -28,8 +28,8 @@ your source directories.
Here's a way of visualizing what borgmatic does with the above configuration:
-1. Backup `/home` and `/etc` to `1234@usw-s001.rsync.net:backups.borg`
2. Backup `/home` and `/etc` to `k8pDxu32@k8pDxu32.repo.borgbase.com:repo`
+1. Backup `/home` and `/etc` to `1234@usw-s001.rsync.net:backups.borg`
3. Backup `/home` and `/etc` to `/var/lib/backups/local.borg`
This gives you redundancy of your data across repositories and even
diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md
index d53cd63dc..66caae19f 100644
--- a/docs/how-to/monitor-your-backups.md
+++ b/docs/how-to/monitor-your-backups.md
@@ -10,48 +10,68 @@ and alerting comes in.
There are several different ways you can monitor your backups and find out
whether they're succeeding. Which of these you choose to do is up to you and
-your particular infrastructure:
+your particular infrastructure.
-1. **Job runner alerts**: The easiest place to start is with failure alerts
-from the [scheduled job
-runner](https://torsion.org/borgmatic/docs/how-to/set-up-backups/#autopilot) (cron,
-systemd, etc.) that's running borgmatic. But note that if the job doesn't even
-get scheduled (e.g. due to the job runner not running), you probably won't get
-an alert at all! Still, this is a decent first line of defense, especially
-when combined with some of the other approaches below.
-2. **borgmatic error hooks**: The `on_error` hook allows you to run an arbitrary
-command or script when borgmatic itself encounters an error running your
-backups. So for instance, you can run a script to send yourself a text message
-alert. But note that if borgmatic doesn't actually run, this alert won't fire.
-See [error
+### Job runner alerts
+
+The easiest place to start is with failure alerts from the [scheduled job
+runner](https://torsion.org/borgmatic/docs/how-to/set-up-backups/#autopilot)
+(cron, systemd, etc.) that's running borgmatic. But note that if the job
+doesn't even get scheduled (e.g. due to the job runner not running), you
+probably won't get an alert at all! Still, this is a decent first line of
+defense, especially when combined with some of the other approaches below.
+
+### Commands run on error
+
+The `on_error` hook allows you to run an arbitrary command or script when
+borgmatic itself encounters an error running your backups. So for instance,
+you can run a script to send yourself a text message alert. But note that if
+borgmatic doesn't actually run, this alert won't fire. See [error
hooks](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#error-hooks)
below for how to configure this.
-4. **borgmatic monitoring hooks**: This feature integrates with monitoring
- services like [Healthchecks](https://healthchecks.io/),
-[Cronitor](https://cronitor.io), [Cronhub](https://cronhub.io), and
-[PagerDuty](https://www.pagerduty.com/) and pings these services whenever
-borgmatic runs. That way, you'll receive an alert when something goes wrong or
-(for certain hooks) the service doesn't hear from borgmatic for a configured
-interval. See [Healthchecks
-hook](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#healthchecks-hook), [Cronitor
-hook](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#cronitor-hook), [Cronhub
-hook](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#cronhub-hook), and
-[PagerDuty hook](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#pagerduty-hook)
+
+### Third-party monitoring services
+
+borgmatic integrates with monitoring services like
+[Healthchecks](https://healthchecks.io/), [Cronitor](https://cronitor.io),
+[Cronhub](https://cronhub.io), and [PagerDuty](https://www.pagerduty.com/) and
+pings these services whenever borgmatic runs. That way, you'll receive an
+alert when something goes wrong or (for certain hooks) the service doesn't
+hear from borgmatic for a configured interval. See [Healthchecks
+hook](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#healthchecks-hook),
+[Cronitor
+hook](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#cronitor-hook),
+[Cronhub
+hook](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#cronhub-hook),
+and [PagerDuty
+hook](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#pagerduty-hook)
below for how to configure this.
-3. **Third-party monitoring software**: You can use traditional monitoring
-software to consume borgmatic JSON output and track when the last
-successful backup occurred. See [scripting
+
+While these services offer different features, you probably only need to use
+one of them at most.
+
+### Third-party monitoring software
+
+You can use traditional monitoring software to consume borgmatic JSON output
+and track when the last successful backup occurred. See [scripting
borgmatic](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#scripting-borgmatic)
-and [related software](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#related-software)
+and [related
+software](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#related-software)
below for how to configure this.
-5. **Borg hosting providers**: Most [Borg hosting
+
+### Borg hosting providers
+
+Most [Borg hosting
providers](https://torsion.org/borgmatic/#hosting-providers) include
monitoring and alerting as part of their offering. This gives you a dashboard
to check on all of your backups, and can alert you if the service doesn't hear
from borgmatic for a configured interval.
-6. **borgmatic consistency checks**: While not strictly part of monitoring, if you
-really want confidence that your backups are not only running but are
-restorable as well, you can configure particular [consistency
+
+### Consistency checks
+
+While not strictly part of monitoring, if you really want confidence that your
+backups are not only running but are restorable as well, you can configure
+particular [consistency
checks](https://torsion.org/borgmatic/docs/how-to/deal-with-very-large-backups/#consistency-check-configuration)
or even script full [extract
tests](https://torsion.org/borgmatic/docs/how-to/extract-a-backup/).
diff --git a/docs/how-to/set-up-backups.md b/docs/how-to/set-up-backups.md
index fbe347b7d..a3bf1b78f 100644
--- a/docs/how-to/set-up-backups.md
+++ b/docs/how-to/set-up-backups.md
@@ -96,8 +96,8 @@ services helps support borgmatic development and hosting. (These are referral
links, but without any tracking scripts or cookies.)
- - rsync.net: Cloud Storage provider with full support for borg and any other SSH/SFTP tool
- BorgBase: Borg hosting service with support for monitoring, 2FA, and append-only repos
+ - rsync.net: Cloud Storage provider with full support for borg and any other SSH/SFTP tool
## Configuration
@@ -135,9 +135,8 @@ configuration](https://torsion.org/borgmatic/docs/how-to/upgrade/#upgrading-your
### Encryption
-Note that if you plan to run borgmatic on a schedule with cron, and you
-encrypt your Borg repository with a passphrase instead of a key file, you'll
-either need to set the borgmatic `encryption_passphrase` configuration
+If you encrypt your Borg repository with a passphrase instead of a key file,
+you'll either need to set the borgmatic `encryption_passphrase` configuration
variable or set the `BORG_PASSPHRASE` environment variable. See the
[repository encryption
section](https://borgbackup.readthedocs.io/en/stable/quickstart.html#repository-encryption)
diff --git a/tests/unit/config/test_collect.py b/tests/unit/config/test_collect.py
index 4c4420a47..5bab1ae0f 100644
--- a/tests/unit/config/test_collect.py
+++ b/tests/unit/config/test_collect.py
@@ -45,6 +45,7 @@ def test_collect_config_filenames_collects_yml_file_endings():
mock_path.should_receive('isdir').with_args('config.yaml').and_return(False)
mock_path.should_receive('isdir').with_args('/etc/borgmatic.d').and_return(True)
mock_path.should_receive('isdir').with_args('/etc/borgmatic.d/foo.yml').and_return(False)
+ flexmock(module.os).should_receive('access').and_return(True)
flexmock(module.os).should_receive('listdir')
flexmock(sys.modules['builtins']).should_receive('sorted').and_return(['foo.yml'])
@@ -62,6 +63,7 @@ def test_collect_config_filenames_collects_files_from_given_directories_and_igno
mock_path.should_receive('isdir').with_args('/etc/borgmatic.d/foo.yaml').and_return(False)
mock_path.should_receive('isdir').with_args('/etc/borgmatic.d/bar').and_return(True)
mock_path.should_receive('isdir').with_args('/etc/borgmatic.d/baz.yaml').and_return(False)
+ flexmock(module.os).should_receive('access').and_return(True)
flexmock(module.os).should_receive('listdir')
flexmock(sys.modules['builtins']).should_receive('sorted').and_return(
['foo.yaml', 'bar', 'baz.yaml']
@@ -84,6 +86,7 @@ def test_collect_config_filenames_collects_files_from_given_directories_and_igno
mock_path.should_receive('isdir').with_args('/etc/borgmatic.d/foo.yaml').and_return(False)
mock_path.should_receive('isdir').with_args('/etc/borgmatic.d/bar.yaml~').and_return(False)
mock_path.should_receive('isdir').with_args('/etc/borgmatic.d/baz.txt').and_return(False)
+ flexmock(module.os).should_receive('access').and_return(True)
flexmock(module.os).should_receive('listdir')
flexmock(sys.modules['builtins']).should_receive('sorted').and_return(
['foo.yaml', 'bar.yaml~', 'baz.txt']
@@ -94,6 +97,21 @@ def test_collect_config_filenames_collects_files_from_given_directories_and_igno
assert config_filenames == ('/etc/borgmatic.d/foo.yaml',)
+def test_collect_config_filenames_skips_permission_denied_directories():
+ config_paths = ('config.yaml', '/etc/borgmatic.d')
+ mock_path = flexmock(module.os.path)
+ mock_path.should_receive('exists').and_return(True)
+ mock_path.should_receive('isdir').with_args('config.yaml').and_return(False)
+ mock_path.should_receive('isdir').with_args('/etc/borgmatic.d').and_return(True)
+ flexmock(module.os).should_receive('access').and_return(False)
+ flexmock(module.os).should_receive('listdir')
+ flexmock(sys.modules['builtins']).should_receive('sorted').and_return(['config.yaml'])
+
+ config_filenames = tuple(module.collect_config_filenames(config_paths))
+
+ assert config_filenames == ('config.yaml',)
+
+
def test_collect_config_filenames_skips_etc_borgmatic_config_dot_yaml_if_it_does_not_exist():
config_paths = ('config.yaml', '/etc/borgmatic/config.yaml')
mock_path = flexmock(module.os.path)