mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 17:07:16 +00:00
* Allow notifications controller to notify on all namespaces This adds functionality to the notifications controller to be notified of and send notifications for applications in any namespace. The namespaces to watch are controlled by the same --application-namespaces and ARGOCD_APPLICATION_NAMESPACES variables as in the application controller. Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au> * Add SEEK to users.md Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au> * Remove unused fields Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au> * Revert changes to Procfile Signed-off-by: Nik Skoufis <n.skoufis@gmail.com> * Fix unit tests Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au> * - add argocd namespaces environment variable to notifications controller Signed-off-by: Stewart Thomson <sthomson@wynshop.com> * - add example cluster role rbac Signed-off-by: Stewart Thomson <sthomson@wynshop.com> * - only look for projects in the controller's namespace (argocd by default) Signed-off-by: Stewart Thomson <sthomson@wynshop.com> * - update base manifest Signed-off-by: Stewart Thomson <sthomson@wynshop.com> * - skip app processing in notification controller Signed-off-by: Stewart Thomson <sthomson@wynshop.com> * added unit test and updated doc Signed-off-by: May Zhang <may_zhang@intuit.com> * added unit test and updated doc Signed-off-by: May Zhang <may_zhang@intuit.com> * updated examples/k8s-rbac/argocd-server-applications/kustomization.yaml's resources Signed-off-by: May Zhang <may_zhang@intuit.com> --------- Signed-off-by: Nikolas Skoufis <nskoufis@seek.com.au> Signed-off-by: Nik Skoufis <n.skoufis@gmail.com> Signed-off-by: Stewart Thomson <sthomson@wynshop.com> Signed-off-by: May Zhang <may_zhang@intuit.com> Co-authored-by: Nikolas Skoufis <nskoufis@seek.com.au> Co-authored-by: Nik Skoufis <n.skoufis@gmail.com> Co-authored-by: Stewart Thomson <sthomson@wynshop.com>
192 lines
4.9 KiB
Go
192 lines
4.9 KiB
Go
package controller
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
|
"github.com/sirupsen/logrus/hooks/test"
|
|
"github.com/stretchr/testify/assert"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/client-go/dynamic/fake"
|
|
k8sfake "k8s.io/client-go/kubernetes/fake"
|
|
"k8s.io/client-go/tools/cache"
|
|
)
|
|
|
|
func TestIsAppSyncStatusRefreshed(t *testing.T) {
|
|
logger, _ := test.NewNullLogger()
|
|
logEntry := logger.WithField("", "")
|
|
|
|
tests := []struct {
|
|
name string
|
|
app *unstructured.Unstructured
|
|
expectedValue bool
|
|
}{
|
|
{
|
|
name: "No OperationState",
|
|
app: &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"status": map[string]interface{}{},
|
|
},
|
|
},
|
|
expectedValue: true,
|
|
},
|
|
{
|
|
name: "No FinishedAt, Completed Phase",
|
|
app: &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"status": map[string]interface{}{
|
|
"operationState": map[string]interface{}{
|
|
"phase": "Succeeded",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedValue: false,
|
|
},
|
|
{
|
|
name: "FinishedAt After ReconciledAt & ObservedAt",
|
|
app: &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"status": map[string]interface{}{
|
|
"operationState": map[string]interface{}{
|
|
"finishedAt": "2021-01-01T01:05:00Z",
|
|
"phase": "Succeeded",
|
|
},
|
|
"reconciledAt": "2021-01-01T01:02:00Z",
|
|
"observedAt": "2021-01-01T01:04:00Z",
|
|
},
|
|
},
|
|
},
|
|
expectedValue: false,
|
|
},
|
|
{
|
|
name: "FinishedAt Before ReconciledAt & ObservedAt",
|
|
app: &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"status": map[string]interface{}{
|
|
"operationState": map[string]interface{}{
|
|
"finishedAt": "2021-01-01T01:02:00Z",
|
|
"phase": "Succeeded",
|
|
},
|
|
"reconciledAt": "2021-01-01T01:04:00Z",
|
|
"observedAt": "2021-01-01T01:06:00Z",
|
|
},
|
|
},
|
|
},
|
|
expectedValue: true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
actualValue := isAppSyncStatusRefreshed(test.app, logEntry)
|
|
assert.Equal(t, test.expectedValue, actualValue)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetAppProj_invalidProjectNestedString(t *testing.T) {
|
|
app := &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"spec": map[string]interface{}{},
|
|
},
|
|
}
|
|
informer := cache.NewSharedIndexInformer(nil, nil, 0, nil)
|
|
proj := getAppProj(app, informer)
|
|
|
|
assert.Nil(t, proj)
|
|
}
|
|
|
|
func TestInit(t *testing.T) {
|
|
scheme := runtime.NewScheme()
|
|
err := v1alpha1.SchemeBuilder.AddToScheme(scheme)
|
|
if err != nil {
|
|
t.Fatalf("Error registering the resource: %v", err)
|
|
}
|
|
dynamicClient := fake.NewSimpleDynamicClient(scheme)
|
|
k8sClient := k8sfake.NewSimpleClientset()
|
|
appLabelSelector := "app=test"
|
|
|
|
nc := NewController(
|
|
k8sClient,
|
|
dynamicClient,
|
|
nil,
|
|
"default",
|
|
[]string{},
|
|
appLabelSelector,
|
|
nil,
|
|
"my-secret",
|
|
"my-configmap",
|
|
)
|
|
|
|
assert.NotNil(t, nc)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
err = nc.Init(ctx)
|
|
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestInitTimeout(t *testing.T) {
|
|
scheme := runtime.NewScheme()
|
|
err := v1alpha1.SchemeBuilder.AddToScheme(scheme)
|
|
if err != nil {
|
|
t.Fatalf("Error registering the resource: %v", err)
|
|
}
|
|
dynamicClient := fake.NewSimpleDynamicClient(scheme)
|
|
k8sClient := k8sfake.NewSimpleClientset()
|
|
appLabelSelector := "app=test"
|
|
|
|
nc := NewController(
|
|
k8sClient,
|
|
dynamicClient,
|
|
nil,
|
|
"default",
|
|
[]string{},
|
|
appLabelSelector,
|
|
nil,
|
|
"my-secret",
|
|
"my-configmap",
|
|
)
|
|
|
|
assert.NotNil(t, nc)
|
|
|
|
// Use a short timeout to simulate a timeout during cache synchronization
|
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
|
|
defer cancel()
|
|
|
|
err = nc.Init(ctx)
|
|
|
|
// Expect an error & add assertion for the error message
|
|
assert.Error(t, err)
|
|
assert.Equal(t, "Timed out waiting for caches to sync", err.Error())
|
|
}
|
|
|
|
func TestCheckAppNotInAdditionalNamespaces(t *testing.T) {
|
|
app := &unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"spec": map[string]interface{}{},
|
|
},
|
|
}
|
|
namespace := "argocd"
|
|
var applicationNamespaces []string
|
|
applicationNamespaces = append(applicationNamespaces, "namespace1")
|
|
applicationNamespaces = append(applicationNamespaces, "namespace2")
|
|
|
|
// app is in same namespace as controller's namespace
|
|
app.SetNamespace(namespace)
|
|
assert.False(t, checkAppNotInAdditionalNamespaces(app, namespace, applicationNamespaces))
|
|
|
|
// app is not in the namespace as controller's namespace, but it is in one of the applicationNamespaces
|
|
app.SetNamespace("namespace2")
|
|
assert.False(t, checkAppNotInAdditionalNamespaces(app, "", applicationNamespaces))
|
|
|
|
// app is not in the namespace as controller's namespace, and it is not in any of the applicationNamespaces
|
|
app.SetNamespace("namespace3")
|
|
assert.True(t, checkAppNotInAdditionalNamespaces(app, "", applicationNamespaces))
|
|
}
|