Skip to content

Commit

Permalink
Merge branch 'master' into f-rate-limit-ii
Browse files Browse the repository at this point in the history
  • Loading branch information
landorg committed Jan 13, 2020
2 parents d7a5d5a + 351c5f4 commit 12a00a4
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 21 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ Have a look at the [examples directory](examples) for some use cases

This provider also exports the following parameters:
- `id`: The ID of the object that is being managed.
- `api_data`: After data from the API server is read, this map will include k/v pairs usable in other terraform resources as readable objects. Currently the value is the golang fmt package's representation of the value (simple primitives are set as expected, but complex types like arrays and maps contain golang formatting).
- `api_data`: After data from the API server is read, this map will include k/v pairs usable in other Terraform resources as readable objects. Currently the value is the golang fmt package's representation of the value (simple primitives are set as expected, but complex types like arrays and maps contain golang formatting).
- `api_response`: Contains the raw JSON response read back from the API server. Can be parsed with [`jsondecode`](https://www.terraform.io/docs/configuration/functions/jsondecode.html) to allow access to deeply nested data.
- `create_response`: Contains the raw JSON response from the initial object creation - use when an API only returns required data during create. Can be parsed with [`jsondecode`](https://www.terraform.io/docs/configuration/functions/jsondecode.html) to allow access to deeply nested data.

Note that the `*_path` elements are for very specific use cases where one might initially create an object in one location, but read/update/delete it on another path. For this reason, they allow for substitution to be done by the provider internally by injecting the `id` somewhere along the path. This is similar to terraform's substitution syntax in the form of `${variable.name}`, but must be done within the provider due to structure. The only substitution available is to replace the string `{id}` with the internal (terraform) `id` of the object as learned by the `id_attribute`.

Expand Down
1 change: 1 addition & 0 deletions restapi/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func NewAPIClient(opt *apiClientOpt) (*api_client, error) {
/* Disable TLS verification if requested */
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: opt.insecure},
Proxy: http.ProxyFromEnvironment,
}

var cookieJar http.CookieJar
Expand Down
11 changes: 8 additions & 3 deletions restapi/api_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/davecgh/go-spew/spew"
"log"
"reflect"
"strings"

"github.com/davecgh/go-spew/spew"
)

type apiObjectOpts struct {
Expand Down Expand Up @@ -36,8 +37,9 @@ type api_object struct {
id_attribute string

/* Set internally */
data map[string]interface{} /* Data as managed by the user */
api_data map[string]interface{} /* Data as available from the API */
data map[string]interface{} /* Data as managed by the user */
api_data map[string]interface{} /* Data as available from the API */
api_response string
}

// Make an api_object to manage a RESTful object in an API
Expand Down Expand Up @@ -152,6 +154,9 @@ func (obj *api_object) update_state(state string) error {
return err
}

/* Store response body for parsing via jsondecode() */
obj.api_response = state

/* A usable ID was not passed (in constructor or here),
so we have to guess what it is from the data structure */
if obj.id == "" {
Expand Down
6 changes: 4 additions & 2 deletions restapi/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package restapi

import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
"log"
"os"
"strconv"
"strings"

"github.com/hashicorp/terraform/helper/schema"
)

/* After any operation that returns API data, we'll stuff
Expand All @@ -18,6 +19,7 @@ func set_resource_state(obj *api_object, d *schema.ResourceData) {
api_data[k] = fmt.Sprintf("%v", v)
}
d.Set("api_data", api_data)
d.Set("api_response", obj.api_response)
}

/* Using GetObjectAtKey, this function verifies the resulting
Expand All @@ -33,7 +35,7 @@ func GetStringAtKey(data map[string]interface{}, path string, debug bool) (strin
if t == "string" {
return res.(string), nil
} else if t == "float64" {
return strconv.FormatFloat(res.(float64), 'f', -1, 64), nil
return strconv.FormatFloat(res.(float64), 'f', -1, 64), nil
} else {
return "", fmt.Errorf("Object at path '%s' is not a JSON string or number (float64). The go fmt package says it is '%T'", path, res)
}
Expand Down
20 changes: 11 additions & 9 deletions restapi/import_api_object_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package restapi

import (
"github.com/Mastercard/terraform-provider-restapi/fakeserver"
"github.com/hashicorp/terraform/helper/resource"
"os"
"testing"

"github.com/Mastercard/terraform-provider-restapi/fakeserver"
"github.com/hashicorp/terraform/helper/resource"
)

func TestAccRestApiObject_importBasic(t *testing.T) {
Expand All @@ -25,7 +26,7 @@ func TestAccRestApiObject_importBasic(t *testing.T) {
copy_keys: make([]string, 0),
write_returns_object: false,
create_returns_object: false,
debug: debug,
debug: debug,
}
client, err := NewAPIClient(opt)
if err != nil {
Expand All @@ -45,12 +46,13 @@ func TestAccRestApiObject_importBasic(t *testing.T) {
),
},
{
ResourceName: "restapi_object.Foo",
ImportState: true,
ImportStateId: "1234",
ImportStateIdPrefix: "/api/objects/",
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"debug", "data"},
ResourceName: "restapi_object.Foo",
ImportState: true,
ImportStateId: "1234",
ImportStateIdPrefix: "/api/objects/",
ImportStateVerify: true,
/* create_response isn't populated during import (we don't know the API response from creation) */
ImportStateVerifyIgnore: []string{"debug", "data", "create_response"},
},
},
})
Expand Down
15 changes: 14 additions & 1 deletion restapi/resource_api_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package restapi

