Skip to content

Commit 230c206

Browse files
committed
Add history db sqlite format support.
gpbackup functionality of the `--gpbackup.history-file` flag has been expanded. Now it can be specified as `gpbackup_history.db` (sqllite format) or `gpbackup_history.yaml` (yaml format). If the file extension does not match, an error is returned and the exporter does not start. In the future, the yaml format will be abandoned (see how gpbackup develops). So this check will become irrelevant.
1 parent be517d9 commit 230c206

6 files changed

+131
-59
lines changed

Diff for: gpbackup_exporter.go

+36-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"errors"
45
"os"
56
"os/signal"
67
"path/filepath"
@@ -36,7 +37,7 @@ func main() {
3637
).Default("0").Int()
3738
gpbckpHistoryFilePath = kingpin.Flag(
3839
"gpbackup.history-file",
39-
"Path to gpbackup_history.yaml.",
40+
"Path to gpbackup_history.db or gpbackup_history.yaml.",
4041
).Default("").String()
4142
gpbckpIncludeDB = kingpin.Flag(
4243
"gpbackup.db-include",
@@ -78,6 +79,9 @@ func main() {
7879
"msg", "Starting exporter",
7980
"name", filepath.Base(os.Args[0]),
8081
"version", version)
82+
level.Info(logger).Log(
83+
"mgs", "History database file path",
84+
"file", *gpbckpHistoryFilePath)
8185
if *collectionDepth > 0 {
8286
level.Info(logger).Log(
8387
"mgs", "Metrics depth collection in days",
@@ -109,6 +113,14 @@ func main() {
109113
"endpoint", *webPath,
110114
"config.file", *webAdditionalToolkitFlags.WebConfigFile,
111115
)
116+
// Check history file type.
117+
// This code will become not actual after full switch to sqlite history file format
118+
historyDB, err := checkHistoryFileType(*gpbckpHistoryFilePath)
119+
if err != nil {
120+
level.Error(logger).Log("msg", "Check gpbackup history file format failed", "err", err)
121+
// Immediately exit.
122+
os.Exit(1)
123+
}
112124
// Start exporter.
113125
gpbckpexporter.StartPromEndpoint(logger)
114126
// Set up exporter info metric.
@@ -121,9 +133,32 @@ func main() {
121133
*gpbckpIncludeDB,
122134
*gpbckpExcludeDB,
123135
*collectionDepth,
136+
historyDB,
124137
logger,
125138
)
126139
// Sleep for 'collection.interval' seconds.
127140
time.Sleep(time.Duration(*collectionInterval) * time.Second)
128141
}
129142
}
143+
144+
// Check history db file extension is:
145+
// - gpbackup_history.db (sqlite, after gpbackup 1.29.0);
146+
// - gpbackup_history.yaml (before gpbackup 1.29.0);
147+
//
148+
// Returns:
149+
// - true, if file extension is db;
150+
// - false, if file extension is yaml.
151+
// - error, in other cases.
152+
//
153+
// Check only file extension, not content or name.
154+
func checkHistoryFileType(filePath string) (bool, error) {
155+
hFileExt := filepath.Ext(filePath)
156+
switch hFileExt {
157+
case ".db":
158+
return true, nil
159+
case ".yaml":
160+
return false, nil
161+
default:
162+
return false, errors.New("file extension is not db or yaml")
163+
}
164+
}

Diff for: gpbackup_exporter_test.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ func TestMain(t *testing.T) {
1818
t.Errorf("\nGet error during generate random int value:\n%v", err)
1919
}
2020
port := 50000 + int(n.Int64())
21-
os.Args = []string{"gpbackup_exporter", "--web.listen-address=:" + strconv.Itoa(port)}
21+
tempFile, err := os.CreateTemp("", "gpbackup_history*.db")
22+
if err != nil {
23+
t.Errorf("Failed to create temp file: %v", err)
24+
}
25+
defer os.Remove(tempFile.Name())
26+
os.Args = []string{"gpbackup_exporter", "--web.listen-address=:" + strconv.Itoa(port), "--gpbackup.history-file=" + tempFile.Name()}
2227
finished := make(chan struct{})
2328
go func() {
2429
main()

Diff for: gpbckpexporter/gpbckp_exporter.go

+36-22
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package gpbckpexporter
33
import (
44
"net/http"
55
"os"
6-
"strings"
76
"time"
87

98
"github.com/go-kit/log"
@@ -53,7 +52,8 @@ func StartPromEndpoint(logger log.Logger) {
5352
}
5453

5554
// GetGPBackupInfo get and parse gpbackup history file
56-
func GetGPBackupInfo(historyFile, backupType string, dbInclude, dbExclude []string, collectDepth int, logger log.Logger) {
55+
func GetGPBackupInfo(historyFile, backupType string, dbInclude, dbExclude []string, collectDepth int, historyDB bool, logger log.Logger) {
56+
var parseHData gpbckpconfig.History
5757
// To calculate the time elapsed since the last completed backup for specific database.
5858
// For all databases values are calculated relative to one value.
5959
currentTime := time.Now()
@@ -67,13 +67,40 @@ func GetGPBackupInfo(historyFile, backupType string, dbInclude, dbExclude []stri
6767
// Check that database from the include list is not in the exclude list.
6868
// If database not set - checking for entry into the exclude list will be performed later.
6969
if dbNotInExclude(db, dbExclude) {
70-
historyData, err := gpbckpconfig.ReadHistoryFile(historyFile)
71-
if err != nil {
72-
level.Error(logger).Log("msg", "Read gpbackup history file failed", "err", err)
73-
}
74-
parseHData, err := gpbckpconfig.ParseResult(historyData)
75-
if err != nil {
76-
level.Error(logger).Log("msg", "Parse YAML failed", "err", err)
70+
if historyDB {
71+
hDB, err := gpbckpconfig.OpenHistoryDB(historyFile)
72+
if err != nil {
73+
level.Error(logger).Log("msg", "Open gpbackup history db failed", "err", err)
74+
}
75+
defer func() {
76+
closeErr := hDB.Close()
77+
if closeErr != nil {
78+
level.Error(logger).Log("msg", "Close gpbackup history db failed", "err", err)
79+
}
80+
}()
81+
// Get only active and deleted backups. Failed backups are ignored.
82+
backupList, err := gpbckpconfig.GetBackupNamesDB(true, false, hDB)
83+
if err != nil {
84+
level.Error(logger).Log("msg", "Get backups from history db failed", "err", err)
85+
}
86+
// Get data for selected backups.
87+
for _, backupName := range backupList {
88+
backupData, err := gpbckpconfig.GetBackupDataDB(backupName, hDB)
89+
if err != nil {
90+
level.Error(logger).Log("msg", "Get backup data from history db failed", "err", err)
91+
break
92+
}
93+
parseHData.BackupConfigs = append(parseHData.BackupConfigs, backupData)
94+
}
95+
} else {
96+
historyData, err := gpbckpconfig.ReadHistoryFile(historyFile)
97+
if err != nil {
98+
level.Error(logger).Log("msg", "Read gpbackup history file failed", "err", err)
99+
}
100+
parseHData, err = gpbckpconfig.ParseResult(historyData)
101+
if err != nil {
102+
level.Error(logger).Log("msg", "Parse YAML failed", "err", err)
103+
}
77104
}
78105
// Reset metrics.
79106
resetMetrics()
@@ -153,16 +180,3 @@ func GetGPBackupInfo(historyFile, backupType string, dbInclude, dbExclude []stri
153180
func GetExporterInfo(exporterVersion string, logger log.Logger) {
154181
getExporterMetrics(exporterVersion, setUpMetricValue, logger)
155182
}
156-
157-
func dbNotInExclude(db string, listExclude []string) bool {
158-
// Check that exclude list is empty.
159-
// If so, no excluding databases are set during startup.
160-
if strings.Join(listExclude, "") != "" {
161-
for _, val := range listExclude {
162-
if val == db {
163-
return false
164-
}
165-
}
166-
}
167-
return true
168-
}

Diff for: gpbckpexporter/gpbckp_exporter_test.go

+10-35
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func TestGetGPBackupInfo(t *testing.T) {
4141
bckpIncl []string
4242
bckpExcl []string
4343
cDepth int
44+
hDB bool
4445
}
4546
tests := []struct {
4647
name string
@@ -111,22 +112,23 @@ func TestGetGPBackupInfo(t *testing.T) {
111112
[]string{""},
112113
[]string{""},
113114
0,
115+
false,
114116
},
115117
"level=debug msg=\"Set up metric\" metric=gpbackup_backup_status value=0 labels=metadata-only,test,none,none,20230118162654",
116118
},
117119
{
118120
"FailedDataReturn",
119-
args{"return error", "", []string{""}, []string{""}, 0},
121+
args{"return error", "", []string{""}, []string{""}, 0, false},
120122
"level=error msg=\"Parse YAML failed\" err=\"yaml: unmarshal errors:\\n line 1: cannot unmarshal !!str `return ...` into gpbckpconfig.History\"",
121123
},
122124
{
123125
"InvalidDataReturn",
124-
args{"42", "", []string{""}, []string{""}, 0},
126+
args{"42", "", []string{""}, []string{""}, 0, false},
125127
"level=error msg=\"Parse YAML failed\" err=\"yaml: unmarshal errors:\\n line 1: cannot unmarshal !!int `42` into gpbckpconfig.History\"",
126128
},
127129
{
128130
"NoDataReturn",
129-
args{"", "", []string{""}, []string{""}, 0},
131+
args{"", "", []string{""}, []string{""}, 0, false},
130132
"level=warn msg=\"No backup data returned\"",
131133
},
132134
{
@@ -163,12 +165,14 @@ func TestGetGPBackupInfo(t *testing.T) {
163165
"",
164166
[]string{""},
165167
[]string{""},
166-
14},
168+
14,
169+
false,
170+
},
167171
"level=warn msg=\"No succeed backups\"",
168172
},
169173
{
170174
"DBinIncludeAndExclude",
171-
args{"", "", []string{"test"}, []string{"test"}, 0},
175+
args{"", "", []string{"test"}, []string{"test"}, 0, false},
172176
"level=warn msg=\"DB is specified in include and exclude lists\" DB=test",
173177
},
174178
}
@@ -188,6 +192,7 @@ func TestGetGPBackupInfo(t *testing.T) {
188192
tt.args.bckpIncl,
189193
tt.args.bckpExcl,
190194
tt.args.cDepth,
195+
tt.args.hDB,
191196
lc,
192197
)
193198
if !strings.Contains(out.String(), tt.testText) {
@@ -197,36 +202,6 @@ func TestGetGPBackupInfo(t *testing.T) {
197202
}
198203
}
199204

200-
func TestDBNotInExclude(t *testing.T) {
201-
type args struct {
202-
db string
203-
listExclude []string
204-
}
205-
tests := []struct {
206-
name string
207-
args args
208-
want bool
209-
}{
210-
{
211-
"Include",
212-
args{"test", []string{"test"}},
213-
false,
214-
},
215-
{
216-
"Exclude",
217-
args{"test", []string{"demo"}},
218-
true,
219-
},
220-
}
221-
for _, tt := range tests {
222-
t.Run(tt.name, func(t *testing.T) {
223-
if got := dbNotInExclude(tt.args.db, tt.args.listExclude); got != tt.want {
224-
t.Errorf("\nVariables do not match:\n%v\nwant:\n%v", got, tt.want)
225-
}
226-
})
227-
}
228-
}
229-
230205
func fakeHistoryFileData(text string) (*os.File, error) {
231206
tempFile, err := os.CreateTemp("", "gpbackup_history*.yaml")
232207
if err != nil {

Diff for: gpbckpexporter/gpbckp_parser.go

+13
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,16 @@ func setUpMetric(metric *prometheus.GaugeVec, metricName string, value float64,
103103
)
104104
}
105105
}
106+
107+
func dbNotInExclude(db string, listExclude []string) bool {
108+
// Check that exclude list is empty.
109+
// If so, no excluding databases are set during startup.
110+
if strings.Join(listExclude, "") != "" {
111+
for _, val := range listExclude {
112+
if val == db {
113+
return false
114+
}
115+
}
116+
}
117+
return true
118+
}

Diff for: gpbckpexporter/gpbckp_parser_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,33 @@ func returnTimeTime(sTime string) time.Time {
213213
}
214214
return rTime
215215
}
216+
217+
func TestDBNotInExclude(t *testing.T) {
218+
type args struct {
219+
db string
220+
listExclude []string
221+
}
222+
tests := []struct {
223+
name string
224+
args args
225+
want bool
226+
}{
227+
{
228+
"Include",
229+
args{"test", []string{"test"}},
230+
false,
231+
},
232+
{
233+
"Exclude",
234+
args{"test", []string{"demo"}},
235+
true,
236+
},
237+
}
238+
for _, tt := range tests {
239+
t.Run(tt.name, func(t *testing.T) {
240+
if got := dbNotInExclude(tt.args.db, tt.args.listExclude); got != tt.want {
241+
t.Errorf("\nVariables do not match:\n%v\nwant:\n%v", got, tt.want)
242+
}
243+
})
244+
}
245+
}

0 commit comments

Comments
 (0)