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
14	"github.com/olivere/elastic/v7/uritemplates"
15)
16
17// ClusterStatsService is documented at
18// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/cluster-stats.html.
19type ClusterStatsService struct {
20	client *Client
21
22	pretty     *bool       // pretty format the returned JSON response
23	human      *bool       // return human readable values for statistics
24	errorTrace *bool       // include the stack trace of returned errors
25	filterPath []string    // list of filters used to reduce the response
26	headers    http.Header // custom request-level HTTP headers
27
28	nodeId       []string
29	flatSettings *bool
30}
31
32// NewClusterStatsService creates a new ClusterStatsService.
33func NewClusterStatsService(client *Client) *ClusterStatsService {
34	return &ClusterStatsService{
35		client: client,
36		nodeId: make([]string, 0),
37	}
38}
39
40// Pretty tells Elasticsearch whether to return a formatted JSON response.
41func (s *ClusterStatsService) Pretty(pretty bool) *ClusterStatsService {
42	s.pretty = &pretty
43	return s
44}
45
46// Human specifies whether human readable values should be returned in
47// the JSON response, e.g. "7.5mb".
48func (s *ClusterStatsService) Human(human bool) *ClusterStatsService {
49	s.human = &human
50	return s
51}
52
53// ErrorTrace specifies whether to include the stack trace of returned errors.
54func (s *ClusterStatsService) ErrorTrace(errorTrace bool) *ClusterStatsService {
55	s.errorTrace = &errorTrace
56	return s
57}
58
59// FilterPath specifies a list of filters used to reduce the response.
60func (s *ClusterStatsService) FilterPath(filterPath ...string) *ClusterStatsService {
61	s.filterPath = filterPath
62	return s
63}
64
65// Header adds a header to the request.
66func (s *ClusterStatsService) Header(name string, value string) *ClusterStatsService {
67	if s.headers == nil {
68		s.headers = http.Header{}
69	}
70	s.headers.Add(name, value)
71	return s
72}
73
74// Headers specifies the headers of the request.
75func (s *ClusterStatsService) Headers(headers http.Header) *ClusterStatsService {
76	s.headers = headers
77	return s
78}
79
80// NodeId is documented as: A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes.
81func (s *ClusterStatsService) NodeId(nodeId []string) *ClusterStatsService {
82	s.nodeId = nodeId
83	return s
84}
85
86// FlatSettings is documented as: Return settings in flat format (default: false).
87func (s *ClusterStatsService) FlatSettings(flatSettings bool) *ClusterStatsService {
88	s.flatSettings = &flatSettings
89	return s
90}
91
92// buildURL builds the URL for the operation.
93func (s *ClusterStatsService) buildURL() (string, url.Values, error) {
94	// Build URL
95	var err error
96	var path string
97
98	if len(s.nodeId) > 0 {
99		path, err = uritemplates.Expand("/_cluster/stats/nodes/{node_id}", map[string]string{
100			"node_id": strings.Join(s.nodeId, ","),
101		})
102		if err != nil {
103			return "", url.Values{}, err
104		}
105	} else {
106		path, err = uritemplates.Expand("/_cluster/stats", map[string]string{})
107		if err != nil {
108			return "", url.Values{}, err
109		}
110	}
111
112	// Add query string parameters
113	params := url.Values{}
114	if v := s.pretty; v != nil {
115		params.Set("pretty", fmt.Sprint(*v))
116	}
117	if v := s.human; v != nil {
118		params.Set("human", fmt.Sprint(*v))
119	}
120	if v := s.errorTrace; v != nil {
121		params.Set("error_trace", fmt.Sprint(*v))
122	}
123	if len(s.filterPath) > 0 {
124		params.Set("filter_path", strings.Join(s.filterPath, ","))
125	}
126	if s.flatSettings != nil {
127		params.Set("flat_settings", fmt.Sprintf("%v", *s.flatSettings))
128	}
129	return path, params, nil
130}
131
132// Validate checks if the operation is valid.
133func (s *ClusterStatsService) Validate() error {
134	return nil
135}
136
137// Do executes the operation.
138func (s *ClusterStatsService) Do(ctx context.Context) (*ClusterStatsResponse, error) {
139	// Check pre-conditions
140	if err := s.Validate(); err != nil {
141		return nil, err
142	}
143
144	// Get URL for request
145	path, params, err := s.buildURL()
146	if err != nil {
147		return nil, err
148	}
149
150	// Get HTTP response
151	res, err := s.client.PerformRequest(ctx, PerformRequestOptions{
152		Method:  "GET",
153		Path:    path,
154		Params:  params,
155		Headers: s.headers,
156	})
157	if err != nil {
158		return nil, err
159	}
160
161	// Return operation response
162	ret := new(ClusterStatsResponse)
163	if err := s.client.decoder.Decode(res.Body, ret); err != nil {
164		return nil, err
165	}
166	return ret, nil
167}
168
169// ClusterStatsResponse is the response of ClusterStatsService.Do.
170type ClusterStatsResponse struct {
171	NodesStats  *ClusterStatsNodesResponse `json:"_nodes,omitempty"`
172	Timestamp   int64                      `json:"timestamp"`
173	ClusterName string                     `json:"cluster_name"`
174	ClusterUUID string                     `json:"cluster_uuid"`
175	Status      string                     `json:"status,omitempty"` // e.g. green
176	Indices     *ClusterStatsIndices       `json:"indices"`
177	Nodes       *ClusterStatsNodes         `json:"nodes"`
178}
179
180type ClusterStatsNodesResponse struct {
181	Total      int                    `json:"total"`
182	Successful int                    `json:"successful"`
183	Failed     int                    `json:"failed"`
184	Failures   []*FailedNodeException `json:"failures,omitempty"`
185}
186
187type ClusterStatsIndices struct {
188	Count      int                            `json:"count"` // number of indices
189	Shards     *ClusterStatsIndicesShards     `json:"shards"`
190	Docs       *ClusterStatsIndicesDocs       `json:"docs"`
191	Store      *ClusterStatsIndicesStore      `json:"store"`
192	FieldData  *ClusterStatsIndicesFieldData  `json:"fielddata"`
193	QueryCache *ClusterStatsIndicesQueryCache `json:"query_cache"`
194	Completion *ClusterStatsIndicesCompletion `json:"completion"`
195	Segments   *IndexStatsSegments            `json:"segments"`
196}
197
198type ClusterStatsIndicesShards struct {
199	Total       int                             `json:"total"`
200	Primaries   int                             `json:"primaries"`
201	Replication float64                         `json:"replication"`
202	Index       *ClusterStatsIndicesShardsIndex `json:"index"`
203}
204
205type ClusterStatsIndicesShardsIndex struct {
206	Shards      *ClusterStatsIndicesShardsIndexIntMinMax     `json:"shards"`
207	Primaries   *ClusterStatsIndicesShardsIndexIntMinMax     `json:"primaries"`
208	Replication *ClusterStatsIndicesShardsIndexFloat64MinMax `json:"replication"`
209}
210
211type ClusterStatsIndicesShardsIndexIntMinMax struct {
212	Min int     `json:"min"`
213	Max int     `json:"max"`
214	Avg float64 `json:"avg"`
215}
216
217type ClusterStatsIndicesShardsIndexFloat64MinMax struct {
218	Min float64 `json:"min"`
219	Max float64 `json:"max"`
220	Avg float64 `json:"avg"`
221}
222
223type ClusterStatsIndicesDocs struct {
224	Count   int `json:"count"`
225	Deleted int `json:"deleted"`
226}
227
228type ClusterStatsIndicesStore struct {
229	Size        string `json:"size"` // e.g. "5.3gb"
230	SizeInBytes int64  `json:"size_in_bytes"`
231}
232
233type ClusterStatsIndicesFieldData struct {
234	MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
235	MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
236	Evictions         int64  `json:"evictions"`
237	Fields            map[string]struct {
238		MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
239		MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
240	} `json:"fields,omitempty"`
241}
242
243type ClusterStatsIndicesQueryCache struct {
244	MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
245	MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
246	TotalCount        int64  `json:"total_count"`
247	HitCount          int64  `json:"hit_count"`
248	MissCount         int64  `json:"miss_count"`
249	CacheSize         int64  `json:"cache_size"`
250	CacheCount        int64  `json:"cache_count"`
251	Evictions         int64  `json:"evictions"`
252}
253
254type ClusterStatsIndicesCompletion struct {
255	Size        string `json:"size"` // e.g. "61.3kb"
256	SizeInBytes int64  `json:"size_in_bytes"`
257	Fields      map[string]struct {
258		Size        string `json:"size"` // e.g. "61.3kb"
259		SizeInBytes int64  `json:"size_in_bytes"`
260	} `json:"fields,omitempty"`
261}
262
263type ClusterStatsIndicesSegmentsFile struct {
264	Size        string `json:"size"` // e.g. "61.3kb"
265	SizeInBytes int64  `json:"size_in_bytes"`
266	Description string `json:"description,omitempty"`
267}
268
269// ---
270
271type ClusterStatsNodes struct {
272	Count    *ClusterStatsNodesCount        `json:"count"`
273	Versions []string                       `json:"versions"`
274	OS       *ClusterStatsNodesOsStats      `json:"os"`
275	Process  *ClusterStatsNodesProcessStats `json:"process"`
276	JVM      *ClusterStatsNodesJvmStats     `json:"jvm"`
277	FS       *ClusterStatsNodesFsStats      `json:"fs"`
278	Plugins  []*ClusterStatsNodesPlugin     `json:"plugins"`
279
280	NetworkTypes   *ClusterStatsNodesNetworkTypes   `json:"network_types"`
281	DiscoveryTypes *ClusterStatsNodesDiscoveryTypes `json:"discovery_types"`
282	PackagingTypes *ClusterStatsNodesPackagingTypes `json:"packaging_types"`
283}
284
285type ClusterStatsNodesCount struct {
286	Total            int `json:"total"`
287	Data             int `json:"data"`
288	CoordinatingOnly int `json:"coordinating_only"`
289	Master           int `json:"master"`
290	Ingest           int `json:"ingest"`
291}
292
293type ClusterStatsNodesOsStats struct {
294	AvailableProcessors int `json:"available_processors"`
295	AllocatedProcessors int `json:"allocated_processors"`
296	Names               []struct {
297		Name  string `json:"name"`
298		Value int    `json:"count"`
299	} `json:"names"`
300	PrettyNames []struct {
301		PrettyName string `json:"pretty_name"`
302		Value      int    `json:"count"`
303	} `json:"pretty_names"`
304	Mem *ClusterStatsNodesOsStatsMem `json:"mem"`
305	// CPU []*ClusterStatsNodesOsStatsCPU `json:"cpu"`
306}
307
308type ClusterStatsNodesOsStatsMem struct {
309	Total        string `json:"total"` // e.g. "16gb"
310	TotalInBytes int64  `json:"total_in_bytes"`
311	Free         string `json:"free"` // e.g. "12gb"
312	FreeInBytes  int64  `json:"free_in_bytes"`
313	Used         string `json:"used"` // e.g. "4gb"
314	UsedInBytes  int64  `json:"used_in_bytes"`
315	FreePercent  int    `json:"free_percent"`
316	UsedPercent  int    `json:"used_percent"`
317}
318
319type ClusterStatsNodesOsStatsCPU struct {
320	Vendor           string `json:"vendor"`
321	Model            string `json:"model"`
322	MHz              int    `json:"mhz"`
323	TotalCores       int    `json:"total_cores"`
324	TotalSockets     int    `json:"total_sockets"`
325	CoresPerSocket   int    `json:"cores_per_socket"`
326	CacheSize        string `json:"cache_size"` // e.g. "256b"
327	CacheSizeInBytes int64  `json:"cache_size_in_bytes"`
328	Count            int    `json:"count"`
329}
330
331type ClusterStatsNodesProcessStats struct {
332	CPU                 *ClusterStatsNodesProcessStatsCPU                 `json:"cpu"`
333	OpenFileDescriptors *ClusterStatsNodesProcessStatsOpenFileDescriptors `json:"open_file_descriptors"`
334}
335
336type ClusterStatsNodesProcessStatsCPU struct {
337	Percent float64 `json:"percent"`
338}
339
340type ClusterStatsNodesProcessStatsOpenFileDescriptors struct {
341	Min int64 `json:"min"`
342	Max int64 `json:"max"`
343	Avg int64 `json:"avg"`
344}
345
346type ClusterStatsNodesJvmStats struct {
347	MaxUptime         string                              `json:"max_uptime"` // e.g. "5h"
348	MaxUptimeInMillis int64                               `json:"max_uptime_in_millis"`
349	Versions          []*ClusterStatsNodesJvmStatsVersion `json:"versions"`
350	Mem               *ClusterStatsNodesJvmStatsMem       `json:"mem"`
351	Threads           int64                               `json:"threads"`
352}
353
354type ClusterStatsNodesJvmStatsVersion struct {
355	Version         string `json:"version"`    // e.g. "1.8.0_45"
356	VMName          string `json:"vm_name"`    // e.g. "Java HotSpot(TM) 64-Bit Server VM"
357	VMVersion       string `json:"vm_version"` // e.g. "25.45-b02"
358	VMVendor        string `json:"vm_vendor"`  // e.g. "Oracle Corporation"
359	BundledJDK      bool   `json:"bundled_jdk"`
360	UsingBundledJDK bool   `json:"using_bundled_jdk"`
361	Count           int    `json:"count"`
362}
363
364type ClusterStatsNodesJvmStatsMem struct {
365	HeapUsed        string `json:"heap_used"`
366	HeapUsedInBytes int64  `json:"heap_used_in_bytes"`
367	HeapMax         string `json:"heap_max"`
368	HeapMaxInBytes  int64  `json:"heap_max_in_bytes"`
369}
370
371type ClusterStatsNodesFsStats struct {
372	Path                 string `json:"path"`
373	Mount                string `json:"mount"`
374	Dev                  string `json:"dev"`
375	Total                string `json:"total"` // e.g. "930.7gb"`
376	TotalInBytes         int64  `json:"total_in_bytes"`
377	Free                 string `json:"free"` // e.g. "930.7gb"`
378	FreeInBytes          int64  `json:"free_in_bytes"`
379	Available            string `json:"available"` // e.g. "930.7gb"`
380	AvailableInBytes     int64  `json:"available_in_bytes"`
381	DiskReads            int64  `json:"disk_reads"`
382	DiskWrites           int64  `json:"disk_writes"`
383	DiskIOOp             int64  `json:"disk_io_op"`
384	DiskReadSize         string `json:"disk_read_size"` // e.g. "0b"`
385	DiskReadSizeInBytes  int64  `json:"disk_read_size_in_bytes"`
386	DiskWriteSize        string `json:"disk_write_size"` // e.g. "0b"`
387	DiskWriteSizeInBytes int64  `json:"disk_write_size_in_bytes"`
388	DiskIOSize           string `json:"disk_io_size"` // e.g. "0b"`
389	DiskIOSizeInBytes    int64  `json:"disk_io_size_in_bytes"`
390	DiskQueue            string `json:"disk_queue"`
391	DiskServiceTime      string `json:"disk_service_time"`
392}
393
394type ClusterStatsNodesPlugin struct {
395	Name        string `json:"name"`
396	Version     string `json:"version"`
397	Description string `json:"description"`
398	URL         string `json:"url"`
399	JVM         bool   `json:"jvm"`
400	Site        bool   `json:"site"`
401}
402
403type ClusterStatsNodesNetworkTypes struct {
404	TransportTypes map[string]interface{} `json:"transport_types"` // e.g. "netty4": 1
405	HTTPTypes      map[string]interface{} `json:"http_types"`      // e.g. "netty4": 1
406}
407
408type ClusterStatsNodesDiscoveryTypes interface{}
409
410type ClusterStatsNodesPackagingTypes []*ClusterStatsNodesPackagingType
411
412type ClusterStatsNodesPackagingType struct {
413	Flavor string `json:"flavor"` // e.g. "oss"
414	Type   string `json:"type"`   // e.g. "docker"
415	Count  int    `json:"count"`  // e.g. 1
416}
417