217 lines
9.0 KiB
Markdown
217 lines
9.0 KiB
Markdown
# terraform-bundle
|
|
|
|
`terraform-bundle` is a helper program to create "bundle archives", which are
|
|
zip files that contain both a particular version of Terraform and a number
|
|
of provider plugins.
|
|
|
|
Normally `terraform init` will download and install the plugins necessary to
|
|
work with a particular configuration, but sometimes Terraform is deployed in
|
|
a network that, for one reason or another, cannot access the official
|
|
plugin repository for automatic download.
|
|
|
|
In some cases, this can be solved by installing provider plugins into the
|
|
[user plugins directory](https://www.terraform.io/docs/configuration/providers.html#third-party-plugins).
|
|
However, this doesn't always meet the needs of automated deployments.
|
|
|
|
`terraform-bundle` provides an alternative, by allowing the auto-download
|
|
process to be run out-of-band on a separate machine that _does_ have access
|
|
to the repository. The result is a zip file that can be extracted onto the
|
|
target system to install both the desired Terraform version and a selection
|
|
of providers, thus avoiding the need for on-the-fly plugin installation.
|
|
|
|
## Building
|
|
|
|
To build `terraform-bundle` from source, set up a Terraform development
|
|
environment per [Terraform's own README](../../README.md) and then install
|
|
this tool from within it:
|
|
|
|
```
|
|
$ go install ./tools/terraform-bundle
|
|
```
|
|
|
|
This will install `terraform-bundle` in `$GOPATH/bin`, which is assumed by
|
|
the rest of this README to be in `PATH`.
|
|
|
|
`terraform-bundle` is a repackaging of the module installation functionality
|
|
from Terraform itself, so for best results you should build from the tag
|
|
relating to the version of Terraform you plan to use. For example, use the v0.12
|
|
tag to build a version of terraform-bundle compatible with Terraform v0.12*.
|
|
|
|
## Usage
|
|
|
|
`terraform-bundle` uses a simple configuration file to define what should
|
|
be included in a bundle. This is designed so that it can be checked into
|
|
version control and used by an automated build and deploy process.
|
|
|
|
The configuration file format works as follows:
|
|
|
|
```hcl
|
|
terraform {
|
|
# Version of Terraform to include in the bundle. An exact version number
|
|
# is required.
|
|
version = "0.10.0"
|
|
}
|
|
|
|
# Define which provider plugins are to be included
|
|
providers {
|
|
# Include the newest "aws" provider version in the 1.0 series.
|
|
aws = {
|
|
versions = ["~> 1.0"]
|
|
}
|
|
|
|
# Include both the newest 1.0 and 2.0 versions of the "google" provider.
|
|
# Each item in these lists allows a distinct version to be added. If the
|
|
# two expressions match different versions then _both_ are included in
|
|
# the bundle archive.
|
|
google = {
|
|
versions = ["~> 1.0", "~> 2.0"]
|
|
}
|
|
|
|
# Include a custom plugin to the bundle. Will search for the plugin in the
|
|
# plugins directory and package it with the bundle archive. Plugin must have
|
|
# a name of the form: terraform-provider-*, and must be built with the operating
|
|
# system and architecture that terraform enterprise is running, e.g. linux and amd64.
|
|
customplugin = {
|
|
versions = ["0.1"]
|
|
source = "myorg/customplugin"
|
|
}
|
|
}
|
|
|
|
```
|
|
|
|
The `terraform` block defines which version of Terraform will be included
|
|
in the bundle. An exact version is required here.
|
|
|
|
The `providers` block defines zero or more providers to include in the bundle
|
|
along with core Terraform. Each attribute is a provider name, and its value is a
|
|
block with the list of version constraints and (optional) source. For each given
|
|
constraint, `terraform-bundle` will find the newest available version matching
|
|
the constraint and include it in the bundle.
|
|
|
|
It is allowed to specify multiple constraints for the same provider, in which
|
|
case multiple versions can be included in the resulting bundle. Each constraint
|
|
string given results in a separate plugin in the bundle, unless two constraints
|
|
resolve to the same concrete plugin.
|
|
|
|
Including multiple versions of the same provider allows several configurations
|
|
running on the same system to share an installation of the bundle and to
|
|
choose a version using version constraints within the main Terraform
|
|
configuration. This avoids the need to upgrade all configurations to newer
|
|
versions in lockstep.
|
|
|
|
After creating the configuration file, e.g. `terraform-bundle.hcl`, a bundle
|
|
zip file can be produced as follows:
|
|
|
|
```
|
|
$ terraform-bundle package terraform-bundle.hcl
|
|
```
|
|
|
|
By default the bundle package will target the operating system and CPU
|
|
architecture where the tool is being run. To override this, use the `-os` and
|
|
`-arch` options. For example, to build a bundle for on-premises Terraform
|
|
Enterprise:
|
|
|
|
```
|
|
$ terraform-bundle package -os=linux -arch=amd64 terraform-bundle.hcl
|
|
```
|
|
|
|
The bundle file is assigned a name that includes the core Terraform version
|
|
number, a timestamp to the nearest hour of when the bundle was built, and the
|
|
target OS and CPU architecture. It is recommended to refer to a bundle using
|
|
this composite version number so that bundle archives can be easily
|
|
distinguished from official release archives and from each other when multiple
|
|
bundles contain the same core Terraform version.
|
|
|
|
## Custom Plugins
|
|
To include custom plugins in the bundle file, create a local directory named
|
|
`./plugins` and put all the plugins you want to include there, under the
|
|
required [sub directory](#plugins-directory-layout). Optionally, you can use the
|
|
`-plugin-dir` flag to specify a location where to find the plugins. To be
|
|
recognized as a valid plugin, the file must have a name of the form
|
|
`terraform-provider-<NAME>`. In addition, ensure that the plugin is built using
|
|
the same operating system and architecture used for Terraform Enterprise.
|
|
Typically this will be `linux` and `amd64`.
|
|
|
|
### Plugins Directory Layout
|
|
To include custom plugins in the bundle file, you must specify a "source"
|
|
attribute in the configuration and place the plugin in the appropriate
|
|
subdirectory under `./plugins`. The directory must have the following layout:
|
|
|
|
```
|
|
./plugins/$SOURCEHOST/$SOURCENAMESPACE/$NAME/$VERSION/$OS_$ARCH/
|
|
```
|
|
|
|
When installing custom plugins, you may choose any arbitrary identifier for the
|
|
$SOURCEHOST and $SOURCENAMESPACE subdirectories.
|
|
|
|
For example, given the following configuration and a plugin built for Terraform Enterprise:
|
|
|
|
```
|
|
providers {
|
|
customplugin = {
|
|
versions = ["0.1"]
|
|
source = "example.com/myorg/customplugin"
|
|
}
|
|
}
|
|
```
|
|
|
|
The binary must be placed in the following directory:
|
|
|
|
```
|
|
./plugins/example.com/myorg/customplugin/0.1/linux_amd64/
|
|
```
|
|
|
|
## Provider Resolution Behavior
|
|
|
|
Terraform's provider resolution behavior is such that if a given constraint
|
|
can be resolved by any plugin already installed on the system it will use
|
|
the newest matching plugin and not attempt automatic installation.
|
|
|
|
Therefore if automatic installation is not desired, it is important to ensure
|
|
that version constraints within Terraform configurations do not exclude all
|
|
of the versions available from the bundle. If a suitable version cannot be
|
|
found in the bundle, Terraform _will_ attempt to satisfy that dependency by
|
|
automatic installation from the official repository. If you want
|
|
`terraform init` to explicitly fail instead of contacting the repository, pass
|
|
the `-get-plugins=false` option.
|
|
|
|
For full details about provider resolution, see
|
|
[How Terraform Works: Plugin Discovery](https://www.terraform.io/docs/extend/how-terraform-works.html#discovery).
|
|
|
|
The downloaded provider archives are verified using the same signature check
|
|
that is used for auto-installed plugins, using Hashicorp's release key. At
|
|
this time, the core Terraform archive itself is _not_ verified in this way;
|
|
that may change in a future version of this tool.
|
|
|
|
## Installing a Bundle in Terraform Enterprise
|
|
|
|
If using a Terraform Enterprise instance in an "air-gapped"
|
|
environment, this tool can produce a custom Terraform version package, which
|
|
includes a set of provider plugins along with core Terraform.
|
|
|
|
To create a suitable bundle, use the `-os` and `-arch` options as described
|
|
above to produce a bundle targeting `linux_amd64`. You can then place this
|
|
archive on an HTTP server reachable by the Terraform Enterprise hosts and
|
|
install it as per
|
|
[Administration: Managing Terraform Versions](https://www.terraform.io/docs/enterprise/admin/resources.html#managing-terraform-versions).
|
|
|
|
After clicking the "Add Terraform Version" button:
|
|
|
|
1. In the "Version" field, enter the generated bundle version from the bundle
|
|
filename, which will be of the form `N.N.N-bundleYYYYMMDDHH`.
|
|
2. In the "URL" field, enter the URL where the generated bundle archive can be found.
|
|
3. In the "SHA256 Checksum" field, enter the SHA256 hash of the file, which can
|
|
be found by running `sha256sum <FILE>` or `shasum -a256 <FILE>`.
|
|
|
|
The new bundle version can then be selected as the Terraform version for
|
|
any workspace. When selected, configurations that require only plugins
|
|
included in the bundle will run without trying to auto-install.
|
|
|
|
Note that the above does _not_ apply to Terraform Pro, or to Terraform Premium
|
|
when not running a private install. In these packages, Terraform versions
|
|
are managed centrally across _all_ organizations and so custom bundles are not
|
|
supported.
|
|
|
|
For more information on the available Terraform Enterprise packages, see
|
|
[the Terraform product site](https://www.hashicorp.com/products/terraform/).
|