Skip to content

Commit a913c7a

Browse files
committed
trial version
1 parent ac4ca0b commit a913c7a

File tree

7 files changed

+124
-65
lines changed

7 files changed

+124
-65
lines changed

Makefile

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ all: down up
2121

2222
test:
2323
go build -o app/main cmd/main.go
24-
docker compose exec -u postgres postgres /app/main --project test --backup_type psql --backup_cron "*/1 * * * *"
24+
docker compose exec -u postgres postgres /app/main --project test --backup_type psql --backup_cron "*/1 * * * *" --delete_cron "*/1 * * * *" --delete_retain 5
2525

2626
tc:
2727
go build -o app/main cmd/main.go
28-
docker compose exec -u postgres postgres /app/main --project test --backup_type psql --config_file /var/lib/postgre
28+
docker compose exec -u postgres postgres /app/main --project test --backup_type psql
2929

3030
tm:
3131
go build -o app/main cmd/main.go
@@ -35,9 +35,7 @@ tmy:
3535
docker compose exec -u mysql mysql /app/main --project test --backup_type mysql --backup_cron "*/1 * * * *"
3636
tmd:
3737
go build -o app/main cmd/main.go
38-
docker compose exec -u mongodb mongo wal-g backup-list
39-
docker compose exec -u mongodb mongo wal-g delete retain FULL 5 --confirm
40-
docker compose exec -u mongodb mongo /app/main --project test --backup_type mongodb --backup_cron "*/1 * * * *"
38+
docker compose exec -u mongodb mongo /app/main --project test --backup_type mongodb --backup_cron "*/1 * * * *" --delete_cron "*/1 * * * *" --delete_retain 5
4139

4240

4341

README.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,32 @@
1-
# Вся логика по созданию бекапа в create.go
1+
# Бекапилка не несет ответственности за то в каком виде конфиг файлы.
2+
Установка wal-g, clickhouse-backup осуществляется отдельно
3+
4+
Пример команды для запуска
5+
```
6+
main --project projectName --backup_type <psql|mysql|mariadb|mongodb|clickhouse> --cron "* * * * *"
7+
Support only for postgresql --delete_cron "*/1 * * * *" --delete_retain 5
8+
```
9+
10+
# Вся логика по созданию бекапа в create/create.go
11+
Удаление старых бекапов поддерживается долько для postgresql
12+
Проверка проходит на стадии задания переменных в config.go
13+
Также здесь создаю `config.DeleteEnable` которая в main.go определяет состояние удаления старых бекапов
214

315
# Переменные создаются в config/config.go
416

517
# Метрики exporter/collector.go
6-
clickhouse need create table
718

8-
wal-g psql retein
19+
# Крон запускает выполнение тасок cron/cron.go
20+
21+
# Локальная проверка
22+
В build/docker лежат Докер файлы и конфиги для запуска и теста
23+
Бекап предпологает наличие конфиг файлов в дирах по умолчанию (кроме mysql там установил home dir /var/lib/mysql руками)
24+
Если нужно изменить место конфига, добовляем --config флаг.
25+
Команды запускаются от имени пользователя бекапилки.
26+
Обязательные поля для заполнения (в конфигах бекапилок)
27+
- "AWS_ACCESS_KEY_ID": "",
28+
- "AWS_SECRET_ACCESS_KEY": "",
29+
- "AWS_REGION": "eu-central-1",
30+
- "AWS_ENDPOINT": "",
31+
- "WALE_S3_PREFIX": "",
32+

app/main

5.94 KB
Binary file not shown.

cmd/main.go

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,8 @@ import (
1818
"github.com/efremov-it/backup_exporter/pkg/cron"
1919
)
2020

