mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 17:30:00 +00:00
Fixes the regression of GCEPD not provisioning correctly on alpha clusters.
This commit is contained in:
parent
283d35a481
commit
02352460f6
@ -111,6 +111,8 @@ type gceServiceManager struct {
|
|||||||
gce *GCECloud
|
gce *GCECloud
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ diskServiceManager = &gceServiceManager{}
|
||||||
|
|
||||||
func (manager *gceServiceManager) CreateDiskOnCloudProvider(
|
func (manager *gceServiceManager) CreateDiskOnCloudProvider(
|
||||||
name string,
|
name string,
|
||||||
sizeGb int64,
|
sizeGb int64,
|
||||||
@ -118,23 +120,11 @@ func (manager *gceServiceManager) CreateDiskOnCloudProvider(
|
|||||||
diskType string,
|
diskType string,
|
||||||
zone string) (gceObject, error) {
|
zone string) (gceObject, error) {
|
||||||
diskTypeURI, err := manager.getDiskTypeURI(
|
diskTypeURI, err := manager.getDiskTypeURI(
|
||||||
manager.gce.region /* diskRegion */, singleZone{zone}, diskType)
|
manager.gce.region /* diskRegion */, singleZone{zone}, diskType, false /* useAlphaAPI */)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
|
||||||
diskToCreateAlpha := &computealpha.Disk{
|
|
||||||
Name: name,
|
|
||||||
SizeGb: sizeGb,
|
|
||||||
Description: tagsStr,
|
|
||||||
Type: diskTypeURI,
|
|
||||||
}
|
|
||||||
|
|
||||||
return manager.gce.serviceAlpha.Disks.Insert(
|
|
||||||
manager.gce.projectID, zone, diskToCreateAlpha).Do()
|
|
||||||
}
|
|
||||||
|
|
||||||
diskToCreateV1 := &compute.Disk{
|
diskToCreateV1 := &compute.Disk{
|
||||||
Name: name,
|
Name: name,
|
||||||
SizeGb: sizeGb,
|
SizeGb: sizeGb,
|
||||||
@ -151,17 +141,19 @@ func (manager *gceServiceManager) CreateRegionalDiskOnCloudProvider(
|
|||||||
tagsStr string,
|
tagsStr string,
|
||||||
diskType string,
|
diskType string,
|
||||||
replicaZones sets.String) (gceObject, error) {
|
replicaZones sets.String) (gceObject, error) {
|
||||||
diskTypeURI, err := manager.getDiskTypeURI(
|
|
||||||
manager.gce.region /* diskRegion */, multiZone{replicaZones}, diskType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
fullyQualifiedReplicaZones := []string{}
|
|
||||||
for _, replicaZone := range replicaZones.UnsortedList() {
|
|
||||||
fullyQualifiedReplicaZones = append(
|
|
||||||
fullyQualifiedReplicaZones, manager.getReplicaZoneURI(replicaZone))
|
|
||||||
}
|
|
||||||
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
||||||
|
diskTypeURI, err := manager.getDiskTypeURI(
|
||||||
|
manager.gce.region /* diskRegion */, multiZone{replicaZones}, diskType, true /* useAlphaAPI */)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fullyQualifiedReplicaZones := []string{}
|
||||||
|
for _, replicaZone := range replicaZones.UnsortedList() {
|
||||||
|
fullyQualifiedReplicaZones = append(
|
||||||
|
fullyQualifiedReplicaZones, manager.getReplicaZoneURI(replicaZone, true))
|
||||||
|
}
|
||||||
|
|
||||||
diskToCreateAlpha := &computealpha.Disk{
|
diskToCreateAlpha := &computealpha.Disk{
|
||||||
Name: name,
|
Name: name,
|
||||||
SizeGb: sizeGb,
|
SizeGb: sizeGb,
|
||||||
@ -186,24 +178,12 @@ func (manager *gceServiceManager) AttachDiskOnCloudProvider(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
|
||||||
attachedDiskAlpha := &computealpha.AttachedDisk{
|
|
||||||
DeviceName: disk.Name,
|
|
||||||
Kind: disk.Kind,
|
|
||||||
Mode: readWrite,
|
|
||||||
Source: source,
|
|
||||||
Type: diskTypePersistent,
|
|
||||||
}
|
|
||||||
return manager.gce.serviceAlpha.Instances.AttachDisk(
|
|
||||||
manager.gce.projectID, instanceZone, instanceName, attachedDiskAlpha).Do()
|
|
||||||
}
|
|
||||||
|
|
||||||
attachedDiskV1 := &compute.AttachedDisk{
|
attachedDiskV1 := &compute.AttachedDisk{
|
||||||
DeviceName: disk.Name,
|
DeviceName: disk.Name,
|
||||||
Kind: disk.Kind,
|
Kind: disk.Kind,
|
||||||
Mode: readWrite,
|
Mode: readWrite,
|
||||||
Source: source,
|
Source: source,
|
||||||
Type: disk.Type,
|
Type: diskTypePersistent,
|
||||||
}
|
}
|
||||||
return manager.gce.service.Instances.AttachDisk(
|
return manager.gce.service.Instances.AttachDisk(
|
||||||
manager.gce.projectID, instanceZone, instanceName, attachedDiskV1).Do()
|
manager.gce.projectID, instanceZone, instanceName, attachedDiskV1).Do()
|
||||||
@ -213,11 +193,6 @@ func (manager *gceServiceManager) DetachDiskOnCloudProvider(
|
|||||||
instanceZone string,
|
instanceZone string,
|
||||||
instanceName string,
|
instanceName string,
|
||||||
devicePath string) (gceObject, error) {
|
devicePath string) (gceObject, error) {
|
||||||
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
|
||||||
manager.gce.serviceAlpha.Instances.DetachDisk(
|
|
||||||
manager.gce.projectID, instanceZone, instanceName, devicePath).Do()
|
|
||||||
}
|
|
||||||
|
|
||||||
return manager.gce.service.Instances.DetachDisk(
|
return manager.gce.service.Instances.DetachDisk(
|
||||||
manager.gce.projectID, instanceZone, instanceName, devicePath).Do()
|
manager.gce.projectID, instanceZone, instanceName, devicePath).Do()
|
||||||
}
|
}
|
||||||
@ -233,45 +208,6 @@ func (manager *gceServiceManager) GetDiskFromCloudProvider(
|
|||||||
return nil, fmt.Errorf("Can not fetch disk. Zone is specified (%q). But disk name is empty.", zone)
|
return nil, fmt.Errorf("Can not fetch disk. Zone is specified (%q). But disk name is empty.", zone)
|
||||||
}
|
}
|
||||||
|
|
||||||
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
|
||||||
diskAlpha, err := manager.gce.serviceAlpha.Disks.Get(
|
|
||||||
manager.gce.projectID, zone, diskName).Do()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var zoneInfo zoneType
|
|
||||||
if len(diskAlpha.ReplicaZones) > 1 {
|
|
||||||
zones := sets.NewString()
|
|
||||||
for _, zoneURI := range diskAlpha.ReplicaZones {
|
|
||||||
zones.Insert(lastComponent(zoneURI))
|
|
||||||
}
|
|
||||||
zoneInfo = multiZone{zones}
|
|
||||||
} else {
|
|
||||||
zoneInfo = singleZone{lastComponent(diskAlpha.Zone)}
|
|
||||||
if diskAlpha.Zone == "" {
|
|
||||||
zoneInfo = singleZone{lastComponent(zone)}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
region := strings.TrimSpace(lastComponent(diskAlpha.Region))
|
|
||||||
if region == "" {
|
|
||||||
region, err = manager.getRegionFromZone(zoneInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to extract region from zone for %q/%q err=%v", zone, diskName, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &GCEDisk{
|
|
||||||
ZoneInfo: zoneInfo,
|
|
||||||
Region: region,
|
|
||||||
Name: diskAlpha.Name,
|
|
||||||
Kind: diskAlpha.Kind,
|
|
||||||
Type: diskAlpha.Type,
|
|
||||||
SizeGb: diskAlpha.SizeGb,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
diskStable, err := manager.gce.service.Disks.Get(
|
diskStable, err := manager.gce.service.Disks.Get(
|
||||||
manager.gce.projectID, zone, diskName).Do()
|
manager.gce.projectID, zone, diskName).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -329,12 +265,6 @@ func (manager *gceServiceManager) GetRegionalDiskFromCloudProvider(
|
|||||||
func (manager *gceServiceManager) DeleteDiskOnCloudProvider(
|
func (manager *gceServiceManager) DeleteDiskOnCloudProvider(
|
||||||
zone string,
|
zone string,
|
||||||
diskName string) (gceObject, error) {
|
diskName string) (gceObject, error) {
|
||||||
|
|
||||||
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
|
||||||
return manager.gce.serviceAlpha.Disks.Delete(
|
|
||||||
manager.gce.projectID, zone, diskName).Do()
|
|
||||||
}
|
|
||||||
|
|
||||||
return manager.gce.service.Disks.Delete(
|
return manager.gce.service.Disks.Delete(
|
||||||
manager.gce.projectID, zone, diskName).Do()
|
manager.gce.projectID, zone, diskName).Do()
|
||||||
}
|
}
|
||||||
@ -361,9 +291,6 @@ func (manager *gceServiceManager) WaitForRegionalOp(
|
|||||||
|
|
||||||
func (manager *gceServiceManager) getDiskSourceURI(disk *GCEDisk) (string, error) {
|
func (manager *gceServiceManager) getDiskSourceURI(disk *GCEDisk) (string, error) {
|
||||||
getProjectsAPIEndpoint := manager.getProjectsAPIEndpoint()
|
getProjectsAPIEndpoint := manager.getProjectsAPIEndpoint()
|
||||||
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
|
||||||
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch zoneInfo := disk.ZoneInfo.(type) {
|
switch zoneInfo := disk.ZoneInfo.(type) {
|
||||||
case singleZone:
|
case singleZone:
|
||||||
@ -397,10 +324,13 @@ func (manager *gceServiceManager) getDiskSourceURI(disk *GCEDisk) (string, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (manager *gceServiceManager) getDiskTypeURI(
|
func (manager *gceServiceManager) getDiskTypeURI(
|
||||||
diskRegion string, diskZoneInfo zoneType, diskType string) (string, error) {
|
diskRegion string, diskZoneInfo zoneType, diskType string, useAlphaAPI bool) (string, error) {
|
||||||
getProjectsAPIEndpoint := manager.getProjectsAPIEndpoint()
|
|
||||||
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
var getProjectsAPIEndpoint string
|
||||||
|
if useAlphaAPI {
|
||||||
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
|
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
|
||||||
|
} else {
|
||||||
|
getProjectsAPIEndpoint = manager.getProjectsAPIEndpoint()
|
||||||
}
|
}
|
||||||
|
|
||||||
switch zoneInfo := diskZoneInfo.(type) {
|
switch zoneInfo := diskZoneInfo.(type) {
|
||||||
@ -430,10 +360,12 @@ func (manager *gceServiceManager) getDiskTypeURI(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (manager *gceServiceManager) getReplicaZoneURI(zone string) string {
|
func (manager *gceServiceManager) getReplicaZoneURI(zone string, useAlphaAPI bool) string {
|
||||||
getProjectsAPIEndpoint := manager.getProjectsAPIEndpoint()
|
var getProjectsAPIEndpoint string
|
||||||
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
if useAlphaAPI {
|
||||||
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
|
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
|
||||||
|
} else {
|
||||||
|
getProjectsAPIEndpoint = manager.getProjectsAPIEndpoint()
|
||||||
}
|
}
|
||||||
|
|
||||||
return getProjectsAPIEndpoint + fmt.Sprintf(
|
return getProjectsAPIEndpoint + fmt.Sprintf(
|
||||||
@ -477,13 +409,6 @@ func (manager *gceServiceManager) getRegionFromZone(zoneInfo zoneType) (string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (manager *gceServiceManager) ResizeDiskOnCloudProvider(disk *GCEDisk, sizeGb int64, zone string) (gceObject, error) {
|
func (manager *gceServiceManager) ResizeDiskOnCloudProvider(disk *GCEDisk, sizeGb int64, zone string) (gceObject, error) {
|
||||||
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
|
||||||
resizeServiceRequest := &computealpha.DisksResizeRequest{
|
|
||||||
SizeGb: sizeGb,
|
|
||||||
}
|
|
||||||
return manager.gce.serviceAlpha.Disks.Resize(manager.gce.projectID, zone, disk.Name, resizeServiceRequest).Do()
|
|
||||||
|
|
||||||
}
|
|
||||||
resizeServiceRequest := &compute.DisksResizeRequest{
|
resizeServiceRequest := &compute.DisksResizeRequest{
|
||||||
SizeGb: sizeGb,
|
SizeGb: sizeGb,
|
||||||
}
|
}
|
||||||
@ -504,7 +429,7 @@ func (manager *gceServiceManager) RegionalResizeDiskOnCloudProvider(disk *GCEDis
|
|||||||
type Disks interface {
|
type Disks interface {
|
||||||
// AttachDisk attaches given disk to the node with the specified NodeName.
|
// AttachDisk attaches given disk to the node with the specified NodeName.
|
||||||
// Current instance is used when instanceID is empty string.
|
// Current instance is used when instanceID is empty string.
|
||||||
AttachDisk(diskName string, nodeName types.NodeName, readOnly bool) error
|
AttachDisk(diskName string, nodeName types.NodeName, readOnly bool, regional bool) error
|
||||||
|
|
||||||
// DetachDisk detaches given disk to the node with the specified NodeName.
|
// DetachDisk detaches given disk to the node with the specified NodeName.
|
||||||
// Current instance is used when nodeName is empty string.
|
// Current instance is used when nodeName is empty string.
|
||||||
@ -594,7 +519,7 @@ func (gce *GCECloud) GetLabelsForVolume(pv *v1.PersistentVolume) (map[string]str
|
|||||||
return labels, nil
|
return labels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) AttachDisk(diskName string, nodeName types.NodeName, readOnly bool) error {
|
func (gce *GCECloud) AttachDisk(diskName string, nodeName types.NodeName, readOnly bool, regional bool) error {
|
||||||
instanceName := mapNodeNameToInstanceName(nodeName)
|
instanceName := mapNodeNameToInstanceName(nodeName)
|
||||||
instance, err := gce.getInstanceByName(instanceName)
|
instance, err := gce.getInstanceByName(instanceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -604,7 +529,7 @@ func (gce *GCECloud) AttachDisk(diskName string, nodeName types.NodeName, readOn
|
|||||||
// Try fetching as regional PD
|
// Try fetching as regional PD
|
||||||
var disk *GCEDisk
|
var disk *GCEDisk
|
||||||
var mc *metricContext
|
var mc *metricContext
|
||||||
if gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
|
if regional {
|
||||||
disk, err = gce.getRegionalDiskByName(diskName)
|
disk, err = gce.getRegionalDiskByName(diskName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(5).Infof("Could not find regional PD named %q to Attach. Will look for a zonal PD", diskName)
|
glog.V(5).Infof("Could not find regional PD named %q to Attach. Will look for a zonal PD", diskName)
|
||||||
|
@ -18,6 +18,7 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/cloudprovider:go_default_library",
|
"//pkg/cloudprovider:go_default_library",
|
||||||
"//pkg/cloudprovider/providers/gce:go_default_library",
|
"//pkg/cloudprovider/providers/gce:go_default_library",
|
||||||
|
"//pkg/kubelet/apis:go_default_library",
|
||||||
"//pkg/util/mount:go_default_library",
|
"//pkg/util/mount:go_default_library",
|
||||||
"//pkg/util/strings:go_default_library",
|
"//pkg/util/strings:go_default_library",
|
||||||
"//pkg/volume:go_default_library",
|
"//pkg/volume:go_default_library",
|
||||||
@ -42,6 +43,7 @@ go_test(
|
|||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
importpath = "k8s.io/kubernetes/pkg/volume/gce_pd",
|
importpath = "k8s.io/kubernetes/pkg/volume/gce_pd",
|
||||||
deps = [
|
deps = [
|
||||||
|
"//pkg/kubelet/apis:go_default_library",
|
||||||
"//pkg/util/mount:go_default_library",
|
"//pkg/util/mount:go_default_library",
|
||||||
"//pkg/volume:go_default_library",
|
"//pkg/volume:go_default_library",
|
||||||
"//pkg/volume/testing:go_default_library",
|
"//pkg/volume/testing:go_default_library",
|
||||||
|
@ -88,7 +88,7 @@ func (attacher *gcePersistentDiskAttacher) Attach(spec *volume.Spec, nodeName ty
|
|||||||
// Volume is already attached to node.
|
// Volume is already attached to node.
|
||||||
glog.Infof("Attach operation is successful. PD %q is already attached to node %q.", pdName, nodeName)
|
glog.Infof("Attach operation is successful. PD %q is already attached to node %q.", pdName, nodeName)
|
||||||
} else {
|
} else {
|
||||||
if err := attacher.gceDisks.AttachDisk(pdName, nodeName, readOnly); err != nil {
|
if err := attacher.gceDisks.AttachDisk(pdName, nodeName, readOnly, isRegionalPD(spec)); err != nil {
|
||||||
glog.Errorf("Error attaching PD %q to node %q: %+v", pdName, nodeName, err)
|
glog.Errorf("Error attaching PD %q to node %q: %+v", pdName, nodeName, err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetDeviceName_Volume(t *testing.T) {
|
func TestGetDeviceName_Volume(t *testing.T) {
|
||||||
@ -48,7 +50,7 @@ func TestGetDeviceName_Volume(t *testing.T) {
|
|||||||
func TestGetDeviceName_PersistentVolume(t *testing.T) {
|
func TestGetDeviceName_PersistentVolume(t *testing.T) {
|
||||||
plugin := newPlugin()
|
plugin := newPlugin()
|
||||||
name := "my-pd-pv"
|
name := "my-pd-pv"
|
||||||
spec := createPVSpec(name, true)
|
spec := createPVSpec(name, true, nil)
|
||||||
|
|
||||||
deviceName, err := plugin.GetVolumeName(spec)
|
deviceName, err := plugin.GetVolumeName(spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -74,10 +76,39 @@ type testcase struct {
|
|||||||
expectedReturn error
|
expectedReturn error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAttachDetachRegional(t *testing.T) {
|
||||||
|
diskName := "disk"
|
||||||
|
nodeName := types.NodeName("instance")
|
||||||
|
readOnly := false
|
||||||
|
regional := true
|
||||||
|
spec := createPVSpec(diskName, readOnly, []string{"zone1", "zone2"})
|
||||||
|
// Successful Attach call
|
||||||
|
testcase := testcase{
|
||||||
|
name: "Attach_Regional_Positive",
|
||||||
|
diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, nil},
|
||||||
|
attach: attachCall{diskName, nodeName, readOnly, regional, nil},
|
||||||
|
test: func(testcase *testcase) error {
|
||||||
|
attacher := newAttacher(testcase)
|
||||||
|
devicePath, err := attacher.Attach(spec, nodeName)
|
||||||
|
if devicePath != "/dev/disk/by-id/google-disk" {
|
||||||
|
return fmt.Errorf("devicePath incorrect. Expected<\"/dev/disk/by-id/google-disk\"> Actual: <%q>", devicePath)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := testcase.test(&testcase)
|
||||||
|
if err != testcase.expectedReturn {
|
||||||
|
t.Errorf("%s failed: expected err=%q, got %q", testcase.name, testcase.expectedReturn.Error(), err.Error())
|
||||||
|
}
|
||||||
|
t.Logf("Test %q succeeded", testcase.name)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAttachDetach(t *testing.T) {
|
func TestAttachDetach(t *testing.T) {
|
||||||
diskName := "disk"
|
diskName := "disk"
|
||||||
nodeName := types.NodeName("instance")
|
nodeName := types.NodeName("instance")
|
||||||
readOnly := false
|
readOnly := false
|
||||||
|
regional := false
|
||||||
spec := createVolSpec(diskName, readOnly)
|
spec := createVolSpec(diskName, readOnly)
|
||||||
attachError := errors.New("Fake attach error")
|
attachError := errors.New("Fake attach error")
|
||||||
detachError := errors.New("Fake detach error")
|
detachError := errors.New("Fake detach error")
|
||||||
@ -87,7 +118,7 @@ func TestAttachDetach(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Attach_Positive",
|
name: "Attach_Positive",
|
||||||
diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, nil},
|
diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, nil},
|
||||||
attach: attachCall{diskName, nodeName, readOnly, nil},
|
attach: attachCall{diskName, nodeName, readOnly, regional, nil},
|
||||||
test: func(testcase *testcase) error {
|
test: func(testcase *testcase) error {
|
||||||
attacher := newAttacher(testcase)
|
attacher := newAttacher(testcase)
|
||||||
devicePath, err := attacher.Attach(spec, nodeName)
|
devicePath, err := attacher.Attach(spec, nodeName)
|
||||||
@ -116,7 +147,7 @@ func TestAttachDetach(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Attach_Positive_CheckFails",
|
name: "Attach_Positive_CheckFails",
|
||||||
diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, diskCheckError},
|
diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, diskCheckError},
|
||||||
attach: attachCall{diskName, nodeName, readOnly, nil},
|
attach: attachCall{diskName, nodeName, readOnly, regional, nil},
|
||||||
test: func(testcase *testcase) error {
|
test: func(testcase *testcase) error {
|
||||||
attacher := newAttacher(testcase)
|
attacher := newAttacher(testcase)
|
||||||
devicePath, err := attacher.Attach(spec, nodeName)
|
devicePath, err := attacher.Attach(spec, nodeName)
|
||||||
@ -131,7 +162,7 @@ func TestAttachDetach(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Attach_Negative",
|
name: "Attach_Negative",
|
||||||
diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, diskCheckError},
|
diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, diskCheckError},
|
||||||
attach: attachCall{diskName, nodeName, readOnly, attachError},
|
attach: attachCall{diskName, nodeName, readOnly, regional, attachError},
|
||||||
test: func(testcase *testcase) error {
|
test: func(testcase *testcase) error {
|
||||||
attacher := newAttacher(testcase)
|
attacher := newAttacher(testcase)
|
||||||
devicePath, err := attacher.Attach(spec, nodeName)
|
devicePath, err := attacher.Attach(spec, nodeName)
|
||||||
@ -238,8 +269,8 @@ func createVolSpec(name string, readOnly bool) *volume.Spec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPVSpec(name string, readOnly bool) *volume.Spec {
|
func createPVSpec(name string, readOnly bool, zones []string) *volume.Spec {
|
||||||
return &volume.Spec{
|
spec := &volume.Spec{
|
||||||
PersistentVolume: &v1.PersistentVolume{
|
PersistentVolume: &v1.PersistentVolume{
|
||||||
Spec: v1.PersistentVolumeSpec{
|
Spec: v1.PersistentVolumeSpec{
|
||||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||||
@ -251,6 +282,15 @@ func createPVSpec(name string, readOnly bool) *volume.Spec {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if zones != nil {
|
||||||
|
zonesLabel := strings.Join(zones, kubeletapis.LabelMultiZoneDelimiter)
|
||||||
|
spec.PersistentVolume.ObjectMeta.Labels = map[string]string{
|
||||||
|
kubeletapis.LabelZoneFailureDomain: zonesLabel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fake GCE implementation
|
// Fake GCE implementation
|
||||||
@ -259,6 +299,7 @@ type attachCall struct {
|
|||||||
diskName string
|
diskName string
|
||||||
nodeName types.NodeName
|
nodeName types.NodeName
|
||||||
readOnly bool
|
readOnly bool
|
||||||
|
regional bool
|
||||||
ret error
|
ret error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +316,7 @@ type diskIsAttachedCall struct {
|
|||||||
ret error
|
ret error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (testcase *testcase) AttachDisk(diskName string, nodeName types.NodeName, readOnly bool) error {
|
func (testcase *testcase) AttachDisk(diskName string, nodeName types.NodeName, readOnly bool, regional bool) error {
|
||||||
expected := &testcase.attach
|
expected := &testcase.attach
|
||||||
|
|
||||||
if expected.diskName == "" && expected.nodeName == "" {
|
if expected.diskName == "" && expected.nodeName == "" {
|
||||||
@ -300,6 +341,11 @@ func (testcase *testcase) AttachDisk(diskName string, nodeName types.NodeName, r
|
|||||||
return errors.New("Unexpected AttachDisk call: wrong readOnly")
|
return errors.New("Unexpected AttachDisk call: wrong readOnly")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if expected.regional != regional {
|
||||||
|
testcase.t.Errorf("Unexpected AttachDisk call: expected regional %v, got %v", expected.regional, regional)
|
||||||
|
return errors.New("Unexpected AttachDisk call: wrong regional")
|
||||||
|
}
|
||||||
|
|
||||||
glog.V(4).Infof("AttachDisk call: %s, %s, %v, returning %v", diskName, nodeName, readOnly, expected.ret)
|
glog.V(4).Infof("AttachDisk call: %s, %s, %v, returning %v", diskName, nodeName, readOnly, expected.ret)
|
||||||
|
|
||||||
return expected.ret
|
return expected.ret
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
gcecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
|
gcecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
|
||||||
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume"
|
||||||
volumeutil "k8s.io/kubernetes/pkg/volume/util"
|
volumeutil "k8s.io/kubernetes/pkg/volume/util"
|
||||||
"k8s.io/utils/exec"
|
"k8s.io/utils/exec"
|
||||||
@ -356,3 +357,13 @@ func udevadmChangeToDrive(drivePath string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks whether the given GCE PD volume spec is associated with a regional PD.
|
||||||
|
func isRegionalPD(spec *volume.Spec) bool {
|
||||||
|
if spec.PersistentVolume != nil {
|
||||||
|
zonesLabel := spec.PersistentVolume.Labels[kubeletapis.LabelZoneFailureDomain]
|
||||||
|
zones := strings.Split(zonesLabel, kubeletapis.LabelMultiZoneDelimiter)
|
||||||
|
return len(zones) > 1
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user