Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(appset): Policies create-only, create-update, sync per ApplicationSet #11462

Merged
merged 64 commits into from
Jun 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
f28a144
11073: SyncPolicy per applicationset
speedfl Feb 7, 2023
e1ba30c
Merge branch 'master' into feature/11073
speedfl Feb 8, 2023
5a96ff4
Merge branch 'master' into feature/11073
speedfl Feb 9, 2023
6a441f1
Merge branch 'master' into feature/11073
speedfl Feb 9, 2023
610120f
Merge branch 'master' into feature/11073
speedfl Feb 13, 2023
cdfd64d
Merge branch 'master' into feature/11073
speedfl Feb 14, 2023
5c71e4c
Merge branch 'master' into feature/11073
speedfl Feb 14, 2023
31f6f30
Merge branch 'master' into feature/11073
speedfl Feb 16, 2023
01f4bb6
Merge branch 'master' into feature/11073
speedfl Feb 16, 2023
9d680ba
Merge branch 'master' into feature/11073
speedfl Feb 18, 2023
005f967
Merge branch 'master' into feature/11073
speedfl Feb 21, 2023
2ff3b6d
Merge branch 'master' into feature/11073
speedfl Feb 23, 2023
4350615
Merge branch 'master' into feature/11073
speedfl Mar 3, 2023
80666b3
Merge branch 'master' of github.com:speedfl/argo-cd into feature/11073
speedfl Mar 23, 2023
d768cff
11073: Fix Lint
speedfl Apr 12, 2023
b30dd35
Merge branch 'master' into feature/11073
speedfl Apr 17, 2023
954779b
11073: Fix Lint 2
speedfl Apr 17, 2023
04c9345
Merge branch 'master' into feature/11073
speedfl Apr 17, 2023
8d6214a
Merge branch 'master' of github.com:speedfl/argo-cd into feature/11073
speedfl Apr 21, 2023
ddf31aa
Merge branch 'master' of github.com:speedfl/argo-cd into feature/11073
speedfl May 1, 2023
6aad6fb
11073: Empty
speedfl May 1, 2023
f7cd5a7
Merge branch 'master' of github.com:speedfl/argo-cd into feature/11073
speedfl May 2, 2023
b67e242
11073: Empty
speedfl May 2, 2023
e05858b
11073: Empty
speedfl May 3, 2023
fc2d442
Merge branch 'master' into feature/11073
speedfl May 3, 2023
215a78e
Merge branch 'master' into feature/11073
speedfl May 3, 2023
3a209a3
11073: Empty
speedfl May 3, 2023
bf7aa4d
11073: Empty
speedfl May 3, 2023
2f6a4a2
11073: Empty
speedfl May 3, 2023
be2a79c
Merge branch 'master' into feature/11073
speedfl May 4, 2023
34bb2ea
Merge branch 'master' into feature/11073
speedfl May 4, 2023
f0a23ad
11073: Empty
speedfl May 4, 2023
d4a9313
Merge branch 'master' into feature/11073
speedfl May 5, 2023
8cb17d7
Merge branch 'master' of github.com:speedfl/argo-cd into feature/11073
speedfl May 10, 2023
7831d3f
Merge branch 'feature/11073' of github.com:speedfl/argo-cd into featu…
speedfl May 10, 2023
efd5faa
Merge branch 'master' into feature/11073
speedfl May 11, 2023
d873bba
11073: Fix after review
speedfl May 11, 2023
8392a14
Merge branch 'master' into feature/11073
speedfl May 11, 2023
ee97b54
Merge branch 'master' into feature/11073
speedfl May 12, 2023
61de56e
11073: Empty
speedfl May 12, 2023
188f637
Merge branch 'master' into feature/11073
speedfl May 13, 2023
9c56c2c
Merge branch 'master' into feature/11073
speedfl May 15, 2023
7deb75b
Merge branch 'master' into feature/11073
speedfl May 17, 2023
fa33335
11073: Fix after review
speedfl May 17, 2023
4737145
11073: Fix doc
speedfl May 17, 2023
8811d12
11073: Fix doc
speedfl May 17, 2023
e94c7af
Merge branch 'master' into feature/11073
speedfl May 18, 2023
05b41a6
Merge branch 'master' into feature/11073
speedfl May 19, 2023
f8a4b62
Merge branch 'master' of github.com:speedfl/argo-cd into feature/11073
speedfl May 29, 2023
0eb2806
Merge branch 'master' into feature/11073
speedfl May 29, 2023
2506b72
Merge branch 'master' of github.com:speedfl/argo-cd into feature/11073
speedfl May 31, 2023
5083b61
Merge branch 'master' into feature/11073
speedfl Jun 1, 2023
c421200
Merge branch 'master' of github.com:speedfl/argo-cd into feature/11073
speedfl Jun 5, 2023
01a9532
Merge branch 'master' into feature/11073
speedfl Jun 7, 2023
f1c564c
Merge branch 'master' into feature/11073
speedfl Jun 8, 2023
fb65694
Merge branch 'master' into feature/11073
speedfl Jun 13, 2023
64d0039
11073: Use enable policy override
speedfl Jun 13, 2023
a6bbd9a
11073: Fix unit test label
speedfl Jun 13, 2023
888f0a3
Merge branch 'master' into feature/11073
speedfl Jun 13, 2023
18877d1
11073: Update documentation
speedfl Jun 13, 2023
3d99bfd
Merge branch 'master' into feature/11073
speedfl Jun 13, 2023
d39e297
11073: Update e2e
speedfl Jun 13, 2023
2f303a8
Merge branch 'feature/11073' of github.com:speedfl/argo-cd into featu…
speedfl Jun 13, 2023
58cbf24
Merge branch 'master' into feature/11073
speedfl Jun 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions applicationset/controllers/applicationset_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,14 @@ var (
// ApplicationSetReconciler reconciles a ApplicationSet object
type ApplicationSetReconciler struct {
client.Client
Scheme *runtime.Scheme
Recorder record.EventRecorder
Generators map[string]generators.Generator
ArgoDB db.ArgoDB
ArgoAppClientset appclientset.Interface
KubeClientset kubernetes.Interface
utils.Policy
Scheme *runtime.Scheme
Recorder record.EventRecorder
Generators map[string]generators.Generator
ArgoDB db.ArgoDB
ArgoAppClientset appclientset.Interface
KubeClientset kubernetes.Interface
Policy argov1alpha1.ApplicationsSyncPolicy
EnablePolicyOverride bool
utils.Renderer

EnableProgressiveSyncs bool
Expand Down Expand Up @@ -226,7 +227,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}
}

