Merge pull request #30535 from abrarshivani/vsphere_attach_detach_interface

Automatic merge from submit-queue

Implements Attacher Plugin Interface for vSphere

This PR does the following,

Fixes #29028 (vsphere volume should implement attacher interface):  Implements Attacher Plugin Interface for vSphere. 
See file: 
pkg/volume/vsphere_volume/vsphere_volume.go. - Removed attach and detach calls from SetupAt and TearDownAt.
pkg/volume/vsphere_volume/attacher.go. - Implements Attacher & Detacher Plugin Interface for vSphere. (Ref :- GCE_PD & AWS attacher.go)
pkg/cloudproviders/provider/vsphere.go - Added DiskIsAttach method.

The vSphere plugin code needs clean up. (ex: The code for getting vSphere instance is repeated in file pkg/cloudprovider/providers/vsphere.go). I will fix this in next PR.
This commit is contained in:
Kubernetes Submit Queue
2016-08-23 05:13:12 -07:00
committed by GitHub
7 changed files with 792 additions and 247 deletions

View File

@@ -66,6 +66,7 @@ var supportedSCSIControllerType = []string{"lsilogic-sas", "pvscsi"}
var ErrNoDiskUUIDFound = errors.New("No disk UUID found")
var ErrNoDiskIDFound = errors.New("No vSphere disk ID found")
var ErrNoDevicesFound = errors.New("No devices found")
var ErrNonSupportedControllerType = errors.New("Disk is attached to non-supported controller type")
// VSphere is an implementation of cloud provider Interface for VSphere.
type VSphere struct {
@@ -104,6 +105,27 @@ type VSphereConfig struct {
}
}
type Volumes interface {
// AttachDisk attaches given disk to given node. Current node
// is used when nodeName is empty string.
AttachDisk(vmDiskPath string, nodeName string) (diskID string, diskUUID string, err error)
// DetachDisk detaches given disk to given node. Current node
// is used when nodeName is empty string.
// Assumption: If node doesn't exist, disk is already detached from node.
DetachDisk(volPath string, nodeName string) error
// DiskIsAttached checks if a disk is attached to the given node.
// Assumption: If node doesn't exist, disk is not attached to the node.
DiskIsAttached(volPath, nodeName string) (bool, error)
// CreateVolume creates a new vmdk with specified parameters.
CreateVolume(name string, size int, tags *map[string]string) (volumePath string, err error)
// DeleteVolume deletes vmdk.
DeleteVolume(vmDiskPath string) error
}
// Parses vSphere cloud config file and stores it into VSphereConfig.
func readConfig(config io.Reader) (VSphereConfig, error) {
if config == nil {
@@ -582,11 +604,18 @@ func (vs *VSphere) AttachDisk(vmDiskPath string, nodeName string) (diskID string
}
// Get VM device list
vm, vmDevices, ds, _, err := getVirtualMachineDevices(vs.cfg, ctx, c, vSphereInstance)
vm, vmDevices, ds, dc, err := getVirtualMachineDevices(vs.cfg, ctx, c, vSphereInstance)
if err != nil {
return "", "", err
}
attached, _ := checkDiskAttached(vmDiskPath, vmDevices, dc, c)
if attached {
diskID, _ = getVirtualDiskID(vmDiskPath, vmDevices, dc, c)
diskUUID, _ = getVirtualDiskUUIDByPath(vmDiskPath, dc, c)
return diskID, diskUUID, nil
}
var diskControllerType = vs.cfg.Disk.SCSIControllerType
// find SCSI controller of particular type from VM devices
allSCSIControllers := getSCSIControllers(vmDevices)
@@ -768,6 +797,107 @@ func getAvailableSCSIController(scsiControllers []*types.VirtualController) *typ
return nil
}
// DiskIsAttached returns if disk is attached to the VM using controllers supported by the plugin.
func (vs *VSphere) DiskIsAttached(volPath string, nodeName string) (bool, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Create vSphere client
c, err := vsphereLogin(vs.cfg, ctx)
if err != nil {
glog.Errorf("Failed to create vSphere client. err: %s", err)
return false, err
}
defer c.Logout(ctx)
// Find virtual machine to attach disk to
var vSphereInstance string
if nodeName == "" {
vSphereInstance = vs.localInstanceID
} else {
vSphereInstance = nodeName
}
nodeExist, err := vs.NodeExists(c, vSphereInstance)
if err != nil {
glog.Errorf("Failed to check whether node exist. err: %s.", err)
return false, err
}
if !nodeExist {
glog.Warningf(
"Node %q does not exist. DiskIsAttached will assume vmdk %q is not attached to it.",
vSphereInstance,
volPath)
return false, nil
}
// Get VM device list
_, vmDevices, _, dc, err := getVirtualMachineDevices(vs.cfg, ctx, c, vSphereInstance)
if err != nil {
glog.Errorf("Failed to get VM devices for VM %#q. err: %s", vSphereInstance, err)
return false, err
}
attached, err := checkDiskAttached(volPath, vmDevices, dc, c)
return attached, err
}
func checkDiskAttached(volPath string, vmdevices object.VirtualDeviceList, dc *object.Datacenter, client *govmomi.Client) (bool, error) {
virtualDiskControllerKey, err := getVirtualDiskControllerKey(volPath, vmdevices, dc, client)
if err != nil {
if err == ErrNoDevicesFound {
return false, nil
}
glog.Errorf("Failed to check whether disk is attached. err: %s", err)
return false, err
}
for _, controllerType := range supportedSCSIControllerType {
controllerkey, _ := getControllerKey(controllerType, vmdevices, dc, client)
if controllerkey == virtualDiskControllerKey {
return true, nil
}
}
return false, ErrNonSupportedControllerType
}
// Returns the object key that denotes the controller object to which vmdk is attached.
func getVirtualDiskControllerKey(volPath string, vmDevices object.VirtualDeviceList, dc *object.Datacenter, client *govmomi.Client) (int32, error) {
volumeUUID, err := getVirtualDiskUUIDByPath(volPath, dc, client)
if err != nil {
glog.Errorf("disk uuid not found for %v. err: %s", volPath, err)
return -1, err
}
// filter vm devices to retrieve disk ID for the given vmdk file
for _, device := range vmDevices {
if vmDevices.TypeName(device) == "VirtualDisk" {
diskUUID, _ := getVirtualDiskUUID(device)
if diskUUID == volumeUUID {
return device.GetVirtualDevice().ControllerKey, nil
}
}
}
return -1, ErrNoDevicesFound
}
// Returns key of the controller.
// Key is unique id that distinguishes one device from other devices in the same virtual machine.
func getControllerKey(scsiType string, vmDevices object.VirtualDeviceList, dc *object.Datacenter, client *govmomi.Client) (int32, error) {
for _, device := range vmDevices {
devType := vmDevices.Type(device)
if devType == scsiType {
if c, ok := device.(types.BaseVirtualController); ok {
return c.GetVirtualController().Key, nil
}
}
}
return -1, ErrNoDevicesFound
}
// Returns formatted UUID for a virtual disk device.
func getVirtualDiskUUID(newDevice types.BaseVirtualDevice) (string, error) {
vd := newDevice.GetVirtualDevice()
@@ -859,6 +989,21 @@ func (vs *VSphere) DetachDisk(volPath string, nodeName string) error {
vSphereInstance = nodeName
}
nodeExist, err := vs.NodeExists(c, vSphereInstance)
if err != nil {
glog.Errorf("Failed to check whether node exist. err: %s.", err)
return err
}
if !nodeExist {
glog.Warningf(
"Node %q does not exist. DetachDisk will assume vmdk %q is not attached to it.",
vSphereInstance,
volPath)
return nil
}
vm, vmDevices, _, dc, err := getVirtualMachineDevices(vs.cfg, ctx, c, vSphereInstance)
if err != nil {
return err
@@ -962,3 +1107,43 @@ func (vs *VSphere) DeleteVolume(vmDiskPath string) error {
return task.Wait(ctx)
}
// NodeExists checks if the node with given nodeName exist.
// Returns false if VM doesn't exist or VM is in powerOff state.
func (vs *VSphere) NodeExists(c *govmomi.Client, nodeName string) (bool, error) {
if nodeName == "" {
return false, nil
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
vm, err := getVirtualMachineByName(vs.cfg, ctx, c, nodeName)
if err != nil {
if _, ok := err.(*find.NotFoundError); ok {
return false, nil
}
glog.Errorf("Failed to get virtual machine object for node %+q. err %s", nodeName, err)
return false, err
}
var mvm mo.VirtualMachine
err = getVirtualMachineManagedObjectReference(ctx, c, vm, "summary", &mvm)
if err != nil {
glog.Errorf("Failed to get virtual machine object reference for node %+q. err %s", nodeName, err)
return false, err
}
if mvm.Summary.Runtime.PowerState == ActivePowerState {
return true, nil
}
if mvm.Summary.Config.Template == false {
glog.Warningf("VM %s, is not in %s state", nodeName, ActivePowerState)
} else {
glog.Warningf("VM %s, is a template", nodeName)
}
return false, nil
}