From 37f73ab22990ac3d224cf1afc74d682abaae91f4 Mon Sep 17 00:00:00 2001 From: Derek Collison Date: Mon, 20 Jun 2022 10:39:37 -0700 Subject: [PATCH] Allow users directives for leafnodes to not block reloads. Signed-off-by: Derek Collison --- server/leafnode_test.go | 30 ++++++++++++++++++++++++++++ server/reload.go | 44 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/server/leafnode_test.go b/server/leafnode_test.go index 381adc2f..3ddde95b 100644 --- a/server/leafnode_test.go +++ b/server/leafnode_test.go @@ -4349,3 +4349,33 @@ func TestLeafNodeStreamAndShadowSubs(t *testing.T) { // Check again subPubAndCheck() } + +func TestLeafNodeAuthConfigReload(t *testing.T) { + template := ` + listen: 127.0.0.1:-1 + accounts { test: {} } + leaf { + listen: "127.0.0.1:7422" + tls { + cert_file: "../test/configs/certs/server-cert.pem" + key_file: "../test/configs/certs/server-key.pem" + ca_file: "../test/configs/certs/ca.pem" + } + authorization { + # These are only fields allowed atm. + users = [ { user: test, password: "s3cret1", account: "test" } ] + } + } + ` + conf := createConfFile(t, []byte(template)) + defer removeFile(t, conf) + + s, _ := RunServerWithConfig(conf) + defer s.Shutdown() + + lg := &captureErrorLogger{errCh: make(chan string, 10)} + s.SetLogger(lg, false, false) + + // Reload here should work ok. + reloadUpdateConfig(t, s, conf, template) +} diff --git a/server/reload.go b/server/reload.go index 38658d5e..2ae53172 100644 --- a/server/reload.go +++ b/server/reload.go @@ -1,4 +1,4 @@ -// Copyright 2017-2021 The NATS Authors +// Copyright 2017-2022 The NATS Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -1097,19 +1097,19 @@ func (s *Server) diffOptions(newOpts *Options) ([]option, error) { // Special check for leafnode remotes changes which are not supported right now. leafRemotesChanged := func(a, b LeafNodeOpts) bool { - if len(tmpOld.Remotes) != len(tmpNew.Remotes) { + if len(a.Remotes) != len(b.Remotes) { return true } // Check whether all remotes URLs are still the same. - for _, oldRemote := range tmpOld.Remotes { + for _, oldRemote := range a.Remotes { var found bool if oldRemote.LocalAccount == _EMPTY_ { oldRemote.LocalAccount = globalAccountName } - for _, newRemote := range tmpNew.Remotes { + for _, newRemote := range b.Remotes { // Bind to global account in case not defined. if newRemote.LocalAccount == _EMPTY_ { newRemote.LocalAccount = globalAccountName @@ -1120,7 +1120,6 @@ func (s *Server) diffOptions(newOpts *Options) ([]option, error) { break } } - if !found { return true } @@ -1136,6 +1135,41 @@ func (s *Server) diffOptions(newOpts *Options) ([]option, error) { tmpNew.Remotes = nil } + // Special check for auth users to detect changes. + // If anything is off will fall through and fail below. + // If we detect they are semantically the same we nil them out + // to pass the check below. + if tmpOld.Users != nil || tmpNew.Users != nil { + if len(tmpOld.Users) == len(tmpNew.Users) { + oua := make(map[string]*User, len(tmpOld.Users)) + nua := make(map[string]*User, len(tmpOld.Users)) + for _, u := range tmpOld.Users { + oua[u.Username] = u + } + for _, u := range tmpNew.Users { + nua[u.Username] = u + } + same := true + for uname, u := range oua { + // If we can not find new one with same name, drop through to fail. + nu, ok := nua[uname] + if !ok { + same = false + break + } + // If username or password or account different break. + if u.Username != nu.Username || u.Password != nu.Password || u.Account.GetName() != nu.Account.GetName() { + same = false + break + } + } + // We can nil out here. + if same { + tmpOld.Users, tmpNew.Users = nil, nil + } + } + } + // If there is really a change prevents reload. if !reflect.DeepEqual(tmpOld, tmpNew) { // See TODO(ik) note below about printing old/new values.