Feat: support customizing application revision limit number in policy (#5995)

Signed-off-by: Somefive <yd219913@alibaba-inc.com>
This commit is contained in:
Somefive 2023-05-16 16:12:37 +08:00 committed by GitHub
parent 1af82cd282
commit da8588c887
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 96 additions and 2 deletions

View File

@ -27,6 +27,10 @@ const (
// GarbageCollectPolicySpec defines the spec of configuration drift
type GarbageCollectPolicySpec struct {
// ApplicationRevisionLimit if set, this application will use this number for application revision instead of
// the global configuration
ApplicationRevisionLimit *int `json:"applicationRevisionLimit,omitempty"`
// KeepLegacyResource if is set, outdated versioned resourcetracker will not be recycled automatically
// outdated resources will be kept until resourcetracker be deleted manually
KeepLegacyResource bool `json:"keepLegacyResource,omitempty"`

View File

@ -329,6 +329,11 @@ func (in *GarbageCollectPolicyRule) DeepCopy() *GarbageCollectPolicyRule {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GarbageCollectPolicySpec) DeepCopyInto(out *GarbageCollectPolicySpec) {
*out = *in
if in.ApplicationRevisionLimit != nil {
in, out := &in.ApplicationRevisionLimit, &out.ApplicationRevisionLimit
*out = new(int)
**out = **in
}
if in.Rules != nil {
in, out := &in.Rules, &out.Rules
*out = make([]GarbageCollectPolicyRule, len(*in))

View File

@ -34,6 +34,8 @@ spec:
}
parameter: {
// +usage=If set, it will override the default revision limit number and customize this number for the current application
applicationRevisionLimit?: int
// +usage=If is set, outdated versioned resourcetracker will not be recycled automatically, outdated resources will be kept until resourcetracker be deleted manually
keepLegacyResource: *false | bool
// +usage=If is set, continue to execute gc when the workflow fails, by default gc will be executed only after the workflow succeeds

View File

@ -901,6 +901,18 @@ func (h *AppHandler) UpdateAppLatestRevisionStatus(ctx context.Context) error {
return nil
}
func getApplicationRevisionLimitForApp(app *v1beta1.Application, fallback int) int {
for _, p := range app.Spec.Policies {
if p.Type == v1alpha1.GarbageCollectPolicyType && p.Properties != nil && p.Properties.Raw != nil {
prop := &v1alpha1.GarbageCollectPolicySpec{}
if err := json.Unmarshal(p.Properties.Raw, prop); err == nil && prop.ApplicationRevisionLimit != nil && *prop.ApplicationRevisionLimit >= 0 {
return *prop.ApplicationRevisionLimit
}
}
}
return fallback
}
// cleanUpApplicationRevision check all appRevisions of the application, remove them if the number of them exceed the limit
func cleanUpApplicationRevision(ctx context.Context, h *AppHandler) error {
if DisableAllApplicationRevision {
@ -915,11 +927,12 @@ func cleanUpApplicationRevision(ctx context.Context, h *AppHandler) error {
return err
}
appRevisionInUse := gatherUsingAppRevision(h)
needKill := len(sortedRevision) - h.r.appRevisionLimit - len(appRevisionInUse)
appRevisionLimit := getApplicationRevisionLimitForApp(h.app, h.r.appRevisionLimit)
needKill := len(sortedRevision) - appRevisionLimit - len(appRevisionInUse)
if needKill <= 0 {
return nil
}
klog.InfoS("Going to garbage collect app revisions", "limit", h.r.appRevisionLimit,
klog.InfoS("Going to garbage collect app revisions", "limit", appRevisionLimit,
"total", len(sortedRevision), "using", len(appRevisionInUse), "kill", needKill)
for _, rev := range sortedRevision {

View File

@ -1111,5 +1111,60 @@ var _ = Describe("Test multicluster scenario", func() {
Expect(k8sClient.Get(workerCtx, appKey, _deploy)).Should(Succeed())
Expect(int(*_deploy.Spec.Replicas)).Should(Equal(0))
})
It("Test application with customized application revision limit", func() {
ctx := context.Background()
app := &v1beta1.Application{}
bs, err := os.ReadFile("./testdata/app/app-lite.yaml")
Expect(err).Should(Succeed())
Expect(yaml.Unmarshal(bs, app)).Should(Succeed())
app.SetNamespace(namespace)
Eventually(func(g Gomega) {
g.Expect(k8sClient.Create(ctx, app)).Should(Succeed())
}).WithPolling(2 * time.Second).WithTimeout(5 * time.Second).Should(Succeed())
appKey := client.ObjectKeyFromObject(app)
Eventually(func(g Gomega) {
_app := &v1beta1.Application{}
g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed())
g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning))
}).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed())
By("update app and should have two revisions")
Eventually(func(g Gomega) {
_app := &v1beta1.Application{}
g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed())
_app.Spec.Components[0].Name = "dw"
g.Expect(k8sClient.Update(ctx, _app)).Should(Succeed())
}).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed())
Eventually(func(g Gomega) {
_app := &v1beta1.Application{}
g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed())
g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning))
_revs := &v1beta1.ApplicationRevisionList{}
g.Expect(k8sClient.List(ctx, _revs, client.InNamespace(namespace))).Should(Succeed())
g.Expect(len(_revs.Items)).Should(Equal(2))
}).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed())
By("update app with gc policy and should have one revision")
Eventually(func(g Gomega) {
_app := &v1beta1.Application{}
g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed())
_app.Spec.Components[0].Name = "dw2"
_app.Spec.Policies = []v1beta1.AppPolicy{{
Type: "garbage-collect",
Name: "gc",
Properties: &runtime.RawExtension{Raw: []byte(`{"applicationRevisionLimit":0}`)},
}}
g.Expect(k8sClient.Update(ctx, _app)).Should(Succeed())
}).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed())
Eventually(func(g Gomega) {
_app := &v1beta1.Application{}
g.Expect(k8sClient.Get(ctx, appKey, _app)).Should(Succeed())
g.Expect(_app.Status.Phase).Should(Equal(common.ApplicationRunning))
_revs := &v1beta1.ApplicationRevisionList{}
g.Expect(k8sClient.List(ctx, _revs, client.InNamespace(namespace))).Should(Succeed())
g.Expect(len(_revs.Items)).Should(Equal(1))
}).WithPolling(2 * time.Second).WithTimeout(20 * time.Second).Should(Succeed())
})
})
})

View File

@ -0,0 +1,13 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: example-lite-app
spec:
components:
- name: data-worker
type: worker
properties:
image: busybox
cmd:
- sleep
- '1000000'

View File

@ -30,6 +30,8 @@ template: {
}
parameter: {
// +usage=If set, it will override the default revision limit number and customize this number for the current application
applicationRevisionLimit?: int
// +usage=If is set, outdated versioned resourcetracker will not be recycled automatically, outdated resources will be kept until resourcetracker be deleted manually
keepLegacyResource: *false | bool
// +usage=If is set, continue to execute gc when the workflow fails, by default gc will be executed only after the workflow succeeds