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 }