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: remove argocd api dependency #18

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading