Skip to content

Commit 492be1b

Browse files
committed
try adding vmss update
1 parent cfaa2eb commit 492be1b

File tree

8 files changed

+95
-1
lines changed

8 files changed

+95
-1
lines changed

api/v1beta1/types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ const (
6363
PatchFuture string = "PATCH"
6464
// PutFuture is a future that was derived from a PUT request.
6565
PutFuture string = "PUT"
66+
// PostFuture is a future that was derived from a POST request.
67+
PostFuture string = "POST"
6668
// DeleteFuture is a future that was derived from a DELETE request.
6769
DeleteFuture string = "DELETE"
6870
)

azure/converters/vmss.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ func SDKToVMSSVM(sdkInstance armcompute.VirtualMachineScaleSetVM) *azure.VMSSVM
154154
instance.AvailabilityZone = *sdkInstance.Zones[0]
155155
}
156156

157+
if sdkInstance.Properties != nil && sdkInstance.Properties.LatestModelApplied != nil {
158+
instance.LatestModelApplied = *sdkInstance.Properties.LatestModelApplied
159+
}
160+
157161
return &instance
158162
}
159163

azure/services/scalesets/client.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ type Client interface {
3636

3737
CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string, parameters interface{}) (result interface{}, poller *runtime.Poller[armcompute.VirtualMachineScaleSetsClientCreateOrUpdateResponse], err error)
3838
DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string) (poller *runtime.Poller[armcompute.VirtualMachineScaleSetsClientDeleteResponse], err error)
39+
40+
BeginUpdateInstances(ctx context.Context, spec azure.ResourceSpecGetter, vmInstanceIDs armcompute.VirtualMachineScaleSetVMInstanceRequiredIDs, resumeToken string) (*runtime.Poller[armcompute.VirtualMachineScaleSetsClientUpdateInstancesResponse], error)
3941
}
4042

4143
// AzureClient contains the Azure go-sdk Client.
@@ -206,3 +208,34 @@ func (ac *AzureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG
206208
// if the operation completed, return a nil poller.
207209
return nil, err
208210
}
211+
212+
// BeginUpdateInstances - Upgrades one or more virtual machines to the latest SKU set in the VM scale set model.
213+
// If the operation fails it returns an *azcore.ResponseError type.
214+
//
215+
// Parameters
216+
// - spec - The ResourceSpecGetter containing used for name and resource group of the virtual machine scale set.
217+
// - vmInstanceIDs - A list of virtual machine instance IDs from the VM scale set.
218+
func (ac *AzureClient) BeginUpdateInstances(ctx context.Context, spec azure.ResourceSpecGetter, vmInstanceIDs armcompute.VirtualMachineScaleSetVMInstanceRequiredIDs, resumeToken string) (poller *runtime.Poller[armcompute.VirtualMachineScaleSetsClientUpdateInstancesResponse], err error) {
219+
ctx, _, done := tele.StartSpanWithLogger(ctx, "scalesets.AzureClient.BeginUpdateInstances")
220+
defer done()
221+
222+
opts := &armcompute.VirtualMachineScaleSetsClientBeginUpdateInstancesOptions{ResumeToken: resumeToken}
223+
poller, err = ac.scalesets.BeginUpdateInstances(ctx, spec.ResourceGroupName(), spec.ResourceName(), vmInstanceIDs, opts)
224+
if err != nil {
225+
return nil, err
226+
}
227+
228+
ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout)
229+
defer cancel()
230+
231+
pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency}
232+
_, err = poller.PollUntilDone(ctx, pollOpts)
233+
if err != nil {
234+
// if an error occurs, return the Poller.
235+
// this means the long-running operation didn't finish in the specified timeout.
236+
return poller, err
237+
}
238+
239+
// if the operation completed, return a nil poller.
240+
return nil, err
241+
}

azure/services/scalesets/mock_scalesets/client_mock.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

azure/services/scalesets/scalesets.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,44 @@ func (s *Service) Reconcile(ctx context.Context) (retErr error) {
130130
}
131131
s.Scope.SetProviderID(providerID)
132132
s.Scope.SetVMSSState(&fetchedVMSS)
133+
134+
azLatestModelApplied := true
135+
for _, instance := range scaleSetSpec.VMSSInstances {
136+
if instance.Properties.LatestModelApplied != nil && !*instance.Properties.LatestModelApplied {
137+
azLatestModelApplied = false
138+
break
139+
}
140+
}
141+
if !azLatestModelApplied {
142+
resourceName := spec.ResourceName()
143+
futureType := infrav1.PostFuture
144+
// Check for an ongoing long-running operation.
145+
resumeToken := ""
146+
if future := s.Scope.GetLongRunningOperationState(resourceName, serviceName, futureType); future != nil {
147+
t, err := converters.FutureToResumeToken(*future)
148+
if err != nil {
149+
s.Scope.DeleteLongRunningOperationState(resourceName, serviceName, futureType)
150+
return errors.Wrap(err, "could not decode future data, resetting long-running operation state")
151+
}
152+
resumeToken = t
153+
}
154+
target := "*"
155+
poller, err := s.Client.BeginUpdateInstances(ctx, spec, armcompute.VirtualMachineScaleSetVMInstanceRequiredIDs{
156+
InstanceIDs: []*string{&target},
157+
}, resumeToken)
158+
if poller != nil && azure.IsContextDeadlineExceededOrCanceledError(err) {
159+
future, err := converters.PollerToFuture(poller, futureType, serviceName, resourceName, spec.ResourceGroupName())
160+
if err != nil {
161+
return errors.Wrap(err, "failed to convert poller to future")
162+
}
163+
s.Scope.SetLongRunningOperationState(future)
164+
return azure.WithTransientError(azure.NewOperationNotDoneError(future), s.Scope.DefaultedReconcilerRequeue())
165+
}
166+
167+
// Once the operation is done, delete the long-running operation state. Even if the operation ended with
168+
// an error, clear out any lingering state to try the operation again.
169+
s.Scope.DeleteLongRunningOperationState(resourceName, serviceName, futureType)
170+
}
133171
}
134172

135173
return err

azure/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ type (
104104
State infrav1.ProvisioningState `json:"vmState,omitempty"`
105105
BootstrappingState infrav1.ProvisioningState `json:"bootstrappingState,omitempty"`
106106
OrchestrationMode infrav1.OrchestrationModeType `json:"orchestrationMode,omitempty"`
107+
LatestModelApplied bool `json:"latestModelApplied,omitempty"`
107108
}
108109

109110
// VMSS defines a virtual machine scale set.

config/capz/manager_image_patch.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ spec:
88
spec:
99
containers:
1010
# Change the value of image field below to your controller image URL
11-
- image: gcr.io/k8s-staging-cluster-api-azure/cluster-api-azure-controller:main
11+
- image: localhost:5000/cluster-api-azure-controller-amd64:dev
1212
name: manager

exp/controllers/azuremachinepoolmachine_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ func (ampmr *AzureMachinePoolMachineController) reconcileDelete(ctx context.Cont
332332
if !machineScope.AzureMachinePool.ObjectMeta.DeletionTimestamp.IsZero() {
333333
log.Info("Skipping VMSS VM deletion as VMSS delete will delete individual instances")
334334

335+
// FIXME(mw): check if VMSS VM is already deleted to avoid recreating AMPM
335336
controllerutil.RemoveFinalizer(machineScope.AzureMachinePoolMachine, infrav1exp.AzureMachinePoolMachineFinalizer)
336337
return reconcile.Result{}, nil
337338
}

0 commit comments

Comments
 (0)