diff --git a/worker/appm/store/store.go b/worker/appm/store/store.go index 3eb205f5c..6523a71ea 100644 --- a/worker/appm/store/store.go +++ b/worker/appm/store/store.go @@ -157,6 +157,7 @@ type appRuntimeStore struct { volumeTypeListenerLock sync.Mutex resourceCache *ResourceCache initLocks sync.Map // map[serviceID]*sync.Mutex for AppService initialization + syncImagePullSecret func(string) error } // NewStore new app runtime store @@ -176,6 +177,7 @@ func NewStore(dbmanager db.Manager) Storer { podUpdateListeners: make(map[string]chan<- *corev1.Pod, 1), volumeTypeListeners: make(map[string]chan<- *model.TenantServiceVolumeType, 1), } + store.syncImagePullSecret = store.createOrUpdateImagePullSecret crdClient, err := internalclientset.NewForConfig(store.k8sClient.RestConfig) if err != nil { logrus.Errorf("create crd client failure %s", err.Error()) @@ -1850,22 +1852,34 @@ func (a *appRuntimeStore) evtEventHandler() cache.ResourceEventHandlerFuncs { func (a *appRuntimeStore) nsEventHandler() cache.ResourceEventHandlerFuncs { return cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + ns := obj.(*corev1.Namespace) + a.syncNamespaceImagePullSecret(ns) + }, UpdateFunc: func(old, cur interface{}) { ns := cur.(*corev1.Namespace) + a.syncNamespaceImagePullSecret(ns) + }, + } +} - // check if the namespace is created by Rainbond - if !filterOutNotRainbondNamespace(ns) { - return - } +func (a *appRuntimeStore) syncNamespaceImagePullSecret(ns *corev1.Namespace) { + // check if the namespace is created by Rainbond + if !filterOutNotRainbondNamespace(ns) { + return + } - if ns.Status.Phase == corev1.NamespaceTerminating { - return - } + if ns.Status.Phase == corev1.NamespaceTerminating { + return + } - if err := a.createOrUpdateImagePullSecret(ns.Name); err != nil { - logrus.Errorf("create or update imagepullsecret: %v", err) - } - }, + syncFn := a.syncImagePullSecret + if syncFn == nil { + syncFn = a.createOrUpdateImagePullSecret + } + + if err := syncFn(ns.Name); err != nil { + logrus.Errorf("create or update imagepullsecret: %v", err) } } diff --git a/worker/appm/store/store_test.go b/worker/appm/store/store_test.go index c1bd23f66..42e376a44 100644 --- a/worker/appm/store/store_test.go +++ b/worker/appm/store/store_test.go @@ -24,6 +24,8 @@ import ( v1 "github.com/goodrain/rainbond/worker/appm/types/v1" "github.com/goodrain/rainbond/worker/server/pb" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func TestGetAppStatus(t *testing.T) { @@ -108,3 +110,58 @@ func TestGetAppStatus(t *testing.T) { }) } } + +func TestNsEventHandlerProvidesAddFunc(t *testing.T) { + handler := (&appRuntimeStore{}).nsEventHandler() + assert.NotNil(t, handler.AddFunc, "namespace add events should trigger image pull secret sync") +} + +func TestNsEventHandlerSyncsManagedNamespacesOnAddAndUpdate(t *testing.T) { + var synced []string + store := &appRuntimeStore{ + syncImagePullSecret: func(namespace string) error { + synced = append(synced, namespace) + return nil + }, + } + handler := store.nsEventHandler() + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"app.kubernetes.io/managed-by": "rainbond"}, + }, + Status: corev1.NamespaceStatus{Phase: corev1.NamespaceActive}, + } + + handler.AddFunc(ns) + handler.UpdateFunc(nil, ns) + + assert.Equal(t, []string{"test", "test"}, synced) +} + +func TestNsEventHandlerSkipsNamespacesThatShouldNotSync(t *testing.T) { + var synced []string + store := &appRuntimeStore{ + syncImagePullSecret: func(namespace string) error { + synced = append(synced, namespace) + return nil + }, + } + handler := store.nsEventHandler() + unmanaged := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "external"}, + Status: corev1.NamespaceStatus{Phase: corev1.NamespaceActive}, + } + terminating := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"app.kubernetes.io/managed-by": "rainbond"}, + }, + Status: corev1.NamespaceStatus{Phase: corev1.NamespaceTerminating}, + } + + handler.AddFunc(unmanaged) + handler.UpdateFunc(nil, terminating) + + assert.Empty(t, synced) +}