Merge pull request #51281 from verult/GCEDiskCleanup

Automatic merge from submit-queue (batch tested with PRs 43016, 50503, 51281, 51518, 51582). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>..

Refactor: Moving disk-related cloud provider operations to gce_disks.go

**What this PR does / why we need it**: The main GCE cloud provider code (pkg/cloudprovider/providers/gce/gce.go) should not contain disk-related operations. Moved them to gce_disks.go

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #51280 

**Release note**:

```release-note
NONE
```
/release-note-none
/sig storage
/assign @msau42 @bowei
pull/6/head
Kubernetes Submit Queue 2017-09-22 23:35:57 -07:00 committed by GitHub
commit 55798b265c
3 changed files with 439 additions and 437 deletions

View File

@ -125,7 +125,7 @@ type GCECloud struct {
nodeInstancePrefix string // If non-"", an advisory prefix for all nodes in the cluster
useMetadataServer bool
operationPollRateLimiter flowcontrol.RateLimiter
manager ServiceManager
manager diskServiceManager
// sharedResourceLock is used to serialize GCE operations that may mutate shared state to
// prevent inconsistencies. For example, load balancers manipulation methods will take the
// lock to prevent shared resources from being prematurely deleted while the operation is
@ -138,59 +138,6 @@ type GCECloud struct {
AlphaFeatureGate *AlphaFeatureGate
}
type ServiceManager interface {
// Creates a new persistent disk on GCE with the given disk spec.
CreateDisk(
name string,
sizeGb int64,
tagsStr string,
diskType string,
zone string) (gceObject, error)
// Creates a new regional persistent disk on GCE with the given disk spec.
CreateRegionalDisk(
name string,
sizeGb int64,
tagsStr string,
diskType string,
zones sets.String) (gceObject, error)
// Deletes the persistent disk from GCE with the given diskName.
DeleteDisk(zone string, disk string) (gceObject, error)
// Deletes the regional persistent disk from GCE with the given diskName.
DeleteRegionalDisk(diskName string) (gceObject, error)
// Attach a persistent disk on GCE with the given disk spec to the specified instance.
AttachDisk(
disk *GCEDisk,
readWrite string,
instanceZone string,
instanceName string) (gceObject, error)
// Detach a persistent disk on GCE with the given disk spec from the specified instance.
DetachDisk(
instanceZone string,
instanceName string,
devicePath string) (gceObject, error)
// Gets the persistent disk from GCE with the given diskName.
GetDisk(zone string, diskName string) (*GCEDisk, error)
// Gets the regional persistent disk from GCE with the given diskName.
GetRegionalDisk(diskName string) (*GCEDisk, error)
// Waits until GCE reports the given operation in the given zone as done.
WaitForZoneOp(op gceObject, zone string, mc *metricContext) error
// Waits until GCE reports the given operation in the given region is done.
WaitForRegionalOp(op gceObject, mc *metricContext) error
}
type GCEServiceManager struct {
gce *GCECloud
}
type ConfigGlobal struct {
TokenURL string `gcfg:"token-url"`
TokenBody string `gcfg:"token-body"`
@ -511,7 +458,7 @@ func CreateGCECloud(config *CloudConfig) (*GCECloud, error) {
AlphaFeatureGate: config.AlphaFeatureGate,
}
gce.manager = &GCEServiceManager{gce}
gce.manager = &gceServiceManager{gce}
// Registering the KMS plugin only the first time.
kmsPluginRegisterOnce.Do(func() {
@ -768,335 +715,7 @@ func newOauthClient(tokenSource oauth2.TokenSource) (*http.Client, error) {
return oauth2.NewClient(oauth2.NoContext, tokenSource), nil
}
func (manager *GCEServiceManager) CreateDisk(
name string,
sizeGb int64,
tagsStr string,
diskType string,
zone string) (gceObject, error) {
diskTypeURI, err := manager.getDiskTypeURI(
manager.gce.region /* diskRegion */, singleZone{zone}, diskType)
if err != nil {
return nil, err
}
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
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{
Name: name,
SizeGb: sizeGb,
Description: tagsStr,
Type: diskTypeURI,
}
return manager.gce.service.Disks.Insert(
manager.gce.projectID, zone, diskToCreateV1).Do()
}
func (manager *GCEServiceManager) CreateRegionalDisk(
name string,
sizeGb int64,
tagsStr string,
diskType string,
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(GCEDiskAlphaFeatureGate) {
diskToCreateAlpha := &computealpha.Disk{
Name: name,
SizeGb: sizeGb,
Description: tagsStr,
Type: diskTypeURI,
ReplicaZones: fullyQualifiedReplicaZones,
}
return manager.gce.serviceAlpha.RegionDisks.Insert(
manager.gce.projectID, manager.gce.region, diskToCreateAlpha).Do()
}
return nil, fmt.Errorf("The regional PD feature is only available via the GCE Alpha API. Enable \"GCEDiskAlphaAPI\" in the list of \"alpha-features\" in \"gce.conf\" to use the feature.")
}
func (manager *GCEServiceManager) AttachDisk(
disk *GCEDisk,
readWrite string,
instanceZone string,
instanceName string) (gceObject, error) {
source, err := manager.getDiskSourceURI(disk)
if err != nil {
return nil, err
}
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
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{
DeviceName: disk.Name,
Kind: disk.Kind,
Mode: readWrite,
Source: source,
Type: disk.Type,
}
return manager.gce.service.Instances.AttachDisk(
manager.gce.projectID, instanceZone, instanceName, attachedDiskV1).Do()
}
func (manager *GCEServiceManager) DetachDisk(
instanceZone string,
instanceName string,
devicePath string) (gceObject, error) {
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
manager.gce.serviceAlpha.Instances.DetachDisk(
manager.gce.projectID, instanceZone, instanceName, devicePath).Do()
}
return manager.gce.service.Instances.DetachDisk(
manager.gce.projectID, instanceZone, instanceName, devicePath).Do()
}
func (manager *GCEServiceManager) GetDisk(
zone string,
diskName string) (*GCEDisk, error) {
if zone == "" {
return nil, fmt.Errorf("Can not fetch disk %q. Zone is empty.", diskName)
}
if diskName == "" {
return nil, fmt.Errorf("Can not fetch disk. Zone is specified (%q). But disk name is empty.", zone)
}
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
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,
}, nil
}
diskStable, err := manager.gce.service.Disks.Get(
manager.gce.projectID, zone, diskName).Do()
if err != nil {
return nil, err
}
zoneInfo := singleZone{strings.TrimSpace(lastComponent(diskStable.Zone))}
if zoneInfo.zone == "" {
zoneInfo = singleZone{zone}
}
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: diskStable.Name,
Kind: diskStable.Kind,
Type: diskStable.Type,
}, nil
}
func (manager *GCEServiceManager) GetRegionalDisk(
diskName string) (*GCEDisk, error) {
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
diskAlpha, err := manager.gce.serviceAlpha.RegionDisks.Get(
manager.gce.projectID, manager.gce.region, diskName).Do()
if err != nil {
return nil, err
}
zones := sets.NewString()
for _, zoneURI := range diskAlpha.ReplicaZones {
zones.Insert(lastComponent(zoneURI))
}
return &GCEDisk{
ZoneInfo: multiZone{zones},
Region: lastComponent(diskAlpha.Region),
Name: diskAlpha.Name,
Kind: diskAlpha.Kind,
Type: diskAlpha.Type,
}, nil
}
return nil, fmt.Errorf("The regional PD feature is only available via the GCE Alpha API. Enable \"GCEDiskAlphaAPI\" in the list of \"alpha-features\" in \"gce.conf\" to use the feature.")
}
func (manager *GCEServiceManager) DeleteDisk(
zone string,
diskName string) (gceObject, error) {
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
return manager.gce.serviceAlpha.Disks.Delete(
manager.gce.projectID, zone, diskName).Do()
}
return manager.gce.service.Disks.Delete(
manager.gce.projectID, zone, diskName).Do()
}
func (manager *GCEServiceManager) DeleteRegionalDisk(
diskName string) (gceObject, error) {
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
return manager.gce.serviceAlpha.RegionDisks.Delete(
manager.gce.projectID, manager.gce.region, diskName).Do()
}
return nil, fmt.Errorf("DeleteRegionalDisk is a regional PD feature and is only available via the GCE Alpha API. Enable \"GCEDiskAlphaAPI\" in the list of \"alpha-features\" in \"gce.conf\" to use the feature.")
}
func (manager *GCEServiceManager) WaitForZoneOp(
op gceObject, zone string, mc *metricContext) error {
return manager.gce.waitForZoneOp(op, zone, mc)
}
func (manager *GCEServiceManager) WaitForRegionalOp(
op gceObject, mc *metricContext) error {
return manager.gce.waitForRegionOp(op, manager.gce.region, mc)
}
func (manager *GCEServiceManager) getDiskSourceURI(disk *GCEDisk) (string, error) {
getProjectsAPIEndpoint := manager.getProjectsAPIEndpoint()
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
}
switch zoneInfo := disk.ZoneInfo.(type) {
case singleZone:
if zoneInfo.zone == "" || disk.Region == "" {
// Unexpected, but sanity-check
return "", fmt.Errorf("PD does not have zone/region information: %#v", disk)
}
return getProjectsAPIEndpoint + fmt.Sprintf(
diskSourceURITemplateSingleZone,
manager.gce.projectID,
zoneInfo.zone,
disk.Name), nil
case multiZone:
if zoneInfo.replicaZones == nil || zoneInfo.replicaZones.Len() <= 0 {
// Unexpected, but sanity-check
return "", fmt.Errorf("PD is regional but does not have any replicaZones specified: %v", disk)
}
return getProjectsAPIEndpoint + fmt.Sprintf(
diskSourceURITemplateRegional,
manager.gce.projectID,
disk.Region,
disk.Name), nil
case nil:
// Unexpected, but sanity-check
return "", fmt.Errorf("PD did not have ZoneInfo: %v", disk)
default:
// Unexpected, but sanity-check
return "", fmt.Errorf("disk.ZoneInfo has unexpected type %T", zoneInfo)
}
}
func (manager *GCEServiceManager) getDiskTypeURI(
diskRegion string, diskZoneInfo zoneType, diskType string) (string, error) {
getProjectsAPIEndpoint := manager.getProjectsAPIEndpoint()
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
}
switch zoneInfo := diskZoneInfo.(type) {
case singleZone:
if zoneInfo.zone == "" {
return "", fmt.Errorf("zone is empty: %v", zoneInfo)
}
return getProjectsAPIEndpoint + fmt.Sprintf(
diskTypeURITemplateSingleZone,
manager.gce.projectID,
zoneInfo.zone,
diskType), nil
case multiZone:
if zoneInfo.replicaZones == nil || zoneInfo.replicaZones.Len() <= 0 {
return "", fmt.Errorf("zoneInfo is regional but does not have any replicaZones specified: %v", zoneInfo)
}
return getProjectsAPIEndpoint + fmt.Sprintf(
diskTypeURITemplateRegional,
manager.gce.projectID,
diskRegion,
diskType), nil
case nil:
return "", fmt.Errorf("zoneInfo nil")
default:
return "", fmt.Errorf("zoneInfo has unexpected type %T", zoneInfo)
}
}
func (manager *GCEServiceManager) getReplicaZoneURI(zone string) string {
getProjectsAPIEndpoint := manager.getProjectsAPIEndpoint()
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
}
return getProjectsAPIEndpoint + fmt.Sprintf(
replicaZoneURITemplateSingleZone,
manager.gce.projectID,
zone)
}
func (manager *GCEServiceManager) getProjectsAPIEndpoint() string {
func (manager *gceServiceManager) getProjectsAPIEndpoint() string {
projectsApiEndpoint := gceComputeAPIEndpoint + "projects/"
if manager.gce.service != nil {
projectsApiEndpoint = manager.gce.service.BasePath
@ -1105,7 +724,7 @@ func (manager *GCEServiceManager) getProjectsAPIEndpoint() string {
return projectsApiEndpoint
}
func (manager *GCEServiceManager) getProjectsAPIEndpointAlpha() string {
func (manager *gceServiceManager) getProjectsAPIEndpointAlpha() string {
projectsApiEndpoint := gceComputeAPIEndpointAlpha + "projects/"
if manager.gce.service != nil {
projectsApiEndpoint = manager.gce.serviceAlpha.BasePath
@ -1113,37 +732,3 @@ func (manager *GCEServiceManager) getProjectsAPIEndpointAlpha() string {
return projectsApiEndpoint
}
func (manager *GCEServiceManager) getRegionFromZone(zoneInfo zoneType) (string, error) {
var zone string
switch zoneInfo := zoneInfo.(type) {
case singleZone:
if zoneInfo.zone == "" {
// Unexpected, but sanity-check
return "", fmt.Errorf("PD is single zone, but zone is not specified: %#v", zoneInfo)
}
zone = zoneInfo.zone
case multiZone:
if zoneInfo.replicaZones == nil || zoneInfo.replicaZones.Len() <= 0 {
// Unexpected, but sanity-check
return "", fmt.Errorf("PD is regional but does not have any replicaZones specified: %v", zoneInfo)
}
zone = zoneInfo.replicaZones.UnsortedList()[0]
case nil:
// Unexpected, but sanity-check
return "", fmt.Errorf("zoneInfo is nil")
default:
// Unexpected, but sanity-check
return "", fmt.Errorf("zoneInfo has unexpected type %T", zoneInfo)
}
region, err := GetGCERegion(zone)
if err != nil {
glog.Warningf("failed to parse GCE region from zone %q: %v", zone, err)
region = manager.gce.region
}
return region, nil
}

View File

@ -32,6 +32,8 @@ import (
volumeutil "k8s.io/kubernetes/pkg/volume/util"
"github.com/golang/glog"
computealpha "google.golang.org/api/compute/v0.alpha"
compute "google.golang.org/api/compute/v1"
"google.golang.org/api/googleapi"
)
@ -52,6 +54,421 @@ const (
replicaZoneURITemplateSingleZone = "%s/zones/%s" // {gce.projectID}/zones/{disk.Zone}
)
type diskServiceManager interface {
// Creates a new persistent disk on GCE with the given disk spec.
CreateDiskOnCloudProvider(
name string,
sizeGb int64,
tagsStr string,
diskType string,
zone string) (gceObject, error)
// Creates a new regional persistent disk on GCE with the given disk spec.
CreateRegionalDiskOnCloudProvider(
name string,
sizeGb int64,
tagsStr string,
diskType string,
zones sets.String) (gceObject, error)
// Deletes the persistent disk from GCE with the given diskName.
DeleteDiskOnCloudProvider(zone string, disk string) (gceObject, error)
// Deletes the regional persistent disk from GCE with the given diskName.
DeleteRegionalDiskOnCloudProvider(diskName string) (gceObject, error)
// Attach a persistent disk on GCE with the given disk spec to the specified instance.
AttachDiskOnCloudProvider(
disk *GCEDisk,
readWrite string,
instanceZone string,
instanceName string) (gceObject, error)
// Detach a persistent disk on GCE with the given disk spec from the specified instance.
DetachDiskOnCloudProvider(
instanceZone string,
instanceName string,
devicePath string) (gceObject, error)
// Gets the persistent disk from GCE with the given diskName.
GetDiskFromCloudProvider(zone string, diskName string) (*GCEDisk, error)
// Gets the regional persistent disk from GCE with the given diskName.
GetRegionalDiskFromCloudProvider(diskName string) (*GCEDisk, error)
// Waits until GCE reports the given operation in the given zone as done.
WaitForZoneOp(op gceObject, zone string, mc *metricContext) error
// Waits until GCE reports the given operation in the given region is done.
WaitForRegionalOp(op gceObject, mc *metricContext) error
}
type gceServiceManager struct {
gce *GCECloud
}
func (manager *gceServiceManager) CreateDiskOnCloudProvider(
name string,
sizeGb int64,
tagsStr string,
diskType string,
zone string) (gceObject, error) {
diskTypeURI, err := manager.getDiskTypeURI(
manager.gce.region /* diskRegion */, singleZone{zone}, diskType)
if err != nil {
return nil, err
}
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
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{
Name: name,
SizeGb: sizeGb,
Description: tagsStr,
Type: diskTypeURI,
}
return manager.gce.service.Disks.Insert(
manager.gce.projectID, zone, diskToCreateV1).Do()
}
func (manager *gceServiceManager) CreateRegionalDiskOnCloudProvider(
name string,
sizeGb int64,
tagsStr string,
diskType string,
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(GCEDiskAlphaFeatureGate) {
diskToCreateAlpha := &computealpha.Disk{
Name: name,
SizeGb: sizeGb,
Description: tagsStr,
Type: diskTypeURI,
ReplicaZones: fullyQualifiedReplicaZones,
}
return manager.gce.serviceAlpha.RegionDisks.Insert(
manager.gce.projectID, manager.gce.region, diskToCreateAlpha).Do()
}
return nil, fmt.Errorf("The regional PD feature is only available via the GCE Alpha API. Enable \"GCEDiskAlphaAPI\" in the list of \"alpha-features\" in \"gce.conf\" to use the feature.")
}
func (manager *gceServiceManager) AttachDiskOnCloudProvider(
disk *GCEDisk,
readWrite string,
instanceZone string,
instanceName string) (gceObject, error) {
source, err := manager.getDiskSourceURI(disk)
if err != nil {
return nil, err
}
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
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{
DeviceName: disk.Name,
Kind: disk.Kind,
Mode: readWrite,
Source: source,
Type: disk.Type,
}
return manager.gce.service.Instances.AttachDisk(
manager.gce.projectID, instanceZone, instanceName, attachedDiskV1).Do()
}
func (manager *gceServiceManager) DetachDiskOnCloudProvider(
instanceZone string,
instanceName string,
devicePath string) (gceObject, error) {
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
manager.gce.serviceAlpha.Instances.DetachDisk(
manager.gce.projectID, instanceZone, instanceName, devicePath).Do()
}
return manager.gce.service.Instances.DetachDisk(
manager.gce.projectID, instanceZone, instanceName, devicePath).Do()
}
func (manager *gceServiceManager) GetDiskFromCloudProvider(
zone string,
diskName string) (*GCEDisk, error) {
if zone == "" {
return nil, fmt.Errorf("Can not fetch disk %q. Zone is empty.", diskName)
}
if diskName == "" {
return nil, fmt.Errorf("Can not fetch disk. Zone is specified (%q). But disk name is empty.", zone)
}
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
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,
}, nil
}
diskStable, err := manager.gce.service.Disks.Get(
manager.gce.projectID, zone, diskName).Do()
if err != nil {
return nil, err
}
zoneInfo := singleZone{strings.TrimSpace(lastComponent(diskStable.Zone))}
if zoneInfo.zone == "" {
zoneInfo = singleZone{zone}
}
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: diskStable.Name,
Kind: diskStable.Kind,
Type: diskStable.Type,
}, nil
}
func (manager *gceServiceManager) GetRegionalDiskFromCloudProvider(
diskName string) (*GCEDisk, error) {
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
diskAlpha, err := manager.gce.serviceAlpha.RegionDisks.Get(
manager.gce.projectID, manager.gce.region, diskName).Do()
if err != nil {
return nil, err
}
zones := sets.NewString()
for _, zoneURI := range diskAlpha.ReplicaZones {
zones.Insert(lastComponent(zoneURI))
}
return &GCEDisk{
ZoneInfo: multiZone{zones},
Region: lastComponent(diskAlpha.Region),
Name: diskAlpha.Name,
Kind: diskAlpha.Kind,
Type: diskAlpha.Type,
}, nil
}
return nil, fmt.Errorf("The regional PD feature is only available via the GCE Alpha API. Enable \"GCEDiskAlphaAPI\" in the list of \"alpha-features\" in \"gce.conf\" to use the feature.")
}
func (manager *gceServiceManager) DeleteDiskOnCloudProvider(
zone string,
diskName string) (gceObject, error) {
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
return manager.gce.serviceAlpha.Disks.Delete(
manager.gce.projectID, zone, diskName).Do()
}
return manager.gce.service.Disks.Delete(
manager.gce.projectID, zone, diskName).Do()
}
func (manager *gceServiceManager) DeleteRegionalDiskOnCloudProvider(
diskName string) (gceObject, error) {
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
return manager.gce.serviceAlpha.RegionDisks.Delete(
manager.gce.projectID, manager.gce.region, diskName).Do()
}
return nil, fmt.Errorf("DeleteRegionalDiskOnCloudProvider is a regional PD feature and is only available via the GCE Alpha API. Enable \"GCEDiskAlphaAPI\" in the list of \"alpha-features\" in \"gce.conf\" to use the feature.")
}
func (manager *gceServiceManager) WaitForZoneOp(
op gceObject, zone string, mc *metricContext) error {
return manager.gce.waitForZoneOp(op, zone, mc)
}
func (manager *gceServiceManager) WaitForRegionalOp(
op gceObject, mc *metricContext) error {
return manager.gce.waitForRegionOp(op, manager.gce.region, mc)
}
func (manager *gceServiceManager) getDiskSourceURI(disk *GCEDisk) (string, error) {
getProjectsAPIEndpoint := manager.getProjectsAPIEndpoint()
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
}
switch zoneInfo := disk.ZoneInfo.(type) {
case singleZone:
if zoneInfo.zone == "" || disk.Region == "" {
// Unexpected, but sanity-check
return "", fmt.Errorf("PD does not have zone/region information: %#v", disk)
}
return getProjectsAPIEndpoint + fmt.Sprintf(
diskSourceURITemplateSingleZone,
manager.gce.projectID,
zoneInfo.zone,
disk.Name), nil
case multiZone:
if zoneInfo.replicaZones == nil || zoneInfo.replicaZones.Len() <= 0 {
// Unexpected, but sanity-check
return "", fmt.Errorf("PD is regional but does not have any replicaZones specified: %v", disk)
}
return getProjectsAPIEndpoint + fmt.Sprintf(
diskSourceURITemplateRegional,
manager.gce.projectID,
disk.Region,
disk.Name), nil
case nil:
// Unexpected, but sanity-check
return "", fmt.Errorf("PD did not have ZoneInfo: %v", disk)
default:
// Unexpected, but sanity-check
return "", fmt.Errorf("disk.ZoneInfo has unexpected type %T", zoneInfo)
}
}
func (manager *gceServiceManager) getDiskTypeURI(
diskRegion string, diskZoneInfo zoneType, diskType string) (string, error) {
getProjectsAPIEndpoint := manager.getProjectsAPIEndpoint()
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
}
switch zoneInfo := diskZoneInfo.(type) {
case singleZone:
if zoneInfo.zone == "" {
return "", fmt.Errorf("zone is empty: %v", zoneInfo)
}
return getProjectsAPIEndpoint + fmt.Sprintf(
diskTypeURITemplateSingleZone,
manager.gce.projectID,
zoneInfo.zone,
diskType), nil
case multiZone:
if zoneInfo.replicaZones == nil || zoneInfo.replicaZones.Len() <= 0 {
return "", fmt.Errorf("zoneInfo is regional but does not have any replicaZones specified: %v", zoneInfo)
}
return getProjectsAPIEndpoint + fmt.Sprintf(
diskTypeURITemplateRegional,
manager.gce.projectID,
diskRegion,
diskType), nil
case nil:
return "", fmt.Errorf("zoneInfo nil")
default:
return "", fmt.Errorf("zoneInfo has unexpected type %T", zoneInfo)
}
}
func (manager *gceServiceManager) getReplicaZoneURI(zone string) string {
getProjectsAPIEndpoint := manager.getProjectsAPIEndpoint()
if manager.gce.AlphaFeatureGate.Enabled(GCEDiskAlphaFeatureGate) {
getProjectsAPIEndpoint = manager.getProjectsAPIEndpointAlpha()
}
return getProjectsAPIEndpoint + fmt.Sprintf(
replicaZoneURITemplateSingleZone,
manager.gce.projectID,
zone)
}
func (manager *gceServiceManager) getRegionFromZone(zoneInfo zoneType) (string, error) {
var zone string
switch zoneInfo := zoneInfo.(type) {
case singleZone:
if zoneInfo.zone == "" {
// Unexpected, but sanity-check
return "", fmt.Errorf("PD is single zone, but zone is not specified: %#v", zoneInfo)
}
zone = zoneInfo.zone
case multiZone:
if zoneInfo.replicaZones == nil || zoneInfo.replicaZones.Len() <= 0 {
// Unexpected, but sanity-check
return "", fmt.Errorf("PD is regional but does not have any replicaZones specified: %v", zoneInfo)
}
zone = zoneInfo.replicaZones.UnsortedList()[0]
case nil:
// Unexpected, but sanity-check
return "", fmt.Errorf("zoneInfo is nil")
default:
// Unexpected, but sanity-check
return "", fmt.Errorf("zoneInfo has unexpected type %T", zoneInfo)
}
region, err := GetGCERegion(zone)
if err != nil {
glog.Warningf("failed to parse GCE region from zone %q: %v", zone, err)
region = manager.gce.region
}
return region, nil
}
// Disks is interface for manipulation with GCE PDs.
type Disks interface {
// AttachDisk attaches given disk to the node with the specified NodeName.
@ -175,7 +592,7 @@ func (gce *GCECloud) AttachDisk(diskName string, nodeName types.NodeName, readOn
readWrite = "READ_ONLY"
}
attachOp, err := gce.manager.AttachDisk(
attachOp, err := gce.manager.AttachDiskOnCloudProvider(
disk, readWrite, instance.Zone, instance.Name)
if err != nil {
@ -202,7 +619,7 @@ func (gce *GCECloud) DetachDisk(devicePath string, nodeName types.NodeName) erro
}
mc := newDiskMetricContextZonal("detach", gce.region, inst.Zone)
detachOp, err := gce.manager.DetachDisk(inst.Zone, inst.Name, devicePath)
detachOp, err := gce.manager.DetachDiskOnCloudProvider(inst.Zone, inst.Name, devicePath)
if err != nil {
return mc.Observe(err)
}
@ -292,7 +709,7 @@ func (gce *GCECloud) CreateDisk(
mc := newDiskMetricContextZonal("create", gce.region, zone)
createOp, err := gce.manager.CreateDisk(
createOp, err := gce.manager.CreateDiskOnCloudProvider(
name, sizeGb, tagsStr, diskType, zone)
if isGCEError(err, "alreadyExists") {
@ -341,7 +758,7 @@ func (gce *GCECloud) CreateRegionalDisk(
mc := newDiskMetricContextRegional("create", gce.region)
createOp, err := gce.manager.CreateRegionalDisk(
createOp, err := gce.manager.CreateRegionalDiskOnCloudProvider(
name, sizeGb, tagsStr, diskType, replicaZones)
if isGCEError(err, "alreadyExists") {
@ -469,7 +886,7 @@ func (gce *GCECloud) GetAutoLabelsForPD(name string, zone string) (map[string]st
// If not found, returns (nil, nil)
func (gce *GCECloud) findDiskByName(diskName string, zone string) (*GCEDisk, error) {
mc := newDiskMetricContextZonal("get", gce.region, zone)
disk, err := gce.manager.GetDisk(zone, diskName)
disk, err := gce.manager.GetDiskFromCloudProvider(zone, diskName)
if err == nil {
return disk, mc.Observe(nil)
}
@ -492,7 +909,7 @@ func (gce *GCECloud) getDiskByName(diskName string, zone string) (*GCEDisk, erro
// If not found, returns (nil, nil)
func (gce *GCECloud) findRegionalDiskByName(diskName string) (*GCEDisk, error) {
mc := newDiskMetricContextRegional("get", gce.region)
disk, err := gce.manager.GetRegionalDisk(diskName)
disk, err := gce.manager.GetRegionalDiskFromCloudProvider(diskName)
if err == nil {
return disk, mc.Observe(nil)
}
@ -593,14 +1010,14 @@ func (gce *GCECloud) doDeleteDisk(diskToDelete string) error {
switch zoneInfo := disk.ZoneInfo.(type) {
case singleZone:
mc = newDiskMetricContextZonal("delete", disk.Region, zoneInfo.zone)
deleteOp, err := gce.manager.DeleteDisk(zoneInfo.zone, disk.Name)
deleteOp, err := gce.manager.DeleteDiskOnCloudProvider(zoneInfo.zone, disk.Name)
if err != nil {
return mc.Observe(err)
}
return gce.manager.WaitForZoneOp(deleteOp, zoneInfo.zone, mc)
case multiZone:
mc = newDiskMetricContextRegional("delete", disk.Region)
deleteOp, err := gce.manager.DeleteRegionalDisk(disk.Name)
deleteOp, err := gce.manager.DeleteRegionalDiskOnCloudProvider(disk.Name)
if err != nil {
return mc.Observe(err)
}

View File

@ -386,8 +386,8 @@ func TestDeleteDisk_SameDiskMultiZone(t *testing.T) {
}
/* Act */
// DeleteDisk will call FakeServiceManager.GetDisk() with all zones,
// and FakeServiceManager.GetDisk() always returns a disk,
// DeleteDisk will call FakeServiceManager.GetDiskFromCloudProvider() with all zones,
// and FakeServiceManager.GetDiskFromCloudProvider() always returns a disk,
// so DeleteDisk thinks a disk with diskName exists in all zones.
err := gce.DeleteDisk(diskName)
@ -662,7 +662,7 @@ func newFakeManager(gceProjectID string, gceRegion string) *FakeServiceManager {
* Upon disk creation, disk info is stored in FakeServiceManager
* to be used by other tested methods.
*/
func (manager *FakeServiceManager) CreateDisk(
func (manager *FakeServiceManager) CreateDiskOnCloudProvider(
name string,
sizeGb int64,
tagsStr string,
@ -716,7 +716,7 @@ func (manager *FakeServiceManager) CreateDisk(
* Upon disk creation, disk info is stored in FakeServiceManager
* to be used by other tested methods.
*/
func (manager *FakeServiceManager) CreateRegionalDisk(
func (manager *FakeServiceManager) CreateRegionalDiskOnCloudProvider(
name string,
sizeGb int64,
tagsStr string,
@ -746,7 +746,7 @@ func (manager *FakeServiceManager) CreateRegionalDisk(
}
}
func (manager *FakeServiceManager) AttachDisk(
func (manager *FakeServiceManager) AttachDiskOnCloudProvider(
disk *GCEDisk,
readWrite string,
instanceZone string,
@ -767,7 +767,7 @@ func (manager *FakeServiceManager) AttachDisk(
}
}
func (manager *FakeServiceManager) DetachDisk(
func (manager *FakeServiceManager) DetachDiskOnCloudProvider(
instanceZone string,
instanceName string,
devicePath string) (gceObject, error) {
@ -789,7 +789,7 @@ func (manager *FakeServiceManager) DetachDisk(
/**
* Gets disk info stored in the FakeServiceManager.
*/
func (manager *FakeServiceManager) GetDisk(
func (manager *FakeServiceManager) GetDiskFromCloudProvider(
zone string, diskName string) (*GCEDisk, error) {
if manager.zonalDisks[zone] == "" {
@ -814,7 +814,7 @@ func (manager *FakeServiceManager) GetDisk(
/**
* Gets disk info stored in the FakeServiceManager.
*/
func (manager *FakeServiceManager) GetRegionalDisk(
func (manager *FakeServiceManager) GetRegionalDiskFromCloudProvider(
diskName string) (*GCEDisk, error) {
if _, ok := manager.regionalDisks[diskName]; !ok {
@ -839,7 +839,7 @@ func (manager *FakeServiceManager) GetRegionalDisk(
/**
* Disk info is removed from the FakeServiceManager.
*/
func (manager *FakeServiceManager) DeleteDisk(
func (manager *FakeServiceManager) DeleteDiskOnCloudProvider(
zone string,
disk string) (gceObject, error) {
@ -861,7 +861,7 @@ func (manager *FakeServiceManager) DeleteDisk(
}
}
func (manager *FakeServiceManager) DeleteRegionalDisk(
func (manager *FakeServiceManager) DeleteRegionalDiskOnCloudProvider(
disk string) (gceObject, error) {
manager.deleteDiskCalled = true