yle_tf 1.0.0 → 1.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/bin/tf +1 -0
  3. data/lib/yle_tf/action/builder.rb +2 -0
  4. data/lib/yle_tf/action/command.rb +4 -2
  5. data/lib/yle_tf/action/copy_root_module.rb +2 -0
  6. data/lib/yle_tf/action/generate_vars_file.rb +2 -0
  7. data/lib/yle_tf/action/load_config.rb +9 -1
  8. data/lib/yle_tf/action/terraform_init.rb +14 -36
  9. data/lib/yle_tf/action/tf_hooks.rb +2 -0
  10. data/lib/yle_tf/action/tmpdir.rb +3 -1
  11. data/lib/yle_tf/action/verify_terraform_version.rb +19 -6
  12. data/lib/yle_tf/action/verify_tf_env.rb +2 -0
  13. data/lib/yle_tf/action/write_terraformrc_defaults.rb +4 -2
  14. data/lib/yle_tf/action.rb +2 -0
  15. data/lib/yle_tf/backend.rb +42 -0
  16. data/lib/yle_tf/cli.rb +2 -0
  17. data/lib/yle_tf/config/defaults.rb +19 -11
  18. data/lib/yle_tf/config/erb.rb +2 -0
  19. data/lib/yle_tf/config/file.rb +2 -0
  20. data/lib/yle_tf/config/loader.rb +89 -59
  21. data/lib/yle_tf/config/migration.rb +110 -0
  22. data/lib/yle_tf/config.rb +25 -9
  23. data/lib/yle_tf/error.rb +2 -0
  24. data/lib/yle_tf/helpers/hash.rb +22 -0
  25. data/lib/yle_tf/logger/colorize.rb +2 -0
  26. data/lib/yle_tf/logger.rb +2 -0
  27. data/lib/yle_tf/plugin/action_hook.rb +2 -0
  28. data/lib/yle_tf/plugin/loader.rb +8 -1
  29. data/lib/yle_tf/plugin/manager.rb +3 -0
  30. data/lib/yle_tf/plugin.rb +6 -2
  31. data/lib/yle_tf/system/io_handlers.rb +4 -0
  32. data/lib/yle_tf/system/output_logger.rb +2 -0
  33. data/lib/yle_tf/system/tf_hook_output_logger.rb +2 -0
  34. data/lib/yle_tf/system.rb +3 -1
  35. data/lib/yle_tf/tf_hook/runner.rb +2 -0
  36. data/lib/yle_tf/tf_hook.rb +11 -9
  37. data/lib/yle_tf/vars_file.rb +16 -3
  38. data/lib/yle_tf/version.rb +3 -1
  39. data/lib/yle_tf/version_requirement.rb +2 -5
  40. data/lib/yle_tf.rb +4 -0
  41. data/lib/yle_tf_plugins/backends/{s3 → __default}/plugin.rb +6 -4
  42. data/lib/yle_tf_plugins/backends/file/{command.rb → backend.rb} +12 -13
  43. data/lib/yle_tf_plugins/backends/file/plugin.rb +4 -2
  44. data/lib/yle_tf_plugins/commands/__default/command.rb +2 -0
  45. data/lib/yle_tf_plugins/commands/__default/plugin.rb +2 -0
  46. data/lib/yle_tf_plugins/commands/_config/command.rb +2 -0
  47. data/lib/yle_tf_plugins/commands/_config/plugin.rb +2 -0
  48. data/lib/yle_tf_plugins/commands/_shell/command.rb +2 -0
  49. data/lib/yle_tf_plugins/commands/_shell/plugin.rb +2 -0
  50. data/lib/yle_tf_plugins/commands/help/command.rb +2 -0
  51. data/lib/yle_tf_plugins/commands/help/plugin.rb +2 -0
  52. data/lib/yle_tf_plugins/commands/version/command.rb +2 -0
  53. data/lib/yle_tf_plugins/commands/version/plugin.rb +2 -0
  54. metadata +41 -16
  55. data/lib/yle_tf/backend_config.rb +0 -41
  56. data/lib/yle_tf_plugins/backends/file/config.rb +0 -17
  57. data/lib/yle_tf_plugins/backends/s3/command.rb +0 -19
  58. data/lib/yle_tf_plugins/backends/swift/command.rb +0 -18
  59. data/lib/yle_tf_plugins/backends/swift/plugin.rb +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f901e67d48b00b9c2a6692677eee372f69db444952618773bdc6edac24d5fd0
