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): ApplicationSet in any namespace #12378

Merged
merged 37 commits into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
06d70cc
12107: ApplicationSet in any namespaces
speedfl Feb 17, 2023
1474668
12107: fix build
speedfl Feb 17, 2023
cd30116
Merge branch 'master' into feature/12107
speedfl Mar 3, 2023
beda433
Merge branch 'master' of github.com:speedfl/argo-cd into feature/12107
speedfl May 2, 2023
9f313ee
12107: Fix lint
speedfl May 2, 2023
f239352
Merge branch 'master' into feature/12107
speedfl May 3, 2023
aeb52f5
Merge branch 'master' into feature/12107
speedfl May 5, 2023
9240bb0
Merge branch 'master' of github.com:speedfl/argo-cd into feature/12107
speedfl May 10, 2023
f3a6b23
Merge branch 'master' into feature/12107
speedfl May 12, 2023
b76eef2
Merge branch 'master' into feature/12107
speedfl May 12, 2023
c682ab7
Merge branch 'master' into feature/12107
speedfl May 15, 2023
5f5e8a1
Merge branch 'master' into feature/12107
speedfl May 17, 2023
1da2472
Merge branch 'master' of github.com:speedfl/argo-cd into feature/12107
speedfl May 29, 2023
8e2bd99
12107: Fix After review 2
speedfl May 29, 2023
4689f00
12107: Fix After review 2
speedfl May 29, 2023
5cedd8c
Merge branch 'master' into feature/12107
speedfl May 29, 2023
97fbc5a
Merge branch 'master' into feature/12107
speedfl May 30, 2023
ee9d5fd
Merge branch 'master' into feature/12107
speedfl May 31, 2023
b5e6360
Merge branch 'master' into feature/12107
speedfl Jun 1, 2023
c5fde60
Merge branch 'master' of github.com:speedfl/argo-cd into feature/12107
speedfl Jun 5, 2023
7f434dd
Merge branch 'master' into feature/12107
speedfl Jun 7, 2023
8ad18e1
Merge branch 'master' into feature/12107
speedfl Jun 7, 2023
50b95dc
Merge branch 'master' into feature/12107
speedfl Jun 7, 2023
6b81b19
Merge branch 'master' into feature/12107
speedfl Jun 8, 2023
d485b63
Merge branch 'master' into feature/12107
speedfl Jun 13, 2023
c055845
Merge branch 'master' into feature/12107
speedfl Jun 13, 2023
705b9b7
Merge branch 'master' of github.com:speedfl/argo-cd into feature/12107
speedfl Jun 22, 2023
dbb8d16
12107: Fix after rebase
speedfl Jun 22, 2023
9ad6655
12107: Fix syncspolicy after rebase
speedfl Jun 22, 2023
7968341
12107: Fix tests labels
speedfl Jun 22, 2023
eb385aa
12107: Fix tests labels 2
speedfl Jun 22, 2023
a18c011
12107: Fix after review
speedfl Jun 22, 2023
b3d2df5
Merge branch 'master' into feature/12107
speedfl Jun 22, 2023
47fccac
Merge branch 'master' into feature/12107
speedfl Jun 23, 2023
43005dd
match existing appset controller arg pattern
crenshaw-dev Jun 25, 2023
e9b769b
Merge remote-tracking branch 'origin/master' into feature/12107
crenshaw-dev Jun 25, 2023
fec35ea
remove unused env var
crenshaw-dev Jun 25, 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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ start-e2e-local: mod-vendor-local dep-ui-local cli-local
ARGOCD_IN_CI=$(ARGOCD_IN_CI) \
BIN_MODE=$(ARGOCD_BIN_MODE) \
ARGOCD_APPLICATION_NAMESPACES=argocd-e2e-external \
ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES=argocd-e2e-external \
ARGOCD_E2E_TEST=true \
goreman -f $(ARGOCD_PROCFILE) start ${ARGOCD_START}

