diff --git a/builtin/providers/test/provider.go b/builtin/providers/test/provider.go index 4afae201a..400bc30f9 100644 --- a/builtin/providers/test/provider.go +++ b/builtin/providers/test/provider.go @@ -16,6 +16,13 @@ func Provider() terraform.ResourceProvider { Optional: true, }, }, + ProviderMetaSchema: map[string]*schema.Schema{ + // Optionally allow specifying information at a module-level + "foo": { + Type: schema.TypeString, + Optional: true, + }, + }, ResourcesMap: map[string]*schema.Resource{ "test_resource": testResource(), "test_resource_gh12183": testResourceGH12183(), @@ -36,6 +43,7 @@ func Provider() terraform.ResourceProvider { "test_resource_computed_set": testResourceComputedSet(), "test_resource_config_mode": testResourceConfigMode(), "test_resource_nested_id": testResourceNestedId(), + "test_resource_provider_meta": testResourceProviderMeta(), "test_undeleteable": testResourceUndeleteable(), "test_resource_required_min": testResourceRequiredMin(), }, diff --git a/builtin/providers/test/resource_provider_meta.go b/builtin/providers/test/resource_provider_meta.go new file mode 100644 index 000000000..c05adb170 --- /dev/null +++ b/builtin/providers/test/resource_provider_meta.go @@ -0,0 +1,95 @@ +package test + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" +) + +func testResourceProviderMeta() *schema.Resource { + return &schema.Resource{ + Create: testResourceProviderMetaCreate, + Read: testResourceProviderMetaRead, + Update: testResourceProviderMetaUpdate, + Delete: testResourceProviderMetaDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "optional": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + +type providerMeta struct { + Foo string `cty:"foo"` +} + +func testResourceProviderMetaCreate(d *schema.ResourceData, meta interface{}) error { + d.SetId("testId") + var m providerMeta + + err := d.GetProviderMeta(&m) + if err != nil { + return err + } + + if m.Foo != "bar" { + return fmt.Errorf("expected provider_meta.foo to be %q, was %q", + "bar", m.Foo) + } + + return testResourceProviderMetaRead(d, meta) +} + +func testResourceProviderMetaRead(d *schema.ResourceData, meta interface{}) error { + var m providerMeta + + err := d.GetProviderMeta(&m) + if err != nil { + return err + } + + if m.Foo != "bar" { + return fmt.Errorf("expected provider_meta.foo to be %q, was %q", + "bar", m.Foo) + } + + return nil +} + +func testResourceProviderMetaUpdate(d *schema.ResourceData, meta interface{}) error { + var m providerMeta + + err := d.GetProviderMeta(&m) + if err != nil { + return err + } + + if m.Foo != "bar" { + return fmt.Errorf("expected provider_meta.foo to be %q, was %q", + "bar", m.Foo) + } + return testResourceProviderMetaRead(d, meta) +} + +func testResourceProviderMetaDelete(d *schema.ResourceData, meta interface{}) error { + d.SetId("") + var m providerMeta + + err := d.GetProviderMeta(&m) + if err != nil { + return err + } + + if m.Foo != "bar" { + return fmt.Errorf("expected provider_meta.foo to be %q, was %q", + "bar", m.Foo) + } + return nil +} diff --git a/builtin/providers/test/resource_provider_meta_test.go b/builtin/providers/test/resource_provider_meta_test.go new file mode 100644 index 000000000..3b92d0a40 --- /dev/null +++ b/builtin/providers/test/resource_provider_meta_test.go @@ -0,0 +1,29 @@ +package test + +import ( + "strings" + "testing" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestResourceProviderMeta_basic(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + Providers: testAccProviders, + CheckDestroy: testAccCheckResourceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: strings.TrimSpace(` +terraform { + provider_meta "test" { + foo = "bar" + } +} + +resource "test_resource_provider_meta" "foo" { +} + `), + }, + }, + }) +} diff --git a/command/jsonprovider/attribute.go b/command/jsonprovider/attribute.go index dbdd4590e..fd5adb268 100644 --- a/command/jsonprovider/attribute.go +++ b/command/jsonprovider/attribute.go @@ -7,12 +7,23 @@ import ( ) type attribute struct { - AttributeType json.RawMessage `json:"type,omitempty"` - Description string `json:"description,omitempty"` - Required bool `json:"required,omitempty"` - Optional bool `json:"optional,omitempty"` - Computed bool `json:"computed,omitempty"` - Sensitive bool `json:"sensitive,omitempty"` + AttributeType json.RawMessage `json:"type,omitempty"` + Description string `json:"description,omitempty"` + DescriptionKind string `json:"description_kind,omitempty"` + Deprecated bool `json:"deprecated,omitempty"` + Required bool `json:"required,omitempty"` + Optional bool `json:"optional,omitempty"` + Computed bool `json:"computed,omitempty"` + Sensitive bool `json:"sensitive,omitempty"` +} + +func marshalStringKind(sk configschema.StringKind) string { + switch sk { + default: + return "plain" + case configschema.StringMarkdown: + return "markdown" + } } func marshalAttribute(attr *configschema.Attribute) *attribute { @@ -21,11 +32,13 @@ func marshalAttribute(attr *configschema.Attribute) *attribute { attrTy, _ := attr.Type.MarshalJSON() return &attribute{ - AttributeType: attrTy, - Description: attr.Description, - Required: attr.Required, - Optional: attr.Optional, - Computed: attr.Computed, - Sensitive: attr.Sensitive, + AttributeType: attrTy, + Description: attr.Description, + DescriptionKind: marshalStringKind(attr.DescriptionKind), + Required: attr.Required, + Optional: attr.Optional, + Computed: attr.Computed, + Sensitive: attr.Sensitive, + Deprecated: attr.Deprecated, } } diff --git a/command/jsonprovider/attribute_test.go b/command/jsonprovider/attribute_test.go index 8e2d92f07..6cd2cab9b 100644 --- a/command/jsonprovider/attribute_test.go +++ b/command/jsonprovider/attribute_test.go @@ -18,17 +18,19 @@ func TestMarshalAttribute(t *testing.T) { { &configschema.Attribute{Type: cty.String, Optional: true, Computed: true}, &attribute{ - AttributeType: json.RawMessage(`"string"`), - Optional: true, - Computed: true, + AttributeType: json.RawMessage(`"string"`), + Optional: true, + Computed: true, + DescriptionKind: "plain", }, }, { // collection types look a little odd. &configschema.Attribute{Type: cty.Map(cty.String), Optional: true, Computed: true}, &attribute{ - AttributeType: json.RawMessage(`["map","string"]`), - Optional: true, - Computed: true, + AttributeType: json.RawMessage(`["map","string"]`), + Optional: true, + Computed: true, + DescriptionKind: "plain", }, }, } diff --git a/command/jsonprovider/block.go b/command/jsonprovider/block.go index 240724ca8..3f90987f2 100644 --- a/command/jsonprovider/block.go +++ b/command/jsonprovider/block.go @@ -5,8 +5,11 @@ import ( ) type block struct { - Attributes map[string]*attribute `json:"attributes,omitempty"` - BlockTypes map[string]*blockType `json:"block_types,omitempty"` + Attributes map[string]*attribute `json:"attributes,omitempty"` + BlockTypes map[string]*blockType `json:"block_types,omitempty"` + Description string `json:"description,omitempty"` + DescriptionKind string `json:"description_kind,omitempty"` + Deprecated bool `json:"deprecated,omitempty"` } type blockType struct { @@ -48,7 +51,12 @@ func marshalBlock(configBlock *configschema.Block) *block { return &block{} } - var ret block + ret := block{ + Deprecated: configBlock.Deprecated, + Description: configBlock.Description, + DescriptionKind: marshalStringKind(configBlock.DescriptionKind), + } + if len(configBlock.Attributes) > 0 { attrs := make(map[string]*attribute, len(configBlock.Attributes)) for k, attr := range configBlock.Attributes { diff --git a/command/jsonprovider/block_test.go b/command/jsonprovider/block_test.go index 59841499a..6f61b1c69 100644 --- a/command/jsonprovider/block_test.go +++ b/command/jsonprovider/block_test.go @@ -39,20 +39,22 @@ func TestMarshalBlock(t *testing.T) { }, Want: &block{ Attributes: map[string]*attribute{ - "ami": {AttributeType: json.RawMessage(`"string"`), Optional: true}, - "id": {AttributeType: json.RawMessage(`"string"`), Optional: true, Computed: true}, + "ami": {AttributeType: json.RawMessage(`"string"`), Optional: true, DescriptionKind: "plain"}, + "id": {AttributeType: json.RawMessage(`"string"`), Optional: true, Computed: true, DescriptionKind: "plain"}, }, BlockTypes: map[string]*blockType{ "network_interface": { NestingMode: "list", Block: &block{ Attributes: map[string]*attribute{ - "description": {AttributeType: json.RawMessage(`"string"`), Optional: true}, - "device_index": {AttributeType: json.RawMessage(`"string"`), Optional: true}, + "description": {AttributeType: json.RawMessage(`"string"`), Optional: true, DescriptionKind: "plain"}, + "device_index": {AttributeType: json.RawMessage(`"string"`), Optional: true, DescriptionKind: "plain"}, }, + DescriptionKind: "plain", }, }, }, + DescriptionKind: "plain", }, }, } diff --git a/command/jsonprovider/provider_test.go b/command/jsonprovider/provider_test.go index 120e4fa73..ccadb1a3d 100644 --- a/command/jsonprovider/provider_test.go +++ b/command/jsonprovider/provider_test.go @@ -28,10 +28,12 @@ func TestMarshalProvider(t *testing.T) { Block: &block{ Attributes: map[string]*attribute{ "region": { - AttributeType: json.RawMessage(`"string"`), - Required: true, + AttributeType: json.RawMessage(`"string"`), + Required: true, + DescriptionKind: "plain", }, }, + DescriptionKind: "plain", }, }, ResourceSchemas: map[string]*schema{ @@ -40,13 +42,15 @@ func TestMarshalProvider(t *testing.T) { Block: &block{ Attributes: map[string]*attribute{ "id": { - AttributeType: json.RawMessage(`"string"`), - Optional: true, - Computed: true, + AttributeType: json.RawMessage(`"string"`), + Optional: true, + Computed: true, + DescriptionKind: "plain", }, "ami": { - AttributeType: json.RawMessage(`"string"`), - Optional: true, + AttributeType: json.RawMessage(`"string"`), + Optional: true, + DescriptionKind: "plain", }, }, BlockTypes: map[string]*blockType{ @@ -54,18 +58,22 @@ func TestMarshalProvider(t *testing.T) { Block: &block{ Attributes: map[string]*attribute{ "device_index": { - AttributeType: json.RawMessage(`"string"`), - Optional: true, + AttributeType: json.RawMessage(`"string"`), + Optional: true, + DescriptionKind: "plain", }, "description": { - AttributeType: json.RawMessage(`"string"`), - Optional: true, + AttributeType: json.RawMessage(`"string"`), + Optional: true, + DescriptionKind: "plain", }, }, + DescriptionKind: "plain", }, NestingMode: "list", }, }, + DescriptionKind: "plain", }, }, }, @@ -75,13 +83,15 @@ func TestMarshalProvider(t *testing.T) { Block: &block{ Attributes: map[string]*attribute{ "id": { - AttributeType: json.RawMessage(`"string"`), - Optional: true, - Computed: true, + AttributeType: json.RawMessage(`"string"`), + Optional: true, + Computed: true, + DescriptionKind: "plain", }, "ami": { - AttributeType: json.RawMessage(`"string"`), - Optional: true, + AttributeType: json.RawMessage(`"string"`), + Optional: true, + DescriptionKind: "plain", }, }, BlockTypes: map[string]*blockType{ @@ -89,18 +99,22 @@ func TestMarshalProvider(t *testing.T) { Block: &block{ Attributes: map[string]*attribute{ "device_index": { - AttributeType: json.RawMessage(`"string"`), - Optional: true, + AttributeType: json.RawMessage(`"string"`), + Optional: true, + DescriptionKind: "plain", }, "description": { - AttributeType: json.RawMessage(`"string"`), - Optional: true, + AttributeType: json.RawMessage(`"string"`), + Optional: true, + DescriptionKind: "plain", }, }, + DescriptionKind: "plain", }, NestingMode: "list", }, }, + DescriptionKind: "plain", }, }, }, diff --git a/command/testdata/providers-schema/basic/output.json b/command/testdata/providers-schema/basic/output.json index 53424e022..bc32d8493 100644 --- a/command/testdata/providers-schema/basic/output.json +++ b/command/testdata/providers-schema/basic/output.json @@ -9,17 +9,20 @@ "attributes": { "ami": { "type": "string", - "optional": true + "optional": true, + "description_kind": "plain" }, "id": { "type": "string", "optional": true, - "computed": true + "computed": true, + "description_kind": "plain" } - } + }, + "description_kind": "plain" } } } } } -} \ No newline at end of file +} diff --git a/configs/configschema/schema.go b/configs/configschema/schema.go index f4702d369..4d3e7cabc 100644 --- a/configs/configschema/schema.go +++ b/configs/configschema/schema.go @@ -4,6 +4,13 @@ import ( "github.com/zclconf/go-cty/cty" ) +type StringKind int + +const ( + StringPlain StringKind = iota + StringMarkdown +) + // Block represents a configuration block. // // "Block" here is a logical grouping construct, though it happens to map @@ -21,6 +28,11 @@ type Block struct { // BlockTypes describes any nested block types that may appear directly // inside the block. BlockTypes map[string]*NestedBlock + + Description string + DescriptionKind StringKind + + Deprecated bool } // Attribute represents a configuration attribute, within a block. @@ -32,7 +44,8 @@ type Attribute struct { // usage of the attribute. A description should be concise and use only // one or two sentences, leaving full definition to longer-form // documentation defined elsewhere. - Description string + Description string + DescriptionKind StringKind // Required, if set to true, specifies that an omitted or null value is // not permitted. @@ -55,6 +68,8 @@ type Attribute struct { // future to help Terraform mask sensitive information. (Terraform // currently achieves this in a limited sense via other mechanisms.) Sensitive bool + + Deprecated bool } // NestedBlock represents the embedding of one block within another. diff --git a/configs/module.go b/configs/module.go index 1aba88172..a6112d1f3 100644 --- a/configs/module.go +++ b/configs/module.go @@ -32,6 +32,7 @@ type Module struct { ProviderConfigs map[string]*Provider ProviderRequirements map[string]ProviderRequirements ProviderLocalNames map[addrs.Provider]string + ProviderMetas map[addrs.Provider]*ProviderMeta Variables map[string]*Variable Locals map[string]*Local @@ -61,6 +62,7 @@ type File struct { Backends []*Backend ProviderConfigs []*Provider + ProviderMetas []*ProviderMeta RequiredProviders []*RequiredProvider Variables []*Variable @@ -93,6 +95,7 @@ func NewModule(primaryFiles, overrideFiles []*File) (*Module, hcl.Diagnostics) { ModuleCalls: map[string]*ModuleCall{}, ManagedResources: map[string]*Resource{}, DataResources: map[string]*Resource{}, + ProviderMetas: map[addrs.Provider]*ProviderMeta{}, } for _, file := range primaryFiles { @@ -195,6 +198,19 @@ func (m *Module) appendFile(file *File) hcl.Diagnostics { } } + for _, pm := range file.ProviderMetas { + // TODO(paddy): pm.Provider is a string, but we need to build an addrs.Provider out of it somehow + if existing, exists := m.ProviderMetas[addrs.NewLegacyProvider(pm.Provider)]; exists { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Duplicate provider_meta block", + Detail: fmt.Sprintf("A provider_meta block for provider %q was already declared at %s. Providers may only have one provider_meta block per module.", existing.Provider, existing.DeclRange), + Subject: &pm.DeclRange, + }) + } + m.ProviderMetas[addrs.NewLegacyProvider(pm.Provider)] = pm + } + for _, v := range file.Variables { if existing, exists := m.Variables[v.Name]; exists { diags = append(diags, &hcl.Diagnostic{ diff --git a/configs/parser_config.go b/configs/parser_config.go index e8f94721d..b4510df18 100644 --- a/configs/parser_config.go +++ b/configs/parser_config.go @@ -77,6 +77,13 @@ func (p *Parser) loadConfigFile(path string, override bool) (*File, hcl.Diagnost diags = append(diags, reqsDiags...) file.RequiredProviders = append(file.RequiredProviders, reqs...) + case "provider_meta": + providerCfg, cfgDiags := decodeProviderMetaBlock(innerBlock) + diags = append(diags, cfgDiags...) + if providerCfg != nil { + file.ProviderMetas = append(file.ProviderMetas, providerCfg) + } + default: // Should never happen because the above cases should be exhaustive // for all block type names in our schema. @@ -231,6 +238,10 @@ var terraformBlockSchema = &hcl.BodySchema{ { Type: "required_providers", }, + { + Type: "provider_meta", + LabelNames: []string{"provider"}, + }, }, } diff --git a/configs/provider_meta.go b/configs/provider_meta.go new file mode 100644 index 000000000..5db321373 --- /dev/null +++ b/configs/provider_meta.go @@ -0,0 +1,22 @@ +package configs + +import "github.com/hashicorp/hcl/v2" + +// ProviderMeta represents a "provider_meta" block inside a "terraform" block +// in a module or file. +type ProviderMeta struct { + Provider string + Config hcl.Body + + ProviderRange hcl.Range + DeclRange hcl.Range +} + +func decodeProviderMetaBlock(block *hcl.Block) (*ProviderMeta, hcl.Diagnostics) { + return &ProviderMeta{ + Provider: block.Labels[0], + ProviderRange: block.LabelRanges[0], + Config: block.Body, + DeclRange: block.DefRange, + }, nil +} diff --git a/docs/plugin-protocol/tfplugin5.2.proto b/docs/plugin-protocol/tfplugin5.2.proto new file mode 100644 index 000000000..4f365697a --- /dev/null +++ b/docs/plugin-protocol/tfplugin5.2.proto @@ -0,0 +1,368 @@ +// Terraform Plugin RPC protocol version 5.2 +// +// This file defines version 5.2 of the RPC protocol. To implement a plugin +// against this protocol, copy this definition into your own codebase and +// use protoc to generate stubs for your target language. +// +// This file will not be updated. Any minor versions of protocol 5 to follow +// should copy this file and modify the copy while maintaing backwards +// compatibility. Breaking changes, if any are required, will come +// in a subsequent major version with its own separate proto definition. +// +// Note that only the proto files included in a release tag of Terraform are +// official protocol releases. Proto files taken from other commits may include +// incomplete changes or features that did not make it into a final release. +// In all reasonable cases, plugin developers should take the proto file from +// the tag of the most recent release of Terraform, and not from the master +// branch or any other development branch. +// +syntax = "proto3"; + +package tfplugin5; + +// DynamicValue is an opaque encoding of terraform data, with the field name +// indicating the encoding scheme used. +message DynamicValue { + bytes msgpack = 1; + bytes json = 2; +} + +message Diagnostic { + enum Severity { + INVALID = 0; + ERROR = 1; + WARNING = 2; + } + Severity severity = 1; + string summary = 2; + string detail = 3; + AttributePath attribute = 4; +} + +message AttributePath { + message Step { + oneof selector { + // Set "attribute_name" to represent looking up an attribute + // in the current object value. + string attribute_name = 1; + // Set "element_key_*" to represent looking up an element in + // an indexable collection type. + string element_key_string = 2; + int64 element_key_int = 3; + } + } + repeated Step steps = 1; +} + +message Stop { + message Request { + } + message Response { + string Error = 1; + } +} + +// RawState holds the stored state for a resource to be upgraded by the +// provider. It can be in one of two formats, the current json encoded format +// in bytes, or the legacy flatmap format as a map of strings. +message RawState { + bytes json = 1; + map flatmap = 2; +} + +enum StringKind { + PLAIN = 0; + MARKDOWN = 1; +} + +// Schema is the configuration schema for a Resource, Provider, or Provisioner. +message Schema { + message Block { + int64 version = 1; + repeated Attribute attributes = 2; + repeated NestedBlock block_types = 3; + string description = 4; + StringKind description_kind = 5; + bool deprecated = 6; + } + + message Attribute { + string name = 1; + bytes type = 2; + string description = 3; + bool required = 4; + bool optional = 5; + bool computed = 6; + bool sensitive = 7; + StringKind description_kind = 8; + bool deprecated = 9; + } + + message NestedBlock { + enum NestingMode { + INVALID = 0; + SINGLE = 1; + LIST = 2; + SET = 3; + MAP = 4; + GROUP = 5; + } + + string type_name = 1; + Block block = 2; + NestingMode nesting = 3; + int64 min_items = 4; + int64 max_items = 5; + } + + // The version of the schema. + // Schemas are versioned, so that providers can upgrade a saved resource + // state when the schema is changed. + int64 version = 1; + + // Block is the top level configuration block for this schema. + Block block = 2; +} + +service Provider { + //////// Information about what a provider supports/expects + rpc GetSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response); + rpc PrepareProviderConfig(PrepareProviderConfig.Request) returns (PrepareProviderConfig.Response); + rpc ValidateResourceTypeConfig(ValidateResourceTypeConfig.Request) returns (ValidateResourceTypeConfig.Response); + rpc ValidateDataSourceConfig(ValidateDataSourceConfig.Request) returns (ValidateDataSourceConfig.Response); + rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response); + + //////// One-time initialization, called before other functions below + rpc Configure(Configure.Request) returns (Configure.Response); + + //////// Managed Resource Lifecycle + rpc ReadResource(ReadResource.Request) returns (ReadResource.Response); + rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response); + rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response); + rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response); + + rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response); + + //////// Graceful Shutdown + rpc Stop(Stop.Request) returns (Stop.Response); +} + +message GetProviderSchema { + message Request { + } + message Response { + Schema provider = 1; + map resource_schemas = 2; + map data_source_schemas = 3; + repeated Diagnostic diagnostics = 4; + Schema provider_meta = 5; + } +} + +message PrepareProviderConfig { + message Request { + DynamicValue config = 1; + } + message Response { + DynamicValue prepared_config = 1; + repeated Diagnostic diagnostics = 2; + } +} + +message UpgradeResourceState { + message Request { + string type_name = 1; + + // version is the schema_version number recorded in the state file + int64 version = 2; + + // raw_state is the raw states as stored for the resource. Core does + // not have access to the schema of prior_version, so it's the + // provider's responsibility to interpret this value using the + // appropriate older schema. The raw_state will be the json encoded + // state, or a legacy flat-mapped format. + RawState raw_state = 3; + } + message Response { + // new_state is a msgpack-encoded data structure that, when interpreted with + // the _current_ schema for this resource type, is functionally equivalent to + // that which was given in prior_state_raw. + DynamicValue upgraded_state = 1; + + // diagnostics describes any errors encountered during migration that could not + // be safely resolved, and warnings about any possibly-risky assumptions made + // in the upgrade process. + repeated Diagnostic diagnostics = 2; + } +} + +message ValidateResourceTypeConfig { + message Request { + string type_name = 1; + DynamicValue config = 2; + } + message Response { + repeated Diagnostic diagnostics = 1; + } +} + +message ValidateDataSourceConfig { + message Request { + string type_name = 1; + DynamicValue config = 2; + } + message Response { + repeated Diagnostic diagnostics = 1; + } +} + +message Configure { + message Request { + string terraform_version = 1; + DynamicValue config = 2; + } + message Response { + repeated Diagnostic diagnostics = 1; + } +} + +message ReadResource { + message Request { + string type_name = 1; + DynamicValue current_state = 2; + bytes private = 3; + DynamicValue provider_meta = 4; + } + message Response { + DynamicValue new_state = 1; + repeated Diagnostic diagnostics = 2; + bytes private = 3; + } +} + +message PlanResourceChange { + message Request { + string type_name = 1; + DynamicValue prior_state = 2; + DynamicValue proposed_new_state = 3; + DynamicValue config = 4; + bytes prior_private = 5; + DynamicValue provider_meta = 6; + } + + message Response { + DynamicValue planned_state = 1; + repeated AttributePath requires_replace = 2; + bytes planned_private = 3; + repeated Diagnostic diagnostics = 4; + + + // This may be set only by the helper/schema "SDK" in the main Terraform + // repository, to request that Terraform Core >=0.12 permit additional + // inconsistencies that can result from the legacy SDK type system + // and its imprecise mapping to the >=0.12 type system. + // The change in behavior implied by this flag makes sense only for the + // specific details of the legacy SDK type system, and are not a general + // mechanism to avoid proper type handling in providers. + // + // ==== DO NOT USE THIS ==== + // ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ==== + // ==== DO NOT USE THIS ==== + bool legacy_type_system = 5; + } +} + +message ApplyResourceChange { + message Request { + string type_name = 1; + DynamicValue prior_state = 2; + DynamicValue planned_state = 3; + DynamicValue config = 4; + bytes planned_private = 5; + DynamicValue provider_meta = 6; + } + message Response { + DynamicValue new_state = 1; + bytes private = 2; + repeated Diagnostic diagnostics = 3; + + // This may be set only by the helper/schema "SDK" in the main Terraform + // repository, to request that Terraform Core >=0.12 permit additional + // inconsistencies that can result from the legacy SDK type system + // and its imprecise mapping to the >=0.12 type system. + // The change in behavior implied by this flag makes sense only for the + // specific details of the legacy SDK type system, and are not a general + // mechanism to avoid proper type handling in providers. + // + // ==== DO NOT USE THIS ==== + // ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ==== + // ==== DO NOT USE THIS ==== + bool legacy_type_system = 4; + } +} + +message ImportResourceState { + message Request { + string type_name = 1; + string id = 2; + } + + message ImportedResource { + string type_name = 1; + DynamicValue state = 2; + bytes private = 3; + } + + message Response { + repeated ImportedResource imported_resources = 1; + repeated Diagnostic diagnostics = 2; + } +} + +message ReadDataSource { + message Request { + string type_name = 1; + DynamicValue config = 2; + DynamicValue provider_meta = 3; + } + message Response { + DynamicValue state = 1; + repeated Diagnostic diagnostics = 2; + } +} + +service Provisioner { + rpc GetSchema(GetProvisionerSchema.Request) returns (GetProvisionerSchema.Response); + rpc ValidateProvisionerConfig(ValidateProvisionerConfig.Request) returns (ValidateProvisionerConfig.Response); + rpc ProvisionResource(ProvisionResource.Request) returns (stream ProvisionResource.Response); + rpc Stop(Stop.Request) returns (Stop.Response); +} + +message GetProvisionerSchema { + message Request { + } + message Response { + Schema provisioner = 1; + repeated Diagnostic diagnostics = 2; + } +} + +message ValidateProvisionerConfig { + message Request { + DynamicValue config = 1; + } + message Response { + repeated Diagnostic diagnostics = 1; + } +} + +message ProvisionResource { + message Request { + DynamicValue config = 1; + DynamicValue connection = 2; + } + message Response { + string output = 1; + repeated Diagnostic diagnostics = 2; + } +} diff --git a/go.sum b/go.sum index c95ddf0eb..3381c5304 100644 --- a/go.sum +++ b/go.sum @@ -106,7 +106,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.0 h1:HIgH5xUWXT914HCI671AxuTTqjj64UOFr7pHn48LUTI= github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= +github.com/coreos/etcd v3.3.10+incompatible h1:KjVWqrZ5U0wa3CxY2AxlH6/UcB+PK2td1DcsYhA+HRs= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -372,6 +372,8 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= +github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg= @@ -479,6 +481,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191009170851-d66e71096ffb h1:TR699M2v0qoKTOHxeLgp6zPqaQNs74f01a/ob9W0qko= golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -529,11 +532,15 @@ google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 h1:Lj2SnHtxkRGJDqnGaSjo+CCdIieEnwVazbOXILwQemk= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= diff --git a/helper/plugin/grpc_provider.go b/helper/plugin/grpc_provider.go index f32610c6c..06ebaf421 100644 --- a/helper/plugin/grpc_provider.go +++ b/helper/plugin/grpc_provider.go @@ -55,6 +55,10 @@ func (s *GRPCProviderServer) GetSchema(_ context.Context, req *proto.GetProvider Block: convert.ConfigSchemaToProto(s.getProviderSchemaBlock()), } + resp.ProviderMeta = &proto.Schema{ + Block: convert.ConfigSchemaToProto(s.getProviderMetaSchemaBlock()), + } + for typ, res := range s.provider.ResourcesMap { resp.ResourceSchemas[typ] = &proto.Schema{ Version: int64(res.SchemaVersion), @@ -76,6 +80,10 @@ func (s *GRPCProviderServer) getProviderSchemaBlock() *configschema.Block { return schema.InternalMap(s.provider.Schema).CoreConfigSchema() } +func (s *GRPCProviderServer) getProviderMetaSchemaBlock() *configschema.Block { + return schema.InternalMap(s.provider.ProviderMetaSchema).CoreConfigSchema() +} + func (s *GRPCProviderServer) getResourceSchemaBlock(name string) *configschema.Block { res := s.provider.ResourcesMap[name] return res.CoreConfigSchema() @@ -522,6 +530,16 @@ func (s *GRPCProviderServer) ReadResource(_ context.Context, req *proto.ReadReso } instanceState.Meta = private + pmSchemaBlock := s.getProviderMetaSchemaBlock() + if pmSchemaBlock != nil && req.ProviderMeta != nil { + providerSchemaVal, err := msgpack.Unmarshal(req.ProviderMeta.Msgpack, pmSchemaBlock.ImpliedType()) + if err != nil { + resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err) + return resp, nil + } + instanceState.ProviderMeta = providerSchemaVal + } + newInstanceState, err := res.RefreshWithoutUpgrade(instanceState, s.provider.Meta()) if err != nil { resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err) @@ -621,6 +639,16 @@ func (s *GRPCProviderServer) PlanResourceChange(_ context.Context, req *proto.Pl priorState.Meta = priorPrivate + pmSchemaBlock := s.getProviderMetaSchemaBlock() + if pmSchemaBlock != nil && req.ProviderMeta != nil { + providerSchemaVal, err := msgpack.Unmarshal(req.ProviderMeta.Msgpack, pmSchemaBlock.ImpliedType()) + if err != nil { + resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err) + return resp, nil + } + priorState.ProviderMeta = providerSchemaVal + } + // Ensure there are no nulls that will cause helper/schema to panic. if err := validateConfigNulls(proposedNewStateVal, nil); err != nil { resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err) @@ -882,6 +910,16 @@ func (s *GRPCProviderServer) ApplyResourceChange(_ context.Context, req *proto.A } } + pmSchemaBlock := s.getProviderMetaSchemaBlock() + if pmSchemaBlock != nil && req.ProviderMeta != nil { + providerSchemaVal, err := msgpack.Unmarshal(req.ProviderMeta.Msgpack, pmSchemaBlock.ImpliedType()) + if err != nil { + resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err) + return resp, nil + } + priorState.ProviderMeta = providerSchemaVal + } + newInstanceState, err := s.provider.Apply(info, priorState, diff) // we record the error here, but continue processing any returned state. if err != nil { diff --git a/helper/schema/provider.go b/helper/schema/provider.go index 9efc90e7b..59dc750ee 100644 --- a/helper/schema/provider.go +++ b/helper/schema/provider.go @@ -7,7 +7,7 @@ import ( "sort" "sync" - "github.com/hashicorp/go-multierror" + multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform/configs/configschema" "github.com/hashicorp/terraform/terraform" ) @@ -50,6 +50,14 @@ type Provider struct { // and must *not* implement Create, Update or Delete. DataSourcesMap map[string]*Resource + // ProviderMetaSchema is the schema for the configuration of the meta + // information for this provider. If this provider has no meta info, + // this can be omitted. This functionality is currently experimental + // and subject to change or break without warning; it should only be + // used by providers that are collaborating on its use with the + // Terraform team. + ProviderMetaSchema map[string]*Schema + // ConfigureFunc is a function for configuring the provider. If the // provider doesn't need to be configured, this can be omitted. // diff --git a/helper/schema/resource.go b/helper/schema/resource.go index 8cd2703aa..dcfb32aea 100644 --- a/helper/schema/resource.go +++ b/helper/schema/resource.go @@ -247,6 +247,9 @@ func (r *Resource) Apply( if err != nil { return s, err } + if s != nil && data != nil { + data.providerMeta = s.ProviderMeta + } // Instance Diff shoould have the timeout info, need to copy it over to the // ResourceData meta @@ -437,6 +440,10 @@ func (r *Resource) RefreshWithoutUpgrade( return s, err } + if s != nil { + data.providerMeta = s.ProviderMeta + } + exists, err := r.Exists(data, meta) if err != nil { return s, err @@ -452,6 +459,10 @@ func (r *Resource) RefreshWithoutUpgrade( return s, err } + if s != nil { + data.providerMeta = s.ProviderMeta + } + err = r.Read(data, meta) state := data.State() if state != nil && state.ID == "" { diff --git a/helper/schema/resource_data.go b/helper/schema/resource_data.go index 1c390709e..fb9387e29 100644 --- a/helper/schema/resource_data.go +++ b/helper/schema/resource_data.go @@ -8,6 +8,8 @@ import ( "time" "github.com/hashicorp/terraform/terraform" + "github.com/zclconf/go-cty/cty" + "github.com/zclconf/go-cty/cty/gocty" ) // ResourceData is used to query and set the attributes of a resource. @@ -20,12 +22,13 @@ import ( // The most relevant methods to take a look at are Get, Set, and Partial. type ResourceData struct { // Settable (internally) - schema map[string]*Schema - config *terraform.ResourceConfig - state *terraform.InstanceState - diff *terraform.InstanceDiff - meta map[string]interface{} - timeouts *ResourceTimeout + schema map[string]*Schema + config *terraform.ResourceConfig + state *terraform.InstanceState + diff *terraform.InstanceDiff + meta map[string]interface{} + timeouts *ResourceTimeout + providerMeta cty.Value // Don't set multiReader *MultiLevelFieldReader @@ -549,3 +552,10 @@ func (d *ResourceData) get(addr []string, source getSource) getResult { Schema: schema, } } + +func (d *ResourceData) GetProviderMeta(dst interface{}) error { + if d.providerMeta.IsNull() { + return nil + } + return gocty.FromCtyValue(d.providerMeta, &dst) +} diff --git a/internal/tfplugin5/tfplugin5.pb.go b/internal/tfplugin5/tfplugin5.pb.go index 86fd21e41..26e62c6a9 100644 --- a/internal/tfplugin5/tfplugin5.pb.go +++ b/internal/tfplugin5/tfplugin5.pb.go @@ -24,6 +24,31 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +type StringKind int32 + +const ( + StringKind_PLAIN StringKind = 0 + StringKind_MARKDOWN StringKind = 1 +) + +var StringKind_name = map[int32]string{ + 0: "PLAIN", + 1: "MARKDOWN", +} + +var StringKind_value = map[string]int32{ + "PLAIN": 0, + "MARKDOWN": 1, +} + +func (x StringKind) String() string { + return proto.EnumName(StringKind_name, int32(x)) +} + +func (StringKind) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_17ae6090ff270234, []int{0} +} + type Diagnostic_Severity int32 const ( @@ -542,6 +567,9 @@ type Schema_Block struct { Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` Attributes []*Schema_Attribute `protobuf:"bytes,2,rep,name=attributes,proto3" json:"attributes,omitempty"` BlockTypes []*Schema_NestedBlock `protobuf:"bytes,3,rep,name=block_types,json=blockTypes,proto3" json:"block_types,omitempty"` + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` + DescriptionKind StringKind `protobuf:"varint,5,opt,name=description_kind,json=descriptionKind,proto3,enum=tfplugin5.StringKind" json:"description_kind,omitempty"` + Deprecated bool `protobuf:"varint,6,opt,name=deprecated,proto3" json:"deprecated,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -593,17 +621,40 @@ func (m *Schema_Block) GetBlockTypes() []*Schema_NestedBlock { return nil } +func (m *Schema_Block) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Schema_Block) GetDescriptionKind() StringKind { + if m != nil { + return m.DescriptionKind + } + return StringKind_PLAIN +} + +func (m *Schema_Block) GetDeprecated() bool { + if m != nil { + return m.Deprecated + } + return false +} + type Schema_Attribute struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Type []byte `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - Required bool `protobuf:"varint,4,opt,name=required,proto3" json:"required,omitempty"` - Optional bool `protobuf:"varint,5,opt,name=optional,proto3" json:"optional,omitempty"` - Computed bool `protobuf:"varint,6,opt,name=computed,proto3" json:"computed,omitempty"` - Sensitive bool `protobuf:"varint,7,opt,name=sensitive,proto3" json:"sensitive,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Type []byte `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + Required bool `protobuf:"varint,4,opt,name=required,proto3" json:"required,omitempty"` + Optional bool `protobuf:"varint,5,opt,name=optional,proto3" json:"optional,omitempty"` + Computed bool `protobuf:"varint,6,opt,name=computed,proto3" json:"computed,omitempty"` + Sensitive bool `protobuf:"varint,7,opt,name=sensitive,proto3" json:"sensitive,omitempty"` + DescriptionKind StringKind `protobuf:"varint,8,opt,name=description_kind,json=descriptionKind,proto3,enum=tfplugin5.StringKind" json:"description_kind,omitempty"` + Deprecated bool `protobuf:"varint,9,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Schema_Attribute) Reset() { *m = Schema_Attribute{} } @@ -680,6 +731,20 @@ func (m *Schema_Attribute) GetSensitive() bool { return false } +func (m *Schema_Attribute) GetDescriptionKind() StringKind { + if m != nil { + return m.DescriptionKind + } + return StringKind_PLAIN +} + +func (m *Schema_Attribute) GetDeprecated() bool { + if m != nil { + return m.Deprecated + } + return false +} + type Schema_NestedBlock struct { TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` Block *Schema_Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"` @@ -818,6 +883,7 @@ type GetProviderSchema_Response struct { ResourceSchemas map[string]*Schema `protobuf:"bytes,2,rep,name=resource_schemas,json=resourceSchemas,proto3" json:"resource_schemas,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` DataSourceSchemas map[string]*Schema `protobuf:"bytes,3,rep,name=data_source_schemas,json=dataSourceSchemas,proto3" json:"data_source_schemas,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Diagnostics []*Diagnostic `protobuf:"bytes,4,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` + ProviderMeta *Schema `protobuf:"bytes,5,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -876,6 +942,13 @@ func (m *GetProviderSchema_Response) GetDiagnostics() []*Diagnostic { return nil } +func (m *GetProviderSchema_Response) GetProviderMeta() *Schema { + if m != nil { + return m.ProviderMeta + } + return nil +} + type PrepareProviderConfig struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -1524,6 +1597,7 @@ type ReadResource_Request struct { TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` CurrentState *DynamicValue `protobuf:"bytes,2,opt,name=current_state,json=currentState,proto3" json:"current_state,omitempty"` Private []byte `protobuf:"bytes,3,opt,name=private,proto3" json:"private,omitempty"` + ProviderMeta *DynamicValue `protobuf:"bytes,4,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1575,6 +1649,13 @@ func (m *ReadResource_Request) GetPrivate() []byte { return nil } +func (m *ReadResource_Request) GetProviderMeta() *DynamicValue { + if m != nil { + return m.ProviderMeta + } + return nil +} + type ReadResource_Response struct { NewState *DynamicValue `protobuf:"bytes,1,opt,name=new_state,json=newState,proto3" json:"new_state,omitempty"` Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` @@ -1667,6 +1748,7 @@ type PlanResourceChange_Request struct { ProposedNewState *DynamicValue `protobuf:"bytes,3,opt,name=proposed_new_state,json=proposedNewState,proto3" json:"proposed_new_state,omitempty"` Config *DynamicValue `protobuf:"bytes,4,opt,name=config,proto3" json:"config,omitempty"` PriorPrivate []byte `protobuf:"bytes,5,opt,name=prior_private,json=priorPrivate,proto3" json:"prior_private,omitempty"` + ProviderMeta *DynamicValue `protobuf:"bytes,6,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1732,6 +1814,13 @@ func (m *PlanResourceChange_Request) GetPriorPrivate() []byte { return nil } +func (m *PlanResourceChange_Request) GetProviderMeta() *DynamicValue { + if m != nil { + return m.ProviderMeta + } + return nil +} + type PlanResourceChange_Response struct { PlannedState *DynamicValue `protobuf:"bytes,1,opt,name=planned_state,json=plannedState,proto3" json:"planned_state,omitempty"` RequiresReplace []*AttributePath `protobuf:"bytes,2,rep,name=requires_replace,json=requiresReplace,proto3" json:"requires_replace,omitempty"` @@ -1851,6 +1940,7 @@ type ApplyResourceChange_Request struct { PlannedState *DynamicValue `protobuf:"bytes,3,opt,name=planned_state,json=plannedState,proto3" json:"planned_state,omitempty"` Config *DynamicValue `protobuf:"bytes,4,opt,name=config,proto3" json:"config,omitempty"` PlannedPrivate []byte `protobuf:"bytes,5,opt,name=planned_private,json=plannedPrivate,proto3" json:"planned_private,omitempty"` + ProviderMeta *DynamicValue `protobuf:"bytes,6,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1916,6 +2006,13 @@ func (m *ApplyResourceChange_Request) GetPlannedPrivate() []byte { return nil } +func (m *ApplyResourceChange_Request) GetProviderMeta() *DynamicValue { + if m != nil { + return m.ProviderMeta + } + return nil +} + type ApplyResourceChange_Response struct { NewState *DynamicValue `protobuf:"bytes,1,opt,name=new_state,json=newState,proto3" json:"new_state,omitempty"` Private []byte `protobuf:"bytes,2,opt,name=private,proto3" json:"private,omitempty"` @@ -2204,6 +2301,7 @@ var xxx_messageInfo_ReadDataSource proto.InternalMessageInfo type ReadDataSource_Request struct { TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` Config *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` + ProviderMeta *DynamicValue `protobuf:"bytes,3,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2248,6 +2346,13 @@ func (m *ReadDataSource_Request) GetConfig() *DynamicValue { return nil } +func (m *ReadDataSource_Request) GetProviderMeta() *DynamicValue { + if m != nil { + return m.ProviderMeta + } + return nil +} + type ReadDataSource_Response struct { State *DynamicValue `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` @@ -2639,6 +2744,7 @@ func (m *ProvisionResource_Response) GetDiagnostics() []*Diagnostic { } func init() { + proto.RegisterEnum("tfplugin5.StringKind", StringKind_name, StringKind_value) proto.RegisterEnum("tfplugin5.Diagnostic_Severity", Diagnostic_Severity_name, Diagnostic_Severity_value) proto.RegisterEnum("tfplugin5.Schema_NestedBlock_NestingMode", Schema_NestedBlock_NestingMode_name, Schema_NestedBlock_NestingMode_value) proto.RegisterType((*DynamicValue)(nil), "tfplugin5.DynamicValue") @@ -2704,125 +2810,133 @@ func init() { func init() { proto.RegisterFile("tfplugin5.proto", fileDescriptor_17ae6090ff270234) } var fileDescriptor_17ae6090ff270234 = []byte{ - // 1880 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0xcb, 0x6f, 0x23, 0x49, - 0x19, 0x9f, 0xf6, 0x23, 0xb1, 0x3f, 0xe7, 0xe1, 0xd4, 0xcc, 0x0e, 0xa6, 0x77, 0x17, 0x82, 0x79, - 0x24, 0xab, 0xdd, 0xf1, 0xac, 0x32, 0xb0, 0xbb, 0x84, 0xd1, 0x8a, 0x6c, 0x26, 0x64, 0x22, 0x66, - 0xb2, 0xa1, 0x3c, 0x0f, 0x24, 0xa4, 0xb5, 0x6a, 0xdc, 0x15, 0x4f, 0x33, 0x76, 0x77, 0x6f, 0x75, - 0x39, 0x89, 0x85, 0xc4, 0x05, 0xc1, 0x19, 0x09, 0xf1, 0x90, 0x78, 0x5c, 0x40, 0xe2, 0x1f, 0xe0, - 0x00, 0xdc, 0x38, 0xf1, 0x0f, 0x70, 0x03, 0x4e, 0x08, 0x6e, 0x9c, 0xe1, 0x82, 0x84, 0xea, 0xd5, - 0x5d, 0xb6, 0xdb, 0x4e, 0x4f, 0xb2, 0x23, 0xc4, 0xad, 0xab, 0xbe, 0x5f, 0x7d, 0xdf, 0x57, 0xdf, - 0xab, 0xbe, 0xcf, 0x86, 0x55, 0x7e, 0x1c, 0xf5, 0x87, 0x3d, 0x3f, 0xf8, 0x42, 0x2b, 0x62, 0x21, - 0x0f, 0x51, 0x35, 0xd9, 0x68, 0xde, 0x86, 0xa5, 0x3b, 0xa3, 0x80, 0x0c, 0xfc, 0xee, 0x23, 0xd2, - 0x1f, 0x52, 0xd4, 0x80, 0xc5, 0x41, 0xdc, 0x8b, 0x48, 0xf7, 0x59, 0xc3, 0x59, 0x77, 0x36, 0x97, - 0xb0, 0x59, 0x22, 0x04, 0xa5, 0x6f, 0xc6, 0x61, 0xd0, 0x28, 0xc8, 0x6d, 0xf9, 0xdd, 0xfc, 0x9b, - 0x03, 0x70, 0xc7, 0x27, 0xbd, 0x20, 0x8c, 0xb9, 0xdf, 0x45, 0xdb, 0x50, 0x89, 0xe9, 0x09, 0x65, - 0x3e, 0x1f, 0xc9, 0xd3, 0x2b, 0x5b, 0x9f, 0x68, 0xa5, 0xb2, 0x53, 0x60, 0xab, 0xad, 0x51, 0x38, - 0xc1, 0x0b, 0xc1, 0xf1, 0x70, 0x30, 0x20, 0x6c, 0x24, 0x25, 0x54, 0xb1, 0x59, 0xa2, 0xeb, 0xb0, - 0xe0, 0x51, 0x4e, 0xfc, 0x7e, 0xa3, 0x28, 0x09, 0x7a, 0x85, 0xde, 0x82, 0x2a, 0xe1, 0x9c, 0xf9, - 0x4f, 0x86, 0x9c, 0x36, 0x4a, 0xeb, 0xce, 0x66, 0x6d, 0xab, 0x61, 0x89, 0xdb, 0x31, 0xb4, 0x23, - 0xc2, 0x9f, 0xe2, 0x14, 0xda, 0xbc, 0x09, 0x15, 0x23, 0x1f, 0xd5, 0x60, 0xf1, 0xe0, 0xf0, 0xd1, - 0xce, 0xbd, 0x83, 0x3b, 0xf5, 0x2b, 0xa8, 0x0a, 0xe5, 0x3d, 0x8c, 0xdf, 0xc7, 0x75, 0x47, 0xec, - 0x3f, 0xde, 0xc1, 0x87, 0x07, 0x87, 0xfb, 0xf5, 0x42, 0xf3, 0x2f, 0x0e, 0x2c, 0x8f, 0x71, 0x43, - 0xb7, 0xa0, 0x1c, 0x73, 0x1a, 0xc5, 0x0d, 0x67, 0xbd, 0xb8, 0x59, 0xdb, 0x7a, 0x75, 0x96, 0xd8, - 0x56, 0x9b, 0xd3, 0x08, 0x2b, 0xac, 0xfb, 0x43, 0x07, 0x4a, 0x62, 0x8d, 0x36, 0x60, 0x25, 0xd1, - 0xa6, 0x13, 0x90, 0x01, 0x95, 0xc6, 0xaa, 0xde, 0xbd, 0x82, 0x97, 0x93, 0xfd, 0x43, 0x32, 0xa0, - 0xa8, 0x05, 0x88, 0xf6, 0xe9, 0x80, 0x06, 0xbc, 0xf3, 0x8c, 0x8e, 0x3a, 0x31, 0x67, 0x7e, 0xd0, - 0x53, 0xe6, 0xb9, 0x7b, 0x05, 0xd7, 0x35, 0xed, 0xab, 0x74, 0xd4, 0x96, 0x14, 0xb4, 0x09, 0xab, - 0x36, 0xde, 0x0f, 0xb8, 0x34, 0x59, 0x51, 0x70, 0x4e, 0xc1, 0x07, 0x01, 0x7f, 0x0f, 0x84, 0xa7, - 0xfa, 0xb4, 0xcb, 0x43, 0xd6, 0xbc, 0x25, 0xd4, 0x0a, 0x23, 0xb7, 0x0a, 0x8b, 0x98, 0x7e, 0x38, - 0xa4, 0x31, 0x77, 0xd7, 0xa1, 0x82, 0x69, 0x1c, 0x85, 0x41, 0x4c, 0xd1, 0x35, 0x28, 0xef, 0x31, - 0x16, 0x32, 0xa5, 0x24, 0x56, 0x8b, 0xe6, 0x8f, 0x1c, 0xa8, 0x60, 0x72, 0xda, 0xe6, 0x84, 0xd3, - 0x24, 0x34, 0x9c, 0x34, 0x34, 0xd0, 0x36, 0x2c, 0x1e, 0xf7, 0x09, 0x1f, 0x90, 0xa8, 0x51, 0x90, - 0x46, 0x5a, 0xb7, 0x8c, 0x64, 0x4e, 0xb6, 0xbe, 0xa2, 0x20, 0x7b, 0x01, 0x67, 0x23, 0x6c, 0x0e, - 0xb8, 0xdb, 0xb0, 0x64, 0x13, 0x50, 0x1d, 0x8a, 0xcf, 0xe8, 0x48, 0x2b, 0x20, 0x3e, 0x85, 0x52, - 0x27, 0x22, 0x5e, 0x75, 0xac, 0xa8, 0xc5, 0x76, 0xe1, 0x1d, 0xa7, 0xf9, 0x8f, 0x32, 0x2c, 0xb4, - 0xbb, 0x4f, 0xe9, 0x80, 0x88, 0x90, 0x3a, 0xa1, 0x2c, 0xf6, 0xb5, 0x66, 0x45, 0x6c, 0x96, 0xe8, - 0x06, 0x94, 0x9f, 0xf4, 0xc3, 0xee, 0x33, 0x79, 0xbc, 0xb6, 0xf5, 0x31, 0x4b, 0x35, 0x75, 0xb6, - 0xf5, 0x9e, 0x20, 0x63, 0x85, 0x72, 0x7f, 0xe1, 0x40, 0x59, 0x6e, 0xcc, 0x61, 0xf9, 0x25, 0x80, - 0xc4, 0x79, 0xb1, 0xbe, 0xf2, 0xcb, 0xd3, 0x7c, 0x93, 0xf0, 0xc0, 0x16, 0x1c, 0xbd, 0x0b, 0x35, - 0x29, 0xa9, 0xc3, 0x47, 0x11, 0x8d, 0x1b, 0xc5, 0xa9, 0xa8, 0xd2, 0xa7, 0x0f, 0x69, 0xcc, 0xa9, - 0xa7, 0x74, 0x03, 0x79, 0xe2, 0x81, 0x38, 0xe0, 0xfe, 0xd1, 0x81, 0x6a, 0xc2, 0x59, 0xb8, 0x23, - 0x8d, 0x2a, 0x2c, 0xbf, 0xc5, 0x9e, 0xe0, 0x6d, 0xb2, 0x57, 0x7c, 0xa3, 0x75, 0xa8, 0x79, 0x34, - 0xee, 0x32, 0x3f, 0xe2, 0xe2, 0x42, 0x2a, 0xbb, 0xec, 0x2d, 0xe4, 0x42, 0x85, 0xd1, 0x0f, 0x87, - 0x3e, 0xa3, 0x9e, 0xcc, 0xb0, 0x0a, 0x4e, 0xd6, 0x82, 0x16, 0x4a, 0x14, 0xe9, 0x37, 0xca, 0x8a, - 0x66, 0xd6, 0x82, 0xd6, 0x0d, 0x07, 0xd1, 0x90, 0x53, 0xaf, 0xb1, 0xa0, 0x68, 0x66, 0x8d, 0x5e, - 0x81, 0x6a, 0x4c, 0x83, 0xd8, 0xe7, 0xfe, 0x09, 0x6d, 0x2c, 0x4a, 0x62, 0xba, 0xe1, 0xfe, 0xba, - 0x00, 0x35, 0xeb, 0x96, 0xe8, 0x65, 0xa8, 0x0a, 0x5d, 0xad, 0x34, 0xc1, 0x15, 0xb1, 0x21, 0xf3, - 0xe3, 0xf9, 0xdc, 0x88, 0x76, 0x61, 0x31, 0xa0, 0x31, 0x17, 0x39, 0x54, 0x94, 0xd5, 0xe9, 0xb5, - 0xb9, 0x16, 0x96, 0xdf, 0x7e, 0xd0, 0xbb, 0x1f, 0x7a, 0x14, 0x9b, 0x93, 0x42, 0xa1, 0x81, 0x1f, - 0x74, 0x7c, 0x4e, 0x07, 0xb1, 0xb4, 0x49, 0x11, 0x57, 0x06, 0x7e, 0x70, 0x20, 0xd6, 0x92, 0x48, - 0xce, 0x34, 0xb1, 0xac, 0x89, 0xe4, 0x4c, 0x12, 0x9b, 0xf7, 0xd5, 0xcd, 0x34, 0xc7, 0xf1, 0xd2, - 0x03, 0xb0, 0xd0, 0x3e, 0x38, 0xdc, 0xbf, 0xb7, 0x57, 0x77, 0x50, 0x05, 0x4a, 0xf7, 0x0e, 0xda, - 0x0f, 0xea, 0x05, 0xb4, 0x08, 0xc5, 0xf6, 0xde, 0x83, 0x7a, 0x51, 0x7c, 0xdc, 0xdf, 0x39, 0xaa, - 0x97, 0x44, 0x89, 0xda, 0xc7, 0xef, 0x3f, 0x3c, 0xaa, 0x97, 0x9b, 0x3f, 0x29, 0xc1, 0xda, 0x3e, - 0xe5, 0x47, 0x2c, 0x3c, 0xf1, 0x3d, 0xca, 0x94, 0xfe, 0x76, 0x12, 0xff, 0xab, 0x68, 0x65, 0xf1, - 0x0d, 0xa8, 0x44, 0x1a, 0x29, 0xcd, 0x58, 0xdb, 0x5a, 0x9b, 0xba, 0x3c, 0x4e, 0x20, 0x88, 0x42, - 0x9d, 0xd1, 0x38, 0x1c, 0xb2, 0x2e, 0xed, 0xc4, 0x92, 0x68, 0x62, 0x7a, 0xdb, 0x3a, 0x36, 0x25, - 0xbe, 0x65, 0xe4, 0x89, 0x0f, 0x79, 0x5a, 0xed, 0xc7, 0x2a, 0xc1, 0x57, 0xd9, 0xf8, 0x2e, 0xea, - 0xc3, 0x55, 0x8f, 0x70, 0xd2, 0x99, 0x90, 0xa4, 0xe2, 0xff, 0x76, 0x3e, 0x49, 0x77, 0x08, 0x27, - 0xed, 0x69, 0x59, 0x6b, 0xde, 0xe4, 0x3e, 0x7a, 0x1b, 0x6a, 0x5e, 0xf2, 0x06, 0x09, 0xe7, 0x09, - 0x29, 0x2f, 0x65, 0xbe, 0x50, 0xd8, 0x46, 0xba, 0x0f, 0xe1, 0x5a, 0xd6, 0x7d, 0x32, 0xea, 0xd2, - 0x86, 0x5d, 0x97, 0x32, 0x6d, 0x9c, 0x96, 0x2a, 0xf7, 0x31, 0x5c, 0xcf, 0x56, 0xfe, 0x92, 0x8c, - 0x9b, 0x7f, 0x76, 0xe0, 0xa5, 0x23, 0x46, 0x23, 0xc2, 0xa8, 0xb1, 0xda, 0x6e, 0x18, 0x1c, 0xfb, - 0x3d, 0x77, 0x3b, 0x09, 0x0f, 0x74, 0x13, 0x16, 0xba, 0x72, 0x53, 0xc7, 0x83, 0x9d, 0x3d, 0x76, - 0x4b, 0x80, 0x35, 0xcc, 0xfd, 0xae, 0x63, 0xc5, 0xd3, 0x97, 0x61, 0x35, 0x52, 0x12, 0xbc, 0x4e, - 0x3e, 0x36, 0x2b, 0x06, 0xaf, 0x54, 0x99, 0xf4, 0x46, 0x21, 0xaf, 0x37, 0x9a, 0xdf, 0x2f, 0xc0, - 0xb5, 0x87, 0x51, 0x8f, 0x11, 0x8f, 0x26, 0x5e, 0x11, 0x8f, 0x89, 0xcb, 0xd2, 0xcb, 0xcd, 0x2d, - 0x1b, 0x56, 0x11, 0x2f, 0x8c, 0x17, 0xf1, 0x37, 0xa1, 0xca, 0xc8, 0x69, 0x27, 0x16, 0xec, 0x64, - 0x8d, 0xa8, 0x6d, 0x5d, 0xcd, 0x78, 0xb6, 0x70, 0x85, 0xe9, 0x2f, 0xf7, 0x3b, 0xb6, 0x51, 0xde, - 0x85, 0x95, 0xa1, 0x52, 0xcc, 0xd3, 0x3c, 0xce, 0xb1, 0xc9, 0xb2, 0x81, 0xab, 0x77, 0xf4, 0xc2, - 0x26, 0xf9, 0xbd, 0x03, 0xee, 0x23, 0xd2, 0xf7, 0x3d, 0xa1, 0x9c, 0xb6, 0x89, 0x78, 0x19, 0xb4, - 0xd7, 0x1f, 0xe7, 0x34, 0x4c, 0x1a, 0x12, 0x85, 0x7c, 0x21, 0xb1, 0x6b, 0x5d, 0x7e, 0x42, 0x79, - 0x27, 0xb7, 0xf2, 0xbf, 0x75, 0xa0, 0x61, 0x94, 0x4f, 0xf3, 0xe1, 0xff, 0x42, 0xf5, 0xdf, 0x39, - 0x50, 0x55, 0x8a, 0x0e, 0x19, 0x75, 0x7b, 0xa9, 0xae, 0xaf, 0xc3, 0x1a, 0xa7, 0x8c, 0x91, 0xe3, - 0x90, 0x0d, 0x3a, 0x76, 0xc7, 0x50, 0xc5, 0xf5, 0x84, 0xf0, 0x48, 0x47, 0xdd, 0xff, 0x46, 0xf7, - 0x5f, 0x15, 0x60, 0x09, 0x53, 0xe2, 0x99, 0x78, 0x71, 0xbf, 0x9d, 0xd3, 0xd4, 0xb7, 0x61, 0xb9, - 0x3b, 0x64, 0x4c, 0x74, 0x99, 0x2a, 0xc8, 0xcf, 0xd1, 0x7a, 0x49, 0xa3, 0x55, 0x8c, 0x37, 0x60, - 0x31, 0x62, 0xfe, 0x89, 0x49, 0xb0, 0x25, 0x6c, 0x96, 0xee, 0x0f, 0xec, 0x54, 0xfa, 0x3c, 0x54, - 0x03, 0x7a, 0x9a, 0x2f, 0x8b, 0x2a, 0x01, 0x3d, 0xbd, 0x5c, 0x02, 0xcd, 0xd6, 0xaa, 0xf9, 0x9b, - 0x12, 0xa0, 0xa3, 0x3e, 0x09, 0x8c, 0x99, 0x76, 0x9f, 0x92, 0xa0, 0x47, 0xdd, 0xff, 0x38, 0x39, - 0xad, 0xf5, 0x0e, 0xd4, 0x22, 0xe6, 0x87, 0x2c, 0x9f, 0xad, 0x40, 0x62, 0xd5, 0x65, 0xf6, 0x00, - 0x45, 0x2c, 0x8c, 0xc2, 0x98, 0x7a, 0x9d, 0xd4, 0x16, 0xc5, 0xf9, 0x0c, 0xea, 0xe6, 0xc8, 0xa1, - 0xb1, 0x49, 0x1a, 0x5d, 0xa5, 0x5c, 0xd1, 0x85, 0x3e, 0x0d, 0xcb, 0x4a, 0x63, 0x63, 0x91, 0xb2, - 0xb4, 0xc8, 0x92, 0xdc, 0x3c, 0xd2, 0xce, 0xfa, 0x79, 0xc1, 0x72, 0xd6, 0x6d, 0x58, 0x8e, 0xfa, - 0x24, 0x08, 0xf2, 0x96, 0xbd, 0x25, 0x8d, 0x56, 0x0a, 0xee, 0x8a, 0x5e, 0x43, 0x36, 0x95, 0x71, - 0x87, 0xd1, 0xa8, 0x4f, 0xba, 0x54, 0x7b, 0x6e, 0xf6, 0x38, 0xb7, 0x6a, 0x4e, 0x60, 0x75, 0x00, - 0x6d, 0xc0, 0xaa, 0x51, 0x61, 0xdc, 0x91, 0x2b, 0x7a, 0x5b, 0x2b, 0x7e, 0xe1, 0x26, 0x00, 0xbd, - 0x01, 0xa8, 0x4f, 0x7b, 0xa4, 0x3b, 0x92, 0x4d, 0x7a, 0x27, 0x1e, 0xc5, 0x9c, 0x0e, 0x74, 0xe7, - 0x5b, 0x57, 0x14, 0x51, 0x72, 0xdb, 0x72, 0xbf, 0xf9, 0xa7, 0x22, 0x5c, 0xdd, 0x89, 0xa2, 0xfe, - 0x68, 0x22, 0x6e, 0xfe, 0xfd, 0xe2, 0xe3, 0x66, 0xca, 0x1b, 0xc5, 0xe7, 0xf1, 0xc6, 0x73, 0x87, - 0x4b, 0x86, 0xe5, 0xcb, 0x59, 0x96, 0x77, 0xff, 0x70, 0xf9, 0xfc, 0xb6, 0xd2, 0xb4, 0x30, 0x96, - 0xa6, 0x93, 0x6e, 0x2d, 0x5e, 0xd2, 0xad, 0xa5, 0x19, 0x6e, 0xfd, 0x67, 0x01, 0xae, 0x1e, 0x0c, - 0xa2, 0x90, 0xf1, 0xf1, 0xd6, 0xe3, 0xad, 0x9c, 0x5e, 0x5d, 0x81, 0x82, 0xef, 0xe9, 0xa1, 0xb5, - 0xe0, 0x7b, 0xee, 0x19, 0xd4, 0x15, 0x3b, 0x9a, 0xd4, 0xe1, 0x73, 0x47, 0x9e, 0x5c, 0x01, 0xa1, - 0x50, 0x73, 0xaa, 0xed, 0x2f, 0x6d, 0x6f, 0x7c, 0x00, 0xc8, 0xd7, 0x6a, 0x74, 0x4c, 0x8f, 0x6e, - 0xde, 0x92, 0x9b, 0x96, 0x88, 0x8c, 0xab, 0xb7, 0x26, 0xf5, 0xc7, 0x6b, 0xfe, 0xc4, 0x4e, 0x7c, - 0xf1, 0xc6, 0xe6, 0xaf, 0x0e, 0xac, 0x88, 0x47, 0x2a, 0xed, 0x0b, 0x5e, 0x5c, 0x47, 0xc0, 0xc6, - 0xc6, 0xa5, 0x72, 0xae, 0xd0, 0xd4, 0x66, 0xbe, 0xf0, 0xfd, 0x7e, 0xea, 0xc0, 0x35, 0x33, 0xdb, - 0x88, 0x5e, 0x20, 0x6b, 0x8e, 0x3b, 0xb3, 0xf4, 0xba, 0x25, 0xaa, 0x42, 0x82, 0x9d, 0x3d, 0xc9, - 0xd9, 0xa8, 0x8b, 0x6b, 0xf7, 0x33, 0x07, 0x3e, 0x6e, 0x3a, 0x33, 0x4b, 0xc5, 0x8f, 0x60, 0x96, - 0xf8, 0x48, 0x3a, 0x98, 0xbf, 0x3b, 0xb0, 0x96, 0xa8, 0x95, 0xb4, 0x31, 0xf1, 0xc5, 0xd5, 0x42, - 0x6f, 0x03, 0x74, 0xc3, 0x20, 0xa0, 0x5d, 0x6e, 0x86, 0x83, 0x79, 0x35, 0x37, 0x85, 0xba, 0xdf, - 0xb0, 0xee, 0x73, 0x1d, 0x16, 0xc2, 0x21, 0x8f, 0x86, 0x5c, 0x87, 0xa4, 0x5e, 0x5d, 0xd8, 0x0d, - 0x5b, 0x3f, 0xae, 0x42, 0xc5, 0xcc, 0x71, 0xe8, 0xeb, 0x50, 0xdd, 0xa7, 0x5c, 0xff, 0xc2, 0xf5, - 0x99, 0x73, 0x46, 0x64, 0x15, 0x40, 0x9f, 0xcd, 0x35, 0x48, 0xa3, 0xfe, 0x8c, 0xa1, 0x11, 0x6d, - 0x5a, 0xe7, 0x33, 0x11, 0x89, 0xa4, 0xd7, 0x72, 0x20, 0xb5, 0xb4, 0x6f, 0xcd, 0x9b, 0x58, 0xd0, - 0x0d, 0x8b, 0xd1, 0x6c, 0x58, 0x22, 0xb7, 0x95, 0x17, 0xae, 0x85, 0x0f, 0x67, 0x4f, 0x1c, 0xe8, - 0xf5, 0x0c, 0x5e, 0x93, 0xa0, 0x44, 0xf0, 0x1b, 0xf9, 0xc0, 0x5a, 0xac, 0x9f, 0x3d, 0xb8, 0xa2, - 0x0d, 0x8b, 0x4b, 0x16, 0x20, 0x11, 0xb7, 0x79, 0x3e, 0x50, 0x8b, 0xba, 0x6b, 0x0d, 0x26, 0xe8, - 0x15, 0xeb, 0x58, 0xb2, 0x9b, 0x30, 0x7d, 0x75, 0x06, 0x55, 0x73, 0xfa, 0xda, 0xf8, 0x98, 0x80, - 0x3e, 0x69, 0x0f, 0xc4, 0x16, 0x21, 0xe1, 0xb7, 0x3e, 0x1b, 0xa0, 0x59, 0x76, 0xb3, 0x5a, 0x6a, - 0x64, 0x87, 0xe9, 0x34, 0x39, 0x61, 0xff, 0xb9, 0xf3, 0x60, 0x5a, 0xc8, 0x71, 0x66, 0x03, 0x86, - 0xec, 0xe3, 0x19, 0xf4, 0x44, 0xcc, 0xc6, 0xb9, 0xb8, 0x54, 0x4e, 0xc6, 0xb3, 0x38, 0x26, 0x27, - 0xeb, 0xd9, 0xcc, 0x92, 0x93, 0x8d, 0xd3, 0x72, 0x1e, 0x4f, 0xbe, 0x84, 0xe8, 0x53, 0x13, 0x86, - 0x4e, 0x49, 0x09, 0xf7, 0xe6, 0x3c, 0x88, 0x66, 0xfc, 0x45, 0xf5, 0xfb, 0x3f, 0x1a, 0xfb, 0xf9, - 0x94, 0x87, 0x51, 0xc2, 0xa4, 0x31, 0x4d, 0x50, 0x47, 0xb7, 0xbe, 0x57, 0x84, 0x9a, 0xf5, 0x30, - 0xa0, 0x0f, 0xec, 0xe2, 0xb4, 0x91, 0x51, 0x76, 0xec, 0x37, 0x2e, 0x33, 0xaa, 0x67, 0x00, 0xb5, - 0xaa, 0x67, 0x73, 0xde, 0x23, 0x94, 0x95, 0x8b, 0x53, 0xa8, 0x44, 0xe8, 0x8d, 0x9c, 0x68, 0x2d, - 0xf9, 0x49, 0xc6, 0x53, 0x33, 0x56, 0x7e, 0xa7, 0xa8, 0x99, 0xe5, 0x37, 0x0b, 0xa5, 0x24, 0xbc, - 0xe9, 0x5c, 0xc2, 0x11, 0x4f, 0x16, 0xe4, 0x1f, 0x7b, 0xb7, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, - 0x8a, 0x61, 0xfa, 0xcc, 0xeb, 0x1b, 0x00, 0x00, + // 2010 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0xcd, 0x6f, 0x23, 0x49, + 0x15, 0x9f, 0x6e, 0xdb, 0x89, 0xfd, 0xec, 0x49, 0x3a, 0x35, 0x1f, 0x98, 0xde, 0x0f, 0x82, 0x61, + 0x49, 0x96, 0xdd, 0xf1, 0xac, 0x32, 0x30, 0xbb, 0x84, 0xd1, 0x6a, 0xb3, 0x49, 0xc8, 0x44, 0x33, + 0xf1, 0x84, 0xf2, 0xcc, 0x04, 0x09, 0x69, 0xad, 0x1a, 0x77, 0xc5, 0xd3, 0xc4, 0xee, 0xee, 0xad, + 0x2e, 0x67, 0x62, 0x71, 0x44, 0x70, 0x46, 0xa0, 0x85, 0x03, 0x70, 0x81, 0x03, 0xe2, 0xc4, 0x0d, + 0xf1, 0x75, 0xe1, 0xce, 0x81, 0x3b, 0xdc, 0x56, 0x1c, 0xb9, 0xf0, 0x17, 0xa0, 0xaa, 0xae, 0xee, + 0x2e, 0xdb, 0xed, 0xa4, 0x93, 0xec, 0x0a, 0xed, 0xad, 0xeb, 0xbd, 0x5f, 0xbd, 0xf7, 0xea, 0xbd, + 0x5f, 0xbd, 0xaa, 0xb2, 0x61, 0x91, 0x1f, 0x06, 0xfd, 0x61, 0xcf, 0xf5, 0xbe, 0xde, 0x0c, 0x98, + 0xcf, 0x7d, 0x54, 0x49, 0x04, 0x8d, 0x7b, 0x50, 0xdb, 0x1a, 0x79, 0x64, 0xe0, 0x76, 0x9f, 0x92, + 0xfe, 0x90, 0xa2, 0x3a, 0xcc, 0x0f, 0xc2, 0x5e, 0x40, 0xba, 0x47, 0x75, 0x63, 0xd9, 0x58, 0xad, + 0xe1, 0x78, 0x88, 0x10, 0x14, 0xbf, 0x17, 0xfa, 0x5e, 0xdd, 0x94, 0x62, 0xf9, 0xdd, 0xf8, 0xd8, + 0x00, 0xd8, 0x72, 0x49, 0xcf, 0xf3, 0x43, 0xee, 0x76, 0xd1, 0x3a, 0x94, 0x43, 0x7a, 0x4c, 0x99, + 0xcb, 0x47, 0x72, 0xf6, 0xc2, 0xda, 0xab, 0xcd, 0xd4, 0x77, 0x0a, 0x6c, 0xb6, 0x15, 0x0a, 0x27, + 0x78, 0xe1, 0x38, 0x1c, 0x0e, 0x06, 0x84, 0x8d, 0xa4, 0x87, 0x0a, 0x8e, 0x87, 0xe8, 0x26, 0xcc, + 0x39, 0x94, 0x13, 0xb7, 0x5f, 0x2f, 0x48, 0x85, 0x1a, 0xa1, 0xbb, 0x50, 0x21, 0x9c, 0x33, 0xf7, + 0xd9, 0x90, 0xd3, 0x7a, 0x71, 0xd9, 0x58, 0xad, 0xae, 0xd5, 0x35, 0x77, 0x1b, 0xb1, 0x6e, 0x9f, + 0xf0, 0xe7, 0x38, 0x85, 0x36, 0x6e, 0x43, 0x39, 0xf6, 0x8f, 0xaa, 0x30, 0xbf, 0xdb, 0x7a, 0xba, + 0xf1, 0x70, 0x77, 0xcb, 0xba, 0x82, 0x2a, 0x50, 0xda, 0xc6, 0xf8, 0x11, 0xb6, 0x0c, 0x21, 0x3f, + 0xd8, 0xc0, 0xad, 0xdd, 0xd6, 0x8e, 0x65, 0x36, 0xfe, 0x65, 0xc0, 0xd5, 0x31, 0x6b, 0xe8, 0x0e, + 0x94, 0x42, 0x4e, 0x83, 0xb0, 0x6e, 0x2c, 0x17, 0x56, 0xab, 0x6b, 0xaf, 0xcc, 0x72, 0xdb, 0x6c, + 0x73, 0x1a, 0xe0, 0x08, 0x6b, 0x7f, 0x64, 0x40, 0x51, 0x8c, 0xd1, 0x0a, 0x2c, 0x24, 0xd1, 0x74, + 0x3c, 0x32, 0xa0, 0x32, 0x59, 0x95, 0xfb, 0x57, 0xf0, 0xd5, 0x44, 0xde, 0x22, 0x03, 0x8a, 0x9a, + 0x80, 0x68, 0x9f, 0x0e, 0xa8, 0xc7, 0x3b, 0x47, 0x74, 0xd4, 0x09, 0x39, 0x73, 0xbd, 0x5e, 0x94, + 0x9e, 0xfb, 0x57, 0xb0, 0xa5, 0x74, 0x0f, 0xe8, 0xa8, 0x2d, 0x35, 0x68, 0x15, 0x16, 0x75, 0xbc, + 0xeb, 0x71, 0x99, 0xb2, 0x82, 0xb0, 0x9c, 0x82, 0x77, 0x3d, 0xfe, 0x3e, 0x88, 0x4a, 0xf5, 0x69, + 0x97, 0xfb, 0xac, 0x71, 0x47, 0x84, 0xe5, 0x07, 0x76, 0x05, 0xe6, 0x31, 0xfd, 0x70, 0x48, 0x43, + 0x6e, 0x2f, 0x43, 0x19, 0xd3, 0x30, 0xf0, 0xbd, 0x90, 0xa2, 0xeb, 0x50, 0xda, 0x66, 0xcc, 0x67, + 0x51, 0x90, 0x38, 0x1a, 0x34, 0x7e, 0x66, 0x40, 0x19, 0x93, 0x17, 0x6d, 0x4e, 0x38, 0x4d, 0xa8, + 0x61, 0xa4, 0xd4, 0x40, 0xeb, 0x30, 0x7f, 0xd8, 0x27, 0x7c, 0x40, 0x82, 0xba, 0x29, 0x93, 0xb4, + 0xac, 0x25, 0x29, 0x9e, 0xd9, 0xfc, 0x56, 0x04, 0xd9, 0xf6, 0x38, 0x1b, 0xe1, 0x78, 0x82, 0xbd, + 0x0e, 0x35, 0x5d, 0x81, 0x2c, 0x28, 0x1c, 0xd1, 0x91, 0x0a, 0x40, 0x7c, 0x8a, 0xa0, 0x8e, 0x05, + 0x5f, 0x15, 0x57, 0xa2, 0xc1, 0xba, 0xf9, 0x8e, 0xd1, 0xf8, 0xfb, 0x3c, 0xcc, 0xb5, 0xbb, 0xcf, + 0xe9, 0x80, 0x08, 0x4a, 0x1d, 0x53, 0x16, 0xba, 0x2a, 0xb2, 0x02, 0x8e, 0x87, 0xe8, 0x16, 0x94, + 0x9e, 0xf5, 0xfd, 0xee, 0x91, 0x9c, 0x5e, 0x5d, 0xfb, 0x9c, 0x16, 0x5a, 0x34, 0xb7, 0xf9, 0xbe, + 0x50, 0xe3, 0x08, 0x65, 0xff, 0xda, 0x84, 0x92, 0x14, 0x9c, 0x62, 0xf2, 0x9b, 0x00, 0x49, 0xf1, + 0x42, 0xb5, 0xe4, 0x97, 0xa6, 0xed, 0x26, 0xf4, 0xc0, 0x1a, 0x1c, 0xbd, 0x0b, 0x55, 0xe9, 0xa9, + 0xc3, 0x47, 0x01, 0x0d, 0xeb, 0x85, 0x29, 0x56, 0xa9, 0xd9, 0x2d, 0x1a, 0x72, 0xea, 0x44, 0xb1, + 0x81, 0x9c, 0xf1, 0x58, 0x4c, 0x40, 0xcb, 0x50, 0x75, 0x68, 0xd8, 0x65, 0x6e, 0xc0, 0x45, 0x68, + 0x45, 0x99, 0x14, 0x5d, 0x84, 0xde, 0x03, 0x4b, 0x1b, 0x76, 0x8e, 0x5c, 0xcf, 0xa9, 0x97, 0xe4, + 0x16, 0xbd, 0xa1, 0xbb, 0x91, 0x3c, 0x7a, 0xe0, 0x7a, 0x0e, 0x5e, 0xd4, 0xe0, 0x42, 0x80, 0x5e, + 0x05, 0x70, 0x68, 0xc0, 0x68, 0x97, 0x70, 0xea, 0xd4, 0xe7, 0x96, 0x8d, 0xd5, 0x32, 0xd6, 0x24, + 0xf6, 0xef, 0x4c, 0xa8, 0x24, 0xab, 0x13, 0x94, 0x48, 0x99, 0x8d, 0xe5, 0xb7, 0x90, 0x89, 0xf5, + 0xc5, 0x1d, 0x44, 0x7c, 0x4f, 0x46, 0x5e, 0x98, 0x8e, 0xdc, 0x86, 0x32, 0xa3, 0x1f, 0x0e, 0x5d, + 0x46, 0x1d, 0xb9, 0xb0, 0x32, 0x4e, 0xc6, 0x42, 0xe7, 0x4b, 0x14, 0xe9, 0xcb, 0xd5, 0x94, 0x71, + 0x32, 0x16, 0xba, 0xae, 0x3f, 0x08, 0x86, 0x69, 0xb4, 0xc9, 0x18, 0xbd, 0x0c, 0x95, 0x90, 0x7a, + 0xa1, 0xcb, 0xdd, 0x63, 0x5a, 0x9f, 0x97, 0xca, 0x54, 0x90, 0x99, 0xab, 0xf2, 0x25, 0x72, 0x55, + 0x99, 0xca, 0xd5, 0x6f, 0x4d, 0xa8, 0x6a, 0xb5, 0x44, 0x2f, 0x41, 0x45, 0x64, 0x43, 0x6b, 0x06, + 0xb8, 0x2c, 0x04, 0xb2, 0x0b, 0x9c, 0x8f, 0xac, 0x68, 0x13, 0xe6, 0x3d, 0x1a, 0x72, 0xd1, 0x29, + 0x0a, 0x32, 0xe8, 0xd7, 0x4f, 0xe5, 0x91, 0xfc, 0x76, 0xbd, 0xde, 0x9e, 0xef, 0x50, 0x1c, 0xcf, + 0x14, 0x01, 0x0d, 0x5c, 0xaf, 0xe3, 0x72, 0x3a, 0x08, 0x65, 0xd6, 0x0b, 0xb8, 0x3c, 0x70, 0xbd, + 0x5d, 0x31, 0x96, 0x4a, 0x72, 0xa2, 0x94, 0x25, 0xa5, 0x24, 0x27, 0x52, 0xd9, 0xd8, 0x8b, 0x56, + 0xa6, 0x2c, 0x8e, 0x37, 0x58, 0x80, 0xb9, 0xf6, 0x6e, 0x6b, 0xe7, 0xe1, 0xb6, 0x65, 0xa0, 0x32, + 0x14, 0x1f, 0xee, 0xb6, 0x1f, 0x5b, 0x26, 0x9a, 0x87, 0x42, 0x7b, 0xfb, 0xb1, 0x55, 0x10, 0x1f, + 0x7b, 0x1b, 0xfb, 0x56, 0x51, 0x34, 0xe2, 0x1d, 0xfc, 0xe8, 0xc9, 0xbe, 0x55, 0x6a, 0xfc, 0xa3, + 0x08, 0x4b, 0x3b, 0x94, 0xef, 0x33, 0xff, 0xd8, 0x75, 0x28, 0x8b, 0xe2, 0xd7, 0x5b, 0xd5, 0xef, + 0x8b, 0x5a, 0xaf, 0xba, 0x05, 0xe5, 0x40, 0x21, 0x65, 0x1a, 0xab, 0x6b, 0x4b, 0x53, 0x8b, 0xc7, + 0x09, 0x04, 0x51, 0xb0, 0x18, 0x0d, 0xfd, 0x21, 0xeb, 0xd2, 0x4e, 0x28, 0x95, 0xf1, 0xce, 0x5d, + 0xd7, 0xa6, 0x4d, 0xb9, 0x6f, 0xc6, 0xfe, 0xc4, 0x87, 0x9c, 0x1d, 0xc9, 0xc3, 0xa8, 0x8d, 0x2d, + 0xb2, 0x71, 0x29, 0xea, 0xc3, 0x35, 0x87, 0x70, 0xd2, 0x99, 0xf0, 0x14, 0xed, 0xf2, 0x7b, 0xf9, + 0x3c, 0x6d, 0x11, 0x4e, 0xda, 0xd3, 0xbe, 0x96, 0x9c, 0x49, 0x39, 0x7a, 0x1b, 0xaa, 0x4e, 0x72, + 0xd2, 0x8a, 0xe2, 0x09, 0x2f, 0x37, 0x32, 0xcf, 0x61, 0xac, 0x23, 0xd1, 0x5d, 0xb8, 0x1a, 0x67, + 0xa6, 0x33, 0xa0, 0x9c, 0xc8, 0xd2, 0x66, 0x66, 0xb0, 0x16, 0xe3, 0xf6, 0x28, 0x27, 0xf6, 0x13, + 0xb8, 0x9e, 0x95, 0x87, 0x8c, 0xae, 0xbd, 0xa2, 0x77, 0xed, 0x4c, 0xcb, 0x69, 0x23, 0xb7, 0x0f, + 0xe0, 0x66, 0xf6, 0xa2, 0x2f, 0x69, 0xb8, 0xf1, 0x4f, 0x03, 0x6e, 0xec, 0x33, 0x1a, 0x10, 0x46, + 0xe3, 0x6c, 0x6f, 0xfa, 0xde, 0xa1, 0xdb, 0xb3, 0xd7, 0x13, 0x5a, 0xa1, 0xdb, 0x30, 0xd7, 0x95, + 0x42, 0xc5, 0x23, 0x7d, 0xd7, 0xe9, 0x17, 0x26, 0xac, 0x60, 0xf6, 0x0f, 0x0d, 0x8d, 0x87, 0xef, + 0xc1, 0x62, 0x10, 0x79, 0x70, 0x3a, 0xf9, 0xcc, 0x2c, 0xc4, 0xf8, 0x28, 0x94, 0xc9, 0x2a, 0x9a, + 0x79, 0xab, 0xd8, 0xf8, 0xb1, 0x09, 0xd7, 0x9f, 0x04, 0x3d, 0x46, 0x1c, 0x9a, 0x54, 0x45, 0x1c, + 0xb5, 0x36, 0x4b, 0x17, 0x77, 0x6a, 0xbb, 0xd1, 0x8e, 0x38, 0x73, 0xfc, 0x88, 0x7b, 0x0b, 0x2a, + 0x8c, 0xbc, 0xe8, 0x84, 0xc2, 0x9c, 0xec, 0x2d, 0xd5, 0xb5, 0x6b, 0x19, 0x87, 0x3a, 0x2e, 0x33, + 0xf5, 0x65, 0xff, 0x40, 0x4f, 0xca, 0xbb, 0xb0, 0x30, 0x8c, 0x02, 0x73, 0x94, 0x8d, 0x33, 0x72, + 0x72, 0x35, 0x86, 0x47, 0xb7, 0x8c, 0x0b, 0xa7, 0xe4, 0xcf, 0x06, 0xd8, 0x4f, 0x49, 0xdf, 0x75, + 0x44, 0x70, 0x2a, 0x27, 0xe2, 0xdc, 0x54, 0x55, 0x3f, 0xc8, 0x99, 0x98, 0x94, 0x12, 0x66, 0x3e, + 0x4a, 0x6c, 0x6a, 0x8b, 0x9f, 0x08, 0xde, 0xc8, 0x1d, 0xfc, 0x1f, 0x0d, 0xa8, 0xc7, 0xc1, 0xa7, + 0xfb, 0xe1, 0x33, 0x11, 0xfa, 0x9f, 0x0c, 0xa8, 0x44, 0x81, 0x0e, 0x19, 0xb5, 0x7b, 0x69, 0xac, + 0x6f, 0xc0, 0x12, 0xa7, 0x8c, 0x91, 0x43, 0x9f, 0x0d, 0x3a, 0xfa, 0x7d, 0xaa, 0x82, 0xad, 0x44, + 0xf1, 0x54, 0xb1, 0xee, 0xff, 0x13, 0xfb, 0xc7, 0x26, 0xd4, 0x30, 0x25, 0x4e, 0xcc, 0x17, 0xfb, + 0xaf, 0x46, 0xce, 0x5c, 0xdf, 0x83, 0xab, 0xdd, 0x21, 0x63, 0xe2, 0x12, 0x1e, 0xb1, 0xfc, 0x8c, + 0xb0, 0x6b, 0x0a, 0x1d, 0x91, 0xbc, 0x0e, 0xf3, 0x01, 0x73, 0x8f, 0xe3, 0x1d, 0x56, 0xc3, 0xf1, + 0x50, 0xd8, 0x1d, 0x6f, 0xcf, 0xc5, 0x33, 0xec, 0x8e, 0x35, 0xe9, 0x9f, 0xea, 0x3b, 0xf1, 0x6b, + 0x50, 0xf1, 0xe8, 0x8b, 0x7c, 0x9b, 0xb0, 0xec, 0xd1, 0x17, 0x97, 0xdb, 0x7f, 0xb3, 0xd7, 0xd4, + 0xf8, 0x6f, 0x11, 0xd0, 0x7e, 0x9f, 0x78, 0x71, 0x96, 0x37, 0x9f, 0x13, 0xaf, 0x47, 0xed, 0xbf, + 0x98, 0x39, 0x73, 0xfd, 0x0e, 0x54, 0x03, 0xe6, 0xfa, 0x2c, 0x5f, 0xa6, 0x41, 0x62, 0xa3, 0xc5, + 0x6c, 0x03, 0x0a, 0x98, 0x1f, 0xf8, 0x21, 0x75, 0x3a, 0x69, 0x2e, 0x0a, 0xa7, 0x1b, 0xb0, 0xe2, + 0x29, 0xad, 0x38, 0x27, 0x29, 0x39, 0x8b, 0xb9, 0xc8, 0x89, 0xbe, 0x24, 0xaa, 0x28, 0x22, 0x8e, + 0x33, 0x52, 0x92, 0x19, 0xa9, 0x49, 0xe1, 0xfe, 0xac, 0x52, 0xcf, 0x9d, 0xa7, 0xd4, 0xbf, 0x32, + 0xb5, 0x52, 0x0b, 0x53, 0x7d, 0xe2, 0x79, 0x79, 0x7b, 0x6e, 0x4d, 0xa1, 0xa3, 0xe5, 0x6d, 0x8a, + 0x0b, 0x92, 0xbc, 0x6b, 0x87, 0x1d, 0x46, 0x83, 0x3e, 0xe9, 0x52, 0x55, 0xf7, 0xd9, 0x2f, 0xed, + 0xc5, 0x78, 0x06, 0x8e, 0x26, 0xa0, 0x15, 0x58, 0x8c, 0x43, 0x18, 0xa7, 0xc1, 0x82, 0x12, 0xc7, + 0xcb, 0xbe, 0xf0, 0xcd, 0xe5, 0x4d, 0x40, 0x7d, 0xda, 0x23, 0xdd, 0x91, 0x7c, 0x3f, 0x75, 0xc2, + 0x51, 0xc8, 0xe9, 0x40, 0x3d, 0x08, 0xac, 0x48, 0x23, 0xfa, 0x7d, 0x5b, 0xca, 0x1b, 0x3f, 0x29, + 0xc2, 0xb5, 0x8d, 0x20, 0xe8, 0x8f, 0x26, 0x58, 0xf7, 0x87, 0x4f, 0x9f, 0x75, 0x53, 0xd5, 0x28, + 0x9c, 0xa7, 0x1a, 0xe7, 0x26, 0x5b, 0x46, 0xe6, 0x4b, 0x99, 0x99, 0xbf, 0x1c, 0xe1, 0xfe, 0x76, + 0xf9, 0xde, 0xa2, 0xb5, 0x08, 0x73, 0xbc, 0xed, 0x4d, 0x90, 0xa2, 0x70, 0x49, 0x52, 0x14, 0x67, + 0x90, 0xe2, 0x3f, 0x26, 0x5c, 0xdb, 0x1d, 0x04, 0x3e, 0xe3, 0xe3, 0xb7, 0xa6, 0xbb, 0x39, 0x39, + 0xb1, 0x00, 0xa6, 0xeb, 0xa8, 0x5f, 0x23, 0x4c, 0xd7, 0xb1, 0x4f, 0xc0, 0x8a, 0xcc, 0xd1, 0xe4, + 0x08, 0x39, 0xf3, 0x95, 0x97, 0x8b, 0x4e, 0x11, 0x6a, 0x76, 0x4f, 0xb5, 0x7f, 0xa3, 0x57, 0xe3, + 0x03, 0x40, 0xae, 0x0a, 0xa3, 0x13, 0x3f, 0x4b, 0xe2, 0x63, 0xf0, 0xb6, 0xe6, 0x22, 0x63, 0xe9, + 0xcd, 0xc9, 0xf8, 0xf1, 0x92, 0x3b, 0x21, 0x09, 0x2f, 0x7e, 0x27, 0xfb, 0xa5, 0x09, 0x0b, 0xe2, + 0x7c, 0x4d, 0xaf, 0x34, 0xf6, 0x47, 0xc6, 0xa7, 0x74, 0x9b, 0x99, 0xa6, 0x77, 0xe1, 0x3c, 0xf4, + 0x66, 0x63, 0x0f, 0xcc, 0x52, 0x2e, 0x66, 0xab, 0x2a, 0x5d, 0x38, 0x3d, 0xbf, 0x30, 0xe0, 0x7a, + 0xfc, 0x1a, 0x14, 0xb7, 0xa0, 0xac, 0x97, 0xef, 0x89, 0x16, 0xd7, 0x1d, 0xd1, 0x92, 0x12, 0xec, + 0xec, 0xb7, 0xaf, 0x8e, 0xba, 0x44, 0xf1, 0x0c, 0xf8, 0x7c, 0x7c, 0x27, 0xd5, 0x42, 0xfc, 0x04, + 0x5e, 0x51, 0x9f, 0xc8, 0xdd, 0xed, 0xdf, 0x06, 0x2c, 0x25, 0x61, 0x25, 0x17, 0xb8, 0xf0, 0xe2, + 0x61, 0xa1, 0xb7, 0x01, 0xba, 0xbe, 0xe7, 0xd1, 0x2e, 0x8f, 0x9f, 0x45, 0xa7, 0x35, 0xfc, 0x14, + 0x6a, 0x7f, 0x57, 0x5b, 0xcf, 0x4d, 0x98, 0xf3, 0x87, 0x3c, 0x18, 0x72, 0x45, 0x68, 0x35, 0xba, + 0x70, 0x19, 0xbe, 0xfa, 0x1a, 0x40, 0xfa, 0x23, 0x14, 0xaa, 0x40, 0x69, 0xff, 0xe1, 0xc6, 0x6e, + 0xcb, 0xba, 0x82, 0x6a, 0x50, 0xde, 0xdb, 0xc0, 0x0f, 0xb6, 0x1e, 0x1d, 0xb4, 0x2c, 0x63, 0xed, + 0xe7, 0x15, 0x28, 0xc7, 0x0f, 0x5d, 0xf4, 0x1d, 0xa8, 0xec, 0x50, 0xae, 0x7e, 0x20, 0xfd, 0xf2, + 0x19, 0xbf, 0x3d, 0x44, 0x3c, 0x7b, 0x2d, 0xd7, 0x2f, 0x14, 0xa8, 0x3f, 0xe3, 0x55, 0x8d, 0x56, + 0xb5, 0xf9, 0x99, 0x88, 0xc4, 0xd3, 0xeb, 0x39, 0x90, 0xca, 0xdb, 0xf7, 0x4f, 0x7b, 0xd2, 0xa1, + 0x5b, 0x9a, 0xa1, 0xd9, 0xb0, 0xc4, 0x6f, 0x33, 0x2f, 0x5c, 0x39, 0x1f, 0xce, 0x7e, 0x92, 0xa1, + 0x37, 0x32, 0x6c, 0x4d, 0x82, 0x12, 0xc7, 0x6f, 0xe6, 0x03, 0x2b, 0xb7, 0x6e, 0xf6, 0xcb, 0x1e, + 0xad, 0x68, 0x56, 0xb2, 0x00, 0x89, 0xbb, 0xd5, 0xb3, 0x81, 0xca, 0xd5, 0x7d, 0xed, 0xe5, 0x86, + 0x5e, 0xd6, 0xa6, 0x25, 0xd2, 0xc4, 0xe8, 0x2b, 0x33, 0xb4, 0xca, 0xd2, 0xb7, 0xc7, 0xdf, 0x51, + 0xe8, 0x0b, 0xfa, 0x2f, 0x06, 0x9a, 0x22, 0xb1, 0xb7, 0x3c, 0x1b, 0xa0, 0x4c, 0x76, 0xb3, 0x1e, + 0x0d, 0x48, 0xa7, 0xe9, 0xb4, 0x3a, 0x31, 0xff, 0x95, 0xb3, 0x60, 0xca, 0xc9, 0x61, 0xe6, 0x25, + 0x11, 0xe9, 0xd3, 0x33, 0xf4, 0x89, 0x9b, 0x95, 0x33, 0x71, 0xa9, 0x9f, 0x8c, 0xc3, 0x77, 0xcc, + 0x4f, 0xd6, 0xe1, 0x9c, 0xe5, 0x27, 0x1b, 0xa7, 0xfc, 0x1c, 0x4c, 0x9e, 0xb7, 0xe8, 0x8b, 0x13, + 0x89, 0x4e, 0x55, 0x89, 0xf5, 0xc6, 0x69, 0x10, 0x65, 0xf8, 0x1b, 0xd1, 0xdf, 0x47, 0x68, 0xec, + 0x77, 0x69, 0xee, 0x07, 0x89, 0x91, 0xfa, 0xb4, 0x22, 0x9a, 0xba, 0xf6, 0xa3, 0x02, 0x54, 0xb5, + 0xf3, 0x03, 0x7d, 0xa0, 0x37, 0xa7, 0x95, 0x8c, 0xb6, 0xa3, 0x1f, 0x85, 0x99, 0xac, 0x9e, 0x01, + 0x54, 0xa1, 0x9e, 0x9c, 0x72, 0x6c, 0xa1, 0xac, 0xbd, 0x38, 0x85, 0x4a, 0x9c, 0xde, 0xca, 0x89, + 0x56, 0x9e, 0x9f, 0x65, 0x9c, 0x48, 0x63, 0xed, 0x77, 0x4a, 0x9b, 0xd9, 0x7e, 0xb3, 0x50, 0x91, + 0x87, 0xb7, 0x8c, 0x4b, 0x14, 0xe2, 0xd9, 0x9c, 0xfc, 0x5f, 0xf8, 0xce, 0xff, 0x02, 0x00, 0x00, + 0xff, 0xff, 0xe3, 0x8e, 0xe1, 0x22, 0x2a, 0x1e, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/internal/tfplugin5/tfplugin5.proto b/internal/tfplugin5/tfplugin5.proto index 0837e1d4a..2c3d0a477 120000 --- a/internal/tfplugin5/tfplugin5.proto +++ b/internal/tfplugin5/tfplugin5.proto @@ -1 +1 @@ -../../docs/plugin-protocol/tfplugin5.1.proto \ No newline at end of file +../../docs/plugin-protocol/tfplugin5.2.proto \ No newline at end of file diff --git a/plugin/convert/schema.go b/plugin/convert/schema.go index 6a45f54c9..a206ef9af 100644 --- a/plugin/convert/schema.go +++ b/plugin/convert/schema.go @@ -13,17 +13,24 @@ import ( // ConfigSchemaToProto takes a *configschema.Block and converts it to a // proto.Schema_Block for a grpc response. func ConfigSchemaToProto(b *configschema.Block) *proto.Schema_Block { - block := &proto.Schema_Block{} + block := &proto.Schema_Block{ + Description: b.Description, + DescriptionKind: protoStringKind(b.DescriptionKind), + Deprecated: b.Deprecated, + } for _, name := range sortedKeys(b.Attributes) { a := b.Attributes[name] + attr := &proto.Schema_Attribute{ - Name: name, - Description: a.Description, - Optional: a.Optional, - Computed: a.Computed, - Required: a.Required, - Sensitive: a.Sensitive, + Name: name, + Description: a.Description, + DescriptionKind: protoStringKind(a.DescriptionKind), + Optional: a.Optional, + Computed: a.Computed, + Required: a.Required, + Sensitive: a.Sensitive, + Deprecated: a.Deprecated, } ty, err := json.Marshal(a.Type) @@ -44,6 +51,15 @@ func ConfigSchemaToProto(b *configschema.Block) *proto.Schema_Block { return block } +func protoStringKind(k configschema.StringKind) proto.StringKind { + switch k { + default: + return proto.StringKind_PLAIN + case configschema.StringMarkdown: + return proto.StringKind_MARKDOWN + } +} + func protoSchemaNestedBlock(name string, b *configschema.NestedBlock) *proto.Schema_NestedBlock { var nesting proto.Schema_NestedBlock_NestingMode switch b.Nesting { @@ -83,15 +99,21 @@ func ProtoToConfigSchema(b *proto.Schema_Block) *configschema.Block { block := &configschema.Block{ Attributes: make(map[string]*configschema.Attribute), BlockTypes: make(map[string]*configschema.NestedBlock), + + Description: b.Description, + DescriptionKind: schemaStringKind(b.DescriptionKind), + Deprecated: b.Deprecated, } for _, a := range b.Attributes { attr := &configschema.Attribute{ - Description: a.Description, - Required: a.Required, - Optional: a.Optional, - Computed: a.Computed, - Sensitive: a.Sensitive, + Description: a.Description, + DescriptionKind: schemaStringKind(a.DescriptionKind), + Required: a.Required, + Optional: a.Optional, + Computed: a.Computed, + Sensitive: a.Sensitive, + Deprecated: a.Deprecated, } if err := json.Unmarshal(a.Type, &attr.Type); err != nil { @@ -108,6 +130,15 @@ func ProtoToConfigSchema(b *proto.Schema_Block) *configschema.Block { return block } +func schemaStringKind(k proto.StringKind) configschema.StringKind { + switch k { + default: + return configschema.StringPlain + case proto.StringKind_MARKDOWN: + return configschema.StringMarkdown + } +} + func schemaNestedBlock(b *proto.Schema_NestedBlock) *configschema.NestedBlock { var nesting configschema.NestingMode switch b.Nesting { diff --git a/plugin/grpc_provider.go b/plugin/grpc_provider.go index 1abdbe297..3f29e0f10 100644 --- a/plugin/grpc_provider.go +++ b/plugin/grpc_provider.go @@ -105,6 +105,13 @@ func (p *GRPCProvider) getDatasourceSchema(name string) providers.Schema { return dataSchema } +// getProviderMetaSchema is a helper to extract the schema for the meta info +// defined for a provider, +func (p *GRPCProvider) getProviderMetaSchema() providers.Schema { + schema := p.getSchema() + return schema.ProviderMeta +} + func (p *GRPCProvider) GetSchema() (resp providers.GetSchemaResponse) { log.Printf("[TRACE] GRPCProvider: GetSchema") p.mu.Lock() @@ -137,6 +144,11 @@ func (p *GRPCProvider) GetSchema() (resp providers.GetSchemaResponse) { } resp.Provider = convert.ProtoToProviderSchema(protoResp.Provider) + if protoResp.ProviderMeta == nil { + log.Printf("[TRACE] No provider meta schema returned") + } else { + resp.ProviderMeta = convert.ProtoToProviderSchema(protoResp.ProviderMeta) + } for name, res := range protoResp.ResourceSchemas { resp.ResourceTypes[name] = convert.ProtoToProviderSchema(res) @@ -319,6 +331,7 @@ func (p *GRPCProvider) ReadResource(r providers.ReadResourceRequest) (resp provi log.Printf("[TRACE] GRPCProvider: ReadResource") resSchema := p.getResourceSchema(r.TypeName) + metaSchema := p.getProviderMetaSchema() mp, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType()) if err != nil { @@ -332,6 +345,15 @@ func (p *GRPCProvider) ReadResource(r providers.ReadResourceRequest) (resp provi Private: r.Private, } + if metaSchema.Block != nil { + metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType()) + if err != nil { + resp.Diagnostics = resp.Diagnostics.Append(err) + return resp + } + protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP} + } + protoResp, err := p.client.ReadResource(p.ctx, protoReq) if err != nil { resp.Diagnostics = resp.Diagnostics.Append(err) @@ -357,6 +379,7 @@ func (p *GRPCProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) log.Printf("[TRACE] GRPCProvider: PlanResourceChange") resSchema := p.getResourceSchema(r.TypeName) + metaSchema := p.getProviderMetaSchema() priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType()) if err != nil { @@ -384,6 +407,15 @@ func (p *GRPCProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) PriorPrivate: r.PriorPrivate, } + if metaSchema.Block != nil { + metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType()) + if err != nil { + resp.Diagnostics = resp.Diagnostics.Append(err) + return resp + } + protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP} + } + protoResp, err := p.client.PlanResourceChange(p.ctx, protoReq) if err != nil { resp.Diagnostics = resp.Diagnostics.Append(err) @@ -416,6 +448,7 @@ func (p *GRPCProvider) ApplyResourceChange(r providers.ApplyResourceChangeReques log.Printf("[TRACE] GRPCProvider: ApplyResourceChange") resSchema := p.getResourceSchema(r.TypeName) + metaSchema := p.getProviderMetaSchema() priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType()) if err != nil { @@ -441,6 +474,15 @@ func (p *GRPCProvider) ApplyResourceChange(r providers.ApplyResourceChangeReques PlannedPrivate: r.PlannedPrivate, } + if metaSchema.Block != nil { + metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType()) + if err != nil { + resp.Diagnostics = resp.Diagnostics.Append(err) + return resp + } + protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP} + } + protoResp, err := p.client.ApplyResourceChange(p.ctx, protoReq) if err != nil { resp.Diagnostics = resp.Diagnostics.Append(err) @@ -506,6 +548,7 @@ func (p *GRPCProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp p log.Printf("[TRACE] GRPCProvider: ReadDataSource") dataSchema := p.getDatasourceSchema(r.TypeName) + metaSchema := p.getProviderMetaSchema() config, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType()) if err != nil { @@ -520,6 +563,15 @@ func (p *GRPCProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp p }, } + if metaSchema.Block != nil { + metaMP, err := msgpack.Marshal(r.ProviderMeta, metaSchema.Block.ImpliedType()) + if err != nil { + resp.Diagnostics = resp.Diagnostics.Append(err) + return resp + } + protoReq.ProviderMeta = &proto.DynamicValue{Msgpack: metaMP} + } + protoResp, err := p.client.ReadDataSource(p.ctx, protoReq) if err != nil { resp.Diagnostics = resp.Diagnostics.Append(err) diff --git a/plugin/resource_provider.go b/plugin/resource_provider.go index 459661a55..a9d520581 100644 --- a/plugin/resource_provider.go +++ b/plugin/resource_provider.go @@ -3,7 +3,7 @@ package plugin import ( "net/rpc" - "github.com/hashicorp/go-plugin" + plugin "github.com/hashicorp/go-plugin" "github.com/hashicorp/terraform/terraform" ) diff --git a/providers/provider.go b/providers/provider.go index 7e0a74c58..b27e3dbce 100644 --- a/providers/provider.go +++ b/providers/provider.go @@ -73,6 +73,9 @@ type GetSchemaResponse struct { // Provider is the schema for the provider itself. Provider Schema + // ProviderMeta is the schema for the provider's meta info in a module + ProviderMeta Schema + // ResourceTypes map the resource type name to that type's schema. ResourceTypes map[string]Schema @@ -180,6 +183,12 @@ type ReadResourceRequest struct { // Private is an opaque blob that will be stored in state along with the // resource. It is intended only for interpretation by the provider itself. Private []byte + + // ProviderMeta is the configuration for the provider_meta block for the + // module and provider this resource belongs to. Its use is defined by + // each provider, and it should not be used without coordination with + // HashiCorp. It is considered experimental and subject to change. + ProviderMeta cty.Value } type ReadResourceResponse struct { @@ -216,6 +225,12 @@ type PlanResourceChangeRequest struct { // PriorPrivate is the previously saved private data returned from the // provider during the last apply. PriorPrivate []byte + + // ProviderMeta is the configuration for the provider_meta block for the + // module and provider this resource belongs to. Its use is defined by + // each provider, and it should not be used without coordination with + // HashiCorp. It is considered experimental and subject to change. + ProviderMeta cty.Value } type PlanResourceChangeResponse struct { @@ -262,6 +277,12 @@ type ApplyResourceChangeRequest struct { // PlannedPrivate is the same value as returned by PlanResourceChange. PlannedPrivate []byte + + // ProviderMeta is the configuration for the provider_meta block for the + // module and provider this resource belongs to. Its use is defined by + // each provider, and it should not be used without coordination with + // HashiCorp. It is considered experimental and subject to change. + ProviderMeta cty.Value } type ApplyResourceChangeResponse struct { @@ -348,6 +369,12 @@ type ReadDataSourceRequest struct { // Config is the complete configuration for the requested data source. Config cty.Value + + // ProviderMeta is the configuration for the provider_meta block for the + // module and provider this resource belongs to. Its use is defined by + // each provider, and it should not be used without coordination with + // HashiCorp. It is considered experimental and subject to change. + ProviderMeta cty.Value } type ReadDataSourceResponse struct { diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index fc26f446b..44ac90f71 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -29,6 +29,7 @@ import ( "github.com/hashicorp/terraform/states/statefile" "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" + "github.com/zclconf/go-cty/cty/gocty" ) func TestContext2Apply_basic(t *testing.T) { @@ -10174,7 +10175,6 @@ func TestContext2Apply_invalidIndexRef(t *testing.T) { }, ), }) - diags := c.Validate() if diags.HasErrors() { t.Fatalf("unexpected validation failure: %s", diags.Err()) @@ -10741,3 +10741,915 @@ func TestContext2Apply_cbdCycle(t *testing.T) { t.Fatalf("diags: %s", diags.Err()) } } + +func TestContext2Apply_ProviderMeta_apply_set(t *testing.T) { + m := testModule(t, "provider-meta-set") + p := testProvider("test") + p.DiffFn = testDiffFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + arcPMs := map[string]cty.Value{} + p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { + arcPMs[req.TypeName] = req.ProviderMeta + s := req.PlannedState.AsValueMap() + s["id"] = cty.StringVal("ID") + return providers.ApplyResourceChangeResponse{ + NewState: cty.ObjectVal(s), + } + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + + _, diags := ctx.Plan() + assertNoErrors(t, diags) + + _, diags = ctx.Apply() + assertNoErrors(t, diags) + + if !p.ApplyResourceChangeCalled { + t.Fatalf("ApplyResourceChange not called") + } + + expectations := map[string]cty.Value{} + + if pm, ok := arcPMs["test_resource"]; !ok { + t.Fatalf("sub-module ApplyResourceChange not called") + } else if pm.IsNull() { + t.Fatalf("null ProviderMeta in sub-module ApplyResourceChange") + } else { + expectations["quux-submodule"] = pm + } + + if pm, ok := arcPMs["test_instance"]; !ok { + t.Fatalf("root module ApplyResourceChange not called") + } else if pm.IsNull() { + t.Fatalf("null ProviderMeta in root module ApplyResourceChange") + } else { + expectations["quux"] = pm + } + + type metaStruct struct { + Baz string `cty:"baz"` + } + + for expected, v := range expectations { + var meta metaStruct + err := gocty.FromCtyValue(v, &meta) + if err != nil { + t.Fatalf("Error parsing cty value: %s", err) + } + if meta.Baz != expected { + t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz) + } + } +} + +func TestContext2Apply_ProviderMeta_apply_unset(t *testing.T) { + m := testModule(t, "provider-meta-unset") + p := testProvider("test") + p.DiffFn = testDiffFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + arcPMs := map[string]cty.Value{} + p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { + arcPMs[req.TypeName] = req.ProviderMeta + s := req.PlannedState.AsValueMap() + s["id"] = cty.StringVal("ID") + return providers.ApplyResourceChangeResponse{ + NewState: cty.ObjectVal(s), + } + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + + _, diags := ctx.Plan() + assertNoErrors(t, diags) + + _, diags = ctx.Apply() + assertNoErrors(t, diags) + + if !p.ApplyResourceChangeCalled { + t.Fatalf("ApplyResourceChange not called") + } + + if pm, ok := arcPMs["test_resource"]; !ok { + t.Fatalf("sub-module ApplyResourceChange not called") + } else if !pm.IsNull() { + t.Fatalf("non-null ProviderMeta in sub-module ApplyResourceChange: %+v", pm) + } + + if pm, ok := arcPMs["test_instance"]; !ok { + t.Fatalf("root module ApplyResourceChange not called") + } else if !pm.IsNull() { + t.Fatalf("non-null ProviderMeta in root module ApplyResourceChange: %+v", pm) + } +} + +func TestContext2Apply_ProviderMeta_plan_set(t *testing.T) { + m := testModule(t, "provider-meta-set") + p := testProvider("test") + p.ApplyFn = testApplyFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + prcPMs := map[string]cty.Value{} + p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { + prcPMs[req.TypeName] = req.ProviderMeta + return providers.PlanResourceChangeResponse{ + PlannedState: req.ProposedNewState, + } + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + + _, diags := ctx.Plan() + assertNoErrors(t, diags) + + if !p.PlanResourceChangeCalled { + t.Fatalf("PlanResourceChange not called") + } + + expectations := map[string]cty.Value{} + + if pm, ok := prcPMs["test_resource"]; !ok { + t.Fatalf("sub-module PlanResourceChange not called") + } else if pm.IsNull() { + t.Fatalf("null ProviderMeta in sub-module PlanResourceChange") + } else { + expectations["quux-submodule"] = pm + } + + if pm, ok := prcPMs["test_instance"]; !ok { + t.Fatalf("root module PlanResourceChange not called") + } else if pm.IsNull() { + t.Fatalf("null ProviderMeta in root module PlanResourceChange") + } else { + expectations["quux"] = pm + } + + type metaStruct struct { + Baz string `cty:"baz"` + } + + for expected, v := range expectations { + var meta metaStruct + err := gocty.FromCtyValue(v, &meta) + if err != nil { + t.Fatalf("Error parsing cty value: %s", err) + } + if meta.Baz != expected { + t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz) + } + } +} + +func TestContext2Apply_ProviderMeta_plan_unset(t *testing.T) { + m := testModule(t, "provider-meta-unset") + p := testProvider("test") + p.ApplyFn = testApplyFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + prcPMs := map[string]cty.Value{} + p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { + prcPMs[req.TypeName] = req.ProviderMeta + return providers.PlanResourceChangeResponse{ + PlannedState: req.ProposedNewState, + } + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + + _, diags := ctx.Plan() + assertNoErrors(t, diags) + + if !p.PlanResourceChangeCalled { + t.Fatalf("PlanResourceChange not called") + } + + if pm, ok := prcPMs["test_resource"]; !ok { + t.Fatalf("sub-module PlanResourceChange not called") + } else if !pm.IsNull() { + t.Fatalf("non-null ProviderMeta in sub-module PlanResourceChange: %+v", pm) + } + + if pm, ok := prcPMs["test_instance"]; !ok { + t.Fatalf("root module PlanResourceChange not called") + } else if !pm.IsNull() { + t.Fatalf("non-null ProviderMeta in root module PlanResourceChange: %+v", pm) + } +} + +func TestContext2Apply_ProviderMeta_plan_setNoSchema(t *testing.T) { + m := testModule(t, "provider-meta-set") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + + _, diags := ctx.Plan() + if !diags.HasErrors() { + t.Fatalf("plan supposed to error, has no errors") + } + + var rootErr, subErr bool + errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks" + for _, diag := range diags { + if diag.Description().Summary != "Provider registry.terraform.io/-/test doesn't support provider_meta" { + t.Errorf("Unexpected error: %+v", diag.Description()) + } + switch diag.Description().Detail { + case fmt.Sprintf(errorSummary, "instance"): + rootErr = true + case fmt.Sprintf(errorSummary, "resource"): + subErr = true + default: + t.Errorf("Unexpected error: %s", diag.Description()) + } + } + if !rootErr { + t.Errorf("Expected unsupported provider_meta block error for root module, none received") + } + if !subErr { + t.Errorf("Expected unsupported provider_meta block error for sub-module, none received") + } +} + +func TestContext2Apply_ProviderMeta_plan_setInvalid(t *testing.T) { + m := testModule(t, "provider-meta-set") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "quux": { + Type: cty.String, + Required: true, + }, + }, + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + + _, diags := ctx.Plan() + if !diags.HasErrors() { + t.Fatalf("plan supposed to error, has no errors") + } + + var reqErr, invalidErr bool + for _, diag := range diags { + switch diag.Description().Summary { + case "Missing required argument": + if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` { + reqErr = true + } else { + t.Errorf("Unexpected error %+v", diag.Description()) + } + case "Unsupported argument": + if diag.Description().Detail == `An argument named "baz" is not expected here.` { + invalidErr = true + } else { + t.Errorf("Unexpected error %+v", diag.Description()) + } + default: + t.Errorf("Unexpected error %+v", diag.Description()) + } + } + if !reqErr { + t.Errorf("Expected missing required argument error, none received") + } + if !invalidErr { + t.Errorf("Expected unsupported argument error, none received") + } +} + +func TestContext2Apply_ProviderMeta_refresh_set(t *testing.T) { + m := testModule(t, "provider-meta-set") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + rrcPMs := map[string]cty.Value{} + p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { + rrcPMs[req.TypeName] = req.ProviderMeta + newState, err := p.GetSchemaReturn.ResourceTypes[req.TypeName].CoerceValue(p.ReadResourceResponse.NewState) + if err != nil { + panic(err) + } + resp := p.ReadResourceResponse + resp.NewState = newState + return resp + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + + _, diags := ctx.Plan() + assertNoErrors(t, diags) + + _, diags = ctx.Apply() + assertNoErrors(t, diags) + + _, diags = ctx.Refresh() + assertNoErrors(t, diags) + + if !p.ReadResourceCalled { + t.Fatalf("ReadResource not called") + } + + expectations := map[string]cty.Value{} + + if pm, ok := rrcPMs["test_resource"]; !ok { + t.Fatalf("sub-module ReadResource not called") + } else if pm.IsNull() { + t.Fatalf("null ProviderMeta in sub-module ReadResource") + } else { + expectations["quux-submodule"] = pm + } + + if pm, ok := rrcPMs["test_instance"]; !ok { + t.Fatalf("root module ReadResource not called") + } else if pm.IsNull() { + t.Fatalf("null ProviderMeta in root module ReadResource") + } else { + expectations["quux"] = pm + } + + type metaStruct struct { + Baz string `cty:"baz"` + } + + for expected, v := range expectations { + var meta metaStruct + err := gocty.FromCtyValue(v, &meta) + if err != nil { + t.Fatalf("Error parsing cty value: %s", err) + } + if meta.Baz != expected { + t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz) + } + } +} + +func TestContext2Apply_ProviderMeta_refresh_unset(t *testing.T) { + m := testModule(t, "provider-meta-unset") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + + _, diags := ctx.Plan() + assertNoErrors(t, diags) + + _, diags = ctx.Apply() + assertNoErrors(t, diags) + + _, diags = ctx.Refresh() + assertNoErrors(t, diags) + + if !p.ReadResourceCalled { + t.Fatalf("ReadResource not called") + } + if !p.ReadResourceRequest.ProviderMeta.IsNull() { + t.Fatalf("Expected null ProviderMeta in ReadResource, got %v", p.ReadResourceRequest.ProviderMeta) + } +} + +func TestContext2Apply_ProviderMeta_refresh_setNoSchema(t *testing.T) { + m := testModule(t, "provider-meta-set") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + + // we need a schema for plan/apply so they don't error + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + + _, diags := ctx.Plan() + assertNoErrors(t, diags) + + _, diags = ctx.Apply() + assertNoErrors(t, diags) + + // drop the schema before refresh, to test that it errors + schema.ProviderMeta = nil + p.GetSchemaReturn = schema + ctx = testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + State: ctx.State(), + }) + + _, diags = ctx.Refresh() + if !diags.HasErrors() { + t.Fatalf("refresh supposed to error, has no errors") + } + + var rootErr, subErr bool + errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks" + for _, diag := range diags { + if diag.Description().Summary != "Provider registry.terraform.io/-/test doesn't support provider_meta" { + t.Errorf("Unexpected error: %+v", diag.Description()) + } + switch diag.Description().Detail { + case fmt.Sprintf(errorSummary, "instance"): + rootErr = true + case fmt.Sprintf(errorSummary, "resource"): + subErr = true + default: + t.Errorf("Unexpected error: %s", diag.Description()) + } + } + if !rootErr { + t.Errorf("Expected unsupported provider_meta block error for root module, none received") + } + if !subErr { + t.Errorf("Expected unsupported provider_meta block error for sub-module, none received") + } +} + +func TestContext2Apply_ProviderMeta_refresh_setInvalid(t *testing.T) { + m := testModule(t, "provider-meta-set") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + + // we need a matching schema for plan/apply so they don't error + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + + _, diags := ctx.Plan() + assertNoErrors(t, diags) + + _, diags = ctx.Apply() + assertNoErrors(t, diags) + + // change the schema before refresh, to test that it errors + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "quux": { + Type: cty.String, + Required: true, + }, + }, + } + p.GetSchemaReturn = schema + ctx = testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + State: ctx.State(), + }) + + _, diags = ctx.Refresh() + if !diags.HasErrors() { + t.Fatalf("refresh supposed to error, has no errors") + } + + var reqErr, invalidErr bool + for _, diag := range diags { + switch diag.Description().Summary { + case "Missing required argument": + if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` { + reqErr = true + } else { + t.Errorf("Unexpected error %+v", diag.Description()) + } + case "Unsupported argument": + if diag.Description().Detail == `An argument named "baz" is not expected here.` { + invalidErr = true + } else { + t.Errorf("Unexpected error %+v", diag.Description()) + } + default: + t.Errorf("Unexpected error %+v", diag.Description()) + } + } + if !reqErr { + t.Errorf("Expected missing required argument error, none received") + } + if !invalidErr { + t.Errorf("Expected unsupported argument error, none received") + } +} + +func TestContext2Apply_ProviderMeta_refreshdata_set(t *testing.T) { + m := testModule(t, "provider-meta-data-set") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + rdsPMs := map[string]cty.Value{} + p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { + rdsPMs[req.TypeName] = req.ProviderMeta + switch req.TypeName { + case "test_data_source": + log.Printf("[TRACE] test_data_source RDSR returning") + return providers.ReadDataSourceResponse{ + State: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("yo"), + "foo": cty.StringVal("bar"), + }), + } + case "test_file": + log.Printf("[TRACE] test_file RDSR returning") + return providers.ReadDataSourceResponse{ + State: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("bar"), + "rendered": cty.StringVal("baz"), + "template": cty.StringVal(""), + }), + } + default: + // config drift, oops + log.Printf("[TRACE] unknown request TypeName: %q", req.TypeName) + return providers.ReadDataSourceResponse{} + } + } + + _, diags := ctx.Plan() + assertNoErrors(t, diags) + + _, diags = ctx.Apply() + assertNoErrors(t, diags) + + _, diags = ctx.Refresh() + assertNoErrors(t, diags) + + if !p.ReadDataSourceCalled { + t.Fatalf("ReadDataSource not called") + } + + expectations := map[string]cty.Value{} + + if pm, ok := rdsPMs["test_file"]; !ok { + t.Fatalf("sub-module ReadDataSource not called") + } else if pm.IsNull() { + t.Fatalf("null ProviderMeta in sub-module ReadDataSource") + } else { + expectations["quux-submodule"] = pm + } + + if pm, ok := rdsPMs["test_data_source"]; !ok { + t.Fatalf("root module ReadDataSource not called") + } else if pm.IsNull() { + t.Fatalf("null ProviderMeta in root module ReadDataSource") + } else { + expectations["quux"] = pm + } + + type metaStruct struct { + Baz string `cty:"baz"` + } + + for expected, v := range expectations { + var meta metaStruct + err := gocty.FromCtyValue(v, &meta) + if err != nil { + t.Fatalf("Error parsing cty value: %s", err) + } + if meta.Baz != expected { + t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz) + } + } +} + +func TestContext2Apply_ProviderMeta_refreshdata_unset(t *testing.T) { + m := testModule(t, "provider-meta-data-unset") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "baz": { + Type: cty.String, + Required: true, + }, + }, + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + rdsPMs := map[string]cty.Value{} + p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { + rdsPMs[req.TypeName] = req.ProviderMeta + switch req.TypeName { + case "test_data_source": + return providers.ReadDataSourceResponse{ + State: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("yo"), + "foo": cty.StringVal("bar"), + }), + } + case "test_file": + return providers.ReadDataSourceResponse{ + State: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("bar"), + "rendered": cty.StringVal("baz"), + "template": cty.StringVal(""), + }), + } + default: + // config drift, oops + return providers.ReadDataSourceResponse{} + } + } + + _, diags := ctx.Refresh() + assertNoErrors(t, diags) + + _, diags = ctx.Plan() + assertNoErrors(t, diags) + + _, diags = ctx.Apply() + assertNoErrors(t, diags) + + if !p.ReadDataSourceCalled { + t.Fatalf("ReadDataSource not called") + } + + if pm, ok := rdsPMs["test_file"]; !ok { + t.Fatalf("sub-module ReadDataSource not called") + } else if !pm.IsNull() { + t.Fatalf("non-null ProviderMeta in sub-module ReadDataSource") + } + + if pm, ok := rdsPMs["test_data_source"]; !ok { + t.Fatalf("root module ReadDataSource not called") + } else if !pm.IsNull() { + t.Fatalf("non-null ProviderMeta in root module ReadDataSource") + } +} + +func TestContext2Apply_ProviderMeta_refreshdata_setNoSchema(t *testing.T) { + m := testModule(t, "provider-meta-data-set") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + p.ReadDataSourceResponse = providers.ReadDataSourceResponse{ + State: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("yo"), + "foo": cty.StringVal("bar"), + }), + } + + _, diags := ctx.Refresh() + if !diags.HasErrors() { + t.Fatalf("refresh supposed to error, has no errors") + } + + var rootErr, subErr bool + errorSummary := "The resource data.test_%s.foo belongs to a provider that doesn't support provider_meta blocks" + for _, diag := range diags { + if diag.Description().Summary != "Provider registry.terraform.io/-/test doesn't support provider_meta" { + t.Errorf("Unexpected error: %+v", diag.Description()) + } + switch diag.Description().Detail { + case fmt.Sprintf(errorSummary, "data_source"): + rootErr = true + case fmt.Sprintf(errorSummary, "file"): + subErr = true + default: + t.Errorf("Unexpected error: %s", diag.Description()) + } + } + if !rootErr { + t.Errorf("Expected unsupported provider_meta block error for root module, none received") + } + if !subErr { + t.Errorf("Expected unsupported provider_meta block error for sub-module, none received") + } +} + +func TestContext2Apply_ProviderMeta_refreshdata_setInvalid(t *testing.T) { + m := testModule(t, "provider-meta-data-set") + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + schema := p.GetSchemaReturn + schema.ProviderMeta = &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "quux": { + Type: cty.String, + Required: true, + }, + }, + } + p.GetSchemaReturn = schema + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test"): testProviderFuncFixed(p), + }, + ), + }) + p.ReadDataSourceResponse = providers.ReadDataSourceResponse{ + State: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("yo"), + "foo": cty.StringVal("bar"), + }), + } + + _, diags := ctx.Refresh() + if !diags.HasErrors() { + t.Fatalf("refresh supposed to error, has no errors") + } + + var reqErr, invalidErr bool + for _, diag := range diags { + switch diag.Description().Summary { + case "Missing required argument": + if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` { + reqErr = true + } else { + t.Errorf("Unexpected error %+v", diag.Description()) + } + case "Unsupported argument": + if diag.Description().Detail == `An argument named "baz" is not expected here.` { + invalidErr = true + } else { + t.Errorf("Unexpected error %+v", diag.Description()) + } + default: + t.Errorf("Unexpected error %+v", diag.Description()) + } + } + if !reqErr { + t.Errorf("Expected missing required argument error, none received") + } + if !invalidErr { + t.Errorf("Expected unsupported argument error, none received") + } +} diff --git a/terraform/eval_apply.go b/terraform/eval_apply.go index 0755c6b9f..cba8d44cd 100644 --- a/terraform/eval_apply.go +++ b/terraform/eval_apply.go @@ -5,7 +5,7 @@ import ( "log" "strings" - "github.com/hashicorp/go-multierror" + multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/hcl/v2" "github.com/zclconf/go-cty/cty" @@ -28,6 +28,7 @@ type EvalApply struct { Change **plans.ResourceInstanceChange ProviderAddr addrs.AbsProviderConfig Provider *providers.Interface + ProviderMetas map[addrs.Provider]*configs.ProviderMeta ProviderSchema **ProviderSchema Output **states.ResourceInstanceObject CreateNew *bool @@ -76,6 +77,31 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) { ) } + metaConfigVal := cty.NullVal(cty.DynamicPseudoType) + if n.ProviderMetas != nil { + log.Printf("[DEBUG] EvalApply: ProviderMeta config value set") + if m, ok := n.ProviderMetas[n.ProviderAddr.Provider]; ok && m != nil { + // if the provider doesn't support this feature, throw an error + if (*n.ProviderSchema).ProviderMeta == nil { + log.Printf("[DEBUG] EvalApply: no ProviderMeta schema") + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", n.ProviderAddr.Provider.String()), + Detail: fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr), + Subject: &m.ProviderRange, + }) + } else { + log.Printf("[DEBUG] EvalApply: ProviderMeta schema found") + var configDiags tfdiags.Diagnostics + metaConfigVal, _, configDiags = ctx.EvaluateBlock(m.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey) + diags = diags.Append(configDiags) + if configDiags.HasErrors() { + return nil, diags.Err() + } + } + } + } + log.Printf("[DEBUG] %s: applying the planned %s change", n.Addr.Absolute(ctx.Path()), change.Action) resp := provider.ApplyResourceChange(providers.ApplyResourceChangeRequest{ TypeName: n.Addr.Resource.Type, @@ -83,6 +109,7 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) { Config: configVal, PlannedState: change.After, PlannedPrivate: change.Private, + ProviderMeta: metaConfigVal, }) applyDiags := resp.Diagnostics if n.Config != nil { diff --git a/terraform/eval_diff.go b/terraform/eval_diff.go index 39aa288b5..f00814c9e 100644 --- a/terraform/eval_diff.go +++ b/terraform/eval_diff.go @@ -93,6 +93,7 @@ type EvalDiff struct { Config *configs.Resource Provider *providers.Interface ProviderAddr addrs.AbsProviderConfig + ProviderMetas map[addrs.Provider]*configs.ProviderMeta ProviderSchema **ProviderSchema State **states.ResourceInstanceObject PreviousDiff **plans.ResourceInstanceChange @@ -140,6 +141,28 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) { return nil, diags.Err() } + metaConfigVal := cty.NullVal(cty.DynamicPseudoType) + if n.ProviderMetas != nil { + if m, ok := n.ProviderMetas[n.ProviderAddr.Provider]; ok && m != nil { + // if the provider doesn't support this feature, throw an error + if (*n.ProviderSchema).ProviderMeta == nil { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", n.ProviderAddr.Provider.String()), + Detail: fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr), + Subject: &m.ProviderRange, + }) + } else { + var configDiags tfdiags.Diagnostics + metaConfigVal, _, configDiags = ctx.EvaluateBlock(m.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey) + diags = diags.Append(configDiags) + if configDiags.HasErrors() { + return nil, diags.Err() + } + } + } + } + absAddr := n.Addr.Absolute(ctx.Path()) var priorVal cty.Value var priorValTainted cty.Value @@ -204,6 +227,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) { PriorState: priorVal, ProposedNewState: proposedNewVal, PriorPrivate: priorPrivate, + ProviderMeta: metaConfigVal, }) diags = diags.Append(resp.Diagnostics.InConfigBody(config.Config)) if diags.HasErrors() { @@ -382,6 +406,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) { PriorState: nullPriorVal, ProposedNewState: proposedNewVal, PriorPrivate: plannedPrivate, + ProviderMeta: metaConfigVal, }) // We need to tread carefully here, since if there are any warnings // in here they probably also came out of our previous call to diff --git a/terraform/eval_read_data.go b/terraform/eval_read_data.go index f869b44b9..76b4a86fd 100644 --- a/terraform/eval_read_data.go +++ b/terraform/eval_read_data.go @@ -6,6 +6,7 @@ import ( "github.com/zclconf/go-cty/cty" + "github.com/hashicorp/hcl/v2" "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/configs" "github.com/hashicorp/terraform/plans" @@ -23,6 +24,7 @@ type EvalReadData struct { Config *configs.Resource Provider *providers.Interface ProviderAddr addrs.AbsProviderConfig + ProviderMetas map[addrs.Provider]*configs.ProviderMeta ProviderSchema **ProviderSchema // Planned is set when dealing with data resources that were deferred to @@ -104,6 +106,28 @@ func (n *EvalReadData) Eval(ctx EvalContext) (interface{}, error) { return nil, diags.Err() } + metaConfigVal := cty.NullVal(cty.DynamicPseudoType) + if n.ProviderMetas != nil { + if m, ok := n.ProviderMetas[n.ProviderAddr.Provider]; ok && m != nil { + // if the provider doesn't support this feature, throw an error + if (*n.ProviderSchema).ProviderMeta == nil { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", n.ProviderAddr.Provider.String()), + Detail: fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr), + Subject: &m.ProviderRange, + }) + } else { + var configDiags tfdiags.Diagnostics + metaConfigVal, _, configDiags = ctx.EvaluateBlock(m.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey) + diags = diags.Append(configDiags) + if configDiags.HasErrors() { + return nil, diags.Err() + } + } + } + } + proposedNewVal := objchange.PlannedDataResourceObject(schema, configVal) // If our configuration contains any unknown values then we must defer the @@ -203,8 +227,9 @@ func (n *EvalReadData) Eval(ctx EvalContext) (interface{}, error) { } resp := provider.ReadDataSource(providers.ReadDataSourceRequest{ - TypeName: n.Addr.Resource.Type, - Config: configVal, + TypeName: n.Addr.Resource.Type, + Config: configVal, + ProviderMeta: metaConfigVal, }) diags = diags.Append(resp.Diagnostics.InConfigBody(n.Config.Config)) if diags.HasErrors() { @@ -306,6 +331,7 @@ type EvalReadDataApply struct { Addr addrs.ResourceInstance Provider *providers.Interface ProviderAddr addrs.AbsProviderConfig + ProviderMeta *configs.ProviderMeta ProviderSchema **ProviderSchema Output **states.ResourceInstanceObject Config *configs.Resource @@ -330,6 +356,26 @@ func (n *EvalReadDataApply) Eval(ctx EvalContext) (interface{}, error) { return nil, nil } + metaConfigVal := cty.NullVal(cty.DynamicPseudoType) + if n.ProviderMeta != nil { + // if the provider doesn't support this feature, throw an error + if (*n.ProviderSchema).ProviderMeta == nil { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", n.ProviderAddr.Provider.String()), + Detail: fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr), + Subject: &n.ProviderMeta.ProviderRange, + }) + } else { + var configDiags tfdiags.Diagnostics + metaConfigVal, _, configDiags = ctx.EvaluateBlock(n.ProviderMeta.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey) + diags = diags.Append(configDiags) + if configDiags.HasErrors() { + return nil, diags.Err() + } + } + } + // For the purpose of external hooks we present a data apply as a // "Refresh" rather than an "Apply" because creating a data source // is presented to users/callers as a "read" operation. @@ -343,8 +389,9 @@ func (n *EvalReadDataApply) Eval(ctx EvalContext) (interface{}, error) { } resp := provider.ReadDataSource(providers.ReadDataSourceRequest{ - TypeName: n.Addr.Resource.Type, - Config: change.After, + TypeName: n.Addr.Resource.Type, + Config: change.After, + ProviderMeta: metaConfigVal, }) diags = diags.Append(resp.Diagnostics.InConfigBody(n.Config.Config)) if diags.HasErrors() { diff --git a/terraform/eval_refresh.go b/terraform/eval_refresh.go index d3bfffaf8..7ec875a97 100644 --- a/terraform/eval_refresh.go +++ b/terraform/eval_refresh.go @@ -6,7 +6,9 @@ import ( "github.com/zclconf/go-cty/cty" + "github.com/hashicorp/hcl/v2" "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" "github.com/hashicorp/terraform/providers" "github.com/hashicorp/terraform/states" "github.com/hashicorp/terraform/tfdiags" @@ -18,6 +20,7 @@ type EvalRefresh struct { Addr addrs.ResourceInstance ProviderAddr addrs.AbsProviderConfig Provider *providers.Interface + ProviderMetas map[addrs.Provider]*configs.ProviderMeta ProviderSchema **ProviderSchema State **states.ResourceInstanceObject Output **states.ResourceInstanceObject @@ -42,6 +45,31 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) { return nil, fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type) } + metaConfigVal := cty.NullVal(cty.DynamicPseudoType) + if n.ProviderMetas != nil { + if m, ok := n.ProviderMetas[n.ProviderAddr.Provider]; ok && m != nil { + log.Printf("[DEBUG] EvalRefresh: ProviderMeta config value set") + // if the provider doesn't support this feature, throw an error + if (*n.ProviderSchema).ProviderMeta == nil { + log.Printf("[DEBUG] EvalRefresh: no ProviderMeta schema") + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", n.ProviderAddr.Provider.String()), + Detail: fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr), + Subject: &m.ProviderRange, + }) + } else { + log.Printf("[DEBUG] EvalRefresh: ProviderMeta schema found: %+v", (*n.ProviderSchema).ProviderMeta) + var configDiags tfdiags.Diagnostics + metaConfigVal, _, configDiags = ctx.EvaluateBlock(m.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey) + diags = diags.Append(configDiags) + if configDiags.HasErrors() { + return nil, diags.Err() + } + } + } + } + // Call pre-refresh hook err := ctx.Hook(func(h Hook) (HookAction, error) { return h.PreRefresh(absAddr, states.CurrentGen, state.Value) @@ -53,9 +81,10 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) { // Refresh! priorVal := state.Value req := providers.ReadResourceRequest{ - TypeName: n.Addr.Resource.Type, - PriorState: priorVal, - Private: state.Private, + TypeName: n.Addr.Resource.Type, + PriorState: priorVal, + Private: state.Private, + ProviderMeta: metaConfigVal, } provider := *n.Provider diff --git a/terraform/eval_validate.go b/terraform/eval_validate.go index d42b49b88..9146d5577 100644 --- a/terraform/eval_validate.go +++ b/terraform/eval_validate.go @@ -349,6 +349,7 @@ type EvalValidateResource struct { Provider *providers.Interface ProviderSchema **ProviderSchema Config *configs.Resource + ProviderMetas map[addrs.Provider]*configs.ProviderMeta // IgnoreWarnings means that warnings will not be passed through. This allows // "just-in-time" passes of validation to continue execution through warnings. @@ -423,6 +424,40 @@ func (n *EvalValidateResource) Eval(ctx EvalContext) (interface{}, error) { } } + // Validate the provider_meta block for the provider this resource + // belongs to, if there is one. + // + // Note: this will return an error for every resource a provider + // uses in a module, if the provider_meta for that module is + // incorrect. The only way to solve this that we've foudn is to + // insert a new ProviderMeta graph node in the graph, and make all + // that provider's resources in the module depend on the node. That's + // an awful heavy hammer to swing for this feature, which should be + // used only in limited cases with heavy coordination with the + // Terraform team, so we're going to defer that solution for a future + // enhancement to this functionality. + /* + if n.ProviderMetas != nil { + if m, ok := n.ProviderMetas[n.ProviderAddr.ProviderConfig.Type]; ok && m != nil { + // if the provider doesn't support this feature, throw an error + if (*n.ProviderSchema).ProviderMeta == nil { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Provider %s doesn't support provider_meta", cfg.ProviderConfigAddr()), + Detail: fmt.Sprintf("The resource %s belongs to a provider that doesn't support provider_meta blocks", n.Addr), + Subject: &m.ProviderRange, + }) + } else { + _, _, metaDiags := ctx.EvaluateBlock(m.Config, (*n.ProviderSchema).ProviderMeta, nil, EvalDataForNoInstanceKey) + diags = diags.Append(metaDiags) + } + } + } + */ + // BUG(paddy): we're not validating provider_meta blocks on EvalValidate right now + // because the ProviderAddr for the resource isn't available on the EvalValidate + // struct. + // Provider entry point varies depending on resource mode, because // managed resources and data resources are two distinct concepts // in the provider abstraction. diff --git a/terraform/node_data_refresh.go b/terraform/node_data_refresh.go index f3d3f262a..87795a97f 100644 --- a/terraform/node_data_refresh.go +++ b/terraform/node_data_refresh.go @@ -15,12 +15,13 @@ type NodeRefreshableDataResource struct { } var ( - _ GraphNodeSubPath = (*NodeRefreshableDataResource)(nil) - _ GraphNodeDynamicExpandable = (*NodeRefreshableDataResource)(nil) - _ GraphNodeReferenceable = (*NodeRefreshableDataResource)(nil) - _ GraphNodeReferencer = (*NodeRefreshableDataResource)(nil) - _ GraphNodeResource = (*NodeRefreshableDataResource)(nil) - _ GraphNodeAttachResourceConfig = (*NodeRefreshableDataResource)(nil) + _ GraphNodeSubPath = (*NodeRefreshableDataResource)(nil) + _ GraphNodeDynamicExpandable = (*NodeRefreshableDataResource)(nil) + _ GraphNodeReferenceable = (*NodeRefreshableDataResource)(nil) + _ GraphNodeReferencer = (*NodeRefreshableDataResource)(nil) + _ GraphNodeResource = (*NodeRefreshableDataResource)(nil) + _ GraphNodeAttachResourceConfig = (*NodeRefreshableDataResource)(nil) + _ GraphNodeAttachProviderMetaConfigs = (*NodeAbstractResource)(nil) ) // GraphNodeDynamicExpandable @@ -76,6 +77,7 @@ func (n *NodeRefreshableDataResource) DynamicExpand(ctx EvalContext) (*Graph, er // Add the config and state since we don't do that via transforms a.Config = n.Config a.ResolvedProvider = n.ResolvedProvider + a.ProviderMetas = n.ProviderMetas return &NodeRefreshableDataResourceInstance{ NodeAbstractResourceInstance: a, @@ -182,6 +184,7 @@ func (n *NodeRefreshableDataResourceInstance) EvalTree() EvalNode { Config: n.Config, Provider: &provider, ProviderAddr: n.ResolvedProvider, + ProviderMetas: n.ProviderMetas, ProviderSchema: &providerSchema, OutputChange: &change, OutputConfigValue: &configVal, diff --git a/terraform/node_resource_abstract.go b/terraform/node_resource_abstract.go index 09ca14abd..957c1fc6b 100644 --- a/terraform/node_resource_abstract.go +++ b/terraform/node_resource_abstract.go @@ -57,6 +57,9 @@ type NodeAbstractResource struct { SchemaVersion uint64 // Schema version of "Schema", as decided by the provider Config *configs.Resource // Config is the resource in the config + // ProviderMetas is the provider_meta configs for the module this resource belongs to + ProviderMetas map[addrs.Provider]*configs.ProviderMeta + ProvisionerSchemas map[string]*configschema.Block Targets []addrs.Targetable // Set from GraphNodeTargetable @@ -66,17 +69,18 @@ type NodeAbstractResource struct { } var ( - _ GraphNodeSubPath = (*NodeAbstractResource)(nil) - _ GraphNodeReferenceable = (*NodeAbstractResource)(nil) - _ GraphNodeReferencer = (*NodeAbstractResource)(nil) - _ GraphNodeProviderConsumer = (*NodeAbstractResource)(nil) - _ GraphNodeProvisionerConsumer = (*NodeAbstractResource)(nil) - _ GraphNodeResource = (*NodeAbstractResource)(nil) - _ GraphNodeAttachResourceConfig = (*NodeAbstractResource)(nil) - _ GraphNodeAttachResourceSchema = (*NodeAbstractResource)(nil) - _ GraphNodeAttachProvisionerSchema = (*NodeAbstractResource)(nil) - _ GraphNodeTargetable = (*NodeAbstractResource)(nil) - _ dag.GraphNodeDotter = (*NodeAbstractResource)(nil) + _ GraphNodeSubPath = (*NodeAbstractResource)(nil) + _ GraphNodeReferenceable = (*NodeAbstractResource)(nil) + _ GraphNodeReferencer = (*NodeAbstractResource)(nil) + _ GraphNodeProviderConsumer = (*NodeAbstractResource)(nil) + _ GraphNodeProvisionerConsumer = (*NodeAbstractResource)(nil) + _ GraphNodeResource = (*NodeAbstractResource)(nil) + _ GraphNodeAttachResourceConfig = (*NodeAbstractResource)(nil) + _ GraphNodeAttachResourceSchema = (*NodeAbstractResource)(nil) + _ GraphNodeAttachProvisionerSchema = (*NodeAbstractResource)(nil) + _ GraphNodeAttachProviderMetaConfigs = (*NodeAbstractResource)(nil) + _ GraphNodeTargetable = (*NodeAbstractResource)(nil) + _ dag.GraphNodeDotter = (*NodeAbstractResource)(nil) ) // NewNodeAbstractResource creates an abstract resource graph node for @@ -104,19 +108,20 @@ type NodeAbstractResourceInstance struct { } var ( - _ GraphNodeSubPath = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeReferenceable = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeReferencer = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeProviderConsumer = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeProvisionerConsumer = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeResource = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeResourceInstance = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeAttachResourceState = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeAttachResourceConfig = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeAttachResourceSchema = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeAttachProvisionerSchema = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeTargetable = (*NodeAbstractResourceInstance)(nil) - _ dag.GraphNodeDotter = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeSubPath = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeReferenceable = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeReferencer = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeProviderConsumer = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeProvisionerConsumer = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeResource = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeResourceInstance = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeAttachResourceState = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeAttachResourceConfig = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeAttachResourceSchema = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeAttachProvisionerSchema = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeAttachProviderMetaConfigs = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeTargetable = (*NodeAbstractResourceInstance)(nil) + _ dag.GraphNodeDotter = (*NodeAbstractResourceInstance)(nil) ) // NewNodeAbstractResourceInstance creates an abstract resource instance graph @@ -404,6 +409,11 @@ func (n *NodeAbstractResource) AttachResourceSchema(schema *configschema.Block, n.SchemaVersion = version } +// GraphNodeAttachProviderMetaConfigs impl +func (n *NodeAbstractResource) AttachProviderMetaConfigs(c map[addrs.Provider]*configs.ProviderMeta) { + n.ProviderMetas = c +} + // GraphNodeDotter impl. func (n *NodeAbstractResource) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { return &dag.DotNode{ diff --git a/terraform/node_resource_apply_instance.go b/terraform/node_resource_apply_instance.go index 217a06b7d..84c1fd148 100644 --- a/terraform/node_resource_apply_instance.go +++ b/terraform/node_resource_apply_instance.go @@ -180,6 +180,7 @@ func (n *NodeApplyableResourceInstance) evalTreeDataResource(addr addrs.AbsResou Planned: &change, // setting this indicates that the result must be complete Provider: &provider, ProviderAddr: n.ResolvedProvider, + ProviderMetas: n.ProviderMetas, ProviderSchema: &providerSchema, OutputState: &state, }, @@ -287,6 +288,7 @@ func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe Config: n.Config, Provider: &provider, ProviderAddr: n.ResolvedProvider, + ProviderMetas: n.ProviderMetas, ProviderSchema: &providerSchema, State: &state, PreviousDiff: &diff, @@ -350,6 +352,7 @@ func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe Change: &diffApply, Provider: &provider, ProviderAddr: n.ResolvedProvider, + ProviderMetas: n.ProviderMetas, ProviderSchema: &providerSchema, Output: &state, Error: &err, diff --git a/terraform/node_resource_destroy.go b/terraform/node_resource_destroy.go index 0374d83dd..d4fb95260 100644 --- a/terraform/node_resource_destroy.go +++ b/terraform/node_resource_destroy.go @@ -246,6 +246,7 @@ func (n *NodeDestroyResourceInstance) EvalTree() EvalNode { Change: &changeApply, Provider: &provider, ProviderAddr: n.ResolvedProvider, + ProviderMetas: n.ProviderMetas, ProviderSchema: &providerSchema, Output: &state, Error: &err, diff --git a/terraform/node_resource_destroy_deposed.go b/terraform/node_resource_destroy_deposed.go index e0d5db836..7afab72bc 100644 --- a/terraform/node_resource_destroy_deposed.go +++ b/terraform/node_resource_destroy_deposed.go @@ -97,6 +97,7 @@ func (n *NodePlanDeposedResourceInstanceObject) EvalTree() EvalNode { Addr: addr.Resource, ProviderAddr: n.ResolvedProvider, Provider: &provider, + ProviderMetas: n.ProviderMetas, ProviderSchema: &providerSchema, State: &state, Output: &state, diff --git a/terraform/node_resource_plan.go b/terraform/node_resource_plan.go index 192d11c1e..69187d5f3 100644 --- a/terraform/node_resource_plan.go +++ b/terraform/node_resource_plan.go @@ -104,6 +104,7 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) { a.ResolvedProvider = n.ResolvedProvider a.Schema = n.Schema a.ProvisionerSchemas = n.ProvisionerSchemas + a.ProviderMetas = n.ProviderMetas return &NodePlannableResourceInstance{ NodeAbstractResourceInstance: a, @@ -122,6 +123,7 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) { a.ResolvedProvider = n.ResolvedProvider a.Schema = n.Schema a.ProvisionerSchemas = n.ProvisionerSchemas + a.ProviderMetas = n.ProviderMetas return &NodePlannableResourceInstanceOrphan{ NodeAbstractResourceInstance: a, diff --git a/terraform/node_resource_plan_instance.go b/terraform/node_resource_plan_instance.go index 05ccefc34..e9a3c60f5 100644 --- a/terraform/node_resource_plan_instance.go +++ b/terraform/node_resource_plan_instance.go @@ -116,6 +116,7 @@ func (n *NodePlannableResourceInstance) evalTreeDataResource(addr addrs.AbsResou Config: n.Config, Provider: &provider, ProviderAddr: n.ResolvedProvider, + ProviderMetas: n.ProviderMetas, ProviderSchema: &providerSchema, ForcePlanRead: true, // _always_ produce a Read change, even if the config seems ready OutputChange: &change, @@ -174,6 +175,7 @@ func (n *NodePlannableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe CreateBeforeDestroy: n.ForceCreateBeforeDestroy, Provider: &provider, ProviderAddr: n.ResolvedProvider, + ProviderMetas: n.ProviderMetas, ProviderSchema: &providerSchema, State: &state, OutputChange: &change, diff --git a/terraform/node_resource_refresh.go b/terraform/node_resource_refresh.go index fa1590093..37ac90592 100644 --- a/terraform/node_resource_refresh.go +++ b/terraform/node_resource_refresh.go @@ -85,6 +85,7 @@ func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph, a.Config = n.Config a.ResolvedProvider = n.ResolvedProvider a.Dependencies = n.Dependencies + a.ProviderMetas = n.ProviderMetas return &NodeRefreshableManagedResourceInstance{ NodeAbstractResourceInstance: a, @@ -237,6 +238,7 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResource() EvalN Addr: addr.Resource, ProviderAddr: n.ResolvedProvider, Provider: &provider, + ProviderMetas: n.ProviderMetas, ProviderSchema: &providerSchema, State: &state, Output: &state, diff --git a/terraform/node_resource_validate.go b/terraform/node_resource_validate.go index efa657bf0..dec63d8df 100644 --- a/terraform/node_resource_validate.go +++ b/terraform/node_resource_validate.go @@ -15,12 +15,13 @@ type NodeValidatableResource struct { } var ( - _ GraphNodeSubPath = (*NodeValidatableResource)(nil) - _ GraphNodeEvalable = (*NodeValidatableResource)(nil) - _ GraphNodeReferenceable = (*NodeValidatableResource)(nil) - _ GraphNodeReferencer = (*NodeValidatableResource)(nil) - _ GraphNodeResource = (*NodeValidatableResource)(nil) - _ GraphNodeAttachResourceConfig = (*NodeValidatableResource)(nil) + _ GraphNodeSubPath = (*NodeValidatableResource)(nil) + _ GraphNodeEvalable = (*NodeValidatableResource)(nil) + _ GraphNodeReferenceable = (*NodeValidatableResource)(nil) + _ GraphNodeReferencer = (*NodeValidatableResource)(nil) + _ GraphNodeResource = (*NodeValidatableResource)(nil) + _ GraphNodeAttachResourceConfig = (*NodeValidatableResource)(nil) + _ GraphNodeAttachProviderMetaConfigs = (*NodeValidatableResource)(nil) ) // GraphNodeEvalable @@ -45,6 +46,7 @@ func (n *NodeValidatableResource) EvalTree() EvalNode { &EvalValidateResource{ Addr: addr.Resource, Provider: &provider, + ProviderMetas: n.ProviderMetas, ProviderSchema: &providerSchema, Config: config, ConfigVal: &configVal, diff --git a/terraform/provider_mock.go b/terraform/provider_mock.go index d82dc0f4e..ed7b7849a 100644 --- a/terraform/provider_mock.go +++ b/terraform/provider_mock.go @@ -118,6 +118,7 @@ func (p *MockProvider) getSchema() providers.GetSchemaResponse { } if p.GetSchemaReturn != nil { ret.Provider.Block = p.GetSchemaReturn.Provider + ret.ProviderMeta.Block = p.GetSchemaReturn.ProviderMeta for n, s := range p.GetSchemaReturn.DataSources { ret.DataSources[n] = providers.Schema{ Block: s, diff --git a/terraform/schemas.go b/terraform/schemas.go index 9158382d8..86cd45dc9 100644 --- a/terraform/schemas.go +++ b/terraform/schemas.go @@ -164,6 +164,10 @@ func loadProviderSchemas(schemas map[addrs.Provider]*ProviderSchema, config *con } schemas[fqn] = s + + if resp.ProviderMeta.Block != nil { + s.ProviderMeta = resp.ProviderMeta.Block + } } if config != nil { @@ -246,6 +250,7 @@ func loadProvisionerSchemas(schemas map[string]*configschema.Block, config *conf // resource types and data sources used by that configuration. type ProviderSchema struct { Provider *configschema.Block + ProviderMeta *configschema.Block ResourceTypes map[string]*configschema.Block DataSources map[string]*configschema.Block diff --git a/terraform/state.go b/terraform/state.go index 2f97e5af3..95c1e8513 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -1634,6 +1634,8 @@ type InstanceState struct { // and collections. Meta map[string]interface{} `json:"meta"` + ProviderMeta cty.Value + // Tainted is used to mark a resource for recreation. Tainted bool `json:"tainted"` diff --git a/terraform/testdata/provider-meta-data-set/main.tf b/terraform/testdata/provider-meta-data-set/main.tf new file mode 100644 index 000000000..ef7acd957 --- /dev/null +++ b/terraform/testdata/provider-meta-data-set/main.tf @@ -0,0 +1,13 @@ +data "test_data_source" "foo" { + foo = "bar" +} + +terraform { + provider_meta "test" { + baz = "quux" + } +} + +module "my_module" { + source = "./my-module" +} diff --git a/terraform/testdata/provider-meta-data-set/my-module/main.tf b/terraform/testdata/provider-meta-data-set/my-module/main.tf new file mode 100644 index 000000000..61a977069 --- /dev/null +++ b/terraform/testdata/provider-meta-data-set/my-module/main.tf @@ -0,0 +1,9 @@ +data "test_file" "foo" { + id = "bar" +} + +terraform { + provider_meta "test" { + baz = "quux-submodule" + } +} diff --git a/terraform/testdata/provider-meta-data-unset/main.tf b/terraform/testdata/provider-meta-data-unset/main.tf new file mode 100644 index 000000000..c4091f37b --- /dev/null +++ b/terraform/testdata/provider-meta-data-unset/main.tf @@ -0,0 +1,7 @@ +data "test_data_source" "foo" { + foo = "bar" +} + +module "my_module" { + source = "./my-module" +} diff --git a/terraform/testdata/provider-meta-data-unset/my-module/main.tf b/terraform/testdata/provider-meta-data-unset/my-module/main.tf new file mode 100644 index 000000000..7e0ea46b6 --- /dev/null +++ b/terraform/testdata/provider-meta-data-unset/my-module/main.tf @@ -0,0 +1,3 @@ +data "test_file" "foo" { + id = "bar" +} diff --git a/terraform/testdata/provider-meta-set/main.tf b/terraform/testdata/provider-meta-set/main.tf new file mode 100644 index 000000000..a3e9f804b --- /dev/null +++ b/terraform/testdata/provider-meta-set/main.tf @@ -0,0 +1,13 @@ +resource "test_instance" "bar" { + foo = "bar" +} + +terraform { + provider_meta "test" { + baz = "quux" + } +} + +module "my_module" { + source = "./my-module" +} diff --git a/terraform/testdata/provider-meta-set/my-module/main.tf b/terraform/testdata/provider-meta-set/my-module/main.tf new file mode 100644 index 000000000..2a89dd51f --- /dev/null +++ b/terraform/testdata/provider-meta-set/my-module/main.tf @@ -0,0 +1,9 @@ +resource "test_resource" "bar" { + value = "bar" +} + +terraform { + provider_meta "test" { + baz = "quux-submodule" + } +} diff --git a/terraform/testdata/provider-meta-unset/main.tf b/terraform/testdata/provider-meta-unset/main.tf new file mode 100644 index 000000000..0ae85d39f --- /dev/null +++ b/terraform/testdata/provider-meta-unset/main.tf @@ -0,0 +1,7 @@ +resource "test_instance" "bar" { + foo = "bar" +} + +module "my_module" { + source = "./my-module" +} diff --git a/terraform/testdata/provider-meta-unset/my-module/main.tf b/terraform/testdata/provider-meta-unset/my-module/main.tf new file mode 100644 index 000000000..ec9701f95 --- /dev/null +++ b/terraform/testdata/provider-meta-unset/my-module/main.tf @@ -0,0 +1,3 @@ +resource "test_resource" "bar" { + value = "bar" +} diff --git a/terraform/transform_attach_config_provider_meta.go b/terraform/transform_attach_config_provider_meta.go new file mode 100644 index 000000000..9947d120c --- /dev/null +++ b/terraform/transform_attach_config_provider_meta.go @@ -0,0 +1,15 @@ +package terraform + +import ( + "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/configs" +) + +// GraphNodeAttachProviderMetaConfigs is an interface that must be implemented +// by nodes that want provider meta configurations attached. +type GraphNodeAttachProviderMetaConfigs interface { + GraphNodeResource + + // Sets the configuration + AttachProviderMetaConfigs(map[addrs.Provider]*configs.ProviderMeta) +} diff --git a/terraform/transform_attach_config_resource.go b/terraform/transform_attach_config_resource.go index 03f8564d7..a0f981bae 100644 --- a/terraform/transform_attach_config_resource.go +++ b/terraform/transform_attach_config_resource.go @@ -56,6 +56,24 @@ func (t *AttachResourceConfigTransformer) Transform(g *Graph) error { log.Printf("[TRACE] AttachResourceConfigTransformer: attaching to %q (%T) config from %s", dag.VertexName(v), v, r.DeclRange) arn.AttachResourceConfig(r) + + // attach the provider_meta info + if gnapmc, ok := v.(GraphNodeAttachProviderMetaConfigs); ok { + log.Printf("[TRACE] AttachResourceConfigTransformer: attaching provider meta configs to %s", dag.VertexName(v)) + if config == nil { + log.Printf("[TRACE] AttachResourceConfigTransformer: no config set on the transformer for %s", dag.VertexName(v)) + continue + } + if config.Module == nil { + log.Printf("[TRACE] AttachResourceConfigTransformer: no module in config for %s", dag.VertexName(v)) + continue + } + if config.Module.ProviderMetas == nil { + log.Printf("[TRACE] AttachResourceConfigTransformer: no provider metas defined for %s", dag.VertexName(v)) + continue + } + gnapmc.AttachProviderMetaConfigs(config.Module.ProviderMetas) + } } for _, r := range config.Module.DataResources { rAddr := r.Addr() @@ -67,6 +85,24 @@ func (t *AttachResourceConfigTransformer) Transform(g *Graph) error { log.Printf("[TRACE] AttachResourceConfigTransformer: attaching to %q (%T) config from %#v", dag.VertexName(v), v, r.DeclRange) arn.AttachResourceConfig(r) + + // attach the provider_meta info + if gnapmc, ok := v.(GraphNodeAttachProviderMetaConfigs); ok { + log.Printf("[TRACE] AttachResourceConfigTransformer: attaching provider meta configs to %s", dag.VertexName(v)) + if config == nil { + log.Printf("[TRACE] AttachResourceConfigTransformer: no config set on the transformer for %s", dag.VertexName(v)) + continue + } + if config.Module == nil { + log.Printf("[TRACE] AttachResourceConfigTransformer: no module in config for %s", dag.VertexName(v)) + continue + } + if config.Module.ProviderMetas == nil { + log.Printf("[TRACE] AttachResourceConfigTransformer: no provider metas defined for %s", dag.VertexName(v)) + continue + } + gnapmc.AttachProviderMetaConfigs(config.Module.ProviderMetas) + } } } diff --git a/website/docs/configuration/terraform.html.md b/website/docs/configuration/terraform.html.md index 50a28e723..6b41b1ee2 100644 --- a/website/docs/configuration/terraform.html.md +++ b/website/docs/configuration/terraform.html.md @@ -179,3 +179,11 @@ The introduction and completion of experiments is reported in [Terraform's changelog](https://github.com/hashicorp/terraform/blob/master/CHANGELOG.md), so you can watch the release notes there to discover which experiment keywords, if any, are available in a particular Terraform release. + +## Passing Metadata to Providers + +The `terraform` block can have a nested `provider_meta` block for each +provider a module is using, if the provider defines a schema for it. This +allows the provider to receive module-specific information. No interpolations +are performed on this block. For more information, see the +[`provider_meta` page](/docs/internals/provider-meta.html). diff --git a/website/docs/internals/provider-meta.html.md b/website/docs/internals/provider-meta.html.md new file mode 100644 index 000000000..9559b6cd5 --- /dev/null +++ b/website/docs/internals/provider-meta.html.md @@ -0,0 +1,71 @@ +--- +layout: "docs" +page_title: "Provider Metadata" +sidebar_current: "docs-internals-provider-meta" +description: |- + For advanced use cases, modules can provide some pre-defined metadata for providers. +--- + +# Provider Metadata + +In some situations it's beneficial for a provider to offer an interface +through which modules can pass it information unrelated to the resources +in the module, but scoped on a per-module basis. The provider metadata +functionality allows a provider to do this in a straightforward way. + +~> **Advanced Topic!** This page covers technical details +of Terraform. You don't need to understand these details to +effectively use Terraform. The details are documented here for +module authors and provider developers working on advanced +functionality. + +~> **Experimental Feature!** This functionality is still considered +experimental, and anyone taking advantage of it should [coordinate +with the Terraform team](https://github.com/hashicorp/terraform/issues/new) +to help the team understand how the feature is being used and to make +sure their use case is taken into account as the feature develops. + +## Defining the Schema + +Before a provider can receive information from a module, the provider +must strictly define the data it can accept. You can do this by setting +the `ProviderMeta` property on your `schema.Provider` struct. Its value +functions similarly to the provider config: a map of strings to the +`schema.Schema` describing the values those strings accept. + +## Using the Data + +When Terraform calls your provider, you can use the `schema.ResourceData` +that your `Create`, `Read`, and `Update` functions already use to get +access to the provider metadata being passed. First define a struct +that matches your schema, then call the `GetProviderSchema` method on +your `schema.ResourceData`, passing a pointer to a variable of that type. +The variable will be populated with the provider metadata, and will return +an error if there was an issue with parsing the data into the struct. + +## Specifying Data in Modules + +To include data in your modules, create a `provider_meta` nested block under +your module's `terraform` block, with the name of the provider it's trying +to pass information to: + +```hcl +terraform { + provider_meta "my-provider" { + hello = "world" + } +} +``` + +The `provider_meta` block must match the schema the provider has defined. + +## Versioning Your Modules + +Any module taking advantage of this functionality must make sure that the +provider metadata supplied matches the schema defined in the provider, and +that the version of Terraform that is being run has support for the provider +metadata functionality. It's therefore recommended that any module taking +advantage of this functionality should specify a minimum Terraform version of +0.13.0 or higher, and a minimum version of each of the providers it specifies +metadata as the first version the schema being used was supported by the +provider. diff --git a/website/layouts/docs.erb b/website/layouts/docs.erb index 38765f2ba..58bb99312 100644 --- a/website/layouts/docs.erb +++ b/website/layouts/docs.erb @@ -472,6 +472,10 @@ > Internal Plugins + + > + Provider Metadata +