4
- data.tar.gz: 8f98e4fa5c53bdc58cc758aa46be51ff7867747b5fe187cb54b1a2b83e025f80
3
+ metadata.gz: 8203ca939d1933be0bb2aae8ba26d4a7a8b385fce0f65c52f4d707cf6260f323
4
+ data.tar.gz: 0e518cdaa2a4ecbdb76dae38b86b4f31a178e345c0e16fb10f469d1df8f950ab
5
5
  SHA512:
6
- metadata.gz: 4aef3de1f089f711fffe0e538186516b3cd3a81c0b0f672e3302a66d2fb5c625dd22076a5f9ac7e6b228ad34ea90780f28f160ddc73709c3967717646bde56e6
7
- data.tar.gz: 79508c7c0031a6515820efa3c415a131ff3e6cf34e840cd0f479436bf41a86cde065671e292a3e88a26132a47297d5a78ed6f5ccbdde5cd6a89ec92508b66f0b
6
+ metadata.gz: 9127c39276c80009aa7d233f7398ec0ee2ea2784eac1d9fc460c245c5f654fb36a910d4c52bd3453cd9db19595d207f4f545de2aa408e1866cb84b9a534d3cd8
7
+ data.tar.gz: 5c851247db9645aeef3711baa47f40ff682b21ae7030ae1a8a90b3acb6eb70dbb70a8a3f044f92b7d235f87f678a8919cc563368861042fa8c82ed48bf843997
data/bin/tf CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # Catch Ctrl+C to avoid stack traces
4
5
  Signal.trap('INT') { abort }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../../../vendor/middleware/builder'
2
4
 
3
5
  class YleTf
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yle_tf/logger'
2
4
 
3
5
  class YleTf
@@ -12,9 +14,9 @@ class YleTf
12
14
 
13
15
  def call(env)
14
16
  if env[:tf_options][:only_hooks]
15
- Logger.debug "Skipping command #{command.class} due to `--only-hooks`"
17
+ Logger.debug "Skipping command #{command} due to `--only-hooks`"
16
18
  else
17
- Logger.debug "Executing command #{command.class} with env: #{env.inspect}"
19
+ Logger.debug "Executing command #{command} with env: #{env.inspect}"
18
20
  command.new.execute(env)
19
21
  end
20
22
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fileutils'
2
4
 
3
5
  require 'yle_tf/logger'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yle_tf/logger'
2
4
  require 'yle_tf/vars_file'
3
5
 
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yle_tf/config'
4
+ require 'yle_tf/logger'
2
5
 
3
6
  class YleTf
4
7
  module Action
@@ -8,10 +11,15 @@ class YleTf
8
11
  end
9
12
 
10
13
  def call(env)
11
- env[:config] ||= Config.new(env[:tf_env])
14
+ env[:config] ||= load_config(env[:tf_env])
12
15
 
13
16
  @app.call(env)
14
17
  end
18
+
19
+ def load_config(tf_env)
20
+ Logger.debug("Initializing configuration for the #{tf_env.inspect} environment")
21
+ Config.load(tf_env).tap { |config| Logger.debug(config.inspect) }
22
+ end
15
23
  end
16
24
  end
17
25
  end
@@ -1,8 +1,8 @@
1
- require 'yle_tf/error'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'yle_tf/logger'
3
4
  require 'yle_tf/plugin'
4
5
  require 'yle_tf/system'
5
- require 'yle_tf/version_requirement'
6
6
 
7
7
  class YleTf
8
8
  module Action
@@ -10,8 +10,8 @@ class YleTf
10
10
  TF_CMD_ARGS = %w[-input=false -no-color].freeze
11
11
 
12
12
  TF_CMD_OPTS = {
13
- env: { 'TF_IN_AUTOMATION' => 'true' }, # Reduces some output
14
- stdout: :debug # Hide the output to the debug level
13
+ env: { 'TF_IN_AUTOMATION' => 'true' }, # Reduces some output
14
+ stdout: :debug # Hide the output to the debug level
15
15
  }.freeze
16
16
 
17
17
  def initialize(app)
@@ -20,52 +20,30 @@ class YleTf
20
20
 
21
21
  def call(env)
22
22
  config = env[:config]
23
- backend = backend_config(config)
23
+ backend = backend(config)
24
24
 
25
25
  Logger.info('Initializing Terraform')
26
26
  Logger.debug("Backend configuration: #{backend}")
27
27
 
