hashicorp / hashicorp/terraform-plugin-sdk
Add support for resource schema properties with nested structures
- Dominant language
- Go
- Stars
- 485
- Forks
- 244
- Avg merge
- 19h 57m
- Merged PRs (30d)
- 4
Description
### Current Terraform Version
````
Terraform v0.11.13
````
### Use-cases
_As a service provider building my own custom terraform provider, I would like to be able to have resources with schemas that contain properties with nested structures._
More context:
One of the APIs I am building a custom terraform plugin for, requires support for nested objects (nested structures).
After building the custom terraform provider providing support for the API aforementioned, I ran into the following error message when managing such resource:
````
Error: swaggercodegen_cdn_v1.my_cdn: object_nested_scheme_property (object_property): '' expected type 'string', got unconvertible type '[]map[string]interface {}'
````
The terraform config looks like this:
````
resource "swaggercodegen_cdn_v1" "my_cdn" {
object_nested_scheme_property = {
name = "dani"
object_property = {
account = "something"
}
}
}
````
For the sake of more context, the API in question has the following OpenAPI v2 spec model.
````
definitions:
ExampleModel:
type: "object"
required:
- object_nested_scheme_property
properties:
id:
type: "string"
readOnly: true
object_nested_scheme_property:
type: object # nested properties required type equal object to be considered as object
properties:
name:
type: string
object_property:
type: "object"
properties:
account:
type: string
````
### Attempted Solutions
So far I have just tried to understand where the error is being thrown, and that's where I ran into the following line of code from the terraform core library where it clearly states that nested structs are not currently supported:
Link to potentially the source of the issue:
https://github.com/hashicorp/terraform/blob/master/helper/schema/schema.go#L1646
Pasting here the comment line the above link points to:
````
Comment:
// TODO: We don't actually support this (yet)
// but silently pass the validation, until we decide
// how to handle nested structures in maps
````
The translated terraform resource schema struct for the above definition looks as follows:
````
(*schema.Resource)(0xc0002b9260)({
Schema: (map[string]*schema.Schema) (len=9) {
(string) (len=29) "object_nested_scheme_property": (*schema.Schema)(0xc0001573b0)({
Type: (schema.ValueType) TypeMap,
Optional: (bool) false,
Required: (bool) true,
DiffSuppressFunc: (schema.SchemaDiffSuppressFunc) ,
Default: (interface {}) ,
DefaultFunc: (schema.SchemaDefaultFunc) ,
Description: (string) "",
InputDefault: (string) "",
Computed: (bool) false,
ForceNew: (bool) false,
StateFunc: (schema.SchemaStateFunc) ,
Elem: (*schema.Resource)(0xc0002b8850)({
Schema: (map[string]*schema.Schema) (len=2) {
(string) (len=15) "object_property": (*schema.Schema)(0xc000157590)({
Type: (schema.ValueType) TypeMap,
Optional: (bool) true,
Required: (bool) false,
DiffSuppressFunc: (schema.SchemaDiffSuppressFunc) ,
Default: (interface {}) ,
DefaultFunc: (schema.SchemaDefaultFunc) ,
Description: (string) "",
InputDefault: (string) "",
Computed: (bool) false,
ForceNew: (bool) false,
StateFunc: (schema.SchemaStateFunc) ,
Elem: (*schema.Resource)(0xc0002b87e0)({
Schema: (map[string]*schema.Schema) (len=1) {
(string) (len=7) "account": (*schema.Schema)(0xc000157680)({
Type: (schema.ValueType) TypeString,
Optional: (bool) true,
Required: (bool) false,
DiffSuppressFunc: (schema.SchemaDiffSuppressFunc) ,
Default: (interface {}) ,
DefaultFunc: (schema.SchemaDefaultFunc) ,
Description: (string) "",
InputDefault: (string) "",
Computed: (bool) false,
ForceNew: (bool) false,
StateFunc: (schema.SchemaStateFunc) ,
Elem: (interface {}) ,
MaxItems: (int) 0,
MinItems: (int) 0,
PromoteSingle: (bool) false,
Set: (schema.SchemaSetFunc) ,
ComputedWhen: ([]string) ,
ConflictsWith: ([]string) ,
Deprecated: (string) "",
Removed: (string) "",
ValidateFunc: (schema.SchemaValidateFunc) 0x1bf1c80,
Sensitive: (bool) false
})
},
SchemaVersion: (int) 0,
MigrateState: (schema.StateMigrateFunc) ,
Create: (schema.CreateFunc) ,
Read: (schema.ReadFunc) ,
Update: (schema.UpdateFunc) ,
Delete: (schema.DeleteFunc) ,
Exists: (schema.ExistsFunc) ,
CustomizeDiff: (schema.CustomizeDiffFunc) ,
Importer: (*schema.ResourceImporter)(),
DeprecationMessage: (string) "",
Timeouts: (*schema.ResourceTimeout)()
}),
MaxItems: (int) 0,
MinItems: (int) 0,
PromoteSingle: (bool) false,
Set: (schema.SchemaSetFunc) ,
ComputedWhen: ([]string) ,
ConflictsWith: ([]string) ,
Deprecated: (string) "",
Removed: (string) "",
ValidateFunc: (schema.SchemaValidateFunc) ,
Sensitive: (bool) false
}),
(string) (len=4) "name": (*schema.Schema)(0xc0001574a0)({
Type: (schema.ValueType) TypeString,
Optional: (bool) true,
Required: (bool) false,
DiffSuppressFunc: (schema.SchemaDiffSuppressFunc) ,
Default: (interface {}) ,
DefaultFunc: (schema.SchemaDefaultFunc) ,
Description: (string) "",
InputDefault: (string) "",
Computed: (bool) false,
ForceNew: (bool) false,
StateFunc: (schema.SchemaStateFunc) ,
Elem: (interface {}) ,
MaxItems: (int) 0,
MinItems: (int) 0,
PromoteSingle: (bool) false,
Set: (schema.SchemaSetFunc) ,
ComputedWhen: ([]string) ,
ConflictsWith: ([]string) ,
Deprecated: (string) "",
Removed: (string) "",
ValidateFunc: (schema.SchemaValidateFunc) 0x1bf1c80,
Sensitive: (bool) false
})
},
SchemaVersion: (int) 0,
MigrateState: (schema.StateMigrateFunc) ,
Create: (schema.CreateFunc) ,
Read: (schema.ReadFunc) ,
Update: (schema.UpdateFunc) ,
Delete: (schema.DeleteFunc) ,
Exists: (schema.ExistsFunc) ,
CustomizeDiff: (schema.CustomizeDiffFunc) ,
Importer: (*schema.ResourceImporter)(),
DeprecationMessage: (string) "",
Timeouts: (*schema.ResourceTimeout)()
}),
MaxItems: (int) 0,
MinItems: (int) 0,
PromoteSingle: (bool) false,
Set: (schema.SchemaSetFunc) ,
ComputedWhen: ([]string) ,
ConflictsWith: ([]string) ,
Deprecated: (string) "",
Removed: (string) "",
ValidateFunc: (schema.SchemaValidateFunc) ,
Sensitive: (bool) false
}),
},
SchemaVersion: (int) 0,
MigrateState: (schema.StateMigrateFunc) ,
Create: (schema.CreateFunc) 0x1bf8ef0,
Read: (schema.ReadFunc) 0x1bf8ff0,
Update: (schema.UpdateFunc) 0x1bf91f0,
Delete: (schema.DeleteFunc) 0x1bf90f0,
Exists: (schema.ExistsFunc) ,
CustomizeDiff: (schema.CustomizeDiffFunc) ,
Importer: (*schema.ResourceImporter)(0xc000010368)({
State: (schema.StateFunc) 0x1bf34b0
}),
DeprecationMessage: (string) "",
Timeouts: (*schema.ResourceTimeout)(0xc000370ba0)({
Create: (*time.Duration)(0xc0003ba690)(30s),
Read: (*time.Duration)(),
Update: (*time.Duration)(),
Delete: (*time.Duration)(),
Default: (*time.Duration)(0xc000370ac0)(10m0s)
})
})
````
I am happy yo contribute to add support for this feature, however the comment above seems to suggest the terraform team has not decided yet ```how to handle nested structures in maps``` so I was wondering if you could provide more insight about this.
Thanks!
### Proposal
### References
Contributor guide
Assessment
This issue has not been assessed yet.