This commit is contained in:
@@ -77,18 +77,23 @@ func (a *App) handleCreatePool(w http.ResponseWriter, r *http.Request) {
|
|||||||
req.Options = make(map[string]string)
|
req.Options = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("creating pool: name=%s, vdevs=%v, options=%v", req.Name, req.VDEVs, req.Options)
|
||||||
|
|
||||||
err := a.zfs.CreatePool(req.Name, req.VDEVs, req.Options)
|
err := a.zfs.CreatePool(req.Name, req.VDEVs, req.Options)
|
||||||
|
|
||||||
// CRITICAL: Always check if pool exists, regardless of reported error
|
// CRITICAL: Always check if pool exists, regardless of reported error
|
||||||
// ZFS often reports mountpoint errors but pool is still created
|
// ZFS often reports mountpoint errors but pool is still created
|
||||||
|
// The CreatePool function already does retries, but we double-check here
|
||||||
// Wait a brief moment for pool to be fully registered
|
// Wait a brief moment for pool to be fully registered
|
||||||
time.Sleep(200 * time.Millisecond)
|
time.Sleep(300 * time.Millisecond)
|
||||||
|
|
||||||
pool, getErr := a.zfs.GetPool(req.Name)
|
pool, getErr := a.zfs.GetPool(req.Name)
|
||||||
if getErr == nil {
|
if getErr == nil {
|
||||||
// Pool exists - this is success!
|
// Pool exists - this is success!
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("info: pool %s created successfully despite reported error: %v", req.Name, err)
|
log.Printf("info: pool %s created successfully despite CreatePool reporting error: %v", req.Name, err)
|
||||||
|
} else {
|
||||||
|
log.Printf("info: pool %s created successfully", req.Name)
|
||||||
}
|
}
|
||||||
// Set cache-control headers
|
// Set cache-control headers
|
||||||
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
@@ -98,15 +103,21 @@ func (a *App) handleCreatePool(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pool doesn't exist - return the error
|
// Pool doesn't exist - return the error with detailed context
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("create pool error: %v", err)
|
log.Printf("error: pool %s creation failed - CreatePool error: %v, GetPool error: %v", req.Name, err, getErr)
|
||||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
writeJSON(w, http.StatusInternalServerError, map[string]string{
|
||||||
|
"error": err.Error(),
|
||||||
|
"details": fmt.Sprintf("Pool '%s' was not created. Check logs for zpool command output.", req.Name),
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// No error but pool doesn't exist (shouldn't happen, but handle it)
|
// No error but pool doesn't exist (shouldn't happen, but handle it)
|
||||||
writeJSON(w, http.StatusCreated, map[string]string{"message": "pool created", "name": req.Name})
|
log.Printf("warning: pool %s creation reported no error but pool was not found", req.Name)
|
||||||
|
writeJSON(w, http.StatusInternalServerError, map[string]string{
|
||||||
|
"error": fmt.Sprintf("Pool '%s' creation reported success but pool was not found", req.Name),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) handleGetPool(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleGetPool(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -226,31 +226,61 @@ func (s *Service) CreatePool(name string, vdevs []string, options map[string]str
|
|||||||
args = append(args, name)
|
args = append(args, name)
|
||||||
args = append(args, vdevs...)
|
args = append(args, vdevs...)
|
||||||
|
|
||||||
|
// Log the command we're about to run for debugging
|
||||||
|
log.Printf("executing: %s %v", s.zpoolPath, args)
|
||||||
|
|
||||||
// Create the pool (without mountpoint to avoid mount errors)
|
// Create the pool (without mountpoint to avoid mount errors)
|
||||||
_, err := s.execCommand(s.zpoolPath, args...)
|
createOutput, err := s.execCommand(s.zpoolPath, args...)
|
||||||
|
|
||||||
|
// Log the command output for debugging
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("zpool create failed - output: %s, error: %v", createOutput, err)
|
||||||
|
} else {
|
||||||
|
log.Printf("zpool create succeeded - output: %s", createOutput)
|
||||||
|
}
|
||||||
|
|
||||||
// CRITICAL: Always check if pool exists, even if creation reported an error
|
// CRITICAL: Always check if pool exists, even if creation reported an error
|
||||||
// ZFS often reports mountpoint errors but pool is still created successfully
|
// ZFS often reports mountpoint errors but pool is still created successfully
|
||||||
|
// Retry checking pool existence up to 3 times with delays
|
||||||
poolExists := false
|
poolExists := false
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
if i > 0 {
|
||||||
|
// Wait before retry (100ms, 200ms, 300ms)
|
||||||
|
time.Sleep(time.Duration(i*100) * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
if existingPools, listErr := s.ListPools(); listErr == nil {
|
if existingPools, listErr := s.ListPools(); listErr == nil {
|
||||||
for _, pool := range existingPools {
|
for _, pool := range existingPools {
|
||||||
if pool.Name == name {
|
if pool.Name == name {
|
||||||
poolExists = true
|
poolExists = true
|
||||||
|
log.Printf("pool %s found after %d check(s)", name, i+1)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if poolExists {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if poolExists {
|
if poolExists {
|
||||||
// Pool exists! This is success, regardless of any reported errors
|
// Pool exists! This is success, regardless of any reported errors
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("info: pool %s created successfully despite reported error: %v", name, err)
|
log.Printf("info: pool %s created successfully despite reported error: %v", name, err)
|
||||||
|
} else {
|
||||||
|
log.Printf("info: pool %s created successfully", name)
|
||||||
}
|
}
|
||||||
// Clear error since pool was created
|
// Clear error since pool was created
|
||||||
err = nil
|
err = nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
// Pool doesn't exist and we have an error - return it
|
// Pool doesn't exist and we have an error - return it with full context
|
||||||
return err
|
log.Printf("error: pool %s creation failed and pool does not exist: %v", name, err)
|
||||||
|
return fmt.Errorf("failed to create pool %s: %v", name, err)
|
||||||
|
} else {
|
||||||
|
// No error reported but pool doesn't exist - this shouldn't happen
|
||||||
|
log.Printf("warning: pool %s creation reported no error but pool does not exist", name)
|
||||||
|
return fmt.Errorf("pool %s creation reported success but pool was not found", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pool created successfully - now set mountpoint and mount if needed
|
// Pool created successfully - now set mountpoint and mount if needed
|
||||||
|
|||||||
Reference in New Issue
Block a user