main #1
@@ -76,19 +76,29 @@ func (a *App) handleCreatePool(w http.ResponseWriter, r *http.Request) {
|
|||||||
req.Options = make(map[string]string)
|
req.Options = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.zfs.CreatePool(req.Name, req.VDEVs, req.Options); err != nil {
|
err := a.zfs.CreatePool(req.Name, req.VDEVs, req.Options)
|
||||||
|
|
||||||
|
// Always check if pool exists, even if creation reported an error
|
||||||
|
// Sometimes pool is created despite errors (e.g., mountpoint issues)
|
||||||
|
pool, getErr := a.zfs.GetPool(req.Name)
|
||||||
|
if getErr == nil {
|
||||||
|
// Pool exists - return success even if creation reported an error
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("create pool reported error but pool exists: %v", err)
|
||||||
|
}
|
||||||
|
writeJSON(w, http.StatusCreated, pool)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pool doesn't exist - return the error
|
||||||
|
if err != nil {
|
||||||
log.Printf("create pool error: %v", err)
|
log.Printf("create pool error: %v", err)
|
||||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pool, err := a.zfs.GetPool(req.Name)
|
// No error but pool doesn't exist (shouldn't happen, but handle it)
|
||||||
if err != nil {
|
writeJSON(w, http.StatusCreated, map[string]string{"message": "pool created", "name": req.Name})
|
||||||
writeJSON(w, http.StatusCreated, map[string]string{"message": "pool created", "name": req.Name})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
writeJSON(w, http.StatusCreated, pool)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) handleGetPool(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleGetPool(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -185,6 +185,10 @@ func (s *Service) CreatePool(name string, vdevs []string, options map[string]str
|
|||||||
options = make(map[string]string)
|
options = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add -f flag to force creation even if devices have existing filesystems
|
||||||
|
// This handles cases where devices are "in use" or contain "unknown filesystem"
|
||||||
|
args = append(args, "-f")
|
||||||
|
|
||||||
// If mountpoint is not explicitly set, use dedicated storage directory
|
// If mountpoint is not explicitly set, use dedicated storage directory
|
||||||
mountpoint := options["mountpoint"]
|
mountpoint := options["mountpoint"]
|
||||||
if mountpoint == "" {
|
if mountpoint == "" {
|
||||||
@@ -218,8 +222,26 @@ func (s *Service) CreatePool(name string, vdevs []string, options map[string]str
|
|||||||
|
|
||||||
// Create the pool
|
// Create the pool
|
||||||
_, err := s.execCommand(s.zpoolPath, args...)
|
_, err := s.execCommand(s.zpoolPath, args...)
|
||||||
|
|
||||||
|
// Even if creation reports an error, check if pool actually exists
|
||||||
|
// Sometimes ZFS reports errors but pool is still created
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
// Check if pool exists despite the error
|
||||||
|
if existingPools, listErr := s.ListPools(); listErr == nil {
|
||||||
|
for _, pool := range existingPools {
|
||||||
|
if pool.Name == name {
|
||||||
|
// Pool exists! Log the original error but don't fail
|
||||||
|
log.Printf("warning: pool creation reported error but pool %s exists: %v", name, err)
|
||||||
|
err = nil // Clear error since pool was created
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If pool doesn't exist and we still have an error, return it
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pool created successfully - now try to set mountpoint and mount if needed
|
// Pool created successfully - now try to set mountpoint and mount if needed
|
||||||
|
|||||||
@@ -516,16 +516,28 @@ async function createPool(e) {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const data = await res.json().catch(() => null);
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
closeModal('create-pool-modal');
|
closeModal('create-pool-modal');
|
||||||
e.target.reset();
|
e.target.reset();
|
||||||
loadPools();
|
// Wait a moment for pool to be fully created, then refresh
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
await loadPools();
|
||||||
alert('Pool created successfully');
|
alert('Pool created successfully');
|
||||||
} else {
|
} else {
|
||||||
const err = await res.json();
|
// Even if error, check if pool was actually created
|
||||||
alert(`Error: ${err.error || 'Failed to create pool'}`);
|
// Sometimes creation reports error but pool exists
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
await loadPools();
|
||||||
|
|
||||||
|
const err = await res.json().catch(() => ({ error: 'Failed to create pool' }));
|
||||||
|
alert(`Error: ${err.error || 'Failed to create pool'}\n\nNote: Please check if the pool was created despite the error.`);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
// On network error, still try to refresh to see if pool was created
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
await loadPools();
|
||||||
alert(`Error: ${err.message}`);
|
alert(`Error: ${err.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user