incusd/storage: Improve handling of daemon volumes

Signed-off-by: Benjamin Somers <benjamin.somers@imt-atlantique.fr>
This commit is contained in:
Benjamin Somers 2026-05-27 20:37:26 +00:00
parent ae5b55a706
commit acc1db764e
4 changed files with 16 additions and 21 deletions

View File

@ -1533,12 +1533,12 @@ func storagePoolVolumePost(d *Daemon, r *http.Request) response.Response {
}
// Check if the daemon itself is using it.
used, err := storagePools.VolumeUsedByDaemon(s, srcPoolName, volumeName)
frag, err := storagePools.VolumeUsedByDaemon(s, srcPoolName, volumeName)
if err != nil {
return response.SmartError(err)
}
if used {
if frag != "" {
return response.SmartError(errors.New("Volume is used by Incus itself and cannot be renamed"))
}

View File

@ -186,12 +186,12 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res
}
// Check that this isn't a restricted volume
used, err := storagePools.VolumeUsedByDaemon(s, poolName, volumeName)
frag, err := storagePools.VolumeUsedByDaemon(s, poolName, volumeName)
if err != nil {
return response.InternalError(err)
}
if used {
if frag != "" {
return response.BadRequest(errors.New("Volumes used by Incus itself cannot have snapshots"))
}

View File

@ -107,13 +107,13 @@ func storagePoolVolumeUsedByGet(s *state.State, requestProjectName string, poolN
}
// Check if the daemon itself is using it.
used, err := storagePools.VolumeUsedByDaemon(s, poolName, vol.Name)
frag, err := storagePools.VolumeUsedByDaemon(s, poolName, vol.Name)
if err != nil {
return []string{}, err
}
if used {
return []string{api.NewURL().Path(version.APIVersion).String()}, nil
if frag != "" {
return []string{api.NewURL().Path(version.APIVersion).Target(vol.Location).Fragment(frag).String()}, nil
}
// Look for instances using this volume.

View File

@ -1063,31 +1063,26 @@ func VolumeUsedByExclusiveRemoteInstancesWithProfiles(s *state.State, poolName s
return remoteInstance, nil
}
// VolumeUsedByDaemon indicates whether the volume is used by daemon storage.
func VolumeUsedByDaemon(s *state.State, poolName string, volumeName string) (bool, error) {
var storageBackups string
var storageImages string
// VolumeUsedByDaemon indicates whether the volume is used by daemon storage, by returning a
// configuration fragment.
func VolumeUsedByDaemon(s *state.State, poolName string, volumeName string) (string, error) {
daemonVolumes := make(map[string]string, 3)
err := s.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error {
nodeConfig, err := node.ConfigLoad(ctx, tx)
if err != nil {
return err
}
storageBackups = nodeConfig.StorageBackupsVolume()
storageImages = nodeConfig.StorageImagesVolume()
daemonVolumes[nodeConfig.StorageBackupsVolume()] = "storage.backups_volume"
daemonVolumes[nodeConfig.StorageImagesVolume()] = "storage.images_volume"
daemonVolumes[nodeConfig.StorageLogsVolume()] = "storage.logs_volume"
return nil
})
if err != nil {
return false, err
return "", err
}
fullName := fmt.Sprintf("%s/%s", poolName, volumeName)
if storageBackups == fullName || storageImages == fullName {
return true, nil
}
return false, nil
return daemonVolumes[fmt.Sprintf("%s/%s", poolName, volumeName)], nil
}
// FallbackMigrationType returns the fallback migration transport to use based on volume content type.