From 14253743714f085b81cefe3e5af300bae7c15d55 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Fri, 11 Jun 2021 11:59:49 -0700 Subject: [PATCH] providers: A type for all schemas for a particular provider Previously the "providers" package contained only a type for representing the schema of a particular object within a provider, and the terraform package had the responsibility of aggregating many of those together to describe the entire surface area of a provider. Here we move what was previously terraform.ProviderSchema to instead be providers.Schemas, retaining its existing API otherwise, and leave behind a type alias to allow us to gradually update other references over time. We've gradually been shrinking down the responsibilities of the "terraform" package to just representing the graph components and behaviors anyway, but the specific motivation for doing this _now_ is to allow for other packages to both be called by the terraform package _and_ work with provider schemas at the same time, without creating a package dependency cycle: instead, these other packages can just import the "providers" package and not need to import the "terraform" package at all. For now this does still leave the responsibility for _building_ a providers.Schemas object over in the "terraform" package, because it's currently doing that as part of some larger work that isn't easily separable, and so reorganizing that would be a more involved and riskier change than just moving the existing type elsewhere. --- internal/providers/provider.go | 8 ----- internal/providers/schemas.go | 62 ++++++++++++++++++++++++++++++++++ internal/terraform/schemas.go | 52 ++++++---------------------- 3 files changed, 73 insertions(+), 49 deletions(-) create mode 100644 internal/providers/schemas.go diff --git a/internal/providers/provider.go b/internal/providers/provider.go index 8d3914f00..26d434588 100644 --- a/internal/providers/provider.go +++ b/internal/providers/provider.go @@ -3,7 +3,6 @@ package providers import ( "github.com/zclconf/go-cty/cty" - "github.com/hashicorp/terraform/internal/configs/configschema" "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/tfdiags" ) @@ -88,13 +87,6 @@ type GetProviderSchemaResponse struct { Diagnostics tfdiags.Diagnostics } -// Schema pairs a provider or resource schema with that schema's version. -// This is used to be able to upgrade the schema in UpgradeResourceState. -type Schema struct { - Version int64 - Block *configschema.Block -} - type ValidateProviderConfigRequest struct { // Config is the raw configuration value for the provider. Config cty.Value diff --git a/internal/providers/schemas.go b/internal/providers/schemas.go new file mode 100644 index 000000000..213ff4f0e --- /dev/null +++ b/internal/providers/schemas.go @@ -0,0 +1,62 @@ +package providers + +import ( + "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/internal/configs/configschema" +) + +// Schemas is an overall container for all of the schemas for all configurable +// objects defined within a particular provider. +// +// The schema for each individual configurable object is represented by nested +// instances of type Schema (singular) within this data structure. +// +// This type used to be known as terraform.ProviderSchema, but moved out here +// as part of our ongoing efforts to shrink down the "terraform" package. +// There's still a type alias at the old name, but we should prefer using +// providers.Schema in new code. However, a consequence of this transitional +// situation is that the "terraform" package still has the responsibility for +// constructing a providers.Schemas object based on responses from the provider +// API; hopefully we'll continue this refactor later so that functions in this +// package totally encapsulate the unmarshalling and include this as part of +// providers.GetProviderSchemaResponse. +type Schemas struct { + Provider *configschema.Block + ProviderMeta *configschema.Block + ResourceTypes map[string]*configschema.Block + DataSources map[string]*configschema.Block + + ResourceTypeSchemaVersions map[string]uint64 +} + +// SchemaForResourceType attempts to find a schema for the given mode and type. +// Returns nil if no such schema is available. +func (ss *Schemas) SchemaForResourceType(mode addrs.ResourceMode, typeName string) (schema *configschema.Block, version uint64) { + switch mode { + case addrs.ManagedResourceMode: + return ss.ResourceTypes[typeName], ss.ResourceTypeSchemaVersions[typeName] + case addrs.DataResourceMode: + // Data resources don't have schema versions right now, since state is discarded for each refresh + return ss.DataSources[typeName], 0 + default: + // Shouldn't happen, because the above cases are comprehensive. + return nil, 0 + } +} + +// SchemaForResourceAddr attempts to find a schema for the mode and type from +// the given resource address. Returns nil if no such schema is available. +func (ss *Schemas) SchemaForResourceAddr(addr addrs.Resource) (schema *configschema.Block, version uint64) { + return ss.SchemaForResourceType(addr.Mode, addr.Type) +} + +// Schema pairs a provider or resource schema with that schema's version. +// This is used to be able to upgrade the schema in UpgradeResourceState. +// +// This describes the schema for a single object within a provider. Type +// "Schemas" (plural) instead represents the overall collection of schemas +// for everything within a particular provider. +type Schema struct { + Version int64 + Block *configschema.Block +} diff --git a/internal/terraform/schemas.go b/internal/terraform/schemas.go index d09cc2cb2..24edeb85a 100644 --- a/internal/terraform/schemas.go +++ b/internal/terraform/schemas.go @@ -12,10 +12,16 @@ import ( "github.com/hashicorp/terraform/internal/tfdiags" ) +// ProviderSchema is an alias for providers.Schemas, which is the new location +// for what we originally called terraform.ProviderSchema but which has +// moved out as part of ongoing refactoring to shrink down the main "terraform" +// package. +type ProviderSchema = providers.Schemas + // Schemas is a container for various kinds of schema that Terraform needs // during processing. type Schemas struct { - Providers map[addrs.Provider]*ProviderSchema + Providers map[addrs.Provider]*providers.Schemas Provisioners map[string]*configschema.Block } @@ -24,7 +30,7 @@ type Schemas struct { // // It's usually better to go use the more precise methods offered by type // Schemas to handle this detail automatically. -func (ss *Schemas) ProviderSchema(provider addrs.Provider) *ProviderSchema { +func (ss *Schemas) ProviderSchema(provider addrs.Provider) *providers.Schemas { if ss.Providers == nil { return nil } @@ -76,7 +82,7 @@ func (ss *Schemas) ProvisionerConfig(name string) *configschema.Block { // still valid but may be incomplete. func loadSchemas(config *configs.Config, state *states.State, plugins *contextPlugins) (*Schemas, error) { schemas := &Schemas{ - Providers: map[addrs.Provider]*ProviderSchema{}, + Providers: map[addrs.Provider]*providers.Schemas{}, Provisioners: map[string]*configschema.Block{}, } var diags tfdiags.Diagnostics @@ -89,7 +95,7 @@ func loadSchemas(config *configs.Config, state *states.State, plugins *contextPl return schemas, diags.Err() } -func loadProviderSchemas(schemas map[addrs.Provider]*ProviderSchema, config *configs.Config, state *states.State, plugins *contextPlugins) tfdiags.Diagnostics { +func loadProviderSchemas(schemas map[addrs.Provider]*providers.Schemas, config *configs.Config, state *states.State, plugins *contextPlugins) tfdiags.Diagnostics { var diags tfdiags.Diagnostics ensure := func(fqn addrs.Provider) { @@ -105,7 +111,7 @@ func loadProviderSchemas(schemas map[addrs.Provider]*ProviderSchema, config *con // We'll put a stub in the map so we won't re-attempt this on // future calls, which would then repeat the same error message // multiple times. - schemas[fqn] = &ProviderSchema{} + schemas[fqn] = &providers.Schemas{} diags = diags.Append( tfdiags.Sourceless( tfdiags.Error, @@ -179,39 +185,3 @@ func loadProvisionerSchemas(schemas map[string]*configschema.Block, config *conf return diags } - -// ProviderSchema represents the schema for a provider's own configuration -// and the configuration for some or all of its resources and data sources. -// -// The completeness of this structure depends on how it was constructed. -// When constructed for a configuration, it will generally include only -// 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 - - ResourceTypeSchemaVersions map[string]uint64 -} - -// SchemaForResourceType attempts to find a schema for the given mode and type. -// Returns nil if no such schema is available. -func (ps *ProviderSchema) SchemaForResourceType(mode addrs.ResourceMode, typeName string) (schema *configschema.Block, version uint64) { - switch mode { - case addrs.ManagedResourceMode: - return ps.ResourceTypes[typeName], ps.ResourceTypeSchemaVersions[typeName] - case addrs.DataResourceMode: - // Data resources don't have schema versions right now, since state is discarded for each refresh - return ps.DataSources[typeName], 0 - default: - // Shouldn't happen, because the above cases are comprehensive. - return nil, 0 - } -} - -// SchemaForResourceAddr attempts to find a schema for the mode and type from -// the given resource address. Returns nil if no such schema is available. -func (ps *ProviderSchema) SchemaForResourceAddr(addr addrs.Resource) (schema *configschema.Block, version uint64) { - return ps.SchemaForResourceType(addr.Mode, addr.Type) -}