From 9848ca2edf0e3593370bd668d1502dbb8000a315 Mon Sep 17 00:00:00 2001 From: Marcela Campo Date: Tue, 9 Apr 2024 11:26:18 +0100 Subject: [PATCH] fix: change tofu unpacking to default to terraform registry (#1001) * fix: default to registry.terraform.io as the default unpacking location when reading a brokerpak and creating the plugins folder, we were defaulting the domain of the providers to registry.opentofu.org instead of registry.terraform.io. This was not consistent with our default for the download location, which is registry.terraform.io. It now defaults to terraform registry in both places. This means brokerpaks which don't indicate any domain in their provider definitions in the manifest.yml file, will need to fully qualify the provider in the required_providers block to avoid errors, as OpenTofu will default to the opentofu registry. [#187379198](https://www.pivotaltracker.com/story/show/187379198) * fix: workaround to prevent tofu from renaming providers on show when fixing [this issue in tofu](https://github.com/opentofu/opentofu/issues/1139) some logic was introduced to change the hostname of the providers to [#187199940](https://www.pivotaltracker.com/story/show/187199940) point to the opentofu registry (in-memory) when executing a show, if the terraform code didn't specify a hostname in the provider's block. However this functionality seems to be buggy and it is renaming providers regardless, which breaks the tf_attribute_skip functionality. A way to disable this rename is to set the OPENTOFU_STATEFILE_PROVIDER_ADDRESS_TRANSLATION environment variable to `0`. This PR implements that workaround for the broker. [#187379198](https://www.pivotaltracker.com/story/show/187379198) Co-authored-by: Felisia Martini * chore: tidy up go.mod [#187379198](https://www.pivotaltracker.com/story/show/187379198) Co-authored-by: Marcela Campo * chore: add reference to opentofu issue [#187379198](https://www.pivotaltracker.com/story/show/187379198) Co-authored-by: Felisia Martini --------- Co-authored-by: Felisia Martini --- go.sum | 2 - .../fixtures/binding-cleanup/fake-bad-bind.tf | 8 ++++ .../binding-cleanup/fake-good-bind.tf | 8 ++++ .../binding-cleanup/fake-provision.tf | 8 ++++ .../fixtures/golden-path/fake-uuid-bind.tf | 8 ++++ .../golden-path/fake-uuid-provision.tf | 8 ++++ .../maintenance-info/fake-provision.tf | 2 +- .../fixtures/osbapi/fake-provision.tf | 8 +++- .../fake-provision.tf | 8 +++- .../fake-string-provision.tf | 8 ++++ .../fixtures/subsume/fake-string-service.yml | 1 + .../fixtures/subsume/fake-uuid-service.yml | 1 + integrationtest/fixtures/subsume/versions.tf | 7 ++++ .../termination-recovery/fake-uuid-bind.tf | 8 ++++ .../fake-uuid-provision.tf | 8 ++++ .../fake-provision.tf | 2 +- .../fake-provision.tf | 8 ++++ .../fake-provision.tf | 2 +- .../fake-provision.tf | 8 +++- .../fake-provision.tf | 2 +- .../terraform-upgrade-updated/fake-bind.tf | 2 +- .../fake-provision.tf | 2 +- .../fixtures/terraform-upgrade/fake-bind.tf | 8 +++- .../terraform-upgrade/fake-provision.tf | 8 +++- .../tf_attribute_skip/fake-provision.tf | 10 ----- .../tf_attribute_skip/fake-service.yml | 1 + .../fixtures/tf_attribute_skip/versions.tf | 8 ++++ integrationtest/subsume_test.go | 3 +- internal/brokerpak/manifest/parser_test.go | 6 +-- internal/brokerpak/reader/reader.go | 6 +++ internal/brokerpak/reader/reader_test.go | 9 ++++- internal/tfproviderfqn/tfproviderfqn.go | 2 +- internal/tfproviderfqn/tfproviderfqn_test.go | 8 ++-- pkg/providers/tf/command/command.go | 1 + pkg/providers/tf/command/terraform_command.go | 30 ++++++++++++++ .../tf/command/terraform_command_test.go | 27 +++++++++++-- pkg/providers/tf/workspace/workspace.go | 2 +- pkg/providers/tf/workspace/workspace_test.go | 40 +++++++++++++++++++ 38 files changed, 249 insertions(+), 39 deletions(-) create mode 100644 integrationtest/fixtures/subsume/versions.tf create mode 100644 integrationtest/fixtures/tf_attribute_skip/versions.tf diff --git a/go.sum b/go.sum index b93460350..a5d124db2 100644 --- a/go.sum +++ b/go.sum @@ -718,8 +718,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= diff --git a/integrationtest/fixtures/binding-cleanup/fake-bad-bind.tf b/integrationtest/fixtures/binding-cleanup/fake-bad-bind.tf index 9de1f243c..47edd5e47 100644 --- a/integrationtest/fixtures/binding-cleanup/fake-bad-bind.tf +++ b/integrationtest/fixtures/binding-cleanup/fake-bad-bind.tf @@ -1,4 +1,12 @@ // Fails as required "length" parameter is missing +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} + resource "random_string" "random" {} output bind_output { value = random_string.random.result } \ No newline at end of file diff --git a/integrationtest/fixtures/binding-cleanup/fake-good-bind.tf b/integrationtest/fixtures/binding-cleanup/fake-good-bind.tf index fcbed15be..a214915a0 100644 --- a/integrationtest/fixtures/binding-cleanup/fake-good-bind.tf +++ b/integrationtest/fixtures/binding-cleanup/fake-good-bind.tf @@ -1,3 +1,11 @@ +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} + resource "random_string" "random" { length = 10 } diff --git a/integrationtest/fixtures/binding-cleanup/fake-provision.tf b/integrationtest/fixtures/binding-cleanup/fake-provision.tf index adbe4074b..db12d4a33 100644 --- a/integrationtest/fixtures/binding-cleanup/fake-provision.tf +++ b/integrationtest/fixtures/binding-cleanup/fake-provision.tf @@ -1,3 +1,11 @@ +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} + resource "random_uuid" "random" {} output provision_output { value = random_uuid.random.result } \ No newline at end of file diff --git a/integrationtest/fixtures/golden-path/fake-uuid-bind.tf b/integrationtest/fixtures/golden-path/fake-uuid-bind.tf index 3820163a0..7c92100ef 100644 --- a/integrationtest/fixtures/golden-path/fake-uuid-bind.tf +++ b/integrationtest/fixtures/golden-path/fake-uuid-bind.tf @@ -1,3 +1,11 @@ +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} + resource "random_uuid" "random" {} output bind_output { value = random_uuid.random.result } \ No newline at end of file diff --git a/integrationtest/fixtures/golden-path/fake-uuid-provision.tf b/integrationtest/fixtures/golden-path/fake-uuid-provision.tf index adbe4074b..db12d4a33 100644 --- a/integrationtest/fixtures/golden-path/fake-uuid-provision.tf +++ b/integrationtest/fixtures/golden-path/fake-uuid-provision.tf @@ -1,3 +1,11 @@ +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} + resource "random_uuid" "random" {} output provision_output { value = random_uuid.random.result } \ No newline at end of file diff --git a/integrationtest/fixtures/maintenance-info/fake-provision.tf b/integrationtest/fixtures/maintenance-info/fake-provision.tf index a815f8953..f3a9b7dd4 100644 --- a/integrationtest/fixtures/maintenance-info/fake-provision.tf +++ b/integrationtest/fixtures/maintenance-info/fake-provision.tf @@ -1,7 +1,7 @@ terraform { required_providers { random = { - source = "hashicorp/random" + source = "registry.terraform.io/hashicorp/random" version = "3.5.1" } } diff --git a/integrationtest/fixtures/osbapi/fake-provision.tf b/integrationtest/fixtures/osbapi/fake-provision.tf index 266b79568..364770813 100644 --- a/integrationtest/fixtures/osbapi/fake-provision.tf +++ b/integrationtest/fixtures/osbapi/fake-provision.tf @@ -1,4 +1,10 @@ -provider "random" { } +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} resource "random_integer" "priority" { min = 1 diff --git a/integrationtest/fixtures/prevent-destroy-during-update/fake-provision.tf b/integrationtest/fixtures/prevent-destroy-during-update/fake-provision.tf index 27a2decb7..84864d59b 100644 --- a/integrationtest/fixtures/prevent-destroy-during-update/fake-provision.tf +++ b/integrationtest/fixtures/prevent-destroy-during-update/fake-provision.tf @@ -1,4 +1,10 @@ -provider "random" { } +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} variable length { type = number } diff --git a/integrationtest/fixtures/provision-cleanup/fake-string-provision.tf b/integrationtest/fixtures/provision-cleanup/fake-string-provision.tf index c53142595..773443262 100644 --- a/integrationtest/fixtures/provision-cleanup/fake-string-provision.tf +++ b/integrationtest/fixtures/provision-cleanup/fake-string-provision.tf @@ -1,4 +1,12 @@ // Fails as required "length" parameter is missing +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} + resource "random_string" "random" {} output provision_output { value = random_string.random.result } \ No newline at end of file diff --git a/integrationtest/fixtures/subsume/fake-string-service.yml b/integrationtest/fixtures/subsume/fake-string-service.yml index cddbf098f..108b71257 100644 --- a/integrationtest/fixtures/subsume/fake-string-service.yml +++ b/integrationtest/fixtures/subsume/fake-string-service.yml @@ -24,6 +24,7 @@ provision: import_parameters_to_delete: [ "random_string.random.id", "random_string.random.result" ] template_refs: main: fake-string-provision.tf + versions: versions.tf outputs: - field_name: provision_output type: string diff --git a/integrationtest/fixtures/subsume/fake-uuid-service.yml b/integrationtest/fixtures/subsume/fake-uuid-service.yml index 02ee298c6..ae1fe29be 100644 --- a/integrationtest/fixtures/subsume/fake-uuid-service.yml +++ b/integrationtest/fixtures/subsume/fake-uuid-service.yml @@ -21,6 +21,7 @@ provision: import_parameters_to_delete: [ "random_uuid.random.id" , "random_uuid.random.result" ] template_refs: main: fake-uuid-provision.tf + versions: versions.tf outputs: - field_name: provision_output type: string diff --git a/integrationtest/fixtures/subsume/versions.tf b/integrationtest/fixtures/subsume/versions.tf new file mode 100644 index 000000000..09be45e87 --- /dev/null +++ b/integrationtest/fixtures/subsume/versions.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} diff --git a/integrationtest/fixtures/termination-recovery/fake-uuid-bind.tf b/integrationtest/fixtures/termination-recovery/fake-uuid-bind.tf index 3820163a0..7c92100ef 100644 --- a/integrationtest/fixtures/termination-recovery/fake-uuid-bind.tf +++ b/integrationtest/fixtures/termination-recovery/fake-uuid-bind.tf @@ -1,3 +1,11 @@ +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} + resource "random_uuid" "random" {} output bind_output { value = random_uuid.random.result } \ No newline at end of file diff --git a/integrationtest/fixtures/termination-recovery/fake-uuid-provision.tf b/integrationtest/fixtures/termination-recovery/fake-uuid-provision.tf index adbe4074b..db12d4a33 100644 --- a/integrationtest/fixtures/termination-recovery/fake-uuid-provision.tf +++ b/integrationtest/fixtures/termination-recovery/fake-uuid-provision.tf @@ -1,3 +1,11 @@ +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} + resource "random_uuid" "random" {} output provision_output { value = random_uuid.random.result } \ No newline at end of file diff --git a/integrationtest/fixtures/terraform-block-action-before-upgrade-updated/fake-provision.tf b/integrationtest/fixtures/terraform-block-action-before-upgrade-updated/fake-provision.tf index a815f8953..f3a9b7dd4 100644 --- a/integrationtest/fixtures/terraform-block-action-before-upgrade-updated/fake-provision.tf +++ b/integrationtest/fixtures/terraform-block-action-before-upgrade-updated/fake-provision.tf @@ -1,7 +1,7 @@ terraform { required_providers { random = { - source = "hashicorp/random" + source = "registry.terraform.io/hashicorp/random" version = "3.5.1" } } diff --git a/integrationtest/fixtures/terraform-block-action-before-upgrade/fake-provision.tf b/integrationtest/fixtures/terraform-block-action-before-upgrade/fake-provision.tf index 266b79568..0934e7635 100644 --- a/integrationtest/fixtures/terraform-block-action-before-upgrade/fake-provision.tf +++ b/integrationtest/fixtures/terraform-block-action-before-upgrade/fake-provision.tf @@ -1,3 +1,11 @@ +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} + provider "random" { } resource "random_integer" "priority" { diff --git a/integrationtest/fixtures/terraform-module-upgrade-updated/fake-provision.tf b/integrationtest/fixtures/terraform-module-upgrade-updated/fake-provision.tf index f495d310e..f3727e069 100644 --- a/integrationtest/fixtures/terraform-module-upgrade-updated/fake-provision.tf +++ b/integrationtest/fixtures/terraform-module-upgrade-updated/fake-provision.tf @@ -1,7 +1,7 @@ terraform { required_providers { random = { - source = "hashicorp/random" + source = "registry.terraform.io/hashicorp/random" version = "3.5.1" } } diff --git a/integrationtest/fixtures/terraform-module-upgrade/fake-provision.tf b/integrationtest/fixtures/terraform-module-upgrade/fake-provision.tf index 7f81ef008..902b2254d 100644 --- a/integrationtest/fixtures/terraform-module-upgrade/fake-provision.tf +++ b/integrationtest/fixtures/terraform-module-upgrade/fake-provision.tf @@ -1,4 +1,10 @@ -provider "random" { } +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} resource "random_password" "password" { length = 5 diff --git a/integrationtest/fixtures/terraform-rename-provider/fake-provision.tf b/integrationtest/fixtures/terraform-rename-provider/fake-provision.tf index a0e2b6d3d..f4a462069 100644 --- a/integrationtest/fixtures/terraform-rename-provider/fake-provision.tf +++ b/integrationtest/fixtures/terraform-rename-provider/fake-provision.tf @@ -1,7 +1,7 @@ terraform { required_providers { random = { - source = "ContentSquare/random" + source = "registry.terraform.io/ContentSquare/random" version = "3.1.0" } } diff --git a/integrationtest/fixtures/terraform-upgrade-updated/fake-bind.tf b/integrationtest/fixtures/terraform-upgrade-updated/fake-bind.tf index f1a26f231..b110440d3 100644 --- a/integrationtest/fixtures/terraform-upgrade-updated/fake-bind.tf +++ b/integrationtest/fixtures/terraform-upgrade-updated/fake-bind.tf @@ -1,7 +1,7 @@ terraform { required_providers { random = { - source = "hashicorp/random" + source = "registry.terraform.io/hashicorp/random" version = "3.5.1" } } diff --git a/integrationtest/fixtures/terraform-upgrade-updated/fake-provision.tf b/integrationtest/fixtures/terraform-upgrade-updated/fake-provision.tf index 333608861..de374db86 100644 --- a/integrationtest/fixtures/terraform-upgrade-updated/fake-provision.tf +++ b/integrationtest/fixtures/terraform-upgrade-updated/fake-provision.tf @@ -1,7 +1,7 @@ terraform { required_providers { random = { - source = "hashicorp/random" + source = "registry.terraform.io/hashicorp/random" version = "3.5.1" } } diff --git a/integrationtest/fixtures/terraform-upgrade/fake-bind.tf b/integrationtest/fixtures/terraform-upgrade/fake-bind.tf index 6e2687d35..0ef2520a4 100644 --- a/integrationtest/fixtures/terraform-upgrade/fake-bind.tf +++ b/integrationtest/fixtures/terraform-upgrade/fake-bind.tf @@ -1,4 +1,10 @@ -provider "random" { } +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} resource "random_integer" "priority" { min = 1 diff --git a/integrationtest/fixtures/terraform-upgrade/fake-provision.tf b/integrationtest/fixtures/terraform-upgrade/fake-provision.tf index 6e2687d35..0ef2520a4 100644 --- a/integrationtest/fixtures/terraform-upgrade/fake-provision.tf +++ b/integrationtest/fixtures/terraform-upgrade/fake-provision.tf @@ -1,4 +1,10 @@ -provider "random" { } +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + } + } +} resource "random_integer" "priority" { min = 1 diff --git a/integrationtest/fixtures/tf_attribute_skip/fake-provision.tf b/integrationtest/fixtures/tf_attribute_skip/fake-provision.tf index 2cd10bf80..145b86a3e 100644 --- a/integrationtest/fixtures/tf_attribute_skip/fake-provision.tf +++ b/integrationtest/fixtures/tf_attribute_skip/fake-provision.tf @@ -1,15 +1,5 @@ ## new versions of terraform fail with a different error to the one we want to trigger if this file is empty. ## adding some dummy terraform to test errors when a particular field is not present. - -terraform { - required_providers { - random = { - source = "hashicorp/random" - version = "3.5.1" - } - } -} - resource "random_integer" "priority" { min = 3 max = 4 diff --git a/integrationtest/fixtures/tf_attribute_skip/fake-service.yml b/integrationtest/fixtures/tf_attribute_skip/fake-service.yml index 15d9be5d2..ea3756800 100644 --- a/integrationtest/fixtures/tf_attribute_skip/fake-service.yml +++ b/integrationtest/fixtures/tf_attribute_skip/fake-service.yml @@ -20,6 +20,7 @@ plans: provision: template_refs: main: fake-provision.tf + versions: versions.tf user_inputs: - field_name: skip type: boolean diff --git a/integrationtest/fixtures/tf_attribute_skip/versions.tf b/integrationtest/fixtures/tf_attribute_skip/versions.tf new file mode 100644 index 000000000..577c5f6b9 --- /dev/null +++ b/integrationtest/fixtures/tf_attribute_skip/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.5.1" + } + } +} diff --git a/integrationtest/subsume_test.go b/integrationtest/subsume_test.go index dc268df5a..31b78cf44 100644 --- a/integrationtest/subsume_test.go +++ b/integrationtest/subsume_test.go @@ -31,7 +31,8 @@ var _ = Describe("Subsume", func() { It("can subsume a resource", func() { const serviceOfferingGUID = "547cad88-fa93-11eb-9f44-97feefe52547" const servicePlanGUID = "59624c68-fa93-11eb-9081-e79b0e1ab5ae" - broker.Provision(serviceOfferingGUID, servicePlanGUID, testdrive.WithProvisionParams(`{"value":"a97fd57a-fa94-11eb-8256-930255607a99"}`)) + _, err := broker.Provision(serviceOfferingGUID, servicePlanGUID, testdrive.WithProvisionParams(`{"value":"a97fd57a-fa94-11eb-8256-930255607a99"}`)) + Expect(err).NotTo(HaveOccurred()) }) It("cancels a subsume operation when a resource would be deleted", func() { diff --git a/internal/brokerpak/manifest/parser_test.go b/internal/brokerpak/manifest/parser_test.go index 5db35376b..444f9bd52 100644 --- a/internal/brokerpak/manifest/parser_test.go +++ b/internal/brokerpak/manifest/parser_test.go @@ -320,9 +320,9 @@ var _ = Describe("Parser", func() { Expect(err).NotTo(HaveOccurred()) Expect(m.TerraformProviders[1].Provider.String()).To(Equal(expected)) }, - Entry("empty 'provider' field", "", "registry.opentofu.org/hashicorp/foo"), - Entry("just type", "lala", "registry.opentofu.org/hashicorp/lala"), - Entry("type and namespace", "mycorp/lala", "registry.opentofu.org/mycorp/lala"), + Entry("empty 'provider' field", "", "registry.terraform.io/hashicorp/foo"), + Entry("just type", "lala", "registry.terraform.io/hashicorp/lala"), + Entry("type and namespace", "mycorp/lala", "registry.terraform.io/mycorp/lala"), Entry("fully qualified", "mything.io/mycorp/lala", "mything.io/mycorp/lala"), ) diff --git a/internal/brokerpak/reader/reader.go b/internal/brokerpak/reader/reader.go index d4373d5e7..e9fa35796 100644 --- a/internal/brokerpak/reader/reader.go +++ b/internal/brokerpak/reader/reader.go @@ -19,6 +19,7 @@ import ( "archive/zip" "fmt" "io" + "log" "os" "path" "path/filepath" @@ -268,6 +269,11 @@ func (pak *BrokerPakReader) readBytes(name string) ([]byte, error) { func providerInstallPath(destination string, tfProvider manifest.TerraformProvider) string { plat := platform.CurrentPlatform() + log.Println("ProviderInstallPath:", filepath.Join( + destination, + tfProvider.Provider.String(), + tfProvider.Version.String(), + fmt.Sprintf("%s_%s", plat.Os, plat.Arch))) return filepath.Join( destination, tfProvider.Provider.String(), diff --git a/internal/brokerpak/reader/reader_test.go b/internal/brokerpak/reader/reader_test.go index d0dfee1f1..363884c72 100644 --- a/internal/brokerpak/reader/reader_test.go +++ b/internal/brokerpak/reader/reader_test.go @@ -35,6 +35,7 @@ var _ = Describe("reader", func() { withTerraform(binaryV160), withProvider("", "terraform-provider-google-beta", "1.19.0", "x4"), withProvider("other-namespace/google", "terraform-provider-google", "1.19.0", "x5"), + withProvider("custom.registry.org/other-namespace/custom", "terraform-provider-custom", "1.19.0", "x5"), ) pakReader, err := reader.OpenBrokerPak(pk) @@ -44,11 +45,15 @@ var _ = Describe("reader", func() { Expect(pakReader.ExtractPlatformBins(binOutput)).NotTo(HaveOccurred()) plat := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH) - hashicorpBinOutput := filepath.Join(binOutput, "registry.opentofu.org", "hashicorp") + hashicorpBinOutput := filepath.Join(binOutput, "registry.terraform.io", "hashicorp") Expect(filepath.Join(hashicorpBinOutput, "google-beta", "1.19.0", plat, "terraform-provider-google-beta_v1.19.0_x4")).To(BeAnExistingFile()) - otherNamespaceBinOutput := filepath.Join(binOutput, "registry.opentofu.org", "other-namespace") + otherNamespaceBinOutput := filepath.Join(binOutput, "registry.terraform.io", "other-namespace") Expect(filepath.Join(otherNamespaceBinOutput, "google", "1.19.0", plat, "terraform-provider-google_v1.19.0_x5")).To(BeAnExistingFile()) + + customDomainBinOutput := filepath.Join(binOutput, "custom.registry.org", "other-namespace") + Expect(filepath.Join(customDomainBinOutput, "custom", "1.19.0", plat, "terraform-provider-custom_v1.19.0_x5")).To(BeAnExistingFile()) + }) Context("single version of tofu", func() { diff --git a/internal/tfproviderfqn/tfproviderfqn.go b/internal/tfproviderfqn/tfproviderfqn.go index af01bd681..26ed9226d 100644 --- a/internal/tfproviderfqn/tfproviderfqn.go +++ b/internal/tfproviderfqn/tfproviderfqn.go @@ -5,7 +5,7 @@ import "fmt" const ( prefix = "terraform-provider-" - defaultRegistry = "registry.opentofu.org" + defaultRegistry = "registry.terraform.io" defaultNamespace = "hashicorp" ) diff --git a/internal/tfproviderfqn/tfproviderfqn_test.go b/internal/tfproviderfqn/tfproviderfqn_test.go index a5bc97d48..0959d951f 100644 --- a/internal/tfproviderfqn/tfproviderfqn_test.go +++ b/internal/tfproviderfqn/tfproviderfqn_test.go @@ -9,14 +9,14 @@ import ( "github.com/cloudfoundry/cloud-service-broker/internal/tfproviderfqn" ) -const defaultRegistrydomain = "registry.opentofu.org" +const defaultRegistryDomain = "registry.terraform.io" var _ = Describe("TfProviderFQN", func() { Context("from name", func() { It("can be created from a name", func() { n, err := tfproviderfqn.New("terraform-provider-mysql", "") Expect(err).NotTo(HaveOccurred()) - Expect(n.String()).To(Equal(fmt.Sprintf("%s/hashicorp/mysql", defaultRegistrydomain))) + Expect(n.String()).To(Equal(fmt.Sprintf("%s/hashicorp/mysql", defaultRegistryDomain))) }) When("the name has the wrong prefix", func() { @@ -32,13 +32,13 @@ var _ = Describe("TfProviderFQN", func() { It("can be created from the type", func() { n, err := tfproviderfqn.New("", "postgresql") Expect(err).NotTo(HaveOccurred()) - Expect(n.String()).To(Equal(fmt.Sprintf("%s/hashicorp/postgresql", defaultRegistrydomain))) + Expect(n.String()).To(Equal(fmt.Sprintf("%s/hashicorp/postgresql", defaultRegistryDomain))) }) It("can be created from the namespace and type", func() { n, err := tfproviderfqn.New("", "cyrilgdn/postgresql") Expect(err).NotTo(HaveOccurred()) - Expect(n.String()).To(Equal(fmt.Sprintf("%s/cyrilgdn/postgresql", defaultRegistrydomain))) + Expect(n.String()).To(Equal(fmt.Sprintf("%s/cyrilgdn/postgresql", defaultRegistryDomain))) }) It("can be created from the registry, namespace and type", func() { diff --git a/pkg/providers/tf/command/command.go b/pkg/providers/tf/command/command.go index 1e0aaf51c..ae1f32eb9 100644 --- a/pkg/providers/tf/command/command.go +++ b/pkg/providers/tf/command/command.go @@ -3,4 +3,5 @@ package command type TerraformCommand interface { Command() []string + Env() []string } diff --git a/pkg/providers/tf/command/terraform_command.go b/pkg/providers/tf/command/terraform_command.go index 37f5cb12b..accb176a3 100644 --- a/pkg/providers/tf/command/terraform_command.go +++ b/pkg/providers/tf/command/terraform_command.go @@ -16,11 +16,20 @@ func (cmd initCommand) Command() []string { return []string{"init", fmt.Sprintf("-plugin-dir=%s", cmd.pluginDir), "-no-color"} } +func (cmd initCommand) Env() []string { + return []string{} +} + type apply struct{} func NewApply() TerraformCommand { return apply{} } + +func (cmd apply) Env() []string { + return []string{} +} + func (apply) Command() []string { return []string{"apply", "-auto-approve", "-no-color"} } @@ -35,6 +44,10 @@ func (destroy) Command() []string { return []string{"destroy", "-auto-approve", "-no-color"} } +func (cmd destroy) Env() []string { + return []string{} +} + func NewShow() TerraformCommand { return show{} } @@ -45,6 +58,11 @@ func (show) Command() []string { return []string{"show", "-no-color"} } +func (cmd show) Env() []string { + // workaround for bug introduced by https://github.com/opentofu/opentofu/issues/1139 + return []string{"OPENTOFU_STATEFILE_PROVIDER_ADDRESS_TRANSLATION=0"} +} + func NewPlan() TerraformCommand { return plan{} } @@ -55,6 +73,10 @@ func (plan) Command() []string { return []string{"plan", "-no-color"} } +func (cmd plan) Env() []string { + return []string{} +} + func NewImport(addr, id string) TerraformCommand { return importCmd{Addr: addr, ID: id} } @@ -68,6 +90,10 @@ func (cmd importCmd) Command() []string { return []string{"import", cmd.Addr, cmd.ID} } +func (cmd importCmd) Env() []string { + return []string{} +} + type renameProvider struct { oldProviderName string newProviderName string @@ -80,3 +106,7 @@ func (cmd renameProvider) Command() []string { func NewRenameProvider(oldProviderName, newProviderName string) TerraformCommand { return renameProvider{oldProviderName: oldProviderName, newProviderName: newProviderName} } + +func (cmd renameProvider) Env() []string { + return []string{} +} diff --git a/pkg/providers/tf/command/terraform_command_test.go b/pkg/providers/tf/command/terraform_command_test.go index e124f54f2..6035fff91 100644 --- a/pkg/providers/tf/command/terraform_command_test.go +++ b/pkg/providers/tf/command/terraform_command_test.go @@ -11,20 +11,39 @@ var _ = Context("Terraform Commands", func() { It("calls init with the plugin directory", func() { initCommand := command.NewInit("plugindir") Expect(initCommand.Command()).To(Equal([]string{"init", "-plugin-dir=plugindir", "-no-color"})) + Expect(initCommand.Env()).To(BeEmpty()) }) }) Context("apply", func() { - It("calls init with the plugin directory", func() { + It("calls apply with the right options", func() { apply := command.NewApply() Expect(apply.Command()).To(Equal([]string{"apply", "-auto-approve", "-no-color"})) + Expect(apply.Env()).To(BeEmpty()) }) }) Context("Destroy", func() { - It("calls init with the plugin directory", func() { - apply := command.NewDestroy() - Expect(apply.Command()).To(Equal([]string{"destroy", "-auto-approve", "-no-color"})) + It("calls destroy with the right options", func() { + destroy := command.NewDestroy() + Expect(destroy.Command()).To(Equal([]string{"destroy", "-auto-approve", "-no-color"})) + Expect(destroy.Env()).To(BeEmpty()) + }) + }) + + Context("Show", func() { + It("calls show with the right env variables", func() { + show := command.NewShow() + Expect(show.Command()).To(Equal([]string{"show", "-no-color"})) + Expect(show.Env()).To(Equal([]string{"OPENTOFU_STATEFILE_PROVIDER_ADDRESS_TRANSLATION=0"})) + }) + }) + + Context("Plan", func() { + It("calls show with the right env variables", func() { + plan := command.NewPlan() + Expect(plan.Command()).To(Equal([]string{"plan", "-no-color"})) + Expect(plan.Env()).To(BeEmpty()) }) }) }) diff --git a/pkg/providers/tf/workspace/workspace.go b/pkg/providers/tf/workspace/workspace.go index 8b5b60aa6..d4e2da813 100644 --- a/pkg/providers/tf/workspace/workspace.go +++ b/pkg/providers/tf/workspace/workspace.go @@ -322,7 +322,7 @@ func (workspace *TerraformWorkspace) Execute(ctx context.Context, terraformExecu for _, cmd := range commands { c := exec.Command(binaryName, cmd.Command()...) - c.Env = os.Environ() + c.Env = append(os.Environ(), cmd.Env()...) c.Dir = workspace.dir lastExecutionOutput, err = terraformExecutor.Execute(ctx, c) diff --git a/pkg/providers/tf/workspace/workspace_test.go b/pkg/providers/tf/workspace/workspace_test.go index ae196c11a..1d01d19f5 100644 --- a/pkg/providers/tf/workspace/workspace_test.go +++ b/pkg/providers/tf/workspace/workspace_test.go @@ -213,6 +213,46 @@ func TestTerrafromWorkspace_StateTFVersion(t *testing.T) { }) } +func TestTerrafromWorkspace_Execute(t *testing.T) { + t.Parallel() + + t.Run("custom command env", func(t *testing.T) { + const definitionTfContents = "variable azure_tenant_id { type = string }" + ws, err := NewWorkspace(map[string]any{}, definitionTfContents, map[string]string{}, []ParameterMapping{}, []string{}, []ParameterMapping{}) + if err != nil { + t.Fatal(err) + } + + tExecutor := newTestExecutor(func(ctx context.Context, cmd *exec.Cmd) (executor.ExecutionOutput, error) { + if cmd.Env[len(cmd.Env)-1] != "OPENTOFU_STATEFILE_PROVIDER_ADDRESS_TRANSLATION=0" { + t.Fatalf("Custom command environment variable not set. Expected `OPENTOFU_STATEFILE_PROVIDER_ADDRESS_TRANSLATION=0` got %s", cmd.Env[len(cmd.Env)-1]) + } + return executor.ExecutionOutput{}, nil + }) + + ws.Execute(context.TODO(), tExecutor, command.NewShow()) + + }) + + t.Run("empty command env", func(t *testing.T) { + const definitionTfContents = "variable azure_tenant_id { type = string }" + ws, err := NewWorkspace(map[string]any{}, definitionTfContents, map[string]string{}, []ParameterMapping{}, []string{}, []ParameterMapping{}) + if err != nil { + t.Fatal(err) + } + + tExecutor := newTestExecutor(func(ctx context.Context, cmd *exec.Cmd) (executor.ExecutionOutput, error) { + if !reflect.DeepEqual(cmd.Env, os.Environ()) { + t.Fatalf("Unexpected env variable set. Expected %s got %s", os.Environ(), cmd.Env) + } + return executor.ExecutionOutput{}, nil + }) + + ws.Execute(context.TODO(), tExecutor, command.NewApply()) + + }) +} + func TestCustomEnvironmentExecutor(t *testing.T) { c := exec.Command("/path/to/terraform", "apply") c.Env = []string{"ORIGINAL=value"}