Skip to content

Commit 70f7931

Browse files
authored
Add VMs implementation to master (#8078)
1 parent daa1570 commit 70f7931

17 files changed

+1459
-468
lines changed

cluster-autoscaler/cloudprovider/azure/azure_cache.go

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"sync"
2626
"time"
2727

28+
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v5"
2829
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2022-08-01/compute"
2930
"github.com/Azure/go-autorest/autorest/to"
3031
"github.com/Azure/skewer"
@@ -67,13 +68,18 @@ type azureCache struct {
6768

6869
// Cache content.
6970

70-
// resourceGroup specifies the name of the resource group that this cache tracks
71-
resourceGroup string
71+
// resourceGroup specifies the name of the node resource group that this cache tracks
72+
resourceGroup string
73+
clusterResourceGroup string
74+
clusterName string
75+
76+
// enableVMsAgentPool specifies whether VMs agent pool type is supported.
77+
enableVMsAgentPool bool
7278

7379
// vmType can be one of vmTypeVMSS (default), vmTypeStandard
7480
vmType string
7581

76-
vmsPoolSet map[string]struct{} // track the nodepools that're vms pool
82+
vmsPoolMap map[string]armcontainerservice.AgentPool // track the nodepools that're vms pool
7783

7884
// scaleSets keeps the set of all known scalesets in the resource group, populated/refreshed via VMSS.List() call.
7985
// It is only used/populated if vmType is vmTypeVMSS (default).
@@ -106,8 +112,11 @@ func newAzureCache(client *azClient, cacheTTL time.Duration, config Config) (*az
106112
azClient: client,
107113
refreshInterval: cacheTTL,
108114
resourceGroup: config.ResourceGroup,
115+
clusterResourceGroup: config.ClusterResourceGroup,
116+
clusterName: config.ClusterName,
117+
enableVMsAgentPool: config.EnableVMsAgentPool,
109118
vmType: config.VMType,
110-
vmsPoolSet: make(map[string]struct{}),
119+
vmsPoolMap: make(map[string]armcontainerservice.AgentPool),
111120
scaleSets: make(map[string]compute.VirtualMachineScaleSet),
112121
virtualMachines: make(map[string][]compute.VirtualMachine),
113122
registeredNodeGroups: make([]cloudprovider.NodeGroup, 0),
@@ -130,11 +139,11 @@ func newAzureCache(client *azClient, cacheTTL time.Duration, config Config) (*az
130139
return cache, nil
131140
}
132141

133-
func (m *azureCache) getVMsPoolSet() map[string]struct{} {
142+
func (m *azureCache) getVMsPoolMap() map[string]armcontainerservice.AgentPool {
134143
m.mutex.Lock()
135144
defer m.mutex.Unlock()
136145

137-
return m.vmsPoolSet
146+
return m.vmsPoolMap
138147
}
139148

140149
func (m *azureCache) getVirtualMachines() map[string][]compute.VirtualMachine {
@@ -232,13 +241,20 @@ func (m *azureCache) fetchAzureResources() error {
232241
return err
233242
}
234243
m.scaleSets = vmssResult
235-
vmResult, vmsPoolSet, err := m.fetchVirtualMachines()
244+
vmResult, err := m.fetchVirtualMachines()
236245
if err != nil {
237246
return err
238247
}
239248
// we fetch both sets of resources since CAS may operate on mixed nodepools
240249
m.virtualMachines = vmResult
241-
m.vmsPoolSet = vmsPoolSet
250+
// fetch VMs pools if enabled
251+
if m.enableVMsAgentPool {
252+
vmsPoolMap, err := m.fetchVMsPools()
253+
if err != nil {
254+
return err
255+
}
256+
m.vmsPoolMap = vmsPoolMap
257+
}
242258

243259
return nil
244260
}
@@ -251,19 +267,17 @@ const (
251267
)
252268

253269
// fetchVirtualMachines returns the updated list of virtual machines in the config resource group using the Azure API.
254-
func (m *azureCache) fetchVirtualMachines() (map[string][]compute.VirtualMachine, map[string]struct{}, error) {
270+
func (m *azureCache) fetchVirtualMachines() (map[string][]compute.VirtualMachine, error) {
255271
ctx, cancel := getContextWithCancel()
256272
defer cancel()
257273

258274
result, err := m.azClient.virtualMachinesClient.List(ctx, m.resourceGroup)
259275
if err != nil {
260276
klog.Errorf("VirtualMachinesClient.List in resource group %q failed: %v", m.resourceGroup, err)
261-
return nil, nil, err.Error()
277+
return nil, err.Error()
262278
}
263279

264280
instances := make(map[string][]compute.VirtualMachine)
265-
// track the nodepools that're vms pools
266-
vmsPoolSet := make(map[string]struct{})
267281
for _, instance := range result {
268282
if instance.Tags == nil {
269283
continue
@@ -280,20 +294,43 @@ func (m *azureCache) fetchVirtualMachines() (map[string][]compute.VirtualMachine
280294
}
281295

282296
instances[to.String(vmPoolName)] = append(instances[to.String(vmPoolName)], instance)
297+
}
298+
return instances, nil
299+
}
283300

284-
// if the nodepool is already in the map, skip it
285-
if _, ok := vmsPoolSet[to.String(vmPoolName)]; ok {
286-
continue
301+
// fetchVMsPools returns a name to agentpool map of all the VMs pools in the cluster
302+
func (m *azureCache) fetchVMsPools() (map[string]armcontainerservice.AgentPool, error) {
303+
ctx, cancel := getContextWithTimeout(vmsContextTimeout)
304+
defer cancel()
305+
306+
// defensive check, should never happen when enableVMsAgentPool toggle is on
307+
if m.azClient.agentPoolClient == nil {
308+
return nil, errors.New("agentPoolClient is nil")
309+
}
310+
311+
vmsPoolMap := make(map[string]armcontainerservice.AgentPool)
312+
pager := m.azClient.agentPoolClient.NewListPager(m.clusterResourceGroup, m.clusterName, nil)
313+
var aps []*armcontainerservice.AgentPool
314+
for pager.More() {
315+
resp, err := pager.NextPage(ctx)
316+
if err != nil {
317+
klog.Errorf("agentPoolClient.pager.NextPage in cluster %s resource group %s failed: %v",
318+
m.clusterName, m.clusterResourceGroup, err)
319+
return nil, err
287320
}
321+
aps = append(aps, resp.Value...)
322+
}
288323

289-
// nodes from vms pool will have tag "aks-managed-agentpool-type" set to "VirtualMachines"
290-
if agentpoolType := tags[agentpoolTypeTag]; agentpoolType != nil {
291-
if strings.EqualFold(to.String(agentpoolType), vmsPoolType) {
292-
vmsPoolSet[to.String(vmPoolName)] = struct{}{}
293-
}
324+
for _, ap := range aps {
325+
if ap != nil && ap.Name != nil && ap.Properties != nil && ap.Properties.Type != nil &&
326+
*ap.Properties.Type == armcontainerservice.AgentPoolTypeVirtualMachines {
327+
// we only care about VMs pools, skip other types
328+
klog.V(6).Infof("Found VMs pool %q", *ap.Name)
329+
vmsPoolMap[*ap.Name] = *ap
294330
}
295331
}
296-
return instances, vmsPoolSet, nil
332+
333+
return vmsPoolMap, nil
297334
}
298335

299336
// fetchScaleSets returns the updated list of scale sets in the config resource group using the Azure API.
@@ -422,7 +459,7 @@ func (m *azureCache) HasInstance(providerID string) (bool, error) {
422459

423460
// FindForInstance returns node group of the given Instance
424461
func (m *azureCache) FindForInstance(instance *azureRef, vmType string) (cloudprovider.NodeGroup, error) {
425-
vmsPoolSet := m.getVMsPoolSet()
462+
vmsPoolMap := m.getVMsPoolMap()
426463
m.mutex.Lock()
427464
defer m.mutex.Unlock()
428465

@@ -441,7 +478,7 @@ func (m *azureCache) FindForInstance(instance *azureRef, vmType string) (cloudpr
441478
}
442479

443480
// cluster with vmss pool only
444-
if vmType == providerazureconsts.VMTypeVMSS && len(vmsPoolSet) == 0 {
481+
if vmType == providerazureconsts.VMTypeVMSS && len(vmsPoolMap) == 0 {
445482
if m.areAllScaleSetsUniform() {
446483
// Omit virtual machines not managed by vmss only in case of uniform scale set.
447484
if ok := virtualMachineRE.Match([]byte(inst.Name)); ok {

cluster-autoscaler/cloudprovider/azure/azure_cache_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,42 @@ import (
2222
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
2323
providerazureconsts "sigs.k8s.io/cloud-provider-azure/pkg/consts"
2424

25+
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v5"
26+
"github.com/Azure/go-autorest/autorest/to"
2527
"github.com/stretchr/testify/assert"
28+
"go.uber.org/mock/gomock"
2629
)
2730

31+
func TestFetchVMsPools(t *testing.T) {
32+
ctrl := gomock.NewController(t)
33+
defer ctrl.Finish()
34+
35+
provider := newTestProvider(t)
36+
ac := provider.azureManager.azureCache
37+
mockAgentpoolclient := NewMockAgentPoolsClient(ctrl)
38+
ac.azClient.agentPoolClient = mockAgentpoolclient
39+
40+
vmsPool := getTestVMsAgentPool(false)
41+
vmssPoolType := armcontainerservice.AgentPoolTypeVirtualMachineScaleSets
42+
vmssPool := armcontainerservice.AgentPool{
43+
Name: to.StringPtr("vmsspool1"),
44+
Properties: &armcontainerservice.ManagedClusterAgentPoolProfileProperties{
45+
Type: &vmssPoolType,
46+
},
47+
}
48+
invalidPool := armcontainerservice.AgentPool{}
49+
fakeAPListPager := getFakeAgentpoolListPager(&vmsPool, &vmssPool, &invalidPool)
50+
mockAgentpoolclient.EXPECT().NewListPager(gomock.Any(), gomock.Any(), nil).
51+
Return(fakeAPListPager)
52+
53+
vmsPoolMap, err := ac.fetchVMsPools()
54+
assert.NoError(t, err)
55+
assert.Equal(t, 1, len(vmsPoolMap))
56+
57+
_, ok := vmsPoolMap[to.String(vmsPool.Name)]
58+
assert.True(t, ok)
59+
}
60+
2861
func TestRegister(t *testing.T) {
2962
provider := newTestProvider(t)
3063
ss := newTestScaleSet(provider.azureManager, "ss")

0 commit comments

Comments
 (0)