yle_tf 1.0.0 → 1.1.0.rc1

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.
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