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

Terraform: Add lockfile update support #3766

Merged
merged 57 commits into from
Jun 9, 2021

Conversation

Nishnha
Copy link
Member

@Nishnha Nishnha commented May 21, 2021

Overview

Lockfiles were added to Terraform v0.14 and only track Terraform providers. The lockfile entry for a provider will contain the version, the version constraints, and the dependency hash.

This pull request adds in Dependabot updater support for lockfiles.

What it does

When a provider dependency is updated by Dependabot, we update the mainfest vile (main.tf or versions.tf) dependency version and update the lockfile entry.

The implementation for terraform lockfile updates is based on bundler lockfile updates.

Known issues

** These will be addressed in future PRs **

  • Lockfiles will not update if the provider dependency version is pinned.
    • This is because lockfile entries are updated independently of the manifest file. When the lockfile update it is not aware of the version change in the manifest file.
  • Rspec tests for the lockfile currently match against the latest at the time dependency version. If there is a new version for a dependency after the test was updated, the test will fail.
    • Fix might require stubbing the network call for terraform providers lock

Testing the Pull Request

Currrently testing against Terraform rspec tests and 3 GitHub internal repositories. From inside the docker-dev-shell with LOCAL_GITHUB_ACCESS_TOKEN set:

cd terraform && rspec spec
bin/dry-run.rb terraform dsp-testing/dependabot-terraform-v0.15-test --cache=files --dir="/." 
bin/dry-run.rb terraform dsp-testing/dependabot-terraform-lockfile-test --cache=files --dir="/."
bin/dry-run.rb terraform dsp-testing/dependabot-terraform-lockfile-test --cache=files --dir="/." --branch=pinned-versions

Update log

  • Add lockfiles as a dependency source
  • Update lockfile dependencies individually via providers lock update
  • Refactor: remove lockfile dependencies, update lockfile when provider dependency matches lockfile entry.
  • Fix: lockfile detected changes when dependency hash opportunistically updated. Only update when lockfile version changes.
  • Delete "dead" commits from PR
  • Rebase onto main
  • Memoize network calls from terraform provider lock
  • Update lockfile when updating from a pinned version
  • Pin rspec tests dependency versions! (stub network call?)
  • Merge PR, cut release

when "provider"
update_registry_declaration(new_req, old_req, content)
when "lockfile"
update_lockfile_declaration(new_req, old_req, content)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should refactor these methods to return the updated content instead of mutating the content argument, this might make it easier to reason about update_lockfile_declaration, e.g.

when "provider"
  content = update_registry_declaration(new_req, old_req, content)
when "lockfile"
  content = update_lockfile_declaration(new_req, old_req, content)
...

@Nishnha Nishnha force-pushed the nishnha/terraform-lockfile-support branch from f5095bc to 468b3ce Compare May 26, 2021 14:36
Comment on lines 56 to 62
lock_file.each do |file|
lockfile_provider = parsed_file(file).fetch("provider", {})
lockfile_provider.each do |provider|
provider.each do |details, hashes|
dependency_set << build_lockfile_dependency(file, details, hashes)
end
end
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can get rid of this as these files are already parsed and pull out the resolved version (the only thing we care about in this step) here. That means we can also get rid of build_lockfile_dependency. It'd be sweet to keep def lock_file in the file fetcher, so we'd get rid of that method in the file_parser.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially the lockfile didn't build dependencies, but then FileUpdater would skip over the lockfile since no dependencies changed:

[*terraform_files, *terragrunt_files, *lock_file].each do |file|
      next unless file_changed?(file)

Where file_changed? calls the FileUpdaters/base#requirements_changed? function on each dependency of the file

def requirement_changed?(file, dependency)
    changed_requirements = dependency.requirements - dependency.previous_requirements
    changed_requirements.any? { |f| f[:file] == file.name }
end

If we get rid of lockfile dependencies we would need to either remove the file_changed?(file) check and fix the test suite or create exceptions for when the file being updated is a lockfile.

