Can the Terraform Schema support multiple Schema types for an Elem
? The problem I'm trying to solve is that the data from my external API is an array that has multiple types--some elements are strings and some are lists. For instance a value would look something like:
condition = [
"and",
[
"contains",
["foo","bar","baz"],
"website"
]
And then, I create my schema for that property to look something like this
"condition": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeList,
},
},
But, when I run my test I get a message that says:
condition.0: should be a list
Which, this makes sense because my schema definition declares that every Elem
should be a list. Is there a way to define multiple types for the Elem
?
UPDATE:
I've changed my condition
field from the above to be
"condition_json": {
Type: schema.TypeString,
Required: true,
},
My .tf
file is now using jsonencode()
like so:
variable "condition_list" {
default = [
["and"],
["contains",["path","payload","source"],"website"],
["contains",["path","headers","from","0","address"],"homer"]
]
}
resource "event_rule" "first" {
condition_json = "${jsonencode(var.condition_list)}"
}
When I build my struct for my event rule object, the Condition
field is getting the value of condition_json
like so:
Condition: d.Get("condition_json").([]interface{}),
Because my Condition field in the library interfacing with the API looks like:
Condition []interface{} `json:"condition,omitempty"`
My problem is that I'm getting an error that
interface {} is string, not []interface {}
This message makes sense because I have the schema set to TypeString
but, in my struct interfacing with the API I have Condition
typed as []interface{}
. My question is, is there a way to cast d.Get("condition_json") to []interface{}
rather than assert?
I'm obviously missing something, and I'm not sure what. :)
In the current (at the time of writing) Terraform SDK, this is not possible: every value must have a specific defined type because the SDK relies on it to correctly decode the data stored in Terraform state snapshots.
A common workaround for that limitation in providers today is to have a field of a string type that accepts a JSON serialization of the value. In order to allow migration away from this workaround in future, these attributes are conventionally named with a _json
suffix, like condition_json
in your case. Terraform 0.12 improved the robustness of the jsonencode
function to make it easier to provide values for such attributes without needing to hand-write JSON strings in the configuration.
Terraform 0.12 introduced support for dynamically-typed attributes at the core layer and in the provider protocol, and so a future version of the Terraform SDK will include a capability to define an attribute as being runtime-typed. That is, the value type will be included in the message sent over the wire rather than being assumed from the schema. At that point, you can potentially use that mode for your attribute here. If you'd previously used the _json
attribute workaround at that point, it would be possible to support both the JSON mode and the dynamic-type mode at the same time for a while to gracefully transition.