aboutsummaryrefslogtreecommitdiff
path: root/infra/libkookie/nixpkgs/pkgs/applications/networking/cluster/terraform-providers/update-provider
#!/usr/bin/env nix-shell
#! nix-shell -i bash -p coreutils curl jq moreutils
# shellcheck shell=bash
# vim: ft=sh
#
# Update a terraform provider to the latest version advertised at the
# provider source address.
#
set -euo pipefail

show_usage() {
  cat <<DOC
Usage: ./update-provider [--force] [--vendor] [<owner>/]<provider>

Update a single provider in the providers.json inventory file.

For example to update 'terraform-providers.aws' run:

    ./update-provider aws

If the provider is not in the list already, use the form '<owner>/<provider>'
to add the provider to the list:

    ./update-provider hetznercloud/hcloud

Options:

  * --force: Force the update even if the version matches.
  * --vendor: Switch from go package to go modules with vendor.
  * --vendor-sha256 <sha256>: Override the SHA256 or "null".
DOC
}

force=
provider=
vendor=
vendorSha256=

while [[ $# -gt 0 ]]; do
  case "$1" in
  -h | --help)
    show_usage
    exit
    ;;
  --force)
    force=1
    shift
    ;;
  --vendor)
    force=1
    vendor=1
    shift
    ;;
  --vendor-sha256)
    force=1
    vendorSha256=$2
    shift 2
    ;;
  *)
    if [[ -n "$provider" ]]; then
      echo "ERROR: provider name was passed two times: '$provider' and '$1'"
      echo "Use --help for more info"
      exit 1
    fi
    provider=$1
    shift
  esac
done

if [[ -z "$provider" ]]; then
  echo "ERROR: No providers specified!"
  echo
  show_usage
  exit 1
fi

provider_name=$(basename "$provider")

# Usage: read_attr <key>
read_attr() {
  jq -r ".\"$provider_name\".\"$1\"" providers.json
}

# Usage: update_attr <key> <value>
update_attr() {
  if [[ "$2" == "null" ]]; then
    jq -S ".\"$provider_name\".\"$1\" = null" providers.json | sponge providers.json
  else
    jq -S ".\"$provider_name\".\"$1\" = \"$2\"" providers.json | sponge providers.json
  fi
}

prefetch_github() {
  # of a given owner, repo and rev, fetch the tarball and return the output of
  # `nix-prefetch-url`
  local owner=$1
  local repo=$2
  local rev=$3
  nix-prefetch-url --unpack "https://github.com/$owner/$repo/archive/$rev.tar.gz"
}

old_source_address="$(read_attr provider-source-address)"
old_vendor_sha256=$(read_attr vendorSha256)
old_version=$(read_attr version)

if [[ $provider =~ ^[^/]+/[^/]+$ ]]; then
  source_address=registry.terraform.io/$provider
else
  source_address=$old_source_address
fi
if [[ "$source_address" == "null" ]]; then
  echo "Could not find the source address for provider: $provider"
  exit 1
fi
update_attr "provider-source-address" "$source_address"

# The provider source address (used inside Terraform `required_providers` block) is
# used to compute the registry API endpoint
#
# registry.terraform.io/hashicorp/aws (provider source address)
# registry.terraform.io/providers/hashicorp/aws (provider URL for the website)
# registry.terraform.io/v1/providers/hashicorp/aws (provider URL for the JSON API)
registry_response=$(curl -s https://"${source_address/\///v1/providers/}")

version="$(jq -r '.version' <<< "$registry_response")"
if [[ "$old_version" = "$version" && "$force" != 1 && -z "$vendorSha256" && "$old_vendor_sha256" != "$vendorSha256" ]]; then
  echo "$provider_name is already at version $version"
  exit
fi
update_attr version "$version"

provider_source_url="$(jq -r '.source' <<< "$registry_response")"

org="$(echo "$provider_source_url" | cut -d '/' -f 4)"
update_attr owner "$org"
repo="$(echo "$provider_source_url" | cut -d '/' -f 5)"
update_attr repo "$repo"
rev="$(jq -r '.tag' <<< "$registry_response")"
update_attr rev "$rev"
sha256=$(prefetch_github "$org" "$repo" "$rev")
update_attr sha256 "$sha256"

repo_root=$(git rev-parse --show-toplevel)

if [[ -z "$vendorSha256" ]]; then
  if [[ "$old_vendor_sha256" == null ]]; then
    vendorSha256=null
  elif [[ -n "$old_vendor_sha256" || "$vendor" = 1 ]]; then
    echo "=== Calculating vendorSha256 ==="
    update_attr vendorSha256 "0000000000000000000000000000000000000000000000000000000000000000"
    # Hackish way to find out the desired sha256. First build, then extract the
    # error message from the logs.
    set +e
    nix-build --no-out-link "$repo_root" -A "terraform-providers.$provider_name.go-modules" 2>vendor_log.txt
    set -e
    logs=$(< vendor_log.txt)
    if ! [[ $logs =~ got:\ +([^\ ]+) ]]; then
      echo "ERROR: could not find new hash in output:"
      cat vendor_log.txt
      rm -f vendor_log.txt
      exit 1
    fi
    rm -f vendor_log.txt
    vendorSha256=${BASH_REMATCH[1]}
    # Deal with nix unstable
    if [[ $vendorSha256 = sha256-* ]]; then
      vendorSha256=$(nix to-base32 "$vendorSha256")
    fi
  fi
fi

if [[ -n "$vendorSha256" ]]; then
  update_attr vendorSha256 "$vendorSha256"
fi

# Check that the provider builds
echo "=== Building terraform-providers.$provider_name ==="
nix-build "$repo_root" -A "terraform-providers.$provider_name"