Skip to content

Commit dbc4d54

Browse files
authored
Merge pull request #5164 from helio/fix-vmss-update-models
fix(machinepool): clear VirtualMachineProfile if no model/custom data update
2 parents 9ba44ee + c8cf42a commit dbc4d54

File tree

5 files changed

+254
-40
lines changed

5 files changed

+254
-40
lines changed

azure/scope/machinepool.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ type (
8181
capiMachinePoolPatchHelper *patch.Helper
8282
vmssState *azure.VMSS
8383
cache *MachinePoolCache
84+
skuCache *resourceskus.Cache
8485
}
8586

8687
// NodeStatus represents the status of a Kubernetes node.
@@ -164,12 +165,15 @@ func (m *MachinePoolScope) InitMachinePoolCache(ctx context.Context) error {
164165
return err
165166
}
166167

167-
skuCache, err := resourceskus.GetCache(m, m.Location())
168-
if err != nil {
169-
return err
168+
if m.skuCache == nil {
169+
skuCache, err := resourceskus.GetCache(m, m.Location())
170+
if err != nil {
171+
return errors.Wrap(err, "failed to init resourceskus cache")
172+
}
173+
m.skuCache = skuCache
170174
}
171175

172-
m.cache.VMSKU, err = skuCache.Get(ctx, m.AzureMachinePool.Spec.Template.VMSize, resourceskus.VirtualMachines)
176+
m.cache.VMSKU, err = m.skuCache.Get(ctx, m.AzureMachinePool.Spec.Template.VMSize, resourceskus.VirtualMachines)
173177
if err != nil {
174178
return errors.Wrapf(err, "failed to get VM SKU %s in compute api", m.AzureMachinePool.Spec.Template.VMSize)
175179
}
@@ -222,10 +226,8 @@ func (m *MachinePoolScope) ScaleSetSpec(ctx context.Context) azure.ResourceSpecG
222226
}
223227

