hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io
Other
42.84k stars 9.56k forks source link

Terraform validate try to execute provider_name.zip #32434

Open grimlokason opened 1 year ago

grimlokason commented 1 year ago

Terraform Version

bash-5.1# terraform version
Terraform v1.3.6
on linux_amd64
+ provider local.terraform.com/root/flexibleengine v1.35.1
+ provider registry.terraform.io/hashicorp/local v1.4.0

Terraform Configuration Files

--- version.tf
terraform {
  required_providers {
    local = "~> 1.0"
    flexibleengine = {
      source  = "local.terraform.com/root/flexibleengine"
      version = "1.35.1"
    }
  }
}
--- modules.tf
module "env_secgroup" {
  source      = "/root/.terraform.d/modules/FlexibleEngineCloud/terraform-flexibleengine-secgroup/v2.0.1"
  name        = "secgroup"
  description = "Allow ports"

  ingress_with_source_cidr = [
    {
      from_port   = 22
      to_port     = 22
      protocol    = "tcp"
      ethertype   = "IPv4"
      source_cidr = "0.0.0.0/0"
    },
    {
      from_port   = 5432
      to_port     = 5432
      protocol    = "tcp"
      ethertype   = "IPv4"
      source_cidr = "0.0.0.0/0"
    }
  ]
}
--- /root/.terraform.d/modules/FlexibleEngineCloud/terraform-flexibleengine-secgroup/v2.0.1/versions.tf
terraform {
  required_providers {
    flexibleengine = {
      source = "local.terraform.com/root/flexibleengine"
    }
  }
  required_version = ">= 0.13"
}

Debug Output

NB : this contains the workaround used to bypass the issue.

https://gist.github.com/grimlokason/7010c546e9084270d6c47b614dd11663

Expected Behavior

terraform validate should not try to use the terraform-provider-flexibleengine_1.35.1_linux_amd64.zip but terraform-provider-flexibleengine_v1.35.1

Actual Behavior

terraform validate crash because it try to execute a zip file instead of a go file with that error :

│ Error: failed to read schema for module.env_secgroup.flexibleengine_networking_secgroup_rule_v2.egress_with_source_security_group_id in local.terraform.com/root/flexibleengine: failed to instantiate provider "local.terraform.com/root/flexibleengine" to obtain schema: fork/exec .terraform/providers/local.terraform.com/root/flexibleengine/1.35.1/linux_amd64/terraform-provider-flexibleengine_1.35.1_linux_amd64.zip: exec format error

Steps to Reproduce


terraform validate``` 

### Additional Context

Nb : i don't know how you can effectively reproduce it since it's using local module/prodivers within a docker container in private registry.

I can try to publish the full project within a docker container, but only after the 2 january.

Best regards.

### References

_No response_
apparentlymart commented 1 year ago

Hi @grimlokason! Thanks for reporting this.

Terraform's current behavior is to search each file in the root of the provider's distribution package until it finds one that has the prefix terraform-provider-NAME, where NAME matches the name given in the last part of the provider's source address.

Terraform behaves this way because historically (before we formalized the plugin packaging format and the registry protocol) provider developers used a variety of different naming schemes and so this prefix-matching approach covers all of the various different naming schemes that older provider packages used, and so allows modern Terraform to still work with some older provider packages.

In your case it seems like for some reason your provider package directory contained the package itself. I'm guessing that's because you manually constructed a local mirror directory for your custom provider and did so by first downloading the zip file and then extracting it. Something like this:

This then caused your mirror directory to contain incorrect package contents for this provider, because you still had the terraform-provider-flexibleengine_1.35.1_linux_amd64.zip in the directory even though that isn't part of the package. If you want to populate a mirror like this then you'll need to remove the archive file afterwards so that the package directory exactly matches the contents of the zip file, without any other files:

If you are careful to make sure that your mirror really is a true mirror of the upstream package -- without any extra files like this one -- then Terraform should be able to use it correctly.

The other thing I'd note is that if you are just mirroring the upstream provider flexibleenginecloud/flexibleengine without making any modifications to it then it would be better to mirror it at the same address it would have in the upstream registry, by extracting its files to the following sub-path:

registry.terraform.io/flexibleenginecloud/flexibleengine/1.35.1/linux_amd64

If you do that then you'll be able to use the provider's typical source address source = "flexibleenginecloud/flexibleengine" instead of re-publishing it at a new address, and any existing modules that use this provider will work against your mirror without any modifications.


We could consider adding a special case to the logic which tries to find the provider executable to not consider any file whose suffix is .zip, but that feels like just hiding a problem rather than fixing it.

I think it would be better to keep this as an error but add an extra hint to the error message if the selected plugin file has a .zip suffix. For example, Terraform could try to execute the file it found and then if it fails first check to see if the filename has a .zip suffix and if so add to the error message:

"Did you forget to clean up the provider's distribution archive after manually extracting it? The provider package directory must exactly match the contents of the archive, with no additional files."

This would then hopefully hint at the correct solution and help ensure that you have a correct mirror, which will then avoid recording incorrect checksums in the dependency lock file that are likely to cause problems when trying to use the same configuration on a different computer later.