Skip to content

Commit 1edd5fb

Browse files
eofffprismagod
andauthored
fix(vd): time spent in the WaitForFirstConsumer phase is no longer included in totalProvisioning (#2379)
Signed-off-by: Valeriy Khorunzhin <valeriy.khorunzhin@flant.com> Co-authored-by: Vladislav Panfilov <97229646+prismagod@users.noreply.github.com>
1 parent a01cf49 commit 1edd5fb

9 files changed

Lines changed: 162 additions & 191 deletions

File tree

api/core/v1alpha2/virtual_disk.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ type VirtualDiskStatsCreationDuration struct {
9797
// Waiting time for dependent resources.
9898
// +nullable
9999
WaitingForDependencies *metav1.Duration `json:"waitingForDependencies,omitempty"`
100+
// Waiting time in the `WaitForFirstConsumer` phase.
101+
// +nullable
102+
WaitingForFirstConsumer *metav1.Duration `json:"waitingForFirstConsumer,omitempty"`
100103
// Duration of the loading into DVCR.
101104
// +nullable
102105
DVCRProvisioning *metav1.Duration `json:"dvcrProvisioning,omitempty"`

api/core/v1alpha2/zz_generated.deepcopy.go

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

crds/doc-ru-virtualdisks.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ spec:
163163
waitingForDependencies:
164164
description: |
165165
Длительность ожидания зависимостей для создания виртуального диска.
166+
waitingForFirstConsumer:
167+
description: |
168+
Длительность ожидания в фазе `WaitForFirstConsumer`.
166169
dvcrProvisioning:
167170
description: |
168171
Длительность загрузки в Deckhouse Virtualization Container Registry (DVCR).

crds/virtualdisks.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,10 @@ spec:
460460
description: Waiting time for dependent resources.
461461
nullable: true
462462
type: string
463+
waitingForFirstConsumer:
464+
description: Waiting time in the `WaitForFirstConsumer` phase.
465+
nullable: true
466+
type: string
463467
type: object
464468
type: object
465469
storageClassName:

images/virtualization-artifact/pkg/controller/vd/internal/source/http.go

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk) (re
117117
case IsDiskProvisioningFinished(condition):
118118
log.Debug("Disk provisioning finished: clean up")
119119

120-
setPhaseConditionForFinishedDisk(pvc, cb, &vd.Status.Phase, supgen)
120+
setPhaseConditionForFinishedDisk(vd, pvc, cb, &vd.Status.Phase, supgen)
121121

122122
// Protect Ready Disk and underlying PVC.
123123
err = ds.diskService.Protect(ctx, supgen, vd, nil, pvc)
@@ -161,17 +161,14 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk) (re
161161
// OK.
162162
case common.ErrQuotaExceeded(err):
163163
ds.recorder.Event(vd, corev1.EventTypeWarning, v1alpha2.ReasonDataSourceQuotaExceeded, "DataSource quota exceed")
164-
return setQuotaExceededPhaseCondition(cb, &vd.Status.Phase, err, vd.CreationTimestamp), nil
164+
return setQuotaExceededPhaseCondition(vd, cb, &vd.Status.Phase, err, vd.CreationTimestamp), nil
165165
default:
166-
setPhaseConditionToFailed(cb, &vd.Status.Phase, fmt.Errorf("unexpected error: %w", err))
166+
setPhaseConditionToFailed(vd, cb, &vd.Status.Phase, fmt.Errorf("unexpected error: %w", err))
167167
return reconcile.Result{}, err
168168
}
169169

170170
vd.Status.Phase = v1alpha2.DiskProvisioning
171-
cb.
172-
Status(metav1.ConditionFalse).
173-
Reason(vdcondition.Provisioning).
174-
Message("DVCR Provisioner not found: create the new one.")
171+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.Provisioning, "DVCR Provisioner not found: create the new one.")
175172

176173
return reconcile.Result{RequeueAfter: time.Second}, nil
177174
case !podutil.IsPodComplete(pod):
@@ -188,17 +185,21 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk) (re
188185
}
189186

190187
vd.Status.Phase = v1alpha2.DiskProvisioning
191-
cb.
192-
Status(metav1.ConditionFalse).
193-
Reason(vdcondition.Provisioning).
194-
Message("Import is in the process of provisioning to DVCR.")
188+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.Provisioning, "Import is in the process of provisioning to DVCR.")
195189

