Highway of Life
Highway of Life

Reputation: 24301

Terraform: Failed to install provider, doesn't match checksums from dependency lock file

I use a CI system to compile terraform providers and bundle them into an image, but every time I run terraform init, I am getting the following error/failure.

│ Error: Failed to install provider
│ 
│ Error while installing rancher/rancher2 v1.13.0: the current package for
│ registry.terraform.io/rancher/rancher2 1.13.0 doesn't match any of the
│ checksums previously recorded in the dependency lock file

This message is repeated for all of the providers listed in my provider file, which looks like this:

terraform {
  required_version = ">= 0.13"

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "2.55.0"
    }
    github = {
      source  = "integrations/github"
      version = "4.8.0"
    }
  }
...snip...
}

The terraform hcl lock file is stored in the repo and it's only when the lock file exists in the repo that these errors appear and terraform init fails. What could be the cause?

Upvotes: 41

Views: 39456

Answers (3)

ostergaard
ostergaard

Reputation: 3507

While the accepted answer is absolutely correct, the easiest way to handle this situation is to deploy pre-commit and use a hook like https://github.com/antonbabenko/pre-commit-terraform#terraform_providers_lock.

Upvotes: 1

Alex Torres
Alex Torres

Reputation: 21

Just to improve a bit what was already posted above, I've done the same fix either in my local machine but also in automation (Github actions), wrapping up this solution into a tiny bash script. Putting this script into a GH action would solve this problem in a wider way

    #!/usr/bin/env bash

export PATH=$PATH:/usr/local/bin

function main() {
  parse_args "$@"

  generate_terraform_lock_command_by_option

  fix_lock_file
}

function fix_lock_file() {
  pushd "$DIR" >/dev/null || exit

  if [[ "${RUNON}" != "automation" ]]; then
    clean_terraform_local_state
  fi


  if [[ -f ".terraform.lock.hcl" ]]; then
    echo "Removing terraform.lock file"
    cat $LOCK_FILE
    rm -f "$LOCK_FILE"
  fi

  terraform get

  terraform providers lock -platform=$OS

  if [[ "${RUNON}" != "automation" ]]; then
    clean_terraform_local_state
  fi

  popd >/dev/null || exit
}

function generate_terraform_lock_command_by_option(){
  local platform

  case "$PLATFORM" in
    windows)
      platform="windows_amd64"
      ;;
    linux)
      platform="darwin_amd64"
      ;;
    mac)
      platform="linux_amd64"
      ;;
    *)
      echo "Invalid platform: $PLATFORM"
      exit 1
      ;;
  esac

  OS="$platform"

  echo "Selected platform set: $OS"
}

function clean_terraform_local_state() {

  if [[ -f ".terraform.tfstate" ]]; then
    echo "Removing terraform.tfstate file"
    rm terraform.tfstate
  fi

  if [[ -f ".terraform.tfstate.backup" ]]; then
    echo "Removing terraform.tfstate.backup file"
    rm terraform.tfstate.backup
  fi

  if [[ -d ".terraform" ]]; then
    echo "Removing .terraform metadata folder to avoid local state conflicts "
    rm -rf .terraform
  fi
}


# Parse command line arguments
function parse_args() {
  for arg in "$@"; do
    echo "argument received --> [$arg]"
    echo
  done

  for i in "$@"; do
    case $i in
    -d=* | --dir=*)
      DIR="${i#*=}"
      shift
      ;;
    -=p* | --platform*)
      PLATFORM="${i#*=}"
      shift
      ;;
    -e=* | --env=*)
      ENV="${i#*=}"
      shift
      ;;
    -r=* | --runon=*)
      RUNON="${i#*=}"
      shift
      ;;
    *) fatal "Unknown option: '-${i}'" "See '${0} --help' for usage" ;;
    esac
  done
}

# Globals
declare DIR
declare ENV
declare RUNON
declare LOCK_FILE=".terraform.lock.hcl"
declare OS
declare PLATFORM

[[ ${BASH_SOURCE[0]} != "$0" ]] || main "$@"

I'm running it from my local as follows:

.fix-terraform-lock-file.sh --dir=infrastructure/terraform/web_static --env=prod --platform=mac --runon=local

Upvotes: 1

Highway of Life
Highway of Life

Reputation: 24301

The issue is that my local workstation is a Mac which uses the darwin platform, so all of the providers are downloaded for darwin and the hashes stored in the lockfile for that platform. When the CI system, which is running on Linux runs, it attempts to retrieve the providers listed in the lockfile, but the checksums don't match because they use a different platform.

The solution is to use the following command locally to generate a new terraform dependency lock file with all of the platforms for terraform, other systems running on different platforms will then be able to obey the dependency lock file.

terraform providers lock -platform=windows_amd64 -platform=darwin_amd64 -platform=linux_amd64

Upvotes: 68

Related Questions