github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/reload.go (about)

     1  // Copyright 2017-2023 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package server
    15  
    16  import (
    17  	"crypto/tls"
    18  	"errors"
    19  	"fmt"
    20  	"net/url"
    21  	"reflect"
    22  	"sort"
    23  	"strings"
    24  	"sync/atomic"
    25  	"time"
    26  
    27  	"github.com/klauspost/compress/s2"
    28  
    29  	"github.com/nats-io/jwt/v2"
    30  	"github.com/nats-io/nuid"
    31  )
    32  
    33  // FlagSnapshot captures the server options as specified by CLI flags at
    34  // startup. This should not be modified once the server has started.
    35  var FlagSnapshot *Options
    36  
    37  type reloadContext struct {
    38  	oldClusterPerms *RoutePermissions
    39  }
    40  
    41  // option is a hot-swappable configuration setting.
    42  type option interface {
    43  	// Apply the server option.
    44  	Apply(server *Server)
    45  
    46  	// IsLoggingChange indicates if this option requires reloading the logger.
    47  	IsLoggingChange() bool
    48  
    49  	// IsTraceLevelChange indicates if this option requires reloading cached trace level.
    50  	// Clients store trace level separately.
    51  	IsTraceLevelChange() bool
    52  
    53  	// IsAuthChange indicates if this option requires reloading authorization.
    54  	IsAuthChange() bool
    55  
    56  	// IsTLSChange indicates if this option requires reloading TLS.
    57  	IsTLSChange() bool
    58  
    59  	// IsClusterPermsChange indicates if this option requires reloading
    60  	// cluster permissions.
    61  	IsClusterPermsChange() bool
    62  
    63  	// IsClusterPoolSizeOrAccountsChange indicates if this option requires
    64  	// special handling for changes in cluster's pool size or accounts list.
    65  	IsClusterPoolSizeOrAccountsChange() bool
    66  
    67  	// IsJetStreamChange inidicates a change in the servers config for JetStream.
    68  	// Account changes will be handled separately in reloadAuthorization.
    69  	IsJetStreamChange() bool
    70  
    71  	// Indicates a change in the server that requires publishing the server's statz
    72  	IsStatszChange() bool
    73  }
    74  
    75  // noopOption is a base struct that provides default no-op behaviors.
    76  type noopOption struct{}
    77  
    78  func (n noopOption) IsLoggingChange() bool {
    79  	return false
    80  }
    81  
    82  func (n noopOption) IsTraceLevelChange() bool {
    83  	return false
    84  }
    85  
    86  func (n noopOption) IsAuthChange() bool {
    87  	return false
    88  }
    89  
    90  func (n noopOption) IsTLSChange() bool {
    91  	return false
    92  }
    93  
    94  func (n noopOption) IsClusterPermsChange() bool {
    95  	return false
    96  }
    97  
    98  func (n noopOption) IsClusterPoolSizeOrAccountsChange() bool {
    99  	return false
   100  }
   101  
   102  func (n noopOption) IsJetStreamChange() bool {
   103  	return false
   104  }
   105  
   106  func (n noopOption) IsStatszChange() bool {
   107  	return false
   108  }
   109  
   110  // loggingOption is a base struct that provides default option behaviors for
   111  // logging-related options.
   112  type loggingOption struct {
   113  	noopOption
   114  }
   115  
   116  func (l loggingOption) IsLoggingChange() bool {
   117  	return true
   118  }
   119  
   120  // traceLevelOption is a base struct that provides default option behaviors for
   121  // tracelevel-related options.
   122  type traceLevelOption struct {
   123  	loggingOption
   124  }
   125  
   126  func (l traceLevelOption) IsTraceLevelChange() bool {
   127  	return true
   128  }
   129  
   130  // traceOption implements the option interface for the `trace` setting.
   131  type traceOption struct {
   132  	traceLevelOption
   133  	newValue bool
   134  }
   135  
   136  // Apply is a no-op because logging will be reloaded after options are applied.
   137  func (t *traceOption) Apply(server *Server) {
   138  	server.Noticef("Reloaded: trace = %v", t.newValue)
   139  }
   140  
   141  // traceOption implements the option interface for the `trace` setting.
   142  type traceVerboseOption struct {
   143  	traceLevelOption
   144  	newValue bool
   145  }
   146  
   147  // Apply is a no-op because logging will be reloaded after options are applied.
   148  func (t *traceVerboseOption) Apply(server *Server) {
   149  	server.Noticef("Reloaded: trace_verbose = %v", t.newValue)
   150  }
   151  
   152  // debugOption implements the option interface for the `debug` setting.
   153  type debugOption struct {
   154  	loggingOption
   155  	newValue bool
   156  }
   157  
   158  // Apply is mostly a no-op because logging will be reloaded after options are applied.
   159  // However we will kick the raft nodes if they exist to reload.
   160  func (d *debugOption) Apply(server *Server) {
   161  	server.Noticef("Reloaded: debug = %v", d.newValue)
   162  	server.reloadDebugRaftNodes(d.newValue)
   163  }
   164  
   165  // logtimeOption implements the option interface for the `logtime` setting.
   166  type logtimeOption struct {
   167  	loggingOption
   168  	newValue bool
   169  }
   170  
   171  // Apply is a no-op because logging will be reloaded after options are applied.
   172  func (l *logtimeOption) Apply(server *Server) {
   173  	server.Noticef("Reloaded: logtime = %v", l.newValue)
   174  }
   175  
   176  // logtimeUTCOption implements the option interface for the `logtime_utc` setting.
   177  type logtimeUTCOption struct {
   178  	loggingOption
   179  	newValue bool
   180  }
   181  
   182  // Apply is a no-op because logging will be reloaded after options are applied.
   183  func (l *logtimeUTCOption) Apply(server *Server) {
   184  	server.Noticef("Reloaded: logtime_utc = %v", l.newValue)
   185  }
   186  
   187  // logfileOption implements the option interface for the `log_file` setting.
   188  type logfileOption struct {
   189  	loggingOption
   190  	newValue string
   191  }
   192  
   193  // Apply is a no-op because logging will be reloaded after options are applied.
   194  func (l *logfileOption) Apply(server *Server) {
   195  	server.Noticef("Reloaded: log_file = %v", l.newValue)
   196  }
   197  
   198  // syslogOption implements the option interface for the `syslog` setting.
   199  type syslogOption struct {
   200  	loggingOption
   201  	newValue bool
   202  }
   203  
   204  // Apply is a no-op because logging will be reloaded after options are applied.
   205  func (s *syslogOption) Apply(server *Server) {
   206  	server.Noticef("Reloaded: syslog = %v", s.newValue)
   207  }
   208  
   209  // remoteSyslogOption implements the option interface for the `remote_syslog`
   210  // setting.
   211  type remoteSyslogOption struct {
   212  	loggingOption
   213  	newValue string
   214  }
   215  
   216  // Apply is a no-op because logging will be reloaded after options are applied.
   217  func (r *remoteSyslogOption) Apply(server *Server) {
   218  	server.Noticef("Reloaded: remote_syslog = %v", r.newValue)
   219  }
   220  
   221  // tlsOption implements the option interface for the `tls` setting.
   222  type tlsOption struct {
   223  	noopOption
   224  	newValue *tls.Config
   225  }
   226  
   227  // Apply the tls change.
   228  func (t *tlsOption) Apply(server *Server) {
   229  	server.mu.Lock()
   230  	tlsRequired := t.newValue != nil
   231  	server.info.TLSRequired = tlsRequired && !server.getOpts().AllowNonTLS
   232  	message := "disabled"
   233  	if tlsRequired {
   234  		server.info.TLSVerify = (t.newValue.ClientAuth == tls.RequireAndVerifyClientCert)
   235  		message = "enabled"
   236  	}
   237  	server.mu.Unlock()
   238  	server.Noticef("Reloaded: tls = %s", message)
   239  }
   240  
   241  func (t *tlsOption) IsTLSChange() bool {
   242  	return true
   243  }
   244  
   245  // tlsTimeoutOption implements the option interface for the tls `timeout`
   246  // setting.
   247  type tlsTimeoutOption struct {
   248  	noopOption
   249  	newValue float64
   250  }
   251  
   252  // Apply is a no-op because the timeout will be reloaded after options are
   253  // applied.
   254  func (t *tlsTimeoutOption) Apply(server *Server) {
   255  	server.Noticef("Reloaded: tls timeout = %v", t.newValue)
   256  }
   257  
   258  // tlsPinnedCertOption implements the option interface for the tls `pinned_certs` setting.
   259  type tlsPinnedCertOption struct {
   260  	noopOption
   261  	newValue PinnedCertSet
   262  }
   263  
   264  // Apply is a no-op because the pinned certs will be reloaded after options are  applied.
   265  func (t *tlsPinnedCertOption) Apply(server *Server) {
   266  	server.Noticef("Reloaded: %d pinned_certs", len(t.newValue))
   267  }
   268  
   269  // tlsHandshakeFirst implements the option interface for the tls `handshake first` setting.
   270  type tlsHandshakeFirst struct {
   271  	noopOption
   272  	newValue bool
   273  }
   274  
   275  // Apply is a no-op because the timeout will be reloaded after options are applied.
   276  func (t *tlsHandshakeFirst) Apply(server *Server) {
   277  	server.Noticef("Reloaded: Client TLS handshake first: %v", t.newValue)
   278  }
   279  
   280  // tlsHandshakeFirstFallback implements the option interface for the tls `handshake first fallback delay` setting.
   281  type tlsHandshakeFirstFallback struct {
   282  	noopOption
   283  	newValue time.Duration
   284  }
   285  
   286  // Apply is a no-op because the timeout will be reloaded after options are applied.
   287  func (t *tlsHandshakeFirstFallback) Apply(server *Server) {
   288  	server.Noticef("Reloaded: Client TLS handshake first fallback delay: %v", t.newValue)
   289  }
   290  
   291  // authOption is a base struct that provides default option behaviors.
   292  type authOption struct {
   293  	noopOption
   294  }
   295  
   296  func (o authOption) IsAuthChange() bool {
   297  	return true
   298  }
   299  
   300  // usernameOption implements the option interface for the `username` setting.
   301  type usernameOption struct {
   302  	authOption
   303  }
   304  
   305  // Apply is a no-op because authorization will be reloaded after options are
   306  // applied.
   307  func (u *usernameOption) Apply(server *Server) {
   308  	server.Noticef("Reloaded: authorization username")
   309  }
   310  
   311  // passwordOption implements the option interface for the `password` setting.
   312  type passwordOption struct {
   313  	authOption
   314  }
   315  
   316  // Apply is a no-op because authorization will be reloaded after options are
   317  // applied.
   318  func (p *passwordOption) Apply(server *Server) {
   319  	server.Noticef("Reloaded: authorization password")
   320  }
   321  
   322  // authorizationOption implements the option interface for the `token`
   323  // authorization setting.
   324  type authorizationOption struct {
   325  	authOption
   326  }
   327  
   328  // Apply is a no-op because authorization will be reloaded after options are
   329  // applied.
   330  func (a *authorizationOption) Apply(server *Server) {
   331  	server.Noticef("Reloaded: authorization token")
   332  }
   333  
   334  // authTimeoutOption implements the option interface for the authorization
   335  // `timeout` setting.
   336  type authTimeoutOption struct {
   337  	noopOption // Not authOption because this is a no-op; will be reloaded with options.
   338  	newValue   float64
   339  }
   340  
   341  // Apply is a no-op because the timeout will be reloaded after options are
   342  // applied.
   343  func (a *authTimeoutOption) Apply(server *Server) {
   344  	server.Noticef("Reloaded: authorization timeout = %v", a.newValue)
   345  }
   346  
   347  // tagsOption implements the option interface for the `tags` setting.
   348  type tagsOption struct {
   349  	noopOption // Not authOption because this is a no-op; will be reloaded with options.
   350  }
   351  
   352  func (u *tagsOption) Apply(server *Server) {
   353  	server.Noticef("Reloaded: tags")
   354  }
   355  
   356  func (u *tagsOption) IsStatszChange() bool {
   357  	return true
   358  }
   359  
   360  // usersOption implements the option interface for the authorization `users`
   361  // setting.
   362  type usersOption struct {
   363  	authOption
   364  }
   365  
   366  func (u *usersOption) Apply(server *Server) {
   367  	server.Noticef("Reloaded: authorization users")
   368  }
   369  
   370  // nkeysOption implements the option interface for the authorization `users`
   371  // setting.
   372  type nkeysOption struct {
   373  	authOption
   374  }
   375  
   376  func (u *nkeysOption) Apply(server *Server) {
   377  	server.Noticef("Reloaded: authorization nkey users")
   378  }
   379  
   380  // clusterOption implements the option interface for the `cluster` setting.
   381  type clusterOption struct {
   382  	authOption
   383  	newValue        ClusterOpts
   384  	permsChanged    bool
   385  	accsAdded       []string
   386  	accsRemoved     []string
   387  	poolSizeChanged bool
   388  	compressChanged bool
   389  }
   390  
   391  // Apply the cluster change.
   392  func (c *clusterOption) Apply(s *Server) {
   393  	// TODO: support enabling/disabling clustering.
   394  	s.mu.Lock()
   395  	tlsRequired := c.newValue.TLSConfig != nil
   396  	s.routeInfo.TLSRequired = tlsRequired
   397  	s.routeInfo.TLSVerify = tlsRequired
   398  	s.routeInfo.AuthRequired = c.newValue.Username != ""
   399  	if c.newValue.NoAdvertise {
   400  		s.routeInfo.ClientConnectURLs = nil
   401  		s.routeInfo.WSConnectURLs = nil
   402  	} else {
   403  		s.routeInfo.ClientConnectURLs = s.clientConnectURLs
   404  		s.routeInfo.WSConnectURLs = s.websocket.connectURLs
   405  	}
   406  	s.setRouteInfoHostPortAndIP()
   407  	var routes []*client
   408  	if c.compressChanged {
   409  		co := &s.getOpts().Cluster.Compression
   410  		newMode := co.Mode
   411  		s.forEachRoute(func(r *client) {
   412  			r.mu.Lock()
   413  			// Skip routes that are "not supported" (because they will never do
   414  			// compression) or the routes that have already the new compression
   415  			// mode.
   416  			if r.route.compression == CompressionNotSupported || r.route.compression == newMode {
   417  				r.mu.Unlock()
   418  				return
   419  			}
   420  			// We need to close the route if it had compression "off" or the new
   421  			// mode is compression "off", or if the new mode is "accept", because
   422  			// these require negotiation.
   423  			if r.route.compression == CompressionOff || newMode == CompressionOff || newMode == CompressionAccept {
   424  				routes = append(routes, r)
   425  			} else if newMode == CompressionS2Auto {
   426  				// If the mode is "s2_auto", we need to check if there is really
   427  				// need to change, and at any rate, we want to save the actual
   428  				// compression level here, not s2_auto.
   429  				r.updateS2AutoCompressionLevel(co, &r.route.compression)
   430  			} else {
   431  				// Simply change the compression writer
   432  				r.out.cw = s2.NewWriter(nil, s2WriterOptions(newMode)...)
   433  				r.route.compression = newMode
   434  			}
   435  			r.mu.Unlock()
   436  		})
   437  	}
   438  	s.mu.Unlock()
   439  	if c.newValue.Name != "" && c.newValue.Name != s.ClusterName() {
   440  		s.setClusterName(c.newValue.Name)
   441  	}
   442  	for _, r := range routes {
   443  		r.closeConnection(ClientClosed)
   444  	}
   445  	s.Noticef("Reloaded: cluster")
   446  	if tlsRequired && c.newValue.TLSConfig.InsecureSkipVerify {
   447  		s.Warnf(clusterTLSInsecureWarning)
   448  	}
   449  }
   450  
   451  func (c *clusterOption) IsClusterPermsChange() bool {
   452  	return c.permsChanged
   453  }
   454  
   455  func (c *clusterOption) IsClusterPoolSizeOrAccountsChange() bool {
   456  	return c.poolSizeChanged || len(c.accsAdded) > 0 || len(c.accsRemoved) > 0
   457  }
   458  
   459  func (c *clusterOption) diffPoolAndAccounts(old *ClusterOpts) {
   460  	c.poolSizeChanged = c.newValue.PoolSize != old.PoolSize
   461  addLoop:
   462  	for _, na := range c.newValue.PinnedAccounts {
   463  		for _, oa := range old.PinnedAccounts {
   464  			if na == oa {
   465  				continue addLoop
   466  			}
   467  		}
   468  		c.accsAdded = append(c.accsAdded, na)
   469  	}
   470  removeLoop:
   471  	for _, oa := range old.PinnedAccounts {
   472  		for _, na := range c.newValue.PinnedAccounts {
   473  			if oa == na {
   474  				continue removeLoop
   475  			}
   476  		}
   477  		c.accsRemoved = append(c.accsRemoved, oa)
   478  	}
   479  }
   480  
   481  // routesOption implements the option interface for the cluster `routes`
   482  // setting.
   483  type routesOption struct {
   484  	noopOption
   485  	add    []*url.URL
   486  	remove []*url.URL
   487  }
   488  
   489  // Apply the route changes by adding and removing the necessary routes.
   490  func (r *routesOption) Apply(server *Server) {
   491  	server.mu.Lock()
   492  	routes := make([]*client, server.numRoutes())
   493  	i := 0
   494  	server.forEachRoute(func(r *client) {
   495  		routes[i] = r
   496  		i++
   497  	})
   498  	// If there was a change, notify monitoring code that it should
   499  	// update the route URLs if /varz endpoint is inspected.
   500  	if len(r.add)+len(r.remove) > 0 {
   501  		server.varzUpdateRouteURLs = true
   502  	}
   503  	server.mu.Unlock()
   504  
   505  	// Remove routes.
   506  	for _, remove := range r.remove {
   507  		for _, client := range routes {
   508  			var url *url.URL
   509  			client.mu.Lock()
   510  			if client.route != nil {
   511  				url = client.route.url
   512  			}
   513  			client.mu.Unlock()
   514  			if url != nil && urlsAreEqual(url, remove) {
   515  				// Do not attempt to reconnect when route is removed.
   516  				client.setNoReconnect()
   517  				client.closeConnection(RouteRemoved)
   518  				server.Noticef("Removed route %v", remove)
   519  			}
   520  		}
   521  	}
   522  
   523  	// Add routes.
   524  	server.mu.Lock()
   525  	server.solicitRoutes(r.add, server.getOpts().Cluster.PinnedAccounts)
   526  	server.mu.Unlock()
   527  
   528  	server.Noticef("Reloaded: cluster routes")
   529  }
   530  
   531  // maxConnOption implements the option interface for the `max_connections`
   532  // setting.
   533  type maxConnOption struct {
   534  	noopOption
   535  	newValue int
   536  }
   537  
   538  // Apply the max connections change by closing random connections til we are
   539  // below the limit if necessary.
   540  func (m *maxConnOption) Apply(server *Server) {
   541  	server.mu.Lock()
   542  	var (
   543  		clients = make([]*client, len(server.clients))
   544  		i       = 0
   545  	)
   546  	// Map iteration is random, which allows us to close random connections.
   547  	for _, client := range server.clients {
   548  		clients[i] = client
   549  		i++
   550  	}
   551  	server.mu.Unlock()
   552  
   553  	if m.newValue > 0 && len(clients) > m.newValue {
   554  		// Close connections til we are within the limit.
   555  		var (
   556  			numClose = len(clients) - m.newValue
   557  			closed   = 0
   558  		)
   559  		for _, client := range clients {
   560  			client.maxConnExceeded()
   561  			closed++
   562  			if closed >= numClose {
   563  				break
   564  			}
   565  		}
   566  		server.Noticef("Closed %d connections to fall within max_connections", closed)
   567  	}
   568  	server.Noticef("Reloaded: max_connections = %v", m.newValue)
   569  }
   570  
   571  // pidFileOption implements the option interface for the `pid_file` setting.
   572  type pidFileOption struct {
   573  	noopOption
   574  	newValue string
   575  }
   576  
   577  // Apply the setting by logging the pid to the new file.
   578  func (p *pidFileOption) Apply(server *Server) {
   579  	if p.newValue == "" {
   580  		return
   581  	}
   582  	if err := server.logPid(); err != nil {
   583  		server.Errorf("Failed to write pidfile: %v", err)
   584  	}
   585  	server.Noticef("Reloaded: pid_file = %v", p.newValue)
   586  }
   587  
   588  // portsFileDirOption implements the option interface for the `portFileDir` setting.
   589  type portsFileDirOption struct {
   590  	noopOption
   591  	oldValue string
   592  	newValue string
   593  }
   594  
   595  func (p *portsFileDirOption) Apply(server *Server) {
   596  	server.deletePortsFile(p.oldValue)
   597  	server.logPorts()
   598  	server.Noticef("Reloaded: ports_file_dir = %v", p.newValue)
   599  }
   600  
   601  // maxControlLineOption implements the option interface for the
   602  // `max_control_line` setting.
   603  type maxControlLineOption struct {
   604  	noopOption
   605  	newValue int32
   606  }
   607  
   608  // Apply the setting by updating each client.
   609  func (m *maxControlLineOption) Apply(server *Server) {
   610  	mcl := int32(m.newValue)
   611  	server.mu.Lock()
   612  	for _, client := range server.clients {
   613  		atomic.StoreInt32(&client.mcl, mcl)
   614  	}
   615  	server.mu.Unlock()
   616  	server.Noticef("Reloaded: max_control_line = %d", mcl)
   617  }
   618  
   619  // maxPayloadOption implements the option interface for the `max_payload`
   620  // setting.
   621  type maxPayloadOption struct {
   622  	noopOption
   623  	newValue int32
   624  }
   625  
   626  // Apply the setting by updating the server info and each client.
   627  func (m *maxPayloadOption) Apply(server *Server) {
   628  	server.mu.Lock()
   629  	server.info.MaxPayload = m.newValue
   630  	for _, client := range server.clients {
   631  		atomic.StoreInt32(&client.mpay, int32(m.newValue))
   632  	}
   633  	server.mu.Unlock()
   634  	server.Noticef("Reloaded: max_payload = %d", m.newValue)
   635  }
   636  
   637  // pingIntervalOption implements the option interface for the `ping_interval`
   638  // setting.
   639  type pingIntervalOption struct {
   640  	noopOption
   641  	newValue time.Duration
   642  }
   643  
   644  // Apply is a no-op because the ping interval will be reloaded after options
   645  // are applied.
   646  func (p *pingIntervalOption) Apply(server *Server) {
   647  	server.Noticef("Reloaded: ping_interval = %s", p.newValue)
   648  }
   649  
   650  // maxPingsOutOption implements the option interface for the `ping_max`
   651  // setting.
   652  type maxPingsOutOption struct {
   653  	noopOption
   654  	newValue int
   655  }
   656  
   657  // Apply is a no-op because the ping interval will be reloaded after options
   658  // are applied.
   659  func (m *maxPingsOutOption) Apply(server *Server) {
   660  	server.Noticef("Reloaded: ping_max = %d", m.newValue)
   661  }
   662  
   663  // writeDeadlineOption implements the option interface for the `write_deadline`
   664  // setting.
   665  type writeDeadlineOption struct {
   666  	noopOption
   667  	newValue time.Duration
   668  }
   669  
   670  // Apply is a no-op because the write deadline will be reloaded after options
   671  // are applied.
   672  func (w *writeDeadlineOption) Apply(server *Server) {
   673  	server.Noticef("Reloaded: write_deadline = %s", w.newValue)
   674  }
   675  
   676  // clientAdvertiseOption implements the option interface for the `client_advertise` setting.
   677  type clientAdvertiseOption struct {
   678  	noopOption
   679  	newValue string
   680  }
   681  
   682  // Apply the setting by updating the server info and regenerate the infoJSON byte array.
   683  func (c *clientAdvertiseOption) Apply(server *Server) {
   684  	server.mu.Lock()
   685  	server.setInfoHostPort()
   686  	server.mu.Unlock()
   687  	server.Noticef("Reload: client_advertise = %s", c.newValue)
   688  }
   689  
   690  // accountsOption implements the option interface.
   691  // Ensure that authorization code is executed if any change in accounts
   692  type accountsOption struct {
   693  	authOption
   694  }
   695  
   696  // Apply is a no-op. Changes will be applied in reloadAuthorization
   697  func (a *accountsOption) Apply(s *Server) {
   698  	s.Noticef("Reloaded: accounts")
   699  }
   700  
   701  // For changes to a server's config.
   702  type jetStreamOption struct {
   703  	noopOption
   704  	newValue bool
   705  }
   706  
   707  func (a *jetStreamOption) Apply(s *Server) {
   708  	s.Noticef("Reloaded: JetStream")
   709  }
   710  
   711  func (jso jetStreamOption) IsJetStreamChange() bool {
   712  	return true
   713  }
   714  
   715  func (jso jetStreamOption) IsStatszChange() bool {
   716  	return true
   717  }
   718  
   719  type ocspOption struct {
   720  	tlsOption
   721  	newValue *OCSPConfig
   722  }
   723  
   724  func (a *ocspOption) Apply(s *Server) {
   725  	s.Noticef("Reloaded: OCSP")
   726  }
   727  
   728  type ocspResponseCacheOption struct {
   729  	tlsOption
   730  	newValue *OCSPResponseCacheConfig
   731  }
   732  
   733  func (a *ocspResponseCacheOption) Apply(s *Server) {
   734  	s.Noticef("Reloaded OCSP peer cache")
   735  }
   736  
   737  // connectErrorReports implements the option interface for the `connect_error_reports`
   738  // setting.
   739  type connectErrorReports struct {
   740  	noopOption
   741  	newValue int
   742  }
   743  
   744  // Apply is a no-op because the value will be reloaded after options are applied.
   745  func (c *connectErrorReports) Apply(s *Server) {
   746  	s.Noticef("Reloaded: connect_error_reports = %v", c.newValue)
   747  }
   748  
   749  // connectErrorReports implements the option interface for the `connect_error_reports`
   750  // setting.
   751  type reconnectErrorReports struct {
   752  	noopOption
   753  	newValue int
   754  }
   755  
   756  // Apply is a no-op because the value will be reloaded after options are applied.
   757  func (r *reconnectErrorReports) Apply(s *Server) {
   758  	s.Noticef("Reloaded: reconnect_error_reports = %v", r.newValue)
   759  }
   760  
   761  // maxTracedMsgLenOption implements the option interface for the `max_traced_msg_len` setting.
   762  type maxTracedMsgLenOption struct {
   763  	noopOption
   764  	newValue int
   765  }
   766  
   767  // Apply the setting by updating the maximum traced message length.
   768  func (m *maxTracedMsgLenOption) Apply(server *Server) {
   769  	server.mu.Lock()
   770  	defer server.mu.Unlock()
   771  	server.opts.MaxTracedMsgLen = m.newValue
   772  	server.Noticef("Reloaded: max_traced_msg_len = %d", m.newValue)
   773  }
   774  
   775  type mqttAckWaitReload struct {
   776  	noopOption
   777  	newValue time.Duration
   778  }
   779  
   780  func (o *mqttAckWaitReload) Apply(s *Server) {
   781  	s.Noticef("Reloaded: MQTT ack_wait = %v", o.newValue)
   782  }
   783  
   784  type mqttMaxAckPendingReload struct {
   785  	noopOption
   786  	newValue uint16
   787  }
   788  
   789  func (o *mqttMaxAckPendingReload) Apply(s *Server) {
   790  	s.mqttUpdateMaxAckPending(o.newValue)
   791  	s.Noticef("Reloaded: MQTT max_ack_pending = %v", o.newValue)
   792  }
   793  
   794  type mqttStreamReplicasReload struct {
   795  	noopOption
   796  	newValue int
   797  }
   798  
   799  func (o *mqttStreamReplicasReload) Apply(s *Server) {
   800  	s.Noticef("Reloaded: MQTT stream_replicas = %v", o.newValue)
   801  }
   802  
   803  type mqttConsumerReplicasReload struct {
   804  	noopOption
   805  	newValue int
   806  }
   807  
   808  func (o *mqttConsumerReplicasReload) Apply(s *Server) {
   809  	s.Noticef("Reloaded: MQTT consumer_replicas = %v", o.newValue)
   810  }
   811  
   812  type mqttConsumerMemoryStorageReload struct {
   813  	noopOption
   814  	newValue bool
   815  }
   816  
   817  func (o *mqttConsumerMemoryStorageReload) Apply(s *Server) {
   818  	s.Noticef("Reloaded: MQTT consumer_memory_storage = %v", o.newValue)
   819  }
   820  
   821  type mqttInactiveThresholdReload struct {
   822  	noopOption
   823  	newValue time.Duration
   824  }
   825  
   826  func (o *mqttInactiveThresholdReload) Apply(s *Server) {
   827  	s.Noticef("Reloaded: MQTT consumer_inactive_threshold = %v", o.newValue)
   828  }
   829  
   830  type profBlockRateReload struct {
   831  	noopOption
   832  	newValue int
   833  }
   834  
   835  func (o *profBlockRateReload) Apply(s *Server) {
   836  	s.setBlockProfileRate(o.newValue)
   837  	s.Noticef("Reloaded: prof_block_rate = %v", o.newValue)
   838  }
   839  
   840  type leafNodeOption struct {
   841  	noopOption
   842  	tlsFirstChanged    bool
   843  	compressionChanged bool
   844  }
   845  
   846  func (l *leafNodeOption) Apply(s *Server) {
   847  	opts := s.getOpts()
   848  	if l.tlsFirstChanged {
   849  		s.Noticef("Reloaded: LeafNode TLS HandshakeFirst value is: %v", opts.LeafNode.TLSHandshakeFirst)
   850  		for _, r := range opts.LeafNode.Remotes {
   851  			s.Noticef("Reloaded: LeafNode Remote to %v TLS HandshakeFirst value is: %v", r.URLs, r.TLSHandshakeFirst)
   852  		}
   853  	}
   854  	if l.compressionChanged {
   855  		var leafs []*client
   856  		acceptSideCompOpts := &opts.LeafNode.Compression
   857  
   858  		s.mu.RLock()
   859  		// First, update our internal leaf remote configurations with the new
   860  		// compress options.
   861  		// Since changing the remotes (as in adding/removing) is currently not
   862  		// supported, we know that we should have the same number in Options
   863  		// than in leafRemoteCfgs, but to be sure, use the max size.
   864  		max := len(opts.LeafNode.Remotes)
   865  		if l := len(s.leafRemoteCfgs); l < max {
   866  			max = l
   867  		}
   868  		for i := 0; i < max; i++ {
   869  			lr := s.leafRemoteCfgs[i]
   870  			lr.Lock()
   871  			lr.Compression = opts.LeafNode.Remotes[i].Compression
   872  			lr.Unlock()
   873  		}
   874  
   875  		for _, l := range s.leafs {
   876  			var co *CompressionOpts
   877  
   878  			l.mu.Lock()
   879  			if r := l.leaf.remote; r != nil {
   880  				co = &r.Compression
   881  			} else {
   882  				co = acceptSideCompOpts
   883  			}
   884  			newMode := co.Mode
   885  			// Skip leaf connections that are "not supported" (because they
   886  			// will never do compression) or the ones that have already the
   887  			// new compression mode.
   888  			if l.leaf.compression == CompressionNotSupported || l.leaf.compression == newMode {
   889  				l.mu.Unlock()
   890  				continue
   891  			}
   892  			// We need to close the connections if it had compression "off" or the new
   893  			// mode is compression "off", or if the new mode is "accept", because
   894  			// these require negotiation.
   895  			if l.leaf.compression == CompressionOff || newMode == CompressionOff || newMode == CompressionAccept {
   896  				leafs = append(leafs, l)
   897  			} else if newMode == CompressionS2Auto {
   898  				// If the mode is "s2_auto", we need to check if there is really
   899  				// need to change, and at any rate, we want to save the actual
   900  				// compression level here, not s2_auto.
   901  				l.updateS2AutoCompressionLevel(co, &l.leaf.compression)
   902  			} else {
   903  				// Simply change the compression writer
   904  				l.out.cw = s2.NewWriter(nil, s2WriterOptions(newMode)...)
   905  				l.leaf.compression = newMode
   906  			}
   907  			l.mu.Unlock()
   908  		}
   909  		s.mu.RUnlock()
   910  		// Close the connections for which negotiation is required.
   911  		for _, l := range leafs {
   912  			l.closeConnection(ClientClosed)
   913  		}
   914  		s.Noticef("Reloaded: LeafNode compression settings")
   915  	}
   916  }
   917  
   918  // Compares options and disconnects clients that are no longer listed in pinned certs. Lock must not be held.
   919  func (s *Server) recheckPinnedCerts(curOpts *Options, newOpts *Options) {
   920  	s.mu.Lock()
   921  	disconnectClients := []*client{}
   922  	protoToPinned := map[int]PinnedCertSet{}
   923  	if !reflect.DeepEqual(newOpts.TLSPinnedCerts, curOpts.TLSPinnedCerts) {
   924  		protoToPinned[NATS] = curOpts.TLSPinnedCerts
   925  	}
   926  	if !reflect.DeepEqual(newOpts.MQTT.TLSPinnedCerts, curOpts.MQTT.TLSPinnedCerts) {
   927  		protoToPinned[MQTT] = curOpts.MQTT.TLSPinnedCerts
   928  	}
   929  	if !reflect.DeepEqual(newOpts.Websocket.TLSPinnedCerts, curOpts.Websocket.TLSPinnedCerts) {
   930  		protoToPinned[WS] = curOpts.Websocket.TLSPinnedCerts
   931  	}
   932  	for _, c := range s.clients {
   933  		if c.kind != CLIENT {
   934  			continue
   935  		}
   936  		if pinned, ok := protoToPinned[c.clientType()]; ok {
   937  			if !c.matchesPinnedCert(pinned) {
   938  				disconnectClients = append(disconnectClients, c)
   939  			}
   940  		}
   941  	}
   942  	checkClients := func(kind int, clients map[uint64]*client, set PinnedCertSet) {
   943  		for _, c := range clients {
   944  			if c.kind == kind && !c.matchesPinnedCert(set) {
   945  				disconnectClients = append(disconnectClients, c)
   946  			}
   947  		}
   948  	}
   949  	if !reflect.DeepEqual(newOpts.LeafNode.TLSPinnedCerts, curOpts.LeafNode.TLSPinnedCerts) {
   950  		checkClients(LEAF, s.leafs, newOpts.LeafNode.TLSPinnedCerts)
   951  	}
   952  	if !reflect.DeepEqual(newOpts.Cluster.TLSPinnedCerts, curOpts.Cluster.TLSPinnedCerts) {
   953  		s.forEachRoute(func(c *client) {
   954  			if !c.matchesPinnedCert(newOpts.Cluster.TLSPinnedCerts) {
   955  				disconnectClients = append(disconnectClients, c)
   956  			}
   957  		})
   958  	}
   959  	if s.gateway.enabled && reflect.DeepEqual(newOpts.Gateway.TLSPinnedCerts, curOpts.Gateway.TLSPinnedCerts) {
   960  		gw := s.gateway
   961  		gw.RLock()
   962  		for _, c := range gw.out {
   963  			if !c.matchesPinnedCert(newOpts.Gateway.TLSPinnedCerts) {
   964  				disconnectClients = append(disconnectClients, c)
   965  			}
   966  		}
   967  		checkClients(GATEWAY, gw.in, newOpts.Gateway.TLSPinnedCerts)
   968  		gw.RUnlock()
   969  	}
   970  	s.mu.Unlock()
   971  	if len(disconnectClients) > 0 {
   972  		s.Noticef("Disconnect %d clients due to pinned certs reload", len(disconnectClients))
   973  		for _, c := range disconnectClients {
   974  			c.closeConnection(TLSHandshakeError)
   975  		}
   976  	}
   977  }
   978  
   979  // Reload reads the current configuration file and calls out to ReloadOptions
   980  // to apply the changes. This returns an error if the server was not started
   981  // with a config file or an option which doesn't support hot-swapping was changed.
   982  func (s *Server) Reload() error {
   983  	s.mu.Lock()
   984  	configFile := s.configFile
   985  	s.mu.Unlock()
   986  	if configFile == "" {
   987  		return errors.New("can only reload config when a file is provided using -c or --config")
   988  	}
   989  
   990  	newOpts, err := ProcessConfigFile(configFile)
   991  	if err != nil {
   992  		// TODO: Dump previous good config to a .bak file?
   993  		return err
   994  	}
   995  	return s.ReloadOptions(newOpts)
   996  }
   997  
   998  // ReloadOptions applies any supported options from the provided Option
   999  // type. This returns an error if an option which doesn't support
  1000  // hot-swapping was changed.
  1001  func (s *Server) ReloadOptions(newOpts *Options) error {
  1002  	s.reloadMu.Lock()
  1003  	defer s.reloadMu.Unlock()
  1004  
  1005  	s.mu.Lock()
  1006  
  1007  	curOpts := s.getOpts()
  1008  
  1009  	// Wipe trusted keys if needed when we have an operator.
  1010  	if len(curOpts.TrustedOperators) > 0 && len(curOpts.TrustedKeys) > 0 {
  1011  		curOpts.TrustedKeys = nil
  1012  	}
  1013  
  1014  	clientOrgPort := curOpts.Port
  1015  	clusterOrgPort := curOpts.Cluster.Port
  1016  	gatewayOrgPort := curOpts.Gateway.Port
  1017  	leafnodesOrgPort := curOpts.LeafNode.Port
  1018  	websocketOrgPort := curOpts.Websocket.Port
  1019  	mqttOrgPort := curOpts.MQTT.Port
  1020  
  1021  	s.mu.Unlock()
  1022  
  1023  	// In case "-cluster ..." was provided through the command line, this will
  1024  	// properly set the Cluster.Host/Port etc...
  1025  	if l := curOpts.Cluster.ListenStr; l != _EMPTY_ {
  1026  		newOpts.Cluster.ListenStr = l
  1027  		overrideCluster(newOpts)
  1028  	}
  1029  
  1030  	// Apply flags over config file settings.
  1031  	newOpts = MergeOptions(newOpts, FlagSnapshot)
  1032  
  1033  	// Need more processing for boolean flags...
  1034  	if FlagSnapshot != nil {
  1035  		applyBoolFlags(newOpts, FlagSnapshot)
  1036  	}
  1037  
  1038  	setBaselineOptions(newOpts)
  1039  
  1040  	// setBaselineOptions sets Port to 0 if set to -1 (RANDOM port)
  1041  	// If that's the case, set it to the saved value when the accept loop was
  1042  	// created.
  1043  	if newOpts.Port == 0 {
  1044  		newOpts.Port = clientOrgPort
  1045  	}
  1046  	// We don't do that for cluster, so check against -1.
  1047  	if newOpts.Cluster.Port == -1 {
  1048  		newOpts.Cluster.Port = clusterOrgPort
  1049  	}
  1050  	if newOpts.Gateway.Port == -1 {
  1051  		newOpts.Gateway.Port = gatewayOrgPort
  1052  	}
  1053  	if newOpts.LeafNode.Port == -1 {
  1054  		newOpts.LeafNode.Port = leafnodesOrgPort
  1055  	}
  1056  	if newOpts.Websocket.Port == -1 {
  1057  		newOpts.Websocket.Port = websocketOrgPort
  1058  	}
  1059  	if newOpts.MQTT.Port == -1 {
  1060  		newOpts.MQTT.Port = mqttOrgPort
  1061  	}
  1062  
  1063  	if err := s.reloadOptions(curOpts, newOpts); err != nil {
  1064  		return err
  1065  	}
  1066  
  1067  	s.recheckPinnedCerts(curOpts, newOpts)
  1068  
  1069  	s.mu.Lock()
  1070  	s.configTime = time.Now().UTC()
  1071  	s.updateVarzConfigReloadableFields(s.varz)
  1072  	s.mu.Unlock()
  1073  	return nil
  1074  }
  1075  func applyBoolFlags(newOpts, flagOpts *Options) {
  1076  	// Reset fields that may have been set to `true` in
  1077  	// MergeOptions() when some of the flags default to `true`
  1078  	// but have not been explicitly set and therefore value
  1079  	// from config file should take precedence.
  1080  	for name, val := range newOpts.inConfig {
  1081  		f := reflect.ValueOf(newOpts).Elem()
  1082  		names := strings.Split(name, ".")
  1083  		for _, name := range names {
  1084  			f = f.FieldByName(name)
  1085  		}
  1086  		f.SetBool(val)
  1087  	}
  1088  	// Now apply value (true or false) from flags that have
  1089  	// been explicitly set in command line
  1090  	for name, val := range flagOpts.inCmdLine {
  1091  		f := reflect.ValueOf(newOpts).Elem()
  1092  		names := strings.Split(name, ".")
  1093  		for _, name := range names {
  1094  			f = f.FieldByName(name)
  1095  		}
  1096  		f.SetBool(val)
  1097  	}
  1098  }
  1099  
  1100  // reloadOptions reloads the server config with the provided options. If an
  1101  // option that doesn't support hot-swapping is changed, this returns an error.
  1102  func (s *Server) reloadOptions(curOpts, newOpts *Options) error {
  1103  	// Apply to the new options some of the options that may have been set
  1104  	// that can't be configured in the config file (this can happen in
  1105  	// applications starting NATS Server programmatically).
  1106  	newOpts.CustomClientAuthentication = curOpts.CustomClientAuthentication
  1107  	newOpts.CustomRouterAuthentication = curOpts.CustomRouterAuthentication
  1108  
  1109  	changed, err := s.diffOptions(newOpts)
  1110  	if err != nil {
  1111  		return err
  1112  	}
  1113  
  1114  	if len(changed) != 0 {
  1115  		if err := validateOptions(newOpts); err != nil {
  1116  			return err
  1117  		}
  1118  	}
  1119  
  1120  	// Create a context that is used to pass special info that we may need
  1121  	// while applying the new options.
  1122  	ctx := reloadContext{oldClusterPerms: curOpts.Cluster.Permissions}
  1123  	s.setOpts(newOpts)
  1124  	s.applyOptions(&ctx, changed)
  1125  	return nil
  1126  }
  1127  
  1128  // For the purpose of comparing, impose a order on slice data types where order does not matter
  1129  func imposeOrder(value any) error {
  1130  	switch value := value.(type) {
  1131  	case []*Account:
  1132  		sort.Slice(value, func(i, j int) bool {
  1133  			return value[i].Name < value[j].Name
  1134  		})
  1135  		for _, a := range value {
  1136  			sort.Slice(a.imports.streams, func(i, j int) bool {
  1137  				return a.imports.streams[i].acc.Name < a.imports.streams[j].acc.Name
  1138  			})
  1139  		}
  1140  	case []*User:
  1141  		sort.Slice(value, func(i, j int) bool {
  1142  			return value[i].Username < value[j].Username
  1143  		})
  1144  	case []*NkeyUser:
  1145  		sort.Slice(value, func(i, j int) bool {
  1146  			return value[i].Nkey < value[j].Nkey
  1147  		})
  1148  	case []*url.URL:
  1149  		sort.Slice(value, func(i, j int) bool {
  1150  			return value[i].String() < value[j].String()
  1151  		})
  1152  	case []string:
  1153  		sort.Strings(value)
  1154  	case []*jwt.OperatorClaims:
  1155  		sort.Slice(value, func(i, j int) bool {
  1156  			return value[i].Issuer < value[j].Issuer
  1157  		})
  1158  	case GatewayOpts:
  1159  		sort.Slice(value.Gateways, func(i, j int) bool {
  1160  			return value.Gateways[i].Name < value.Gateways[j].Name
  1161  		})
  1162  	case WebsocketOpts:
  1163  		sort.Strings(value.AllowedOrigins)
  1164  	case string, bool, uint8, int, int32, int64, time.Duration, float64, nil, LeafNodeOpts, ClusterOpts, *tls.Config, PinnedCertSet,
  1165  		*URLAccResolver, *MemAccResolver, *DirAccResolver, *CacheDirAccResolver, Authentication, MQTTOpts, jwt.TagList,
  1166  		*OCSPConfig, map[string]string, JSLimitOpts, StoreCipher, *OCSPResponseCacheConfig:
  1167  		// explicitly skipped types
  1168  	case *AuthCallout:
  1169  	case JSTpmOpts:
  1170  	default:
  1171  		// this will fail during unit tests
  1172  		return fmt.Errorf("OnReload, sort or explicitly skip type: %s",
  1173  			reflect.TypeOf(value))
  1174  	}
  1175  	return nil
  1176  }
  1177  
  1178  // diffOptions returns a slice containing options which have been changed. If
  1179  // an option that doesn't support hot-swapping is changed, this returns an
  1180  // error.
  1181  func (s *Server) diffOptions(newOpts *Options) ([]option, error) {
  1182  	var (
  1183  		oldConfig = reflect.ValueOf(s.getOpts()).Elem()
  1184  		newConfig = reflect.ValueOf(newOpts).Elem()
  1185  		diffOpts  = []option{}
  1186  
  1187  		// Need to keep track of whether JS is being disabled
  1188  		// to prevent changing limits at runtime.
  1189  		jsEnabled           = s.JetStreamEnabled()
  1190  		disableJS           bool
  1191  		jsMemLimitsChanged  bool
  1192  		jsFileLimitsChanged bool
  1193  		jsStoreDirChanged   bool
  1194  	)
  1195  	for i := 0; i < oldConfig.NumField(); i++ {
  1196  		field := oldConfig.Type().Field(i)
  1197  		// field.PkgPath is empty for exported fields, and is not for unexported ones.
  1198  		// We skip the unexported fields.
  1199  		if field.PkgPath != _EMPTY_ {
  1200  			continue
  1201  		}
  1202  		var (
  1203  			oldValue = oldConfig.Field(i).Interface()
  1204  			newValue = newConfig.Field(i).Interface()
  1205  		)
  1206  		if err := imposeOrder(oldValue); err != nil {
  1207  			return nil, err
  1208  		}
  1209  		if err := imposeOrder(newValue); err != nil {
  1210  			return nil, err
  1211  		}
  1212  
  1213  		optName := strings.ToLower(field.Name)
  1214  		// accounts and users (referencing accounts) will always differ as accounts
  1215  		// contain internal state, say locks etc..., so we don't bother here.
  1216  		// This also avoids races with atomic stats counters
  1217  		if optName != "accounts" && optName != "users" {
  1218  			if changed := !reflect.DeepEqual(oldValue, newValue); !changed {
  1219  				// Check to make sure we are running JetStream if we think we should be.
  1220  				if optName == "jetstream" && newValue.(bool) {
  1221  					if !jsEnabled {
  1222  						diffOpts = append(diffOpts, &jetStreamOption{newValue: true})
  1223  					}
  1224  				}
  1225  				continue
  1226  			}
  1227  		}
  1228  		switch optName {
  1229  		case "traceverbose":
  1230  			diffOpts = append(diffOpts, &traceVerboseOption{newValue: newValue.(bool)})
  1231  		case "trace":
  1232  			diffOpts = append(diffOpts, &traceOption{newValue: newValue.(bool)})
  1233  		case "debug":
  1234  			diffOpts = append(diffOpts, &debugOption{newValue: newValue.(bool)})
  1235  		case "logtime":
  1236  			diffOpts = append(diffOpts, &logtimeOption{newValue: newValue.(bool)})
  1237  		case "logtimeutc":
  1238  			diffOpts = append(diffOpts, &logtimeUTCOption{newValue: newValue.(bool)})
  1239  		case "logfile":
  1240  			diffOpts = append(diffOpts, &logfileOption{newValue: newValue.(string)})
  1241  		case "syslog":
  1242  			diffOpts = append(diffOpts, &syslogOption{newValue: newValue.(bool)})
  1243  		case "remotesyslog":
  1244  			diffOpts = append(diffOpts, &remoteSyslogOption{newValue: newValue.(string)})
  1245  		case "tlsconfig":
  1246  			diffOpts = append(diffOpts, &tlsOption{newValue: newValue.(*tls.Config)})
  1247  		case "tlstimeout":
  1248  			diffOpts = append(diffOpts, &tlsTimeoutOption{newValue: newValue.(float64)})
  1249  		case "tlspinnedcerts":
  1250  			diffOpts = append(diffOpts, &tlsPinnedCertOption{newValue: newValue.(PinnedCertSet)})
  1251  		case "tlshandshakefirst":
  1252  			diffOpts = append(diffOpts, &tlsHandshakeFirst{newValue: newValue.(bool)})
  1253  		case "tlshandshakefirstfallback":
  1254  			diffOpts = append(diffOpts, &tlsHandshakeFirstFallback{newValue: newValue.(time.Duration)})
  1255  		case "username":
  1256  			diffOpts = append(diffOpts, &usernameOption{})
  1257  		case "password":
  1258  			diffOpts = append(diffOpts, &passwordOption{})
  1259  		case "tags":
  1260  			diffOpts = append(diffOpts, &tagsOption{})
  1261  		case "authorization":
  1262  			diffOpts = append(diffOpts, &authorizationOption{})
  1263  		case "authtimeout":
  1264  			diffOpts = append(diffOpts, &authTimeoutOption{newValue: newValue.(float64)})
  1265  		case "users":
  1266  			diffOpts = append(diffOpts, &usersOption{})
  1267  		case "nkeys":
  1268  			diffOpts = append(diffOpts, &nkeysOption{})
  1269  		case "cluster":
  1270  			newClusterOpts := newValue.(ClusterOpts)
  1271  			oldClusterOpts := oldValue.(ClusterOpts)
  1272  			if err := validateClusterOpts(oldClusterOpts, newClusterOpts); err != nil {
  1273  				return nil, err
  1274  			}
  1275  			co := &clusterOption{
  1276  				newValue:        newClusterOpts,
  1277  				permsChanged:    !reflect.DeepEqual(newClusterOpts.Permissions, oldClusterOpts.Permissions),
  1278  				compressChanged: !reflect.DeepEqual(oldClusterOpts.Compression, newClusterOpts.Compression),
  1279  			}
  1280  			co.diffPoolAndAccounts(&oldClusterOpts)
  1281  			// If there are added accounts, first make sure that we can look them up.
  1282  			// If we can't let's fail the reload.
  1283  			for _, acc := range co.accsAdded {
  1284  				if _, err := s.LookupAccount(acc); err != nil {
  1285  					return nil, fmt.Errorf("unable to add account %q to the list of dedicated routes: %v", acc, err)
  1286  				}
  1287  			}
  1288  			// If pool_size has been set to negative (but was not before), then let's
  1289  			// add the system account to the list of removed accounts (we don't have
  1290  			// to check if already there, duplicates are ok in that case).
  1291  			if newClusterOpts.PoolSize < 0 && oldClusterOpts.PoolSize >= 0 {
  1292  				if sys := s.SystemAccount(); sys != nil {
  1293  					co.accsRemoved = append(co.accsRemoved, sys.GetName())
  1294  				}
  1295  			}
  1296  			diffOpts = append(diffOpts, co)
  1297  		case "routes":
  1298  			add, remove := diffRoutes(oldValue.([]*url.URL), newValue.([]*url.URL))
  1299  			diffOpts = append(diffOpts, &routesOption{add: add, remove: remove})
  1300  		case "maxconn":
  1301  			diffOpts = append(diffOpts, &maxConnOption{newValue: newValue.(int)})
  1302  		case "pidfile":
  1303  			diffOpts = append(diffOpts, &pidFileOption{newValue: newValue.(string)})
  1304  		case "portsfiledir":
  1305  			diffOpts = append(diffOpts, &portsFileDirOption{newValue: newValue.(string), oldValue: oldValue.(string)})
  1306  		case "maxcontrolline":
  1307  			diffOpts = append(diffOpts, &maxControlLineOption{newValue: newValue.(int32)})
  1308  		case "maxpayload":
  1309  			diffOpts = append(diffOpts, &maxPayloadOption{newValue: newValue.(int32)})
  1310  		case "pinginterval":
  1311  			diffOpts = append(diffOpts, &pingIntervalOption{newValue: newValue.(time.Duration)})
  1312  		case "maxpingsout":
  1313  			diffOpts = append(diffOpts, &maxPingsOutOption{newValue: newValue.(int)})
  1314  		case "writedeadline":
  1315  			diffOpts = append(diffOpts, &writeDeadlineOption{newValue: newValue.(time.Duration)})
  1316  		case "clientadvertise":
  1317  			cliAdv := newValue.(string)
  1318  			if cliAdv != "" {
  1319  				// Validate ClientAdvertise syntax
  1320  				if _, _, err := parseHostPort(cliAdv, 0); err != nil {
  1321  					return nil, fmt.Errorf("invalid ClientAdvertise value of %s, err=%v", cliAdv, err)
  1322  				}
  1323  			}
  1324  			diffOpts = append(diffOpts, &clientAdvertiseOption{newValue: cliAdv})
  1325  		case "accounts":
  1326  			diffOpts = append(diffOpts, &accountsOption{})
  1327  		case "resolver", "accountresolver", "accountsresolver":
  1328  			// We can't move from no resolver to one. So check for that.
  1329  			if (oldValue == nil && newValue != nil) ||
  1330  				(oldValue != nil && newValue == nil) {
  1331  				return nil, fmt.Errorf("config reload does not support moving to or from an account resolver")
  1332  			}
  1333  			diffOpts = append(diffOpts, &accountsOption{})
  1334  		case "accountresolvertlsconfig":
  1335  			diffOpts = append(diffOpts, &accountsOption{})
  1336  		case "gateway":
  1337  			// Not supported for now, but report warning if configuration of gateway
  1338  			// is actually changed so that user knows that it won't take effect.
  1339  
  1340  			// Any deep-equal is likely to fail for when there is a TLSConfig. so
  1341  			// remove for the test.
  1342  			tmpOld := oldValue.(GatewayOpts)
  1343  			tmpNew := newValue.(GatewayOpts)
  1344  			tmpOld.TLSConfig = nil
  1345  			tmpNew.TLSConfig = nil
  1346  			tmpOld.tlsConfigOpts = nil
  1347  			tmpNew.tlsConfigOpts = nil
  1348  
  1349  			// Need to do the same for remote gateways' TLS configs.
  1350  			// But we can't just set remotes' TLSConfig to nil otherwise this
  1351  			// would lose the real TLS configuration.
  1352  			tmpOld.Gateways = copyRemoteGWConfigsWithoutTLSConfig(tmpOld.Gateways)
  1353  			tmpNew.Gateways = copyRemoteGWConfigsWithoutTLSConfig(tmpNew.Gateways)
  1354  
  1355  			// If there is really a change prevents reload.
  1356  			if !reflect.DeepEqual(tmpOld, tmpNew) {
  1357  				// See TODO(ik) note below about printing old/new values.
  1358  				return nil, fmt.Errorf("config reload not supported for %s: old=%v, new=%v",
  1359  					field.Name, oldValue, newValue)
  1360  			}
  1361  		case "leafnode":
  1362  			// Similar to gateways
  1363  			tmpOld := oldValue.(LeafNodeOpts)
  1364  			tmpNew := newValue.(LeafNodeOpts)
  1365  			tmpOld.TLSConfig = nil
  1366  			tmpNew.TLSConfig = nil
  1367  			tmpOld.tlsConfigOpts = nil
  1368  			tmpNew.tlsConfigOpts = nil
  1369  			// We will allow TLSHandshakeFirst to me config reloaded. First,
  1370  			// we just want to detect if there was a change in the leafnodes{}
  1371  			// block, and if not, we will check the remotes.
  1372  			handshakeFirstChanged := tmpOld.TLSHandshakeFirst != tmpNew.TLSHandshakeFirst
  1373  			// If changed, set them (in the temporary variables) to false so that the
  1374  			// rest of the comparison does not fail.
  1375  			if handshakeFirstChanged {
  1376  				tmpOld.TLSHandshakeFirst, tmpNew.TLSHandshakeFirst = false, false
  1377  			} else if len(tmpOld.Remotes) == len(tmpNew.Remotes) {
  1378  				// Since we don't support changes in the remotes, we will do a
  1379  				// simple pass to see if there was a change of this field.
  1380  				for i := 0; i < len(tmpOld.Remotes); i++ {
  1381  					if tmpOld.Remotes[i].TLSHandshakeFirst != tmpNew.Remotes[i].TLSHandshakeFirst {
  1382  						handshakeFirstChanged = true
  1383  						break
  1384  					}
  1385  				}
  1386  			}
  1387  			// We also support config reload for compression. Check if it changed before
  1388  			// blanking them out for the deep-equal check at the end.
  1389  			compressionChanged := !reflect.DeepEqual(tmpOld.Compression, tmpNew.Compression)
  1390  			if compressionChanged {
  1391  				tmpOld.Compression, tmpNew.Compression = CompressionOpts{}, CompressionOpts{}
  1392  			} else if len(tmpOld.Remotes) == len(tmpNew.Remotes) {
  1393  				// Same that for tls first check, do the remotes now.
  1394  				for i := 0; i < len(tmpOld.Remotes); i++ {
  1395  					if !reflect.DeepEqual(tmpOld.Remotes[i].Compression, tmpNew.Remotes[i].Compression) {
  1396  						compressionChanged = true
  1397  						break
  1398  					}
  1399  				}
  1400  			}
  1401  
  1402  			// Need to do the same for remote leafnodes' TLS configs.
  1403  			// But we can't just set remotes' TLSConfig to nil otherwise this
  1404  			// would lose the real TLS configuration.
  1405  			tmpOld.Remotes = copyRemoteLNConfigForReloadCompare(tmpOld.Remotes)
  1406  			tmpNew.Remotes = copyRemoteLNConfigForReloadCompare(tmpNew.Remotes)
  1407  
  1408  			// Special check for leafnode remotes changes which are not supported right now.
  1409  			leafRemotesChanged := func(a, b LeafNodeOpts) bool {
  1410  				if len(a.Remotes) != len(b.Remotes) {
  1411  					return true
  1412  				}
  1413  
  1414  				// Check whether all remotes URLs are still the same.
  1415  				for _, oldRemote := range a.Remotes {
  1416  					var found bool
  1417  
  1418  					if oldRemote.LocalAccount == _EMPTY_ {
  1419  						oldRemote.LocalAccount = globalAccountName
  1420  					}
  1421  
  1422  					for _, newRemote := range b.Remotes {
  1423  						// Bind to global account in case not defined.
  1424  						if newRemote.LocalAccount == _EMPTY_ {
  1425  							newRemote.LocalAccount = globalAccountName
  1426  						}
  1427  
  1428  						if reflect.DeepEqual(oldRemote, newRemote) {
  1429  							found = true
  1430  							break
  1431  						}
  1432  					}
  1433  					if !found {
  1434  						return true
  1435  					}
  1436  				}
  1437  
  1438  				return false
  1439  			}
  1440  
  1441  			// First check whether remotes changed at all. If they did not,
  1442  			// skip them in the complete equal check.
  1443  			if !leafRemotesChanged(tmpOld, tmpNew) {
  1444  				tmpOld.Remotes = nil
  1445  				tmpNew.Remotes = nil
  1446  			}
  1447  
  1448  			// Special check for auth users to detect changes.
  1449  			// If anything is off will fall through and fail below.
  1450  			// If we detect they are semantically the same we nil them out
  1451  			// to pass the check below.
  1452  			if tmpOld.Users != nil || tmpNew.Users != nil {
  1453  				if len(tmpOld.Users) == len(tmpNew.Users) {
  1454  					oua := make(map[string]*User, len(tmpOld.Users))
  1455  					nua := make(map[string]*User, len(tmpOld.Users))
  1456  					for _, u := range tmpOld.Users {
  1457  						oua[u.Username] = u
  1458  					}
  1459  					for _, u := range tmpNew.Users {
  1460  						nua[u.Username] = u
  1461  					}
  1462  					same := true
  1463  					for uname, u := range oua {
  1464  						// If we can not find new one with same name, drop through to fail.
  1465  						nu, ok := nua[uname]
  1466  						if !ok {
  1467  							same = false
  1468  							break
  1469  						}
  1470  						// If username or password or account different break.
  1471  						if u.Username != nu.Username || u.Password != nu.Password || u.Account.GetName() != nu.Account.GetName() {
  1472  							same = false
  1473  							break
  1474  						}
  1475  					}
  1476  					// We can nil out here.
  1477  					if same {
  1478  						tmpOld.Users, tmpNew.Users = nil, nil
  1479  					}
  1480  				}
  1481  			}
  1482  
  1483  			// If there is really a change prevents reload.
  1484  			if !reflect.DeepEqual(tmpOld, tmpNew) {
  1485  				// See TODO(ik) note below about printing old/new values.
  1486  				return nil, fmt.Errorf("config reload not supported for %s: old=%v, new=%v",
  1487  					field.Name, oldValue, newValue)
  1488  			}
  1489  
  1490  			diffOpts = append(diffOpts, &leafNodeOption{
  1491  				tlsFirstChanged:    handshakeFirstChanged,
  1492  				compressionChanged: compressionChanged,
  1493  			})
  1494  		case "jetstream":
  1495  			new := newValue.(bool)
  1496  			old := oldValue.(bool)
  1497  			if new != old {
  1498  				diffOpts = append(diffOpts, &jetStreamOption{newValue: new})
  1499  			}
  1500  
  1501  			// Mark whether JS will be disabled.
  1502  			disableJS = !new
  1503  		case "storedir":
  1504  			new := newValue.(string)
  1505  			old := oldValue.(string)
  1506  			modified := new != old
  1507  
  1508  			// Check whether JS is being disabled and/or storage dir attempted to change.
  1509  			if jsEnabled && modified {
  1510  				if new == _EMPTY_ {
  1511  					// This means that either JS is being disabled or it is using an temp dir.
  1512  					// Allow the change but error in case JS was not disabled.
  1513  					jsStoreDirChanged = true
  1514  				} else {
  1515  					return nil, fmt.Errorf("config reload not supported for jetstream storage directory")
  1516  				}
  1517  			}
  1518  		case "jetstreammaxmemory", "jetstreammaxstore":
  1519  			old := oldValue.(int64)
  1520  			new := newValue.(int64)
  1521  
  1522  			// Check whether JS is being disabled and/or limits are being changed.
  1523  			var (
  1524  				modified  = new != old
  1525  				fromUnset = old == -1
  1526  				fromSet   = !fromUnset
  1527  				toUnset   = new == -1
  1528  				toSet     = !toUnset
  1529  			)
  1530  			if jsEnabled && modified {
  1531  				// Cannot change limits from dynamic storage at runtime.
  1532  				switch {
  1533  				case fromSet && toUnset:
  1534  					// Limits changed but it may mean that JS is being disabled,
  1535  					// keep track of the change and error in case it is not.
  1536  					switch optName {
  1537  					case "jetstreammaxmemory":
  1538  						jsMemLimitsChanged = true
  1539  					case "jetstreammaxstore":
  1540  						jsFileLimitsChanged = true
  1541  					default:
  1542  						return nil, fmt.Errorf("config reload not supported for jetstream max memory and store")
  1543  					}
  1544  				case fromUnset && toSet:
  1545  					// Prevent changing from dynamic max memory / file at runtime.
  1546  					return nil, fmt.Errorf("config reload not supported for jetstream dynamic max memory and store")
  1547  				default:
  1548  					return nil, fmt.Errorf("config reload not supported for jetstream max memory and store")
  1549  				}
  1550  			}
  1551  		case "websocket":
  1552  			// Similar to gateways
  1553  			tmpOld := oldValue.(WebsocketOpts)
  1554  			tmpNew := newValue.(WebsocketOpts)
  1555  			tmpOld.TLSConfig, tmpOld.tlsConfigOpts = nil, nil
  1556  			tmpNew.TLSConfig, tmpNew.tlsConfigOpts = nil, nil
  1557  			// If there is really a change prevents reload.
  1558  			if !reflect.DeepEqual(tmpOld, tmpNew) {
  1559  				// See TODO(ik) note below about printing old/new values.
  1560  				return nil, fmt.Errorf("config reload not supported for %s: old=%v, new=%v",
  1561  					field.Name, oldValue, newValue)
  1562  			}
  1563  		case "mqtt":
  1564  			diffOpts = append(diffOpts, &mqttAckWaitReload{newValue: newValue.(MQTTOpts).AckWait})
  1565  			diffOpts = append(diffOpts, &mqttMaxAckPendingReload{newValue: newValue.(MQTTOpts).MaxAckPending})
  1566  			diffOpts = append(diffOpts, &mqttStreamReplicasReload{newValue: newValue.(MQTTOpts).StreamReplicas})
  1567  			diffOpts = append(diffOpts, &mqttConsumerReplicasReload{newValue: newValue.(MQTTOpts).ConsumerReplicas})
  1568  			diffOpts = append(diffOpts, &mqttConsumerMemoryStorageReload{newValue: newValue.(MQTTOpts).ConsumerMemoryStorage})
  1569  			diffOpts = append(diffOpts, &mqttInactiveThresholdReload{newValue: newValue.(MQTTOpts).ConsumerInactiveThreshold})
  1570  
  1571  			// Nil out/set to 0 the options that we allow to be reloaded so that
  1572  			// we only fail reload if some that we don't support are changed.
  1573  			tmpOld := oldValue.(MQTTOpts)
  1574  			tmpNew := newValue.(MQTTOpts)
  1575  			tmpOld.TLSConfig, tmpOld.tlsConfigOpts, tmpOld.AckWait, tmpOld.MaxAckPending, tmpOld.StreamReplicas, tmpOld.ConsumerReplicas, tmpOld.ConsumerMemoryStorage = nil, nil, 0, 0, 0, 0, false
  1576  			tmpOld.ConsumerInactiveThreshold = 0
  1577  			tmpNew.TLSConfig, tmpNew.tlsConfigOpts, tmpNew.AckWait, tmpNew.MaxAckPending, tmpNew.StreamReplicas, tmpNew.ConsumerReplicas, tmpNew.ConsumerMemoryStorage = nil, nil, 0, 0, 0, 0, false
  1578  			tmpNew.ConsumerInactiveThreshold = 0
  1579  
  1580  			if !reflect.DeepEqual(tmpOld, tmpNew) {
  1581  				// See TODO(ik) note below about printing old/new values.
  1582  				return nil, fmt.Errorf("config reload not supported for %s: old=%v, new=%v",
  1583  					field.Name, oldValue, newValue)
  1584  			}
  1585  			tmpNew.AckWait = newValue.(MQTTOpts).AckWait
  1586  			tmpNew.MaxAckPending = newValue.(MQTTOpts).MaxAckPending
  1587  			tmpNew.StreamReplicas = newValue.(MQTTOpts).StreamReplicas
  1588  			tmpNew.ConsumerReplicas = newValue.(MQTTOpts).ConsumerReplicas
  1589  			tmpNew.ConsumerMemoryStorage = newValue.(MQTTOpts).ConsumerMemoryStorage
  1590  			tmpNew.ConsumerInactiveThreshold = newValue.(MQTTOpts).ConsumerInactiveThreshold
  1591  		case "connecterrorreports":
  1592  			diffOpts = append(diffOpts, &connectErrorReports{newValue: newValue.(int)})
  1593  		case "reconnecterrorreports":
  1594  			diffOpts = append(diffOpts, &reconnectErrorReports{newValue: newValue.(int)})
  1595  		case "nolog", "nosigs":
  1596  			// Ignore NoLog and NoSigs options since they are not parsed and only used in
  1597  			// testing.
  1598  			continue
  1599  		case "disableshortfirstping":
  1600  			newOpts.DisableShortFirstPing = oldValue.(bool)
  1601  			continue
  1602  		case "maxtracedmsglen":
  1603  			diffOpts = append(diffOpts, &maxTracedMsgLenOption{newValue: newValue.(int)})
  1604  		case "port":
  1605  			// check to see if newValue == 0 and continue if so.
  1606  			if newValue == 0 {
  1607  				// ignore RANDOM_PORT
  1608  				continue
  1609  			}
  1610  			fallthrough
  1611  		case "noauthuser":
  1612  			if oldValue != _EMPTY_ && newValue == _EMPTY_ {
  1613  				for _, user := range newOpts.Users {
  1614  					if user.Username == oldValue {
  1615  						return nil, fmt.Errorf("config reload not supported for %s: old=%v, new=%v",
  1616  							field.Name, oldValue, newValue)
  1617  					}
  1618  				}
  1619  			} else {
  1620  				return nil, fmt.Errorf("config reload not supported for %s: old=%v, new=%v",
  1621  					field.Name, oldValue, newValue)
  1622  			}
  1623  		case "systemaccount":
  1624  			if oldValue != DEFAULT_SYSTEM_ACCOUNT || newValue != _EMPTY_ {
  1625  				return nil, fmt.Errorf("config reload not supported for %s: old=%v, new=%v",
  1626  					field.Name, oldValue, newValue)
  1627  			}
  1628  		case "ocspconfig":
  1629  			diffOpts = append(diffOpts, &ocspOption{newValue: newValue.(*OCSPConfig)})
  1630  		case "ocspcacheconfig":
  1631  			diffOpts = append(diffOpts, &ocspResponseCacheOption{newValue: newValue.(*OCSPResponseCacheConfig)})
  1632  		case "profblockrate":
  1633  			new := newValue.(int)
  1634  			old := oldValue.(int)
  1635  			if new != old {
  1636  				diffOpts = append(diffOpts, &profBlockRateReload{newValue: new})
  1637  			}
  1638  		default:
  1639  			// TODO(ik): Implement String() on those options to have a nice print.
  1640  			// %v is difficult to figure what's what, %+v print private fields and
  1641  			// would print passwords. Tried json.Marshal but it is too verbose for
  1642  			// the URL array.
  1643  
  1644  			// Bail out if attempting to reload any unsupported options.
  1645  			return nil, fmt.Errorf("config reload not supported for %s: old=%v, new=%v",
  1646  				field.Name, oldValue, newValue)
  1647  		}
  1648  	}
  1649  
  1650  	// If not disabling JS but limits have changed then it is an error.
  1651  	if !disableJS {
  1652  		if jsMemLimitsChanged || jsFileLimitsChanged {
  1653  			return nil, fmt.Errorf("config reload not supported for jetstream max memory and max store")
  1654  		}
  1655  		if jsStoreDirChanged {
  1656  			return nil, fmt.Errorf("config reload not supported for jetstream storage dir")
  1657  		}
  1658  	}
  1659  
  1660  	return diffOpts, nil
  1661  }
  1662  
  1663  func copyRemoteGWConfigsWithoutTLSConfig(current []*RemoteGatewayOpts) []*RemoteGatewayOpts {
  1664  	l := len(current)
  1665  	if l == 0 {
  1666  		return nil
  1667  	}
  1668  	rgws := make([]*RemoteGatewayOpts, 0, l)
  1669  	for _, rcfg := range current {
  1670  		cp := *rcfg
  1671  		cp.TLSConfig = nil
  1672  		cp.tlsConfigOpts = nil
  1673  		rgws = append(rgws, &cp)
  1674  	}
  1675  	return rgws
  1676  }
  1677  
  1678  func copyRemoteLNConfigForReloadCompare(current []*RemoteLeafOpts) []*RemoteLeafOpts {
  1679  	l := len(current)
  1680  	if l == 0 {
  1681  		return nil
  1682  	}
  1683  	rlns := make([]*RemoteLeafOpts, 0, l)
  1684  	for _, rcfg := range current {
  1685  		cp := *rcfg
  1686  		cp.TLSConfig = nil
  1687  		cp.tlsConfigOpts = nil
  1688  		cp.TLSHandshakeFirst = false
  1689  		// This is set only when processing a CONNECT, so reset here so that we
  1690  		// don't fail the DeepEqual comparison.
  1691  		cp.TLS = false
  1692  		// For now, remove DenyImports/Exports since those get modified at runtime
  1693  		// to add JS APIs.
  1694  		cp.DenyImports, cp.DenyExports = nil, nil
  1695  		// Remove compression mode
  1696  		cp.Compression = CompressionOpts{}
  1697  		rlns = append(rlns, &cp)
  1698  	}
  1699  	return rlns
  1700  }
  1701  
  1702  func (s *Server) applyOptions(ctx *reloadContext, opts []option) {
  1703  	var (
  1704  		reloadLogging      = false
  1705  		reloadAuth         = false
  1706  		reloadClusterPerms = false
  1707  		reloadClientTrcLvl = false
  1708  		reloadJetstream    = false
  1709  		jsEnabled          = false
  1710  		isStatszChange     = false
  1711  		co                 *clusterOption
  1712  	)
  1713  	for _, opt := range opts {
  1714  		opt.Apply(s)
  1715  		if opt.IsLoggingChange() {
  1716  			reloadLogging = true
  1717  		}
  1718  		if opt.IsTraceLevelChange() {
  1719  			reloadClientTrcLvl = true
  1720  		}
  1721  		if opt.IsAuthChange() {
  1722  			reloadAuth = true
  1723  		}
  1724  		if opt.IsClusterPoolSizeOrAccountsChange() {
  1725  			co = opt.(*clusterOption)
  1726  		}
  1727  		if opt.IsClusterPermsChange() {
  1728  			reloadClusterPerms = true
  1729  		}
  1730  		if opt.IsJetStreamChange() {
  1731  			reloadJetstream = true
  1732  			jsEnabled = opt.(*jetStreamOption).newValue
  1733  		}
  1734  		if opt.IsStatszChange() {
  1735  			isStatszChange = true
  1736  		}
  1737  	}
  1738  
  1739  	if reloadLogging {
  1740  		s.ConfigureLogger()
  1741  	}
  1742  	if reloadClientTrcLvl {
  1743  		s.reloadClientTraceLevel()
  1744  	}
  1745  	if reloadAuth {
  1746  		s.reloadAuthorization()
  1747  	}
  1748  	if reloadClusterPerms {
  1749  		s.reloadClusterPermissions(ctx.oldClusterPerms)
  1750  	}
  1751  	newOpts := s.getOpts()
  1752  	// If we need to reload cluster pool/per-account, then co will be not nil
  1753  	if co != nil {
  1754  		s.reloadClusterPoolAndAccounts(co, newOpts)
  1755  	}
  1756  	if reloadJetstream {
  1757  		if !jsEnabled {
  1758  			s.DisableJetStream()
  1759  		} else if !s.JetStreamEnabled() {
  1760  			if err := s.restartJetStream(); err != nil {
  1761  				s.Warnf("Can't start JetStream: %v", err)
  1762  			}
  1763  		}
  1764  		// Make sure to reset the internal loop's version of JS.
  1765  		s.resetInternalLoopInfo()
  1766  	}
  1767  	if isStatszChange {
  1768  		s.sendStatszUpdate()
  1769  	}
  1770  
  1771  	// For remote gateways and leafnodes, make sure that their TLS configuration
  1772  	// is updated (since the config is "captured" early and changes would otherwise
  1773  	// not be visible).
  1774  	if s.gateway.enabled {
  1775  		s.gateway.updateRemotesTLSConfig(newOpts)
  1776  	}
  1777  	if len(newOpts.LeafNode.Remotes) > 0 {
  1778  		s.updateRemoteLeafNodesTLSConfig(newOpts)
  1779  	}
  1780  
  1781  	// Always restart OCSP monitoring on reload.
  1782  	if err := s.reloadOCSP(); err != nil {
  1783  		s.Warnf("Can't restart OCSP features: %v", err)
  1784  	}
  1785  
  1786  	s.Noticef("Reloaded server configuration")
  1787  }
  1788  
  1789  // This will send a reset to the internal send loop.
  1790  func (s *Server) resetInternalLoopInfo() {
  1791  	var resetCh chan struct{}
  1792  	s.mu.Lock()
  1793  	if s.sys != nil {
  1794  		// can't hold the lock as go routine reading it may be waiting for lock as well
  1795  		resetCh = s.sys.resetCh
  1796  	}
  1797  	s.mu.Unlock()
  1798  
  1799  	if resetCh != nil {
  1800  		resetCh <- struct{}{}
  1801  	}
  1802  }
  1803  
  1804  // Update all cached debug and trace settings for every client
  1805  func (s *Server) reloadClientTraceLevel() {
  1806  	opts := s.getOpts()
  1807  
  1808  	if opts.NoLog {
  1809  		return
  1810  	}
  1811  
  1812  	// Create a list of all clients.
  1813  	// Update their trace level when not holding server or gateway lock
  1814  
  1815  	s.mu.Lock()
  1816  	clientCnt := 1 + len(s.clients) + len(s.grTmpClients) + s.numRoutes() + len(s.leafs)
  1817  	s.mu.Unlock()
  1818  
  1819  	s.gateway.RLock()
  1820  	clientCnt += len(s.gateway.in) + len(s.gateway.outo)
  1821  	s.gateway.RUnlock()
  1822  
  1823  	clients := make([]*client, 0, clientCnt)
  1824  
  1825  	s.mu.Lock()
  1826  	if s.eventsEnabled() {
  1827  		clients = append(clients, s.sys.client)
  1828  	}
  1829  
  1830  	cMaps := []map[uint64]*client{s.clients, s.grTmpClients, s.leafs}
  1831  	for _, m := range cMaps {
  1832  		for _, c := range m {
  1833  			clients = append(clients, c)
  1834  		}
  1835  	}
  1836  	s.forEachRoute(func(c *client) {
  1837  		clients = append(clients, c)
  1838  	})
  1839  	s.mu.Unlock()
  1840  
  1841  	s.gateway.RLock()
  1842  	for _, c := range s.gateway.in {
  1843  		clients = append(clients, c)
  1844  	}
  1845  	clients = append(clients, s.gateway.outo...)
  1846  	s.gateway.RUnlock()
  1847  
  1848  	for _, c := range clients {
  1849  		// client.trace is commonly read while holding the lock
  1850  		c.mu.Lock()
  1851  		c.setTraceLevel()
  1852  		c.mu.Unlock()
  1853  	}
  1854  }
  1855  
  1856  // reloadAuthorization reconfigures the server authorization settings,
  1857  // disconnects any clients who are no longer authorized, and removes any
  1858  // unauthorized subscriptions.
  1859  func (s *Server) reloadAuthorization() {
  1860  	// This map will contain the names of accounts that have their streams
  1861  	// import configuration changed.
  1862  	var awcsti map[string]struct{}
  1863  	checkJetStream := false
  1864  	opts := s.getOpts()
  1865  	s.mu.Lock()
  1866  
  1867  	deletedAccounts := make(map[string]*Account)
  1868  
  1869  	// This can not be changed for now so ok to check server's trustedKeys unlocked.
  1870  	// If plain configured accounts, process here.
  1871  	if s.trustedKeys == nil {
  1872  		// Make a map of the configured account names so we figure out the accounts
  1873  		// that should be removed later on.
  1874  		configAccs := make(map[string]struct{}, len(opts.Accounts))
  1875  		for _, acc := range opts.Accounts {
  1876  			configAccs[acc.GetName()] = struct{}{}
  1877  		}
  1878  		// Now range over existing accounts and keep track of the ones deleted
  1879  		// so some cleanup can be made after releasing the server lock.
  1880  		s.accounts.Range(func(k, v any) bool {
  1881  			an, acc := k.(string), v.(*Account)
  1882  			// Exclude default and system account from this test since those
  1883  			// may not actually be in opts.Accounts.
  1884  			if an == DEFAULT_GLOBAL_ACCOUNT || an == DEFAULT_SYSTEM_ACCOUNT {
  1885  				return true
  1886  			}
  1887  			// Check check if existing account is still in opts.Accounts.
  1888  			if _, ok := configAccs[an]; !ok {
  1889  				deletedAccounts[an] = acc
  1890  				s.accounts.Delete(k)
  1891  			}
  1892  			return true
  1893  		})
  1894  		// This will update existing and add new ones.
  1895  		awcsti, _ = s.configureAccounts(true)
  1896  		s.configureAuthorization()
  1897  		// Double check any JetStream configs.
  1898  		checkJetStream = s.getJetStream() != nil
  1899  	} else if opts.AccountResolver != nil {
  1900  		s.configureResolver()
  1901  		if _, ok := s.accResolver.(*MemAccResolver); ok {
  1902  			// Check preloads so we can issue warnings etc if needed.
  1903  			s.checkResolvePreloads()
  1904  			// With a memory resolver we want to do something similar to configured accounts.
  1905  			// We will walk the accounts and delete them if they are no longer present via fetch.
  1906  			// If they are present we will force a claim update to process changes.
  1907  			s.accounts.Range(func(k, v any) bool {
  1908  				acc := v.(*Account)
  1909  				// Skip global account.
  1910  				if acc == s.gacc {
  1911  					return true
  1912  				}
  1913  				accName := acc.GetName()
  1914  				// Release server lock for following actions
  1915  				s.mu.Unlock()
  1916  				accClaims, claimJWT, _ := s.fetchAccountClaims(accName)
  1917  				if accClaims != nil {
  1918  					if err := s.updateAccountWithClaimJWT(acc, claimJWT); err != nil {
  1919  						s.Noticef("Reloaded: deleting account [bad claims]: %q", accName)
  1920  						s.accounts.Delete(k)
  1921  					}
  1922  				} else {
  1923  					s.Noticef("Reloaded: deleting account [removed]: %q", accName)
  1924  					s.accounts.Delete(k)
  1925  				}
  1926  				// Regrab server lock.
  1927  				s.mu.Lock()
  1928  				return true
  1929  			})
  1930  		}
  1931  	}
  1932  
  1933  	var (
  1934  		cclientsa [64]*client
  1935  		cclients  = cclientsa[:0]
  1936  		clientsa  [64]*client
  1937  		clients   = clientsa[:0]
  1938  		routesa   [64]*client
  1939  		routes    = routesa[:0]
  1940  	)
  1941  
  1942  	// Gather clients that changed accounts. We will close them and they
  1943  	// will reconnect, doing the right thing.
  1944  	for _, client := range s.clients {
  1945  		if s.clientHasMovedToDifferentAccount(client) {
  1946  			cclients = append(cclients, client)
  1947  		} else {
  1948  			clients = append(clients, client)
  1949  		}
  1950  	}
  1951  	s.forEachRoute(func(route *client) {
  1952  		routes = append(routes, route)
  1953  	})
  1954  	// Check here for any system/internal clients which will not be in the servers map of normal clients.
  1955  	if s.sys != nil && s.sys.account != nil && !opts.NoSystemAccount {
  1956  		s.accounts.Store(s.sys.account.Name, s.sys.account)
  1957  	}
  1958  
  1959  	s.accounts.Range(func(k, v any) bool {
  1960  		acc := v.(*Account)
  1961  		acc.mu.RLock()
  1962  		// Check for sysclients accounting, ignore the system account.
  1963  		if acc.sysclients > 0 && (s.sys == nil || s.sys.account != acc) {
  1964  			for c := range acc.clients {
  1965  				if c.kind != CLIENT && c.kind != LEAF {
  1966  					clients = append(clients, c)
  1967  				}
  1968  			}
  1969  		}
  1970  		acc.mu.RUnlock()
  1971  		return true
  1972  	})
  1973  
  1974  	var resetCh chan struct{}
  1975  	if s.sys != nil {
  1976  		// can't hold the lock as go routine reading it may be waiting for lock as well
  1977  		resetCh = s.sys.resetCh
  1978  	}
  1979  	s.mu.Unlock()
  1980  
  1981  	// Clear some timers and remove service import subs for deleted accounts.
  1982  	for _, acc := range deletedAccounts {
  1983  		acc.mu.Lock()
  1984  		clearTimer(&acc.etmr)
  1985  		clearTimer(&acc.ctmr)
  1986  		for _, se := range acc.exports.services {
  1987  			se.clearResponseThresholdTimer()
  1988  		}
  1989  		acc.mu.Unlock()
  1990  		acc.removeAllServiceImportSubs()
  1991  	}
  1992  
  1993  	if resetCh != nil {
  1994  		resetCh <- struct{}{}
  1995  	}
  1996  
  1997  	// Check that publish retained messages sources are still allowed to publish.
  1998  	s.mqttCheckPubRetainedPerms()
  1999  
  2000  	// Close clients that have moved accounts
  2001  	for _, client := range cclients {
  2002  		client.closeConnection(ClientClosed)
  2003  	}
  2004  
  2005  	for _, c := range clients {
  2006  		// Disconnect any unauthorized clients.
  2007  		// Ignore internal clients.
  2008  		if (c.kind == CLIENT || c.kind == LEAF) && !s.isClientAuthorized(c) {
  2009  			c.authViolation()
  2010  			continue
  2011  		}
  2012  		// Check to make sure account is correct.
  2013  		c.swapAccountAfterReload()
  2014  		// Remove any unauthorized subscriptions and check for account imports.
  2015  		c.processSubsOnConfigReload(awcsti)
  2016  	}
  2017  
  2018  	for _, route := range routes {
  2019  		// Disconnect any unauthorized routes.
  2020  		// Do this only for routes that were accepted, not initiated
  2021  		// because in the later case, we don't have the user name/password
  2022  		// of the remote server.
  2023  		if !route.isSolicitedRoute() && !s.isRouterAuthorized(route) {
  2024  			route.setNoReconnect()
  2025  			route.authViolation()
  2026  		}
  2027  	}
  2028  
  2029  	if res := s.AccountResolver(); res != nil {
  2030  		res.Reload()
  2031  	}
  2032  
  2033  	// We will double check all JetStream configs on a reload.
  2034  	if checkJetStream {
  2035  		if err := s.enableJetStreamAccounts(); err != nil {
  2036  			s.Errorf(err.Error())
  2037  		}
  2038  	}
  2039  }
  2040  
  2041  // Returns true if given client current account has changed (or user
  2042  // no longer exist) in the new config, false if the user did not
  2043  // change accounts.
  2044  // Server lock is held on entry.
  2045  func (s *Server) clientHasMovedToDifferentAccount(c *client) bool {
  2046  	var (
  2047  		nu *NkeyUser
  2048  		u  *User
  2049  	)
  2050  	c.mu.Lock()
  2051  	defer c.mu.Unlock()
  2052  	if c.opts.Nkey != _EMPTY_ {
  2053  		if s.nkeys != nil {
  2054  			nu = s.nkeys[c.opts.Nkey]
  2055  		}
  2056  	} else if c.opts.Username != _EMPTY_ {
  2057  		if s.users != nil {
  2058  			u = s.users[c.opts.Username]
  2059  		}
  2060  	} else {
  2061  		return false
  2062  	}
  2063  	// Get the current account name
  2064  	var curAccName string
  2065  	if c.acc != nil {
  2066  		curAccName = c.acc.Name
  2067  	}
  2068  	if nu != nil && nu.Account != nil {
  2069  		return curAccName != nu.Account.Name
  2070  	} else if u != nil && u.Account != nil {
  2071  		return curAccName != u.Account.Name
  2072  	}
  2073  	// user/nkey no longer exists.
  2074  	return true
  2075  }
  2076  
  2077  // reloadClusterPermissions reconfigures the cluster's permssions
  2078  // and set the permissions to all existing routes, sending an
  2079  // update INFO protocol so that remote can resend their local
  2080  // subs if needed, and sending local subs matching cluster's
  2081  // import subjects.
  2082  func (s *Server) reloadClusterPermissions(oldPerms *RoutePermissions) {
  2083  	s.mu.Lock()
  2084  	newPerms := s.getOpts().Cluster.Permissions
  2085  	routes := make(map[uint64]*client, s.numRoutes())
  2086  	// Get all connected routes
  2087  	s.forEachRoute(func(route *client) {
  2088  		route.mu.Lock()
  2089  		routes[route.cid] = route
  2090  		route.mu.Unlock()
  2091  	})
  2092  	// If new permissions is nil, then clear routeInfo import/export
  2093  	if newPerms == nil {
  2094  		s.routeInfo.Import = nil
  2095  		s.routeInfo.Export = nil
  2096  	} else {
  2097  		s.routeInfo.Import = newPerms.Import
  2098  		s.routeInfo.Export = newPerms.Export
  2099  	}
  2100  	infoJSON := generateInfoJSON(&s.routeInfo)
  2101  	s.mu.Unlock()
  2102  
  2103  	// Close connections for routes that don't understand async INFO.
  2104  	for _, route := range routes {
  2105  		route.mu.Lock()
  2106  		close := route.opts.Protocol < RouteProtoInfo
  2107  		cid := route.cid
  2108  		route.mu.Unlock()
  2109  		if close {
  2110  			route.closeConnection(RouteRemoved)
  2111  			delete(routes, cid)
  2112  		}
  2113  	}
  2114  
  2115  	// If there are no route left, we are done
  2116  	if len(routes) == 0 {
  2117  		return
  2118  	}
  2119  
  2120  	// Fake clients to test cluster permissions
  2121  	oldPermsTester := &client{}
  2122  	oldPermsTester.setRoutePermissions(oldPerms)
  2123  	newPermsTester := &client{}
  2124  	newPermsTester.setRoutePermissions(newPerms)
  2125  
  2126  	var (
  2127  		_localSubs       [4096]*subscription
  2128  		subsNeedSUB      = map[*client][]*subscription{}
  2129  		subsNeedUNSUB    = map[*client][]*subscription{}
  2130  		deleteRoutedSubs []*subscription
  2131  	)
  2132  
  2133  	getRouteForAccount := func(accName string, poolIdx int) *client {
  2134  		for _, r := range routes {
  2135  			r.mu.Lock()
  2136  			ok := (poolIdx >= 0 && poolIdx == r.route.poolIdx) || (string(r.route.accName) == accName) || r.route.noPool
  2137  			r.mu.Unlock()
  2138  			if ok {
  2139  				return r
  2140  			}
  2141  		}
  2142  		return nil
  2143  	}
  2144  
  2145  	// First set the new permissions on all routes.
  2146  	for _, route := range routes {
  2147  		route.mu.Lock()
  2148  		route.setRoutePermissions(newPerms)
  2149  		route.mu.Unlock()
  2150  	}
  2151  
  2152  	// Then, go over all accounts and gather local subscriptions that need to be
  2153  	// sent over as SUB or removed as UNSUB, and routed subscriptions that need
  2154  	// to be dropped due to export permissions.
  2155  	s.accounts.Range(func(_, v any) bool {
  2156  		acc := v.(*Account)
  2157  		acc.mu.RLock()
  2158  		accName, sl, poolIdx := acc.Name, acc.sl, acc.routePoolIdx
  2159  		acc.mu.RUnlock()
  2160  		// Get the route handling this account. If no route or sublist, bail out.
  2161  		route := getRouteForAccount(accName, poolIdx)
  2162  		if route == nil || sl == nil {
  2163  			return true
  2164  		}
  2165  		localSubs := _localSubs[:0]
  2166  		sl.localSubs(&localSubs, false)
  2167  
  2168  		// Go through all local subscriptions
  2169  		for _, sub := range localSubs {
  2170  			// Get all subs that can now be imported
  2171  			subj := string(sub.subject)
  2172  			couldImportThen := oldPermsTester.canImport(subj)
  2173  			canImportNow := newPermsTester.canImport(subj)
  2174  			if canImportNow {
  2175  				// If we could not before, then will need to send a SUB protocol.
  2176  				if !couldImportThen {
  2177  					subsNeedSUB[route] = append(subsNeedSUB[route], sub)
  2178  				}
  2179  			} else if couldImportThen {
  2180  				// We were previously able to import this sub, but now
  2181  				// we can't so we need to send an UNSUB protocol
  2182  				subsNeedUNSUB[route] = append(subsNeedUNSUB[route], sub)
  2183  			}
  2184  		}
  2185  		deleteRoutedSubs = deleteRoutedSubs[:0]
  2186  		route.mu.Lock()
  2187  		for key, sub := range route.subs {
  2188  			if an := strings.Fields(key)[0]; an != accName {
  2189  				continue
  2190  			}
  2191  			// If we can't export, we need to drop the subscriptions that
  2192  			// we have on behalf of this route.
  2193  			subj := string(sub.subject)
  2194  			if !route.canExport(subj) {
  2195  				delete(route.subs, string(sub.sid))
  2196  				deleteRoutedSubs = append(deleteRoutedSubs, sub)
  2197  			}
  2198  		}
  2199  		route.mu.Unlock()
  2200  		// Remove as a batch all the subs that we have removed from each route.
  2201  		sl.RemoveBatch(deleteRoutedSubs)
  2202  		return true
  2203  	})
  2204  
  2205  	// Send an update INFO, which will allow remote server to show
  2206  	// our current route config in monitoring and resend subscriptions
  2207  	// that we now possibly allow with a change of Export permissions.
  2208  	for _, route := range routes {
  2209  		route.mu.Lock()
  2210  		route.enqueueProto(infoJSON)
  2211  		// Now send SUB and UNSUB protocols as needed.
  2212  		if subs, ok := subsNeedSUB[route]; ok && len(subs) > 0 {
  2213  			route.sendRouteSubProtos(subs, false, nil)
  2214  		}
  2215  		if unsubs, ok := subsNeedUNSUB[route]; ok && len(unsubs) > 0 {
  2216  			route.sendRouteUnSubProtos(unsubs, false, nil)
  2217  		}
  2218  		route.mu.Unlock()
  2219  	}
  2220  }
  2221  
  2222  func (s *Server) reloadClusterPoolAndAccounts(co *clusterOption, opts *Options) {
  2223  	s.mu.Lock()
  2224  	// Prevent adding new routes until we are ready to do so.
  2225  	s.routesReject = true
  2226  	var ch chan struct{}
  2227  	// For accounts that have been added to the list of dedicated routes,
  2228  	// send a protocol to their current assigned routes to allow the
  2229  	// other side to prepare for the changes.
  2230  	if len(co.accsAdded) > 0 {
  2231  		protosSent := 0
  2232  		s.accAddedReqID = nuid.Next()
  2233  		for _, an := range co.accsAdded {
  2234  			if s.accRoutes == nil {
  2235  				s.accRoutes = make(map[string]map[string]*client)
  2236  			}
  2237  			// In case a config reload was first done on another server,
  2238  			// we may have already switched this account to a dedicated route.
  2239  			// But we still want to send the protocol over the routes that
  2240  			// would have otherwise handled it.
  2241  			if _, ok := s.accRoutes[an]; !ok {
  2242  				s.accRoutes[an] = make(map[string]*client)
  2243  			}
  2244  			if a, ok := s.accounts.Load(an); ok {
  2245  				acc := a.(*Account)
  2246  				acc.mu.Lock()
  2247  				sl := acc.sl
  2248  				// Get the current route pool index before calling setRouteInfo.
  2249  				rpi := acc.routePoolIdx
  2250  				// Switch to per-account route if not already done.
  2251  				if rpi >= 0 {
  2252  					s.setRouteInfo(acc)
  2253  				} else {
  2254  					// If it was transitioning, make sure we set it to the state
  2255  					// that indicates that it has a dedicated route
  2256  					if rpi == accTransitioningToDedicatedRoute {
  2257  						acc.routePoolIdx = accDedicatedRoute
  2258  					}
  2259  					// Otherwise get the route pool index it would have been before
  2260  					// the move so we can send the protocol to those routes.
  2261  					rpi = s.computeRoutePoolIdx(acc)
  2262  				}
  2263  				acc.mu.Unlock()
  2264  				// Generate the INFO protocol to send indicating that this account
  2265  				// is being moved to a dedicated route.
  2266  				ri := Info{
  2267  					RoutePoolSize: s.routesPoolSize,
  2268  					RouteAccount:  an,
  2269  					RouteAccReqID: s.accAddedReqID,
  2270  				}
  2271  				proto := generateInfoJSON(&ri)
  2272  				// Go over each remote's route at pool index `rpi` and remove
  2273  				// remote subs for this account and send the protocol.
  2274  				s.forEachRouteIdx(rpi, func(r *client) bool {
  2275  					r.mu.Lock()
  2276  					// Exclude routes to servers that don't support pooling.
  2277  					if !r.route.noPool {
  2278  						if subs := r.removeRemoteSubsForAcc(an); len(subs) > 0 {
  2279  							sl.RemoveBatch(subs)
  2280  						}
  2281  						r.enqueueProto(proto)
  2282  						protosSent++
  2283  					}
  2284  					r.mu.Unlock()
  2285  					return true
  2286  				})
  2287  			}
  2288  		}
  2289  		if protosSent > 0 {
  2290  			s.accAddedCh = make(chan struct{}, protosSent)
  2291  			ch = s.accAddedCh
  2292  		}
  2293  	}
  2294  	// Collect routes that need to be closed.
  2295  	routes := make(map[*client]struct{})
  2296  	// Collect the per-account routes that need to be closed.
  2297  	if len(co.accsRemoved) > 0 {
  2298  		for _, an := range co.accsRemoved {
  2299  			if remotes, ok := s.accRoutes[an]; ok && remotes != nil {
  2300  				for _, r := range remotes {
  2301  					if r != nil {
  2302  						r.setNoReconnect()
  2303  						routes[r] = struct{}{}
  2304  					}
  2305  				}
  2306  			}
  2307  		}
  2308  	}
  2309  	// If the pool size has changed, we need to close all pooled routes.
  2310  	if co.poolSizeChanged {
  2311  		s.forEachNonPerAccountRoute(func(r *client) {
  2312  			routes[r] = struct{}{}
  2313  		})
  2314  	}
  2315  	// If there are routes to close, we need to release the server lock.
  2316  	// Same if we need to wait on responses from the remotes when
  2317  	// processing new per-account routes.
  2318  	if len(routes) > 0 || len(ch) > 0 {
  2319  		s.mu.Unlock()
  2320  
  2321  		for done := false; !done && len(ch) > 0; {
  2322  			select {
  2323  			case <-ch:
  2324  			case <-time.After(2 * time.Second):
  2325  				s.Warnf("Timed out waiting for confirmation from all routes regarding per-account routes changes")
  2326  				done = true
  2327  			}
  2328  		}
  2329  
  2330  		for r := range routes {
  2331  			r.closeConnection(RouteRemoved)
  2332  		}
  2333  
  2334  		s.mu.Lock()
  2335  	}
  2336  	// Clear the accAddedCh/ReqID fields in case they were set.
  2337  	s.accAddedReqID, s.accAddedCh = _EMPTY_, nil
  2338  	// Now that per-account routes that needed to be closed are closed,
  2339  	// remove them from s.accRoutes. Doing so before would prevent
  2340  	// removeRoute() to do proper cleanup because the route would not
  2341  	// be found in s.accRoutes.
  2342  	for _, an := range co.accsRemoved {
  2343  		delete(s.accRoutes, an)
  2344  		// Do not lookup and call setRouteInfo() on the accounts here.
  2345  		// We need first to set the new s.routesPoolSize value and
  2346  		// anyway, there is no need to do here if the pool size has
  2347  		// changed (since it will be called for all accounts).
  2348  	}
  2349  	// We have already added the accounts to s.accRoutes that needed to
  2350  	// be added.
  2351  
  2352  	// We should always have at least the system account with a dedicated route,
  2353  	// but in case we have a configuration that disables pooling and without
  2354  	// a system account, possibly set the accRoutes to nil.
  2355  	if len(opts.Cluster.PinnedAccounts) == 0 {
  2356  		s.accRoutes = nil
  2357  	}
  2358  	// Now deal with pool size updates.
  2359  	if ps := opts.Cluster.PoolSize; ps > 0 {
  2360  		s.routesPoolSize = ps
  2361  		s.routeInfo.RoutePoolSize = ps
  2362  	} else {
  2363  		s.routesPoolSize = 1
  2364  		s.routeInfo.RoutePoolSize = 0
  2365  	}
  2366  	// If the pool size has changed, we need to recompute all accounts' route
  2367  	// pool index. Note that the added/removed accounts will be reset there
  2368  	// too, but that's ok (we could use a map to exclude them, but not worth it).
  2369  	if co.poolSizeChanged {
  2370  		s.accounts.Range(func(_, v any) bool {
  2371  			acc := v.(*Account)
  2372  			acc.mu.Lock()
  2373  			s.setRouteInfo(acc)
  2374  			acc.mu.Unlock()
  2375  			return true
  2376  		})
  2377  	} else if len(co.accsRemoved) > 0 {
  2378  		// For accounts that no longer have a dedicated route, we need to send
  2379  		// the subsriptions on the existing pooled routes for those accounts.
  2380  		for _, an := range co.accsRemoved {
  2381  			if a, ok := s.accounts.Load(an); ok {
  2382  				acc := a.(*Account)
  2383  				acc.mu.Lock()
  2384  				// First call this which will assign a new route pool index.
  2385  				s.setRouteInfo(acc)
  2386  				// Get the value so we can send the subscriptions interest
  2387  				// on all routes with this pool index.
  2388  				rpi := acc.routePoolIdx
  2389  				acc.mu.Unlock()
  2390  				s.forEachRouteIdx(rpi, func(r *client) bool {
  2391  					// We have the guarantee that if the route exists, it
  2392  					// is not a new one that would have been created when
  2393  					// we released the server lock if some routes needed
  2394  					// to be closed, because we have set s.routesReject
  2395  					// to `true` at the top of this function.
  2396  					s.sendSubsToRoute(r, rpi, an)
  2397  					return true
  2398  				})
  2399  			}
  2400  		}
  2401  	}
  2402  	// Allow routes to be accepted now.
  2403  	s.routesReject = false
  2404  	// If there is a pool size change or added accounts, solicit routes now.
  2405  	if co.poolSizeChanged || len(co.accsAdded) > 0 {
  2406  		s.solicitRoutes(opts.Routes, co.accsAdded)
  2407  	}
  2408  	s.mu.Unlock()
  2409  }
  2410  
  2411  // validateClusterOpts ensures the new ClusterOpts does not change some of the
  2412  // fields that do not support reload.
  2413  func validateClusterOpts(old, new ClusterOpts) error {
  2414  	if old.Host != new.Host {
  2415  		return fmt.Errorf("config reload not supported for cluster host: old=%s, new=%s",
  2416  			old.Host, new.Host)
  2417  	}
  2418  	if old.Port != new.Port {
  2419  		return fmt.Errorf("config reload not supported for cluster port: old=%d, new=%d",
  2420  			old.Port, new.Port)
  2421  	}
  2422  	// Validate Cluster.Advertise syntax
  2423  	if new.Advertise != "" {
  2424  		if _, _, err := parseHostPort(new.Advertise, 0); err != nil {
  2425  			return fmt.Errorf("invalid Cluster.Advertise value of %s, err=%v", new.Advertise, err)
  2426  		}
  2427  	}
  2428  	return nil
  2429  }
  2430  
  2431  // diffRoutes diffs the old routes and the new routes and returns the ones that
  2432  // should be added and removed from the server.
  2433  func diffRoutes(old, new []*url.URL) (add, remove []*url.URL) {
  2434  	// Find routes to remove.
  2435  removeLoop:
  2436  	for _, oldRoute := range old {
  2437  		for _, newRoute := range new {
  2438  			if urlsAreEqual(oldRoute, newRoute) {
  2439  				continue removeLoop
  2440  			}
  2441  		}
  2442  		remove = append(remove, oldRoute)
  2443  	}
  2444  
  2445  	// Find routes to add.
  2446  addLoop:
  2447  	for _, newRoute := range new {
  2448  		for _, oldRoute := range old {
  2449  			if urlsAreEqual(oldRoute, newRoute) {
  2450  				continue addLoop
  2451  			}
  2452  		}
  2453  		add = append(add, newRoute)
  2454  	}
  2455  
  2456  	return add, remove
  2457  }