if r.Policy.Update() {
if utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowUpdate() {
err = r.createOrUpdateInCluster(ctx, applicationSetInfo, validApps)
if err != nil {
_ = r.setApplicationSetStatusCondition(ctx,
Expand Down Expand Up @@ -256,7 +257,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}
}

if r.Policy.Delete() {
if utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowDelete() {
err = r.deleteInCluster(ctx, applicationSetInfo, desiredApplications)
if err != nil {
_ = r.setApplicationSetStatusCondition(ctx,
Expand Down
333 changes: 332 additions & 1 deletion applicationset/controllers/applicationset_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1922,7 +1922,7 @@ func TestReconcilerValidationErrorBehaviour(t *testing.T) {
ArgoDB: &argoDBMock,
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
KubeClientset: kubeclientset,
Policy: &utils.SyncPolicy{},
Policy: v1alpha1.ApplicationsSyncPolicySync,
}

req := ctrl.Request{
Expand Down Expand Up @@ -2005,6 +2005,337 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {
assert.Len(t, appSet.Status.Conditions, 3)
}

func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alpha1.ApplicationsSyncPolicy, recordBuffer int, allowPolicyOverride bool) v1alpha1.Application {

scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = v1alpha1.AddToScheme(scheme)
assert.Nil(t, err)

defaultProject := v1alpha1.AppProject{
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "argocd"},
Spec: v1alpha1.AppProjectSpec{SourceRepos: []string{"*"}, Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "https://good-cluster"}}},
}
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": "good-cluster","url": "https://good-cluster"}`),
}},
},
},
},
SyncPolicy: &v1alpha1.ApplicationSetSyncPolicy{
ApplicationsSync: &applicationsSyncPolicy,
},
Template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "{{cluster}}",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"},
Project: "default",
Destination: v1alpha1.ApplicationDestination{Server: "{{url}}"},
},
},
},
}

kubeclientset := kubefake.NewSimpleClientset()
argoDBMock := dbmocks.ArgoDB{}
argoObjs := []runtime.Object{&defaultProject}

client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build()
goodCluster := v1alpha1.Cluster{Server: "https://good-cluster", Name: "good-cluster"}
argoDBMock.On("GetCluster", mock.Anything, "https://good-cluster").Return(&goodCluster, nil)
argoDBMock.On("ListClusters", mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{
goodCluster,
}}, nil)