196190
vd.Status.Progress = ds.statService.GetProgress(vd.GetUID(), pod, vd.Status.Progress, service.NewScaleOption(0, 50))
197191
vd.Status.DownloadSpeed = ds.statService.GetDownloadSpeed(vd.GetUID(), pod)
198192
case dv == nil:
199193
if isStorageClassWFFC(sc) && len(vd.Status.AttachedToVirtualMachines) != 1 {
200194
vd.Status.Progress = "50%"
201195
vd.Status.Phase = v1alpha2.DiskWaitForFirstConsumer
196+
setReadyConditionWithWFFCAccounting(
197+
vd,
198+
cb,
199+
metav1.ConditionFalse,
200+
vdcondition.WaitingForFirstConsumer,
201+
"The provisioning has been suspended: a created and scheduled virtual machine is awaited.",
202+
)
202203
return reconcile.Result{}, nil
203204
}
204205

@@ -216,10 +217,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk) (re
216217
switch {
217218
case errors.Is(err, service.ErrProvisioningFailed):
218219
ds.recorder.Event(vd, corev1.EventTypeWarning, v1alpha2.ReasonDataSourceDiskProvisioningFailed, "Disk provisioning failed")
219-
cb.
220-
Status(metav1.ConditionFalse).
221-
Reason(vdcondition.ProvisioningFailed).
222-
Message(service.CapitalizeFirstLetter(err.Error() + "."))
220+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.ProvisioningFailed, service.CapitalizeFirstLetter(err.Error()+"."))
223221
return reconcile.Result{}, nil
224222
default:
225223
return reconcile.Result{}, err
@@ -230,14 +228,14 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk) (re
230228
vd.Status.DownloadSpeed = ds.statService.GetDownloadSpeed(vd.GetUID(), pod)
231229

232230
if imageformat.IsISO(ds.statService.GetFormat(pod)) {
233-
setPhaseConditionToFailed(cb, &vd.Status.Phase, ErrISOSourceNotSupported)
231+
setPhaseConditionToFailed(vd, cb, &vd.Status.Phase, ErrISOSourceNotSupported)
234232
return reconcile.Result{}, nil
235233
}
236234

237235
var diskSize resource.Quantity
238236
diskSize, err = ds.getPVCSize(vd, pod)
239237
if err != nil {
240-
setPhaseConditionToFailed(cb, &vd.Status.Phase, err)
238+
setPhaseConditionToFailed(vd, cb, &vd.Status.Phase, err)
241239

242240
if errors.Is(err, service.ErrInsufficientPVCSize) {
243241
return reconcile.Result{}, nil
@@ -251,7 +249,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk) (re
251249
var nodePlacement *provisioner.NodePlacement
252250
nodePlacement, err = getNodePlacement(ctx, ds.client, vd)
253251
if err != nil {
254-
setPhaseConditionToFailed(cb, &vd.Status.Phase, fmt.Errorf("unexpected error: %w", err))
252+
setPhaseConditionToFailed(vd, cb, &vd.Status.Phase, fmt.Errorf("unexpected error: %w", err))
255253
return reconcile.Result{}, fmt.Errorf("failed to get importer tolerations: %w", err)
256254
}
257255

@@ -261,39 +259,27 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk) (re
261259
}
262260

263261
vd.Status.Phase = v1alpha2.DiskProvisioning
264-
cb.
265-
Status(metav1.ConditionFalse).
266-
Reason(vdcondition.Provisioning).
267-
Message("PVC Provisioner not found: create the new one.")
262+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.Provisioning, "PVC Provisioner not found: create the new one.")
268263

269264
return reconcile.Result{RequeueAfter: time.Second}, nil
270265
case dvQuotaNotExceededCondition != nil && dvQuotaNotExceededCondition.Status == corev1.ConditionFalse:
271266
vd.Status.Phase = v1alpha2.DiskPending
272267
if dv.Status.ClaimName != "" && isStorageClassWFFC(sc) {
273268
vd.Status.Phase = v1alpha2.DiskWaitForFirstConsumer
274269
}
275-
cb.
276-
Status(metav1.ConditionFalse).
277-
Reason(vdcondition.QuotaExceeded).
278-
Message(dvQuotaNotExceededCondition.Message)
270+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.QuotaExceeded, dvQuotaNotExceededCondition.Message)
279271
return reconcile.Result{}, nil
280272
case dvRunningCondition != nil && dvRunningCondition.Status != corev1.ConditionTrue && dvRunningCondition.Reason == DVImagePullFailedReason:
281273
vd.Status.Phase = v1alpha2.DiskPending
282274
if dv.Status.ClaimName != "" && isStorageClassWFFC(sc) {
283275
vd.Status.Phase = v1alpha2.DiskWaitForFirstConsumer
284276
}
285-
cb.
286-
Status(metav1.ConditionFalse).
287-
Reason(vdcondition.ImagePullFailed).
288-
Message(dvRunningCondition.Message)
277+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.ImagePullFailed, dvRunningCondition.Message)
289278
ds.recorder.Event(vd, corev1.EventTypeWarning, vdcondition.ImagePullFailed.String(), dvRunningCondition.Message)
290279
return reconcile.Result{}, nil
291280
case pvc == nil:
292281
vd.Status.Phase = v1alpha2.DiskProvisioning
293-
cb.
294-
Status(metav1.ConditionFalse).
295-
Reason(vdcondition.Provisioning).
296-
Message("PVC not found: waiting for creation.")
282+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.Provisioning, "PVC not found: waiting for creation.")
297283
return reconcile.Result{RequeueAfter: time.Second}, nil
298284
case ds.diskService.IsImportDone(dv, pvc):
299285
log.Info("Import has completed", "dvProgress", dv.Status.Progress, "dvPhase", dv.Status.Phase, "pvcPhase", pvc.Status.Phase)
@@ -306,10 +292,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk) (re
306292
)
307293

