Skip to content

Automated cherry pick of #1593: Add support for a multi-zone volumeHandle #1616

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
19 changes: 15 additions & 4 deletions cmd/gce-pd-csi-driver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,16 @@ var (
maxConcurrentFormatAndMount = flag.Int("max-concurrent-format-and-mount", 1, "If set then format and mount operations are serialized on each node. This is stronger than max-concurrent-format as it includes fsck and other mount operations")
formatAndMountTimeout = flag.Duration("format-and-mount-timeout", 1*time.Minute, "The maximum duration of a format and mount operation before another such operation will be started. Used only if --serialize-format-and-mount")
fallbackRequisiteZonesFlag = flag.String("fallback-requisite-zones", "", "Comma separated list of requisite zones that will be used if there are not sufficient zones present in requisite topologies when provisioning a disk")
enableStoragePoolsFlag = flag.Bool("enable-storage-pools", false, "If set to true, the CSI Driver will allow volumes to be provisioned in Storage Pools")

multiZoneVolumeHandleDiskTypesFlag = flag.String("multi-zone-volume-handle-disk-types", "", "Comma separated list of allowed disk types that can use the multi-zone volumeHandle. Used only if --multi-zone-volume-handle-enable")
multiZoneVolumeHandleEnableFlag = flag.Bool("multi-zone-volume-handle-enable", false, "If set to true, the multi-zone volumeHandle feature will be enabled")

enableStoragePoolsFlag = flag.Bool("enable-storage-pools", false, "If set to true, the CSI Driver will allow volumes to be provisioned in Storage Pools")
computeEnvironment gce.Environment = gce.EnvironmentProduction
computeEndpoint *url.URL
version string
allowedComputeEnvironment = []gce.Environment{gce.EnvironmentStaging, gce.EnvironmentProduction}

version string
)

const (
Expand Down Expand Up @@ -156,9 +160,16 @@ func handle() {
// Initialize identity server
identityServer := driver.NewIdentityServer(gceDriver)

// Initilaize requisite zones
// Initialize requisite zones
fallbackRequisiteZones := strings.Split(*fallbackRequisiteZonesFlag, ",")

// Initialize multi-zone disk types
multiZoneVolumeHandleDiskTypes := strings.Split(*multiZoneVolumeHandleDiskTypesFlag, ",")
multiZoneVolumeHandleConfig := driver.MultiZoneVolumeHandleConfig{
Enable: *multiZoneVolumeHandleEnableFlag,
DiskTypes: multiZoneVolumeHandleDiskTypes,
}

// Initialize requirements for the controller service
var controllerServer *driver.GCEControllerServer
if *runControllerService {
Expand All @@ -168,7 +179,7 @@ func handle() {
}
initialBackoffDuration := time.Duration(*errorBackoffInitialDurationMs) * time.Millisecond
maxBackoffDuration := time.Duration(*errorBackoffMaxDurationMs) * time.Millisecond
controllerServer = driver.NewControllerServer(gceDriver, cloudProvider, initialBackoffDuration, maxBackoffDuration, fallbackRequisiteZones, *enableStoragePoolsFlag)
controllerServer = driver.NewControllerServer(gceDriver, cloudProvider, initialBackoffDuration, maxBackoffDuration, fallbackRequisiteZones, *enableStoragePoolsFlag, multiZoneVolumeHandleConfig)
} else if *cloudConfigFilePath != "" {
klog.Warningf("controller service is disabled but cloud config given - it has no effect")
}
Expand Down
8 changes: 8 additions & 0 deletions pkg/common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@ const (
VolumeAttributePartition = "partition"

UnspecifiedValue = "UNSPECIFIED"

// Keyword indicating a 'multi-zone' volumeHandle. Replaces "zones" in the volumeHandle:
// eg: projects/{project}/zones/multi-zone/disks/{name} vs.
// projects/{project}/zones/{zone}/disks/{name}
MultiZoneValue = "multi-zone"

// Label that is set on a disk when it is used by a 'multi-zone' VolumeHandle
MultiZoneLabel = "goog-gke-multi-zone"
)
12 changes: 12 additions & 0 deletions pkg/common/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,3 +478,15 @@ func UnorderedSlicesEqual(slice1 []string, slice2 []string) bool {
}
return true
}

func VolumeIdAsMultiZone(volumeId string) (string, error) {
splitId := strings.Split(volumeId, "/")
if len(splitId) != volIDTotalElements {
return "", fmt.Errorf("failed to get id components. Expected projects/{project}/zones/{zone}/disks/{name}. Got: %s", volumeId)
}
if splitId[volIDToplogyKey] != "zones" {
return "", fmt.Errorf("expected id to be zonal. Got: %s", volumeId)
}
splitId[volIDToplogyValue] = MultiZoneValue
return strings.Join(splitId, "/"), nil
}
13 changes: 13 additions & 0 deletions pkg/gce-cloud-provider/compute/cloud-disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,16 @@ func (d *CloudDisk) GetEnableStoragePools() bool {
return false
}
}

func (d *CloudDisk) GetLabels() map[string]string {
switch {
case d.disk != nil:
return d.disk.Labels
case d.betaDisk != nil:
return d.betaDisk.Labels
case d.alphaDisk != nil:
return d.alphaDisk.Labels
default:
return nil
}
}
45 changes: 45 additions & 0 deletions pkg/gce-cloud-provider/compute/cloud-disk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package gcecloudprovider
import (
"testing"

"github.com/google/go-cmp/cmp"
computealpha "google.golang.org/api/compute/v0.alpha"
computebeta "google.golang.org/api/compute/v0.beta"
computev1 "google.golang.org/api/compute/v1"
Expand Down Expand Up @@ -129,3 +130,47 @@ func TestGetEnableStoragePools(t *testing.T) {
}
}
}

func TestGetLabels(t *testing.T) {
testCases := []struct {
name string
cloudDisk *CloudDisk
wantLabels map[string]string
}{
{
name: "v1 disk labels",
cloudDisk: &CloudDisk{
disk: &computev1.Disk{
Labels: map[string]string{"foo": "v1", "goog-gke-multi-zone": "true"},
},
},
wantLabels: map[string]string{"foo": "v1", "goog-gke-multi-zone": "true"},
},
{
name: "beta disk labels",
cloudDisk: &CloudDisk{
betaDisk: &computebeta.Disk{
Labels: map[string]string{"bar": "beta", "goog-gke-multi-zone": "true"},
},
},
wantLabels: map[string]string{"bar": "beta", "goog-gke-multi-zone": "true"},
},
{
name: "alpha disk without storage pool returns false",
cloudDisk: &CloudDisk{
alphaDisk: &computealpha.Disk{
Labels: map[string]string{"baz": "alpha", "goog-gke-multi-zone": "true"},
},
},
wantLabels: map[string]string{"baz": "alpha", "goog-gke-multi-zone": "true"},
},
}

for _, tc := range testCases {
t.Logf("Running test: %v", tc.name)
gotLabels := tc.cloudDisk.GetLabels()
if diff := cmp.Diff(tc.wantLabels, gotLabels); diff != "" {
t.Errorf("GetLabels() returned unexpected difference (-want +got):\n%s", diff)
}
}
}
Loading