r := ApplicationSetReconciler{
Client: client,
Scheme: scheme,
Renderer: &utils.Render{},
Recorder: record.NewFakeRecorder(recordBuffer),
Generators: map[string]generators.Generator{
"List": generators.NewListGenerator(),
},
ArgoDB: &argoDBMock,
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
KubeClientset: kubeclientset,
Policy: v1alpha1.ApplicationsSyncPolicySync,
EnablePolicyOverride: allowPolicyOverride,
}

req := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "argocd",
Name: "name",
},
}

// Verify that on validation error, no error is returned, but the object is requeued
resCreate, err := r.Reconcile(context.Background(), req)
assert.Nil(t, err)
assert.True(t, resCreate.RequeueAfter == 0)

var app v1alpha1.Application

// make sure good app got created
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
assert.Nil(t, err)
assert.Equal(t, app.Name, "good-cluster")

// Update resource
var retrievedApplicationSet v1alpha1.ApplicationSet
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet)
assert.Nil(t, err)

retrievedApplicationSet.Spec.Template.Annotations = map[string]string{"annotation-key": "annotation-value"}
retrievedApplicationSet.Spec.Template.Labels = map[string]string{"argocd.argoproj.io/application-set-name": "name", "label-key": "label-value"}

retrievedApplicationSet.Spec.Template.Spec.Source.Helm = &v1alpha1.ApplicationSourceHelm{
Values: "global.test: test",
}

err = r.Client.Update(context.TODO(), &retrievedApplicationSet)
assert.Nil(t, err)

resUpdate, err := r.Reconcile(context.Background(), req)
assert.Nil(t, err)

err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
assert.Nil(t, err)
assert.True(t, resUpdate.RequeueAfter == 0)
assert.Equal(t, app.Name, "good-cluster")

return app
}

func TestUpdateNotPerformedWithSyncPolicyCreateOnly(t *testing.T) {

applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateOnly

app := applicationsUpdateSyncPolicyTest(t, applicationsSyncPolicy, 1, true)

assert.Nil(t, app.Spec.Source.Helm)
assert.Nil(t, app.ObjectMeta.Annotations)
assert.Equal(t, map[string]string{"argocd.argoproj.io/application-set-name": "name"}, app.ObjectMeta.Labels)
}

func TestUpdateNotPerformedWithSyncPolicyCreateDelete(t *testing.T) {

applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateDelete

app := applicationsUpdateSyncPolicyTest(t, applicationsSyncPolicy, 1, true)

assert.Nil(t, app.Spec.Source.Helm)
assert.Nil(t, app.ObjectMeta.Annotations)
assert.Equal(t, map[string]string{"argocd.argoproj.io/application-set-name": "name"}, app.ObjectMeta.Labels)
}

func TestUpdatePerformedWithSyncPolicyCreateUpdate(t *testing.T) {

applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateUpdate

app := applicationsUpdateSyncPolicyTest(t, applicationsSyncPolicy, 2, true)

assert.Equal(t, "global.test: test", app.Spec.Source.Helm.Values)
assert.Equal(t, map[string]string{"annotation-key": "annotation-value"}, app.ObjectMeta.Annotations)
assert.Equal(t, map[string]string{"argocd.argoproj.io/application-set-name": "name", "label-key": "label-value"}, app.ObjectMeta.Labels)
}

func TestUpdatePerformedWithSyncPolicySync(t *testing.T) {

applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicySync

app := applicationsUpdateSyncPolicyTest(t, applicationsSyncPolicy, 2, true)

assert.Equal(t, "global.test: test", app.Spec.Source.Helm.Values)
assert.Equal(t, map[string]string{"annotation-key": "annotation-value"}, app.ObjectMeta.Annotations)
assert.Equal(t, map[string]string{"argocd.argoproj.io/application-set-name": "name", "label-key": "label-value"}, app.ObjectMeta.Labels)
}

func TestUpdatePerformedWithSyncPolicyCreateOnlyAndAllowPolicyOverrideFalse(t *testing.T) {

applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateOnly

app := applicationsUpdateSyncPolicyTest(t, applicationsSyncPolicy, 2, false)

assert.Equal(t, "global.test: test", app.Spec.Source.Helm.Values)
assert.Equal(t, map[string]string{"annotation-key": "annotation-value"}, app.ObjectMeta.Annotations)
assert.Equal(t, map[string]string{"argocd.argoproj.io/application-set-name": "name", "label-key": "label-value"}, app.ObjectMeta.Labels)
}

