diff --git a/pkg/cloudprovider/providers/azure/azure_backoff.go b/pkg/cloudprovider/providers/azure/azure_backoff.go index 3947e912a39..6f5e41349db 100644 --- a/pkg/cloudprovider/providers/azure/azure_backoff.go +++ b/pkg/cloudprovider/providers/azure/azure_backoff.go @@ -58,6 +58,23 @@ func (az *Cloud) GetVirtualMachineWithRetry(name types.NodeName) (compute.Virtua return machine, exists, err } +// GetScaleSetsVMWithRetry invokes az.getScaleSetsVM with exponential backoff retry +func (az *Cloud) GetScaleSetsVMWithRetry(name types.NodeName) (compute.VirtualMachineScaleSetVM, bool, error) { + var machine compute.VirtualMachineScaleSetVM + var exists bool + err := wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { + var retryErr error + machine, exists, retryErr = az.getVmssVirtualMachine(name) + if retryErr != nil { + glog.Errorf("GetScaleSetsVMWithRetry backoff: failure, will retry,err=%v", retryErr) + return false, nil + } + glog.V(10).Infof("GetScaleSetsVMWithRetry backoff: success") + return true, nil + }) + return machine, exists, err +} + // VirtualMachineClientGetWithRetry invokes az.VirtualMachinesClient.Get with exponential backoff retry func (az *Cloud) VirtualMachineClientGetWithRetry(resourceGroup, vmName string, types compute.InstanceViewTypes) (compute.VirtualMachine, error) { var machine compute.VirtualMachine diff --git a/pkg/cloudprovider/providers/azure/azure_instances.go b/pkg/cloudprovider/providers/azure/azure_instances.go index bde33ab323a..8378e596a9d 100644 --- a/pkg/cloudprovider/providers/azure/azure_instances.go +++ b/pkg/cloudprovider/providers/azure/azure_instances.go @@ -117,6 +117,44 @@ func (az *Cloud) InstanceID(name types.NodeName) (string, error) { } } } + + if az.Config.VMType == vmTypeVMSS { + id, err := az.getVmssInstanceID(name) + if err == cloudprovider.InstanceNotFound || err == ErrorNotVmssInstance { + // Retry with standard type because master nodes may not belong to any vmss. + return az.getStandardInstanceID(name) + } + + return id, err + } + + return az.getStandardInstanceID(name) +} + +func (az *Cloud) getVmssInstanceID(name types.NodeName) (string, error) { + var machine compute.VirtualMachineScaleSetVM + var exists bool + var err error + az.operationPollRateLimiter.Accept() + machine, exists, err = az.getVmssVirtualMachine(name) + if err != nil { + if az.CloudProviderBackoff { + glog.V(2).Infof("InstanceID(%s) backing off", name) + machine, exists, err = az.GetScaleSetsVMWithRetry(name) + if err != nil { + glog.V(2).Infof("InstanceID(%s) abort backoff", name) + return "", err + } + } else { + return "", err + } + } else if !exists { + return "", cloudprovider.InstanceNotFound + } + return *machine.ID, nil +} + +func (az *Cloud) getStandardInstanceID(name types.NodeName) (string, error) { var machine compute.VirtualMachine var exists bool var err error @@ -168,6 +206,39 @@ func (az *Cloud) InstanceType(name types.NodeName) (string, error) { } } } + + if az.Config.VMType == vmTypeVMSS { + machineType, err := az.getVmssInstanceType(name) + if err == cloudprovider.InstanceNotFound || err == ErrorNotVmssInstance { + // Retry with standard type because master nodes may not belong to any vmss. + return az.getStandardInstanceType(name) + } + + return machineType, err + } + + return az.getStandardInstanceType(name) +} + +// getVmssInstanceType gets instance with type vmss. +func (az *Cloud) getVmssInstanceType(name types.NodeName) (string, error) { + machine, exists, err := az.getVmssVirtualMachine(name) + if err != nil { + glog.Errorf("error: az.InstanceType(%s), az.getVmssVirtualMachine(%s) err=%v", name, name, err) + return "", err + } else if !exists { + return "", cloudprovider.InstanceNotFound + } + + if machine.Sku.Name != nil { + return *machine.Sku.Name, nil + } + + return "", fmt.Errorf("instance type is not set") +} + +// getStandardInstanceType gets instance with standard type. +func (az *Cloud) getStandardInstanceType(name types.NodeName) (string, error) { machine, exists, err := az.getVirtualMachine(name) if err != nil { glog.Errorf("error: az.InstanceType(%s), az.getVirtualMachine(%s) err=%v", name, name, err) diff --git a/pkg/cloudprovider/providers/azure/azure_util.go b/pkg/cloudprovider/providers/azure/azure_util.go index 7d2aa565c4a..958275ca66b 100644 --- a/pkg/cloudprovider/providers/azure/azure_util.go +++ b/pkg/cloudprovider/providers/azure/azure_util.go @@ -402,6 +402,19 @@ outer: } func (az *Cloud) getIPForMachine(nodeName types.NodeName) (string, error) { + if az.Config.VMType == vmTypeVMSS { + ip, err := az.getIPForVmssMachine(nodeName) + if err == cloudprovider.InstanceNotFound || err == ErrorNotVmssInstance { + return az.getIPForStandardMachine(nodeName) + } + + return ip, err + } + + return az.getIPForStandardMachine(nodeName) +} + +func (az *Cloud) getIPForStandardMachine(nodeName types.NodeName) (string, error) { az.operationPollRateLimiter.Accept() machine, exists, err := az.getVirtualMachine(nodeName) if !exists { diff --git a/pkg/cloudprovider/providers/azure/azure_wrap.go b/pkg/cloudprovider/providers/azure/azure_wrap.go index 8bfa2ca81eb..52d033b9294 100644 --- a/pkg/cloudprovider/providers/azure/azure_wrap.go +++ b/pkg/cloudprovider/providers/azure/azure_wrap.go @@ -17,6 +17,7 @@ limitations under the License. package azure import ( + "errors" "net/http" "github.com/Azure/azure-sdk-for-go/arm/compute" @@ -26,6 +27,11 @@ import ( "k8s.io/apimachinery/pkg/types" ) +var ( + // ErrorNotVmssInstance indicates an instance is not belongint to any vmss. + ErrorNotVmssInstance = errors.New("not a vmss instance") +) + // checkExistsFromError inspects an error and returns a true if err is nil, // false if error is an autorest.Error with StatusCode=404 and will return the // error back if error is another status code or another type of error. @@ -74,6 +80,32 @@ func (az *Cloud) getVirtualMachine(nodeName types.NodeName) (vm compute.VirtualM return vm, exists, err } +func (az *Cloud) getVmssVirtualMachine(nodeName types.NodeName) (vm compute.VirtualMachineScaleSetVM, exists bool, err error) { + var realErr error + + vmName := string(nodeName) + instanceID, err := getVmssInstanceID(vmName) + if err != nil { + return vm, false, err + } + + az.operationPollRateLimiter.Accept() + glog.V(10).Infof("VirtualMachineScaleSetVMsClient.Get(%s): start", vmName) + vm, err = az.VirtualMachineScaleSetVMsClient.Get(az.ResourceGroup, az.PrimaryScaleSetName, instanceID) + glog.V(10).Infof("VirtualMachineScaleSetVMsClient.Get(%s): end", vmName) + + exists, realErr = checkResourceExistsFromError(err) + if realErr != nil { + return vm, false, realErr + } + + if !exists { + return vm, false, nil + } + + return vm, exists, err +} + func (az *Cloud) getRouteTable() (routeTable network.RouteTable, exists bool, err error) { var realErr error