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