Skip to content

Commit

Permalink
feat: remove argocd api dependency (#18)
Browse files Browse the repository at this point in the history
Signed-off-by: Mike Ng <[email protected]>
  • Loading branch information
mikeshng authored Nov 14, 2024
1 parent 6950841 commit 339170f
Show file tree
Hide file tree
Showing 16 changed files with 529 additions and 1,879 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go-postsubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

env:
# Common versions
GO_VERSION: '1.19'
GO_VERSION: '1.22'
GO_REQUIRED_MIN_VERSION: ''
GOPATH: '/home/runner/work/argocd-pull-integration/argocd-pull-integration/go'
defaults:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/go-presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

env:
# Common versions
GO_VERSION: '1.19'
GO_VERSION: '1.22'
GO_REQUIRED_MIN_VERSION: ''
GOPATH: '/home/runner/work/argocd-pull-integration/argocd-pull-integration/go'
defaults:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/go-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
- 'v*.*.*'
env:
# Common versions
GO_VERSION: '1.19'
GO_VERSION: '1.22'
GO_REQUIRED_MIN_VERSION: ''
GOPATH: '/home/runner/work/argocd-pull-integration/go'
GITHUB_REF: ${{ github.ref }}
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.19 as builder
FROM golang:1.22 AS builder
ARG TARGETOS
ARG TARGETARCH

Expand Down
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,17 @@ vet: ## Run go vet against code.
go vet ./...

.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
test: manifests fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out

##@ Build

.PHONY: build
build: generate fmt vet ## Build manager binary.
build: fmt vet ## Build manager binary.
go build -o bin/manager main.go

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
run: manifests fmt vet ## Run a controller from your host.
go run ./main.go

# If you wish built the manager image targeting other platforms you can use the --platform flag.
Expand Down
51 changes: 33 additions & 18 deletions controllers/application/application_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ import (
"context"

"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"

argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
clusterv1 "open-cluster-management.io/api/cluster/v1"
workv1 "open-cluster-management.io/api/work/v1"
)
Expand All @@ -50,6 +51,8 @@ const (
LabelKeyAppSet = "apps.open-cluster-management.io/application-set"
// Application and ManifestWork label that enables the pull controller to wrap the Application in ManifestWork payload
LabelKeyPull = "apps.open-cluster-management.io/pull-to-ocm-managed-cluster"
// ResourcesFinalizerName is the finalizer value which we inject to finalize deletion of an application
ResourcesFinalizerName string = "resources-finalizer.argocd.argoproj.io"
)

// ApplicationReconciler reconciles a Application object
Expand All @@ -65,25 +68,32 @@ type ApplicationReconciler struct {
// ApplicationPredicateFunctions defines which Application this controller should wrap inside ManifestWork's payload
var ApplicationPredicateFunctions = predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
newApp := e.ObjectNew.(*argov1alpha1.Application)
return containsValidPullLabel(newApp.Labels) && containsValidPullAnnotation(*newApp)

newObj := e.ObjectNew.(*unstructured.Unstructured)
return containsValidPullLabel(newObj.GetLabels()) &&
containsValidPullAnnotation(newObj.GetAnnotations())
},
CreateFunc: func(e event.CreateEvent) bool {
app := e.Object.(*argov1alpha1.Application)
return containsValidPullLabel(app.Labels) && containsValidPullAnnotation(*app)
obj := e.Object.(*unstructured.Unstructured)
return containsValidPullLabel(obj.GetLabels()) &&
containsValidPullAnnotation(obj.GetAnnotations())
},

DeleteFunc: func(e event.DeleteEvent) bool {
app := e.Object.(*argov1alpha1.Application)
return containsValidPullLabel(app.Labels) && containsValidPullAnnotation(*app)
obj := e.Object.(*unstructured.Unstructured)
return containsValidPullLabel(obj.GetLabels()) &&
containsValidPullAnnotation(obj.GetAnnotations())
},
}

// SetupWithManager sets up the controller with the Manager.
func (r *ApplicationReconciler) SetupWithManager(mgr ctrl.Manager) error {
applicationGVK := &unstructured.Unstructured{}
applicationGVK.SetGroupVersionKind(schema.GroupVersionKind{
Group: "argoproj.io",
Version: "v1alpha1",
Kind: "Application",
})
return ctrl.NewControllerManagedBy(mgr).
For(&argov1alpha1.Application{}).
For(applicationGVK).
WithEventFilter(ApplicationPredicateFunctions).
Complete(r)
}
Expand All @@ -93,22 +103,27 @@ func (r *ApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request)
log := log.FromContext(ctx)
log.Info("reconciling Application...")

