mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
add abandoning state to the rollout (#1290)
* add abandoning state * fine tunee2e timing and improve logging * add back one application UT and fine tune timing in e2e and improve test robustness
This commit is contained in:
@@ -34,22 +34,24 @@ const (
|
||||
type RollingState string
|
||||
|
||||
const (
|
||||
// VerifyingSpecState verify that the rollout setting is valid and the controller can locate both the
|
||||
// target and the source
|
||||
// VerifyingSpecState indicates that the rollout is in the stage of verifying the rollout settings
|
||||
// and the controller can locate both the target and the source
|
||||
VerifyingSpecState RollingState = "verifyingSpec"
|
||||
// InitializingState rollout is initializing all the new resources
|
||||
// InitializingState indicates that the rollout is initializing all the new resources
|
||||
InitializingState RollingState = "initializing"
|
||||
// RollingInBatchesState rolling out
|
||||
// RollingInBatchesState indicates that the rollout starts rolling
|
||||
RollingInBatchesState RollingState = "rollingInBatches"
|
||||
// FinalisingState finalize the rolling, possibly clean up the old resources, adjust traffic
|
||||
// FinalisingState indicates that the rollout is finalizing, possibly clean up the old resources, adjust traffic
|
||||
FinalisingState RollingState = "finalising"
|
||||
// RolloutSucceedState rollout successfully completed to match the desired target state
|
||||
RolloutSucceedState RollingState = "rolloutSucceed"
|
||||
// RolloutFailingState finalize the rollout before giving up, possibly clean up the old resources, adjust traffic
|
||||
// RolloutFailingState indicates that the rollout is failing
|
||||
// one needs to finalize it before mark it as failed by cleaning up the old resources, adjust traffic
|
||||
RolloutFailingState RollingState = "rolloutFailing"
|
||||
// RolloutFailedState rollout is failed, the target replica is not reached
|
||||
// we can not move forward anymore
|
||||
// we will let the client to decide when or whether to revert
|
||||
// RolloutSucceedState indicates that rollout successfully completed to match the desired target state
|
||||
RolloutSucceedState RollingState = "rolloutSucceed"
|
||||
// RolloutAbandoningState indicates that the rollout is abandoned, can be restarted. This is a terminal state
|
||||
RolloutAbandoningState RollingState = "rolloutAbandoned"
|
||||
// RolloutFailedState indicates that rollout is failed, the target replica is not reached
|
||||
// we can not move forward anymore, we will let the client to decide when or whether to revert.
|
||||
RolloutFailedState RollingState = "rolloutFailed"
|
||||
)
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ const (
|
||||
// RollingRetriableFailureEvent indicates that we encountered an unexpected but retriable error
|
||||
RollingRetriableFailureEvent RolloutEvent = "RollingRetriableFailureEvent"
|
||||
|
||||
// RollingModifiedEvent indicates that the rolling target or source has changed
|
||||
RollingModifiedEvent RolloutEvent = "RollingModifiedEvent"
|
||||
|
||||
// RollingSpecVerifiedEvent indicates that we have successfully verified that the rollout spec
|
||||
RollingSpecVerifiedEvent RolloutEvent = "RollingSpecVerifiedEvent"
|
||||
|
||||
@@ -65,6 +68,8 @@ const (
|
||||
RolloutFinalizing runtimev1alpha1.ConditionType = "RolloutFinalizing"
|
||||
// RolloutFailing means the rollout is failing
|
||||
RolloutFailing runtimev1alpha1.ConditionType = "RolloutFailing"
|
||||
// RolloutAbandoning means that the rollout is being abandoned.
|
||||
RolloutAbandoning runtimev1alpha1.ConditionType = "RolloutAbandoning"
|
||||
// RolloutFailed means that the rollout failed.
|
||||
RolloutFailed runtimev1alpha1.ConditionType = "RolloutFailed"
|
||||
// RolloutSucceed means that the rollout is done.
|
||||
@@ -142,6 +147,9 @@ func (r *RolloutStatus) getRolloutConditionType() runtimev1alpha1.ConditionType
|
||||
case RolloutFailingState:
|
||||
return RolloutFailing
|
||||
|
||||
case RolloutAbandoningState:
|
||||
return RolloutAbandoning
|
||||
|
||||
case RolloutFailedState:
|
||||
return RolloutFailed
|
||||
|
||||
@@ -159,12 +167,6 @@ func (r *RolloutStatus) RolloutRetry(reason string) {
|
||||
r.SetConditions(NewNegativeCondition(r.getRolloutConditionType(), reason))
|
||||
}
|
||||
|
||||
// RolloutModified is special state transition as we allow it to happen at any time
|
||||
func (r *RolloutStatus) RolloutModified() {
|
||||
r.SetRolloutCondition(NewNegativeCondition(r.getRolloutConditionType(), "Rollout Spec is modified"))
|
||||
r.ResetStatus()
|
||||
}
|
||||
|
||||
// RolloutFailed is a special state transition since we need an error message
|
||||
func (r *RolloutStatus) RolloutFailed(reason string) {
|
||||
// set the condition first which depends on the state
|
||||
@@ -233,10 +235,20 @@ func (r *RolloutStatus) StateTransition(event RolloutEvent) {
|
||||
"post batch rolling state", r.BatchRollingState)
|
||||
}()
|
||||
|
||||
// we have special transition for these two types of event
|
||||
// we have special transition for these types of event since they require additional info
|
||||
if event == RollingFailedEvent || event == RollingRetriableFailureEvent {
|
||||
panic(fmt.Errorf(invalidRollingStateTransition, rollingState, event))
|
||||
}
|
||||
// special handle modified event here
|
||||
if event == RollingModifiedEvent {
|
||||
if r.RollingState == RolloutFailedState || r.RollingState == RolloutSucceedState {
|
||||
r.ResetStatus()
|
||||
} else {
|
||||
r.SetRolloutCondition(NewNegativeCondition(r.getRolloutConditionType(), "Rollout Spec is modified"))
|
||||
r.RollingState = RolloutAbandoningState
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch rollingState {
|
||||
case VerifyingSpecState:
|
||||
@@ -260,6 +272,14 @@ func (r *RolloutStatus) StateTransition(event RolloutEvent) {
|
||||
r.batchStateTransition(event)
|
||||
return
|
||||
|
||||
case RolloutAbandoningState:
|
||||
if event == RollingFinalizedEvent {
|
||||
r.SetRolloutCondition(NewPositiveCondition(r.getRolloutConditionType()))
|
||||
r.ResetStatus()
|
||||
return
|
||||
}
|
||||
panic(fmt.Errorf(invalidRollingStateTransition, rollingState, event))
|
||||
|
||||
case FinalisingState:
|
||||
if event == RollingFinalizedEvent {
|
||||
r.SetRolloutCondition(NewPositiveCondition(r.getRolloutConditionType()))
|
||||
|
||||
@@ -63,7 +63,7 @@ func NewRolloutPlanController(client client.Client, parentController oam.Object,
|
||||
|
||||
// Reconcile reconciles a rollout plan
|
||||
func (r *Controller) Reconcile(ctx context.Context) (res reconcile.Result, status *v1alpha1.RolloutStatus) {
|
||||
klog.InfoS("Reconcile the rollout plan", "rollout Spec", r.rolloutSpec,
|
||||
klog.InfoS("Reconcile the rollout plan", "rollout status", r.rolloutStatus,
|
||||
"target workload", klog.KObj(r.targetWorkload))
|
||||
if r.sourceWorkload != nil {
|
||||
klog.InfoS("We will do rolling upgrades", "source workload", klog.KObj(r.sourceWorkload))
|
||||
@@ -122,7 +122,7 @@ func (r *Controller) Reconcile(ctx context.Context) (res reconcile.Result, statu
|
||||
case v1alpha1.RollingInBatchesState:
|
||||
r.reconcileBatchInRolling(ctx, workloadController)
|
||||
|
||||
case v1alpha1.RolloutFailingState:
|
||||
case v1alpha1.RolloutFailingState, v1alpha1.RolloutAbandoningState:
|
||||
if succeed := workloadController.Finalize(ctx, false); succeed {
|
||||
r.finalizeRollout(ctx)
|
||||
}
|
||||
|
||||
@@ -165,21 +165,21 @@ func (c *CloneSetController) CheckOneBatchPods(ctx context.Context) (bool, error
|
||||
if currentBatch.MaxUnavailable != nil {
|
||||
unavail, _ = intstr.GetValueFromIntOrPercent(currentBatch.MaxUnavailable, int(cloneSetSize), true)
|
||||
}
|
||||
klog.InfoS("checking the rolling out progress", "current batch", currentBatch,
|
||||
klog.InfoS("checking the rolling out progress", "current batch", c.rolloutStatus.CurrentBatch,
|
||||
"new pod count target", newPodTarget, "new ready pod count", readyPodCount,
|
||||
"max unavailable pod allowed", unavail)
|
||||
c.rolloutStatus.UpgradedReadyReplicas = int32(readyPodCount)
|
||||
// we could overshoot in the revert case when many pods are already upgraded
|
||||
if unavail+readyPodCount >= newPodTarget {
|
||||
// record the successful upgrade
|
||||
klog.InfoS("all pods in current batch are ready", "current batch", currentBatch)
|
||||
klog.InfoS("all pods in current batch are ready", "current batch", c.rolloutStatus.CurrentBatch)
|
||||
c.recorder.Event(c.parentController, event.Normal("Batch Available",
|
||||
fmt.Sprintf("Batch %d is available", c.rolloutStatus.CurrentBatch)))
|
||||
c.rolloutStatus.LastAppliedPodTemplateIdentifier = c.rolloutStatus.NewPodTemplateIdentifier
|
||||
return true, nil
|
||||
}
|
||||
// continue to verify
|
||||
klog.InfoS("the batch is not ready yet", "current batch", currentBatch)
|
||||
klog.InfoS("the batch is not ready yet", "current batch", c.rolloutStatus.CurrentBatch)
|
||||
c.rolloutStatus.RolloutRetry("the batch is not ready yet")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -115,8 +115,8 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
||||
oamutil.PassLabelAndAnnotation(app, ac)
|
||||
|
||||
app.Status.SetConditions(readyCondition("Built"))
|
||||
applog.Info("apply appConfig & component to the cluster")
|
||||
// apply appConfig & component to the cluster
|
||||
applog.Info("apply application revision & component to the cluster")
|
||||
// apply application revision & component to the cluster
|
||||
if err := handler.apply(ctx, ac, comps); err != nil {
|
||||
applog.Error(err, "[Handle apply]")
|
||||
app.Status.SetConditions(errorCondition("Applied", err))
|
||||
|
||||
@@ -891,8 +891,7 @@ var _ = Describe("Test Application Controller", func() {
|
||||
Expect(k8sClient.Delete(ctx, app)).Should(BeNil())
|
||||
})
|
||||
|
||||
// Fix rollout related test in next PR
|
||||
PIt("app generate appConfigs with annotation", func() {
|
||||
It("app with rollout annotation", func() {
|
||||
By("create application with rolling out annotation")
|
||||
ns := &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -916,26 +915,23 @@ var _ = Describe("Test Application Controller", func() {
|
||||
}
|
||||
reconcileRetry(reconciler, reconcile.Request{NamespacedName: appKey})
|
||||
|
||||
By("Check Application Created with the correct revision")
|
||||
curApp := &v1beta1.Application{}
|
||||
Expect(k8sClient.Get(ctx, appKey, curApp)).Should(BeNil())
|
||||
Expect(curApp.Status.Phase).Should(Equal(common.ApplicationRunning))
|
||||
Expect(curApp.Status.LatestRevision).ShouldNot(BeNil())
|
||||
Expect(curApp.Status.LatestRevision.Revision).Should(BeEquivalentTo(1))
|
||||
|
||||
By("Check AppRevision created as expected")
|
||||
Expect(k8sClient.Get(ctx, appKey, rolloutApp)).Should(Succeed())
|
||||
appRevision := &v1beta1.ApplicationRevision{}
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: rolloutApp.Namespace,
|
||||
Name: curApp.Status.LatestRevision.Name,
|
||||
Name: utils.ConstructRevisionName(rolloutApp.Name, 1),
|
||||
}, appRevision)).Should(BeNil())
|
||||
|
||||
By("Check ApplicationContext not created")
|
||||
appContext := &v1alpha2.ApplicationContext{}
|
||||
// no appContext same name as app exist
|
||||
Expect(k8sClient.Get(ctx, appKey, appContext)).ShouldNot(Succeed())
|
||||
// no appContext same name as apprevision exist
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: rolloutApp.Namespace,
|
||||
Name: utils.ConstructRevisionName(rolloutApp.Name, 1),
|
||||
}, appContext)).Should(HaveOccurred())
|
||||
}, appContext)).ShouldNot(Succeed())
|
||||
|
||||
By("Check Component Created with the expected workload spec")
|
||||
var component v1alpha2.Component
|
||||
@@ -945,27 +941,29 @@ var _ = Describe("Test Application Controller", func() {
|
||||
}, &component)).Should(BeNil())
|
||||
Expect(component.Status.LatestRevision).ShouldNot(BeNil())
|
||||
Expect(component.Status.LatestRevision.Revision).Should(BeEquivalentTo(1))
|
||||
// check that the new appconfig has the correct annotation and labels
|
||||
// check that the appconfig has the correct annotation and labels
|
||||
ac, err := util.RawExtension2AppConfig(appRevision.Spec.ApplicationConfiguration)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(ac.GetAnnotations()[oam.AnnotationAppRollout]).Should(Equal(strconv.FormatBool(true)))
|
||||
Expect(ac.GetAnnotations()["keep"]).Should(Equal("true"))
|
||||
Expect(ac.GetLabels()[oam.LabelAppRevisionHash]).ShouldNot(BeEmpty())
|
||||
Expect(ac.Spec.Components[0].ComponentName).Should(BeEmpty())
|
||||
Expect(ac.Spec.Components[0].RevisionName).Should(Equal(component.Status.LatestRevision.Name))
|
||||
|
||||
By("Reconcile again to make sure we are not creating more appConfigs")
|
||||
reconcileRetry(reconciler, reconcile.Request{NamespacedName: appKey})
|
||||
Expect(k8sClient.Get(ctx, appKey, curApp)).Should(BeNil())
|
||||
Expect(curApp.Status.Phase).Should(Equal(common.ApplicationRunning))
|
||||
Expect(curApp.Status.LatestRevision).ShouldNot(BeNil())
|
||||
Expect(curApp.Status.LatestRevision.Revision).Should(BeEquivalentTo(1))
|
||||
|
||||
By("Check no new ApplicationConfiguration created")
|
||||
By("Verify that no new AppRevision created")
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: rolloutApp.Namespace,
|
||||
Name: utils.ConstructRevisionName(rolloutApp.Name, 2),
|
||||
}, appRevision)).ShouldNot(Succeed())
|
||||
// no appContext same name as app exist
|
||||
Expect(k8sClient.Get(ctx, appKey, appContext)).ShouldNot(Succeed())
|
||||
// no appContext same name as apprevision exist
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: rolloutApp.Namespace,
|
||||
Name: utils.ConstructRevisionName(rolloutApp.Name, 1),
|
||||
}, appContext)).Should(HaveOccurred())
|
||||
}, appContext)).ShouldNot(Succeed())
|
||||
|
||||
By("Check no new Component created")
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: rolloutApp.Namespace,
|
||||
@@ -975,20 +973,26 @@ var _ = Describe("Test Application Controller", func() {
|
||||
Expect(component.Status.LatestRevision.Revision).ShouldNot(BeNil())
|
||||
Expect(component.Status.LatestRevision.Revision).Should(BeEquivalentTo(1))
|
||||
|
||||
By("Remove rollout annotation which should not trigger any change")
|
||||
By("Remove rollout annotation should lead to new appContext created")
|
||||
Expect(k8sClient.Get(ctx, appKey, rolloutApp)).Should(Succeed())
|
||||
rolloutApp.SetAnnotations(map[string]string{
|
||||
"keep": "true",
|
||||
})
|
||||
Expect(k8sClient.Update(ctx, rolloutApp)).Should(BeNil())
|
||||
reconcileRetry(reconciler, reconcile.Request{NamespacedName: appKey})
|
||||
Expect(k8sClient.Get(ctx, appKey, curApp)).Should(BeNil())
|
||||
Expect(curApp.Status.Phase).Should(Equal(common.ApplicationRunning))
|
||||
Expect(curApp.Status.LatestRevision).ShouldNot(BeNil())
|
||||
Expect(curApp.Status.LatestRevision.Revision).Should(BeEquivalentTo(1))
|
||||
// check v2 is not created
|
||||
// app should create an appContext
|
||||
Expect(k8sClient.Get(ctx, appKey, appContext)).Should(Succeed())
|
||||
Expect(appContext.Spec.ApplicationRevisionName).Should(Equal(utils.ConstructRevisionName(rolloutApp.Name, 1)))
|
||||
By("Verify that no new AppRevision created")
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: rolloutApp.Namespace,
|
||||
Name: utils.ConstructRevisionName(rolloutApp.Name, 2),
|
||||
}, appContext)).Should(HaveOccurred())
|
||||
}, appRevision)).ShouldNot(Succeed())
|
||||
// no appContext same name as apprevision exist
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: rolloutApp.Namespace,
|
||||
Name: utils.ConstructRevisionName(rolloutApp.Name, 1),
|
||||
}, appContext)).ShouldNot(Succeed())
|
||||
By("Delete Application, clean the resource")
|
||||
Expect(k8sClient.Delete(ctx, rolloutApp)).Should(BeNil())
|
||||
})
|
||||
|
||||
@@ -40,7 +40,7 @@ var _ = Describe("test generate revision ", func() {
|
||||
ctx := context.Background()
|
||||
|
||||
BeforeEach(func() {
|
||||
namespaceName = "apply-test-" + strconv.Itoa(rand.Intn(1000))
|
||||
namespaceName = "apply-test-" + strconv.FormatInt(rand.Int63n(10000000), 16)
|
||||
ns = corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespaceName,
|
||||
|
||||
@@ -41,7 +41,6 @@ import (
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
core "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
|
||||
@@ -91,12 +90,6 @@ func Setup(mgr ctrl.Manager, args core.Args, l logging.Logger) error {
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
Named(name).
|
||||
For(&v1alpha2.ApplicationConfiguration{}).
|
||||
Watches(&source.Kind{Type: &v1alpha2.Component{}}, &ComponentHandler{
|
||||
Client: mgr.GetClient(),
|
||||
Logger: l,
|
||||
RevisionLimit: args.RevisionLimit,
|
||||
CustomRevisionHookURL: args.CustomRevisionHookURL,
|
||||
}).
|
||||
Complete(NewReconciler(mgr, args.DiscoveryMapper,
|
||||
l.WithValues("controller", name),
|
||||
WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))),
|
||||
|
||||
@@ -80,8 +80,7 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res reconcile.Result, retErr e
|
||||
r.handleFinalizer(&appRollout)
|
||||
targetAppRevisionName := appRollout.Spec.TargetAppRevisionName
|
||||
sourceAppRevisionName := appRollout.Spec.SourceAppRevisionName
|
||||
|
||||
// handle rollout target/source change
|
||||
// handle rollout completed
|
||||
if appRollout.Status.RollingState == v1alpha1.RolloutSucceedState ||
|
||||
appRollout.Status.RollingState == v1alpha1.RolloutFailedState {
|
||||
if appRollout.Status.LastUpgradedTargetAppRevision == targetAppRevisionName &&
|
||||
@@ -91,7 +90,7 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res reconcile.Result, retErr e
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// handle rollout target/source change
|
||||
if appRollout.Status.LastUpgradedTargetAppRevision != "" &&
|
||||
appRollout.Status.LastUpgradedTargetAppRevision != targetAppRevisionName ||
|
||||
(appRollout.Status.LastSourceAppRevision != "" && appRollout.Status.LastSourceAppRevision != sourceAppRevisionName) {
|
||||
@@ -100,13 +99,16 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res reconcile.Result, retErr e
|
||||
r.record.Event(&appRollout, event.Normal("Rollout Restarted",
|
||||
"rollout target changed, restart the rollout", "new source", sourceAppRevisionName,
|
||||
"new target", targetAppRevisionName))
|
||||
|
||||
if err := r.finalizeRollingAborted(ctx, appRollout.Status.LastUpgradedTargetAppRevision,
|
||||
appRollout.Status.LastSourceAppRevision); err != nil {
|
||||
klog.ErrorS(err, "failed to finalize the previous rolling resources ", "old source",
|
||||
appRollout.Status.LastSourceAppRevision, "old target", appRollout.Status.LastUpgradedTargetAppRevision)
|
||||
// we are okay to move directly to restart the rollout since we are at the terminal state
|
||||
// however, we need to make sure we properly finalizing the existing rollout before restart if it's
|
||||
// still in the middle of rolling out
|
||||
if appRollout.Status.RollingState != v1alpha1.RolloutSucceedState &&
|
||||
appRollout.Status.RollingState != v1alpha1.RolloutFailedState {
|
||||
// continue to handle the previous resources until we are okay to move forward
|
||||
targetAppRevisionName = appRollout.Status.LastUpgradedTargetAppRevision
|
||||
sourceAppRevisionName = appRollout.Status.LastSourceAppRevision
|
||||
}
|
||||
appRollout.Status.RolloutModified()
|
||||
appRollout.Status.StateTransition(v1alpha1.RollingModifiedEvent)
|
||||
}
|
||||
|
||||
// Get the source application
|
||||
@@ -162,8 +164,11 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res reconcile.Result, retErr e
|
||||
result, rolloutStatus := rolloutPlanController.Reconcile(ctx)
|
||||
// make sure that the new status is copied back
|
||||
appRollout.Status.RolloutStatus = *rolloutStatus
|
||||
appRollout.Status.LastUpgradedTargetAppRevision = targetAppRevisionName
|
||||
appRollout.Status.LastSourceAppRevision = sourceAppRevisionName
|
||||
// do not update the last with new revision if we are still trying to abandon the previous rollout
|
||||
if rolloutStatus.RollingState != v1alpha1.RolloutAbandoningState {
|
||||
appRollout.Status.LastUpgradedTargetAppRevision = appRollout.Spec.TargetAppRevisionName
|
||||
appRollout.Status.LastSourceAppRevision = appRollout.Spec.SourceAppRevisionName
|
||||
}
|
||||
if rolloutStatus.RollingState == v1alpha1.RolloutSucceedState {
|
||||
if err = r.finalizeRollingSucceeded(ctx, sourceApp, targetApp); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
@@ -197,11 +202,6 @@ func (r *Reconciler) finalizeRollingSucceeded(ctx context.Context, sourceApp *oa
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reconciler) finalizeRollingAborted(ctx context.Context, sourceRevision, targetRevision string) error {
|
||||
// TODO: finalize the previous appcontext the best we can
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateStatus updates v1alpha2.AppRollout's Status with retry.RetryOnConflict
|
||||
func (r *Reconciler) updateStatus(ctx context.Context, appRollout *v1beta1.AppRollout, opts ...client.UpdateOption) error {
|
||||
status := appRollout.DeepCopy().Status
|
||||
|
||||
@@ -19,14 +19,14 @@ func DefaultRolloutPlan(rollout *v1alpha1.RolloutPlan) {
|
||||
totalSize := int(*rollout.TargetSize)
|
||||
// create the batch array
|
||||
rollout.RolloutBatches = make([]v1alpha1.RolloutBatch, int(*rollout.NumBatches))
|
||||
avg := intstr.FromInt(totalSize / numBatches)
|
||||
total := 0
|
||||
for i := 0; i < numBatches-1; i++ {
|
||||
rollout.RolloutBatches[i].Replicas = avg
|
||||
total += avg.IntValue()
|
||||
total := totalSize
|
||||
for total > 0 {
|
||||
for i := numBatches - 1; i >= 0 && total > 0; i-- {
|
||||
replica := rollout.RolloutBatches[i].Replicas.IntValue() + 1
|
||||
rollout.RolloutBatches[i].Replicas = intstr.FromInt(replica)
|
||||
total--
|
||||
}
|
||||
}
|
||||
// fill out the last batch
|
||||
rollout.RolloutBatches[numBatches-1].Replicas = intstr.FromInt(totalSize - total)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
99
pkg/webhook/common/rollout/rollout_plan_test.go
Normal file
99
pkg/webhook/common/rollout/rollout_plan_test.go
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright 2021 KubeVela Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package rollout
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/utils/pointer"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
|
||||
)
|
||||
|
||||
func TestDefaultRolloutPlan_EvenlyDivid(t *testing.T) {
|
||||
var numBatch int32 = 5
|
||||
rollout := &v1alpha1.RolloutPlan{
|
||||
TargetSize: &numBatch,
|
||||
NumBatches: &numBatch,
|
||||
}
|
||||
DefaultRolloutPlan(rollout)
|
||||
|
||||
if len(rollout.RolloutBatches) != int(numBatch) {
|
||||
t.Errorf("number of batch %d does not equal to %d ", len(rollout.RolloutBatches), numBatch)
|
||||
}
|
||||
for i, batch := range rollout.RolloutBatches {
|
||||
if batch.Replicas.IntVal != int32(1) {
|
||||
t.Errorf("batch %d replica does not equal to 1", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultRolloutPlan_HasRemanence(t *testing.T) {
|
||||
var numBatch int32 = 5
|
||||
rollout := &v1alpha1.RolloutPlan{
|
||||
TargetSize: pointer.Int32Ptr(8),
|
||||
NumBatches: &numBatch,
|
||||
}
|
||||
DefaultRolloutPlan(rollout)
|
||||
|
||||
if len(rollout.RolloutBatches) != int(numBatch) {
|
||||
t.Errorf("number of batch %d does not equal to %d ", len(rollout.RolloutBatches), numBatch)
|
||||
}
|
||||
if rollout.RolloutBatches[0].Replicas.IntValue() != 1 {
|
||||
t.Errorf("batch 0's replica %d does not equal to 1", rollout.RolloutBatches[0].Replicas.IntValue())
|
||||
}
|
||||
if rollout.RolloutBatches[1].Replicas.IntValue() != 1 {
|
||||
t.Errorf("batch 1's replica %d does not equal to 1", rollout.RolloutBatches[1].Replicas.IntValue())
|
||||
}
|
||||
if rollout.RolloutBatches[2].Replicas.IntValue() != 2 {
|
||||
t.Errorf("batch 2's replica %d does not equal to 2", rollout.RolloutBatches[2].Replicas.IntValue())
|
||||
}
|
||||
if rollout.RolloutBatches[3].Replicas.IntValue() != 2 {
|
||||
t.Errorf("batch 3's replica %d does not equal to 2", rollout.RolloutBatches[3].Replicas.IntValue())
|
||||
}
|
||||
if rollout.RolloutBatches[4].Replicas.IntValue() != 2 {
|
||||
t.Errorf("batch 4's replica %d does not equal to 2", rollout.RolloutBatches[4].Replicas.IntValue())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultRolloutPlan_NotEnough(t *testing.T) {
|
||||
var numBatch int32 = 5
|
||||
rollout := &v1alpha1.RolloutPlan{
|
||||
TargetSize: pointer.Int32Ptr(4),
|
||||
NumBatches: &numBatch,
|
||||
}
|
||||
DefaultRolloutPlan(rollout)
|
||||
|
||||
if len(rollout.RolloutBatches) != int(numBatch) {
|
||||
t.Errorf("number of batch %d does not equal to %d ", len(rollout.RolloutBatches), numBatch)
|
||||
}
|
||||
if rollout.RolloutBatches[0].Replicas.IntValue() != 0 {
|
||||
t.Errorf("batch 0's replica %d does not equal to 0", rollout.RolloutBatches[0].Replicas.IntValue())
|
||||
}
|
||||
if rollout.RolloutBatches[1].Replicas.IntValue() != 1 {
|
||||
t.Errorf("batch 1's replica %d does not equal to 1", rollout.RolloutBatches[1].Replicas.IntValue())
|
||||
}
|
||||
if rollout.RolloutBatches[2].Replicas.IntValue() != 1 {
|
||||
t.Errorf("batch 2's replica %d does not equal to 1", rollout.RolloutBatches[2].Replicas.IntValue())
|
||||
}
|
||||
if rollout.RolloutBatches[3].Replicas.IntValue() != 1 {
|
||||
t.Errorf("batch 3's replica %d does not equal to 1", rollout.RolloutBatches[3].Replicas.IntValue())
|
||||
}
|
||||
if rollout.RolloutBatches[4].Replicas.IntValue() != 1 {
|
||||
t.Errorf("batch 4's replica %d does not equal to 1", rollout.RolloutBatches[4].Replicas.IntValue())
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,11 @@ package controllers_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
cpv1 "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1"
|
||||
kruise "github.com/openkruise/kruise-api/apps/v1alpha1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -20,10 +16,10 @@ import (
|
||||
|
||||
oamcomm "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
oamstd "github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
@@ -32,10 +28,9 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
ctx := context.Background()
|
||||
var namespace string
|
||||
var ns corev1.Namespace
|
||||
var app v1alpha2.Application
|
||||
var appConfig1, appConfig2 v1alpha2.ApplicationContext
|
||||
var app v1beta1.Application
|
||||
var kc kruise.CloneSet
|
||||
var appRollout v1alpha2.AppRollout
|
||||
var appRollout v1beta1.AppRollout
|
||||
|
||||
createNamespace := func(namespace string) {
|
||||
ns = corev1.Namespace{
|
||||
@@ -68,7 +63,7 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
|
||||
CreateClonesetDef := func() {
|
||||
By("Install CloneSet based componentDefinition")
|
||||
var cd v1alpha2.ComponentDefinition
|
||||
var cd v1beta1.ComponentDefinition
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/clonesetDefinition.yaml", &cd)).Should(BeNil())
|
||||
// create the componentDefinition if not exist
|
||||
Eventually(
|
||||
@@ -78,37 +73,9 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
time.Second*3, time.Millisecond*300).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
}
|
||||
|
||||
VerifyAppConfigTemplated := func(revision int64) {
|
||||
var appConfigName string
|
||||
By("Get Application latest status after AppConfig created")
|
||||
Eventually(
|
||||
func() int64 {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: app.Name}, &app)
|
||||
return app.Status.LatestRevision.Revision
|
||||
},
|
||||
time.Second*30, time.Millisecond*500).Should(BeEquivalentTo(revision))
|
||||
appConfigName = app.Status.LatestRevision.Name
|
||||
By(fmt.Sprintf("Wait for AppConfig %s synced", appConfigName))
|
||||
var appConfig v1alpha2.ApplicationContext
|
||||
Eventually(
|
||||
func() corev1.ConditionStatus {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appConfigName}, &appConfig)
|
||||
return appConfig.Status.GetCondition(cpv1.TypeSynced).Status
|
||||
},
|
||||
time.Second*30, time.Millisecond*500).Should(BeEquivalentTo(corev1.ConditionTrue))
|
||||
|
||||
By(fmt.Sprintf("Wait for AppConfig %s to be templated", appConfigName))
|
||||
Eventually(
|
||||
func() types.RollingStatus {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appConfigName}, &appConfig)
|
||||
return appConfig.Status.RollingStatus
|
||||
},
|
||||
time.Second*60, time.Millisecond*500).Should(BeEquivalentTo(types.RollingTemplated))
|
||||
}
|
||||
|
||||
ApplySourceApp := func() {
|
||||
applySourceApp := func() {
|
||||
By("Apply an application")
|
||||
var newApp v1alpha2.Application
|
||||
var newApp v1beta1.Application
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/app-source.yaml", &newApp)).Should(BeNil())
|
||||
newApp.Namespace = namespace
|
||||
Expect(k8sClient.Create(ctx, &newApp)).Should(Succeed())
|
||||
@@ -125,23 +92,9 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
time.Second*30, time.Millisecond*500).ShouldNot(BeNil())
|
||||
}
|
||||
|
||||
MarkAppRolling := func(revision int64) {
|
||||
By("Mark the application as rolling")
|
||||
Eventually(
|
||||
func() error {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: app.Name}, &app)
|
||||
app.SetAnnotations(util.MergeMapOverrideWithDst(app.GetAnnotations(),
|
||||
map[string]string{oam.AnnotationRollingComponent: app.Spec.Components[0].Name,
|
||||
oam.AnnotationAppRollout: strconv.FormatBool(true)}))
|
||||
return k8sClient.Update(ctx, &app)
|
||||
}, time.Second*5, time.Millisecond*500).Should(Succeed())
|
||||
|
||||
VerifyAppConfigTemplated(revision)
|
||||
}
|
||||
|
||||
ApplyTargetApp := func() {
|
||||
applyTargetApp := func() {
|
||||
By("Update the application to target spec during rolling")
|
||||
var targetApp v1alpha2.Application
|
||||
var targetApp v1beta1.Application
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/app-target.yaml", &targetApp)).Should(BeNil())
|
||||
|
||||
Eventually(
|
||||
@@ -152,7 +105,15 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
}, time.Second*5, time.Millisecond*500).Should(Succeed())
|
||||
}
|
||||
|
||||
VerifyRolloutOwnsCloneset := func() {
|
||||
createAppRolling := func(newAppRollout *v1beta1.AppRollout) {
|
||||
By("Mark the application as rolling")
|
||||
Eventually(
|
||||
func() error {
|
||||
return k8sClient.Create(ctx, newAppRollout)
|
||||
}, time.Second*5, time.Millisecond).Should(Succeed())
|
||||
}
|
||||
|
||||
verifyRolloutOwnsCloneset := func() {
|
||||
By("Verify that rollout controller owns the cloneset")
|
||||
clonesetName := appRollout.Spec.ComponentList[0]
|
||||
Eventually(
|
||||
@@ -163,12 +124,12 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
return ""
|
||||
}
|
||||
return clonesetOwner.Kind
|
||||
}, time.Second*10, time.Second).Should(BeEquivalentTo(v1alpha2.AppRolloutKind))
|
||||
}, time.Second*10, time.Second).Should(BeEquivalentTo(v1beta1.AppRolloutKind))
|
||||
clonesetOwner := metav1.GetControllerOf(&kc)
|
||||
Expect(clonesetOwner.APIVersion).Should(BeEquivalentTo(v1alpha2.SchemeGroupVersion.String()))
|
||||
Expect(clonesetOwner.APIVersion).Should(BeEquivalentTo(v1beta1.SchemeGroupVersion.String()))
|
||||
}
|
||||
|
||||
VerifyRolloutSucceeded := func(targetAppName string) {
|
||||
verifyRolloutSucceeded := func(targetAppName string) {
|
||||
By("Wait for the rollout phase change to succeed")
|
||||
Eventually(
|
||||
func() oamstd.RollingState {
|
||||
@@ -210,7 +171,7 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
Expect(kc.Status.UpdatedReadyReplicas).Should(BeEquivalentTo(*kc.Spec.Replicas))
|
||||
}
|
||||
|
||||
VerifyAppConfigInactive := func(appConfigName string) {
|
||||
verifyAppConfigInactive := func(appConfigName string) {
|
||||
var appConfig v1alpha2.ApplicationContext
|
||||
By("Verify AppConfig is inactive")
|
||||
Eventually(
|
||||
@@ -221,15 +182,15 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
time.Second*30, time.Millisecond*500).Should(BeEquivalentTo(types.InactiveAfterRollingCompleted))
|
||||
}
|
||||
|
||||
ApplyTwoAppVersion := func() {
|
||||
applyTwoAppVersion := func() {
|
||||
CreateClonesetDef()
|
||||
ApplySourceApp()
|
||||
ApplyTargetApp()
|
||||
applySourceApp()
|
||||
applyTargetApp()
|
||||
}
|
||||
|
||||
RevertBackToSource := func() {
|
||||
revertBackToSource := func() {
|
||||
By("Revert the application back to source")
|
||||
var sourceApp v1alpha2.Application
|
||||
var sourceApp v1beta1.Application
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/app-source.yaml", &sourceApp)).Should(BeNil())
|
||||
|
||||
Eventually(
|
||||
@@ -251,7 +212,6 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
},
|
||||
time.Second*5, time.Millisecond*500).Should(Succeed())
|
||||
|
||||
By("Verify AppConfig rolling status")
|
||||
By("Wait for the rollout phase change to rolling in batches")
|
||||
Eventually(
|
||||
func() oamstd.RollingState {
|
||||
@@ -260,9 +220,9 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
},
|
||||
time.Second*10, time.Millisecond*10).Should(BeEquivalentTo(oamstd.RollingInBatchesState))
|
||||
|
||||
VerifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
verifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
|
||||
VerifyAppConfigInactive(appRollout.Spec.SourceAppRevisionName)
|
||||
verifyAppConfigInactive(appRollout.Spec.SourceAppRevisionName)
|
||||
|
||||
// Clean up
|
||||
k8sClient.Delete(ctx, &appRollout)
|
||||
@@ -276,8 +236,6 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
|
||||
AfterEach(func() {
|
||||
By("Clean up resources after a test")
|
||||
k8sClient.Delete(ctx, &appConfig2)
|
||||
k8sClient.Delete(ctx, &appConfig1)
|
||||
k8sClient.Delete(ctx, &app)
|
||||
By(fmt.Sprintf("Delete the entire namespace %s", ns.Name))
|
||||
// delete the namespace with all its resources
|
||||
@@ -287,32 +245,32 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
|
||||
It("Test cloneset rollout first time (no source)", func() {
|
||||
CreateClonesetDef()
|
||||
ApplySourceApp()
|
||||
applySourceApp()
|
||||
By("Apply the application rollout go directly to the target")
|
||||
var newAppRollout v1alpha2.AppRollout
|
||||
var newAppRollout v1beta1.AppRollout
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/app-rollout.yaml", &newAppRollout)).Should(BeNil())
|
||||
newAppRollout.Namespace = namespace
|
||||
newAppRollout.Spec.SourceAppRevisionName = ""
|
||||
newAppRollout.Spec.TargetAppRevisionName = utils.ConstructRevisionName(app.GetName(), 1)
|
||||
Expect(k8sClient.Create(ctx, &newAppRollout)).Should(Succeed())
|
||||
createAppRolling(&newAppRollout)
|
||||
appRollout.Name = newAppRollout.Name
|
||||
VerifyRolloutSucceeded(newAppRollout.Spec.TargetAppRevisionName)
|
||||
verifyRolloutSucceeded(newAppRollout.Spec.TargetAppRevisionName)
|
||||
// Clean up
|
||||
k8sClient.Delete(ctx, &appRollout)
|
||||
})
|
||||
|
||||
It("Test cloneset rollout with a manual check", func() {
|
||||
ApplyTwoAppVersion()
|
||||
applyTwoAppVersion()
|
||||
|
||||
By("Apply the application rollout to deploy the source")
|
||||
var newAppRollout v1alpha2.AppRollout
|
||||
var newAppRollout v1beta1.AppRollout
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/app-rollout.yaml", &newAppRollout)).Should(BeNil())
|
||||
newAppRollout.Namespace = namespace
|
||||
newAppRollout.Spec.SourceAppRevisionName = ""
|
||||
newAppRollout.Spec.TargetAppRevisionName = utils.ConstructRevisionName(app.GetName(), 1)
|
||||
Expect(k8sClient.Create(ctx, &newAppRollout)).Should(Succeed())
|
||||
createAppRolling(&newAppRollout)
|
||||
appRollout.Name = newAppRollout.Name
|
||||
VerifyRolloutSucceeded(newAppRollout.Spec.TargetAppRevisionName)
|
||||
verifyRolloutSucceeded(newAppRollout.Spec.TargetAppRevisionName)
|
||||
|
||||
By("Apply the application rollout that stops after the first batch")
|
||||
batchPartition := 0
|
||||
@@ -356,24 +314,16 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
Expect(appRollout.Status.BatchRollingState).Should(BeEquivalentTo(oamstd.BatchReadyState))
|
||||
Expect(appRollout.Status.CurrentBatch).Should(BeEquivalentTo(batchPartition))
|
||||
|
||||
VerifyRolloutOwnsCloneset()
|
||||
verifyRolloutOwnsCloneset()
|
||||
|
||||
By("Finish the application rollout")
|
||||
// set the partition as the same size as the array
|
||||
appRollout.Spec.RolloutPlan.BatchPartition = pointer.Int32Ptr(int32(len(appRollout.Spec.RolloutPlan.
|
||||
RolloutBatches) - 1))
|
||||
Expect(k8sClient.Update(ctx, &appRollout)).Should(Succeed())
|
||||
By("Wait for the rollout phase change to rolling in batches")
|
||||
Eventually(
|
||||
func() oamstd.RollingState {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
return appRollout.Status.RollingState
|
||||
},
|
||||
time.Second*10, time.Millisecond*10).Should(BeEquivalentTo(oamstd.RollingInBatchesState))
|
||||
verifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
|
||||
VerifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
|
||||
VerifyAppConfigInactive(appRollout.Spec.SourceAppRevisionName)
|
||||
verifyAppConfigInactive(appRollout.Spec.SourceAppRevisionName)
|
||||
|
||||
// Clean up
|
||||
k8sClient.Delete(ctx, &appRollout)
|
||||
@@ -381,14 +331,19 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
|
||||
It("Test pause and modify rollout plan after rolling succeeded", func() {
|
||||
CreateClonesetDef()
|
||||
ApplySourceApp()
|
||||
applySourceApp()
|
||||
By("Apply the application rollout go directly to the target")
|
||||
var newAppRollout v1alpha2.AppRollout
|
||||
var newAppRollout v1beta1.AppRollout
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/app-rollout.yaml", &newAppRollout)).Should(BeNil())
|
||||
newAppRollout.Namespace = namespace
|
||||
newAppRollout.Spec.SourceAppRevisionName = ""
|
||||
newAppRollout.Spec.TargetAppRevisionName = utils.ConstructRevisionName(app.GetName(), 1)
|
||||
Expect(k8sClient.Create(ctx, &newAppRollout)).Should(Succeed())
|
||||
newAppRollout.Spec.RolloutPlan.BatchPartition = nil
|
||||
newAppRollout.Spec.RolloutPlan.RolloutBatches = nil
|
||||
// webhook would fill the batches
|
||||
newAppRollout.Spec.RolloutPlan.TargetSize = pointer.Int32Ptr(5)
|
||||
newAppRollout.Spec.RolloutPlan.NumBatches = pointer.Int32Ptr(5)
|
||||
createAppRolling(&newAppRollout)
|
||||
|
||||
By("Wait for the rollout phase change to initialize")
|
||||
Eventually(
|
||||
@@ -396,7 +351,7 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: newAppRollout.Name}, &appRollout)
|
||||
return appRollout.Status.RollingState
|
||||
},
|
||||
time.Second*10, time.Millisecond*50).Should(BeEquivalentTo(oamstd.RollingInBatchesState))
|
||||
time.Second*10, time.Millisecond).Should(BeEquivalentTo(oamstd.RollingInBatchesState))
|
||||
|
||||
By("Pause the rollout")
|
||||
Eventually(
|
||||
@@ -428,21 +383,20 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
}
|
||||
Expect((<).Before(&beforeSleep)).Should(BeTrue())
|
||||
|
||||
VerifyRolloutOwnsCloneset()
|
||||
verifyRolloutOwnsCloneset()
|
||||
|
||||
By("Finish the application rollout")
|
||||
// remove the batch restriction
|
||||
appRollout.Spec.RolloutPlan.Paused = false
|
||||
appRollout.Spec.RolloutPlan.BatchPartition = nil
|
||||
Expect(k8sClient.Update(ctx, &appRollout)).Should(Succeed())
|
||||
|
||||
VerifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
verifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
// record the transition time
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
lt = appRollout.Status.GetCondition(oamstd.RolloutSucceed).LastTransitionTime
|
||||
|
||||
// nothing should happen, the transition time should be the same
|
||||
VerifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
verifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
Expect(appRollout.Status.RollingState).Should(BeEquivalentTo(oamstd.RolloutSucceedState))
|
||||
Expect(appRollout.Status.GetCondition(oamstd.RolloutSucceed).LastTransitionTime).Should(BeEquivalentTo(lt))
|
||||
@@ -452,17 +406,54 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
})
|
||||
|
||||
It("Test rolling back after a successful rollout", func() {
|
||||
ApplyTwoAppVersion()
|
||||
applyTwoAppVersion()
|
||||
|
||||
By("Apply the application rollout to deploy the source")
|
||||
var newAppRollout v1alpha2.AppRollout
|
||||
var newAppRollout v1beta1.AppRollout
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/app-rollout.yaml", &newAppRollout)).Should(BeNil())
|
||||
newAppRollout.Namespace = namespace
|
||||
newAppRollout.Spec.SourceAppRevisionName = ""
|
||||
newAppRollout.Spec.TargetAppRevisionName = utils.ConstructRevisionName(app.GetName(), 1)
|
||||
Expect(k8sClient.Create(ctx, &newAppRollout)).Should(Succeed())
|
||||
createAppRolling(&newAppRollout)
|
||||
appRollout.Name = newAppRollout.Name
|
||||
VerifyRolloutSucceeded(newAppRollout.Spec.TargetAppRevisionName)
|
||||
verifyRolloutSucceeded(newAppRollout.Spec.TargetAppRevisionName)
|
||||
|
||||
By("Finish the application rollout")
|
||||
Eventually(
|
||||
func() error {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
appRollout.Spec.SourceAppRevisionName = utils.ConstructRevisionName(app.GetName(), 1)
|
||||
appRollout.Spec.TargetAppRevisionName = utils.ConstructRevisionName(app.GetName(), 2)
|
||||
appRollout.Spec.RolloutPlan.BatchPartition = nil
|
||||
return k8sClient.Update(ctx, &appRollout)
|
||||
}, time.Second*5, time.Millisecond).Should(Succeed())
|
||||
|
||||
By("Wait for the rollout phase change to rolling in batches")
|
||||
Eventually(
|
||||
func() oamstd.RollingState {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
return appRollout.Status.RollingState
|
||||
},
|
||||
time.Second*10, time.Millisecond*10).Should(BeEquivalentTo(oamstd.RollingInBatchesState))
|
||||
|
||||
verifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
verifyAppConfigInactive(appRollout.Spec.SourceAppRevisionName)
|
||||
|
||||
revertBackToSource()
|
||||
})
|
||||
|
||||
It("Test rolling back in the middle of rollout", func() {
|
||||
applyTwoAppVersion()
|
||||
|
||||
By("Apply the application rollout to deploy the source")
|
||||
var newAppRollout v1beta1.AppRollout
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/app-rollout.yaml", &newAppRollout)).Should(BeNil())
|
||||
newAppRollout.Namespace = namespace
|
||||
newAppRollout.Spec.SourceAppRevisionName = ""
|
||||
newAppRollout.Spec.TargetAppRevisionName = utils.ConstructRevisionName(app.GetName(), 1)
|
||||
createAppRolling(&newAppRollout)
|
||||
appRollout.Name = newAppRollout.Name
|
||||
verifyRolloutSucceeded(newAppRollout.Spec.TargetAppRevisionName)
|
||||
|
||||
By("Finish the application rollout")
|
||||
Eventually(
|
||||
@@ -482,61 +473,14 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
},
|
||||
time.Second*10, time.Millisecond*10).Should(BeEquivalentTo(oamstd.RollingInBatchesState))
|
||||
|
||||
VerifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
VerifyAppConfigInactive(appRollout.Spec.SourceAppRevisionName)
|
||||
|
||||
RevertBackToSource()
|
||||
})
|
||||
|
||||
It("Test rolling back in the middle of rollout", func() {
|
||||
ApplyTwoAppVersion()
|
||||
|
||||
By("Apply the application rollout to deploy the source")
|
||||
var newAppRollout v1alpha2.AppRollout
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/app-rollout.yaml", &newAppRollout)).Should(BeNil())
|
||||
newAppRollout.Namespace = namespace
|
||||
newAppRollout.Spec.SourceAppRevisionName = ""
|
||||
newAppRollout.Spec.TargetAppRevisionName = utils.ConstructRevisionName(app.GetName(), 1)
|
||||
Expect(k8sClient.Create(ctx, &newAppRollout)).Should(Succeed())
|
||||
appRollout.Name = newAppRollout.Name
|
||||
VerifyRolloutSucceeded(newAppRollout.Spec.TargetAppRevisionName)
|
||||
|
||||
By("Finish the application rollout")
|
||||
batchPartition := 1
|
||||
Eventually(
|
||||
func() error {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
appRollout.Spec.SourceAppRevisionName = utils.ConstructRevisionName(app.GetName(), 1)
|
||||
appRollout.Spec.TargetAppRevisionName = utils.ConstructRevisionName(app.GetName(), 2)
|
||||
appRollout.Spec.RolloutPlan.BatchPartition = pointer.Int32Ptr(int32(batchPartition))
|
||||
return k8sClient.Update(ctx, &appRollout)
|
||||
}, time.Second*5, time.Millisecond*500).Should(Succeed())
|
||||
|
||||
By("Wait for the rollout phase change to rolling in batches")
|
||||
Eventually(
|
||||
func() oamstd.RollingState {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: newAppRollout.Name}, &appRollout)
|
||||
return appRollout.Status.RollingState
|
||||
},
|
||||
time.Second*10, time.Millisecond*500).Should(BeEquivalentTo(oamstd.RollingInBatchesState))
|
||||
|
||||
By("Wait for rollout to start the batch")
|
||||
Eventually(
|
||||
func() int32 {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
return appRollout.Status.CurrentBatch
|
||||
},
|
||||
time.Second*60, time.Millisecond*500).Should(BeEquivalentTo(batchPartition))
|
||||
|
||||
RevertBackToSource()
|
||||
revertBackToSource()
|
||||
})
|
||||
|
||||
PIt("Test rolling by changing the definition", func() {
|
||||
CreateClonesetDef()
|
||||
ApplySourceApp()
|
||||
MarkAppRolling(1)
|
||||
applySourceApp()
|
||||
By("Apply the definition change")
|
||||
var cd, newCD v1alpha2.ComponentDefinition
|
||||
var cd, newCD v1beta1.ComponentDefinition
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/clonesetDefinitionModified.yaml.yaml", &newCD)).Should(BeNil())
|
||||
Eventually(
|
||||
func() error {
|
||||
@@ -545,19 +489,16 @@ var _ = Describe("Cloneset based rollout tests", func() {
|
||||
return k8sClient.Update(ctx, &cd)
|
||||
},
|
||||
time.Second*3, time.Millisecond*300).Should(Succeed())
|
||||
VerifyAppConfigTemplated(2)
|
||||
By("Apply the application rollout")
|
||||
var newAppRollout v1alpha2.AppRollout
|
||||
var newAppRollout v1beta1.AppRollout
|
||||
Expect(common.ReadYamlToObject("testdata/rollout/cloneset/app-rollout.yaml", &newAppRollout)).Should(BeNil())
|
||||
newAppRollout.Namespace = namespace
|
||||
newAppRollout.Spec.RolloutPlan.BatchPartition = pointer.Int32Ptr(int32(len(newAppRollout.Spec.RolloutPlan.
|
||||
RolloutBatches) - 1))
|
||||
Expect(k8sClient.Create(ctx, &newAppRollout)).Should(Succeed())
|
||||
|
||||
VerifyRolloutSucceeded(appConfig2.Name)
|
||||
|
||||
VerifyAppConfigInactive(appConfig1.Name)
|
||||
createAppRolling(&newAppRollout)
|
||||
|
||||
verifyRolloutSucceeded(appRollout.Spec.TargetAppRevisionName)
|
||||
verifyAppConfigInactive(appRollout.Spec.SourceAppRevisionName)
|
||||
// Clean up
|
||||
k8sClient.Delete(ctx, &appRollout)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user