Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Variables
##############################################################################
APP_NAME = datasafed
VERSION ?= 0.0.6
VERSION ?= 0.1.0
GITHUB_PROXY ?=
GIT_COMMIT = $(shell git rev-list -1 HEAD)
GIT_VERSION = $(shell git describe --always --abbrev=0 --tag)
Expand Down
84 changes: 6 additions & 78 deletions cmd/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,12 @@ import (
"context"
"fmt"
"os"
"strconv"
"strings"

"github.com/spf13/cobra"

"github.com/apecloud/datasafed/pkg/config"
"github.com/apecloud/datasafed/pkg/app"
"github.com/apecloud/datasafed/pkg/logging"
"github.com/apecloud/datasafed/pkg/storage"
"github.com/apecloud/datasafed/pkg/storage/kopia"
"github.com/apecloud/datasafed/pkg/storage/rclone"
)

const (
backendBasePathEnv = "DATASAFED_BACKEND_BASE_PATH"
kopiaRepoRootEnv = "DATASAFED_KOPIA_REPO_ROOT"
kopiaPasswordEnv = "DATASAFED_KOPIA_PASSWORD"
kopiaDisableCacheEnv = "DATASAFED_KOPIA_DISABLE_CACHE"
kopiaMaintenanceEnv = "DATASAFED_KOPIA_MAINTENANCE"
kopiaSafetyEnv = "DATASAFED_KOPIA_SAFETY"
)

