forked from mhausenblas/burry.sh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
200 lines (187 loc) · 6.86 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package main
import (
"fmt"
"os"
"strconv"
"strings"
"time"
log "github.com/sirupsen/logrus"
etcd "github.com/coreos/etcd/client"
consul "github.com/hashicorp/consul/api"
flag "github.com/ogier/pflag"
"github.com/samuel/go-zookeeper/zk"
)
const (
VERSION string = "0.4.0"
BURRYFEST_FILE string = ".burryfest"
BURRYMETA_FILE string = ".burrymeta"
CONTENT_FILE string = "content"
BURRY_OPERATION_BACKUP string = "backup"
BURRY_OPERATION_RESTORE string = "restore"
INFRA_SERVICE_ETCD string = "etcd"
INFRA_SERVICE_ZK string = "zk"
INFRA_SERVICE_CONSUL string = "consul"
STORAGE_TARGET_TTY string = "tty"
STORAGE_TARGET_LOCAL string = "local"
STORAGE_TARGET_S3 string = "s3"
STORAGE_TARGET_MINIO string = "minio"
REMOTE_ARCH_FILE string = "latest.zip"
REMOTE_ARCH_TYPE string = "application/zip"
)
var (
version bool
createburryfest bool
// the operation burry should to carry out:
bop string
bops = [...]string{BURRY_OPERATION_BACKUP, BURRY_OPERATION_RESTORE}
// the type of infra service to back up or restore:
isvc string
isvcs = [...]string{INFRA_SERVICE_ZK, INFRA_SERVICE_ETCD, INFRA_SERVICE_CONSUL}
// the infra service endpoint to use:
endpoint string
timeout int
zkconn *zk.Conn
kapi etcd.KeysAPI
ckv *consul.KV
// the storage target to use:
starget string
startgets = [...]string{
STORAGE_TARGET_TTY,
STORAGE_TARGET_LOCAL,
STORAGE_TARGET_S3,
STORAGE_TARGET_MINIO,
}
// the backup and restore manifest to use:
brf Burryfest
cred string
// local scratch base directory:
based string
// the snapshot ID:
snapshotid string
// number of restored items (znodes or keys):
numrestored int
// Forget existing data
forget bool
)
// reap function types take a node path
// and a value as parameters and perform
// some side effect, such as storing it.
// see for example aux.go#reapsimple()
type reap func(string, string)
func init() {
flag.BoolVarP(&version, "version", "v", false, "Display version information and exit.")
flag.BoolVarP(&createburryfest, "burryfest", "b", false, fmt.Sprintf("Create a burry manifest file %s in the current directory.\n\tThe manifest file captures the current command line parameters for re-use in subsequent operations.", BURRYFEST_FILE))
flag.StringVarP(&bop, "operation", "o", BURRY_OPERATION_BACKUP, fmt.Sprintf("The operation to carry out.\n\tSupported values are %v", bops))
flag.StringVarP(&isvc, "isvc", "i", INFRA_SERVICE_ZK, fmt.Sprintf("The type of infra service to back up or restore.\n\tSupported values are %v", isvcs))
flag.StringVarP(&endpoint, "endpoint", "e", "", fmt.Sprintf("The infra service HTTP API endpoint to use.\n\tExample: localhost:8181 for Exhibitor"))
flag.IntVar(&timeout, "timeout", 1, fmt.Sprintf("The infra service timeout, by default 1 second"))
flag.StringVarP(&starget, "target", "t", STORAGE_TARGET_TTY, fmt.Sprintf("The storage target to use.\n\tSupported values are %v", startgets))
flag.StringVarP(&cred, "credentials", "c", "", fmt.Sprintf("The credentials to use in format STORAGE_TARGET_ENDPOINT,KEY1=VAL1,...KEYn=VALn.\n\tExample: s3.amazonaws.com,ACCESS_KEY_ID=...,SECRET_ACCESS_KEY=...,BUCKET=...,PREFIX=...,SSL=..."))
flag.StringVarP(&snapshotid, "snapshot", "s", "", fmt.Sprintf("The ID of the snapshot.\n\tExample: 1483193387"))
flag.BoolVarP(&forget, "forget", "f", true, fmt.Sprintf("Forget existing data "))
flag.Usage = func() {
fmt.Printf("Usage: burry [args]\n\n")
fmt.Println("Arguments:")
flag.PrintDefaults()
}
flag.Parse()
switch log_level := os.Getenv("LOG_LEVEL"); log_level {
case "DEBUG":
log.SetLevel(log.DebugLevel)
case "WARN":
log.SetLevel(log.WarnLevel)
case "ERROR":
log.SetLevel(log.ErrorLevel)
case "FATAL":
log.SetLevel(log.FatalLevel)
case "PANIC":
log.SetLevel(log.PanicLevel)
default:
log.SetLevel(log.InfoLevel)
}
if bfpath, mbrf, err := loadbf(); err != nil {
brf = Burryfest{InfraService: isvc, Endpoint: endpoint, Timeout: timeout, StorageTarget: starget, Creds: parsecred()}
} else {
brf = mbrf
log.WithFields(log.Fields{"func": "init"}).Info(fmt.Sprintf("Using burryfest %s", bfpath))
}
based = strconv.FormatInt(time.Now().Unix(), 10)
if bop == BURRY_OPERATION_BACKUP {
snapshotid = based
} else { // for restore ops
if snapshotid != "" {
based = snapshotid
}
}
numrestored = 0
}
func processop() bool {
success := false
// validate available operations parameter:
if brf.Endpoint == "" {
log.WithFields(log.Fields{"func": "processop"}).Error(fmt.Sprintf("You MUST supply an infra service endpoint with -e/--endpoint"))
return false
}
switch bop {
case BURRY_OPERATION_BACKUP:
switch brf.InfraService {
case INFRA_SERVICE_ZK:
success = backupZK()
case INFRA_SERVICE_ETCD:
success = backupETCD()
case INFRA_SERVICE_CONSUL:
success = backupCONSUL()
default:
log.WithFields(log.Fields{"func": "processop"}).Error(fmt.Sprintf("Infra service %s unknown or not yet supported", brf.InfraService))
}
case BURRY_OPERATION_RESTORE:
if brf.StorageTarget == STORAGE_TARGET_TTY {
log.WithFields(log.Fields{"func": "processop"}).Error(fmt.Sprintf("I can't restore from TTY, pick a different storage target with -t/--target"))
return false
}
if snapshotid == "" {
log.WithFields(log.Fields{"func": "processop"}).Error(fmt.Sprintf("You MUST supply a snapshot ID with -s/--snapshot"))
return false
}
switch brf.InfraService {
case INFRA_SERVICE_ZK:
success = restoreZK()
case INFRA_SERVICE_ETCD:
success = restoreETCD()
case INFRA_SERVICE_CONSUL:
success = restoreCONSUL()
default:
log.WithFields(log.Fields{"func": "processop"}).Error(fmt.Sprintf("Infra service %s unknown or not yet supported", brf.InfraService))
}
default:
log.WithFields(log.Fields{"func": "processop"}).Error(fmt.Sprintf("%s is not a valid operation", bop))
flag.Usage()
os.Exit(2)
}
return success
}
func main() {
if version {
about()
os.Exit(0)
}
log.WithFields(log.Fields{"func": "main"}).Info(fmt.Sprintf("Selected operation: %s", strings.ToUpper(bop)))
log.WithFields(log.Fields{"func": "main"}).Debug(fmt.Sprintf("My config: %+v", brf))
if ok := processop(); ok {
if createburryfest {
if err := writebf(); err != nil {
log.WithFields(log.Fields{"func": "main"}).Fatal(fmt.Sprintf("Something went wrong when I tried to create the burryfest: %s ", err))
}
}
switch bop {
case BURRY_OPERATION_BACKUP:
log.WithFields(log.Fields{"func": "main"}).Info(fmt.Sprintf("Operation successfully completed. The snapshot ID is: %s", snapshotid))
case BURRY_OPERATION_RESTORE:
log.WithFields(log.Fields{"func": "main"}).Info(fmt.Sprintf("Operation successfully completed. Restored %d items from snapshot %s", numrestored, snapshotid))
}
} else {
log.WithFields(log.Fields{"func": "main"}).Error(fmt.Sprintf("Operation completed with error(s)."))
flag.Usage()
os.Exit(1)
}
}