SharedHelpers.in_a_temporary_directory do
dependency_files.each do |file|
# Do not include the .terraform directory
next if file.name.include?(".terraform/")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not expect any of the dependency_files to be this directory, when does this happen?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dependency files are copied to a temporary directory to provide context for the terraform providers lock command. The files are copied over in the FileUpdater#update_lockfile_declaration function but I'm not sure when the dependency_files array itself is populated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's what we grab in the FileFetcher, I don't think we ever pull in those files so we probably don't need to worry about it?

@Nishnha Nishnha force-pushed the nishnha/terraform-lockfile-support branch 9 times, most recently from f186306 to b562938 Compare June 4, 2021 05:36
Nishnha and others added 8 commits June 4, 2021 12:00
Co-authored-by: mo khan <xlgmokha@github.com>
Co-authored-by: mo khan <xlgmokha@github.com>
Co-authored-by: mo khan <xlgmokha@github.com>
Co-authored-by: mo khan <xlgmokha@github.com>
Co-authored-by: mo khan <xlgmokha@github.com>

updated_files << updated_file(file: file, content: updated_content)
end

updated_files << update_lockfile_declaration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanup! I'm still wondering if this should return the content instead of the updated_file(file..)? That way you could only append it to updated_files if the content has changed.

Something like

updated_lockfile_content = update_lockfile_declaration
if (updated_lockfile_content && lock_file.content != update_lockfile_content)
  updated_files << updated_file(file: lock_file, content: update_lockfile_content)
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to add a test case to make sure updated_dependency_files doesn't return a lockfile if it doesn't change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented @feelepxyz's suggestion and created a test/fixture to make sure updated_dependency_files doesn't return a lockfile if it doesn't change.

The test uses a terraform project fixture that is fully up-to-date. However, since no files change after running dependabot on the fixture, it raises a "No files changed!" error.

The error makes the function quit early and prevents the test from directly checking whether the lockfile is unmodified or appended to the updated_files array.

So instead, I am testing for the error, which indicates that the lockfile didn't change.

Copy link
Contributor

@feelepxyz feelepxyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking very close to done! Only have one comment remaining about checking the lockfile content has changed 🙌

Nishnha and others added 5 commits June 8, 2021 14:26
Co-authored-by: Philip Harrison <feelepxyz@github.com>
Co-authored-by: Philip Harrison <feelepxyz@github.com>
Co-authored-by: Philip Harrison <feelepxyz@github.com>
Co-authored-by: Philip Harrison <philip@mailharrison.com>
…e if it doesn't change

Co-authored-by: Philip Harrison <feelepxyz@github.com>
@Nishnha Nishnha force-pushed the nishnha/terraform-lockfile-support branch from 0a174a7 to 234640f Compare June 8, 2021 18:26
Copy link
Contributor

@feelepxyz feelepxyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Thanks for incorporating the feedback and for adding the test case! This looks good to go to me :shipit:

@Nishnha Nishnha enabled auto-merge June 9, 2021 14:46
Dockerfile Outdated
RUN curl -fsSL https://apt.releases.hashicorp.com/gpg | apt-key add -
RUN apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
&& apt-get update -y \
&& apt-get install terraform \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we pin the version here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meh, whatevs let's do it in a follow-up PR

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinned to 1.0.0 81a424e

@Nishnha Nishnha force-pushed the nishnha/terraform-lockfile-support branch from 26b20e1 to db8974a Compare June 9, 2021 15:01
@Nishnha Nishnha disabled auto-merge June 9, 2021 15:01
@Nishnha Nishnha enabled auto-merge June 9, 2021 15:13
@Nishnha Nishnha merged commit b930756 into main Jun 9, 2021
@Nishnha Nishnha deleted the nishnha/terraform-lockfile-support branch June 9, 2021 15:48
Nishnha added a commit that referenced this pull request Jun 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants