Repository: argoproj-labs/applicationset
Pull request #55 (2020-09-25 18:35:58)

Refine ApplicationSet SyncPolicy API to be less like ArgoCD.
The ArgoCD core Application.Spec.SyncPolicy is available as part of the
embedded ApplicationSet.Spec.Template.

However we inherited some of this API within the ApplicationSet.Spec
where it does not make sense.

This PR drops the "automated" sub-struct, as automated is really the
only sync policy for an ApplicationSet. We do not support the concept of
a manual Sync from a UI or CLI tool as we would in ArgoCD itself, and as
far as I know this is not desirable.

This PR also drops the "initialSync" field, as I do not believe this
concept makes sense for an ApplicationSet. Applications are always
synced for their ApplicationSet.

ApplicationSet.Spec.SyncPolicy.Automated.Prune then moves up to
ApplicationSet.Spec.SyncPolicy.Prune.

dgoodwin: This PR is for consideration and may be controversial, or I may be missing vision on how this is intended to be used. Core assumption I'm making here is that there will be no UI around ApplicationSets where you click a button to reconcile to your Applications. It just happens via the standard watch/reconcile controller loop. 

If I am mistaken about this then this PR should be closed.

However if not I think the API should be adjusted to better reflect what is possible and prevent Application SyncPolicy concepts from slipping in.

Additionally I changed Prune to SkipPrune, as I believe pruning should be the default behavior, and thus the go default of false would better align with SkipPrune.
OmerKahani: Related to #32 

Patch:
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..67e99b0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2017-2018 The Argo 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.
diff --git a/Makefile b/Makefile
index 756cc34..474e981 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ image:
 
 .PHONY: deploy
 deploy:
-	kustomize build manifests/cluster-install | kubectl apply -f -
+	kustomize build manifests/namespace-install | kubectl apply -f -
 	kubectl patch deployment -n argocd argocd-applicationset-controller --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value": "$(IMAGE)"}]'
 
 # Generate manifests e.g. CRD, RBAC etc.
diff --git a/api/v1alpha1/applicationset_types.go b/api/v1alpha1/applicationset_types.go
index 3b0db37..1fc1175 100644
--- a/api/v1alpha1/applicationset_types.go
+++ b/api/v1alpha1/applicationset_types.go
@@ -23,18 +23,11 @@ type ApplicationSetSpec struct {
 	SyncPolicy *ApplicationSetSyncPolicy `json:"syncPolicy,omitempty"`
 }
 
-// ApplicationSetSyncPolicy will provide a syncPolicy similar to Applications
+// ApplicationSetSyncPolicy configures how generated Applications will relate to their
+// ApplicationSet.
 type ApplicationSetSyncPolicy struct {
-	// Automated will keep an application synced to the target revision
-	Automated *SyncPolicyAutomated `json:"automated,omitempty"`
-}
-
-// SyncPolicyAutomated
-type SyncPolicyAutomated struct {
-	// Prune will prune resources automatically as part of automated sync (default: false)
-	Prune bool `json:"prune,omitempty"`
-	// Initial will perform an initial sync for any newly created Applications which do not have automated sync turned on.
-	Initial bool `json:"initial,omitempty"`
+	// SkipPrune will disable the default behavior which will delete Applications that are no longer being generated for the ApplicationSet which created them, or the ApplicationSet itself is deleted. If SkipPrune is set to true, these Applications will be orphaned but continue to exist.
+	SkipPrune bool `json:"skipPrune,omitempty"`
 }
 
 // ApplicationSetTemplate represents argocd ApplicationSpec
