Skip to content
This repository was archived by the owner on Mar 22, 2018. It is now read-only.

Commit c1a2b22

Browse files
author
Kubernetes Submit Queue
authored
Merge pull request #56846 from zetaab/fixvolumeattached
Automatic merge from submit-queue. 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>. fix cinder detach problems **What this PR does / why we need it**: We have currently huge problems in cinder volume detach. This PR tries to fix these issues. **Which issue(s) this PR fixes**: Fixes #50004 Fixes #57497 **Special notes for your reviewer**: **Release note**: ```release-note openstack cinder detach problem is fixed if nova is shutdowned ```
2 parents 9fad374 + 3f5d4c9 commit c1a2b22

9 files changed

Lines changed: 183 additions & 52 deletions

File tree

pkg/cloudprovider/providers/openstack/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ go_library(
2626
"//pkg/controller:go_default_library",
2727
"//pkg/util/mount:go_default_library",
2828
"//pkg/volume:go_default_library",
29+
"//pkg/volume/util:go_default_library",
2930
"//vendor/github.com/golang/glog:go_default_library",
3031
"//vendor/github.com/gophercloud/gophercloud:go_default_library",
3132
"//vendor/github.com/gophercloud/gophercloud/openstack:go_default_library",

pkg/cloudprovider/providers/openstack/openstack.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,22 @@ func mapNodeNameToServerName(nodeName types.NodeName) string {
319319
return string(nodeName)
320320
}
321321

322+
// getNodeNameByID maps instanceid to types.NodeName
323+
func (os *OpenStack) GetNodeNameByID(instanceID string) (types.NodeName, error) {
324+
client, err := os.NewComputeV2()
325+
var nodeName types.NodeName
326+
if err != nil {
327+
return nodeName, err
328+
}
329+
330+
server, err := servers.Get(client, instanceID).Extract()
331+
if err != nil {
332+
return nodeName, err
333+
}
334+
nodeName = mapServerToNodeName(server)
335+
return nodeName, nil
336+
}
337+
322338
// mapServerToNodeName maps an OpenStack Server to a k8s NodeName
323339
func mapServerToNodeName(server *servers.Server) types.NodeName {
324340
// Node names are always lowercase, and (at least)
@@ -346,11 +362,14 @@ func foreachServer(client *gophercloud.ServiceClient, opts servers.ListOptsBuild
346362
return err
347363
}
348364

349-
func getServerByName(client *gophercloud.ServiceClient, name types.NodeName) (*servers.Server, error) {
365+
func getServerByName(client *gophercloud.ServiceClient, name types.NodeName, showOnlyActive bool) (*servers.Server, error) {
350366
opts := servers.ListOpts{
351-
Name: fmt.Sprintf("^%s$", regexp.QuoteMeta(mapNodeNameToServerName(name))),
352-
Status: "ACTIVE",
367+
Name: fmt.Sprintf("^%s$", regexp.QuoteMeta(mapNodeNameToServerName(name))),
353368
}
369+
if showOnlyActive {
370+
opts.Status = "ACTIVE"
371+
}
372+
354373
pager := servers.List(client, opts)
355374

356375
serverList := make([]servers.Server, 0, 1)
@@ -432,7 +451,7 @@ func nodeAddresses(srv *servers.Server) ([]v1.NodeAddress, error) {
432451
}
433452

434453
func getAddressesByName(client *gophercloud.ServiceClient, name types.NodeName) ([]v1.NodeAddress, error) {
435-
srv, err := getServerByName(client, name)
454+
srv, err := getServerByName(client, name, true)
436455
if err != nil {
437456
return nil, err
438457
}
@@ -582,7 +601,7 @@ func (os *OpenStack) GetZoneByNodeName(nodeName types.NodeName) (cloudprovider.Z
582601
return cloudprovider.Zone{}, err
583602
}
584603

585-
srv, err := getServerByName(compute, nodeName)
604+
srv, err := getServerByName(compute, nodeName, true)
586605
if err != nil {
587606
if err == ErrNotFound {
588607
return cloudprovider.Zone{}, cloudprovider.InstanceNotFound

pkg/cloudprovider/providers/openstack/openstack_instances.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func (i *Instances) NodeAddressesByProviderID(providerID string) ([]v1.NodeAddre
103103

104104
// ExternalID returns the cloud provider ID of the specified instance (deprecated).
105105
func (i *Instances) ExternalID(name types.NodeName) (string, error) {
106-
srv, err := getServerByName(i.compute, name)
106+
srv, err := getServerByName(i.compute, name, true)
107107
if err != nil {
108108
if err == ErrNotFound {
109109
return "", cloudprovider.InstanceNotFound
@@ -151,7 +151,7 @@ func (os *OpenStack) InstanceID() (string, error) {
151151

152152
// InstanceID returns the cloud provider ID of the specified instance.
153153
func (i *Instances) InstanceID(name types.NodeName) (string, error) {
154-
srv, err := getServerByName(i.compute, name)
154+
srv, err := getServerByName(i.compute, name, true)
155155
if err != nil {
156156
if err == ErrNotFound {
157157
return "", cloudprovider.InstanceNotFound
@@ -184,7 +184,7 @@ func (i *Instances) InstanceTypeByProviderID(providerID string) (string, error)
184184

185185
// InstanceType returns the type of the specified instance.
186186
func (i *Instances) InstanceType(name types.NodeName) (string, error) {
187-
srv, err := getServerByName(i.compute, name)
187+
srv, err := getServerByName(i.compute, name, true)
188188

189189
if err != nil {
190190
return "", err

pkg/cloudprovider/providers/openstack/openstack_loadbalancer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ func getNodeSecurityGroupIDForLB(compute *gophercloud.ServiceClient, nodes []*v1
551551

552552
for _, node := range nodes {
553553
nodeName := types.NodeName(node.Name)
554-
srv, err := getServerByName(compute, nodeName)
554+
srv, err := getServerByName(compute, nodeName, true)
555555
if err != nil {
556556
return nodeSecurityGroupIDs.List(), err
557557
}

pkg/cloudprovider/providers/openstack/openstack_routes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ func (r *Routes) DeleteRoute(clusterName string, route *cloudprovider.Route) err
288288
}
289289

290290
func getPortIDByIP(compute *gophercloud.ServiceClient, targetNode types.NodeName, ipAddress string) (string, error) {
291-
srv, err := getServerByName(compute, targetNode)
291+
srv, err := getServerByName(compute, targetNode, true)
292292
if err != nil {
293293
return "", err
294294
}

pkg/cloudprovider/providers/openstack/openstack_volumes.go

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package openstack
1818

1919
import (
20+
"errors"
2021
"fmt"
2122
"io/ioutil"
2223
"path"
@@ -25,7 +26,9 @@ import (
2526
"time"
2627

2728
"k8s.io/apimachinery/pkg/api/resource"
29+
"k8s.io/apimachinery/pkg/types"
2830
k8s_volume "k8s.io/kubernetes/pkg/volume"
31+
volumeutil "k8s.io/kubernetes/pkg/volume/util"
2932

3033
"github.com/gophercloud/gophercloud"
3134
volumeexpand "github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions"
@@ -318,7 +321,17 @@ func (os *OpenStack) AttachDisk(instanceID, volumeID string) (string, error) {
318321
glog.V(4).Infof("Disk %s is already attached to instance %s", volumeID, instanceID)
319322
return volume.ID, nil
320323
}
321-
return "", fmt.Errorf("disk %s is attached to a different instance (%s)", volumeID, volume.AttachedServerId)
324+
nodeName, err := os.GetNodeNameByID(volume.AttachedServerId)
325+
attachErr := fmt.Sprintf("disk %s path %s is attached to a different instance (%s)", volumeID, volume.AttachedDevice, volume.AttachedServerId)
326+
if err != nil {
327+
glog.Error(attachErr)
328+
return "", errors.New(attachErr)
329+
}
330+
// using volume.AttachedDevice may cause problems because cinder does not report device path correctly see issue #33128
331+
devicePath := volume.AttachedDevice
332+
danglingErr := volumeutil.NewDanglingError(attachErr, nodeName, devicePath)
333+
glog.V(2).Infof("Found dangling volume %s attached to node %s", volumeID, nodeName)
334+
return "", danglingErr
322335
}
323336

324337
startTime := time.Now()
@@ -578,6 +591,9 @@ func (os *OpenStack) GetAttachmentDiskPath(instanceID, volumeID string) (string,
578591

579592
// DiskIsAttached queries if a volume is attached to a compute instance
580593
func (os *OpenStack) DiskIsAttached(instanceID, volumeID string) (bool, error) {
594+
if instanceID == "" {
595+
glog.Warningf("calling DiskIsAttached with empty instanceid: %s %s", instanceID, volumeID)
596+
}
581597
volume, err := os.getVolume(volumeID)
582598
if err != nil {
583599
return false, err
@@ -586,6 +602,29 @@ func (os *OpenStack) DiskIsAttached(instanceID, volumeID string) (bool, error) {
586602
return instanceID == volume.AttachedServerId, nil
587603
}
588604

605+
// DiskIsAttachedByName queries if a volume is attached to a compute instance by name
606+
func (os *OpenStack) DiskIsAttachedByName(nodeName types.NodeName, volumeID string) (bool, string, error) {
607+
cClient, err := os.NewComputeV2()
608+
if err != nil {
609+
return false, "", err
610+
}
611+
srv, err := getServerByName(cClient, nodeName, false)
612+
if err != nil {
613+
if err == ErrNotFound {
614+
// instance not found anymore in cloudprovider, assume that cinder is detached
615+
return false, "", nil
616+
} else {
617+
return false, "", err
618+
}
619+
}
620+
instanceID := "/" + srv.ID
621+
if ind := strings.LastIndex(instanceID, "/"); ind >= 0 {
622+
instanceID = instanceID[(ind + 1):]
623+
}
624+
attached, err := os.DiskIsAttached(instanceID, volumeID)
625+
return attached, instanceID, err
626+
}
627+
589628
// DisksAreAttached queries if a list of volumes are attached to a compute instance
590629
func (os *OpenStack) DisksAreAttached(instanceID string, volumeIDs []string) (map[string]bool, error) {
591630
attached := make(map[string]bool)
@@ -600,6 +639,32 @@ func (os *OpenStack) DisksAreAttached(instanceID string, volumeIDs []string) (ma
600639
return attached, nil
601640
}
602641

642+
// DisksAreAttachedByName queries if a list of volumes are attached to a compute instance by name
643+
func (os *OpenStack) DisksAreAttachedByName(nodeName types.NodeName, volumeIDs []string) (map[string]bool, error) {
644+
attached := make(map[string]bool)
645+
cClient, err := os.NewComputeV2()
646+
if err != nil {
647+
return attached, err
648+
}
649+
srv, err := getServerByName(cClient, nodeName, false)
650+
if err != nil {
651+
if err == ErrNotFound {
652+
// instance not found anymore, mark all volumes as detached
653+
for _, volumeID := range volumeIDs {
654+
attached[volumeID] = false
655+
}
656+
return attached, nil
657+
} else {
658+
return attached, err
659+
}
660+
}
661+
instanceID := "/" + srv.ID
662+
if ind := strings.LastIndex(instanceID, "/"); ind >= 0 {
663+
instanceID = instanceID[(ind + 1):]
664+
}
665+
return os.DisksAreAttached(instanceID, volumeIDs)
666+
}
667+
603668
// diskIsUsed returns true a disk is attached to any node.
604669
func (os *OpenStack) diskIsUsed(volumeID string) (bool, error) {
605670
volume, err := os.getVolume(volumeID)

pkg/volume/cinder/attacher.go

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"k8s.io/api/core/v1"
2828
"k8s.io/apimachinery/pkg/types"
2929
"k8s.io/apimachinery/pkg/util/wait"
30-
"k8s.io/kubernetes/pkg/cloudprovider"
3130
"k8s.io/kubernetes/pkg/util/mount"
3231
"k8s.io/kubernetes/pkg/volume"
3332
volumeutil "k8s.io/kubernetes/pkg/volume/util"
@@ -187,23 +186,7 @@ func (attacher *cinderDiskAttacher) VolumesAreAttached(specs []*volume.Spec, nod
187186
volumeSpecMap[volumeSource.VolumeID] = spec
188187
}
189188

190-
instanceID, err := attacher.nodeInstanceID(nodeName)
191-
if err != nil {
192-
if err == cloudprovider.InstanceNotFound {
193-
// If node doesn't exist, OpenStack Nova will assume the volumes are not attached to it.
194-
// Mark the volumes as detached and return false without error.
195-
glog.Warningf("VolumesAreAttached: node %q does not exist.", nodeName)
196-
for spec := range volumesAttachedCheck {
197-
volumesAttachedCheck[spec] = false
198-
}
199-
200-
return volumesAttachedCheck, nil
201-
}
202-
203-
return volumesAttachedCheck, err
204-
}
205-
206-
attachedResult, err := attacher.cinderProvider.DisksAreAttached(instanceID, volumeIDList)
189+
attachedResult, err := attacher.cinderProvider.DisksAreAttachedByName(nodeName, volumeIDList)
207190
if err != nil {
208191
// Log error and continue with attach
209192
glog.Errorf(
@@ -381,20 +364,10 @@ func (detacher *cinderDiskDetacher) waitDiskDetached(instanceID, volumeID string
381364

382365
func (detacher *cinderDiskDetacher) Detach(volumeName string, nodeName types.NodeName) error {
383366
volumeID := path.Base(volumeName)
384-
instances, res := detacher.cinderProvider.Instances()
385-
if !res {
386-
return fmt.Errorf("failed to list openstack instances")
387-
}
388-
instanceID, err := instances.InstanceID(nodeName)
389-
if ind := strings.LastIndex(instanceID, "/"); ind >= 0 {
390-
instanceID = instanceID[(ind + 1):]
391-
}
392-
393367
if err := detacher.waitOperationFinished(volumeID); err != nil {
394368
return err
395369
}
396-
397-
attached, err := detacher.cinderProvider.DiskIsAttached(instanceID, volumeID)
370+
attached, instanceID, err := detacher.cinderProvider.DiskIsAttachedByName(nodeName, volumeID)
398371
if err != nil {
399372
// Log error and continue with detach
400373
glog.Errorf(

0 commit comments

Comments
 (0)