Files
storage-appliance/internal/infra/samba/samba.go

88 lines
2.8 KiB
Go

package samba
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/example/storage-appliance/internal/domain"
"github.com/example/storage-appliance/internal/infra/osexec"
)
type Adapter struct {
Runner osexec.Runner
IncludePath string
}
func NewAdapter(runner osexec.Runner, includePath string) *Adapter {
if includePath == "" {
includePath = "/etc/samba/smb.conf.d/appliance.conf"
}
return &Adapter{Runner: runner, IncludePath: includePath}
}
// RenderConf writes the Samba include file for appliance-managed shares
func (a *Adapter) RenderConf(ctx context.Context, shares []domain.Share) error {
var lines []string
lines = append(lines, "# Appliance-managed SMB share configuration")
for _, s := range shares {
if s.Type != "smb" {
continue
}
opts := []string{"path = " + s.Path}
// parse options if stored in s.Name or s.Config; fallback to broad default
// s.Config may have read-only or allowed users
if ro, ok := s.Config["read_only"]; ok && ro == "true" {
opts = append(opts, "read only = yes")
} else {
opts = append(opts, "read only = no")
}
if users, ok := s.Config["allowed_users"]; ok {
opts = append(opts, "valid users = "+users)
}
// write section
lines = append(lines, fmt.Sprintf("[%s]", s.Name))
for _, l := range opts {
lines = append(lines, l)
}
lines = append(lines, "")
}
content := strings.Join(lines, "\n") + "\n"
dir := filepath.Dir(a.IncludePath)
tmp := filepath.Join(dir, ".appliance.smb.tmp")
if err := os.WriteFile(tmp, []byte(content), 0644); err != nil {
return err
}
if err := os.Rename(tmp, a.IncludePath); err != nil {
return err
}
return nil
}
// Reload reloads or restarts samba to apply config
func (a *Adapter) Reload(ctx context.Context) error {
// try to reload first
_, stderr, _, err := osexec.ExecWithRunner(a.Runner, ctx, "systemctl", "reload", "smbd")
if err == nil {
return nil
}
// fallback to restart
_, stderr, _, err = osexec.ExecWithRunner(a.Runner, ctx, "systemctl", "restart", "smbd")
if err != nil {
return fmt.Errorf("samba reload/restart failed: %s", stderr)
}
return nil
}
// CreateSambaUser optional: stub for creating a local samba user mapped to appliance user
func (a *Adapter) CreateSambaUser(ctx context.Context, user, password string) error {
// This is optional - we use smbpasswd command in production; stub for now
_, stderr, _, err := osexec.ExecWithRunner(a.Runner, ctx, "smbpasswd", "-a", user)
if err != nil {
return fmt.Errorf("smbpasswd failed: %s", stderr)
}
return nil
}