add installer alpha version

This commit is contained in:
2025-12-15 16:38:20 +07:00
parent 732e5aca11
commit b4ef76f0d0
23 changed files with 4279 additions and 136 deletions

View File

@@ -20,12 +20,35 @@ type Service struct {
// New creates a new ZFS service
func New() *Service {
// Find full paths to zfs and zpool commands
zfsPath := findCommandPath("zfs")
zpoolPath := findCommandPath("zpool")
return &Service{
zfsPath: "zfs",
zpoolPath: "zpool",
zfsPath: zfsPath,
zpoolPath: zpoolPath,
}
}
// findCommandPath finds the full path to a command
func findCommandPath(cmd string) string {
// Try which first
if output, err := exec.Command("which", cmd).Output(); err == nil {
path := strings.TrimSpace(string(output))
if path != "" {
return path
}
}
// Try LookPath
if path, err := exec.LookPath(cmd); err == nil {
return path
}
// Fallback to command name (will use PATH)
return cmd
}
// execCommand executes a shell command and returns output
// For ZFS operations that require elevated privileges, it uses sudo
func (s *Service) execCommand(name string, args ...string) (string, error) {
@@ -42,8 +65,9 @@ func (s *Service) execCommand(name string, args ...string) (string, error) {
var cmd *exec.Cmd
if useSudo {
// Use sudo for privileged commands
sudoArgs := append([]string{name}, args...)
// Use sudo -n (non-interactive) for privileged commands
// This prevents password prompts and will fail if sudoers is not configured
sudoArgs := append([]string{"-n", name}, args...)
cmd = exec.Command("sudo", sudoArgs...)
} else {
cmd = exec.Command(name, args...)
@@ -53,7 +77,24 @@ func (s *Service) execCommand(name string, args ...string) (string, error) {
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
err := cmd.Run()
if err != nil && useSudo {
// If sudo failed, try running the command directly
// (user might already have permissions or be root)
directCmd := exec.Command(name, args...)
var directStdout, directStderr bytes.Buffer
directCmd.Stdout = &directStdout
directCmd.Stderr = &directStderr
if directErr := directCmd.Run(); directErr == nil {
// Direct execution succeeded, return that result
return strings.TrimSpace(directStdout.String()), nil
}
// Both sudo and direct failed, return the original sudo error
return "", fmt.Errorf("%s: %v: %s", name, err, stderr.String())
}
if err != nil {
return "", fmt.Errorf("%s: %v: %s", name, err, stderr.String())
}
@@ -64,10 +105,11 @@ func (s *Service) execCommand(name string, args ...string) (string, error) {
func (s *Service) ListPools() ([]models.Pool, error) {
output, err := s.execCommand(s.zpoolPath, "list", "-H", "-o", "name,size,allocated,free,health")
if err != nil {
return nil, err
// Return empty slice instead of nil to ensure JSON encodes as [] not null
return []models.Pool{}, err
}
var pools []models.Pool
pools := []models.Pool{}
lines := strings.Split(output, "\n")
for _, line := range lines {
if line == "" {
@@ -347,10 +389,11 @@ func (s *Service) ListDatasets(pool string) ([]models.Dataset, error) {
output, err := s.execCommand(s.zfsPath, args...)
if err != nil {
return nil, err
// Return empty slice instead of nil to ensure JSON encodes as [] not null
return []models.Dataset{}, err
}
var datasets []models.Dataset
datasets := []models.Dataset{}
lines := strings.Split(output, "\n")
for _, line := range lines {
if line == "" {
@@ -428,10 +471,11 @@ func (s *Service) ListZVOLs(pool string) ([]models.ZVOL, error) {
output, err := s.execCommand(s.zfsPath, args...)
if err != nil {
return nil, err
// Return empty slice instead of nil to ensure JSON encodes as [] not null
return []models.ZVOL{}, err
}
var zvols []models.ZVOL
zvols := []models.ZVOL{}
lines := strings.Split(output, "\n")
for _, line := range lines {
if line == "" {
@@ -588,10 +632,11 @@ func (s *Service) ListSnapshots(dataset string) ([]models.Snapshot, error) {
output, err := s.execCommand(s.zfsPath, args...)
if err != nil {
return nil, err
// Return empty slice instead of nil to ensure JSON encodes as [] not null
return []models.Snapshot{}, err
}
var snapshots []models.Snapshot
snapshots := []models.Snapshot{}
lines := strings.Split(output, "\n")
for _, line := range lines {
if line == "" {