Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
refactor: rename notifiers to services
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmt committed Dec 31, 2020
1 parent d849bc6 commit 87c0965
Show file tree
Hide file tree
Showing 66 changed files with 1,057 additions and 1,661 deletions.
7 changes: 4 additions & 3 deletions bot/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import (
"net/http"
"strings"

"github.com/argoproj-labs/argocd-notifications/shared/clients"
"github.com/argoproj-labs/argocd-notifications/shared/k8s"

"github.com/argoproj-labs/argocd-notifications/shared/recipients"

v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -23,8 +24,8 @@ type Server interface {
func NewServer(dynamicClient dynamic.Interface, namespace string) *server {
return &server{
mux: http.NewServeMux(),
appClient: clients.NewAppClient(dynamicClient, namespace),
appProjClient: clients.NewAppProjClient(dynamicClient, namespace),
appClient: k8s.NewAppClient(dynamicClient, namespace),
appProjClient: k8s.NewAppProjClient(dynamicClient, namespace),
}
}

Expand Down
28 changes: 21 additions & 7 deletions bot/slack/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"fmt"
"net/http"

"github.com/argoproj-labs/argocd-notifications/pkg"

slackclient "github.com/slack-go/slack"
v1 "k8s.io/api/core/v1"
"k8s.io/client-go/tools/cache"

"github.com/argoproj-labs/argocd-notifications/shared/settings"
"github.com/argoproj-labs/argocd-notifications/shared/k8s"
)

type HasSigningSecret interface {
Expand All @@ -18,23 +20,35 @@ type HasSigningSecret interface {

type RequestVerifier func(data []byte, header http.Header) error

func NewVerifier(secretInformer cache.SharedIndexInformer) RequestVerifier {
func NewVerifier(cmInformer cache.SharedIndexInformer, secretInformer cache.SharedIndexInformer) RequestVerifier {
return func(data []byte, header http.Header) error {
secrets := secretInformer.GetStore().List()
if len(secrets) == 0 {
return fmt.Errorf("cannot find secret %s the slack app secret", settings.SecretName)
return fmt.Errorf("cannot find secret %s the slack app secret", k8s.SecretName)
}
secret, ok := secrets[0].(*v1.Secret)
if !ok {
return errors.New("unexpected object in the secret informer storage")
}
notifiers, err := settings.ParseSecret(secret)
configMaps := cmInformer.GetStore().List()
if len(configMaps) == 0 {
return fmt.Errorf("cannot find config map %s the slack app secret", k8s.ConfigMapName)
}
cm, ok := configMaps[0].(*v1.ConfigMap)
if !ok {
return errors.New("unexpected object in the configmap informer storage")
}
cfg, err := pkg.ParseConfig(cm, secret)
if err != nil {
return fmt.Errorf("unable to parse slack configuration: %v", err)
}
notifier, err := pkg.NewNotifier(*cfg)
if err != nil {
return errors.New("unable to parse slack configuration")
return fmt.Errorf("unable to parse slack configuration: %v", err)
}
signingSecret := ""
for _, notifier := range notifiers {
if hasSecret, ok := notifier.(HasSigningSecret); ok {
for _, service := range notifier.GetServices() {
if hasSecret, ok := service.(HasSigningSecret); ok {
signingSecret = hasSecret.GetSigningSecret()
if signingSecret == "" {
return errors.New("slack signing secret is not configured")
Expand Down
64 changes: 37 additions & 27 deletions bot/slack/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,47 +12,54 @@ import (
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/cache"

"github.com/argoproj-labs/argocd-notifications/shared/settings"
"github.com/argoproj-labs/argocd-notifications/shared/k8s"
testingutil "github.com/argoproj-labs/argocd-notifications/testing"
"github.com/stretchr/testify/assert"
)

func syncedInformer(t *testing.T, ctx context.Context, objects ...runtime.Object) cache.SharedIndexInformer {
informer := settings.NewSecretInformer(fake.NewSimpleClientset(objects...), testingutil.TestNamespace)
go informer.Run(ctx.Done())
if !cache.WaitForCacheSync(context.Background().Done(), informer.HasSynced) {
func syncedInformers(t *testing.T, ctx context.Context, objects ...runtime.Object) (cache.SharedIndexInformer, cache.SharedIndexInformer) {
objects = append(objects, &v1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: k8s.SecretName, Namespace: testingutil.TestNamespace},
})
clientset := fake.NewSimpleClientset(objects...)
cmInformer := k8s.NewConfigMapInformer(clientset, testingutil.TestNamespace)
secretInformer := k8s.NewSecretInformer(clientset, testingutil.TestNamespace)
go cmInformer.Run(ctx.Done())
go secretInformer.Run(ctx.Done())
if !cache.WaitForCacheSync(context.Background().Done(), cmInformer.HasSynced, secretInformer.HasSynced) {
t.Fatal("Timed out waiting for caches to sync")
}
return informer

return cmInformer, secretInformer
}

func notificationSecret(data map[string][]byte) *v1.Secret {
return &v1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: settings.SecretName, Namespace: testingutil.TestNamespace},
func notificationConfigMap(data map[string]string) *v1.ConfigMap {
return &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: k8s.ConfigMapName, Namespace: testingutil.TestNamespace},
Data: data,
}
}

func TestNewVerifier_IncorrectConfig(t *testing.T) {
testCases := map[string]struct {
Secret *v1.Secret
Error string
ConfigMap *v1.ConfigMap
Error string
}{
"NoSecret": {
Secret: nil,
Error: "cannot find secret",
"NoConfigMap": {
ConfigMap: nil,
Error: "cannot find config map",
},
"IncorrectSecret": {
Secret: notificationSecret(map[string][]byte{"notifiers.yaml": []byte("bad")}),
Error: "unable to parse slack configuration",
"IncorrectConfigMap": {
ConfigMap: notificationConfigMap(map[string]string{"service.slack": "bad"}),
Error: "unable to parse slack configuration",
},
"NoSlack": {
Secret: notificationSecret(map[string][]byte{"notifiers.yaml": []byte("email: {}")}),
Error: "slack is not configured",
ConfigMap: notificationConfigMap(map[string]string{"service.email": "{}"}),
Error: "slack is not configured",
},
"SlackWithoutSigningSecret": {
Secret: notificationSecret(map[string][]byte{"notifiers.yaml": []byte("slack: {}")}),
Error: "slack signing secret is not configured",
ConfigMap: notificationConfigMap(map[string]string{"service.slack": "{}"}),
Error: "slack signing secret is not configured",
},
}

Expand All @@ -65,10 +72,11 @@ func TestNewVerifier_IncorrectConfig(t *testing.T) {
defer cancel()

var objs []runtime.Object
if testCase.Secret != nil {
objs = append(objs, testCase.Secret)
if testCase.ConfigMap != nil {
objs = append(objs, testCase.ConfigMap)
}
verifier := NewVerifier(syncedInformer(t, ctx, objs...))
cmInformer, secretInformer := syncedInformers(t, ctx, objs...)
verifier := NewVerifier(cmInformer, secretInformer)

err := verifier(nil, nil)

Expand All @@ -82,9 +90,11 @@ func TestNewVerifier_IncorrectSignature(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

verifier := NewVerifier(syncedInformer(t, ctx, notificationSecret(map[string][]byte{
"notifiers.yaml": []byte(`slack: {signingSecret: "helloworld"}`),
})))
cmInformer, secretInformer := syncedInformers(t, ctx, notificationConfigMap(map[string]string{
"service.slack": `{signingSecret: "helloworld"}`,
}))

verifier := NewVerifier(cmInformer, secretInformer)
now := time.Now()
data := "hello world"
err := verifier([]byte(data), map[string][]string{
Expand Down
10 changes: 6 additions & 4 deletions cmd/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/argoproj-labs/argocd-notifications/bot"
"github.com/argoproj-labs/argocd-notifications/bot/slack"
"github.com/argoproj-labs/argocd-notifications/shared/cmd"
"github.com/argoproj-labs/argocd-notifications/shared/settings"
"github.com/argoproj-labs/argocd-notifications/shared/k8s"
)

func newBotCommand() *cobra.Command {
Expand Down Expand Up @@ -43,13 +43,15 @@ func newBotCommand() *cobra.Command {
return err
}
}
secretInformer := settings.NewSecretInformer(clientset, namespace)
secretInformer := k8s.NewSecretInformer(clientset, namespace)
cmInformer := k8s.NewConfigMapInformer(clientset, namespace)
go secretInformer.Run(context.Background().Done())
if !cache.WaitForCacheSync(context.Background().Done(), secretInformer.HasSynced) {
go cmInformer.Run(context.Background().Done())
if !cache.WaitForCacheSync(context.Background().Done(), secretInformer.HasSynced, cmInformer.HasSynced) {
log.Fatal("Timed out waiting for caches to sync")
}
server := bot.NewServer(dynamicClient, namespace)
server.AddAdapter("/slack", slack.NewSlackAdapter(slack.NewVerifier(secretInformer)))
server.AddAdapter("/slack", slack.NewSlackAdapter(slack.NewVerifier(cmInformer, secretInformer)))
return server.Serve(port)
},
}
Expand Down
27 changes: 12 additions & 15 deletions cmd/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import (
"strings"
"sync"

"github.com/argoproj-labs/argocd-notifications/shared/settings"

"github.com/argoproj-labs/argocd-notifications/controller"
"github.com/argoproj-labs/argocd-notifications/notifiers"
"github.com/argoproj-labs/argocd-notifications/shared/argocd"
"github.com/argoproj-labs/argocd-notifications/shared/cmd"
"github.com/argoproj-labs/argocd-notifications/shared/settings"
"github.com/argoproj-labs/argocd-notifications/triggers"
"github.com/argoproj-labs/argocd-notifications/shared/k8s"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
Expand Down Expand Up @@ -85,13 +85,13 @@ func newControllerCommand() *cobra.Command {
log.Infof("loading configuration %d", metricsPort)

var cancelPrev context.CancelFunc
watchConfig(context.Background(), argocdService, k8sClient, namespace, func(triggers map[string]triggers.Trigger, notifiers map[string]notifiers.Notifier, cfg *settings.Config) error {
watchConfig(context.Background(), argocdService, k8sClient, namespace, func(cfg settings.Config) error {
if cancelPrev != nil {
log.Info("Settings had been updated. Restarting controller...")
cancelPrev()
cancelPrev = nil
}
ctrl, err := controller.NewController(dynamicClient, namespace, triggers, notifiers, cfg.Context, cfg.Subscriptions, appLabelSelector, registry)
ctrl, err := controller.NewController(dynamicClient, namespace, cfg, appLabelSelector, registry)
if err != nil {
return err
}
Expand Down Expand Up @@ -120,12 +120,9 @@ func newControllerCommand() *cobra.Command {
return &command
}

func watchConfig(ctx context.Context, argocdService argocd.Service, clientset kubernetes.Interface, namespace string, callback func(map[string]triggers.Trigger, map[string]notifiers.Notifier, *settings.Config) error) {
func watchConfig(ctx context.Context, argocdService argocd.Service, clientset kubernetes.Interface, namespace string, callback func(settings.Config) error) {
var secret *v1.Secret
var configMap *v1.ConfigMap
defaultConfig := settings.Config{
Context: map[string]string{argocdURLContextVariable: "https://localhost:4000"},
}
lock := &sync.Mutex{}
onNewConfigMapAndSecret := func(newSecret *v1.Secret, newConfigMap *v1.ConfigMap) {
lock.Lock()
Expand All @@ -138,8 +135,8 @@ func watchConfig(ctx context.Context, argocdService argocd.Service, clientset ku
}

if secret != nil && configMap != nil {
if t, n, c, err := settings.ParseConfig(configMap, secret, defaultConfig, argocdService); err == nil {
if err = callback(t, n, c); err != nil {
if cfg, err := settings.NewConfig(configMap, secret, argocdService); err == nil {
if err = callback(*cfg); err != nil {
log.Fatalf("Failed to start controller: %v", err)
}
} else {
Expand All @@ -160,7 +157,7 @@ func watchConfig(ctx context.Context, argocdService argocd.Service, clientset ku
}
}

cmInformer := settings.NewConfigMapInformer(clientset, namespace)
cmInformer := k8s.NewConfigMapInformer(clientset, namespace)
cmInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
UpdateFunc: func(oldObj, newObj interface{}) {
onConfigMapChanged(newObj)
Expand All @@ -171,7 +168,7 @@ func watchConfig(ctx context.Context, argocdService argocd.Service, clientset ku
},
})

secretInformer := settings.NewSecretInformer(clientset, namespace)
secretInformer := k8s.NewSecretInformer(clientset, namespace)
secretInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
UpdateFunc: func(oldObj, newObj interface{}) {
onSecretChanged(newObj)
Expand All @@ -189,10 +186,10 @@ func watchConfig(ctx context.Context, argocdService argocd.Service, clientset ku
}
var missingWarn []string
if len(cmInformer.GetStore().List()) == 0 {
missingWarn = append(missingWarn, fmt.Sprintf("config map %s", settings.ConfigMapName))
missingWarn = append(missingWarn, fmt.Sprintf("config map %s", k8s.ConfigMapName))
}
if len(secretInformer.GetStore().List()) == 0 {
missingWarn = append(missingWarn, fmt.Sprintf("secret %s", settings.SecretName))
missingWarn = append(missingWarn, fmt.Sprintf("secret %s", k8s.SecretName))
}
if len(missingWarn) > 0 {
log.Warnf("Cannot find %s. Waiting when both config map and secret are created.", strings.Join(missingWarn, " and "))
Expand Down
45 changes: 16 additions & 29 deletions cmd/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import (
"context"
"testing"

"github.com/argoproj-labs/argocd-notifications/shared/settings"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"

"github.com/argoproj-labs/argocd-notifications/notifiers"
"github.com/argoproj-labs/argocd-notifications/shared/argocd/mocks"
"github.com/argoproj-labs/argocd-notifications/shared/settings"
"github.com/argoproj-labs/argocd-notifications/triggers"
"github.com/argoproj-labs/argocd-notifications/shared/k8s"
)

func TestWatchConfig(t *testing.T) {
Expand All @@ -24,47 +24,34 @@ func TestWatchConfig(t *testing.T) {
defer cancel()
configMap := &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: settings.ConfigMapName,
Name: k8s.ConfigMapName,
Namespace: "default",
},
Data: map[string]string{
"config.yaml": `
triggers:
- name: on-sync-status-unknown
condition: "app.status.sync.status == 'Unknown'"
template: app-sync-status
enabled: true
templates:
- name: app-sync-status
title: updated
body: updated"`,
"context": `
argocdUrl: https://myargocd.com
`,
},
}
secret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: settings.SecretName,
Name: k8s.SecretName,
Namespace: "default",
},
Data: map[string][]byte{
"notifiers.yaml": []byte(`slack: {token: my-token}`),
},
Data: map[string][]byte{},
}

triggersMap := make(map[string]triggers.Trigger)
notifiersMap := make(map[string]notifiers.Notifier)
argocdService := mocks.NewMockService(ctrl)
clientset := fake.NewSimpleClientset(configMap, secret)
watchConfig(ctx, argocdService, clientset, "default", func(t map[string]triggers.Trigger, n map[string]notifiers.Notifier, cfg *settings.Config) error {
triggersMap = t
notifiersMap = n
var parsedCfg *settings.Config
watchConfig(ctx, argocdService, clientset, "default", func(cfg settings.Config) error {
parsedCfg = &cfg
return nil
})

assert.Len(t, triggersMap, 1)

_, ok := triggersMap["on-sync-status-unknown"]
assert.True(t, ok)
if !assert.NotNil(t, parsedCfg) {
return
}

_, ok = notifiersMap["slack"]
assert.True(t, ok)
assert.Equal(t, "https://myargocd.com", parsedCfg.Context["argocdUrl"])
}
Loading

0 comments on commit 87c0965

Please sign in to comment.