Skip to content

Commit

Permalink
Add workaround for missing metadata file
Browse files Browse the repository at this point in the history
  • Loading branch information
ljfranklin committed Jan 31, 2021
1 parent 7b200d6 commit e6f1922
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 10 deletions.
31 changes: 21 additions & 10 deletions src/terraform-resource/in/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,6 @@ func (r Runner) inWithMigratedFromStorage(req models.InRequest, tmpDir string) (
}

func (r Runner) inWithBackend(req models.InRequest, tmpDir string) (models.InResponse, error) {
if req.Version.IsPlan() && req.Params.OutputJSONPlanfile == false {
resp := models.InResponse{
Version: req.Version,
}
return resp, nil
}

terraformModel := req.Source.Terraform
if err := terraformModel.Validate(); err != nil {
return models.InResponse{}, fmt.Errorf("Failed to validate terraform Model: %s", err)
Expand All @@ -117,16 +110,34 @@ func (r Runner) inWithBackend(req models.InRequest, tmpDir string) (models.InRes
return models.InResponse{}, err
}

if req.Params.OutputJSONPlanfile && req.Version.IsPlan() {
if err := r.writeJSONPlanToFile(targetEnvName+"-plan", client); err != nil {
return models.InResponse{}, err
if req.Version.IsPlan() {
if req.Params.OutputJSONPlanfile {
if err := r.writeJSONPlanToFile(targetEnvName+"-plan", client); err != nil {
return models.InResponse{}, err
}
}

// HACK: Attempt to download a statefile if one exists, but silently ignore
// any errors on failure. This is a workaround for an intermittent issue
// where generating and applying a plan within the same job will incorrectly
// mark the plan run as the latest version. This results in missing `metadata`
// file on subsequent `get` calls. Issue:
// https://github.com/ljfranklin/terraform-resource/issues/136. A better long-term
// fix would be to make `check` more robust by updating Terraform to record
// timestamps in the statefile: https://github.com/hashicorp/terraform/issues/15950.
_, _ = r.writeBackendOutputs(req, targetEnvName, client)

resp := models.InResponse{
Version: req.Version,
}

return resp, nil
}

return r.writeBackendOutputs(req, targetEnvName, client)
}

func (r Runner) writeBackendOutputs(req models.InRequest, targetEnvName string, client terraform.Client) (models.InResponse, error) {
if err := r.ensureEnvExistsInBackend(targetEnvName, client); err != nil {
return models.InResponse{}, err
}
Expand Down
110 changes: 110 additions & 0 deletions src/terraform-resource/in/in_plan_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package in_test

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
Expand Down Expand Up @@ -278,4 +279,113 @@ var _ = Describe("JSON Plan", func() {
Expect(string(stateContents)).To(ContainSubstring("resource_changes"))
Expect(string(stateContents)).To(ContainSubstring("\"format_version\":\"0.1\""))
})

It("HACK: outputs metadata file if statefile exists", func() {
planApplyRequest := models.OutRequest{
Source: models.Source{
Terraform: models.Terraform{
BackendType: backendType,
BackendConfig: backendConfig,
},
},
Params: models.OutParams{
EnvName: envName,
Terraform: models.Terraform{
Source: "fixtures/aws/",
Env: map[string]string{
"HOME": workingDir, // in prod plugin is installed system-wide
},
Vars: map[string]interface{}{
"access_key": accessKey,
"secret_key": secretKey,
"bucket": bucket,
"object_key": s3ObjectPath,
"object_content": "terraform-is-neat",
"region": region,
},
},
},
}

applyRunner := out.Runner{
SourceDir: workingDir,
LogWriter: GinkgoWriter,
}
_, err := applyRunner.Run(planApplyRequest)
Expect(err).ToNot(HaveOccurred())

planOutRequest := models.OutRequest{
Source: models.Source{
Terraform: models.Terraform{
BackendType: backendType,
BackendConfig: backendConfig,
},
},
Params: models.OutParams{
EnvName: envName,
Terraform: models.Terraform{
Source: "fixtures/aws/",
PlanOnly: true,
Env: map[string]string{
"HOME": workingDir, // in prod plugin is installed system-wide
},
Vars: map[string]interface{}{
"access_key": accessKey,
"secret_key": secretKey,
"bucket": bucket,
"object_key": s3ObjectPath,
"object_content": "terraform-is-neat",
"region": region,
},
},
},
}

planrunner := out.Runner{
SourceDir: workingDir,
LogWriter: GinkgoWriter,
}
planOutput, err := planrunner.Run(planOutRequest)
Expect(err).ToNot(HaveOccurred())

inReq := models.InRequest{
Source: models.Source{
Terraform: models.Terraform{
Source: ".",
Env: map[string]string{
"HOME": inDir,
},
BackendType: "s3",
BackendConfig: map[string]interface{}{
"bucket": bucket,
"key": "terraform.tfstate",
"access_key": accessKey,
"secret_key": secretKey,
"region": region,
"workspace_key_prefix": workspacePath,
},
},
},
Version: planOutput.Version,
Params: models.InParams{},
}

runner := in.Runner{
OutputDir: inDir,
}
_, err = runner.Run(inReq)
Expect(err).ToNot(HaveOccurred())

expectedOutputPath := path.Join(inDir, "metadata")
Expect(expectedOutputPath).To(BeAnExistingFile())
outputFile, err := os.Open(expectedOutputPath)
Expect(err).ToNot(HaveOccurred())
defer outputFile.Close()

outputContents := map[string]interface{}{}
err = json.NewDecoder(outputFile).Decode(&outputContents)
Expect(err).ToNot(HaveOccurred())

Expect(outputContents).NotTo(BeEmpty())
})
})

0 comments on commit e6f1922

Please sign in to comment.