1// Copyright 2012-2015 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	"encoding/json"
9	"fmt"
10	"net/url"
11	"strings"
12
13	"gopkg.in/olivere/elastic.v2/uritemplates"
14)
15
16// ClusterStateService returns the state of the cluster.
17// It is documented at http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.4/cluster-state.html.
18type ClusterStateService struct {
19	client        *Client
20	pretty        bool
21	indices       []string
22	metrics       []string
23	local         *bool
24	masterTimeout string
25	flatSettings  *bool
26}
27
28// NewClusterStateService creates a new ClusterStateService.
29func NewClusterStateService(client *Client) *ClusterStateService {
30	return &ClusterStateService{
31		client:  client,
32		indices: make([]string, 0),
33		metrics: make([]string, 0),
34	}
35}
36
37// Index the name of the index. Use _all or an empty string to perform
38// the operation on all indices.
39func (s *ClusterStateService) Index(index string) *ClusterStateService {
40	s.indices = make([]string, 0)
41	s.indices = append(s.indices, index)
42	return s
43}
44
45// Indices is a list of index names. Use _all or an empty string to
46// perform the operation on all indices.
47func (s *ClusterStateService) Indices(indices ...string) *ClusterStateService {
48	s.indices = make([]string, 0)
49	s.indices = append(s.indices, indices...)
50	return s
51}
52
53// Metric limits the information returned to the specified metric.
54// It can be one of: version, master_node, nodes, routing_table, metadata,
55// blocks, or customs.
56func (s *ClusterStateService) Metric(metric string) *ClusterStateService {
57	s.metrics = make([]string, 0)
58	s.metrics = append(s.metrics, metric)
59	return s
60}
61
62// Metrics limits the information returned to the specified metrics.
63// It can be any of: version, master_node, nodes, routing_table, metadata,
64// blocks, or customs.
65func (s *ClusterStateService) Metrics(metrics ...string) *ClusterStateService {
66	s.metrics = make([]string, 0)
67	s.metrics = append(s.metrics, metrics...)
68	return s
69}
70
71// Local indicates whether to return local information. If it is true,
72// we do not retrieve the state from master node (default: false).
73func (s *ClusterStateService) Local(local bool) *ClusterStateService {
74	s.local = &local
75	return s
76}
77
78// MasterTimeout specifies the timeout for connection to master.
79func (s *ClusterStateService) MasterTimeout(masterTimeout string) *ClusterStateService {
80	s.masterTimeout = masterTimeout
81	return s
82}
83
84// FlatSettings indicates whether to return settings in flat format (default: false).
85func (s *ClusterStateService) FlatSettings(flatSettings bool) *ClusterStateService {
86	s.flatSettings = &flatSettings
87	return s
88}
89
90// buildURL builds the URL for the operation.
91func (s *ClusterStateService) buildURL() (string, url.Values, error) {
92	// Build URL
93	metrics := strings.Join(s.metrics, ",")
94	if metrics == "" {
95		metrics = "_all"
96	}
97	indices := strings.Join(s.indices, ",")
98	if indices == "" {
99		indices = "_all"
100	}
101	path, err := uritemplates.Expand("/_cluster/state/{metrics}/{indices}", map[string]string{
102		"metrics": metrics,
103		"indices": indices,
104	})
105	if err != nil {
106		return "", url.Values{}, err
107	}
108
109	// Add query string parameters
110	params := url.Values{}
111	if s.masterTimeout != "" {
112		params.Set("master_timeout", s.masterTimeout)
113	}
114	if s.flatSettings != nil {
115		params.Set("flat_settings", fmt.Sprintf("%v", *s.flatSettings))
116	}
117	if s.local != nil {
118		params.Set("local", fmt.Sprintf("%v", *s.local))
119	}
120
121	return path, params, nil
122}
123
124// Validate checks if the operation is valid.
125func (s *ClusterStateService) Validate() error {
126	return nil
127}
128
129// Do executes the operation.
130func (s *ClusterStateService) Do() (*ClusterStateResponse, error) {
131	// Check pre-conditions
132	if err := s.Validate(); err != nil {
133		return nil, err
134	}
135
136	// Get URL for request
137	path, params, err := s.buildURL()
138	if err != nil {
139		return nil, err
140	}
141
142	// Get HTTP response
143	res, err := s.client.PerformRequest("GET", path, params, nil)
144	if err != nil {
145		return nil, err
146	}
147
148	// Return operation response
149	ret := new(ClusterStateResponse)
150	if err := json.Unmarshal(res.Body, ret); err != nil {
151		return nil, err
152	}
153	return ret, nil
154}
155
156// ClusterStateResponse is the response of ClusterStateService.Do.
157type ClusterStateResponse struct {
158	ClusterName  string                               `json:"cluster_name"`
159	Version      int                                  `json:"version"`
160	MasterNode   string                               `json:"master_node"`
161	Blocks       map[string]interface{}               `json:"blocks"`
162	Nodes        map[string]*ClusterStateNode         `json:"nodes"`
163	Metadata     *ClusterStateMetadata                `json:"metadata"`
164	RoutingTable map[string]*ClusterStateRoutingTable `json:"routing_table"`
165	RoutingNodes *ClusterStateRoutingNode             `json:"routing_nodes"`
166	Allocations  []interface{}                        `json:"allocations"`
167	Customs      map[string]interface{}               `json:"customs"`
168}
169
170type ClusterStateMetadata struct {
171	Templates    map[string]interface{} `json:"templates"`
172	Indices      map[string]interface{} `json:"indices"`
173	Repositories map[string]interface{} `json:"repositories"`
174}
175
176type ClusterStateNode struct {
177	Name             string                 `json:"name"`
178	TransportAddress string                 `json:"transport_address"`
179	Attributes       map[string]interface{} `json:"attributes"`
180
181	// TODO(oe) are these still valid?
182	State          string  `json:"state"`
183	Primary        bool    `json:"primary"`
184	Node           string  `json:"node"`
185	RelocatingNode *string `json:"relocating_node"`
186	Shard          int     `json:"shard"`
187	Index          string  `json:"index"`
188}
189
190type ClusterStateRoutingTable struct {
191	Indices map[string]interface{} `json:"indices"`
192}
193
194type ClusterStateRoutingNode struct {
195	Unassigned []interface{}          `json:"unassigned"`
196	Nodes      map[string]interface{} `json:"nodes"`
197}
198