func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alpha1.ApplicationsSyncPolicy, recordBuffer int, allowPolicyOverride bool) v1alpha1.ApplicationList {

scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
assert.Nil(t, err)
err = v1alpha1.AddToScheme(scheme)
assert.Nil(t, err)

defaultProject := v1alpha1.AppProject{
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "argocd"},
Spec: v1alpha1.AppProjectSpec{SourceRepos: []string{"*"}, Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "https://good-cluster"}}},
}
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": "good-cluster","url": "https://good-cluster"}`),
}},
},
},
},
SyncPolicy: &v1alpha1.ApplicationSetSyncPolicy{
ApplicationsSync: &applicationsSyncPolicy,
},
Template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "{{cluster}}",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"},
Project: "default",
Destination: v1alpha1.ApplicationDestination{Server: "{{url}}"},
},
},
},
}

kubeclientset := kubefake.NewSimpleClientset()
argoDBMock := dbmocks.ArgoDB{}
argoObjs := []runtime.Object{&defaultProject}

client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build()
goodCluster := v1alpha1.Cluster{Server: "https://good-cluster", Name: "good-cluster"}
argoDBMock.On("GetCluster", mock.Anything, "https://good-cluster").Return(&goodCluster, nil)
argoDBMock.On("ListClusters", mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{
goodCluster,
}}, nil)

r := ApplicationSetReconciler{
Client: client,
Scheme: scheme,
Renderer: &utils.Render{},
Recorder: record.NewFakeRecorder(recordBuffer),
Generators: map[string]generators.Generator{
"List": generators.NewListGenerator(),
},
ArgoDB: &argoDBMock,
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
KubeClientset: kubeclientset,
Policy: v1alpha1.ApplicationsSyncPolicySync,
EnablePolicyOverride: allowPolicyOverride,
}

req := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "argocd",
Name: "name",
},
}

// Verify that on validation error, no error is returned, but the object is requeued
resCreate, err := r.Reconcile(context.Background(), req)
assert.Nil(t, err)
assert.True(t, resCreate.RequeueAfter == 0)

var app v1alpha1.Application

// make sure good app got created
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app)
assert.Nil(t, err)
assert.Equal(t, app.Name, "good-cluster")

// Update resource
var retrievedApplicationSet v1alpha1.ApplicationSet
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet)
assert.Nil(t, err)
retrievedApplicationSet.Spec.Generators = []v1alpha1.ApplicationSetGenerator{
{
List: &v1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{},
},
},
}

err = r.Client.Update(context.TODO(), &retrievedApplicationSet)
assert.Nil(t, err)

resUpdate, err := r.Reconcile(context.Background(), req)
assert.Nil(t, err)

var apps v1alpha1.ApplicationList

err = r.Client.List(context.TODO(), &apps)
assert.Nil(t, err)
assert.True(t, resUpdate.RequeueAfter == 0)

return apps
}

func TestDeleteNotPerformedWithSyncPolicyCreateOnly(t *testing.T) {

applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateOnly

apps := applicationsDeleteSyncPolicyTest(t, applicationsSyncPolicy, 1, true)

assert.Equal(t, "good-cluster", apps.Items[0].Name)
}

func TestDeleteNotPerformedWithSyncPolicyCreateUpdate(t *testing.T) {

applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateUpdate

apps := applicationsDeleteSyncPolicyTest(t, applicationsSyncPolicy, 2, true)

assert.Equal(t, "good-cluster", apps.Items[0].Name)
}

func TestDeletePerformedWithSyncPolicyCreateDelete(t *testing.T) {

applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateDelete

apps := applicationsDeleteSyncPolicyTest(t, applicationsSyncPolicy, 3, true)

assert.Equal(t, 0, len(apps.Items))
}

func TestDeletePerformedWithSyncPolicySync(t *testing.T) {

applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicySync

apps := applicationsDeleteSyncPolicyTest(t, applicationsSyncPolicy, 3, true)

assert.Equal(t, 0, len(apps.Items))
}

func TestDeletePerformedWithSyncPolicyCreateOnlyAndAllowPolicyOverrideFalse(t *testing.T) {

applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateOnly

apps := applicationsDeleteSyncPolicyTest(t, applicationsSyncPolicy, 3, false)

assert.Equal(t, 0, len(apps.Items))
}

// Test app generation from a go template application set using a pull request generator
func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) {
scheme := runtime.NewScheme()
Expand Down
Loading