308294
vd.Status.Phase = v1alpha2.DiskReady
309-
cb.
310-
Status(metav1.ConditionTrue).
311-
Reason(vdcondition.Ready).
312-
Message("")
295+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionTrue, vdcondition.Ready, "")
313296

314297
vd.Status.Progress = "100%"
315298
vd.Status.Capacity = ds.diskService.GetCapacity(pvc)

images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk)
119119
case IsDiskProvisioningFinished(condition):
120120
log.Debug("Disk provisioning finished: clean up")
121121

122-
setPhaseConditionForFinishedDisk(pvc, cb, &vd.Status.Phase, supgen)
122+
setPhaseConditionForFinishedDisk(vd, pvc, cb, &vd.Status.Phase, supgen)
123123

124124
// Protect Ready Disk and underlying PVC.
125125
err = ds.diskService.Protect(ctx, supgen, vd, nil, pvc)
@@ -163,17 +163,14 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk)
163163
// OK.
164164
case common.ErrQuotaExceeded(err):
165165
ds.recorder.Event(vd, corev1.EventTypeWarning, v1alpha2.ReasonDataSourceQuotaExceeded, "DataSource quota exceed")
166-
return setQuotaExceededPhaseCondition(cb, &vd.Status.Phase, err, vd.CreationTimestamp), nil
166+
return setQuotaExceededPhaseCondition(vd, cb, &vd.Status.Phase, err, vd.CreationTimestamp), nil
167167
default:
168-
setPhaseConditionToFailed(cb, &vd.Status.Phase, fmt.Errorf("unexpected error: %w", err))
168+
setPhaseConditionToFailed(vd, cb, &vd.Status.Phase, fmt.Errorf("unexpected error: %w", err))
169169
return reconcile.Result{}, err
170170
}
171171

172172
vd.Status.Phase = v1alpha2.DiskPending
173-
cb.
174-
Status(metav1.ConditionFalse).
175-
Reason(vdcondition.WaitForUserUpload).
176-
Message("DVCR Provisioner not found: create the new one.")
173+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.WaitForUserUpload, "DVCR Provisioner not found: create the new one.")
177174

178175
return reconcile.Result{RequeueAfter: time.Second}, nil
179176
case !podutil.IsPodComplete(pod):
@@ -185,10 +182,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk)
185182
}
186183

187184
vd.Status.Phase = v1alpha2.DiskProvisioning
188-
cb.
189-
Status(metav1.ConditionFalse).
190-
Reason(vdcondition.Provisioning).
191-
Message("DVCR Provisioner not found: create the new one.")
185+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.Provisioning, "DVCR Provisioner not found: create the new one.")
192186

193187
vd.Status.Progress = ds.statService.GetProgress(vd.GetUID(), pod, vd.Status.Progress, service.NewScaleOption(0, 50))
194188

@@ -200,6 +194,13 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk)
200194
if isStorageClassWFFC(sc) && len(vd.Status.AttachedToVirtualMachines) != 1 {
201195
vd.Status.Progress = "50%"
202196
vd.Status.Phase = v1alpha2.DiskWaitForFirstConsumer
197+
setReadyConditionWithWFFCAccounting(
198+
vd,
199+
cb,
200+
metav1.ConditionFalse,
201+
vdcondition.WaitingForFirstConsumer,
202+
"The provisioning has been suspended: a created and scheduled virtual machine is awaited.",
203+
)
203204
return reconcile.Result{}, nil
204205
}
205206

@@ -217,10 +218,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk)
217218
switch {
218219
case errors.Is(err, service.ErrProvisioningFailed):
219220
ds.recorder.Event(vd, corev1.EventTypeWarning, v1alpha2.ReasonDataSourceDiskProvisioningFailed, "Disk provisioning failed")
220-
cb.
221-
Status(metav1.ConditionFalse).
222-
Reason(vdcondition.ProvisioningFailed).
223-
Message(service.CapitalizeFirstLetter(err.Error() + "."))
221+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.ProvisioningFailed, service.CapitalizeFirstLetter(err.Error()+"."))
224222
return reconcile.Result{}, nil
225223
default:
226224
return reconcile.Result{}, err
@@ -230,14 +228,14 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk)
230228
vd.Status.Progress = "50%"
231229

