From 100c44b6c326c73fa2c0931f9db2a0d9f6c67899 Mon Sep 17 00:00:00 2001 From: Reda Khaled Date: Fri, 24 Feb 2023 23:41:31 +0100 Subject: [PATCH] bugfix: issue-28274, terraform providers mirror command should honor terraform lock file --- .../command/e2etest/providers_mirror_test.go | 10 ++++- .../.terraform.lock.hcl | 44 +++++++++++++++++++ .../terraform-providers-mirror.tf | 7 +++ internal/command/providers_mirror.go | 20 ++++++++- 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl create mode 100644 internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf diff --git a/internal/command/e2etest/providers_mirror_test.go b/internal/command/e2etest/providers_mirror_test.go index f237fa65135f..08c54f4c68fa 100644 --- a/internal/command/e2etest/providers_mirror_test.go +++ b/internal/command/e2etest/providers_mirror_test.go @@ -17,6 +17,14 @@ import ( // compromise for now to keep these tests relatively simple. func TestTerraformProvidersMirror(t *testing.T) { + testTerraformProvidersMirror(t, "terraform-providers-mirror") +} + +func TestTerraformProvidersMirrorWithLockFile(t *testing.T) { + testTerraformProvidersMirror(t, "terraform-providers-mirror-with-lock-file") +} + +func testTerraformProvidersMirror(t *testing.T, fixture string) { // This test reaches out to releases.hashicorp.com to download the // template and null providers, so it can only run if network access is // allowed. @@ -25,7 +33,7 @@ func TestTerraformProvidersMirror(t *testing.T) { outputDir := t.TempDir() t.Logf("creating mirror directory in %s", outputDir) - fixturePath := filepath.Join("testdata", "terraform-providers-mirror") + fixturePath := filepath.Join("testdata", fixture) tf := e2e.NewBinary(t, terraformBin, fixturePath) stdout, stderr, err := tf.Run("providers", "mirror", "-platform=linux_amd64", "-platform=windows_386", outputDir) diff --git a/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl b/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl new file mode 100644 index 000000000000..64d78c2e313a --- /dev/null +++ b/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/.terraform.lock.hcl @@ -0,0 +1,44 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/null" { + version = "2.1.0" + constraints = "2.1.0" + hashes = [ + "h1:J/XPKw4nOAsE0iHHqkR0oIBfchtt3pokNj4gFlHqVvk=", + "h1:uugNjv4FEabvXfifTzRCqSerdraltZR0UwXzH8QYPUQ=", + "zh:022eb9cefb72d25cb39aebf17787ae5a1a239544abae7ac11fdc2b5a464c06f8", + "zh:089aec7ba6b9843741fec84e0bc046d97d2e41a9fedbe5d77124e66227395c63", + "zh:09e9a6fe88e8d33e4656a4f3768275c0f959f4624886a3a96d250e1067afec8c", + "zh:0fa2d6a05874405eb8b2a7ececb6b7522be25642e31838d23620bf7b4f371c9d", + "zh:2a7ab2f42d86e8bd4db3cdf94287a6d91c61456b59a0ce2d0f5d6992a08b668b", + "zh:6526bfa4f547223d4a14d7bf9098a4f7177a5c886a7edc65056df1cb98f6aad9", + "zh:8e58a5a130d377e8fc0da8ad526f33738c320b19463679f7d68212c5c939bad4", + "zh:9dc5be5713fca7dbfa99e9673450aaa7216915bffbc043b30798e037a8f2c870", + "zh:ab7671e33198b718a1ae3272dcea0380f357926324f96c3be0c6ef9423ebece1", + "zh:b27db66404ea0704fb076ef26bb5b5c556a31b81a8b2302ec705a7e46d93d3e0", + "zh:bcc4a07ce1fb3bdee4ea360dd9549e099ecc2e9d80aab7f8daf54387a87a5f8e", + "zh:bf44f8693075f46ae833303fee17e0b0649c72e9347027670fa30e9fbce37fc4", + ] +} + +provider "registry.terraform.io/hashicorp/template" { + version = "2.1.1" + constraints = "2.1.1" + hashes = [ + "h1:fBNBluCX4pWlYEw5ZyCTHB00E+3BDSe7GjRzF1ojcvU=", + "h1:x2/zuJFN/oOUpE1C1nSk4n86AA2zASOyy2BUdFYcpXw=", + "zh:05fddf3cacb607f623c2b221c3e9ab724079deca0b703b2738e9d55c10e31717", + "zh:1a250b29274f3e340ea775bf9bd57476e982bca1fb4b59343fb3126e75dfd85c", + "zh:284735b9bd0e416ec02c0844e7f4ebbd4b5744140a21606e33f16eb14640cbf1", + "zh:2e9d246094ac8a68951015d40f42145e795b31d7c84fee20fa9f997b3d428906", + "zh:65e8e73860662a0c0698c8a8d35c857302f1fe3f41947e7c048c49a541a9c7f1", + "zh:70dacd22d0c93b2000948c06ded67fa147d992a0353737438f24a61e3f956c41", + "zh:aa1a0321e79e08ffb52789ab0af3896c493d436de7396d154d09a0be7d5d50e1", + "zh:bea4c276c4df9d117f19c4266d060db9b48c865ac7a71d2e77a27866c19bfaf5", + "zh:de04cb0cb046dad184f5bb783659cf98d88c6798db038cbf5a2c3c08e853d444", + "zh:de3c45a4fa1f756aa4db3350c021d1c0f9b23640cff77e0ba4df4eeb8eae957f", + "zh:e3cf2db204f64ad4e288af00fabc6a8af13a6687aba60a7e1ce0ea215a9580b1", + "zh:f795833225207d2eee022b91d26bee18d5e518e70912dd7a1d2a0eff2cbe4f1d", + ] +} diff --git a/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf b/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf new file mode 100644 index 000000000000..1598a278354b --- /dev/null +++ b/internal/command/e2etest/testdata/terraform-providers-mirror-with-lock-file/terraform-providers-mirror.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + template = { source = "hashicorp/template" } + null = { source = "hashicorp/null" } + terraform = { source = "terraform.io/builtin/terraform" } + } +} diff --git a/internal/command/providers_mirror.go b/internal/command/providers_mirror.go index 5890ed8d995c..f6ab2258244c 100644 --- a/internal/command/providers_mirror.go +++ b/internal/command/providers_mirror.go @@ -76,12 +76,27 @@ func (c *ProvidersMirrorCommand) Run(args []string) int { reqs, moreDiags := config.ProviderRequirements() diags = diags.Append(moreDiags) + // Read lock file + lockedDeps, lockedDepsDiags := c.Meta.lockedDependencies() + diags = diags.Append(lockedDepsDiags) + // If we have any error diagnostics already then we won't proceed further. if diags.HasErrors() { c.showDiagnostics(diags) return 1 } + // If lock file is present, validate it against configuration + if !lockedDeps.Empty() { + if errs := config.VerifyDependencySelections(lockedDeps); len(errs) > 0 { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Inconsistent dependency lock file", + fmt.Sprintf("To update the locked dependency selections to match a changed configuration, run:\n terraform init -upgrade\n got:%v", errs), + )) + } + } + // Unlike other commands, this command always consults the origin registry // for every provider so that it can be used to update a local mirror // directory without needing to first disable that local mirror @@ -140,7 +155,10 @@ func (c *ProvidersMirrorCommand) Run(args []string) int { continue } selected := candidates.Newest() - if len(constraintsStr) > 0 { + if !lockedDeps.Empty() { + selected = lockedDeps.Provider(provider).Version() + c.Ui.Output(fmt.Sprintf(" - Selected v%s to match dependency lock file", selected.String())) + } else if len(constraintsStr) > 0 { c.Ui.Output(fmt.Sprintf(" - Selected v%s to meet constraints %s", selected.String(), constraintsStr)) } else { c.Ui.Output(fmt.Sprintf(" - Selected v%s with no constraints", selected.String()))