RubyTerraform
A simple wrapper around the Terraform binary to allow execution from within a Ruby program or Rakefile.
Installation
Add this line to your application's Gemfile:
gem 'ruby-terraform'
And then execute:
$ bundle
Or install it yourself as:
$ gem install ruby-terraform
Usage
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 initRubyTerraform::Commands::Get: executesterraform getRubyTerraform::Commands::Plan: executesterraform planRubyTerraform::Commands::Apply: executesterraform applyRubyTerraform::Commands::Show: executesterraform showRubyTerraform::Commands::Destroy: executesterraform destroyRubyTerraform::Commands::Output: executesterraform outputRubyTerraform::Commands::Refresh: executesterraform refreshRubyTerraform::Commands::RemoteConfig: executesterraform remote configRubyTerraform::Commands::Validate: executesterraform validateRubyTerraform::Commands::Workspace: executesterraform workspace
RubyTerraform::Commands::Clean
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.
RubyTerraform::Commands::Init
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 ifpathis 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.
RubyTerraform::Commands::Get
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.
RubyTerraform::Commands::Plan
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_fileandvar_filesare provided, all var files will be passed to terraform.var_files: an array of paths to terraform var files; if bothvar_fileandvar_filesare provided, all var files will be passed to terraform.target: the address of a resource to target; if bothtargetandtargetsare provided, all targets will be passed to terraform.targets: and array of resource addresses to target; if bothtargetandtargetsare 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.
RubyTerraform::Commands::Apply
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_fileandvar_filesare provided, all var files will be passed to terraform.var_files: an array of paths to terraform var files; if bothvar_fileandvar_filesare provided, all var files will be passed to terraform.target: the address of a resource to target; if bothtargetandtargetsare provided, all targets will be passed to terraform.targets: and array of resource addresses to target; if bothtargetandtargetsare 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.
RubyTerraform::Commands::Show
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::Apply.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.
RubyTerraform::Commands::Destroy
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_fileandvar_filesare provided, all var files will be passed to terraform.var_files: an array of paths to terraform var files; if bothvar_fileandvar_filesare provided, all var files will be passed to terraform.target: the address of a resource to target; if bothtargetandtargetsare provided, all targets will be passed to terraform.targets: and array of resource addresses to target; if bothtargetandtargetsare 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.
RubyTerraform::Commands::Output
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.
RubyTerraform::Commands::Refresh
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_fileandvar_filesare provided, all var files will be passed to terraform.var_files: an array of paths to terraform var files; if bothvar_fileandvar_filesare provided, all var files will be passed to terraform.target: the address of a resource to target; if bothtargetandtargetsare provided, all targets will be passed to terraform.targets: and array of resource addresses to target; if bothtargetandtargetsare 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.
RubyTerraform::Commands::RemoteConfig
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.
RubyTerraform::Commands::Validate
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_fileandvar_filesare provided, all var files will be passed to terraform.var_files: an array of paths to terraform var files; if bothvar_fileandvar_filesare 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.
RubyTerraform::Commands::Workspace
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,newordelete. defaultlist.workspace: Workspace name.
Configuration
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.
Logging
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 = File.open('path/to/some/ruby_terraform.log', 'a')
logger = Logger.new(
RubyTerraform::MultiIO.new($stdout, log_file))
logger.level = Logger::DEBUG
RubyTerraform.configure do |config|
config.logger = logger
end
Configured in this way, any logging performed by RubyTerraform will log to both
STDOUT and the provided log_file.
Standard Streams
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.
Development
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.
Managing CircleCI keys
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>"
Contributing
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.
License
The gem is available as open source under the terms of the MIT License.