helper/plugin: Implement Schema.SkipCoreTypeCheck
The previous commit added this flag but did not implement it. Here we implement it by adjusting the shape of schema we return to Terraform Core to mark the attribute as untyped and then ensure that gets handled correctly on the SDK side.
This commit is contained in:
parent
7f860dc83e
commit
135121562e
|
@ -27,6 +27,21 @@ func testResourceConfigMode() *schema.Resource {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"resource_as_attr_dynamic": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
ConfigMode: schema.SchemaConfigModeAttr,
|
||||||
|
SkipCoreTypeCheck: true,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"foo": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,13 +52,14 @@ func testResourceConfigModeCreate(d *schema.ResourceData, meta interface{}) erro
|
||||||
}
|
}
|
||||||
|
|
||||||
func testResourceConfigModeRead(d *schema.ResourceData, meta interface{}) error {
|
func testResourceConfigModeRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
const k = "resource_as_attr"
|
for _, k := range []string{"resource_as_attr", "resource_as_attr_dynamic"} {
|
||||||
if l, ok := d.Get(k).([]interface{}); !ok {
|
if l, ok := d.Get(k).([]interface{}); !ok {
|
||||||
return fmt.Errorf("%s should appear as []interface{}, not %T", k, l)
|
return fmt.Errorf("%s should appear as []interface{}, not %T", k, l)
|
||||||
} else {
|
} else {
|
||||||
for i, item := range l {
|
for i, item := range l {
|
||||||
if _, ok := item.(map[string]interface{}); !ok {
|
if _, ok := item.(map[string]interface{}); !ok {
|
||||||
return fmt.Errorf("%s[%d] should appear as map[string]interface{}, not %T", k, i, item)
|
return fmt.Errorf("%s[%d] should appear as map[string]interface{}, not %T", k, i, item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,22 @@ resource "test_resource_config_mode" "foo" {
|
||||||
foo = "resource_as_attr 1"
|
foo = "resource_as_attr 1"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
resource_as_attr_dynamic = [
|
||||||
|
{
|
||||||
|
foo = "resource_as_attr_dynamic 0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
`),
|
`),
|
||||||
Check: resource.ComposeTestCheckFunc(
|
Check: resource.ComposeTestCheckFunc(
|
||||||
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.#", "2"),
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.#", "2"),
|
||||||
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.0.foo", "resource_as_attr 0"),
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.0.foo", "resource_as_attr 0"),
|
||||||
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.1.foo", "resource_as_attr 1"),
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.1.foo", "resource_as_attr 1"),
|
||||||
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr_dynamic.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr_dynamic.0.foo", "resource_as_attr_dynamic 0"),
|
||||||
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr_dynamic.1.foo", "default"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
resource.TestStep{
|
resource.TestStep{
|
||||||
|
@ -39,21 +49,39 @@ resource "test_resource_config_mode" "foo" {
|
||||||
foo = "resource_as_attr 0 updated"
|
foo = "resource_as_attr 0 updated"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
resource_as_attr_dynamic = [
|
||||||
|
{
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
`),
|
`),
|
||||||
Check: resource.ComposeTestCheckFunc(
|
Check: resource.ComposeTestCheckFunc(
|
||||||
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.#", "1"),
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.#", "1"),
|
||||||
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.0.foo", "resource_as_attr 0 updated"),
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.0.foo", "resource_as_attr 0 updated"),
|
||||||
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr_dynamic.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr_dynamic.0.foo", "default"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
resource.TestStep{
|
resource.TestStep{
|
||||||
Config: strings.TrimSpace(`
|
Config: strings.TrimSpace(`
|
||||||
resource "test_resource_config_mode" "foo" {
|
resource "test_resource_config_mode" "foo" {
|
||||||
resource_as_attr = []
|
resource_as_attr = []
|
||||||
|
resource_as_attr_dynamic = []
|
||||||
}
|
}
|
||||||
`),
|
`),
|
||||||
Check: resource.ComposeTestCheckFunc(
|
Check: resource.ComposeTestCheckFunc(
|
||||||
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.#", "0"),
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr.#", "0"),
|
||||||
|
resource.TestCheckResourceAttr("test_resource_config_mode.foo", "resource_as_attr_dynamic.#", "0"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: strings.TrimSpace(`
|
||||||
|
resource "test_resource_config_mode" "foo" {
|
||||||
|
}
|
||||||
|
`),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckNoResourceAttr("test_resource_config_mode.foo", "resource_as_attr.#"),
|
||||||
|
resource.TestCheckNoResourceAttr("test_resource_config_mode.foo", "resource_as_attr_dynamic.#"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (s *GRPCProviderServer) GetSchema(_ context.Context, req *proto.GetProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Provider = &proto.Schema{
|
resp.Provider = &proto.Schema{
|
||||||
Block: convert.ConfigSchemaToProto(s.getProviderSchemaBlock()),
|
Block: convert.ConfigSchemaToProto(s.getProviderSchemaBlockForCore()),
|
||||||
}
|
}
|
||||||
|
|
||||||
for typ, res := range s.provider.ResourcesMap {
|
for typ, res := range s.provider.ResourcesMap {
|
||||||
|
@ -72,26 +72,41 @@ func (s *GRPCProviderServer) GetSchema(_ context.Context, req *proto.GetProvider
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GRPCProviderServer) getProviderSchemaBlock() *configschema.Block {
|
func (s *GRPCProviderServer) getProviderSchemaBlockForCore() *configschema.Block {
|
||||||
return schema.InternalMap(s.provider.Schema).CoreConfigSchema()
|
return schema.InternalMap(s.provider.Schema).CoreConfigSchema()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GRPCProviderServer) getResourceSchemaBlock(name string) *configschema.Block {
|
func (s *GRPCProviderServer) getResourceSchemaBlockForCore(name string) *configschema.Block {
|
||||||
res := s.provider.ResourcesMap[name]
|
res := s.provider.ResourcesMap[name]
|
||||||
return res.CoreConfigSchema()
|
return res.CoreConfigSchema()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GRPCProviderServer) getDatasourceSchemaBlock(name string) *configschema.Block {
|
func (s *GRPCProviderServer) getDatasourceSchemaBlockForCore(name string) *configschema.Block {
|
||||||
dat := s.provider.DataSourcesMap[name]
|
dat := s.provider.DataSourcesMap[name]
|
||||||
return dat.CoreConfigSchema()
|
return dat.CoreConfigSchema()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *GRPCProviderServer) getProviderSchemaBlockForShimming() *configschema.Block {
|
||||||
|
return schema.InternalMap(s.provider.Schema).CoreConfigSchemaForShimming()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GRPCProviderServer) getResourceSchemaBlockForShimming(name string) *configschema.Block {
|
||||||
|
res := s.provider.ResourcesMap[name]
|
||||||
|
return res.CoreConfigSchemaForShimming()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GRPCProviderServer) getDatasourceSchemaBlockForShimming(name string) *configschema.Block {
|
||||||
|
dat := s.provider.DataSourcesMap[name]
|
||||||
|
return dat.CoreConfigSchemaForShimming()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *GRPCProviderServer) PrepareProviderConfig(_ context.Context, req *proto.PrepareProviderConfig_Request) (*proto.PrepareProviderConfig_Response, error) {
|
func (s *GRPCProviderServer) PrepareProviderConfig(_ context.Context, req *proto.PrepareProviderConfig_Request) (*proto.PrepareProviderConfig_Response, error) {
|
||||||
resp := &proto.PrepareProviderConfig_Response{}
|
resp := &proto.PrepareProviderConfig_Response{}
|
||||||
|
|
||||||
block := s.getProviderSchemaBlock()
|
blockForCore := s.getProviderSchemaBlockForCore()
|
||||||
|
blockForShimming := s.getProviderSchemaBlockForShimming()
|
||||||
|
|
||||||
configVal, err := msgpack.Unmarshal(req.Config.Msgpack, block.ImpliedType())
|
configVal, err := msgpack.Unmarshal(req.Config.Msgpack, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -162,19 +177,19 @@ func (s *GRPCProviderServer) PrepareProviderConfig(_ context.Context, req *proto
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
configVal, err = block.CoerceValue(configVal)
|
configVal, err = blockForShimming.CoerceValue(configVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
config := terraform.NewResourceConfigShimmed(configVal, block)
|
config := terraform.NewResourceConfigShimmed(configVal, blockForShimming)
|
||||||
schema.FixupAsSingleResourceConfigIn(config, s.provider.Schema)
|
schema.FixupAsSingleResourceConfigIn(config, s.provider.Schema)
|
||||||
|
|
||||||
warns, errs := s.provider.Validate(config)
|
warns, errs := s.provider.Validate(config)
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, convert.WarnsAndErrsToProto(warns, errs))
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, convert.WarnsAndErrsToProto(warns, errs))
|
||||||
|
|
||||||
preparedConfigMP, err := msgpack.Marshal(configVal, block.ImpliedType())
|
preparedConfigMP, err := msgpack.Marshal(configVal, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -188,15 +203,16 @@ func (s *GRPCProviderServer) PrepareProviderConfig(_ context.Context, req *proto
|
||||||
func (s *GRPCProviderServer) ValidateResourceTypeConfig(_ context.Context, req *proto.ValidateResourceTypeConfig_Request) (*proto.ValidateResourceTypeConfig_Response, error) {
|
func (s *GRPCProviderServer) ValidateResourceTypeConfig(_ context.Context, req *proto.ValidateResourceTypeConfig_Request) (*proto.ValidateResourceTypeConfig_Response, error) {
|
||||||
resp := &proto.ValidateResourceTypeConfig_Response{}
|
resp := &proto.ValidateResourceTypeConfig_Response{}
|
||||||
|
|
||||||
block := s.getResourceSchemaBlock(req.TypeName)
|
blockForCore := s.getResourceSchemaBlockForCore(req.TypeName)
|
||||||
|
blockForShimming := s.getResourceSchemaBlockForShimming(req.TypeName)
|
||||||
|
|
||||||
configVal, err := msgpack.Unmarshal(req.Config.Msgpack, block.ImpliedType())
|
configVal, err := msgpack.Unmarshal(req.Config.Msgpack, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
config := terraform.NewResourceConfigShimmed(configVal, block)
|
config := terraform.NewResourceConfigShimmed(configVal, blockForShimming)
|
||||||
schema.FixupAsSingleResourceConfigIn(config, s.provider.ResourcesMap[req.TypeName].Schema)
|
schema.FixupAsSingleResourceConfigIn(config, s.provider.ResourcesMap[req.TypeName].Schema)
|
||||||
|
|
||||||
warns, errs := s.provider.ValidateResource(req.TypeName, config)
|
warns, errs := s.provider.ValidateResource(req.TypeName, config)
|
||||||
|
@ -208,15 +224,16 @@ func (s *GRPCProviderServer) ValidateResourceTypeConfig(_ context.Context, req *
|
||||||
func (s *GRPCProviderServer) ValidateDataSourceConfig(_ context.Context, req *proto.ValidateDataSourceConfig_Request) (*proto.ValidateDataSourceConfig_Response, error) {
|
func (s *GRPCProviderServer) ValidateDataSourceConfig(_ context.Context, req *proto.ValidateDataSourceConfig_Request) (*proto.ValidateDataSourceConfig_Response, error) {
|
||||||
resp := &proto.ValidateDataSourceConfig_Response{}
|
resp := &proto.ValidateDataSourceConfig_Response{}
|
||||||
|
|
||||||
block := s.getDatasourceSchemaBlock(req.TypeName)
|
blockForCore := s.getDatasourceSchemaBlockForCore(req.TypeName)
|
||||||
|
blockForShimming := s.getDatasourceSchemaBlockForShimming(req.TypeName)
|
||||||
|
|
||||||
configVal, err := msgpack.Unmarshal(req.Config.Msgpack, block.ImpliedType())
|
configVal, err := msgpack.Unmarshal(req.Config.Msgpack, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
config := terraform.NewResourceConfigShimmed(configVal, block)
|
config := terraform.NewResourceConfigShimmed(configVal, blockForShimming)
|
||||||
schema.FixupAsSingleResourceConfigIn(config, s.provider.DataSourcesMap[req.TypeName].Schema)
|
schema.FixupAsSingleResourceConfigIn(config, s.provider.DataSourcesMap[req.TypeName].Schema)
|
||||||
|
|
||||||
warns, errs := s.provider.ValidateDataSource(req.TypeName, config)
|
warns, errs := s.provider.ValidateDataSource(req.TypeName, config)
|
||||||
|
@ -229,7 +246,8 @@ func (s *GRPCProviderServer) UpgradeResourceState(_ context.Context, req *proto.
|
||||||
resp := &proto.UpgradeResourceState_Response{}
|
resp := &proto.UpgradeResourceState_Response{}
|
||||||
|
|
||||||
res := s.provider.ResourcesMap[req.TypeName]
|
res := s.provider.ResourcesMap[req.TypeName]
|
||||||
block := res.CoreConfigSchema()
|
blockForCore := s.getResourceSchemaBlockForCore(req.TypeName)
|
||||||
|
blockForShimming := s.getResourceSchemaBlockForShimming(req.TypeName)
|
||||||
|
|
||||||
version := int(req.Version)
|
version := int(req.Version)
|
||||||
|
|
||||||
|
@ -272,14 +290,14 @@ func (s *GRPCProviderServer) UpgradeResourceState(_ context.Context, req *proto.
|
||||||
|
|
||||||
// now we need to turn the state into the default json representation, so
|
// now we need to turn the state into the default json representation, so
|
||||||
// that it can be re-decoded using the actual schema.
|
// that it can be re-decoded using the actual schema.
|
||||||
val, err := schema.JSONMapToStateValue(jsonMap, block)
|
val, err := schema.JSONMapToStateValue(jsonMap, blockForShimming)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode the final state to the expected msgpack format
|
// encode the final state to the expected msgpack format
|
||||||
newStateMP, err := msgpack.Marshal(val, block.ImpliedType())
|
newStateMP, err := msgpack.Marshal(val, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -302,7 +320,7 @@ func (s *GRPCProviderServer) upgradeFlatmapState(version int, m map[string]strin
|
||||||
// first determine if we need to call the legacy MigrateState func
|
// first determine if we need to call the legacy MigrateState func
|
||||||
requiresMigrate := version < res.SchemaVersion
|
requiresMigrate := version < res.SchemaVersion
|
||||||
|
|
||||||
schemaType := res.CoreConfigSchema().ImpliedType()
|
schemaType := res.CoreConfigSchemaForShimming().ImpliedType()
|
||||||
|
|
||||||
// if there are any StateUpgraders, then we need to only compare
|
// if there are any StateUpgraders, then we need to only compare
|
||||||
// against the first version there
|
// against the first version there
|
||||||
|
@ -395,9 +413,10 @@ func (s *GRPCProviderServer) Stop(_ context.Context, _ *proto.Stop_Request) (*pr
|
||||||
func (s *GRPCProviderServer) Configure(_ context.Context, req *proto.Configure_Request) (*proto.Configure_Response, error) {
|
func (s *GRPCProviderServer) Configure(_ context.Context, req *proto.Configure_Request) (*proto.Configure_Response, error) {
|
||||||
resp := &proto.Configure_Response{}
|
resp := &proto.Configure_Response{}
|
||||||
|
|
||||||
block := s.getProviderSchemaBlock()
|
blockForCore := s.getProviderSchemaBlockForCore()
|
||||||
|
blockForShimming := s.getProviderSchemaBlockForShimming()
|
||||||
|
|
||||||
configVal, err := msgpack.Unmarshal(req.Config.Msgpack, block.ImpliedType())
|
configVal, err := msgpack.Unmarshal(req.Config.Msgpack, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -405,7 +424,7 @@ func (s *GRPCProviderServer) Configure(_ context.Context, req *proto.Configure_R
|
||||||
|
|
||||||
s.provider.TerraformVersion = req.TerraformVersion
|
s.provider.TerraformVersion = req.TerraformVersion
|
||||||
|
|
||||||
config := terraform.NewResourceConfigShimmed(configVal, block)
|
config := terraform.NewResourceConfigShimmed(configVal, blockForShimming)
|
||||||
schema.FixupAsSingleResourceConfigIn(config, s.provider.Schema)
|
schema.FixupAsSingleResourceConfigIn(config, s.provider.Schema)
|
||||||
err = s.provider.Configure(config)
|
err = s.provider.Configure(config)
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
|
@ -417,9 +436,10 @@ func (s *GRPCProviderServer) ReadResource(_ context.Context, req *proto.ReadReso
|
||||||
resp := &proto.ReadResource_Response{}
|
resp := &proto.ReadResource_Response{}
|
||||||
|
|
||||||
res := s.provider.ResourcesMap[req.TypeName]
|
res := s.provider.ResourcesMap[req.TypeName]
|
||||||
block := res.CoreConfigSchema()
|
blockForCore := s.getResourceSchemaBlockForCore(req.TypeName)
|
||||||
|
blockForShimming := s.getResourceSchemaBlockForShimming(req.TypeName)
|
||||||
|
|
||||||
stateVal, err := msgpack.Unmarshal(req.CurrentState.Msgpack, block.ImpliedType())
|
stateVal, err := msgpack.Unmarshal(req.CurrentState.Msgpack, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -442,7 +462,7 @@ func (s *GRPCProviderServer) ReadResource(_ context.Context, req *proto.ReadReso
|
||||||
// The old provider API used an empty id to signal that the remote
|
// The old provider API used an empty id to signal that the remote
|
||||||
// object appears to have been deleted, but our new protocol expects
|
// object appears to have been deleted, but our new protocol expects
|
||||||
// to see a null value (in the cty sense) in that case.
|
// to see a null value (in the cty sense) in that case.
|
||||||
newStateMP, err := msgpack.Marshal(cty.NullVal(block.ImpliedType()), block.ImpliedType())
|
newStateMP, err := msgpack.Marshal(cty.NullVal(blockForCore.ImpliedType()), blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
}
|
}
|
||||||
|
@ -456,7 +476,7 @@ func (s *GRPCProviderServer) ReadResource(_ context.Context, req *proto.ReadReso
|
||||||
newInstanceState.Attributes["id"] = newInstanceState.ID
|
newInstanceState.Attributes["id"] = newInstanceState.ID
|
||||||
|
|
||||||
schema.FixupAsSingleInstanceStateOut(newInstanceState, s.provider.ResourcesMap[req.TypeName])
|
schema.FixupAsSingleInstanceStateOut(newInstanceState, s.provider.ResourcesMap[req.TypeName])
|
||||||
newStateVal, err := hcl2shim.HCL2ValueFromFlatmap(newInstanceState.Attributes, block.ImpliedType())
|
newStateVal, err := hcl2shim.HCL2ValueFromFlatmap(newInstanceState.Attributes, blockForShimming.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -465,7 +485,7 @@ func (s *GRPCProviderServer) ReadResource(_ context.Context, req *proto.ReadReso
|
||||||
newStateVal = normalizeNullValues(newStateVal, stateVal, true)
|
newStateVal = normalizeNullValues(newStateVal, stateVal, true)
|
||||||
newStateVal = copyTimeoutValues(newStateVal, stateVal)
|
newStateVal = copyTimeoutValues(newStateVal, stateVal)
|
||||||
|
|
||||||
newStateMP, err := msgpack.Marshal(newStateVal, block.ImpliedType())
|
newStateMP, err := msgpack.Marshal(newStateVal, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -490,9 +510,10 @@ func (s *GRPCProviderServer) PlanResourceChange(_ context.Context, req *proto.Pl
|
||||||
resp.LegacyTypeSystem = true
|
resp.LegacyTypeSystem = true
|
||||||
|
|
||||||
res := s.provider.ResourcesMap[req.TypeName]
|
res := s.provider.ResourcesMap[req.TypeName]
|
||||||
block := res.CoreConfigSchema()
|
blockForCore := s.getResourceSchemaBlockForCore(req.TypeName)
|
||||||
|
blockForShimming := s.getResourceSchemaBlockForShimming(req.TypeName)
|
||||||
|
|
||||||
priorStateVal, err := msgpack.Unmarshal(req.PriorState.Msgpack, block.ImpliedType())
|
priorStateVal, err := msgpack.Unmarshal(req.PriorState.Msgpack, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -500,7 +521,7 @@ func (s *GRPCProviderServer) PlanResourceChange(_ context.Context, req *proto.Pl
|
||||||
|
|
||||||
create := priorStateVal.IsNull()
|
create := priorStateVal.IsNull()
|
||||||
|
|
||||||
proposedNewStateVal, err := msgpack.Unmarshal(req.ProposedNewState.Msgpack, block.ImpliedType())
|
proposedNewStateVal, err := msgpack.Unmarshal(req.ProposedNewState.Msgpack, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -533,7 +554,7 @@ func (s *GRPCProviderServer) PlanResourceChange(_ context.Context, req *proto.Pl
|
||||||
priorState.Meta = priorPrivate
|
priorState.Meta = priorPrivate
|
||||||
|
|
||||||
// turn the proposed state into a legacy configuration
|
// turn the proposed state into a legacy configuration
|
||||||
cfg := terraform.NewResourceConfigShimmed(proposedNewStateVal, block)
|
cfg := terraform.NewResourceConfigShimmed(proposedNewStateVal, blockForShimming)
|
||||||
schema.FixupAsSingleResourceConfigIn(cfg, s.provider.ResourcesMap[req.TypeName].Schema)
|
schema.FixupAsSingleResourceConfigIn(cfg, s.provider.ResourcesMap[req.TypeName].Schema)
|
||||||
|
|
||||||
diff, err := s.provider.SimpleDiff(info, priorState, cfg)
|
diff, err := s.provider.SimpleDiff(info, priorState, cfg)
|
||||||
|
@ -590,13 +611,13 @@ func (s *GRPCProviderServer) PlanResourceChange(_ context.Context, req *proto.Pl
|
||||||
// also fixes up the requiresNew keys to match.
|
// also fixes up the requiresNew keys to match.
|
||||||
schema.FixupAsSingleInstanceDiffOut(diff, s.provider.ResourcesMap[req.TypeName])
|
schema.FixupAsSingleInstanceDiffOut(diff, s.provider.ResourcesMap[req.TypeName])
|
||||||
|
|
||||||
plannedStateVal, err := hcl2shim.HCL2ValueFromFlatmap(plannedAttrs, block.ImpliedType())
|
plannedStateVal, err := hcl2shim.HCL2ValueFromFlatmap(plannedAttrs, blockForShimming.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
plannedStateVal, err = block.CoerceValue(plannedStateVal)
|
plannedStateVal, err = blockForShimming.CoerceValue(plannedStateVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -628,10 +649,10 @@ func (s *GRPCProviderServer) PlanResourceChange(_ context.Context, req *proto.Pl
|
||||||
// if this was creating the resource, we need to set any remaining computed
|
// if this was creating the resource, we need to set any remaining computed
|
||||||
// fields
|
// fields
|
||||||
if create {
|
if create {
|
||||||
plannedStateVal = SetUnknowns(plannedStateVal, block)
|
plannedStateVal = SetUnknowns(plannedStateVal, blockForShimming)
|
||||||
}
|
}
|
||||||
|
|
||||||
plannedMP, err := msgpack.Marshal(plannedStateVal, block.ImpliedType())
|
plannedMP, err := msgpack.Marshal(plannedStateVal, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -684,7 +705,7 @@ func (s *GRPCProviderServer) PlanResourceChange(_ context.Context, req *proto.Pl
|
||||||
requiresNew = append(requiresNew, "id")
|
requiresNew = append(requiresNew, "id")
|
||||||
}
|
}
|
||||||
|
|
||||||
requiresReplace, err := hcl2shim.RequiresReplace(requiresNew, block.ImpliedType())
|
requiresReplace, err := hcl2shim.RequiresReplace(requiresNew, blockForShimming.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -705,15 +726,16 @@ func (s *GRPCProviderServer) ApplyResourceChange(_ context.Context, req *proto.A
|
||||||
}
|
}
|
||||||
|
|
||||||
res := s.provider.ResourcesMap[req.TypeName]
|
res := s.provider.ResourcesMap[req.TypeName]
|
||||||
block := res.CoreConfigSchema()
|
blockForCore := s.getResourceSchemaBlockForCore(req.TypeName)
|
||||||
|
blockForShimming := s.getResourceSchemaBlockForShimming(req.TypeName)
|
||||||
|
|
||||||
priorStateVal, err := msgpack.Unmarshal(req.PriorState.Msgpack, block.ImpliedType())
|
priorStateVal, err := msgpack.Unmarshal(req.PriorState.Msgpack, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
plannedStateVal, err := msgpack.Unmarshal(req.PlannedState.Msgpack, block.ImpliedType())
|
plannedStateVal, err := msgpack.Unmarshal(req.PlannedState.Msgpack, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -823,13 +845,13 @@ func (s *GRPCProviderServer) ApplyResourceChange(_ context.Context, req *proto.A
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
}
|
}
|
||||||
schema.FixupAsSingleInstanceStateOut(newInstanceState, s.provider.ResourcesMap[req.TypeName])
|
schema.FixupAsSingleInstanceStateOut(newInstanceState, s.provider.ResourcesMap[req.TypeName])
|
||||||
newStateVal := cty.NullVal(block.ImpliedType())
|
newStateVal := cty.NullVal(blockForShimming.ImpliedType())
|
||||||
|
|
||||||
// Always return a null value for destroy.
|
// Always return a null value for destroy.
|
||||||
// While this is usually indicated by a nil state, check for missing ID or
|
// While this is usually indicated by a nil state, check for missing ID or
|
||||||
// attributes in the case of a provider failure.
|
// attributes in the case of a provider failure.
|
||||||
if destroy || newInstanceState == nil || newInstanceState.Attributes == nil || newInstanceState.ID == "" {
|
if destroy || newInstanceState == nil || newInstanceState.Attributes == nil || newInstanceState.ID == "" {
|
||||||
newStateMP, err := msgpack.Marshal(newStateVal, block.ImpliedType())
|
newStateMP, err := msgpack.Marshal(newStateVal, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -845,7 +867,7 @@ func (s *GRPCProviderServer) ApplyResourceChange(_ context.Context, req *proto.A
|
||||||
|
|
||||||
// We keep the null val if we destroyed the resource, otherwise build the
|
// We keep the null val if we destroyed the resource, otherwise build the
|
||||||
// entire object, even if the new state was nil.
|
// entire object, even if the new state was nil.
|
||||||
newStateVal, err = schema.StateValueFromInstanceState(newInstanceState, block.ImpliedType())
|
newStateVal, err = schema.StateValueFromInstanceState(newInstanceState, blockForShimming.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -855,7 +877,7 @@ func (s *GRPCProviderServer) ApplyResourceChange(_ context.Context, req *proto.A
|
||||||
|
|
||||||
newStateVal = copyTimeoutValues(newStateVal, plannedStateVal)
|
newStateVal = copyTimeoutValues(newStateVal, plannedStateVal)
|
||||||
|
|
||||||
newStateMP, err := msgpack.Marshal(newStateVal, block.ImpliedType())
|
newStateMP, err := msgpack.Marshal(newStateVal, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -906,14 +928,15 @@ func (s *GRPCProviderServer) ImportResourceState(_ context.Context, req *proto.I
|
||||||
resourceType = req.TypeName
|
resourceType = req.TypeName
|
||||||
}
|
}
|
||||||
|
|
||||||
block := s.getResourceSchemaBlock(resourceType)
|
blockForCore := s.getResourceSchemaBlockForCore(resourceType)
|
||||||
newStateVal, err := hcl2shim.HCL2ValueFromFlatmap(is.Attributes, block.ImpliedType())
|
blockForShimming := s.getResourceSchemaBlockForShimming(resourceType)
|
||||||
|
newStateVal, err := hcl2shim.HCL2ValueFromFlatmap(is.Attributes, blockForShimming.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
newStateMP, err := msgpack.Marshal(newStateVal, block.ImpliedType())
|
newStateMP, err := msgpack.Marshal(newStateVal, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -942,10 +965,10 @@ func (s *GRPCProviderServer) ImportResourceState(_ context.Context, req *proto.I
|
||||||
func (s *GRPCProviderServer) ReadDataSource(_ context.Context, req *proto.ReadDataSource_Request) (*proto.ReadDataSource_Response, error) {
|
func (s *GRPCProviderServer) ReadDataSource(_ context.Context, req *proto.ReadDataSource_Request) (*proto.ReadDataSource_Response, error) {
|
||||||
resp := &proto.ReadDataSource_Response{}
|
resp := &proto.ReadDataSource_Response{}
|
||||||
|
|
||||||
res := s.provider.DataSourcesMap[req.TypeName]
|
blockForCore := s.getDatasourceSchemaBlockForCore(req.TypeName)
|
||||||
block := res.CoreConfigSchema()
|
blockForShimming := s.getDatasourceSchemaBlockForShimming(req.TypeName)
|
||||||
|
|
||||||
configVal, err := msgpack.Unmarshal(req.Config.Msgpack, block.ImpliedType())
|
configVal, err := msgpack.Unmarshal(req.Config.Msgpack, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -955,7 +978,7 @@ func (s *GRPCProviderServer) ReadDataSource(_ context.Context, req *proto.ReadDa
|
||||||
Type: req.TypeName,
|
Type: req.TypeName,
|
||||||
}
|
}
|
||||||
|
|
||||||
config := terraform.NewResourceConfigShimmed(configVal, block)
|
config := terraform.NewResourceConfigShimmed(configVal, blockForShimming)
|
||||||
schema.FixupAsSingleResourceConfigIn(config, s.provider.DataSourcesMap[req.TypeName].Schema)
|
schema.FixupAsSingleResourceConfigIn(config, s.provider.DataSourcesMap[req.TypeName].Schema)
|
||||||
|
|
||||||
// we need to still build the diff separately with the Read method to match
|
// we need to still build the diff separately with the Read method to match
|
||||||
|
@ -974,7 +997,7 @@ func (s *GRPCProviderServer) ReadDataSource(_ context.Context, req *proto.ReadDa
|
||||||
}
|
}
|
||||||
schema.FixupAsSingleInstanceStateOut(newInstanceState, s.provider.DataSourcesMap[req.TypeName])
|
schema.FixupAsSingleInstanceStateOut(newInstanceState, s.provider.DataSourcesMap[req.TypeName])
|
||||||
|
|
||||||
newStateVal, err := schema.StateValueFromInstanceState(newInstanceState, block.ImpliedType())
|
newStateVal, err := schema.StateValueFromInstanceState(newInstanceState, blockForShimming.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -982,7 +1005,7 @@ func (s *GRPCProviderServer) ReadDataSource(_ context.Context, req *proto.ReadDa
|
||||||
|
|
||||||
newStateVal = copyTimeoutValues(newStateVal, configVal)
|
newStateVal = copyTimeoutValues(newStateVal, configVal)
|
||||||
|
|
||||||
newStateMP, err := msgpack.Marshal(newStateVal, block.ImpliedType())
|
newStateMP, err := msgpack.Marshal(newStateVal, blockForCore.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
|
|
@ -22,7 +22,18 @@ import (
|
||||||
// This method presumes a schema that passes InternalValidate, and so may
|
// This method presumes a schema that passes InternalValidate, and so may
|
||||||
// panic or produce an invalid result if given an invalid schemaMap.
|
// panic or produce an invalid result if given an invalid schemaMap.
|
||||||
func (m schemaMap) CoreConfigSchema() *configschema.Block {
|
func (m schemaMap) CoreConfigSchema() *configschema.Block {
|
||||||
return m.coreConfigSchema(true)
|
return m.coreConfigSchema(true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CoreConfigSchemaForShimming is a variant of CoreConfigSchema that returns
|
||||||
|
// the schema that should be used when applying our shimming behaviors.
|
||||||
|
//
|
||||||
|
// In particular, it ignores the SkipCoreTypeCheck flag on any legacy schemas,
|
||||||
|
// since the shims live on the SDK side and so they need to see the full
|
||||||
|
// type information that we'd normally hide from Terraform Core when skipping
|
||||||
|
// type checking over there.
|
||||||
|
func (m schemaMap) CoreConfigSchemaForShimming() *configschema.Block {
|
||||||
|
return m.coreConfigSchema(true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CoreConfigSchemaWhenShimmed is a variant of CoreConfigSchema that returns
|
// CoreConfigSchemaWhenShimmed is a variant of CoreConfigSchema that returns
|
||||||
|
@ -36,10 +47,10 @@ func (m schemaMap) CoreConfigSchema() *configschema.Block {
|
||||||
// This should be used with care only in unusual situations where we need to
|
// This should be used with care only in unusual situations where we need to
|
||||||
// work with an already-shimmed value using a new-style schema.
|
// work with an already-shimmed value using a new-style schema.
|
||||||
func (m schemaMap) CoreConfigSchemaWhenShimmed() *configschema.Block {
|
func (m schemaMap) CoreConfigSchemaWhenShimmed() *configschema.Block {
|
||||||
return m.coreConfigSchema(false)
|
return m.coreConfigSchema(false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m schemaMap) coreConfigSchema(enableAsSingle bool) *configschema.Block {
|
func (m schemaMap) coreConfigSchema(asSingle, skipCoreCheck bool) *configschema.Block {
|
||||||
if len(m) == 0 {
|
if len(m) == 0 {
|
||||||
// We return an actual (empty) object here, rather than a nil,
|
// We return an actual (empty) object here, rather than a nil,
|
||||||
// because a nil result would mean that we don't have a schema at
|
// because a nil result would mean that we don't have a schema at
|
||||||
|
@ -54,7 +65,7 @@ func (m schemaMap) coreConfigSchema(enableAsSingle bool) *configschema.Block {
|
||||||
|
|
||||||
for name, schema := range m {
|
for name, schema := range m {
|
||||||
if schema.Elem == nil {
|
if schema.Elem == nil {
|
||||||
ret.Attributes[name] = schema.coreConfigSchemaAttribute(enableAsSingle)
|
ret.Attributes[name] = schema.coreConfigSchemaAttribute(asSingle, skipCoreCheck)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if schema.Type == TypeMap {
|
if schema.Type == TypeMap {
|
||||||
|
@ -68,27 +79,27 @@ func (m schemaMap) coreConfigSchema(enableAsSingle bool) *configschema.Block {
|
||||||
sch.Elem = &Schema{
|
sch.Elem = &Schema{
|
||||||
Type: TypeString,
|
Type: TypeString,
|
||||||
}
|
}
|
||||||
ret.Attributes[name] = sch.coreConfigSchemaAttribute(enableAsSingle)
|
ret.Attributes[name] = sch.coreConfigSchemaAttribute(asSingle, skipCoreCheck)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch schema.ConfigMode {
|
switch schema.ConfigMode {
|
||||||
case SchemaConfigModeAttr:
|
case SchemaConfigModeAttr:
|
||||||
ret.Attributes[name] = schema.coreConfigSchemaAttribute(enableAsSingle)
|
ret.Attributes[name] = schema.coreConfigSchemaAttribute(asSingle, skipCoreCheck)
|
||||||
case SchemaConfigModeBlock:
|
case SchemaConfigModeBlock:
|
||||||
ret.BlockTypes[name] = schema.coreConfigSchemaBlock(enableAsSingle)
|
ret.BlockTypes[name] = schema.coreConfigSchemaBlock(asSingle, skipCoreCheck)
|
||||||
default: // SchemaConfigModeAuto, or any other invalid value
|
default: // SchemaConfigModeAuto, or any other invalid value
|
||||||
if schema.Computed && !schema.Optional {
|
if schema.Computed && !schema.Optional {
|
||||||
// Computed-only schemas are always handled as attributes,
|
// Computed-only schemas are always handled as attributes,
|
||||||
// because they never appear in configuration.
|
// because they never appear in configuration.
|
||||||
ret.Attributes[name] = schema.coreConfigSchemaAttribute(enableAsSingle)
|
ret.Attributes[name] = schema.coreConfigSchemaAttribute(asSingle, skipCoreCheck)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch schema.Elem.(type) {
|
switch schema.Elem.(type) {
|
||||||
case *Schema, ValueType:
|
case *Schema, ValueType:
|
||||||
ret.Attributes[name] = schema.coreConfigSchemaAttribute(enableAsSingle)
|
ret.Attributes[name] = schema.coreConfigSchemaAttribute(asSingle, skipCoreCheck)
|
||||||
case *Resource:
|
case *Resource:
|
||||||
ret.BlockTypes[name] = schema.coreConfigSchemaBlock(enableAsSingle)
|
ret.BlockTypes[name] = schema.coreConfigSchemaBlock(asSingle, skipCoreCheck)
|
||||||
default:
|
default:
|
||||||
// Should never happen for a valid schema
|
// Should never happen for a valid schema
|
||||||
panic(fmt.Errorf("invalid Schema.Elem %#v; need *Schema or *Resource", schema.Elem))
|
panic(fmt.Errorf("invalid Schema.Elem %#v; need *Schema or *Resource", schema.Elem))
|
||||||
|
@ -103,7 +114,7 @@ func (m schemaMap) coreConfigSchema(enableAsSingle bool) *configschema.Block {
|
||||||
// of a schema. This is appropriate only for primitives or collections whose
|
// of a schema. This is appropriate only for primitives or collections whose
|
||||||
// Elem is an instance of Schema. Use coreConfigSchemaBlock for collections
|
// Elem is an instance of Schema. Use coreConfigSchemaBlock for collections
|
||||||
// whose elem is a whole resource.
|
// whose elem is a whole resource.
|
||||||
func (s *Schema) coreConfigSchemaAttribute(enableAsSingle bool) *configschema.Attribute {
|
func (s *Schema) coreConfigSchemaAttribute(asSingle, skipCoreCheck bool) *configschema.Attribute {
|
||||||
// The Schema.DefaultFunc capability adds some extra weirdness here since
|
// The Schema.DefaultFunc capability adds some extra weirdness here since
|
||||||
// it can be combined with "Required: true" to create a sitution where
|
// it can be combined with "Required: true" to create a sitution where
|
||||||
// required-ness is conditional. Terraform Core doesn't share this concept,
|
// required-ness is conditional. Terraform Core doesn't share this concept,
|
||||||
|
@ -134,7 +145,7 @@ func (s *Schema) coreConfigSchemaAttribute(enableAsSingle bool) *configschema.At
|
||||||
}
|
}
|
||||||
|
|
||||||
return &configschema.Attribute{
|
return &configschema.Attribute{
|
||||||
Type: s.coreConfigSchemaType(enableAsSingle),
|
Type: s.coreConfigSchemaType(asSingle, skipCoreCheck),
|
||||||
Optional: opt,
|
Optional: opt,
|
||||||
Required: reqd,
|
Required: reqd,
|
||||||
Computed: s.Computed,
|
Computed: s.Computed,
|
||||||
|
@ -146,9 +157,9 @@ func (s *Schema) coreConfigSchemaAttribute(enableAsSingle bool) *configschema.At
|
||||||
// coreConfigSchemaBlock prepares a configschema.NestedBlock representation of
|
// coreConfigSchemaBlock prepares a configschema.NestedBlock representation of
|
||||||
// a schema. This is appropriate only for collections whose Elem is an instance
|
// a schema. This is appropriate only for collections whose Elem is an instance
|
||||||
// of Resource, and will panic otherwise.
|
// of Resource, and will panic otherwise.
|
||||||
func (s *Schema) coreConfigSchemaBlock(enableAsSingle bool) *configschema.NestedBlock {
|
func (s *Schema) coreConfigSchemaBlock(asSingle, skipCoreCheck bool) *configschema.NestedBlock {
|
||||||
ret := &configschema.NestedBlock{}
|
ret := &configschema.NestedBlock{}
|
||||||
if nested := schemaMap(s.Elem.(*Resource).Schema).coreConfigSchema(enableAsSingle); nested != nil {
|
if nested := schemaMap(s.Elem.(*Resource).Schema).coreConfigSchema(asSingle, skipCoreCheck); nested != nil {
|
||||||
ret.Block = *nested
|
ret.Block = *nested
|
||||||
}
|
}
|
||||||
switch s.Type {
|
switch s.Type {
|
||||||
|
@ -166,7 +177,7 @@ func (s *Schema) coreConfigSchemaBlock(enableAsSingle bool) *configschema.Nested
|
||||||
ret.MinItems = s.MinItems
|
ret.MinItems = s.MinItems
|
||||||
ret.MaxItems = s.MaxItems
|
ret.MaxItems = s.MaxItems
|
||||||
|
|
||||||
if s.AsSingle && enableAsSingle {
|
if s.AsSingle && asSingle {
|
||||||
// In AsSingle mode, we artifically force a TypeList or TypeSet
|
// In AsSingle mode, we artifically force a TypeList or TypeSet
|
||||||
// attribute in the SDK to be treated as a single block by Terraform Core.
|
// attribute in the SDK to be treated as a single block by Terraform Core.
|
||||||
// This must then be fixed up in the shim code (in helper/plugin) so
|
// This must then be fixed up in the shim code (in helper/plugin) so
|
||||||
|
@ -199,7 +210,15 @@ func (s *Schema) coreConfigSchemaBlock(enableAsSingle bool) *configschema.Nested
|
||||||
|
|
||||||
// coreConfigSchemaType determines the core config schema type that corresponds
|
// coreConfigSchemaType determines the core config schema type that corresponds
|
||||||
// to a particular schema's type.
|
// to a particular schema's type.
|
||||||
func (s *Schema) coreConfigSchemaType(enableAsSingle bool) cty.Type {
|
func (s *Schema) coreConfigSchemaType(asSingle, skipCoreCheck bool) cty.Type {
|
||||||
|
if skipCoreCheck && s.SkipCoreTypeCheck {
|
||||||
|
// If we're preparing a schema for Terraform Core and the schema is
|
||||||
|
// asking us to skip the Core type-check then we'll tell core that this
|
||||||
|
// attribute is dynamically-typed, so it'll just pass through anything
|
||||||
|
// and let us validate it on the plugin side.
|
||||||
|
return cty.DynamicPseudoType
|
||||||
|
}
|
||||||
|
|
||||||
switch s.Type {
|
switch s.Type {
|
||||||
case TypeString:
|
case TypeString:
|
||||||
return cty.String
|
return cty.String
|
||||||
|
@ -214,17 +233,17 @@ func (s *Schema) coreConfigSchemaType(enableAsSingle bool) cty.Type {
|
||||||
var elemType cty.Type
|
var elemType cty.Type
|
||||||
switch set := s.Elem.(type) {
|
switch set := s.Elem.(type) {
|
||||||
case *Schema:
|
case *Schema:
|
||||||
elemType = set.coreConfigSchemaType(enableAsSingle)
|
elemType = set.coreConfigSchemaType(asSingle, skipCoreCheck)
|
||||||
case ValueType:
|
case ValueType:
|
||||||
// This represents a mistake in the provider code, but it's a
|
// This represents a mistake in the provider code, but it's a
|
||||||
// common one so we'll just shim it.
|
// common one so we'll just shim it.
|
||||||
elemType = (&Schema{Type: set}).coreConfigSchemaType(enableAsSingle)
|
elemType = (&Schema{Type: set}).coreConfigSchemaType(asSingle, skipCoreCheck)
|
||||||
case *Resource:
|
case *Resource:
|
||||||
// By default we construct a NestedBlock in this case, but this
|
// By default we construct a NestedBlock in this case, but this
|
||||||
// behavior is selected either for computed-only schemas or
|
// behavior is selected either for computed-only schemas or
|
||||||
// when ConfigMode is explicitly SchemaConfigModeBlock.
|
// when ConfigMode is explicitly SchemaConfigModeBlock.
|
||||||
// See schemaMap.CoreConfigSchema for the exact rules.
|
// See schemaMap.CoreConfigSchema for the exact rules.
|
||||||
elemType = schemaMap(set.Schema).coreConfigSchema(enableAsSingle).ImpliedType()
|
elemType = schemaMap(set.Schema).coreConfigSchema(asSingle, skipCoreCheck).ImpliedType()
|
||||||
default:
|
default:
|
||||||
if set != nil {
|
if set != nil {
|
||||||
// Should never happen for a valid schema
|
// Should never happen for a valid schema
|
||||||
|
@ -234,7 +253,7 @@ func (s *Schema) coreConfigSchemaType(enableAsSingle bool) cty.Type {
|
||||||
// to be compatible with them.
|
// to be compatible with them.
|
||||||
elemType = cty.String
|
elemType = cty.String
|
||||||
}
|
}
|
||||||
if s.AsSingle && enableAsSingle {
|
if s.AsSingle && asSingle {
|
||||||
// In AsSingle mode, we artifically force a TypeList or TypeSet
|
// In AsSingle mode, we artifically force a TypeList or TypeSet
|
||||||
// attribute in the SDK to be treated as a single value by Terraform Core.
|
// attribute in the SDK to be treated as a single value by Terraform Core.
|
||||||
// This must then be fixed up in the shim code (in helper/plugin) so
|
// This must then be fixed up in the shim code (in helper/plugin) so
|
||||||
|
@ -262,7 +281,16 @@ func (s *Schema) coreConfigSchemaType(enableAsSingle bool) cty.Type {
|
||||||
// the resource's schema. CoreConfigSchema adds the implicitly required "id"
|
// the resource's schema. CoreConfigSchema adds the implicitly required "id"
|
||||||
// attribute for top level resources if it doesn't exist.
|
// attribute for top level resources if it doesn't exist.
|
||||||
func (r *Resource) CoreConfigSchema() *configschema.Block {
|
func (r *Resource) CoreConfigSchema() *configschema.Block {
|
||||||
return r.coreConfigSchema(true)
|
return r.coreConfigSchema(true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CoreConfigSchemaForShimming is a variant of CoreConfigSchema that returns
|
||||||
|
// the schema that should be used to apply shims on the SDK side.
|
||||||
|
//
|
||||||
|
// In particular, it ignores the SkipCoreTypeCheck flag on any legacy schemas
|
||||||
|
// and uses the real type information instead.
|
||||||
|
func (r *Resource) CoreConfigSchemaForShimming() *configschema.Block {
|
||||||
|
return r.coreConfigSchema(true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CoreConfigSchemaWhenShimmed is a variant of CoreConfigSchema that returns
|
// CoreConfigSchemaWhenShimmed is a variant of CoreConfigSchema that returns
|
||||||
|
@ -276,11 +304,11 @@ func (r *Resource) CoreConfigSchema() *configschema.Block {
|
||||||
// This should be used with care only in unusual situations where we need to
|
// This should be used with care only in unusual situations where we need to
|
||||||
// work with an already-shimmed value using a new-style schema.
|
// work with an already-shimmed value using a new-style schema.
|
||||||
func (r *Resource) CoreConfigSchemaWhenShimmed() *configschema.Block {
|
func (r *Resource) CoreConfigSchemaWhenShimmed() *configschema.Block {
|
||||||
return r.coreConfigSchema(false)
|
return r.coreConfigSchema(false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resource) coreConfigSchema(enableAsSingle bool) *configschema.Block {
|
func (r *Resource) coreConfigSchema(asSingle, skipCoreCheck bool) *configschema.Block {
|
||||||
block := schemaMap(r.Schema).coreConfigSchema(enableAsSingle)
|
block := schemaMap(r.Schema).coreConfigSchema(asSingle, skipCoreCheck)
|
||||||
|
|
||||||
if block.Attributes == nil {
|
if block.Attributes == nil {
|
||||||
block.Attributes = map[string]*configschema.Attribute{}
|
block.Attributes = map[string]*configschema.Attribute{}
|
||||||
|
|
|
@ -445,6 +445,28 @@ func TestSchemaMapCoreConfigSchema(t *testing.T) {
|
||||||
BlockTypes: map[string]*configschema.NestedBlock{},
|
BlockTypes: map[string]*configschema.NestedBlock{},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
"skip core type check": {
|
||||||
|
map[string]*Schema{
|
||||||
|
"list": {
|
||||||
|
Type: TypeList,
|
||||||
|
ConfigMode: SchemaConfigModeAttr,
|
||||||
|
SkipCoreTypeCheck: true,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &Resource{
|
||||||
|
Schema: map[string]*Schema{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
testResource(&configschema.Block{
|
||||||
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"list": {
|
||||||
|
Type: cty.DynamicPseudoType,
|
||||||
|
Optional: true, // Just so we can progress to provider-driven validation and return the error there
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BlockTypes: map[string]*configschema.NestedBlock{},
|
||||||
|
}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
|
|
Loading…
Reference in New Issue