diff --git a/go.sum b/go.sum index dc44e727..aba1c2c1 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/restapi/api_client.go b/restapi/api_client.go index ffdb97ab..4de80ce5 100644 --- a/restapi/api_client.go +++ b/restapi/api_client.go @@ -29,6 +29,7 @@ type apiClientOpt struct { idAttribute string createMethod string readMethod string + readData string updateMethod string destroyMethod string copyKeys []string @@ -58,6 +59,7 @@ type APIClient struct { idAttribute string createMethod string readMethod string + readData string updateMethod string destroyMethod string copyKeys []string @@ -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, diff --git a/restapi/api_object.go b/restapi/api_object.go index 5549cb69..84daf435 100644 --- a/restapi/api_object.go +++ b/restapi/api_object.go @@ -18,6 +18,7 @@ type apiObjectOpts struct { putPath string createMethod string readMethod string + readData string updateMethod string destroyMethod string deletePath string @@ -38,6 +39,7 @@ type APIObject struct { putPath string createMethod string readMethod string + readData string updateMethod string destroyMethod string deletePath string @@ -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 } @@ -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, @@ -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)) @@ -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) diff --git a/restapi/resource_api_object.go b/restapi/resource_api_object.go index 03683bbd..e343a8e4 100644 --- a/restapi/resource_api_object.go +++ b/restapi/resource_api_object.go @@ -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 */ } @@ -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) { + 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 } @@ -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