Machanism for filter annotation&label passed from Application to workload and trait (#1843)

* Add two filter

* only filter in app->ac and ac->other

* move filter logic to assemble phase

* simplify, add indication

* simplify trim

* add unit test

* clean up testdata
This commit is contained in:
chival
2021-06-28 15:12:03 +08:00
committed by GitHub
parent b2adf5b472
commit 2b4d12fbdd
5 changed files with 202 additions and 16 deletions

View File

@@ -97,10 +97,7 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
Name: req.Name,
Namespace: req.Namespace,
}, app); err != nil {
if kerrors.IsNotFound(err) {
err = nil
}
return ctrl.Result{}, err
return ctrl.Result{}, client.IgnoreNotFound(err)
}
ctx = oamutil.SetNamespaceInCtx(ctx, app.Namespace)
if len(app.GetAnnotations()[oam.AnnotationKubeVelaVersion]) == 0 {

View File

@@ -17,6 +17,8 @@ limitations under the License.
package assemble
import (
"strings"
runtimev1alpha1 "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1"
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
"github.com/pkg/errors"
@@ -31,6 +33,15 @@ import (
"github.com/oam-dev/kubevela/pkg/oam/util"
)
// DefaultFilterAnnots are annotations won't pass to workload or trait
var DefaultFilterAnnots = []string{
oam.AnnotationAppRollout,
oam.AnnotationRollingComponent,
oam.AnnotationInplaceUpgrade,
oam.AnnotationFilterLabelKeys,
oam.AnnotationFilterAnnotationKeys,
}
// NewAppManifests create a AppManifests
func NewAppManifests(appRevision *v1beta1.ApplicationRevision) *AppManifests {
return &AppManifests{AppRevision: appRevision}
@@ -163,7 +174,7 @@ func (am *AppManifests) assemble() {
for _, comp := range am.componentManifests {
compRevisionName := comp.RevisionName
compName := comp.Name
commonLabels := am.generateCommonLabels(compName, compRevisionName)
commonLabels := am.generateAndFilterCommonLabels(compName, compRevisionName)
klog.InfoS("Assemble manifests for component", "name", compName)
wl, err := am.assembleWorkload(compName, comp.StandardWorkload, commonLabels, comp.PackagedWorkloadResources)
if err != nil {
@@ -236,7 +247,12 @@ func (am *AppManifests) validate() error {
}
// workload and trait in the same component both have these labels
func (am *AppManifests) generateCommonLabels(compName, compRevisionName string) map[string]string {
func (am *AppManifests) generateAndFilterCommonLabels(compName, compRevisionName string) map[string]string {
filter := func(labels map[string]string, notAllowedKey []string) {
for _, l := range notAllowedKey {
delete(labels, strings.TrimSpace(l))
}
}
Labels := map[string]string{
oam.LabelAppName: am.appName,
oam.LabelAppRevision: am.AppRevision.Name,
@@ -244,20 +260,29 @@ func (am *AppManifests) generateCommonLabels(compName, compRevisionName string)
oam.LabelAppComponent: compName,
oam.LabelAppComponentRevision: compRevisionName,
}
// pass application's all labels to workload/trait
return util.MergeMapOverrideWithDst(Labels, am.appLabels)
// merge application's all labels
finalLabels := util.MergeMapOverrideWithDst(Labels, am.appLabels)
filterLabels, ok := am.appAnnotations[oam.AnnotationFilterLabelKeys]
if ok {
filter(finalLabels, strings.Split(filterLabels, ","))
}
return finalLabels
}
// workload and trait both have these annotations
func (am *AppManifests) setAnnotations(obj *unstructured.Unstructured) {
func (am *AppManifests) filterAndSetAnnotations(obj *unstructured.Unstructured) {
var allFilterAnnotation []string
allFilterAnnotation = append(allFilterAnnotation, DefaultFilterAnnots...)
passedFilterAnnotation, ok := am.appAnnotations[oam.AnnotationFilterAnnotationKeys]
if ok {
allFilterAnnotation = append(allFilterAnnotation, strings.Split(passedFilterAnnotation, ",")...)
}
// pass application's all annotations
util.AddAnnotations(obj, am.appAnnotations)
// remove useless annotations for workload/trait
util.RemoveAnnotations(obj, []string{
oam.AnnotationAppRollout,
oam.AnnotationRollingComponent,
oam.AnnotationInplaceUpgrade,
})
util.RemoveAnnotations(obj, allFilterAnnotation)
}
func (am *AppManifests) setNamespace(obj *unstructured.Unstructured) {
@@ -274,7 +299,7 @@ func (am *AppManifests) assembleWorkload(compName string, wl *unstructured.Unstr
// override the name set in render phase if exist
wl.SetName(compName)
am.setWorkloadLabels(wl, labels)
am.setAnnotations(wl)
am.filterAndSetAnnotations(wl)
am.setNamespace(wl)
workloadType := wl.GetLabels()[oam.WorkloadTypeLabel]
@@ -319,7 +344,7 @@ func (am *AppManifests) assembleTrait(trait *unstructured.Unstructured, compName
trait.SetName(traitName)
}
am.setTraitLabels(trait, labels)
am.setAnnotations(trait)
am.filterAndSetAnnotations(trait)
am.setNamespace(trait)
klog.InfoS("Successfully assemble a trait", "trait", klog.KObj(trait), "APIVersion", trait.GetAPIVersion(), "Kind", trait.GetKind())
return trait

View File

@@ -151,4 +151,59 @@ var _ = Describe("Test Assemble Options", func() {
}
Expect(wlScope).Should(Equal(wantScopeRef))
})
It("test annotation and label filter", func() {
var (
compName = "frontend"
)
appRev := &v1beta1.ApplicationRevision{}
b, err := ioutil.ReadFile("./testdata/filter_annotations.yaml")
getKeys := func(m map[string]string) []string {
var keys []string
for k := range m {
keys = append(keys, k)
}
return keys
}
//this appRev is generated on below this app:
/*
metadata:
name: website
annotations:
filter.oam.dev/annotation-keys: "notPassAnno1, notPassAnno2"
filter.oam.dev/label-keys: "notPassLabel"
notPassAnno1: "Annotation-filtered"
notPassAnno2: "Annotation-filtered"
canPassAnno: "Annotation-passed"
labels:
notPassLabel: "Label-filtered"
canPassLabel: "Label-passed"
spec:
components:
- name: frontend
type: webservice
properties:
image: nginx
*/
Expect(err).Should(BeNil())
err = yaml.Unmarshal(b, appRev)
Expect(err).Should(BeNil())
ao := NewAppManifests(appRev)
workloads, _, _, err := ao.GroupAssembledManifests()
Expect(err).Should(BeNil())
By("verify labels specified should be filtered")
wl := workloads[compName]
labelKeys := getKeys(wl.GetLabels())
Expect(labelKeys).ShouldNot(ContainElements("notPassLabel"))
Expect(labelKeys).Should(ContainElements("canPassLabel"))
By("verify annotations specified should be filtered")
annotationKeys := getKeys(wl.GetAnnotations())
Expect(annotationKeys).ShouldNot(ContainElements("notPassAnno1", "notPassAnno2"))
Expect(annotationKeys).Should(ContainElements("canPassAnno"))
})
})

File diff suppressed because one or more lines are too long

View File

@@ -99,4 +99,10 @@ const (
// AnnotationKubeVelaVersion is used to record current KubeVela version
AnnotationKubeVelaVersion = "oam.dev/kubevela-version"
// AnnotationFilterAnnotationKeys is used to filter annotations passed to workload and trait, split by comma
AnnotationFilterAnnotationKeys = "filter.oam.dev/annotation-keys"
// AnnotationFilterLabelKeys is used to filter labels passed to workload and trait, split by comma
AnnotationFilterLabelKeys = "filter.oam.dev/label-keys"
)