28
- if VersionRequirement.pre_0_9?(env[:terraform_version])
29
- init_pre_0_9(backend)
30
- else
31
- init(backend)
32
- end
28
+ init(backend)
33
29
 
34
30
  @app.call(env)
35
31
  end
36
32
 
37
- def init_pre_0_9(backend)
38
- cli_args = backend.cli_args
39
- if cli_args
40
- YleTf::System.cmd('terraform', 'remote', 'config', *TF_CMD_ARGS, *cli_args, TF_CMD_OPTS)
41
- end
42
-
43
- Logger.debug('Fetching Terraform modules')
44
- YleTf::System.cmd('terraform', 'get', *TF_CMD_ARGS, TF_CMD_OPTS)
45
- end
46
-
47
33
  def init(backend)
48
- Logger.debug('Generating the backend configuration')
49
- backend.generate_config do
50
- Logger.debug('Initializing Terraform')
51
- YleTf::System.cmd('terraform', 'init', *TF_CMD_ARGS, TF_CMD_OPTS)
52
- end
34
+ Logger.debug('Configuring the backend')
35
+ backend.configure
36
+
37
+ Logger.debug('Initializing Terraform')
38
+ YleTf::System.cmd('terraform', 'init', *TF_CMD_ARGS, TF_CMD_OPTS)
53
39
  end
54
40
 
55
- def backend_config(config)
41
+ def backend(config)
56
42
  backend_type = config.fetch('backend', 'type').downcase
57
- backend_proc = backend_proc(backend_type)
43
+ backend_proc = Plugin.manager.backends[backend_type]
58
44
 
59
45
  klass = backend_proc.call
60
- klass.new.backend_config(config)
61
- end
62
-
63
- def backend_proc(backend_type)
64
- backends = Plugin.manager.backends
65
- backends.fetch(backend_type.to_sym) do
66
- raise Error, "Unknown backend type '#{backend_type}'. " \
67
- "Supported backends: #{backends.keys.join(', ')}"
68
- end
46
+ klass.new(config)
69
47
  end
70
48
  end
71
49
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yle_tf/logger'
2
4
  require 'yle_tf/tf_hook/runner'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fileutils'
2
4
  require 'tmpdir'
3
5
 
@@ -20,7 +22,7 @@ class YleTf
20
22
  @app.call(env)
21
23
  end
22
24
  ensure
23
- FileUtils.rm_r(tmpdir) if tmpdir && Dir.exist?(tmpdir)
25
+ FileUtils.rm_rf(tmpdir, secure: true) if tmpdir && Dir.exist?(tmpdir)
24
26
  end
25
27
 
26
28
  def tmpdir_prefix(config)
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yle_tf'
1
4
  require 'yle_tf/error'
2
5
  require 'yle_tf/logger'
3
6
  require 'yle_tf/system'
@@ -17,22 +20,32 @@ class YleTf
17
20
  raise(Error, 'Terraform not found') if !version
18
21
 
19
22
  Logger.debug("Terraform version: #{version}")
20
- verify_version(env)
23
+
24
+ verify_version(version, requirement_by_yletf, required_by: 'YleTf')
25
+ verify_version(version, requirement_by_config(env), required_by: 'config')
21
26
 
22
27
  @app.call(env)
23
28
  end
24
29
 
25
30
  def terraform_version
26
31
  v = YleTf::System.read_cmd('terraform', 'version', error_handler: proc {})
27
- Regexp.last_match(1) if v =~ /^Terraform v([^\s]+)/
32
+ m = /^Terraform v(?<version>[^\s]+)/.match(v)
33
+ m && m[:version]
28
34
  end
29
35
 
30
- def verify_version(env)
31
- version = env[:terraform_version]
36
+ def requirement_by_config(env)
32
37
  requirement = env[:config].fetch('terraform', 'version_requirement') { nil }
38
+ VersionRequirement.new(requirement)
39
+ end
40
+
41
+ def requirement_by_yletf
42
+ VersionRequirement.new(YleTf::TERRAFORM_VERSION_REQUIREMENT)
43
+ end
33
44
 
34
- if !VersionRequirement.new(requirement).satisfied_by?(version)
35
- raise Error, "Terraform version '#{requirement}' required, '#{version}' found"
45
+ def verify_version(version, requirement, **opts)
46
+ if !requirement.satisfied_by?(version)
47
+ raise Error, "Terraform version '#{requirement}' required by #{opts[:required_by]}, " \
48
+ "'#{version}' found"
36
49
  end
37
50
  end
38
51
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yle_tf/error'
2
4
  require 'yle_tf/vars_file'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fileutils'
2
4
  require 'yle_tf/logger'
3
5
 
@@ -5,10 +7,10 @@ class YleTf
5
7
  module Action
6
8
  class WriteTerraformrcDefaults
7
9
  # Path of the Terraform CLI configuration file
8
- RC_PATH = '~/.terraformrc'.freeze
10
+ RC_PATH = '~/.terraformrc'
9
11
 
10
12
  # Path of the plugin cache directory
11
- DEFAULT_PLUGIN_CACHE_PATH = '~/.terraform.d/plugin-cache'.freeze
13
+ DEFAULT_PLUGIN_CACHE_PATH = '~/.terraform.d/plugin-cache'
12
14
 
13
15
  def initialize(app)
14
16
  @app = app
data/lib/yle_tf/action.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class YleTf
2
4
  module Action
3
5
  autoload :Builder, 'yle_tf/action/builder'
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ class YleTf
6
+ class Backend
7
+ BACKEND_CONFIG_FILE = '_backend.tf.json'
8
+
9
+ attr_reader :config
10
+
11
+ def initialize(config)
12
+ @config = config
13
+ end
14
+
15
+ def type
16
+ @type ||= config.fetch('backend', 'type')
17
+ end
18
+
19
+ def backend_specific_config
20
+ config.fetch('backend', type)
21
+ end
22
+
23
+ # Generate backend configuration file for Terraform
24
+ def configure
25
+ data = {
26
+ terraform: [{
27
+ backend: [to_h]
28
+ }]
29
+ }
30
+ File.write(BACKEND_CONFIG_FILE, JSON.pretty_generate(data))
31
+ end
32
+
33
+ # Returns the backend configuration as a `Hash` for Terraform
34
+ def to_h
35
+ { type => backend_specific_config }
36
+ end
37
+
38
+ def to_s
39
+ to_h.to_s
40
+ end
41
+ end
42
+ end
data/lib/yle_tf/cli.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yle_tf'
2
4
 
3
5
  class YleTf
@@ -1,33 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yle_tf/helpers/hash'
4
+
1
5
  class YleTf
2
6
  class Config
3
7
  module Defaults
4
8
  DEFAULT_CONFIG = {
5
- 'hooks' => {
6
- 'pre' => [],
9
+ 'hooks' => {
10
+ 'pre' => [],
7
11
  'post' => []
8
12
  },
9
- 'backend' => {
13
+ 'backend' => {
10
14
  'type' => 'file',
11
- 'bucket' => nil,
12
- 'file' => '<%= @module %>_<%= @env %>.tfstate',
13
- 'region' => nil,
14
- 'encrypt' => false,
15
+ 'file' => {
16
+ 'path' => '<%= @module %>_<%= @env %>.tfstate'
17
+ },
18
+ 's3' => {
19
+ 'key' => '<%= @module %>_<%= @env %>.tfstate'
20
+ }
15
21
  },
16
- 'tfvars' => {
22
+ 'tfvars' => {
17
23
  },
18
24
  'terraform' => {
19
25
  'version_requirement' => nil
20
26
  }
21
27
  }.freeze
22
28
 
29
+ # Returns deep copy of the default config Hash.
23
30
  def default_config
24
- DEFAULT_CONFIG.dup
31
+ Helpers::Hash.deep_copy(DEFAULT_CONFIG)
25
32
  end
26
33
 
27
34
  def default_config_context
28
35
  {
29
- env: tf_env,
30
- module: module_dir.basename.to_s,
36
+ env: tf_env,
37
+ module: module_dir.basename.to_s,
38
+ module_dir: module_dir.to_s,
31
39
  }
32
40
  end
33
41
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'erb'
2
4
 
3
5
  class YleTf
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
 
3
5
  require 'yle_tf/logger'
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yle_tf/config/defaults'
2
4
  require 'yle_tf/config/erb'
3
5
  require 'yle_tf/config/file'
6
+ require 'yle_tf/config/migration'
7
+ require 'yle_tf/helpers/hash'
4
8
  require 'yle_tf/logger'
5
9
  require 'yle_tf/plugin'
6
10
 
7
- require_relative '../../../vendor/hash_deep_merge'
8
-
9
11
  class YleTf
10
12
  class Config
11
13
  class Loader
@@ -19,20 +21,88 @@ class YleTf
19
21
  end
20
22
 
21
23
  def load
22
- Logger.debug('Loading default config')
23
- config = default_config
24
- Logger.debug(config.inspect)
24
+ load_sequence = %i[
25
+ load_default_config
26
+ load_plugin_configurations
27
+ load_config_files
28
+ evaluate_configuration_strings
29
+ ]
30
+ load_sequence.inject({}) { |config, method| send(method, config) }
31
+ end
32
+
33
+ def load_default_config(_config)
34
+ task('Loading default config') { default_config }
35
+ end
36
+
37
+ def load_plugin_configurations(config)
38
+ Logger.debug('Loading configuration from plugins')
39
+
40
+ plugins.inject(config) do |prev_config, plugin|
41
+ migrate_and_merge_configuration(prev_config, plugin.default_config,
42
+ type: 'plugin', name: plugin.to_s)
43
+ end
44
+ end
45
+
46
+ def load_config_files(config)
47
+ Logger.debug('Loading configuration from files')
48
+
49
+ config_files.inject(config) do |prev_config, file|
50
+ migrate_and_merge_configuration(prev_config, file.read,
51
+ type: 'file', name: file.name)
52
+ end
53
+ end
54
+
55
+ def evaluate_configuration_strings(config)
56
+ task('Evaluating the configuration strings') { eval_config(config) }
57
+ end
58
+
59
+ def eval_config(config)
60
+ case config
61
+ when Hash
62
+ config.each_with_object({}) { |(key, value), h| h[key] = eval_config(value) }
63
+ when Array
64
+ config.map { |item| eval_config(item) }
65
+ when String
66
+ Config::ERB.evaluate(config, config_context)
67
+ else
68
+ config
69
+ end
70
+ end
25
71
 
26
- Logger.debug('Merging default configurations from plugins')
27
- merge_plugin_configurations(config)
28
- Logger.debug(config.inspect)
72
+ def plugins
73
+ Plugin.manager.registered
74
+ end
75
+
76
+ def config_files
77
+ module_dir.descend.lazy
78
+ .map { |dir| dir.join('tf.yaml') }
79
+ .select(&:exist?)
80
+ .map { |file| Config::File.new(file) }
81
+ end
29
82
 
30
- Logger.debug('Merging configurations from files')
31
- merge_config_files(config)
32
- Logger.debug(config.inspect)
83
+ def migrate_and_merge_configuration(prev_config, config, **opts)
84
+ task("- #{opts[:name]}") { config }
85
+ return prev_config if config.empty?
33
86
 
34
- Logger.debug('Evaluating the configuration strings')
35
- eval_config(config)
87
+ source = "#{opts[:type]}: '#{opts[:name]}'"
88
+ config = migrate_old_config(config, source: source)
89
+ deep_merge(prev_config, config, source: source)
90
+ end
91
+
92
+ def migrate_old_config(config, **opts)
93
+ task(' -> Migrating') do
94
+ Config::Migration.migrate_old_config(config, opts)
95
+ end
96
+ end
97
+
98
+ def deep_merge(prev_config, config, **opts)
99
+ task(' -> Merging') do
100
+ Helpers::Hash.deep_merge(prev_config, config)
101
+ end
102
+ rescue StandardError => e
103
+ Logger.fatal("Failed to merge configuration from #{opts[:source]}:\n" \
104
+ "#{config.inspect}\ninto:\n#{prev_config.inspect}")
105
+ raise e
36
106
  end
37
107
 
38
108
  def config_context
@@ -54,53 +124,13 @@ class YleTf
54
124
  end
55
125
  end
56
126
 
57
- def merge_plugin_configurations(config)
58
- Plugin.manager.default_configs.each do |plugin_config|
59
- deep_merge(
60
- config, plugin_config,
61
- error_msg:
62
- "Failed to merge a plugin's default configuration:\n" \
63
- "#{plugin_config.inspect}\ninto:\n#{config.inspect}"
64
- )
65
- end
66
- end
67
-
68
- def merge_config_files(config)
69
- config_files do |file|
70
- Logger.debug(" - #{file}")
71
- deep_merge(
72
- config, file.read,
73
- error_msg:
74
- "Failed to merge configuration from '#{file}' into:\n" \
75
- "#{config.inspect}"
76
- )
77
- end
78
- end
127
+ # Helper to print debug information about the task and configuration
128
+ # after it
129
+ def task(message = nil)
130
+ Logger.debug(message) if message
79
131
 
80
- def deep_merge(config, new_config, opts = {})
81
- config.deep_merge!(new_config)
82
- rescue StandardError => e
83
- Logger.fatal(opts[:error_msg]) if opts[:error_msg]
84
- raise e
85
- end
86
-
87
- def config_files
88
- module_dir.descend do |dir|
89
- file = dir.join('tf.yaml')
90
- yield(Config::File.new(file)) if file.exist?
91
- end
92
- end
93
-
94
- def eval_config(config)
95
- case config
96
- when Hash
97
- config.each_with_object({}) { |(key, value), h| h[key] = eval_config(value) }
98
- when Array
99
- config.map { |item| eval_config(item) }
100
- when String
101
- Config::ERB.evaluate(config, config_context)
102
- else
103
- config
132
+ yield.tap do |config|
133
+ Logger.debug(" #{config.inspect}")
104
134
  end
105
135
  end
106
136
  end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require 'yle_tf/helpers/hash'
5
+ require 'yle_tf/logger'
6
+
7
+ class YleTf
8
+ class Config
9
+ class Migration
10
+ BACKEND_MIGRATIONS = {
11
+ 'file' => {
12
+ 'file' => 'path'
13
+ },
14
+ 's3' => {
15
+ 'region' => 'region',
16
+ 'bucket' => 'bucket',
17
+ 'file' => 'key',
18
+ 'encrypt' => 'encrypt'
19
+ },
20
+ 'swift' => {
21
+ 'region' => 'region_name',
22
+ 'container' => 'container',
23
+ 'archive_container' => 'archive_container'
24
+ }
25
+ }.freeze
26
+
27
+ include Helpers::Hash
28
+
29
+ def self.migrate_old_config(config, **opts)
30
+ new(config, **opts).migrated_config
31
+ end
32
+
33
+ attr_reader :config, :config_source
34
+
35
+ def initialize(config, **opts)
36
+ @config = config
37
+ @config_source = opts.fetch(:source)
38
+ end
39
+
40
+ def old_backend_config
41
+ config['backend']
42
+ end
43
+
44
+ def migrated_config
45
+ migrate_old_backend_config do |new_config|
46
+ Logger.warn("Old configuration found in #{config_source}")
47
+ Logger.warn("Please migrate to relevant parts of:\n" \
48
+ "#{sanitize_config(new_config)}")
49
+ Logger.warn(
50
+ 'See https://github.com/Yleisradio/yle_tf/wiki/Migrating-Configuration for more details'
51
+ )
52
+ end
53
+ end
54
+
55
+ # TODO: Remove support in v2.0
56
+ def migrate_old_backend_config
57
+ changed = false
58
+
59
+ new_config = BACKEND_MIGRATIONS.inject(config) do |prev_config, (type, keys)|
60
+ migrate_old_backend_config_keys(prev_config, type, keys) { changed = true }
61
+ end
62
+
63
+ yield(new_config) if changed
64
+
65
+ new_config
66
+ end
67
+
68
+ def migrate_old_backend_config_keys(config, type, keys)
69
+ migrated_keys = find_old_backend_config_keys(keys)
70
+ return config if migrated_keys.empty?
71
+
72
+ defaults = {
73
+ 'backend' => {
74
+ type => {}
75
+ }
76
+ }
77
+ copy_with_defaults(config, defaults).tap do |new_config|
78
+ migrated_keys.each do |old_key, new_key|
79
+ new_config['backend'][type][new_key] = old_backend_config[old_key]
80
+ end
81
+
82
+ yield new_config
83
+ end
84
+ end
85
+
86
+ def find_old_backend_config_keys(keys)
87
+ return {} if !old_backend_config.is_a?(Hash)
88
+
89
+ keys.select do |old_key, _new_key|
90
+ old_backend_config.key?(old_key) &&
91
+ # Special case for 'file' as it is now used for option Hash for the
92
+ # 'file' backend
93
+ !(old_key == 'file' && old_backend_config['file'].is_a?(Hash))
94
+ end
95
+ end
96
+
97
+ def copy_with_defaults(config, defaults)
98
+ deep_merge(deep_copy(config), defaults)
99
+ end
100
+
101
+ def sanitize_config(config)
102
+ backend_config = config['backend'].select do |key, value|
103
+ key == 'type' || value.is_a?(Hash)
104
+ end
105
+
106
+ YAML.dump('backend' => backend_config)
107
+ end
108
+ end
109
+ end
110
+ end