224228
if m.cache != nil {
225-
if m.HasReplicasExternallyManaged(ctx) {
226-
spec.ShouldPatchCustomData = m.cache.HasBootstrapDataChanges
227-
log.V(4).Info("has bootstrap data changed?", "shouldPatchCustomData", spec.ShouldPatchCustomData)
228-
}
229+
spec.ShouldPatchCustomData = m.cache.HasBootstrapDataChanges
230+
log.V(4).Info("has bootstrap data changed?", "shouldPatchCustomData", spec.ShouldPatchCustomData)
229231
spec.VMSSExtensionSpecs = m.VMSSExtensionSpecs()
230232
spec.SKU = m.cache.VMSKU
231233
spec.VMImage = m.cache.VMImage
@@ -705,11 +707,9 @@ func (m *MachinePoolScope) Close(ctx context.Context) error {
705707
if err := m.updateReplicasAndProviderIDs(ctx); err != nil {
706708
return errors.Wrap(err, "failed to update replicas and providerIDs")
707709
}
708-
if m.HasReplicasExternallyManaged(ctx) {
709-
if err := m.updateCustomDataHash(ctx); err != nil {
710-
// ignore errors to calculating the custom data hash since it's not absolutely crucial.
711-
log.V(4).Error(err, "unable to update custom data hash, ignoring.")
712-
}
710+
if err := m.updateCustomDataHash(ctx); err != nil {
711+
// ignore errors to calculating the custom data hash since it's not absolutely crucial.
712+
log.V(4).Error(err, "unable to update custom data hash, ignoring.")
713713
}
714714
}
715715

azure/scope/machinepool_test.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ package scope
1818

1919
import (
2020
"context"
21+
"crypto/sha256"
22+
"encoding/base64"
2123
"fmt"
24+
"io"
2225
"reflect"
2326
"testing"
2427
"time"
2528

2629
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
2730
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2"
31+
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
2832
azureautorest "github.com/Azure/go-autorest/autorest/azure"
2933
"github.com/Azure/go-autorest/autorest/azure/auth"
3034
. "github.com/onsi/gomega"
@@ -1576,3 +1580,148 @@ func TestMachinePoolScope_applyAzureMachinePoolMachines(t *testing.T) {
15761580
})
15771581
}
15781582
}
1583+
1584+
func TestBootstrapDataChanges(t *testing.T) {
1585+
ctx, cancel := context.WithCancel(context.Background())
1586+
defer cancel()
1587+
scheme := runtime.NewScheme()
1588+
_ = clusterv1.AddToScheme(scheme)
1589+
_ = infrav1.AddToScheme(scheme)
1590+
_ = infrav1exp.AddToScheme(scheme)
1591+
_ = corev1.AddToScheme(scheme)
1592+
1593+
var (
1594+
g = NewWithT(t)
1595+
mockCtrl = gomock.NewController(t)
1596+
cb = fake.NewClientBuilder().WithScheme(scheme)
1597+
cluster = &clusterv1.Cluster{
1598+
ObjectMeta: metav1.ObjectMeta{
1599+
Name: "cluster1",
1600+
Namespace: "default",
1601+
},
1602+
Spec: clusterv1.ClusterSpec{
1603+
InfrastructureRef: &corev1.ObjectReference{
1604+
Name: "azCluster1",
1605+
},
1606+
},
1607+
Status: clusterv1.ClusterStatus{
1608+
InfrastructureReady: true,
1609+
},
1610+
}
1611+
azureCluster = &infrav1.AzureCluster{
1612+
ObjectMeta: metav1.ObjectMeta{
1613+
Name: "azCluster1",
1614+
Namespace: "default",
1615+
},
1616+
Spec: infrav1.AzureClusterSpec{
1617+
AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
1618+
Location: "test",
1619+
},
1620+
},
1621+
}
1622+
mp = &expv1.MachinePool{
1623+
ObjectMeta: metav1.ObjectMeta{
1624+
Name: "mp1",
1625+
Namespace: "default",
1626+
OwnerReferences: []metav1.OwnerReference{
1627+
{
1628+
Name: "cluster1",
1629+
Kind: "Cluster",
1630+
APIVersion: clusterv1.GroupVersion.String(),
1631+
},
1632+
},
1633+
},
1634+
Spec: expv1.MachinePoolSpec{
1635+
Template: clusterv1.MachineTemplateSpec{
1636+
Spec: clusterv1.MachineSpec{
1637+
Bootstrap: clusterv1.Bootstrap{
1638+
DataSecretName: ptr.To("mp-secret"),
1639+
},
1640+
Version: ptr.To("v1.31.0"),
1641+
},
1642+
},
1643+
},
1644+
}
1645+
bootstrapData = "test"
1646+
bootstrapDataHash = sha256Hash(base64.StdEncoding.EncodeToString([]byte(bootstrapData)))
1647+
bootstrapSecret = corev1.Secret{
1648+
ObjectMeta: metav1.ObjectMeta{
1649+
Name: "mp-secret",
1650+
Namespace: "default",
1651+
},
1652+
Data: map[string][]byte{"value": []byte(bootstrapData)},
1653+
}
1654+
amp = &infrav1exp.AzureMachinePool{
1655+
ObjectMeta: metav1.ObjectMeta{
1656+
Name: "amp1",
1657+
Namespace: "default",
1658+
OwnerReferences: []metav1.OwnerReference{
1659+
{
1660+
Name: "mp1",
1661+
Kind: "MachinePool",
1662+
APIVersion: expv1.GroupVersion.String(),
1663+
},
1664+
},
1665+
Annotations: map[string]string{
1666+
azure.CustomDataHashAnnotation: fmt.Sprintf("%x", bootstrapDataHash),
1667+
},
1668+
},
1669+
Spec: infrav1exp.AzureMachinePoolSpec{
1670+
Template: infrav1exp.AzureMachinePoolMachineTemplate{
1671+
Image: &infrav1.Image{},
1672+
NetworkInterfaces: []infrav1.NetworkInterface{
1673+
{
1674+
SubnetName: "test",
1675+
},
1676+
},
1677+
VMSize: "VM_SIZE",
1678+
},
1679+
},
1680+
}
1681+
vmssState = &azure.VMSS{}
1682+
)
1683+
defer mockCtrl.Finish()
1684+
1685+
s := &MachinePoolScope{
1686+
client: cb.
1687+
WithObjects(&bootstrapSecret).
1688+
Build(),
1689+
ClusterScoper: &ClusterScope{
1690+
Cluster: cluster,
1691+
AzureCluster: azureCluster,
1692+
},
1693+
skuCache: resourceskus.NewStaticCache([]armcompute.ResourceSKU{
1694+
{
1695+
Name: ptr.To("VM_SIZE"),
1696+
},
1697+
}, "test"),
1698+
MachinePool: mp,
1699+
AzureMachinePool: amp,
1700+
vmssState: vmssState,
1701+
}
1702+
1703+
g.Expect(s.InitMachinePoolCache(ctx)).NotTo(HaveOccurred())
1704+
1705+
spec := s.ScaleSetSpec(ctx)
1706+
sSpec := spec.(*scalesets.ScaleSetSpec)
1707+
g.Expect(sSpec.ShouldPatchCustomData).To(Equal(false))
1708+
1709+
amp.Annotations[azure.CustomDataHashAnnotation] = "old"
1710+
1711+
// reset cache to be able to build up the cache again
1712+
s.cache = nil
1713+
g.Expect(s.InitMachinePoolCache(ctx)).NotTo(HaveOccurred())
1714+
1715+
spec = s.ScaleSetSpec(ctx)
1716+
sSpec = spec.(*scalesets.ScaleSetSpec)
1717+
g.Expect(sSpec.ShouldPatchCustomData).To(Equal(true))
1718+
}
1719+
1720+
func sha256Hash(text string) []byte {
1721+
h := sha256.New()
1722+
_, err := io.WriteString(h, text)
1723+
if err != nil {
1724+
panic(err)
1725+
}
1726+
return h.Sum(nil)
1727+
}

