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
|
- name: Build
|
||||||
run: goreleaser build --snapshot --rm-dist
|
run: goreleaser build --snapshot --rm-dist
|
||||||
- name: Test
|
- name: Test
|
||||||
run: go test -v -cover
|
run: go test -v ./...
|
||||||
|
|
||||||
|
@ -30,4 +30,4 @@ What I currently see as optional:
|
|||||||
|
|
||||||
# Current state
|
# Current state
|
||||||
|
|
||||||
Working daemon and udev binary. Ready for first basic usage and testing in "production".
|
In the very beginning...
|
||||||
|
65
backup.go
65
backup.go
@ -12,21 +12,16 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mockings
|
|
||||||
var mockCmdRun = func(c *exec.Cmd) error {
|
|
||||||
return c.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Backup contains all necessary information for executing a configured backup.
|
// Backup contains all necessary information for executing a configured backup.
|
||||||
type Backup struct {
|
type Backup struct {
|
||||||
Name string `mapstructure:",omitempty"`
|
Name string `mapstructure:",omitempty"`
|
||||||
TargetDevice string `mapstructure:"targetDevice"`
|
TargetDevice string `mapstructure:"targetDevice"`
|
||||||
TargetPath string `mapstructure:"targetPath"`
|
TargetPath string `mapstructure:"targetPath"`
|
||||||
SourcePath string `mapstructure:"sourcePath"`
|
SourcePath string `mapstructure:"sourcePath"`
|
||||||
ScriptPath interface{} `mapstructure:"scriptPath"`
|
ScriptPath string `mapstructure:"scriptPath"`
|
||||||
Frequency int `mapstructure:"frequency"`
|
Frequency int `mapstructure:"frequency"`
|
||||||
ExeUser string `mapstructure:"user,omitempty"`
|
ExeUser string `mapstructure:"user,omitempty"`
|
||||||
Label string `mapstructure:"label,omitempty"`
|
Label string `mapstructure:"label,omitempty"`
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +47,7 @@ func (b *Backup) CanRun() error {
|
|||||||
return fmt.Errorf("the setting targetPath MUST exist within a backup configuration")
|
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
|
// 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")
|
return fmt.Errorf("the setting scriptPath must exist within a backup configuration")
|
||||||
}
|
}
|
||||||
if !b.ShouldRun() {
|
if !b.ShouldRun() {
|
||||||
@ -70,9 +65,10 @@ func (b *Backup) PrepareRun() error {
|
|||||||
)
|
)
|
||||||
CreateDirectoryIfNotExists(backupPath)
|
CreateDirectoryIfNotExists(backupPath)
|
||||||
// configure extra logger
|
// configure extra logger
|
||||||
logdir := config.Settings.LogLocation
|
logname := "/var/log/backive/backive.log"
|
||||||
|
logdir, _ := path.Split(logname)
|
||||||
CreateDirectoryIfNotExists(logdir)
|
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)
|
logfile, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error creating logfile!")
|
log.Println("Error creating logfile!")
|
||||||
@ -81,12 +77,11 @@ func (b *Backup) PrepareRun() error {
|
|||||||
writer := io.MultiWriter(logfile)
|
writer := io.MultiWriter(logfile)
|
||||||
b.logger = log.New(writer, b.Name, log.LstdFlags)
|
b.logger = log.New(writer, b.Name, log.LstdFlags)
|
||||||
cmd := exec.Command("chown", "-R", b.ExeUser, backupPath)
|
cmd := exec.Command("chown", "-R", b.ExeUser, backupPath)
|
||||||
err = mockCmdRun(cmd)
|
err = cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.logger.Printf("chown for backup directory failed: %s", err)
|
b.logger.Printf("chown for backup directory failed: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
b.logger.Printf("Backup %s prepared.", b.Name)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,40 +93,17 @@ func (b *Backup) Run() error {
|
|||||||
log.Printf("Device found: %s (%s).", dev.Name, dev.UUID)
|
log.Printf("Device found: %s (%s).", dev.Name, dev.UUID)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Device %s not found", b.TargetDevice)
|
log.Printf("Device %s not found", b.TargetDevice)
|
||||||
return fmt.Errorf("device %s not found", b.TargetDevice)
|
|
||||||
}
|
}
|
||||||
if ok && dev.IsMounted() {
|
if ok && dev.IsMounted() {
|
||||||
var scriptWArgs []string
|
if !strings.ContainsAny(b.ScriptPath, "/") || strings.HasPrefix(b.ScriptPath, ".") {
|
||||||
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], ".") {
|
|
||||||
//The scriptPath is a relative path, from the place of the config, so use the config as base
|
//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.")
|
log.Printf("ERROR: Script path is relative, aborting.")
|
||||||
return fmt.Errorf("script path is relative, aborting")
|
return fmt.Errorf("script path is relative, aborting")
|
||||||
}
|
}
|
||||||
var cmd *exec.Cmd
|
cmd := exec.Command("/usr/bin/sh", b.ScriptPath)
|
||||||
var args []string
|
|
||||||
if b.ExeUser != "" {
|
if b.ExeUser != "" {
|
||||||
// setup script environment including user to use
|
// setup script environment including user to use
|
||||||
args = []string{"-E", "-u", b.ExeUser, "/usr/bin/sh"}
|
cmd = exec.Command("sudo", "-E", "-u", b.ExeUser, "/usr/bin/sh", b.ScriptPath)
|
||||||
args = append(args, scriptWArgs...)
|
|
||||||
cmd = exec.Command("sudo", args...)
|
|
||||||
} else {
|
|
||||||
args = []string{}
|
|
||||||
args = append(args, scriptWArgs...)
|
|
||||||
cmd = exec.Command("/usr/bin/sh", args...)
|
|
||||||
}
|
}
|
||||||
b.logger.Printf("Running backup script of '%s'", b.Name)
|
b.logger.Printf("Running backup script of '%s'", b.Name)
|
||||||
b.logger.Printf("Script is: %s", b.ScriptPath)
|
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())
|
log.Printf("About to run: %s", cmd.String())
|
||||||
// run script
|
// run script
|
||||||
err := mockCmdRun(cmd)
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Backup '%s' run failed", b.Name)
|
log.Printf("Backup '%s' run failed", b.Name)
|
||||||
return err
|
return err
|
||||||
@ -180,9 +152,6 @@ func (r *Runs) Load(db Database) {
|
|||||||
|
|
||||||
// Save saves the data into the json database
|
// Save saves the data into the json database
|
||||||
func (r *Runs) Save(db Database) {
|
func (r *Runs) Save(db Database) {
|
||||||
if db.data == nil {
|
|
||||||
db.data = map[string]string{}
|
|
||||||
}
|
|
||||||
str, err := json.Marshal(r.data)
|
str, err := json.Marshal(r.data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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() {
|
func setupLogging() {
|
||||||
logname := path.Join(config.Settings.LogLocation, "backive.log")
|
logname := "/var/log/backive/backive.log"
|
||||||
logdir, _ := path.Split(logname)
|
logdir, _ := path.Split(logname)
|
||||||
backive.CreateDirectoryIfNotExists(logdir)
|
backive.CreateDirectoryIfNotExists(logdir)
|
||||||
logfile, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
|
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")
|
panic("no logfile no info")
|
||||||
}
|
}
|
||||||
log.SetOutput(logfile)
|
log.SetOutput(logfile)
|
||||||
log.Println("Logging initialized")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global variables for backive
|
// Global variables for backive
|
||||||
@ -88,6 +87,7 @@ func defaultCallback(envMap map[string]string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
setupLogging()
|
||||||
signalChan := make(chan os.Signal, 1)
|
signalChan := make(chan os.Signal, 1)
|
||||||
signal.Notify(signalChan,
|
signal.Notify(signalChan,
|
||||||
syscall.SIGHUP,
|
syscall.SIGHUP,
|
||||||
@ -123,10 +123,6 @@ func main() {
|
|||||||
code := <-exitChan
|
code := <-exitChan
|
||||||
database.Save()
|
database.Save()
|
||||||
log.Printf("Received exit code (%d), shutting down.", code)
|
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)
|
os.Exit(code)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -135,7 +131,6 @@ func main() {
|
|||||||
// find and load config
|
// find and load config
|
||||||
database.Load()
|
database.Load()
|
||||||
config.Load()
|
config.Load()
|
||||||
setupLogging()
|
|
||||||
backive.Init(config, database)
|
backive.Init(config, database)
|
||||||
|
|
||||||
// init scheduler and check for next needed runs?
|
// init scheduler and check for next needed runs?
|
||||||
|
@ -34,16 +34,12 @@ func main() {
|
|||||||
env[pair[0]] = pair[1]
|
env[pair[0]] = pair[1]
|
||||||
log.Println(e)
|
log.Println(e)
|
||||||
}
|
}
|
||||||
message := map[string]interface{}{}
|
|
||||||
|
|
||||||
message["request"] = "udev"
|
|
||||||
message["data"] = env
|
|
||||||
|
|
||||||
c, err := net.Dial("unix", "/var/local/backive/backive.sock")
|
c, err := net.Dial("unix", "/var/local/backive/backive.sock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Could not instantiate unix socket. Aborting")
|
log.Fatalln("Could not instantiate unix socket. Aborting")
|
||||||
}
|
}
|
||||||
jsonstr, err := json.Marshal(message)
|
jsonstr, err := json.Marshal(env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Could not convert to json. Aborting")
|
log.Fatalln("Could not convert to json. Aborting")
|
||||||
}
|
}
|
||||||
|
32
config.go
32
config.go
@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,27 +26,16 @@ type Settings struct {
|
|||||||
|
|
||||||
// CreateViper creates a viper instance for usage later
|
// CreateViper creates a viper instance for usage later
|
||||||
func (c *Configuration) CreateViper() {
|
func (c *Configuration) CreateViper() {
|
||||||
if c.Vconfig == nil {
|
vconfig := viper.New()
|
||||||
vconfig := viper.New()
|
// vconfig.Debug()
|
||||||
// vconfig.Debug()
|
vconfig.SetConfigName("backive")
|
||||||
vconfig.SetConfigName("backive")
|
vconfig.SetConfigFile("backive.yml")
|
||||||
// do not set config file explicitly or viper doesnt search for it, and /etc search fails
|
//vconfig.SetConfigFile("backive.yaml")
|
||||||
//vconfig.SetConfigFile("backive.yml")
|
vconfig.SetConfigType("yaml")
|
||||||
//vconfig.SetConfigFile("backive.yaml")
|
vconfig.AddConfigPath("/etc/backive/") // system config
|
||||||
vconfig.SetConfigType("yaml")
|
//vconfig.AddConfigPath("$HOME/.backive/")
|
||||||
//vconfig.AddConfigPath("$HOME/.backive/")
|
vconfig.AddConfigPath(".")
|
||||||
vconfig.AddConfigPath(".") // backup config in local dir
|
c.Vconfig = vconfig
|
||||||
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()
|
|
||||||
c.Vconfig = vconfig
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load loads the configuration from the disk
|
// Load loads the configuration from the disk
|
||||||
|
@ -7,9 +7,6 @@ import (
|
|||||||
"path"
|
"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
|
// Database is a simple string to string mapping, where arbitrary strings can be stored and safed to disk or loaded
|
||||||
type Database struct {
|
type Database struct {
|
||||||
data map[string]string
|
data map[string]string
|
||||||
@ -26,7 +23,7 @@ func (d *Database) Save() {
|
|||||||
log.Printf("Writing database output to file: %s", jsonstr)
|
log.Printf("Writing database output to file: %s", jsonstr)
|
||||||
saveDir, _ := path.Split(dbPath)
|
saveDir, _ := path.Split(dbPath)
|
||||||
CreateDirectoryIfNotExists(saveDir)
|
CreateDirectoryIfNotExists(saveDir)
|
||||||
err := mockOsWriteFile(dbPath, []byte(jsonstr), 0644)
|
err := os.WriteFile(dbPath, []byte(jsonstr), 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -35,7 +32,7 @@ func (d *Database) Save() {
|
|||||||
// Load loads the database
|
// Load loads the database
|
||||||
func (d *Database) Load() {
|
func (d *Database) Load() {
|
||||||
if _, err := os.Stat(dbPath); err == nil {
|
if _, err := os.Stat(dbPath); err == nil {
|
||||||
data, rferr := mockOsReadFile(dbPath)
|
data, rferr := os.ReadFile(dbPath)
|
||||||
if rferr != nil {
|
if rferr != nil {
|
||||||
panic(rferr)
|
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.Stdout = log.Writer()
|
||||||
cmd.Stderr = log.Writer()
|
cmd.Stderr = log.Writer()
|
||||||
log.Printf("Command to execute: %s", cmd.String())
|
log.Printf("Command to execute: %s", cmd.String())
|
||||||
err := mockCmdRun(cmd)
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Mounting failed with error %v", err)
|
log.Printf("Mounting failed with error %v", err)
|
||||||
return err
|
return err
|
||||||
@ -49,7 +49,7 @@ func (d *Device) Unmount() error {
|
|||||||
if d.isMounted {
|
if d.isMounted {
|
||||||
log.Printf("Unmounting %s", d.Name)
|
log.Printf("Unmounting %s", d.Name)
|
||||||
sync := exec.Command("sync")
|
sync := exec.Command("sync")
|
||||||
syncErr := mockCmdRun(sync)
|
syncErr := sync.Run()
|
||||||
if syncErr != nil {
|
if syncErr != nil {
|
||||||
log.Println(syncErr)
|
log.Println(syncErr)
|
||||||
return syncErr
|
return syncErr
|
||||||
@ -59,7 +59,7 @@ func (d *Device) Unmount() error {
|
|||||||
path.Join(config.Settings.SystemMountPoint, d.Name),
|
path.Join(config.Settings.SystemMountPoint, d.Name),
|
||||||
)
|
)
|
||||||
log.Printf("About to run: %s", cmd.String())
|
log.Printf("About to run: %s", cmd.String())
|
||||||
err := mockCmdRun(cmd)
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return 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()
|
|
||||||
}
|
|
||||||
}
|
|
40
events.go
40
events.go
@ -9,29 +9,24 @@ import (
|
|||||||
"path"
|
"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.
|
// EventHandler holds the necessary elements to get an eventhandler setup and working.
|
||||||
type EventHandler struct {
|
type EventHandler struct {
|
||||||
ls net.Listener
|
ls net.Listener
|
||||||
|
//done <-chan struct{}
|
||||||
callbacks []func(map[string]string)
|
callbacks []func(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes the unix socket.
|
// Init initializes the unix socket.
|
||||||
func (eh *EventHandler) Init(socketPath string) error {
|
func (eh *EventHandler) Init(socketPath string) {
|
||||||
log.Println("Initializing EventHandler...")
|
log.Println("Initializing EventHandler...")
|
||||||
var err error
|
var err error
|
||||||
dir, _ := path.Split(socketPath)
|
dir, _ := path.Split(socketPath)
|
||||||
CreateDirectoryIfNotExists(dir)
|
CreateDirectoryIfNotExists(dir)
|
||||||
eh.ls, err = net.Listen("unix", socketPath)
|
eh.ls, err = net.Listen("unix", socketPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
panic(err)
|
||||||
}
|
}
|
||||||
eh.callbacks = make([]func(map[string]string), 3)
|
eh.callbacks = make([]func(map[string]string), 3)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen starts the event loop.
|
// 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.
|
// process processes each and every unix socket event, Unmarshals the json data and calls the list of callbacks.
|
||||||
func (eh *EventHandler) process() {
|
func (eh *EventHandler) process() {
|
||||||
client, err := mockAccept(eh)
|
client, err := eh.ls.Accept()
|
||||||
log.Println("Accepted client")
|
log.Println("Accepted client")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Fatal(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
defer client.Close()
|
|
||||||
data := make([]byte, 2048)
|
data := make([]byte, 2048)
|
||||||
for {
|
for {
|
||||||
buf := make([]byte, 512)
|
buf := make([]byte, 512)
|
||||||
nr, err := client.Read(buf)
|
nr, err := client.Read(buf)
|
||||||
log.Printf("Read %d bytes...", nr)
|
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
log.Println(err)
|
log.Fatal(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
data = append(data, buf[0:nr]...)
|
data = append(data, buf[0:nr]...)
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@ -73,23 +64,14 @@ func (eh *EventHandler) process() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sdata := string(bytes.Trim(data, "\x00"))
|
sdata := string(bytes.Trim(data, "\x00"))
|
||||||
var message map[string]interface{}
|
//log.Println(sdata)
|
||||||
log.Printf("Reading JSON: %s", sdata)
|
env := map[string]string{}
|
||||||
errjson := json.Unmarshal([]byte(sdata), &message)
|
errjson := json.Unmarshal([]byte(sdata), &env)
|
||||||
if errjson != nil {
|
if errjson != nil {
|
||||||
log.Println(errjson)
|
log.Fatal(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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, v := range eh.callbacks {
|
for _, v := range eh.callbacks {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
log.Println("Calling callback")
|
|
||||||
v(env)
|
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
|
go 1.17
|
||||||
|
|
||||||
require (
|
require github.com/spf13/viper v1.9.0
|
||||||
github.com/fsnotify/fsnotify v1.5.1
|
|
||||||
github.com/spf13/viper v1.9.0
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/magiconair/properties v1.8.5 // 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/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/subosito/gotenv v1.2.0 // indirect
|
github.com/subosito/gotenv v1.2.0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
|
||||||
golang.org/x/text v0.3.8 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // 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.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/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.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/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/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
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-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-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-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-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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
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.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.1/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.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-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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/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-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-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-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-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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/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-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-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-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-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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/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-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-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-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-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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-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.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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/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.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.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-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-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/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.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.4/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.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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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
|
package backive
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"os"
|
"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.
|
// 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 {
|
func CreateDirectoryIfNotExists(dir string) {
|
||||||
if _, err := mockOsStat(dir); err == nil {
|
if _, err := os.Stat(dir); err == nil {
|
||||||
//ignore
|
//ignore
|
||||||
} else if mockOsIsNotExist(err) {
|
} else if os.IsNotExist(err) {
|
||||||
return mockOsMkdirAll(dir, 0755)
|
os.MkdirAll(dir, 0755)
|
||||||
} else {
|
} 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