-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for getting snapshots for a repository (#983)
The commit adds the Snapshot Get API specified in the [REST API spec](https://github.com/elastic/elasticsearch/blob/6.x/rest-api-spec/src/main/resources/rest-api-spec/api/snapshot.get.json).
- Loading branch information
Showing
4 changed files
with
248 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// Copyright 2012-present Oliver Eilhard. All rights reserved. | ||
// Use of this source code is governed by a MIT-license. | ||
// See http://olivere.mit-license.org/license.txt for details. | ||
|
||
package elastic | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"net/url" | ||
"strings" | ||
"time" | ||
|
||
"github.com/olivere/elastic/uritemplates" | ||
) | ||
|
||
// SnapshotGetService lists the snapshots on a repository | ||
// See https://www.elastic.co/guide/en/elasticsearch/reference/6.2/modules-snapshots.html | ||
// for details. | ||
type SnapshotGetService struct { | ||
client *Client | ||
repository string | ||
snapshot []string | ||
masterTimeout string | ||
ignoreUnavailable bool | ||
verbose bool | ||
} | ||
|
||
// NewSnapshotGetService creates a new SnapshotGetService. | ||
func NewSnapshotGetService(client *Client) *SnapshotGetService { | ||
return &SnapshotGetService{ | ||
client: client, | ||
snapshot: make([]string, 0), | ||
} | ||
} | ||
|
||
// Repository is the repository name. | ||
func (s *SnapshotGetService) Repository(repository string) *SnapshotGetService { | ||
s.repository = repository | ||
return s | ||
} | ||
|
||
// Snapshot is the list of snapshot names. If not set, defaults to all snapshots. | ||
func (s *SnapshotGetService) Snapshot(snapshots ...string) *SnapshotGetService { | ||
s.snapshot = append(s.snapshot, snapshots...) | ||
return s | ||
} | ||
|
||
// MasterTimeout specifies an explicit operation timeout for connection to master node. | ||
func (s *SnapshotGetService) MasterTimeout(masterTimeout string) *SnapshotGetService { | ||
s.masterTimeout = masterTimeout | ||
return s | ||
} | ||
|
||
// IgnoreUnavailable specifies whether to ignore unavailable snapshots, defaults to false | ||
func (s *SnapshotGetService) IgnoreUnavailable(ignoreUnavailable bool) *SnapshotGetService { | ||
s.ignoreUnavailable = ignoreUnavailable | ||
return s | ||
} | ||
|
||
// Verbose specifies whether to show verbose snapshot info or only show the basic info found in the repository index blob | ||
func (s *SnapshotGetService) Verbose(verbose bool) *SnapshotGetService { | ||
s.verbose = verbose | ||
return s | ||
} | ||
|
||
// buildURL builds the URL for the operation. | ||
func (s *SnapshotGetService) buildURL() (string, url.Values, error) { | ||
// Build URL | ||
var err error | ||
var path string | ||
if len(s.snapshot) > 0 { | ||
path, err = uritemplates.Expand("/_snapshot/{repository}/{snapshot}", map[string]string{ | ||
"repository": s.repository, | ||
"snapshot": strings.Join(s.snapshot, ","), | ||
}) | ||
} else { | ||
path, err = uritemplates.Expand("/_snapshot/{repository}/_all", map[string]string{ | ||
"repository": s.repository, | ||
}) | ||
} | ||
if err != nil { | ||
return "", url.Values{}, err | ||
} | ||
|
||
// Add query string parameters | ||
params := url.Values{} | ||
if s.masterTimeout != "" { | ||
params.Set("master_timeout", s.masterTimeout) | ||
} | ||
if s.ignoreUnavailable { | ||
params.Set("ignore_unavailable", "true") | ||
} | ||
if s.verbose { | ||
params.Set("verbose", "true") | ||
} | ||
return path, params, nil | ||
} | ||
|
||
// Validate checks if the operation is valid. | ||
func (s *SnapshotGetService) Validate() error { | ||
var invalid []string | ||
if s.repository == "" { | ||
invalid = append(invalid, "Repository") | ||
} | ||
if len(invalid) > 0 { | ||
return fmt.Errorf("missing required fields: %v", invalid) | ||
} | ||
return nil | ||
} | ||
|
||
// Do executes the operation. | ||
func (s *SnapshotGetService) Do(ctx context.Context) (*SnapshotGetResponse, error) { | ||
// Check pre-conditions | ||
if err := s.Validate(); err != nil { | ||
return nil, err | ||
} | ||
|
||
// Get URL for request | ||
path, params, err := s.buildURL() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Get HTTP response | ||
res, err := s.client.PerformRequest(ctx, PerformRequestOptions{ | ||
Method: "GET", | ||
Path: path, | ||
Params: params, | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Return operation response | ||
ret := new(SnapshotGetResponse) | ||
if err := json.Unmarshal(res.Body, ret); err != nil { | ||
return nil, err | ||
} | ||
return ret, nil | ||
} | ||
|
||
// SnapshotGetResponse is the response of SnapshotGetService.Do. | ||
type SnapshotGetResponse struct { | ||
Snapshots []*Snapshot `json:"snapshots"` | ||
} | ||
|
||
// Snapshot contains all information about a single snapshot | ||
type Snapshot struct { | ||
Snapshot string `json:"snapshot"` | ||
UUID string `json:"uuid"` | ||
VersionID int `json:"version_id"` | ||
Version string `json:"version"` | ||
Indices []string `json:"indices"` | ||
State string `json:"state"` | ||
Reason string `json:"reason"` | ||
StartTime time.Time `json:"start_time"` | ||
StartTimeInMillis int64 `json:"start_time_in_millis"` | ||
EndTime time.Time `json:"end_time"` | ||
EndTimeInMillis int64 `json:"end_time_in_millis"` | ||
DurationInMillis int64 `json:"duration_in_millis"` | ||
Failures []SnapshotShardFailure `json:"failures"` | ||
Shards *ShardsInfo `json:"shards"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package elastic | ||
|
||
import ( | ||
"net/url" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func TestSnapshotGetValidate(t *testing.T) { | ||
var client *Client | ||
|
||
err := NewSnapshotGetService(client).Validate() | ||
got := err.Error() | ||
expected := "missing required fields: [Repository]" | ||
if got != expected { | ||
t.Errorf("expected %q; got: %q", expected, got) | ||
} | ||
} | ||
|
||
func TestSnapshotGetURL(t *testing.T) { | ||
client := setupTestClient(t) | ||
|
||
tests := []struct { | ||
Repository string | ||
Snapshot []string | ||
MasterTimeout string | ||
IgnoreUnavailable bool | ||
Verbose bool | ||
ExpectedPath string | ||
ExpectedParams url.Values | ||
}{ | ||
{ | ||
Repository: "repo", | ||
Snapshot: []string{}, | ||
MasterTimeout: "60s", | ||
IgnoreUnavailable: true, | ||
Verbose: true, | ||
ExpectedPath: "/_snapshot/repo/_all", | ||
ExpectedParams: url.Values{ | ||
"master_timeout": []string{"60s"}, | ||
"ignore_unavailable": []string{"true"}, | ||
"verbose": []string{"true"}, | ||
}, | ||
}, | ||
{ | ||
Repository: "repo", | ||
Snapshot: []string{"snapA", "snapB"}, | ||
MasterTimeout: "60s", | ||
IgnoreUnavailable: true, | ||
Verbose: true, | ||
ExpectedPath: "/_snapshot/repo/snapA%2CsnapB", | ||
ExpectedParams: url.Values{ | ||
"master_timeout": []string{"60s"}, | ||
"ignore_unavailable": []string{"true"}, | ||
"verbose": []string{"true"}, | ||
}, | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
path, params, err := client.SnapshotGet(test.Repository). | ||
MasterTimeout(test.MasterTimeout). | ||
Snapshot(test.Snapshot...). | ||
IgnoreUnavailable(true). | ||
Verbose(true). | ||
buildURL() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if path != test.ExpectedPath { | ||
t.Errorf("expected %q; got: %q", test.ExpectedPath, path) | ||
} | ||
if !reflect.DeepEqual(params, test.ExpectedParams) { | ||
t.Errorf("expected %q; got: %q", test.ExpectedParams, params) | ||
} | ||
} | ||
} |