github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/utils/httpserverutils.go (about) 1 /* 2 Copyright 2023. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package utils 18 19 import ( 20 "bytes" 21 "encoding/base64" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "io" 26 "net" 27 "os" 28 "strings" 29 30 "github.com/cespare/xxhash" 31 log "github.com/sirupsen/logrus" 32 "github.com/valyala/fasthttp" 33 ) 34 35 const ( 36 ContentJson = "application/json; charset=utf-8" 37 ) 38 39 type HttpServerResponse struct { 40 Message string `json:"message"` 41 StatusCode int `json:"status"` 42 } 43 44 type HttpServerSettingsResponse struct { 45 Persistent map[string]string `json:"persistent"` 46 Transient map[string]string `json:"transient"` 47 } 48 49 type Hits struct { 50 Index string `json:"_index"` 51 Type string `json:"_type"` 52 Id string `json:"_id"` 53 Version int `json:"_version"` 54 Score int `json:"_score"` 55 Source map[string]interface{} `json:"_source"` 56 } 57 58 type HitsCount struct { 59 Value uint64 `json:"value"` 60 Relation string `json:"relation"` 61 } 62 type HttpServerESResponse struct { 63 Hits []Hits `json:"hits"` 64 Max_score int `json:"max_score"` 65 Total interface{} `json:"total"` 66 } 67 68 type StatResponse struct { 69 Value interface{} `json:"value"` 70 } 71 72 type BucketWrapper struct { 73 Bucket []map[string]interface{} `json:"buckets"` 74 } 75 76 type HttpServerESResponseOuter struct { 77 Hits HttpServerESResponse `json:"hits"` 78 Aggs map[string]BucketWrapper `json:"aggregations"` 79 Took int64 `json:"took"` 80 Timed_out bool `json:"timed_out"` 81 StatusCode int `json:"status"` 82 Shards map[string]interface{} `json:"_shards"` 83 } 84 85 type MultiSearchESResponse struct { 86 Results []HttpServerESResponseOuter `json:"responses"` 87 } 88 89 type HttpServerESResponseScroll struct { 90 Hits HttpServerESResponse `json:"hits"` 91 Aggs map[string]BucketWrapper `json:"aggregations"` 92 Took int64 `json:"took"` 93 Timed_out bool `json:"timed_out"` 94 StatusCode int `json:"status"` 95 Scroll_id string `json:"_scroll_id"` 96 } 97 98 type SingleESResponse struct { 99 Index string `json:"_index"` 100 Type string `json:"_type"` 101 Id string `json:"_id"` 102 Version int `json:"_version"` 103 SequenceNumber int `json:"_seq_no"` 104 Source map[string]interface{} `json:"_source"` 105 Found bool `json:"found"` 106 PrimaryTerm int `json:"_primary_term"` 107 } 108 109 type DocIndexedResponse struct { 110 Index string `json:"_index"` 111 Type string `json:"_type"` 112 Id string `json:"_id"` 113 Version int `json:"_version"` 114 SequenceNumber int `json:"_seq_no"` 115 Result string `json:"result"` 116 PrimaryTerm int `json:"_primary_term"` 117 Shards map[string]interface{} `json:"_shards"` 118 Get DocIndexedResponseSubFieldGet `json:"get"` 119 } 120 121 type DocIndexedResponseSubFieldGet struct { 122 SequenceNumber int `json:"_seq_no"` 123 PrimaryTerm int `json:"_primary_term"` 124 Found bool `json:"found"` 125 Source map[string]interface{} `json:"_source"` 126 } 127 128 type IndexNameInfoResponse struct { 129 Aliases map[string]bool `json:"aliases"` 130 Mappings map[string]interface{} `json:"mappings"` 131 Settings SettingsInfo `json:"settings"` 132 } 133 type NodesStatsResponseInfo struct { 134 Total int `json:"total"` 135 Successful int `json:"successful"` 136 Failed int `json:"failed"` 137 } 138 139 type NodesStatsMemResponse struct { 140 HeapCommitted string `json:"heap_committed"` 141 HeapCommittedInBytes uint64 `json:"heap_committed_in_bytes"` 142 HeapMax string `json:"heap_max"` 143 HeapMaxInBytes uint64 `json:"heap_max_in_bytes"` 144 HeapUsed string `json:"heap_used"` 145 HeapUsedInBytes uint64 `json:"heap_used_in_bytes"` 146 HeapUsedPercent int `json:"heap_used_percent"` 147 NonHeapCommitted string `json:"non_heap_committed"` 148 NonHeapCommittedInBytes int `json:"non_heap_committed_in_bytes"` 149 NonHeapUsed string `json:"non_heap_used"` 150 NonHeapUsedInBytes int `json:"non_heap_used_bytes"` 151 } 152 type NodesResponseInfo struct { 153 Timestamp int64 `json:"timestamp"` 154 Name string `json:"name"` 155 TransportAddress string `json:"transport_address"` 156 HostName string `json:"host"` 157 IP string `json:"ip"` 158 OSResponse map[string]interface{} `json:"os"` 159 JVMResponse map[string]interface{} `json:"jvm"` 160 FSResponse map[string]interface{} `json:"fs"` 161 ProcessResponse map[string]interface{} `json:"process"` 162 } 163 164 type AllResponseInfo struct { 165 Primaries map[string]interface{} `json:"primaries"` 166 Total map[string]interface{} `json:"total"` 167 } 168 type LoadAverageResponseInfo struct { 169 LoadResponse float64 `json:"1m"` 170 } 171 type SettingsInfo struct { 172 Index SettingsIndexInfo `json:"index"` 173 } 174 175 type SettingsIndexInfo struct { 176 NumberOfShards int `json:"number_of_shards"` 177 NumberOfReplicas int `json:"number_of_replicas"` 178 ProvidedName string `json:"provided_name"` 179 } 180 type BulkErrorResponse struct { 181 ErrorResponse BulkErrorResponseInfo `json:"error"` 182 } 183 type BulkErrorResponseInfo struct { 184 Reason string `json:"reason"` 185 Type string `json:"type"` 186 } 187 type MgetESResponse struct { 188 Docs []SingleESResponse `json:"docs"` 189 } 190 type AllNodesInfoResponse struct { 191 Nodes map[string]*NodeInfo `json:"nodes"` 192 } 193 194 type MemResponseInfo struct { 195 Total string `json:"total"` 196 TotalInBytes uint64 `json:"total_in_bytes"` 197 Free string `json:"free"` 198 FreeInBytes uint64 `json:"free_in_bytes"` 199 Used string `json:"used"` 200 UsedInBytes uint64 `json:"used_in_bytes"` 201 FreePercent uint64 `json:"free_percent"` 202 UsedPercent uint64 `json:"used_percent"` 203 } 204 type VirtualMemResponse struct { 205 TotalVirtual string `json:"total_virtual"` 206 TotalVirtualInBytes uint64 `json:"total_virtual_in_bytes"` 207 } 208 type SwapResponseInfo struct { 209 Total string `json:"total"` 210 TotalInBytes int64 `json:"total_in_bytes"` 211 Free string `json:"free"` 212 FreeInBytes int64 `json:"free_in_bytes"` 213 Used string `json:"used"` 214 UsedInBytes int64 `json:"used_in_bytes"` 215 } 216 217 type NodesTransportResponseInfo struct { 218 Name string `json:"name"` 219 TransportAddress string `json:"transport_address"` 220 HostName string `json:"host"` 221 IP string `json:"ip"` 222 Version string `json:"version"` 223 BuildFlavor string `json:"build_flavor"` 224 BuildType string `json:"build_type"` 225 BuildHash string `json:"build_hash"` 226 } 227 228 type ClusterHealthResponseInfo struct { 229 ClusterName string `json:"cluster_name"` 230 Status string `json:"status"` 231 TimedOut bool `json:"timed_out"` 232 NumberOfNodes int `json:"number_of_nodes"` 233 NumberOfDataNodes int `json:"number_of_data_nodes"` 234 ActivePrimaryShards int `json:"active_primary_shards"` 235 ActiveShards int `json:"active_shards"` 236 RelocatingShards int `json:"relocating_shards"` 237 InitiliazeShards int `json:"initializing_shards"` 238 UnassignedShards int `json:"unassigned_shards"` 239 DelayedShards int `json:"delayed_unassigned_shards"` 240 NumberOfPendingTasks int `json:"number_of_pending_tasks"` 241 NumberInFlightFetch int `json:"number_of_in_flight_fetch"` 242 TaskMaxWaiting int `json:"task_max_waiting_in_queue_millis"` 243 ActiveShardsPercent float64 `json:"active_shards_percent_as_number"` 244 } 245 246 type DocsResponse struct { 247 Count int `json:"count"` 248 Deleted int `json:"deleted"` 249 } 250 type StoreResponse struct { 251 SizeInBytes uint64 `json:"size_in_bytes"` 252 ReservedInBytes int `json:"reservec_in_bytes"` 253 } 254 type ClusterStateResponseInfo struct { 255 ClusterName string `json:"cluster_name"` 256 ClusterUUID string `json:"cluster_uuid"` 257 MasterNode string `json:"master_node"` 258 Blocks map[string]interface{} `json:"blocks"` 259 RoutingTable map[string]interface{} `json:"routing_table"` 260 } 261 262 type ClusterStateBlocksInfo struct { 263 ClusterName string `json:"cluster_name"` 264 ClusterUUID string `json:"cluster_uuid"` 265 Blocks map[string]interface{} `json:"blocks"` 266 } 267 268 type NodesAllResponseInfo struct { 269 Name string `json:"name"` 270 TransportAddress string `json:"transport_address"` 271 HostName string `json:"host"` 272 IP string `json:"ip"` 273 Version string `json:"version"` 274 BuildFlavor string `json:"build_flavor"` 275 BuildType string `json:"build_type"` 276 BuildHash string `json:"build_hash"` 277 OSResponse NodesOSResponseInfo `json:"os"` 278 } 279 type NodesOSResponseInfo struct { 280 RefreshInterval string `json:"refresh_interval"` 281 RefreshIntervalInMS int `json:"refresh_interval_in_millis"` 282 Name string `json:"name"` 283 PrettyName string `json:"pretty_name"` 284 Arch string `json:"arch"` 285 Version string `json:"version"` 286 AvailableProcessors int `json:"available_processors"` 287 AllocatedProcessors int `json:"allocated_processors"` 288 } 289 290 type ShardsItemsResponse struct { 291 State string `json:"state"` 292 Primary bool `json:"primary"` 293 Node string `json:"node"` 294 RelocatingNode *string `json:"relocating_node"` 295 Shard int `json:"shard"` 296 Index string `json:"index"` 297 AllocationId map[string]interface{} `json:"allocation_id"` 298 } 299 type AllIndicesInfoResponse []IndexInfo 300 301 type MultiNodesInfoResponse []*MemberInfo 302 303 type GreetResponse struct { 304 Name string `json:"name"` 305 ClusterName string `json:"cluster_name"` 306 ClusterUUID string `json:"cluster_uuid"` 307 Version GreetVersion `json:"version"` 308 } 309 310 type GreetVersion struct { 311 Number string `json:"number"` 312 BuildFlavour string `json:"build_flavor"` 313 BuildType string `json:"build_type"` 314 BuildDate string `json:"build_date"` 315 BuildHash string `json:"build_hash"` 316 BuildSnapshot bool `json:"build_snapshot"` 317 LuceneVersion string `json:"lucene_version"` 318 MinimumWireCompatibilityVersion string `json:"minimum_wire_compatibility_version"` 319 MinimumIndexCompatibilityVersion string `json:"minimum_index_compatibility_version"` 320 } 321 type TotalFsResponse struct { 322 Total string `json:"total"` 323 TotalInBytes uint64 `json:"total_in_bytes"` 324 Free string `json:"free"` 325 FreeInBytes uint64 `json:"free_in_bytes"` 326 Available string `json:"available"` 327 AvailableInBytes uint64 `json:"available_in_bytes"` 328 } 329 type ProcessCpuResponse struct { 330 Percent int `json:"percent"` 331 Total string `json:"total"` 332 TotalInMillis uint64 `json:"total_in_millis"` 333 } 334 type GetMasterResponse struct { 335 Id string `json:"id"` 336 Host string `json:"host"` 337 IP string `json:"ip"` 338 Node string `json:"node"` 339 } 340 type NodesStatsIdInfo struct { 341 Timestamp int64 `json:"timestamp"` 342 Name string `json:"name"` 343 TransportAddress string `json:"transport_address"` 344 Host string `json:"host"` 345 IP string `json:"ip"` 346 } 347 348 type NodesStatsIngestInfo struct { 349 Name string `json:"name"` 350 TransportAddress string `json:"transport_address"` 351 Host string `json:"host"` 352 IP string `json:"ip"` 353 Version string `json:"version"` 354 BuildFlavour string `json:"build_flavor"` 355 BuildType string `json:"build_type"` 356 BuildHash string `json:"build_hash"` 357 Roles []string `json:"roles"` 358 Ingest map[string]interface{} `json:"ingest"` 359 } 360 361 type DeleteIndexErrorResponseInfo struct { 362 Type string `json:"type"` 363 Reason string `json:"reason"` 364 ResourceType string `json:"resource.type"` 365 ResourceId string `json:"resource.id"` 366 IndexUUID string `json:"index.uuid"` 367 Index string `json:"index"` 368 } 369 370 type ResultPerIndex map[string]map[string]interface{} // maps index name to index stats 371 372 type ClusterStatsResponseInfo struct { 373 IngestionStats map[string]interface{} `json:"ingestionStats"` 374 QueryStats map[string]interface{} `json:"queryStats"` 375 MetricsStats map[string]interface{} `json:"metricsStats"` 376 IndexStats []ResultPerIndex `json:"indexStats"` 377 ChartStats map[string]map[string]interface{} `json:"chartStats"` 378 } 379 380 type MetricsStatsResponseInfo struct { 381 AggStats map[string]map[string]interface{} `json:"aggStats"` 382 } 383 384 type AllSavedQueries map[string]map[string]interface{} 385 386 type AutoCompleteDataInfo struct { 387 ColumnNames []string `json:"colNames"` 388 MeasureFunctions []string `json:"measureFunctions"` 389 } 390 391 func NewSingleESResponse() *SingleESResponse { 392 return &SingleESResponse{ 393 Index: "", 394 Type: "", 395 Id: "", 396 Version: 1, 397 SequenceNumber: 0, 398 Source: make(map[string]interface{}), 399 Found: false, 400 PrimaryTerm: 1, 401 } 402 } 403 404 func WriteResponse(ctx *fasthttp.RequestCtx, httpResp HttpServerResponse) { 405 ctx.SetContentType(ContentJson) 406 jval, _ := json.Marshal(httpResp) 407 _, err := ctx.Write(jval) 408 if err != nil { 409 return 410 } 411 } 412 413 func WriteJsonResponse(ctx *fasthttp.RequestCtx, httpResp interface{}) { 414 ctx.SetContentType(ContentJson) 415 jval, _ := json.Marshal(httpResp) 416 _, err := ctx.Write(jval) 417 if err != nil { 418 return 419 } 420 } 421 422 func SetBadMsg(ctx *fasthttp.RequestCtx, msg string) { 423 if len(msg) == 0 { 424 msg = "Bad Request" 425 } 426 var httpResp HttpServerResponse 427 ctx.SetStatusCode(fasthttp.StatusBadRequest) 428 httpResp.Message = msg 429 httpResp.StatusCode = fasthttp.StatusBadRequest 430 WriteResponse(ctx, httpResp) 431 } 432 433 func ExtractParamAsString(_interface interface{}) string { 434 switch intfc := _interface.(type) { 435 case string: 436 return intfc 437 default: 438 return "" 439 } 440 } 441 442 func NewSettingsIndexInfo(providedName string) *SettingsIndexInfo { 443 return &SettingsIndexInfo{ 444 NumberOfShards: 1, 445 NumberOfReplicas: 1, 446 ProvidedName: providedName, 447 } 448 } 449 450 func NewBulkErrorResponseInfo(reason string, typ string) *BulkErrorResponseInfo { 451 return &BulkErrorResponseInfo{ 452 Reason: reason, 453 Type: typ, 454 } 455 } 456 457 func NewNodesStatsResponseInfo(total int, successful int, failed int) *NodesStatsResponseInfo { 458 return &NodesStatsResponseInfo{ 459 Total: total, 460 Successful: successful, 461 Failed: failed, 462 } 463 } 464 465 func NewNodesResponseInfo(timestamp int64, host string, addressPort string, ipAddress string, osResponse map[string]interface{}, jvmResponse map[string]interface{}, fsResponse map[string]interface{}, processResponse map[string]interface{}) *NodesResponseInfo { 466 return &NodesResponseInfo{ 467 Timestamp: timestamp, 468 Name: host, 469 HostName: ipAddress, 470 TransportAddress: addressPort, 471 IP: ipAddress, 472 OSResponse: osResponse, 473 JVMResponse: jvmResponse, 474 FSResponse: fsResponse, 475 ProcessResponse: processResponse, 476 } 477 } 478 479 func NewLoadAverageResponseInfo(loadAverage float64) *LoadAverageResponseInfo { 480 return &LoadAverageResponseInfo{ 481 LoadResponse: loadAverage, 482 } 483 } 484 485 func NewAllResponseInfo() *AllResponseInfo { 486 return &AllResponseInfo{ 487 Primaries: make(map[string]interface{}), 488 Total: make(map[string]interface{}), 489 } 490 } 491 492 func NewMemResponseInfo(total string, totalInBytes uint64, free string, freeInBytes uint64, used string, usedInBytes uint64, freePercent float64, usedPercent float64) *MemResponseInfo { 493 return &MemResponseInfo{ 494 Total: total, 495 TotalInBytes: totalInBytes, 496 Free: free, 497 FreeInBytes: freeInBytes, 498 Used: used, 499 UsedInBytes: usedInBytes, 500 FreePercent: uint64(freePercent), 501 UsedPercent: uint64(usedPercent), 502 } 503 } 504 505 func NewSwapResponseInfo() *SwapResponseInfo { 506 return &SwapResponseInfo{ 507 Total: "3gb", 508 TotalInBytes: 3221225472, 509 Free: "816.2mb", 510 FreeInBytes: 855900160, 511 Used: "2.2gb", 512 UsedInBytes: 2365325312, 513 } 514 } 515 516 func NewNodesTransportResponseInfo(host string, addressPort string, version string) *NodesTransportResponseInfo { 517 return &NodesTransportResponseInfo{ 518 Name: host, 519 TransportAddress: addressPort, 520 HostName: addressPort, 521 IP: addressPort, 522 Version: version, 523 BuildFlavor: "oss", 524 BuildType: "tar", 525 BuildHash: "c4138e51121ef06a6404866cddc601906fe5c868", 526 } 527 } 528 529 func NewClusterStateResponseInfo(uuidVal string, indicesResponse map[string]interface{}) *ClusterStateResponseInfo { 530 return &ClusterStateResponseInfo{ 531 ClusterName: "siglens", 532 ClusterUUID: uuidVal, 533 MasterNode: "QXiD6Xa-RVqdZSLL8I_ZpQ", 534 Blocks: make(map[string]interface{}), 535 RoutingTable: indicesResponse, 536 } 537 } 538 539 func NewClusterStateBlocksInfo(uuidVal string) *ClusterStateBlocksInfo { 540 return &ClusterStateBlocksInfo{ 541 ClusterName: "siglens", 542 ClusterUUID: uuidVal, 543 Blocks: make(map[string]interface{}), 544 } 545 } 546 547 func NewNodesAllResponseInfo(host string, addressPort string, version string, osResponse NodesOSResponseInfo) *NodesAllResponseInfo { 548 return &NodesAllResponseInfo{ 549 Name: host, 550 TransportAddress: addressPort, 551 HostName: addressPort, 552 IP: addressPort, 553 Version: version, 554 BuildFlavor: "oss", 555 BuildType: "tar", 556 BuildHash: "c4138e51121ef06a6404866cddc601906fe5c868", 557 OSResponse: osResponse, 558 } 559 } 560 561 func NewNodesOSResponseInfo() *NodesOSResponseInfo { 562 return &NodesOSResponseInfo{ 563 RefreshInterval: "1s", 564 RefreshIntervalInMS: 1000, 565 Name: "Mac OS X", 566 PrettyName: "Mac OS X", 567 Arch: "aarch64", 568 Version: "11.3", 569 AvailableProcessors: 8, 570 AllocatedProcessors: 8, 571 } 572 } 573 574 func NewClusterHealthResponseInfo() *ClusterHealthResponseInfo { 575 return &ClusterHealthResponseInfo{ 576 ClusterName: "siglens", 577 Status: "green", 578 TimedOut: false, 579 NumberOfNodes: 1, 580 NumberOfDataNodes: 1, 581 ActivePrimaryShards: 0, 582 ActiveShards: 0, 583 RelocatingShards: 0, 584 InitiliazeShards: 0, 585 UnassignedShards: 0, 586 DelayedShards: 0, 587 NumberOfPendingTasks: 0, 588 NumberInFlightFetch: 0, 589 TaskMaxWaiting: 0, 590 ActiveShardsPercent: 100.0, 591 } 592 } 593 594 func NewNodesStatsMemResponse(heapcommitted string, heapCommittedBytes uint64, heapMax string, heapMaxBytes uint64, heapUsed string, heapUsedBytes uint64) *NodesStatsMemResponse { 595 return &NodesStatsMemResponse{ 596 HeapCommitted: heapcommitted, 597 HeapCommittedInBytes: heapCommittedBytes, 598 HeapMax: heapMax, 599 HeapMaxInBytes: heapMaxBytes, 600 HeapUsed: heapUsed, 601 HeapUsedInBytes: heapUsedBytes, 602 HeapUsedPercent: 2, 603 NonHeapCommitted: "80.6mb", 604 NonHeapCommittedInBytes: 84606976, 605 NonHeapUsed: "77.9mb", 606 NonHeapUsedInBytes: 81756968, 607 } 608 } 609 func NewDocsResponse(evenCount int) *DocsResponse { 610 return &DocsResponse{ 611 Count: evenCount, 612 Deleted: 0, 613 } 614 } 615 func NewStoreResponse(bytesReceivedCount uint64) *StoreResponse { 616 return &StoreResponse{ 617 SizeInBytes: bytesReceivedCount, 618 ReservedInBytes: 0, 619 } 620 } 621 func NewShardsItemsResponse(indexName string, allocationResponse map[string]interface{}) *ShardsItemsResponse { 622 return &ShardsItemsResponse{ 623 State: "STARTED", 624 Primary: true, 625 Node: "Ic2KfXpfQhaWhgeXAAcMYw", 626 RelocatingNode: nil, 627 Shard: 0, 628 Index: indexName, 629 AllocationId: allocationResponse, 630 } 631 } 632 func NewGreetVersion(esVersion string) GreetVersion { 633 return GreetVersion{ 634 Number: esVersion, 635 BuildFlavour: "oss", 636 BuildType: "tar", 637 BuildDate: "2021-10-07T21:56:19.031608185Z", 638 BuildHash: "83c34f456ae29d60e94d886e455e6a3409bba9ed", 639 BuildSnapshot: false, 640 LuceneVersion: "8.9.0", 641 MinimumWireCompatibilityVersion: "6.8.0", 642 MinimumIndexCompatibilityVersion: "6.0.0-beta1", 643 } 644 } 645 646 func NewGreetResponse(host string, uuidVal string, esVersion string) GreetResponse { 647 return GreetResponse{ 648 Name: host, 649 ClusterName: "siglens", 650 ClusterUUID: uuidVal, 651 Version: NewGreetVersion(esVersion), 652 } 653 } 654 func NewTotalFsResponse(total string, totalInBytes uint64, free string, freeInBytes uint64, available string, availableInBytes uint64) *TotalFsResponse { 655 return &TotalFsResponse{ 656 Total: total, 657 TotalInBytes: totalInBytes, 658 Free: free, 659 FreeInBytes: freeInBytes, 660 Available: available, 661 AvailableInBytes: totalInBytes - availableInBytes, 662 } 663 } 664 func NewVirtualMemResponse(totalVirtual string, totalVirtualBytes uint64) *VirtualMemResponse { 665 return &VirtualMemResponse{ 666 TotalVirtual: totalVirtual, 667 TotalVirtualInBytes: totalVirtualBytes, 668 } 669 } 670 func NewProcessCpuResponse(percent int) *ProcessCpuResponse { 671 return &ProcessCpuResponse{ 672 Percent: percent, 673 Total: "10.2s", 674 TotalInMillis: 10256, 675 } 676 } 677 func NewGetMasterResponse(id string, host string, node string) *GetMasterResponse { 678 return &GetMasterResponse{ 679 Id: id, 680 Host: host, 681 IP: host, 682 Node: node, 683 } 684 } 685 func NewNodesStatsIdInfo(timestamp int64, hostname string, addressPort string, ipAddress string) *NodesStatsIdInfo { 686 return &NodesStatsIdInfo{ 687 Timestamp: timestamp, 688 Name: hostname, 689 TransportAddress: addressPort, 690 Host: ipAddress, 691 IP: ipAddress, 692 } 693 } 694 695 func NewNodesStatsIngestInfo(hostname string, addressPort string, 696 ipAddress string, version string, ingestFeats map[string]interface{}) *NodesStatsIngestInfo { 697 return &NodesStatsIngestInfo{ 698 Name: hostname, 699 TransportAddress: addressPort, 700 Host: ipAddress, 701 IP: ipAddress, 702 Version: version, 703 BuildFlavour: "oss", 704 BuildType: "tar", 705 BuildHash: "83c34f456ae29d60e94d886e455e6a3409bba9ed", 706 Roles: []string{"data", "ingest", "master", "remote_cluster_client"}, 707 Ingest: ingestFeats, 708 } 709 } 710 711 func NewDeleteIndexErrorResponseInfo(indexName string) *DeleteIndexErrorResponseInfo { 712 return &DeleteIndexErrorResponseInfo{ 713 Type: "index_not_found_exception", 714 Reason: "no such index" + "[" + indexName + "]", 715 ResourceType: "index_or_alias", 716 ResourceId: indexName, 717 IndexUUID: "_na_", 718 Index: indexName, 719 } 720 } 721 722 func NewAutoCompleteDataInfo(columnNames []string, measureFunctions []string) *AutoCompleteDataInfo { 723 return &AutoCompleteDataInfo{ 724 ColumnNames: columnNames, 725 MeasureFunctions: measureFunctions, 726 } 727 } 728 729 func (eo *HttpServerESResponse) GetHits() uint64 { 730 switch t := eo.Total.(type) { 731 case uint64: 732 return t 733 case HitsCount: 734 return t.Value 735 case map[string]interface{}: 736 retVal, ok := t["value"] 737 if !ok { 738 log.Infof("Tried to get hits for a map with no 'value' key! Map: %v", retVal) 739 return 0 740 } 741 switch hit := retVal.(type) { 742 case float64: 743 return uint64(hit) 744 case uint64: 745 return hit 746 case int64: 747 return uint64(hit) 748 default: 749 log.Infof("Map value is not a supported type!: %v %T", hit, hit) 750 return 0 751 } 752 default: 753 log.Infof("Tried to get hits for unsupported type %T", t) 754 return 0 755 } 756 } 757 758 func ExtractBearerToken(ctx *fasthttp.RequestCtx) (string, error) { 759 authHeader := ctx.Request.Header.Peek("Authorization") 760 authToken := strings.Split(string(authHeader), "Bearer ") 761 if len(authToken) != 2 { 762 return "", errors.New("malformed bearer token") 763 } 764 jwtToken := authToken[1] 765 return jwtToken, nil 766 } 767 768 // Reads the basic authorization from the request to extract the username and 769 // password. Then hashes the username and password and compares with the 770 // expected hash values. 771 // Returns true if the hashes match. Returns false if the hashes do not match 772 // or if basic authentication credentials are not provided in the request. 773 // The provided usernameHash and passwordHash fields should be hashed with 774 // the xxhash.Sum64 algorithm. 775 // Basic authentication is defined at https://www.rfc-editor.org/rfc/rfc2617#section-2 776 func VerifyBasicAuth(ctx *fasthttp.RequestCtx, usernameHash uint64, passwordHash uint64) bool { 777 auth := string(ctx.Request.Header.Peek("Authorization")) 778 if len(auth) == 0 { 779 return false 780 } 781 782 // The auth string should be something like: 783 // Basic dXNlcm5hbWU6cGFzc3dvcmQK 784 const prefix = "Basic " 785 if !strings.HasPrefix(auth, prefix) { 786 return false 787 } 788 789 base64Encoding := auth[len(prefix):] 790 decoded, err := base64.StdEncoding.DecodeString(base64Encoding) 791 if err != nil { 792 log.Errorf("VerifyBasicAuth: failed to decode %s: %v", base64Encoding, err) 793 } 794 795 // The decoded string should be something like: 796 // username:password 797 username, password, foundColon := strings.Cut(string(decoded), ":") 798 if !foundColon { 799 return false 800 } 801 802 usernameMatches := (xxhash.Sum64String(username) == usernameHash) 803 passwordMatches := (xxhash.Sum64String(password) == passwordHash) 804 805 return usernameMatches && passwordMatches 806 } 807 808 // Use the MAC address as a computer-specific identifier. If it is not available, use the hostname instead. 809 func GetSpecificIdentifier() (string, error) { 810 interfaces, err := net.Interfaces() 811 if err != nil { 812 return "", fmt.Errorf("GetSpecificIdentifier: %v", err) 813 } 814 815 for _, iface := range interfaces { 816 if len(iface.HardwareAddr.String()) != 0 { 817 return iface.HardwareAddr.String(), nil 818 } 819 } 820 821 hostname, err := os.Hostname() 822 if err != nil { 823 return "", nil 824 } 825 826 return hostname, nil 827 } 828 829 func GetDecodedBody(ctx *fasthttp.RequestCtx) ([]byte, error) { 830 contentEncoding := string(ctx.Request.Header.Peek("Content-Encoding")) 831 switch contentEncoding { 832 case "": 833 return ctx.Request.Body(), nil 834 case "gzip": 835 return gunzip(ctx.Request.Body()) 836 default: 837 return nil, fmt.Errorf("GetDecodedBody: unsupported content encoding: %s", contentEncoding) 838 } 839 } 840 841 func gunzip(data []byte) ([]byte, error) { 842 return fasthttp.AppendGunzipBytes(nil, data) 843 } 844 845 // This takes a group of JSON objects (not inside a JSON array) and splits them 846 // into individual JSON objects. 847 func ExtractSeriesOfJsonObjects(body []byte) ([]map[string]interface{}, error) { 848 var objects []map[string]interface{} 849 decoder := json.NewDecoder(bytes.NewReader(body)) 850 851 for { 852 var obj map[string]interface{} 853 if err := decoder.Decode(&obj); err != nil { 854 // If we reach the end of the input, break the loop. 855 if err == io.EOF { 856 break 857 } 858 859 return nil, fmt.Errorf("ExtractSeriesOfJsonObjects: error decoding JSON: %v", err) 860 } 861 862 objects = append(objects, obj) 863 } 864 865 return objects, nil 866 }