mirror of
https://github.com/qwc/backive.git
synced 2025-04-20 07:32:02 +02:00
Compare commits
No commits in common. "main" and "v0.1.1" have entirely different histories.
31
.github/workflows/go-release.yml
vendored
31
.github/workflows/go-release.yml
vendored
@ -1,31 +0,0 @@
|
||||
name: Go
|
||||
|
||||
on:
|
||||
release
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
- name: Install GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2.7.0
|
||||
with:
|
||||
install-only: true
|
||||
- name: Go-linter
|
||||
# You may pin to the exact commit or the version.
|
||||
# uses: Jerome1337/golint-action@c5d17206a0a436bbf1edb91e314ed084f7c57589
|
||||
uses: Jerome1337/golint-action@v1.0.2
|
||||
#with:
|
||||
# Path used by golint command
|
||||
# golint-path: # optional, default is ./...
|
||||
- name: Build
|
||||
run: goreleaser
|
||||
- name: Test
|
||||
run: go test -v ./...
|
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
@ -31,5 +31,5 @@ jobs:
|
||||
- name: Build
|
||||
run: goreleaser build --snapshot --rm-dist
|
||||
- name: Test
|
||||
run: go test -v -cover
|
||||
run: go test -v ./...
|
||||
|
||||
|
@ -30,4 +30,4 @@ What I currently see as optional:
|
||||
|
||||
# Current state
|
||||
|
||||
Working daemon and udev binary. Ready for first basic usage and testing in "production".
|
||||
In the very beginning...
|
||||
|
51
backup.go
51
backup.go
@ -12,18 +12,13 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Mockings
|
||||
var mockCmdRun = func(c *exec.Cmd) error {
|
||||
return c.Run()
|
||||
}
|
||||
|
||||
// Backup contains all necessary information for executing a configured backup.
|
||||
type Backup struct {
|
||||
Name string `mapstructure:",omitempty"`
|
||||
TargetDevice string `mapstructure:"targetDevice"`
|
||||
TargetPath string `mapstructure:"targetPath"`
|
||||
SourcePath string `mapstructure:"sourcePath"`
|
||||
ScriptPath interface{} `mapstructure:"scriptPath"`
|
||||
ScriptPath string `mapstructure:"scriptPath"`
|
||||
Frequency int `mapstructure:"frequency"`
|
||||
ExeUser string `mapstructure:"user,omitempty"`
|
||||
Label string `mapstructure:"label,omitempty"`
|
||||
@ -52,7 +47,7 @@ func (b *Backup) CanRun() error {
|
||||
return fmt.Errorf("the setting targetPath MUST exist within a backup configuration")
|
||||
}
|
||||
// script must exist, having only script means this is handled in the script
|
||||
if b.ScriptPath == nil {
|
||||
if b.ScriptPath == "" {
|
||||
return fmt.Errorf("the setting scriptPath must exist within a backup configuration")
|
||||
}
|
||||
if !b.ShouldRun() {
|
||||
@ -70,9 +65,10 @@ func (b *Backup) PrepareRun() error {
|
||||
)
|
||||
CreateDirectoryIfNotExists(backupPath)
|
||||
// configure extra logger
|
||||
logdir := config.Settings.LogLocation
|
||||
logname := "/var/log/backive/backive.log"
|
||||
logdir, _ := path.Split(logname)
|
||||
CreateDirectoryIfNotExists(logdir)
|
||||
logname := path.Join(logdir, b.Name) + ".log"
|
||||
logname = path.Join(logdir, b.Name) + ".log"
|
||||
logfile, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
log.Println("Error creating logfile!")
|
||||
@ -81,12 +77,11 @@ func (b *Backup) PrepareRun() error {
|
||||
writer := io.MultiWriter(logfile)
|
||||
b.logger = log.New(writer, b.Name, log.LstdFlags)
|
||||
cmd := exec.Command("chown", "-R", b.ExeUser, backupPath)
|
||||
err = mockCmdRun(cmd)
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
b.logger.Printf("chown for backup directory failed: %s", err)
|
||||
return err
|
||||
}
|
||||
b.logger.Printf("Backup %s prepared.", b.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -98,40 +93,17 @@ func (b *Backup) Run() error {
|
||||
log.Printf("Device found: %s (%s).", dev.Name, dev.UUID)
|
||||
} else {
|
||||
log.Printf("Device %s not found", b.TargetDevice)
|
||||
return fmt.Errorf("device %s not found", b.TargetDevice)
|
||||
}
|
||||
if ok && dev.IsMounted() {
|
||||
var scriptWArgs []string
|
||||
switch slice := b.ScriptPath.(type) {
|
||||
case []interface{}:
|
||||
for _, v := range slice {
|
||||
scriptWArgs = append(scriptWArgs, v.(string))
|
||||
}
|
||||
case []string:
|
||||
for _, v := range slice {
|
||||
scriptWArgs = append(scriptWArgs, v)
|
||||
}
|
||||
case string:
|
||||
scriptWArgs = append(scriptWArgs, slice)
|
||||
default:
|
||||
log.Print("Fuck, the var is nothing we predicted...")
|
||||
}
|
||||
if !strings.ContainsAny(scriptWArgs[0], "/") || strings.HasPrefix(scriptWArgs[0], ".") {
|
||||
if !strings.ContainsAny(b.ScriptPath, "/") || strings.HasPrefix(b.ScriptPath, ".") {
|
||||
//The scriptPath is a relative path, from the place of the config, so use the config as base
|
||||
log.Printf("ERROR: Script path is relative, aborting.")
|
||||
return fmt.Errorf("script path is relative, aborting")
|
||||
}
|
||||
var cmd *exec.Cmd
|
||||
var args []string
|
||||
cmd := exec.Command("/usr/bin/sh", b.ScriptPath)
|
||||
if b.ExeUser != "" {
|
||||
// setup script environment including user to use
|
||||
args = []string{"-E", "-u", b.ExeUser, "/usr/bin/sh"}
|
||||
args = append(args, scriptWArgs...)
|
||||
cmd = exec.Command("sudo", args...)
|
||||
} else {
|
||||
args = []string{}
|
||||
args = append(args, scriptWArgs...)
|
||||
cmd = exec.Command("/usr/bin/sh", args...)
|
||||
cmd = exec.Command("sudo", "-E", "-u", b.ExeUser, "/usr/bin/sh", b.ScriptPath)
|
||||
}
|
||||
b.logger.Printf("Running backup script of '%s'", b.Name)
|
||||
b.logger.Printf("Script is: %s", b.ScriptPath)
|
||||
@ -150,7 +122,7 @@ func (b *Backup) Run() error {
|
||||
|
||||
log.Printf("About to run: %s", cmd.String())
|
||||
// run script
|
||||
err := mockCmdRun(cmd)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Printf("Backup '%s' run failed", b.Name)
|
||||
return err
|
||||
@ -180,9 +152,6 @@ func (r *Runs) Load(db Database) {
|
||||
|
||||
// Save saves the data into the json database
|
||||
func (r *Runs) Save(db Database) {
|
||||
if db.data == nil {
|
||||
db.data = map[string]string{}
|
||||
}
|
||||
str, err := json.Marshal(r.data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
172
backup_test.go
172
backup_test.go
@ -1,172 +0,0 @@
|
||||
package backive
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"path"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getCurrentFilePath() string {
|
||||
pc, file, line, ok := runtime.Caller(1)
|
||||
fmt.Printf("pc: %d, file: %s, line: %d, ok: %v\n", pc, file, line, ok)
|
||||
return file
|
||||
}
|
||||
|
||||
func TestFindBackupsForDevice(t *testing.T) {
|
||||
var testBackups = Backups{}
|
||||
|
||||
testBackups["backup1"] = &Backup{
|
||||
Name: "backup1",
|
||||
TargetDevice: "dev1",
|
||||
}
|
||||
testBackups["backup2"] = &Backup{
|
||||
Name: "backup2",
|
||||
TargetDevice: "dev1",
|
||||
}
|
||||
testBackups["backup3"] = &Backup{
|
||||
Name: "backup3",
|
||||
TargetDevice: "dev2",
|
||||
}
|
||||
|
||||
var testDevice = Device{
|
||||
Name: "dev1",
|
||||
}
|
||||
bkps, found := testBackups.FindBackupsForDevice(testDevice)
|
||||
|
||||
if !found {
|
||||
t.Log("found has to be true")
|
||||
t.Fail()
|
||||
}
|
||||
if len(bkps) != 2 {
|
||||
t.Log("Length of the returned backup slice has to be 2")
|
||||
t.Fail()
|
||||
}
|
||||
for _, b := range bkps {
|
||||
if b.TargetDevice != testDevice.Name {
|
||||
t.Log("All resulting elements of the returned slice have to have the questioned device as TargetDevice!")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanRun(t *testing.T) {
|
||||
var bkpTargetPathMissing = Backup{
|
||||
Name: "targetPathMissing",
|
||||
ScriptPath: "Somethingsomething",
|
||||
}
|
||||
err := bkpTargetPathMissing.CanRun()
|
||||
if err == nil {
|
||||
t.Log("Missing targetPath has to fail function 'CanRun()'")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
var bkpScriptPathMissing = Backup{
|
||||
Name: "scriptPathMissing",
|
||||
TargetPath: "somethingsomething",
|
||||
}
|
||||
err = bkpScriptPathMissing.CanRun()
|
||||
if err == nil {
|
||||
t.Logf("ScriptPath is %v", bkpScriptPathMissing.ScriptPath)
|
||||
t.Log("Missing scriptPath has to fail function 'CanRun()'")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
var bkpFrequencyZero = Backup{
|
||||
Name: "testFrequencyZero",
|
||||
TargetPath: "somewhere",
|
||||
ScriptPath: "somehwere_else",
|
||||
Frequency: 0,
|
||||
}
|
||||
var bkpFrequencySeven = Backup{
|
||||
Name: "testFrequencySeven",
|
||||
TargetPath: "somewhere",
|
||||
ScriptPath: "somewhere_else",
|
||||
Frequency: 7,
|
||||
}
|
||||
database.Load()
|
||||
runs.Load(database)
|
||||
runs.RegisterRun(&bkpFrequencyZero)
|
||||
err = bkpFrequencyZero.CanRun()
|
||||
if err != nil {
|
||||
t.Log("Frequency zero can be executed anytime.")
|
||||
t.Fail()
|
||||
}
|
||||
if !bkpFrequencyZero.ShouldRun() {
|
||||
t.Log("Frequency zero can be executed anytime, should run does not work.")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
runs.RegisterRun(&bkpFrequencySeven)
|
||||
err = bkpFrequencySeven.CanRun()
|
||||
if err == nil {
|
||||
t.Log("Frequency 7 must give an error about not having reached the interval")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func setupNewTestEnv(subdir string) {
|
||||
file := getCurrentFilePath()
|
||||
dir, _ := path.Split(file)
|
||||
dir = path.Join(dir, "test", "_workarea", subdir)
|
||||
config.Settings.SystemMountPoint = path.Join(dir, "mnt")
|
||||
config.Settings.LogLocation = path.Join(dir, "log")
|
||||
fmt.Printf("SystemMountPoint: %s, LogLocation: %s\n", config.Settings.SystemMountPoint, config.Settings.LogLocation)
|
||||
}
|
||||
|
||||
func TestPrepareRun(t *testing.T) {
|
||||
setupNewTestEnv("preparerun")
|
||||
|
||||
mockCmdRun = func(c *exec.Cmd) error {
|
||||
return nil
|
||||
}
|
||||
var testBkp = Backup{
|
||||
Name: "testbkp",
|
||||
TargetDevice: "mytarget",
|
||||
TargetPath: "mypath",
|
||||
}
|
||||
err := testBkp.PrepareRun()
|
||||
if err != nil {
|
||||
t.Log("When this fails, something's fishy...")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
setupNewTestEnv("run")
|
||||
config.Devices = map[string]*Device{
|
||||
"mytarget": new(Device),
|
||||
}
|
||||
config.Devices["mytarget"].Name = "mytarget"
|
||||
config.Devices["mytarget"].UUID = "123-456-789-abc-def"
|
||||
|
||||
mockCmdRun = func(c *exec.Cmd) error {
|
||||
return nil
|
||||
}
|
||||
var testBkp = Backup{
|
||||
Name: "testbkp",
|
||||
TargetDevice: "mytargets",
|
||||
TargetPath: "mypath",
|
||||
ScriptPath: "/dev/null",
|
||||
SourcePath: "/dev/random",
|
||||
}
|
||||
err := testBkp.Run()
|
||||
if err == nil || err.Error() != "device mytargets not found" {
|
||||
if err != nil {
|
||||
t.Logf("The error should be 'device mytargets not found', but is '%s'", err.Error())
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
testBkp.TargetDevice = "mytarget"
|
||||
config.Devices["mytarget"].Mount()
|
||||
err = testBkp.PrepareRun()
|
||||
err = testBkp.Run()
|
||||
if err != nil {
|
||||
t.Logf("Error which should not occur: %s", err)
|
||||
t.Fail()
|
||||
}
|
||||
mockCmdRun = func(c *exec.Cmd) error {
|
||||
return nil
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func setupLogging() {
|
||||
logname := path.Join(config.Settings.LogLocation, "backive.log")
|
||||
logname := "/var/log/backive/backive.log"
|
||||
logdir, _ := path.Split(logname)
|
||||
backive.CreateDirectoryIfNotExists(logdir)
|
||||
logfile, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
|
||||
@ -21,7 +21,6 @@ func setupLogging() {
|
||||
panic("no logfile no info")
|
||||
}
|
||||
log.SetOutput(logfile)
|
||||
log.Println("Logging initialized")
|
||||
}
|
||||
|
||||
// Global variables for backive
|
||||
@ -88,6 +87,7 @@ func defaultCallback(envMap map[string]string) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
setupLogging()
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChan,
|
||||
syscall.SIGHUP,
|
||||
@ -123,10 +123,6 @@ func main() {
|
||||
code := <-exitChan
|
||||
database.Save()
|
||||
log.Printf("Received exit code (%d), shutting down.", code)
|
||||
err := os.Remove(config.Settings.UnixSocketLocation)
|
||||
if err != nil {
|
||||
log.Printf("Removal of %s failed.", config.Settings.UnixSocketLocation)
|
||||
}
|
||||
os.Exit(code)
|
||||
}()
|
||||
|
||||
@ -135,7 +131,6 @@ func main() {
|
||||
// find and load config
|
||||
database.Load()
|
||||
config.Load()
|
||||
setupLogging()
|
||||
backive.Init(config, database)
|
||||
|
||||
// init scheduler and check for next needed runs?
|
||||
|
@ -34,16 +34,12 @@ func main() {
|
||||
env[pair[0]] = pair[1]
|
||||
log.Println(e)
|
||||
}
|
||||
message := map[string]interface{}{}
|
||||
|
||||
message["request"] = "udev"
|
||||
message["data"] = env
|
||||
|
||||
c, err := net.Dial("unix", "/var/local/backive/backive.sock")
|
||||
if err != nil {
|
||||
log.Fatalln("Could not instantiate unix socket. Aborting")
|
||||
}
|
||||
jsonstr, err := json.Marshal(message)
|
||||
jsonstr, err := json.Marshal(env)
|
||||
if err != nil {
|
||||
log.Fatalln("Could not convert to json. Aborting")
|
||||
}
|
||||
|
18
config.go
18
config.go
@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
@ -27,27 +26,16 @@ type Settings struct {
|
||||
|
||||
// CreateViper creates a viper instance for usage later
|
||||
func (c *Configuration) CreateViper() {
|
||||
if c.Vconfig == nil {
|
||||
vconfig := viper.New()
|
||||
// vconfig.Debug()
|
||||
vconfig.SetConfigName("backive")
|
||||
// do not set config file explicitly or viper doesnt search for it, and /etc search fails
|
||||
//vconfig.SetConfigFile("backive.yml")
|
||||
vconfig.SetConfigFile("backive.yml")
|
||||
//vconfig.SetConfigFile("backive.yaml")
|
||||
vconfig.SetConfigType("yaml")
|
||||
//vconfig.AddConfigPath("$HOME/.backive/")
|
||||
vconfig.AddConfigPath(".") // backup config in local dir
|
||||
vconfig.AddConfigPath("/etc/backive/") // system config
|
||||
vconfig.OnConfigChange(func(e fsnotify.Event) {
|
||||
log.Printf("Event: %s", e)
|
||||
if e.Op == fsnotify.Write {
|
||||
log.Printf("Reloading %s", e.Name)
|
||||
c.Load()
|
||||
}
|
||||
})
|
||||
vconfig.WatchConfig()
|
||||
//vconfig.AddConfigPath("$HOME/.backive/")
|
||||
vconfig.AddConfigPath(".")
|
||||
c.Vconfig = vconfig
|
||||
}
|
||||
}
|
||||
|
||||
// Load loads the configuration from the disk
|
||||
|
@ -7,9 +7,6 @@ import (
|
||||
"path"
|
||||
)
|
||||
|
||||
var mockOsWriteFile = os.WriteFile
|
||||
var mockOsReadFile = os.ReadFile
|
||||
|
||||
// Database is a simple string to string mapping, where arbitrary strings can be stored and safed to disk or loaded
|
||||
type Database struct {
|
||||
data map[string]string
|
||||
@ -26,7 +23,7 @@ func (d *Database) Save() {
|
||||
log.Printf("Writing database output to file: %s", jsonstr)
|
||||
saveDir, _ := path.Split(dbPath)
|
||||
CreateDirectoryIfNotExists(saveDir)
|
||||
err := mockOsWriteFile(dbPath, []byte(jsonstr), 0644)
|
||||
err := os.WriteFile(dbPath, []byte(jsonstr), 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -35,7 +32,7 @@ func (d *Database) Save() {
|
||||
// Load loads the database
|
||||
func (d *Database) Load() {
|
||||
if _, err := os.Stat(dbPath); err == nil {
|
||||
data, rferr := mockOsReadFile(dbPath)
|
||||
data, rferr := os.ReadFile(dbPath)
|
||||
if rferr != nil {
|
||||
panic(rferr)
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
package backive
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDatabase(t *testing.T) {
|
||||
mockOsStat = func(p string) (fs.FileInfo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
db := new(Database)
|
||||
mockOsReadFile = func(p string) ([]byte, error) {
|
||||
return []byte("{}"), nil
|
||||
}
|
||||
db.Load()
|
||||
|
||||
mockOsWriteFile = func(p string, data []byte, rights fs.FileMode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
db.Save()
|
||||
}
|
@ -35,7 +35,7 @@ func (d *Device) Mount() error {
|
||||
cmd.Stdout = log.Writer()
|
||||
cmd.Stderr = log.Writer()
|
||||
log.Printf("Command to execute: %s", cmd.String())
|
||||
err := mockCmdRun(cmd)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Printf("Mounting failed with error %v", err)
|
||||
return err
|
||||
@ -49,7 +49,7 @@ func (d *Device) Unmount() error {
|
||||
if d.isMounted {
|
||||
log.Printf("Unmounting %s", d.Name)
|
||||
sync := exec.Command("sync")
|
||||
syncErr := mockCmdRun(sync)
|
||||
syncErr := sync.Run()
|
||||
if syncErr != nil {
|
||||
log.Println(syncErr)
|
||||
return syncErr
|
||||
@ -59,7 +59,7 @@ func (d *Device) Unmount() error {
|
||||
path.Join(config.Settings.SystemMountPoint, d.Name),
|
||||
)
|
||||
log.Printf("About to run: %s", cmd.String())
|
||||
err := mockCmdRun(cmd)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return err
|
||||
|
@ -1,33 +0,0 @@
|
||||
package backive
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDevice(t *testing.T) {
|
||||
testDevice := new(Device)
|
||||
testDevice.Name = "Testdevice"
|
||||
testDevice.UUID = "123-456-789-abc-def"
|
||||
mockCmdRun = func(c *exec.Cmd) error {
|
||||
return nil
|
||||
}
|
||||
err := testDevice.Mount()
|
||||
if err != nil {
|
||||
t.Log("Should not fail, is mocked.")
|
||||
t.Fail()
|
||||
}
|
||||
if !testDevice.IsMounted() {
|
||||
t.Log("Should return true.")
|
||||
t.Fail()
|
||||
}
|
||||
err = testDevice.Unmount()
|
||||
if err != nil {
|
||||
t.Log("Should not fail, is mocked.")
|
||||
t.Fail()
|
||||
}
|
||||
if testDevice.IsMounted() {
|
||||
t.Log("Should return false.")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
38
events.go
38
events.go
@ -9,29 +9,24 @@ import (
|
||||
"path"
|
||||
)
|
||||
|
||||
var mockAccept = func(eh *EventHandler) (net.Conn, error) {
|
||||
log.Println("Calling eh.ls.Accept()")
|
||||
return eh.ls.Accept()
|
||||
}
|
||||
|
||||
// EventHandler holds the necessary elements to get an eventhandler setup and working.
|
||||
type EventHandler struct {
|
||||
ls net.Listener
|
||||
//done <-chan struct{}
|
||||
callbacks []func(map[string]string)
|
||||
}
|
||||
|
||||
// Init initializes the unix socket.
|
||||
func (eh *EventHandler) Init(socketPath string) error {
|
||||
func (eh *EventHandler) Init(socketPath string) {
|
||||
log.Println("Initializing EventHandler...")
|
||||
var err error
|
||||
dir, _ := path.Split(socketPath)
|
||||
CreateDirectoryIfNotExists(dir)
|
||||
eh.ls, err = net.Listen("unix", socketPath)
|
||||
if err != nil {
|
||||
return err
|
||||
panic(err)
|
||||
}
|
||||
eh.callbacks = make([]func(map[string]string), 3)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Listen starts the event loop.
|
||||
@ -51,21 +46,17 @@ func (eh *EventHandler) RegisterCallback(cb func(map[string]string)) {
|
||||
|
||||
// process processes each and every unix socket event, Unmarshals the json data and calls the list of callbacks.
|
||||
func (eh *EventHandler) process() {
|
||||
client, err := mockAccept(eh)
|
||||
client, err := eh.ls.Accept()
|
||||
log.Println("Accepted client")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer client.Close()
|
||||
data := make([]byte, 2048)
|
||||
for {
|
||||
buf := make([]byte, 512)
|
||||
nr, err := client.Read(buf)
|
||||
log.Printf("Read %d bytes...", nr)
|
||||
if err != nil && err != io.EOF {
|
||||
log.Println(err)
|
||||
return
|
||||
log.Fatal(err)
|
||||
}
|
||||
data = append(data, buf[0:nr]...)
|
||||
if err == io.EOF {
|
||||
@ -73,23 +64,14 @@ func (eh *EventHandler) process() {
|
||||
}
|
||||
}
|
||||
sdata := string(bytes.Trim(data, "\x00"))
|
||||
var message map[string]interface{}
|
||||
log.Printf("Reading JSON: %s", sdata)
|
||||
errjson := json.Unmarshal([]byte(sdata), &message)
|
||||
//log.Println(sdata)
|
||||
env := map[string]string{}
|
||||
errjson := json.Unmarshal([]byte(sdata), &env)
|
||||
if errjson != nil {
|
||||
log.Println(errjson)
|
||||
return
|
||||
}
|
||||
log.Println("Calling callbacks")
|
||||
var env = map[string]string{}
|
||||
if message["request"] == "udev" {
|
||||
for k, v := range message["data"].(map[string]interface{}) {
|
||||
env[k] = v.(string)
|
||||
}
|
||||
log.Fatal(errjson)
|
||||
}
|
||||
for _, v := range eh.callbacks {
|
||||
if v != nil {
|
||||
log.Println("Calling callback")
|
||||
v(env)
|
||||
}
|
||||
}
|
||||
|
@ -1,99 +0,0 @@
|
||||
package backive
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ConnStub struct {
|
||||
}
|
||||
|
||||
var counter int
|
||||
|
||||
func (c ConnStub) Read(b []byte) (int, error) {
|
||||
switch {
|
||||
case counter == 0:
|
||||
counter++
|
||||
env := map[string]string{}
|
||||
env["test"] = "test"
|
||||
message := map[string]interface{}{}
|
||||
message["request"] = "udev"
|
||||
message["data"] = env
|
||||
data, err := json.Marshal(message)
|
||||
copy(b, data)
|
||||
log.Println(string(b))
|
||||
return len(data), err
|
||||
case counter == 1:
|
||||
counter++
|
||||
return 0, io.EOF
|
||||
case counter == 2:
|
||||
counter++
|
||||
return 0, fmt.Errorf("Some Error for testing")
|
||||
default:
|
||||
return 0, io.EOF
|
||||
}
|
||||
}
|
||||
func (c ConnStub) Close() error {
|
||||
return nil
|
||||
}
|
||||
func (c ConnStub) LocalAddr() net.Addr {
|
||||
return nil
|
||||
}
|
||||
func (c ConnStub) RemoteAddr() net.Addr {
|
||||
return nil
|
||||
}
|
||||
func (c ConnStub) SetDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
func (c ConnStub) SetReadDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
func (c ConnStub) SetWriteDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
func (c ConnStub) Write(b []byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var hasBeenCalled = false
|
||||
|
||||
func TestEventhandler(t *testing.T) {
|
||||
eh := new(EventHandler)
|
||||
err := eh.Init("./backive.socket")
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
defer func() {
|
||||
err := os.Remove("./backive.socket")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
}()
|
||||
t.Log("Initialized test")
|
||||
//var hasBeenCalled = make(chan bool)
|
||||
eh.RegisterCallback(
|
||||
func(m map[string]string) {
|
||||
t.Log("Callback got called")
|
||||
hasBeenCalled = true
|
||||
},
|
||||
)
|
||||
t.Log("registered callback")
|
||||
|
||||
mockAccept = func(eh *EventHandler) (net.Conn, error) {
|
||||
t.Log("Mocked Accept() has been called.")
|
||||
mycon := ConnStub{}
|
||||
return mycon, nil
|
||||
}
|
||||
eh.process()
|
||||
//beenCalled := <-hasBeenCalled
|
||||
if !hasBeenCalled {
|
||||
t.Log("Got false, need true.")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
10
go.mod
10
go.mod
@ -2,12 +2,10 @@ module github.com/qwc/backive
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/spf13/viper v1.9.0
|
||||
)
|
||||
require github.com/spf13/viper v1.9.0
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
@ -18,8 +16,8 @@ require (
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
|
||||
golang.org/x/text v0.3.8 // indirect
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
15
go.sum
15
go.sum
@ -256,7 +256,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
@ -280,7 +279,6 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -316,7 +314,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -354,7 +351,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -381,7 +377,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -437,11 +432,9 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -450,9 +443,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@ -510,7 +502,6 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -1,9 +0,0 @@
|
||||
[Unit]
|
||||
Description=Backive
|
||||
|
||||
[Service]
|
||||
Nice=19
|
||||
IOSchedulingClass=2
|
||||
IOSchedulingPriority=7
|
||||
WorkingDirectory=/the/path/of/backive
|
||||
ExecStart=backive
|
@ -1 +0,0 @@
|
||||
KERNEL=="sd*", RUN+="/path/to/backive_udev"
|
16
utils.go
16
utils.go
@ -1,21 +1,17 @@
|
||||
package backive
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
var mockOsStat = os.Stat
|
||||
var mockOsMkdirAll = os.MkdirAll
|
||||
var mockOsIsNotExist = os.IsNotExist
|
||||
|
||||
// CreateDirectoryIfNotExists Checks for a directory string and creates the directory if it does not exist, must be a absolute path.
|
||||
func CreateDirectoryIfNotExists(dir string) error {
|
||||
if _, err := mockOsStat(dir); err == nil {
|
||||
func CreateDirectoryIfNotExists(dir string) {
|
||||
if _, err := os.Stat(dir); err == nil {
|
||||
//ignore
|
||||
} else if mockOsIsNotExist(err) {
|
||||
return mockOsMkdirAll(dir, 0755)
|
||||
} else if os.IsNotExist(err) {
|
||||
os.MkdirAll(dir, 0755)
|
||||
} else {
|
||||
return err
|
||||
log.Fatal(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
package backive
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var creatingDir = false
|
||||
|
||||
func TestCreateDirectoryIfNotExists(t *testing.T) {
|
||||
mockOsMkdirAll = func(dir string, mode os.FileMode) error {
|
||||
t.Log("Creating directories")
|
||||
creatingDir = true
|
||||
return nil
|
||||
}
|
||||
mockOsStat = os.Stat
|
||||
CreateDirectoryIfNotExists("/somewhere/which.does/not/exist")
|
||||
if !creatingDir {
|
||||
t.Log("Should have called MkdirAll")
|
||||
t.Fail()
|
||||
}
|
||||
mockOsStat = func(dir string) (fs.FileInfo, error) {
|
||||
return nil, fmt.Errorf("Just some error for testing")
|
||||
}
|
||||
err := CreateDirectoryIfNotExists("asdfasdfasdf")
|
||||
if err == nil {
|
||||
t.Log("Should have an error here")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user