Skip to content

Commit 4507dd2

Browse files
authored
Recreate listener Service when deleted (#2387)
* Recreate listener Service when deleted Fixes #2383 * Added unit test
1 parent f1d555b commit 4507dd2

4 files changed

Lines changed: 121 additions & 21 deletions

File tree

internal/kube/controller/controller.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,11 @@ func (c *Controller) checkListener(key string, listener *skupperv2alpha1.Listene
407407
if listener != nil {
408408
_, svcExists = c.observedServices[namespace+"/"+listener.Spec.Host]
409409
}
410-
return c.getSite(namespace).CheckListener(name, listener, svcExists)
410+
err = c.getSite(namespace).CheckListener(name, listener, svcExists)
411+
if err != nil {
412+
return err
413+
}
414+
return nil
411415
}
412416

413417
func (c *Controller) checkMultiKeyListener(key string, mkl *skupperv2alpha1.MultiKeyListener) error {
@@ -422,7 +426,14 @@ func (c *Controller) checkMultiKeyListener(key string, mkl *skupperv2alpha1.Mult
422426
func (c *Controller) checkListenerService(key string, svc *corev1.Service) error {
423427
c.log.Debug("checkListenerService", slog.String("key", key))
424428
if svc == nil {
425-
return nil
429+
namespace, serviceName, err := cache.SplitMetaNamespaceKey(key)
430+
if err != nil {
431+
return err
432+
}
433+
if !c.namespaces.isControlled(namespace) {
434+
return nil
435+
}
436+
return c.getSite(namespace).HandleDeletedListenerService(serviceName)
426437
}
427438
return c.getSite(svc.Namespace).CheckListenerService(svc)
428439
}

internal/kube/controller/controller_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/skupperproject/skupper/internal/kube/resource"
3636
"github.com/skupperproject/skupper/internal/network"
3737
"github.com/skupperproject/skupper/internal/qdr"
38+
"github.com/skupperproject/skupper/internal/utils"
3839
"github.com/skupperproject/skupper/internal/version"
3940
skupperv2alpha1 "github.com/skupperproject/skupper/pkg/apis/skupper/v2alpha1"
4041
)
@@ -663,6 +664,18 @@ func TestUpdate(t *testing.T) {
663664
serviceCheck("adifferentsvc", "test").check,
664665
negativeServiceCheck("mysvc", "test"),
665666
},
667+
}, {
668+
name: "listener service recreated when deleted",
669+
skupperObjects: []runtime.Object{
670+
f.site("mysite", "test", "", false, false),
671+
f.listener("mylistener", "test", "mysvc", 8080),
672+
},
673+
functions: []WaitFunction{
674+
isListenerStatusConditionTrue("mylistener", "test", skupperv2alpha1.CONDITION_TYPE_CONFIGURED),
675+
serviceCheck("mysvc", "test").check,
676+
deleteListenerService("mysvc", "test"),
677+
waitForService("mysvc", "test"),
678+
},
666679
}, {
667680
name: "exposePodsByName handles pod delete",
668681
k8sObjects: []runtime.Object{
@@ -840,6 +853,47 @@ func TestUpdate(t *testing.T) {
840853
}
841854
}
842855

856+
func TestListenerServiceRecreatedWhenDeleted(t *testing.T) {
857+
runListenerServiceRecreatedWithFakeClient(t)
858+
}
859+
860+
func runListenerServiceRecreatedWithFakeClient(t *testing.T) {
861+
t.Helper()
862+
flags := flag.NewFlagSet("", flag.ContinueOnError)
863+
config, err := BoundConfig(flags)
864+
assert.NilError(t, err)
865+
clients, err := fakeclient.NewFakeClient("test", nil, []runtime.Object{
866+
f.site("mysite", "test", "", false, false),
867+
f.listener("mylistener", "test", "mysvc", 8080),
868+
}, "")
869+
assert.NilError(t, err)
870+
enableSSA(clients.GetDynamicClient())
871+
ctrl, err := NewController(clients, config, func(e *watchers.EventProcessor) { e.SetResyncShort(time.Second) })
872+
assert.NilError(t, err)
873+
stopCh := make(chan struct{})
874+
err = ctrl.init(stopCh)
875+
assert.NilError(t, err)
876+
for i := 0; i < 2; i++ {
877+
ctrl.eventProcessor.TestProcess()
878+
}
879+
err = utils.Retry(100*time.Millisecond, 50, func() (bool, error) {
880+
ctrl.eventProcessor.TestProcess()
881+
return isListenerStatusConditionTrue("mylistener", "test", skupperv2alpha1.CONDITION_TYPE_CONFIGURED)(t, clients), nil
882+
})
883+
assert.NilError(t, err)
884+
err = utils.Retry(100*time.Millisecond, 50, func() (bool, error) {
885+
ctrl.eventProcessor.TestProcess()
886+
return serviceCheck("mysvc", "test").check(t, clients), nil
887+
})
888+
assert.NilError(t, err)
889+
deleteListenerService("mysvc", "test")(t, clients)
890+
err = utils.Retry(100*time.Millisecond, 50, func() (bool, error) {
891+
ctrl.eventProcessor.TestProcess()
892+
return waitForService("mysvc", "test")(t, clients), nil
893+
})
894+
assert.NilError(t, err)
895+
}
896+
843897
func deleteAttachedConnector(name string, namespace string) WaitFunction {
844898
return func(t *testing.T, clients internalclient.Clients) bool {
845899
err := clients.GetSkupperClient().SkupperV2alpha1().AttachedConnectors(namespace).Delete(context.Background(), name, metav1.DeleteOptions{})
@@ -1973,6 +2027,17 @@ func (s *ServiceCheck) checkAbsent(t *testing.T, clients internalclient.Clients)
19732027
return false
19742028
}
19752029

2030+
func waitForService(name string, namespace string) WaitFunction {
2031+
return func(t *testing.T, clients internalclient.Clients) bool {
2032+
_, err := clients.GetKubeClient().CoreV1().Services(namespace).Get(context.Background(), name, metav1.GetOptions{})
2033+
if errors.IsNotFound(err) {
2034+
return false
2035+
}
2036+
assert.Assert(t, err)
2037+
return true
2038+
}
2039+
}
2040+
19762041
func updateListener(name string, namespace string, host string, port int) WaitFunction {
19772042
return func(t *testing.T, clients internalclient.Clients) bool {
19782043
ctxt := context.Background()
@@ -1995,6 +2060,14 @@ func negativeServiceCheck(name string, namespace string) WaitFunction {
19952060
}
19962061
}
19972062

2063+
func deleteListenerService(serviceName string, namespace string) WaitFunction {
2064+
return func(t *testing.T, clients internalclient.Clients) bool {
2065+
err := clients.GetKubeClient().CoreV1().Services(namespace).Delete(context.Background(), serviceName, metav1.DeleteOptions{})
2066+
assert.Assert(t, err)
2067+
return true
2068+
}
2069+
}
2070+
19982071
func deleteTargetPod(name string, namespace string) WaitFunction {
19992072
return func(t *testing.T, clients internalclient.Clients) bool {
20002073
ctxt := context.Background()

internal/kube/site/extended_bindings.go

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -109,28 +109,33 @@ func (a *ExtendedBindings) ListenerUpdated(listener *skupperv2alpha1.Listener) {
109109
slog.String("name", listener.Name),
110110
slog.Any("error", err),
111111
)
112-
} else {
113-
port := Port{
114-
Name: listener.Name,
115-
Port: listener.Spec.Port,
116-
TargetPort: allocatedRouterPort,
117-
Protocol: listener.Protocol(),
112+
return
113+
}
114+
port := Port{
115+
Name: listener.Name,
116+
Port: listener.Spec.Port,
117+
TargetPort: allocatedRouterPort,
118+
Protocol: listener.Protocol(),
119+
}
120+
if exposed := a.exposed.Expose(listener.Spec.Host, port); exposed != nil {
121+
if err := a.context.Expose(exposed); err != nil {
122+
bindings_logger.Error("Error exposing listener",
123+
slog.String("namespace", listener.Namespace),
124+
slog.String("name", listener.Name),
125+
slog.Any("error", err))
126+
} else {
127+
bindings_logger.Info("Exposed listener",
128+
slog.String("namespace", listener.Namespace),
129+
slog.String("name", listener.Name))
118130
}
119-
if exposed := a.exposed.Expose(listener.Spec.Host, port); exposed != nil {
120-
if err := a.context.Expose(exposed); err != nil {
121-
//TODO: write error to listener status
122-
bindings_logger.Error("Error exposing listener",
123-
slog.String("namespace", listener.Namespace),
124-
slog.String("name", listener.Name),
125-
slog.Any("error", err))
126-
} else {
127-
bindings_logger.Info("Exposed listener",
128-
slog.String("namespace", listener.Namespace),
129-
slog.String("name", listener.Name))
131+
}
132+
}
130133

131-
}
132-
}
134+
func (a *ExtendedBindings) GetExposedPortSet(host string) *ExposedPortSet {
135+
if existing, ok := a.exposed[host]; ok && !existing.empty() {
136+
return existing
133137
}
138+
return nil
134139
}
135140

136141
func (a *ExtendedBindings) ListenerDeleted(listener *skupperv2alpha1.Listener) {

internal/kube/site/site.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,17 @@ func (s *Site) CheckListenerService(svc *corev1.Service) error {
936936
return nil
937937
}
938938

939+
func (s *Site) HandleDeletedListenerService(serviceName string) error {
940+
if s.site == nil {
941+
return nil
942+
}
943+
portSet := s.bindings.GetExposedPortSet(serviceName)
944+
if portSet == nil {
945+
return nil
946+
}
947+
return s.Expose(portSet)
948+
}
949+
939950
func (s *Site) CheckListener(name string, listener *skupperv2alpha1.Listener, svcExists bool) error {
940951
if s.site == nil {
941952
if listener == nil {

0 commit comments

Comments
 (0)