diff --git a/pkg/cloudprovider/providers/vsphere/nodemanager.go b/pkg/cloudprovider/providers/vsphere/nodemanager.go index d2c1770bc2..1ed39bccd5 100644 --- a/pkg/cloudprovider/providers/vsphere/nodemanager.go +++ b/pkg/cloudprovider/providers/vsphere/nodemanager.go @@ -33,6 +33,7 @@ type NodeInfo struct { dataCenter *vclib.Datacenter vm *vclib.VirtualMachine vcServer string + vmUUID string } type NodeManager struct { @@ -53,6 +54,7 @@ type NodeManager struct { type NodeDetails struct { NodeName string vm *vclib.VirtualMachine + VMUUID string } // TODO: Make it configurable in vsphere.conf @@ -74,7 +76,10 @@ func (nm *NodeManager) DiscoverNode(node *v1.Node) error { var globalErr *error queueChannel = make(chan *VmSearch, QUEUE_SIZE) - nodeUUID := node.Status.NodeInfo.SystemUUID + nodeUUID := GetUUIDFromProviderID(node.Spec.ProviderID) + + glog.V(4).Infof("Discovering node %s with uuid %s", node.ObjectMeta.Name, nodeUUID) + vmFound := false globalErr = nil @@ -178,7 +183,7 @@ func (nm *NodeManager) DiscoverNode(node *v1.Node) error { glog.V(4).Infof("Found node %s as vm=%+v in vc=%s and datacenter=%s", node.Name, vm, res.vc, res.datacenter.Name()) - nodeInfo := &NodeInfo{dataCenter: res.datacenter, vm: vm, vcServer: res.vc} + nodeInfo := &NodeInfo{dataCenter: res.datacenter, vm: vm, vcServer: res.vc, vmUUID: nodeUUID} nm.addNodeInfo(node.ObjectMeta.Name, nodeInfo) for range queueChannel { } @@ -311,7 +316,7 @@ func (nm *NodeManager) GetNodeDetails() ([]NodeDetails, error) { } nm.nodeInfoMap[nodeName] = n glog.V(4).Infof("Updated NodeInfo %q for node %q.", nodeInfo, nodeName) - nodeDetails = append(nodeDetails, NodeDetails{nodeName, n.vm}) + nodeDetails = append(nodeDetails, NodeDetails{nodeName, n.vm, n.vmUUID}) } return nodeDetails, nil } diff --git a/pkg/cloudprovider/providers/vsphere/vsphere.go b/pkg/cloudprovider/providers/vsphere/vsphere.go index a4e7f60d9b..106e99d783 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere.go @@ -54,8 +54,6 @@ const ( MacOuiVC = "00:50:56" MacOuiEsx = "00:0c:29" CleanUpDummyVMRoutineInterval = 5 - UUIDPath = "/sys/class/dmi/id/product_serial" - UUIDPrefix = "VMware-" ) var cleanUpRoutineInitialized = false @@ -72,6 +70,7 @@ type VSphere struct { vsphereInstanceMap map[string]*VSphereInstance // Responsible for managing discovery of k8s node, their location etc. nodeManager *NodeManager + vmUUID string } // Represents a vSphere instance where one or more kubernetes nodes are running. @@ -237,7 +236,11 @@ func newWorkerNode() (*VSphere, error) { glog.Errorf("Failed to get hostname. err: %+v", err) return nil, err } - + vs.vmUUID, err = GetVMUUID() + if err != nil { + glog.Errorf("Failed to get uuid. err: %+v", err) + return nil, err + } return &vs, nil } @@ -395,6 +398,11 @@ func newControllerNode(cfg VSphereConfig) (*VSphere, error) { glog.Errorf("Failed to get hostname. err: %+v", err) return nil, err } + vs.vmUUID, err = GetVMUUID() + if err != nil { + glog.Errorf("Failed to get uuid. err: %+v", err) + return nil, err + } runtime.SetFinalizer(&vs, logout) return &vs, nil } @@ -576,7 +584,23 @@ func (vs *VSphere) ExternalID(ctx context.Context, nodeName k8stypes.NodeName) ( // InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running. // If false is returned with no error, the instance will be immediately deleted by the cloud controller manager. func (vs *VSphere) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) { - _, err := vs.InstanceID(ctx, convertToK8sType(providerID)) + var nodeName string + nodes, err := vs.nodeManager.GetNodeDetails() + if err != nil { + glog.Errorf("Error while obtaining Kubernetes node nodeVmDetail details. error : %+v", err) + return false, err + } + for _, node := range nodes { + if node.VMUUID == GetUUIDFromProviderID(providerID) { + nodeName = node.NodeName + break + } + } + if nodeName == "" { + msg := fmt.Sprintf("Error while obtaining Kubernetes nodename for providerID %s.", providerID) + return false, errors.New(msg) + } + _, err = vs.InstanceID(ctx, convertToK8sType(nodeName)) if err == nil { return true, nil } @@ -589,7 +613,7 @@ func (vs *VSphere) InstanceID(ctx context.Context, nodeName k8stypes.NodeName) ( instanceIDInternal := func() (string, error) { if vs.hostName == convertToString(nodeName) { - return vs.hostName, nil + return vs.vmUUID, nil } // Below logic can be performed only on master node where VC details are preset. @@ -623,7 +647,7 @@ func (vs *VSphere) InstanceID(ctx context.Context, nodeName k8stypes.NodeName) ( return "", err } if isActive { - return convertToString(nodeName), nil + return vs.vmUUID, nil } glog.Warningf("The VM: %s is not in %s state", convertToString(nodeName), vclib.ActivePowerState) return "", cloudprovider.InstanceNotFound diff --git a/pkg/cloudprovider/providers/vsphere/vsphere_util.go b/pkg/cloudprovider/providers/vsphere/vsphere_util.go index e0c62ebfe2..20077a43cc 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere_util.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere_util.go @@ -32,6 +32,7 @@ import ( "path/filepath" "github.com/vmware/govmomi/vim25/mo" + "io/ioutil" k8stypes "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vclib" "k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vclib/diskmanagers" @@ -43,6 +44,9 @@ const ( Folder = "Folder" VirtualMachine = "VirtualMachine" DummyDiskName = "kube-dummyDisk.vmdk" + UUIDPath = "/sys/class/dmi/id/product_serial" + UUIDPrefix = "VMware-" + ProviderPrefix = "vsphere://" vSphereConfFileEnvVar = "VSPHERE_CONF_FILE" ) @@ -468,8 +472,9 @@ func (vs *VSphere) checkDiskAttached(ctx context.Context, nodes []k8stypes.NodeN if err != nil { return nodesToRetry, err } - glog.V(9).Infof("Verifying volume for node %s with nodeuuid %q: %s", nodeName, node.Status.NodeInfo.SystemUUID, vmMoMap) - vclib.VerifyVolumePathsForVM(vmMoMap[strings.ToLower(node.Status.NodeInfo.SystemUUID)], nodeVolumes[nodeName], convertToString(nodeName), attached) + nodeUUID := strings.ToLower(GetUUIDFromProviderID(node.Spec.ProviderID)) + glog.V(9).Infof("Verifying volume for node %s with nodeuuid %q: %s", nodeName, nodeUUID, vmMoMap) + vclib.VerifyVolumePathsForVM(vmMoMap[nodeUUID], nodeVolumes[nodeName], convertToString(nodeName), attached) } return nodesToRetry, nil } @@ -510,3 +515,30 @@ func (vs *VSphere) IsDummyVMPresent(vmName string) (bool, error) { return isDummyVMPresent, nil } + +func GetVMUUID() (string, error) { + id, err := ioutil.ReadFile(UUIDPath) + if err != nil { + return "", fmt.Errorf("error retrieving vm uuid: %s", err) + } + uuidFromFile := string(id[:]) + //strip leading and trailing white space and new line char + uuid := strings.TrimSpace(uuidFromFile) + // check the uuid starts with "VMware-" + if !strings.HasPrefix(uuid, UUIDPrefix) { + return "", fmt.Errorf("Failed to match Prefix, UUID read from the file is %v", uuidFromFile) + } + // Strip the prefix and white spaces and - + uuid = strings.Replace(uuid[len(UUIDPrefix):(len(uuid))], " ", "", -1) + uuid = strings.Replace(uuid, "-", "", -1) + if len(uuid) != 32 { + return "", fmt.Errorf("Length check failed, UUID read from the file is %v", uuidFromFile) + } + // need to add dashes, e.g. "564d395e-d807-e18a-cb25-b79f65eb2b9f" + uuid = fmt.Sprintf("%s-%s-%s-%s-%s", uuid[0:8], uuid[8:12], uuid[12:16], uuid[16:20], uuid[20:32]) + return uuid, nil +} + +func GetUUIDFromProviderID(providerID string) string { + return strings.TrimPrefix(providerID, ProviderPrefix) +}