Skip to content

Commit

Permalink
Add valuesString field for matchExpressions in ApplicationSet
Browse files Browse the repository at this point in the history
Signed-off-by: Damien Dassieu <[email protected]>
  • Loading branch information
damsien committed Nov 27, 2024
1 parent 36d189c commit 97f0463
Show file tree
Hide file tree
Showing 7 changed files with 867 additions and 724 deletions.
25 changes: 24 additions & 1 deletion applicationset/controllers/applicationset_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package controllers

import (
"context"
"errors"
"fmt"
"reflect"
"runtime/debug"
Expand Down Expand Up @@ -938,6 +939,22 @@ func (r *ApplicationSetReconciler) buildAppDependencyList(logCtx *log.Entry, app
return appDependencyList, appStepMap
}

func getMatchExpressionValues(matchExpression argov1alpha1.ApplicationMatchExpression) ([]string, error) {

Check failure on line 942 in applicationset/controllers/applicationset_controller.go

View workflow job for this annotation

GitHub Actions / Lint Go code

unnecessary leading newline (whitespace)

if len(matchExpression.ValuesString) > 0 && matchExpression.ValuesString != "" {
return nil, errors.New("only one of 'values' or 'valuesString' must be set")
}
if matchExpression.ValuesString != "" {
values := strings.Split(matchExpression.ValuesString, ",")
return values, nil
}
if len(matchExpression.Values) > 0 {
return matchExpression.Values, nil
}

return nil, errors.New("nor of the 'values' and 'valuesString' fields are defined")
}

func labelMatchedExpression(logCtx *log.Entry, val string, matchExpression argov1alpha1.ApplicationMatchExpression) bool {
if matchExpression.Operator != "In" && matchExpression.Operator != "NotIn" {
logCtx.Errorf("skipping AppSet rollingUpdate step Application selection, invalid matchExpression operator provided: %q ", matchExpression.Operator)
Expand All @@ -948,7 +965,13 @@ func labelMatchedExpression(logCtx *log.Entry, val string, matchExpression argov
// if operator == NotIn, default to true
valueMatched := matchExpression.Operator == "NotIn"

for _, value := range matchExpression.Values {
// Get values from Values or ValuesString
values, err := getMatchExpressionValues(matchExpression)
if err != nil {
return false
}

for _, value := range values {
if val == value {
// first "In" match returns true
// first "NotIn" match returns false
Expand Down
63 changes: 63 additions & 0 deletions applicationset/controllers/applicationset_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2360,6 +2360,69 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
assert.True(t, isProgressingCondition, "RolloutProgressing should be set for rollout strategy appset")
},
},
{
appset: v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSetSpec{
Generators: []v1alpha1.ApplicationSetGenerator{
{List: &v1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{{
Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`),
}},
}},
},
Template: v1alpha1.ApplicationSetTemplate{},
Strategy: &v1alpha1.ApplicationSetStrategy{
Type: "RollingSync",
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
Steps: []v1alpha1.ApplicationSetRolloutStep{
{
MatchExpressions: []v1alpha1.ApplicationMatchExpression{
{
Key: "test",
Operator: "In",
ValuesString: "test,anotherKey",
},
},
},
},
},
},
},
},
conditions: []v1alpha1.ApplicationSetCondition{
{
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
Message: "All applications have been generated successfully",
Reason: v1alpha1.ApplicationSetReasonApplicationSetUpToDate,
Status: v1alpha1.ApplicationSetConditionStatusTrue,
},
{
Type: v1alpha1.ApplicationSetConditionRolloutProgressing,
Message: "ApplicationSet Rollout Rollout started",
Reason: v1alpha1.ApplicationSetReasonApplicationSetUpToDate,
Status: v1alpha1.ApplicationSetConditionStatusTrue,
},
},
testfunc: func(t *testing.T, appset v1alpha1.ApplicationSet) {
t.Helper()
assert.Len(t, appset.Status.Conditions, 4)

isProgressingCondition := false

for _, condition := range appset.Status.Conditions {
if condition.Type == v1alpha1.ApplicationSetConditionRolloutProgressing {
isProgressingCondition = true
break
}
}

assert.True(t, isProgressingCondition, "RolloutProgressing should be set for rollout strategy appset using valuesString matchExpressions")
},
},
}

kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...)
Expand Down
5 changes: 5 additions & 0 deletions assets/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions manifests/crds/applicationset-crd.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions pkg/apis/application/v1alpha1/applicationset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,14 @@ type ApplicationSetRolloutStep struct {
}

type ApplicationMatchExpression struct {
Key string `json:"key,omitempty" protobuf:"bytes,1,opt,name=key"`
Operator string `json:"operator,omitempty" protobuf:"bytes,2,opt,name=operator"`
Values []string `json:"values,omitempty" protobuf:"bytes,3,opt,name=values"`
Key string `json:"key,omitempty" protobuf:"bytes,1,opt,name=key"`
Operator string `json:"operator,omitempty" protobuf:"bytes,2,opt,name=operator"`
// +kubebuilder:validation:Optional
Values []string `json:"values,omitempty" protobuf:"bytes,3,opt,name=values"`
// +kubebuilder:validation:Optional
ValuesString string `json:"valuesString,omitempty" protobuf:"bytes,4,opt,name=valuesString"`
// If needed, either Values or ValuesString must be set, but not both.
// +kubebuilder:validation:XValidation:rule="!(self.values != null && self.valuesString != null)",message="Only one of 'values' or 'valuesString' must be set"
}

// ApplicationsSyncPolicy representation
Expand Down
Loading

0 comments on commit 97f0463

Please sign in to comment.