Mastercard / terraform-provider-restapi

A terraform provider to manage objects in a RESTful API
Other
816 stars 218 forks source link

Can URIs be varaibles? #167

Open jdavies opened 2 years ago

jdavies commented 2 years ago

I creating a script that first creates a database with a REST API. The URI to the newly created database is not static. As a result, I am setting the uri field i the restapi provider to equal an object reference. It WILL work if I pass in a variable as shown below, but that technique would requir

provider "restapi" {
  alias                = "restapi_headers"
  uri                  = "${var.myuri}"
  debug                = true
  write_returns_object = true
}

However, when I use an object reference instead...

provider "restapi" {
  alias                = "restapi_headers"
  uri                  = "${astra_database.cdc_demo_db.data_endpoint_url}"
  # uri                  = "https://06de6da8-79b7-4d41-b993-8479e87a75d4-us-east-2.apps.astra.datastax.com/api/rest/v1/keyspaces"
  debug                = true
  write_returns_object = true

  headers = {
    X-Cassandra-Token = astra_token.api_token.token
  }
}

I think the key to this problem is that the ${astra_database.cdc_demo_db.data_endpoint_url} value is not known until the terrafrom apply action is complete. Is there anyway to get the restapi provider to use the value during the apply stage? The Astra DB provider is able to do this so it must be possible. Here is the output of my terraform init command and you can see the place holders for furture generated values

Changes to Outputs:
  + cdc_demo_admin_role_API_Token     = (known after apply)
  + cdc_demo_admin_role_Client_ID     = (known after apply)
  + cdc_demo_admin_role_Client_Secret = (known after apply)
  + cdc_demo_admin_role_ID            = (known after apply)
  + cqlsh_url                         = (known after apply)
  + data_endpoint_url                 = (known after apply)
  + database_id                       = (known after apply)
  + grafana_url                       = (known after apply)
  + graphql_url                       = (known after apply)
jonathan-kaufman-by commented 2 years ago

If the DB is already created when you run terraform, you could try using a data resource to enumerate your database and get the url that way. If you are trying to create the DB and use the API in a single run of terraform .. That might be tough. In general, I believe the official terraform recommendation for cases where you need to use a value known only after apply, it is recommended to first use terraform apply -target to create the resource (DB in this case) and then run apply again for the rest of it. https://learn.hashicorp.com/tutorials/terraform/resource-targeting Other possible way's of handling this would be to use something like terragrunt (https://terragrunt.gruntwork.io/docs/) to run the db create and the follow up terraform together as a single deployment stack with the follow up scenario having the db create as a dependency (so Terragrunt knows to run it first). You might be able to create the DB, and then use a data resource which is dependent on the create resource and see if you can trick the provider into getting the data resource info after the DB is created, but before the object reference is "available" internally.

DRuggeri commented 2 years ago

Hi, @jdavies! @jonathan-kaufman-by's response is very thorough. I think your initial report came a bit short of sharing what happens when you try it (started with "However, when I use an object reference instead..."), but only the config snippet was shared :-) So I am operating on the assumption that terraform doesn't support using resource variables in a provider definition.

The provider should support variable interpolation on a resource directly in Terraform just fine, though, so one additional thing I was thinking about is marking a dependency on the astra_database resource for your restapi resource (this may happen naturally as Terraform walks the graph, but I prefer being explicit). The expectation is that as long as the astra_database resource is well-behaved, the variable you would like to reference should be available immediately after the resource is created.

It's a slight 'hack', but you could then plumb up the provider with a dummy path and override the resource paths ((create|update|read|delete)_path) with variable interpolation. Might be worth a shot? In any event, it would be super helpful if you find a working formula to share an example via pull request.

jdavies commented 2 years ago

Thanks for the tips Jonathan-kauffman-by! I'll try running with a specific target first. I now the Astra provider marks all of it's output as "known after apply", but is then able to access them while the script is running the apply stage. It the reason it can access those values because they are all within the same provider? I'll take a shot and let you know how it goes! Thanks again!

jdavies commented 2 years ago

@DRuggeri Ill see if I can setup the dependency as you suggest. I'm no expert in Terraform (yet) but if I know the terminology, it makes searching all that much easier! I'll keep you posted.