lono 8.0.0.pre.rc2 → 8.0.0.pre.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -2
  3. data/Gemfile +1 -3
  4. data/lib/lono/app/callable_option/concern.rb +12 -0
  5. data/lib/lono/app/callable_option.rb +56 -0
  6. data/lib/lono/app.rb +22 -23
  7. data/lib/lono/autoloader.rb +1 -0
  8. data/lib/lono/aws_services/helper.rb +0 -2
  9. data/lib/lono/blueprint.rb +1 -18
  10. data/lib/lono/builder/allow/base.rb +54 -0
  11. data/lib/lono/builder/allow/env.rb +17 -0
  12. data/lib/lono/builder/allow/region.rb +20 -0
  13. data/lib/lono/builder/allow.rb +8 -0
  14. data/lib/lono/builder/configset/combiner.rb +145 -0
  15. data/lib/lono/builder/configset/definition/base.rb +47 -0
  16. data/lib/lono/builder/configset/definition/context.rb +29 -0
  17. data/lib/lono/{configset/strategy/helpers/dsl → builder/configset/definition/dsl/syntax}/auth.rb +1 -1
  18. data/lib/lono/{configset/strategy/helpers/dsl/core.rb → builder/configset/definition/dsl/syntax/content.rb} +12 -4
  19. data/lib/lono/{configset/strategy/helpers/dsl/syntax.rb → builder/configset/definition/dsl/syntax/core.rb} +15 -9
  20. data/lib/lono/{configset/strategy/helpers/dsl → builder/configset/definition/dsl/syntax}/package.rb +1 -1
  21. data/lib/lono/builder/configset/definition/dsl/syntax.rb +5 -0
  22. data/lib/lono/{configset/strategy → builder/configset/definition}/dsl.rb +10 -14
  23. data/lib/lono/{configset/strategy → builder/configset/definition}/erb.rb +13 -16
  24. data/lib/lono/builder/configset/definition.rb +18 -0
  25. data/lib/lono/builder/configset/evaluator.rb +10 -0
  26. data/lib/lono/builder/configset/registration.rb +35 -0
  27. data/lib/lono/builder/context.rb +40 -0
  28. data/lib/lono/builder/dsl/evaluator.rb +6 -55
  29. data/lib/lono/builder/dsl/finalizer/base.rb +8 -0
  30. data/lib/lono/builder/dsl/finalizer/configsets.rb +7 -28
  31. data/lib/lono/builder/dsl/finalizer/files/base.rb +4 -0
  32. data/lib/lono/builder/dsl/finalizer/files/build.rb +58 -0
  33. data/lib/lono/builder/dsl/finalizer/files/replace.rb +31 -0
  34. data/lib/lono/builder/dsl/finalizer/files.rb +9 -0
  35. data/lib/lono/builder/dsl/finalizer/parameter_groups.rb +4 -3
  36. data/lib/lono/builder/dsl/finalizer.rb +4 -2
  37. data/lib/lono/builder/dsl/helpers/files.rb +7 -0
  38. data/lib/lono/builder/dsl/helpers/partials.rb +48 -53
  39. data/lib/lono/builder/dsl/helpers/s3.rb +1 -1
  40. data/lib/lono/builder/dsl/helpers/ssm/fetcher.rb +3 -1
  41. data/lib/lono/builder/dsl/helpers/template_file.rb +18 -6
  42. data/lib/lono/builder/dsl/helpers.rb +1 -11
  43. data/lib/lono/builder/dsl/syntax/core/resource/property_mover.rb +11 -1
  44. data/lib/lono/builder/dsl/syntax/core/squeezer.rb +16 -2
  45. data/lib/lono/builder/dsl.rb +1 -1
  46. data/lib/lono/builder/param.rb +4 -1
  47. data/lib/lono/builder/template/upload.rb +2 -15
  48. data/lib/lono/cfn/cancel.rb +5 -5
  49. data/lib/lono/cfn/deploy/iam.rb +1 -1
  50. data/lib/lono/cfn/deploy.rb +32 -3
  51. data/lib/lono/cfn/download.rb +0 -1
  52. data/lib/lono/cfn/plan/changeset.rb +2 -2
  53. data/lib/lono/cfn/plan/diff/data.rb +11 -1
  54. data/lib/lono/cfn/plan/param.rb +1 -1
  55. data/lib/lono/cfn/plan/template.rb +2 -2
  56. data/lib/lono/cfn/plan.rb +1 -0
  57. data/lib/lono/cli/abstract.rb +0 -6
  58. data/lib/lono/cli/base.rb +5 -3
  59. data/lib/lono/cli/build.rb +16 -60
  60. data/lib/lono/cli/clean.rb +3 -2
  61. data/lib/lono/cli/code.rb +12 -12
  62. data/lib/lono/cli/help/new/helper/blueprint.md +17 -0
  63. data/lib/lono/cli/help/new/helper/project.md +16 -0
  64. data/lib/lono/cli/list.rb +3 -6
  65. data/lib/lono/cli/new/blueprint.rb +3 -7
  66. data/lib/lono/cli/new/configset.rb +11 -44
  67. data/lib/lono/cli/new/helper/blueprint.rb +26 -0
  68. data/lib/lono/cli/new/helper/project.rb +24 -0
  69. data/lib/lono/cli/new/helper.rb +8 -27
  70. data/lib/lono/cli/new/sequence.rb +6 -1
  71. data/lib/lono/cli/new.rb +8 -12
  72. data/lib/lono/cli/status.rb +18 -0
  73. data/lib/lono/cli.rb +6 -9
  74. data/lib/lono/command.rb +0 -1
  75. data/lib/lono/component.rb +29 -0
  76. data/lib/lono/concerns/aws_info.rb +14 -0
  77. data/lib/lono/concerns/names.rb +9 -0
  78. data/lib/lono/configset.rb +17 -0
  79. data/lib/lono/core.rb +1 -1
  80. data/lib/lono/ext/bundler.rb +7 -0
  81. data/lib/lono/ext/core/module.rb +31 -0
  82. data/lib/lono/ext/core/object.rb +32 -0
  83. data/lib/lono/ext/core/string.rb +9 -0
  84. data/lib/lono/ext.rb +4 -0
  85. data/lib/lono/files/base.rb +12 -0
  86. data/lib/lono/files/builder.rb +37 -0
  87. data/lib/lono/files/compressor.rb +53 -0
  88. data/lib/lono/files/concerns/post_processing.rb +35 -0
  89. data/lib/lono/files/concerns/registration.rb +13 -0
  90. data/lib/lono/files/registry.rb +6 -0
  91. data/lib/lono/files.rb +37 -0
  92. data/lib/lono/importer/base.rb +1 -1
  93. data/lib/lono/inspector/summary.rb +0 -3
  94. data/lib/lono/layering/layer.rb +3 -17
  95. data/lib/lono/logger.rb +1 -3
  96. data/lib/lono/names.rb +1 -1
  97. data/lib/lono/s3/uploader.rb +29 -28
  98. data/lib/lono/seeder.rb +18 -27
  99. data/lib/lono/user_data.rb +3 -1
  100. data/lib/lono/version.rb +1 -1
  101. data/lib/lono/yamler/validator.rb +7 -22
  102. data/lib/lono.rb +8 -0
  103. data/lib/templates/configset/configset.rb +2 -16
  104. data/lib/templates/examples/configset/configset.rb +16 -0
  105. data/lib/templates/helper/%underscore_name%_helper.rb.tt +1 -1
  106. data/lono.gemspec +1 -1
  107. metadata +52 -39
  108. data/lib/lono/app_file/base.rb +0 -28
  109. data/lib/lono/app_file/build/lambda_layer/ruby_packager.rb +0 -153
  110. data/lib/lono/app_file/build/lambda_layer.rb +0 -20
  111. data/lib/lono/app_file/build.rb +0 -79
  112. data/lib/lono/app_file/registry/item.rb +0 -24
  113. data/lib/lono/app_file/registry.rb +0 -16
  114. data/lib/lono/app_file/upload.rb +0 -12
  115. data/lib/lono/builder/context/generic.rb +0 -11
  116. data/lib/lono/builder/context/loaders/load_files.rb +0 -23
  117. data/lib/lono/builder/context/loaders.rb +0 -35
  118. data/lib/lono/builder/context/params.rb +0 -6
  119. data/lib/lono/builder/context/template.rb +0 -4
  120. data/lib/lono/configset/builder.rb +0 -59
  121. data/lib/lono/configset/combiner.rb +0 -164
  122. data/lib/lono/configset/evaluate_file.rb +0 -8
  123. data/lib/lono/configset/meta/dsl.rb +0 -12
  124. data/lib/lono/configset/meta.rb +0 -19
  125. data/lib/lono/configset/s3_file/build.rb +0 -34
  126. data/lib/lono/configset/s3_file/item.rb +0 -38
  127. data/lib/lono/configset/s3_file/registry.rb +0 -12
  128. data/lib/lono/configset/s3_file/upload.rb +0 -12
  129. data/lib/lono/configset/strategy/base.rb +0 -83
  130. data/lib/lono/configset/strategy/helpers/dsl.rb +0 -8
  131. data/lib/lono/configset/strategy/helpers/erb.rb +0 -9
  132. data/lib/lono/lookup.rb +0 -12
  133. data/lib/lono/seeder/service_role.rb +0 -11
  134. data/lib/lono/utils/contexts.rb +0 -15
  135. data/lib/lono/utils/item/file_methods.rb +0 -29
  136. data/lib/lono/utils/item/zip.rb +0 -42