Expand Down
27 changes: 19 additions & 8 deletions applicationset/controllers/applicationset_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import (
"github.com/argoproj/argo-cd/v2/applicationset/utils"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/util/db"
"github.com/argoproj/argo-cd/v2/util/glob"

argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
Expand Down Expand Up @@ -82,8 +83,9 @@ type ApplicationSetReconciler struct {
Policy argov1alpha1.ApplicationsSyncPolicy
EnablePolicyOverride bool
utils.Renderer

EnableProgressiveSyncs bool
ArgoCDNamespace string
ApplicationSetNamespaces []string
EnableProgressiveSyncs bool
}

// +kubebuilder:rbac:groups=argoproj.io,resources=applicationsets,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -126,7 +128,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque

parametersGenerated = true

validateErrors, err := r.validateGeneratedApplications(ctx, desiredApplications, applicationSetInfo, req.Namespace)
validateErrors, err := r.validateGeneratedApplications(ctx, desiredApplications, applicationSetInfo)
if err != nil {
// While some generators may return an error that requires user intervention,
// other generators reference external resources that may change to cause
Expand Down Expand Up @@ -417,7 +419,7 @@ func (r *ApplicationSetReconciler) setApplicationSetStatusCondition(ctx context.

// validateGeneratedApplications uses the Argo CD validation functions to verify the correctness of the
// generated applications.
func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Context, desiredApplications []argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet, namespace string) (map[int]error, error) {
func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Context, desiredApplications []argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet) (map[int]error, error) {
errorsByIndex := map[int]error{}
namesSet := map[string]bool{}
for i, app := range desiredApplications {
Expand All @@ -429,7 +431,7 @@ func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Con
continue
}

proj, err := r.ArgoAppClientset.ArgoprojV1alpha1().AppProjects(namespace).Get(ctx, app.Spec.GetProject(), metav1.GetOptions{})
proj, err := r.ArgoAppClientset.ArgoprojV1alpha1().AppProjects(r.ArgoCDNamespace).Get(ctx, app.Spec.GetProject(), metav1.GetOptions{})
if err != nil {
if apierr.IsNotFound(err) {
errorsByIndex[i] = fmt.Errorf("application references project %s which does not exist", app.Spec.Project)
Expand All @@ -438,7 +440,7 @@ func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Con
return nil, err
}

if err := utils.ValidateDestination(ctx, &app.Spec.Destination, r.KubeClientset, namespace); err != nil {
if err := utils.ValidateDestination(ctx, &app.Spec.Destination, r.KubeClientset, r.ArgoCDNamespace); err != nil {
errorsByIndex[i] = fmt.Errorf("application destination spec is invalid: %s", err.Error())
continue
}
Expand Down Expand Up @@ -537,6 +539,14 @@ func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argov
return res, applicationSetReason, firstError
}

func ignoreNotAllowedNamespaces(namespaces []string) predicate.Predicate {
return predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
return glob.MatchStringInList(namespaces, e.Object.GetNamespace(), false)
},
}
}

func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager, enableProgressiveSyncs bool, maxConcurrentReconciliations int) error {
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &argov1alpha1.Application{}, ".metadata.controller", func(rawObj client.Object) []string {
// grab the job object, extract the owner...
Expand All @@ -562,6 +572,7 @@ func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager, enableProg
MaxConcurrentReconciles: maxConcurrentReconciliations,
}).For(&argov1alpha1.ApplicationSet{}).
Owns(&argov1alpha1.Application{}, builder.WithPredicates(ownsHandler)).
WithEventFilter(ignoreNotAllowedNamespaces(r.ApplicationSetNamespaces)).
Watches(
&source.Kind{Type: &corev1.Secret{}},
&clusterSecretEventHandler{
Expand Down Expand Up @@ -689,7 +700,7 @@ func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, applicat
// settingsMgr := settings.NewSettingsManager(context.TODO(), r.KubeClientset, applicationSet.Namespace)
// argoDB := db.NewDB(applicationSet.Namespace, settingsMgr, r.KubeClientset)
// clusterList, err := argoDB.ListClusters(ctx)
clusterList, err := utils.ListClusters(ctx, r.KubeClientset, applicationSet.Namespace)
clusterList, err := utils.ListClusters(ctx, r.KubeClientset, r.ArgoCDNamespace)
if err != nil {
return fmt.Errorf("error listing clusters: %w", err)
}
Expand Down Expand Up @@ -750,7 +761,7 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte
var validDestination bool

// Detect if the destination is invalid (name doesn't correspond to a matching cluster)
if err := utils.ValidateDestination(ctx, &app.Spec.Destination, r.KubeClientset, applicationSet.Namespace); err != nil {
if err := utils.ValidateDestination(ctx, &app.Spec.Destination, r.KubeClientset, r.ArgoCDNamespace); err != nil {
appLog.Warnf("The destination cluster for %s couldn't be found: %v", app.Name, err)
validDestination = false
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1815,13 +1815,14 @@ func TestValidateGeneratedApplications(t *testing.T) {
Recorder: record.NewFakeRecorder(1),
Generators: map[string]generators.Generator{},
ArgoDB: &argoDBMock,
ArgoCDNamespace: "namespace",
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
KubeClientset: kubeclientset,
}

appSetInfo := v1alpha1.ApplicationSet{}

validationErrors, _ := r.validateGeneratedApplications(context.TODO(), cc.apps, appSetInfo, "namespace")
validationErrors, _ := r.validateGeneratedApplications(context.TODO(), cc.apps, appSetInfo)
var errorMessages []string
for _, v := range validationErrors {
errorMessages = append(errorMessages, v.Error())
Expand Down Expand Up @@ -1923,6 +1924,7 @@ func TestReconcilerValidationErrorBehaviour(t *testing.T) {
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
KubeClientset: kubeclientset,
Policy: v1alpha1.ApplicationsSyncPolicySync,
ArgoCDNamespace: "argocd",
}

req := ctrl.Request{
Expand Down Expand Up @@ -2069,6 +2071,7 @@ func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
"List": generators.NewListGenerator(),
},
ArgoDB: &argoDBMock,
ArgoCDNamespace: "argocd",
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
KubeClientset: kubeclientset,
Policy: v1alpha1.ApplicationsSyncPolicySync,
Expand Down Expand Up @@ -2239,6 +2242,7 @@ func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp
"List": generators.NewListGenerator(),
},
ArgoDB: &argoDBMock,
ArgoCDNamespace: "argocd",
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
KubeClientset: kubeclientset,
Policy: v1alpha1.ApplicationsSyncPolicySync,
Expand Down Expand Up @@ -2543,6 +2547,7 @@ func TestPolicies(t *testing.T) {
"List": generators.NewListGenerator(),
},
ArgoDB: &argoDBMock,
ArgoCDNamespace: "argocd",
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
KubeClientset: kubeclientset,
Policy: policy,
Expand Down
8 changes: 4 additions & 4 deletions applicationset/utils/clusterUtils.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ const (
// ValidateDestination checks:
// if we used destination name we infer the server url
// if we used both name and server then we return an invalid spec error
func ValidateDestination(ctx context.Context, dest *appv1.ApplicationDestination, clientset kubernetes.Interface, namespace string) error {
func ValidateDestination(ctx context.Context, dest *appv1.ApplicationDestination, clientset kubernetes.Interface, argoCDNamespace string) error {
if dest.Name != "" {
if dest.Server == "" {
server, err := getDestinationServer(ctx, dest.Name, clientset, namespace)
server, err := getDestinationServer(ctx, dest.Name, clientset, argoCDNamespace)
if err != nil {
return fmt.Errorf("unable to find destination server: %v", err)
}
Expand All @@ -70,11 +70,11 @@ func ValidateDestination(ctx context.Context, dest *appv1.ApplicationDestination
return nil
}

func getDestinationServer(ctx context.Context, clusterName string, clientset kubernetes.Interface, namespace string) (string, error) {
func getDestinationServer(ctx context.Context, clusterName string, clientset kubernetes.Interface, argoCDNamespace string) (string, error) {
// settingsMgr := settings.NewSettingsManager(context.TODO(), clientset, namespace)
// argoDB := db.NewDB(namespace, settingsMgr, clientset)
// clusterList, err := argoDB.ListClusters(ctx)
clusterList, err := ListClusters(ctx, clientset, namespace)
clusterList, err := ListClusters(ctx, clientset, argoCDNamespace)
if err != nil {
return "", err
}
Expand Down
18 changes: 18 additions & 0 deletions assets/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1778,6 +1778,12 @@
"description": "the selector to restrict returned list to applications only with matched labels.",
"name": "selector",
"in": "query"
},
{
"type": "string",
"description": "The application set namespace. Default empty is argocd control plane namespace.",
"name": "appsetNamespace",
"in": "query"
}
],
"responses": {
Expand Down Expand Up @@ -1846,6 +1852,12 @@
"name": "name",
"in": "path",
"required": true
},
{
"type": "string",
"description": "The application set namespace. Default empty is argocd control plane namespace.",
"name": "appsetNamespace",
"in": "query"
}
],
"responses": {
Expand Down Expand Up @@ -1875,6 +1887,12 @@
"name": "name",
"in": "path",
"required": true
},
{
"type": "string",
"description": "The application set namespace. Default empty is argocd control plane namespace.",
"name": "appsetNamespace",
"in": "query"
}
],
"responses": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import (
"os"
"time"

"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/util/tls"
"github.com/argoproj/pkg/stats"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"

"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/util/tls"

"github.com/argoproj/argo-cd/v2/applicationset/controllers"
"github.com/argoproj/argo-cd/v2/applicationset/generators"
Expand Down Expand Up @@ -52,7 +52,7 @@ func NewCommand() *cobra.Command {
probeBindAddr string
webhookAddr string
enableLeaderElection bool
namespace string
applicationSetNamespaces []string
argocdRepoServer string
policy string
enablePolicyOverride bool
Expand All @@ -76,6 +76,8 @@ func NewCommand() *cobra.Command {

vers := common.GetVersion()
namespace, _, err := clientConfig.Namespace()
applicationSetNamespaces = append(applicationSetNamespaces, namespace)

errors.CheckError(err)
vers.LogStartupInfo(
"ArgoCD ApplicationSet Controller",
Expand All @@ -98,19 +100,25 @@ func NewCommand() *cobra.Command {
os.Exit(1)
}

// By default watch all namespace
var watchedNamespace string = ""

// If the applicationset-namespaces contains only one namespace it corresponds to the current namespace
if len(applicationSetNamespaces) == 1 {
watchedNamespace = (applicationSetNamespaces)[0]
}

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,
// Our cache and thus watches and client queries are restricted to the namespace we're running in. This assumes
// the applicationset controller is in the same namespace as argocd, which should be the same namespace of
// all cluster Secrets and Applications we interact with.
NewCache: cache.MultiNamespacedCacheBuilder([]string{namespace}),
Scheme: scheme,
MetricsBindAddress: metricsAddr,
Namespace: watchedNamespace,
HealthProbeBindAddress: probeBindAddr,
Port: 9443,
LeaderElection: enableLeaderElection,
LeaderElectionID: "58ac56fa.applicationsets.argoproj.io",
DryRunClient: dryRun,
})

if err != nil {
log.Error(err, "unable to start manager")
os.Exit(1)
Expand Down Expand Up @@ -190,17 +198,19 @@ func NewCommand() *cobra.Command {
}

if err = (&controllers.ApplicationSetReconciler{
Generators: topLevelGenerators,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("applicationset-controller"),
Renderer: &utils.Render{},
Policy: policyObj,
EnablePolicyOverride: enablePolicyOverride,
ArgoAppClientset: appSetConfig,
KubeClientset: k8sClient,
ArgoDB: argoCDDB,
EnableProgressiveSyncs: enableProgressiveSyncs,
Generators: topLevelGenerators,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("applicationset-controller"),
Renderer: &utils.Render{},
Policy: policyObj,
EnablePolicyOverride: enablePolicyOverride,
ArgoAppClientset: appSetConfig,
KubeClientset: k8sClient,
ArgoDB: argoCDDB,
ArgoCDNamespace: namespace,
ApplicationSetNamespaces: applicationSetNamespaces,
EnableProgressiveSyncs: enableProgressiveSyncs,
}).SetupWithManager(mgr, enableProgressiveSyncs, maxConcurrentReconciliations); err != nil {
log.Error(err, "unable to create controller", "controller", "ApplicationSet")
os.Exit(1)
Expand All @@ -222,7 +232,7 @@ func NewCommand() *cobra.Command {
command.Flags().BoolVar(&enableLeaderElection, "enable-leader-election", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_LEADER_ELECTION", false),
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
command.Flags().StringVar(&namespace, "namespace", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE", ""), "Argo CD repo namespace (default: argocd)")
command.Flags().StringSliceVar(&applicationSetNamespaces, "applicationset-namespaces", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES", []string{}, ","), "Argo CD applicationset namespaces")
command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER", common.DefaultRepoServerAddr), "Argo CD repo server address")
command.Flags().StringVar(&policy, "policy", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_POLICY", ""), "Modify how application is synced between the generator and the cluster. Default is 'sync' (create & update & delete), options: 'create-only', 'create-update' (no deletion), 'create-delete' (no update)")
command.Flags().BoolVar(&enablePolicyOverride, "enable-policy-override", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE", policy == ""), "For security reason if 'policy' is set, it is not possible to override it at applicationSet level. 'allow-policy-override' allows user to define their own policy")
Expand Down
Loading