pupirka
/
pupirka.go
395 строк · 11.9 Кб
1package main
2
3import (
4"encoding/json"
5"errors"
6"fmt"
7"github.com/gammazero/workerpool"
8logrus "github.com/sirupsen/logrus"
9"io/ioutil"
10"os"
11"regexp"
12"strconv"
13"strings"
14"time"
15)
16
17type Logger logrus.Logger
18
19func ScanDevice() {
20dir := ConfigV.GetString("path.devices")
21
22files, err := ioutil.ReadDir(dir)
23if err != nil {
24es := fmt.Sprintf(err.Error())
25LogConsole.Error(es)
26LogConsole.Error("Program exit")
27os.Exit(1)
28}
29
30for _, f := range files {
31fr := regexp.MustCompile(`\.json$`)
32if frr := string(fr.Find([]byte(f.Name()))); frr == "" {
33es := fmt.Sprintf("File %s skipped, not valid file extension", f.Name())
34LogConsole.Error(es)
35continue
36}
37DeviceFiles = append(DeviceFiles, f.Name())
38}
39}
40
41func ReadDevice(Dev *DeviceList) {
42for _, f := range DeviceFiles {
43filepath := fmt.Sprintf("%s/%s", ConfigV.GetString("path.devices"), f)
44jsonFile, err := os.Open(filepath)
45if err != nil {
46es := fmt.Sprintf("Error file Open %s, Error:%s, Skip file", f, err.Error())
47LogConsole.Error(es)
48continue
49}
50defer jsonFile.Close()
51
52byteValueFromFile, err := ioutil.ReadAll(jsonFile)
53if err != nil {
54
55es := fmt.Sprintf("Error file Read %s, Error:%s, Skip file", f, err.Error())
56LogConsole.Error(es)
57jsonFile.Close()
58continue
59}
60var d Device
61err = json.Unmarshal(byteValueFromFile, &d)
62if err != nil {
63es := fmt.Sprintf("Error Read file json %s, Error:%s, Skip file", f, err.Error())
64LogConsole.Error(es)
65jsonFile.Close()
66continue
67}
68d.Name = f[:len(f)-5]
69d.LogConfig()
70SetDefaultParameter(&d)
71
72MDeviceList[d.Name] = d
73Dev.Devices = append(Dev.Devices, d)
74}
75}
76
77func RotateDevice(device *DeviceList) {
78LogConsole.Info("Rotate device list...")
79
80for i, d := range device.Devices {
81d.LogDebug("RotateDevice: check directory backup", d.Name, d.Dirbackup)
82if _, err := os.Stat(d.Dirbackup); os.IsNotExist(err) {
83_ = os.Mkdir(d.Dirbackup, os.ModePerm)
84LogConsole.Info(fmt.Sprintf("Create Folder %s for backup", d.Dirbackup))
85continue
86}
87d.LogDebug("RotateDevice: read folder backup", d.Name, d.Dirbackup)
88files, err := ioutil.ReadDir(d.Dirbackup)
89if err != nil {
90es := fmt.Sprintf("Error read folder backup %s, Error:%s", d.Dirbackup, err.Error())
91LogConsole.Error(es)
92device.Devices[i].StatusJob = "skip"
93continue
94}
95d.LogDebug("RotateDevice: Find old backup", d.Name, d.Dirbackup)
96for _, f := range files {
97d.LogDebug(fmt.Sprintf("RotateDevice: Check File %s, time %s", f.Name(), f.ModTime().String()))
98now := time.Now()
99fdifftimesecond := now.Sub(f.ModTime()).Seconds()
100diffday := fdifftimesecond / 60 / 60 / 24
101if int(diffday) > d.Rotate {
102d.LogDebug(fmt.Sprintf("RotateDevice: File %s old backup for device %s", f.Name(), d.Name))
103if len(files) > 5 {
104d.LogDebug("RotateDevice: File Count > 5 in backup", d.Name)
105d.LogDebug("RotateDevice: Remove old files", f.Name())
106filename := fmt.Sprintf("%s/%s", d.Dirbackup, f.Name())
107err := os.Remove(filename)
108if err != nil {
109es := fmt.Sprintf("Error Remove file %s, Error:%s", f.Name(), err.Error())
110LogConsole.Error(es)
111continue
112}
113if err := gitClient.RemoveFile(filename); err != nil {
114d.LogWarn(err)
115continue
116}
117}
118
119}
120if int(fdifftimesecond) < d.Every {
121d.LogDebug(fmt.Sprintf("RotateDevice: control check file time (%f), need time (%d)", fdifftimesecond, d.Every))
122d.LogDebug("RotateDevice: Device no need backup", d.Name)
123device.Devices[i].StatusJob = "skip"
124break
125}
126
127}
128
129}
130/*
131newDev := DeviceList{}
132for _, d := range device.Devices {
133if d.Name == "" {
134continue
135}
136newDev.Devices = append(newDev.Devices, d)
137}
138device.Devices = newDev.Devices
139*/
140}
141
142func RunBackups(Dev *DeviceList) {
143LogConsole.Info("Backup Start ---->")
144//todo need create dynamic group, curent group 10 and wait all execute after next 10.
145//todo need if one exit group, send one next to group
146wp := workerpool.New(ConfigV.GetInt("process.max"))
147for _, d := range Dev.Devices {
148d := d
149if d.StatusJob == "skip" {
150d.Hook()
151continue
152}
153d.LogDebug("RunBackups: wait groups", d.Name)
154wp.Submit(func() {
155d.LogDebug("RunBackups: enter groups", d.Name)
156backup(&d)
157d.Hook()
158})
159d.LogDebug("RunBackups: Exit groups", d.Name)
160}
161wp.StopWait()
162LogConsole.Info("Backup Finish <----")
163}
164
165func backup(device *Device) {
166
167LogConsole.Warn(fmt.Sprintf("Starting backup %s ...", device.Name))
168device.LogDebug("Starting backup ", device.Name)
169var bytefromsshclient []byte
170
171if device.Parent != "" {
172device.LogDebug("backup: parent exist ", device.Name)
173parent, child, err := SshNeedForward(device)
174if err != nil {
175ers := fmt.Sprintf("Fatal error Device:%s get parent %s error: %s", device.Name, device.Parent, err.Error())
176LogConsole.Error(ers)
177device.LogError(ers)
178device.StatusJob = "error"
179return
180}
181
182newd := SshForwardNewDevice(parent, child)
183
184bytefromsshclient, err = SshClientRun(&newd)
185if err != nil {
186ers := fmt.Sprintf("Fatal error Forward Device:%s: %s", device.Name, err.Error())
187LogConsole.Error(ers)
188device.LogError(ers)
189device.StatusJob = "error"
190return
191}
192} else {
193device.LogDebug("backup: no parent ", device.Name)
194bytefromssh, err := SshClientRun(device)
195if err != nil {
196ers := fmt.Sprintf("Fatal error Device:%s: %s", device.Name, err.Error())
197LogConsole.Error(ers)
198device.LogError(ers)
199device.StatusJob = "error"
200return
201}
202bytefromsshclient = bytefromssh
203}
204
205if bytefromsshclient == nil {
206ers := fmt.Sprintf("Fatal error Device:%s not bytes for backup", device.Name)
207LogConsole.Error(ers)
208device.LogError(ers)
209device.StatusJob = "error"
210return
211}
212err := SaveBackupFile(device, bytefromsshclient)
213if err != nil {
214ers := fmt.Sprintf("Bad saved config device %s Error: %s", device.Name, err.Error())
215LogConsole.Error(ers)
216device.LogError(ers)
217device.StatusJob = "error"
218return
219}
220device.StatusJob = "backup"
221device.LogInfo("Backup complete")
222
223}
224
225func SaveBackupFile(device *Device, b []byte) error {
226
227device.LogDebug(fmt.Sprintf("SaveBackupFile: saved backups... %s", device.Name))
228backupfile := fmt.Sprintf("%s/%s", device.Dirbackup, device.BackupFileName)
229FileBackupExist := FileExistBool(backupfile)
230result := b
231if device.Clearstring != "" {
232device.LogDebug(fmt.Sprintf("SaveBackupFile: Need clear string in config... %s", device.Name))
233result = RemoveStringFromBakcup(device, b)
234}
235if FileBackupExist == true {
236com, err := FileCompareByteBool(backupfile, result)
237if err != nil {
238return err
239}
240if com == true {
241return nil
242}
243}
244
245var fn *os.File
246
247var err error
248if FileBackupExist == false {
249device.LogDebug(fmt.Sprintf("SaveBackupFile: Create file... %s", backupfile))
250fn, err = os.Create(backupfile)
251if err != nil {
252return errors.New(fmt.Sprintf("SaveBackupFile: Create file Error:%s", err.Error()))
253}
254} else {
255fn, err = os.OpenFile(backupfile, os.O_RDWR|os.O_CREATE, 0755)
256if err != nil {
257return errors.New(fmt.Sprintf("SaveBackupFile: Open file Error:%s", err.Error()))
258}
259}
260
261device.LogDebug(fmt.Sprintf("SaveBackupFile: Write to file... %s", backupfile))
262_, err = fn.Write(result)
263if err != nil {
264return errors.New(fmt.Sprintf("SaveBackupFile: Write to file Error:%s", err.Error()))
265}
266device.LogDebug(fmt.Sprintf("SaveBackupFile: Close file... %s", backupfile))
267_ = fn.Close()
268if FileBackupExist {
269//CommitName := fmt.Sprintf("Change backup in device %s", device.Name)
270if err := gitClient.SetCommit(backupfile); err != nil {
271device.LogWarn(err)
272LogConsole.Error(err)
273return err
274}
275
276} else {
277if err := gitClient.AddFile(backupfile); err != nil {
278device.LogWarn(err)
279LogConsole.Error(err)
280return err
281}
282}
283
284return nil
285}
286
287func RemoveStringFromBakcup(device *Device, b []byte) []byte {
288device.LogDebug(fmt.Sprintf("RemoveStringFromBackup: ... %s", device.Name))
289device.LogDebug(fmt.Sprintf("RemoveStringFromBackup: ... %s", device.Name))
290regstr := fmt.Sprintf(`(?m:^%s.*$)`, device.Clearstring)
291device.LogDebug(fmt.Sprintf("RemoveStringFromBackup: regexp %s", regstr))
292re := regexp.MustCompile(regstr)
293device.LogDebug(fmt.Sprintf("RemoveStringFromBackup: replace string %s", device.Name))
294config := re.ReplaceAllString(string(b), "")
295config = strings.Trim(config, "\r\n")
296device.LogDebug(fmt.Sprintf("RemoveStringFromBackup: Remove empty string %s", device.Name))
297return []byte(config)
298}
299
300func SetDefaultParameter(d *Device) {
301
302if d.Timeout == 0 {
303
304d.Timeout = ConfigV.GetInt("devicedefault.timeout")
305d.LogDebug("SetDefaultParameter: Set default Timeout ", d.Name, d.Timeout)
306}
307if d.Every == 0 {
308
309d.Every = ConfigV.GetInt("devicedefault.every")
310
311d.LogDebug("SetDefaultParameter: Set default Every ", d.Name, d.Every)
312}
313if d.Rotate == 0 {
314
315d.Rotate = ConfigV.GetInt("devicedefault.rotate")
316d.LogDebug("SetDefaultParameter: Set default Rotate ", d.Name, d.Rotate)
317}
318if d.Command == "" {
319
320d.Command = ConfigV.GetString("devicedefault.command")
321d.LogDebug("SetDefaultParameter: Set default Command ", d.Name, d.Command)
322}
323if d.PortSSH == 0 {
324d.LogDebug("SetDefaultParameter: Set default PortSSH", d.Name)
325p, err := strconv.Atoi(ConfigV.GetString("devicedefault.portshh"))
326if err != nil {
327
328d.PortSSH = 22
329d.LogDebug("SetDefaultParameter: Error parse ssh port field", d.PortSSH)
330}
331
332if err == nil || p < 65535 || p > 0 {
333d.PortSSH = uint16(p)
334d.LogDebug("SetDefaultParameter: Set default PortSSH ", d.Name, d.PortSSH)
335} else {
336
337d.PortSSH = 22
338d.LogDebug("SetDefaultParameter: Error port ssh not range 1-65535", d.Name, d.PortSSH)
339}
340}
341d.Authkey = false
342if d.Key != "" {
343d.LogDebug("SetDefaultParameter: Need use private key uniq ", d.Name, d.Key)
344d.Authkey = true
345}
346
347if d.Authkey == false && d.Password == "" && d.Key != "" {
348d.LogDebug("SetDefaultParameter: Need use private key uniq ", d.Name, d.Key)
349d.Authkey = true
350}
351if d.Authkey == false && d.Password == "" && d.Key == "" && ConfigV.GetString("devicedefault.key") != "" {
352
353d.Authkey = true
354d.Key = ConfigV.GetString("devicedefault.key")
355d.LogDebug("SetDefaultParameter: Need use private key default ", d.Name, d.Key)
356}
357
358if d.TimeFormat == "" {
359d.TimeFormat = ConfigV.GetString("devicedefault.timeformat")
360d.LogDebug("SetDefaultParameter: Set default time format ", d.Name, d.TimeFormat)
361}
362
363if d.Prefix == "" {
364d.Prefix = ConfigV.GetString("devicedefault.prefix")
365d.LogDebug("SetDefaultParameter: Set default Prefix", d.Name, d.Prefix)
366}
367if d.FileNameFormat == "" {
368d.FileNameFormat = ConfigV.GetString("devicedefault.filenameformat")
369d.LogDebug("SetDefaultParameter: Set default FileNameFormat", d.Name, d.FileNameFormat)
370}
371
372if d.Clearstring == "" {
373d.Clearstring = ConfigV.GetString("devicedefault.clearstring")
374d.LogDebug("SetDefaultParameter: Set default Clear string", d.Name, d.Clearstring)
375}
376d.Dirbackup = fmt.Sprintf("%s/%s", ConfigV.GetString("path.backup"), d.Name)
377ditetimestring := time.Now().Format(d.TimeFormat)
378nameinprefix := strings.ReplaceAll(d.FileNameFormat, "%p", d.Prefix)
379nameintime := strings.ReplaceAll(nameinprefix, "%t", ditetimestring)
380nameinname := strings.ReplaceAll(nameintime, "%n", d.Name)
381d.BackupFileName = nameinname
382d.LogDebug("SetDefaultParameter: Set default BackupFileName", d.Name, d.BackupFileName)
383if d.DeviceHooks.Error == "" {
384d.DeviceHooks.Error = ConfigV.GetString("devicedefault.hook.error")
385d.LogDebug(fmt.Sprintf("SetDefaultParameter: Set default devicedefault.hook.error Velue %s in Device %s", d.DeviceHooks.Error, d.Name))
386}
387if d.DeviceHooks.Backup == "" {
388d.DeviceHooks.Backup = ConfigV.GetString("devicedefault.hook.backup")
389d.LogDebug(fmt.Sprintf("SetDefaultParameter: Set default devicedefault.hook.backup Velue %s in Device %s", d.DeviceHooks.Backup, d.Name))
390}
391if d.DeviceHooks.Skip == "" {
392d.DeviceHooks.Skip = ConfigV.GetString("devicedefault.hook.skip")
393d.LogDebug(fmt.Sprintf("SetDefaultParameter: Set default devicedefault.hook.skip Velue %s in Device %s", d.DeviceHooks.Skip, d.Name))
394}
395}
396