support custom component revision

This commit is contained in:
天元
2020-12-25 09:40:54 +08:00
parent 1f2c38d3c7
commit e3b4bcd2ca
3 changed files with 94 additions and 14 deletions
@@ -29,30 +29,33 @@ const ControllerRevisionComponentLabel = "controller.oam.dev/component"
// ComponentHandler will watch component change and generate Revision automatically.
type ComponentHandler struct {
Client client.Client
Logger logging.Logger
RevisionLimit int
Client client.Client
Logger logging.Logger
RevisionLimit int
CustomWebHookURL string
}
// Create implements EventHandler
func (c *ComponentHandler) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
if !c.createControllerRevision(evt.Meta, evt.Object) {
reqs, succeed := c.createControllerRevision(evt.Meta, evt.Object)
if !succeed {
// No revision created, return
return
}
for _, req := range c.getRelatedAppConfig(evt.Meta) {
for _, req := range reqs {
q.Add(req)
}
}
// Update implements EventHandler
func (c *ComponentHandler) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
if !c.createControllerRevision(evt.MetaNew, evt.ObjectNew) {
reqs, succeed := c.createControllerRevision(evt.MetaNew, evt.ObjectNew)
if !succeed {
// No revision created, return
return
}
// Note(wonderflow): MetaOld => MetaNew, requeue once is enough
for _, req := range c.getRelatedAppConfig(evt.MetaNew) {
for _, req := range reqs {
q.Add(req)
}
}
@@ -133,14 +136,22 @@ func newTrue() *bool {
return &b
}
func (c *ComponentHandler) createControllerRevision(mt metav1.Object, obj runtime.Object) bool {
func (c *ComponentHandler) createControllerRevision(mt metav1.Object, obj runtime.Object) ([]reconcile.Request, bool) {
curComp := obj.(*v1alpha2.Component)
comp := curComp.DeepCopy()
diff, curRevision := c.IsRevisionDiff(mt, comp)
if !diff {
// No difference, no need to create new revision.
return false
return nil, false
}
reqs := c.getRelatedAppConfig(mt)
// Hook to custom revision service if exist
if err := c.customComponentRevisionHook(reqs, comp); err != nil {
c.Logger.Info(fmt.Sprintf("fail to hook from custom revision service(%s) %v", c.CustomWebHookURL, err), "componentName", mt.GetName())
return nil, false
}
nextRevision := curRevision + 1
revisionName := ConstructRevisionName(mt.GetName(), nextRevision)
@@ -177,13 +188,13 @@ func (c *ComponentHandler) createControllerRevision(mt metav1.Object, obj runtim
err := c.Client.Create(context.TODO(), &revision)
if err != nil {
c.Logger.Info(fmt.Sprintf("error create controllerRevision %v", err), "componentName", mt.GetName())
return false
return nil, false
}
err = c.Client.Status().Update(context.Background(), comp)
if err != nil {
c.Logger.Info(fmt.Sprintf("update component status latestRevision %s err %v", revisionName, err), "componentName", mt.GetName())
return false
return nil, false
}
c.Logger.Info(fmt.Sprintf("ControllerRevision %s created", revisionName))
if int64(c.RevisionLimit) < nextRevision {
@@ -191,7 +202,7 @@ func (c *ComponentHandler) createControllerRevision(mt metav1.Object, obj runtim
c.Logger.Info(fmt.Sprintf("failed to clean up revisions of Component %v.", err))
}
}
return true
return reqs, true
}
// get sorted controllerRevisions, prepare to delete controllerRevisions
@@ -0,0 +1,66 @@
/*
Copyright 2020 The 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 applicationconfiguration
import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"net/http"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
"github.com/oam-dev/kubevela/pkg/server/util"
)
// RevisionHookRequest is request body for custom component revision hook
type RevisionHookRequest struct {
RelatedApps []reconcile.Request `json:"relatedApps"`
Comp *v1alpha2.Component `json:"component"`
}
func (c *ComponentHandler) customComponentRevisionHook(relatedApps []reconcile.Request, comp *v1alpha2.Component) error {
if c.CustomWebHookURL == "" {
return nil
}
req := RevisionHookRequest{
RelatedApps: relatedApps,
Comp: comp.DeepCopy(),
}
data, err := json.Marshal(req)
if err != nil {
return err
}
httpRequest, err := http.NewRequestWithContext(context.Background(), http.MethodPost, c.CustomWebHookURL, bytes.NewBuffer(data))
if err != nil {
return err
}
httpRequest.Header.Set("Content-Type", util.ContentTypeJSON)
resp, err := http.DefaultClient.Do(httpRequest)
if err != nil {
return err
}
//nolint:errcheck
defer resp.Body.Close()
respData, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
return json.Unmarshal(respData, comp)
}
@@ -137,7 +137,10 @@ var _ = Describe("Test ApplicationConfiguration Component Revision Enabled trait
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compName}, cmpV1)).Should(Succeed())
By("component handler will automatically create controller revision")
Expect(componentHandler.createControllerRevision(cmpV1, cmpV1)).Should(BeTrue())
Expect(func() bool {
_, ok := componentHandler.createControllerRevision(cmpV1, cmpV1)
return ok
}()).Should(BeTrue())
var crList v1.ControllerRevisionList
By("Check controller revision created successfully")
Eventually(func() error {
@@ -250,7 +253,7 @@ var _ = Describe("Test ApplicationConfiguration Component Revision Enabled trait
By("Update Component")
Expect(k8sClient.Update(ctx, cmpV2)).Should(Succeed())
By("component handler will automatically create a ne controller revision")
Expect(componentHandler.createControllerRevision(cmpV2, cmpV2)).Should(BeTrue())
Expect(func() bool { _, ok := componentHandler.createControllerRevision(cmpV2, cmpV2); return ok }()).Should(BeTrue())
By("Check controller revision created successfully")
Eventually(func() error {
labels := &metav1.LabelSelector{