Modify the wrong ConfigMap name in v1.13 node-agent-concurrency document. (#7715)

Fix condition matching in resource modifier when there are multiple rules

Signed-off-by: lou <alex1988@outlook.com>
Co-authored-by: Xun Jiang <blackpigletbruce@gmail.com>
pull/7671/head
Guang Jiong Lou 2024-05-15 05:01:50 +08:00 committed by GitHub
parent 27392d3411
commit 6c2b66b480
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 145 additions and 17 deletions

View File

@ -0,0 +1 @@
Fix condition matching in resource modifier when there are multiple rules

View File

@ -86,8 +86,22 @@ func GetResourceModifiersFromConfig(cm *v1.ConfigMap) (*ResourceModifiers, error
func (p *ResourceModifiers) ApplyResourceModifierRules(obj *unstructured.Unstructured, groupResource string, scheme *runtime.Scheme, log logrus.FieldLogger) []error {
var errs []error
origin := obj
// If there are more than one rules, we need to keep the original object for condition matching
if len(p.ResourceModifierRules) > 1 {
origin = obj.DeepCopy()
}
for _, rule := range p.ResourceModifierRules {
err := rule.apply(obj, groupResource, scheme, log)
matched, err := rule.match(origin, groupResource, log)
if err != nil {
errs = append(errs, err)
continue
} else if !matched {
continue
}
log.Infof("Applying resource modifier patch on %s/%s", origin.GetNamespace(), origin.GetName())
err = rule.applyPatch(obj, scheme, log)
if err != nil {
errs = append(errs, err)
}
@ -96,59 +110,54 @@ func (p *ResourceModifiers) ApplyResourceModifierRules(obj *unstructured.Unstruc
return errs
}
func (r *ResourceModifierRule) apply(obj *unstructured.Unstructured, groupResource string, scheme *runtime.Scheme, log logrus.FieldLogger) error {
func (r *ResourceModifierRule) match(obj *unstructured.Unstructured, groupResource string, log logrus.FieldLogger) (bool, error) {
ns := obj.GetNamespace()
if ns != "" {
namespaceInclusion := collections.NewIncludesExcludes().Includes(r.Conditions.Namespaces...)
if !namespaceInclusion.ShouldInclude(ns) {
return nil
return false, nil
}
}
g, err := glob.Compile(r.Conditions.GroupResource, '.')
if err != nil {
log.Errorf("Bad glob pattern of groupResource in condition, groupResource: %s, err: %s", r.Conditions.GroupResource, err)
return err
return false, err
}
if !g.Match(groupResource) {
return nil
return false, nil
}
if r.Conditions.ResourceNameRegex != "" {
match, err := regexp.MatchString(r.Conditions.ResourceNameRegex, obj.GetName())
if err != nil {
return errors.Errorf("error in matching regex %s", err.Error())
return false, errors.Errorf("error in matching regex %s", err.Error())
}
if !match {
return nil
return false, nil
}
}
if r.Conditions.LabelSelector != nil {
selector, err := metav1.LabelSelectorAsSelector(r.Conditions.LabelSelector)
if err != nil {
return errors.Errorf("error in creating label selector %s", err.Error())
return false, errors.Errorf("error in creating label selector %s", err.Error())
}
if !selector.Matches(labels.Set(obj.GetLabels())) {
return nil
return false, nil
}
}
match, err := matchConditions(obj, r.Conditions.Matches, log)
if err != nil {
return err
return false, err
} else if !match {
log.Info("Conditions do not match, skip it")
return nil
return false, nil
}
log.Infof("Applying resource modifier patch on %s/%s", obj.GetNamespace(), obj.GetName())
err = r.applyPatch(obj, scheme, log)
if err != nil {
return err
}
return nil
return true, nil
}
func matchConditions(u *unstructured.Unstructured, rules []MatchRule, _ logrus.FieldLogger) (bool, error) {

View File

@ -456,6 +456,20 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) {
},
}
pvcGoldSc := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "PersistentVolumeClaim",
"metadata": map[string]interface{}{
"name": "test-pvc",
"namespace": "foo",
},
"spec": map[string]interface{}{
"storageClassName": "gold",
},
},
}
deployNginxOneReplica := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
@ -679,6 +693,110 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) {
wantErr: false,
wantObj: pvcPremiumSc.DeepCopy(),
},
{
name: "pvc with standard storage class should be patched to premium, even when rules are [standard => premium, premium => gold]",
fields: fields{
Version: "v1",
ResourceModifierRules: []ResourceModifierRule{
{
Conditions: Conditions{
GroupResource: "persistentvolumeclaims",
ResourceNameRegex: ".*",
Matches: []MatchRule{
{
Path: "/spec/storageClassName",
Value: "standard",
},
},
},
Patches: []JSONPatch{
{
Operation: "replace",
Path: "/spec/storageClassName",
Value: "premium",
},
},
},
{
Conditions: Conditions{
GroupResource: "persistentvolumeclaims",
ResourceNameRegex: ".*",
Matches: []MatchRule{
{
Path: "/spec/storageClassName",
Value: "premium",
},
},
},
Patches: []JSONPatch{
{
Operation: "replace",
Path: "/spec/storageClassName",
Value: "gold",
},
},
},
},
},
args: args{
obj: pvcStandardSc.DeepCopy(),
groupResource: "persistentvolumeclaims",
},
wantErr: false,
wantObj: pvcPremiumSc.DeepCopy(),
},
{
name: "pvc with standard storage class should be patched to gold, even when rules are [standard => premium, standard => gold]",
fields: fields{
Version: "v1",
ResourceModifierRules: []ResourceModifierRule{
{
Conditions: Conditions{
GroupResource: "persistentvolumeclaims",
ResourceNameRegex: ".*",
Matches: []MatchRule{
{
Path: "/spec/storageClassName",
Value: "standard",
},
},
},
Patches: []JSONPatch{
{
Operation: "replace",
Path: "/spec/storageClassName",
Value: "premium",
},
},
},
{
Conditions: Conditions{
GroupResource: "persistentvolumeclaims",
ResourceNameRegex: ".*",
Matches: []MatchRule{
{
Path: "/spec/storageClassName",
Value: "standard",
},
},
},
Patches: []JSONPatch{
{
Operation: "replace",
Path: "/spec/storageClassName",
Value: "gold",
},
},
},
},
},
args: args{
obj: pvcStandardSc.DeepCopy(),
groupResource: "persistentvolumeclaims",
},
wantErr: false,
wantObj: pvcGoldSc.DeepCopy(),
},
{
name: "nginx deployment: 1 -> 2 replicas",
fields: fields{