@@ -70,10 +63,10 @@ type ClusterGenerator struct {
 }
 
 type GitGenerator struct {
-	RepoURL     		string                      `json:"repoURL"`
-	Directories 		[]GitDirectoryGeneratorItem `json:"directories,omitempty"`
-	Revision    		string                      `json:"revision"`
-	RequeueAfterSeconds	int64						`json:"requeueAfterSeconds,omitempty"`
+	RepoURL             string                      `json:"repoURL"`
+	Directories         []GitDirectoryGeneratorItem `json:"directories,omitempty"`
+	Revision            string                      `json:"revision"`
+	RequeueAfterSeconds int64                       `json:"requeueAfterSeconds,omitempty"`
 }
 
 type GitDirectoryGeneratorItem struct {
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index fdbd3df..9117f16 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -110,7 +110,7 @@ func (in *ApplicationSetSpec) DeepCopyInto(out *ApplicationSetSpec) {
 	if in.SyncPolicy != nil {
 		in, out := &in.SyncPolicy, &out.SyncPolicy
 		*out = new(ApplicationSetSyncPolicy)
-		(*in).DeepCopyInto(*out)
+		**out = **in
 	}
 }
 
@@ -127,11 +127,6 @@ func (in *ApplicationSetSpec) DeepCopy() *ApplicationSetSpec {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ApplicationSetSyncPolicy) DeepCopyInto(out *ApplicationSetSyncPolicy) {
 	*out = *in
-	if in.Automated != nil {
-		in, out := &in.Automated, &out.Automated
-		*out = new(SyncPolicyAutomated)
-		**out = **in
-	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSetSyncPolicy.
@@ -246,18 +241,3 @@ func (in *ListGeneratorElement) DeepCopy() *ListGeneratorElement {
 	in.DeepCopyInto(out)
 	return out
 }
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SyncPolicyAutomated) DeepCopyInto(out *SyncPolicyAutomated) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SyncPolicyAutomated.
-func (in *SyncPolicyAutomated) DeepCopy() *SyncPolicyAutomated {
-	if in == nil {
-		return nil
-	}
-	out := new(SyncPolicyAutomated)
-	in.DeepCopyInto(out)
-	return out
-}
diff --git a/manifests/base/rbac.yaml b/manifests/base/rbac.yaml
index 9cf2616..fb74c53 100644
--- a/manifests/base/rbac.yaml
+++ b/manifests/base/rbac.yaml
@@ -23,6 +23,7 @@ rules:
     resources:
       - applications
       - applicationsets
+      - applicationsets/finalizers
     verbs:
       - create
       - delete
diff --git a/manifests/cluster-install/kustomization.yaml b/manifests/cluster-install/kustomization.yaml
deleted file mode 100644
index 552d8de..0000000
--- a/manifests/cluster-install/kustomization.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-apiVersion: kustomize.config.k8s.io/v1beta1
-kind: Kustomization
-
-namespace: argocd
-
-resources:
-  - ../namespace-install
-  - ../cluster-rbac
diff --git a/manifests/cluster-rbac/kustomization.yaml b/manifests/cluster-rbac/kustomization.yaml
deleted file mode 100644
index 7221e60..0000000
--- a/manifests/cluster-rbac/kustomization.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-apiVersion: kustomize.config.k8s.io/v1beta1
-kind: Kustomization
-
-namespace: argocd
-
-resources:
-  - rbac.yaml
diff --git a/manifests/cluster-rbac/rbac.yaml b/manifests/cluster-rbac/rbac.yaml
deleted file mode 100644
index c9fcbcd..0000000
--- a/manifests/cluster-rbac/rbac.yaml
+++ /dev/null
@@ -1,69 +0,0 @@
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
-  labels:
-    app.kubernetes.io/name: argocd-applicationset-controller
-    app.kubernetes.io/part-of: argocd-applicationset
-    app.kubernetes.io/component: controller
-  name: argocd-applicationset-controller
-rules:
-  - apiGroups:
-      - argoproj.io
-    resources:
-      - applications
-      - applicationsets
-    verbs:
-      - create
-      - delete
-      - get
-      - list
-      - patch
-      - update
-      - watch
-  - apiGroups:
-      - argoproj.io
-    resources:
-      - applicationsets/status
-    verbs:
-      - get
-      - patch
-      - update
-  - apiGroups:
-      - ''
-    resources:
-      - events
-    verbs:
-      - create
-      - delete
-      - get
-      - list
-      - patch
-      - update
-      - watch
-  - apiGroups:
-      - ''
-    resources:
-      - secrets
-      - configmaps
-    verbs:
-      - get
-      - list
-      - watch
-
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
-  labels:
-    app.kubernetes.io/name: argocd-applicationset-controller
-    app.kubernetes.io/part-of: argocd-applicationset
-    app.kubernetes.io/component: controller
-  name: argocd-applicationset-controller
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: argocd-applicationset-controller
-subjects:
-  - kind: ServiceAccount
-    name: argocd-applicationset-controller
diff --git a/manifests/crds/applicationset-crd.yaml b/manifests/crds/argoproj.io_applicationsets.yaml
similarity index 69%
rename from manifests/crds/applicationset-crd.yaml
rename to manifests/crds/argoproj.io_applicationsets.yaml
index e86da15..9393ec5 100644
--- a/manifests/crds/applicationset-crd.yaml
+++ b/manifests/crds/argoproj.io_applicationsets.yaml
@@ -1,3 +1,4 @@
+
 ---
 apiVersion: apiextensions.k8s.io/v1beta1
 kind: CustomResourceDefinition
@@ -5,9 +6,6 @@ metadata:
   annotations:
     controller-gen.kubebuilder.io/version: v0.3.0
   creationTimestamp: null
-  labels:
-    app.kubernetes.io/name: applicationsets.argoproj.io
-    app.kubernetes.io/part-of: argocd-applicationset
   name: applicationsets.argoproj.io
 spec:
   group: argoproj.io
@@ -22,14 +20,12 @@ spec:
       description: ApplicationSet is a set of Application resources
       properties:
         apiVersion:
-          description:
-            'APIVersion defines the versioned schema of this representation
+          description: 'APIVersion defines the versioned schema of this representation
             of an object. Servers should convert recognized schemas to the latest
             internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
           type: string
         kind:
-          description:
-            'Kind is a string value representing the REST resource this
+          description: 'Kind is a string value representing the REST resource this
             object represents. Servers may infer this from the endpoint the client
             submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
           type: string
@@ -43,41 +39,34 @@ spec:
                 description: ApplicationSetGenerator include list item info
                 properties:
                   clusters:
-                    description:
-                      ClusterGenerator defines a generator to match against
+                    description: ClusterGenerator defines a generator to match against
                       clusters registered with ArgoCD.
                     properties:
                       selector:
-                        description:
-                          Selector defines a label selector to match against
+                        description: Selector defines a label selector to match against
                           all clusters registered with ArgoCD. Clusters today are
                           stored as Kubernetes Secrets, thus the Secret labels will
                           be used for matching the selector.
                         properties:
                           matchExpressions:
-                            description:
-                              matchExpressions is a list of label selector
+                            description: matchExpressions is a list of label selector
                               requirements. The requirements are ANDed.
                             items:
-                              description:
-                                A label selector requirement is a selector
+                              description: A label selector requirement is a selector
                                 that contains values, a key, and an operator that
                                 relates the key and values.
                               properties:
                                 key:
-                                  description:
-                                    key is the label key that the selector
+                                  description: key is the label key that the selector
                                     applies to.
                                   type: string
                                 operator:
-                                  description:
-                                    operator represents a key's relationship
+                                  description: operator represents a key's relationship
                                     to a set of values. Valid operators are In, NotIn,
                                     Exists and DoesNotExist.
                                   type: string
                                 values:
-                                  description:
-                                    values is an array of string values.
+                                  description: values is an array of string values.
                                     If the operator is In or NotIn, the values array
                                     must be non-empty. If the operator is Exists or
                                     DoesNotExist, the values array must be empty.
@@ -87,15 +76,14 @@ spec:
                                     type: string
                                   type: array
                               required:
-                                - key
-                                - operator
+                              - key
+                              - operator
                               type: object
                             type: array
                           matchLabels:
                             additionalProperties:
                               type: string
-                            description:
-                              matchLabels is a map of {key,value} pairs.
+                            description: matchLabels is a map of {key,value} pairs.
                               A single {key,value} in the matchLabels map is equivalent
                               to an element of matchExpressions, whose key field is
                               "key", the operator is "In", and the values array contains
@@ -111,16 +99,16 @@ spec:
                             path:
                               type: string
                           required:
-                            - path
+                          - path
                           type: object
                         type: array
                       repoURL:
                         type: string
-                      revision:
-                        type: string
                       requeueAfterSeconds:
                         format: int64
                         type: integer
+                      revision:
+                        type: string
                     required:
                     - repoURL
                     - revision
@@ -137,37 +125,26 @@ spec:
                             url:
                               type: string
                           required:
-                            - cluster
-                            - url
+                          - cluster
+                          - url
                           type: object
                         type: array
                     required:
-                      - elements
+                    - elements
                     type: object
                 type: object
               type: array
             syncPolicy:
-              description:
-                ApplicationSetSyncPolicy will provide a syncPolicy similar
-                to Applications
+              description: ApplicationSetSyncPolicy configures how generated Applications
+                will relate to their ApplicationSet.
               properties:
-                automated:
-                  description:
-                    Automated will keep an application synced to the target
-                    revision
-                  properties:
-                    initial:
-                      description:
-                        Initial will perform an initial sync for any newly
-                        created Applications which do not have automated sync turned
-                        on.
-                      type: boolean
-                    prune:
-                      description:
-                        'Prune will prune resources automatically as part
-                        of automated sync (default: false)'
-                      type: boolean
-                  type: object
+                skipPrune:
+                  description: SkipPrune will disable the default behavior which will
+                    delete Applications that are no longer being generated for the
+                    ApplicationSet which created them, or the ApplicationSet itself
+                    is deleted. If SkipPrune is set to true, these Applications will
+                    be orphaned but continue to exist.
+                  type: boolean
               type: object
             template:
               description: ApplicationSetTemplate represents argocd ApplicationSpec
@@ -175,34 +152,32 @@ spec:
                 metadata:
                   type: object
                 spec:
-                  description:
-                    ApplicationSpec represents desired application state.
+                  description: ApplicationSpec represents desired application state.
                     Contains link to repository with application definition and additional
                     parameters link definition revision.
                   properties:
                     destination:
-                      description:
-                        Destination overrides the kubernetes server and
+                      description: Destination overrides the kubernetes server and
                         namespace defined in the environment ksonnet app.yaml
                       properties:
+                        name:
+                          description: Name of the destination cluster which can be
+                            used instead of server (url) field
+                          type: string
                         namespace:
-                          description:
-                            Namespace overrides the environment namespace
+                          description: Namespace overrides the environment namespace
                             value in the ksonnet app.yaml
                           type: string
                         server:
-                          description:
-                            Server overrides the environment server value
+                          description: Server overrides the environment server value
                             in the ksonnet app.yaml
                           type: string
                       type: object
                     ignoreDifferences:
-                      description:
-                        IgnoreDifferences controls resources fields which
+                      description: IgnoreDifferences controls resources fields which
                         should be ignored during comparison
                       items:
-                        description:
-                          ResourceIgnoreDifferences contains resource filter
+                        description: ResourceIgnoreDifferences contains resource filter
                           and list of json paths which should be ignored during comparison
                           with live state.
                         properties:
@@ -219,13 +194,12 @@ spec:
                           namespace:
                             type: string
                         required:
-                          - jsonPointers
-                          - kind
+                        - jsonPointers
+                        - kind
                         type: object
                       type: array
                     info:
-                      description:
-                        Infos contains a list of useful information (URLs,
+                      description: Infos contains a list of useful information (URLs,
                         email addresses, and plain text) that relates to the application
                       items:
                         properties:
@@ -234,18 +208,16 @@ spec:
                           value:
                             type: string
                         required:
-                          - name
-                          - value
+                        - name
+                        - value
                         type: object
                       type: array
                     project:
-                      description:
-                        Project is a application project name. Empty name
+                      description: Project is a application project name. Empty name
                         means that application belongs to 'default' project.
                       type: string
                     revisionHistoryLimit:
-                      description:
-                        This limits this number of items kept in the apps
+                      description: This limits this number of items kept in the apps
                         revision history. This should only be changed in exceptional
                         circumstances. Setting to zero will store no history. This
                         will reduce storage used. Increasing will increase the space
@@ -254,8 +226,7 @@ spec:
                       format: int64
                       type: integer
                     source:
-                      description:
-                        Source is a reference to the location ksonnet application
+                      description: Source is a reference to the location ksonnet application
                         definition
                       properties:
                         chart:
@@ -265,13 +236,11 @@ spec:
                           description: Directory holds path/directory specific options
                           properties:
                             jsonnet:
-                              description:
-                                ApplicationSourceJsonnet holds jsonnet
+                              description: ApplicationSourceJsonnet holds jsonnet
                                 specific options
                               properties:
                                 extVars:
-                                  description:
-                                    ExtVars is a list of Jsonnet External
+                                  description: ExtVars is a list of Jsonnet External
                                     Variables
                                   items:
                                     description: JsonnetVar is a jsonnet variable
@@ -283,13 +252,17 @@ spec:
                                       value:
                                         type: string
                                     required:
-                                      - name
-                                      - value
+                                    - name
+                                    - value
                                     type: object
                                   type: array
+                                libs:
+                                  description: Additional library search dirs
+                                  items:
+                                    type: string
+                                  type: array
                                 tlas:
-                                  description:
-                                    TLAS is a list of Jsonnet Top-level
+                                  description: TLAS is a list of Jsonnet Top-level
                                     Arguments
                                   items:
                                     description: JsonnetVar is a jsonnet variable
@@ -301,8 +274,8 @@ spec:
                                       value:
                                         type: string
                                     required:
-                                      - name
-                                      - value
+                                    - name
+                                    - value
                                     type: object
                                   type: array
                               type: object
@@ -313,20 +286,17 @@ spec:
                           description: Helm holds helm specific options
                           properties:
                             fileParameters:
-                              description:
-                                FileParameters are file parameters to the
+                              description: FileParameters are file parameters to the
                                 helm template
                               items:
-                                description:
-                                  HelmFileParameter is a file parameter
+                                description: HelmFileParameter is a file parameter
                                   to a helm template
                                 properties:
                                   name:
                                     description: Name is the name of the helm parameter
                                     type: string
                                   path:
-                                    description:
-                                      Path is the path value for the helm
+                                    description: Path is the path value for the helm
                                       parameter
                                     type: string
                                 type: object
@@ -334,13 +304,11 @@ spec:
                             parameters:
                               description: Parameters are parameters to the helm template
                               items:
-                                description:
-                                  HelmParameter is a parameter to a helm
+                                description: HelmParameter is a parameter to a helm
                                   template
                                 properties:
                                   forceString:
-                                    description:
-                                      ForceString determines whether to
+                                    description: ForceString determines whether to
                                       tell Helm to interpret booleans and numbers
                                       as strings
                                     type: boolean
@@ -353,20 +321,17 @@ spec:
                                 type: object
                               type: array
                             releaseName:
-                              description:
-                                The Helm release name. If omitted it will
+                              description: The Helm release name. If omitted it will
                                 use the application name
                               type: string
                             valueFiles:
-                              description:
-                                ValuesFiles is a list of Helm value files
+                              description: ValuesFiles is a list of Helm value files
                                 to use when generating a template
                               items:
                                 type: string
                               type: array
                             values:
-                              description:
-                                Values is Helm values, typically defined
+                              description: Values is Helm values, typically defined
                                 as a block
                               type: string
                           type: object
@@ -374,17 +339,14 @@ spec:
                           description: Ksonnet holds ksonnet specific options
                           properties:
                             environment:
-                              description:
-                                Environment is a ksonnet application environment
+                              description: Environment is a ksonnet application environment
                                 name
                               type: string
                             parameters:
-                              description:
-                                Parameters are a list of ksonnet component
+                              description: Parameters are a list of ksonnet component
                                 parameter override values
                               items:
-                                description:
-                                  KsonnetParameter is a ksonnet component
+                                description: KsonnetParameter is a ksonnet component
                                   parameter
                                 properties:
                                   component:
@@ -394,8 +356,8 @@ spec:
                                   value:
                                     type: string
                                 required:
-                                  - name
-                                  - value
+                                - name
+                                - value
                                 type: object
                               type: array
                           type: object
@@ -405,8 +367,7 @@ spec:
                             commonLabels:
                               additionalProperties:
                                 type: string
-                              description:
-                                CommonLabels adds additional kustomize
+                              description: CommonLabels adds additional kustomize
                                 commonLabels
                               type: object
                             images:
@@ -415,13 +376,11 @@ spec:
                                 type: string
                               type: array
                             namePrefix:
-                              description:
-                                NamePrefix is a prefix appended to resources
+                              description: NamePrefix is a prefix appended to resources
                                 for kustomize apps
                               type: string
                             nameSuffix:
-                              description:
-                                NameSuffix is a suffix appended to resources
+                              description: NameSuffix is a suffix appended to resources
                                 for kustomize apps
                               type: string
                             version:
@@ -432,8 +391,7 @@ spec:
                           description: Path is a directory path within the Git repository
                           type: string
                         plugin:
-                          description:
-                            ConfigManagementPlugin holds config management
+                          description: ConfigManagementPlugin holds config management
                             plugin specific options
                           properties:
                             env:
@@ -446,71 +404,99 @@ spec:
                                     description: the value
                                     type: string
                                 required:
-                                  - name
-                                  - value
+                                - name
+                                - value
                                 type: object
                               type: array
                             name:
                               type: string
                           type: object
                         repoURL:
-                          description:
-                            RepoURL is the repository URL of the application
+                          description: RepoURL is the repository URL of the application
                             manifests
                           type: string
                         targetRevision:
-                          description:
-                            TargetRevision defines the commit, tag, or
+                          description: TargetRevision defines the commit, tag, or
                             branch in which to sync the application to. If omitted,
                             will sync to HEAD
                           type: string
                       required:
-                        - repoURL
+                      - repoURL
                       type: object
                     syncPolicy:
                       description: SyncPolicy controls when a sync will be performed
                       properties:
                         automated:
-                          description:
-                            Automated will keep an application synced to
+                          description: Automated will keep an application synced to
                             the target revision
                           properties:
                             prune:
-                              description:
-                                'Prune will prune resources automatically
+                              description: 'Prune will prune resources automatically
                                 as part of automated sync (default: false)'
                               type: boolean
                             selfHeal:
-                              description:
-                                'SelfHeal enables auto-syncing if  (default:
+                              description: 'SelfHeal enables auto-syncing if  (default:
                                 false)'
                               type: boolean
                           type: object
+                        retry:
+                          description: Retry controls failed sync retry behavior
+                          properties:
+                            backoff:
+                              description: Backoff is a backoff strategy
+                              properties:
+                                duration:
+                                  description: Duration is the amount to back off.
+                                    Default unit is seconds, but could also be a duration
+                                    (e.g. "2m", "1h")
+                                  type: string
+                                factor:
+                                  description: Factor is a factor to multiply the
+                                    base duration after each failed retry
+                                  format: int64
+                                  type: integer
+                                maxDuration:
+                                  description: MaxDuration is the maximum amount of
+                                    time allowed for the backoff strategy
+                                  type: string
+                              type: object
+                            limit:
+                              description: Limit is the maximum number of attempts
+                                when retrying a container
+                              format: int64
+                              type: integer
+                          type: object
                         syncOptions:
-                          description: Options allow youe to specify whole app sync-options
+                          description: Options allow you to specify whole app sync-options
                           items:
                             type: string
                           type: array
                       type: object
                   required:
-                    - destination
-                    - project
-                    - source
+                  - destination
+                  - project
+                  - source
                   type: object
               required:
-                - metadata
-                - spec
+              - metadata
+              - spec
               type: object
           required:
-            - generators
-            - template
+          - generators
+          - template
           type: object
       required:
-        - metadata
-        - spec
+      - metadata
+      - spec
       type: object
   version: v1alpha1
   versions:
-    - name: v1alpha1
-      served: true
-      storage: true
+  - name: v1alpha1
+    served: true
+    storage: true
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
diff --git a/pkg/controllers/applicationset_controller.go b/pkg/controllers/applicationset_controller.go
index 829b61b..e5df7f9 100644
--- a/pkg/controllers/applicationset_controller.go
+++ b/pkg/controllers/applicationset_controller.go
@@ -19,6 +19,9 @@ package controllers
 import (
 	"context"
 	"fmt"
+	"reflect"
+	"time"
+
 	"github.com/argoproj-labs/applicationset/pkg/generators"
 	"github.com/argoproj-labs/applicationset/pkg/utils"
 	argov1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
@@ -26,11 +29,9 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/tools/record"
 	"k8s.io/kubernetes/pkg/apis/core"
-	"reflect"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 	"sigs.k8s.io/controller-runtime/pkg/handler"
 	"sigs.k8s.io/controller-runtime/pkg/source"
-	"time"
 
 	log "github.com/sirupsen/logrus"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -43,8 +44,8 @@ import (
 // ApplicationSetReconciler reconciles a ApplicationSet object
 type ApplicationSetReconciler struct {
 	client.Client
-	Scheme   *runtime.Scheme
-	Recorder record.EventRecorder
+	Scheme     *runtime.Scheme
+	Recorder   record.EventRecorder
 	Generators map[string]generators.Generator
 	utils.Policy
 	utils.Renderer
@@ -99,7 +100,7 @@ func (r *ApplicationSetReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
 	}, nil
 }
 
-func (r *ApplicationSetReconciler) GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator) []generators.Generator{
+func (r *ApplicationSetReconciler) GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator) []generators.Generator {
 	var res []generators.Generator
 
 	v := reflect.Indirect(reflect.ValueOf(requestedGenerator))
@@ -109,7 +110,7 @@ func (r *ApplicationSetReconciler) GetRelevantGenerators(requestedGenerator *arg
 			continue
 		}
 
-		if !reflect.ValueOf(field.Interface()).IsNil()  {
+		if !reflect.ValueOf(field.Interface()).IsNil() {
 			res = append(res, r.Generators[v.Type().Field(i).Name])
 		}
 	}
@@ -117,7 +118,7 @@ func (r *ApplicationSetReconciler) GetRelevantGenerators(requestedGenerator *arg
 	return res
 }
 
-func (r *ApplicationSetReconciler) getMinRequeueAfter(applicationSetInfo *argoprojiov1alpha1.ApplicationSet) time.Duration{
+func (r *ApplicationSetReconciler) getMinRequeueAfter(applicationSetInfo *argoprojiov1alpha1.ApplicationSet) time.Duration {
 	var res time.Duration
 	for _, requestedGenerator := range applicationSetInfo.Spec.Generators {
 
@@ -137,8 +138,9 @@ func (r *ApplicationSetReconciler) getMinRequeueAfter(applicationSetInfo *argopr
 	return res
 }
 
-func getTempApplication(applicationSetTemplate argoprojiov1alpha1.ApplicationSetTemplate) *argov1alpha1.Application{
+func getTempApplication(applicationSetTemplate argoprojiov1alpha1.ApplicationSetTemplate) *argov1alpha1.Application {
 	var tmplApplication argov1alpha1.Application
+	tmplApplication.Annotations = applicationSetTemplate.Annotations
 	tmplApplication.Labels = applicationSetTemplate.Labels
 	tmplApplication.Namespace = applicationSetTemplate.Namespace
 	tmplApplication.Name = applicationSetTemplate.Name
@@ -250,13 +252,12 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
 	return firstError
 }
 
-
 // createInCluster will filter from the desiredApplications only the application that needs to be created
 // Then it will call createOrUpdateInCluster to do the actual create
 func (r *ApplicationSetReconciler) createInCluster(ctx context.Context, applicationSet argoprojiov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
 
 	var createApps []argov1alpha1.Application
-	current, err := r.getCurrentApplications(ctx,applicationSet)
+	current, err := r.getCurrentApplications(ctx, applicationSet)
 	if err != nil {
 		return err
 	}
@@ -279,7 +280,7 @@ func (r *ApplicationSetReconciler) createInCluster(ctx context.Context, applicat
 	return r.createOrUpdateInCluster(ctx, applicationSet, createApps)
 }
 
-func (r *ApplicationSetReconciler) getCurrentApplications(ctx context.Context, applicationSet argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error){
+func (r *ApplicationSetReconciler) getCurrentApplications(ctx context.Context, applicationSet argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) {
 	var current argov1alpha1.ApplicationList
 	err := r.Client.List(context.Background(), &current, client.MatchingFields{".metadata.controller": applicationSet.Name})
 
@@ -295,7 +296,7 @@ func (r *ApplicationSetReconciler) getCurrentApplications(ctx context.Context, a
 func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, applicationSet argoprojiov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
 
 	// Save current applications to be able to delete the ones that are not in appList
-	current,err := r.getCurrentApplications(ctx,applicationSet)
+	current, err := r.getCurrentApplications(ctx, applicationSet)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/generators/cluster.go b/pkg/generators/cluster.go
index b93de63..5fde9d8 100644
--- a/pkg/generators/cluster.go
+++ b/pkg/generators/cluster.go
@@ -26,7 +26,6 @@ type ClusterGenerator struct {
 	client.Client
 }
 
-
 func NewClusterGenerator(c client.Client) Generator {
 	g := &ClusterGenerator{
 		Client: c,
@@ -34,7 +33,7 @@ func NewClusterGenerator(c client.Client) Generator {
 	return g
 }
 
-func (g * ClusterGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {
+func (g *ClusterGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {
 	return NoRequeueAfter
 }
 
@@ -65,9 +64,12 @@ func (g *ClusterGenerator) GenerateParams(
 
 	res := make([]map[string]string, len(clusterSecretList.Items))
 	for i, cluster := range clusterSecretList.Items {
-		params := make(map[string]string, len(cluster.ObjectMeta.Labels) + 2)
+		params := make(map[string]string, len(cluster.ObjectMeta.Annotations)+len(cluster.ObjectMeta.Labels)+2)
 		params["name"] = string(cluster.Data["name"])
 		params["server"] = string(cluster.Data["server"])
+		for key, value := range cluster.ObjectMeta.Annotations {
+			params[fmt.Sprintf("metadata.annotations.%s", key)] = value
+		}
 		for key, value := range cluster.ObjectMeta.Labels {
 			params[fmt.Sprintf("metadata.labels.%s", key)] = value
 		}


Test patch:
diff --git a/pkg/generators/cluster_test.go b/pkg/generators/cluster_test.go
index 803a1d3..a6bdedb 100644
--- a/pkg/generators/cluster_test.go
+++ b/pkg/generators/cluster_test.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"encoding/base64"
 	"errors"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -11,9 +12,10 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 
-	argoprojiov1alpha1 "github.com/argoproj-labs/applicationset/api/v1alpha1"
 	"testing"
 
+	argoprojiov1alpha1 "github.com/argoproj-labs/applicationset/api/v1alpha1"
+
 	"github.com/stretchr/testify/assert"
 )
 
@@ -44,6 +46,9 @@ func TestGenerateParams(t *testing.T) {
 					"environment":                    "staging",
 					"org":                            "foo",
 				},
+				Annotations: map[string]string{
+					"foo.argoproj.io": "staging",
+				},
 			},
 			Data: map[string][]byte{
 				"config": []byte(base64.StdEncoding.EncodeToString([]byte("foo"))),
@@ -65,6 +70,9 @@ func TestGenerateParams(t *testing.T) {
 					"environment":                    "production",
 					"org":                            "bar",
 				},
+				Annotations: map[string]string{
+					"foo.argoproj.io": "production",
+				},
 			},
 			Data: map[string][]byte{
 				"config": []byte(base64.StdEncoding.EncodeToString([]byte("foo"))),
@@ -83,8 +91,8 @@ func TestGenerateParams(t *testing.T) {
 		{
 			metav1.LabelSelector{},
 			[]map[string]string{
-				{"name": "c3RhZ2luZy0wMQ==", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org":"foo", "metadata.labels.argocd.argoproj.io/secret-type": "cluster"},
-				{"name": "cHJvZHVjdGlvbi0wMQ==", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org":"bar", "metadata.labels.argocd.argoproj.io/secret-type": "cluster"},
+				{"name": "c3RhZ2luZy0wMQ==", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo", "metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging"},
+				{"name": "cHJvZHVjdGlvbi0wMQ==", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar", "metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production"},
 			},
 			false,
 			nil,
@@ -96,7 +104,7 @@ func TestGenerateParams(t *testing.T) {
 				},
 			},
 			[]map[string]string{
-				{"name": "cHJvZHVjdGlvbi0wMQ==", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org":"bar", "metadata.labels.argocd.argoproj.io/secret-type": "cluster"},
+				{"name": "cHJvZHVjdGlvbi0wMQ==", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar", "metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production"},
 			},
 			false,
 			nil,
@@ -115,8 +123,8 @@ func TestGenerateParams(t *testing.T) {
 				},
 			},
 			[]map[string]string{
-				{"name": "c3RhZ2luZy0wMQ==", "server": "https://staging-01.example.com", "metadata.labels.argocd.argoproj.io/secret-type":"cluster", "metadata.labels.environment": "staging", "metadata.labels.org":"foo"},
-				{"name": "cHJvZHVjdGlvbi0wMQ==", "server": "https://production-01.example.com", "metadata.labels.argocd.argoproj.io/secret-type":"cluster", "metadata.labels.environment": "production", "metadata.labels.org":"bar"},
+				{"name": "c3RhZ2luZy0wMQ==", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo", "metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging"},
+				{"name": "cHJvZHVjdGlvbi0wMQ==", "server": "https://production-01.example.com", "metadata.labels.environment": "production", "metadata.labels.org": "bar", "metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "production"},
 			},
 			false,
 			nil,
@@ -138,7 +146,7 @@ func TestGenerateParams(t *testing.T) {
 				},
 			},
 			[]map[string]string{
-				{"name": "c3RhZ2luZy0wMQ==", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org":"foo", "metadata.labels.argocd.argoproj.io/secret-type":"cluster"},
+				{"name": "c3RhZ2luZy0wMQ==", "server": "https://staging-01.example.com", "metadata.labels.environment": "staging", "metadata.labels.org": "foo", "metadata.labels.argocd.argoproj.io/secret-type": "cluster", "metadata.annotations.foo.argoproj.io": "staging"},
 			},
 			false,
 			nil,