@@ -1,153 +0,0 @@
1
- class Lono::AppFile::Build::LambdaLayer
2
- # Based on jets
3
- class RubyPackager
4
- include Lono::Utils::Rsync
5
-
6
- def initialize(blueprint, registry_item)
7
- @blueprint.name, @registry_item = blueprint, registry_item
8
-
9
- @registry_name = @registry_item.name.sub(/\/$/,'')
10
- @app_root = "#{@blueprint.root}/app/files/#{@registry_name}"
11
- end
12
-
13
- def build
14
- return unless gemfile_exist?
15
-
16
- bundle_install
17
- package
18
- end
19
-
20
- # We consolidate all gems to opt
21
- def package
22
- setup_bundle_config(output_area)
23
- # copy_cache_gems # TODO: might not need this cache
24
- consolidate_gems_to_opt
25
- end
26
-
27
- # Also restructure the folder from:
28
- # vendor/gems/ruby/2.5.0
29
- # To:
30
- # ruby/gems/2.5.0
31
- #
32
- # For Lambda Layer structure
33
- def consolidate_gems_to_opt
34
- src = "#{cache_area}/vendor/gems/ruby/#{ruby_folder}"
35
- dest = "#{opt_area}/ruby/gems/#{ruby_folder}"
36
- rsync_and_link(src, dest)
37
- end
38
-
39
- def rsync_and_link(src, dest)
40
- FileUtils.mkdir_p(dest)
41
- rsync(src, dest)
42
-
43
- # create symlink in output path not the cache path
44
- symlink_dest = "#{output_area}/vendor/gems/ruby/#{ruby_folder}"
45
- logger.info "symlink_dest #{symlink_dest}"
46
- FileUtils.rm_rf(symlink_dest) # blow away original 2.5.0 folder
47
-
48
- # Create symlink that will point to the gems in the Lambda Layer:
49
- # stage/opt/ruby/gems/2.5.0 -> /opt/ruby/gems/2.5.0
50
- FileUtils.mkdir_p(File.dirname(symlink_dest))
51
- FileUtils.ln_sf("/opt/ruby/gems/#{ruby_folder}", symlink_dest)
52
- end
53
-
54
- def ruby_folder
55
- major, minor, _ = RUBY_VERSION.split('.')
56
- [major, minor, '0'].join('.') # 2.5.1 => 2.5.0
57
- end
58
-
59
- # Installs gems on the current target system: both compiled and non-compiled.
60
- # If user is on a macosx machine, macosx gems will be installed.
61
- # If user is on a linux machine, linux gems will be installed.
62
- #
63
- # Copies Gemfile* to /tmp/jets/demo/cache folder and installs
64
- # gems with bundle install from there.
65
- #
66
- # We take the time to copy Gemfile and bundle into a separate directory
67
- # because it gets left around to act as a 'cache'. So, when the builds the
68
- # project gets built again not all the gems from get installed from the
69
- # beginning.
70
- def bundle_install
71
- logger.info "Bundling: running bundle install in cache area: #{cache_area}."
72
-
73
- rsync(output_area, cache_area)
74
-
75
- # Uncomment out to always remove the cache/vendor/gems to debug
76
- # FileUtils.rm_rf("#{cache_area}/vendor/gems")
77
-
78
- # Remove .bundle folder so .bundle/config doesnt affect how gems are packages
79
- # Not using BUNDLE_IGNORE_CONFIG=1 to allow home ~/.bundle/config to affect bundling though.
80
- # This is useful if you have private gems sources that require authentication. Example:
81
- #
82
- # bundle config gems.myprivatesource.com user:pass
83
- #
84
-
85
- FileUtils.rm_rf("#{cache_area}/.bundle")
86
- require "bundler" # dynamically require bundler so user can use any bundler
87
- setup_bundle_config(cache_area)
88
- ::Bundler.with_unbundled_env do
89
- sh "cd #{cache_area} && env bundle install"
90
- end
91
-
92
- remove_bundled_with("#{cache_area}/Gemfile.lock")
93
- # Fixes really tricky bug where Gemfile and Gemfile.lock is out-of-sync. Details: https://gist.github.com/tongueroo/b5b0d0c924a4a1633eee514795e4b04b
94
- FileUtils.cp("#{cache_area}/Gemfile.lock", "#{Lono.root}/output/#{@blueprint.name}/files/#{@registry_name}/Gemfile.lock")
95
-
96
- logger.info 'Bundle install success.'
97
- end
98
-
99
- # Remove the BUNDLED WITH line since we don't control the bundler gem version on AWS Lambda
100
- # And this can cause issues with require 'bundler/setup'
101
- def remove_bundled_with(gemfile_lock)
102
- lines = IO.readlines(gemfile_lock)
103
-
104
- # amount is the number of lines to remove
105
- new_lines, capture, count, amount = [], true, 0, 2
106
- lines.each do |l|
107
- capture = false if l.include?('BUNDLED WITH')
108
- if capture
109
- new_lines << l
110
- end
111
- if capture == false
112
- count += 1
113
- capture = count > amount # renable capture
114
- end
115
- end
116
-
117
- content = new_lines.join('')
118
- IO.write(gemfile_lock, content)
119
- end
120
-
121
- def setup_bundle_config(dir)
122
- text =<<-EOL
123
- ---
124
- BUNDLE_PATH: "vendor/gems"
125
- BUNDLE_WITHOUT: "development:test"
126
- EOL
127
- bundle_config = "#{dir}/.bundle/config"
128
- FileUtils.mkdir_p(File.dirname(bundle_config))
129
- IO.write(bundle_config, text)
130
- end
131
-
132
- def output_area
133
- "#{Lono.root}/output/#{@blueprint.name}/files/#{@registry_name}"
134
- end
135
-
136
- def build_area
137
- "#{Lono.root}/output/#{@blueprint.name}/lambda_layers/#{@registry_name}"
138
- end
139
-
140
- def cache_area
141
- "#{build_area}/cache"
142
- end
143
-
144
- def opt_area
145
- "#{build_area}/opt"
146
- end
147
-
148
- def gemfile_exist?
149
- gemfile_path = "#{@app_root}/Gemfile"
150
- File.exist?(gemfile_path)
151
- end
152
- end
153
- end
@@ -1,20 +0,0 @@
1
- class Lono::AppFile::Build
2
- class LambdaLayer
3
- def initialize(blueprint, registry_item)
4
- @blueprint.name, @registry_item = blueprint, registry_item
5
- end
6
-
7
- def build
8
- lang = @registry_item.options[:lang]
9
- unless lang =~ /ruby/
10
- logger.info "WARN: Currently only support ruby lambda layers".color(:yellow)
11
- return
12
- end
13
-
14
- klass_name = "Lono::AppFile::Build::LambdaLayer::#{lang.camelize}Packager"
15
- klass = klass_name.constantize
16
- packager = klass.new(@blueprint.name, @registry_item)
17
- packager.build
18
- end
19
- end
20
- end
@@ -1,79 +0,0 @@
1
- require "thor"
2
-
3
- module Lono::AppFile
4
- class Build < Base
5
- include Lono::Utils::Item::Zip
6
-
7
- def initialize_variables
8
- @output_files_path = "#{Lono.root}/output/#{@blueprint.name}/files"
9
- end
10
-
11
- def run
12
- return unless detect_files?
13
- logger.info "Building app/files"
14
- build_all
15
- end
16
-
17
- def build_all
18
- clean_output
19
- validate_files!
20
- copy_to_output
21
- build_layers
22
- compress_output
23
- end
24
-
25
- def validate_files!
26
- items = Registry.items + Registry.layers
27
- missing = items.select do |item|
28
- !File.exist?(item.src_path)
29
- end
30
- missing_paths = missing.map { |item| item.src_path }.uniq
31
- unless missing_paths.empty?
32
- logger.info "ERROR: These app/files are missing were used by the s3_key method but are missing".color(:red)
33
- missing_paths.each do |path|
34
- logger.info " #{path}"
35
- end
36
- logger.info "Please double check that they exist."
37
- exit 1
38
- end
39
- end
40
-
41
- def build_layers
42
- layer_items = Registry.layers
43
- layer_items.each do |item|
44
- LambdaLayer.new(@blueprint, item).build
45
- end
46
- end
47
-
48
- def compress_output
49
- Registry.items.each do |item|
50
- # type can be lambda_layer or file
51
- if item.type == "lambda_layer" || item.exist?
52
- zip(item)
53
- else
54
- logger.info "WARN: #{item.src_path} does not exist. Double check that the path is correct in the s3_key call.".color(:yellow)
55
- end
56
- end
57
- end
58
-
59
- def copy_to_output
60
- override_source_paths("#{@blueprint.root}/app/files")
61
- self.destination_root = @output_files_path
62
- directory(".", verbose: false, context: template_context.get_binding) # Thor::Action
63
- end
64
-
65
- def clean_output
66
- FileUtils.rm_rf(@output_files_path)
67
- end
68
-
69
- def detect_files?
70
- app_files = Dir["#{@blueprint.root}/app/files/*"]
71
- if app_files.empty?
72
- false
73
- else
74
- logger.info "Detected app/files"
75
- true
76
- end
77
- end
78
- end
79
- end
@@ -1,24 +0,0 @@
1
- class Lono::AppFile::Registry
2
- # Holds metadata about the item in the regsitry.
3
- class Item
4
- include Lono::Utils::Item::FileMethods
5
-
6
- attr_reader :name, :options, :type
7
- def initialize(name, blueprint, options={})
8
- @name, @blueprint.name, @options = name, blueprint, options
9
- @type = options[:type] || "file"
10
- end
11
-
12
- def src_path
13
- "#{@blueprint.root}/app/files/#{@name}"
14
- end
15
-
16
- def output_path
17
- if @type == "file"
18
- "#{Lono.root}/output/#{@blueprint.name}/files/#{@name}"
19
- else
20
- "#{Lono.root}/output/#{@blueprint.name}/lambda_layers/#{@name}/opt"
21
- end
22
- end
23
- end
24
- end
@@ -1,16 +0,0 @@
1
- module Lono::AppFile
2
- class Registry
3
- cattr_reader :items
4
- @@items = []
5
-
6
- class << self
7
- def register(name, blueprint, options={})
8
- @@items << Item.new(name, blueprint, options) unless @@items.detect { |i| i.name == name && i.type == options[:type] }
9
- end
10
-
11
- def layers
12
- @@items.select { |i| i.type == "lambda_layer" }
13
- end
14
- end
15
- end
16
- end
@@ -1,12 +0,0 @@
1
- module Lono::AppFile
2
- class Upload < Base
3
- def upload
4
- return unless Registry.items.size > 0
5
- logger.info "Uploading app/files..."
6
-
7
- Registry.items.each do |item|
8
- Lono::S3::Uploader.new(item.zip_file_path).upload
9
- end
10
- end
11
- end
12
- end
@@ -1,11 +0,0 @@
1
- module Lono::Builder::Context
2
- class Generic < Lono::CLI::Base
3
- include Lono::Builder::Dsl::Syntax
4
-
5
- # For Lono::AppFile::Build usage of Thor::Action directory
6
- # For some reason a send(:binding) doesnt work but get_binding like this works.
7
- def get_binding
8
- binding
9
- end
10
- end
11
- end
@@ -1,23 +0,0 @@
1
- module Lono::Builder::Context::Loaders
2
- module LoadFiles
3
- # Load custom helper methods from project
4
- def load_files(dir)
5
- paths = Dir.glob("#{dir}/**/*.rb")
6
- paths.sort_by! { |p| p.size } # so namespaces are loaded first
7
- paths.each do |path|
8
- # helpers = blueprint or project extensions
9
- filename = path.sub(%r{.*/helpers/},'').sub('.rb','')
10
- module_name = filename.camelize
11
-
12
- # Prepend a period so require works LONO_ROOT is set to a relative path without a period.
13
- #
14
- # Example: LONO_ROOT=tmp/lono_project
15
- first_char = path[0..0]
16
- path = "./#{path}" unless %w[. /].include?(first_char)
17
-
18
- require path
19
- self.class.send :include, module_name.constantize
20
- end
21
- end
22
- end
23
- end
@@ -1,35 +0,0 @@
1
- module Lono::Builder::Context
2
- module Loaders
3
- include LoadFiles
4
-
5
- # Variables in base.rb are overridden by their environment specific variables
6
- # file. Example, file LONO_ENV=dev:
7
- #
8
- # config/vars/base.rb
9
- # config/vars/dev.rb - will override any variables in base.rb
10
- # config/vars/base.rb
11
- # config/vars/dev.rb - will override any variables in base.rb
12
- #
13
- def load_variables
14
- layers = Lono::Layering::Layer.new(@blueprint, "vars").paths
15
- layers.each do |layer|
16
- evaluate_variables_file(layer)
17
- end
18
- end
19
-
20
- # Load the variables defined in config/vars/* to make available in lono scope.
21
- #
22
- # NOTE: Was only able to make instance variables avaialble with instance_eval, wasnt able to make local variables
23
- # available.
24
- def evaluate_variables_file(path)
25
- return unless File.exist?(path)
26
- instance_eval(IO.read(path), path)
27
- end
28
-
29
- # Load blueprint helpers
30
- # blueprint helpers override extension helpers
31
- def load_blueprint_helpers
32
- load_files("#{@blueprint.root}/#{Lono.config.paths.helpers}")
33
- end
34
- end
35
- end
@@ -1,6 +0,0 @@
1
- module Lono::Builder::Context
2
- class Params < Generic
3
- # Overriding output resource DSL method
4
- alias_method :output, :stack_output
5
- end
6
- end
@@ -1,4 +0,0 @@
1
- module Lono::Builder::Context
2
- class Template < Generic
3
- end
4
- end
@@ -1,59 +0,0 @@
1
- module Lono::Configset
2
- class Builder
3
- include Lono::Utils::Logging
4
-
5
- def initialize(options)
6
- @options = options
7
- @configset = options[:configset]
8
- @type = options[:type] || "project"
9
- end
10
-
11
- def run
12
- check_configset_exist!
13
- structure = build
14
- logger.info YAML.dump(structure)
15
- end
16
-
17
- def check_configset_exist!
18
- exist = !!Lono::Finder::Configset.find(@configset)
19
- unless exist
20
- logger.info "configset #{@configset.color(:green)} not found."
21
- exit 1
22
- end
23
- end
24
-
25
- def build
26
- # Examples:
27
- # Erb.new(options).build
28
- # Dsl.new(options).build
29
- builder_class = "Lono::Configset::Strategy::#{strategy.camelize}"
30
- builder_class = Object.const_get(builder_class)
31
- full = builder_class.new(@options.merge(root: configset_root)).build
32
- if @options[:cli]
33
- full["Metadata"] # contains AWS::CloudFormation::Init and optional AWS::CloudFormation::Authentication
34
- else
35
- full # Combiner uses full metadata structure
36
- end
37
- end
38
-
39
- def strategy
40
- jadespec = Lono::Jadespec.new(configset_root, "unknown") # abusing Jadespec to get strategy
41
- jadespec.lono_strategy
42
- end
43
-
44
- def configset_root
45
- finder = finder_class.new
46
- found = finder.find(@configset, local_only: false)
47
- found.root if found
48
- end
49
-
50
- def finder_class
51
- case @type
52
- when "project"
53
- Lono::Finder::Configset
54
- when "blueprint"
55
- Lono::Finder::Blueprint::Configset
56
- end
57
- end
58
- end
59
- end
@@ -1,164 +0,0 @@
1
- require "yaml"
2
-
3
- module Lono::Configset
4
- class Combiner
5
- include Lono::Utils::Logging
6
-
7
- def initialize(cfn, options={})
8
- @cfn, @options = cfn, options
9
-
10
- @sets = []
11
- @map = {} # stores resource logical id => metadata cfn-init
12
- end
13
-
14
- def generator_options(registry, options={})
15
- o = @options.merge(configset: registry.name, resource: registry.resource)
16
- o.merge(options)
17
- end
18
-
19
- def metadata_map
20
- return {} unless additional_configsets?
21
-
22
- existing_configsets.each do |data|
23
- add(data[:registry], data[:metdata_configset])
24
- end
25
-
26
- Register::Blueprint.configsets.each do |registry|
27
- generator = Lono::Configset::Generator.new(generator_options(registry, type: "blueprint"))
28
- cloudformation_init = generator.build
29
- add(registry, cloudformation_init)
30
- end
31
- Register::Project.configsets.each do |registry|
32
- generator = Lono::Configset::Generator.new(generator_options(registry, type: "project"))
33
- cloudformation_init = generator.build
34
- add(registry, cloudformation_init)
35
- end
36
-
37
- combine
38
- Register::Blueprint.clear! # in case of lono build for all templates
39
- Register::Project.clear! # in case of lono build for all templates
40
- @map
41
- end
42
-
43
- def add(registry, metadata)
44
- @sets << [registry, metadata.dup]
45
- end
46
-
47
- def additional_configsets?
48
- !Register::Blueprint.configsets.empty? || !Register::Project.configsets.empty?
49
- end
50
-
51
- # Normalized/convert cfn template to mimic the registry format
52
- def existing_configsets
53
- configsets = []
54
- @cfn["Resources"].each do |logical_id, attributes|
55
- init = attributes.dig("Metadata", "AWS::CloudFormation::Init")
56
-
57
- next unless init
58
-
59
- data = {
60
- registry: Lono::Jade::Registry.new(["#{logical_id}OriginalConfigset"], resource: logical_id),
61
- metdata_configset: {"Metadata" => attributes["Metadata"]} # # wrap metadata to create right structure
62
- }
63
- configsets << data
64
- end
65
- configsets
66
- end
67
-
68
- def combine
69
- # Remove duplicate configsets. Can happen if same configset is in blueprint and project.
70
- # Ugly because of the sets structure.
71
- @sets.uniq! do |array|
72
- registry, _ = array
73
- registry.name
74
- end
75
-
76
- metadata_map = {}
77
- configsets_map = {}
78
-
79
- @sets.each_with_index do |array, i|
80
- padded_i = "%03d" % i
81
- registry, metadata = array
82
-
83
- # metadata example (full structure):
84
- #
85
- # {"Metadata"=>
86
- # {"AWS::CloudFormation::Init"=>
87
- # {"configSets"=>{"default"=>["aaa1", "aaa2"]},
88
- # "aaa1"=>{"commands"=>{"test"=>{"command"=>"echo from-aaa1 > test1.txt"}}},
89
- # "aaa2"=>
90
- # {"commands"=>{"test"=>{"command"=>"echo from-aaa2 > test1.txt"}}}}}}
91
-
92
- name, resource = registry.name, registry.resource
93
- configsets = configsets_map[resource] ||= {}
94
-
95
- validate_structure!(name, metadata)
96
-
97
- new_metadata = metadata["Metadata"].dup
98
- init = new_metadata["AWS::CloudFormation::Init"] # important: adjust data by reference
99
-
100
- if init.key?("configSets")
101
- validate_simple!(registry, new_metadata["AWS::CloudFormation::Init"]["configSets"]) # validate original configset for only simple elements
102
-
103
- # 1. expand each config as its own config, flattening to top-level
104
- cs = init.delete("configSets") # Only support configSets with simple Array of Strings
105
- new_config_set = {}
106
- new_config_set[name] = cs["default"].map {|c| "#{padded_i}_#{c}" }
107
- init.transform_keys! { |c| "#{padded_i}_#{c}" }
108
-
109
- # Rebuild default configSet, append the new complex ConfigSet structure with each iteration
110
- configsets["default"] ||= []
111
- configsets["default"] << {"ConfigSet" => name}
112
- configsets.merge!(new_config_set) # add each config from #1 to the top-level
113
-
114
- init["configSets"] = configsets # replace new configset
115
- else # simple config
116
- init["configSets"] = configsets # adjust data by reference
117
- configsets["default"] ||= []
118
- configsets["default"] << {"ConfigSet" => name}
119
-
120
- # build new config
121
- config_key = "#{padded_i}_single_generated"
122
- configsets[name] = [config_key]
123
- new_config = {config_key => init["config"]}
124
- # replace old config with new one
125
- init.delete("config") # delete original simple config
126
- init.merge!(new_config)
127
- end
128
-
129
- metadata_map[resource] ||= {"Metadata" => {}}
130
- metadata_map[resource]["Metadata"].deep_merge!(new_metadata)
131
- @map[resource] = metadata_map[resource]
132
- end
133
- @map
134
- end
135
-
136
- def validate_structure!(name, metadata)
137
- return if metadata.is_a?(Hash) && metadata.dig("Metadata", "AWS::CloudFormation::Init")
138
-
139
- logger.info "ERROR: The #{name} configset does not appear to have a AWS::CloudFormation::Init key".color(:red)
140
- logger.info "Please double check the #{name} configset.yml structure"
141
- exit 1
142
- end
143
-
144
- def validate_simple!(registry, cs)
145
- has_complex_type = cs["default"].detect { |s| !s.is_a?(String) }
146
- if has_complex_type
147
- message =<<~EOL
148
- ERROR: The configset #{registry.name} has a configSets property with a complex type.
149
- configSets:
150
-
151
- #{cs}
152
-
153
- lono configsets only supports combining configSets with an Array of Strings.
154
- EOL
155
- if ENV['LONO_TEST']
156
- raise message
157
- else
158
- logger.info message.color(:red)
159
- exit 1
160
- end
161
- end
162
- end
163
- end
164
- end
@@ -1,8 +0,0 @@
1
- module Lono::Configset
2
- module EvaluateFile
3
- def evaluate_file(path)
4
- return unless path && File.exist?(path)
5
- instance_eval(IO.read(path), path)
6
- end
7
- end
8
- end
@@ -1,12 +0,0 @@
1
- class Lono::Configset::Meta
2
- module Dsl
3
- def depends_on(*args)
4
- options = args.last.is_a?(Hash) ? args.pop : {}
5
- registry = Lono::Jade::Registry.new(args, options)
6
- registry.depends_on = args.first
7
- registry.parent = @jade
8
- already_has = @jade.depends_ons.detect { |d| d.name == registry.name && d.args == registry.args }
9
- @jade.depends_ons << registry unless already_has
10
- end
11
- end
12
- end
@@ -1,19 +0,0 @@
1
- module Lono::Configset
2
- class Meta
3
- extend Memoist
4
- include EvaluateFile
5
- include Dsl
6
-
7
- class_attribute :registries
8
- self.registries = []
9
-
10
- def initialize(jade)
11
- @jade = jade
12
- end
13
-
14
- def evaluate
15
- path = "#{@jade.root}/lib/meta.rb"
16
- evaluate_file(path) # DSL depends_on sets @jade.depends_on decorated options
17
- end
18
- end
19
- end