backend/manta: Update manta dependencies
Internally, triton-go has changed how it handles errors. We can now get rid of checking strings for errors, and we have introduced an errors library that wraps some of the major errors we encounter and test for
This commit is contained in:
parent
0e93e0c2b0
commit
e9476c6765
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/hashicorp/terraform/state"
|
||||
"github.com/hashicorp/terraform/state/remote"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
tritonErrors "github.com/joyent/triton-go/errors"
|
||||
"github.com/joyent/triton-go/storage"
|
||||
)
|
||||
|
||||
|
@ -22,7 +23,7 @@ func (b *Backend) States() ([]string, error) {
|
|||
DirectoryName: path.Join(mantaDefaultRootStore, b.path),
|
||||
})
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "ResourceNotFound") {
|
||||
if tritonErrors.IsResourceNotFound(err) {
|
||||
return result, nil
|
||||
}
|
||||
return nil, err
|
||||
|
|
|
@ -9,11 +9,10 @@ import (
|
|||
"log"
|
||||
"path"
|
||||
|
||||
"strings"
|
||||
|
||||
uuid "github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/terraform/state"
|
||||
"github.com/hashicorp/terraform/state/remote"
|
||||
tritonErrors "github.com/joyent/triton-go/errors"
|
||||
"github.com/joyent/triton-go/storage"
|
||||
)
|
||||
|
||||
|
@ -34,7 +33,7 @@ func (c *RemoteClient) Get() (*remote.Payload, error) {
|
|||
ObjectPath: path.Join(mantaDefaultRootStore, c.directoryName, c.keyName),
|
||||
})
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "ResourceNotFound") {
|
||||
if tritonErrors.IsResourceNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
|
@ -107,7 +106,7 @@ func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
|
|||
lockErr := &state.LockError{}
|
||||
lockInfo, err := c.getLockInfo()
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "ResourceNotFound") {
|
||||
if tritonErrors.IsResourceNotFound(err) {
|
||||
lockErr.Err = fmt.Errorf("failed to retrieve lock info: %s", err)
|
||||
return "", lockErr
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 requestMethod != http.MethodHead && resp.Body != nil {
|
||||
errorDecoder := json.NewDecoder(resp.Body)
|
||||
if err := errorDecoder.Decode(err); err != nil {
|
||||
return errwrap.Wrapf("Error decoding error response: {{err}}", err)
|
||||
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,12 +306,18 @@ 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")
|
||||
}
|
||||
|
||||
// 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) {
|
||||
method := inputs.Method
|
||||
path := inputs.Path
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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,13 +378,9 @@ 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 {
|
||||
if tt.IsResourceNotFoundError(err) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
if exists {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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"
|
|
@ -1802,28 +1802,34 @@
|
|||
"revisionTime": "2016-06-16T18:50:15Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "oINoQSRkPinChzwEHr3VatB9++Y=",
|
||||
"checksumSHA1": "Lg8OHK87XRGCaipG+5+zFyN8OMw=",
|
||||
"path": "github.com/joyent/triton-go",
|
||||
"revision": "86ba9699869b6cd5ea3290faad7be659efc7d6ce",
|
||||
"revisionTime": "2017-12-28T20:20:46Z"
|
||||
"revision": "545edbe0d564f075ac576f1ad177f4ff39c9adaf",
|
||||
"revisionTime": "2018-01-16T16:57:42Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "d6pxw8DLxYehLr92fWZTLEWVws8=",
|
||||
"checksumSHA1": "Y03+L+I0FVZ2bMGWt1MHTDEyWM4=",
|
||||
"path": "github.com/joyent/triton-go/authentication",
|
||||
"revision": "86ba9699869b6cd5ea3290faad7be659efc7d6ce",
|
||||
"revisionTime": "2017-12-28T20:20:46Z"
|
||||
"revision": "545edbe0d564f075ac576f1ad177f4ff39c9adaf",
|
||||
"revisionTime": "2018-01-16T16:57:42Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "GCHfn8d1Mhswm7n7IRnT0n/w+dw=",
|
||||
"checksumSHA1": "MuJsGBr6HlXQYxZY9cM5rBk+Lns=",
|
||||
"path": "github.com/joyent/triton-go/client",
|
||||
"revision": "86ba9699869b6cd5ea3290faad7be659efc7d6ce",
|
||||
"revisionTime": "2017-12-28T20:20:46Z"
|
||||
"revision": "545edbe0d564f075ac576f1ad177f4ff39c9adaf",
|
||||
"revisionTime": "2018-01-16T16:57:42Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "PJe3Rs8H466xR8o5audO8oWk44Q=",
|
||||
"checksumSHA1": "d/Py6j/uMgOAFNFGpsQrNnSsO+k=",
|
||||
"path": "github.com/joyent/triton-go/errors",
|
||||
"revision": "545edbe0d564f075ac576f1ad177f4ff39c9adaf",
|
||||
"revisionTime": "2018-01-16T16:57:42Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "5v533ELM047YOiwHsyMaVzITpR0=",
|
||||
"path": "github.com/joyent/triton-go/storage",
|
||||
"revision": "86ba9699869b6cd5ea3290faad7be659efc7d6ce",
|
||||
"revisionTime": "2017-12-28T20:20:46Z"
|
||||
"revision": "545edbe0d564f075ac576f1ad177f4ff39c9adaf",
|
||||
"revisionTime": "2018-01-16T16:57:42Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "g+afVQQVopBLiLB5pFZp/8s6aBs=",
|
||||
|
|
Loading…
Reference in New Issue