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
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
class YleTf
|
4
|
+
# Helper class for comparing versions
|
5
|
+
class VersionRequirement
|
6
|
+
# Checks if the specified Terrform version is older than 0.9
|
7
|
+
def self.pre_0_9?(terraform_version)
|
8
|
+
new('< 0.9.0-beta').satisfied_by?(terraform_version)
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :requirement
|
12
|
+
|
13
|
+
def initialize(requirement)
|
14
|
+
@requirement = requirement && Gem::Requirement.new(*requirement)
|
15
|
+
end
|
16
|
+
|
17
|
+
def satisfied_by?(version)
|
18
|
+
!requirement || requirement.satisfied_by?(Gem::Version.new(version))
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
requirement.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative 'config'
|
2
|
+
|
3
|
+
module YleTfPlugins
|
4
|
+
module Backends
|
5
|
+
module File
|
6
|
+
class Command
|
7
|
+
def backend_config(config)
|
8
|
+
local_path = Pathname.pwd.join('terraform.tfstate')
|
9
|
+
tfstate_path = tfstate_path(config)
|
10
|
+
|
11
|
+
YleTf::Logger.info("Symlinking state to '#{tfstate_path}'")
|
12
|
+
local_path.make_symlink(tfstate_path)
|
13
|
+
tfstate_path.write(tfstate_template, perm: 0o644) if !tfstate_path.exist?
|
14
|
+
|
15
|
+
Config.new(
|
16
|
+
'file',
|
17
|
+
'file' => tfstate_path.to_s
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def tfstate_path(config)
|
22
|
+
config.module_dir.join(config.fetch('backend', 'file'))
|
23
|
+
end
|
24
|
+
|
25
|
+
def tfstate_template
|
26
|
+
'{"version": 1}'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'yle_tf/backend_config'
|
2
|
+
|
3
|
+
module YleTfPlugins
|
4
|
+
module Backends
|
5
|
+
module S3
|
6
|
+
class Command
|
7
|
+
def backend_config(config)
|
8
|
+
YleTf::BackendConfig.new(
|
9
|
+
's3',
|
10
|
+
'region' => config.fetch('backend', 'region'),
|
11
|
+
'bucket' => config.fetch('backend', 'bucket'),
|
12
|
+
'key' => config.fetch('backend', 'file'),
|
13
|
+
'encrypt' => config.fetch('backend', 'encrypt')
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'yle_tf'
|
2
|
+
|
3
|
+
module YleTfPlugins
|
4
|
+
module CommandDefault
|
5
|
+
class Plugin < YleTf::Plugin
|
6
|
+
register
|
7
|
+
|
8
|
+
command(DEFAULT_COMMAND, 'Calls Terraform with the given subcommand') do
|
9
|
+
require_relative 'command'
|
10
|
+
YleTf::Action.default_action_stack(Command)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'yle_tf'
|
2
|
+
|
3
|
+
module YleTfPlugins
|
4
|
+
module CommandConfig
|
5
|
+
class Plugin < YleTf::Plugin
|
6
|
+
register
|
7
|
+
|
8
|
+
command('_config', 'Prints the evaluated configuration') do
|
9
|
+
require_relative 'command'
|
10
|
+
|
11
|
+
YleTf::Action::Builder.new do
|
12
|
+
use YleTf::Action::LoadConfig
|
13
|
+
use YleTf::Action::VerifyTfEnv
|
14
|
+
use YleTf::Action::Command, Command
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module YleTfPlugins
|
2
|
+
module CommandShell
|
3
|
+
class Command
|
4
|
+
def execute(_env)
|
5
|
+
shell = ENV.fetch('SHELL', 'bash')
|
6
|
+
|
7
|
+
puts "Executing shell '#{shell}' in the Terraform directory"
|
8
|
+
puts 'Use `exit` to quit'
|
9
|
+
puts
|
10
|
+
|
11
|
+
system(shell)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'yle_tf'
|
2
|
+
|
3
|
+
module YleTfPlugins
|
4
|
+
module CommandShell
|
5
|
+
class Plugin < YleTf::Plugin
|
6
|
+
register
|
7
|
+
|
8
|
+
command('_shell', 'Executes shell in the prepared environment') do
|
9
|
+
require_relative 'command'
|
10
|
+
YleTf::Action.default_action_stack(Command)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
require 'yle_tf/plugin'
|
4
|
+
|
5
|
+
module YleTfPlugins
|
6
|
+
module CommandHelp
|
7
|
+
class Command
|
8
|
+
def execute(env)
|
9
|
+
device(env).puts(opts.help)
|
10
|
+
exit 1 if error?(env)
|
11
|
+
end
|
12
|
+
|
13
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
14
|
+
def opts
|
15
|
+
OptionParser.new do |o|
|
16
|
+
o.summary_width = 18
|
17
|
+
o.banner = 'Usage: tf <environment> <command> [<args>]'
|
18
|
+
o.separator ''
|
19
|
+
o.separator 'YleTf options:'
|
20
|
+
o.on('-h', '--help', 'Prints this help')
|
21
|
+
o.on('-v', '--version', 'Prints the version information')
|
22
|
+
o.on('--debug', 'Print debug information')
|
23
|
+
o.on('--no-hooks', 'Do not run any hooks')
|
24
|
+
o.on('--only-hooks', 'Only run the hooks')
|
25
|
+
o.separator ''
|
26
|
+
o.separator 'Special tf commands:'
|
27
|
+
o.separator tf_command_help
|
28
|
+
o.separator ''
|
29
|
+
o.separator 'Terraform commands:'
|
30
|
+
o.separator terraform_help
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def error?(env)
|
35
|
+
env[:tf_env] == 'error'
|
36
|
+
end
|
37
|
+
|
38
|
+
def device(env)
|
39
|
+
error?(env) ? STDERR : STDOUT
|
40
|
+
end
|
41
|
+
|
42
|
+
def tf_command_help
|
43
|
+
YleTf::Plugin.manager.commands.sort.map do |command, data|
|
44
|
+
" #{command.ljust(18)} #{data[:synopsis]}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def terraform_help
|
49
|
+
`terraform help`.lines.grep(/^ /)
|
50
|
+
rescue Errno::ENOENT
|
51
|
+
' [Terraform not found]'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'yle_tf'
|
2
|
+
|
3
|
+
module YleTfPlugins
|
4
|
+
module CommandHelp
|
5
|
+
class Plugin < YleTf::Plugin
|
6
|
+
register
|
7
|
+
|
8
|
+
command('help', 'Prints this help') do
|
9
|
+
require_relative 'command'
|
10
|
+
|
11
|
+
YleTf::Action::Builder.new do
|
12
|
+
use YleTf::Action::TmpDir
|
13
|
+
use YleTf::Action::Command, Command
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
require 'yle_tf/version'
|
4
|
+
|
5
|
+
module YleTfPlugins
|
6
|
+
module CommandVersion
|
7
|
+
class Command
|
8
|
+
def execute(_env)
|
9
|
+
puts "YleTf #{YleTf::VERSION}"
|
10
|
+
puts terraform_version
|
11
|
+
end
|
12
|
+
|
13
|
+
def terraform_version
|
14
|
+
`terraform version`.lines.first
|
15
|
+
rescue Errno::ENOENT
|
16
|
+
'[Terraform not found]'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'yle_tf'
|
2
|
+
|
3
|
+
module YleTfPlugins
|
4
|
+
module CommandVersion
|
5
|
+
class Plugin < YleTf::Plugin
|
6
|
+
register
|
7
|
+
|
8
|
+
command('version', 'Prints the version information') do
|
9
|
+
require_relative 'command'
|
10
|
+
|
11
|
+
YleTf::Action::Builder.new do
|
12
|
+
use YleTf::Action::TmpDir
|
13
|
+
use YleTf::Action::Command, Command
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright (c) 2005-2017 David Heinemeier Hansson
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
class Hash
|
23
|
+
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
24
|
+
#
|
25
|
+
# h1 = { a: true, b: { c: [1, 2, 3] } }
|
26
|
+
# h2 = { a: false, b: { x: [3, 4, 5] } }
|
27
|
+
#
|
28
|
+
# h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
|
29
|
+
#
|
30
|
+
# Like with Hash#merge in the standard library, a block can be provided
|
31
|
+
# to merge values:
|
32
|
+
#
|
33
|
+
# h1 = { a: 100, b: 200, c: { c1: 100 } }
|
34
|
+
# h2 = { b: 250, c: { c1: 200 } }
|
35
|
+
# h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
|
36
|
+
# # => { a: 100, b: 450, c: { c1: 300 } }
|
37
|
+
def deep_merge(other_hash, &block)
|
38
|
+
dup.deep_merge!(other_hash, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Same as +deep_merge+, but modifies +self+.
|
42
|
+
def deep_merge!(other_hash, &block)
|
43
|
+
other_hash.each_pair do |current_key, other_value|
|
44
|
+
this_value = self[current_key]
|
45
|
+
|
46
|
+
self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
|
47
|
+
this_value.deep_merge(other_value, &block)
|
48
|
+
else
|
49
|
+
if block_given? && key?(current_key)
|
50
|
+
block.call(current_key, this_value, other_value)
|
51
|
+
else
|
52
|
+
other_value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
self
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
class YleTf
|
4
|
+
module LoggerLevelPatch
|
5
|
+
# Taken from Ruby 2.4.1
|
6
|
+
def level=(severity)
|
7
|
+
if severity.is_a?(Integer)
|
8
|
+
@level = severity
|
9
|
+
else
|
10
|
+
case severity.to_s.downcase
|
11
|
+
when 'debug'.freeze
|
12
|
+
@level = ::Logger::DEBUG
|
13
|
+
when 'info'.freeze
|
14
|
+
@level = ::Logger::INFO
|
15
|
+
when 'warn'.freeze
|
16
|
+
@level = ::Logger::WARN
|
17
|
+
when 'error'.freeze
|
18
|
+
@level = ::Logger::ERROR
|
19
|
+
when 'fatal'.freeze
|
20
|
+
@level = ::Logger::FATAL
|
21
|
+
when 'unknown'.freeze
|
22
|
+
@level = ::Logger::UNKNOWN
|
23
|
+
else
|
24
|
+
raise ArgumentError, "invalid log level: #{severity}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|