Skip to content

Commit db4fdd4

Browse files
committed
implemented retention and api
1 parent 9892487 commit db4fdd4

14 files changed

+881
-311
lines changed

Dockerfile

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ ENV WEBHOOK_DELETE_BODY ''
2525
ENV WEBHOOK_GRACE_TIME 3600
2626
ENV DATA_DIR '/var/lib/schelly/data'
2727

28-
ENV RETENTION_SECONDLY 0@L
2928
ENV RETENTION_MINUTELY 0@L
3029
ENV RETENTION_HOURLY 0@L
3130
ENV RETENTION_DAILY 4@L

README.md

+57-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Schelly is a backup tool focused on the scheduling stuff, so that the heavy lift
33

44
The triggering and retainment of backups are based on the functional perception of backups, so you configure:
55
- Triggering cron string: cron string that defines when a new backup will be created (by calling a backend backup webhook, as [schelly-restic](http://github.com/flaviostutz/schelly-restic), for example)
6-
- Retention policies: for how long do a backup must be retained? It depends on what the user needs when something goes wrong. In general, the more recent, more backups in time you need. By default, Schelly will try to keep something like (if a backup is outsIDe this, the webhook for backup removal will be called):
6+
- Retention policies: for how long do a backup must be retained? It depends on what the user needs when something goes wrong. In general, the more recent, more backups in time you need. By default, Schelly will try to keep something like (if a backup is outside this, the webhook for backup removal will be called):
77
- the last 4 daily backups
88
- the last 4 weekly backps
99
- the last 3 monthly backups
@@ -26,10 +26,60 @@ The triggering and retainment of backups are based on the functional perception
2626
* RETENTION_YEARLY - retention config for years
2727
format "header1=contents1,header2=contents2"
2828
* WEBHOOK_BODY - custom data to be sent as body for webhook calls to backup backends
29-
* GRACE\_TIME\_SECONDS - when trying to run a new backup task, if a previous task is still running because it dIDn't finish yet, check for this parameter. if time elapsed for the running task is greater than this parameter, try to cancel it by emitting a DELETE webhook and start the new task, else mark the new task as SKIPPED and keep the running task as is.
29+
* GRACE\_TIME\_SECONDS - when trying to run a new backup task, if a previous task is still running because it didn't finish yet, check for this parameter. if time elapsed for the running task is greater than this parameter, try to cancel it by emitting a DELETE webhook and start the new task, else mark the new task as SKIPPED and keep the running task as is.
30+
31+
# REST API
32+
33+
- ```GET /backups```
34+
- Query backups managed by Schelly
35+
- Request body: none
36+
- Request header: none
37+
- Response body: json
38+
39+
```
40+
{
41+
id:{same id as returned by underlying webhook on backup creation},
42+
status:{backup-status}
43+
start_time:{time of backup trigger on webhook}
44+
end_time:{time of backup finish detection}
45+
custom_data:{data returned from webhook}
46+
tags: {array of tags}
47+
}
48+
```
49+
- status must be one of:
50+
- 'running' - backup is not finished yet
51+
- 'available' - backup has completed successfuly
52+
53+
- tags may be: 'minutely', 'hourly', 'daily', 'weekly', 'monthly', 'yearly'
54+
55+
- Status code 201 if created successfuly
56+
57+
- ```POST /backups```
58+
- Trigger a new backup now
59+
- Request body: none
60+
- Request header: none
61+
- Response body: json
62+
63+
```
64+
{
65+
id:{same id as returned by underlying webhook on backup creation},
66+
status:{backup-status}
67+
start_time:{time of backup trigger on webhook}
68+
end_time:{time of backup finish detection}
69+
custom_data:{data returned from webhook}
70+
}
71+
```
72+
- status must be one of:
73+
- 'running' - backup is not finished yet
74+
- 'available' - backup has completed successfuly
75+
76+
- Status code 201 if created successfuly
77+
3078
3179
# Webhook spec
3280
81+
will be invoked when Schelly needs to create/delete a backup on a backend server
82+
3383
The webhook server must expose the following REST endpoints:
3484
3585
- ```POST {webhook-url}```
@@ -40,7 +90,7 @@ The webhook server must expose the following REST endpoints:
4090
4191
```
4292
{
43-
ID:{alphanumeric-backup-ID},
93+
id:{alphanumeric-backup-id},
4494
status:{backup-status}
4595
message:{backend-message}
4696
}
@@ -51,29 +101,29 @@ The webhook server must expose the following REST endpoints:
51101
52102
- Status code 201 if created successfuly
53103
54-
- ```GET {webhook-url}/{backup-ID}```
104+
- ```GET {webhook-url}/{backup-id}```
55105
- Invoked when Schelly wants to query a specific backup instance
56106
- Request header: ```{webhook-headers}```
57107
- Response body: json
58108
59109
```
60110
{
61-
ID:{ID},
111+
id:{id},
62112
status:{backup-status},
63113
message:{backend message}
64114
}
65115
```
66116
- Status code: 200 if found, 404 if not found
67117
68-
- ```DELETE {webhook-url}/{backup-ID}```
118+
- ```DELETE {webhook-url}/{backup-id}```
69119
- Invoked when Schelly wants to trigger a new backup
70120
- Request body: json ```{webhook-delete-body}```
71121
- Request header: ```{webhook-headers}```
72122
- Response body: json
73123
74124
```
75125
{
76-
ID:{alphanumeric-backup-ID},
126+
id:{alphanumeric-backup-id},
77127
status:{backup-status}
78128
message:{backend-message}
79129
}

docker-compose.yml

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ services:
55
schelly:
66
build:
77
context: .
8-
# target: IMAGE
8+
target: IMAGE
9+
ports:
10+
- 7070:8080
911
environment:
1012
- LOG_LEVEL=debug
1113
- BACKUP_NAME=test
@@ -14,9 +16,8 @@ services:
1416
- WEBHOOK_HEADERS=k1=v1,k2=v2
1517
# - WEBHOOK_CREATE_BODY=""
1618
# - WEBHOOK_DELETE_BODY=""
17-
# - WEBHOOK_GRACE_TIME=""
18-
# - RETENTION_SECONDLY=""
19-
# - RETENTION_MINUTELY=""
19+
- WEBHOOK_GRACE_TIME=30
20+
- RETENTION_MINUTELY=2
2021
# - RETENTION_HOURLY=""
2122
# - RETENTION_DAILY=""
2223
# - RETENTION_WEEKLY=""

main.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
_ "bytes"
5+
_ "context"
56
_ "database/sql"
67
_ "encoding/json"
78
_ "flag"
@@ -15,6 +16,7 @@ import (
1516
_ "time"
1617

1718
_ "github.com/Sirupsen/logrus"
19+
_ "github.com/gorilla/mux"
1820
_ "github.com/mattn/go-sqlite3"
1921
_ "github.com/robfig/cron"
2022
)

schelly/api.go

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"os"
7+
8+
"github.com/Sirupsen/logrus"
9+
"github.com/gorilla/mux"
10+
)
11+
12+
func startRestAPI() {
13+
router := mux.NewRouter()
14+
router.HandleFunc("/backups", GetBackups).Methods("GET")
15+
router.HandleFunc("/backups", TriggerBackup).Methods("POST")
16+
listen := fmt.Sprintf("%s:%d", options.listenIP, options.listenPort)
17+
logrus.Infof("Listening at %s", listen)
18+
err := http.ListenAndServe(listen, router)
19+
if err != nil {
20+
logrus.Errorf("Error while listening requests: %s", err)
21+
os.Exit(1)
22+
}
23+
}
24+
25+
//GetBackups get currently tracked backups
26+
func GetBackups(w http.ResponseWriter, r *http.Request) {
27+
logrus.Debugf("GetBackups r=%s", r)
28+
tag := r.URL.Query().Get("tag")
29+
backups, err := getMaterializedBackups(0, tag)
30+
if err != nil {
31+
http.Error(w, err.Error(), http.StatusInternalServerError)
32+
return
33+
}
34+
35+
rjson := ""
36+
for _, b := range backups {
37+
tags := ""
38+
39+
bt := getTags(b)
40+
for _, tag := range bt {
41+
if tags != "" {
42+
tags = tags + ","
43+
}
44+
tags = tags + "\"" + tag + "\""
45+
}
46+
47+
if rjson != "" {
48+
rjson = rjson + ","
49+
}
50+
rjson = rjson + "{\"id\":\"" + b.ID + "\", \"status\":\"" + b.Status + "\", \"start_time\":\"" + fmt.Sprintf("%s", b.StartTime) + "\", \"end_time\":\"" + fmt.Sprintf("%s", b.EndTime) + "\", \"custom_data\":\"" + b.CustomData + "\", \"tags\":[" + tags + "]}"
51+
}
52+
53+
w.Header().Set("Content-Type", "application/json")
54+
w.Write([]byte("[" + rjson + "]"))
55+
logrus.Debugf("result: %s", "["+rjson+"]")
56+
}
57+
58+
//TriggerBackup get currently tracked backups
59+
func TriggerBackup(w http.ResponseWriter, r *http.Request) {
60+
logrus.Debugf("TriggerBackup r=%s", r)
61+
result, err := triggerNewBackup()
62+
if err != nil {
63+
http.Error(w, err.Error(), http.StatusInternalServerError)
64+
return
65+
}
66+
w.Header().Set("Content-Type", "application/json")
67+
rs := "{}"
68+
if result.ID != "" {
69+
rs = "{id:'" + result.ID + "',status:'" + result.Status + "',message:'" + result.Message + "'}"
70+
}
71+
w.Write([]byte(rs))
72+
logrus.Debugf("result: %s", rs)
73+
}

0 commit comments

Comments
 (0)