var (
Expand All @@ -37,23 +24,23 @@ var (
doNotInitStorage bool
globalStorage storage.Storage
appCtx context.Context = context.Background()
onFinishFuncs []func()
)

func init() {
rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
appCtx = logging.WithLogger(appCtx, logging.DefaultLoggerFactory)
if !doNotInitStorage {
if err := initStorage(); err != nil {
if err := app.InitGlobalStorage(appCtx, configFile); err != nil {
return err
}
var err error
globalStorage, err = app.GetGlobalStorage()
exitIfError(err)
}
return nil
}
rootCmd.PersistentPostRunE = func(cmd *cobra.Command, args []string) error {
for _, fn := range onFinishFuncs {
fn()
}
app.InvokeFinalizers()
return nil
}
rootCmd.PersistentFlags().StringVarP(&configFile, "conf", "c",
Expand All @@ -75,65 +62,6 @@ func exitIfError(err error) {
}
}

func initStorage() error {
if err := config.InitGlobal(configFile); err != nil {
return err
}

basePath := strings.TrimSpace(os.Getenv(backendBasePathEnv))
storageConf := config.GetGlobal().GetAll(config.StorageSection)

if kopiaRoot := strings.TrimSpace(os.Getenv(kopiaRepoRootEnv)); kopiaRoot != "" {
return initKopiaStorage(storageConf, basePath, kopiaRoot)
} else {
st, err := createStorage(storageConf, basePath)
if err != nil {
return err
}
globalStorage = st
return nil
}
}

func initKopiaStorage(storageConf map[string]string, basePath, kopiaRoot string) error {
underlying, err := createStorage(storageConf, "")
if err != nil {
return err
}
kopia.SetUnderlyingStorage(underlying)
storageConf[kopia.RepoRootKey] = kopiaRoot
storageConf[kopia.PasswordKey] = strings.TrimSpace(os.Getenv(kopiaPasswordEnv))
storageConf[kopia.DisableCacheKey] = strings.TrimSpace(os.Getenv(kopiaDisableCacheEnv))
st, err := kopia.New(appCtx, storageConf, basePath)
if err != nil {
return err
}
globalStorage = st

maintenance := os.Getenv(kopiaMaintenanceEnv)
if ok, _ := strconv.ParseBool(maintenance); ok {
onFinish(func() {
err := kopia.RunMaintenance(appCtx, globalStorage, os.Getenv(kopiaSafetyEnv))
if err != nil {
fmt.Fprintf(os.Stderr, "RunMaintenance() failed, err: %v\n", err)
}
})
}
return nil
}

func createStorage(conf map[string]string, basePath string) (storage.Storage, error) {
cloneConf := make(map[string]string, len(conf))
for k, v := range conf {
cloneConf[k] = v
}
return rclone.New(appCtx, cloneConf, basePath)
}

func onFinish(fn func()) {
onFinishFuncs = append(onFinishFuncs, fn)
}

func Execute() {
exitIfError(rootCmd.Execute())
}
90 changes: 90 additions & 0 deletions pkg/app/globalstorage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package app

import (
"context"
"fmt"
"os"
"strconv"
"strings"

"github.com/apecloud/datasafed/pkg/config"
"github.com/apecloud/datasafed/pkg/storage"
"github.com/apecloud/datasafed/pkg/storage/kopia"
"github.com/apecloud/datasafed/pkg/storage/rclone"
)

const (
backendBasePathEnv = "DATASAFED_BACKEND_BASE_PATH"
kopiaRepoRootEnv = "DATASAFED_KOPIA_REPO_ROOT"
kopiaPasswordEnv = "DATASAFED_KOPIA_PASSWORD"
kopiaDisableCacheEnv = "DATASAFED_KOPIA_DISABLE_CACHE"
kopiaMaintenanceEnv = "DATASAFED_KOPIA_MAINTENANCE"
kopiaSafetyEnv = "DATASAFED_KOPIA_SAFETY"
)

var globalStorage storage.Storage

func InitGlobalStorage(ctx context.Context, configFile string) error {
if globalStorage != nil {
return fmt.Errorf("already inited")
}
if err := config.InitGlobal(configFile); err != nil {
return err
}

basePath := strings.TrimSpace(os.Getenv(backendBasePathEnv))
storageConf := config.GetGlobal().GetAll(config.StorageSection)

if kopiaRoot := strings.TrimSpace(os.Getenv(kopiaRepoRootEnv)); kopiaRoot != "" {
return initKopiaStorage(ctx, storageConf, basePath, kopiaRoot)
} else {
st, err := createStorage(ctx, storageConf, basePath)
if err != nil {
return err
}
globalStorage = st
return nil
}
}

func GetGlobalStorage() (storage.Storage, error) {
if globalStorage == nil {
return nil, fmt.Errorf("not inited, call InitGlobalStorage() first")
}
return globalStorage, nil
}

func initKopiaStorage(ctx context.Context, storageConf map[string]string, basePath, kopiaRoot string) error {
underlying, err := createStorage(ctx, storageConf, "")
if err != nil {
return err
}
kopia.SetUnderlyingStorage(underlying)
storageConf[kopia.RepoRootKey] = kopiaRoot
storageConf[kopia.PasswordKey] = strings.TrimSpace(os.Getenv(kopiaPasswordEnv))
storageConf[kopia.DisableCacheKey] = strings.TrimSpace(os.Getenv(kopiaDisableCacheEnv))
st, err := kopia.New(ctx, storageConf, basePath)
if err != nil {
return err
}
globalStorage = st

maintenance := os.Getenv(kopiaMaintenanceEnv)
if ok, _ := strconv.ParseBool(maintenance); ok {
OnFinalize(func() {
err := kopia.RunMaintenance(ctx, globalStorage, os.Getenv(kopiaSafetyEnv))
if err != nil {
fmt.Fprintf(os.Stderr, "RunMaintenance() failed, err: %v\n", err)
}
})
}
return nil
}

func createStorage(ctx context.Context, conf map[string]string, basePath string) (storage.Storage, error) {
cloneConf := make(map[string]string, len(conf))
for k, v := range conf {
cloneConf[k] = v
}
return rclone.New(ctx, cloneConf, basePath)
}
22 changes: 22 additions & 0 deletions pkg/app/lifecycle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package app

import "sync"

var (
finalizers []func()
finalizersMutex sync.Mutex
)

func OnFinalize(f func()) {
finalizersMutex.Lock()
defer finalizersMutex.Unlock()
finalizers = append(finalizers, f)
}

func InvokeFinalizers() {
finalizersMutex.Lock()
defer finalizersMutex.Unlock()
for _, f := range finalizers {
f()
}
}