azure/services/scalesets/scalesets_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -741,8 +741,8 @@ func newWindowsVMSSSpec() ScaleSetSpec {
741741
return vmss
742742
}
743743

744-
func newDefaultExistingVMSS(vmSize string) armcompute.VirtualMachineScaleSet {
745-
vmss := newDefaultVMSS(vmSize)
744+
func newDefaultExistingVMSS() armcompute.VirtualMachineScaleSet {
745+
vmss := newDefaultVMSS("VM_SIZE")
746746
vmss.ID = ptr.To("subscriptions/1234/resourceGroups/my_resource_group/providers/Microsoft.Compute/virtualMachines/my-vm")
747747
return vmss
748748
}

azure/services/scalesets/spec.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ func (s *ScaleSetSpec) OwnerResourceName() string {
9393
}
9494

9595
func (s *ScaleSetSpec) existingParameters(ctx context.Context, existing interface{}) (parameters interface{}, err error) {
96+
ctx, log, done := tele.StartSpanWithLogger(ctx, "scalesets.ScaleSetSpec.existingParameters")
97+
defer done()
98+
9699
existingVMSS, ok := existing.(armcompute.VirtualMachineScaleSet)
97100
if !ok {
98101
return nil, errors.Errorf("%T is not an armcompute.VirtualMachineScaleSet", existing)
@@ -132,6 +135,15 @@ func (s *ScaleSetSpec) existingParameters(ctx context.Context, existing interfac
132135
return nil, nil
133136
}
134137

138+
// if there are no model changes and no change in custom data, remove VirtualMachineProfile to avoid unnecessary VMSS model
139+
// updates.
140+
if !hasModelChanges && !s.ShouldPatchCustomData {
141+
log.V(4).Info("removing virtual machine profile from parameters", "hasModelChanges", hasModelChanges, "shouldPatchCustomData", s.ShouldPatchCustomData)
142+
vmss.Properties.VirtualMachineProfile = nil
143+
} else {
144+
log.V(4).Info("has changes, not removing virtual machine profile from parameters", "hasModelChanges", hasModelChanges, "shouldPatchCustomData", s.ShouldPatchCustomData)
145+
}
146+
135147
return vmss, nil
136148
}
137149

0 commit comments

Comments
 (0)