add installer alpha version
This commit is contained in:
@@ -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 == "" {
|
||||
|
||||
Reference in New Issue
Block a user