-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
078b47b
commit 2249f07
Showing
8 changed files
with
238 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package bucketclient | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
) | ||
|
||
func (client *BucketClient) GetBucketSessionID(bucketName string) (int, error) { | ||
url := fmt.Sprintf("/_/buckets/%s/id", bucketName) | ||
responseBody, err := client.Request("GetBucketSessionID", "GET", url, nil, "") | ||
if err != nil { | ||
requestErr := err.(*BucketClientError) | ||
if requestErr.StatusCode == 404 { | ||
return -1, fmt.Errorf("bucket '%s' does not exist", bucketName) | ||
} | ||
return -1, err | ||
} | ||
sessionId, err := strconv.ParseInt(string(responseBody), 10, 0) | ||
if err != nil { | ||
return -1, fmt.Errorf("bucketd did not return a valid session ID in response body") | ||
} | ||
return int(sessionId), nil | ||
} |
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,54 @@ | ||
package bucketclient | ||
|
||
import ( | ||
"encoding/json" | ||
) | ||
|
||
type MemberInfo struct { | ||
ID int `json:"id"` | ||
Name string `json:"name"` | ||
DisplayName string `json:"display_name"` | ||
Host string `json:"host"` | ||
Port int `json:"port"` | ||
AdminPort int `json:"adminPort"` | ||
MDClusterId string `json:"mdClusterId"` | ||
} | ||
|
||
type SessionInfo struct { | ||
ID int `json:"id"` | ||
RaftMembers []MemberInfo `json:"raftMembers"` | ||
ConnectedToLeader bool `json:"connectedToLeader"` | ||
} | ||
|
||
func (client *BucketClient) GetAllSessionsInfo() ([]SessionInfo, error) { | ||
responseBody, err := client.Request("GetAllSessionsInfo", "GET", "/_/raft_sessions", nil, "") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var parsedInfo []SessionInfo | ||
jsonErr := json.Unmarshal(responseBody, &parsedInfo) | ||
if jsonErr != nil { | ||
return nil, ErrorMalformedResponse("GetAllSessionsInfo", jsonErr) | ||
} | ||
return parsedInfo, nil | ||
} | ||
|
||
func (client *BucketClient) GetSessionInfo(sessionId int) (*SessionInfo, error) { | ||
// When querying /_/raft_sessions/X/info, bucketd returns a | ||
// status 500 if the raft session doesn't exist, which is hard | ||
// to distinguish from a generic type of failure. For this | ||
// reason, instead, we fetch the info for all raft sessions | ||
// then lookup the one we want. | ||
sessionsInfo, err := client.GetAllSessionsInfo() | ||
if err != nil { | ||
return nil, err | ||
} | ||
for _, sessionInfo := range sessionsInfo { | ||
if sessionInfo.ID == sessionId { | ||
return &sessionInfo, nil | ||
} | ||
} | ||
// raft session does not exist | ||
return nil, nil | ||
} |
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,28 @@ | ||
package bucketclient | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
type BucketClientError struct { | ||
ApiMethod string | ||
StatusCode int | ||
ErrorType string | ||
Err error | ||
} | ||
|
||
func (e *BucketClientError) Error() string { | ||
if e.StatusCode > 0 { | ||
return fmt.Sprintf("error in %s: bucketd returned HTTP status %d", | ||
e.ApiMethod, e.StatusCode) | ||
} else { | ||
return fmt.Sprintf("error in %s: HTTP request to bucketd failed: %v", | ||
e.ApiMethod, e.Err) | ||
} | ||
} | ||
|
||
func ErrorMalformedResponse(apiMethod string, err error) error { | ||
return &BucketClientError{apiMethod, 0, "", | ||
fmt.Errorf("bucketd returned a malformed response body: %w", err), | ||
} | ||
} |
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,55 @@ | ||
package bucketclient | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"net/http" | ||
"io" | ||
"strings" | ||
) | ||
|
||
type BucketClient struct { | ||
URL string | ||
} | ||
|
||
func New(bucketdURL string) *BucketClient { | ||
return &BucketClient{bucketdURL} | ||
} | ||
|
||
|
||
func (client *BucketClient) Request(apiMethod string, httpMethod string, path string, | ||
requestBody []byte, requestBodyContentType string) ([]byte, error) { | ||
|
||
url := fmt.Sprintf("%s%s", client.URL, path) | ||
var response *http.Response | ||
var err error = nil | ||
|
||
switch httpMethod { | ||
case "GET": | ||
response, err = http.Get(url) | ||
case "POST": | ||
response, err = http.Post(url, requestBodyContentType, bytes.NewReader(requestBody)) | ||
default: | ||
err = fmt.Errorf("unsupported HTTP method %s", httpMethod) | ||
} | ||
if err != nil { | ||
return nil, &BucketClientError{apiMethod, 0, "", err} | ||
} | ||
defer response.Body.Close() | ||
|
||
if response.StatusCode / 100 != 2 { | ||
splitStatus := strings.Split(response.Status, " ") | ||
errorType := "" | ||
if len(splitStatus) == 2 { | ||
errorType = splitStatus[1] | ||
} | ||
return nil, &BucketClientError{apiMethod, response.StatusCode, errorType, nil} | ||
} | ||
responseBody, err := io.ReadAll(response.Body) | ||
if err != nil { | ||
return nil, &BucketClientError{ | ||
apiMethod, 0, "", fmt.Errorf("error reading response body: %w", err), | ||
} | ||
} | ||
return responseBody, nil | ||
} |
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,18 @@ | ||
package bucketclient | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
func (client *BucketClient) CreateBucket(bucketName string, bucketAttributes []byte) error { | ||
url := fmt.Sprintf("/default/bucket/%s", bucketName) | ||
_, err := client.Request("CreateBucket", "POST", url, bucketAttributes, "application/json") | ||
return err | ||
} | ||
|
||
func (client *BucketClient) CreateBucketOnSession(bucketName string, sessionId int, | ||
bucketAttributes []byte) error { | ||
url := fmt.Sprintf("/default/bucket/%s?raftsession=%d", bucketName, sessionId) | ||
_, err := client.Request("CreateBucket", "POST", url, bucketAttributes, "application/json") | ||
return err | ||
} |
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,10 @@ | ||
package bucketclient | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
func (client *BucketClient) GetBucketAttributes(bucketName string) ([]byte, error) { | ||
path := fmt.Sprintf("/default/attributes/%s", bucketName) | ||
return client.Request("GetBucketAttributes", "GET", path, nil, "") | ||
} |
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,38 @@ | ||
package bucketclient | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/url" | ||
) | ||
|
||
type ListObjectVersionsEntry struct { | ||
Key string `json:"key"` | ||
VersionId string `json:"versionId"` | ||
Value string `json:"value"` | ||
} | ||
|
||
type ListObjectVersionsResponse struct { | ||
Versions []ListObjectVersionsEntry | ||
CommonPrefixes []string | ||
IsTruncated bool | ||
NextKeyMarker string | ||
NextVersionIdMarker string | ||
} | ||
|
||
func (client *BucketClient) ListObjectVersions(bucketName string, | ||
keyMarker string, versionIdMarker string, maxKeys int) (*ListObjectVersionsResponse, error) { | ||
path := fmt.Sprintf( | ||
"/default/bucket/%s?listingType=DelimiterVersions&keyMarker=%s&versionIdMarker=%s&maxKeys=%d", | ||
bucketName, url.QueryEscape(keyMarker), url.QueryEscape(versionIdMarker), maxKeys) | ||
responseBody, reqErr := client.Request("ListObjectVersions", "GET", path, nil, "") | ||
if reqErr != nil { | ||
return nil, reqErr | ||
} | ||
var parsedResponse = new(ListObjectVersionsResponse) | ||
jsonErr := json.Unmarshal(responseBody, parsedResponse) | ||
if jsonErr != nil { | ||
return nil, ErrorMalformedResponse("ListObjectVersions", jsonErr) | ||
} | ||
return parsedResponse, nil | ||
} |
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,12 @@ | ||
package bucketclient | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
func (client *BucketClient) PutBucketAttributes(bucketName string, bucketAttributes []byte) error { | ||
path := fmt.Sprintf("/default/attributes/%s", bucketName) | ||
_, err := client.Request("PutBucketAttributes", "POST", path, | ||
bucketAttributes, "application/json") | ||
return err | ||
} |