Skip to content

Commit

Permalink
Notification (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
liweiyi88 authored Mar 1, 2023
1 parent 27dcefd commit 936b8e1
Show file tree
Hide file tree
Showing 19 changed files with 808 additions and 464 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.18, 1.19]
go-version: [1.19, 1.20.1]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down
77 changes: 41 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,29 @@

Onedump is a database dump and backup tool. It can dump different databases to different storages with a simple configuration file or cli commands.

## Features
* Database backup from different sources to different destinations.
* Load configuration from S3 bucket.
* Compression (use `job.gzip: true` to enable compression).
* Unique filename (use `job.unique: true` to enable unique filename).
* Slack notification.
* Maintained docker image.

### Supported data sources
| Driver | Status |
| --- | --- |
| MySQL | ✅ Suported |
| PostgreSQL | ✅ Suported |

### Supported destinations
| Storage | Status |
| --- | --- |
| Local | ✅ Suported |
| S3 | ✅ Suported |
| Googl Drive | ✅ Supported |
| Dropbox | ✅ Supported |


## Installation
We build and publish both binaries and docker images via the release process.

Expand All @@ -24,7 +47,7 @@ $ onedump
### Docker image
If you want to run onedump in Kubernetes, ECS or any other container environment. We also offer the docker images for you. Images are available in [docker hub](https://hub.docker.com/r/julianli/onedump/tags).

*Note: Although we maintain both arm64 and amd64 docker image, usually what you need is the `amd64` image in your prod linux machine. For example: `julianli/onedump:v0.2.0-amd64`*
*Note: Although we maintain both arm64 and amd64 docker image, usually what you need is the `amd64` image in your prod linux machine. For example: `julianli/onedump:v1.0.0-amd64`*

## Prerequisites
Behind the scenes, `onedump` uses `mysqldump` and `pg_dump` for database dump. If you use onedump binary in a single machine, make sure you install `mysql-client` or `postgresql-client` as required. If you use the docker image maintained by us, you will have these tools by default. Besides, build the docker image yourself if you need more customisation.
Expand Down Expand Up @@ -116,6 +139,22 @@ jobs:
secret-access-key: awssecret
```

#### Slack notification

```
notifier:
slack:
- incomingwebhook: https://hooks.slack.com/services/A0B8A11N4N/...
jobs:
- name: local-dump
dbdriver: mysql
dbdsn: root@tcp(127.0.0.1)/test_local
gzip: true
storage:
local:
- path: /Users/jack/Desktop/mydb.sql
```

### Recommendation

Loading the configuration from a local directory is handy when you have control of a machine and want to run `onedump` as a normal cli command. However, you are responsible to make sure the config file is stored securely in that machine or maybe you are responsible for encryption at rest yourself.
Expand Down Expand Up @@ -176,38 +215,4 @@ jobs:
region: ap-southeast-2
access-key-id: MYKEY...
secret-access-key: AWSSECRET..
```

### Extra features
#### Compression
Compress your DB content in gzip format. Set the `gzip` config to `true` (it is `false` by default)
```
jobs:
- name: local-dump
gzip: true
# the rest of config...
```
#### Unique filename
If you want to keep previous DB dump files in the storage. Set the `unique` config to `true` (it is `false` by default). For example:
```
jobs:
- name: local-dump
unique: true
# the rest of config...
```
`onedump` will add a unique prefix to the dump file, by doing so, it won't overwrite previous dump files.


## Database drivers
| Driver | Status |
| --- | --- |
| MySQL | ✅ Suported |
| PostgreSQL | ✅ Suported |

## Storages
| Storage | Status |
| --- | --- |
| Local | ✅ Suported |
| S3 | ✅ Suported |
| Googl Drive | ✅ Supported |
| Dropbox | ✅ Supported |
```
31 changes: 2 additions & 29 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ package cmd
import (
"fmt"
"os"
"sync"

"github.com/hashicorp/go-multierror"
"github.com/liweiyi88/onedump/config"
"github.com/liweiyi88/onedump/dumper"
"github.com/liweiyi88/onedump/handler"
"github.com/liweiyi88/onedump/storage/s3"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -41,32 +39,7 @@ var rootCmd = &cobra.Command{
return fmt.Errorf("no job is defined in the file %s", file)
}

resultCh := make(chan *config.JobResult)

for _, job := range oneDump.Jobs {
go func(job *config.Job, resultCh chan *config.JobResult) {
dumper := dumper.NewDumper(job)
resultCh <- dumper.Dump()
}(job, resultCh)
}

var jobErr error
var wg sync.WaitGroup
wg.Add(numberOfJobs)
go func(resultCh chan *config.JobResult) {
for result := range resultCh {
if result.Error != nil {
jobErr = multierror.Append(jobErr, result.Error)
}
fmt.Println(result.String())
wg.Done()
}
}(resultCh)

wg.Wait()
close(resultCh)

return jobErr
return handler.NewDumpHandler(&oneDump).Do()
},
}

Expand Down
82 changes: 4 additions & 78 deletions config/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,10 @@ package config

import (
"errors"
"fmt"
"io"
"reflect"
"strings"
"time"

"github.com/hashicorp/go-multierror"
"github.com/liweiyi88/onedump/driver"
"github.com/liweiyi88/onedump/dumper/runner"
"github.com/liweiyi88/onedump/notifier/slack"
"github.com/liweiyi88/onedump/storage/dropbox"
"github.com/liweiyi88/onedump/storage/gdrive"
"github.com/liweiyi88/onedump/storage/local"
Expand All @@ -23,11 +18,10 @@ var (
ErrMissingDBDriver = errors.New("databse driver is required")
)

type Storage interface {
Save(reader io.Reader, gzip bool, unique bool) error
}

type Dump struct {
Notifier struct {
Slack []*slack.Slack `yaml:"slack"`
} `yaml:"notifier"`
Jobs []*Job `yaml:"jobs"`
}

Expand All @@ -44,20 +38,6 @@ func (dump *Dump) Validate() error {
return errs
}

type JobResult struct {
Error error
JobName string
Elapsed time.Duration
}

func (result *JobResult) String() string {
if result.Error != nil {
return fmt.Sprintf("Job: %s failed, it took %s with error: %v", result.JobName, result.Elapsed, result.Error)
}

return fmt.Sprintf("Job: %s succeeded, it took %v", result.JobName, result.Elapsed)
}

type Job struct {
Name string `yaml:"name"`
DBDriver string `yaml:"dbdriver"`
Expand Down Expand Up @@ -145,57 +125,3 @@ func (job *Job) ViaSsh() bool {

return false
}

func (job *Job) GetRunner() (runner.Runner, error) {
driver, err := job.getDBDriver()
if err != nil {
return nil, fmt.Errorf("failed to get db driver %v", err)
}

if job.ViaSsh() {
return runner.NewSshRunner(job.SshHost, job.SshKey, job.SshUser, job.Gzip, driver), nil
} else {
return runner.NewExecRunner(job.Gzip, driver), nil
}
}

func (job *Job) getDBDriver() (driver.Driver, error) {
switch job.DBDriver {
case "mysql":
driver, err := driver.NewMysqlDriver(job.DBDsn, job.DumpOptions, job.ViaSsh())
if err != nil {
return nil, err
}

return driver, nil
case "postgresql":
driver, err := driver.NewPostgreSqlDriver(job.DBDsn, job.DumpOptions, job.ViaSsh())
if err != nil {
return nil, err
}

return driver, nil
default:
return nil, fmt.Errorf("%s is not a supported database driver", job.DBDriver)
}
}

func (job *Job) GetStorages() []Storage {
var storages []Storage

v := reflect.ValueOf(job.Storage)
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
switch field.Kind() {
case reflect.Slice:
for i := 0; i < field.Len(); i++ {
s, ok := field.Index(i).Interface().(Storage)
if ok {
storages = append(storages, s)
}
}
}
}

return storages
}
Loading

0 comments on commit 936b8e1

Please sign in to comment.