21-
// c := NewCron()
22-
// if err := c.AddJob("First", "* * * * *", func(ctx context.Context) {
23-
// }); err != nil {
24-
// panic(err)
25-
// }
26-
// if err := c.AddJob("Second", "* * * * *", func(ctx context.Context) {
27-
// }); err != nil {
28-
// panic(err)
29-
// }
30-
3121
func main() {
3222
config, err := config.ParseFlags()
33-
3423
if err != nil {
3524
log.Fatal("Error parsing flags:\n", err)
3625
}
@@ -43,10 +32,16 @@ func main() {
4332
prometheus.MustRegister(collectorVars)
4433
backupService := create.NewBackupService(config, collectorVars)
4534

46-
if err := c.AddJob("Backup", config.CronTime, backupService.Run); err != nil {
35+
// create backup
36+
if err := c.AddJob("Backup", config.CronTime, backupService.Create); err != nil {
4737
panic(err)
4838
}
49-
// create.NewBackupService(config, collectorVars).Run(ctx)
39+
// retain Backup for postgresql.
40+
if config.DeleteEnable {
41+
if err := c.AddJob("Backup-Retain", config.DeleteCronTime, backupService.Retain); err != nil {
42+
panic(err)
43+
}
44+
}
5045
// Create a Prometheus registry
5146
mux := http.NewServeMux()
5247
mux.Handle("/metrics", promhttp.Handler())
@@ -63,7 +58,6 @@ func main() {
6358
}); err != nil {
6459
panic(err)
6560
}
66-
6761
if err := c.Run(ctx); err != nil {
6862
panic(err)
6963
}

pkg/collector/collector.go

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,22 @@ import (
99
)
1010

1111
type CollectorMetrics struct {
12-
mutex sync.RWMutex
13-
result Result
14-
config *config.Config
15-
BackupStatus *prometheus.Desc
16-
BackupDuration *prometheus.Desc
17-
BackupNextTime *prometheus.Desc
12+
mutex sync.RWMutex
13+
resultCreate ResultCreate
14+
resultRetain ResultRetain
15+
config *config.Config
16+
BackupCreateStatus *prometheus.Desc
17+
BackupCreateDuration *prometheus.Desc
18+
BackupRetainStatus *prometheus.Desc
19+
BackupRetainDuration *prometheus.Desc
1820
}
1921

20-
type Result struct {
22+
type ResultCreate struct {
23+
BackupStartTime time.Time
24+
BackupDuration float64
25+
BackupStatus int
26+
}
27+
type ResultRetain struct {
2128
BackupStartTime time.Time
2229
BackupDuration float64
2330
BackupStatus int
@@ -26,16 +33,20 @@ type Result struct {
2633
func NewCollector(config *config.Config) *CollectorMetrics {
2734
labelNames := []string{"backup_type", "project_name", "instance_name"}
2835
return &CollectorMetrics{
29-
BackupStatus: prometheus.V2.NewDesc("backup_status",
36+
BackupCreateStatus: prometheus.V2.NewDesc("backup_create_status",
3037
"Show backup status",
3138
prometheus.UnconstrainedLabels(labelNames),
3239
prometheus.Labels(nil)),
33-
BackupDuration: prometheus.V2.NewDesc("backup_duration",
40+
BackupCreateDuration: prometheus.V2.NewDesc("backup_create_duration",
3441
"Show backup duration",
3542
prometheus.UnconstrainedLabels(labelNames),
3643
prometheus.Labels(nil)),
37-
BackupNextTime: prometheus.V2.NewDesc("backup_next_time",
38-
"Show when the next backup will be created",
44+
BackupRetainStatus: prometheus.V2.NewDesc("backup_retain_status",
45+
"Show backup retain status (only for postgresql)",
46+
prometheus.UnconstrainedLabels(labelNames),
47+
prometheus.Labels(nil)),
48+
BackupRetainDuration: prometheus.V2.NewDesc("backup_retain_duration",
49+
"Show backup retain duration (only for postgresql)",
3950
prometheus.UnconstrainedLabels(labelNames),
4051
prometheus.Labels(nil)),
4152
config: config,
@@ -44,9 +55,10 @@ func NewCollector(config *config.Config) *CollectorMetrics {
4455

4556
func (collector *CollectorMetrics) Describe(ch chan<- *prometheus.Desc) {
4657
ds := []*prometheus.Desc{
47-
collector.BackupStatus,
48-
collector.BackupDuration,
49-
collector.BackupNextTime,
58+
collector.BackupCreateStatus,
59+
collector.BackupCreateDuration,
60+
collector.BackupRetainStatus,
61+
collector.BackupRetainDuration,
5062
}
5163

5264
for _, d := range ds {
@@ -58,23 +70,42 @@ func (c *CollectorMetrics) Collect(ch chan<- prometheus.Metric) {
5870
c.mutex.RLock()
5971
defer c.mutex.RUnlock()
6072

61-
ch <- prometheus.NewMetricWithTimestamp(c.result.BackupStartTime, prometheus.MustNewConstMetric(
62-
c.BackupDuration,
73+
ch <- prometheus.NewMetricWithTimestamp(c.resultCreate.BackupStartTime, prometheus.MustNewConstMetric(
74+
c.BackupCreateDuration,
75+
prometheus.GaugeValue,
76+
c.resultCreate.BackupDuration,
77+
c.config.BackupType, c.config.ProjectName, c.config.Host,
78+
))
79+
ch <- prometheus.NewMetricWithTimestamp(c.resultCreate.BackupStartTime, prometheus.MustNewConstMetric(
80+
c.BackupCreateStatus,
6381
prometheus.GaugeValue,
64-
c.result.BackupDuration,
82+
float64(c.resultCreate.BackupStatus),
6583
c.config.BackupType, c.config.ProjectName, c.config.Host,
6684
))
67-
ch <- prometheus.NewMetricWithTimestamp(c.result.BackupStartTime, prometheus.MustNewConstMetric(
68-
c.BackupStatus,
85+
ch <- prometheus.NewMetricWithTimestamp(c.resultRetain.BackupStartTime, prometheus.MustNewConstMetric(
86+
c.BackupRetainDuration,
6987
prometheus.GaugeValue,
70-
float64(c.result.BackupStatus),
88+
c.resultRetain.BackupDuration,
7189
c.config.BackupType, c.config.ProjectName, c.config.Host,
7290
))
91+
ch <- prometheus.NewMetricWithTimestamp(c.resultRetain.BackupStartTime, prometheus.MustNewConstMetric(
92+
c.BackupRetainStatus,
93+
prometheus.GaugeValue,
94+
float64(c.resultRetain.BackupStatus),
95+
c.config.BackupType, c.config.ProjectName, c.config.Host,
96+
))
97+
}
98+
99+
func (c *CollectorMetrics) SetResultCreate(result ResultCreate) {
100+
c.mutex.Lock()
101+
defer c.mutex.Unlock()
102+
103+
c.resultCreate = result
73104
}
74105

75-
func (c *CollectorMetrics) SetResult(result Result) {
106+
func (c *CollectorMetrics) SetResultRetain(result ResultRetain) {
76107
c.mutex.Lock()
77108
defer c.mutex.Unlock()
78109

79-
c.result = result
110+
c.resultRetain = result
80111
}

pkg/config/config.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"flag"
55
"fmt"
66
"os"
7+
"strconv"
78
)
89

910
type Config struct {
@@ -14,6 +15,7 @@ type Config struct {
1415
ConfigFile string
1516
BackupStorage string
1617
CronTime string
18+
DeleteEnable bool
1719
DeleteRetain string
1820
DeleteCronTime string
1921
}
@@ -37,39 +39,48 @@ func ParseFlags() (*Config, error) {
3739
flag.StringVar(&config.ConfigFile, "config_file", "", "Path to config file (default is different for each backup tools)")
3840
flag.StringVar(&config.BackupStorage, "backup_storage", "", "When uploading backups to storage, the user should pass the Postgres data directory as an argument (default: $PGDATA)")
3941
flag.StringVar(&config.CronTime, "backup_cron", "0 2 * * *", "How often you should create your backup. Format crontab --backup_cron \"* * * * *\" (default: \"0 2 * * *\" At 02:00)")
40-
flag.StringVar(&config.DeleteRetain, "delete_retain", "", "when set keep 5(or) full backups and all deltas of them (default: not set. example 5)")
42+
flag.StringVar(&config.DeleteRetain, "delete_retain", "", "when set keep 5(or) full backups and all deltas of them (default: not set. example 5 int type)")
4143
flag.StringVar(&config.DeleteCronTime, "delete_cron", "0 3* * 6", "How often you should retain your backups (default: \"0 3* * 6\" At 03:00 on Saturday)")
4244

4345
flag.Parse()
4446

45-
errUsage := fmt.Errorf("usage: main --project projectName --backup_type <psql|mysql|mariadb|mongodb|clickhouse> --cron \"* * * * *\"")
46-
47-
fmt.Println("DeleteRetain \n DeleteCronTime", config.DeleteRetain, config.DeleteCronTime)
48-
// Set default values
47+
errUsage := fmt.Errorf("usage: main --project projectName --backup_type <psql|mysql|mariadb|mongodb|clickhouse> --cron \"* * * * *\"\nSupport only for postgresql (--delete_cron \"*/1 * * * *\" --delete_retain 5)")
4948

49+
// Set up default values
5050
if config.InstanceName == "" {
5151
hostname, err := getHostname()
5252
if err != nil {
5353
return nil, err
5454
}
5555
config.InstanceName = hostname
5656
}
57-
5857
if config.BackupStorage == "" && config.BackupType == "psql" {
5958
pgdata := os.Getenv("PGDATA")
6059
if pgdata == "" {
6160
return nil, fmt.Errorf("error: $PGDATA environment variable is not set")
6261
}
6362
config.BackupStorage = pgdata
6463
}
65-
64+
// enable backup Retain
65+
config.DeleteEnable = false
66+
if config.BackupType == "psql" {
67+
if config.DeleteRetain != "" {
68+
// if delete_retain contain string
69+
_, err := strconv.Atoi(config.DeleteRetain)
70+
if err != nil {
71+
return nil, errUsage
72+
}
73+
config.DeleteEnable = true
74+
} else {
75+
fmt.Print("For enable deleting old backups you need to use flags:\n --delete_cron \"*/1 * * * *\" --delete_retain 5\n")
76+
}
77+
}
6678
checkBackupType := true
6779
for _, db := range []string{"psql", "mysql", "mariadb", "mongodb", "clickhouse"} {
6880
if db == config.BackupType {
6981
checkBackupType = false
7082
}
7183
}
72-
7384
// Validate required flags
7485
if config.ProjectName == "" || checkBackupType {
7586
return nil, errUsage

pkg/create/create.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type BackupService struct {
2424
metrics *collector.CollectorMetrics
2525
}
2626

27-
func (bs *BackupService) Run(ctx context.Context) {
27+
func (bs *BackupService) Create(ctx context.Context) {
2828
var command string
2929
var use_flags []string
3030
// set backup command and arguments
@@ -47,15 +47,15 @@ func (bs *BackupService) Run(ctx context.Context) {
4747
// create backup
4848
n := 0
4949
for n < 3 {
50-
result, err := backup(command, use_flags...)
50+
t, d, s, err := backup(command, use_flags...)
5151
if err != nil {
52-
bs.metrics.SetResult(result)
52+
bs.metrics.SetResultCreate(collector.ResultCreate{t, d, s})
5353
fmt.Fprint(os.Stdout, []any{"Backup failed\nStart backup one more time\n"}...)
5454
time.Sleep(5 * time.Second)
5555
} else {
5656
n = 3
5757
print("Backup created\n")
58-
bs.metrics.SetResult(result)
58+
bs.metrics.SetResultCreate(collector.ResultCreate{t, d, s})
5959
return
6060
}
6161
n++
@@ -64,42 +64,43 @@ func (bs *BackupService) Run(ctx context.Context) {
6464

6565
func (bs *BackupService) Retain(ctx context.Context) {
6666
var use_flags []string
67-
// for psql we need to use BackupStorage
6867
if bs.config.BackupType == "psql" {
6968
if bs.config.DeleteRetain != "" {
7069
use_flags = append(use_flags, "delete", "retain", "FULL", bs.config.DeleteRetain, "--confirm")
7170
}
7271
use_flags = append(use_flags, bs.config.BackupStorage)
72+
} else {
73+
print("Retain backup support only for postgresql\n")
7374
}
7475

7576
if bs.config.ConfigFile != "" {
7677
use_flags = append(use_flags, "--config", bs.config.ConfigFile)
7778
}
7879

7980
// Retain backup
80-
result, err := backup("wal-g", use_flags...)
81+
t, d, s, err := backup("wal-g", use_flags...)
8182
if err != nil {
82-
bs.metrics.SetResult(result)
83+
bs.metrics.SetResultRetain(collector.ResultRetain{t, d, s})
8384
fmt.Fprint(os.Stdout, []any{"Retain backup failed\n"}...)
8485
} else {
8586
print("Retain backup finished\n")
86-
bs.metrics.SetResult(result)
87+
bs.metrics.SetResultRetain(collector.ResultRetain{t, d, s})
8788
return
8889
}
8990
}
9091

91-
func backup(command string, args ...string) (result collector.Result, err error) {
92-
result.BackupStartTime = time.Now()
92+
func backup(command string, args ...string) (startTime time.Time, duration float64, status int, err error) {
93+
startTime = time.Now()
9394
cmd := exec.Command(command, args...)
9495
output, err := cmd.CombinedOutput()
9596

9697
defer func() {
97-
result.BackupDuration = float64(time.Since(result.BackupStartTime).Seconds())
98+
duration = float64(time.Since(startTime).Seconds())
9899
if err != nil {
99-
result.BackupStatus = 1
100+
status = 1
100101
log.Printf("Error:\n", err, string(output))
101102
} else {
102-
result.BackupStatus = 0
103+
status = 0
103104
log.Printf("Command Output: %s\n", string(output))
104105
}
105106
}()

0 commit comments

Comments
 (0)