Skip to content
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

Config() rpc call failing when terraform variable has default value but no type defined #1300

Closed
Vince-Chenal opened this issue Jan 21, 2022 · 4 comments
Labels

Comments

@Vince-Chenal
Copy link

I was writing a custom tflint ruleset and found this problem.

My usecase is to be able to verify that any aws provider has default_tags block defined.

I can use RootProvider() function to get a provider by name like this:

runner.RootProvider("aws")
runner.RootProvider("aws.<some_alias>")

But I don't know the aliases in advance, so I need a way to list providers first.

I found this issue in which I saw that there was no official way for listing providers and that the only way was calling the Config() function and then search for .Module.ProviderConfigs inside.

Trying to do so, I got a lot of errors like this one:

$ tflint --only=myrule
Failed to check ruleset. An error occurred:

Error: Failed to check `myrule` rule: variables.tf:1,1-16: cannot unmarshal variable default value; msgpack: invalid code=a6 decoding array length

After investigations I found that the problem was that Config() function is unable to encode variables that have a default value but no type defined.

I think having a RootProviders() function listing all providers as suggested here would be the best option.

In the meantime I'll stick with Config() function and catch the error.

Steps to reproduce

tflint custom rule

...
func (r *MyCustomRule) Name() string {
	return "myrule"
}
...
func (r *MyCustomRule) Check(runner tflint.Runner) error {
	conf, err := runner.Config()
	if err != nil {
		return err
	}
	_ = conf

	return nil
}
...

Terraform

Working:

variable "test" {
    default = 123
    type    = number
}
$ tflint --only=myrule

Not Working:

variable "test" {
    default = 123
}
$ tflint --only=myrule
Failed to check ruleset. An error occurred:

Error: Failed to check `myrule` rule: variables.tf:1,1-16: cannot unmarshal variable default value; msgpack: invalid code=a6 decoding array length

Version

$ tflint -v
TFLint version 0.34.1
+ ruleset.aws (0.11.0)
+ ruleset.myrule (0.0.1)

$ terraform -v
Terraform v1.1.4
@wata727
Copy link
Member

wata727 commented Jan 23, 2022

Hi @Vince-Chenal, thank you for opening this issue.

I'm currently working on a major update to the plugin API, and perhaps the new API will be able to meet this requirement.
For example, you can get a list of providers in the root module like this:

providers, _ := runner.GetModuleContent(&hclext.BodySchema{
    Blocks: []hclext.BlockSchema{
        {
            Type: "provider",
            LabelNames: []string{"name"},
            Body: &hclext.BodySchema{
                Attributes: []hclext.AttributeSchema{{Name: "default_tags"}},
            },
        },
    },
}, nil)

for _, provider := range providers.Blocks {
    provider.Body.Attributes["default_tags"].Expr // => An expression of `default_tags`
}

Please see here for details. You can try out the new API by building these.

If you're in a hurry, it's a bug that causes an error in the current Config(), and we can fix it. I'm happy to review it.

@wata727 wata727 added the bug label Jan 23, 2022
@Vince-Chenal
Copy link
Author

Hey @wata727,
Thanks for your answer. I did not have the time to dig into the actual issue in Config() yet so I don't know if it's easily fixable or not.
Good to hear that the tool is alive and evolving 👍

@Vince-Chenal
Copy link
Author

Vince-Chenal commented Mar 30, 2022

Hey @wata727,

I've been trying to adapt my custom plugin to the new sdk version with success so far.
But I just found something which I wanted to ask you about.

At some point I need to retrieve all the aws providers so I wrote the following code as you suggested:

providers, err := runner.GetModuleContent(&hclext.BodySchema{
	Blocks: []hclext.BlockSchema{
		{
			Type:       "provider",
			LabelNames: []string{"name"},
			Body: &hclext.BodySchema{
				Attributes: []hclext.AttributeSchema{{Name: "default_tags"}},
			},
		},
	},
}, nil)
if err != nil {
	return err
}

I thought the schema would act as some kind of filter (retrieving only the providers that match this schema) but in the result I get all the providers and not only the ones that match the schema.
It's not a problem since I can re-filter everything myself but I was wondering if I was doing something weird.

Am I missing something?

@wata727
Copy link
Member

wata727 commented Mar 30, 2022

This is intended behavior. Top-level schemas only match provider blocks, but nested schemas are always optional. So, it also matches provider blocks that do not have default_tags. However, these blocks do not have any attributes.
This is so that you can get a provider that does not have a specific attribute.

The original issue has been fixed in v0.35, so close this issue. If you have any other questions about the SDK's usage, open a new issue in https://github.com/terraform-linters/tflint-plugin-sdk.

@wata727 wata727 closed this as completed Mar 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants