Merge pull request #4130 from marwanad/dont-decrement-azure-cache

dont proactively decrement azure cache for unregistered nodes
This commit is contained in:
Kubernetes Prow Robot 2021-06-10 22:06:13 -07:00 committed by GitHub
commit 0623a00d29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 5 deletions

View File

@ -340,7 +340,7 @@ func (scaleSet *ScaleSet) Belongs(node *apiv1.Node) (bool, error) {
} }
// DeleteInstances deletes the given instances. All instances must be controlled by the same ASG. // DeleteInstances deletes the given instances. All instances must be controlled by the same ASG.
func (scaleSet *ScaleSet) DeleteInstances(instances []*azureRef) error { func (scaleSet *ScaleSet) DeleteInstances(instances []*azureRef, hasUnregisteredNodes bool) error {
if len(instances) == 0 { if len(instances) == 0 {
return nil return nil
} }
@ -405,9 +405,12 @@ func (scaleSet *ScaleSet) DeleteInstances(instances []*azureRef) error {
// Proactively decrement scale set size so that we don't // Proactively decrement scale set size so that we don't
// go below minimum node count if cache data is stale // go below minimum node count if cache data is stale
scaleSet.sizeMutex.Lock() // only do it for non-unregistered nodes
scaleSet.curSize -= int64(len(instanceIDs)) if !hasUnregisteredNodes {
scaleSet.sizeMutex.Unlock() scaleSet.sizeMutex.Lock()
scaleSet.curSize -= int64(len(instanceIDs))
scaleSet.sizeMutex.Unlock()
}
// Proactively set the status of the instances to be deleted in cache // Proactively set the status of the instances to be deleted in cache
for _, instance := range instancesToDelete { for _, instance := range instancesToDelete {
@ -432,6 +435,7 @@ func (scaleSet *ScaleSet) DeleteNodes(nodes []*apiv1.Node) error {
} }
refs := make([]*azureRef, 0, len(nodes)) refs := make([]*azureRef, 0, len(nodes))
hasUnregisteredNodes := false
for _, node := range nodes { for _, node := range nodes {
belongs, err := scaleSet.Belongs(node) belongs, err := scaleSet.Belongs(node)
if err != nil { if err != nil {
@ -442,13 +446,16 @@ func (scaleSet *ScaleSet) DeleteNodes(nodes []*apiv1.Node) error {
return fmt.Errorf("%s belongs to a different asg than %s", node.Name, scaleSet.Id()) return fmt.Errorf("%s belongs to a different asg than %s", node.Name, scaleSet.Id())
} }
if node.Annotations[cloudprovider.FakeNodeReasonAnnotation] == cloudprovider.FakeNodeUnregistered {
hasUnregisteredNodes = true
}
ref := &azureRef{ ref := &azureRef{
Name: node.Spec.ProviderID, Name: node.Spec.ProviderID,
} }
refs = append(refs, ref) refs = append(refs, ref)
} }
return scaleSet.DeleteInstances(refs) return scaleSet.DeleteInstances(refs, hasUnregisteredNodes)
} }
// Id returns ScaleSet id. // Id returns ScaleSet id.

View File

@ -18,6 +18,7 @@ package azure
import ( import (
"fmt" "fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net/http" "net/http"
"testing" "testing"
"time" "time"
@ -346,6 +347,82 @@ func TestDeleteNodes(t *testing.T) {
assert.Equal(t, instance2.Status.State, cloudprovider.InstanceDeleting) assert.Equal(t, instance2.Status.State, cloudprovider.InstanceDeleting)
} }
func TestDeleteNodeUnregistered(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
manager := newTestAzureManager(t)
vmssName := "test-asg"
var vmssCapacity int64 = 2
expectedScaleSets := []compute.VirtualMachineScaleSet{
{
Name: &vmssName,
Sku: &compute.Sku{
Capacity: &vmssCapacity,
},
},
}
expectedVMSSVMs := newTestVMSSVMList(2)
mockVMSSClient := mockvmssclient.NewMockInterface(ctrl)
mockVMSSClient.EXPECT().List(gomock.Any(), manager.config.ResourceGroup).Return(expectedScaleSets, nil).Times(2)
mockVMSSClient.EXPECT().DeleteInstancesAsync(gomock.Any(), manager.config.ResourceGroup, gomock.Any(), gomock.Any()).Return(nil, nil)
mockVMSSClient.EXPECT().WaitForAsyncOperationResult(gomock.Any(), gomock.Any()).Return(&http.Response{StatusCode: http.StatusOK}, nil).AnyTimes()
manager.azClient.virtualMachineScaleSetsClient = mockVMSSClient
mockVMSSVMClient := mockvmssvmclient.NewMockInterface(ctrl)
mockVMSSVMClient.EXPECT().List(gomock.Any(), manager.config.ResourceGroup, "test-asg", gomock.Any()).Return(expectedVMSSVMs, nil).AnyTimes()
manager.azClient.virtualMachineScaleSetVMsClient = mockVMSSVMClient
err := manager.forceRefresh()
assert.NoError(t, err)
resourceLimiter := cloudprovider.NewResourceLimiter(
map[string]int64{cloudprovider.ResourceNameCores: 1, cloudprovider.ResourceNameMemory: 10000000},
map[string]int64{cloudprovider.ResourceNameCores: 10, cloudprovider.ResourceNameMemory: 100000000})
provider, err := BuildAzureCloudProvider(manager, resourceLimiter)
assert.NoError(t, err)
registered := manager.RegisterNodeGroup(
newTestScaleSet(manager, "test-asg"))
manager.explicitlyConfigured["test-asg"] = true
assert.True(t, registered)
err = manager.forceRefresh()
assert.NoError(t, err)
scaleSet, ok := provider.NodeGroups()[0].(*ScaleSet)
assert.True(t, ok)
targetSize, err := scaleSet.TargetSize()
assert.NoError(t, err)
assert.Equal(t, 2, targetSize)
// annotate node with unregistered annotation
annotations := make(map[string]string)
annotations[cloudprovider.FakeNodeReasonAnnotation] = cloudprovider.FakeNodeUnregistered
nodesToDelete := []*apiv1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Annotations: annotations,
},
Spec: apiv1.NodeSpec{
ProviderID: "azure://" + fmt.Sprintf(fakeVirtualMachineScaleSetVMID, 0),
},
},
}
err = scaleSet.DeleteNodes(nodesToDelete)
assert.NoError(t, err)
// Ensure the the cached size has NOT been proactively decremented
targetSize, err = scaleSet.TargetSize()
assert.NoError(t, err)
assert.Equal(t, 2, targetSize)
// Ensure that the status for the instances is Deleting
instance0, found := scaleSet.getInstanceByProviderID("azure://" + fmt.Sprintf(fakeVirtualMachineScaleSetVMID, 0))
assert.True(t, found, true)
assert.Equal(t, instance0.Status.State, cloudprovider.InstanceDeleting)
}
func TestDeleteNoConflictRequest(t *testing.T) { func TestDeleteNoConflictRequest(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()