Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 0 additions & 45 deletions api/core/v1alpha2/vmopcondition/condition.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ const (
// TypeSignalSent is a type for condition that indicates operation signal has been sent.
TypeSignalSent Type = "SignalSent"

// TypeRestoreCompleted is a type for condition that indicates success of restore.
TypeRestoreCompleted Type = "RestoreCompleted"

// TypeCloneCompleted is a type for condition that indicates success of clone.
TypeCloneCompleted Type = "CloneCompleted"

// TypeMaintenanceMode is a type for condition that indicates VMOP has put VM in maintenance mode.
TypeMaintenanceMode Type = "MaintenanceMode"

Expand Down Expand Up @@ -111,45 +105,6 @@ const (
ReasonOperationCompleted ReasonCompleted = "OperationCompleted"
)

// ReasonRestoreCompleted represents specific reasons for the 'RestoreCompleted' condition type.
type ReasonRestoreCompleted string

func (r ReasonRestoreCompleted) String() string {
return string(r)
}

const (
// ReasonRestoreInProgress is a ReasonRestoreCompleted indicating that the restore operation is in progress.
ReasonRestoreOperationInProgress ReasonRestoreCompleted = "RestoreInProgress"

// ReasonRestoreOperationCompleted is a ReasonRestoreCompleted indicating that the restore operation has completed successfully.
ReasonRestoreOperationCompleted ReasonRestoreCompleted = "RestoreCompleted"

// ReasonDryRunOperationCompleted is a ReasonRestoreCompleted indicating that the restore dry run operation has completed successfully.
ReasonDryRunOperationCompleted ReasonRestoreCompleted = "RestoreDryRunCompleted"

// ReasonRestoreOperationFailed is a ReasonRestoreCompleted indicating that operation has failed.
ReasonRestoreOperationFailed ReasonRestoreCompleted = "RestoreFailed"
)

// ReasonCloneCompleted represents specific reasons for the 'CloneCompleted' condition type.
type ReasonCloneCompleted string

func (r ReasonCloneCompleted) String() string {
return string(r)
}

const (
// ReasonCloneOperationInProgress is a ReasonCloneCompleted indicating that the clone operation is in progress.
ReasonCloneOperationInProgress ReasonCloneCompleted = "CloneInProgress"

// ReasonCloneOperationCompleted is a ReasonCloneCompleted indicating that the clone operation has completed successfully.
ReasonCloneOperationCompleted ReasonCloneCompleted = "CloneCompleted"

// ReasonCloneOperationFailed is a ReasonCloneCompleted indicating that clone operation has failed.
ReasonCloneOperationFailed ReasonCloneCompleted = "CloneFailed"
)

// ReasonCompleted represents specific reasons for the 'SignalSent' condition type.
type ReasonSignalSent string

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,14 @@ package handler

import (
"context"
"fmt"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

commonvmop "github.com/deckhouse/virtualization-controller/pkg/common/vmop"
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
genericservice "github.com/deckhouse/virtualization-controller/pkg/controller/vmop/service"
"github.com/deckhouse/virtualization-controller/pkg/controller/vmop/snapshot/internal/service"
"github.com/deckhouse/virtualization-controller/pkg/eventrecord"
"github.com/deckhouse/virtualization-controller/pkg/logger"
"github.com/deckhouse/virtualization/api/core/v1alpha2"
"github.com/deckhouse/virtualization/api/core/v1alpha2/vmopcondition"
)
Expand Down Expand Up @@ -66,16 +62,22 @@ func (h LifecycleHandler) Handle(ctx context.Context, vmop *v1alpha2.VirtualMach
return reconcile.Result{}, nil
}

svcOp, err := h.svcOpCreator(vmop)
if err != nil {
return reconcile.Result{}, err
// Ignore if VMOP is in final state or failed.
if vmop.Status.Phase == v1alpha2.VMOPPhaseCompleted || vmop.Status.Phase == v1alpha2.VMOPPhaseFailed {
return reconcile.Result{}, nil
}

// Ignore if VMOP is in final state.
if complete, _ := svcOp.IsComplete(); complete {
completed, completedFound := conditions.GetCondition(vmopcondition.TypeCompleted, vmop.Status.Conditions)
if completedFound && completed.Status == metav1.ConditionTrue {
vmop.Status.Phase = v1alpha2.VMOPPhaseCompleted
return reconcile.Result{}, nil
}

svcOp, err := h.svcOpCreator(vmop)
if err != nil {
return reconcile.Result{}, err
}

// 1.Initialize new VMOP resource: set phase to Pending and all conditions to Unknown.
h.base.Init(vmop)

Expand All @@ -87,8 +89,8 @@ func (h LifecycleHandler) Handle(ctx context.Context, vmop *v1alpha2.VirtualMach

// 3. Operation already in progress. Check if the operation is completed.
// Run execute until the operation is completed.
if svcOp.IsInProgress() {
return h.execute(ctx, vmop, svcOp)
if _, found := conditions.GetCondition(vmopcondition.TypeCompleted, vmop.Status.Conditions); found {
return svcOp.Execute(ctx)
}

// 4. VMOP is not in progress.
Expand All @@ -108,46 +110,10 @@ func (h LifecycleHandler) Handle(ctx context.Context, vmop *v1alpha2.VirtualMach
}

// 6. The Operation is valid, and can be executed.
return h.execute(ctx, vmop, svcOp)
vmop.Status.Phase = v1alpha2.VMOPPhaseInProgress
return svcOp.Execute(ctx)
}

func (h LifecycleHandler) Name() string {
return lifecycleHandlerName
}

func (h LifecycleHandler) execute(ctx context.Context, vmop *v1alpha2.VirtualMachineOperation, svcOp service.Operation) (rec reconcile.Result, err error) {
log := logger.FromContext(ctx)

completedCond := conditions.NewConditionBuilder(vmopcondition.TypeCompleted).Generation(vmop.GetGeneration())
rec, err = svcOp.Execute(ctx)
if err != nil {
failMsg := fmt.Sprintf("%s is failed", vmop.Spec.Type)
log.Debug(failMsg, logger.SlogErr(err))
failMsg = fmt.Errorf("%s: %w", failMsg, err).Error()
h.recorder.Event(vmop, corev1.EventTypeWarning, v1alpha2.ReasonErrVMOPFailed, failMsg)

vmop.Status.Phase = v1alpha2.VMOPPhaseFailed
conditions.SetCondition(completedCond.Reason(vmopcondition.ReasonOperationFailed).Message(failMsg).Status(metav1.ConditionFalse), &vmop.Status.Conditions)
} else {
vmop.Status.Phase = v1alpha2.VMOPPhaseInProgress
reason := svcOp.GetInProgressReason()
conditions.SetCondition(completedCond.Reason(reason).Message("Wait for operation to complete.").Status(metav1.ConditionFalse), &vmop.Status.Conditions)
}

isComplete, failMsg := svcOp.IsComplete()
if isComplete {
if failMsg != "" {
vmop.Status.Phase = v1alpha2.VMOPPhaseFailed
h.recorder.Event(vmop, corev1.EventTypeWarning, v1alpha2.ReasonErrVMOPFailed, failMsg)

conditions.SetCondition(completedCond.Reason(vmopcondition.ReasonOperationFailed).Message(failMsg).Status(metav1.ConditionFalse), &vmop.Status.Conditions)
} else {
vmop.Status.Phase = v1alpha2.VMOPPhaseCompleted
h.recorder.Event(vmop, corev1.EventTypeNormal, v1alpha2.ReasonVMOPSucceeded, "VirtualMachineOperation completed")

conditions.SetCondition(completedCond.Reason(vmopcondition.ReasonOperationCompleted).Message("VirtualMachineOperation succeeded.").Status(metav1.ConditionTrue), &vmop.Status.Conditions)
}
}

return rec, err
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"fmt"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -28,9 +29,9 @@ import (
"github.com/deckhouse/virtualization-controller/pkg/common/object"
"github.com/deckhouse/virtualization-controller/pkg/common/steptaker"
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
"github.com/deckhouse/virtualization-controller/pkg/controller/service"
"github.com/deckhouse/virtualization-controller/pkg/controller/vmop/snapshot/internal/step"
"github.com/deckhouse/virtualization-controller/pkg/eventrecord"
"github.com/deckhouse/virtualization-controller/pkg/logger"
"github.com/deckhouse/virtualization/api/core/v1alpha2"
"github.com/deckhouse/virtualization/api/core/v1alpha2/vmopcondition"
)
Expand All @@ -50,44 +51,51 @@ type CloneOperation struct {
}

func (o CloneOperation) Execute(ctx context.Context) (reconcile.Result, error) {
cb := conditions.NewConditionBuilder(vmopcondition.TypeCloneCompleted)
defer func() { conditions.SetCondition(cb.Generation(o.vmop.Generation), &o.vmop.Status.Conditions) }()

cond, exist := conditions.GetCondition(vmopcondition.TypeCloneCompleted, o.vmop.Status.Conditions)
if exist {
if cond.Status == metav1.ConditionUnknown {
cb.Status(metav1.ConditionFalse).Reason(vmopcondition.ReasonCloneOperationInProgress)
} else {
cb.Status(cond.Status).Reason(vmopcondition.ReasonRestoreCompleted(cond.Reason)).Message(cond.Message)
}
}
log := logger.FromContext(ctx)

if o.vmop.Spec.Clone == nil {
err := fmt.Errorf("clone specification is mandatory to start cloning")
cb.Status(metav1.ConditionFalse).Reason(vmopcondition.ReasonCloneOperationFailed).Message(service.CapitalizeFirstLetter(err.Error()))
return reconcile.Result{}, err
}

vmKey := types.NamespacedName{Namespace: o.vmop.Namespace, Name: o.vmop.Spec.VirtualMachine}
vm, err := object.FetchObject(ctx, vmKey, o.client, &v1alpha2.VirtualMachine{})
if err != nil {
err := fmt.Errorf("failed to fetch the virtual machine %q: %w", vmKey.Name, err)
cb.Status(metav1.ConditionFalse).Reason(vmopcondition.ReasonCloneOperationFailed).Message(service.CapitalizeFirstLetter(err.Error()))
return reconcile.Result{}, err
}

if vm == nil {
err := fmt.Errorf("virtual machine specified is not found")
cb.Status(metav1.ConditionFalse).Reason(vmopcondition.ReasonCloneOperationFailed).Message(service.CapitalizeFirstLetter(err.Error()))
return reconcile.Result{}, err
}

return steptaker.NewStepTakers(
step.NewCleanupSnapshotStep(o.client, o.recorder, cb),
step.NewCreateSnapshotStep(o.client, o.recorder, cb),
step.NewVMSnapshotReadyStep(o.client, cb),
step.NewProcessCloneStep(o.client, o.recorder, cb),
o.vmop.Status.Phase = v1alpha2.VMOPPhaseInProgress

result, err := steptaker.NewStepTakers(
step.NewCreateSnapshotStep(o.client, o.recorder),
step.NewVMSnapshotReadyStep(o.client),
step.NewProcessCloneStep(o.client, o.recorder),
step.NewWaitingDisksStep(o.client, o.recorder),
step.NewCleanupSnapshotStep(o.client, o.recorder),
step.NewCompletedStep(o.recorder),
).Run(ctx, o.vmop)
if err != nil {
failMsg := fmt.Sprintf("%s is failed", o.vmop.Spec.Type)
log.Debug(failMsg, logger.SlogErr(err))
failMsg = fmt.Errorf("%s: %w", failMsg, err).Error()
o.recorder.Event(o.vmop, corev1.EventTypeWarning, v1alpha2.ReasonErrVMOPFailed, failMsg)

o.vmop.Status.Phase = v1alpha2.VMOPPhaseFailed
conditions.SetCondition(
conditions.NewConditionBuilder(vmopcondition.TypeCompleted).
Reason(vmopcondition.ReasonOperationFailed).
Message(failMsg).Status(metav1.ConditionFalse),
&o.vmop.Status.Conditions,
)
}

return result, err
}

func (o CloneOperation) IsApplicableForVMPhase(phase v1alpha2.MachinePhase) bool {
Expand All @@ -101,35 +109,3 @@ func (o CloneOperation) IsApplicableForRunPolicy(runPolicy v1alpha2.RunPolicy) b
func (o CloneOperation) GetInProgressReason() vmopcondition.ReasonCompleted {
return vmopcondition.ReasonCloneInProgress
}

func (o CloneOperation) IsInProgress() bool {
snapshotCondition, found := conditions.GetCondition(vmopcondition.TypeSnapshotReady, o.vmop.Status.Conditions)
if found && snapshotCondition.Status != metav1.ConditionUnknown {
return true
}

cloneCondition, found := conditions.GetCondition(vmopcondition.TypeCloneCompleted, o.vmop.Status.Conditions)
if found && cloneCondition.Status != metav1.ConditionUnknown {
return true
}

return false
}

func (o CloneOperation) IsComplete() (bool, string) {
cloneCondition, ok := conditions.GetCondition(vmopcondition.TypeCloneCompleted, o.vmop.Status.Conditions)
if !ok {
return false, ""
}

snapshotCondition, ok := conditions.GetCondition(vmopcondition.TypeSnapshotReady, o.vmop.Status.Conditions)
if !ok {
return false, ""
}

if cloneCondition.Reason == string(vmopcondition.ReasonCloneOperationFailed) && snapshotCondition.Reason == string(vmopcondition.ReasonSnapshotCleanedUp) {
return true, cloneCondition.Message
}

return cloneCondition.Status == metav1.ConditionTrue && snapshotCondition.Reason == string(vmopcondition.ReasonSnapshotCleanedUp), ""
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ type Operation interface {
IsApplicableForVMPhase(phase v1alpha2.MachinePhase) bool
IsApplicableForRunPolicy(runPolicy v1alpha2.RunPolicy) bool
GetInProgressReason() vmopcondition.ReasonCompleted
IsInProgress() bool
IsComplete() (bool, string)
}

func NewOperationService(client client.Client, recorder eventrecord.EventRecorderLogger, vmop *v1alpha2.VirtualMachineOperation) (Operation, error) {
Expand Down
Loading
Loading