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/url"
11	"strings"
12
13	"github.com/olivere/elastic/uritemplates"
14)
15
16// CatAllocationService provides a snapshot of how many shards are allocated
17// to each data node and how much disk space they are using.
18//
19// See https://www.elastic.co/guide/en/elasticsearch/reference/6.7/cat-allocation.html
20// for details.
21type CatAllocationService struct {
22	client        *Client
23	pretty        bool
24	bytes         string // b, k, m, or g
25	local         *bool
26	masterTimeout string
27	nodes         []string
28	columns       []string
29	sort          []string // list of columns for sort order
30}
31
32// NewCatAllocationService creates a new CatAllocationService.
33func NewCatAllocationService(client *Client) *CatAllocationService {
34	return &CatAllocationService{
35		client: client,
36	}
37}
38
39// NodeID specifies one or more node IDs to for information should be returned.
40func (s *CatAllocationService) NodeID(nodes ...string) *CatAllocationService {
41	s.nodes = nodes
42	return s
43}
44
45// Bytes represents the unit in which to display byte values.
46// Valid values are: "b", "k", "m", or "g".
47func (s *CatAllocationService) Bytes(bytes string) *CatAllocationService {
48	s.bytes = bytes
49	return s
50}
51
52// Local indicates to return local information, i.e. do not retrieve
53// the state from master node (default: false).
54func (s *CatAllocationService) Local(local bool) *CatAllocationService {
55	s.local = &local
56	return s
57}
58
59// MasterTimeout is the explicit operation timeout for connection to master node.
60func (s *CatAllocationService) MasterTimeout(masterTimeout string) *CatAllocationService {
61	s.masterTimeout = masterTimeout
62	return s
63}
64
65// Columns to return in the response.
66// To get a list of all possible columns to return, run the following command
67// in your terminal:
68//
69// Example:
70//   curl 'http://localhost:9200/_cat/aliases?help'
71//
72// You can use Columns("*") to return all possible columns. That might take
73// a little longer than the default set of columns.
74func (s *CatAllocationService) Columns(columns ...string) *CatAllocationService {
75	s.columns = columns
76	return s
77}
78
79// Sort is a list of fields to sort by.
80func (s *CatAllocationService) Sort(fields ...string) *CatAllocationService {
81	s.sort = fields
82	return s
83}
84
85// Pretty indicates that the JSON response be indented and human readable.
86func (s *CatAllocationService) Pretty(pretty bool) *CatAllocationService {
87	s.pretty = pretty
88	return s
89}
90
91// buildURL builds the URL for the operation.
92func (s *CatAllocationService) buildURL() (string, url.Values, error) {
93	// Build URL
94	var (
95		path string
96		err  error
97	)
98
99	if len(s.nodes) > 0 {
100		path, err = uritemplates.Expand("/_cat/allocation/{node_id}", map[string]string{
101			"node_id": strings.Join(s.nodes, ","),
102		})
103	} else {
104		path = "/_cat/allocation"
105	}
106	if err != nil {
107		return "", url.Values{}, err
108	}
109
110	// Add query string parameters
111	params := url.Values{
112		"format": []string{"json"}, // always returns as JSON
113	}
114	if s.pretty {
115		params.Set("pretty", "true")
116	}
117	if s.bytes != "" {
118		params.Set("bytes", s.bytes)
119	}
120	if v := s.local; v != nil {
121		params.Set("local", fmt.Sprint(*v))
122	}
123	if s.masterTimeout != "" {
124		params.Set("master_timeout", s.masterTimeout)
125	}
126	if len(s.sort) > 0 {
127		params.Set("s", strings.Join(s.sort, ","))
128	}
129	if len(s.columns) > 0 {
130		params.Set("h", strings.Join(s.columns, ","))
131	}
132	return path, params, nil
133}
134
135// Do executes the operation.
136func (s *CatAllocationService) Do(ctx context.Context) (CatAllocationResponse, error) {
137	// Get URL for request
138	path, params, err := s.buildURL()
139	if err != nil {
140		return nil, err
141	}
142
143	// Get HTTP response
144	res, err := s.client.PerformRequest(ctx, PerformRequestOptions{
145		Method: "GET",
146		Path:   path,
147		Params: params,
148	})
149	if err != nil {
150		return nil, err
151	}
152
153	// Return operation response
154	var ret CatAllocationResponse
155	if err := s.client.decoder.Decode(res.Body, &ret); err != nil {
156		return nil, err
157	}
158	return ret, nil
159}
160
161// -- Result of a get request.
162
163// CatAllocationResponse is the outcome of CatAllocationService.Do.
164type CatAllocationResponse []CatAllocationResponseRow
165
166// CatAllocationResponseRow is a single row in a CatAllocationResponse.
167// Notice that not all of these fields might be filled; that depends
168// on the number of columns chose in the request (see CatAllocationService.Columns).
169type CatAllocationResponseRow struct {
170	// Shards represents the number of shards on a node.
171	Shards int `json:"shards,string"`
172	// DiskIndices represents the disk used by ES indices, e.g. "46.1kb".
173	DiskIndices string `json:"disk.indices"`
174	// DiskUsed represents the disk used (total, not just ES), e.g. "34.5gb"
175	DiskUsed string `json:"disk.used"`
176	// DiskAvail represents the disk available, e.g. "53.2gb".
177	DiskAvail string `json:"disk.avail"`
178	// DiskTotal represents the total capacity of all volumes, e.g. "87.7gb".
179	DiskTotal string `json:"disk.total"`
180	// DiskPercent represents the percent of disk used, e.g. 39.
181	DiskPercent int `json:"disk.percent,string"`
182	// Host represents the hostname of the node.
183	Host string `json:"host"`
184	// IP represents the IP address of the node.
185	IP string `json:"ip"`
186	// Node represents the node ID.
187	Node string `json:"node"`
188}
189