Skip to content

Commit 4abd758

Browse files
authored
Merge pull request #1 from qrkourier/update-state-with-results-key-path
Update state with results key path
2 parents b881c1c + 01de2fa commit 4abd758

File tree

6 files changed

+67
-43
lines changed

6 files changed

+67
-43
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ dist
1515
.idea
1616
.terraform.lock.hcl
1717
dev.tfrc
18+
__debug_bin
19+
.vscode/launch.json

README.md

+34-33
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,103 @@
11
[![Build Status](https://travis-ci.com/burbon/terraform-provider-restapi.svg?branch=master)](https://travis-ci.com/burbon/terraform-provider-restapi)
22
[![Coverage Status](https://coveralls.io/repos/github/burbon/terraform-provider-restapi/badge.svg?branch=master)](https://coveralls.io/github/burbon/terraform-provider-restapi?branch=master)
33
[![Go Report Card](https://goreportcard.com/badge/github.com/burbon/terraform-provider-restapi)](https://goreportcard.com/report/github.com/burbon/terraform-provider-restapi)
4-
# Terraform provider for generic REST APIs
4+
5+
# Generic Terraform Provider for RESTful APIs
56

67
## Maintenance Note
8+
79
This provider is largely feature-complete and in maintenance mode.
8-
* It's not dead - it's just slow moving and updates must be done very carefully
9-
* We encourage community participation with open issues for usage and remain welcoming of pull requests
10+
11+
* It's not dead - it's just slow-moving, and updates must be done very carefully
12+
* We encourage community participation with open issues for usage, and remain welcoming of pull requests
1013
* Code updates happen sporadically throughout the year, driven primarily by security fixes and PRs
1114
* Because of the many API variations and flexibility of this provider, detailed per-API troubleshooting cannot be guaranteed
1215

13-
 
14-
1516
## About This Provider
16-
This terraform provider allows you to interact with APIs that may not yet have a first-class provider available by implementing a "dumb" REST API client.
1717

18-
This provider is essentially created to be a terraform-wrapped `cURL` client. Because of this, you need to know quite a bit about the API you are interacting with as opposed to full-featured terraform providers written with a specific API in mind.
18+
This terraform provider allows you to interact with APIs that may not yet have a first-class provider available by implementing a thin-wrapper of an REST API client.
19+
20+
This provider is essentially created to be a terraform-wrapped cURL client. Because of this, you need to know quite a bit about the API you are interacting with, as opposed to full-featured terraform providers written with a specific API in mind.
1921

2022
There are a few requirements about how the API must work for this provider to be able to do its thing:
21-
* The API is expected to support the following HTTP methods:
22-
* POST: create an object
23-
* GET: read an object
24-
* PUT: update an object
25-
* DELETE: remove an object
26-
* An "object" in the API has a unique identifier the API will return
27-
* Objects live under a distinct path such that for the path `/api/v1/things`...
28-
* POST on `/api/v1/things` creates a new object
29-
* GET, PUT and DELETE on `/api/v1/things/{id}` manages an existing object
3023

31-
Have a look at the [examples directory](examples) for some use cases.
24+
* With the default provider configuration, The API must support the following HTTP methods:
25+
* POST: create an object
26+
* GET: read an object
27+
* PUT: update an object
28+
* DELETE: remove an object
29+
* An "object" in the API has a unique identifier the API will return upon CREATE as property `id`
30+
* Objects live under a distinct path, e.g., `/api/v1/things` where
31+
* POST on `/api/v1/things` creates a new object
32+
* GET, PUT and DELETE on `/api/v1/things/{id}` are read, update, and destroy operations
3233

33-
 
34+
Have a look at the [examples directory](./examples/) for some use cases.
3435

3536
## Provider Documentation
37+
3638
This provider has only a few moving components, but LOTS of configurable parameters:
39+
3740
* [provider documentation](https://registry.terraform.io/providers/Mastercard/restapi/latest/docs)
3841
* [restapi_object resource documentation](https://registry.terraform.io/providers/Mastercard/restapi/latest/docs/resources/object)
3942
* [restapi_object datasource documentation](https://registry.terraform.io/providers/Mastercard/restapi/latest/docs/data-sources/object)
4043

41-
 
42-
4344
## Usage
45+
4446
* Try to set as few parameters as possible to begin with. The more complicated the configuration gets, the more difficult troubleshooting can become.
4547
* Play with the [fakeserver cli tool](fakeservercli/) (included in releases) to get a feel for how this API client is expected to work. Also see the [examples directory](examples) directory for some working use cases with fakeserver.
4648
* By default, data isn't considered sensitive. If you want to hide the data this provider submits as well as the data returned by the API, you would need to set environment variable `API_DATA_IS_SENSITIVE=true`.
4749
* 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`.
4850

49-
 
50-
5151
### Troubleshooting
52+
5253
Because this provider is just a terraform-wrapped `cURL`, the API details and the go implementation of this client are often leaked to you.
5354
This means you, as the user, will have a bit more troubleshooting on your hands than would typically be required of a full-fledged provider if you experience issues.
5455

5556
Here are some tips for troubleshooting that may be helpful...
5657

57-
 
58-
5958
#### Debug log
59+
6060
**Rely heavily on the debug log.** The debug log, enabled by setting the environment variable `TF_LOG=1` and enabling the `debug` parameter on the provider, is the best way to figure out what is happening.
6161

6262
If an unexpected error occurs, enable debug log and review the output:
63+
6364
* Does the API return an odd HTTP response code? This is common for bad requests to the API. Look closely at the HTTP request details.
6465
* Does an unexpected golang 'unmarshaling' error occur? Take a look at the debug log and see if anything other than a hash (for resources) or an array (for the datasource) is being returned. For example, the provider cannot cope with cases where a JSON object is requested, but an array of JSON objects is returned.
6566

66-
 
67-
6867
### Importing existing resources
69-
This provider supports importing existing resources into the terraform state. Import is done according to the various provider/resource configuation settings to contact the API server and obtain data. That is: if a custom read method, path, or id attribute is defined, the provider will honor those settings to pull data in.
68+
69+
This provider supports importing existing resources into the terraform state. Import is done according to the various provider/resource configuration settings to contact the API server and obtain data. That is, if a custom read method, path, or id attribute is defined, the provider will honor those settings to pull data in.
7070

7171
To import data:
7272
`terraform import restapi.Name /path/to/resource`.
7373

7474
See a concrete example [here](examples/dummy_users_with_fakeserver.tf).
7575

76-
 
77-
7876
## Installation
77+
7978
There are two standard methods of installing this provider detailed [in Terraform's documentation](https://www.terraform.io/docs/configuration/providers.html#third-party-plugins). You can place the file in the directory of your .tf file in `terraform.d/plugins/{OS}_{ARCH}/` or place it in your home directory at `~/.terraform.d/plugins/{OS}_{ARCH}/`.
8079

8180
The released binaries are named `terraform-provider-restapi_vX.Y.Z-{OS}-{ARCH}` so you know which binary to install. You *may* need to rename the binary you use during installation to just `terraform-provider-restapi_vX.Y.Z`.
8281

8382
Once downloaded, be sure to make the plugin executable by running `chmod +x terraform-provider-restapi_vX.Y.Z-{OS}-{ARCH}`.
8483

85-
 
86-
8784
## Contributing
85+
8886
Pull requests are always welcome! Please be sure the following things are taken care of with your pull request:
87+
8988
* `go fmt` is run before pushing
9089
* Be sure to add a test case for new functionality (or explain why this cannot be done)
9190
* Run the `scripts/test.sh` script to be sure everything works
9291
* Ensure new attributes can also be set by environment variables
9392

94-
#### Development environment requirements:
93+
#### Development environment requirements
94+
9595
* [Golang](https://golang.org/dl/) v1.11 or newer is installed and `go` is in your path
9696
* [Terraform](https://www.terraform.io/downloads.html) is installed and `terraform` is in your path
9797

9898
To make development easy, you can use the Docker image [druggeri/tdk](https://hub.docker.com/r/druggeri/tdk) as a development environment:
99-
```
99+
100+
```bash
100101
docker run -it --name tdk --rm -v "$HOME/go":/root/go druggeri/tdk
101102
go get github.com/Mastercard/terraform-provider-restapi
102103
cd ~/go/src/github.com/Mastercard/terraform-provider-restapi

main.go

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,36 @@
11
package main
22

33
import (
4+
"context"
5+
"flag"
6+
"log"
7+
48
"github.com/Mastercard/terraform-provider-restapi/restapi"
59

610
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
711
"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
812
)
913

1014
func main() {
11-
plugin.Serve(&plugin.ServeOpts{
15+
16+
var debugMode bool
17+
flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve")
18+
flag.Parse()
19+
20+
opts := &plugin.ServeOpts{
1221
ProviderFunc: func() *schema.Provider {
1322
return restapi.Provider()
1423
},
15-
})
24+
}
25+
26+
if debugMode {
27+
err := plugin.Debug(context.Background(), "terraform.netfoundry.io/openziti/restapi", opts)
28+
if err != nil {
29+
log.Fatal(err.Error())
30+
}
31+
return
32+
}
33+
34+
plugin.Serve(opts)
35+
1636
}

restapi/api_object.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ Centralized function to ensure that our data as managed by
214214
the api_object is updated with data that has come back from
215215
the API
216216
*/
217-
func (obj *APIObject) updateState(state string) error {
217+
func (obj *APIObject) updateState(state string, results_key string) error {
218218
if obj.debug {
219219
log.Printf("api_object.go: Updating API object state to '%s'\n", state)
220220
}
@@ -235,7 +235,7 @@ func (obj *APIObject) updateState(state string) error {
235235
/* A usable ID was not passed (in constructor or here),
236236
so we have to guess what it is from the data structure */
237237
if obj.id == "" {
238-
val, err := GetStringAtKey(obj.apiData, obj.idAttribute, obj.debug)
238+
val, err := GetStringAtKey(obj.apiData, results_key+"/"+obj.idAttribute, obj.debug)
239239
if err != nil {
240240
return fmt.Errorf("api_object.go: Error extracting ID from data element: %s", err)
241241
}
@@ -292,7 +292,7 @@ func (obj *APIObject) createObject() error {
292292
log.Printf("api_object.go: Parsing response from POST to update internal structures (write_returns_object=%t, create_returns_object=%t)...\n",
293293
obj.apiClient.writeReturnsObject, obj.apiClient.createReturnsObject)
294294
}
295-
err = obj.updateState(resultString)
295+
err = obj.updateState(resultString, obj.readSearch["results_key"])
296296
/* Yet another failsafe. In case something terrible went wrong internally,
297297
bail out so the user at least knows that the ID did not get set. */
298298
if obj.id == "" {
@@ -352,10 +352,10 @@ func (obj *APIObject) readObject() error {
352352
return nil
353353
}
354354
objFoundString, _ := json.Marshal(objFound)
355-
return obj.updateState(string(objFoundString))
355+
return obj.updateState(string(objFoundString), obj.readSearch["results_key"])
356356
}
357357

358-
return obj.updateState(resultString)
358+
return obj.updateState(resultString, obj.readSearch["results_key"])
359359
}
360360

361361
func (obj *APIObject) updateObject() error {
@@ -390,7 +390,7 @@ func (obj *APIObject) updateObject() error {
390390
if obj.debug {
391391
log.Printf("api_object.go: Parsing response from PUT to update internal structures (write_returns_object=true)...\n")
392392
}
393-
err = obj.updateState(resultString)
393+
err = obj.updateState(resultString, obj.readSearch["results_key"])
394394
} else {
395395
if obj.debug {
396396
log.Printf("api_object.go: Requesting updated object from API (write_returns_object=false)...\n")

restapi/datasource_api_object.go

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ func dataSourceRestAPIRead(d *schema.ResourceData, meta interface{}) error {
122122
log.Printf("datasource_api_object.go: Attempting to construct api_object to refresh data")
123123
}
124124

125+
// attempt d.SetId() method to detect err with obj.readObject()?
125126
d.SetId(obj.id)
126127

127128
err = obj.readObject()

restapi/provider.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ func Provider() *schema.Provider {
195195
},
196196
ResourcesMap: map[string]*schema.Resource{
197197
/* Could only get terraform to recognize this resource if
198-
the name began with the provider's name and had at least
199-
one underscore. This is not documented anywhere I could find */
198+
the name began with the provider's name and had at least
199+
one underscore. This is not documented anywhere I could find */
200200
"restapi_object": resourceRestAPI(),
201201
},
202202
DataSourcesMap: map[string]*schema.Resource{

0 commit comments

Comments
 (0)