1// Copyright 2012-present Oliver Eilhard. All rights reserved. 2// Use of this source code is governed by a MIT-license. 3// See http://olivere.mit-license.org/license.txt for details. 4 5package elastic 6 7import ( 8 "context" 9 "fmt" 10 "net/http" 11 "net/url" 12 "strings" 13 "time" 14 15 "github.com/olivere/elastic/v7/uritemplates" 16) 17 18// NodesInfoService allows to retrieve one or more or all of the 19// cluster nodes information. 20// It is documented at https://www.elastic.co/guide/en/elasticsearch/reference/7.0/cluster-nodes-info.html. 21type NodesInfoService struct { 22 client *Client 23 24 pretty *bool // pretty format the returned JSON response 25 human *bool // return human readable values for statistics 26 errorTrace *bool // include the stack trace of returned errors 27 filterPath []string // list of filters used to reduce the response 28 headers http.Header // custom request-level HTTP headers 29 30 nodeId []string 31 metric []string 32 flatSettings *bool 33} 34 35// NewNodesInfoService creates a new NodesInfoService. 36func NewNodesInfoService(client *Client) *NodesInfoService { 37 return &NodesInfoService{ 38 client: client, 39 } 40} 41 42// Pretty tells Elasticsearch whether to return a formatted JSON response. 43func (s *NodesInfoService) Pretty(pretty bool) *NodesInfoService { 44 s.pretty = &pretty 45 return s 46} 47 48// Human specifies whether human readable values should be returned in 49// the JSON response, e.g. "7.5mb". 50func (s *NodesInfoService) Human(human bool) *NodesInfoService { 51 s.human = &human 52 return s 53} 54 55// ErrorTrace specifies whether to include the stack trace of returned errors. 56func (s *NodesInfoService) ErrorTrace(errorTrace bool) *NodesInfoService { 57 s.errorTrace = &errorTrace 58 return s 59} 60 61// FilterPath specifies a list of filters used to reduce the response. 62func (s *NodesInfoService) FilterPath(filterPath ...string) *NodesInfoService { 63 s.filterPath = filterPath 64 return s 65} 66 67// Header adds a header to the request. 68func (s *NodesInfoService) Header(name string, value string) *NodesInfoService { 69 if s.headers == nil { 70 s.headers = http.Header{} 71 } 72 s.headers.Add(name, value) 73 return s 74} 75 76// Headers specifies the headers of the request. 77func (s *NodesInfoService) Headers(headers http.Header) *NodesInfoService { 78 s.headers = headers 79 return s 80} 81 82// NodeId is a list of node IDs or names to limit the returned information. 83// Use "_local" to return information from the node you're connecting to, 84// leave empty to get information from all nodes. 85func (s *NodesInfoService) NodeId(nodeId ...string) *NodesInfoService { 86 s.nodeId = append(s.nodeId, nodeId...) 87 return s 88} 89 90// Metric is a list of metrics you wish returned. Leave empty to return all. 91// Valid metrics are: settings, os, process, jvm, thread_pool, network, 92// transport, http, and plugins. 93func (s *NodesInfoService) Metric(metric ...string) *NodesInfoService { 94 s.metric = append(s.metric, metric...) 95 return s 96} 97 98// FlatSettings returns settings in flat format (default: false). 99func (s *NodesInfoService) FlatSettings(flatSettings bool) *NodesInfoService { 100 s.flatSettings = &flatSettings 101 return s 102} 103 104// buildURL builds the URL for the operation. 105func (s *NodesInfoService) buildURL() (string, url.Values, error) { 106 var nodeId, metric string 107 108 if len(s.nodeId) > 0 { 109 nodeId = strings.Join(s.nodeId, ",") 110 } else { 111 nodeId = "_all" 112 } 113 114 if len(s.metric) > 0 { 115 metric = strings.Join(s.metric, ",") 116 } else { 117 metric = "_all" 118 } 119 120 // Build URL 121 path, err := uritemplates.Expand("/_nodes/{node_id}/{metric}", map[string]string{ 122 "node_id": nodeId, 123 "metric": metric, 124 }) 125 if err != nil { 126 return "", url.Values{}, err 127 } 128 129 // Add query string parameters 130 params := url.Values{} 131 if v := s.pretty; v != nil { 132 params.Set("pretty", fmt.Sprint(*v)) 133 } 134 if v := s.human; v != nil { 135 params.Set("human", fmt.Sprint(*v)) 136 } 137 if v := s.errorTrace; v != nil { 138 params.Set("error_trace", fmt.Sprint(*v)) 139 } 140 if len(s.filterPath) > 0 { 141 params.Set("filter_path", strings.Join(s.filterPath, ",")) 142 } 143 if s.flatSettings != nil { 144 params.Set("flat_settings", fmt.Sprintf("%v", *s.flatSettings)) 145 } 146 return path, params, nil 147} 148 149// Validate checks if the operation is valid. 150func (s *NodesInfoService) Validate() error { 151 return nil 152} 153 154// Do executes the operation. 155func (s *NodesInfoService) Do(ctx context.Context) (*NodesInfoResponse, error) { 156 // Check pre-conditions 157 if err := s.Validate(); err != nil { 158 return nil, err 159 } 160 161 // Get URL for request 162 path, params, err := s.buildURL() 163 if err != nil { 164 return nil, err 165 } 166 167 // Get HTTP response 168 res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ 169 Method: "GET", 170 Path: path, 171 Params: params, 172 Headers: s.headers, 173 }) 174 if err != nil { 175 return nil, err 176 } 177 178 // Return operation response 179 ret := new(NodesInfoResponse) 180 if err := s.client.decoder.Decode(res.Body, ret); err != nil { 181 return nil, err 182 } 183 return ret, nil 184} 185 186// NodesInfoResponse is the response of NodesInfoService.Do. 187type NodesInfoResponse struct { 188 ClusterName string `json:"cluster_name"` 189 Nodes map[string]*NodesInfoNode `json:"nodes"` 190} 191 192// NodesInfoNode represents information about a node in the cluster. 193type NodesInfoNode struct { 194 // Name of the node, e.g. "Mister Fear" 195 Name string `json:"name"` 196 // TransportAddress, e.g. "127.0.0.1:9300" 197 TransportAddress string `json:"transport_address"` 198 // Host is the host name, e.g. "macbookair" 199 Host string `json:"host"` 200 // IP is the IP address, e.g. "192.168.1.2" 201 IP string `json:"ip"` 202 // Version is the Elasticsearch version running on the node, e.g. "1.4.3" 203 Version string `json:"version"` 204 // BuildHash is the Elasticsearch build bash, e.g. "36a29a7" 205 BuildHash string `json:"build_hash"` 206 207 // TotalIndexingBuffer represents the total heap allowed to be used to 208 // hold recently indexed documents before they must be written to disk. 209 TotalIndexingBuffer int64 `json:"total_indexing_buffer"` // e.g. 16gb 210 // TotalIndexingBufferInBytes is the same as TotalIndexingBuffer, but 211 // expressed in bytes. 212 TotalIndexingBufferInBytes string `json:"total_indexing_buffer_in_bytes"` 213 214 // Roles of the node, e.g. [master, ingest, data] 215 Roles []string `json:"roles"` 216 217 // Attributes of the node. 218 Attributes map[string]string `json:"attributes"` 219 220 // Settings of the node, e.g. paths and pidfile. 221 Settings map[string]interface{} `json:"settings"` 222 223 // OS information, e.g. CPU and memory. 224 OS *NodesInfoNodeOS `json:"os"` 225 226 // Process information, e.g. max file descriptors. 227 Process *NodesInfoNodeProcess `json:"process"` 228 229 // JVM information, e.g. VM version. 230 JVM *NodesInfoNodeJVM `json:"jvm"` 231 232 // ThreadPool information. 233 ThreadPool *NodesInfoNodeThreadPool `json:"thread_pool"` 234 235 // Network information. 236 Transport *NodesInfoNodeTransport `json:"transport"` 237 238 // HTTP information. 239 HTTP *NodesInfoNodeHTTP `json:"http"` 240 241 // Plugins information. 242 Plugins []*NodesInfoNodePlugin `json:"plugins"` 243 244 // Modules information. 245 Modules []*NodesInfoNodeModule `json:"modules"` 246 247 // Ingest information. 248 Ingest *NodesInfoNodeIngest `json:"ingest"` 249} 250 251// HasRole returns true if the node fulfills the given role. 252func (n *NodesInfoNode) HasRole(role string) bool { 253 for _, r := range n.Roles { 254 if r == role { 255 return true 256 } 257 } 258 return false 259} 260 261// IsMaster returns true if the node is a master node. 262func (n *NodesInfoNode) IsMaster() bool { 263 return n.HasRole("master") 264} 265 266// IsData returns true if the node is a data node. 267func (n *NodesInfoNode) IsData() bool { 268 return n.HasRole("data") 269} 270 271// IsIngest returns true if the node is an ingest node. 272func (n *NodesInfoNode) IsIngest() bool { 273 return n.HasRole("ingest") 274} 275 276// NodesInfoNodeOS represents OS-specific details about a node. 277type NodesInfoNodeOS struct { 278 RefreshInterval string `json:"refresh_interval"` // e.g. 1s 279 RefreshIntervalInMillis int `json:"refresh_interval_in_millis"` // e.g. 1000 280 Name string `json:"name"` // e.g. Linux 281 Arch string `json:"arch"` // e.g. amd64 282 Version string `json:"version"` // e.g. 4.9.87-linuxkit-aufs 283 AvailableProcessors int `json:"available_processors"` // e.g. 4 284 AllocatedProcessors int `json:"allocated_processors"` // e.g. 4 285} 286 287// NodesInfoNodeProcess represents process-related information. 288type NodesInfoNodeProcess struct { 289 RefreshInterval string `json:"refresh_interval"` // e.g. 1s 290 RefreshIntervalInMillis int64 `json:"refresh_interval_in_millis"` // e.g. 1000 291 ID int `json:"id"` // process id, e.g. 87079 292 Mlockall bool `json:"mlockall"` // e.g. false 293} 294 295// NodesInfoNodeJVM represents JVM-related information. 296type NodesInfoNodeJVM struct { 297 PID int `json:"pid"` // process id, e.g. 87079 298 Version string `json:"version"` // e.g. "1.8.0_161" 299 VMName string `json:"vm_name"` // e.g. "OpenJDK 64-Bit Server VM" 300 VMVersion string `json:"vm_version"` // e.g. "25.161-b14" 301 VMVendor string `json:"vm_vendor"` // e.g. "Oracle Corporation" 302 StartTime time.Time `json:"start_time"` // e.g. "2018-03-30T11:06:36.644Z" 303 StartTimeInMillis int64 `json:"start_time_in_millis"` // e.g. 1522407996644 304 305 // Mem information 306 Mem struct { 307 HeapInit string `json:"heap_init"` // e.g. "1gb" 308 HeapInitInBytes int `json:"heap_init_in_bytes"` // e.g. 1073741824 309 HeapMax string `json:"heap_max"` // e.g. "1007.3mb" 310 HeapMaxInBytes int `json:"heap_max_in_bytes"` // e.g. 1056309248 311 NonHeapInit string `json:"non_heap_init"` // e.g. "2.4mb" 312 NonHeapInitInBytes int `json:"non_heap_init_in_bytes"` // e.g. 2555904 313 NonHeapMax string `json:"non_heap_max"` // e.g. "0b" 314 NonHeapMaxInBytes int `json:"non_heap_max_in_bytes"` // e.g. 0 315 DirectMax string `json:"direct_max"` // e.g. "1007.3mb" 316 DirectMaxInBytes int `json:"direct_max_in_bytes"` // e.g. 1056309248 317 } `json:"mem"` 318 319 GCCollectors []string `json:"gc_collectors"` // e.g. ["ParNew", "ConcurrentMarkSweep"] 320 MemoryPools []string `json:"memory_pools"` // e.g. ["Code Cache", "Metaspace", "Compressed Class Space", "Par Eden Space", "Par Survivor Space", "CMS Old Gen"] 321 322 // UsingCompressedOrdinaryObjectPointers should be a bool, but is a 323 // string in 6.2.3. We use an interface{} for now so that it won't break 324 // when this will be fixed in later versions of Elasticsearch. 325 UsingCompressedOrdinaryObjectPointers interface{} `json:"using_compressed_ordinary_object_pointers"` 326 327 InputArguments []string `json:"input_arguments"` // e.g. ["-Xms1g", "-Xmx1g" ...] 328} 329 330// NodesInfoNodeThreadPool represents information about the thread pool. 331type NodesInfoNodeThreadPool struct { 332 ForceMerge *NodesInfoNodeThreadPoolSection `json:"force_merge"` 333 FetchShardStarted *NodesInfoNodeThreadPoolSection `json:"fetch_shard_started"` 334 Listener *NodesInfoNodeThreadPoolSection `json:"listener"` 335 Index *NodesInfoNodeThreadPoolSection `json:"index"` 336 Refresh *NodesInfoNodeThreadPoolSection `json:"refresh"` 337 Generic *NodesInfoNodeThreadPoolSection `json:"generic"` 338 Warmer *NodesInfoNodeThreadPoolSection `json:"warmer"` 339 Search *NodesInfoNodeThreadPoolSection `json:"search"` 340 Flush *NodesInfoNodeThreadPoolSection `json:"flush"` 341 FetchShardStore *NodesInfoNodeThreadPoolSection `json:"fetch_shard_store"` 342 Management *NodesInfoNodeThreadPoolSection `json:"management"` 343 Get *NodesInfoNodeThreadPoolSection `json:"get"` 344 Bulk *NodesInfoNodeThreadPoolSection `json:"bulk"` 345 Snapshot *NodesInfoNodeThreadPoolSection `json:"snapshot"` 346 347 Percolate *NodesInfoNodeThreadPoolSection `json:"percolate"` // check 348 Bench *NodesInfoNodeThreadPoolSection `json:"bench"` // check 349 Suggest *NodesInfoNodeThreadPoolSection `json:"suggest"` // deprecated 350 Optimize *NodesInfoNodeThreadPoolSection `json:"optimize"` // deprecated 351 Merge *NodesInfoNodeThreadPoolSection `json:"merge"` // deprecated 352} 353 354// NodesInfoNodeThreadPoolSection represents information about a certain 355// type of thread pool, e.g. for indexing or searching. 356type NodesInfoNodeThreadPoolSection struct { 357 Type string `json:"type"` // e.g. fixed, scaling, or fixed_auto_queue_size 358 Min int `json:"min"` // e.g. 4 359 Max int `json:"max"` // e.g. 4 360 KeepAlive string `json:"keep_alive"` // e.g. "5m" 361 QueueSize interface{} `json:"queue_size"` // e.g. "1k" or -1 362} 363 364// NodesInfoNodeTransport represents transport-related information. 365type NodesInfoNodeTransport struct { 366 BoundAddress []string `json:"bound_address"` 367 PublishAddress string `json:"publish_address"` 368 Profiles map[string]*NodesInfoNodeTransportProfile `json:"profiles"` 369} 370 371// NodesInfoNodeTransportProfile represents a transport profile. 372type NodesInfoNodeTransportProfile struct { 373 BoundAddress []string `json:"bound_address"` 374 PublishAddress string `json:"publish_address"` 375} 376 377// NodesInfoNodeHTTP represents HTTP-related information. 378type NodesInfoNodeHTTP struct { 379 BoundAddress []string `json:"bound_address"` // e.g. ["127.0.0.1:9200", "[fe80::1]:9200", "[::1]:9200"] 380 PublishAddress string `json:"publish_address"` // e.g. "127.0.0.1:9300" 381 MaxContentLength string `json:"max_content_length"` // e.g. "100mb" 382 MaxContentLengthInBytes int64 `json:"max_content_length_in_bytes"` 383} 384 385// NodesInfoNodePlugin represents information about a plugin. 386type NodesInfoNodePlugin struct { 387 Name string `json:"name"` // e.g. "ingest-geoip" 388 Version string `json:"version"` // e.g. "6.2.3" 389 ElasticsearchVersion string `json:"elasticsearch_version"` 390 JavaVersion string `json:"java_version"` 391 Description string `json:"description"` // e.g. "Ingest processor ..." 392 Classname string `json:"classname"` // e.g. "org.elasticsearch.ingest.geoip.IngestGeoIpPlugin" 393 ExtendedPlugins []string `json:"extended_plugins"` 394 HasNativeController bool `json:"has_native_controller"` 395 RequiresKeystore bool `json:"requires_keystore"` 396} 397 398// NodesInfoNodeModule represents information about a module. 399type NodesInfoNodeModule struct { 400 Name string `json:"name"` // e.g. "ingest-geoip" 401 Version string `json:"version"` // e.g. "6.2.3" 402 ElasticsearchVersion string `json:"elasticsearch_version"` 403 JavaVersion string `json:"java_version"` 404 Description string `json:"description"` // e.g. "Ingest processor ..." 405 Classname string `json:"classname"` // e.g. "org.elasticsearch.ingest.geoip.IngestGeoIpPlugin" 406 ExtendedPlugins []string `json:"extended_plugins"` 407 HasNativeController bool `json:"has_native_controller"` 408 RequiresKeystore bool `json:"requires_keystore"` 409} 410 411// NodesInfoNodeIngest represents information about the ingester. 412type NodesInfoNodeIngest struct { 413 Processors []*NodesInfoNodeIngestProcessorInfo `json:"processors"` 414} 415 416// NodesInfoNodeIngestProcessorInfo represents ingest processor info. 417type NodesInfoNodeIngestProcessorInfo struct { 418 Type string `json:"type"` // e.g. append, convert, date etc. 419} 420