Skip to content

Commit

Permalink
Merge pull request #1200 from nrb/fix-1183
Browse files Browse the repository at this point in the history
Fix restoring GCP regional disks
  • Loading branch information
skriss committed Feb 12, 2019
2 parents ed73be4 + 0ffaeb9 commit e1d4143
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 7 deletions.
1 change: 1 addition & 0 deletions changelogs/unreleased/1200-nrb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Set the zones for GCP regional disks on restore. This requires the `compute.zones.get` permission on the GCP serviceaccount in order to work correctly.
1 change: 1 addition & 0 deletions docs/gcp-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ To integrate Velero with GCP, create an Velero-specific [Service Account][15]:
compute.snapshots.create
compute.snapshots.useReadOnly
compute.snapshots.delete
compute.zones.get
)
gcloud iam roles create velero.server \
Expand Down
42 changes: 35 additions & 7 deletions pkg/cloudprovider/gcp/block_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ import (
"github.com/heptio/velero/pkg/util/collections"
)

const projectKey = "project"
const (
projectKey = "project"
zoneSeparator = "__"
)

type blockStore struct {
gce *compute.Service
Expand Down Expand Up @@ -97,23 +100,23 @@ func extractProjectFromCreds() (string, error) {
// by GKE when a storage class spans multiple availablity
// zones.
func isMultiZone(volumeAZ string) bool {
return strings.Contains(volumeAZ, "__")
return strings.Contains(volumeAZ, zoneSeparator)
}

// parseRegion parses a failure-domain tag with multiple regions
// and returns a single region. Regions are sperated by double underscores (__).
// parseRegion parses a failure-domain tag with multiple zones
// and returns a single region. Zones are sperated by double underscores (__).
// For example
// input: us-central1-a__us-central1-b
// return: us-central1
// When a custom storage class spans multiple geographical regions,
// such as us-central1 and us-west1 only the region matching the cluster is used
// When a custom storage class spans multiple geographical zones,
// such as us-central1 and us-west1 only the zone matching the cluster is used
// in the failure-domain tag.
// For example
// Cluster nodes in us-central1-c, us-central1-f
// Storage class zones us-central1-a, us-central1-f, us-east1-a, us-east1-d
// The failure-domain tag would be: us-central1-a__us-central1-f
func parseRegion(volumeAZ string) (string, error) {
zones := strings.Split(volumeAZ, "__")
zones := strings.Split(volumeAZ, zoneSeparator)
zone := zones[0]
parts := strings.SplitAfterN(zone, "-", 3)
if len(parts) < 2 {
Expand All @@ -122,6 +125,22 @@ func parseRegion(volumeAZ string) (string, error) {
return parts[0] + strings.TrimSuffix(parts[1], "-"), nil
}

// Retrieve the URLs for zones via the GCP API.
func (b *blockStore) getZoneURLs(volumeAZ string) ([]string, error) {
zones := strings.Split(volumeAZ, zoneSeparator)
var zoneURLs []string
for _, z := range zones {
zone, err := b.gce.Zones.Get(b.project, z).Do()
if err != nil {
return nil, errors.WithStack(err)
}

zoneURLs = append(zoneURLs, zone.SelfLink)
}

return zoneURLs, nil
}

func (b *blockStore) CreateVolumeFromSnapshot(snapshotID, volumeType, volumeAZ string, iops *int64) (volumeID string, err error) {
// get the snapshot so we can apply its tags to the volume
res, err := b.gce.Snapshots.Get(b.project, snapshotID).Do()
Expand All @@ -146,6 +165,15 @@ func (b *blockStore) CreateVolumeFromSnapshot(snapshotID, volumeType, volumeAZ s
if err != nil {
return "", err
}

// URLs for zones that the volume is replicated to within GCP
zoneURLs, err := b.getZoneURLs(volumeAZ)
if err != nil {
return "", err
}

disk.ReplicaZones = zoneURLs

if _, err = b.gce.RegionDisks.Insert(b.project, volumeRegion, disk).Do(); err != nil {
return "", errors.WithStack(err)
}
Expand Down

0 comments on commit e1d4143

Please sign in to comment.