diff --git a/server/jetstream_cluster_test.go b/server/jetstream_cluster_test.go index 5f448339..9f22bfae 100644 --- a/server/jetstream_cluster_test.go +++ b/server/jetstream_cluster_test.go @@ -6240,6 +6240,46 @@ func TestJetStreamClusterSuperClusterAndSingleLeafNodeWithSharedSystemAccount(t } } +func TestJetStreamClusterLeafNodeDenyNoDupe(t *testing.T) { + tmpl := strings.Replace(jsClusterAccountsTempl, "store_dir:", "domain: CORE, store_dir:", 1) + c := createJetStreamCluster(t, tmpl, "CORE", _EMPTY_, 3, 18033, true) + defer c.shutdown() + + tmpl = strings.Replace(jsClusterTemplWithSingleLeafNode, "store_dir:", "domain: SPOKE, store_dir:", 1) + ln := c.createLeafNodeWithTemplate("LN-SPOKE", tmpl) + defer ln.Shutdown() + + checkLeafNodeConnectedCount(t, ln, 2) + + // Now disconnect our leafnode connections by restarting the server we are connected to.. + for _, s := range c.servers { + if s.ClusterName() != c.name { + continue + } + if nln := s.NumLeafNodes(); nln > 0 { + s.Shutdown() + c.restartServer(s) + } + } + // Make sure we are back connected. + checkLeafNodeConnectedCount(t, ln, 2) + + // Now grab leaf varz and make sure we have no dupe deny clauses. + vz, err := ln.Varz(nil) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + // Grab the correct remote. + for _, remote := range vz.LeafNode.Remotes { + if remote.LocalAccount == ln.SystemAccount().Name { + if len(remote.Deny.Exports) > 3 { // denyAll := []string{jscAllSubj, raftAllSubj, jsAllAPI} + t.Fatalf("Dupe entries found: %+v", remote.Deny) + } + break + } + } +} + // Multiple JS domains. func TestJetStreamClusterSingleLeafNodeWithoutSharedSystemAccount(t *testing.T) { c := createJetStreamCluster(t, jsClusterAccountsTempl, "HUB", _EMPTY_, 3, 14333, true) diff --git a/server/leafnode.go b/server/leafnode.go index 7b7370db..d14d5b15 100644 --- a/server/leafnode.go +++ b/server/leafnode.go @@ -170,14 +170,35 @@ func (s *Server) addInJSDenyAll(r *leafNodeCfg) { s.Noticef("Sharing system account but utilizing separate JetStream Domains") s.Noticef("Adding deny of %+v for leafnode configuration that bridges system account", denyAll) - r.DenyExports = append(r.DenyExports, denyAll...) - r.DenyImports = append(r.DenyImports, denyAll...) + hasDeny := func(deny string, l []string) bool { + for _, le := range l { + if le == deny { + return true + } + } + return false + } + + var exportAdded, importAdded bool + for _, deny := range denyAll { + if !hasDeny(deny, r.DenyExports) { + r.DenyExports = append(r.DenyExports, deny) + exportAdded = true + } + if !hasDeny(deny, r.DenyImports) { + r.DenyImports = append(r.DenyImports, deny) + importAdded = true + } + } + if !exportAdded && !importAdded { + return + } perms := &Permissions{} - if len(r.DenyExports) > 0 { + if exportAdded { perms.Publish = &SubjectPermission{Deny: r.DenyExports} } - if len(r.DenyImports) > 0 { + if importAdded { perms.Subscribe = &SubjectPermission{Deny: r.DenyImports} } r.perms = perms