var application argov1alpha1.Application
if err := r.Get(ctx, req.NamespacedName, &application); err != nil {
application := &unstructured.Unstructured{}
application.SetGroupVersionKind(schema.GroupVersionKind{
Group: "argoproj.io",
Version: "v1alpha1",
Kind: "Application",
})
if err := r.Get(ctx, req.NamespacedName, application); err != nil {
log.Error(err, "unable to fetch Application")
return ctrl.Result{}, client.IgnoreNotFound(err)
}

managedClusterName := application.GetAnnotations()[AnnotationKeyOCMManagedCluster]
mwName := generateManifestWorkName(application)
mwName := generateManifestWorkName(application.GetName(), application.GetUID())

// the Application is being deleted, find the ManifestWork and delete that as well
if application.ObjectMeta.DeletionTimestamp != nil {
if application.GetDeletionTimestamp() != nil {
// remove finalizer from Application but do not 'commit' yet
if len(application.Finalizers) != 0 {
if len(application.GetFinalizers()) != 0 {
f := application.GetFinalizers()
for i := 0; i < len(f); i++ {
if f[i] == argov1alpha1.ResourcesFinalizerName {
if f[i] == ResourcesFinalizerName {
f = append(f[:i], f[i+1:]...)
i--
}
Expand All @@ -121,7 +136,7 @@ func (r *ApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request)
err := r.Get(ctx, types.NamespacedName{Name: mwName, Namespace: managedClusterName}, &work)
if errors.IsNotFound(err) {
// already deleted ManifestWork, commit the Application finalizer removal
if err = r.Update(ctx, &application); err != nil {
if err = r.Update(ctx, application); err != nil {
log.Error(err, "unable to update Application")
return ctrl.Result{}, err
}
Expand All @@ -136,7 +151,7 @@ func (r *ApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}

// deleted ManifestWork, commit the Application finalizer removal
if err := r.Update(ctx, &application); err != nil {
if err := r.Update(ctx, application); err != nil {
log.Error(err, "unable to update Application")
return ctrl.Result{}, err
}
Expand Down
98 changes: 57 additions & 41 deletions controllers/application/application_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ import (
. "github.com/onsi/gomega"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"

argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
corev1 "k8s.io/api/core/v1"
clusterv1 "open-cluster-management.io/api/cluster/v1"
workv1 "open-cluster-management.io/api/work/v1"
Expand All @@ -48,23 +49,31 @@ var _ = Describe("Application Pull controller", func() {
Context("When Application without OCM pull label is created", func() {
It("Should not create ManifestWork", func() {
By("Creating the Application without OCM pull label")
app1 := argov1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: appNamespace,
Annotations: map[string]string{AnnotationKeyOCMManagedCluster: clusterName},
},
Spec: argov1alpha1.ApplicationSpec{
Source: &argov1alpha1.ApplicationSource{
RepoURL: "default",
},
},
}
Expect(k8sClient.Create(ctx, &app1)).Should(Succeed())
app1 = argov1alpha1.Application{}
Expect(k8sClient.Get(ctx, appKey, &app1)).Should(Succeed())

mwKey := types.NamespacedName{Name: generateManifestWorkName(app1), Namespace: clusterName}
app1 := &unstructured.Unstructured{}
app1.SetGroupVersionKind(schema.GroupVersionKind{
Group: "argoproj.io",
Version: "v1alpha1",
Kind: "Application",
})
app1.SetName(appName)
app1.SetNamespace(appNamespace)
app1.SetAnnotations(map[string]string{AnnotationKeyOCMManagedCluster: clusterName})

// Set required spec fields
_ = unstructured.SetNestedField(app1.Object, "default", "spec", "project")
_ = unstructured.SetNestedField(app1.Object, "default", "spec", "source", "repoURL")
_ = unstructured.SetNestedMap(app1.Object, map[string]interface{}{"server": KubernetesInternalAPIServerAddr}, "spec", "destination")

Expect(k8sClient.Create(ctx, app1)).Should(Succeed())
app1 = &unstructured.Unstructured{}
app1.SetGroupVersionKind(schema.GroupVersionKind{
Group: "argoproj.io",
Version: "v1alpha1",
Kind: "Application",
})
Expect(k8sClient.Get(ctx, appKey, app1)).Should(Succeed())

mwKey := types.NamespacedName{Name: generateManifestWorkName(app1.GetName(), app1.GetUID()), Namespace: clusterName}
mw := workv1.ManifestWork{}
Consistently(func() bool {
if err := k8sClient.Get(ctx, mwKey, &mw); err != nil {
Expand Down Expand Up @@ -94,26 +103,33 @@ var _ = Describe("Application Pull controller", func() {
Expect(k8sClient.Create(ctx, &managedClusterNs)).Should(Succeed())

By("Creating the Application with OCM pull label")
app2 := argov1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName2,
Namespace: appNamespace,
Labels: map[string]string{LabelKeyPull: strconv.FormatBool(true)},
Annotations: map[string]string{AnnotationKeyOCMManagedCluster: clusterName},
Finalizers: []string{argov1alpha1.ResourcesFinalizerName},
},
Spec: argov1alpha1.ApplicationSpec{
Project: "default",
Source: &argov1alpha1.ApplicationSource{
RepoURL: "default",
},
},
}
Expect(k8sClient.Create(ctx, &app2)).Should(Succeed())
app2 = argov1alpha1.Application{}
Expect(k8sClient.Get(ctx, appKey2, &app2)).Should(Succeed())

mwKey := types.NamespacedName{Name: generateManifestWorkName(app2), Namespace: clusterName}
app2 := &unstructured.Unstructured{}
app2.SetGroupVersionKind(schema.GroupVersionKind{
Group: "argoproj.io",
Version: "v1alpha1",
Kind: "Application",
})
app2.SetName(appName2)
app2.SetNamespace(appNamespace)
app2.SetLabels(map[string]string{LabelKeyPull: strconv.FormatBool(true)})
app2.SetAnnotations(map[string]string{AnnotationKeyOCMManagedCluster: clusterName})
app2.SetFinalizers([]string{ResourcesFinalizerName})

// Set required spec fields
_ = unstructured.SetNestedField(app2.Object, "default", "spec", "project")
_ = unstructured.SetNestedField(app2.Object, "default", "spec", "source", "repoURL")
_ = unstructured.SetNestedMap(app2.Object, map[string]interface{}{"server": KubernetesInternalAPIServerAddr}, "spec", "destination")

Expect(k8sClient.Create(ctx, app2)).Should(Succeed())
app2 = &unstructured.Unstructured{}
app2.SetGroupVersionKind(schema.GroupVersionKind{
Group: "argoproj.io",
Version: "v1alpha1",
Kind: "Application",
})
Expect(k8sClient.Get(ctx, appKey2, app2)).Should(Succeed())

mwKey := types.NamespacedName{Name: generateManifestWorkName(app2.GetName(), app2.GetUID()), Namespace: clusterName}
mw := workv1.ManifestWork{}
Eventually(func() bool {
if err := k8sClient.Get(ctx, mwKey, &mw); err != nil {
Expand All @@ -124,8 +140,8 @@ var _ = Describe("Application Pull controller", func() {

By("Updating the Application")
oldRv := mw.GetResourceVersion()
app2.Spec.Project = "somethingelse"
Expect(k8sClient.Update(ctx, &app2)).Should(Succeed())
_ = unstructured.SetNestedField(app2.Object, "somethingelse", "spec", "project")
Expect(k8sClient.Update(ctx, app2)).Should(Succeed())
Eventually(func() bool {
if err := k8sClient.Get(ctx, mwKey, &mw); err != nil {
return false
Expand All @@ -134,7 +150,7 @@ var _ = Describe("Application Pull controller", func() {
}).Should(BeTrue())

By("Deleting the Application")
Expect(k8sClient.Delete(ctx, &app2)).Should(Succeed())
Expect(k8sClient.Delete(ctx, app2)).Should(Succeed())
Eventually(func() bool {
if err := k8sClient.Get(ctx, mwKey, &mw); err != nil {
return true
Expand Down
Loading

0 comments on commit 339170f

Please sign in to comment.