Initial Backupper Unraid plugin
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/backupper-unraid/backupper/internal/model"
|
||||
)
|
||||
|
||||
type CredentialGetter interface{ Get(string) (string, error) }
|
||||
|
||||
type MountManager struct {
|
||||
RuntimeDir string
|
||||
Secrets CredentialGetter
|
||||
}
|
||||
|
||||
type MountedRepository struct {
|
||||
Repository model.Repository
|
||||
Mounted bool
|
||||
CredentialFile string
|
||||
}
|
||||
|
||||
func (m *MountManager) Prepare(ctx context.Context, repo model.Repository) (MountedRepository, error) {
|
||||
result := MountedRepository{Repository: repo}
|
||||
if repo.Type != model.RepositorySMB && repo.Type != model.RepositoryNFS {
|
||||
return result, nil
|
||||
}
|
||||
if repo.Mount == nil || !repo.Mount.Managed {
|
||||
if _, err := os.Stat(repo.Location); err != nil {
|
||||
return result, fmt.Errorf("connectivity: external mount unavailable: %w", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
point := filepath.Clean(repo.Mount.MountPoint)
|
||||
if !strings.HasPrefix(point, "/mnt/remotes/") && !strings.HasPrefix(point, "/mnt/disks/") {
|
||||
return result, errors.New("validation: managed mountPoint must be below /mnt/remotes or /mnt/disks")
|
||||
}
|
||||
if err := os.MkdirAll(point, 0700); err != nil {
|
||||
return result, err
|
||||
}
|
||||
mountType := string(repo.Type)
|
||||
if repo.Type == model.RepositorySMB {
|
||||
mountType = "cifs"
|
||||
}
|
||||
args := []string{"-t", mountType, repo.Mount.Remote, point}
|
||||
if repo.Type == model.RepositorySMB {
|
||||
options := []string{"nosuid", "nodev"}
|
||||
if repo.CredentialRef != "" {
|
||||
credential, err := m.Secrets.Get(repo.CredentialRef)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("authentication: load mount credential: %w", err)
|
||||
}
|
||||
dir := filepath.Join(m.RuntimeDir, "secrets")
|
||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||
return result, err
|
||||
}
|
||||
f, err := os.CreateTemp(dir, "smb-credentials-*")
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.CredentialFile = f.Name()
|
||||
if err := f.Chmod(0600); err != nil {
|
||||
f.Close()
|
||||
return result, err
|
||||
}
|
||||
if _, err := f.WriteString(credential); err != nil {
|
||||
f.Close()
|
||||
return result, err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return result, err
|
||||
}
|
||||
options = append(options, "credentials="+result.CredentialFile)
|
||||
}
|
||||
args = append(args, "-o", strings.Join(options, ","))
|
||||
} else {
|
||||
args = append(args, "-o", "nosuid,nodev")
|
||||
}
|
||||
if err := exec.CommandContext(ctx, "mount", args...).Run(); err != nil {
|
||||
m.Cleanup(context.Background(), result)
|
||||
return result, fmt.Errorf("connectivity: mount repository: %w", err)
|
||||
}
|
||||
result.Mounted = true
|
||||
result.Repository.Location = point
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (m *MountManager) Cleanup(ctx context.Context, mounted MountedRepository) error {
|
||||
if mounted.CredentialFile != "" {
|
||||
defer os.Remove(mounted.CredentialFile)
|
||||
}
|
||||
if !mounted.Mounted {
|
||||
return nil
|
||||
}
|
||||
return exec.CommandContext(ctx, "umount", mounted.Repository.Location).Run()
|
||||
}
|
||||
Reference in New Issue
Block a user