Skip to content

Commit

Permalink
#167 want instances().get of deleted instances
Browse files Browse the repository at this point in the history
Reviewed by: Joshua M. Clulow <[email protected]>
Approved by: Joshua M. Clulow <[email protected]>
  • Loading branch information
Bruce Smith authored and jclulow committed Jun 17, 2019
1 parent f3fe46d commit e816338
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 23 deletions.
23 changes: 16 additions & 7 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
// Copyright 2019 Joyent, Inc.
//
// 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
Expand Down Expand Up @@ -225,12 +225,12 @@ func doNotFollowRedirects(*http.Request, []*http.Request) error {
}

// DecodeError decodes a backend Triton error into a more usable Go error type
func (c *Client) DecodeError(resp *http.Response, requestMethod string) error {
func (c *Client) DecodeError(resp *http.Response, requestMethod string, consumeBody bool) error {
err := &errors.APIError{
StatusCode: resp.StatusCode,
}

if requestMethod != http.MethodHead && resp.Body != nil {
if requestMethod != http.MethodHead && resp.Body != nil && consumeBody {
errorDecoder := json.NewDecoder(resp.Body)
if err := errorDecoder.Decode(err); err != nil {
return pkgerrors.Wrapf(err, "unable to decode error response")
Expand Down Expand Up @@ -267,6 +267,9 @@ type RequestInput struct {
Query *url.Values
Headers *http.Header
Body interface{}

// If the response has the HTTP status code 410 (i.e., "Gone"), should we preserve the contents of the body for the caller?
PreserveGone bool
}

func (c *Client) ExecuteRequestURIParams(ctx context.Context, inputs RequestInput) (io.ReadCloser, error) {
Expand Down Expand Up @@ -330,7 +333,7 @@ func (c *Client) ExecuteRequestURIParams(ctx context.Context, inputs RequestInpu
return resp.Body, nil
}

return nil, c.DecodeError(resp, req.Method)
return nil, c.DecodeError(resp, req.Method, true)
}

func (c *Client) ExecuteRequest(ctx context.Context, inputs RequestInput) (io.ReadCloser, error) {
Expand Down Expand Up @@ -398,7 +401,13 @@ func (c *Client) ExecuteRequestRaw(ctx context.Context, inputs RequestInput) (*h
return resp, nil
}

return nil, c.DecodeError(resp, req.Method)
// GetMachine returns a HTTP 410 response for deleted instances, but the body of the response is still a valid machine object with a State value of "deleted". Return the object to the caller as well as an error.
if inputs.PreserveGone && resp.StatusCode == http.StatusGone {
// Do not consume the response body.
return resp, c.DecodeError(resp, req.Method, false)
}

return nil, c.DecodeError(resp, req.Method, true)
}

func (c *Client) ExecuteRequestStorage(ctx context.Context, inputs RequestInput) (io.ReadCloser, http.Header, error) {
Expand Down Expand Up @@ -468,7 +477,7 @@ func (c *Client) ExecuteRequestStorage(ctx context.Context, inputs RequestInput)
return resp.Body, resp.Header, nil
}

return nil, nil, c.DecodeError(resp, req.Method)
return nil, nil, c.DecodeError(resp, req.Method, true)
}

type RequestNoEncodeInput struct {
Expand Down Expand Up @@ -535,7 +544,7 @@ func (c *Client) ExecuteRequestNoEncode(ctx context.Context, inputs RequestNoEnc
return resp.Body, resp.Header, nil
}

return nil, nil, c.DecodeError(resp, req.Method)
return nil, nil, c.DecodeError(resp, req.Method, true)
}

func (c *Client) ExecuteRequestTSG(ctx context.Context, inputs RequestInput) (io.ReadCloser, error) {
Expand Down
31 changes: 16 additions & 15 deletions compute/instances.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (c) 2018, Joyent, Inc. All rights reserved.
// Copyright 2019 Joyent, Inc.
//
// 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
Expand Down Expand Up @@ -147,38 +147,39 @@ func (c *InstancesClient) Get(ctx context.Context, input *GetInstanceInput) (*In

fullPath := path.Join("/", c.client.AccountName, "machines", input.ID)
reqInputs := client.RequestInput{
Method: http.MethodGet,
Path: fullPath,
Method: http.MethodGet,
Path: fullPath,
PreserveGone: true,
}
response, err := c.client.ExecuteRequestRaw(ctx, reqInputs)
response, reqErr := c.client.ExecuteRequestRaw(ctx, reqInputs)
if response == nil {
return nil, pkgerrors.Wrap(err, "unable to get machine")
return nil, pkgerrors.Wrap(reqErr, "unable to get machine")
}
if response.Body != nil {
defer response.Body.Close()
}
if response.StatusCode == http.StatusNotFound || response.StatusCode == http.StatusGone {
return nil, &errors.APIError{
StatusCode: response.StatusCode,
Code: "ResourceNotFound",
if reqErr != nil {
reqErr = pkgerrors.Wrap(reqErr, "unable to get machine")

// If this is not a HTTP 410 Gone error, return it immediately to the caller. Otherwise, we'll return it alongside the instance below.
if response.StatusCode != http.StatusGone {
return nil, reqErr
}
}
if err != nil {
return nil, pkgerrors.Wrap(err, "unable to get machine")
}

var result *_Instance
decoder := json.NewDecoder(response.Body)
if err = decoder.Decode(&result); err != nil {
return nil, pkgerrors.Wrap(err, "unable to decode get machine response")
if err := decoder.Decode(&result); err != nil {
return nil, pkgerrors.Wrap(err, "unable to parse JSON in get machine response")
}

native, err := result.toNative()
if err != nil {
return nil, pkgerrors.Wrap(err, "unable to decode get machine response")
}

return native, nil
// To remain compatible with the existing interface, we'll return both an error and an instance object in some cases; e.g., for HTTP 410 Gone responses for deleted instances.
return native, reqErr
}

type ListInstancesInput struct {
Expand Down
2 changes: 1 addition & 1 deletion version.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (

// Version represents main version number of the current release
// of the Triton-go SDK.
const Version = "1.5.1"
const Version = "1.6.0"

// Prerelease adds a pre-release marker to the version.
//
Expand Down

0 comments on commit e816338

Please sign in to comment.