A simple wrapper around the Terraform binary to allow execution from within a Ruby program or Rakefile.
Add this line to your application's Gemfile:
gem 'ruby-terraform'
And then execute:
$ bundle
Or install it yourself as:
$ gem install ruby-terraform
RubyTerraform needs to know where the terraform binary is located before it can do anything. By default, RubyTerraform looks on the path however this can be configured with:
RubyTerraform.configure do |config|
config.binary = 'vendor/terraform/bin/terraform'
end
In addition, each command that requires the terraform binary (all except
clean
) takes a binary
keyword argument at initialisation that overrides the
global configuration value.
Currently, there is partial support for the following commands:
RubyTerraform::Commands::Clean
: clean up all locally held terraform state and modules.RubyTerraform::Commands::Init
: executesterraform init
RubyTerraform::Commands::Get
: executesterraform get
RubyTerraform::Commands::Plan
: executesterraform plan
RubyTerraform::Commands::Apply
: executesterraform apply
RubyTerraform::Commands::Show
: executesterraform show
RubyTerraform::Commands::Destroy
: executesterraform destroy
RubyTerraform::Commands::Output
: executesterraform output
RubyTerraform::Commands::Refresh
: executesterraform refresh
RubyTerraform::Commands::Import
: executesterraform import
RubyTerraform::Commands::RemoteConfig
: executesterraform remote config
RubyTerraform::Commands::Validate
: executesterraform validate
RubyTerraform::Commands::Workspace
: executesterraform workspace
The clean command can be called in the following ways:
RubyTerraform.clean
RubyTerraform.clean(directory: 'infra/.terraform')
RubyTerraform::Commands::Clean.new(directory: 'infra/.terraform').execute
RubyTerraform::Commands::Clean.new.execute(directory: 'infra/.terraform')
When called, it removes the contents of the .terraform directory in the working directory by default. If another directory is specified, it instead removes the specified directory.
The init command will initialise a terraform environment. It can be called in the following ways:
RubyTerraform.init
RubyTerraform.init(from_module: 'some/module/path', path: 'infra/module')
RubyTerraform::Commands::Init.new.execute
RubyTerraform::Commands::Init.new.execute(
from_module: 'some/module/path',
path: 'infra/module')
The init command supports the following options passed as keyword arguments:
from_module
: the source module to use to initialise; required ifpath
is specifiedpath
: the path to initialise.backend
:true
/false
, whether or not to configure the backend.get
:true
/false
, whether or not to get dependency modules.backend_config
: a map of backend specific configuration parameters.no_color
: whether or not the output from the command should be in color; defaults tofalse
.plugin_dir
: directory containing plugin binaries. Overrides all default; search paths for plugins and prevents the automatic installation of plugins.
The get command will fetch any modules referenced in the provided terraform configuration directory. It can be called in the following ways:
RubyTerraform.get(directory: 'infra/networking')
RubyTerraform::Commands::Get.new.execute(directory: 'infra/networking')
The get command supports the following options passed as keyword arguments:
directory
: the directory containing terraform configuration; required.update
: whether or not already downloaded modules should be updated; defaults tofalse
.no_color
: whether or not the output from the command should be in color; defaults tofalse
.
The plan command will generate the execution plan in the provided configuration directory. It can be called in the following ways:
RubyTerraform.plan(
directory: 'infra/networking',
vars: {
region: 'eu-central'
})
RubyTerraform::Commands::Plan.new.execute(
directory: 'infra/networking',
vars: {
region: 'eu-central'
})
The plan command supports the following options passed as keyword arguments:
directory
: the directory containing terraform configuration; required.vars
: a map of vars to be passed in to the terraform configuration.var_file
: the path to a terraform var file; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.var_files
: an array of paths to terraform var files; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.target
: the address of a resource to target; if bothtarget
andtargets
are provided, all targets will be passed to terraform.targets
: and array of resource addresses to target; if bothtarget
andtargets
are provided, all targets will be passed to terraform.state
: the path to the state file in which to store state; defaults to terraform.tfstate in the working directory or the remote state if configured.plan
: the name of the file in which to save the generated plan.input
: whenfalse
, will not ask for input for variables not directly set; defaults totrue
.destroy
: whentrue
, a plan will be generated to destroy all resources managed by the given configuration and state; defaults tofalse
.no_color
: whether or not the output from the command should be in color; defaults tofalse
.
The apply command applies terraform configuration in the provided terraform configuration directory. It can be called in the following ways:
RubyTerraform.apply(
directory: 'infra/networking',
vars: {
region: 'eu-central'
})
RubyTerraform::Commands::Apply.new.execute(
directory: 'infra/networking',
vars: {
region: 'eu-central'
})
The apply command supports the following options passed as keyword arguments:
directory
: the directory containing terraform configuration; required.vars
: a map of vars to be passed in to the terraform configuration.var_file
: the path to a terraform var file; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.var_files
: an array of paths to terraform var files; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.target
: the address of a resource to target; if bothtarget
andtargets
are provided, all targets will be passed to terraform.targets
: and array of resource addresses to target; if bothtarget
andtargets
are provided, all targets will be passed to terraform.state
: the path to the state file in which to store state; defaults to terraform.tfstate in the working directory or the remote state if configured.backup
: the path to the backup file in which to store the state backup.input
: whenfalse
, will not ask for input for variables not directly set; defaults totrue
.no_backup
: whentrue
, no backup file will be written; defaults tofalse
.no_color
: whether or not the output from the command should be in color; defaults tofalse
.auto_approve
: iftrue
, the command applys without prompting the user to confirm the changes; defaults tofalse
.
The show command produces human-readable output from a state file or a plan file. It can be called in the following ways:
RubyTerraform.show(
path: 'infra/networking')
RubyTerraform::Commands::Show.new.execute(
path: 'infra/networking')
The show command supports the following options passed as keyword arguments:
path
: the path to a state or plan file; required.no_color
: whether or not the output from the command should be in color; defaults tofalse
.module_depth
: the depth of modules to show in the output; defaults to showing all modules.json
: whether or not the output from the command should be in json format; defaults tofalse
.
The destroy command destroys all resources defined in the terraform configuration in the provided terraform configuration directory. It can be called in the following ways:
RubyTerraform.destroy(
directory: 'infra/networking',
vars: {
region: 'eu-central'
})
RubyTerraform::Commands::Destroy.new.execute(
directory: 'infra/networking',
vars: {
region: 'eu-central'
})
The destroy command supports the following options passed as keyword arguments:
directory
: the directory containing terraform configuration; required.vars
: a map of vars to be passed in to the terraform configuration.var_file
: the path to a terraform var file; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.var_files
: an array of paths to terraform var files; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.target
: the address of a resource to target; if bothtarget
andtargets
are provided, all targets will be passed to terraform.targets
: and array of resource addresses to target; if bothtarget
andtargets
are provided, all targets will be passed to terraform.state
: the path to the state file containing the current state; defaults to terraform.tfstate in the working directory or the remote state if configured.force
: iftrue
, the command destroys without prompting the user to confirm the destruction; defaults tofalse
.backup
: the path to the backup file in which to store the state backup.no_backup
: whentrue
, no backup file will be written; defaults tofalse
.no_color
: whether or not the output from the command should be in color; defaults tofalse
.
The output command retrieves an output from a state file. It can be called in the following ways:
RubyTerraform.output(name: 'vpc_id')
RubyTerraform::Commands::Destroy.new.execute(name: 'vpc_id')
The output command supports the following options passed as keyword arguments:
name
: the name of the output to retrieve; required.state
: the path to the state file containing the current state; defaults to terraform.tfstate in the working directory or the remote state if configured.no_color
: whether or not the output from the command should be in color; defaults tofalse
.module
: the name of a module to retrieve output from.
The refresh command will reconcile state with resources found in the target environment. It can be called in the following ways:
RubyTerraform.refresh(
directory: 'infra/networking',
vars: {
region: 'eu-central'
})
RubyTerraform::Commands::Refresh.new.execute(
directory: 'infra/networking',
vars: {
region: 'eu-central'
})
The refresh command supports the following options passed as keyword arguments:
directory
: the directory containing terraform configuration; required.vars
: a map of vars to be passed in to the terraform configuration.var_file
: the path to a terraform var file; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.var_files
: an array of paths to terraform var files; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.target
: the address of a resource to target; if bothtarget
andtargets
are provided, all targets will be passed to terraform.targets
: and array of resource addresses to target; if bothtarget
andtargets
are provided, all targets will be passed to terraform.state
: the path to the state file in which to store state; defaults to terraform.tfstate in the working directory or the remote state if configured.input
: whenfalse
, will not ask for input for variables not directly set; defaults totrue
.no_color
: whether or not the output from the command should be in color; defaults tofalse
.
The import command imports existing infrastructure into your terraform state. It can be called in the following ways:
RubyTerraform.import(
directory: 'infra/networking',
address: 'a.resource.address',
id: 'a-resource-id',
vars: {
region: 'eu-central'
}))
RubyTerraform::Commands::Import.new.execute(
directory: 'infra/networking',
address: 'a.resource.address',
id: 'a-resource-id',
vars: {
region: 'eu-central'
}))
The import command supports the following options passed as keyword arguments:
directory
: the directory containing terraform configuration; required.address
: a valid resource address; required.id
: id of resource being imported; required.vars
: a map of vars to be passed in to the terraform configuration.var_file
: the path to a terraform var file; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.var_files
: an array of paths to terraform var files; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.input
: whenfalse
, will not ask for input for variables not directly set; defaults totrue
.state
: the path to the state file containing the current state; defaults to terraform.tfstate in the working directory or the remote state if configured.no_backup
: whentrue
, no backup file will be written; defaults tofalse
.backup
: the path to the backup file in which to store the state backup.no_color
: whether or not the output from the command should be in color; defaults tofalse
.
The remote config command configures storage of state using a remote backend. It has been deprecated and since removed from terraform but is retained in this library for backwards compatibility. It can be called in the following ways:
RubyTerraform.remote_config(
backend: 's3',
backend_config: {
bucket: 'example-state-bucket',
key: 'infra/terraform.tfstate',
region: 'eu-west-2'
})
RubyTerraform::Commands::RemoteConfig.new.execute(
backend: 's3',
backend_config: {
bucket: 'example-state-bucket',
key: 'infra/terraform.tfstate',
region: 'eu-west-2'
})
The remote config command supports the following options passed as keyword arguments:
backend
: the type of backend to use; required.backend_config
: a map of backend specific configuration parameters; required.no_color
: whether or not the output from the command should be in color; defaults tofalse
.
The validate command validates terraform configuration in the provided terraform configuration directory. It can be called in the following ways:
RubyTerraform.validate(
directory: 'infra/networking',
vars: {
region: 'eu-central'
})
RubyTerraform::Commands::Validate.new.execute(
directory: 'infra/networking',
vars: {
region: 'eu-central'
})
The validate command supports the following options passed as keyword arguments:
directory
: the directory containing terraform configuration; required.vars
: a map of vars to be passed in to the terraform configuration.var_file
: the path to a terraform var file; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.var_files
: an array of paths to terraform var files; if bothvar_file
andvar_files
are provided, all var files will be passed to terraform.no_color
: whether or not the output from the command should be in color; defaults tofalse
.check_variables
: iftrue
, the command checks whether all variables have been provided; defaults totrue
.json
: whether or not the output from the command should be in json format; defaults tofalse
.
The workspace
command configures
Terraform Workspaces.
It can be used as follows:
RubyTerraform.workspace(operation: 'list')
RubyTerraform.workspace(operation: 'new', workspace: 'staging')
RubyTerraform.workspace(operation: 'select', workspace: 'staging')
RubyTerraform.workspace(operation: 'list')
RubyTerraform.workspace(operation: 'select', workspace: 'default')
RubyTerraform.workspace(operation: 'delete', workspace: 'staging')
arguments:
directory
: the directory containing terraform configuration, the default is the current path.operation
:list
,select
,new
ordelete
. defaultlist
.workspace
: Workspace name.
In addition to configuring the location of the terraform binary, RubyTerraform
offers configuration of logging and standard streams. By default standard
streams map to $stdin
, $stdout
and $stderr
and all logging goes to
$stdout
.
By default, RubyTerraform logs to $stdout
with level info
.
To configure a custom logger:
require 'logger'
logger = Logger.new($stdout)
logger.level = Logger::DEBUG
RubyTerraform.configure do |config|
config.logger = logger
end
RubyTerraform supports logging to multiple different outputs at once, for example:
require 'logger'
log_file = Logger::LogDevice.new('/foo/bar.log') # results in a file with sync true in the background
logger = Logger.new(RubyTerraform::MultiIO.new(STDOUT, log_file), level: :debug)
RubyTerraform.configure do |config|
config.binary = '/binary/path/terraform'
config.logger = logger
config.stdout = logger
config.stderr = logger
end
Creating the Logger with a file this way (using
Logger::LogDevice
), guarantees that the buffer content will be saved/written, as it sets implicit flushing.
Configured in this way, any logging performed by RubyTerraform will log to both
STDOUT
and the provided log_file
.
By default, RubyTerraform uses streams $stdin
, $stdout
and $stderr
.
To configure custom output and error streams:
log_file = File.open('path/to/some/ruby_terraform.log', 'a')
RubyTerraform.configure do |config|
config.stdout = log_file
config.stderr = log_file
end
In this way, both outputs will be redirected to log_file
.
Similarly, a custom input stream can be configured:
require 'stringio'
input = StringIO.new("user\ninput\n")
RubyTerraform.configure do |config|
config.stdin = input
end
In this way, terraform can be driven by input from somewhere other than interactive input from the terminal.
After checking out the repo, run bin/setup
to install dependencies. Then,
run rake spec
to run the tests. You can also run bin/console
for an
interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To
release a new version, update the version number in version.rb
, and then run
bundle exec rake release
, which will create a git tag for the version, push
git commits and tags, and push the .gem
file to
rubygems.org.
To encrypt a GPG key for use by CircleCI:
openssl aes-256-cbc \
-e \
-md sha1 \
-in ./config/secrets/ci/gpg.private \
-out ./.circleci/gpg.private.enc \
-k "<passphrase>"
To check decryption is working correctly:
openssl aes-256-cbc \
-d \
-md sha1 \
-in ./.circleci/gpg.private.enc \
-k "<passphrase>"
Bug reports and pull requests are welcome on GitHub at https://github.com/infrablocks/ruby_terraform. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.