This commit is contained in:
@@ -180,6 +180,23 @@ func (s *Service) GetPool(name string) (*models.Pool, error) {
|
||||
func (s *Service) CreatePool(name string, vdevs []string, options map[string]string) error {
|
||||
args := []string{"create"}
|
||||
|
||||
if options == nil {
|
||||
options = make(map[string]string)
|
||||
}
|
||||
|
||||
// If mountpoint is not explicitly set, use dedicated storage directory
|
||||
mountpoint := options["mountpoint"]
|
||||
if mountpoint == "" {
|
||||
// Default mountpoint: /storage/pools/{poolname}
|
||||
mountpoint = "/storage/pools/" + name
|
||||
options["mountpoint"] = mountpoint
|
||||
// Pre-create the mountpoint directory with sudo
|
||||
_ = s.createMountpointWithSudo(mountpoint)
|
||||
} else if mountpoint != "none" {
|
||||
// Ensure mountpoint directory exists with sudo
|
||||
_ = s.createMountpointWithSudo(mountpoint)
|
||||
}
|
||||
|
||||
// Add options
|
||||
for k, v := range options {
|
||||
args = append(args, "-o", fmt.Sprintf("%s=%s", k, v))
|
||||
@@ -192,6 +209,26 @@ func (s *Service) CreatePool(name string, vdevs []string, options map[string]str
|
||||
return err
|
||||
}
|
||||
|
||||
// createMountpointWithSudo creates a mountpoint directory using sudo
|
||||
// This allows ZFS to mount pools even if root filesystem appears read-only
|
||||
func (s *Service) createMountpointWithSudo(path string) error {
|
||||
// Use sudo to create the directory with proper permissions
|
||||
cmd := exec.Command("sudo", "-n", "mkdir", "-p", path)
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
// If sudo mkdir fails, try without sudo (might already be root or have permissions)
|
||||
directCmd := exec.Command("mkdir", "-p", path)
|
||||
if directErr := directCmd.Run(); directErr != nil {
|
||||
// Both failed, but don't return error - ZFS might handle it
|
||||
// Log but continue, as ZFS might create it or mountpoint might already exist
|
||||
return fmt.Errorf("failed to create mountpoint %s: %v: %s", path, err, stderr.String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DestroyPool destroys a ZFS pool
|
||||
func (s *Service) DestroyPool(name string) error {
|
||||
_, err := s.execCommand(s.zpoolPath, "destroy", name)
|
||||
@@ -440,6 +477,27 @@ func (s *Service) ListDatasets(pool string) ([]models.Dataset, error) {
|
||||
func (s *Service) CreateDataset(name string, options map[string]string) error {
|
||||
args := []string{"create"}
|
||||
|
||||
if options == nil {
|
||||
options = make(map[string]string)
|
||||
}
|
||||
|
||||
// If mountpoint is not explicitly set, use dedicated storage directory
|
||||
mountpoint := options["mountpoint"]
|
||||
if mountpoint == "" {
|
||||
// Extract dataset name (last part after /)
|
||||
parts := strings.Split(name, "/")
|
||||
datasetName := parts[len(parts)-1]
|
||||
// Default mountpoint: /storage/datasets/{datasetname}
|
||||
mountpoint = "/storage/datasets/" + datasetName
|
||||
options["mountpoint"] = mountpoint
|
||||
// Pre-create the mountpoint directory with sudo
|
||||
_ = s.createMountpointWithSudo(mountpoint)
|
||||
} else if mountpoint != "none" {
|
||||
// Ensure mountpoint directory exists with sudo
|
||||
_ = s.createMountpointWithSudo(mountpoint)
|
||||
}
|
||||
|
||||
// Add options
|
||||
for k, v := range options {
|
||||
args = append(args, "-o", fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user