github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/jetstream_api.go (about) 1 // Copyright 2020-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 "bytes" 18 "encoding/json" 19 "errors" 20 "fmt" 21 "math/rand" 22 "os" 23 "path/filepath" 24 "runtime" 25 "sort" 26 "strconv" 27 "strings" 28 "sync/atomic" 29 "time" 30 "unicode" 31 32 "github.com/nats-io/nuid" 33 ) 34 35 // Request API subjects for JetStream. 36 const ( 37 // All API endpoints. 38 jsAllAPI = "$JS.API.>" 39 40 // For constructing JetStream domain prefixes. 41 jsDomainAPI = "$JS.%s.API.>" 42 43 JSApiPrefix = "$JS.API" 44 45 // JSApiAccountInfo is for obtaining general information about JetStream for this account. 46 // Will return JSON response. 47 JSApiAccountInfo = "$JS.API.INFO" 48 49 // JSApiTemplateCreate is the endpoint to create new stream templates. 50 // Will return JSON response. 51 JSApiTemplateCreate = "$JS.API.STREAM.TEMPLATE.CREATE.*" 52 JSApiTemplateCreateT = "$JS.API.STREAM.TEMPLATE.CREATE.%s" 53 54 // JSApiTemplates is the endpoint to list all stream template names for this account. 55 // Will return JSON response. 56 JSApiTemplates = "$JS.API.STREAM.TEMPLATE.NAMES" 57 58 // JSApiTemplateInfo is for obtaining general information about a named stream template. 59 // Will return JSON response. 60 JSApiTemplateInfo = "$JS.API.STREAM.TEMPLATE.INFO.*" 61 JSApiTemplateInfoT = "$JS.API.STREAM.TEMPLATE.INFO.%s" 62 63 // JSApiTemplateDelete is the endpoint to delete stream templates. 64 // Will return JSON response. 65 JSApiTemplateDelete = "$JS.API.STREAM.TEMPLATE.DELETE.*" 66 JSApiTemplateDeleteT = "$JS.API.STREAM.TEMPLATE.DELETE.%s" 67 68 // JSApiStreamCreate is the endpoint to create new streams. 69 // Will return JSON response. 70 JSApiStreamCreate = "$JS.API.STREAM.CREATE.*" 71 JSApiStreamCreateT = "$JS.API.STREAM.CREATE.%s" 72 73 // JSApiStreamUpdate is the endpoint to update existing streams. 74 // Will return JSON response. 75 JSApiStreamUpdate = "$JS.API.STREAM.UPDATE.*" 76 JSApiStreamUpdateT = "$JS.API.STREAM.UPDATE.%s" 77 78 // JSApiStreams is the endpoint to list all stream names for this account. 79 // Will return JSON response. 80 JSApiStreams = "$JS.API.STREAM.NAMES" 81 // JSApiStreamList is the endpoint that will return all detailed stream information 82 JSApiStreamList = "$JS.API.STREAM.LIST" 83 84 // JSApiStreamInfo is for obtaining general information about a named stream. 85 // Will return JSON response. 86 JSApiStreamInfo = "$JS.API.STREAM.INFO.*" 87 JSApiStreamInfoT = "$JS.API.STREAM.INFO.%s" 88 89 // JSApiStreamDelete is the endpoint to delete streams. 90 // Will return JSON response. 91 JSApiStreamDelete = "$JS.API.STREAM.DELETE.*" 92 JSApiStreamDeleteT = "$JS.API.STREAM.DELETE.%s" 93 94 // JSApiStreamPurge is the endpoint to purge streams. 95 // Will return JSON response. 96 JSApiStreamPurge = "$JS.API.STREAM.PURGE.*" 97 JSApiStreamPurgeT = "$JS.API.STREAM.PURGE.%s" 98 99 // JSApiStreamSnapshot is the endpoint to snapshot streams. 100 // Will return a stream of chunks with a nil chunk as EOF to 101 // the deliver subject. Caller should respond to each chunk 102 // with a nil body response for ack flow. 103 JSApiStreamSnapshot = "$JS.API.STREAM.SNAPSHOT.*" 104 JSApiStreamSnapshotT = "$JS.API.STREAM.SNAPSHOT.%s" 105 106 // JSApiStreamRestore is the endpoint to restore a stream from a snapshot. 107 // Caller should respond to each chunk with a nil body response. 108 JSApiStreamRestore = "$JS.API.STREAM.RESTORE.*" 109 JSApiStreamRestoreT = "$JS.API.STREAM.RESTORE.%s" 110 111 // JSApiMsgDelete is the endpoint to delete messages from a stream. 112 // Will return JSON response. 113 JSApiMsgDelete = "$JS.API.STREAM.MSG.DELETE.*" 114 JSApiMsgDeleteT = "$JS.API.STREAM.MSG.DELETE.%s" 115 116 // JSApiMsgGet is the template for direct requests for a message by its stream sequence number. 117 // Will return JSON response. 118 JSApiMsgGet = "$JS.API.STREAM.MSG.GET.*" 119 JSApiMsgGetT = "$JS.API.STREAM.MSG.GET.%s" 120 121 // JSDirectMsgGet is the template for non-api layer direct requests for a message by its stream sequence number or last by subject. 122 // Will return the message similar to how a consumer receives the message, no JSON processing. 123 // If the message can not be found we will use a status header of 404. If the stream does not exist the client will get a no-responders or timeout. 124 JSDirectMsgGet = "$JS.API.DIRECT.GET.*" 125 JSDirectMsgGetT = "$JS.API.DIRECT.GET.%s" 126 127 // This is a direct version of get last by subject, which will be the dominant pattern for KV access once 2.9 is released. 128 // The stream and the key will be part of the subject to allow for no-marshal payloads and subject based security permissions. 129 JSDirectGetLastBySubject = "$JS.API.DIRECT.GET.*.>" 130 JSDirectGetLastBySubjectT = "$JS.API.DIRECT.GET.%s.%s" 131 132 // jsDirectGetPre 133 jsDirectGetPre = "$JS.API.DIRECT.GET" 134 135 // JSApiConsumerCreate is the endpoint to create consumers for streams. 136 // This was also the legacy endpoint for ephemeral consumers. 137 // It now can take consumer name and optional filter subject, which when part of the subject controls access. 138 // Will return JSON response. 139 JSApiConsumerCreate = "$JS.API.CONSUMER.CREATE.*" 140 JSApiConsumerCreateT = "$JS.API.CONSUMER.CREATE.%s" 141 JSApiConsumerCreateEx = "$JS.API.CONSUMER.CREATE.*.>" 142 JSApiConsumerCreateExT = "$JS.API.CONSUMER.CREATE.%s.%s.%s" 143 144 // JSApiDurableCreate is the endpoint to create durable consumers for streams. 145 // You need to include the stream and consumer name in the subject. 146 JSApiDurableCreate = "$JS.API.CONSUMER.DURABLE.CREATE.*.*" 147 JSApiDurableCreateT = "$JS.API.CONSUMER.DURABLE.CREATE.%s.%s" 148 149 // JSApiConsumers is the endpoint to list all consumer names for the stream. 150 // Will return JSON response. 151 JSApiConsumers = "$JS.API.CONSUMER.NAMES.*" 152 JSApiConsumersT = "$JS.API.CONSUMER.NAMES.%s" 153 154 // JSApiConsumerList is the endpoint that will return all detailed consumer information 155 JSApiConsumerList = "$JS.API.CONSUMER.LIST.*" 156 JSApiConsumerListT = "$JS.API.CONSUMER.LIST.%s" 157 158 // JSApiConsumerInfo is for obtaining general information about a consumer. 159 // Will return JSON response. 160 JSApiConsumerInfo = "$JS.API.CONSUMER.INFO.*.*" 161 JSApiConsumerInfoT = "$JS.API.CONSUMER.INFO.%s.%s" 162 163 // JSApiConsumerDelete is the endpoint to delete consumers. 164 // Will return JSON response. 165 JSApiConsumerDelete = "$JS.API.CONSUMER.DELETE.*.*" 166 JSApiConsumerDeleteT = "$JS.API.CONSUMER.DELETE.%s.%s" 167 168 // JSApiConsumerPause is the endpoint to pause or unpause consumers. 169 // Will return JSON response. 170 JSApiConsumerPause = "$JS.API.CONSUMER.PAUSE.*.*" 171 JSApiConsumerPauseT = "$JS.API.CONSUMER.PAUSE.%s.%s" 172 173 // JSApiRequestNextT is the prefix for the request next message(s) for a consumer in worker/pull mode. 174 JSApiRequestNextT = "$JS.API.CONSUMER.MSG.NEXT.%s.%s" 175 176 // jsRequestNextPre 177 jsRequestNextPre = "$JS.API.CONSUMER.MSG.NEXT." 178 179 // For snapshots and restores. The ack will have additional tokens. 180 jsSnapshotAckT = "$JS.SNAPSHOT.ACK.%s.%s" 181 jsRestoreDeliverT = "$JS.SNAPSHOT.RESTORE.%s.%s" 182 183 // JSApiStreamRemovePeer is the endpoint to remove a peer from a clustered stream and its consumers. 184 // Will return JSON response. 185 JSApiStreamRemovePeer = "$JS.API.STREAM.PEER.REMOVE.*" 186 JSApiStreamRemovePeerT = "$JS.API.STREAM.PEER.REMOVE.%s" 187 188 // JSApiStreamLeaderStepDown is the endpoint to have stream leader stepdown. 189 // Will return JSON response. 190 JSApiStreamLeaderStepDown = "$JS.API.STREAM.LEADER.STEPDOWN.*" 191 JSApiStreamLeaderStepDownT = "$JS.API.STREAM.LEADER.STEPDOWN.%s" 192 193 // JSApiConsumerLeaderStepDown is the endpoint to have consumer leader stepdown. 194 // Will return JSON response. 195 JSApiConsumerLeaderStepDown = "$JS.API.CONSUMER.LEADER.STEPDOWN.*.*" 196 JSApiConsumerLeaderStepDownT = "$JS.API.CONSUMER.LEADER.STEPDOWN.%s.%s" 197 198 // JSApiLeaderStepDown is the endpoint to have our metaleader stepdown. 199 // Only works from system account. 200 // Will return JSON response. 201 JSApiLeaderStepDown = "$JS.API.META.LEADER.STEPDOWN" 202 203 // JSApiRemoveServer is the endpoint to remove a peer server from the cluster. 204 // Only works from system account. 205 // Will return JSON response. 206 JSApiRemoveServer = "$JS.API.SERVER.REMOVE" 207 208 // JSApiAccountPurge is the endpoint to purge the js content of an account 209 // Only works from system account. 210 // Will return JSON response. 211 JSApiAccountPurge = "$JS.API.ACCOUNT.PURGE.*" 212 JSApiAccountPurgeT = "$JS.API.ACCOUNT.PURGE.%s" 213 214 // JSApiServerStreamMove is the endpoint to move streams off a server 215 // Only works from system account. 216 // Will return JSON response. 217 JSApiServerStreamMove = "$JS.API.ACCOUNT.STREAM.MOVE.*.*" 218 JSApiServerStreamMoveT = "$JS.API.ACCOUNT.STREAM.MOVE.%s.%s" 219 220 // JSApiServerStreamCancelMove is the endpoint to cancel a stream move 221 // Only works from system account. 222 // Will return JSON response. 223 JSApiServerStreamCancelMove = "$JS.API.ACCOUNT.STREAM.CANCEL_MOVE.*.*" 224 JSApiServerStreamCancelMoveT = "$JS.API.ACCOUNT.STREAM.CANCEL_MOVE.%s.%s" 225 226 // The prefix for system level account API. 227 jsAPIAccountPre = "$JS.API.ACCOUNT." 228 229 // jsAckT is the template for the ack message stream coming back from a consumer 230 // when they ACK/NAK, etc a message. 231 jsAckT = "$JS.ACK.%s.%s" 232 jsAckPre = "$JS.ACK." 233 jsAckPreLen = len(jsAckPre) 234 235 // jsFlowControl is for flow control subjects. 236 jsFlowControlPre = "$JS.FC." 237 // jsFlowControl is for FC responses. 238 jsFlowControl = "$JS.FC.%s.%s.*" 239 240 // JSAdvisoryPrefix is a prefix for all JetStream advisories. 241 JSAdvisoryPrefix = "$JS.EVENT.ADVISORY" 242 243 // JSMetricPrefix is a prefix for all JetStream metrics. 244 JSMetricPrefix = "$JS.EVENT.METRIC" 245 246 // JSMetricConsumerAckPre is a metric containing ack latency. 247 JSMetricConsumerAckPre = "$JS.EVENT.METRIC.CONSUMER.ACK" 248 249 // JSAdvisoryConsumerMaxDeliveryExceedPre is a notification published when a message exceeds its delivery threshold. 250 JSAdvisoryConsumerMaxDeliveryExceedPre = "$JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES" 251 252 // JSAdvisoryConsumerMsgNakPre is a notification published when a message has been naked 253 JSAdvisoryConsumerMsgNakPre = "$JS.EVENT.ADVISORY.CONSUMER.MSG_NAKED" 254 255 // JSAdvisoryConsumerMsgTerminatedPre is a notification published when a message has been terminated. 256 JSAdvisoryConsumerMsgTerminatedPre = "$JS.EVENT.ADVISORY.CONSUMER.MSG_TERMINATED" 257 258 // JSAdvisoryStreamCreatedPre notification that a stream was created. 259 JSAdvisoryStreamCreatedPre = "$JS.EVENT.ADVISORY.STREAM.CREATED" 260 261 // JSAdvisoryStreamDeletedPre notification that a stream was deleted. 262 JSAdvisoryStreamDeletedPre = "$JS.EVENT.ADVISORY.STREAM.DELETED" 263 264 // JSAdvisoryStreamUpdatedPre notification that a stream was updated. 265 JSAdvisoryStreamUpdatedPre = "$JS.EVENT.ADVISORY.STREAM.UPDATED" 266 267 // JSAdvisoryConsumerCreatedPre notification that a template created. 268 JSAdvisoryConsumerCreatedPre = "$JS.EVENT.ADVISORY.CONSUMER.CREATED" 269 270 // JSAdvisoryConsumerDeletedPre notification that a template deleted. 271 JSAdvisoryConsumerDeletedPre = "$JS.EVENT.ADVISORY.CONSUMER.DELETED" 272 273 // JSAdvisoryConsumerPausePre notification that a consumer paused/unpaused. 274 JSAdvisoryConsumerPausePre = "$JS.EVENT.ADVISORY.CONSUMER.PAUSE" 275 276 // JSAdvisoryStreamSnapshotCreatePre notification that a snapshot was created. 277 JSAdvisoryStreamSnapshotCreatePre = "$JS.EVENT.ADVISORY.STREAM.SNAPSHOT_CREATE" 278 279 // JSAdvisoryStreamSnapshotCompletePre notification that a snapshot was completed. 280 JSAdvisoryStreamSnapshotCompletePre = "$JS.EVENT.ADVISORY.STREAM.SNAPSHOT_COMPLETE" 281 282 // JSAdvisoryStreamRestoreCreatePre notification that a restore was start. 283 JSAdvisoryStreamRestoreCreatePre = "$JS.EVENT.ADVISORY.STREAM.RESTORE_CREATE" 284 285 // JSAdvisoryStreamRestoreCompletePre notification that a restore was completed. 286 JSAdvisoryStreamRestoreCompletePre = "$JS.EVENT.ADVISORY.STREAM.RESTORE_COMPLETE" 287 288 // JSAdvisoryDomainLeaderElectedPre notification that a jetstream domain has elected a leader. 289 JSAdvisoryDomainLeaderElected = "$JS.EVENT.ADVISORY.DOMAIN.LEADER_ELECTED" 290 291 // JSAdvisoryStreamLeaderElectedPre notification that a replicated stream has elected a leader. 292 JSAdvisoryStreamLeaderElectedPre = "$JS.EVENT.ADVISORY.STREAM.LEADER_ELECTED" 293 294 // JSAdvisoryStreamQuorumLostPre notification that a stream and its consumers are stalled. 295 JSAdvisoryStreamQuorumLostPre = "$JS.EVENT.ADVISORY.STREAM.QUORUM_LOST" 296 297 // JSAdvisoryConsumerLeaderElectedPre notification that a replicated consumer has elected a leader. 298 JSAdvisoryConsumerLeaderElectedPre = "$JS.EVENT.ADVISORY.CONSUMER.LEADER_ELECTED" 299 300 // JSAdvisoryConsumerQuorumLostPre notification that a consumer is stalled. 301 JSAdvisoryConsumerQuorumLostPre = "$JS.EVENT.ADVISORY.CONSUMER.QUORUM_LOST" 302 303 // JSAdvisoryServerOutOfStorage notification that a server has no more storage. 304 JSAdvisoryServerOutOfStorage = "$JS.EVENT.ADVISORY.SERVER.OUT_OF_STORAGE" 305 306 // JSAdvisoryServerRemoved notification that a server has been removed from the system. 307 JSAdvisoryServerRemoved = "$JS.EVENT.ADVISORY.SERVER.REMOVED" 308 309 // JSAuditAdvisory is a notification about JetStream API access. 310 // FIXME - Add in details about who.. 311 JSAuditAdvisory = "$JS.EVENT.ADVISORY.API" 312 ) 313 314 var denyAllClientJs = []string{jsAllAPI, "$KV.>", "$OBJ.>"} 315 var denyAllJs = []string{jscAllSubj, raftAllSubj, jsAllAPI, "$KV.>", "$OBJ.>"} 316 317 func generateJSMappingTable(domain string) map[string]string { 318 mappings := map[string]string{} 319 // This set of mappings is very very very ugly. 320 // It is a consequence of what we defined the domain prefix to be "$JS.domain.API" and it's mapping to "$JS.API" 321 // For optics $KV and $OBJ where made to be independent subject spaces. 322 // As materialized views of JS, they did not simply extend that subject space to say "$JS.API.KV" "$JS.API.OBJ" 323 // This is very unfortunate!!! 324 // Furthermore, it seemed bad to require different domain prefixes for JS/KV/OBJ. 325 // Especially since the actual API for say KV, does use stream create from JS. 326 // To avoid overlaps KV and OBJ views append the prefix to their API. 327 // (Replacing $KV with the prefix allows users to create collisions with say the bucket name) 328 // This mapping therefore needs to have extra token so that the mapping can properly discern between $JS, $KV, $OBJ 329 for srcMappingSuffix, to := range map[string]string{ 330 "INFO": JSApiAccountInfo, 331 "STREAM.>": "$JS.API.STREAM.>", 332 "CONSUMER.>": "$JS.API.CONSUMER.>", 333 "DIRECT.>": "$JS.API.DIRECT.>", 334 "META.>": "$JS.API.META.>", 335 "SERVER.>": "$JS.API.SERVER.>", 336 "ACCOUNT.>": "$JS.API.ACCOUNT.>", 337 "$KV.>": "$KV.>", 338 "$OBJ.>": "$OBJ.>", 339 } { 340 mappings[fmt.Sprintf("$JS.%s.API.%s", domain, srcMappingSuffix)] = to 341 } 342 return mappings 343 } 344 345 // JSMaxDescription is the maximum description length for streams and consumers. 346 const JSMaxDescriptionLen = 4 * 1024 347 348 // JSMaxMetadataLen is the maximum length for streams and consumers metadata map. 349 // It's calculated by summing length of all keys and values. 350 const JSMaxMetadataLen = 128 * 1024 351 352 // JSMaxNameLen is the maximum name lengths for streams, consumers and templates. 353 // Picked 255 as it seems to be a widely used file name limit 354 const JSMaxNameLen = 255 355 356 // Responses for API calls. 357 358 // ApiResponse is a standard response from the JetStream JSON API 359 type ApiResponse struct { 360 Type string `json:"type"` 361 Error *ApiError `json:"error,omitempty"` 362 } 363 364 const JSApiSystemResponseType = "io.nats.jetstream.api.v1.system_response" 365 366 // When passing back to the clients generalize store failures. 367 var ( 368 errStreamStoreFailed = errors.New("error creating store for stream") 369 errConsumerStoreFailed = errors.New("error creating store for consumer") 370 ) 371 372 // ToError checks if the response has a error and if it does converts it to an error avoiding 373 // the pitfalls described by https://yourbasic.org/golang/gotcha-why-nil-error-not-equal-nil/ 374 func (r *ApiResponse) ToError() error { 375 if r.Error == nil { 376 return nil 377 } 378 379 return r.Error 380 } 381 382 const JSApiOverloadedType = "io.nats.jetstream.api.v1.system_overloaded" 383 384 // ApiPaged includes variables used to create paged responses from the JSON API 385 type ApiPaged struct { 386 Total int `json:"total"` 387 Offset int `json:"offset"` 388 Limit int `json:"limit"` 389 } 390 391 // ApiPagedRequest includes parameters allowing specific pages to be requests from APIs responding with ApiPaged 392 type ApiPagedRequest struct { 393 Offset int `json:"offset"` 394 } 395 396 // JSApiAccountInfoResponse reports back information on jetstream for this account. 397 type JSApiAccountInfoResponse struct { 398 ApiResponse 399 *JetStreamAccountStats 400 } 401 402 const JSApiAccountInfoResponseType = "io.nats.jetstream.api.v1.account_info_response" 403 404 // JSApiStreamCreateResponse stream creation. 405 type JSApiStreamCreateResponse struct { 406 ApiResponse 407 *StreamInfo 408 DidCreate bool `json:"did_create,omitempty"` 409 } 410 411 const JSApiStreamCreateResponseType = "io.nats.jetstream.api.v1.stream_create_response" 412 413 // JSApiStreamDeleteResponse stream removal. 414 type JSApiStreamDeleteResponse struct { 415 ApiResponse 416 Success bool `json:"success,omitempty"` 417 } 418 419 const JSApiStreamDeleteResponseType = "io.nats.jetstream.api.v1.stream_delete_response" 420 421 // JSMaxSubjectDetails The limit of the number of subject details we will send in a stream info response. 422 const JSMaxSubjectDetails = 100_000 423 424 type JSApiStreamInfoRequest struct { 425 ApiPagedRequest 426 DeletedDetails bool `json:"deleted_details,omitempty"` 427 SubjectsFilter string `json:"subjects_filter,omitempty"` 428 } 429 430 type JSApiStreamInfoResponse struct { 431 ApiResponse 432 ApiPaged 433 *StreamInfo 434 } 435 436 const JSApiStreamInfoResponseType = "io.nats.jetstream.api.v1.stream_info_response" 437 438 // JSApiNamesLimit is the maximum entries we will return for streams or consumers lists. 439 // TODO(dlc) - with header or request support could request chunked response. 440 const JSApiNamesLimit = 1024 441 const JSApiListLimit = 256 442 443 type JSApiStreamNamesRequest struct { 444 ApiPagedRequest 445 // These are filters that can be applied to the list. 446 Subject string `json:"subject,omitempty"` 447 } 448 449 // JSApiStreamNamesResponse list of streams. 450 // A nil request is valid and means all streams. 451 type JSApiStreamNamesResponse struct { 452 ApiResponse 453 ApiPaged 454 Streams []string `json:"streams"` 455 } 456 457 const JSApiStreamNamesResponseType = "io.nats.jetstream.api.v1.stream_names_response" 458 459 type JSApiStreamListRequest struct { 460 ApiPagedRequest 461 // These are filters that can be applied to the list. 462 Subject string `json:"subject,omitempty"` 463 } 464 465 // JSApiStreamListResponse list of detailed stream information. 466 // A nil request is valid and means all streams. 467 type JSApiStreamListResponse struct { 468 ApiResponse 469 ApiPaged 470 Streams []*StreamInfo `json:"streams"` 471 Missing []string `json:"missing,omitempty"` 472 } 473 474 const JSApiStreamListResponseType = "io.nats.jetstream.api.v1.stream_list_response" 475 476 // JSApiStreamPurgeRequest is optional request information to the purge API. 477 // Subject will filter the purge request to only messages that match the subject, which can have wildcards. 478 // Sequence will purge up to but not including this sequence and can be combined with subject filtering. 479 // Keep will specify how many messages to keep. This can also be combined with subject filtering. 480 // Note that Sequence and Keep are mutually exclusive, so both can not be set at the same time. 481 type JSApiStreamPurgeRequest struct { 482 // Purge up to but not including sequence. 483 Sequence uint64 `json:"seq,omitempty"` 484 // Subject to match against messages for the purge command. 485 Subject string `json:"filter,omitempty"` 486 // Number of messages to keep. 487 Keep uint64 `json:"keep,omitempty"` 488 } 489 490 type JSApiStreamPurgeResponse struct { 491 ApiResponse 492 Success bool `json:"success,omitempty"` 493 Purged uint64 `json:"purged"` 494 } 495 496 const JSApiStreamPurgeResponseType = "io.nats.jetstream.api.v1.stream_purge_response" 497 498 // JSApiStreamUpdateResponse for updating a stream. 499 type JSApiStreamUpdateResponse struct { 500 ApiResponse 501 *StreamInfo 502 } 503 504 const JSApiStreamUpdateResponseType = "io.nats.jetstream.api.v1.stream_update_response" 505 506 // JSApiMsgDeleteRequest delete message request. 507 type JSApiMsgDeleteRequest struct { 508 Seq uint64 `json:"seq"` 509 NoErase bool `json:"no_erase,omitempty"` 510 } 511 512 type JSApiMsgDeleteResponse struct { 513 ApiResponse 514 Success bool `json:"success,omitempty"` 515 } 516 517 const JSApiMsgDeleteResponseType = "io.nats.jetstream.api.v1.stream_msg_delete_response" 518 519 type JSApiStreamSnapshotRequest struct { 520 // Subject to deliver the chunks to for the snapshot. 521 DeliverSubject string `json:"deliver_subject"` 522 // Do not include consumers in the snapshot. 523 NoConsumers bool `json:"no_consumers,omitempty"` 524 // Optional chunk size preference. 525 // Best to just let server select. 526 ChunkSize int `json:"chunk_size,omitempty"` 527 // Check all message's checksums prior to snapshot. 528 CheckMsgs bool `json:"jsck,omitempty"` 529 } 530 531 // JSApiStreamSnapshotResponse is the direct response to the snapshot request. 532 type JSApiStreamSnapshotResponse struct { 533 ApiResponse 534 // Configuration of the given stream. 535 Config *StreamConfig `json:"config,omitempty"` 536 // Current State for the given stream. 537 State *StreamState `json:"state,omitempty"` 538 } 539 540 const JSApiStreamSnapshotResponseType = "io.nats.jetstream.api.v1.stream_snapshot_response" 541 542 // JSApiStreamRestoreRequest is the required restore request. 543 type JSApiStreamRestoreRequest struct { 544 // Configuration of the given stream. 545 Config StreamConfig `json:"config"` 546 // Current State for the given stream. 547 State StreamState `json:"state"` 548 } 549 550 // JSApiStreamRestoreResponse is the direct response to the restore request. 551 type JSApiStreamRestoreResponse struct { 552 ApiResponse 553 // Subject to deliver the chunks to for the snapshot restore. 554 DeliverSubject string `json:"deliver_subject"` 555 } 556 557 const JSApiStreamRestoreResponseType = "io.nats.jetstream.api.v1.stream_restore_response" 558 559 // JSApiStreamRemovePeerRequest is the required remove peer request. 560 type JSApiStreamRemovePeerRequest struct { 561 // Server name of the peer to be removed. 562 Peer string `json:"peer"` 563 } 564 565 // JSApiStreamRemovePeerResponse is the response to a remove peer request. 566 type JSApiStreamRemovePeerResponse struct { 567 ApiResponse 568 Success bool `json:"success,omitempty"` 569 } 570 571 const JSApiStreamRemovePeerResponseType = "io.nats.jetstream.api.v1.stream_remove_peer_response" 572 573 // JSApiStreamLeaderStepDownResponse is the response to a leader stepdown request. 574 type JSApiStreamLeaderStepDownResponse struct { 575 ApiResponse 576 Success bool `json:"success,omitempty"` 577 } 578 579 const JSApiStreamLeaderStepDownResponseType = "io.nats.jetstream.api.v1.stream_leader_stepdown_response" 580 581 // JSApiConsumerLeaderStepDownResponse is the response to a consumer leader stepdown request. 582 type JSApiConsumerLeaderStepDownResponse struct { 583 ApiResponse 584 Success bool `json:"success,omitempty"` 585 } 586 587 const JSApiConsumerLeaderStepDownResponseType = "io.nats.jetstream.api.v1.consumer_leader_stepdown_response" 588 589 // JSApiLeaderStepdownRequest allows placement control over the meta leader placement. 590 type JSApiLeaderStepdownRequest struct { 591 Placement *Placement `json:"placement,omitempty"` 592 } 593 594 // JSApiLeaderStepDownResponse is the response to a meta leader stepdown request. 595 type JSApiLeaderStepDownResponse struct { 596 ApiResponse 597 Success bool `json:"success,omitempty"` 598 } 599 600 const JSApiLeaderStepDownResponseType = "io.nats.jetstream.api.v1.meta_leader_stepdown_response" 601 602 // JSApiMetaServerRemoveRequest will remove a peer from the meta group. 603 type JSApiMetaServerRemoveRequest struct { 604 // Server name of the peer to be removed. 605 Server string `json:"peer"` 606 // Peer ID of the peer to be removed. If specified this is used 607 // instead of the server name. 608 Peer string `json:"peer_id,omitempty"` 609 } 610 611 // JSApiMetaServerRemoveResponse is the response to a peer removal request in the meta group. 612 type JSApiMetaServerRemoveResponse struct { 613 ApiResponse 614 Success bool `json:"success,omitempty"` 615 } 616 617 const JSApiMetaServerRemoveResponseType = "io.nats.jetstream.api.v1.meta_server_remove_response" 618 619 // JSApiMetaServerStreamMoveRequest will move a stream on a server to another 620 // response to this will come as JSApiStreamUpdateResponse/JSApiStreamUpdateResponseType 621 type JSApiMetaServerStreamMoveRequest struct { 622 // Server name of the peer to be evacuated. 623 Server string `json:"server,omitempty"` 624 // Cluster the server is in 625 Cluster string `json:"cluster,omitempty"` 626 // Domain the sever is in 627 Domain string `json:"domain,omitempty"` 628 // Ephemeral placement tags for the move 629 Tags []string `json:"tags,omitempty"` 630 } 631 632 const JSApiAccountPurgeResponseType = "io.nats.jetstream.api.v1.account_purge_response" 633 634 // JSApiAccountPurgeResponse is the response to a purge request in the meta group. 635 type JSApiAccountPurgeResponse struct { 636 ApiResponse 637 Initiated bool `json:"initiated,omitempty"` 638 } 639 640 // JSApiMsgGetRequest get a message request. 641 type JSApiMsgGetRequest struct { 642 Seq uint64 `json:"seq,omitempty"` 643 LastFor string `json:"last_by_subj,omitempty"` 644 NextFor string `json:"next_by_subj,omitempty"` 645 646 // Batch support. Used to request more then one msg at a time. 647 // Can be used with simple starting seq, but also NextFor with wildcards. 648 Batch int `json:"batch,omitempty"` 649 // This will make sure we limit how much data we blast out. If not set we will 650 // inherit the slow consumer default max setting of the server. Default is MAX_PENDING_SIZE. 651 MaxBytes int `json:"max_bytes,omitempty"` 652 // Return messages as of this start time. 653 StartTime *time.Time `json:"start_time,omitempty"` 654 655 // Multiple response support. Will get the last msgs matching the subjects. These can include wildcards. 656 MultiLastFor []string `json:"multi_last,omitempty"` 657 // Only return messages up to this sequence. If not set, will be last sequence for the stream. 658 UpToSeq uint64 `json:"up_to_seq,omitempty"` 659 // Only return messages up to this time. 660 UpToTime *time.Time `json:"up_to_time,omitempty"` 661 } 662 663 type JSApiMsgGetResponse struct { 664 ApiResponse 665 Message *StoredMsg `json:"message,omitempty"` 666 } 667 668 const JSApiMsgGetResponseType = "io.nats.jetstream.api.v1.stream_msg_get_response" 669 670 // JSWaitQueueDefaultMax is the default max number of outstanding requests for pull consumers. 671 const JSWaitQueueDefaultMax = 512 672 673 type JSApiConsumerCreateResponse struct { 674 ApiResponse 675 *ConsumerInfo 676 } 677 678 const JSApiConsumerCreateResponseType = "io.nats.jetstream.api.v1.consumer_create_response" 679 680 type JSApiConsumerDeleteResponse struct { 681 ApiResponse 682 Success bool `json:"success,omitempty"` 683 } 684 685 const JSApiConsumerDeleteResponseType = "io.nats.jetstream.api.v1.consumer_delete_response" 686 687 type JSApiConsumerPauseRequest struct { 688 PauseUntil time.Time `json:"pause_until,omitempty"` 689 } 690 691 const JSApiConsumerPauseResponseType = "io.nats.jetstream.api.v1.consumer_pause_response" 692 693 type JSApiConsumerPauseResponse struct { 694 ApiResponse 695 Paused bool `json:"paused"` 696 PauseUntil time.Time `json:"pause_until"` 697 PauseRemaining time.Duration `json:"pause_remaining,omitempty"` 698 } 699 700 type JSApiConsumerInfoResponse struct { 701 ApiResponse 702 *ConsumerInfo 703 } 704 705 const JSApiConsumerInfoResponseType = "io.nats.jetstream.api.v1.consumer_info_response" 706 707 type JSApiConsumersRequest struct { 708 ApiPagedRequest 709 } 710 711 type JSApiConsumerNamesResponse struct { 712 ApiResponse 713 ApiPaged 714 Consumers []string `json:"consumers"` 715 } 716 717 const JSApiConsumerNamesResponseType = "io.nats.jetstream.api.v1.consumer_names_response" 718 719 type JSApiConsumerListResponse struct { 720 ApiResponse 721 ApiPaged 722 Consumers []*ConsumerInfo `json:"consumers"` 723 Missing []string `json:"missing,omitempty"` 724 } 725 726 const JSApiConsumerListResponseType = "io.nats.jetstream.api.v1.consumer_list_response" 727 728 // JSApiConsumerGetNextRequest is for getting next messages for pull based consumers. 729 type JSApiConsumerGetNextRequest struct { 730 Expires time.Duration `json:"expires,omitempty"` 731 Batch int `json:"batch,omitempty"` 732 MaxBytes int `json:"max_bytes,omitempty"` 733 NoWait bool `json:"no_wait,omitempty"` 734 Heartbeat time.Duration `json:"idle_heartbeat,omitempty"` 735 } 736 737 // JSApiStreamTemplateCreateResponse for creating templates. 738 type JSApiStreamTemplateCreateResponse struct { 739 ApiResponse 740 *StreamTemplateInfo 741 } 742 743 const JSApiStreamTemplateCreateResponseType = "io.nats.jetstream.api.v1.stream_template_create_response" 744 745 type JSApiStreamTemplateDeleteResponse struct { 746 ApiResponse 747 Success bool `json:"success,omitempty"` 748 } 749 750 const JSApiStreamTemplateDeleteResponseType = "io.nats.jetstream.api.v1.stream_template_delete_response" 751 752 // JSApiStreamTemplateInfoResponse for information about stream templates. 753 type JSApiStreamTemplateInfoResponse struct { 754 ApiResponse 755 *StreamTemplateInfo 756 } 757 758 const JSApiStreamTemplateInfoResponseType = "io.nats.jetstream.api.v1.stream_template_info_response" 759 760 type JSApiStreamTemplatesRequest struct { 761 ApiPagedRequest 762 } 763 764 // JSApiStreamTemplateNamesResponse list of templates 765 type JSApiStreamTemplateNamesResponse struct { 766 ApiResponse 767 ApiPaged 768 Templates []string `json:"streams"` 769 } 770 771 const JSApiStreamTemplateNamesResponseType = "io.nats.jetstream.api.v1.stream_template_names_response" 772 773 // Structure that holds state for a JetStream API request that is processed 774 // in a separate long-lived go routine. This is to avoid possibly blocking 775 // ROUTE and GATEWAY connections. 776 type jsAPIRoutedReq struct { 777 jsub *subscription 778 sub *subscription 779 acc *Account 780 subject string 781 reply string 782 msg []byte 783 pa pubArg 784 } 785 786 func (js *jetStream) apiDispatch(sub *subscription, c *client, acc *Account, subject, reply string, rmsg []byte) { 787 // Ignore system level directives meta stepdown and peer remove requests here. 788 if subject == JSApiLeaderStepDown || 789 subject == JSApiRemoveServer || 790 strings.HasPrefix(subject, jsAPIAccountPre) { 791 return 792 } 793 // No lock needed, those are immutable. 794 s, rr := js.srv, js.apiSubs.Match(subject) 795 796 hdr, msg := c.msgParts(rmsg) 797 if len(getHeader(ClientInfoHdr, hdr)) == 0 { 798 // Check if this is the system account. We will let these through for the account info only. 799 sacc := s.SystemAccount() 800 if sacc != acc { 801 return 802 } 803 if subject != JSApiAccountInfo { 804 // Only respond from the initial server entry to the NATS system. 805 if c.kind == CLIENT || c.kind == LEAF { 806 var resp = ApiResponse{ 807 Type: JSApiSystemResponseType, 808 Error: NewJSNotEnabledForAccountError(), 809 } 810 s.sendAPIErrResponse(nil, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 811 } 812 return 813 } 814 } 815 816 // Short circuit for no interest. 817 if len(rr.psubs)+len(rr.qsubs) == 0 { 818 if (c.kind == CLIENT || c.kind == LEAF) && acc != s.SystemAccount() { 819 ci, acc, _, _, _ := s.getRequestInfo(c, rmsg) 820 var resp = ApiResponse{ 821 Type: JSApiSystemResponseType, 822 Error: NewJSBadRequestError(), 823 } 824 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 825 } 826 return 827 } 828 829 // We should only have psubs and only 1 per result. 830 if len(rr.psubs) != 1 { 831 s.Warnf("Malformed JetStream API Request: [%s] %q", subject, rmsg) 832 if c.kind == CLIENT || c.kind == LEAF { 833 ci, acc, _, _, _ := s.getRequestInfo(c, rmsg) 834 var resp = ApiResponse{ 835 Type: JSApiSystemResponseType, 836 Error: NewJSBadRequestError(), 837 } 838 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 839 } 840 return 841 } 842 jsub := rr.psubs[0] 843 844 // If this is directly from a client connection ok to do in place. 845 if c.kind != ROUTER && c.kind != GATEWAY && c.kind != LEAF { 846 start := time.Now() 847 jsub.icb(sub, c, acc, subject, reply, rmsg) 848 if dur := time.Since(start); dur >= readLoopReportThreshold { 849 s.Warnf("Internal subscription on %q took too long: %v", subject, dur) 850 } 851 return 852 } 853 854 // If we are here we have received this request over a non-client connection. 855 // We need to make sure not to block. We will send the request to a long-lived 856 // pool of go routines. 857 858 // Increment inflight. Do this before queueing. 859 atomic.AddInt64(&js.apiInflight, 1) 860 861 // Copy the state. Note the JSAPI only uses the hdr index to piece apart the 862 // header from the msg body. No other references are needed. 863 // Check pending and warn if getting backed up. 864 const warnThresh = 32 865 pending := s.jsAPIRoutedReqs.push(&jsAPIRoutedReq{jsub, sub, acc, subject, reply, copyBytes(rmsg), c.pa}) 866 if pending > warnThresh { 867 s.RateLimitWarnf("JetStream request queue has high pending count: %d", pending) 868 } 869 } 870 871 func (s *Server) processJSAPIRoutedRequests() { 872 defer s.grWG.Done() 873 874 s.mu.RLock() 875 queue := s.jsAPIRoutedReqs 876 client := &client{srv: s, kind: JETSTREAM} 877 s.mu.RUnlock() 878 879 js := s.getJetStream() 880 881 for { 882 select { 883 case <-queue.ch: 884 reqs := queue.pop() 885 for _, r := range reqs { 886 client.pa = r.pa 887 start := time.Now() 888 r.jsub.icb(r.sub, client, r.acc, r.subject, r.reply, r.msg) 889 if dur := time.Since(start); dur >= readLoopReportThreshold { 890 s.Warnf("Internal subscription on %q took too long: %v", r.subject, dur) 891 } 892 atomic.AddInt64(&js.apiInflight, -1) 893 } 894 queue.recycle(&reqs) 895 case <-s.quitCh: 896 return 897 } 898 } 899 } 900 901 func (s *Server) setJetStreamExportSubs() error { 902 js := s.getJetStream() 903 if js == nil { 904 return NewJSNotEnabledError() 905 } 906 907 // Start the go routine that will process API requests received by the 908 // subscription below when they are coming from routes, etc.. 909 const maxProcs = 16 910 mp := runtime.GOMAXPROCS(0) 911 // Cap at 16 max for now on larger core setups. 912 if mp > maxProcs { 913 mp = maxProcs 914 } 915 s.jsAPIRoutedReqs = newIPQueue[*jsAPIRoutedReq](s, "Routed JS API Requests") 916 for i := 0; i < mp; i++ { 917 s.startGoRoutine(s.processJSAPIRoutedRequests) 918 } 919 920 // This is the catch all now for all JetStream API calls. 921 if _, err := s.sysSubscribe(jsAllAPI, js.apiDispatch); err != nil { 922 return err 923 } 924 925 if err := s.SystemAccount().AddServiceExport(jsAllAPI, nil); err != nil { 926 s.Warnf("Error setting up jetstream service exports: %v", err) 927 return err 928 } 929 930 // API handles themselves. 931 pairs := []struct { 932 subject string 933 handler msgHandler 934 }{ 935 {JSApiAccountInfo, s.jsAccountInfoRequest}, 936 {JSApiTemplateCreate, s.jsTemplateCreateRequest}, 937 {JSApiTemplates, s.jsTemplateNamesRequest}, 938 {JSApiTemplateInfo, s.jsTemplateInfoRequest}, 939 {JSApiTemplateDelete, s.jsTemplateDeleteRequest}, 940 {JSApiStreamCreate, s.jsStreamCreateRequest}, 941 {JSApiStreamUpdate, s.jsStreamUpdateRequest}, 942 {JSApiStreams, s.jsStreamNamesRequest}, 943 {JSApiStreamList, s.jsStreamListRequest}, 944 {JSApiStreamInfo, s.jsStreamInfoRequest}, 945 {JSApiStreamDelete, s.jsStreamDeleteRequest}, 946 {JSApiStreamPurge, s.jsStreamPurgeRequest}, 947 {JSApiStreamSnapshot, s.jsStreamSnapshotRequest}, 948 {JSApiStreamRestore, s.jsStreamRestoreRequest}, 949 {JSApiStreamRemovePeer, s.jsStreamRemovePeerRequest}, 950 {JSApiStreamLeaderStepDown, s.jsStreamLeaderStepDownRequest}, 951 {JSApiConsumerLeaderStepDown, s.jsConsumerLeaderStepDownRequest}, 952 {JSApiMsgDelete, s.jsMsgDeleteRequest}, 953 {JSApiMsgGet, s.jsMsgGetRequest}, 954 {JSApiConsumerCreateEx, s.jsConsumerCreateRequest}, 955 {JSApiConsumerCreate, s.jsConsumerCreateRequest}, 956 {JSApiDurableCreate, s.jsConsumerCreateRequest}, 957 {JSApiConsumers, s.jsConsumerNamesRequest}, 958 {JSApiConsumerList, s.jsConsumerListRequest}, 959 {JSApiConsumerInfo, s.jsConsumerInfoRequest}, 960 {JSApiConsumerDelete, s.jsConsumerDeleteRequest}, 961 {JSApiConsumerPause, s.jsConsumerPauseRequest}, 962 } 963 964 js.mu.Lock() 965 defer js.mu.Unlock() 966 967 for _, p := range pairs { 968 sub := &subscription{subject: []byte(p.subject), icb: p.handler} 969 if err := js.apiSubs.Insert(sub); err != nil { 970 return err 971 } 972 } 973 974 return nil 975 } 976 977 func (s *Server) sendAPIResponse(ci *ClientInfo, acc *Account, subject, reply, request, response string) { 978 acc.trackAPI() 979 if reply != _EMPTY_ { 980 s.sendInternalAccountMsg(nil, reply, response) 981 } 982 s.sendJetStreamAPIAuditAdvisory(ci, acc, subject, request, response) 983 } 984 985 func (s *Server) sendAPIErrResponse(ci *ClientInfo, acc *Account, subject, reply, request, response string) { 986 acc.trackAPIErr() 987 if reply != _EMPTY_ { 988 s.sendInternalAccountMsg(nil, reply, response) 989 } 990 s.sendJetStreamAPIAuditAdvisory(ci, acc, subject, request, response) 991 } 992 993 const errRespDelay = 500 * time.Millisecond 994 995 func (s *Server) sendDelayedAPIErrResponse(ci *ClientInfo, acc *Account, subject, reply, request, response string, rg *raftGroup) { 996 js := s.getJetStream() 997 if js == nil { 998 return 999 } 1000 var quitCh <-chan struct{} 1001 js.mu.RLock() 1002 if rg != nil && rg.node != nil { 1003 quitCh = rg.node.QuitC() 1004 } 1005 js.mu.RUnlock() 1006 1007 s.startGoRoutine(func() { 1008 defer s.grWG.Done() 1009 select { 1010 case <-quitCh: 1011 case <-s.quitCh: 1012 case <-time.After(errRespDelay): 1013 acc.trackAPIErr() 1014 if reply != _EMPTY_ { 1015 s.sendInternalAccountMsg(nil, reply, response) 1016 } 1017 s.sendJetStreamAPIAuditAdvisory(ci, acc, subject, request, response) 1018 } 1019 }) 1020 } 1021 1022 func (s *Server) getRequestInfo(c *client, raw []byte) (pci *ClientInfo, acc *Account, hdr, msg []byte, err error) { 1023 hdr, msg = c.msgParts(raw) 1024 var ci ClientInfo 1025 1026 if len(hdr) > 0 { 1027 if err := json.Unmarshal(getHeader(ClientInfoHdr, hdr), &ci); err != nil { 1028 return nil, nil, nil, nil, err 1029 } 1030 } 1031 1032 if ci.Service != _EMPTY_ { 1033 acc, _ = s.LookupAccount(ci.Service) 1034 } else if ci.Account != _EMPTY_ { 1035 acc, _ = s.LookupAccount(ci.Account) 1036 } else { 1037 // Direct $SYS access. 1038 acc = c.acc 1039 if acc == nil { 1040 acc = s.SystemAccount() 1041 } 1042 } 1043 if acc == nil { 1044 return nil, nil, nil, nil, ErrMissingAccount 1045 } 1046 return &ci, acc, hdr, msg, nil 1047 } 1048 1049 func (a *Account) trackAPI() { 1050 a.mu.RLock() 1051 jsa := a.js 1052 a.mu.RUnlock() 1053 if jsa != nil { 1054 jsa.usageMu.Lock() 1055 jsa.usageApi++ 1056 jsa.apiTotal++ 1057 jsa.sendClusterUsageUpdate() 1058 atomic.AddInt64(&jsa.js.apiTotal, 1) 1059 jsa.usageMu.Unlock() 1060 } 1061 } 1062 1063 func (a *Account) trackAPIErr() { 1064 a.mu.RLock() 1065 jsa := a.js 1066 a.mu.RUnlock() 1067 if jsa != nil { 1068 jsa.usageMu.Lock() 1069 jsa.usageApi++ 1070 jsa.apiTotal++ 1071 jsa.usageErr++ 1072 jsa.apiErrors++ 1073 jsa.sendClusterUsageUpdate() 1074 atomic.AddInt64(&jsa.js.apiTotal, 1) 1075 atomic.AddInt64(&jsa.js.apiErrors, 1) 1076 jsa.usageMu.Unlock() 1077 } 1078 } 1079 1080 const badAPIRequestT = "Malformed JetStream API Request: %q" 1081 1082 // Helper function to check on JetStream being enabled but also on status of leafnodes 1083 // If the local account is not enabled but does have leafnode connectivity we will not 1084 // want to error immediately and let the other side decide. 1085 func (a *Account) checkJetStream() (enabled, shouldError bool) { 1086 a.mu.RLock() 1087 defer a.mu.RUnlock() 1088 return a.js != nil, a.nleafs+a.nrleafs == 0 1089 } 1090 1091 // Request for current usage and limits for this account. 1092 func (s *Server) jsAccountInfoRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 1093 if c == nil || !s.JetStreamEnabled() { 1094 return 1095 } 1096 1097 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 1098 if err != nil { 1099 s.Warnf(badAPIRequestT, msg) 1100 return 1101 } 1102 1103 var resp = JSApiAccountInfoResponse{ApiResponse: ApiResponse{Type: JSApiAccountInfoResponseType}} 1104 1105 // Determine if we should proceed here when we are in clustered mode. 1106 if s.JetStreamIsClustered() { 1107 js, cc := s.getJetStreamCluster() 1108 if js == nil || cc == nil { 1109 return 1110 } 1111 if js.isLeaderless() { 1112 resp.Error = NewJSClusterNotAvailError() 1113 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1114 return 1115 } 1116 // Make sure we are meta leader. 1117 if !s.JetStreamIsLeader() { 1118 return 1119 } 1120 } 1121 1122 if hasJS, doErr := acc.checkJetStream(); !hasJS { 1123 if !doErr { 1124 return 1125 } 1126 resp.Error = NewJSNotEnabledForAccountError() 1127 } else { 1128 stats := acc.JetStreamUsage() 1129 resp.JetStreamAccountStats = &stats 1130 } 1131 b, err := json.Marshal(resp) 1132 if err != nil { 1133 return 1134 } 1135 1136 s.sendAPIResponse(ci, acc, subject, reply, string(msg), string(b)) 1137 } 1138 1139 // Helpers for token extraction. 1140 func templateNameFromSubject(subject string) string { 1141 return tokenAt(subject, 6) 1142 } 1143 1144 func streamNameFromSubject(subject string) string { 1145 return tokenAt(subject, 5) 1146 } 1147 1148 func consumerNameFromSubject(subject string) string { 1149 return tokenAt(subject, 6) 1150 } 1151 1152 // Request to create a new template. 1153 func (s *Server) jsTemplateCreateRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 1154 if c == nil { 1155 return 1156 } 1157 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 1158 if err != nil { 1159 s.Warnf(badAPIRequestT, msg) 1160 return 1161 } 1162 1163 var resp = JSApiStreamTemplateCreateResponse{ApiResponse: ApiResponse{Type: JSApiStreamTemplateCreateResponseType}} 1164 if !acc.JetStreamEnabled() { 1165 resp.Error = NewJSNotEnabledForAccountError() 1166 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1167 return 1168 } 1169 1170 // Not supported for now. 1171 if s.JetStreamIsClustered() { 1172 resp.Error = NewJSClusterUnSupportFeatureError() 1173 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1174 return 1175 } 1176 1177 var cfg StreamTemplateConfig 1178 if err := json.Unmarshal(msg, &cfg); err != nil { 1179 resp.Error = NewJSInvalidJSONError() 1180 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1181 return 1182 } 1183 templateName := templateNameFromSubject(subject) 1184 if templateName != cfg.Name { 1185 resp.Error = NewJSTemplateNameNotMatchSubjectError() 1186 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1187 return 1188 } 1189 1190 t, err := acc.addStreamTemplate(&cfg) 1191 if err != nil { 1192 resp.Error = NewJSStreamTemplateCreateError(err, Unless(err)) 1193 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1194 return 1195 } 1196 t.mu.Lock() 1197 tcfg := t.StreamTemplateConfig.deepCopy() 1198 streams := t.streams 1199 if streams == nil { 1200 streams = []string{} 1201 } 1202 t.mu.Unlock() 1203 resp.StreamTemplateInfo = &StreamTemplateInfo{Config: tcfg, Streams: streams} 1204 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 1205 } 1206 1207 // Request for the list of all template names. 1208 func (s *Server) jsTemplateNamesRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 1209 if c == nil { 1210 return 1211 } 1212 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 1213 if err != nil { 1214 s.Warnf(badAPIRequestT, msg) 1215 return 1216 } 1217 1218 var resp = JSApiStreamTemplateNamesResponse{ApiResponse: ApiResponse{Type: JSApiStreamTemplateNamesResponseType}} 1219 if !acc.JetStreamEnabled() { 1220 resp.Error = NewJSNotEnabledForAccountError() 1221 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1222 return 1223 } 1224 1225 // Not supported for now. 1226 if s.JetStreamIsClustered() { 1227 resp.Error = NewJSClusterUnSupportFeatureError() 1228 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1229 return 1230 } 1231 1232 var offset int 1233 if !isEmptyRequest(msg) { 1234 var req JSApiStreamTemplatesRequest 1235 if err := json.Unmarshal(msg, &req); err != nil { 1236 resp.Error = NewJSInvalidJSONError() 1237 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1238 return 1239 } 1240 offset = req.Offset 1241 } 1242 1243 ts := acc.templates() 1244 sort.Slice(ts, func(i, j int) bool { 1245 return strings.Compare(ts[i].StreamTemplateConfig.Name, ts[j].StreamTemplateConfig.Name) < 0 1246 }) 1247 1248 tcnt := len(ts) 1249 if offset > tcnt { 1250 offset = tcnt 1251 } 1252 1253 for _, t := range ts[offset:] { 1254 t.mu.Lock() 1255 name := t.Name 1256 t.mu.Unlock() 1257 resp.Templates = append(resp.Templates, name) 1258 if len(resp.Templates) >= JSApiNamesLimit { 1259 break 1260 } 1261 } 1262 resp.Total = tcnt 1263 resp.Limit = JSApiNamesLimit 1264 resp.Offset = offset 1265 if resp.Templates == nil { 1266 resp.Templates = []string{} 1267 } 1268 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 1269 } 1270 1271 // Request for information about a stream template. 1272 func (s *Server) jsTemplateInfoRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 1273 if c == nil { 1274 return 1275 } 1276 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 1277 if err != nil { 1278 s.Warnf(badAPIRequestT, msg) 1279 return 1280 } 1281 1282 var resp = JSApiStreamTemplateInfoResponse{ApiResponse: ApiResponse{Type: JSApiStreamTemplateInfoResponseType}} 1283 if !acc.JetStreamEnabled() { 1284 resp.Error = NewJSNotEnabledForAccountError() 1285 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1286 return 1287 } 1288 if !isEmptyRequest(msg) { 1289 resp.Error = NewJSNotEmptyRequestError() 1290 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1291 return 1292 } 1293 name := templateNameFromSubject(subject) 1294 t, err := acc.lookupStreamTemplate(name) 1295 if err != nil { 1296 resp.Error = NewJSStreamTemplateNotFoundError() 1297 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1298 return 1299 } 1300 t.mu.Lock() 1301 cfg := t.StreamTemplateConfig.deepCopy() 1302 streams := t.streams 1303 if streams == nil { 1304 streams = []string{} 1305 } 1306 t.mu.Unlock() 1307 1308 resp.StreamTemplateInfo = &StreamTemplateInfo{Config: cfg, Streams: streams} 1309 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 1310 } 1311 1312 // Request to delete a stream template. 1313 func (s *Server) jsTemplateDeleteRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 1314 if c == nil { 1315 return 1316 } 1317 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 1318 if err != nil { 1319 s.Warnf(badAPIRequestT, msg) 1320 return 1321 } 1322 1323 var resp = JSApiStreamTemplateDeleteResponse{ApiResponse: ApiResponse{Type: JSApiStreamTemplateDeleteResponseType}} 1324 if !acc.JetStreamEnabled() { 1325 resp.Error = NewJSNotEnabledForAccountError() 1326 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1327 return 1328 } 1329 if !isEmptyRequest(msg) { 1330 resp.Error = NewJSNotEmptyRequestError() 1331 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1332 return 1333 } 1334 name := templateNameFromSubject(subject) 1335 err = acc.deleteStreamTemplate(name) 1336 if err != nil { 1337 resp.Error = NewJSStreamTemplateDeleteError(err, Unless(err)) 1338 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1339 return 1340 } 1341 resp.Success = true 1342 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 1343 } 1344 1345 func (s *Server) jsonResponse(v any) string { 1346 b, err := json.Marshal(v) 1347 if err != nil { 1348 s.Warnf("Problem marshaling JSON for JetStream API:", err) 1349 return "" 1350 } 1351 return string(b) 1352 } 1353 1354 // Read lock must be held 1355 func (jsa *jsAccount) tieredReservation(tier string, cfg *StreamConfig) int64 { 1356 reservation := int64(0) 1357 if tier == _EMPTY_ { 1358 for _, sa := range jsa.streams { 1359 if sa.cfg.MaxBytes > 0 { 1360 if sa.cfg.Storage == cfg.Storage && sa.cfg.Name != cfg.Name { 1361 reservation += (int64(sa.cfg.Replicas) * sa.cfg.MaxBytes) 1362 } 1363 } 1364 } 1365 } else { 1366 for _, sa := range jsa.streams { 1367 if sa.cfg.Replicas == cfg.Replicas { 1368 if sa.cfg.MaxBytes > 0 { 1369 if isSameTier(&sa.cfg, cfg) && sa.cfg.Name != cfg.Name { 1370 reservation += (int64(sa.cfg.Replicas) * sa.cfg.MaxBytes) 1371 } 1372 } 1373 } 1374 } 1375 } 1376 return reservation 1377 } 1378 1379 // Request to create a stream. 1380 func (s *Server) jsStreamCreateRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 1381 if c == nil || !s.JetStreamEnabled() { 1382 return 1383 } 1384 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 1385 if err != nil { 1386 s.Warnf(badAPIRequestT, msg) 1387 return 1388 } 1389 1390 var resp = JSApiStreamCreateResponse{ApiResponse: ApiResponse{Type: JSApiStreamCreateResponseType}} 1391 1392 // Determine if we should proceed here when we are in clustered mode. 1393 if s.JetStreamIsClustered() { 1394 js, cc := s.getJetStreamCluster() 1395 if js == nil || cc == nil { 1396 return 1397 } 1398 if js.isLeaderless() { 1399 resp.Error = NewJSClusterNotAvailError() 1400 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1401 return 1402 } 1403 // Make sure we are meta leader. 1404 if !s.JetStreamIsLeader() { 1405 return 1406 } 1407 } 1408 1409 if hasJS, doErr := acc.checkJetStream(); !hasJS { 1410 if doErr { 1411 resp.Error = NewJSNotEnabledForAccountError() 1412 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1413 } 1414 return 1415 } 1416 1417 var cfg StreamConfig 1418 if err := json.Unmarshal(msg, &cfg); err != nil { 1419 resp.Error = NewJSInvalidJSONError() 1420 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1421 return 1422 } 1423 1424 streamName := streamNameFromSubject(subject) 1425 if streamName != cfg.Name { 1426 resp.Error = NewJSStreamMismatchError() 1427 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1428 return 1429 } 1430 1431 // Check for path like separators in the name. 1432 if strings.ContainsAny(streamName, `\/`) { 1433 resp.Error = NewJSStreamNameContainsPathSeparatorsError() 1434 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1435 return 1436 } 1437 1438 // Can't create a stream with a sealed state. 1439 if cfg.Sealed { 1440 resp.Error = NewJSStreamInvalidConfigError(fmt.Errorf("stream configuration for create can not be sealed")) 1441 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1442 return 1443 } 1444 1445 // If we are told to do mirror direct but are not mirroring, error. 1446 if cfg.MirrorDirect && cfg.Mirror == nil { 1447 resp.Error = NewJSStreamInvalidConfigError(fmt.Errorf("stream has no mirror but does have mirror direct")) 1448 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1449 return 1450 } 1451 1452 // Hand off to cluster for processing. 1453 if s.JetStreamIsClustered() { 1454 s.jsClusteredStreamRequest(ci, acc, subject, reply, rmsg, &cfg) 1455 return 1456 } 1457 1458 if err := acc.jsNonClusteredStreamLimitsCheck(&cfg); err != nil { 1459 resp.Error = err 1460 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1461 return 1462 } 1463 1464 mset, err := acc.addStream(&cfg) 1465 if err != nil { 1466 if IsNatsErr(err, JSStreamStoreFailedF) { 1467 s.Warnf("Stream create failed for '%s > %s': %v", acc, streamName, err) 1468 err = errStreamStoreFailed 1469 } 1470 resp.Error = NewJSStreamCreateError(err, Unless(err)) 1471 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1472 return 1473 } 1474 resp.StreamInfo = &StreamInfo{ 1475 Created: mset.createdTime(), 1476 State: mset.state(), 1477 Config: mset.config(), 1478 TimeStamp: time.Now().UTC(), 1479 Mirror: mset.mirrorInfo(), 1480 Sources: mset.sourcesInfo(), 1481 } 1482 resp.DidCreate = true 1483 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 1484 } 1485 1486 // Request to update a stream. 1487 func (s *Server) jsStreamUpdateRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 1488 if c == nil || !s.JetStreamEnabled() { 1489 return 1490 } 1491 1492 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 1493 if err != nil { 1494 s.Warnf(badAPIRequestT, msg) 1495 return 1496 } 1497 1498 var resp = JSApiStreamUpdateResponse{ApiResponse: ApiResponse{Type: JSApiStreamUpdateResponseType}} 1499 1500 // Determine if we should proceed here when we are in clustered mode. 1501 if s.JetStreamIsClustered() { 1502 js, cc := s.getJetStreamCluster() 1503 if js == nil || cc == nil { 1504 return 1505 } 1506 if js.isLeaderless() { 1507 resp.Error = NewJSClusterNotAvailError() 1508 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1509 return 1510 } 1511 // Make sure we are meta leader. 1512 if !s.JetStreamIsLeader() { 1513 return 1514 } 1515 } 1516 1517 if hasJS, doErr := acc.checkJetStream(); !hasJS { 1518 if doErr { 1519 resp.Error = NewJSNotEnabledForAccountError() 1520 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1521 } 1522 return 1523 } 1524 var ncfg StreamConfig 1525 if err := json.Unmarshal(msg, &ncfg); err != nil { 1526 resp.Error = NewJSInvalidJSONError() 1527 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1528 return 1529 } 1530 1531 cfg, apiErr := s.checkStreamCfg(&ncfg, acc) 1532 if apiErr != nil { 1533 resp.Error = apiErr 1534 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1535 return 1536 } 1537 1538 streamName := streamNameFromSubject(subject) 1539 if streamName != cfg.Name { 1540 resp.Error = NewJSStreamMismatchError() 1541 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1542 return 1543 } 1544 1545 // Handle clustered version here. 1546 if s.JetStreamIsClustered() { 1547 // Always do in separate Go routine. 1548 go s.jsClusteredStreamUpdateRequest(ci, acc, subject, reply, copyBytes(rmsg), &cfg, nil) 1549 return 1550 } 1551 1552 mset, err := acc.lookupStream(streamName) 1553 if err != nil { 1554 resp.Error = NewJSStreamNotFoundError(Unless(err)) 1555 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1556 return 1557 } 1558 1559 if err := mset.update(&cfg); err != nil { 1560 resp.Error = NewJSStreamUpdateError(err, Unless(err)) 1561 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1562 return 1563 } 1564 1565 resp.StreamInfo = &StreamInfo{ 1566 Created: mset.createdTime(), 1567 State: mset.state(), 1568 Config: mset.config(), 1569 Domain: s.getOpts().JetStreamDomain, 1570 Mirror: mset.mirrorInfo(), 1571 Sources: mset.sourcesInfo(), 1572 TimeStamp: time.Now().UTC(), 1573 } 1574 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 1575 } 1576 1577 // Request for the list of all stream names. 1578 func (s *Server) jsStreamNamesRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 1579 if c == nil || !s.JetStreamEnabled() { 1580 return 1581 } 1582 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 1583 if err != nil { 1584 s.Warnf(badAPIRequestT, msg) 1585 return 1586 } 1587 1588 var resp = JSApiStreamNamesResponse{ApiResponse: ApiResponse{Type: JSApiStreamNamesResponseType}} 1589 1590 // Determine if we should proceed here when we are in clustered mode. 1591 if s.JetStreamIsClustered() { 1592 js, cc := s.getJetStreamCluster() 1593 if js == nil || cc == nil { 1594 return 1595 } 1596 if js.isLeaderless() { 1597 resp.Error = NewJSClusterNotAvailError() 1598 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1599 return 1600 } 1601 // Make sure we are meta leader. 1602 if !s.JetStreamIsLeader() { 1603 return 1604 } 1605 } 1606 1607 if hasJS, doErr := acc.checkJetStream(); !hasJS { 1608 if doErr { 1609 resp.Error = NewJSNotEnabledForAccountError() 1610 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1611 } 1612 return 1613 } 1614 1615 var offset int 1616 var filter string 1617 1618 if !isEmptyRequest(msg) { 1619 var req JSApiStreamNamesRequest 1620 if err := json.Unmarshal(msg, &req); err != nil { 1621 resp.Error = NewJSInvalidJSONError() 1622 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1623 return 1624 } 1625 offset = req.Offset 1626 if req.Subject != _EMPTY_ { 1627 filter = req.Subject 1628 } 1629 } 1630 1631 // TODO(dlc) - Maybe hold these results for large results that we expect to be paged. 1632 // TODO(dlc) - If this list is long maybe do this in a Go routine? 1633 var numStreams int 1634 if s.JetStreamIsClustered() { 1635 js, cc := s.getJetStreamCluster() 1636 if js == nil || cc == nil { 1637 // TODO(dlc) - Debug or Warn? 1638 return 1639 } 1640 js.mu.RLock() 1641 for stream, sa := range cc.streams[acc.Name] { 1642 if IsNatsErr(sa.err, JSClusterNotAssignedErr) { 1643 continue 1644 } 1645 if filter != _EMPTY_ { 1646 // These could not have subjects auto-filled in since they are raw and unprocessed. 1647 if len(sa.Config.Subjects) == 0 { 1648 if SubjectsCollide(filter, sa.Config.Name) { 1649 resp.Streams = append(resp.Streams, stream) 1650 } 1651 } else { 1652 for _, subj := range sa.Config.Subjects { 1653 if SubjectsCollide(filter, subj) { 1654 resp.Streams = append(resp.Streams, stream) 1655 break 1656 } 1657 } 1658 } 1659 } else { 1660 resp.Streams = append(resp.Streams, stream) 1661 } 1662 } 1663 js.mu.RUnlock() 1664 if len(resp.Streams) > 1 { 1665 sort.Slice(resp.Streams, func(i, j int) bool { return strings.Compare(resp.Streams[i], resp.Streams[j]) < 0 }) 1666 } 1667 numStreams = len(resp.Streams) 1668 if offset > numStreams { 1669 offset = numStreams 1670 } 1671 if offset > 0 { 1672 resp.Streams = resp.Streams[offset:] 1673 } 1674 if len(resp.Streams) > JSApiNamesLimit { 1675 resp.Streams = resp.Streams[:JSApiNamesLimit] 1676 } 1677 } else { 1678 msets := acc.filteredStreams(filter) 1679 // Since we page results order matters. 1680 if len(msets) > 1 { 1681 sort.Slice(msets, func(i, j int) bool { 1682 return strings.Compare(msets[i].cfg.Name, msets[j].cfg.Name) < 0 1683 }) 1684 } 1685 1686 numStreams = len(msets) 1687 if offset > numStreams { 1688 offset = numStreams 1689 } 1690 1691 for _, mset := range msets[offset:] { 1692 resp.Streams = append(resp.Streams, mset.cfg.Name) 1693 if len(resp.Streams) >= JSApiNamesLimit { 1694 break 1695 } 1696 } 1697 } 1698 resp.Total = numStreams 1699 resp.Limit = JSApiNamesLimit 1700 resp.Offset = offset 1701 1702 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 1703 } 1704 1705 // Request for the list of all detailed stream info. 1706 // TODO(dlc) - combine with above long term 1707 func (s *Server) jsStreamListRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 1708 if c == nil || !s.JetStreamEnabled() { 1709 return 1710 } 1711 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 1712 if err != nil { 1713 s.Warnf(badAPIRequestT, msg) 1714 return 1715 } 1716 1717 var resp = JSApiStreamListResponse{ 1718 ApiResponse: ApiResponse{Type: JSApiStreamListResponseType}, 1719 Streams: []*StreamInfo{}, 1720 } 1721 1722 // Determine if we should proceed here when we are in clustered mode. 1723 if s.JetStreamIsClustered() { 1724 js, cc := s.getJetStreamCluster() 1725 if js == nil || cc == nil { 1726 return 1727 } 1728 if js.isLeaderless() { 1729 resp.Error = NewJSClusterNotAvailError() 1730 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1731 return 1732 } 1733 // Make sure we are meta leader. 1734 if !s.JetStreamIsLeader() { 1735 return 1736 } 1737 } 1738 1739 if hasJS, doErr := acc.checkJetStream(); !hasJS { 1740 if doErr { 1741 resp.Error = NewJSNotEnabledForAccountError() 1742 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1743 } 1744 return 1745 } 1746 1747 var offset int 1748 var filter string 1749 1750 if !isEmptyRequest(msg) { 1751 var req JSApiStreamListRequest 1752 if err := json.Unmarshal(msg, &req); err != nil { 1753 resp.Error = NewJSInvalidJSONError() 1754 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1755 return 1756 } 1757 offset = req.Offset 1758 if req.Subject != _EMPTY_ { 1759 filter = req.Subject 1760 } 1761 } 1762 1763 // Clustered mode will invoke a scatter and gather. 1764 if s.JetStreamIsClustered() { 1765 // Need to copy these off before sending.. don't move this inside startGoRoutine!!! 1766 msg = copyBytes(msg) 1767 s.startGoRoutine(func() { s.jsClusteredStreamListRequest(acc, ci, filter, offset, subject, reply, msg) }) 1768 return 1769 } 1770 1771 // TODO(dlc) - Maybe hold these results for large results that we expect to be paged. 1772 // TODO(dlc) - If this list is long maybe do this in a Go routine? 1773 var msets []*stream 1774 if filter == _EMPTY_ { 1775 msets = acc.streams() 1776 } else { 1777 msets = acc.filteredStreams(filter) 1778 } 1779 1780 sort.Slice(msets, func(i, j int) bool { 1781 return strings.Compare(msets[i].cfg.Name, msets[j].cfg.Name) < 0 1782 }) 1783 1784 scnt := len(msets) 1785 if offset > scnt { 1786 offset = scnt 1787 } 1788 1789 for _, mset := range msets[offset:] { 1790 config := mset.config() 1791 resp.Streams = append(resp.Streams, &StreamInfo{ 1792 Created: mset.createdTime(), 1793 State: mset.state(), 1794 Config: config, 1795 Domain: s.getOpts().JetStreamDomain, 1796 Mirror: mset.mirrorInfo(), 1797 Sources: mset.sourcesInfo(), 1798 TimeStamp: time.Now().UTC(), 1799 }) 1800 if len(resp.Streams) >= JSApiListLimit { 1801 break 1802 } 1803 } 1804 resp.Total = scnt 1805 resp.Limit = JSApiListLimit 1806 resp.Offset = offset 1807 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 1808 } 1809 1810 // Request for information about a stream. 1811 func (s *Server) jsStreamInfoRequest(sub *subscription, c *client, a *Account, subject, reply string, rmsg []byte) { 1812 if c == nil || !s.JetStreamEnabled() { 1813 return 1814 } 1815 ci, acc, hdr, msg, err := s.getRequestInfo(c, rmsg) 1816 if err != nil { 1817 s.Warnf(badAPIRequestT, msg) 1818 return 1819 } 1820 1821 streamName := streamNameFromSubject(subject) 1822 1823 var resp = JSApiStreamInfoResponse{ApiResponse: ApiResponse{Type: JSApiStreamInfoResponseType}} 1824 1825 // If someone creates a duplicate stream that is identical we will get this request forwarded to us. 1826 // Make sure the response type is for a create call. 1827 if rt := getHeader(JSResponseType, hdr); len(rt) > 0 && string(rt) == jsCreateResponse { 1828 resp.ApiResponse.Type = JSApiStreamCreateResponseType 1829 } 1830 1831 var clusterWideConsCount int 1832 1833 js, cc := s.getJetStreamCluster() 1834 if js == nil { 1835 return 1836 } 1837 // If we are in clustered mode we need to be the stream leader to proceed. 1838 if cc != nil { 1839 // Check to make sure the stream is assigned. 1840 js.mu.RLock() 1841 isLeader, sa := cc.isLeader(), js.streamAssignment(acc.Name, streamName) 1842 var offline bool 1843 if sa != nil { 1844 clusterWideConsCount = len(sa.consumers) 1845 offline = s.allPeersOffline(sa.Group) 1846 } 1847 js.mu.RUnlock() 1848 1849 if isLeader && sa == nil { 1850 // We can't find the stream, so mimic what would be the errors below. 1851 if hasJS, doErr := acc.checkJetStream(); !hasJS { 1852 if doErr { 1853 resp.Error = NewJSNotEnabledForAccountError() 1854 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1855 } 1856 return 1857 } 1858 // No stream present. 1859 resp.Error = NewJSStreamNotFoundError() 1860 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1861 return 1862 } else if sa == nil { 1863 if js.isLeaderless() { 1864 resp.Error = NewJSClusterNotAvailError() 1865 // Delaying an error response gives the leader a chance to respond before us 1866 s.sendDelayedAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp), nil) 1867 } 1868 return 1869 } else if isLeader && offline { 1870 resp.Error = NewJSStreamOfflineError() 1871 s.sendDelayedAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp), nil) 1872 return 1873 } 1874 1875 // Check to see if we are a member of the group and if the group has no leader. 1876 isLeaderless := js.isGroupLeaderless(sa.Group) 1877 1878 // We have the stream assigned and a leader, so only the stream leader should answer. 1879 if !acc.JetStreamIsStreamLeader(streamName) && !isLeaderless { 1880 if js.isLeaderless() { 1881 resp.Error = NewJSClusterNotAvailError() 1882 // Delaying an error response gives the leader a chance to respond before us 1883 s.sendDelayedAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp), sa.Group) 1884 return 1885 } 1886 1887 // We may be in process of electing a leader, but if this is a scale up from 1 we will still be the state leader 1888 // while the new members work through the election and catchup process. 1889 // Double check for that instead of exiting here and being silent. e.g. nats stream update test --replicas=3 1890 js.mu.RLock() 1891 rg := sa.Group 1892 var ourID string 1893 if cc.meta != nil { 1894 ourID = cc.meta.ID() 1895 } 1896 // We have seen cases where rg or rg.node is nil at this point, 1897 // so check explicitly on those conditions and bail if that is 1898 // the case. 1899 bail := rg == nil || rg.node == nil || !rg.isMember(ourID) 1900 if !bail { 1901 // We know we are a member here, if this group is new and we are preferred allow us to answer. 1902 bail = rg.Preferred != ourID || time.Since(rg.node.Created()) > lostQuorumIntervalDefault 1903 } 1904 js.mu.RUnlock() 1905 if bail { 1906 return 1907 } 1908 } 1909 } 1910 1911 if hasJS, doErr := acc.checkJetStream(); !hasJS { 1912 if doErr { 1913 resp.Error = NewJSNotEnabledForAccountError() 1914 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1915 } 1916 return 1917 } 1918 1919 var details bool 1920 var subjects string 1921 var offset int 1922 if !isEmptyRequest(msg) { 1923 var req JSApiStreamInfoRequest 1924 if err := json.Unmarshal(msg, &req); err != nil { 1925 resp.Error = NewJSInvalidJSONError() 1926 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1927 return 1928 } 1929 details, subjects = req.DeletedDetails, req.SubjectsFilter 1930 offset = req.Offset 1931 } 1932 1933 mset, err := acc.lookupStream(streamName) 1934 // Error is not to be expected at this point, but could happen if same stream trying to be created. 1935 if err != nil { 1936 if cc != nil { 1937 // This could be inflight, pause for a short bit and try again. 1938 // This will not be inline, so ok. 1939 time.Sleep(10 * time.Millisecond) 1940 mset, err = acc.lookupStream(streamName) 1941 } 1942 // Check again. 1943 if err != nil { 1944 resp.Error = NewJSStreamNotFoundError(Unless(err)) 1945 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 1946 return 1947 } 1948 } 1949 1950 config := mset.config() 1951 1952 resp.StreamInfo = &StreamInfo{ 1953 Created: mset.createdTime(), 1954 State: mset.stateWithDetail(details), 1955 Config: config, 1956 Domain: s.getOpts().JetStreamDomain, 1957 Cluster: js.clusterInfo(mset.raftGroup()), 1958 Mirror: mset.mirrorInfo(), 1959 Sources: mset.sourcesInfo(), 1960 Alternates: js.streamAlternates(ci, config.Name), 1961 TimeStamp: time.Now().UTC(), 1962 } 1963 if clusterWideConsCount > 0 { 1964 resp.StreamInfo.State.Consumers = clusterWideConsCount 1965 } 1966 1967 // Check if they have asked for subject details. 1968 if subjects != _EMPTY_ { 1969 st := mset.store.SubjectsTotals(subjects) 1970 if lst := len(st); lst > 0 { 1971 // Common for both cases. 1972 resp.Offset = offset 1973 resp.Limit = JSMaxSubjectDetails 1974 resp.Total = lst 1975 1976 if offset == 0 && lst <= JSMaxSubjectDetails { 1977 resp.StreamInfo.State.Subjects = st 1978 } else { 1979 // Here we have to filter list due to offset or maximum constraints. 1980 subjs := make([]string, 0, len(st)) 1981 for subj := range st { 1982 subjs = append(subjs, subj) 1983 } 1984 // Sort it 1985 sort.Strings(subjs) 1986 1987 if offset > len(subjs) { 1988 offset = len(subjs) 1989 } 1990 1991 end := offset + JSMaxSubjectDetails 1992 if end > len(subjs) { 1993 end = len(subjs) 1994 } 1995 actualSize := end - offset 1996 var sd map[string]uint64 1997 1998 if actualSize > 0 { 1999 sd = make(map[string]uint64, actualSize) 2000 for _, ss := range subjs[offset:end] { 2001 sd[ss] = st[ss] 2002 } 2003 } 2004 resp.StreamInfo.State.Subjects = sd 2005 } 2006 } 2007 } 2008 // Check for out of band catchups. 2009 if mset.hasCatchupPeers() { 2010 mset.checkClusterInfo(resp.StreamInfo.Cluster) 2011 } 2012 2013 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 2014 } 2015 2016 // Request to have a stream leader stepdown. 2017 func (s *Server) jsStreamLeaderStepDownRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 2018 if c == nil || !s.JetStreamEnabled() { 2019 return 2020 } 2021 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 2022 if err != nil { 2023 s.Warnf(badAPIRequestT, msg) 2024 return 2025 } 2026 2027 // Have extra token for this one. 2028 name := tokenAt(subject, 6) 2029 2030 var resp = JSApiStreamLeaderStepDownResponse{ApiResponse: ApiResponse{Type: JSApiStreamLeaderStepDownResponseType}} 2031 2032 // If we are not in clustered mode this is a failed request. 2033 if !s.JetStreamIsClustered() { 2034 resp.Error = NewJSClusterRequiredError() 2035 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2036 return 2037 } 2038 2039 // If we are here we are clustered. See if we are the stream leader in order to proceed. 2040 js, cc := s.getJetStreamCluster() 2041 if js == nil || cc == nil { 2042 return 2043 } 2044 if js.isLeaderless() { 2045 resp.Error = NewJSClusterNotAvailError() 2046 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2047 return 2048 } 2049 2050 js.mu.RLock() 2051 isLeader, sa := cc.isLeader(), js.streamAssignment(acc.Name, name) 2052 js.mu.RUnlock() 2053 2054 if isLeader && sa == nil { 2055 resp.Error = NewJSStreamNotFoundError() 2056 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2057 return 2058 } else if sa == nil { 2059 return 2060 } 2061 2062 if hasJS, doErr := acc.checkJetStream(); !hasJS { 2063 if doErr { 2064 resp.Error = NewJSNotEnabledForAccountError() 2065 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2066 } 2067 return 2068 } 2069 if !isEmptyRequest(msg) { 2070 resp.Error = NewJSBadRequestError() 2071 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2072 return 2073 } 2074 2075 // Check to see if we are a member of the group and if the group has no leader. 2076 if js.isGroupLeaderless(sa.Group) { 2077 resp.Error = NewJSClusterNotAvailError() 2078 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2079 return 2080 } 2081 2082 // We have the stream assigned and a leader, so only the stream leader should answer. 2083 if !acc.JetStreamIsStreamLeader(name) { 2084 return 2085 } 2086 2087 mset, err := acc.lookupStream(name) 2088 if err != nil { 2089 resp.Error = NewJSStreamNotFoundError(Unless(err)) 2090 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2091 return 2092 } 2093 2094 if mset == nil { 2095 resp.Success = true 2096 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 2097 return 2098 } 2099 2100 // Call actual stepdown. Do this in a Go routine. 2101 go func() { 2102 if node := mset.raftNode(); node != nil { 2103 mset.setLeader(false) 2104 // TODO (mh) eventually make sure all go routines exited and all channels are cleared 2105 time.Sleep(250 * time.Millisecond) 2106 node.StepDown() 2107 } 2108 2109 resp.Success = true 2110 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 2111 }() 2112 } 2113 2114 // Request to have a consumer leader stepdown. 2115 func (s *Server) jsConsumerLeaderStepDownRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 2116 if c == nil || !s.JetStreamEnabled() { 2117 return 2118 } 2119 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 2120 if err != nil { 2121 s.Warnf(badAPIRequestT, msg) 2122 return 2123 } 2124 2125 var resp = JSApiConsumerLeaderStepDownResponse{ApiResponse: ApiResponse{Type: JSApiConsumerLeaderStepDownResponseType}} 2126 2127 // If we are not in clustered mode this is a failed request. 2128 if !s.JetStreamIsClustered() { 2129 resp.Error = NewJSClusterRequiredError() 2130 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2131 return 2132 } 2133 2134 // If we are here we are clustered. See if we are the stream leader in order to proceed. 2135 js, cc := s.getJetStreamCluster() 2136 if js == nil || cc == nil { 2137 return 2138 } 2139 if js.isLeaderless() { 2140 resp.Error = NewJSClusterNotAvailError() 2141 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2142 return 2143 } 2144 2145 // Have extra token for this one. 2146 stream := tokenAt(subject, 6) 2147 consumer := tokenAt(subject, 7) 2148 2149 js.mu.RLock() 2150 isLeader, sa := cc.isLeader(), js.streamAssignment(acc.Name, stream) 2151 js.mu.RUnlock() 2152 2153 if isLeader && sa == nil { 2154 resp.Error = NewJSStreamNotFoundError() 2155 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2156 return 2157 } else if sa == nil { 2158 return 2159 } 2160 var ca *consumerAssignment 2161 if sa.consumers != nil { 2162 ca = sa.consumers[consumer] 2163 } 2164 if ca == nil { 2165 resp.Error = NewJSConsumerNotFoundError() 2166 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2167 return 2168 } 2169 // Check to see if we are a member of the group and if the group has no leader. 2170 if js.isGroupLeaderless(ca.Group) { 2171 resp.Error = NewJSClusterNotAvailError() 2172 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2173 return 2174 } 2175 2176 if !acc.JetStreamIsConsumerLeader(stream, consumer) { 2177 return 2178 } 2179 2180 if hasJS, doErr := acc.checkJetStream(); !hasJS { 2181 if doErr { 2182 resp.Error = NewJSNotEnabledForAccountError() 2183 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2184 } 2185 return 2186 } 2187 if !isEmptyRequest(msg) { 2188 resp.Error = NewJSBadRequestError() 2189 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2190 return 2191 } 2192 2193 mset, err := acc.lookupStream(stream) 2194 if err != nil { 2195 resp.Error = NewJSStreamNotFoundError() 2196 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2197 return 2198 } 2199 o := mset.lookupConsumer(consumer) 2200 if o == nil { 2201 resp.Error = NewJSConsumerNotFoundError() 2202 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2203 return 2204 } 2205 2206 n := o.raftNode() 2207 if n == nil { 2208 resp.Success = true 2209 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 2210 return 2211 } 2212 2213 // Call actual stepdown. Do this in a Go routine. 2214 go func() { 2215 o.setLeader(false) 2216 // TODO (mh) eventually make sure all go routines exited and all channels are cleared 2217 time.Sleep(250 * time.Millisecond) 2218 n.StepDown() 2219 2220 resp.Success = true 2221 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 2222 }() 2223 } 2224 2225 // Request to remove a peer from a clustered stream. 2226 func (s *Server) jsStreamRemovePeerRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 2227 if c == nil || !s.JetStreamEnabled() { 2228 return 2229 } 2230 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 2231 if err != nil { 2232 s.Warnf(badAPIRequestT, msg) 2233 return 2234 } 2235 2236 // Have extra token for this one. 2237 name := tokenAt(subject, 6) 2238 2239 var resp = JSApiStreamRemovePeerResponse{ApiResponse: ApiResponse{Type: JSApiStreamRemovePeerResponseType}} 2240 2241 // If we are not in clustered mode this is a failed request. 2242 if !s.JetStreamIsClustered() { 2243 resp.Error = NewJSClusterRequiredError() 2244 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2245 return 2246 } 2247 2248 // If we are here we are clustered. See if we are the stream leader in order to proceed. 2249 js, cc := s.getJetStreamCluster() 2250 if js == nil || cc == nil { 2251 return 2252 } 2253 if js.isLeaderless() { 2254 resp.Error = NewJSClusterNotAvailError() 2255 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2256 return 2257 } 2258 2259 js.mu.RLock() 2260 isLeader, sa := cc.isLeader(), js.streamAssignment(acc.Name, name) 2261 js.mu.RUnlock() 2262 2263 // Make sure we are meta leader. 2264 if !isLeader { 2265 return 2266 } 2267 2268 if hasJS, doErr := acc.checkJetStream(); !hasJS { 2269 if doErr { 2270 resp.Error = NewJSNotEnabledForAccountError() 2271 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2272 } 2273 return 2274 } 2275 if isEmptyRequest(msg) { 2276 resp.Error = NewJSBadRequestError() 2277 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2278 return 2279 } 2280 2281 var req JSApiStreamRemovePeerRequest 2282 if err := json.Unmarshal(msg, &req); err != nil { 2283 resp.Error = NewJSInvalidJSONError() 2284 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2285 return 2286 } 2287 if req.Peer == _EMPTY_ { 2288 resp.Error = NewJSBadRequestError() 2289 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2290 return 2291 } 2292 2293 if sa == nil { 2294 // No stream present. 2295 resp.Error = NewJSStreamNotFoundError() 2296 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2297 return 2298 } 2299 2300 // Check to see if we are a member of the group and if the group has no leader. 2301 // Peers here is a server name, convert to node name. 2302 nodeName := getHash(req.Peer) 2303 2304 js.mu.RLock() 2305 rg := sa.Group 2306 isMember := rg.isMember(nodeName) 2307 js.mu.RUnlock() 2308 2309 // Make sure we are a member. 2310 if !isMember { 2311 resp.Error = NewJSClusterPeerNotMemberError() 2312 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2313 return 2314 } 2315 2316 // If we are here we have a valid peer member set for removal. 2317 if !js.removePeerFromStream(sa, nodeName) { 2318 resp.Error = NewJSPeerRemapError() 2319 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2320 return 2321 } 2322 2323 resp.Success = true 2324 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 2325 } 2326 2327 // Request to have the metaleader remove a peer from the system. 2328 func (s *Server) jsLeaderServerRemoveRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 2329 if c == nil || !s.JetStreamEnabled() { 2330 return 2331 } 2332 2333 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 2334 if err != nil { 2335 s.Warnf(badAPIRequestT, msg) 2336 return 2337 } 2338 2339 js, cc := s.getJetStreamCluster() 2340 if js == nil || cc == nil || cc.meta == nil { 2341 return 2342 } 2343 2344 // Extra checks here but only leader is listening. 2345 js.mu.RLock() 2346 isLeader := cc.isLeader() 2347 js.mu.RUnlock() 2348 2349 if !isLeader { 2350 return 2351 } 2352 2353 var resp = JSApiMetaServerRemoveResponse{ApiResponse: ApiResponse{Type: JSApiMetaServerRemoveResponseType}} 2354 2355 if isEmptyRequest(msg) { 2356 resp.Error = NewJSBadRequestError() 2357 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2358 return 2359 } 2360 2361 var req JSApiMetaServerRemoveRequest 2362 if err := json.Unmarshal(msg, &req); err != nil { 2363 resp.Error = NewJSInvalidJSONError() 2364 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2365 return 2366 } 2367 2368 var found string 2369 js.mu.RLock() 2370 for _, p := range cc.meta.Peers() { 2371 // If Peer is specified, it takes precedence 2372 if req.Peer != _EMPTY_ { 2373 if p.ID == req.Peer { 2374 found = req.Peer 2375 break 2376 } 2377 continue 2378 } 2379 si, ok := s.nodeToInfo.Load(p.ID) 2380 if ok && si.(nodeInfo).name == req.Server { 2381 found = p.ID 2382 break 2383 } 2384 } 2385 js.mu.RUnlock() 2386 2387 if found == _EMPTY_ { 2388 resp.Error = NewJSClusterServerNotMemberError() 2389 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2390 return 2391 } 2392 2393 // So we have a valid peer. 2394 js.mu.Lock() 2395 cc.meta.ProposeRemovePeer(found) 2396 js.mu.Unlock() 2397 2398 resp.Success = true 2399 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2400 } 2401 2402 func (s *Server) peerSetToNames(ps []string) []string { 2403 names := make([]string, len(ps)) 2404 for i := 0; i < len(ps); i++ { 2405 if si, ok := s.nodeToInfo.Load(ps[i]); !ok { 2406 names[i] = ps[i] 2407 } else { 2408 names[i] = si.(nodeInfo).name 2409 } 2410 } 2411 return names 2412 } 2413 2414 // looks up the peer id for a given server name. Cluster and domain name are optional filter criteria 2415 func (s *Server) nameToPeer(js *jetStream, serverName, clusterName, domainName string) string { 2416 js.mu.RLock() 2417 defer js.mu.RUnlock() 2418 if cc := js.cluster; cc != nil { 2419 for _, p := range cc.meta.Peers() { 2420 si, ok := s.nodeToInfo.Load(p.ID) 2421 if ok && si.(nodeInfo).name == serverName { 2422 if clusterName == _EMPTY_ || clusterName == si.(nodeInfo).cluster { 2423 if domainName == _EMPTY_ || domainName == si.(nodeInfo).domain { 2424 return p.ID 2425 } 2426 } 2427 } 2428 } 2429 } 2430 return _EMPTY_ 2431 } 2432 2433 // Request to have the metaleader move a stream on a peer to another 2434 func (s *Server) jsLeaderServerStreamMoveRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 2435 if c == nil || !s.JetStreamEnabled() { 2436 return 2437 } 2438 2439 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 2440 if err != nil { 2441 s.Warnf(badAPIRequestT, msg) 2442 return 2443 } 2444 2445 js, cc := s.getJetStreamCluster() 2446 if js == nil || cc == nil || cc.meta == nil { 2447 return 2448 } 2449 2450 // Extra checks here but only leader is listening. 2451 js.mu.RLock() 2452 isLeader := cc.isLeader() 2453 js.mu.RUnlock() 2454 2455 if !isLeader { 2456 return 2457 } 2458 2459 accName := tokenAt(subject, 6) 2460 streamName := tokenAt(subject, 7) 2461 2462 var resp = JSApiStreamUpdateResponse{ApiResponse: ApiResponse{Type: JSApiStreamUpdateResponseType}} 2463 2464 var req JSApiMetaServerStreamMoveRequest 2465 if err := json.Unmarshal(msg, &req); err != nil { 2466 resp.Error = NewJSInvalidJSONError() 2467 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2468 return 2469 } 2470 2471 srcPeer := _EMPTY_ 2472 if req.Server != _EMPTY_ { 2473 srcPeer = s.nameToPeer(js, req.Server, req.Cluster, req.Domain) 2474 } 2475 2476 targetAcc, ok := s.accounts.Load(accName) 2477 if !ok { 2478 resp.Error = NewJSNoAccountError() 2479 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2480 return 2481 } 2482 2483 var streamFound bool 2484 cfg := StreamConfig{} 2485 currPeers := []string{} 2486 currCluster := _EMPTY_ 2487 js.mu.Lock() 2488 streams, ok := cc.streams[accName] 2489 if ok { 2490 sa, ok := streams[streamName] 2491 if ok { 2492 cfg = *sa.Config 2493 streamFound = true 2494 currPeers = sa.Group.Peers 2495 currCluster = sa.Group.Cluster 2496 } 2497 } 2498 js.mu.Unlock() 2499 2500 if !streamFound { 2501 resp.Error = NewJSStreamNotFoundError() 2502 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2503 return 2504 } 2505 2506 // if server was picked, make sure src peer exists and move it to first position. 2507 // removal will drop peers from the left 2508 if req.Server != _EMPTY_ { 2509 if srcPeer == _EMPTY_ { 2510 resp.Error = NewJSClusterServerNotMemberError() 2511 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2512 return 2513 } 2514 var peerFound bool 2515 for i := 0; i < len(currPeers); i++ { 2516 if currPeers[i] == srcPeer { 2517 copy(currPeers[1:], currPeers[:i]) 2518 currPeers[0] = srcPeer 2519 peerFound = true 2520 break 2521 } 2522 } 2523 if !peerFound { 2524 resp.Error = NewJSClusterPeerNotMemberError() 2525 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2526 return 2527 } 2528 } 2529 2530 // make sure client is scoped to requested account 2531 ciNew := *(ci) 2532 ciNew.Account = accName 2533 2534 // backup placement such that peers can be looked up with modified tag list 2535 var origPlacement *Placement 2536 if cfg.Placement != nil { 2537 tmp := *cfg.Placement 2538 origPlacement = &tmp 2539 } 2540 2541 if len(req.Tags) > 0 { 2542 if cfg.Placement == nil { 2543 cfg.Placement = &Placement{} 2544 } 2545 cfg.Placement.Tags = append(cfg.Placement.Tags, req.Tags...) 2546 } 2547 2548 peers, e := cc.selectPeerGroup(cfg.Replicas+1, currCluster, &cfg, currPeers, 1, nil) 2549 if len(peers) <= cfg.Replicas { 2550 // since expanding in the same cluster did not yield a result, try in different cluster 2551 peers = nil 2552 2553 clusters := map[string]struct{}{} 2554 s.nodeToInfo.Range(func(_, ni any) bool { 2555 if currCluster != ni.(nodeInfo).cluster { 2556 clusters[ni.(nodeInfo).cluster] = struct{}{} 2557 } 2558 return true 2559 }) 2560 errs := &selectPeerError{} 2561 errs.accumulate(e) 2562 for cluster := range clusters { 2563 newPeers, e := cc.selectPeerGroup(cfg.Replicas, cluster, &cfg, nil, 0, nil) 2564 if len(newPeers) >= cfg.Replicas { 2565 peers = append([]string{}, currPeers...) 2566 peers = append(peers, newPeers[:cfg.Replicas]...) 2567 break 2568 } 2569 errs.accumulate(e) 2570 } 2571 if peers == nil { 2572 resp.Error = NewJSClusterNoPeersError(errs) 2573 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2574 return 2575 } 2576 } 2577 2578 cfg.Placement = origPlacement 2579 2580 s.Noticef("Requested move for stream '%s > %s' R=%d from %+v to %+v", 2581 streamName, accName, cfg.Replicas, s.peerSetToNames(currPeers), s.peerSetToNames(peers)) 2582 2583 // We will always have peers and therefore never do a callout, therefore it is safe to call inline 2584 s.jsClusteredStreamUpdateRequest(&ciNew, targetAcc.(*Account), subject, reply, rmsg, &cfg, peers) 2585 } 2586 2587 // Request to have the metaleader move a stream on a peer to another 2588 func (s *Server) jsLeaderServerStreamCancelMoveRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 2589 if c == nil || !s.JetStreamEnabled() { 2590 return 2591 } 2592 2593 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 2594 if err != nil { 2595 s.Warnf(badAPIRequestT, msg) 2596 return 2597 } 2598 2599 js, cc := s.getJetStreamCluster() 2600 if js == nil || cc == nil || cc.meta == nil { 2601 return 2602 } 2603 2604 // Extra checks here but only leader is listening. 2605 js.mu.RLock() 2606 isLeader := cc.isLeader() 2607 js.mu.RUnlock() 2608 2609 if !isLeader { 2610 return 2611 } 2612 2613 var resp = JSApiStreamUpdateResponse{ApiResponse: ApiResponse{Type: JSApiStreamUpdateResponseType}} 2614 2615 accName := tokenAt(subject, 6) 2616 streamName := tokenAt(subject, 7) 2617 2618 targetAcc, ok := s.accounts.Load(accName) 2619 if !ok { 2620 resp.Error = NewJSNoAccountError() 2621 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2622 return 2623 } 2624 2625 streamFound := false 2626 cfg := StreamConfig{} 2627 currPeers := []string{} 2628 js.mu.Lock() 2629 streams, ok := cc.streams[accName] 2630 if ok { 2631 sa, ok := streams[streamName] 2632 if ok { 2633 cfg = *sa.Config 2634 streamFound = true 2635 currPeers = sa.Group.Peers 2636 } 2637 } 2638 js.mu.Unlock() 2639 2640 if !streamFound { 2641 resp.Error = NewJSStreamNotFoundError() 2642 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2643 return 2644 } 2645 2646 if len(currPeers) <= cfg.Replicas { 2647 resp.Error = NewJSStreamMoveNotInProgressError() 2648 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2649 return 2650 } 2651 2652 // make sure client is scoped to requested account 2653 ciNew := *(ci) 2654 ciNew.Account = accName 2655 2656 peers := currPeers[:cfg.Replicas] 2657 2658 // Remove placement in case tags don't match 2659 // This can happen if the move was initiated by modifying the tags. 2660 // This is an account operation. 2661 // This can NOT happen when the move was initiated by the system account. 2662 // There move honors the original tag list. 2663 if cfg.Placement != nil && len(cfg.Placement.Tags) != 0 { 2664 FOR_TAGCHECK: 2665 for _, peer := range peers { 2666 si, ok := s.nodeToInfo.Load(peer) 2667 if !ok { 2668 // can't verify tags, do the safe thing and error 2669 resp.Error = NewJSStreamGeneralError( 2670 fmt.Errorf("peer %s not present for tag validation", peer)) 2671 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2672 return 2673 } 2674 nodeTags := si.(nodeInfo).tags 2675 for _, tag := range cfg.Placement.Tags { 2676 if !nodeTags.Contains(tag) { 2677 // clear placement as tags don't match 2678 cfg.Placement = nil 2679 break FOR_TAGCHECK 2680 } 2681 } 2682 2683 } 2684 } 2685 2686 s.Noticef("Requested cancel of move: R=%d '%s > %s' to peer set %+v and restore previous peer set %+v", 2687 cfg.Replicas, streamName, accName, s.peerSetToNames(currPeers), s.peerSetToNames(peers)) 2688 2689 // We will always have peers and therefore never do a callout, therefore it is safe to call inline 2690 s.jsClusteredStreamUpdateRequest(&ciNew, targetAcc.(*Account), subject, reply, rmsg, &cfg, peers) 2691 } 2692 2693 // Request to have an account purged 2694 func (s *Server) jsLeaderAccountPurgeRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 2695 if c == nil || !s.JetStreamEnabled() { 2696 return 2697 } 2698 2699 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 2700 if err != nil { 2701 s.Warnf(badAPIRequestT, msg) 2702 return 2703 } 2704 2705 js := s.getJetStream() 2706 if js == nil { 2707 return 2708 } 2709 2710 accName := tokenAt(subject, 5) 2711 2712 var resp = JSApiAccountPurgeResponse{ApiResponse: ApiResponse{Type: JSApiAccountPurgeResponseType}} 2713 2714 if !s.JetStreamIsClustered() { 2715 var streams []*stream 2716 var ac *Account 2717 if ac, err = s.lookupAccount(accName); err == nil && ac != nil { 2718 streams = ac.streams() 2719 } 2720 2721 s.Noticef("Purge request for account %s (streams: %d, hasAccount: %t)", 2722 accName, len(streams), ac != nil) 2723 2724 for _, mset := range streams { 2725 err := mset.delete() 2726 if err != nil { 2727 resp.Error = NewJSStreamDeleteError(err) 2728 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2729 return 2730 } 2731 } 2732 if err := os.RemoveAll(filepath.Join(js.config.StoreDir, accName)); err != nil { 2733 resp.Error = NewJSStreamGeneralError(err) 2734 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2735 return 2736 } 2737 resp.Initiated = true 2738 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2739 return 2740 } 2741 2742 _, cc := s.getJetStreamCluster() 2743 if cc == nil || cc.meta == nil || !cc.isLeader() { 2744 return 2745 } 2746 2747 if js.isMetaRecovering() { 2748 // While in recovery mode, the data structures are not fully initialized 2749 resp.Error = NewJSClusterNotAvailError() 2750 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2751 return 2752 } 2753 2754 js.mu.RLock() 2755 ns, nc := 0, 0 2756 streams, hasAccount := cc.streams[accName] 2757 for _, osa := range streams { 2758 for _, oca := range osa.consumers { 2759 oca.deleted = true 2760 ca := &consumerAssignment{Group: oca.Group, Stream: oca.Stream, Name: oca.Name, Config: oca.Config, Subject: subject, Client: oca.Client} 2761 cc.meta.Propose(encodeDeleteConsumerAssignment(ca)) 2762 nc++ 2763 } 2764 sa := &streamAssignment{Group: osa.Group, Config: osa.Config, Subject: subject, Client: osa.Client} 2765 cc.meta.Propose(encodeDeleteStreamAssignment(sa)) 2766 ns++ 2767 } 2768 js.mu.RUnlock() 2769 2770 s.Noticef("Purge request for account %s (streams: %d, consumer: %d, hasAccount: %t)", accName, ns, nc, hasAccount) 2771 2772 resp.Initiated = true 2773 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2774 } 2775 2776 // Request to have the meta leader stepdown. 2777 // These will only be received by the meta leader, so less checking needed. 2778 func (s *Server) jsLeaderStepDownRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 2779 if c == nil || !s.JetStreamEnabled() { 2780 return 2781 } 2782 2783 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 2784 if err != nil { 2785 s.Warnf(badAPIRequestT, msg) 2786 return 2787 } 2788 2789 js, cc := s.getJetStreamCluster() 2790 if js == nil || cc == nil || cc.meta == nil { 2791 return 2792 } 2793 2794 // Extra checks here but only leader is listening. 2795 js.mu.RLock() 2796 isLeader := cc.isLeader() 2797 js.mu.RUnlock() 2798 2799 if !isLeader { 2800 return 2801 } 2802 2803 var preferredLeader string 2804 var resp = JSApiLeaderStepDownResponse{ApiResponse: ApiResponse{Type: JSApiLeaderStepDownResponseType}} 2805 2806 if !isEmptyRequest(msg) { 2807 var req JSApiLeaderStepdownRequest 2808 if err := json.Unmarshal(msg, &req); err != nil { 2809 resp.Error = NewJSInvalidJSONError() 2810 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2811 return 2812 } 2813 if len(req.Placement.Tags) > 0 { 2814 // Tags currently not supported. 2815 resp.Error = NewJSClusterTagsError() 2816 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2817 return 2818 } 2819 cn := req.Placement.Cluster 2820 var peers []string 2821 ourID := cc.meta.ID() 2822 for _, p := range cc.meta.Peers() { 2823 if si, ok := s.nodeToInfo.Load(p.ID); ok && si != nil { 2824 if ni := si.(nodeInfo); ni.offline || ni.cluster != cn || p.ID == ourID { 2825 continue 2826 } 2827 peers = append(peers, p.ID) 2828 } 2829 } 2830 if len(peers) == 0 { 2831 resp.Error = NewJSClusterNoPeersError(fmt.Errorf("no replacement peer connected")) 2832 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2833 return 2834 } 2835 // Randomize and select. 2836 if len(peers) > 1 { 2837 rand.Shuffle(len(peers), func(i, j int) { peers[i], peers[j] = peers[j], peers[i] }) 2838 } 2839 preferredLeader = peers[0] 2840 } 2841 2842 // Call actual stepdown. 2843 err = cc.meta.StepDown(preferredLeader) 2844 if err != nil { 2845 resp.Error = NewJSRaftGeneralError(err, Unless(err)) 2846 } else { 2847 resp.Success = true 2848 } 2849 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 2850 } 2851 2852 func isEmptyRequest(req []byte) bool { 2853 if len(req) == 0 { 2854 return true 2855 } 2856 if bytes.Equal(req, []byte("{}")) { 2857 return true 2858 } 2859 // If we are here we didn't get our simple match, but still could be valid. 2860 var v any 2861 if err := json.Unmarshal(req, &v); err != nil { 2862 return false 2863 } 2864 vm, ok := v.(map[string]any) 2865 if !ok { 2866 return false 2867 } 2868 return len(vm) == 0 2869 } 2870 2871 // Request to delete a stream. 2872 func (s *Server) jsStreamDeleteRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 2873 if c == nil || !s.JetStreamEnabled() { 2874 return 2875 } 2876 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 2877 if err != nil { 2878 s.Warnf(badAPIRequestT, msg) 2879 return 2880 } 2881 2882 var resp = JSApiStreamDeleteResponse{ApiResponse: ApiResponse{Type: JSApiStreamDeleteResponseType}} 2883 2884 // Determine if we should proceed here when we are in clustered mode. 2885 if s.JetStreamIsClustered() { 2886 js, cc := s.getJetStreamCluster() 2887 if js == nil || cc == nil { 2888 return 2889 } 2890 if js.isLeaderless() { 2891 resp.Error = NewJSClusterNotAvailError() 2892 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2893 return 2894 } 2895 // Make sure we are meta leader. 2896 if !s.JetStreamIsLeader() { 2897 return 2898 } 2899 } 2900 2901 if hasJS, doErr := acc.checkJetStream(); !hasJS { 2902 if doErr { 2903 resp.Error = NewJSNotEnabledForAccountError() 2904 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2905 } 2906 return 2907 } 2908 2909 if !isEmptyRequest(msg) { 2910 resp.Error = NewJSNotEmptyRequestError() 2911 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2912 return 2913 } 2914 stream := streamNameFromSubject(subject) 2915 2916 // Clustered. 2917 if s.JetStreamIsClustered() { 2918 s.jsClusteredStreamDeleteRequest(ci, acc, stream, subject, reply, msg) 2919 return 2920 } 2921 2922 mset, err := acc.lookupStream(stream) 2923 if err != nil { 2924 resp.Error = NewJSStreamNotFoundError(Unless(err)) 2925 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2926 return 2927 } 2928 2929 if err := mset.delete(); err != nil { 2930 resp.Error = NewJSStreamDeleteError(err, Unless(err)) 2931 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2932 return 2933 } 2934 resp.Success = true 2935 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 2936 } 2937 2938 // Request to delete a message. 2939 // This expects a stream sequence number as the msg body. 2940 func (s *Server) jsMsgDeleteRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 2941 if c == nil || !s.JetStreamEnabled() { 2942 return 2943 } 2944 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 2945 if err != nil { 2946 s.Warnf(badAPIRequestT, msg) 2947 return 2948 } 2949 2950 stream := tokenAt(subject, 6) 2951 2952 var resp = JSApiMsgDeleteResponse{ApiResponse: ApiResponse{Type: JSApiMsgDeleteResponseType}} 2953 2954 // If we are in clustered mode we need to be the stream leader to proceed. 2955 if s.JetStreamIsClustered() { 2956 // Check to make sure the stream is assigned. 2957 js, cc := s.getJetStreamCluster() 2958 if js == nil || cc == nil { 2959 return 2960 } 2961 if js.isLeaderless() { 2962 resp.Error = NewJSClusterNotAvailError() 2963 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2964 return 2965 } 2966 2967 js.mu.RLock() 2968 isLeader, sa := cc.isLeader(), js.streamAssignment(acc.Name, stream) 2969 js.mu.RUnlock() 2970 2971 if isLeader && sa == nil { 2972 // We can't find the stream, so mimic what would be the errors below. 2973 if hasJS, doErr := acc.checkJetStream(); !hasJS { 2974 if doErr { 2975 resp.Error = NewJSNotEnabledForAccountError() 2976 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2977 } 2978 return 2979 } 2980 // No stream present. 2981 resp.Error = NewJSStreamNotFoundError() 2982 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2983 return 2984 } else if sa == nil { 2985 return 2986 } 2987 2988 // Check to see if we are a member of the group and if the group has no leader. 2989 if js.isGroupLeaderless(sa.Group) { 2990 resp.Error = NewJSClusterNotAvailError() 2991 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 2992 return 2993 } 2994 2995 // We have the stream assigned and a leader, so only the stream leader should answer. 2996 if !acc.JetStreamIsStreamLeader(stream) { 2997 return 2998 } 2999 } 3000 3001 if hasJS, doErr := acc.checkJetStream(); !hasJS { 3002 if doErr { 3003 resp.Error = NewJSNotEnabledForAccountError() 3004 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3005 } 3006 return 3007 } 3008 if isEmptyRequest(msg) { 3009 resp.Error = NewJSBadRequestError() 3010 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3011 return 3012 } 3013 var req JSApiMsgDeleteRequest 3014 if err := json.Unmarshal(msg, &req); err != nil { 3015 resp.Error = NewJSInvalidJSONError() 3016 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3017 return 3018 } 3019 3020 mset, err := acc.lookupStream(stream) 3021 if err != nil { 3022 resp.Error = NewJSStreamNotFoundError(Unless(err)) 3023 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3024 return 3025 } 3026 if mset.cfg.Sealed { 3027 resp.Error = NewJSStreamSealedError() 3028 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3029 return 3030 } 3031 if mset.cfg.DenyDelete { 3032 resp.Error = NewJSStreamMsgDeleteFailedError(errors.New("message delete not permitted")) 3033 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3034 return 3035 } 3036 3037 if s.JetStreamIsClustered() { 3038 s.jsClusteredMsgDeleteRequest(ci, acc, mset, stream, subject, reply, &req, rmsg) 3039 return 3040 } 3041 3042 var removed bool 3043 if req.NoErase { 3044 removed, err = mset.removeMsg(req.Seq) 3045 } else { 3046 removed, err = mset.eraseMsg(req.Seq) 3047 } 3048 if err != nil { 3049 resp.Error = NewJSStreamMsgDeleteFailedError(err, Unless(err)) 3050 } else if !removed { 3051 resp.Error = NewJSSequenceNotFoundError(req.Seq) 3052 } else { 3053 resp.Success = true 3054 } 3055 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 3056 } 3057 3058 // Request to get a raw stream message. 3059 func (s *Server) jsMsgGetRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 3060 if c == nil || !s.JetStreamEnabled() { 3061 return 3062 } 3063 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 3064 if err != nil { 3065 s.Warnf(badAPIRequestT, msg) 3066 return 3067 } 3068 3069 stream := tokenAt(subject, 6) 3070 3071 var resp = JSApiMsgGetResponse{ApiResponse: ApiResponse{Type: JSApiMsgGetResponseType}} 3072 3073 // If we are in clustered mode we need to be the stream leader to proceed. 3074 if s.JetStreamIsClustered() { 3075 // Check to make sure the stream is assigned. 3076 js, cc := s.getJetStreamCluster() 3077 if js == nil || cc == nil { 3078 return 3079 } 3080 if js.isLeaderless() { 3081 resp.Error = NewJSClusterNotAvailError() 3082 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3083 return 3084 } 3085 3086 js.mu.RLock() 3087 isLeader, sa := cc.isLeader(), js.streamAssignment(acc.Name, stream) 3088 js.mu.RUnlock() 3089 3090 if isLeader && sa == nil { 3091 // We can't find the stream, so mimic what would be the errors below. 3092 if hasJS, doErr := acc.checkJetStream(); !hasJS { 3093 if doErr { 3094 resp.Error = NewJSNotEnabledForAccountError() 3095 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3096 } 3097 return 3098 } 3099 // No stream present. 3100 resp.Error = NewJSStreamNotFoundError() 3101 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3102 return 3103 } else if sa == nil { 3104 return 3105 } 3106 3107 // Check to see if we are a member of the group and if the group has no leader. 3108 if js.isGroupLeaderless(sa.Group) { 3109 resp.Error = NewJSClusterNotAvailError() 3110 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3111 return 3112 } 3113 3114 // We have the stream assigned and a leader, so only the stream leader should answer. 3115 if !acc.JetStreamIsStreamLeader(stream) { 3116 return 3117 } 3118 } 3119 3120 if hasJS, doErr := acc.checkJetStream(); !hasJS { 3121 if doErr { 3122 resp.Error = NewJSNotEnabledForAccountError() 3123 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3124 } 3125 return 3126 } 3127 if isEmptyRequest(msg) { 3128 resp.Error = NewJSBadRequestError() 3129 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3130 return 3131 } 3132 var req JSApiMsgGetRequest 3133 if err := json.Unmarshal(msg, &req); err != nil { 3134 resp.Error = NewJSInvalidJSONError() 3135 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3136 return 3137 } 3138 3139 // This version does not support batch. 3140 if req.Batch > 0 || req.MaxBytes > 0 { 3141 resp.Error = NewJSBadRequestError() 3142 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3143 return 3144 } 3145 3146 // Validate non-conflicting options. Seq, LastFor, and AsOfTime are mutually exclusive. 3147 // NextFor can be paired with Seq or AsOfTime indicating a filter subject. 3148 if (req.Seq > 0 && req.LastFor != _EMPTY_) || 3149 (req.Seq == 0 && req.LastFor == _EMPTY_ && req.NextFor == _EMPTY_ && req.StartTime == nil) || 3150 (req.Seq > 0 && req.StartTime != nil) || 3151 (req.StartTime != nil && req.LastFor != _EMPTY_) || 3152 (req.LastFor != _EMPTY_ && req.NextFor != _EMPTY_) { 3153 resp.Error = NewJSBadRequestError() 3154 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3155 return 3156 } 3157 3158 mset, err := acc.lookupStream(stream) 3159 if err != nil { 3160 resp.Error = NewJSStreamNotFoundError() 3161 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3162 return 3163 } 3164 3165 var svp StoreMsg 3166 var sm *StoreMsg 3167 3168 // If AsOfTime is set, perform this first to get the sequence. 3169 var seq uint64 3170 if req.StartTime != nil { 3171 seq = mset.store.GetSeqFromTime(*req.StartTime) 3172 } else { 3173 seq = req.Seq 3174 } 3175 3176 if seq > 0 && req.NextFor == _EMPTY_ { 3177 sm, err = mset.store.LoadMsg(seq, &svp) 3178 } else if req.NextFor != _EMPTY_ { 3179 sm, _, err = mset.store.LoadNextMsg(req.NextFor, subjectHasWildcard(req.NextFor), seq, &svp) 3180 } else { 3181 sm, err = mset.store.LoadLastMsg(req.LastFor, &svp) 3182 } 3183 if err != nil { 3184 resp.Error = NewJSNoMessageFoundError() 3185 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3186 return 3187 } 3188 resp.Message = &StoredMsg{ 3189 Subject: sm.subj, 3190 Sequence: sm.seq, 3191 Header: sm.hdr, 3192 Data: sm.msg, 3193 Time: time.Unix(0, sm.ts).UTC(), 3194 } 3195 3196 // Don't send response through API layer for this call. 3197 s.sendInternalAccountMsg(nil, reply, s.jsonResponse(resp)) 3198 } 3199 3200 // Request to purge a stream. 3201 func (s *Server) jsStreamPurgeRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 3202 if c == nil || !s.JetStreamEnabled() { 3203 return 3204 } 3205 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 3206 if err != nil { 3207 s.Warnf(badAPIRequestT, msg) 3208 return 3209 } 3210 3211 stream := streamNameFromSubject(subject) 3212 3213 var resp = JSApiStreamPurgeResponse{ApiResponse: ApiResponse{Type: JSApiStreamPurgeResponseType}} 3214 3215 // If we are in clustered mode we need to be the stream leader to proceed. 3216 if s.JetStreamIsClustered() { 3217 // Check to make sure the stream is assigned. 3218 js, cc := s.getJetStreamCluster() 3219 if js == nil || cc == nil { 3220 return 3221 } 3222 3223 js.mu.RLock() 3224 isLeader, sa := cc.isLeader(), js.streamAssignment(acc.Name, stream) 3225 js.mu.RUnlock() 3226 3227 if isLeader && sa == nil { 3228 // We can't find the stream, so mimic what would be the errors below. 3229 if hasJS, doErr := acc.checkJetStream(); !hasJS { 3230 if doErr { 3231 resp.Error = NewJSNotEnabledForAccountError() 3232 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3233 } 3234 return 3235 } 3236 // No stream present. 3237 resp.Error = NewJSStreamNotFoundError() 3238 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3239 return 3240 } else if sa == nil { 3241 if js.isLeaderless() { 3242 resp.Error = NewJSClusterNotAvailError() 3243 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3244 } 3245 return 3246 } 3247 3248 // Check to see if we are a member of the group and if the group has no leader. 3249 if js.isGroupLeaderless(sa.Group) { 3250 resp.Error = NewJSClusterNotAvailError() 3251 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3252 return 3253 } 3254 3255 // We have the stream assigned and a leader, so only the stream leader should answer. 3256 if !acc.JetStreamIsStreamLeader(stream) { 3257 if js.isLeaderless() { 3258 resp.Error = NewJSClusterNotAvailError() 3259 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3260 } 3261 return 3262 } 3263 } 3264 3265 if hasJS, doErr := acc.checkJetStream(); !hasJS { 3266 if doErr { 3267 resp.Error = NewJSNotEnabledForAccountError() 3268 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3269 } 3270 return 3271 } 3272 3273 var purgeRequest *JSApiStreamPurgeRequest 3274 if !isEmptyRequest(msg) { 3275 var req JSApiStreamPurgeRequest 3276 if err := json.Unmarshal(msg, &req); err != nil { 3277 resp.Error = NewJSInvalidJSONError() 3278 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3279 return 3280 } 3281 if req.Sequence > 0 && req.Keep > 0 { 3282 resp.Error = NewJSBadRequestError() 3283 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3284 return 3285 } 3286 purgeRequest = &req 3287 } 3288 3289 mset, err := acc.lookupStream(stream) 3290 if err != nil { 3291 resp.Error = NewJSStreamNotFoundError(Unless(err)) 3292 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3293 return 3294 } 3295 if mset.cfg.Sealed { 3296 resp.Error = NewJSStreamSealedError() 3297 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3298 return 3299 } 3300 if mset.cfg.DenyPurge { 3301 resp.Error = NewJSStreamPurgeFailedError(errors.New("stream purge not permitted")) 3302 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3303 return 3304 } 3305 3306 if s.JetStreamIsClustered() { 3307 s.jsClusteredStreamPurgeRequest(ci, acc, mset, stream, subject, reply, rmsg, purgeRequest) 3308 return 3309 } 3310 3311 purged, err := mset.purge(purgeRequest) 3312 if err != nil { 3313 resp.Error = NewJSStreamGeneralError(err, Unless(err)) 3314 } else { 3315 resp.Purged = purged 3316 resp.Success = true 3317 } 3318 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 3319 } 3320 3321 func (acc *Account) jsNonClusteredStreamLimitsCheck(cfg *StreamConfig) *ApiError { 3322 selectedLimits, tier, jsa, apiErr := acc.selectLimits(cfg) 3323 if apiErr != nil { 3324 return apiErr 3325 } 3326 jsa.mu.RLock() 3327 defer jsa.mu.RUnlock() 3328 if selectedLimits.MaxStreams > 0 && jsa.countStreams(tier, cfg) >= selectedLimits.MaxStreams { 3329 return NewJSMaximumStreamsLimitError() 3330 } 3331 reserved := jsa.tieredReservation(tier, cfg) 3332 if err := jsa.js.checkAllLimits(selectedLimits, cfg, reserved, 0); err != nil { 3333 return NewJSStreamLimitsError(err, Unless(err)) 3334 } 3335 return nil 3336 } 3337 3338 // Request to restore a stream. 3339 func (s *Server) jsStreamRestoreRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 3340 if c == nil || !s.JetStreamIsLeader() { 3341 return 3342 } 3343 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 3344 if err != nil { 3345 s.Warnf(badAPIRequestT, msg) 3346 return 3347 } 3348 3349 var resp = JSApiStreamRestoreResponse{ApiResponse: ApiResponse{Type: JSApiStreamRestoreResponseType}} 3350 if !acc.JetStreamEnabled() { 3351 resp.Error = NewJSNotEnabledForAccountError() 3352 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3353 return 3354 } 3355 if isEmptyRequest(msg) { 3356 resp.Error = NewJSBadRequestError() 3357 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3358 return 3359 } 3360 3361 var req JSApiStreamRestoreRequest 3362 if err := json.Unmarshal(msg, &req); err != nil { 3363 resp.Error = NewJSInvalidJSONError() 3364 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3365 return 3366 } 3367 3368 stream := streamNameFromSubject(subject) 3369 3370 if stream != req.Config.Name && req.Config.Name == _EMPTY_ { 3371 req.Config.Name = stream 3372 } 3373 3374 // check stream config at the start of the restore process, not at the end 3375 cfg, apiErr := s.checkStreamCfg(&req.Config, acc) 3376 if apiErr != nil { 3377 resp.Error = apiErr 3378 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3379 return 3380 } 3381 3382 if s.JetStreamIsClustered() { 3383 s.jsClusteredStreamRestoreRequest(ci, acc, &req, subject, reply, rmsg) 3384 return 3385 } 3386 3387 if err := acc.jsNonClusteredStreamLimitsCheck(&cfg); err != nil { 3388 resp.Error = err 3389 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3390 return 3391 } 3392 3393 if _, err := acc.lookupStream(stream); err == nil { 3394 resp.Error = NewJSStreamNameExistRestoreFailedError() 3395 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3396 return 3397 } 3398 3399 if hasJS, doErr := acc.checkJetStream(); !hasJS { 3400 if doErr { 3401 resp.Error = NewJSNotEnabledForAccountError() 3402 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3403 } 3404 return 3405 } 3406 3407 s.processStreamRestore(ci, acc, &req.Config, subject, reply, string(msg)) 3408 } 3409 3410 func (s *Server) processStreamRestore(ci *ClientInfo, acc *Account, cfg *StreamConfig, subject, reply, msg string) <-chan error { 3411 js := s.getJetStream() 3412 3413 var resp = JSApiStreamRestoreResponse{ApiResponse: ApiResponse{Type: JSApiStreamRestoreResponseType}} 3414 3415 snapDir := filepath.Join(js.config.StoreDir, snapStagingDir) 3416 if _, err := os.Stat(snapDir); os.IsNotExist(err) { 3417 if err := os.MkdirAll(snapDir, defaultDirPerms); err != nil { 3418 resp.Error = &ApiError{Code: 503, Description: "JetStream unable to create temp storage for restore"} 3419 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3420 return nil 3421 } 3422 } 3423 3424 tfile, err := os.CreateTemp(snapDir, "js-restore-") 3425 if err != nil { 3426 resp.Error = NewJSTempStorageFailedError() 3427 s.sendAPIErrResponse(ci, acc, subject, reply, msg, s.jsonResponse(&resp)) 3428 return nil 3429 } 3430 3431 streamName := cfg.Name 3432 s.Noticef("Starting restore for stream '%s > %s'", acc.Name, streamName) 3433 3434 start := time.Now().UTC() 3435 domain := s.getOpts().JetStreamDomain 3436 s.publishAdvisory(acc, JSAdvisoryStreamRestoreCreatePre+"."+streamName, &JSRestoreCreateAdvisory{ 3437 TypedEvent: TypedEvent{ 3438 Type: JSRestoreCreateAdvisoryType, 3439 ID: nuid.Next(), 3440 Time: start, 3441 }, 3442 Stream: streamName, 3443 Client: ci, 3444 Domain: domain, 3445 }) 3446 3447 // Create our internal subscription to accept the snapshot. 3448 restoreSubj := fmt.Sprintf(jsRestoreDeliverT, streamName, nuid.Next()) 3449 3450 type result struct { 3451 err error 3452 reply string 3453 } 3454 3455 // For signaling to upper layers. 3456 resultCh := make(chan result, 1) 3457 activeQ := newIPQueue[int](s, fmt.Sprintf("[ACC:%s] stream '%s' restore", acc.Name, streamName)) // of int 3458 3459 var total int 3460 3461 // FIXME(dlc) - Probably take out of network path eventually due to disk I/O? 3462 processChunk := func(sub *subscription, c *client, _ *Account, subject, reply string, msg []byte) { 3463 // We require reply subjects to communicate back failures, flow etc. If they do not have one log and cancel. 3464 if reply == _EMPTY_ { 3465 sub.client.processUnsub(sub.sid) 3466 resultCh <- result{ 3467 fmt.Errorf("restore for stream '%s > %s' requires reply subject for each chunk", acc.Name, streamName), 3468 reply, 3469 } 3470 return 3471 } 3472 // Account client messages have \r\n on end. This is an error. 3473 if len(msg) < LEN_CR_LF { 3474 sub.client.processUnsub(sub.sid) 3475 resultCh <- result{ 3476 fmt.Errorf("restore for stream '%s > %s' received short chunk", acc.Name, streamName), 3477 reply, 3478 } 3479 return 3480 } 3481 // Adjust. 3482 msg = msg[:len(msg)-LEN_CR_LF] 3483 3484 // This means we are complete with our transfer from the client. 3485 if len(msg) == 0 { 3486 s.Debugf("Finished staging restore for stream '%s > %s'", acc.Name, streamName) 3487 resultCh <- result{err, reply} 3488 return 3489 } 3490 3491 // We track total and check on server limits. 3492 // TODO(dlc) - We could check apriori and cancel initial request if we know it won't fit. 3493 total += len(msg) 3494 if js.wouldExceedLimits(FileStorage, total) { 3495 s.resourcesExceededError() 3496 resultCh <- result{NewJSInsufficientResourcesError(), reply} 3497 return 3498 } 3499 3500 // Append chunk to temp file. Mark as issue if we encounter an error. 3501 if n, err := tfile.Write(msg); n != len(msg) || err != nil { 3502 resultCh <- result{err, reply} 3503 if reply != _EMPTY_ { 3504 s.sendInternalAccountMsg(acc, reply, "-ERR 'storage failure during restore'") 3505 } 3506 return 3507 } 3508 3509 activeQ.push(len(msg)) 3510 3511 s.sendInternalAccountMsg(acc, reply, nil) 3512 } 3513 3514 sub, err := acc.subscribeInternal(restoreSubj, processChunk) 3515 if err != nil { 3516 tfile.Close() 3517 os.Remove(tfile.Name()) 3518 resp.Error = NewJSRestoreSubscribeFailedError(err, restoreSubj) 3519 s.sendAPIErrResponse(ci, acc, subject, reply, msg, s.jsonResponse(&resp)) 3520 return nil 3521 } 3522 3523 // Mark the subject so the end user knows where to send the snapshot chunks. 3524 resp.DeliverSubject = restoreSubj 3525 s.sendAPIResponse(ci, acc, subject, reply, msg, s.jsonResponse(resp)) 3526 3527 doneCh := make(chan error, 1) 3528 3529 // Monitor the progress from another Go routine. 3530 s.startGoRoutine(func() { 3531 defer s.grWG.Done() 3532 defer func() { 3533 tfile.Close() 3534 os.Remove(tfile.Name()) 3535 sub.client.processUnsub(sub.sid) 3536 activeQ.unregister() 3537 }() 3538 3539 const activityInterval = 5 * time.Second 3540 notActive := time.NewTimer(activityInterval) 3541 defer notActive.Stop() 3542 3543 total := 0 3544 for { 3545 select { 3546 case result := <-resultCh: 3547 err := result.err 3548 var mset *stream 3549 3550 // If we staged properly go ahead and do restore now. 3551 if err == nil { 3552 s.Debugf("Finalizing restore for stream '%s > %s'", acc.Name, streamName) 3553 tfile.Seek(0, 0) 3554 mset, err = acc.RestoreStream(cfg, tfile) 3555 } else { 3556 errStr := err.Error() 3557 tmp := []rune(errStr) 3558 tmp[0] = unicode.ToUpper(tmp[0]) 3559 s.Warnf(errStr) 3560 } 3561 3562 end := time.Now().UTC() 3563 3564 // TODO(rip) - Should this have the error code in it?? 3565 s.publishAdvisory(acc, JSAdvisoryStreamRestoreCompletePre+"."+streamName, &JSRestoreCompleteAdvisory{ 3566 TypedEvent: TypedEvent{ 3567 Type: JSRestoreCompleteAdvisoryType, 3568 ID: nuid.Next(), 3569 Time: end, 3570 }, 3571 Stream: streamName, 3572 Start: start, 3573 End: end, 3574 Bytes: int64(total), 3575 Client: ci, 3576 Domain: domain, 3577 }) 3578 3579 var resp = JSApiStreamCreateResponse{ApiResponse: ApiResponse{Type: JSApiStreamCreateResponseType}} 3580 3581 if err != nil { 3582 resp.Error = NewJSStreamRestoreError(err, Unless(err)) 3583 s.Warnf("Restore failed for %s for stream '%s > %s' in %v", 3584 friendlyBytes(int64(total)), streamName, acc.Name, end.Sub(start)) 3585 } else { 3586 resp.StreamInfo = &StreamInfo{ 3587 Created: mset.createdTime(), 3588 State: mset.state(), 3589 Config: mset.config(), 3590 TimeStamp: time.Now().UTC(), 3591 } 3592 s.Noticef("Completed restore of %s for stream '%s > %s' in %v", 3593 friendlyBytes(int64(total)), streamName, acc.Name, end.Sub(start).Round(time.Millisecond)) 3594 } 3595 3596 // On the last EOF, send back the stream info or error status. 3597 s.sendInternalAccountMsg(acc, result.reply, s.jsonResponse(&resp)) 3598 // Signal to the upper layers. 3599 doneCh <- err 3600 return 3601 case <-activeQ.ch: 3602 if n, ok := activeQ.popOne(); ok { 3603 total += n 3604 notActive.Reset(activityInterval) 3605 } 3606 case <-notActive.C: 3607 err := fmt.Errorf("restore for stream '%s > %s' is stalled", acc, streamName) 3608 doneCh <- err 3609 return 3610 } 3611 } 3612 }) 3613 3614 return doneCh 3615 } 3616 3617 // Process a snapshot request. 3618 func (s *Server) jsStreamSnapshotRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 3619 if c == nil || !s.JetStreamEnabled() { 3620 return 3621 } 3622 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 3623 if err != nil { 3624 s.Warnf(badAPIRequestT, msg) 3625 return 3626 } 3627 3628 smsg := string(msg) 3629 stream := streamNameFromSubject(subject) 3630 3631 // If we are in clustered mode we need to be the stream leader to proceed. 3632 if s.JetStreamIsClustered() && !acc.JetStreamIsStreamLeader(stream) { 3633 return 3634 } 3635 3636 var resp = JSApiStreamSnapshotResponse{ApiResponse: ApiResponse{Type: JSApiStreamSnapshotResponseType}} 3637 if !acc.JetStreamEnabled() { 3638 resp.Error = NewJSNotEnabledForAccountError() 3639 s.sendAPIErrResponse(ci, acc, subject, reply, smsg, s.jsonResponse(&resp)) 3640 return 3641 } 3642 if isEmptyRequest(msg) { 3643 resp.Error = NewJSBadRequestError() 3644 s.sendAPIErrResponse(ci, acc, subject, reply, smsg, s.jsonResponse(&resp)) 3645 return 3646 } 3647 3648 mset, err := acc.lookupStream(stream) 3649 if err != nil { 3650 resp.Error = NewJSStreamNotFoundError(Unless(err)) 3651 s.sendAPIErrResponse(ci, acc, subject, reply, smsg, s.jsonResponse(&resp)) 3652 return 3653 } 3654 3655 if hasJS, doErr := acc.checkJetStream(); !hasJS { 3656 if doErr { 3657 resp.Error = NewJSNotEnabledForAccountError() 3658 s.sendAPIErrResponse(ci, acc, subject, reply, smsg, s.jsonResponse(&resp)) 3659 } 3660 return 3661 } 3662 3663 var req JSApiStreamSnapshotRequest 3664 if err := json.Unmarshal(msg, &req); err != nil { 3665 resp.Error = NewJSInvalidJSONError() 3666 s.sendAPIErrResponse(ci, acc, subject, reply, smsg, s.jsonResponse(&resp)) 3667 return 3668 } 3669 if !IsValidSubject(req.DeliverSubject) { 3670 resp.Error = NewJSSnapshotDeliverSubjectInvalidError() 3671 s.sendAPIErrResponse(ci, acc, subject, reply, smsg, s.jsonResponse(&resp)) 3672 return 3673 } 3674 3675 // We will do the snapshot in a go routine as well since check msgs may 3676 // stall this go routine. 3677 go func() { 3678 if req.CheckMsgs { 3679 s.Noticef("Starting health check and snapshot for stream '%s > %s'", mset.jsa.account.Name, mset.name()) 3680 } else { 3681 s.Noticef("Starting snapshot for stream '%s > %s'", mset.jsa.account.Name, mset.name()) 3682 } 3683 3684 start := time.Now().UTC() 3685 3686 sr, err := mset.snapshot(0, req.CheckMsgs, !req.NoConsumers) 3687 if err != nil { 3688 s.Warnf("Snapshot of stream '%s > %s' failed: %v", mset.jsa.account.Name, mset.name(), err) 3689 resp.Error = NewJSStreamSnapshotError(err, Unless(err)) 3690 s.sendAPIErrResponse(ci, acc, subject, reply, smsg, s.jsonResponse(&resp)) 3691 return 3692 } 3693 3694 config := mset.config() 3695 resp.State = &sr.State 3696 resp.Config = &config 3697 3698 s.sendAPIResponse(ci, acc, subject, reply, smsg, s.jsonResponse(resp)) 3699 3700 s.publishAdvisory(acc, JSAdvisoryStreamSnapshotCreatePre+"."+mset.name(), &JSSnapshotCreateAdvisory{ 3701 TypedEvent: TypedEvent{ 3702 Type: JSSnapshotCreatedAdvisoryType, 3703 ID: nuid.Next(), 3704 Time: time.Now().UTC(), 3705 }, 3706 Stream: mset.name(), 3707 State: sr.State, 3708 Client: ci, 3709 Domain: s.getOpts().JetStreamDomain, 3710 }) 3711 3712 // Now do the real streaming. 3713 s.streamSnapshot(acc, mset, sr, &req) 3714 3715 end := time.Now().UTC() 3716 3717 s.publishAdvisory(acc, JSAdvisoryStreamSnapshotCompletePre+"."+mset.name(), &JSSnapshotCompleteAdvisory{ 3718 TypedEvent: TypedEvent{ 3719 Type: JSSnapshotCompleteAdvisoryType, 3720 ID: nuid.Next(), 3721 Time: end, 3722 }, 3723 Stream: mset.name(), 3724 Start: start, 3725 End: end, 3726 Client: ci, 3727 Domain: s.getOpts().JetStreamDomain, 3728 }) 3729 3730 s.Noticef("Completed snapshot of %s for stream '%s > %s' in %v", 3731 friendlyBytes(int64(sr.State.Bytes)), 3732 mset.jsa.account.Name, 3733 mset.name(), 3734 end.Sub(start)) 3735 }() 3736 } 3737 3738 // Default chunk size for now. 3739 const defaultSnapshotChunkSize = 128 * 1024 3740 const defaultSnapshotWindowSize = 8 * 1024 * 1024 // 8MB 3741 3742 // streamSnapshot will stream out our snapshot to the reply subject. 3743 func (s *Server) streamSnapshot(acc *Account, mset *stream, sr *SnapshotResult, req *JSApiStreamSnapshotRequest) { 3744 chunkSize := req.ChunkSize 3745 if chunkSize == 0 { 3746 chunkSize = defaultSnapshotChunkSize 3747 } 3748 // Setup for the chunk stream. 3749 reply := req.DeliverSubject 3750 r := sr.Reader 3751 defer r.Close() 3752 3753 // Check interest for the snapshot deliver subject. 3754 inch := make(chan bool, 1) 3755 acc.sl.RegisterNotification(req.DeliverSubject, inch) 3756 defer acc.sl.ClearNotification(req.DeliverSubject, inch) 3757 hasInterest := <-inch 3758 if !hasInterest { 3759 // Allow 2 seconds or so for interest to show up. 3760 select { 3761 case <-inch: 3762 case <-time.After(2 * time.Second): 3763 } 3764 } 3765 3766 // Create our ack flow handler. 3767 // This is very simple for now. 3768 ackSize := defaultSnapshotWindowSize / chunkSize 3769 if ackSize < 8 { 3770 ackSize = 8 3771 } else if ackSize > 8*1024 { 3772 ackSize = 8 * 1024 3773 } 3774 acks := make(chan struct{}, ackSize) 3775 acks <- struct{}{} 3776 3777 // Track bytes outstanding. 3778 var out int32 3779 3780 // We will place sequence number and size of chunk sent in the reply. 3781 ackSubj := fmt.Sprintf(jsSnapshotAckT, mset.name(), nuid.Next()) 3782 ackSub, _ := mset.subscribeInternal(ackSubj+".>", func(_ *subscription, _ *client, _ *Account, subject, _ string, _ []byte) { 3783 cs, _ := strconv.Atoi(tokenAt(subject, 6)) 3784 // This is very crude and simple, but ok for now. 3785 // This only matters when sending multiple chunks. 3786 if atomic.AddInt32(&out, int32(-cs)) < defaultSnapshotWindowSize { 3787 select { 3788 case acks <- struct{}{}: 3789 default: 3790 } 3791 } 3792 }) 3793 defer mset.unsubscribe(ackSub) 3794 3795 // TODO(dlc) - Add in NATS-Chunked-Sequence header 3796 var hdr []byte 3797 for index := 1; ; index++ { 3798 chunk := make([]byte, chunkSize) 3799 n, err := r.Read(chunk) 3800 chunk = chunk[:n] 3801 if err != nil { 3802 if n > 0 { 3803 mset.outq.send(newJSPubMsg(reply, _EMPTY_, _EMPTY_, nil, chunk, nil, 0)) 3804 } 3805 break 3806 } 3807 3808 // Wait on acks for flow control if past our window size. 3809 // Wait up to 10ms for now if no acks received. 3810 if atomic.LoadInt32(&out) > defaultSnapshotWindowSize { 3811 select { 3812 case <-acks: 3813 // ok to proceed. 3814 case <-inch: 3815 // Lost interest 3816 hdr = []byte("NATS/1.0 408 No Interest\r\n\r\n") 3817 goto done 3818 case <-time.After(2 * time.Second): 3819 hdr = []byte("NATS/1.0 408 No Flow Response\r\n\r\n") 3820 goto done 3821 } 3822 } 3823 ackReply := fmt.Sprintf("%s.%d.%d", ackSubj, len(chunk), index) 3824 if hdr == nil { 3825 hdr = []byte("NATS/1.0 204\r\n\r\n") 3826 } 3827 mset.outq.send(newJSPubMsg(reply, _EMPTY_, ackReply, nil, chunk, nil, 0)) 3828 atomic.AddInt32(&out, int32(len(chunk))) 3829 } 3830 done: 3831 // Send last EOF 3832 // TODO(dlc) - place hash in header 3833 mset.outq.send(newJSPubMsg(reply, _EMPTY_, _EMPTY_, hdr, nil, nil, 0)) 3834 } 3835 3836 // For determining consumer request type. 3837 type ccReqType uint8 3838 3839 const ( 3840 ccNew = iota 3841 ccLegacyEphemeral 3842 ccLegacyDurable 3843 ) 3844 3845 // Request to create a consumer where stream and optional consumer name are part of the subject, and optional 3846 // filtered subjects can be at the tail end. 3847 // Assumes stream and consumer names are single tokens. 3848 func (s *Server) jsConsumerCreateRequest(sub *subscription, c *client, a *Account, subject, reply string, rmsg []byte) { 3849 if c == nil || !s.JetStreamEnabled() { 3850 return 3851 } 3852 3853 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 3854 if err != nil { 3855 s.Warnf(badAPIRequestT, msg) 3856 return 3857 } 3858 3859 var resp = JSApiConsumerCreateResponse{ApiResponse: ApiResponse{Type: JSApiConsumerCreateResponseType}} 3860 3861 var req CreateConsumerRequest 3862 if err := json.Unmarshal(msg, &req); err != nil { 3863 resp.Error = NewJSInvalidJSONError() 3864 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3865 return 3866 } 3867 3868 var js *jetStream 3869 isClustered := s.JetStreamIsClustered() 3870 3871 // Determine if we should proceed here when we are in clustered mode. 3872 if isClustered { 3873 if req.Config.Direct { 3874 // Check to see if we have this stream and are the stream leader. 3875 if !acc.JetStreamIsStreamLeader(streamNameFromSubject(subject)) { 3876 return 3877 } 3878 } else { 3879 var cc *jetStreamCluster 3880 js, cc = s.getJetStreamCluster() 3881 if js == nil || cc == nil { 3882 return 3883 } 3884 if js.isLeaderless() { 3885 resp.Error = NewJSClusterNotAvailError() 3886 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3887 return 3888 } 3889 // Make sure we are meta leader. 3890 if !s.JetStreamIsLeader() { 3891 return 3892 } 3893 } 3894 } 3895 3896 var streamName, consumerName, filteredSubject string 3897 var rt ccReqType 3898 3899 if n := numTokens(subject); n < 5 { 3900 s.Warnf(badAPIRequestT, msg) 3901 return 3902 } else if n == 5 { 3903 // Legacy ephemeral. 3904 rt = ccLegacyEphemeral 3905 streamName = streamNameFromSubject(subject) 3906 } else { 3907 // New style and durable legacy. 3908 if tokenAt(subject, 4) == "DURABLE" { 3909 rt = ccLegacyDurable 3910 if n != 7 { 3911 resp.Error = NewJSConsumerDurableNameNotInSubjectError() 3912 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3913 return 3914 } 3915 streamName = tokenAt(subject, 6) 3916 consumerName = tokenAt(subject, 7) 3917 } else { 3918 streamName = streamNameFromSubject(subject) 3919 consumerName = consumerNameFromSubject(subject) 3920 // New has optional filtered subject as part of main subject.. 3921 if n > 6 { 3922 tokens := strings.Split(subject, tsep) 3923 filteredSubject = strings.Join(tokens[6:], tsep) 3924 } 3925 } 3926 } 3927 3928 if hasJS, doErr := acc.checkJetStream(); !hasJS { 3929 if doErr { 3930 resp.Error = NewJSNotEnabledForAccountError() 3931 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3932 } 3933 return 3934 } 3935 3936 if streamName != req.Stream { 3937 resp.Error = NewJSStreamMismatchError() 3938 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3939 return 3940 } 3941 3942 if consumerName != _EMPTY_ { 3943 // Check for path like separators in the name. 3944 if strings.ContainsAny(consumerName, `\/`) { 3945 resp.Error = NewJSConsumerNameContainsPathSeparatorsError() 3946 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3947 return 3948 } 3949 } 3950 3951 // Should we expect a durable name 3952 if rt == ccLegacyDurable { 3953 if numTokens(subject) < 7 { 3954 resp.Error = NewJSConsumerDurableNameNotInSubjectError() 3955 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3956 return 3957 } 3958 // Now check on requirements for durable request. 3959 if req.Config.Durable == _EMPTY_ { 3960 resp.Error = NewJSConsumerDurableNameNotSetError() 3961 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3962 return 3963 } 3964 if consumerName != req.Config.Durable { 3965 resp.Error = NewJSConsumerDurableNameNotMatchSubjectError() 3966 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3967 return 3968 } 3969 } 3970 // If new style and durable set make sure they match. 3971 if rt == ccNew { 3972 if req.Config.Durable != _EMPTY_ { 3973 if consumerName != req.Config.Durable { 3974 resp.Error = NewJSConsumerDurableNameNotMatchSubjectError() 3975 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3976 return 3977 } 3978 } 3979 // New style ephemeral so we need to honor the name. 3980 req.Config.Name = consumerName 3981 } 3982 // Check for legacy ephemeral mis-configuration. 3983 if rt == ccLegacyEphemeral && req.Config.Durable != _EMPTY_ { 3984 resp.Error = NewJSConsumerEphemeralWithDurableNameError() 3985 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3986 return 3987 } 3988 3989 // in case of multiple filters provided, error if new API is used. 3990 if filteredSubject != _EMPTY_ && len(req.Config.FilterSubjects) != 0 { 3991 resp.Error = NewJSConsumerMultipleFiltersNotAllowedError() 3992 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 3993 return 3994 } 3995 3996 // Check for a filter subject. 3997 if filteredSubject != _EMPTY_ && req.Config.FilterSubject != filteredSubject { 3998 resp.Error = NewJSConsumerCreateFilterSubjectMismatchError() 3999 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4000 return 4001 } 4002 4003 if isClustered && !req.Config.Direct { 4004 // If we are inline with client, we still may need to do a callout for consumer info 4005 // during this call, so place in Go routine to not block client. 4006 // Router and Gateway API calls already in separate context. 4007 if c.kind != ROUTER && c.kind != GATEWAY { 4008 go s.jsClusteredConsumerRequest(ci, acc, subject, reply, rmsg, req.Stream, &req.Config, req.Action) 4009 } else { 4010 s.jsClusteredConsumerRequest(ci, acc, subject, reply, rmsg, req.Stream, &req.Config, req.Action) 4011 } 4012 return 4013 } 4014 4015 // If we are here we are single server mode. 4016 if req.Config.Replicas > 1 { 4017 resp.Error = NewJSStreamReplicasNotSupportedError() 4018 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4019 return 4020 } 4021 4022 stream, err := acc.lookupStream(req.Stream) 4023 if err != nil { 4024 resp.Error = NewJSStreamNotFoundError(Unless(err)) 4025 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4026 return 4027 } 4028 4029 // If the consumer already exists then don't allow updating the PauseUntil, just set 4030 // it back to whatever the current configured value is. 4031 if o := stream.lookupConsumer(consumerName); o != nil { 4032 req.Config.PauseUntil = o.cfg.PauseUntil 4033 } 4034 4035 o, err := stream.addConsumerWithAction(&req.Config, req.Action) 4036 4037 if err != nil { 4038 if IsNatsErr(err, JSConsumerStoreFailedErrF) { 4039 cname := req.Config.Durable // Will be empty if ephemeral. 4040 s.Warnf("Consumer create failed for '%s > %s > %s': %v", acc, req.Stream, cname, err) 4041 err = errConsumerStoreFailed 4042 } 4043 resp.Error = NewJSConsumerCreateError(err, Unless(err)) 4044 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4045 return 4046 } 4047 resp.ConsumerInfo = o.initialInfo() 4048 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 4049 4050 if o.cfg.PauseUntil != nil && !o.cfg.PauseUntil.IsZero() && time.Now().Before(*o.cfg.PauseUntil) { 4051 o.sendPauseAdvisoryLocked(&o.cfg) 4052 } 4053 } 4054 4055 // Request for the list of all consumer names. 4056 func (s *Server) jsConsumerNamesRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 4057 if c == nil || !s.JetStreamEnabled() { 4058 return 4059 } 4060 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 4061 if err != nil { 4062 s.Warnf(badAPIRequestT, msg) 4063 return 4064 } 4065 4066 var resp = JSApiConsumerNamesResponse{ 4067 ApiResponse: ApiResponse{Type: JSApiConsumerNamesResponseType}, 4068 Consumers: []string{}, 4069 } 4070 4071 // Determine if we should proceed here when we are in clustered mode. 4072 if s.JetStreamIsClustered() { 4073 js, cc := s.getJetStreamCluster() 4074 if js == nil || cc == nil { 4075 return 4076 } 4077 if js.isLeaderless() { 4078 resp.Error = NewJSClusterNotAvailError() 4079 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4080 return 4081 } 4082 // Make sure we are meta leader. 4083 if !s.JetStreamIsLeader() { 4084 return 4085 } 4086 } 4087 4088 if hasJS, doErr := acc.checkJetStream(); !hasJS { 4089 if doErr { 4090 resp.Error = NewJSNotEnabledForAccountError() 4091 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4092 } 4093 return 4094 } 4095 4096 var offset int 4097 if !isEmptyRequest(msg) { 4098 var req JSApiConsumersRequest 4099 if err := json.Unmarshal(msg, &req); err != nil { 4100 resp.Error = NewJSInvalidJSONError() 4101 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4102 return 4103 } 4104 offset = req.Offset 4105 } 4106 4107 streamName := streamNameFromSubject(subject) 4108 var numConsumers int 4109 4110 if s.JetStreamIsClustered() { 4111 js, cc := s.getJetStreamCluster() 4112 if js == nil || cc == nil { 4113 // TODO(dlc) - Debug or Warn? 4114 return 4115 } 4116 js.mu.RLock() 4117 sas := cc.streams[acc.Name] 4118 if sas == nil { 4119 js.mu.RUnlock() 4120 resp.Error = NewJSStreamNotFoundError() 4121 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4122 return 4123 } 4124 sa := sas[streamName] 4125 if sa == nil || sa.err != nil { 4126 js.mu.RUnlock() 4127 resp.Error = NewJSStreamNotFoundError() 4128 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4129 return 4130 } 4131 for consumer := range sa.consumers { 4132 resp.Consumers = append(resp.Consumers, consumer) 4133 } 4134 if len(resp.Consumers) > 1 { 4135 sort.Slice(resp.Consumers, func(i, j int) bool { return strings.Compare(resp.Consumers[i], resp.Consumers[j]) < 0 }) 4136 } 4137 numConsumers = len(resp.Consumers) 4138 if offset > numConsumers { 4139 offset = numConsumers 4140 } 4141 resp.Consumers = resp.Consumers[offset:] 4142 if len(resp.Consumers) > JSApiNamesLimit { 4143 resp.Consumers = resp.Consumers[:JSApiNamesLimit] 4144 } 4145 js.mu.RUnlock() 4146 4147 } else { 4148 mset, err := acc.lookupStream(streamName) 4149 if err != nil { 4150 resp.Error = NewJSStreamNotFoundError(Unless(err)) 4151 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4152 return 4153 } 4154 4155 obs := mset.getPublicConsumers() 4156 sort.Slice(obs, func(i, j int) bool { 4157 return strings.Compare(obs[i].name, obs[j].name) < 0 4158 }) 4159 4160 numConsumers = len(obs) 4161 if offset > numConsumers { 4162 offset = numConsumers 4163 } 4164 4165 for _, o := range obs[offset:] { 4166 resp.Consumers = append(resp.Consumers, o.String()) 4167 if len(resp.Consumers) >= JSApiNamesLimit { 4168 break 4169 } 4170 } 4171 } 4172 resp.Total = numConsumers 4173 resp.Limit = JSApiNamesLimit 4174 resp.Offset = offset 4175 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 4176 } 4177 4178 // Request for the list of all detailed consumer information. 4179 func (s *Server) jsConsumerListRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 4180 if c == nil || !s.JetStreamEnabled() { 4181 return 4182 } 4183 4184 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 4185 if err != nil { 4186 s.Warnf(badAPIRequestT, msg) 4187 return 4188 } 4189 4190 var resp = JSApiConsumerListResponse{ 4191 ApiResponse: ApiResponse{Type: JSApiConsumerListResponseType}, 4192 Consumers: []*ConsumerInfo{}, 4193 } 4194 4195 // Determine if we should proceed here when we are in clustered mode. 4196 if s.JetStreamIsClustered() { 4197 js, cc := s.getJetStreamCluster() 4198 if js == nil || cc == nil { 4199 return 4200 } 4201 if js.isLeaderless() { 4202 resp.Error = NewJSClusterNotAvailError() 4203 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4204 return 4205 } 4206 // Make sure we are meta leader. 4207 if !s.JetStreamIsLeader() { 4208 return 4209 } 4210 } 4211 4212 if hasJS, doErr := acc.checkJetStream(); !hasJS { 4213 if doErr { 4214 resp.Error = NewJSNotEnabledForAccountError() 4215 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4216 } 4217 return 4218 } 4219 4220 var offset int 4221 if !isEmptyRequest(msg) { 4222 var req JSApiConsumersRequest 4223 if err := json.Unmarshal(msg, &req); err != nil { 4224 resp.Error = NewJSInvalidJSONError() 4225 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4226 return 4227 } 4228 offset = req.Offset 4229 } 4230 4231 streamName := streamNameFromSubject(subject) 4232 4233 // Clustered mode will invoke a scatter and gather. 4234 if s.JetStreamIsClustered() { 4235 // Need to copy these off before sending.. don't move this inside startGoRoutine!!! 4236 msg = copyBytes(msg) 4237 s.startGoRoutine(func() { 4238 s.jsClusteredConsumerListRequest(acc, ci, offset, streamName, subject, reply, msg) 4239 }) 4240 return 4241 } 4242 4243 mset, err := acc.lookupStream(streamName) 4244 if err != nil { 4245 resp.Error = NewJSStreamNotFoundError(Unless(err)) 4246 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4247 return 4248 } 4249 4250 obs := mset.getPublicConsumers() 4251 sort.Slice(obs, func(i, j int) bool { 4252 return strings.Compare(obs[i].name, obs[j].name) < 0 4253 }) 4254 4255 ocnt := len(obs) 4256 if offset > ocnt { 4257 offset = ocnt 4258 } 4259 4260 for _, o := range obs[offset:] { 4261 if cinfo := o.info(); cinfo != nil { 4262 resp.Consumers = append(resp.Consumers, cinfo) 4263 } 4264 if len(resp.Consumers) >= JSApiListLimit { 4265 break 4266 } 4267 } 4268 resp.Total = ocnt 4269 resp.Limit = JSApiListLimit 4270 resp.Offset = offset 4271 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 4272 } 4273 4274 // Request for information about an consumer. 4275 func (s *Server) jsConsumerInfoRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 4276 if c == nil || !s.JetStreamEnabled() { 4277 return 4278 } 4279 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 4280 if err != nil { 4281 s.Warnf(badAPIRequestT, msg) 4282 return 4283 } 4284 4285 streamName := streamNameFromSubject(subject) 4286 consumerName := consumerNameFromSubject(subject) 4287 4288 var resp = JSApiConsumerInfoResponse{ApiResponse: ApiResponse{Type: JSApiConsumerInfoResponseType}} 4289 4290 if !isEmptyRequest(msg) { 4291 resp.Error = NewJSNotEmptyRequestError() 4292 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4293 return 4294 } 4295 4296 // If we are in clustered mode we need to be the consumer leader to proceed. 4297 if s.JetStreamIsClustered() { 4298 // Check to make sure the consumer is assigned. 4299 js, cc := s.getJetStreamCluster() 4300 if js == nil || cc == nil { 4301 return 4302 } 4303 4304 js.mu.RLock() 4305 isLeader, sa, ca := cc.isLeader(), js.streamAssignment(acc.Name, streamName), js.consumerAssignment(acc.Name, streamName, consumerName) 4306 ourID := cc.meta.ID() 4307 var rg *raftGroup 4308 var offline, isMember bool 4309 if ca != nil { 4310 if rg = ca.Group; rg != nil { 4311 offline = s.allPeersOffline(rg) 4312 isMember = rg.isMember(ourID) 4313 } 4314 } 4315 // Capture consumer leader here. 4316 isConsumerLeader := cc.isConsumerLeader(acc.Name, streamName, consumerName) 4317 // Also capture if we think there is no meta leader. 4318 var isLeaderLess bool 4319 if !isLeader { 4320 isLeaderLess = cc.meta.GroupLeader() == _EMPTY_ && time.Since(cc.meta.Created()) > lostQuorumIntervalDefault 4321 } 4322 js.mu.RUnlock() 4323 4324 if isLeader && ca == nil { 4325 // We can't find the consumer, so mimic what would be the errors below. 4326 if hasJS, doErr := acc.checkJetStream(); !hasJS { 4327 if doErr { 4328 resp.Error = NewJSNotEnabledForAccountError() 4329 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4330 } 4331 return 4332 } 4333 if sa == nil { 4334 resp.Error = NewJSStreamNotFoundError() 4335 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4336 return 4337 } 4338 // If we are here the consumer is not present. 4339 resp.Error = NewJSConsumerNotFoundError() 4340 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4341 return 4342 } else if ca == nil { 4343 if isLeaderLess { 4344 resp.Error = NewJSClusterNotAvailError() 4345 // Delaying an error response gives the leader a chance to respond before us 4346 s.sendDelayedAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp), nil) 4347 } 4348 return 4349 } else if isLeader && offline { 4350 resp.Error = NewJSConsumerOfflineError() 4351 s.sendDelayedAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp), nil) 4352 return 4353 } 4354 4355 // Check to see if we are a member of the group and if the group has no leader. 4356 if isMember && js.isGroupLeaderless(ca.Group) { 4357 resp.Error = NewJSClusterNotAvailError() 4358 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4359 return 4360 } 4361 4362 // We have the consumer assigned and a leader, so only the consumer leader should answer. 4363 if !isConsumerLeader { 4364 if isLeaderLess { 4365 resp.Error = NewJSClusterNotAvailError() 4366 // Delaying an error response gives the leader a chance to respond before us 4367 s.sendDelayedAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp), ca.Group) 4368 return 4369 } 4370 4371 var node RaftNode 4372 var leaderNotPartOfGroup bool 4373 4374 // We have a consumer assignment. 4375 if isMember { 4376 js.mu.RLock() 4377 if rg.node != nil { 4378 node = rg.node 4379 if gl := node.GroupLeader(); gl != _EMPTY_ && !rg.isMember(gl) { 4380 leaderNotPartOfGroup = true 4381 } 4382 } 4383 js.mu.RUnlock() 4384 } 4385 4386 // Check if we should ignore all together. 4387 if node == nil { 4388 // We have been assigned but have not created a node yet. If we are a member return 4389 // our config and defaults for state and no cluster info. 4390 if isMember { 4391 // Since we access consumerAssignment, need js lock. 4392 js.mu.RLock() 4393 resp.ConsumerInfo = &ConsumerInfo{ 4394 Stream: ca.Stream, 4395 Name: ca.Name, 4396 Created: ca.Created, 4397 Config: ca.Config, 4398 TimeStamp: time.Now().UTC(), 4399 } 4400 b := s.jsonResponse(resp) 4401 js.mu.RUnlock() 4402 s.sendAPIResponse(ci, acc, subject, reply, string(msg), b) 4403 } 4404 return 4405 } 4406 // If we are a member and we have a group leader or we had a previous leader consider bailing out. 4407 if node.GroupLeader() != _EMPTY_ || node.HadPreviousLeader() { 4408 if leaderNotPartOfGroup { 4409 resp.Error = NewJSConsumerOfflineError() 4410 s.sendDelayedAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp), nil) 4411 } 4412 return 4413 } 4414 // If we are here we are a member and this is just a new consumer that does not have a leader yet. 4415 // Will fall through and return what we have. All consumers can respond but this should be very rare 4416 // but makes more sense to clients when they try to create, get a consumer exists, and then do consumer info. 4417 } 4418 } 4419 4420 if !acc.JetStreamEnabled() { 4421 resp.Error = NewJSNotEnabledForAccountError() 4422 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4423 return 4424 } 4425 4426 mset, err := acc.lookupStream(streamName) 4427 if err != nil { 4428 resp.Error = NewJSStreamNotFoundError(Unless(err)) 4429 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4430 return 4431 } 4432 4433 obs := mset.lookupConsumer(consumerName) 4434 if obs == nil { 4435 resp.Error = NewJSConsumerNotFoundError() 4436 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4437 return 4438 } 4439 4440 if resp.ConsumerInfo = obs.info(); resp.ConsumerInfo == nil { 4441 // This consumer returned nil which means it's closed. Respond with not found. 4442 resp.Error = NewJSConsumerNotFoundError() 4443 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4444 return 4445 } 4446 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 4447 } 4448 4449 // Request to delete an Consumer. 4450 func (s *Server) jsConsumerDeleteRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 4451 if c == nil || !s.JetStreamEnabled() { 4452 return 4453 } 4454 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 4455 if err != nil { 4456 s.Warnf(badAPIRequestT, msg) 4457 return 4458 } 4459 4460 var resp = JSApiConsumerDeleteResponse{ApiResponse: ApiResponse{Type: JSApiConsumerDeleteResponseType}} 4461 4462 // Determine if we should proceed here when we are in clustered mode. 4463 if s.JetStreamIsClustered() { 4464 js, cc := s.getJetStreamCluster() 4465 if js == nil || cc == nil { 4466 return 4467 } 4468 if js.isLeaderless() { 4469 resp.Error = NewJSClusterNotAvailError() 4470 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4471 return 4472 } 4473 // Make sure we are meta leader. 4474 if !s.JetStreamIsLeader() { 4475 return 4476 } 4477 } 4478 4479 if hasJS, doErr := acc.checkJetStream(); !hasJS { 4480 if doErr { 4481 resp.Error = NewJSNotEnabledForAccountError() 4482 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4483 } 4484 return 4485 } 4486 if !isEmptyRequest(msg) { 4487 resp.Error = NewJSNotEmptyRequestError() 4488 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4489 return 4490 } 4491 stream := streamNameFromSubject(subject) 4492 consumer := consumerNameFromSubject(subject) 4493 4494 if s.JetStreamIsClustered() { 4495 s.jsClusteredConsumerDeleteRequest(ci, acc, stream, consumer, subject, reply, rmsg) 4496 return 4497 } 4498 4499 mset, err := acc.lookupStream(stream) 4500 if err != nil { 4501 resp.Error = NewJSStreamNotFoundError(Unless(err)) 4502 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4503 return 4504 } 4505 4506 obs := mset.lookupConsumer(consumer) 4507 if obs == nil { 4508 resp.Error = NewJSConsumerNotFoundError() 4509 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4510 return 4511 } 4512 if err := obs.delete(); err != nil { 4513 resp.Error = NewJSStreamGeneralError(err, Unless(err)) 4514 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4515 return 4516 } 4517 resp.Success = true 4518 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 4519 } 4520 4521 // Request to pause or unpause a Consumer. 4522 func (s *Server) jsConsumerPauseRequest(sub *subscription, c *client, _ *Account, subject, reply string, rmsg []byte) { 4523 if c == nil || !s.JetStreamEnabled() { 4524 return 4525 } 4526 ci, acc, _, msg, err := s.getRequestInfo(c, rmsg) 4527 if err != nil { 4528 s.Warnf(badAPIRequestT, msg) 4529 return 4530 } 4531 4532 var req JSApiConsumerPauseRequest 4533 var resp = JSApiConsumerPauseResponse{ApiResponse: ApiResponse{Type: JSApiConsumerPauseResponseType}} 4534 4535 if !isEmptyRequest(msg) { 4536 if err := json.Unmarshal(msg, &req); err != nil { 4537 resp.Error = NewJSInvalidJSONError() 4538 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4539 return 4540 } 4541 } 4542 4543 // Determine if we should proceed here when we are in clustered mode. 4544 isClustered := s.JetStreamIsClustered() 4545 js, cc := s.getJetStreamCluster() 4546 if isClustered { 4547 if js == nil || cc == nil { 4548 return 4549 } 4550 if js.isLeaderless() { 4551 resp.Error = NewJSClusterNotAvailError() 4552 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4553 return 4554 } 4555 // Make sure we are meta leader. 4556 if !s.JetStreamIsLeader() { 4557 return 4558 } 4559 } 4560 4561 if hasJS, doErr := acc.checkJetStream(); !hasJS { 4562 if doErr { 4563 resp.Error = NewJSNotEnabledForAccountError() 4564 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4565 } 4566 return 4567 } 4568 4569 stream := streamNameFromSubject(subject) 4570 consumer := consumerNameFromSubject(subject) 4571 4572 if isClustered { 4573 sa := js.streamAssignment(acc.Name, stream) 4574 if sa == nil { 4575 resp.Error = NewJSStreamNotFoundError(Unless(err)) 4576 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4577 return 4578 } 4579 4580 ca, ok := sa.consumers[consumer] 4581 if !ok || ca == nil { 4582 resp.Error = NewJSConsumerNotFoundError() 4583 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4584 return 4585 } 4586 4587 nca := *ca 4588 pauseUTC := req.PauseUntil.UTC() 4589 if !pauseUTC.IsZero() { 4590 nca.Config.PauseUntil = &pauseUTC 4591 } 4592 eca := encodeAddConsumerAssignment(&nca) 4593 cc.meta.Propose(eca) 4594 4595 resp.PauseUntil = pauseUTC 4596 if resp.Paused = time.Now().Before(pauseUTC); resp.Paused { 4597 resp.PauseRemaining = time.Until(pauseUTC) 4598 } 4599 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 4600 return 4601 } 4602 4603 mset, err := acc.lookupStream(stream) 4604 if err != nil { 4605 resp.Error = NewJSStreamNotFoundError(Unless(err)) 4606 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4607 return 4608 } 4609 4610 obs := mset.lookupConsumer(consumer) 4611 if obs == nil { 4612 resp.Error = NewJSConsumerNotFoundError() 4613 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4614 return 4615 } 4616 4617 ncfg := obs.cfg 4618 pauseUTC := req.PauseUntil.UTC() 4619 if !pauseUTC.IsZero() { 4620 ncfg.PauseUntil = &pauseUTC 4621 } else { 4622 ncfg.PauseUntil = nil 4623 } 4624 4625 if err := obs.updateConfig(&ncfg); err != nil { 4626 // The only type of error that should be returned here is from o.store, 4627 // so use a store failed error type. 4628 resp.Error = NewJSConsumerStoreFailedError(err) 4629 s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp)) 4630 return 4631 } 4632 4633 resp.PauseUntil = pauseUTC 4634 if resp.Paused = time.Now().Before(pauseUTC); resp.Paused { 4635 resp.PauseRemaining = time.Until(pauseUTC) 4636 } 4637 s.sendAPIResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(resp)) 4638 } 4639 4640 // sendJetStreamAPIAuditAdvisor will send the audit event for a given event. 4641 func (s *Server) sendJetStreamAPIAuditAdvisory(ci *ClientInfo, acc *Account, subject, request, response string) { 4642 s.publishAdvisory(acc, JSAuditAdvisory, JSAPIAudit{ 4643 TypedEvent: TypedEvent{ 4644 Type: JSAPIAuditType, 4645 ID: nuid.Next(), 4646 Time: time.Now().UTC(), 4647 }, 4648 Server: s.Name(), 4649 Client: ci, 4650 Subject: subject, 4651 Request: request, 4652 Response: response, 4653 Domain: s.getOpts().JetStreamDomain, 4654 }) 4655 }