Skip to content

Commit

Permalink
Change skipped backups to be a "first class" citizen
Browse files Browse the repository at this point in the history
Skipped backups were treated as failed backups with lip gloss (a
special E-Mail message). Now they are handled with a notifier,
like other backups. That way, user controls disposition of the
message (including not sending the message at all).
  • Loading branch information
jeffaco committed Sep 22, 2018
1 parent a43771e commit af141a5
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 32 deletions.
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,19 +159,21 @@ The following fields are checked in the global configuration file:

##### Notifications

`Duplicacy-util` supports notifying you when backups succeed, fail and start. Unless
you're planning to only be running `dupliacy-util` interactively, it's strongly
recommended to configure notifications.
`Duplicacy-util` supports notifying you when backups start, are skipped (if
already running), succeed, and fail. Unless you're planning to only be running
`dupliacy-util` interactively, it's strongly recommended to configure
notifications.

For now only email notifications are supported, but more notification channels
will be implemented. The following config snippet shows how to subscribe to
specific notifications:

```
notifications:
onStart: []
onSkip: ['email']
onSuccess: ['email']
onFailure: ['email']
onStart: []
```

##### Email notifications
Expand Down Expand Up @@ -199,9 +201,10 @@ Here is an example how to setup email notifications:

```
notifications:
onStart: []
onSkip: ['email']
onSuccess: ['email']
onFailure: ['email']
onStart: []
email:
fromAddress: "Donald Duck <[email protected]>"
Expand All @@ -216,10 +219,10 @@ E-Mail subjects from `duplicacy-util` will be of the following format:

| Notification | Subject Line |
| --------------- | -------------------------------------------------------------------------- |
| Start | `duplicacy-util: Backup started for configuration <config-name>` |
| Skip | `duplicacy-util: Backup results for configuration <config-name> (skipped)` |
| Success | `duplicacy-util: Backup results for configuration <config-name> (success)` |
| Failure | `duplicacy-util: Backup results for configuration <config-name> (FAILURE)` |
| Already running | `duplicacy-util: Backup results for configuration <config-name> (skipped)` |
| Start | `duplicacy-util: Backup started for configuration <config-name>` |

You can filter on the subject line to direct the E-Mail appropriately
to a folder of your choice.
Expand Down Expand Up @@ -443,8 +446,8 @@ Exit codes from `duplicacy-util` are as follows:
| --------------- | ----------------------------------------------- |
| 0 | Success |
| 1-2 | Command line errors |
| 200-201 | Run skipped due to existing job already running |
| 500 | Operation from `duplicacy` command failed |
| 6200 | Run skipped due to existing job already running |

In the event of an error, a notification will be sent with details of the
error. Note that 200-201 operations are not considered fatal from an notification
Expand Down Expand Up @@ -547,7 +550,7 @@ function duplicacy_utils() {
// Naming conventions with duplicacy-util are formatted like:
// "duplicacy-util: Backup results for configuration test (success)" (for successful backups), or
// "duplicacy-util: Backup results for configuration test (FAILURE)" (for failed backups)
// Check to see that it start with "duplicacy-util..." and ends with " (Success)", and if so, count
// Check to see that it starts with "duplicacy-util..." and ends with " (Success)", and if so, count
// the message.
for (var i = 0; i < threads.length; i++) {
Expand Down
34 changes: 23 additions & 11 deletions configGlobal.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ var (
globalLogFileCount int

// Notification publishers
onStartNotifiers []Notifier
onSkipNotifiers []Notifier
onSuccessNotifiers []Notifier
onFailureNotifiers []Notifier
onStartNotifiers []Notifier
)

// loadGlobalConfig reads in config file and ENV variables if set.
Expand Down Expand Up @@ -98,9 +99,10 @@ func setGlobalConfigVariables(storageDir string, cfgFile string) error {
globalLockDir = storageDir
globalLogDir = filepath.Join(storageDir, "log")
globalLogFileCount = 5
onStartNotifiers = []Notifier{}
onSkipNotifiers = []Notifier{}
onSuccessNotifiers = []Notifier{}
onFailureNotifiers = []Notifier{}
onStartNotifiers = []Notifier{}

// If a config file is found, read it in.
if err := viper.ReadInConfig(); err != nil {
Expand Down Expand Up @@ -143,31 +145,41 @@ func setGlobalConfigVariables(storageDir string, cfgFile string) error {
if err != nil {
return err
}

onSkipNotifiers = append(onSkipNotifiers, defaultNotifier)
onSuccessNotifiers = append(onSuccessNotifiers, defaultNotifier)
onFailureNotifiers = append(onFailureNotifiers, defaultNotifier)
return nil
}

var err error
// Configure notifiers for onSucces notification
if configSlice := viper.GetStringSlice("notifications.onSuccess"); len(configSlice) > 0 {
onSuccessNotifiers, err = configureNotificationChannel(configSlice, "onSuccess")
// Configure notifiers for onStart notification
if configSlice := viper.GetStringSlice("notifications.onStart"); len(configSlice) > 0 {
onStartNotifiers, err = configureNotificationChannel(configSlice, "onStart")
if err != nil {
return err
}
}

// Configure notifiers for onFailure notification
if configSlice := viper.GetStringSlice("notifications.onFailure"); len(configSlice) > 0 {
onFailureNotifiers, err = configureNotificationChannel(configSlice, "onFailure")
// Configure notifiers for onSkip notification
if configSlice := viper.GetStringSlice("notifications.onSkip"); len(configSlice) > 0 {
onSkipNotifiers, err = configureNotificationChannel(configSlice, "onSkip")
if err != nil {
return err
}
}

// Configure notifiers for onStart notification
if configSlice := viper.GetStringSlice("notifications.onStart"); len(configSlice) > 0 {
onStartNotifiers, err = configureNotificationChannel(configSlice, "onStart")
// Configure notifiers for onSuccess notification
if configSlice := viper.GetStringSlice("notifications.onSuccess"); len(configSlice) > 0 {
onSuccessNotifiers, err = configureNotificationChannel(configSlice, "onSuccess")
if err != nil {
return err
}
}

// Configure notifiers for onFailure notification
if configSlice := viper.GetStringSlice("notifications.onFailure"); len(configSlice) > 0 {
onFailureNotifiers, err = configureNotificationChannel(configSlice, "onFailure")
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions duplicacy-util.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,12 @@ func main() {
case 6200:
// Notify that the backup process has been skipped
logError(nil, fmt.Sprintf("Warning: %s", err))
notifyOfFailure(fmt.Sprintf("duplicacy-util: Backup results for configuration %s (skipped)", cmdConfig))
notifyOfSkip()

default:
// Notify that the backup process has failed
logError(nil, fmt.Sprintf("Error: %s", err))
notifyOfFailure("")
notifyOfFailure()
}
}

Expand Down
13 changes: 8 additions & 5 deletions emailNotifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,15 @@ func (notifier EmailNotifier) NotifyOfSuccess() error {
return notifier.email(subject, htmlGenerateBody(), mailBody)
}

// NotifyOfFailure is triggered when a failure occurred during backup
func (notifier EmailNotifier) NotifyOfFailure(subject string) error {
if len(subject) == 0 {
subject = fmt.Sprintf("duplicacy-util: Backup results for configuration %s (FAILURE)", cmdConfig)
}
// NotifyOfSkip is triggered when a backup is skipped (if already running)
func (notifier EmailNotifier) NotifyOfSkip() error {
subject := fmt.Sprintf("duplicacy-util: Backup results for configuration %s (skipped)", cmdConfig)
return notifier.email(subject, htmlGenerateBody(), mailBody)
}

// NotifyOfFailure is triggered when a failure occurred during backup
func (notifier EmailNotifier) NotifyOfFailure() error {
subject := fmt.Sprintf("duplicacy-util: Backup results for configuration %s (FAILURE)", cmdConfig)
return notifier.email(subject, htmlGenerateBody(), mailBody)
}

Expand Down
3 changes: 2 additions & 1 deletion notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
// Notifier interface exposes all notification triggers
type Notifier interface {
NotifyOfStart() error
NotifyOfSkip() error
NotifyOfSuccess() error
NotifyOfFailure(string) error
NotifyOfFailure() error
}
13 changes: 10 additions & 3 deletions notify.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ func notifyOfStart() {
}
}

func notifyOfSkip() {
for _, notifier := range onSkipNotifiers {
_ = notifier.NotifyOfSkip()
}
}

func notifyOfSuccess() {
for _, notifier := range onSuccessNotifiers {
_ = notifier.NotifyOfSuccess()
Expand All @@ -19,9 +25,9 @@ func notifyOfSuccess() {
// notifyOfFailure takes a subject argument:
// If zero length, subject will be chosen by default
// If specified, will override the default subject
func notifyOfFailure(subject string) {
func notifyOfFailure() {
for _, notifier := range onFailureNotifiers {
_ = notifier.NotifyOfFailure(subject)
_ = notifier.NotifyOfFailure()
}
}

Expand Down Expand Up @@ -74,8 +80,9 @@ func testNotifications() error {
}

notifyOfStart()
notifyOfSkip()
notifyOfSuccess()
notifyOfFailure("")
notifyOfFailure()

return nil
}
3 changes: 2 additions & 1 deletion test/assets/globalConfigs/fullValidConfig.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
notifications:
onStart: []
onSkipped: ['email']
onSuccess: ['email']
onFailure: ['email']
onStart: []

email:
fromAddress: "Donald Duck <[email protected]>"
Expand Down

0 comments on commit af141a5

Please sign in to comment.