import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
"log"
"strconv"
"strings"

"github.com/hashicorp/terraform/helper/schema"
)

func resourceRestApi() *schema.Resource {
Expand Down Expand Up @@ -76,6 +77,16 @@ func resourceRestApi() *schema.Resource {
Description: "After data from the API server is read, this map will include k/v pairs usable in other terraform resources as readable objects. Currently the value is the golang fmt package's representation of the value (simple primitives are set as expected, but complex types like arrays and maps contain golang formatting).",
Computed: true,
},
"api_response": &schema.Schema{
Type: schema.TypeString,
Description: "The raw body of the HTTP response from the last read of the object.",
Computed: true,
},
"create_response": &schema.Schema{
Type: schema.TypeString,
Description: "The raw body of the HTTP response returned when creating the object.",
Computed: true,
},
"force_new": &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Expand Down Expand Up @@ -139,6 +150,8 @@ func resourceRestApiCreate(d *schema.ResourceData, meta interface{}) error {
/* Setting terraform ID tells terraform the object was created or it exists */
d.SetId(obj.id)
set_resource_state(obj, d)
/* Only set during create for APIs that don't return sensitive data on subsequent retrieval */
d.Set("create_response", obj.api_response)
}
return err
}
Expand Down
25 changes: 22 additions & 3 deletions restapi/resource_api_object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ package restapi
import (
"encoding/json"
"fmt"
"github.com/Mastercard/terraform-provider-restapi/fakeserver"
"github.com/hashicorp/terraform/helper/resource"
"os"
"testing"

"github.com/Mastercard/terraform-provider-restapi/fakeserver"
"github.com/hashicorp/terraform/helper/resource"
)

// example.Widget represents a concrete Go type that represents an API resource
Expand All @@ -39,7 +40,7 @@ func TestAccRestApiObject_Basic(t *testing.T) {
copy_keys: make([]string, 0),
write_returns_object: false,
create_returns_object: false,
debug: debug,
debug: debug,
}
client, err := NewAPIClient(opt)
if err != nil {
Expand All @@ -61,6 +62,24 @@ func TestAccRestApiObject_Basic(t *testing.T) {
resource.TestCheckResourceAttr("restapi_object.Foo", "id", "1234"),
resource.TestCheckResourceAttr("restapi_object.Foo", "api_data.first", "Foo"),
resource.TestCheckResourceAttr("restapi_object.Foo", "api_data.last", "Bar"),
resource.TestCheckResourceAttr("restapi_object.Foo", "api_response", "{\"first\":\"Foo\",\"id\":\"1234\",\"last\":\"Bar\"}"),
resource.TestCheckResourceAttr("restapi_object.Foo", "create_response", "{\"first\":\"Foo\",\"id\":\"1234\",\"last\":\"Bar\"}"),
),
},
/* Try updating the object and check create_response is unmodified */
{
Config: generate_test_resource(
"Foo",
`{ "id": "1234", "first": "Updated", "last": "Value" }`,
make(map[string]interface{}),
),
Check: resource.ComposeTestCheckFunc(
testAccCheckRestapiObjectExists("restapi_object.Foo", "1234", client),
resource.TestCheckResourceAttr("restapi_object.Foo", "id", "1234"),
resource.TestCheckResourceAttr("restapi_object.Foo", "api_data.first", "Updated"),
resource.TestCheckResourceAttr("restapi_object.Foo", "api_data.last", "Value"),
resource.TestCheckResourceAttr("restapi_object.Foo", "api_response", "{\"first\":\"Updated\",\"id\":\"1234\",\"last\":\"Value\"}"),
resource.TestCheckResourceAttr("restapi_object.Foo", "create_response", "{\"first\":\"Foo\",\"id\":\"1234\",\"last\":\"Bar\"}"),
),
},
/* Make a complex object with id_attribute as a child of another key
Expand Down
3 changes: 2 additions & 1 deletion scripts/do_release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ OSs=("darwin" "linux" "windows")
ARCHs=("386" "amd64")

export REST_API_URI="http://127.0.0.1:8082"
export GOPATH="$HOME/go"
[[ -z "${GOPATH}" ]] && export GOPATH=$HOME/go
export CGO_ENABLED=0

#Get into the right directory
cd $(dirname $0)
Expand Down
3 changes: 2 additions & 1 deletion scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ cd $(dirname $0)

export GOOS=""
export GOARCH=""
export GOPATH="$HOME/go"

[[ -z "${GOPATH}" ]] && export GOPATH=$HOME/go

echo "Synchronizing dependencies..."
cd ../
Expand Down

0 comments on commit 12a00a4

Please sign in to comment.