Compiling a custom Terraform provider
Several times now, I’ve been presented with provider bugs in Terraform - specifically the AWS provider - that are fixed in PRs that have sat unmerged for months, if not years. While Hashicorp has now codified that community pull requests aren’t being reviewed, I’ve had a dirty trick up my sleeve for about two years now: in some projects, I don’t use the upstream provider anymore. Instead, I run a fork, where I’ve cherry-picked in any fixes I’ve needed. And after having admitted to doing that publicly, I got an e-mail just yesterday, asking how I did it.
Truth be told, I’ve never wanted to blog about my solution, because it feels dirty. At best, it’s a workaround for what should be a more seamless community process, but I’ll get off my soapbox and just give the details of what I’m doing. It’s actually pretty simple:
- I fork the provider code, and use
git cherry-pickto cherry-pick in the commits I want from various other PRs. (I prefer doing it this way, capturing the original commits, so I can keep track of what’s on my fork and where it came from.)
- I hijack the version string
0.0.1- which, luckily, has never had a real release. It doesn’t exist upstream, which is a happy accident.
- When I run
terraform init, I use Docker to compile the provider - optionally cross-compiling if I’m running Terraform locally on a Mac, rather than in CI on Linux.
- I put the compiled provider in the plugin cache directory where
terraform initwould normally put it.
That’s it. Here’s a very basic script that can run inline with CI - or, alternatively, be run in a wrapper script that also calls
if [ "$(uname)" == "Darwin" ]; then export GOOS=darwin else export GOOS=linux fi PROVIDER_DIR="$(pwd)/.terraform/plugins/$GOOS_amd64" PROVIDER_FILE=terraform-provider-aws_v0.0.1_x5 echo "Building custom AWS provider..." if [ ! -d $PROVIDER_DIR ]; then mkdir -p $PROVIDER_DIR fi if [ ! -f $PROVIDER_DIR/$PROVIDER_FILE ]; then # custom provider has no version string buildroot=$(mktemp -d) git clone --depth=1 email@example.com:my-copy-of/terraform-provider-aws.git $buildroot docker run -it --rm -e GOOS=$GOOS -v $buildroot:/buildroot golang:1.14 bash -c "cd /buildroot && make tools && make build && mv /go/bin/$GOOS_amd64/terraform-provider-aws /buildroot/$PROVIDER_FILE" mv $buildroot/$PROVIDER_FILE $PROVIDER_DIR/ rm -rf $buildroot fi if [ ! -f $PROVIDER_DIR/$PROVIDER_FILE ]; then # if it still doesn't exist, it failed to build and we should exit echo -e "Custom provider failed to build; refusing to continue." exit 1 fi
Note that you’ll also need to set
GOARCH if you’re working across architectures (for instance, if you have ARM anywhere in your ecosystem, like on an M1 MacBook). I don’t have this problem (yet, but I’m always hopeful that ARM will only become more ubiquitous), so I didn’t solve for it here.