Skip to content

Commit 45934b7

Browse files
committed
feat: copy labels from Disk to Snapshot
It can be very useful to be able to track your snapshots using the same labels are you have on your original disks, this PR copies over all of the labels of the disk and adds a new permission requirement of `compute.snapshots.setLabels` to allow for that however if it's not available it will fall back to the previous behaviour. Signed-off-by: Daniel Hobley <danielh@unity3d.com>
1 parent a9bc7bb commit 45934b7

File tree

3 files changed

+35
-5
lines changed

3 files changed

+35
-5
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ These permissions are required by Velero to manage snapshot resources in the GCP
115115
compute.snapshots.create
116116
compute.snapshots.useReadOnly
117117
compute.snapshots.delete
118+
compute.snapshots.setLabels
118119
compute.zones.get
119120
storage.objects.create
120121
storage.objects.delete

changelogs/unreleased/178-opdude

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Attempt to copy labels from source Disk to snapshot to help with tracking your snapshots in the Google console and billing account, requires `compute.snapshots.setLabels` permission but will fall back to the previous behavior if the permission is not available.

velero-plugin-for-gcp/volume_snapshotter.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ func (b *VolumeSnapshotter) CreateVolumeFromSnapshot(snapshotID, volumeType, vol
216216
SourceSnapshot: res.SelfLink,
217217
Type: volumeType,
218218
Description: res.Description,
219+
Labels: res.Labels,
219220
}
220221

221222
if isMultiZone(volumeAZ) {
@@ -319,23 +320,36 @@ func (b *VolumeSnapshotter) createSnapshot(snapshotName, volumeID, volumeAZ stri
319320
return "", errors.WithStack(err)
320321
}
321322

322-
gceSnap := compute.Snapshot{
323+
snapshot := &compute.Snapshot{
323324
Name: snapshotName,
324325
Description: getSnapshotTags(tags, disk.Description, b.log),
325326
SourceDisk: disk.SelfLink,
326327
SnapshotType: b.snapshotType,
328+
Labels: disk.Labels,
327329
}
328330

329331
if b.snapshotLocation != "" {
330-
gceSnap.StorageLocations = []string{b.snapshotLocation}
332+
snapshot.StorageLocations = []string{b.snapshotLocation}
331333
}
332334

333-
_, err = b.gce.Snapshots.Insert(b.snapshotProject, &gceSnap).Do()
334-
if err != nil {
335+
// Try creating snapshot with labels
336+
_, err = b.gce.Snapshots.Insert(b.snapshotProject, snapshot).Do()
337+
338+
// If we get a permission error for labels, retry without them
339+
if err != nil && isLabelPermissionError(err) {
340+
b.log.WithError(err).Warn("Missing compute.snapshots.setLabels permission, creating snapshot without labels")
341+
342+
// Retry without labels
343+
snapshot.Labels = nil
344+
_, err = b.gce.Snapshots.Insert(b.snapshotProject, snapshot).Do()
345+
if err != nil {
346+
return "", errors.WithStack(err)
347+
}
348+
} else if err != nil {
335349
return "", errors.WithStack(err)
336350
}
337351

338-
return gceSnap.Name, nil
352+
return snapshot.Name, nil
339353
}
340354

341355
func (b *VolumeSnapshotter) createRegionSnapshot(snapshotName, volumeID, volumeRegion string, tags map[string]string) (string, error) {
@@ -349,6 +363,7 @@ func (b *VolumeSnapshotter) createRegionSnapshot(snapshotName, volumeID, volumeR
349363
Description: getSnapshotTags(tags, disk.Description, b.log),
350364
SourceDisk: disk.SelfLink,
351365
SnapshotType: b.snapshotType,
366+
Labels: disk.Labels,
352367
}
353368

354369
if b.snapshotLocation != "" {
@@ -498,3 +513,16 @@ func (b *VolumeSnapshotter) IsVolumeCreatedCrossProjects(volumeHandle string) bo
498513

499514
return false
500515
}
516+
517+
// isLabelPermissionError Helper function to detect label permission errors
518+
func isLabelPermissionError(err error) bool {
519+
if err == nil {
520+
return false
521+
}
522+
523+
// Check for specific GCP permission error
524+
// This might need adjustment based on actual error format
525+
errStr := err.Error()
526+
return strings.Contains(errStr, "compute.snapshots.setLabels") ||
527+
(strings.Contains(errStr, "permission") && strings.Contains(errStr, "label"))
528+
}

0 commit comments

Comments
 (0)