diff --git a/cmd/stunnerctl/main.go b/cmd/stunnerctl/main.go index ed7f3ab4..a874f976 100644 --- a/cmd/stunnerctl/main.go +++ b/cmd/stunnerctl/main.go @@ -169,6 +169,10 @@ func runConfig(cmd *cobra.Command, args []string) error { } for c := range confChan { + if cdsclient.IsConfigDeleted(c) { + fmt.Printf("Gateway: %s \n", c.Admin.Name) + continue + } switch output { case "yaml": if out, err := yaml.Marshal(c); err != nil { diff --git a/pkg/config/cds_test.go b/pkg/config/cds_test.go index fdfb6a08..c53daa7b 100644 --- a/pkg/config/cds_test.go +++ b/pkg/config/cds_test.go @@ -946,9 +946,7 @@ func TestServerAPI(t *testing.T) { assert.NotNil(t, findConfById(lst, "ns3/gw1")) assert.True(t, findConfById(lst, "ns3/gw1").DeepEqual(sc4), "deepeq") assert.NotNil(t, findConfById(lst, "ns1/gw2")) - gw2zero := client.ZeroConfig("ns1/gw2") // deleted! - assert.NoError(t, gw2zero.Validate()) - assert.True(t, findConfById(lst, "ns1/gw2").DeepEqual(gw2zero), "deepeq") + assert.True(t, client.IsConfigDeleted(findConfById(lst, "ns1/gw2")), "deepeq") // 1 config from client2 watch (removed config never updated) s1 = watchConfig(ch2, 50*time.Millisecond) @@ -956,7 +954,7 @@ func TestServerAPI(t *testing.T) { s2 = watchConfig(ch2, 50*time.Millisecond) assert.NotNil(t, s2) assert.True(t, s1.DeepEqual(sc1), "deepeq") - assert.True(t, s2.DeepEqual(gw2zero), "deepeq") // deleted! + assert.True(t, client.IsConfigDeleted(s2), "deepeq") // deleted! // no config from client3 watch s = watchConfig(ch3, 50*time.Millisecond) diff --git a/pkg/config/client/config.go b/pkg/config/client/config.go index 001ceeba..f25916c2 100644 --- a/pkg/config/client/config.go +++ b/pkg/config/client/config.go @@ -122,3 +122,19 @@ func parseRaw(c []byte) (*stnrv1.StunnerConfig, error) { return &s, nil } + +// IsConfigDeleted is a helper that allows to decide whether a config is being deleted. When a +// config is being removed (say, because the corresponding Gateway is deleted), the CDS server +// sends a validated zero-config for the client. This function is a quick helper to decide whether +// the config received is such a zero-config. +func IsConfigDeleted(conf *stnrv1.StunnerConfig) bool { + if conf == nil { + return false + } + zeroConf := ZeroConfig(conf.Admin.Name) + // zeroconfs have to be explcitly validated before deepEq (the cds client validates) + if err := zeroConf.Validate(); err != nil { + return false + } + return conf.DeepEqual(zeroConf) +} diff --git a/pkg/config/server/server.go b/pkg/config/server/server.go index 1f3d15db..b900913e 100644 --- a/pkg/config/server/server.go +++ b/pkg/config/server/server.go @@ -86,7 +86,8 @@ func (s *Server) Start(ctx context.Context) error { s.broadcastConfig(c) case c := <-s.deleteCh: - // delayed config deletion + s.log.V(2).Info("initiating deleyed config deletion", "id", c.Id) + go func() { select { case <-ctx.Done(): @@ -206,15 +207,12 @@ func (s *Server) sendConfig(conn *Conn, e *stnrv1.StunnerConfig) { json, err := json.Marshal(c) if err != nil { - s.log.Error(err, "cannor JSON serialize config", "event", e.String()) + s.log.Error(err, "cannot JSON serialize config", "event", e.String()) return } - s.sendJSONConfig(conn, json) -} - -func (s *Server) sendJSONConfig(conn *Conn, json []byte) { - s.log.V(2).Info("sending configuration to client", "client", conn.Id()) + s.log.V(2).Info("sending configuration to client", "client", conn.Id(), + "config", c.String()) if err := conn.WriteMessage(websocket.TextMessage, json); err != nil { s.log.Error(err, "error sending config update", "client", conn.Id())