gateway/manta: Bump manta dependencies (#5414)

Internally, triton-go, what manta minio is built on, changed it's internal
error handling. This means we no longer need to unwrap specific error types

This doesn't change any manta minio functionality - it just changes how errors are
handled internally and adds a wrapper for a 404 error
This commit is contained in:
Paul Stack
2018-01-17 20:38:39 +02:00
committed by kannappanr
parent 3f09c17bfe
commit a020a70484
34 changed files with 1205 additions and 996 deletions

View File

@@ -1,5 +1,11 @@
## Unreleased
- Add support for managing columes in Triton [#100]
- identity/policies: Add support for managing policies in Triton [#86]
- addition of triton-go errors package to expose unwraping of internal errors
- Migration from hashicorp/errwrap to pkg/errors
- Using path.Join() for URL structures rather than fmt.Sprintf()
## 0.5.2 (December 28)
- Standardise the API SSH Signers input casing and naming

View File

@@ -12,9 +12,8 @@ tools:: ## Download and install all dev/code tools
go test -i $(TEST) || exit 1
test:: ## Run unit tests
@echo "==> Running unit tests"
@echo $(TEST) | \
xargs -t go test -v $(TESTARGS) -timeout=30s -parallel=1 | grep -Ev 'TRITON_TEST|TestAcc'
@echo "==> Running unit test with coverage"
@./scripts/go-test-with-coverage.sh
testacc:: ## Run acceptance tests
@echo "==> Running acceptance tests"

View File

@@ -7,17 +7,11 @@
packages = ["."]
revision = "d5467c17e7afe8d8f08f556c6c811a50c3feb28d"
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/hashicorp/errwrap"
name = "github.com/pkg/errors"
packages = ["."]
revision = "7554cd9344cec97297fa6649b055a8c98c2a1e55"
revision = "e881fd58d78e04cf6d0de1217f8707c8cc2249bc"
[[projects]]
branch = "master"
@@ -29,11 +23,11 @@
branch = "master"
name = "golang.org/x/crypto"
packages = ["curve25519","ed25519","ed25519/internal/edwards25519","ssh","ssh/agent"]
revision = "bd6f299fb381e4c3393d1c4b1f0b94f5e77650c8"
revision = "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "28853a8970ee33112a9e7998b18e658bed04d177537ec69db678189f0b8a9a7d"
inputs-digest = "f7efd974ae38e2ee077c4d2698df74128a04797460b5f9c833853ddfaa86a0a0"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -25,14 +25,6 @@
branch = "master"
name = "github.com/abdullin/seq"
[[constraint]]
name = "github.com/davecgh/go-spew"
version = "1.1.0"
[[constraint]]
branch = "master"
name = "github.com/hashicorp/errwrap"
[[constraint]]
branch = "master"
name = "github.com/sean-/seed"
@@ -40,3 +32,7 @@
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"
[[constraint]]
branch = "master"
name = "github.com/pkg/errors"

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package authentication
// DON'T USE THIS OUTSIDE TESTING ~ This key was only created to use for

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package authentication
import (
@@ -6,7 +14,7 @@ import (
"fmt"
"math/big"
"github.com/hashicorp/errwrap"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
)
@@ -44,7 +52,7 @@ func newECDSASignature(signatureBlob []byte) (*ecdsaSignature, error) {
}
if err := ssh.Unmarshal(signatureBlob, &ecSig); err != nil {
return nil, errwrap.Wrapf("Error unmarshaling signature: {{err}}", err)
return nil, errors.Wrap(err, "unable to unmarshall signature")
}
rValue := ecSig.R.Bytes()

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package authentication
import (
@@ -7,12 +15,11 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"path"
"strings"
"github.com/hashicorp/errwrap"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
)
@@ -44,12 +51,12 @@ func NewPrivateKeySigner(input PrivateKeySignerInput) (*PrivateKeySigner, error)
rsakey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, errwrap.Wrapf("Error parsing private key: {{err}}", err)
return nil, errors.Wrap(err, "unable to parse private key")
}
sshPublicKey, err := ssh.NewPublicKey(rsakey.Public())
if err != nil {
return nil, errwrap.Wrapf("Error parsing SSH key from private key: {{err}}", err)
return nil, errors.Wrap(err, "unable to parse SSH key from private key")
}
matchKeyFingerprint := formatPublicKeyFingerprint(sshPublicKey, false)
@@ -89,7 +96,7 @@ func (s *PrivateKeySigner) Sign(dateHeader string) (string, error) {
signed, err := rsa.SignPKCS1v15(rand.Reader, s.privateKey, s.hashFunc, digest)
if err != nil {
return "", errwrap.Wrapf("Error signing date header: {{err}}", err)
return "", errors.Wrap(err, "unable to sign date header")
}
signedBase64 := base64.StdEncoding.EncodeToString(signed)
@@ -110,7 +117,7 @@ func (s *PrivateKeySigner) SignRaw(toSign string) (string, string, error) {
signed, err := rsa.SignPKCS1v15(rand.Reader, s.privateKey, s.hashFunc, digest)
if err != nil {
return "", "", errwrap.Wrapf("Error signing date header: {{err}}", err)
return "", "", errors.Wrap(err, "unable to sign date header")
}
signedBase64 := base64.StdEncoding.EncodeToString(signed)
return signedBase64, "rsa-sha1", nil

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package authentication
import (

View File

@@ -1,8 +1,16 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package authentication
import (
"regexp"
"fmt"
"regexp"
)
type httpAuthSignature interface {

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package authentication
const authorizationHeaderFormat = `Signature keyId="%s",algorithm="%s",headers="%s",signature="%s"`

View File

@@ -1,23 +1,30 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package authentication
import (
"crypto/md5"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"net"
"os"
"path"
"strings"
"github.com/hashicorp/errwrap"
pkgerrors "github.com/pkg/errors"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
var (
ErrUnsetEnvVar = errors.New("SSH_AUTH_SOCK is not set")
ErrUnsetEnvVar = pkgerrors.New("environment variable SSH_AUTH_SOCK not set")
)
type SSHAgentSigner struct {
@@ -46,7 +53,7 @@ func NewSSHAgentSigner(input SSHAgentSignerInput) (*SSHAgentSigner, error) {
conn, err := net.Dial("unix", sshAgentAddress)
if err != nil {
return nil, errwrap.Wrapf("Error dialing SSH agent: {{err}}", err)
return nil, pkgerrors.Wrap(err, "unable to dial SSH agent")
}
ag := agent.NewClient(conn)
@@ -82,7 +89,7 @@ func NewSSHAgentSigner(input SSHAgentSignerInput) (*SSHAgentSigner, error) {
func (s *SSHAgentSigner) MatchKey() (ssh.PublicKey, error) {
keys, err := s.agent.List()
if err != nil {
return nil, errwrap.Wrapf("Error listing keys in SSH Agent: %s", err)
return nil, pkgerrors.Wrap(err, "unable to list keys in SSH Agent")
}
keyFingerprintStripped := strings.TrimPrefix(s.keyFingerprint, "MD5:")
@@ -116,12 +123,12 @@ func (s *SSHAgentSigner) Sign(dateHeader string) (string, error) {
signature, err := s.agent.Sign(s.key, []byte(fmt.Sprintf("%s: %s", headerName, dateHeader)))
if err != nil {
return "", errwrap.Wrapf("Error signing date header: {{err}}", err)
return "", pkgerrors.Wrap(err, "unable to sign date header")
}
keyFormat, err := keyFormatToKeyType(signature.Format)
if err != nil {
return "", errwrap.Wrapf("Error reading signature: {{err}}", err)
return "", pkgerrors.Wrap(err, "unable to format signature")
}
var authSignature httpAuthSignature
@@ -129,12 +136,12 @@ func (s *SSHAgentSigner) Sign(dateHeader string) (string, error) {
case "rsa":
authSignature, err = newRSASignature(signature.Blob)
if err != nil {
return "", errwrap.Wrapf("Error reading signature: {{err}}", err)
return "", pkgerrors.Wrap(err, "unable to read RSA signature")
}
case "ecdsa":
authSignature, err = newECDSASignature(signature.Blob)
if err != nil {
return "", errwrap.Wrapf("Error reading signature: {{err}}", err)
return "", pkgerrors.Wrap(err, "unable to read ECDSA signature")
}
default:
return "", fmt.Errorf("Unsupported algorithm from SSH agent: %s", signature.Format)
@@ -147,12 +154,12 @@ func (s *SSHAgentSigner) Sign(dateHeader string) (string, error) {
func (s *SSHAgentSigner) SignRaw(toSign string) (string, string, error) {
signature, err := s.agent.Sign(s.key, []byte(toSign))
if err != nil {
return "", "", errwrap.Wrapf("Error signing string: {{err}}", err)
return "", "", pkgerrors.Wrap(err, "unable to sign string")
}
keyFormat, err := keyFormatToKeyType(signature.Format)
if err != nil {
return "", "", errwrap.Wrapf("Error reading signature: {{err}}", err)
return "", "", pkgerrors.Wrap(err, "unable to format key")
}
var authSignature httpAuthSignature
@@ -160,12 +167,12 @@ func (s *SSHAgentSigner) SignRaw(toSign string) (string, string, error) {
case "rsa":
authSignature, err = newRSASignature(signature.Blob)
if err != nil {
return "", "", errwrap.Wrapf("Error reading signature: {{err}}", err)
return "", "", pkgerrors.Wrap(err, "unable to read RSA signature")
}
case "ecdsa":
authSignature, err = newECDSASignature(signature.Blob)
if err != nil {
return "", "", errwrap.Wrapf("Error reading signature: {{err}}", err)
return "", "", pkgerrors.Wrap(err, "unable to read ECDSA signature")
}
default:
return "", "", fmt.Errorf("Unsupported algorithm from SSH agent: %s", signature.Format)

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package authentication
// TestSigner represents an authentication key signer which we can use for

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package authentication
import (

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package client
import (
@@ -5,7 +13,6 @@ import (
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"net"
@@ -14,19 +21,21 @@ import (
"os"
"time"
"github.com/hashicorp/errwrap"
"github.com/joyent/triton-go"
"github.com/joyent/triton-go/authentication"
"github.com/joyent/triton-go/errors"
pkgerrors "github.com/pkg/errors"
)
const nilContext = "nil context"
var (
ErrDefaultAuth = errors.New("default SSH agent authentication requires SDC_KEY_ID / TRITON_KEY_ID and SSH_AUTH_SOCK")
ErrAccountName = errors.New("missing account name for Triton/Manta")
ErrMissingURL = errors.New("missing Triton and/or Manta URL")
ErrDefaultAuth = pkgerrors.New("default SSH agent authentication requires SDC_KEY_ID / TRITON_KEY_ID and SSH_AUTH_SOCK")
ErrAccountName = pkgerrors.New("missing account name")
ErrMissingURL = pkgerrors.New("missing API URL")
BadTritonURL = "invalid format of triton URL"
BadMantaURL = "invalid format of manta URL"
InvalidTritonURL = "invalid format of Triton URL"
InvalidMantaURL = "invalid format of Manta URL"
)
// Client represents a connection to the Triton Compute or Object Storage APIs.
@@ -55,12 +64,12 @@ func New(tritonURL string, mantaURL string, accountName string, signers ...authe
cloudURL, err := url.Parse(tritonURL)
if err != nil {
return nil, errwrap.Wrapf(BadTritonURL+": {{err}}", err)
return nil, pkgerrors.Wrapf(err, InvalidTritonURL)
}
storageURL, err := url.Parse(mantaURL)
if err != nil {
return nil, errwrap.Wrapf(BadMantaURL+": {{err}}", err)
return nil, pkgerrors.Wrapf(err, InvalidMantaURL)
}
authorizers := make([]authentication.Signer, 0)
@@ -124,7 +133,7 @@ func (c *Client) DefaultAuth() error {
}
defaultSigner, err := authentication.NewSSHAgentSigner(input)
if err != nil {
return errwrap.Wrapf("problem initializing NewSSHAgentSigner: {{err}}", err)
return pkgerrors.Wrapf(err, "unable to initialize NewSSHAgentSigner")
}
c.Authorizers = append(c.Authorizers, defaultSigner)
}
@@ -164,19 +173,20 @@ func doNotFollowRedirects(*http.Request, []*http.Request) error {
return http.ErrUseLastResponse
}
// TODO(justinwr): Deprecated?
// func (c *Client) FormatURL(path string) string {
// return fmt.Sprintf("%s%s", c.Endpoint, path)
// }
func (c *Client) DecodeError(statusCode int, body io.Reader) error {
err := &TritonError{
StatusCode: statusCode,
func (c *Client) DecodeError(resp *http.Response, requestMethod string) error {
err := &errors.APIError{
StatusCode: resp.StatusCode,
}
errorDecoder := json.NewDecoder(body)
if err := errorDecoder.Decode(err); err != nil {
return errwrap.Wrapf("Error decoding error response: {{err}}", err)
if requestMethod != http.MethodHead && resp.Body != nil {
errorDecoder := json.NewDecoder(resp.Body)
if err := errorDecoder.Decode(err); err != nil {
return pkgerrors.Wrapf(err, "unable to decode error response")
}
}
if err.Message == "" {
err.Message = fmt.Sprintf("HTTP response returned status code %d", err.StatusCode)
}
return err
@@ -215,7 +225,7 @@ func (c *Client) ExecuteRequestURIParams(ctx context.Context, inputs RequestInpu
req, err := http.NewRequest(method, endpoint.String(), requestBody)
if err != nil {
return nil, errwrap.Wrapf("Error constructing HTTP request: {{err}}", err)
return nil, pkgerrors.Wrapf(err, "unable to construct HTTP request")
}
dateHeader := time.Now().UTC().Format(time.RFC1123)
@@ -225,12 +235,12 @@ func (c *Client) ExecuteRequestURIParams(ctx context.Context, inputs RequestInpu
// outside that constructor).
authHeader, err := c.Authorizers[0].Sign(dateHeader)
if err != nil {
return nil, errwrap.Wrapf("Error signing HTTP request: {{err}}", err)
return nil, pkgerrors.Wrapf(err, "unable to sign HTTP request")
}
req.Header.Set("Authorization", authHeader)
req.Header.Set("Accept", "application/json")
req.Header.Set("Accept-Version", "8")
req.Header.Set("User-Agent", "triton-go Client API")
req.Header.Set("Accept-Version", triton.CloudAPIMajorVersion)
req.Header.Set("User-Agent", triton.UserAgent())
if body != nil {
req.Header.Set("Content-Type", "application/json")
@@ -238,14 +248,16 @@ func (c *Client) ExecuteRequestURIParams(ctx context.Context, inputs RequestInpu
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
if err != nil {
return nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
return nil, pkgerrors.Wrapf(err, "unable to execute HTTP request")
}
// We will only return a response from the API it is in the HTTP StatusCode 2xx range
// StatusMultipleChoices is StatusCode 300
if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
return resp.Body, nil
}
return nil, c.DecodeError(resp.StatusCode, resp.Body)
return nil, c.DecodeError(resp, req.Method)
}
func (c *Client) ExecuteRequest(ctx context.Context, inputs RequestInput) (io.ReadCloser, error) {
@@ -271,7 +283,7 @@ func (c *Client) ExecuteRequestRaw(ctx context.Context, inputs RequestInput) (*h
req, err := http.NewRequest(method, endpoint.String(), requestBody)
if err != nil {
return nil, errwrap.Wrapf("Error constructing HTTP request: {{err}}", err)
return nil, pkgerrors.Wrapf(err, "unable to construct HTTP request")
}
dateHeader := time.Now().UTC().Format(time.RFC1123)
@@ -281,12 +293,12 @@ func (c *Client) ExecuteRequestRaw(ctx context.Context, inputs RequestInput) (*h
// outside that constructor).
authHeader, err := c.Authorizers[0].Sign(dateHeader)
if err != nil {
return nil, errwrap.Wrapf("Error signing HTTP request: {{err}}", err)
return nil, pkgerrors.Wrapf(err, "unable to sign HTTP request")
}
req.Header.Set("Authorization", authHeader)
req.Header.Set("Accept", "application/json")
req.Header.Set("Accept-Version", "8")
req.Header.Set("User-Agent", "triton-go c API")
req.Header.Set("Accept-Version", triton.CloudAPIMajorVersion)
req.Header.Set("User-Agent", triton.UserAgent())
if body != nil {
req.Header.Set("Content-Type", "application/json")
@@ -294,10 +306,16 @@ func (c *Client) ExecuteRequestRaw(ctx context.Context, inputs RequestInput) (*h
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
if err != nil {
return nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
return nil, pkgerrors.Wrapf(err, "unable to execute HTTP request")
}
return resp, nil
// We will only return a response from the API it is in the HTTP StatusCode 2xx range
// StatusMultipleChoices is StatusCode 300
if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
return resp, nil
}
return nil, c.DecodeError(resp, req.Method)
}
func (c *Client) ExecuteRequestStorage(ctx context.Context, inputs RequestInput) (io.ReadCloser, http.Header, error) {
@@ -321,7 +339,7 @@ func (c *Client) ExecuteRequestStorage(ctx context.Context, inputs RequestInput)
req, err := http.NewRequest(method, endpoint.String(), requestBody)
if err != nil {
return nil, nil, errwrap.Wrapf("Error constructing HTTP request: {{err}}", err)
return nil, nil, pkgerrors.Wrapf(err, "unable to construct HTTP request")
}
if body != nil && (headers == nil || headers.Get("Content-Type") == "") {
@@ -340,11 +358,11 @@ func (c *Client) ExecuteRequestStorage(ctx context.Context, inputs RequestInput)
authHeader, err := c.Authorizers[0].Sign(dateHeader)
if err != nil {
return nil, nil, errwrap.Wrapf("Error signing HTTP request: {{err}}", err)
return nil, nil, pkgerrors.Wrapf(err, "unable to sign HTTP request")
}
req.Header.Set("Authorization", authHeader)
req.Header.Set("Accept", "*/*")
req.Header.Set("User-Agent", "manta-go client API")
req.Header.Set("User-Agent", triton.UserAgent())
if query != nil {
req.URL.RawQuery = query.Encode()
@@ -352,29 +370,16 @@ func (c *Client) ExecuteRequestStorage(ctx context.Context, inputs RequestInput)
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
if err != nil {
return nil, nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
return nil, nil, pkgerrors.Wrapf(err, "unable to execute HTTP request")
}
// We will only return a response from the API it is in the HTTP StatusCode 2xx range
// StatusMultipleChoices is StatusCode 300
if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
return resp.Body, resp.Header, nil
}
mantaError := &MantaError{
StatusCode: resp.StatusCode,
}
if req.Method != http.MethodHead {
errorDecoder := json.NewDecoder(resp.Body)
if err := errorDecoder.Decode(mantaError); err != nil {
return nil, nil, errwrap.Wrapf("Error decoding error response: {{err}}", err)
}
}
if mantaError.Message == "" {
mantaError.Message = fmt.Sprintf("HTTP response returned status code %d", resp.StatusCode)
}
return nil, nil, mantaError
return nil, nil, c.DecodeError(resp, req.Method)
}
type RequestNoEncodeInput struct {
@@ -397,7 +402,7 @@ func (c *Client) ExecuteRequestNoEncode(ctx context.Context, inputs RequestNoEnc
req, err := http.NewRequest(method, endpoint.String(), body)
if err != nil {
return nil, nil, errwrap.Wrapf("Error constructing HTTP request: {{err}}", err)
return nil, nil, pkgerrors.Wrapf(err, "unable to construct HTTP request")
}
if headers != nil {
@@ -413,11 +418,12 @@ func (c *Client) ExecuteRequestNoEncode(ctx context.Context, inputs RequestNoEnc
authHeader, err := c.Authorizers[0].Sign(dateHeader)
if err != nil {
return nil, nil, errwrap.Wrapf("Error signing HTTP request: {{err}}", err)
return nil, nil, pkgerrors.Wrapf(err, "unable to sign HTTP request")
}
req.Header.Set("Authorization", authHeader)
req.Header.Set("Accept", "*/*")
req.Header.Set("User-Agent", "manta-go client API")
req.Header.Set("Accept-Version", triton.CloudAPIMajorVersion)
req.Header.Set("User-Agent", triton.UserAgent())
if query != nil {
req.URL.RawQuery = query.Encode()
@@ -425,20 +431,14 @@ func (c *Client) ExecuteRequestNoEncode(ctx context.Context, inputs RequestNoEnc
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
if err != nil {
return nil, nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
return nil, nil, pkgerrors.Wrapf(err, "unable to execute HTTP request")
}
// We will only return a response from the API it is in the HTTP StatusCode 2xx range
// StatusMultipleChoices is StatusCode 300
if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
return resp.Body, resp.Header, nil
}
mantaError := &MantaError{
StatusCode: resp.StatusCode,
}
errorDecoder := json.NewDecoder(resp.Body)
if err := errorDecoder.Decode(mantaError); err != nil {
return nil, nil, errwrap.Wrapf("Error decoding error response: {{err}}", err)
}
return nil, nil, mantaError
return nil, nil, c.DecodeError(resp, req.Method)
}

View File

@@ -1,190 +0,0 @@
package client
import (
"fmt"
"github.com/hashicorp/errwrap"
)
// ClientError represents an error code and message along with the status code
// of the HTTP request which resulted in the error message.
type ClientError struct {
StatusCode int
Code string
Message string
}
// Error implements interface Error on the TritonError type.
func (e ClientError) Error() string {
return fmt.Sprintf("%s: %s", e.Code, e.Message)
}
// MantaError represents an error code and message along with
// the status code of the HTTP request which resulted in the error
// message. Error codes used by the Manta API are listed at
// https://apidocs.joyent.com/manta/api.html#errors
type MantaError struct {
StatusCode int
Code string `json:"code"`
Message string `json:"message"`
}
// Error implements interface Error on the MantaError type.
func (e MantaError) Error() string {
return fmt.Sprintf("%s: %s", e.Code, e.Message)
}
// TritonError represents an error code and message along with
// the status code of the HTTP request which resulted in the error
// message. Error codes used by the Triton API are listed at
// https://apidocs.joyent.com/cloudapi/#cloudapi-http-responses
type TritonError struct {
StatusCode int
Code string `json:"code"`
Message string `json:"message"`
}
// Error implements interface Error on the TritonError type.
func (e TritonError) Error() string {
return fmt.Sprintf("%s: %s", e.Code, e.Message)
}
func IsAuthSchemeError(err error) bool {
return isSpecificError(err, "AuthScheme")
}
func IsAuthorizationError(err error) bool {
return isSpecificError(err, "Authorization")
}
func IsBadRequestError(err error) bool {
return isSpecificError(err, "BadRequest")
}
func IsChecksumError(err error) bool {
return isSpecificError(err, "Checksum")
}
func IsConcurrentRequestError(err error) bool {
return isSpecificError(err, "ConcurrentRequest")
}
func IsContentLengthError(err error) bool {
return isSpecificError(err, "ContentLength")
}
func IsContentMD5MismatchError(err error) bool {
return isSpecificError(err, "ContentMD5Mismatch")
}
func IsEntityExistsError(err error) bool {
return isSpecificError(err, "EntityExists")
}
func IsInvalidArgumentError(err error) bool {
return isSpecificError(err, "InvalidArgument")
}
func IsInvalidAuthTokenError(err error) bool {
return isSpecificError(err, "InvalidAuthToken")
}
func IsInvalidCredentialsError(err error) bool {
return isSpecificError(err, "InvalidCredentials")
}
func IsInvalidDurabilityLevelError(err error) bool {
return isSpecificError(err, "InvalidDurabilityLevel")
}
func IsInvalidKeyIdError(err error) bool {
return isSpecificError(err, "InvalidKeyId")
}
func IsInvalidJobError(err error) bool {
return isSpecificError(err, "InvalidJob")
}
func IsInvalidLinkError(err error) bool {
return isSpecificError(err, "InvalidLink")
}
func IsInvalidLimitError(err error) bool {
return isSpecificError(err, "InvalidLimit")
}
func IsInvalidSignatureError(err error) bool {
return isSpecificError(err, "InvalidSignature")
}
func IsInvalidUpdateError(err error) bool {
return isSpecificError(err, "InvalidUpdate")
}
func IsDirectoryDoesNotExistError(err error) bool {
return isSpecificError(err, "DirectoryDoesNotExist")
}
func IsDirectoryExistsError(err error) bool {
return isSpecificError(err, "DirectoryExists")
}
func IsDirectoryNotEmptyError(err error) bool {
return isSpecificError(err, "DirectoryNotEmpty")
}
func IsDirectoryOperationError(err error) bool {
return isSpecificError(err, "DirectoryOperation")
}
func IsInternalError(err error) bool {
return isSpecificError(err, "Internal")
}
func IsJobNotFoundError(err error) bool {
return isSpecificError(err, "JobNotFound")
}
func IsJobStateError(err error) bool {
return isSpecificError(err, "JobState")
}
func IsKeyDoesNotExistError(err error) bool {
return isSpecificError(err, "KeyDoesNotExist")
}
func IsNotAcceptableError(err error) bool {
return isSpecificError(err, "NotAcceptable")
}
func IsNotEnoughSpaceError(err error) bool {
return isSpecificError(err, "NotEnoughSpace")
}
func IsLinkNotFoundError(err error) bool {
return isSpecificError(err, "LinkNotFound")
}
func IsLinkNotObjectError(err error) bool {
return isSpecificError(err, "LinkNotObject")
}
func IsLinkRequiredError(err error) bool {
return isSpecificError(err, "LinkRequired")
}
func IsParentNotDirectoryError(err error) bool {
return isSpecificError(err, "ParentNotDirectory")
}
func IsPreconditionFailedError(err error) bool {
return isSpecificError(err, "PreconditionFailed")
}
func IsPreSignedRequestError(err error) bool {
return isSpecificError(err, "PreSignedRequest")
}
func IsRequestEntityTooLargeError(err error) bool {
return isSpecificError(err, "RequestEntityTooLarge")
}
func IsResourceNotFoundError(err error) bool {
return isSpecificError(err, "ResourceNotFound")
}
func IsRootDirectoryError(err error) bool {
return isSpecificError(err, "RootDirectory")
}
func IsServiceUnavailableError(err error) bool {
return isSpecificError(err, "ServiceUnavailable")
}
func IsSSLRequiredError(err error) bool {
return isSpecificError(err, "SSLRequired")
}
func IsUploadTimeoutError(err error) bool {
return isSpecificError(err, "UploadTimeout")
}
func IsUserDoesNotExistError(err error) bool {
return isSpecificError(err, "UserDoesNotExist")
}
// isSpecificError checks whether the error represented by err wraps
// an underlying MantaError with code errorCode.
func isSpecificError(err error, errorCode string) bool {
tritonErrorInterface := errwrap.GetType(err.(error), &MantaError{})
if tritonErrorInterface == nil {
return false
}
tritonErr := tritonErrorInterface.(*MantaError)
if tritonErr.Code == errorCode {
return true
}
return false
}

297
vendor/github.com/joyent/triton-go/errors/errors.go generated vendored Normal file
View File

@@ -0,0 +1,297 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package errors
import (
"fmt"
"net/http"
"strings"
"github.com/pkg/errors"
)
// APIError represents an error code and message along with
// the status code of the HTTP request which resulted in the error
// message. Error codes used by the Triton API are listed at
// https://apidocs.joyent.com/cloudapi/#cloudapi-http-responses
// Error codes used by the Manta API are listed at
// https://apidocs.joyent.com/manta/api.html#errors
type APIError struct {
StatusCode int
Code string `json:"code"`
Message string `json:"message"`
}
// Error implements interface Error on the APIError type.
func (e APIError) Error() string {
return strings.Trim(fmt.Sprintf("%+q", e.Code), `"`) + ": " + strings.Trim(fmt.Sprintf("%+q", e.Message), `"`)
}
// ClientError represents an error code and message returned
// when connecting to the triton-go client
type ClientError struct {
StatusCode int
Code string `json:"code"`
Message string `json:"message"`
}
// Error implements interface Error on the ClientError type.
func (e ClientError) Error() string {
return strings.Trim(fmt.Sprintf("%+q", e.Code), `"`) + ": " + strings.Trim(fmt.Sprintf("%+q", e.Message), `"`)
}
func IsAuthSchemeError(err error) bool {
return IsSpecificError(err, "AuthScheme")
}
func IsAuthorizationError(err error) bool {
return IsSpecificError(err, "Authorization")
}
func IsBadRequestError(err error) bool {
return IsSpecificError(err, "BadRequest")
}
func IsChecksumError(err error) bool {
return IsSpecificError(err, "Checksum")
}
func IsConcurrentRequestError(err error) bool {
return IsSpecificError(err, "ConcurrentRequest")
}
func IsContentLengthError(err error) bool {
return IsSpecificError(err, "ContentLength")
}
func IsContentMD5MismatchError(err error) bool {
return IsSpecificError(err, "ContentMD5Mismatch")
}
func IsEntityExistsError(err error) bool {
return IsSpecificError(err, "EntityExists")
}
func IsInvalidArgumentError(err error) bool {
return IsSpecificError(err, "InvalidArgument")
}
func IsInvalidAuthTokenError(err error) bool {
return IsSpecificError(err, "InvalidAuthToken")
}
func IsInvalidCredentialsError(err error) bool {
return IsSpecificError(err, "InvalidCredentials")
}
func IsInvalidDurabilityLevelError(err error) bool {
return IsSpecificError(err, "InvalidDurabilityLevel")
}
func IsInvalidKeyIdError(err error) bool {
return IsSpecificError(err, "InvalidKeyId")
}
func IsInvalidJobError(err error) bool {
return IsSpecificError(err, "InvalidJob")
}
func IsInvalidLinkError(err error) bool {
return IsSpecificError(err, "InvalidLink")
}
func IsInvalidLimitError(err error) bool {
return IsSpecificError(err, "InvalidLimit")
}
func IsInvalidSignatureError(err error) bool {
return IsSpecificError(err, "InvalidSignature")
}
func IsInvalidUpdateError(err error) bool {
return IsSpecificError(err, "InvalidUpdate")
}
func IsDirectoryDoesNotExistError(err error) bool {
return IsSpecificError(err, "DirectoryDoesNotExist")
}
func IsDirectoryExistsError(err error) bool {
return IsSpecificError(err, "DirectoryExists")
}
func IsDirectoryNotEmptyError(err error) bool {
return IsSpecificError(err, "DirectoryNotEmpty")
}
func IsDirectoryOperationError(err error) bool {
return IsSpecificError(err, "DirectoryOperation")
}
func IsInternalError(err error) bool {
return IsSpecificError(err, "Internal")
}
func IsJobNotFoundError(err error) bool {
return IsSpecificError(err, "JobNotFound")
}
func IsJobStateError(err error) bool {
return IsSpecificError(err, "JobState")
}
func IsKeyDoesNotExistError(err error) bool {
return IsSpecificError(err, "KeyDoesNotExist")
}
func IsNotAcceptableError(err error) bool {
return IsSpecificError(err, "NotAcceptable")
}
func IsNotEnoughSpaceError(err error) bool {
return IsSpecificError(err, "NotEnoughSpace")
}
func IsLinkNotFoundError(err error) bool {
return IsSpecificError(err, "LinkNotFound")
}
func IsLinkNotObjectError(err error) bool {
return IsSpecificError(err, "LinkNotObject")
}
func IsLinkRequiredError(err error) bool {
return IsSpecificError(err, "LinkRequired")
}
func IsParentNotDirectoryError(err error) bool {
return IsSpecificError(err, "ParentNotDirectory")
}
func IsPreconditionFailedError(err error) bool {
return IsSpecificError(err, "PreconditionFailed")
}
func IsPreSignedRequestError(err error) bool {
return IsSpecificError(err, "PreSignedRequest")
}
func IsRequestEntityTooLargeError(err error) bool {
return IsSpecificError(err, "RequestEntityTooLarge")
}
func IsResourceNotFoundError(err error) bool {
return IsSpecificError(err, "ResourceNotFound")
}
func IsRootDirectoryError(err error) bool {
return IsSpecificError(err, "RootDirectory")
}
func IsServiceUnavailableError(err error) bool {
return IsSpecificError(err, "ServiceUnavailable")
}
func IsSSLRequiredError(err error) bool {
return IsSpecificError(err, "SSLRequired")
}
func IsUploadTimeoutError(err error) bool {
return IsSpecificError(err, "UploadTimeout")
}
func IsUserDoesNotExistError(err error) bool {
return IsSpecificError(err, "UserDoesNotExist")
}
func IsBadRequest(err error) bool {
return IsSpecificError(err, "BadRequest")
}
func IsInUseError(err error) bool {
return IsSpecificError(err, "InUseError")
}
func IsInvalidArgument(err error) bool {
return IsSpecificError(err, "InvalidArgument")
}
func IsInvalidCredentials(err error) bool {
return IsSpecificError(err, "InvalidCredentials")
}
func IsInvalidHeader(err error) bool {
return IsSpecificError(err, "InvalidHeader")
}
func IsInvalidVersion(err error) bool {
return IsSpecificError(err, "InvalidVersion")
}
func IsMissingParameter(err error) bool {
return IsSpecificError(err, "MissingParameter")
}
func IsNotAuthorized(err error) bool {
return IsSpecificError(err, "NotAuthorized")
}
func IsRequestThrottled(err error) bool {
return IsSpecificError(err, "RequestThrottled")
}
func IsRequestTooLarge(err error) bool {
return IsSpecificError(err, "RequestTooLarge")
}
func IsRequestMoved(err error) bool {
return IsSpecificError(err, "RequestMoved")
}
func IsResourceFound(err error) bool {
return IsSpecificError(err, "ResourceFound")
}
func IsResourceNotFound(err error) bool {
return IsSpecificError(err, "ResourceNotFound")
}
func IsUnknownError(err error) bool {
return IsSpecificError(err, "UnknownError")
}
func IsEmptyResponse(err error) bool {
return IsSpecificError(err, "EmptyResponse")
}
func IsStatusNotFoundCode(err error) bool {
return IsSpecificStatusCode(err, http.StatusNotFound)
}
func IsSpecificError(myError error, errorCode string) bool {
switch err := errors.Cause(myError).(type) {
case *APIError:
if err.Code == errorCode {
return true
}
}
return false
}
func IsSpecificStatusCode(myError error, statusCode int) bool {
switch err := errors.Cause(myError).(type) {
case *APIError:
if err.StatusCode == statusCode {
return true
}
}
return false
}

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package storage
import (

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package storage
import (
@@ -10,8 +18,8 @@ import (
"strconv"
"time"
"github.com/hashicorp/errwrap"
"github.com/joyent/triton-go/client"
"github.com/pkg/errors"
)
type DirectoryClient struct {
@@ -58,7 +66,7 @@ func (s *DirectoryClient) List(ctx context.Context, input *ListDirectoryInput) (
}
respBody, respHeader, err := s.client.ExecuteRequestStorage(ctx, reqInput)
if err != nil {
return nil, errwrap.Wrapf("Error executing List request: {{err}}", err)
return nil, errors.Wrap(err, "unable to list directory")
}
defer respBody.Close()
@@ -67,14 +75,14 @@ func (s *DirectoryClient) List(ctx context.Context, input *ListDirectoryInput) (
for scanner.Scan() {
current := &DirectoryEntry{}
if err := json.Unmarshal(scanner.Bytes(), current); err != nil {
return nil, errwrap.Wrapf("error decoding list response: {{err}}", err)
return nil, errors.Wrap(err, "unable to decode list directories response")
}
results = append(results, current)
}
if err := scanner.Err(); err != nil {
return nil, errwrap.Wrapf("error decoding list responses: {{err}}", err)
return nil, errors.Wrap(err, "unable to decode list directories response")
}
output := &ListDirectoryOutput{
@@ -113,7 +121,7 @@ func (s *DirectoryClient) Put(ctx context.Context, input *PutDirectoryInput) err
defer respBody.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing Put request: {{err}}", err)
return errors.Wrap(err, "unable to put directory")
}
return nil
@@ -177,7 +185,7 @@ func deleteDirectory(c DirectoryClient, ctx context.Context, directoryPath _AbsC
defer respBody.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing DeleteDirectory request: {{err}}", err)
return errors.Wrap(err, "unable to delete directory")
}
return nil

View File

@@ -1,18 +1,26 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package storage
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"path"
"strconv"
"strings"
"time"
"github.com/hashicorp/errwrap"
"github.com/joyent/triton-go/client"
"github.com/pkg/errors"
)
type JobClient struct {
@@ -99,11 +107,11 @@ type CreateJobOutput struct {
// CreateJob submits a new job to be executed. This call is not
// idempotent, so calling it twice will create two jobs.
func (s *JobClient) Create(ctx context.Context, input *CreateJobInput) (*CreateJobOutput, error) {
path := fmt.Sprintf("/%s/jobs", s.client.AccountName)
fullPath := path.Join("/", s.client.AccountName, "jobs")
reqInput := client.RequestInput{
Method: http.MethodPost,
Path: path,
Path: fullPath,
Body: input,
}
respBody, respHeaders, err := s.client.ExecuteRequestStorage(ctx, reqInput)
@@ -111,7 +119,7 @@ func (s *JobClient) Create(ctx context.Context, input *CreateJobInput) (*CreateJ
defer respBody.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing CreateJob request: {{err}}", err)
return nil, errors.Wrap(err, "unable to create job")
}
jobURI := respHeaders.Get("Location")
@@ -133,7 +141,7 @@ type AddJobInputsInput struct {
// AddJobInputs submits inputs to an already created job.
func (s *JobClient) AddInputs(ctx context.Context, input *AddJobInputsInput) error {
path := fmt.Sprintf("/%s/jobs/%s/live/in", s.client.AccountName, input.JobID)
fullPath := path.Join("/", s.client.AccountName, "jobs", input.JobID, "live", "in")
headers := &http.Header{}
headers.Set("Content-Type", "text/plain")
@@ -141,7 +149,7 @@ func (s *JobClient) AddInputs(ctx context.Context, input *AddJobInputsInput) err
reqInput := client.RequestNoEncodeInput{
Method: http.MethodPost,
Path: path,
Path: fullPath,
Headers: headers,
Body: reader,
}
@@ -150,7 +158,7 @@ func (s *JobClient) AddInputs(ctx context.Context, input *AddJobInputsInput) err
defer respBody.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing AddJobInputs request: {{err}}", err)
return errors.Wrap(err, "unable to add job inputs")
}
return nil
@@ -163,18 +171,18 @@ type EndJobInputInput struct {
// EndJobInput submits inputs to an already created job.
func (s *JobClient) EndInput(ctx context.Context, input *EndJobInputInput) error {
path := fmt.Sprintf("/%s/jobs/%s/live/in/end", s.client.AccountName, input.JobID)
fullPath := path.Join("/", s.client.AccountName, "jobs", input.JobID, "live", "in", "end")
reqInput := client.RequestNoEncodeInput{
Method: http.MethodPost,
Path: path,
Path: fullPath,
}
respBody, _, err := s.client.ExecuteRequestNoEncode(ctx, reqInput)
if respBody != nil {
defer respBody.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing EndJobInput request: {{err}}", err)
return errors.Wrap(err, "unable to end job inputs")
}
return nil
@@ -194,18 +202,18 @@ type CancelJobInput struct {
// - input is still open
// - you have a long-running job
func (s *JobClient) Cancel(ctx context.Context, input *CancelJobInput) error {
path := fmt.Sprintf("/%s/jobs/%s/live/cancel", s.client.AccountName, input.JobID)
fullPath := path.Join("/", s.client.AccountName, "jobs", input.JobID, "live", "cancel")
reqInput := client.RequestNoEncodeInput{
Method: http.MethodPost,
Path: path,
Path: fullPath,
}
respBody, _, err := s.client.ExecuteRequestNoEncode(ctx, reqInput)
if respBody != nil {
defer respBody.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing CancelJob request: {{err}}", err)
return errors.Wrap(err, "unable to cancel job")
}
return nil
@@ -226,7 +234,7 @@ type ListJobsOutput struct {
// ListJobs returns the list of jobs you currently have.
func (s *JobClient) List(ctx context.Context, input *ListJobsInput) (*ListJobsOutput, error) {
path := fmt.Sprintf("/%s/jobs", s.client.AccountName)
fullPath := path.Join("/", s.client.AccountName, "jobs")
query := &url.Values{}
if input.RunningOnly {
query.Set("state", "running")
@@ -240,7 +248,7 @@ func (s *JobClient) List(ctx context.Context, input *ListJobsInput) (*ListJobsOu
reqInput := client.RequestInput{
Method: http.MethodGet,
Path: path,
Path: fullPath,
Query: query,
}
respBody, respHeader, err := s.client.ExecuteRequestStorage(ctx, reqInput)
@@ -248,7 +256,7 @@ func (s *JobClient) List(ctx context.Context, input *ListJobsInput) (*ListJobsOu
defer respBody.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing ListJobs request: {{err}}", err)
return nil, errors.Wrap(err, "unable to list jobs")
}
var results []*JobSummary
@@ -259,7 +267,7 @@ func (s *JobClient) List(ctx context.Context, input *ListJobsInput) (*ListJobsOu
if err == io.EOF {
break
}
return nil, errwrap.Wrapf("Error decoding ListJobs response: {{err}}", err)
return nil, errors.Wrap(err, "unable to decode list jobs response")
}
results = append(results, current)
}
@@ -288,24 +296,24 @@ type GetJobOutput struct {
// GetJob returns the list of jobs you currently have.
func (s *JobClient) Get(ctx context.Context, input *GetJobInput) (*GetJobOutput, error) {
path := fmt.Sprintf("/%s/jobs/%s/live/status", s.client.AccountName, input.JobID)
fullPath := path.Join("/", s.client.AccountName, "jobs", input.JobID, "live", "status")
reqInput := client.RequestInput{
Method: http.MethodGet,
Path: path,
Path: fullPath,
}
respBody, _, err := s.client.ExecuteRequestStorage(ctx, reqInput)
if respBody != nil {
defer respBody.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing GetJob request: {{err}}", err)
return nil, errors.Wrap(err, "unable to get job")
}
job := &Job{}
decoder := json.NewDecoder(respBody)
if err = decoder.Decode(&job); err != nil {
return nil, errwrap.Wrapf("Error decoding GetJob response: {{err}}", err)
return nil, errors.Wrap(err, "unable to decode get job response")
}
return &GetJobOutput{
@@ -329,18 +337,18 @@ type GetJobOutputOutput struct {
// this like `tail -f`. If error is nil (i.e. the operation is successful), it is
// your responsibility to close the io.ReadCloser named Items in the output.
func (s *JobClient) GetOutput(ctx context.Context, input *GetJobOutputInput) (*GetJobOutputOutput, error) {
path := fmt.Sprintf("/%s/jobs/%s/live/out", s.client.AccountName, input.JobID)
fullPath := path.Join("/", s.client.AccountName, "jobs", input.JobID, "live", "out")
reqInput := client.RequestInput{
Method: http.MethodGet,
Path: path,
Path: fullPath,
}
respBody, respHeader, err := s.client.ExecuteRequestStorage(ctx, reqInput)
if respBody != nil {
defer respBody.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing GetJobOutput request: {{err}}", err)
return nil, errors.Wrap(err, "unable to get job output")
}
output := &GetJobOutputOutput{
@@ -371,18 +379,18 @@ type GetJobInputOutput struct {
// this like `tail -f`. If error is nil (i.e. the operation is successful), it is
// your responsibility to close the io.ReadCloser named Items in the output.
func (s *JobClient) GetInput(ctx context.Context, input *GetJobInputInput) (*GetJobInputOutput, error) {
path := fmt.Sprintf("/%s/jobs/%s/live/in", s.client.AccountName, input.JobID)
fullPath := path.Join("/", s.client.AccountName, "jobs", input.JobID, "live", "in")
reqInput := client.RequestInput{
Method: http.MethodGet,
Path: path,
Path: fullPath,
}
respBody, respHeader, err := s.client.ExecuteRequestStorage(ctx, reqInput)
if respBody != nil {
defer respBody.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing GetJobInput request: {{err}}", err)
return nil, errors.Wrap(err, "unable to get job input")
}
output := &GetJobInputOutput{
@@ -413,18 +421,18 @@ type GetJobFailuresOutput struct {
// this like `tail -f`. If error is nil (i.e. the operation is successful), it is
// your responsibility to close the io.ReadCloser named Items in the output.
func (s *JobClient) GetFailures(ctx context.Context, input *GetJobFailuresInput) (*GetJobFailuresOutput, error) {
path := fmt.Sprintf("/%s/jobs/%s/live/fail", s.client.AccountName, input.JobID)
fullPath := path.Join("/", s.client.AccountName, "jobs", input.JobID, "live", "fail")
reqInput := client.RequestInput{
Method: http.MethodGet,
Path: path,
Path: fullPath,
}
respBody, respHeader, err := s.client.ExecuteRequestStorage(ctx, reqInput)
if respBody != nil {
defer respBody.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing GetJobFailures request: {{err}}", err)
return nil, errors.Wrap(err, "unable to get job failures")
}
output := &GetJobFailuresOutput{

View File

@@ -1,8 +1,15 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package storage
import (
"context"
"errors"
"io"
"net/http"
"net/url"
@@ -11,8 +18,9 @@ import (
"strings"
"time"
"github.com/hashicorp/errwrap"
"github.com/joyent/triton-go/client"
tt "github.com/joyent/triton-go/errors"
"github.com/pkg/errors"
)
type ObjectsClient struct {
@@ -53,7 +61,7 @@ func (s *ObjectsClient) GetInfo(ctx context.Context, input *GetInfoInput) (*GetI
}
_, respHeaders, err := s.client.ExecuteRequestStorage(ctx, reqInput)
if err != nil {
return nil, errwrap.Wrapf("Error executing get info request: {{err}}", err)
return nil, errors.Wrap(err, "unable to get info")
}
response := &GetInfoOutput{
@@ -135,7 +143,7 @@ func (s *ObjectsClient) Get(ctx context.Context, input *GetObjectInput) (*GetObj
}
respBody, respHeaders, err := s.client.ExecuteRequestStorage(ctx, reqInput)
if err != nil {
return nil, errwrap.Wrapf("Error executing Get request: {{err}}", err)
return nil, errors.Wrap(err, "unable to get object")
}
response := &GetObjectOutput{
@@ -191,7 +199,7 @@ func (s *ObjectsClient) Delete(ctx context.Context, input *DeleteObjectInput) er
defer respBody.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing Delete request: {{err}}", err)
return errors.Wrap(err, "unable to delete object")
}
return nil
@@ -235,7 +243,7 @@ func (s *ObjectsClient) PutMetadata(ctx context.Context, input *PutObjectMetadat
defer respBody.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing PutMetadata request: {{err}}", err)
return errors.Wrap(err, "unable to put metadata")
}
return nil
@@ -333,7 +341,7 @@ func putObject(c ObjectsClient, ctx context.Context, input *PutObjectInput, absP
defer respBody.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing Put request: {{err}}", err)
return errors.Wrap(err, "unable to put object")
}
return nil
@@ -370,12 +378,8 @@ func createDirectory(c ObjectsClient, ctx context.Context, absPath _AbsCleanPath
func checkDirectoryTreeExists(c ObjectsClient, ctx context.Context, absPath _AbsCleanPath) (bool, error) {
exists, err := c.IsDir(ctx, string(absPath))
if err != nil {
errType := &client.MantaError{}
if errwrap.ContainsType(err, errType) {
mantaErr := errwrap.GetType(err, errType).(*client.MantaError)
if mantaErr.StatusCode == http.StatusNotFound {
return false, nil
}
if tt.IsResourceNotFoundError(err) {
return false, nil
}
return false, err
}

View File

@@ -1,14 +1,23 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package storage
import (
"bytes"
"fmt"
"net/url"
"path"
"strconv"
"strings"
"time"
"github.com/hashicorp/errwrap"
"github.com/pkg/errors"
)
// SignURLInput represents parameters to a SignURL operation.
@@ -57,7 +66,7 @@ func (s *StorageClient) SignURL(input *SignURLInput) (*SignURLOutput, error) {
Method: input.Method,
Algorithm: strings.ToUpper(s.Client.Authorizers[0].DefaultAlgorithm()),
Expires: strconv.FormatInt(time.Now().Add(input.ValidityPeriod).Unix(), 10),
KeyID: fmt.Sprintf("/%s/keys/%s", s.Client.AccountName, s.Client.Authorizers[0].KeyFingerprint()),
KeyID: path.Join("/", s.Client.AccountName, "keys", s.Client.Authorizers[0].KeyFingerprint()),
}
toSign := bytes.Buffer{}
@@ -73,7 +82,7 @@ func (s *StorageClient) SignURL(input *SignURLInput) (*SignURLOutput, error) {
signature, _, err := s.Client.Authorizers[0].SignRaw(toSign.String())
if err != nil {
return nil, errwrap.Wrapf("Error signing string: {{err}}", err)
return nil, errors.Wrapf(err, "error signing string")
}
output.Signature = signature

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package storage
import (
@@ -5,8 +13,8 @@ import (
"fmt"
"net/http"
"github.com/hashicorp/errwrap"
"github.com/joyent/triton-go/client"
"github.com/pkg/errors"
)
type SnapLinksClient struct {
@@ -39,7 +47,7 @@ func (s *SnapLinksClient) Put(ctx context.Context, input *PutSnapLinkInput) erro
defer respBody.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing PutSnapLink request: {{err}}", err)
return errors.Wrapf(err, "unable to put snaplink")
}
return nil

View File

@@ -1,3 +1,11 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package triton
import (

32
vendor/github.com/joyent/triton-go/version.go generated vendored Normal file
View File

@@ -0,0 +1,32 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
package triton
import (
"fmt"
"runtime"
)
// The main version number of the current released Triton-go SDK.
const Version = "0.9.0"
// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var Prerelease = ""
func UserAgent() string {
if Prerelease != "" {
return fmt.Sprintf("triton-go/%s-%s (%s-%s; %s)", Version, Prerelease, runtime.GOARCH, runtime.GOOS, runtime.Version())
} else {
return fmt.Sprintf("triton-go/%s (%s-%s; %s)", Version, runtime.GOARCH, runtime.GOOS, runtime.Version())
}
}
const CloudAPIMajorVersion = "8"