add backupd

This commit is contained in:
Michael Stapelberg 2018-06-26 18:01:01 +02:00
parent 36282e7cea
commit 4c7741a337
4 changed files with 181 additions and 2 deletions

56
cmd/backupd/backupd.go Normal file
View File

@ -0,0 +1,56 @@
// Binary backupd provides tarballs of /perm.
package main
import (
"net"
"net/http"
"os"
"os/signal"
"syscall"
"github.com/gokrazy/gokrazy"
"router7/internal/backup"
"router7/internal/multilisten"
"router7/internal/teelogger"
)
var log = teelogger.NewConsole()
var httpListeners = multilisten.NewPool()
func updateListeners() error {
hosts, err := gokrazy.PrivateInterfaceAddrs()
if err != nil {
return err
}
httpListeners.ListenAndServe(hosts, func(host string) multilisten.Listener {
return &http.Server{Addr: net.JoinHostPort(host, "8077")}
})
return nil
}
func logic() error {
http.HandleFunc("/backup.tar.gz", func(w http.ResponseWriter, r *http.Request) {
if err := backup.Archive(w, "/perm"); err != nil {
log.Printf("backup.tar.gz: %v", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
updateListeners()
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGUSR1)
for range ch {
if err := updateListeners(); err != nil {
log.Printf("updateListeners: %v", err)
}
}
return nil
}
func main() {
if err := logic(); err != nil {
log.Fatal(err)
}
}

66
internal/backup/backup.go Normal file
View File

@ -0,0 +1,66 @@
// Package backup generates tarballs of /perm.
package backup
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
)
func Archive(w io.Writer, dir string) error {
gw, err := gzip.NewWriterLevel(w, gzip.BestSpeed)
if err != nil {
return err
}
defer gw.Close()
tw := tar.NewWriter(gw)
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info == nil {
return fmt.Errorf("filepath.Walk: nil os.FileInfo")
}
if !info.Mode().IsRegular() && !info.Mode().IsDir() {
return nil // skip non-regular files/directories
}
if path == dir {
return nil // skip root
}
rel, err := filepath.Rel(dir, path)
if err != nil {
return err
}
hdr, err := tar.FileInfoHeader(info, "")
if err != nil {
return err
}
hdr.Name = rel
if err := tw.WriteHeader(hdr); err != nil {
return err
}
if !info.Mode().IsDir() {
b, err := ioutil.ReadFile(path)
if err != nil {
return err
}
if _, err := tw.Write(b); err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
if err := tw.Close(); err != nil {
return err
}
return gw.Close()
}

View File

@ -0,0 +1,55 @@
package backup_test
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"router7/internal/backup"
"testing"
)
func TestArchive(t *testing.T) {
tmpin, err := ioutil.TempDir("", "backuptest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpin)
if err := ioutil.WriteFile(filepath.Join(tmpin, "random.seed"), []byte{0xaa, 0xbb}, 0600); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(filepath.Join(tmpin, "dhcp4d"), 0755); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(tmpin, "dhcp4d", "leases.json"), []byte("{}"), 0600); err != nil {
t.Fatal(err)
}
var buf bytes.Buffer
if err := backup.Archive(&buf, tmpin); err != nil {
t.Fatal(err)
}
tmpout, err := ioutil.TempDir("", "backuptest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpout)
tar := exec.Command("tar", "xzf", "-", "-C", tmpout)
tar.Stdin = &buf
tar.Stderr = os.Stderr
if err := tar.Run(); err != nil {
t.Fatal(err)
}
diff := exec.Command("diff", "-ur", tmpin, tmpout)
diff.Stdout = os.Stdout
diff.Stderr = os.Stderr
if err := diff.Run(); err != nil {
t.Fatal(err)
}
}

View File

@ -600,8 +600,10 @@ func Apply(dir, root string) error {
}
for _, process := range []string{
"dyndns", // depends on the public IPv4 address
"dnsd", // listens on private IPv4/IPv6 and public IPv6Net1
"dyndns", // depends on the public IPv4 address
"dnsd", // listens on private IPv4/IPv6
"diagd", // listens on private IPv4/IPv6
"backupd", // listens on private IPv4/IPv6
} {
if err := notify.Process("/user/"+process, syscall.SIGUSR1); err != nil {
log.Printf("notifying %s: %v", process, err)