yle_tf 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.rubocop.yml +26 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +3 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +442 -0
- data/Rakefile +6 -0
- data/bin/tf +7 -0
- data/examples/envs/prod.tfvars +5 -0
- data/examples/envs/test.tfvars +2 -0
- data/examples/main.tf +10 -0
- data/examples/tf.yaml +4 -0
- data/examples/tf_hooks/pre/get_current_hash.sh +26 -0
- data/examples/variables.tf +22 -0
- data/lib/yle_tf.rb +70 -0
- data/lib/yle_tf/action.rb +29 -0
- data/lib/yle_tf/action/builder.rb +9 -0
- data/lib/yle_tf/action/command.rb +25 -0
- data/lib/yle_tf/action/copy_root_module.rb +22 -0
- data/lib/yle_tf/action/generate_vars_file.rb +27 -0
- data/lib/yle_tf/action/load_config.rb +17 -0
- data/lib/yle_tf/action/terraform_init.rb +63 -0
- data/lib/yle_tf/action/tf_hooks.rb +48 -0
- data/lib/yle_tf/action/tmpdir.rb +35 -0
- data/lib/yle_tf/action/verify_terraform_version.rb +41 -0
- data/lib/yle_tf/action/verify_tf_env.rb +24 -0
- data/lib/yle_tf/backend_config.rb +41 -0
- data/lib/yle_tf/cli.rb +88 -0
- data/lib/yle_tf/config.rb +45 -0
- data/lib/yle_tf/config/defaults.rb +35 -0
- data/lib/yle_tf/config/erb.rb +22 -0
- data/lib/yle_tf/config/file.rb +26 -0
- data/lib/yle_tf/config/loader.rb +108 -0
- data/lib/yle_tf/error.rb +4 -0
- data/lib/yle_tf/logger.rb +48 -0
- data/lib/yle_tf/plugin.rb +55 -0
- data/lib/yle_tf/plugin/action_hook.rb +23 -0
- data/lib/yle_tf/plugin/loader.rb +59 -0
- data/lib/yle_tf/plugin/manager.rb +49 -0
- data/lib/yle_tf/system.rb +22 -0
- data/lib/yle_tf/tf_hook.rb +90 -0
- data/lib/yle_tf/tf_hook/runner.rb +48 -0
- data/lib/yle_tf/vars_file.rb +42 -0
- data/lib/yle_tf/version.rb +3 -0
- data/lib/yle_tf/version_requirement.rb +25 -0
- data/lib/yle_tf_plugins/backends/file/command.rb +31 -0
- data/lib/yle_tf_plugins/backends/file/config.rb +17 -0
- data/lib/yle_tf_plugins/backends/file/plugin.rb +16 -0
- data/lib/yle_tf_plugins/backends/s3/command.rb +19 -0
- data/lib/yle_tf_plugins/backends/s3/plugin.rb +16 -0
- data/lib/yle_tf_plugins/commands/__default/command.rb +14 -0
- data/lib/yle_tf_plugins/commands/__default/plugin.rb +14 -0
- data/lib/yle_tf_plugins/commands/_config/command.rb +11 -0
- data/lib/yle_tf_plugins/commands/_config/plugin.rb +19 -0
- data/lib/yle_tf_plugins/commands/_shell/command.rb +15 -0
- data/lib/yle_tf_plugins/commands/_shell/plugin.rb +14 -0
- data/lib/yle_tf_plugins/commands/help/command.rb +55 -0
- data/lib/yle_tf_plugins/commands/help/plugin.rb +18 -0
- data/lib/yle_tf_plugins/commands/version/command.rb +20 -0
- data/lib/yle_tf_plugins/commands/version/plugin.rb +18 -0
- data/vendor/hash_deep_merge.rb +59 -0
- data/vendor/logger_level_patch.rb +29 -0
- data/vendor/middleware/LICENSE +23 -0
- data/vendor/middleware/builder.rb +149 -0
- data/vendor/middleware/runner.rb +69 -0
- data/yle_tf.gemspec +37 -0
- metadata +160 -0
data/Rakefile
ADDED
data/bin/tf
ADDED
data/examples/main.tf
ADDED
data/examples/tf.yaml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -eu
|
4
|
+
|
5
|
+
current_hash() {
|
6
|
+
CURRENT_GIT_HASH="$(git rev-parse HEAD)"
|
7
|
+
|
8
|
+
cat <<EOF > current_git_hash.tf.json
|
9
|
+
{
|
10
|
+
"variable": {
|
11
|
+
"current_git_hash": {
|
12
|
+
"value": "$CURRENT_GIT_HASH"
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
16
|
+
EOF
|
17
|
+
}
|
18
|
+
|
19
|
+
# Execute only for commands `plan` and `apply`
|
20
|
+
case "$TF_COMMAND" in
|
21
|
+
plan|apply)
|
22
|
+
current_hash
|
23
|
+
;;
|
24
|
+
*)
|
25
|
+
;;
|
26
|
+
esac
|
@@ -0,0 +1,22 @@
|
|
1
|
+
variable "region" {
|
2
|
+
description = "The AWS region for the resources"
|
3
|
+
default = "eu-west-1"
|
4
|
+
}
|
5
|
+
|
6
|
+
variable "env" {
|
7
|
+
# passed by `tf`
|
8
|
+
description = "The environment"
|
9
|
+
}
|
10
|
+
|
11
|
+
variable "aws_access_key" {
|
12
|
+
description = "Your AWS access key id"
|
13
|
+
}
|
14
|
+
|
15
|
+
variable "aws_secret_key" {
|
16
|
+
description = "Your AWS secret key"
|
17
|
+
}
|
18
|
+
|
19
|
+
variable "instance_type" {
|
20
|
+
description = "Instance type to use"
|
21
|
+
default = "t2.micro"
|
22
|
+
}
|
data/lib/yle_tf.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'yle_tf/logger'
|
2
|
+
require 'yle_tf/version'
|
3
|
+
|
4
|
+
class YleTf
|
5
|
+
autoload :Action, 'yle_tf/action'
|
6
|
+
autoload :Error, 'yle_tf/error'
|
7
|
+
autoload :Plugin, 'yle_tf/plugin'
|
8
|
+
|
9
|
+
attr_reader :tf_env, :tf_command, :tf_command_args, :tf_options
|
10
|
+
attr_writer :actions
|
11
|
+
|
12
|
+
def initialize(tf_options, tf_env, tf_command, tf_command_args = [])
|
13
|
+
Logger.debug("YleTf version: #{VERSION}")
|
14
|
+
Logger.debug("Ruby version: #{RUBY_VERSION}")
|
15
|
+
Logger.debug("tf_options: #{tf_options.inspect}")
|
16
|
+
Logger.debug("tf_env: #{tf_env.inspect}")
|
17
|
+
Logger.debug("tf_command: #{tf_command.inspect}")
|
18
|
+
Logger.debug("tf_command_args: #{tf_command_args.inspect}")
|
19
|
+
|
20
|
+
@tf_options = tf_options
|
21
|
+
@tf_env = tf_env
|
22
|
+
@tf_command = tf_command
|
23
|
+
@tf_command_args = tf_command_args
|
24
|
+
|
25
|
+
Plugin::Loader.load_plugins
|
26
|
+
end
|
27
|
+
|
28
|
+
def run(env = {})
|
29
|
+
Logger.debug('Building and running the stack')
|
30
|
+
apply_action_hooks
|
31
|
+
Logger.debug("actions: #{actions.inspect}")
|
32
|
+
env.merge!(action_env)
|
33
|
+
Logger.debug("env: #{env.inspect}")
|
34
|
+
actions.call(env)
|
35
|
+
end
|
36
|
+
|
37
|
+
def actions
|
38
|
+
@actions ||= build_action_stack
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_action_stack
|
42
|
+
command_data = Plugin.manager.commands[tf_command]
|
43
|
+
command_proc = command_data[:proc]
|
44
|
+
command_proc.call
|
45
|
+
end
|
46
|
+
|
47
|
+
def apply_action_hooks
|
48
|
+
hooks = Plugin.manager.action_hooks
|
49
|
+
Logger.debug("Applying #{hooks.length} action hooks")
|
50
|
+
Plugin::ActionHook.new(actions).tap do |h|
|
51
|
+
hooks.each { |hook_proc| hook_proc.call(h) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def action_env
|
56
|
+
{
|
57
|
+
tf_options: tf_options,
|
58
|
+
tf_env: tf_env,
|
59
|
+
tf_command: tf_command,
|
60
|
+
tf_command_args: tf_command_args,
|
61
|
+
tfvars: default_tfvars,
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def default_tfvars
|
66
|
+
{
|
67
|
+
'env' => tf_env,
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class YleTf
|
2
|
+
module Action
|
3
|
+
autoload :Builder, 'yle_tf/action/builder'
|
4
|
+
autoload :Command, 'yle_tf/action/command'
|
5
|
+
autoload :CopyRootModule, 'yle_tf/action/copy_root_module'
|
6
|
+
autoload :GenerateVarsFile, 'yle_tf/action/generate_vars_file'
|
7
|
+
autoload :LoadConfig, 'yle_tf/action/load_config'
|
8
|
+
autoload :TerraformInit, 'yle_tf/action/terraform_init'
|
9
|
+
autoload :TfHooks, 'yle_tf/action/tf_hooks'
|
10
|
+
autoload :TmpDir, 'yle_tf/action/tmpdir'
|
11
|
+
autoload :VerifyTfEnv, 'yle_tf/action/verify_tf_env'
|
12
|
+
autoload :VerifyTerraformVersion, 'yle_tf/action/verify_terraform_version'
|
13
|
+
|
14
|
+
def self.default_action_stack(command_class = nil)
|
15
|
+
Builder.new do
|
16
|
+
use LoadConfig
|
17
|
+
use VerifyTfEnv
|
18
|
+
use TmpDir
|
19
|
+
use VerifyTerraformVersion
|
20
|
+
use CopyRootModule
|
21
|
+
use GenerateVarsFile
|
22
|
+
use TfHooks
|
23
|
+
use TerraformInit
|
24
|
+
|
25
|
+
use(Command, command_class) if command_class
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'yle_tf/logger'
|
2
|
+
|
3
|
+
class YleTf
|
4
|
+
module Action
|
5
|
+
class Command
|
6
|
+
attr_reader :command
|
7
|
+
|
8
|
+
def initialize(app, command)
|
9
|
+
@app = app
|
10
|
+
@command = command
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
if env[:tf_options][:only_hooks]
|
15
|
+
Logger.debug "Skipping command #{command.class} due to `--only-hooks`"
|
16
|
+
else
|
17
|
+
Logger.debug "Executing command #{command.class} with env: #{env.inspect}"
|
18
|
+
command.new.execute(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require 'yle_tf/logger'
|
4
|
+
|
5
|
+
class YleTf
|
6
|
+
module Action
|
7
|
+
class CopyRootModule
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
config = env[:config]
|
14
|
+
|
15
|
+
Logger.debug("Copying the Terraform module from '#{config.module_dir}' to '#{Dir.pwd}'")
|
16
|
+
FileUtils.cp_r("#{config.module_dir}/.", '.')
|
17
|
+
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'yle_tf/logger'
|
2
|
+
require 'yle_tf/vars_file'
|
3
|
+
|
4
|
+
class YleTf
|
5
|
+
module Action
|
6
|
+
class GenerateVarsFile
|
7
|
+
def initialize(app)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
config = env[:config]
|
13
|
+
|
14
|
+
Logger.debug("Generating 'terraform.tfvars'")
|
15
|
+
vars_file = VarsFile.new('terraform.tfvars')
|
16
|
+
vars_file.append_vars(tfvars(env))
|
17
|
+
vars_file.append_file(VarsFile.find_env_vars_file(config))
|
18
|
+
|
19
|
+
@app.call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
def tfvars(env)
|
23
|
+
env[:tfvars].merge(env[:config].fetch('tfvars'))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'yle_tf/error'
|
2
|
+
require 'yle_tf/logger'
|
3
|
+
require 'yle_tf/plugin'
|
4
|
+
require 'yle_tf/system'
|
5
|
+
require 'yle_tf/version_requirement'
|
6
|
+
|
7
|
+
class YleTf
|
8
|
+
module Action
|
9
|
+
class TerraformInit
|
10
|
+
def initialize(app)
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
config = env[:config]
|
16
|
+
backend = backend_config(config)
|
17
|
+
|
18
|
+
Logger.debug('Initializing Terraform with backend configuration:')
|
19
|
+
Logger.debug(backend.to_s)
|
20
|
+
|
21
|
+
if VersionRequirement.pre_0_9?(env[:terraform_version])
|
22
|
+
init_pre_0_9(backend)
|
23
|
+
else
|
24
|
+
init(backend)
|
25
|
+
end
|
26
|
+
|
27
|
+
@app.call(env)
|
28
|
+
end
|
29
|
+
|
30
|
+
def init_pre_0_9(backend)
|
31
|
+
cli_args = backend.cli_args
|
32
|
+
YleTf::System.cmd('terraform', 'remote', 'config', *cli_args) if cli_args
|
33
|
+
|
34
|
+
Logger.debug('Fetching Terraform modules')
|
35
|
+
YleTf::System.cmd('terraform', 'get')
|
36
|
+
end
|
37
|
+
|
38
|
+
def init(backend)
|
39
|
+
Logger.debug('Generating the backend configuration')
|
40
|
+
backend.generate_config do
|
41
|
+
Logger.debug('Initializing Terraform')
|
42
|
+
YleTf::System.cmd('terraform', 'init', '-no-color')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def backend_config(config)
|
47
|
+
backend_type = config.fetch('backend', 'type').downcase
|
48
|
+
backend_proc = backend_proc(backend_type)
|
49
|
+
|
50
|
+
klass = backend_proc.call
|
51
|
+
klass.new.backend_config(config)
|
52
|
+
end
|
53
|
+
|
54
|
+
def backend_proc(backend_type)
|
55
|
+
backends = Plugin.manager.backends
|
56
|
+
backends.fetch(backend_type.to_sym) do
|
57
|
+
raise Error, "Unknown backend type '#{backend_type}'. " \
|
58
|
+
"Supported backends: #{backends.keys.join(', ')}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'yle_tf/logger'
|
2
|
+
require 'yle_tf/tf_hook/runner'
|
3
|
+
|
4
|
+
require 'yle_tf/logger'
|
5
|
+
require 'yle_tf/tf_hook/runner'
|
6
|
+
|
7
|
+
class YleTf
|
8
|
+
module Action
|
9
|
+
class TfHooks
|
10
|
+
def initialize(app)
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
@env = env
|
16
|
+
|
17
|
+
hook_runner.run('pre')
|
18
|
+
@app.call(env)
|
19
|
+
hook_runner.run('post')
|
20
|
+
end
|
21
|
+
|
22
|
+
def hook_runner
|
23
|
+
if run_hooks?
|
24
|
+
TfHook::Runner.new(@env[:config], hook_env)
|
25
|
+
else
|
26
|
+
NoRunner
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def hook_env
|
31
|
+
{
|
32
|
+
'TF_COMMAND' => @env[:tf_command],
|
33
|
+
'TF_ENV' => @env[:tf_env],
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def run_hooks?
|
38
|
+
!@env[:tf_options][:no_hooks]
|
39
|
+
end
|
40
|
+
|
41
|
+
class NoRunner
|
42
|
+
def self.run(hook_type)
|
43
|
+
Logger.debug("Skipping #{hook_type} hooks due to `--no-hooks`")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
require 'yle_tf/logger'
|
5
|
+
|
6
|
+
class YleTf
|
7
|
+
module Action
|
8
|
+
class TmpDir
|
9
|
+
def initialize(app)
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
config = env[:config]
|
15
|
+
|
16
|
+
tmpdir = Dir.mktmpdir(tmpdir_prefix(config))
|
17
|
+
Logger.debug("Temporary Terraform directory: #{tmpdir}")
|
18
|
+
|
19
|
+
Dir.chdir(tmpdir) do
|
20
|
+
@app.call(env)
|
21
|
+
end
|
22
|
+
ensure
|
23
|
+
FileUtils.rm_r(tmpdir) if tmpdir
|
24
|
+
end
|
25
|
+
|
26
|
+
def tmpdir_prefix(config)
|
27
|
+
if config
|
28
|
+
"tf_#{config.module_dir.basename}_#{config.tf_env}_"
|
29
|
+
else
|
30
|
+
'tf_'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|