Skip to content

Commit

Permalink
Merge pull request #1333 from stgraber/main
Browse files Browse the repository at this point in the history
Fix handling of custom volume snapshot patterns
  • Loading branch information
hallyn authored Oct 23, 2024
2 parents c120d62 + c3d82bf commit dc8544e
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 27 deletions.
75 changes: 48 additions & 27 deletions cmd/incusd/storage_volumes_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,6 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res
return response.BadRequest(err)
}

// Get a snapshot name.
if req.Name == "" {
var i int

_ = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error {
i = tx.GetNextStorageVolumeSnapshotIndex(ctx, poolName, volumeName, volumeType, "snap%d")

return nil
})

req.Name = fmt.Sprintf("snap%d", i)
}

// Check that this isn't a restricted volume
used, err := storagePools.VolumeUsedByDaemon(s, poolName, volumeName)
if err != nil {
Expand All @@ -196,22 +183,9 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res
return response.SmartError(err)
}

// Validate the snapshot name using same rule as pool name.
err = pool.ValidateName(req.Name)
if err != nil {
return response.BadRequest(err)
}

// Get the parent volume.
var parentDBVolume *db.StorageVolume
err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error {
// Ensure that the snapshot doesn't already exist.
snapDBVolume, err := tx.GetStoragePoolVolume(ctx, pool.ID(), projectName, volumeType, fmt.Sprintf("%s/%s", volumeName, req.Name), true)
if err != nil && !response.IsNotFoundError(err) {
return err
} else if snapDBVolume != nil {
return api.StatusErrorf(http.StatusConflict, "Snapshot %q already in use", req.Name)
}

// Get the parent volume so we can get the config.
parentDBVolume, err = tx.GetStoragePoolVolume(ctx, pool.ID(), projectName, volumeType, volumeName, true)
if err != nil {
Expand All @@ -224,6 +198,53 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res
return response.SmartError(err)
}

// Get the snapshot pattern.
pattern := parentDBVolume.Config["snapshots.pattern"]
if pattern == "" {
pattern = "snap%d"
}

pattern, err = internalUtil.RenderTemplate(pattern, pongo2.Context{
"creation_date": time.Now(),
})
if err != nil {
return response.InternalError(err)
}

// Get a snapshot name.
if req.Name == "" {
var i int

_ = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error {
i = tx.GetNextStorageVolumeSnapshotIndex(ctx, poolName, volumeName, volumeType, pattern)

return nil
})

req.Name = fmt.Sprintf(pattern, i)
} else {
// Make sure the snapshot doesn't already exist.
err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error {
snapDBVolume, err := tx.GetStoragePoolVolume(ctx, pool.ID(), projectName, volumeType, fmt.Sprintf("%s/%s", volumeName, req.Name), true)
if err != nil && !response.IsNotFoundError(err) {
return err
} else if snapDBVolume != nil {
return api.StatusErrorf(http.StatusConflict, "Snapshot %q already in use", req.Name)
}

return nil
})
if err != nil {
return response.SmartError(err)
}
}

// Validate the snapshot name using same rule as pool name.
err = pool.ValidateName(req.Name)
if err != nil {
return response.BadRequest(err)
}

// Fill in the expiry.
var expiry time.Time
if req.ExpiresAt != nil {
Expand Down
9 changes: 9 additions & 0 deletions test/suites/storage_snapshots.sh
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ test_storage_volume_snapshots() {
incus storage volume delete "${storage_pool}" "vol1"
incus storage volume delete "${storage_pool}" "vol1-snap0"

# Check snapshot pattern
incus storage volume create "${storage_pool}" "vol1"
incus storage volume snapshot create "${storage_pool}" "vol1"
incus storage volume snapshot show "${storage_pool}" "vol1/snap0"
incus storage volume set "${storage_pool}" "vol1" snapshots.pattern="test%d"
incus storage volume snapshot create "${storage_pool}" "vol1"
incus storage volume snapshot show "${storage_pool}" "vol1/test0"
incus storage volume delete "${storage_pool}" "vol1"

# Check snapshot restore of type block volumes.
incus storage volume create "${storage_pool}" "vol1" --type block
incus storage volume snapshot create "${storage_pool}" "vol1" "snap0"
Expand Down

0 comments on commit dc8544e

Please sign in to comment.