mirror of
https://github.com/tizbac/proxmoxbackupclient_go.git
synced 2025-10-26 11:19:03 +00:00
Refactor into modules
Signed-off-by: Tiziano Bacocco <tizbac2@gmail.com>
This commit is contained in:
parent
4561e095aa
commit
c92b59b66f
@ -1,3 +1,4 @@
|
||||
set CGO_ENABLED=1
|
||||
set GOOS=windows
|
||||
go build -o proxmoxbackupgo_cli.exe
|
||||
set GOEXPERIMENT=nodwarf5
|
||||
go build -o proxmoxbackupgo_cli.exe ./directorybackup
|
||||
|
||||
5
clientcommon/go.mod
Normal file
5
clientcommon/go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module clientcommon
|
||||
|
||||
go 1.25.2
|
||||
|
||||
require github.com/rodolfoag/gow32 v0.0.0-20230512144032-1e896a3c51aa
|
||||
2
clientcommon/go.sum
Normal file
2
clientcommon/go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
github.com/rodolfoag/gow32 v0.0.0-20230512144032-1e896a3c51aa h1:cd9mmDEXO4YxGYTbrhbfEt7btgUlcXFedTMoZ9fA4Ns=
|
||||
github.com/rodolfoag/gow32 v0.0.0-20230512144032-1e896a3c51aa/go.mod h1:w/ebPUfAcyZMYjstwPIWTEGSahChHx5R3Y+xElrvxDc=
|
||||
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package clientcommon
|
||||
|
||||
var ICON = []byte{
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x30, 0x30, 0x10, 0x00, 0x01, 0x00,
|
||||
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package clientcommon
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
@ -20,7 +20,7 @@ func (a unencryptedAuth) Start(server *smtp.ServerInfo) (string, []byte, error)
|
||||
return a.Auth.Start(&s)
|
||||
}
|
||||
|
||||
func setupClient(host, port, username, password string, allowInsecure bool) (*smtp.Client, error) {
|
||||
func SetupMailClient(host, port, username, password string, allowInsecure bool) (*smtp.Client, error) {
|
||||
var auth smtp.Auth
|
||||
auth = smtp.PlainAuth("", username, password, host)
|
||||
if port == "25" {
|
||||
@ -75,7 +75,7 @@ func setupClient(host, port, username, password string, allowInsecure bool) (*sm
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func sendMail(from, to, subject, body string, c *smtp.Client) error {
|
||||
func SendMail(from, to, subject, body string, c *smtp.Client) error {
|
||||
// Setup headers
|
||||
headers := make(map[string]string)
|
||||
headers["From"] = from
|
||||
@ -122,7 +122,7 @@ func sendMail(from, to, subject, body string, c *smtp.Client) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type mailCtx struct {
|
||||
type MailCtx struct {
|
||||
NewChunks uint64
|
||||
ReusedChunks uint64
|
||||
Datastore string
|
||||
@ -132,33 +132,33 @@ type mailCtx struct {
|
||||
EndTime time.Time
|
||||
}
|
||||
|
||||
func (m *mailCtx) Duration() time.Duration {
|
||||
func (m *MailCtx) Duration() time.Duration {
|
||||
return m.EndTime.Sub(m.StartTime)
|
||||
}
|
||||
|
||||
func (m *mailCtx) FromattedDuration() string {
|
||||
func (m *MailCtx) FromattedDuration() string {
|
||||
return m.Duration().String()
|
||||
}
|
||||
|
||||
func (m *mailCtx) ErrorStr() string {
|
||||
func (m *MailCtx) ErrorStr() string {
|
||||
if m.Error != nil {
|
||||
return m.Error.Error()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *mailCtx) Success() bool {
|
||||
func (m *MailCtx) Success() bool {
|
||||
return m.Error == nil
|
||||
}
|
||||
|
||||
func (m *mailCtx) Status() string {
|
||||
func (m *MailCtx) Status() string {
|
||||
if m.Success() {
|
||||
return "Success"
|
||||
}
|
||||
return "Failed"
|
||||
}
|
||||
|
||||
func (m *mailCtx) buildStr(txt string) (string, error) {
|
||||
func (m *MailCtx) BuildStr(txt string) (string, error) {
|
||||
tmpl, err := template.New("mail").Parse(txt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -1,7 +1,7 @@
|
||||
//go:build linux || darwin || freebsd || openbsd
|
||||
// +build linux darwin freebsd openbsd
|
||||
|
||||
package main
|
||||
package clientcommon
|
||||
|
||||
type Locking struct {
|
||||
mutexid uintptr
|
||||
@ -1,22 +1,25 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
package main
|
||||
|
||||
import "github.com/rodolfoag/gow32"
|
||||
import "syscall"
|
||||
package clientcommon
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/rodolfoag/gow32"
|
||||
)
|
||||
|
||||
const MutexName = "proxmoxbackupclient_go"
|
||||
|
||||
|
||||
type Locking struct {
|
||||
mutexid uintptr
|
||||
}
|
||||
|
||||
func (l *Locking) AcquireProcessLock() bool {
|
||||
mutexid , err := gow32.CreateMutex(MutexName)
|
||||
mutexid, err := gow32.CreateMutex(MutexName)
|
||||
if err != nil {
|
||||
if exitcode := int(err.(syscall.Errno)); exitcode == gow32.ERROR_ALREADY_EXISTS {
|
||||
return false
|
||||
return false
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@ -24,6 +27,6 @@ func (l *Locking) AcquireProcessLock() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (l * Locking) ReleaseProcessLock() {
|
||||
func (l *Locking) ReleaseProcessLock() {
|
||||
gow32.ReleaseMutex(l.mutexid)
|
||||
}
|
||||
}
|
||||
@ -36,13 +36,13 @@ type Config struct {
|
||||
Namespace string `json:"namespace"`
|
||||
BackupID string `json:"backup-id"`
|
||||
BackupSourceDir string `json:"backupdir"`
|
||||
BackupStreamName string `json:"backupstreamname"`
|
||||
BackupStreamName string `json:"backupstreamname"`
|
||||
PxarOut string `json:"pxarout"`
|
||||
SMTP *SMTPConfig `json:"smtp"`
|
||||
}
|
||||
|
||||
func (c *Config) valid() bool {
|
||||
baseValid := c.BaseURL != "" && c.AuthID != "" && c.Secret != "" && c.Datastore != "" && ( c.BackupSourceDir != "" || c.BackupStreamName != "" )
|
||||
baseValid := c.BaseURL != "" && c.AuthID != "" && c.Secret != "" && c.Datastore != "" && (c.BackupSourceDir != "" || c.BackupStreamName != "")
|
||||
if !baseValid {
|
||||
return baseValid
|
||||
}
|
||||
@ -1,35 +1,37 @@
|
||||
module proxmoxbackupgo
|
||||
module directorybackup
|
||||
|
||||
go 1.19
|
||||
go 1.25.2
|
||||
|
||||
require (
|
||||
github.com/cornelk/hashmap v1.0.8
|
||||
github.com/dchest/siphash v1.2.3
|
||||
github.com/gen2brain/beeep v0.0.0-20230907135156-1a38885a97fc
|
||||
github.com/getlantern/systray v1.2.2
|
||||
github.com/jeromehadorn/vss v0.1.0
|
||||
github.com/klauspost/compress v1.17.4
|
||||
github.com/rodolfoag/gow32 v0.0.0-20230512144032-1e896a3c51aa
|
||||
github.com/tawesoft/golib/v2 v2.10.0
|
||||
golang.org/x/net v0.19.0
|
||||
github.com/gen2brain/beeep v0.11.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/alessio/shellescape v1.4.1 // indirect
|
||||
github.com/alessio/shellescape v1.4.2 // indirect
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect
|
||||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect
|
||||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
|
||||
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
git.sr.ht/~jackmordaunt/go-toast v1.1.2 // indirect
|
||||
github.com/esiqveland/notify v0.13.3 // indirect
|
||||
github.com/getlantern/systray v1.2.2
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/jackmordaunt/icns/v3 v3.0.1 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/sergeymakinen/go-bmp v1.0.0 // indirect
|
||||
github.com/sergeymakinen/go-ico v1.0.0-beta.0 // indirect
|
||||
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
|
||||
github.com/tawesoft/golib/v2 v2.16.0
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
)
|
||||
69
directorybackup/go.sum
Normal file
69
directorybackup/go.sum
Normal file
@ -0,0 +1,69 @@
|
||||
git.sr.ht/~jackmordaunt/go-toast v1.1.2 h1:/yrfI55LRt1M7H1vkaw+NaH1+L1CDxrqDltwm5euVuE=
|
||||
git.sr.ht/~jackmordaunt/go-toast v1.1.2/go.mod h1:jA4OqHKTQ4AFBdwrSnwnskUIIS3HYzlJSgdzCKqfavo=
|
||||
github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4uEoM0=
|
||||
github.com/alessio/shellescape v1.4.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
|
||||
github.com/cornelk/hashmap v1.0.8 h1:nv0AWgw02n+iDcawr5It4CjQIAcdMMKRrs10HOJYlrc=
|
||||
github.com/cornelk/hashmap v1.0.8/go.mod h1:RfZb7JO3RviW/rT6emczVuC/oxpdz4UsSB2LJSclR1k=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/esiqveland/notify v0.13.3 h1:QCMw6o1n+6rl+oLUfg8P1IIDSFsDEb2WlXvVvIJbI/o=
|
||||
github.com/esiqveland/notify v0.13.3/go.mod h1:hesw/IRYTO0x99u1JPweAl4+5mwXJibQVUcP0Iu5ORE=
|
||||
github.com/gen2brain/beeep v0.11.1 h1:EbSIhrQZFDj1K2fzlMpAYlFOzV8YuNe721A58XcCTYI=
|
||||
github.com/gen2brain/beeep v0.11.1/go.mod h1:jQVvuwnLuwOcdctHn/uyh8horSBNJ8uGb9Cn2W4tvoc=
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
|
||||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So=
|
||||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
|
||||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk=
|
||||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc=
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA=
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||
github.com/getlantern/systray v1.2.2 h1:dCEHtfmvkJG7HZ8lS/sLklTH4RKUcIsKrAD9sThoEBE=
|
||||
github.com/getlantern/systray v1.2.2/go.mod h1:pXFOI1wwqwYXEhLPm9ZGjS2u/vVELeIgNMY5HvhHhcE=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/jackmordaunt/icns/v3 v3.0.1 h1:xxot6aNuGrU+lNgxz5I5H0qSeCjNKp8uTXB1j8D4S3o=
|
||||
github.com/jackmordaunt/icns/v3 v3.0.1/go.mod h1:5sHL59nqTd2ynTnowxB/MDQFhKNqkK8X687uKNygaSQ=
|
||||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sergeymakinen/go-bmp v1.0.0 h1:SdGTzp9WvCV0A1V0mBeaS7kQAwNLdVJbmHlqNWq0R+M=
|
||||
github.com/sergeymakinen/go-bmp v1.0.0/go.mod h1:/mxlAQZRLxSvJFNIEGGLBE/m40f3ZnUifpgVDlcUIEY=
|
||||
github.com/sergeymakinen/go-ico v1.0.0-beta.0 h1:m5qKH7uPKLdrygMWxbamVn+tl2HfiA3K6MFJw4GfZvQ=
|
||||
github.com/sergeymakinen/go-ico v1.0.0-beta.0/go.mod h1:wQ47mTczswBO5F0NoDt7O0IXgnV4Xy3ojrroMQzyhUk=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
|
||||
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
|
||||
github.com/tawesoft/golib/v2 v2.16.0 h1:QJPqTFPVz++45fTVyP66o8IfCfz8MYgTrn6nypVLv2o=
|
||||
github.com/tawesoft/golib/v2 v2.16.0/go.mod h1:S+cpYdLd1NwKQmWnycfIJqJegOek/Zz+JY9FH7EJTWs=
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg=
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"clientcommon"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
@ -10,7 +11,9 @@ import (
|
||||
"hash"
|
||||
"io"
|
||||
"os"
|
||||
"pbscommon"
|
||||
"runtime"
|
||||
"snapshot"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@ -21,8 +24,6 @@ import (
|
||||
"github.com/tawesoft/golib/v2/dialog"
|
||||
)
|
||||
|
||||
|
||||
|
||||
var defaultMailSubjectTemplate = "Backup {{.Status}}"
|
||||
var defaultMailBodyTemplate = `{{if .Success}}Backup complete ({{.FromattedDuration}})
|
||||
Chunks New {{.NewChunks}}, Reused {{.ReusedChunks}}.{{else}}Error occurred while working, backup may be not completed.
|
||||
@ -38,10 +39,10 @@ type ChunkState struct {
|
||||
chunkcount uint64
|
||||
chunkdigests hash.Hash
|
||||
current_chunk []byte
|
||||
C Chunker
|
||||
newchunk *atomic.Uint64
|
||||
reusechunk *atomic.Uint64
|
||||
knownChunks *hashmap.Map[string, bool]
|
||||
C pbscommon.Chunker
|
||||
newchunk *atomic.Uint64
|
||||
reusechunk *atomic.Uint64
|
||||
knownChunks *hashmap.Map[string, bool]
|
||||
}
|
||||
|
||||
type DidxEntry struct {
|
||||
@ -49,25 +50,25 @@ type DidxEntry struct {
|
||||
digest []byte
|
||||
}
|
||||
|
||||
func (c *ChunkState) Init(newchunk *atomic.Uint64 , reusechunk *atomic.Uint64, knownChunks *hashmap.Map[string, bool] ) {
|
||||
func (c *ChunkState) Init(newchunk *atomic.Uint64, reusechunk *atomic.Uint64, knownChunks *hashmap.Map[string, bool]) {
|
||||
c.assignments = make([]string, 0)
|
||||
c.assignments_offset = make([]uint64, 0)
|
||||
c.pos = 0
|
||||
c.chunkcount = 0
|
||||
c.chunkdigests = sha256.New()
|
||||
c.current_chunk = make([]byte, 0)
|
||||
c.C = Chunker{}
|
||||
c.C = pbscommon.Chunker{}
|
||||
c.C.New(1024 * 1024 * 4)
|
||||
c.reusechunk = reusechunk
|
||||
c.newchunk = newchunk
|
||||
c.knownChunks = knownChunks
|
||||
}
|
||||
|
||||
func (c *ChunkState) HandleData(b []byte, client *PBSClient){
|
||||
func (c *ChunkState) HandleData(b []byte, client *pbscommon.PBSClient) {
|
||||
chunkpos := c.C.Scan(b)
|
||||
|
||||
if chunkpos == 0 {
|
||||
//No break happened, just append data
|
||||
//No break happened, just append data
|
||||
c.current_chunk = append(c.current_chunk, b...)
|
||||
} else {
|
||||
|
||||
@ -102,9 +103,9 @@ func (c *ChunkState) HandleData(b []byte, client *PBSClient){
|
||||
c.chunkcount += 1
|
||||
|
||||
c.current_chunk = make([]byte, 0)
|
||||
b = b[chunkpos:] //Take remainder of data
|
||||
b = b[chunkpos:] //Take remainder of data
|
||||
chunkpos = c.C.Scan(b)
|
||||
|
||||
|
||||
}
|
||||
|
||||
//No further break happened, append remaining data
|
||||
@ -112,9 +113,9 @@ func (c *ChunkState) HandleData(b []byte, client *PBSClient){
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ChunkState) Eof(client *PBSClient) {
|
||||
func (c *ChunkState) Eof(client *pbscommon.PBSClient) {
|
||||
//Here we write the remainder of data for which cyclic hash did not trigger
|
||||
|
||||
|
||||
if len(c.current_chunk) > 0 {
|
||||
h := sha256.New()
|
||||
_, err := h.Write(c.current_chunk)
|
||||
@ -152,8 +153,6 @@ func (c *ChunkState) Eof(client *PBSClient) {
|
||||
client.CloseDynamicIndex(c.wrid, hex.EncodeToString(c.chunkdigests.Sum(nil)), c.pos, c.chunkcount)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func main() {
|
||||
var newchunk *atomic.Uint64 = new(atomic.Uint64)
|
||||
var reusechunk *atomic.Uint64 = new(atomic.Uint64)
|
||||
@ -175,19 +174,18 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
L := Locking{}
|
||||
L := clientcommon.Locking{}
|
||||
|
||||
|
||||
lock_ok := L.AcquireProcessLock()
|
||||
if !lock_ok {
|
||||
|
||||
|
||||
dialog.Error("Backup jobs need to run exclusively, please wait until the previous job has finished")
|
||||
os.Exit(2)
|
||||
}
|
||||
defer L.ReleaseProcessLock()
|
||||
if runtime.GOOS == "windows" {
|
||||
go systray.Run(func() {
|
||||
systray.SetIcon(ICON)
|
||||
systray.SetIcon(clientcommon.ICON)
|
||||
systray.SetTooltip("PBSGO Backup running")
|
||||
beeep.Notify("Proxmox Backup Go", "Backup started", "")
|
||||
},
|
||||
@ -195,19 +193,18 @@ func main() {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
insecure := cfg.CertFingerprint != ""
|
||||
|
||||
client := &PBSClient{
|
||||
baseurl: cfg.BaseURL,
|
||||
certfingerprint: cfg.CertFingerprint, //"ea:7d:06:f9:87:73:a4:72:d0:e8:05:a4:b3:3d:95:d7:0a:26:dd:6d:5c:ca:e6:99:83:e4:11:3b:5f:10:f4:4b",
|
||||
authid: cfg.AuthID,
|
||||
secret: cfg.Secret,
|
||||
datastore: cfg.Datastore,
|
||||
namespace: cfg.Namespace,
|
||||
insecure: insecure,
|
||||
manifest: BackupManifest{
|
||||
client := &pbscommon.PBSClient{
|
||||
BaseURL: cfg.BaseURL,
|
||||
CertFingerPrint: cfg.CertFingerprint, //"ea:7d:06:f9:87:73:a4:72:d0:e8:05:a4:b3:3d:95:d7:0a:26:dd:6d:5c:ca:e6:99:83:e4:11:3b:5f:10:f4:4b",
|
||||
AuthID: cfg.AuthID,
|
||||
Secret: cfg.Secret,
|
||||
Datastore: cfg.Datastore,
|
||||
Namespace: cfg.Namespace,
|
||||
Insecure: insecure,
|
||||
Manifest: pbscommon.BackupManifest{
|
||||
BackupID: cfg.BackupID,
|
||||
},
|
||||
}
|
||||
@ -222,20 +219,19 @@ func main() {
|
||||
err = backup(client, newchunk, reusechunk, cfg.PxarOut, cfg.BackupSourceDir)
|
||||
} else if cfg.BackupStreamName != "" {
|
||||
sn := cfg.BackupStreamName
|
||||
if ! strings.HasSuffix(sn, ".didx" ) {
|
||||
if !strings.HasSuffix(sn, ".didx") {
|
||||
sn += ".didx"
|
||||
}
|
||||
fmt.Printf("Backing up from STDIN to %s", sn)
|
||||
err = backup_stream(client, newchunk, reusechunk, sn, os.Stdin )
|
||||
err = backup_stream(client, newchunk, reusechunk, sn, os.Stdin)
|
||||
|
||||
}else{
|
||||
} else {
|
||||
panic("No backup dir or stream name specified, exiting")
|
||||
}
|
||||
|
||||
|
||||
end := time.Now()
|
||||
|
||||
mailCtx := mailCtx{
|
||||
mailCtx := clientcommon.MailCtx{
|
||||
NewChunks: newchunk.Load(),
|
||||
ReusedChunks: reusechunk.Load(),
|
||||
Error: err,
|
||||
@ -252,10 +248,10 @@ func main() {
|
||||
|
||||
fmt.Printf("New %d, Reused %d, backup took %s.\n", newchunk.Load(), reusechunk.Load(), end.Sub(begin))
|
||||
var msg string
|
||||
msg, err = mailCtx.buildStr(mailBodyTemplate)
|
||||
msg, err = mailCtx.BuildStr(mailBodyTemplate)
|
||||
if err != nil {
|
||||
fmt.Println("Cannot use custom mail body: " + err.Error())
|
||||
msg, err = mailCtx.buildStr(defaultMailBodyTemplate)
|
||||
msg, err = mailCtx.BuildStr(defaultMailBodyTemplate)
|
||||
if err != nil {
|
||||
// this should never happen
|
||||
panic(err)
|
||||
@ -273,23 +269,23 @@ func main() {
|
||||
mailSubjectTemplate = cfg.SMTP.Template.Subject
|
||||
}
|
||||
|
||||
subject, err = mailCtx.buildStr(mailSubjectTemplate)
|
||||
subject, err = mailCtx.BuildStr(mailSubjectTemplate)
|
||||
if err != nil {
|
||||
fmt.Println("Cannot use custom mail subject: " + err.Error())
|
||||
msg, err = mailCtx.buildStr(defaultMailSubjectTemplate)
|
||||
msg, err = mailCtx.BuildStr(defaultMailSubjectTemplate)
|
||||
if err != nil {
|
||||
// this should never happen
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
client, err := setupClient(cfg.SMTP.Host, cfg.SMTP.Port, cfg.SMTP.Username, cfg.SMTP.Password, cfg.SMTP.Insecure)
|
||||
client, err := clientcommon.SetupMailClient(cfg.SMTP.Host, cfg.SMTP.Port, cfg.SMTP.Username, cfg.SMTP.Password, cfg.SMTP.Insecure)
|
||||
if err != nil {
|
||||
fmt.Println("Cannot connect to mail server: " + err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
defer client.Quit()
|
||||
for _, ccc := range cfg.SMTP.Mails {
|
||||
err = sendMail(ccc.From, ccc.To, subject, msg, client)
|
||||
err = clientcommon.SendMail(ccc.From, ccc.To, subject, msg, client)
|
||||
if err != nil {
|
||||
fmt.Println("Cannot send email: " + err.Error())
|
||||
os.Exit(1)
|
||||
@ -299,7 +295,7 @@ func main() {
|
||||
|
||||
}
|
||||
|
||||
func backup_stream(client *PBSClient, newchunk, reusechunk *atomic.Uint64, filename string, stream io.Reader ) error {
|
||||
func backup_stream(client *pbscommon.PBSClient, newchunk, reusechunk *atomic.Uint64, filename string, stream io.Reader) error {
|
||||
knownChunks := hashmap.New[string, bool]()
|
||||
client.Connect(false)
|
||||
previousDidx, err := client.DownloadPreviousToBytes(filename)
|
||||
@ -337,11 +333,11 @@ func backup_stream(client *PBSClient, newchunk, reusechunk *atomic.Uint64, filen
|
||||
}
|
||||
B := make([]byte, 65536)
|
||||
for {
|
||||
|
||||
|
||||
n, err := stream.Read(B)
|
||||
|
||||
|
||||
b := B[:n]
|
||||
|
||||
|
||||
streamChunk.HandleData(b, client)
|
||||
|
||||
if err == io.EOF {
|
||||
@ -361,21 +357,22 @@ func backup_stream(client *PBSClient, newchunk, reusechunk *atomic.Uint64, filen
|
||||
return client.Finish()
|
||||
}
|
||||
|
||||
func backup(client *PBSClient, newchunk, reusechunk *atomic.Uint64, pxarOut string, backupdir string) error {
|
||||
func backup(client *pbscommon.PBSClient, newchunk, reusechunk *atomic.Uint64, pxarOut string, backupdir string) error {
|
||||
knownChunks := hashmap.New[string, bool]()
|
||||
|
||||
fmt.Printf("Starting backup of %s\n", backupdir)
|
||||
|
||||
backupdir = createVSSSnapshot(backupdir)
|
||||
SNAP := snapshot.CreateVSSSnapshot(backupdir)
|
||||
backupdir = SNAP.FullPath
|
||||
//Remove VSS snapshot on windows, on linux for now NOP
|
||||
defer VSSCleanup()
|
||||
defer snapshot.VSSCleanup()
|
||||
|
||||
client.Connect(false)
|
||||
|
||||
archive := &PXARArchive{}
|
||||
archive.archivename = "backup.pxar.didx"
|
||||
archive := &pbscommon.PXARArchive{}
|
||||
archive.ArchiveName = "backup.pxar.didx"
|
||||
|
||||
previousDidx, err := client.DownloadPreviousToBytes(archive.archivename)
|
||||
previousDidx, err := client.DownloadPreviousToBytes(archive.ArchiveName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -426,7 +423,7 @@ func backup(client *PBSClient, newchunk, reusechunk *atomic.Uint64, pxarOut stri
|
||||
pcat1Chunk := ChunkState{}
|
||||
pcat1Chunk.Init(newchunk, reusechunk, knownChunks)
|
||||
|
||||
pxarChunk.wrid, err = client.CreateDynamicIndex(archive.archivename)
|
||||
pxarChunk.wrid, err = client.CreateDynamicIndex(archive.ArchiveName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -435,8 +432,7 @@ func backup(client *PBSClient, newchunk, reusechunk *atomic.Uint64, pxarOut stri
|
||||
return err
|
||||
}
|
||||
|
||||
archive.writeCB = func(b []byte) {
|
||||
|
||||
archive.WriteCB = func(b []byte) {
|
||||
|
||||
if pxarOut != "" {
|
||||
// TODO: error handling inside callback
|
||||
@ -448,7 +444,7 @@ func backup(client *PBSClient, newchunk, reusechunk *atomic.Uint64, pxarOut stri
|
||||
//
|
||||
}
|
||||
|
||||
archive.catalogWriteCB = func(b []byte) {
|
||||
archive.CatalogWriteCB = func(b []byte) {
|
||||
pcat1Chunk.HandleData(b, client)
|
||||
}
|
||||
|
||||
@ -457,12 +453,9 @@ func backup(client *PBSClient, newchunk, reusechunk *atomic.Uint64, pxarOut stri
|
||||
|
||||
archive.WriteDir(backupdir, "", true)
|
||||
|
||||
|
||||
pxarChunk.Eof(client)
|
||||
pcat1Chunk.Eof(client)
|
||||
|
||||
|
||||
|
||||
err = client.UploadManifest()
|
||||
if err != nil {
|
||||
return err
|
||||
6
go.work
Normal file
6
go.work
Normal file
@ -0,0 +1,6 @@
|
||||
go 1.25.2
|
||||
|
||||
use ./clientcommon
|
||||
use ./pbscommon
|
||||
use ./directorybackup
|
||||
use ./snapshot
|
||||
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package pbscommon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
13
pbscommon/go.mod
Normal file
13
pbscommon/go.mod
Normal file
@ -0,0 +1,13 @@
|
||||
module pbscommon
|
||||
|
||||
go 1.25.2
|
||||
|
||||
require (
|
||||
github.com/klauspost/compress v1.18.0
|
||||
golang.org/x/net v0.46.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/dchest/siphash v1.2.3
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
)
|
||||
8
pbscommon/go.sum
Normal file
8
pbscommon/go.sum
Normal file
@ -0,0 +1,8 @@
|
||||
github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=
|
||||
github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package pbscommon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -75,22 +75,22 @@ func (e *AuthErr) Error() string {
|
||||
}
|
||||
|
||||
type PBSClient struct {
|
||||
baseurl string
|
||||
certfingerprint string
|
||||
apitoken string
|
||||
secret string
|
||||
authid string
|
||||
BaseURL string
|
||||
CertFingerPrint string
|
||||
APIToken string
|
||||
Secret string
|
||||
AuthID string
|
||||
|
||||
datastore string
|
||||
namespace string
|
||||
manifest BackupManifest
|
||||
Datastore string
|
||||
Namespace string
|
||||
Manifest BackupManifest
|
||||
|
||||
insecure bool
|
||||
Insecure bool
|
||||
|
||||
client http.Client
|
||||
tlsConfig tls.Config
|
||||
Client http.Client
|
||||
TLSConfig tls.Config
|
||||
|
||||
writersManifest map[uint64]int
|
||||
WritersManifest map[uint64]int
|
||||
}
|
||||
|
||||
var blobCompressedMagic = []byte{49, 185, 88, 66, 111, 182, 163, 127}
|
||||
@ -98,15 +98,15 @@ var blobUncompressedMagic = []byte{66, 171, 56, 7, 190, 131, 112, 161}
|
||||
|
||||
func (pbs *PBSClient) CreateDynamicIndex(name string) (uint64, error) {
|
||||
|
||||
req, err := http.NewRequest("POST", pbs.baseurl+"/dynamic_index", bytes.NewBuffer([]byte(fmt.Sprintf("{\"archive-name\": \"%s\"}", name))))
|
||||
req, err := http.NewRequest("POST", pbs.BaseURL+"/dynamic_index", bytes.NewBuffer([]byte(fmt.Sprintf("{\"archive-name\": \"%s\"}", name))))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
req.Header.Add("Authorization", fmt.Sprintf("PBSAPIToken=%s:%s", pbs.authid, pbs.secret))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("PBSAPIToken=%s:%s", pbs.AuthID, pbs.Secret))
|
||||
req.Header.Set("Content-Type", "application/json; charset=UTF-8")
|
||||
|
||||
resp2, err := pbs.client.Do(req)
|
||||
resp2, err := pbs.Client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making request:", err)
|
||||
return 0, err
|
||||
@ -133,8 +133,8 @@ func (pbs *PBSClient) CreateDynamicIndex(name string) (uint64, error) {
|
||||
Filename: name,
|
||||
Size: 0,
|
||||
}
|
||||
pbs.manifest.Files = append(pbs.manifest.Files, f)
|
||||
pbs.writersManifest[uint64(R.WriterID)] = len(pbs.manifest.Files) - 1
|
||||
pbs.Manifest.Files = append(pbs.Manifest.Files, f)
|
||||
pbs.WritersManifest[uint64(R.WriterID)] = len(pbs.Manifest.Files) - 1
|
||||
return uint64(R.WriterID), nil
|
||||
}
|
||||
|
||||
@ -151,12 +151,12 @@ func (pbs *PBSClient) UploadUncompressedChunk(writerid uint64, digest string, ch
|
||||
q.Add("size", fmt.Sprintf("%d", len(chunkdata)))
|
||||
q.Add("wid", fmt.Sprintf("%d", writerid))
|
||||
|
||||
req, err := http.NewRequest("POST", pbs.baseurl+"/dynamic_chunk?"+q.Encode(), bytes.NewBuffer(outBuffer))
|
||||
req, err := http.NewRequest("POST", pbs.BaseURL+"/dynamic_chunk?"+q.Encode(), bytes.NewBuffer(outBuffer))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp2, err := pbs.client.Do(req)
|
||||
resp2, err := pbs.Client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making request:", err)
|
||||
return err
|
||||
@ -198,9 +198,9 @@ func (pbs *PBSClient) UploadCompressedChunk(writerid uint64, digest string, chun
|
||||
q.Add("size", fmt.Sprintf("%d", len(chunkdata)))
|
||||
q.Add("wid", fmt.Sprintf("%d", writerid))
|
||||
|
||||
req, err := http.NewRequest("POST", pbs.baseurl+"/dynamic_chunk?"+q.Encode(), bytes.NewBuffer(outBuffer))
|
||||
req, err := http.NewRequest("POST", pbs.BaseURL+"/dynamic_chunk?"+q.Encode(), bytes.NewBuffer(outBuffer))
|
||||
|
||||
resp2, err := pbs.client.Do(req)
|
||||
resp2, err := pbs.Client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making request:", err)
|
||||
return err
|
||||
@ -227,12 +227,12 @@ func (pbs *PBSClient) AssignChunks(writerid uint64, digests []string, offsets []
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("PUT", pbs.baseurl+"/dynamic_index", bytes.NewBuffer(jsondata))
|
||||
req, err := http.NewRequest("PUT", pbs.BaseURL+"/dynamic_index", bytes.NewBuffer(jsondata))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json; charset=UTF-8")
|
||||
resp2, err := pbs.client.Do(req)
|
||||
resp2, err := pbs.Client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making request:", err)
|
||||
return err
|
||||
@ -252,20 +252,20 @@ func (pbs *PBSClient) CloseDynamicIndex(writerid uint64, checksum string, totals
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest("POST", pbs.baseurl+"/dynamic_close", bytes.NewBuffer(jsonpayload))
|
||||
req, err := http.NewRequest("POST", pbs.BaseURL+"/dynamic_close", bytes.NewBuffer(jsonpayload))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("Authorization", fmt.Sprintf("PBSAPIToken=%s:%s", pbs.authid, pbs.secret))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("PBSAPIToken=%s:%s", pbs.AuthID, pbs.Secret))
|
||||
req.Header.Set("Content-Type", "application/json; charset=UTF-8")
|
||||
|
||||
resp2, err := pbs.client.Do(req)
|
||||
resp2, err := pbs.Client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making request:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
f := &pbs.manifest.Files[pbs.writersManifest[writerid]]
|
||||
f := &pbs.Manifest.Files[pbs.WritersManifest[writerid]]
|
||||
|
||||
f.Csum = checksum
|
||||
f.Size = int64(totalsize)
|
||||
@ -286,9 +286,9 @@ func (pbs *PBSClient) UploadBlob(name string, data []byte) error {
|
||||
q.Add("encoded-size", fmt.Sprintf("%d", len(out)))
|
||||
q.Add("file-name", name)
|
||||
|
||||
req, _ := http.NewRequest("POST", pbs.baseurl+"/blob?"+q.Encode(), bytes.NewBuffer(out))
|
||||
req, _ := http.NewRequest("POST", pbs.BaseURL+"/blob?"+q.Encode(), bytes.NewBuffer(out))
|
||||
|
||||
resp2, err := pbs.client.Do(req)
|
||||
resp2, err := pbs.Client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making request:", err)
|
||||
return err
|
||||
@ -304,7 +304,7 @@ func (pbs *PBSClient) UploadBlob(name string, data []byte) error {
|
||||
}
|
||||
|
||||
func (pbs *PBSClient) UploadManifest() error {
|
||||
manifestBin, err := json.Marshal(pbs.manifest)
|
||||
manifestBin, err := json.Marshal(pbs.Manifest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -312,12 +312,12 @@ func (pbs *PBSClient) UploadManifest() error {
|
||||
}
|
||||
|
||||
func (pbs *PBSClient) Finish() error {
|
||||
req, err := http.NewRequest("POST", pbs.baseurl+"/finish", nil)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("PBSAPIToken=%s:%s", pbs.authid, pbs.secret))
|
||||
req, err := http.NewRequest("POST", pbs.BaseURL+"/finish", nil)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("PBSAPIToken=%s:%s", pbs.AuthID, pbs.Secret))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp2, err := pbs.client.Do(req)
|
||||
resp2, err := pbs.Client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making request:", err)
|
||||
if err != nil {
|
||||
@ -329,12 +329,12 @@ func (pbs *PBSClient) Finish() error {
|
||||
}
|
||||
|
||||
func (pbs *PBSClient) Connect(reader bool) {
|
||||
pbs.writersManifest = make(map[uint64]int)
|
||||
pbs.tlsConfig = tls.Config{
|
||||
InsecureSkipVerify: pbs.insecure,
|
||||
pbs.WritersManifest = make(map[uint64]int)
|
||||
pbs.TLSConfig = tls.Config{
|
||||
InsecureSkipVerify: pbs.Insecure,
|
||||
}
|
||||
if pbs.insecure {
|
||||
pbs.tlsConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
if pbs.Insecure {
|
||||
pbs.TLSConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
// Extract the peer certificate
|
||||
if len(rawCerts) == 0 {
|
||||
return fmt.Errorf("no certificates presented by the peer")
|
||||
@ -345,7 +345,7 @@ func (pbs *PBSClient) Connect(reader bool) {
|
||||
}
|
||||
|
||||
// Calculate the SHA-256 fingerprint of the certificate
|
||||
expectedFingerprint := strings.ReplaceAll(pbs.certfingerprint, ":", "")
|
||||
expectedFingerprint := strings.ReplaceAll(pbs.CertFingerPrint, ":", "")
|
||||
calculatedFingerprint := sha256.Sum256(peerCert.Raw)
|
||||
|
||||
// Compare the calculated fingerprint with the expected one
|
||||
@ -358,13 +358,13 @@ func (pbs *PBSClient) Connect(reader bool) {
|
||||
}
|
||||
}
|
||||
|
||||
pbs.manifest.BackupTime = time.Now().Unix()
|
||||
pbs.manifest.BackupType = "host"
|
||||
if pbs.manifest.BackupID == "" {
|
||||
pbs.Manifest.BackupTime = time.Now().Unix()
|
||||
pbs.Manifest.BackupType = "host"
|
||||
if pbs.Manifest.BackupID == "" {
|
||||
hostname, _ := os.Hostname()
|
||||
pbs.manifest.BackupID = hostname
|
||||
pbs.Manifest.BackupID = hostname
|
||||
}
|
||||
pbs.client = http.Client{
|
||||
pbs.Client = http.Client{
|
||||
Transport: &http2.Transport{
|
||||
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
@ -373,22 +373,22 @@ func (pbs *PBSClient) Connect(reader bool) {
|
||||
//So to achieve that the function to create SSL socket has been hijacked here
|
||||
//Here an http 1.1 request to authenticate, start the backup and require upgrade to HTTP2 is done then the socket is passed to
|
||||
// http2.Transport handler
|
||||
conn, err := tls.Dial(network, addr, &pbs.tlsConfig)
|
||||
conn, err := tls.Dial(network, addr, &pbs.TLSConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q := &url.Values{}
|
||||
q.Add("backup-time", fmt.Sprintf("%d", pbs.manifest.BackupTime))
|
||||
q.Add("backup-type", pbs.manifest.BackupType)
|
||||
q.Add("store", pbs.datastore)
|
||||
if pbs.namespace != "" {
|
||||
q.Add("ns", pbs.namespace)
|
||||
q.Add("backup-time", fmt.Sprintf("%d", pbs.Manifest.BackupTime))
|
||||
q.Add("backup-type", pbs.Manifest.BackupType)
|
||||
q.Add("store", pbs.Datastore)
|
||||
if pbs.Namespace != "" {
|
||||
q.Add("ns", pbs.Namespace)
|
||||
}
|
||||
|
||||
q.Add("backup-id", pbs.manifest.BackupID)
|
||||
q.Add("backup-id", pbs.Manifest.BackupID)
|
||||
q.Add("debug", "1")
|
||||
conn.Write([]byte("GET /api2/json/backup?" + q.Encode() + " HTTP/1.1\r\n"))
|
||||
conn.Write([]byte("Authorization: " + fmt.Sprintf("PBSAPIToken=%s:%s", pbs.authid, pbs.secret) + "\r\n"))
|
||||
conn.Write([]byte("Authorization: " + fmt.Sprintf("PBSAPIToken=%s:%s", pbs.AuthID, pbs.Secret) + "\r\n"))
|
||||
if !reader {
|
||||
conn.Write([]byte("Upgrade: proxmox-backup-protocol-v1\r\n"))
|
||||
} else {
|
||||
@ -433,12 +433,12 @@ func (pbs *PBSClient) DownloadPreviousToBytes(archivename string) ([]byte, error
|
||||
|
||||
q.Add("archive-name", archivename)
|
||||
|
||||
req, err := http.NewRequest("GET", pbs.baseurl+"/previous?"+q.Encode(), nil)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("PBSAPIToken=%s:%s", pbs.authid, pbs.secret))
|
||||
req, err := http.NewRequest("GET", pbs.BaseURL+"/previous?"+q.Encode(), nil)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("PBSAPIToken=%s:%s", pbs.AuthID, pbs.Secret))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp2, err := pbs.client.Do(req)
|
||||
resp2, err := pbs.Client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making request:", err)
|
||||
return nil, err
|
||||
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package pbscommon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -141,14 +141,14 @@ func ca_make_bst(input []GoodByeItem, output *[]GoodByeItem) {
|
||||
type PXAROutCB func([]byte)
|
||||
|
||||
type PXARArchive struct {
|
||||
//Create(filename string, writeCB PXAROutCB)
|
||||
//Create(filename string, WriteCB PXAROutCB)
|
||||
//AddFile(filename string)
|
||||
//AddDirectory(dirname string)
|
||||
writeCB PXAROutCB
|
||||
catalogWriteCB PXAROutCB
|
||||
WriteCB PXAROutCB
|
||||
CatalogWriteCB PXAROutCB
|
||||
buffer bytes.Buffer
|
||||
pos uint64
|
||||
archivename string
|
||||
ArchiveName string
|
||||
|
||||
catalog_pos uint64
|
||||
}
|
||||
@ -165,7 +165,7 @@ func (a *PXARArchive) Flush() {
|
||||
if count <= 0 {
|
||||
break
|
||||
}
|
||||
a.writeCB(b[:count])
|
||||
a.WriteCB(b[:count])
|
||||
a.pos = a.pos + uint64(count)
|
||||
}
|
||||
//fmt.Printf("Flush %d bytes\n", count)
|
||||
@ -260,8 +260,8 @@ func (a *PXARArchive) WriteDir(path string, dirname string, toplevel bool) Catal
|
||||
a.buffer.WriteString(dirname)
|
||||
a.buffer.WriteByte(0x00)
|
||||
} else {
|
||||
if a.catalogWriteCB != nil {
|
||||
a.catalogWriteCB(catalog_magic)
|
||||
if a.CatalogWriteCB != nil {
|
||||
a.CatalogWriteCB(catalog_magic)
|
||||
a.catalog_pos = 8
|
||||
}
|
||||
}
|
||||
@ -338,8 +338,8 @@ func (a *PXARArchive) WriteDir(path string, dirname string, toplevel bool) Catal
|
||||
catalog_outdata = append_u64_7bit(catalog_outdata, uint64(len(tabledata)))
|
||||
catalog_outdata = append(catalog_outdata, tabledata...)
|
||||
|
||||
if a.catalogWriteCB != nil {
|
||||
a.catalogWriteCB(catalog_outdata)
|
||||
if a.CatalogWriteCB != nil {
|
||||
a.CatalogWriteCB(catalog_outdata)
|
||||
|
||||
}
|
||||
|
||||
@ -389,17 +389,17 @@ func (a *PXARArchive) WriteDir(path string, dirname string, toplevel bool) Catal
|
||||
tabledata := make([]byte, 0)
|
||||
tabledata = append_u64_7bit(tabledata, uint64(1))
|
||||
tabledata = append(tabledata, 'd')
|
||||
tabledata = append_u64_7bit(tabledata, uint64(len(a.archivename)))
|
||||
tabledata = append(tabledata, []byte(a.archivename)...)
|
||||
tabledata = append_u64_7bit(tabledata, uint64(len(a.ArchiveName)))
|
||||
tabledata = append(tabledata, []byte(a.ArchiveName)...)
|
||||
tabledata = append_u64_7bit(tabledata, a.catalog_pos-oldpos)
|
||||
catalog_outdata := make([]byte, 0)
|
||||
catalog_outdata = append_u64_7bit(catalog_outdata, uint64(len(tabledata)))
|
||||
catalog_outdata = append(catalog_outdata, tabledata...)
|
||||
ptr := make([]byte, 0)
|
||||
ptr = binary.LittleEndian.AppendUint64(ptr, a.catalog_pos)
|
||||
if a.catalogWriteCB != nil {
|
||||
a.catalogWriteCB(catalog_outdata)
|
||||
a.catalogWriteCB(ptr)
|
||||
if a.CatalogWriteCB != nil {
|
||||
a.CatalogWriteCB(catalog_outdata)
|
||||
a.CatalogWriteCB(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
10
snapshot/go.mod
Normal file
10
snapshot/go.mod
Normal file
@ -0,0 +1,10 @@
|
||||
module snapshot
|
||||
|
||||
go 1.25.2
|
||||
|
||||
require github.com/jeromehadorn/vss v0.1.0
|
||||
|
||||
require (
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
)
|
||||
7
snapshot/go.sum
Normal file
7
snapshot/go.sum
Normal file
@ -0,0 +1,7 @@
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/jeromehadorn/vss v0.1.0 h1:0EWv9lG/jv1Wzbt5WhwIUMLxDZ5uSh21LkPHUO34w2Y=
|
||||
github.com/jeromehadorn/vss v0.1.0/go.mod h1:wHwqd/OMHe4Eu0rS/QX4/jKj2sJPtjRf6YrxBhj/EfY=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -1,10 +1,10 @@
|
||||
//go:build linux || darwin || freebsd || openbsd
|
||||
// +build linux darwin freebsd openbsd
|
||||
|
||||
package main
|
||||
package snapshot
|
||||
|
||||
func createVSSSnapshot(path string) string {
|
||||
return path
|
||||
func CreateVSSSnapshot(path string) SnapShot {
|
||||
return SnapShot{FullPath: path, Valid: false}
|
||||
}
|
||||
|
||||
func VSSCleanup() {
|
||||
8
snapshot/snapshot_common.go
Normal file
8
snapshot/snapshot_common.go
Normal file
@ -0,0 +1,8 @@
|
||||
package snapshot
|
||||
|
||||
type SnapShot struct {
|
||||
FullPath string
|
||||
Id string
|
||||
ObjectPath string
|
||||
Valid bool
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package main
|
||||
package snapshot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -52,7 +52,7 @@ func getAppDataFolder() (string, error) {
|
||||
return appDataFolder, nil
|
||||
}
|
||||
|
||||
func createVSSSnapshot(path string) string {
|
||||
func CreateVSSSnapshot(path string) SnapShot {
|
||||
|
||||
path, _ = filepath.Abs(path)
|
||||
volName := filepath.VolumeName(path)
|
||||
@ -62,7 +62,7 @@ func createVSSSnapshot(path string) string {
|
||||
appDataFolder, err := getAppDataFolder()
|
||||
if err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
return path
|
||||
return SnapShot{FullPath: path, Valid: false}
|
||||
}
|
||||
|
||||
sn := vss.Snapshotter{}
|
||||
@ -101,7 +101,7 @@ func createVSSSnapshot(path string) string {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return filepath.Join(appDataFolder, "VSS", snapshot.Id, subPath)
|
||||
return SnapShot{FullPath: filepath.Join(appDataFolder, "VSS", snapshot.Id, subPath), Id: snapshot.Id, ObjectPath: snapshot.DeviceObjectPath, Valid: true}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user