-
Notifications
You must be signed in to change notification settings - Fork 9.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
validate: ignore providers with no configuration #24896
validate: ignore providers with no configuration #24896
Conversation
Codecov Report
|
I had to turn take the |
Willing and eager to help this land as part of 0.13 if I can! |
@bendrucker Thank you for this PR, and apologies for the wait! If you could update this PR on top of the latest main branch, I'll review! We are currently in the 0.14 release cycle, so this would be going into 0.15, for transparency (the main branch is targeting 0.15) |
Hi! Happy to update, thrilled to hear this might make 0.15. |
…ty-provider # Conflicts: # terraform/eval_validate.go
Hey @pselle, merged with master! Relocated this logic to its new location, but the change itself remains the same. To my note above:
I noticed that https://github.com/hashicorp/terraform/blob/master/terraform/node_provider.go#L95-L100 So this wouldn't have a side effect of causing a |
terraform/context_validate_test.go
Outdated
@@ -595,7 +595,7 @@ func TestContext2Validate_providerConfig_bad(t *testing.T) { | |||
} | |||
} | |||
|
|||
func TestContext2Validate_providerConfig_badEmpty(t *testing.T) { | |||
func TestContext2Validate_providerConfig_skippedEmpty(t *testing.T) { | |||
m := testModule(t, "validate-bad-pc-empty") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To match things up, it could be nice to rename this file to match "skipped" versus "bad"
terraform/node_provider.go
Outdated
@@ -48,6 +48,13 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi | |||
|
|||
configBody := buildProviderConfig(ctx, n.Addr, n.ProviderConfig()) | |||
|
|||
// if provider config is empty, return early |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More explanation here in the comment would be nice -- why are we returning early? (explain this)
Suggestion, mashed up from the suggestions that led to this PR:
// if a provider config is empty (only an alias), return early and don't continue
// validation. validate doesn't need to fully configure the provider itself, so
// skipping a provider with an implied configuration won't prevent other validation from completing.
terraform/node_provider.go
Outdated
@@ -48,6 +48,13 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi | |||
|
|||
configBody := buildProviderConfig(ctx, n.Addr, n.ProviderConfig()) | |||
|
|||
// if provider config is empty, return early | |||
emptySchema := &configschema.Block{} | |||
_, _, evalDiags := ctx.EvaluateBlock(configBody, emptySchema, nil, EvalDataForNoInstanceKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Silly Terraform tricks: another way to do this (the approach here is totally valid!)
_, noConfigDiags := configBody.Content(&hcl.BodySchema{})
if !noConfigDiags.HasErrors() {
return nil
}
This is more to share, and offer if you like it, but your way works absolutely fine.
The section you've highlighted shows that there's no check to ensure that To say, I've read through to make sure the validation is still happening -- the thing that is not happening is the nil check, which is in the With that, this is looking merge-able to me, provided you rebase the PR (sorry about that 😅 ). |
Appreciate all the notes! Will address everything and fix the conflict this week. |
Ok, took me a bit longer than expected to get back to this, but should be ready! All comments addressed, and the conflict is resolved. |
There was a meaningful conflict with #27261, which added improved error handling when a In order to resolve the conflict, I made the following changes here:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates and rebases (and patience!!) here @bendrucker! Happy to get this merged now!
Awesome, thrilled to see it land! |
@bendrucker so what does the azurerm provider need to do so that it can take advantage of this? i didn't understand your early explanation unfortunately |
Providers don't necessarily need to do anything. Sorry but I'm not going to provide support for your setup, please don't snipe pull requests like this. |
@bendrucker not sure what you mean by snipe, this pr closed an issue the azure rm folks had pointed us to a few times regarding validate requiring the functions block. Sorry my ignorance offended you some way |
@drdamour To clarify "when can I use this" from the Core side, you'll see this behavior in the 0.15 version of Terraform. This code will go out in the next alpha release, and it would be very helpful for you to test this with the AzureRM intersection when that's available (about over two and a half weeks from now is when we expect to ship the next alpha). You won't need to upgrade the provider/change the provider to get access to this behavior. |
@pselle my question was more around your original comments which seemed to indicate further steps are needed “ If provider authors want to have required non-credential fields, they'll need to make the credentials fields optional, and validate in the ConfigureFunc. And even then, there are good reasons to make credentials optional (https://github.com/terraform-providers/terraform-provider-datadog/pull/474). Even the somewhat odd required features {} block in the Azure provider would seem to be compatible with this stance” That seemed like a call to action for the azurerm provider |
@drdamour Yes, I indeed misinterpreted. Not being familiar with the AzureRM provider, I'd recommend raising this issue with them, but I'd really recommend only doing so after you've tested with the next alpha to see if it's relevant. |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. |
This PR changes the behavior of
terraform validate
so that provider schema validation is bypassed if the user does not supply provider configuration. The strategy is pretty simple: if the provider config validates against any empty schema, consider it valid. In other words, if the configuration is completely empty, skip validation against the provider schema. Otherwise, proceed to fetch the provider schema, build the configuration against it, and report errors as usual.I could particularly use guidance on any side effects this might have, particularly if validation is used ahead of other steps that might depend on current behavior.
What follows is a bit of background on the different variations on provider configuration I'm expecting.
The below provider configurations, many of which @apparentlymart described in #21408 (comment), can become valid at runtime but will currently raise errors during a
terraform validate
.Child Module
When authoring a child module, it's useful to
terraform validate
, particularly because it interacts with provider plugins. It's Terraform's "compile" step—we might still have runtime errors, but we're using types correctly.No provider declared, the default instance of this provider will be inherited from the parent
foo
is declared but not configured, and we expect the caller to passproviders = { aws.foo = ... }
.The module inherits a provider in order to dynamically configure another provider (here in a new AWS account). Or perhaps the module just accepts variables and then configures the provider, though this should be uncommon.
I included this as an edit, because my change will end up handling them.
In a child module, this is unnecessary and will lead to weird bugs when the user inevitably doesn't set
providers = { aws = aws }
once and the child provider has none of the configuration the module is supposed to inherit.Terraform could warn on version-only provider blocks in child modules, probably even in validate, I'd be up for working on that in a separate PR.
Root Module
All the same uses of
terraform validate
apply to root modules. The provider configuration is more likely to be populated, but isn't necessarily so.The configuration doesn't declare a provider.
The provider is declared but has no configuration. This configuration is valid at runtime if environment variables satisfy the required provider configuration. And I believe it is also required to enable provider passing to a module, e.g.
providers = { aws.foo = aws }
as in the case 2 for child modules.My experience as a Terraform user has been that writing provider configuration is a rarity and I'm able to rely on environment variables almost exclusively. This has translated nicely to Terraform Cloud (Enterprise in my case) where we've wired up the
tfe_workspace
andtfe_variable
resources in a module that distributes credentials for ~10 providers to the workspaces that need them such that the Terraform configuration repos/directories have zero provider configuration required.The provider supplies at least partial configuration. At this point I think we have to validate what we're given. If provider authors want to have required non-credential fields, they'll need to make the credentials fields optional, and validate in the
ConfigureFunc
. And even then, there are good reasons to make credentials optional (https://github.com/terraform-providers/terraform-provider-datadog/pull/474).Even the somewhat odd required
features {}
block in the Azure provider would seem to be compatible with this stance:https://www.terraform.io/docs/providers/azurerm/index.html#example-usage
This may not entirely satisfy users who'd like all required fields to be optional, but I don't see how we can accomplish that without throwing away legitimate errors. Azure is a good example there,
features {}
is required, it would be wrong forterraform validate
to preempt or discard an error. Required fields are often credentials which probably useschema.EnvDefaultFunc
, but there's no simple/safe heuristic Terraform could use to ignore those errors.Closes #21408