Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ These permissions are required by Velero to manage snapshot resources in the GCP
compute.snapshots.create
compute.snapshots.useReadOnly
compute.snapshots.delete
compute.snapshots.setLabels
compute.zones.get
storage.objects.create
storage.objects.delete
Expand Down
1 change: 1 addition & 0 deletions changelogs/unreleased/178-opdude
Original file line number Diff line number Diff line change
@@ -0,0 +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.
38 changes: 33 additions & 5 deletions velero-plugin-for-gcp/volume_snapshotter.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ func (b *VolumeSnapshotter) CreateVolumeFromSnapshot(snapshotID, volumeType, vol
SourceSnapshot: res.SelfLink,
Type: volumeType,
Description: res.Description,
Labels: res.Labels,
}

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

gceSnap := compute.Snapshot{
snapshot := &compute.Snapshot{
Name: snapshotName,
Description: getSnapshotTags(tags, disk.Description, b.log),
SourceDisk: disk.SelfLink,
SnapshotType: b.snapshotType,
Labels: disk.Labels,
}

if b.snapshotLocation != "" {
gceSnap.StorageLocations = []string{b.snapshotLocation}
snapshot.StorageLocations = []string{b.snapshotLocation}
}

_, err = b.gce.Snapshots.Insert(b.snapshotProject, &gceSnap).Do()
if err != nil {
// Try creating snapshot with labels
_, err = b.gce.Snapshots.Insert(b.snapshotProject, snapshot).Do()

// If we get a permission error for labels, retry without them
if err != nil && isLabelPermissionError(err) {
b.log.WithError(err).Warn("Missing compute.snapshots.setLabels permission, creating snapshot without labels")

// Retry without labels
snapshot.Labels = nil
_, err = b.gce.Snapshots.Insert(b.snapshotProject, snapshot).Do()
if err != nil {
return "", errors.WithStack(err)
}
} else if err != nil {
return "", errors.WithStack(err)
}

return gceSnap.Name, nil
return snapshot.Name, nil
}

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

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

return false
}

// isLabelPermissionError Helper function to detect label permission errors
func isLabelPermissionError(err error) bool {
if err == nil {
return false
}

// Check for specific GCP permission error
// This might need adjustment based on actual error format
errStr := err.Error()
return strings.Contains(errStr, "compute.snapshots.setLabels") ||
(strings.Contains(errStr, "permission") && strings.Contains(errStr, "label"))
}