Skip to content

Commit 8d32bd3

Browse files
committedJan 4, 2020
Add Snapshot Status API
This commit adds the Snapshot Status API. Close #1263
1 parent 911b7b8 commit 8d32bd3

9 files changed

+339
-5
lines changed
 

‎CONTRIBUTORS

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ Henry Stern [@hstern](https://github.com/hstern)
9191
Igor Dubinskiy [@idubinskiy](https://github.com/idubinskiy)
9292
initialcontext [@initialcontext](https://github.com/initialcontext)
9393
Isaac Saldana [@isaldana](https://github.com/isaldana)
94+
Ishan Jain [@ishanjain28](https://github.com/ishanjain28)
9495
J Barkey Wolf [@jjhbw](https://github.com/jjhbw)
9596
Jack Lindamood [@cep21](https://github.com/cep21)
9697
Jacob [@jdelgad](https://github.com/jdelgad)

‎client.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -1833,11 +1833,10 @@ func (c *Client) TasksGetTask() *TasksGetTaskService {
18331833

18341834
// -- Snapshot and Restore --
18351835

1836-
// TODO Snapshot Delete
1837-
// TODO Snapshot Get
1838-
// TODO Snapshot Restore
1839-
// TODO Snapshot Status
1840-
1836+
// SnapshotStatus returns information about the status of a snapshot.
1837+
func (c *Client) SnapshotStatus() *SnapshotStatusService {
1838+
return NewSnapshotStatusService(c)
1839+
}
18411840
// SnapshotCreate creates a snapshot.
18421841
func (c *Client) SnapshotCreate(repository string, snapshot string) *SnapshotCreateService {
18431842
return NewSnapshotCreateService(c).Repository(repository).Snapshot(snapshot)

‎go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
github.com/golang/mock v1.2.0 // indirect
99
github.com/google/go-cmp v0.3.1
1010
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e
11+
github.com/olivere/elastic v6.2.26+incompatible
1112
github.com/opentracing/opentracing-go v1.1.0
1213
github.com/pkg/errors v0.8.1
1314
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9

‎snapshot_create_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
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+
15
package elastic
26

37
import (

‎snapshot_get_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
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+
15
package elastic
26

37
import (

‎snapshot_restore.go

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
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+
15
package elastic
26

37
import (

‎snapshot_restore_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
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+
15
package elastic
26

37
import (

‎snapshot_status.go

+258
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
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+
5+
package elastic
6+
7+
import (
8+
"context"
9+
"encoding/json"
10+
"fmt"
11+
"net/http"
12+
"net/url"
13+
"strings"
14+
15+
"github.com/olivere/elastic/v7/uritemplates"
16+
)
17+
18+
// SnapshotStatusService returns information about the status of a snapshot.
19+
//
20+
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.5/modules-snapshots.html
21+
// for details.
22+
type SnapshotStatusService struct {
23+
client *Client
24+
25+
pretty *bool // pretty format the returned JSON response
26+
human *bool // return human readable values for statistics
27+
errorTrace *bool // include the stack trace of returned errors
28+
filterPath []string // list of filters used to reduce the response
29+
headers http.Header // custom request-level HTTP headers
30+
31+
repository string
32+
snapshot []string
33+
masterTimeout string
34+
ignoreUnavailable *bool
35+
}
36+
37+
// NewSnapshotStatusService creates a new SnapshotStatusService.
38+
func NewSnapshotStatusService(client *Client) *SnapshotStatusService {
39+
return &SnapshotStatusService{
40+
client: client,
41+
}
42+
}
43+
44+
// Pretty tells Elasticsearch whether to return a formatted JSON response.
45+
func (s *SnapshotStatusService) Pretty(pretty bool) *SnapshotStatusService {
46+
s.pretty = &pretty
47+
return s
48+
}
49+
50+
// Human specifies whether human readable values should be returned in
51+
// the JSON response, e.g. "7.5mb".
52+
func (s *SnapshotStatusService) Human(human bool) *SnapshotStatusService {
53+
s.human = &human
54+
return s
55+
}
56+
57+
// ErrorTrace specifies whether to include the stack trace of returned errors.
58+
func (s *SnapshotStatusService) ErrorTrace(errorTrace bool) *SnapshotStatusService {
59+
s.errorTrace = &errorTrace
60+
return s
61+
}
62+
63+
// FilterPath specifies a list of filters used to reduce the response.
64+
func (s *SnapshotStatusService) FilterPath(filterPath ...string) *SnapshotStatusService {
65+
s.filterPath = filterPath
66+
return s
67+
}
68+
69+
// Header adds a header to the request.
70+
func (s *SnapshotStatusService) Header(name string, value string) *SnapshotStatusService {
71+
if s.headers == nil {
72+
s.headers = http.Header{}
73+
}
74+
s.headers.Add(name, value)
75+
return s
76+
}
77+
78+
// Headers specifies the headers of the request.
79+
func (s *SnapshotStatusService) Headers(headers http.Header) *SnapshotStatusService {
80+
s.headers = headers
81+
return s
82+
}
83+
84+
// Repository is the repository name.
85+
func (s *SnapshotStatusService) Repository(repository string) *SnapshotStatusService {
86+
s.repository = repository
87+
return s
88+
}
89+
90+
// Snapshot is the list of snapshot names. If not set, defaults to all snapshots.
91+
func (s *SnapshotStatusService) Snapshot(snapshots ...string) *SnapshotStatusService {
92+
s.snapshot = append(s.snapshot, snapshots...)
93+
return s
94+
}
95+
96+
// MasterTimeout specifies an explicit operation timeout for connection to master node.
97+
func (s *SnapshotStatusService) MasterTimeout(masterTimeout string) *SnapshotStatusService {
98+
s.masterTimeout = masterTimeout
99+
return s
100+
}
101+
102+
// buildURL builds the URL for the operation.
103+
func (s *SnapshotStatusService) buildURL() (string, url.Values, error) {
104+
var err error
105+
var path string
106+
107+
if s.repository != "" {
108+
if len(s.snapshot) > 0 {
109+
path, err = uritemplates.Expand("/_snapshot/{repository}/{snapshot}/_status", map[string]string{
110+
"repository": s.repository,
111+
"snapshot": strings.Join(s.snapshot, ","),
112+
})
113+
} else {
114+
path, err = uritemplates.Expand("/_snapshot/{repository}/_status", map[string]string{
115+
"repository": s.repository,
116+
})
117+
}
118+
} else {
119+
path, err = uritemplates.Expand("/_snapshot/_status", nil)
120+
}
121+
if err != nil {
122+
return "", url.Values{}, err
123+
}
124+
125+
// Add query string parameters
126+
params := url.Values{}
127+
if v := s.pretty; v != nil {
128+
params.Set("pretty", fmt.Sprint(*v))
129+
}
130+
if v := s.human; v != nil {
131+
params.Set("human", fmt.Sprint(*v))
132+
}
133+
if v := s.errorTrace; v != nil {
134+
params.Set("error_trace", fmt.Sprint(*v))
135+
}
136+
if len(s.filterPath) > 0 {
137+
params.Set("filter_path", strings.Join(s.filterPath, ","))
138+
}
139+
if s.masterTimeout != "" {
140+
params.Set("master_timeout", s.masterTimeout)
141+
}
142+
if v := s.ignoreUnavailable; v != nil {
143+
params.Set("ignore_unavailable", fmt.Sprint(*v))
144+
}
145+
return path, params, nil
146+
}
147+
148+
// Validate checks if the operation is valid.
149+
//
150+
// Validation only fails if snapshot names were provided but no repository was
151+
// provided.
152+
func (s *SnapshotStatusService) Validate() error {
153+
if len(s.snapshot) > 0 && s.repository == "" {
154+
return fmt.Errorf("snapshots were specified but repository is missing")
155+
}
156+
return nil
157+
}
158+
159+
// Do executes the operation.
160+
func (s *SnapshotStatusService) Do(ctx context.Context) (*SnapshotStatusResponse, error) {
161+
// Check pre-conditions
162+
if err := s.Validate(); err != nil {
163+
return nil, err
164+
}
165+
166+
// Get URL for request
167+
path, params, err := s.buildURL()
168+
if err != nil {
169+
return nil, err
170+
}
171+
172+
// Get HTTP response
173+
res, err := s.client.PerformRequest(ctx, PerformRequestOptions{
174+
Method: "GET",
175+
Path: path,
176+
Params: params,
177+
Headers: s.headers,
178+
})
179+
if err != nil {
180+
return nil, err
181+
}
182+
183+
// Return operation response
184+
ret := new(SnapshotStatusResponse)
185+
if err := json.Unmarshal(res.Body, ret); err != nil {
186+
return nil, err
187+
}
188+
return ret, nil
189+
}
190+
191+
type SnapshotStatusResponse struct {
192+
Snapshots []SnapshotStatus `json:"snapshots"`
193+
}
194+
195+
type SnapshotStatus struct {
196+
Snapshot string `json:"snapshot"`
197+
Repository string `json:"repository"`
198+
UUID string `json:"uuid"`
199+
State string `json:"state"`
200+
IncludeGlobalState bool `json:"include_global_state"`
201+
ShardsStats SnapshotShardsStats `json:"shards_stats"`
202+
Stats SnapshotStats `json:"stats"`
203+
Indices map[string]SnapshotIndexStatus `json:"indices"`
204+
}
205+
206+
type SnapshotShardsStats struct {
207+
Initializing int `json:"initializing"`
208+
Started int `json:"started"`
209+
Finalizing int `json:"finalizing"`
210+
Done int `json:"done"`
211+
Failed int `json:"failed"`
212+
Total int `json:"total"`
213+
}
214+
215+
type SnapshotStats struct {
216+
Incremental struct {
217+
FileCount int `json:"file_count"`
218+
Size string `json:"size"`
219+
SizeInBytes int64 `json:"size_in_bytes"`
220+
} `json:"incremental"`
221+
222+
Processed struct {
223+
FileCount int `json:"file_count"`
224+
Size string `json:"size"`
225+
SizeInBytes int64 `json:"size_in_bytes"`
226+
} `json:"processed"`
227+
228+
Total struct {
229+
FileCount int `json:"file_count"`
230+
Size string `json:"size"`
231+
SizeInBytes int64 `json:"size_in_bytes"`
232+
} `json:"total"`
233+
234+
StartTime string `json:"start_time"`
235+
StartTimeInMillis int64 `json:"start_time_in_millis"`
236+
237+
Time string `json:"time"`
238+
TimeInMillis int64 `json:"time_in_millis"`
239+
240+
NumberOfFiles int `json:"number_of_files"`
241+
ProcessedFiles int `json:"processed_files"`
242+
243+
TotalSize string `json:"total_size"`
244+
TotalSizeInBytes int64 `json:"total_size_in_bytes"`
245+
}
246+
247+
type SnapshotIndexStatus struct {
248+
ShardsStats SnapshotShardsStats `json:"shards_stats"`
249+
Stats SnapshotStats `json:"stats"`
250+
Shards map[string]SnapshotIndexShardStatus `json:"shards"`
251+
}
252+
253+
type SnapshotIndexShardStatus struct {
254+
Stage string `json:"stage"` // initializing, started, finalize, done, or failed
255+
Stats SnapshotStats `json:"stats"`
256+
Node string `json:"node"`
257+
Reason string `json:"reason"` // reason for failure
258+
}

‎snapshot_status_test.go

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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+
5+
package elastic
6+
7+
import (
8+
"net/url"
9+
"reflect"
10+
"testing"
11+
)
12+
13+
func TestSnapshotStatusURL(t *testing.T) {
14+
client := setupTestClient(t)
15+
16+
tests := []struct {
17+
Repository string
18+
Snapshot []string
19+
MasterTimeout string
20+
ExpectedPath string
21+
ExpectedParams url.Values
22+
}{
23+
{
24+
Repository: "repo",
25+
Snapshot: []string{},
26+
MasterTimeout: "60s",
27+
ExpectedPath: "/_snapshot/repo/_status",
28+
ExpectedParams: url.Values{
29+
"master_timeout": []string{"60s"},
30+
},
31+
},
32+
{
33+
Repository: "repo",
34+
Snapshot: []string{"snapA", "snapB"},
35+
MasterTimeout: "30s",
36+
ExpectedPath: "/_snapshot/repo/snapA%2CsnapB/_status",
37+
ExpectedParams: url.Values{
38+
"master_timeout": []string{"30s"},
39+
},
40+
},
41+
}
42+
43+
for _, test := range tests {
44+
path, params, err := client.SnapshotStatus().
45+
MasterTimeout(test.MasterTimeout).
46+
Repository(test.Repository).
47+
Snapshot(test.Snapshot...).
48+
buildURL()
49+
if err != nil {
50+
t.Fatal(err)
51+
}
52+
if path != test.ExpectedPath {
53+
t.Errorf("expected %q; got: %q", test.ExpectedPath, path)
54+
}
55+
if !reflect.DeepEqual(params, test.ExpectedParams) {
56+
t.Errorf("expected %q; got: %q", test.ExpectedParams, params)
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)
Please sign in to comment.