Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added read_data and enforce_data parameters #177

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4/go.mod h1:chxPXzS
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022 h1:y8Gs8CzNfDF5AZvjr+5UyGQvQEBL7pwo+v+wX6q9JI8=
github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
github.com/Mastercard/terraform-provider-restapi v1.16.2 h1:7NkBL9/aLn2jUPmpE+ms3o36XXuKd/6JaXPFwQkX15w=
github.com/Mastercard/terraform-provider-restapi v1.16.2/go.mod h1:ICQ7AhJxNbH00GpQfOrcqFnz8GtCFG+KQQFW5wmAnvc=
github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292 h1:tuQ7w+my8a8mkwN7x2TSd7OzTjkZ7rAeSyH4xncuAMI=
github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292/go.mod h1:KYCjqMOeHpNuTOiFQU6WEcTG7poCJrUs0YgyHNtn1no=
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw=
Expand Down
3 changes: 3 additions & 0 deletions restapi/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type apiClientOpt struct {
idAttribute string
createMethod string
readMethod string
readData string
updateMethod string
destroyMethod string
copyKeys []string
Expand Down Expand Up @@ -58,6 +59,7 @@ type APIClient struct {
idAttribute string
createMethod string
readMethod string
readData string
updateMethod string
destroyMethod string
copyKeys []string
Expand Down Expand Up @@ -147,6 +149,7 @@ func NewAPIClient(opt *apiClientOpt) (*APIClient, error) {
idAttribute: opt.idAttribute,
createMethod: opt.createMethod,
readMethod: opt.readMethod,
readData: opt.readData,
updateMethod: opt.updateMethod,
destroyMethod: opt.destroyMethod,
copyKeys: opt.copyKeys,
Expand Down
9 changes: 8 additions & 1 deletion restapi/api_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type apiObjectOpts struct {
putPath string
createMethod string
readMethod string
readData string
updateMethod string
destroyMethod string
deletePath string
Expand All @@ -38,6 +39,7 @@ type APIObject struct {
putPath string
createMethod string
readMethod string
readData string
updateMethod string
destroyMethod string
deletePath string
Expand Down Expand Up @@ -75,6 +77,9 @@ func NewAPIObject(iClient *APIClient, opts *apiObjectOpts) (*APIObject, error) {
if opts.readMethod == "" {
opts.readMethod = iClient.readMethod
}
if opts.readData == "" {
opts.readData = iClient.readData
}
if opts.updateMethod == "" {
opts.updateMethod = iClient.updateMethod
}
Expand Down Expand Up @@ -105,6 +110,7 @@ func NewAPIObject(iClient *APIClient, opts *apiObjectOpts) (*APIObject, error) {
putPath: opts.putPath,
createMethod: opts.createMethod,
readMethod: opts.readMethod,
readData: opts.readData,
updateMethod: opts.updateMethod,
destroyMethod: opts.destroyMethod,
deletePath: opts.deletePath,
Expand Down Expand Up @@ -164,6 +170,7 @@ func (obj *APIObject) toString() string {
buffer.WriteString(fmt.Sprintf("query_string: %s\n", obj.queryString))
buffer.WriteString(fmt.Sprintf("create_method: %s\n", obj.createMethod))
buffer.WriteString(fmt.Sprintf("read_method: %s\n", obj.readMethod))
buffer.WriteString(fmt.Sprintf("read_data: %s\n", obj.readData))
buffer.WriteString(fmt.Sprintf("update_method: %s\n", obj.updateMethod))
buffer.WriteString(fmt.Sprintf("destroy_method: %s\n", obj.destroyMethod))
buffer.WriteString(fmt.Sprintf("debug: %t\n", obj.debug))
Expand Down Expand Up @@ -283,7 +290,7 @@ func (obj *APIObject) readObject() error {
getPath = fmt.Sprintf("%s?%s", obj.getPath, obj.queryString)
}

resultString, err := obj.apiClient.sendRequest(obj.readMethod, strings.Replace(getPath, "{id}", obj.id, -1), "")
resultString, err := obj.apiClient.sendRequest(obj.readMethod, strings.Replace(getPath, "{id}", obj.id, -1), obj.readData)
if err != nil {
if strings.Contains(err.Error(), "Unexpected response code '404'") {
log.Printf("api_object.go: 404 error while refreshing state for '%s' at path '%s'. Removing from state.", obj.id, obj.getPath)
Expand Down
37 changes: 37 additions & 0 deletions restapi/resource_api_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,29 @@ func resourceRestAPI() *schema.Resource {
ForceNew: true,
Description: "Any changes to these values will result in recreating the resource instead of updating.",
},
"read_data": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: "Valid JSON data to pass during to read requests.",
Sensitive: isDataSensitive,
ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
v := val.(string)
if v != "" {
data := make(map[string]interface{})
err := json.Unmarshal([]byte(v), &data)
if err != nil {
errs = append(errs, fmt.Errorf("read_data attribute is invalid JSON: %v", err))
}
}
return warns, errs
},
},
"enforce_data": {
Type: schema.TypeBool,
Description: "Whether to emit enforce values present at data, recreating/updating object if data changed.",
Optional: true,
},
}, /* End schema */

}
Expand Down Expand Up @@ -299,6 +322,17 @@ func resourceRestAPIExists(d *schema.ResourceData, meta interface{}) (exists boo
err = obj.readObject()
if err == nil {
exists = true
if enforce, ok := d.GetOk("enforce_data"); ok && enforce.(bool) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes a lot of sense and is something that I've wanted to add to the provider for quite some time. Unfortunately, this particular implementation falls a bit short because it is only examining first-level child objects to detect differences. I think there needs to be a more "deep" diff that happens

Also, this is expected behavior with Terraform, so we shouldn't require a new parameter.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DRuggeri would you consider accepting just the read_data portion? I have a project I’m working on that needs a POST call when reading. Currently when using the provider and doing a POST on read_method the application will error because no json payload is sent even when the app just expects an empty dictionary.

Would you prefer it gets split off of this pull request to implement this? I can go through the changes and submit a new one with just that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for the delay, @Xboarder56!

Yes, read_data is OK and, in the time since the PR was opened and I've been able to dig into feature reviews again, #252 was opened. Definitely happy to have read_data!

log.Printf("resource_api_object.go: Enforcing data attributes.\n")
for key, _ := range obj.data {
if obj.data[key] != obj.apiData[key] {
log.Printf("resource_api_object.go: key %s missmatch (%s vs %s), forcing re-creation.\n", key, obj.data[key], obj.apiData[key])
d.SetId("")
return false, nil
}
}
}

}
return exists, err
}
Expand Down Expand Up @@ -374,6 +408,9 @@ func buildAPIObjectOpts(d *schema.ResourceData) (*apiObjectOpts, error) {
if v, ok := d.GetOk("query_string"); ok {
opts.queryString = v.(string)
}
if v, ok := d.GetOk("read_data"); ok {
opts.readData = v.(string)
}

readSearch := expandReadSearch(d.Get("read_search").(map[string]interface{}))
opts.readSearch = readSearch
Expand Down