mastercard / terraform-provider-restapi Goto Github PK
View Code? Open in Web Editor NEWA terraform provider to manage objects in a RESTful API
License: Other
A terraform provider to manage objects in a RESTful API
License: Other
The test coverage for the "guts" of the API interaction is... OK. We instantiate an HTTP API server that verifies GET
, PUT
, POST
and DELETE
, but we lack test coverage for the creation and usage of the terraform provider itself. As the provider matures, this is likely to result in gaps/blind spots.
It would be super awesome to have a fakeserver-backed provider test suite.
Some examples of things to test:
GET
, PUT
, POST
and DELETE
operations as the test suitedata
resourceMore complicated test cases:
data
for "deeply nested" objectsI am using the latest release and configured a data source.
data "restapi_object" "ttt-dns-map" {
path = "/api/objects/network/dns_host"
search_key = "name"
search_value = "testing"
}
terraform plan is giving the 404 error. Please see the error below. Please let me know what i need to do to fix this issue.
2018-10-24T18:37:37.181-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: "interface": "",
2018-10-24T18:37:37.181-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: "name": "testing",
2018-10-24T18:37:37.181-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: "resolved": true,
2018-10-24T18:37:37.181-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: "resolved6": false,
2018-10-24T18:37:37.181-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: "timeout": 0
2018-10-24T18:37:37.181-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: }
2018-10-24T18:37:37.181-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: ]
2018-10-24T18:37:37.187-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: 2018/10/24 18:37:37 api_client.go: method='GET', path='/api/objects/network/dns_host/', full uri (derived)='https://test.com:4444/api/objects/network/dns_host/', data=''
2018-10-24T18:37:37.187-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: 2018/10/24 18:37:37 api_client.go: Sending HTTP request to https://test.com:4444/api/objects/network/dns_host/%3Cnil%3E...
2018-10-24T18:37:37.187-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: 2018/10/24 18:37:37 api_client.go: Request headers:
2018-10-24T18:37:37.187-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: 2018/10/24 18:37:37 api_client.go: Authorization: Basic REDACTED
2018-10-24T18:37:37.187-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: 2018/10/24 18:37:37 api_client.go: BODY:
2018-10-24T18:37:37.187-0700 [DEBUG] plugin.terraform-provider-restapi_v1.5.0-linux-amd64: 2018/10/24 18:37:37
2018/10/24 18:37:37 [ERROR] root: eval: *terraform.EvalReadDataApply, err: data.restapi_object.ttt-dns-map: Unexpected response code '404': 404 page not found
2018/10/24 18:37:37 [ERROR] root: eval: *terraform.EvalSequence, err: data.restapi_object.ttt-dns-map: Unexpected response code '404': 404 page not found
2018/10/24 18:37:37 [TRACE] [walkRefresh] Exiting eval tree: data.restapi_object.ttt-dns-map
2018/10/24 18:37:37 [TRACE] dag/walk: upstream errored, not walking "provider.restapi (close)"
2018/10/24 18:37:37 [TRACE] dag/walk: upstream errored, not walking "root"
I'm running into an issue where the provider is bombing out on the data restapi_object returned values. I've validated that the returned payload is valid json.
Thoughts?
data "restapi_object" "account_uuid" {
path = "/Accounts"
search_key = "name"
search_value = "${var.account_name}"
results_key = "id"
debug = true
}
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: panic: interface conversion: interface {} is []interface {}, not map[string]interface {}
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64:
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: goroutine 38 [running]:
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: github.com/Mastercard/terraform-provider-restapi/restapi.dataSourceRestApiRead(0xc420343490, 0x185a9e0, 0xc420372090, 0xc420343490, 0x0)
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: /root/go/src/github.com/Mastercard/terraform-provider-restapi/restapi/datasource_api_object.go:106 +0xe96
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: github.com/hashicorp/terraform/helper/schema.(*Resource).ReadDataApply(0xc420450af0, 0xc42033b0c0, 0x185a9e0, 0xc420372090, 0xc4203c6e58, 0x10b9b01, 0x17ef5e0)
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: /root/go/src/github.com/hashicorp/terraform/helper/schema/resource.go:292 +0x88
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: github.com/hashicorp/terraform/helper/schema.(*Provider).ReadDataApply(0xc420450b60, 0xc420332780, 0xc42033b0c0, 0x18, 0x18, 0xc42033b100)
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: /root/go/src/github.com/hashicorp/terraform/helper/schema/provider.go:426 +0x9a
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: github.com/hashicorp/terraform/plugin.(*ResourceProviderServer).ReadDataApply(0xc4203b7660, 0xc42032b710, 0xc42032b880, 0x0, 0x0)
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: /root/go/src/github.com/hashicorp/terraform/plugin/resource_provider.go:604 +0x4e
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: reflect.Value.call(0xc42013b320, 0xc4203340e8, 0x13, 0x197a629, 0x4, 0xc4203adf18, 0x3, 0x3, 0xc4203362c0, 0x20002, ...)
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: /usr/local/go/src/reflect/value.go:447 +0x969
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: reflect.Value.Call(0xc42013b320, 0xc4203340e8, 0x13, 0xc420051718, 0x3, 0x3, 0xc42045e240, 0x13dcc1b, 0x1)
2018-08-31T18:57:41.615-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: /usr/local/go/src/reflect/value.go:308 +0xa4
2018-08-31T18:57:41.616-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: net/rpc.(*service).call(0xc420336300, 0xc420332640, 0xc42032c340, 0xc42032c350, 0xc420366600, 0xc42033a320, 0x17ef5a0, 0xc42032b710, 0x16, 0x17ef5e0, ...)
2018-08-31T18:57:41.616-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: /usr/local/go/src/net/rpc/server.go:384 +0x14e
2018-08-31T18:57:41.616-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: created by net/rpc.(*Server).ServeCodec
2018-08-31T18:57:41.616-0400 [DEBUG] plugin.terraform-provider-restapi_v1.2.1-darwin-amd64: /usr/local/go/src/net/rpc/server.go:480 +0x43a
2018/08/31 18:57:41 [ERROR] root: eval: *terraform.EvalReadDataApply, err: data.restapi_object.account_uuid: unexpected EOF
2018/08/31 18:57:41 [ERROR] root: eval: *terraform.EvalSequence, err: data.restapi_object.account_uuid: unexpected EOF
2018/08/31 18:57:41 [TRACE] [walkRefresh] Exiting eval tree: data.restapi_object.account_uuid
2018/08/31 18:57:41 [TRACE] dag/walk: upstream errored, not walking "provider.restapi (close)"
It would be helpful if arbitrary headers and could be added and other content types could be specified.
In particular, the authorization_header of the provider is too restrictive as currently implemented without the ability to add other headers. In particular, it hard-codes "Authorization: Bearer " in the header it creates. In the case of HashiCorp's Vault, one needs to add a header like "X-Vault-Token: f3b09679-3001-009d-2b80-9c306ab81aa6" and setting that as the value of authorization_header does not work since one ends up with "Authorization: Bearer X-Vault-Token: f3b09679-3001-009d-2b80-9c306ab81aa6" which does not work.
With regard to the Terraform Enterprise API, the insertion of "Authorization: Bearer " is fine, but the hard-coded content type of "application/json" causes problems since the TFE API expects content-type of "application/vnd.api+json". This is why being able to specify the content-type would be helpful.
according to https://www.terraform.io/upgrade-guides/0-12.html#upgrading-terraform-providers, .11 providers need to upgraded to work with TF .12
I am doing a PUT/POST on an api which does not return anything in response body. In that case terraform always throw the following error since the response body is empty.
I am using terraform-provider-restapi to place a PUT/POST call to slack. Here is my provider config.
provider "restapi" { update_method = "PUT" id_attribute = "username" write_returns_object = false uri = "https://hooks.slack.com/services" headers = { "Accept" = "text/plain" "Content-Type" = "application/json" } }
Since slack rest call doesn't return anything, and terraform-provider-restapi is trying to read the response, which ends up throwing the following error.
unexpected end of JSON input
Is there any option available?
This plugin doesn't work with alpine based terrraform docker image (which the official terraform docker image is the case).
When trying to use the plugin, it will give errors like below:
Error: Failed to instantiate provider "restapi" to obtain schema: fork/exec /workspace/terraform.d/plugins/linux_amd64/terraform-provider-restapi_v1.9.3: no such file or directory
After some google search, it seems to be a known issue with CGO and Alpine Linux. When doing go build
, CGO_ENABLED=0
needs to be set.
Hi All
I am trying to use the restapi_object to fire a put request to my elastic search url, I am trying to create a new watcher as per api https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-put-watch.html
There is always a POST request getting sent, which is not supported as creating a new watcher only supports PUT request, i am not sure how can i import something from the apis as there is no id or parmater present.
below is my config
provider "restapi" {
uri = "elastic.co"
insecure = true
write_returns_object = true
debug = true
headers {
Content-Type = "application/json"
}
username = "watcher"
password = "watcher"
}
resource "restapi_object" "api" {
path = "/_xpack/watcher/watch"
object_id = "alert-1"
update_path = "alert-1"
data = "${data.template_file.alert.rendered}"
}
Hello!
I have terraform installed on my notebook with Windows 10 Pro
Plugin located here %AppData%\terraform.d\plugins\windows-amd64\terraform-provider-restapi_v1.6.0-windows-amd64
c:\git\tf_api>terraform init
Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
Provider "restapi" not available for installation.
A provider named "restapi" could not be found in the official repository.
This may result from mistyping the provider name, or the given provider may
be a third-party provider that cannot be installed automatically.In the latter case, the plugin must be installed manually by locating and
downloading a suitable distribution package and placing the plugin's executable
file in the following directory:
terraform.d/plugins/windows_amd64Terraform detects necessary plugins by inspecting the configuration and state.
To view the provider versions requested by each module, run
"terraform providers".c:\git\tf_api>terraform providers
.
└── provider.restapi
If the "update_method" option is not set, why is the "create_method" being set to a PUT?
See api_client, line 87. Shouldn't the "update_method" be defaulted to PUT instead?
Trying to use the provider but get
Tried versions 1.7.0-1.9.0 - I am using terraform 0.11
I believe that the provider binaries that have been generated under releases are not named correctly. In particular, when I added the v0.2.0 binary, terraform-provider-restapi-darwin-amd64, to my repository under terraform.d/plugins/darwin_amd64, I got errors when I ran terraform init
.
I was able to successfully initiailize my Terraform code after changing the name of the binary in that directory to "terraform-provider-restapi_v0.2.0-darwin-amd64" in which I have added the version between the name of the provider and the platform.
It occurs to me that if you moved id_attribute from the provider to the resource, then multiple resources with different values of this setting could be created against a single instance of the provider. Would that make sense? Or is there some reason it needs to be on the provider itself?
Hello,
I am trying to use this module to create a data source which polls our internal API to get a collection of services owned by a specific team. I am struggling to do this with the current GET data source as it expects specific Search keys, values and id attributes.
Is this module able to:
example.com/team-name/services
which returns a list of all services owned by the specific teamWe try to query Smartsheet API with this code:
data "restapi_object" "data_webhook1" { provider = "restapi.get" path = "/webhooks" search_key = "scopeObjectId" search_value = "${var.sheet1}" results_key = "data" id_attribute = "id" }
It is working if there is a match otherwise it will throw Failed to find an object with the scopeObjectId key
. Is there a better way to handle/bypass this error? Could it return null
if it doesnot exist?
Our goal is to try to check whether this data exists, then we can create/update this record accordingly.
The REST API provider will provision a resource via POST method and wait for a response (call it 'sync' mode) NetApp WFA accepts such a request, but starts the workflow in the background and only returns a job ID (call it 'async' mode) You have to query that job ID separately to get the current status and potential return values. I saw a similar behavior with VMware vRO.
Example:
POST /workflows/{workflow_uuid}/jobs -> creates object and returns job_id
GET /workflows/{workflow_uuid}/jobs/{job_id} -> query on a regular base to get return value (after the job finishes)
Hi,
I have created a new issue since my previous issue was closed and problem is not yet resolved.
Hi
I set the Env variables to Uppercase and ran the terraform script but still getting the same issue.
env | grep PROXY
HTTPS_PROXY=http://10.8.225.113:3128
HTTP_PROXY=http://10.8.225.113:3128
terraform apply
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
create
Terraform will perform the following actions:
restapi_object.create-request
id:
api_data.%:
data: "{"Description": "Venkat request from TF RestAPI","AdditionalInformation": "Testing create req Terraform RestAPI", "ApplicationProfileId": 35, "Requestor": "Venkatraman Ramakrishnan"}\n"
path: "/NetworkAutomation/rest/v1/ChangeRequest"
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
restapi_object.create-request: Creating...
api_data.%: "" => ""
data: "" => "{"Description": "Venkat request from TF RestAPI","AdditionalInformation": "Testing create req Terraform RestAPI", "ApplicationProfileId": 35, "Requestor": "Venkatraman Ramakrishnan"}\n"
path: "" => "/NetworkAutomation/rest/v1/ChangeRequest"
restapi_object.create-request: Still creating... (10s elapsed)
restapi_object.create-request: Still creating... (20s elapsed)
restapi_object.create-request: Still creating... (30s elapsed)
restapi_object.create-request: Still creating... (40s elapsed)
restapi_object.create-request: Still creating... (50s elapsed)
restapi_object.create-request: Still creating... (1m0s elapsed)
restapi_object.create-request: Still creating... (1m10s elapsed)
restapi_object.create-request: Still creating... (1m20s elapsed)
restapi_object.create-request: Still creating... (1m30s elapsed)
restapi_object.create-request: Still creating... (1m40s elapsed)
restapi_object.create-request: Still creating... (1m50s elapsed)
restapi_object.create-request: Still creating... (2m0s elapsed)
Error: Error applying plan:
1 error(s) occurred:
restapi_object.create-request: 1 error(s) occurred:
restapi_object.create-request: Put https://console-d.dynecon.com/NetworkAutomation/rest/v1/ChangeRequest: dial tcp 34.96.75.80:443: connect: connection timed out
Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.
Please let me know if I am doing anything wrong. I am able to get the CURL request work in terraform script.
Thanks
Hi
I am trying to access a REST API Endpoint from my internal network thru Proxy. It is giving the below error
1 error(s) occurred:
restapi_object.create-request: 1 error(s) occurred:
restapi_object.create-request: Put https://console-d.dynecon.com/NetworkAutomation/rest/v1/ChangeRequest: dial tcp 34.96.75.80:443: connect: connection timed out
When I submit a Curl request from the same server, it is working fine. So the proxy is working fine, it is only when I try to connect using Mastercard Provider it is not able to utilize the Proxy setting defined in the Environment.
How to utilize the http_proxy and https_proxy in this Mastercard Provider.
The ID attribute of my API object is being expressed in scientific "E" notation instead of decimal notation.
Here is the output from my Terraform state.
resource "restapi_object" "check" {
api_data = {
"check" = "map[id:5.3502e+06 name:mydomain.com]"
}
create_path = "/checks?encryption=true&host=mydomain.com&name=mydomain.com¬ifyagainevery=0&paused=false&port=443&resolution=1&sendnotificationwhendown=3&teamids=&type=http&url=%2Fhealth_check.php&userids="
id = "5.3502e+06"
path = "/checks"
update_path = "/checks{id}?encryption=true&host=mydomain.com&name=mydomain.com¬ifyagainevery=0&paused=false&port=443&resolution=1&sendnotificationwhendown=3&teamids=&type=http&url=%2Fhealth_check.php&userids="
}
Comparing the Terraform state with the actual response suggests the notation problem is originating from within the provider and not the REST API.
{
"check": {
"id": 5350200,
"name": "mydomain.com"
}
}
Since the ID is expressed as 5.3502e+06
instead of 5350200
the terraform destroy
operation is failing to refresh the object's state using the API as the Terraform debug log shows.
2019-07-23T12:17:03.717-0700 [DEBUG] plugin.terraform-provider-restapi_v1.9.2: 2019/07/23 12:17:03 api_client.go: method='GET', path='/checks/5.3502e+06', full uri (derived)='https://api.pingdom.com/api/2.1/checks/5.3502e+06', data=''
2019-07-23T12:17:03.717-0700 [DEBUG] plugin.terraform-provider-restapi_v1.9.2: 2019/07/23 12:17:03 api_client.go: Sending HTTP request to https://api.pingdom.com/api/2.1/checks/5.3502e+06...
...
Error: Unexpected response code '403': {"error":{"statuscode":403,"statusdesc":"Forbidden","errormessage":"Invalid check identifier"}}
FWIW I believe I configured the provider to properly extract the ID using the argument id_attribute = "check/id"
.
It would be great to hide sensitive data from logs.
e.g
...
hide_data_path = 'json.user.password'
...
or hide "data" string at all:
data: <sensitive>
We have data return from Smartsheet API with this format.
"data": [ { "id": 7243977842812804, "name": "Webhook Tube Life Estimate Listener", "scope": "sheet", "scopeObjectId": 8562070036735876, "events": [ "*.*" ], "callbackUrl": "https://api.bluecentral-test.io/webhook/sheets", "sharedSecret": "6es3m789ebor0ewabxivj1czw0", "enabled": true, "status": "ENABLED", "version": 1, "createdAt": "2019-07-01T18:05:24Z", "modifiedAt": "2019-07-08T22:31:43Z" }]
When we try to access id
or scopeObjectId
, value of these fields have been converted to 7.243977842812804e+15 and 8.562070036735876e+15. Is this an expected result?
This is mostly for x-ref in case someone runs into this when using this provider.
If you are using multiple providers using Terraform's feature to alias providers, you will get an error on destroys
Error: Missing required argument
The argument "uri" is required, but was not set.
This is from hashicorp/terraform#21330
A workaround is to include a dummy default:
provider "restapi" {
# Default provider for rest API to avoid error on destroy WRT uri argument
# https://github.com/hashicorp/terraform/issues/21330
uri = "dummy"
}
I am creating a resource using
resource "restapi_object" "server_name" {
path = "/servernames/application"
data = "{\"appcode\": \"${var.requestor_appcode}\",\"requestor\": \"${var.requestor_id}\"}"
}
and then accessing it via
name = "${restapi_object.server_name.api_data.name}"
however, when running I get the error
* vsphere_virtual_machine.vm: Resource 'restapi_object.server_name' does not have attribute 'api_data.name' for variable 'restapi_object.server_name.api_data.name'
I was able to work around this by creating the restapi_object resource first (commenting out the vm resource) and applying and then uncommenting the rest and applying again. I've also tried adding a depends_on = ["restapi_object.server_name"]
but that also doesn't seem to help.
Any ideas?
Hello, I'm trying to use this provider with HPE OneView API which uses user authentication to generate a token.
Using postman, I post json data in the body with username, password, and authLoginDomain to get the token which I then use in the header using "Auth" for subsequent requests which use json in the body.
My attempts to get this working are not yet successful. I'm wondering if this provider is appropriate for this API?
I have tried hard coding the token and making the config match the API documentation.
Perhaps I'm missing something in my setup for this provider... here is my .tf.
provider "restapi" {
uri = "https://10.0.0.3/rest/"
insecure = true
debug = true
write_returns_object = true
headers {
"Content-Type" = "application/json"
"x-api-version" = 1000
"Auth" = "randomstringofcharacters1234567"
}
}
resource "restapi_object" "authenticate" {
path = "login-sessions"
data = "{ "userName": "${var.apiusername}", "password": "${var.apipassword}", "authLoginDomain": "local"}"
terraform plan gives me this error with or without the resource "restapi_object" block.
Please support the PATCH verb.
In v1.9.2:
When I use update_method: PUT
in the provider and update_path
in the resource. It returns 404 status.
However, if i use update_method:PUT
and create_method:PUT
in provider and create_path
in the resource, it will work for the first run. On the second run it returns 404.
What am I missing on this PUT request?
case 1: provider: PUT and resource : update_path
Originally posted by @cnguyenp in #46 (comment)
Hello There,
I'm very new to terraform restapi provider, Can anyone please help ?
could anyone please provide an example for the all config parameters,? It will be very very helpful for me
Provider configuration
uri
insecure
username
password
headers
use_cookies
timeout
id_attribute
create_method
read_method
update_method
delete_method
copy_keys
write_returns_object
create_returns_object
xssi_prefix
debug
Restapi resource configuration
path
create_path
read_path
update_path
destroy_path
id_attribute
object_id
data
force_new
debug
Restapi datasource configuration
path
query_string
search_key
search_value
results_key
id_attribute
debug
Thanks in advance,
Antonynixson I
Can you provide me sample terraform template for update, create and delete using JSON payload?
in this provider, I am seeing only for adding.
Hi,
I'm using this provider to interact with the Rackspace Load Balancers API.
So far it is working to create a new LB's, but it is not deleting the one that was already created, only creates new LBs instead of deleting the one that was already created an create a new one.
I'm using this code:
nodes_json => Using this to generate a template with the nodes that I will attach to the LB.
data_json => Using this to put all my variables together
token => Generates my auth-token
create_lb => API call to create the LB, and I assume to delete it but seems like it is not working.
provider "restapi" {
uri = "https://iad.loadbalancers.api.rackspacecloud.com/v1.0/${var.openstack_tenant_name}/loadbalancers"
debug = true
write_returns_object = true
create_returns_object = true
create_method = "POST"
update_method = "POST"
headers = {
Content-Type = "application/json",
X-Auth-Token = data.external.token.result["token"]
}
}
data "template_file" "nodes_json" {
template = "${file("${path.module}/templates/nodes_lb.json.tmpl")}"
count = "${var.openstack_count}"
vars = {
node_address = "${element(openstack_compute_instance_v2.nodes.*.network.1.fixed_ip_v4, count.index)}"
}
}
data "template_file" "data_json" {
template = "${file("${path.module}/templates/create_lb.json.tmpl")}"
vars = {
lb_name = "${var.openstack_lb_name}"
lb_port = "${var.openstack_lb_exposed_port}"
lb_protocol = "${var.openstack_lb_protocol}"
lb_timeout = "${var.openstack_lb_timeout}"
lb_algorithm = "${var.openstack_lb_algorithm}"
lb_nodes = "${join(",", data.template_file.nodes_json.*.rendered)}"
}
}
data "external" "token" {
program = [
"files/get_token.sh",
"-e",
"${var.openstack_auth_url}/tokens",
"-u",
"${var.openstack_username}",
"-a",
"${var.openstack_apikey}",
]
}
resource "restapi_object" "create_lb" {
path = "/"
create_path = "{id}"
read_path = "{id}"
update_path = "{id}"
destroy_path = "{id}"
id_attribute = "loadBalancer/id"
debug = true
data = "${data.template_file.data_json.rendered}"
}
create_lb.json.tmpl
{
"loadBalancer":
{
"name" : "${lb_name}",
"port" : "${lb_port}",
"protocol" : "${lb_protocol}",
"timeout" : "${lb_timeout}",
"algorithm" : "${lb_algorithm}",
"virtualIps" : [
{
"type": "PUBLIC"
}
],
"nodes" : [
${lb_nodes}
]
}
}
get_token.sh
#!/bin/bash
#set -eux
function usage() {
# NOTE: Keep sorted for easy git merges
cat << E_O_F
Usage:
-e Endpoint
-u username
-a API Key
E_O_F
}
function check_deps() {
test -f $(which jq) || error_exit "jq command not detected in path, please install it"
}
# NOTE: Keep sorted for easy git merges
while getopts "a:e:u:h?" opt; do
case "$opt" in
e) ENDPOINT=${OPTARG}
;;
u) USERNAME=${OPTARG}
;;
a) API_KEY=${OPTARG}
;;
h|\?)
usage
exit 0
;;
esac
done
check_deps
TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{ "auth": { "RAX-KSKEY:apiKeyCredentials": { "username": "'$USERNAME'", "apiKey": "'$API_KEY'" } } }' $ENDPOINT | jq '.access.token.id' | tr -d "\"")
jq -n --arg token "$TOKEN" '{"token":$token}'
Any light is helpful.
Hello. I know this is not an issue but rather me misunderstanding how the module works, but please bear with me here.
I'm trying to make a PUT request to modify a CloudFlare resource via its API. However, for some reason, I cannot convince the restapi provider to send a PUT request. It always POSTs.
Here is my particular snippet:
resource "cloudflare_load_balancer_pool" "ext_api" {
name = "api-pool"
origins {
name = "origin-1"
address = "10.0.0.1"
}
origins {
name = "origin-2"
address = "10.0.0.2"
}
minimum_origins = "1"
}
provider "restapi" {
uri = "https://api.cloudflare.com"
write_returns_object = true
debug = true
headers {
X-Auth-Email = "${var.cloudflare_api["email"]}"
X-Auth-Key = "${var.cloudflare_api["token"]}"
Content-Type = "application/json"
}
}
resource "restapi_object" "ext_api_pool" {
path = "/client/v4/user/load_balancers/pools"
object_id = "${cloudflare_load_balancer_pool.ext_api.id}"
data = <<EOF
{
"name": "api-pool",
"minimum_origins": 1,
"origins": [
{
"name": "origin-1",
"address": "10.0.0.1",
"enabled": true,
"weight": "${var.origin1_weight}"
},
{
"name": "origin-2",
"address": "10.0.0.2",
"enabled": true,
"weight": "${var.origin2_weight}"
}
]
}EOF
}
On each run, the result is the following:
* restapi_object.ext_api_pool: Unexpected response code '409': {
"result": null,
"success": false,
"errors": [
{
"code": 1003,
"message": "value not unique"
}
],
"messages": []
}
This is due to restapi POSTing and trying to create the resource again, conflicting with the existing one created by the Cloudflare module. I want it to PUT that request so that the weights are modified.
What am I doing wrong here? I tried:
I may be missing something very subtle here, but please help.
Regards,
Claudiu
Where/how do I download the binaries for this does not work directly with Terraform v0.12.6 ?
The installation guide talks about downloading Binaries ?
Hi,
Thanks for creating this. I would use this provider however after cloning the repo, I can't seem to identify the binaries or create then with a "make build"
Any help would be greatly appreciated.
Hi,
Is it possible to add an example.tf with some basic use case?
Thank you
Hi again,
As mentioned on #43, I'm creating some LB's using an API call, and once the API is made I'm trying to use the output on terraform.
Right now, when I use:
output "LB-IP" {
value = ["${restapi_object.create_lb.api_data}"]
}
This is the output:
LB-IP = [
{
"loadBalancer" = "map[cluster:map[name:ztm-n17.iad3.lbaas.rackspace.net] httpsRedirect:false protocol:HTTP port:80 nodes:[map[type:PRIMARY port:80 status:ONLINE condition:ENABLED weight:1 address:10.176.160.39 id:964073] map[condition:ENABLED weight:1 address:10.176.160.34 id:964075 type:PRIMARY port:80 status:ONLINE] map[condition:ENABLED weight:1 address:10.176.160.56 id:964077 type:PRIMARY port:80 status:ONLINE]] contentCaching:map[enabled:false] name:terra-lb updated:map[time:2019-07-03T21:56:34Z] halfClosed:false sourceAddresses:map[ipv6Public:2001:4802:7903:100::5/64 ipv4Public:146.20.52.5 ipv4Servicenet:10.187.186.5] timeout:120 id:250983 connectionLogging:map[enabled:false] created:map[time:2019-07-03T21:56:34Z] virtualIps:[map[id:14393 type:PUBLIC ipVersion:IPV4 address:146.20.52.137] map[ipVersion:IPV6 address:2001:4802:7903:0100:18f8:8715:0000:001a id:9.086273e+06 type:PUBLIC]] algorithm:ROUND_ROBIN status:BUILD]"
},
]
When I use:
output "LB-IP" {
value = ["${restapi_object.create_lb.api_data.loadBalancer}"]
}
The output is:
"map[nodes:[map[condition:ENABLED weight:1 address:10.176.160.56 id:964085 type:PRIMARY port:80 status:ONLINE] map[address:10.176.160.34 id:964087 type:PRIMARY port:80 status:ONLINE condition:ENABLED weight:1] map[type:PRIMARY port:80 status:ONLINE condition:ENABLED weight:1 address:10.176.160.39 id:964089]] contentCaching:map[enabled:false] connectionLogging:map[enabled:false] httpsRedirect:false sourceAddresses:map[ipv6Public:2001:4802:7901::8/64 ipv4Public:162.209.114.8 ipv4Servicenet:10.189.254.8] timeout:120 name:terra-lb port:80 virtualIps:[map[ipVersion:IPV4 address:23.253.147.48 id:4583 type:PUBLIC] map[ipVersion:IPV6 address:2001:4802:7901:0000:18f8:8715:0000:0012 id:9.086277e+06 type:PUBLIC]] updated:map[time:2019-07-03T22:53:15Z] id:250987 protocol:HTTP cluster:map[name:ztm-n05.iad3.lbaas.rackspace.net] created:map[time:2019-07-03T22:53:15Z] halfClosed:false status:BUILD algorithm:ROUND_ROBIN]",
]
And finally, when I use:
output "LB-IP" {
value = ["${lookup(restapi_object.create_lb.api_data.loadBalancer, "ipv4Public}"]
}
Does not even run correctly, the output is:
Error: Invalid character
on terraform/outputs.tf line 17, in output "LB-IP":
17: # value = "${formatlist(
Please help!!
Hi. I have an API, the request body for CREATE looks similar to this:
{
"metadata": {
...,
},
"resources": [
{
"name": "Test Key",
"type": "root"
}
]
}
The response body looks like this:
{
"metadata": {
...,
},
"resources": [
{
"id": "bc17d646-f9ac-46a9-9bff-afcdb5bae888",
"name": "Test Key",
"state": 1,
"type": "root"
}
]
}
The provider is able to create the object but since id
isn't a top-level attribute, it cannot effectively set the Object ID:
Error: Error applying plan:
1 error(s) occurred:
* restapi_object.kmskey: 1 error(s) occurred:
* restapi_object.kmskey: Internal validation failed. Object ID is not set, but *may* have been created. This should never happen!
Can an attribute be added to support non top-level ID attributes? Similar to results_key
in the datasource where:
resource "restapi_object" "kmskey" {
path = "keys"
data = "{...}"
id_key = "resources[0]/id"
}
I understand that this is more of a complex example and may not be the intended purpose of a generic restapi provider.
Is there any plan to support MIME (Content-Type: multipart/form-data
)?
Getting a 500 Internal Server error shouldn't invalidate a resource but rather trigger a fault or a retry.
Some APIs such as the Vault API require the user to specify the ID of an object being created as the last part of the URL. While this provider can actually create a Vault secret, it gets an error when trying to read the secret back during terraform apply
. So, if I set id_attribute to "id", my resource path to "/secret/restapi/test" and data to "{"foo":"bar","id":"test"}", the provider successfully writes the secret to <vault_url>:8200/v1/secret/restapi/test, but then tries to read it back from <vault_url>:8200/v1/secret/restapi/test/test which does not exist.
Additionally, one would not normally include the final part of the Vault path as a key in the body as I have done. I only did that so I could get the provider to write the secret. Normally, my data would have just been "{"foo":"bar"}"
So, I think it would be useful to somehow support URLs like these. Note that these URLs each effectively only manage a single object.
The key to making the provider work with these paths is to make it use the same URL for POSTs that it uses for GETs, PUTs, and DELETEs. Somehow, the user would be able to indicate that the ID for their object actually is the last segment of the resource path.
See #4 in which I requested more flexibility for specifying object IDs and included the possibility of specifying that the ID is the last segment of the resource path.
I've noticed a significant issue with the datasource: the GET done by read_object near the end is being done against the same path as the first GET done on line 83. That means it returns all the objects returned by the first GET and stores data for all the objects in the object identified through the datasource search attributes. I recommend adding a line with obj.get_path = path + "/{id}"
before line 142. The second GET will then use the ID returned by the search logic of the datasource code.
Additionally, it seems to me that the call to d.SetId(obj.id)
on line 139 is not needed since the same call is made on line 146 which is where it is really needed. Even if you were going to keep the call on line 139, it seems to me that it should be done after the call to obj.id = id
that is currently on line 140.
Additionally, the call to d.Id()
in line 65 does not make sense to me. I don't think the d object will have any ID at that point in the execution of the code, at least not when the datasource is first added to the Terraform configuration. I suggest setting the id being passed to NewAPIObject to "0". This will avoid having to set create_returns_object to true in the provider configuration in order to use the datasource which is currently the case since if NewAPIObject sees a blank id (""), it checks to make sure that at least one of create_returns_object or write_returns_object is set to true. But the user should not be forced to set these to true if they don't need them set to true for their resources.
I've actually made these and some other modifications to the datasource code, but have avoided pushing my changes to Github since I would prefer those be handled on a separate branch in my fork and have not had time to do set that up yet. But I do hope to submit a pull request some time this week.
When invoking Terraform Enterprise API endpoints, one typically gets back a response that looks like:
{
"data": {
"id": "4111797",
"type": ...
...
}
}
While I can create TFE objects with this provider, since the id is nested under data, the ID of the object is not set correctly in the Terraform state and it therefore cannot be destroyed.
Would it be possible to handle the ID deeper in the api_data structure?
Possibilities that occur to me include:
Additionally, it would also be useful to allow the user to specify that the id_attribute is actually the last segment of the resource path. This would be useful for APIs like Vault's API in which the object created such are often specified at the end of the URL rather than in the body of the request. For more on this, see #5
I was wondering if set_resource_state might be able to do a deep copy of obj.api_data so that the actual object in Terraform would have nested fields under api_data that would be accessible with outputs and references from other resources. Is this something you've investigated?
Would simply doing api_data[k] = v
in set_resource_state() work?
If not, would one of the deepCopyJSON functions suggested under https://stackoverflow.com/questions/51459083/deep-copying-maps-in-golang work?
Hi,
On issue #43 I mentioned that I'm creating some LB's with an API calls, and I generate a template with some data, and to create a new LB I just need to update a few parameters of my template.
Instead of having template1, template2,..., templateN, and restapi_object1, restapi_object2, etc there is a process to reuse the same API call using diferent data/template each time??
Thanks in advance
Some APIs don't actually need any data sent to them to create objects. It would be good to allow the data attribute on the resource to be empty or "".
Just need a little help wrapping my head around this:
but say I have an API with nested IDs, how would I reference this in terraform?
For example, a URL of a customer object is https://api.website.com/v1/customers
and the customer object has multiple nested objects that have ID fields. For example https://api.website.com/v1/customers/<customer_id>/products/<product_id>
I need to create/set products that are attached to a customer using TF.
I'm still a bit new to TF.
Hi,
We are using restapi provider to configure elasticsearch, which is created in the same terraform apply. It is not possible to set the uri parameter to the output of newly created resource (hashicorp/terraform#2430). It will be great to have a possibility to leave provider's uri parameter empty.
For now we are using "clever" workaround:
provider "restapi" {
uri = "https:"
}
And in the resource:
resource "restapi_object" "elasticsearch_template_others" {
path = "//${aws_elasticsearch_domain.es.endpoint}/_template"
object_id = "template_2"
create_path = "//${aws_elasticsearch_domain.es.endpoint}/_template/{id}"
data = <<EOF
{
"index_patterns": [
"*"
],
"settings": {
"number_of_shards": "1",
"number_of_replicas": "1"
}
}
EOF
}
Hello There,
In my case i do not have username and password to access api ! Can anyone please let me know if it is possible to pass api_key and secret_key through headers ? if yes please help here! how to pass api_key and secret_key through headers ?
Thanks in advance,
Antonynixson I
I am using the provider to post to an api that takes json and returns a string. The post works as expected but always returns 'Error json: cannot unmarshal string into Go value of type map[string]interface {}'. I would like to set the expected return type or ignore the response.
This is a proposal to add support for write operations to send the request body as application/x-www-form-urlencoded
data. Currently the request body is limited to application/json
data. If this proposal is implemented, then it will allow this provider to interact with a greater subset of REST APIs, such as Pingdom's REST API.
From a user's perspective, the restapi_object
could gain an additional argument write_content_type
. This new argument's values would be restricted to json
(default) and x-www-form-urlencoded
. Alternatively, a new argument write_request_body
could be added that overrides the request body generated from the data
argument, allowing the request body for write operations to be formatted arbitrarily. The latter alternative would open up this provider to interact with even more content types than application/json
and application/x-www-form-urlencoded
.
Thanks for this provider - been using for a day or so now and it's nicely thought out.
I'm working with the gitea API, and trying to add a user to a team. The only related API methods for this are:
PUT /team/0/members/robertgates55
- to add a user object to team 0
DELETE /team/0/members/robertgates55
- to remove user object from team 0
GET /team/0/members
- returns an array of the user objects in that team
Is there any way I can work with this API? I've already set create_method = "PUT"
in the provider, and am setting the object_id
manually (as the PUT
doesn't return the object it creates); but since theres no GET /team/0/members/robertgates55
method available, we obviously can't work out whether my object_id
is a member of the team.
Any ideas?
Hi
I was trying to create Host record in infoblox using the provider. The Host record gets created but my terraform apply fails.
restapi_object.allocate_ip: Creating...
api_data.%: "" => ""
create_path: "" => "/record:host"
data: "" => "{"ipv4addrs":[{"ipv4addr":"10.7.8.7"}],"name":"tfhosttest.fisdev.local"}\n"
path: "" => "/record:host"
Error: Error applying plan:
1 error(s) occurred:
restapi_object.allocate_ip: 1 error(s) occurred:
restapi_object.allocate_ip: Internal validation failed. Object ID is not set, but may have been created. This should never happen!
Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.
resource "restapi_object" "allocate_ip" {
path = "/record:host"
create_path = "/record:host"
data = "${file("add_host_record.json")}"
}
{"ipv4addrs":[{"ipv4addr":"10.7.8.7"}],"name":"tfhosttest.fisdev.local"}
provider "restapi" {
uri = "https://myinfoblox.dev.local/wapi/v2.6/"
insecure = true
username = "admin"
password = "xxxxxxxxxxxx"
write_returns_object = true
create_method = "POST"
update_method = "POST"
create_returns_object = true
debug = true
}
Please let me know what I need to do to fix this problem.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.