feat(stdlib): added borg server custom promise
This commit is contained in:
parent
1a4192b5c9
commit
07db4ab5bd
2 changed files with 109 additions and 0 deletions
9
stdlib/backups/borg/common.go
Normal file
9
stdlib/backups/borg/common.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package borg
|
||||
|
||||
import gonf "git.adyxax.org/adyxax/gonf/v2/pkg"
|
||||
|
||||
func installBorgPackage() gonf.Status {
|
||||
packag := gonf.Package("borgbackup")
|
||||
packag.Resolve()
|
||||
return packag.Status()
|
||||
}
|
100
stdlib/backups/borg/server.go
Normal file
100
stdlib/backups/borg/server.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
package borg
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
|
||||
gonf "git.adyxax.org/adyxax/gonf/v2/pkg"
|
||||
)
|
||||
|
||||
type BorgServer struct {
|
||||
chain []gonf.Promise
|
||||
clients map[string][]byte // name -> publicKey
|
||||
path string
|
||||
user string
|
||||
status gonf.Status
|
||||
}
|
||||
|
||||
func (b *BorgServer) IfRepaired(p ...gonf.Promise) gonf.Promise {
|
||||
b.chain = append(b.chain, p...)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *BorgServer) Promise() gonf.Promise {
|
||||
gonf.MakeCustomPromise(b).Promise()
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *BorgServer) Resolve() {
|
||||
b.status = gonf.KEPT
|
||||
// Borg user
|
||||
user := gonf.User(gonf.UserData{
|
||||
HomeDir: b.path,
|
||||
Name: "borg",
|
||||
System: true,
|
||||
})
|
||||
user.Resolve()
|
||||
switch user.Status() {
|
||||
case gonf.BROKEN:
|
||||
b.status = gonf.BROKEN
|
||||
return
|
||||
case gonf.REPAIRED:
|
||||
b.status = gonf.REPAIRED
|
||||
}
|
||||
// borg package
|
||||
switch installBorgPackage() {
|
||||
case gonf.BROKEN:
|
||||
b.status = gonf.BROKEN
|
||||
return
|
||||
case gonf.REPAIRED:
|
||||
b.status = gonf.REPAIRED
|
||||
}
|
||||
// authorized_keys
|
||||
borgDir := gonf.ModeUserGroup(0700, "borg", "borg")
|
||||
borgRO := gonf.ModeUserGroup(0400, "borg", "borg")
|
||||
file := gonf.File(filepath.Join(b.path, ".ssh/authorized_keys")).
|
||||
DirectoriesPermissions(borgDir).
|
||||
Permissions(borgRO)
|
||||
authorizedKeys := ""
|
||||
// we sort the names so that the file contents are stable
|
||||
names := make([]string, len(b.clients)-1)
|
||||
for name := range b.clients {
|
||||
names = append(names, name)
|
||||
}
|
||||
for _, name := range names {
|
||||
key := b.clients[name]
|
||||
authorizedKeys += "command=\"borg serve --restrict-to-path " + filepath.Join(b.path, name) + "\",restrict " + string(key) + "\n"
|
||||
}
|
||||
file.Contents(authorizedKeys).Resolve()
|
||||
switch file.Status() {
|
||||
case gonf.BROKEN:
|
||||
b.status = gonf.BROKEN
|
||||
return
|
||||
case gonf.REPAIRED:
|
||||
b.status = gonf.REPAIRED
|
||||
}
|
||||
// TODO init repositories? or let the borg client do it?
|
||||
}
|
||||
|
||||
func (b BorgServer) Status() gonf.Status {
|
||||
return b.status
|
||||
}
|
||||
|
||||
func Server() *BorgServer {
|
||||
return &BorgServer{
|
||||
chain: nil,
|
||||
clients: make(map[string][]byte),
|
||||
path: "/srv/borg/",
|
||||
user: "borg",
|
||||
status: gonf.PROMISED,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BorgServer) Add(name string, publicKey []byte) *BorgServer {
|
||||
if _, ok := b.clients[name]; ok {
|
||||
slog.Debug("Duplicate name for BorgServer", "name", name)
|
||||
panic("Duplicate name for BorgServer")
|
||||
}
|
||||
b.clients[name] = publicKey
|
||||
return b
|
||||
}
|
Loading…
Add table
Reference in a new issue