mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-04 00:17:19 +00:00
@@ -150,7 +150,7 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
||||
r.Recorder.Event(app, event.Normal(velatypes.ReasonRevisoned, velatypes.MessageRevisioned))
|
||||
klog.Info("Successfully apply application revision", "application", klog.KObj(app))
|
||||
|
||||
policies, wfSteps, err := appFile.GenerateWorkflowAndPolicy(ctx, r.dm, r.Client, r.pd)
|
||||
policies, wfSteps, err := appFile.GenerateWorkflowAndPolicy(ctx, r.dm, r.Client, r.pd, handler.Dispatch)
|
||||
if err != nil {
|
||||
klog.Error(err, "[Handle GenerateWorkflowAndPolicy]")
|
||||
r.Recorder.Event(app, event.Warning(velatypes.ReasonFailedRender, err))
|
||||
@@ -174,16 +174,37 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
||||
r.Recorder.Event(app, event.Normal(velatypes.ReasonApplied, velatypes.MessageApplied))
|
||||
klog.Info("Successfully apply application manifests", "application", klog.KObj(app))
|
||||
|
||||
done, err := workflow.NewWorkflow(app, r.Client).ExecuteSteps(ctx, handler.currentAppRev.Name, wfSteps)
|
||||
done, pause, err := workflow.NewWorkflow(app, r.Client).ExecuteSteps(ctx, handler.currentAppRev.Name, wfSteps)
|
||||
if err != nil {
|
||||
klog.Error(err, "[handle workflow]")
|
||||
r.Recorder.Event(app, event.Warning(velatypes.ReasonFailedWorkflow, err))
|
||||
return r.endWithNegativeCondition(ctx, app, utils.ErrorCondition("Workflow", err))
|
||||
}
|
||||
|
||||
if pause {
|
||||
if err := r.patchStatus(ctx, app); err != nil {
|
||||
return r.endWithNegativeCondition(ctx, app, v1alpha1.ReconcileError(err))
|
||||
}
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
if !done {
|
||||
return reconcile.Result{RequeueAfter: WorkflowReconcileWaitTime}, r.patchStatus(ctx, app)
|
||||
}
|
||||
|
||||
if wfStatus := app.Status.Workflow; wfStatus != nil && !wfStatus.Terminated {
|
||||
ref, err := handler.DispatchAndGC(ctx)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "Failed to gc after workflow",
|
||||
"application", klog.KObj(app))
|
||||
r.Recorder.Event(app, event.Warning(velatypes.ReasonFailedGC, err))
|
||||
return r.endWithNegativeCondition(ctx, app, utils.ErrorCondition("GCAfterWorkflow", err))
|
||||
}
|
||||
wfStatus.Terminated = true
|
||||
app.Status.ResourceTracker = ref
|
||||
return r.endWithNegativeCondition(ctx, app, utils.ReadyCondition("GCAfterWorkflow"))
|
||||
}
|
||||
|
||||
// if inplace is false and rolloutPlan is nil, it means the user will use an outer AppRollout object to rollout the application
|
||||
if handler.app.Spec.RolloutPlan != nil {
|
||||
res, err := handler.handleRollout(ctx)
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"context"
|
||||
|
||||
runtimev1alpha1 "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
@@ -49,10 +48,51 @@ type AppHandler struct {
|
||||
app *v1beta1.Application
|
||||
currentAppRev *v1beta1.ApplicationRevision
|
||||
latestAppRev *v1beta1.ApplicationRevision
|
||||
latestTracker *v1beta1.ResourceTracker
|
||||
dispatcher *dispatch.AppManifestsDispatcher
|
||||
isNewRevision bool
|
||||
currentRevHash string
|
||||
}
|
||||
|
||||
// Dispatch apply manifests into k8s.
|
||||
func (h *AppHandler) Dispatch(ctx context.Context, manifests ...*unstructured.Unstructured) error {
|
||||
h.initDispatcher()
|
||||
_, err := h.dispatcher.Dispatch(ctx, manifests)
|
||||
return err
|
||||
}
|
||||
|
||||
// DispatchAndGC apply manifests and do GC.
|
||||
func (h *AppHandler) DispatchAndGC(ctx context.Context, manifests ...*unstructured.Unstructured) (*runtimev1alpha1.TypedReference, error) {
|
||||
h.initDispatcher()
|
||||
tracker, err := h.dispatcher.EndAndGC(h.latestTracker).Dispatch(ctx, manifests)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, "cannot dispatch application manifests")
|
||||
}
|
||||
return &runtimev1alpha1.TypedReference{
|
||||
APIVersion: tracker.APIVersion,
|
||||
Kind: tracker.Kind,
|
||||
Name: tracker.Name,
|
||||
UID: tracker.UID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *AppHandler) initDispatcher() {
|
||||
if h.latestTracker == nil {
|
||||
if h.app.Status.ResourceTracker != nil {
|
||||
h.latestTracker = &v1beta1.ResourceTracker{}
|
||||
h.latestTracker.Name = h.app.Status.ResourceTracker.Name
|
||||
} else if h.app.Status.LatestRevision != nil {
|
||||
h.latestTracker = &v1beta1.ResourceTracker{}
|
||||
h.latestTracker.SetName(dispatch.ConstructResourceTrackerName(h.app.Status.LatestRevision.Name, h.app.Namespace))
|
||||
}
|
||||
}
|
||||
if h.dispatcher == nil {
|
||||
// only do GC when ALL resources are dispatched successfully
|
||||
// so skip GC while dispatching addon resources
|
||||
h.dispatcher = dispatch.NewAppManifestsDispatcher(h.r.Client, h.currentAppRev).StartAndSkipGC(h.latestTracker)
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyAppManifests will dispatch Application manifests
|
||||
func (h *AppHandler) ApplyAppManifests(ctx context.Context, comps []*types.ComponentManifest, policies []*unstructured.Unstructured) error {
|
||||
appRev := h.currentAppRev
|
||||
@@ -68,13 +108,10 @@ func (h *AppHandler) ApplyAppManifests(ctx context.Context, comps []*types.Compo
|
||||
latestTracker = &v1beta1.ResourceTracker{}
|
||||
latestTracker.SetName(dispatch.ConstructResourceTrackerName(h.app.Status.LatestRevision.Name, h.app.Namespace))
|
||||
}
|
||||
// only do GC when ALL resources are dispatched successfully
|
||||
// so skip GC while dispatching addon resources
|
||||
d := dispatch.NewAppManifestsDispatcher(h.r.Client, appRev).StartAndSkipGC(latestTracker)
|
||||
// dispatch packaged workload resources before dispatching assembled manifests
|
||||
for _, comp := range comps {
|
||||
if len(comp.PackagedWorkloadResources) != 0 {
|
||||
if _, err := d.Dispatch(ctx, comp.PackagedWorkloadResources); err != nil {
|
||||
if err := h.Dispatch(ctx, comp.PackagedWorkloadResources...); err != nil {
|
||||
return errors.WithMessage(err, "cannot dispatch packaged workload resources")
|
||||
}
|
||||
}
|
||||
@@ -82,15 +119,13 @@ func (h *AppHandler) ApplyAppManifests(ctx context.Context, comps []*types.Compo
|
||||
continue
|
||||
}
|
||||
}
|
||||
a := assemble.NewAppManifests(appRev).WithWorkloadOption(assemble.DiscoveryHelmBasedWorkload(ctx, h.r.Client))
|
||||
a := assemble.NewAppManifests(h.currentAppRev).WithWorkloadOption(assemble.DiscoveryHelmBasedWorkload(ctx, h.r.Client))
|
||||
manifests, err := a.AssembledManifests()
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "cannot assemble application manifests")
|
||||
}
|
||||
if _, err := d.EndAndGC(latestTracker).Dispatch(ctx, manifests); err != nil {
|
||||
return errors.WithMessage(err, "cannot dispatch application manifests")
|
||||
}
|
||||
return nil
|
||||
_, err = h.DispatchAndGC(ctx, manifests...)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *AppHandler) aggregateHealthStatus(appFile *appfile.Appfile) ([]common.ApplicationComponentStatus, bool, error) {
|
||||
|
||||
@@ -111,7 +111,7 @@ var _ = Describe("Test Workflow", func() {
|
||||
})
|
||||
|
||||
It("should execute workflow step to apply and wait", func() {
|
||||
Expect(k8sClient.Create(ctx, appWithWorkflow)).Should(BeNil())
|
||||
Expect(k8sClient.Create(ctx, appWithWorkflow.DeepCopy())).Should(BeNil())
|
||||
|
||||
// first try to add finalizer
|
||||
tryReconcile(reconciler, appWithWorkflow.Name, appWithWorkflow.Namespace)
|
||||
@@ -146,6 +146,7 @@ var _ = Describe("Test Workflow", func() {
|
||||
triggerWorkflowStepToSucceed(stepObj)
|
||||
Expect(k8sClient.Update(ctx, stepObj)).Should(BeNil())
|
||||
|
||||
tryReconcile(reconciler, appWithWorkflow.Name, appWithWorkflow.Namespace)
|
||||
tryReconcile(reconciler, appWithWorkflow.Name, appWithWorkflow.Namespace)
|
||||
|
||||
// check workflow status is succeeded
|
||||
@@ -155,7 +156,50 @@ var _ = Describe("Test Workflow", func() {
|
||||
}, appObj)).Should(BeNil())
|
||||
|
||||
Expect(appObj.Status.Workflow.Steps[0].Phase).Should(Equal(common.WorkflowStepPhaseSucceeded))
|
||||
Expect(appObj.Status.Workflow.Terminated).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("test workflow suspend", func() {
|
||||
suspendApp := appWithWorkflow.DeepCopy()
|
||||
suspendApp.Name = "test-app-suspend"
|
||||
suspendApp.Spec.Workflow.Steps = []oamcore.WorkflowStep{{
|
||||
Name: "suspend",
|
||||
Type: "suspend",
|
||||
Properties: runtime.RawExtension{Raw: []byte(`{}`)},
|
||||
}}
|
||||
Expect(k8sClient.Create(ctx, suspendApp)).Should(BeNil())
|
||||
|
||||
// first try to add finalizer
|
||||
tryReconcile(reconciler, suspendApp.Name, suspendApp.Namespace)
|
||||
tryReconcile(reconciler, suspendApp.Name, suspendApp.Namespace)
|
||||
|
||||
appObj := &oamcore.Application{}
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Name: suspendApp.Name,
|
||||
Namespace: suspendApp.Namespace,
|
||||
}, appObj)).Should(BeNil())
|
||||
|
||||
Expect(appObj.Status.Workflow.Suspend).Should(BeTrue())
|
||||
Expect(appObj.Status.Phase).Should(BeEquivalentTo(common.ApplicationRunningWorkflow))
|
||||
|
||||
// resume
|
||||
appObj.Status.Workflow.Suspend = false
|
||||
Expect(k8sClient.Status().Patch(ctx, appObj, client.Merge)).Should(BeNil())
|
||||
|
||||
tryReconcile(reconciler, suspendApp.Name, suspendApp.Namespace)
|
||||
tryReconcile(reconciler, suspendApp.Name, suspendApp.Namespace)
|
||||
|
||||
appObj = &oamcore.Application{}
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Name: suspendApp.Name,
|
||||
Namespace: suspendApp.Namespace,
|
||||
}, appObj)).Should(BeNil())
|
||||
|
||||
Expect(appObj.Status.Workflow.Suspend).Should(BeFalse())
|
||||
Expect(appObj.Status.Workflow.Terminated).Should(BeTrue())
|
||||
Expect(appObj.Status.Workflow.StepIndex).Should(BeEquivalentTo(1))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
func triggerWorkflowStepToSucceed(obj *unstructured.Unstructured) {
|
||||
|
||||
Reference in New Issue
Block a user