232230
if imageformat.IsISO(ds.statService.GetFormat(pod)) {
233-
setPhaseConditionToFailed(cb, &vd.Status.Phase, ErrISOSourceNotSupported)
231+
setPhaseConditionToFailed(vd, cb, &vd.Status.Phase, ErrISOSourceNotSupported)
234232
return reconcile.Result{}, nil
235233
}
236234

237235
var diskSize resource.Quantity
238236
diskSize, err = ds.getPVCSize(vd, pod)
239237
if err != nil {
240-
setPhaseConditionToFailed(cb, &vd.Status.Phase, err)
238+
setPhaseConditionToFailed(vd, cb, &vd.Status.Phase, err)
241239

242240
if errors.Is(err, service.ErrInsufficientPVCSize) {
243241
return reconcile.Result{}, nil
@@ -251,7 +249,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk)
251249
var nodePlacement *provisioner.NodePlacement
252250
nodePlacement, err = getNodePlacement(ctx, ds.client, vd)
253251
if err != nil {
254-
setPhaseConditionToFailed(cb, &vd.Status.Phase, fmt.Errorf("unexpected error: %w", err))
252+
setPhaseConditionToFailed(vd, cb, &vd.Status.Phase, fmt.Errorf("unexpected error: %w", err))
255253
return reconcile.Result{}, fmt.Errorf("failed to get importer tolerations: %w", err)
256254
}
257255

@@ -266,39 +264,27 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk)
266264
return reconcile.Result{}, err
267265
}
268266
vd.Status.Phase = v1alpha2.DiskProvisioning
269-
cb.
270-
Status(metav1.ConditionFalse).
271-
Reason(vdcondition.Provisioning).
272-
Message("PVC Provisioner not found: create the new one.")
267+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.Provisioning, "PVC Provisioner not found: create the new one.")
273268

274269
return reconcile.Result{RequeueAfter: time.Second}, nil
275270
case dvQuotaNotExceededCondition != nil && dvQuotaNotExceededCondition.Status == corev1.ConditionFalse:
276271
vd.Status.Phase = v1alpha2.DiskPending
277272
if dv.Status.ClaimName != "" && isStorageClassWFFC(sc) {
278273
vd.Status.Phase = v1alpha2.DiskWaitForFirstConsumer
279274
}
280-
cb.
281-
Status(metav1.ConditionFalse).
282-
Reason(vdcondition.QuotaExceeded).
283-
Message(dvQuotaNotExceededCondition.Message)
275+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.QuotaExceeded, dvQuotaNotExceededCondition.Message)
284276
return reconcile.Result{}, nil
285277
case dvRunningCondition != nil && dvRunningCondition.Status != corev1.ConditionTrue && dvRunningCondition.Reason == DVImagePullFailedReason:
286278
vd.Status.Phase = v1alpha2.DiskPending
287279
if dv.Status.ClaimName != "" && isStorageClassWFFC(sc) {
288280
vd.Status.Phase = v1alpha2.DiskWaitForFirstConsumer
289281
}
290-
cb.
291-
Status(metav1.ConditionFalse).
292-
Reason(vdcondition.ImagePullFailed).
293-
Message(dvRunningCondition.Message)
282+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.ImagePullFailed, dvRunningCondition.Message)
294283
ds.recorder.Event(vd, corev1.EventTypeWarning, vdcondition.ImagePullFailed.String(), dvRunningCondition.Message)
295284
return reconcile.Result{}, nil
296285
case pvc == nil:
297286
vd.Status.Phase = v1alpha2.DiskProvisioning
298-
cb.
299-
Status(metav1.ConditionFalse).
300-
Reason(vdcondition.Provisioning).
301-
Message("PVC not found: waiting for creation.")
287+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionFalse, vdcondition.Provisioning, "PVC not found: waiting for creation.")
302288
return reconcile.Result{RequeueAfter: time.Second}, nil
303289
case ds.diskService.IsImportDone(dv, pvc):
304290
log.Info("Import has completed", "dvProgress", dv.Status.Progress, "dvPhase", dv.Status.Phase, "pvcPhase", pvc.Status.Phase)
@@ -311,10 +297,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk)
311297
)
312298

313299
vd.Status.Phase = v1alpha2.DiskReady
314-
cb.
315-
Status(metav1.ConditionTrue).
316-
Reason(vdcondition.Ready).
317-
Message("")
300+
setReadyConditionWithWFFCAccounting(vd, cb, metav1.ConditionTrue, vdcondition.Ready, "")
318301

319302
vd.Status.Progress = "100%"
320303
vd.Status.Capacity = ds.diskService.GetCapacity(pvc)

0 commit comments

Comments
 (0)